feat: add audio track types
This commit is contained in:
parent
5a9b6ed2e3
commit
3fb356a706
|
@ -2,6 +2,7 @@ package org.schabi.newpipe.extractor.services.youtube;
|
|||
|
||||
import org.schabi.newpipe.extractor.MediaFormat;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.stream.AudioTrackType;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -201,7 +202,7 @@ public class ItagItem implements Serializable {
|
|||
this.contentLength = itagItem.contentLength;
|
||||
this.audioTrackId = itagItem.audioTrackId;
|
||||
this.audioTrackName = itagItem.audioTrackName;
|
||||
this.isDescriptiveAudio = itagItem.isDescriptiveAudio;
|
||||
this.audioTrackType = itagItem.audioTrackType;
|
||||
this.audioLocale = itagItem.audioLocale;
|
||||
}
|
||||
|
||||
|
@ -251,7 +252,8 @@ public class ItagItem implements Serializable {
|
|||
private long contentLength = CONTENT_LENGTH_UNKNOWN;
|
||||
private String audioTrackId;
|
||||
private String audioTrackName;
|
||||
private boolean isDescriptiveAudio;
|
||||
@Nullable
|
||||
private AudioTrackType audioTrackType;
|
||||
@Nullable
|
||||
private Locale audioLocale;
|
||||
|
||||
|
@ -594,21 +596,22 @@ public class ItagItem implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return whether the stream is a descriptive audio.
|
||||
* Get the {@link AudioTrackType} of the stream.
|
||||
*
|
||||
* @return whether the stream is a descriptive audio
|
||||
* @return the {@link AudioTrackType} of the stream or {@code null}
|
||||
*/
|
||||
public boolean isDescriptiveAudio() {
|
||||
return isDescriptiveAudio;
|
||||
@Nullable
|
||||
public AudioTrackType getAudioTrackType() {
|
||||
return audioTrackType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the stream is a descriptive audio.
|
||||
* Set the {@link AudioTrackType} of the stream, if present.
|
||||
*
|
||||
* @param isDescriptiveAudio whether the stream is a descriptive audio
|
||||
* @param audioTrackType the {@link AudioTrackType} of the stream or {@code null}
|
||||
*/
|
||||
public void setIsDescriptiveAudio(final boolean isDescriptiveAudio) {
|
||||
this.isDescriptiveAudio = isDescriptiveAudio;
|
||||
public void setAudioTrackType(@Nullable final AudioTrackType audioTrackType) {
|
||||
this.audioTrackType = audioTrackType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.schabi.newpipe.extractor.downloader.Response;
|
|||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.services.youtube.DeliveryType;
|
||||
import org.schabi.newpipe.extractor.services.youtube.ItagItem;
|
||||
import org.schabi.newpipe.extractor.stream.AudioTrackType;
|
||||
import org.schabi.newpipe.extractor.utils.ManifestCreatorCache;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.DOMException;
|
||||
|
@ -298,8 +299,10 @@ public final class YoutubeDashManifestCreatorsUtils {
|
|||
final Element roleElement = doc.createElement(ROLE);
|
||||
|
||||
setAttribute(roleElement, doc, "schemeIdUri", "urn:mpeg:DASH:role:2011");
|
||||
setAttribute(roleElement, doc, "value", itagItem.isDescriptiveAudio()
|
||||
? "alternate" : "main");
|
||||
setAttribute(roleElement, doc, "value",
|
||||
itagItem.getAudioTrackType() == null
|
||||
|| itagItem.getAudioTrackType() == AudioTrackType.ORIGINAL
|
||||
? "main" : "alternate");
|
||||
|
||||
adaptationSetElement.appendChild(roleElement);
|
||||
} catch (final DOMException e) {
|
||||
|
|
|
@ -72,6 +72,7 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
|||
import org.schabi.newpipe.extractor.services.youtube.YoutubeThrottlingDecrypter;
|
||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeChannelLinkHandlerFactory;
|
||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
import org.schabi.newpipe.extractor.stream.AudioTrackType;
|
||||
import org.schabi.newpipe.extractor.stream.DeliveryMethod;
|
||||
import org.schabi.newpipe.extractor.stream.Description;
|
||||
import org.schabi.newpipe.extractor.stream.Frameset;
|
||||
|
@ -810,6 +811,8 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
|||
"\\bc\\s*&&\\s*d\\.set\\([^,]+\\s*,\\s*(:encodeURIComponent\\s*\\()([a-zA-Z0-9$]+)\\("
|
||||
};
|
||||
private static final String STS_REGEX = "signatureTimestamp[=:](\\d+)";
|
||||
private static final String AUDIO_STREAM_TYPE_REGEX =
|
||||
"&xtags=[\\w\\d%]*acont(?:=|%3D)([a-z]+)(?:=|%3D|:|%3A|&|$)";
|
||||
|
||||
@Override
|
||||
public void onFetchPage(@Nonnull final Downloader downloader)
|
||||
|
@ -1311,7 +1314,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
|||
.setAudioTrackId(itagItem.getAudioTrackId())
|
||||
.setAudioTrackName(itagItem.getAudioTrackName())
|
||||
.setAudioLocale(itagItem.getAudioLocale())
|
||||
.setIsDescriptive(itagItem.isDescriptiveAudio())
|
||||
.setAudioTrackType(itagItem.getAudioTrackType())
|
||||
.setItagItem(itagItem);
|
||||
|
||||
if (streamType == StreamType.LIVE_STREAM
|
||||
|
@ -1484,16 +1487,25 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
|||
itagItem.setAudioLocale(LocaleCompat.forLanguageTag(
|
||||
audioTrackId.substring(0, audioTrackIdLastLocaleCharacter)));
|
||||
}
|
||||
|
||||
try {
|
||||
final String atype = Parser.matchGroup1(AUDIO_STREAM_TYPE_REGEX, streamUrl);
|
||||
switch (atype) {
|
||||
case "original":
|
||||
itagItem.setAudioTrackType(AudioTrackType.ORIGINAL);
|
||||
break;
|
||||
case "dubbed":
|
||||
itagItem.setAudioTrackType(AudioTrackType.DUBBED);
|
||||
break;
|
||||
case "descriptive":
|
||||
itagItem.setAudioTrackType(AudioTrackType.DESCRIPTIVE);
|
||||
break;
|
||||
}
|
||||
} catch (final Parser.RegexException ignored) { }
|
||||
}
|
||||
|
||||
itagItem.setAudioTrackName(formatData.getObject("audioTrack")
|
||||
.getString("displayName"));
|
||||
|
||||
// Descriptive audio tracks
|
||||
// This information is also provided as a protobuf object in the formatData
|
||||
itagItem.setIsDescriptiveAudio(streamUrl.contains("acont%3Ddescriptive")
|
||||
// Support "decoded" URLs
|
||||
|| streamUrl.contains("acont=descriptive"));
|
||||
}
|
||||
|
||||
// YouTube return the content length and the approximate duration as strings
|
||||
|
|
|
@ -50,7 +50,8 @@ public final class AudioStream extends Stream {
|
|||
private final String audioTrackName;
|
||||
@Nullable
|
||||
private final Locale audioLocale;
|
||||
private final boolean isDescriptive;
|
||||
@Nullable
|
||||
private final AudioTrackType audioTrackType;
|
||||
|
||||
@Nullable
|
||||
private ItagItem itagItem;
|
||||
|
@ -75,7 +76,8 @@ public final class AudioStream extends Stream {
|
|||
private String audioTrackName;
|
||||
@Nullable
|
||||
private Locale audioLocale;
|
||||
private boolean isDescriptive;
|
||||
@Nullable
|
||||
private AudioTrackType audioTrackType;
|
||||
@Nullable
|
||||
private ItagItem itagItem;
|
||||
|
||||
|
@ -223,25 +225,17 @@ public final class AudioStream extends Stream {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set whether this {@link AudioStream} is a descriptive audio.
|
||||
* Set the {@link AudioTrackType} of the {@link AudioStream}.
|
||||
*
|
||||
* <p>
|
||||
* A descriptive audio is an audio in which descriptions of visual elements of a video are
|
||||
* added in the original audio, with the goal to make a video more accessible to blind and
|
||||
* visually impaired people.
|
||||
* The default value is {@code null}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The default value is {@code false}.
|
||||
* </p>
|
||||
*
|
||||
* @param isDescriptive whether this {@link AudioStream} is a descriptive audio
|
||||
* @param audioTrackType the audio track type of the {@link AudioStream}, which can be null
|
||||
* @return this {@link Builder} instance
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Audio_description">
|
||||
* https://en.wikipedia.org/wiki/Audio_description</a>
|
||||
*/
|
||||
public Builder setIsDescriptive(final boolean isDescriptive) {
|
||||
this.isDescriptive = isDescriptive;
|
||||
public Builder setAudioTrackType(final AudioTrackType audioTrackType) {
|
||||
this.audioTrackType = audioTrackType;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -313,7 +307,7 @@ public final class AudioStream extends Stream {
|
|||
}
|
||||
|
||||
return new AudioStream(id, content, isUrl, mediaFormat, deliveryMethod, averageBitrate,
|
||||
manifestUrl, audioTrackId, audioTrackName, audioLocale, isDescriptive,
|
||||
manifestUrl, audioTrackId, audioTrackName, audioLocale, audioTrackType,
|
||||
itagItem);
|
||||
}
|
||||
}
|
||||
|
@ -350,7 +344,7 @@ public final class AudioStream extends Stream {
|
|||
@Nullable final String audioTrackId,
|
||||
@Nullable final String audioTrackName,
|
||||
@Nullable final Locale audioLocale,
|
||||
final boolean isDescriptive,
|
||||
@Nullable final AudioTrackType audioTrackType,
|
||||
@Nullable final ItagItem itagItem) {
|
||||
super(id, content, isUrl, format, deliveryMethod, manifestUrl);
|
||||
if (itagItem != null) {
|
||||
|
@ -368,7 +362,7 @@ public final class AudioStream extends Stream {
|
|||
this.audioTrackId = audioTrackId;
|
||||
this.audioTrackName = audioTrackName;
|
||||
this.audioLocale = audioLocale;
|
||||
this.isDescriptive = isDescriptive;
|
||||
this.audioTrackType = audioTrackType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -379,7 +373,7 @@ public final class AudioStream extends Stream {
|
|||
return super.equalStats(cmp) && cmp instanceof AudioStream
|
||||
&& averageBitrate == ((AudioStream) cmp).averageBitrate
|
||||
&& Objects.equals(audioTrackId, ((AudioStream) cmp).audioTrackId)
|
||||
&& isDescriptive == ((AudioStream) cmp).isDescriptive
|
||||
&& audioTrackType == ((AudioStream) cmp).audioTrackType
|
||||
&& Objects.equals(audioLocale, ((AudioStream) cmp).audioLocale);
|
||||
}
|
||||
|
||||
|
@ -506,21 +500,9 @@ public final class AudioStream extends Stream {
|
|||
return audioLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this stream is a descriptive audio.
|
||||
*
|
||||
* <p>
|
||||
* A descriptive audio is an audio in which descriptions of visual elements of a video are
|
||||
* added in the original audio, with the goal to make a video more accessible to blind and
|
||||
* visually impaired people.
|
||||
* </p>
|
||||
*
|
||||
* @return {@code true} this audio stream is a descriptive audio, {@code false} otherwise
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Audio_description">
|
||||
* https://en.wikipedia.org/wiki/Audio_description</a>
|
||||
*/
|
||||
public boolean isDescriptive() {
|
||||
return isDescriptive;
|
||||
@Nullable
|
||||
public AudioTrackType getAudioTrackType() {
|
||||
return audioTrackType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package org.schabi.newpipe.extractor.stream;
|
||||
|
||||
/**
|
||||
* An enum representing the track type of an {@link AudioStream} extracted by a {@link
|
||||
* StreamExtractor}.
|
||||
*/
|
||||
public enum AudioTrackType {
|
||||
/**
|
||||
* The original audio track of the video
|
||||
*/
|
||||
ORIGINAL,
|
||||
|
||||
/**
|
||||
* Audio track with the original voices replaced, typically in a different language
|
||||
*
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Dubbing">
|
||||
* https://en.wikipedia.org/wiki/Dubbing</a>
|
||||
*/
|
||||
DUBBED,
|
||||
|
||||
/**
|
||||
* Descriptive audio
|
||||
* <p>
|
||||
* A descriptive audio is an audio in which descriptions of visual elements of a video are
|
||||
* added in the original audio, with the goal to make a video more accessible to blind and
|
||||
* visually impaired people.
|
||||
* </p>
|
||||
*
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Audio_description">
|
||||
* https://en.wikipedia.org/wiki/Audio_description</a>
|
||||
*/
|
||||
DESCRIPTIVE,
|
||||
}
|
|
@ -8,7 +8,7 @@ public class DownloaderFactory {
|
|||
|
||||
public static final String RESOURCE_PATH = "src/test/resources/org/schabi/newpipe/extractor/";
|
||||
|
||||
private static final DownloaderType DEFAULT_DOWNLOADER = DownloaderType.REAL;
|
||||
private static final DownloaderType DEFAULT_DOWNLOADER = DownloaderType.RECORDING;
|
||||
|
||||
public static DownloaderType getDownloaderType() {
|
||||
try {
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.schabi.newpipe.extractor.services.youtube.dashmanifestcreators.Creati
|
|||
import org.schabi.newpipe.extractor.services.youtube.dashmanifestcreators.YoutubeOtfDashManifestCreator;
|
||||
import org.schabi.newpipe.extractor.services.youtube.dashmanifestcreators.YoutubeProgressiveDashManifestCreator;
|
||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor;
|
||||
import org.schabi.newpipe.extractor.stream.AudioTrackType;
|
||||
import org.schabi.newpipe.extractor.stream.DeliveryMethod;
|
||||
import org.schabi.newpipe.extractor.stream.Stream;
|
||||
import org.w3c.dom.Document;
|
||||
|
@ -233,7 +234,8 @@ class YoutubeDashManifestCreatorsTest {
|
|||
private void assertRoleElement(@Nonnull final Document document,
|
||||
@Nonnull final ItagItem itagItem) {
|
||||
final Element element = assertGetElement(document, ROLE, ADAPTATION_SET);
|
||||
assertAttrEquals(itagItem.isDescriptiveAudio() ? "alternate" : "main", element, "value");
|
||||
assertAttrEquals(itagItem.getAudioTrackType() == null || itagItem.getAudioTrackType() == AudioTrackType.ORIGINAL
|
||||
? "main" : "alternate", element, "value");
|
||||
}
|
||||
|
||||
private void assertRepresentationElement(@Nonnull final Document document,
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.schabi.newpipe.extractor.services.DefaultStreamExtractorTest;
|
|||
import org.schabi.newpipe.extractor.services.youtube.YoutubeTestsUtils;
|
||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor;
|
||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
import org.schabi.newpipe.extractor.stream.AudioTrackType;
|
||||
import org.schabi.newpipe.extractor.stream.Description;
|
||||
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
||||
import org.schabi.newpipe.extractor.stream.StreamSegment;
|
||||
|
@ -581,12 +582,49 @@ public class YoutubeStreamExtractorDefaultTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
void testCheckDescriptiveAudio() throws Exception {
|
||||
void testCheckOriginalAudio() throws Exception {
|
||||
assertFalse(extractor.getAudioStreams().isEmpty());
|
||||
|
||||
assertTrue(extractor.getAudioStreams()
|
||||
.stream()
|
||||
.anyMatch(AudioStream::isDescriptive));
|
||||
.anyMatch(s -> s.getAudioTrackType() == AudioTrackType.ORIGINAL));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckDescriptiveAudio() throws Exception {
|
||||
assertTrue(extractor.getAudioStreams()
|
||||
.stream()
|
||||
.anyMatch(s -> s.getAudioTrackType() == AudioTrackType.DESCRIPTIVE));
|
||||
}
|
||||
}
|
||||
|
||||
public static class DubbedAudio {
|
||||
private static final String ID = "_8W2LIfl5RE";
|
||||
private static final String URL = BASE_URL + ID;
|
||||
private static StreamExtractor extractor;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp() throws Exception {
|
||||
YoutubeTestsUtils.ensureStateless();
|
||||
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "dubbedAudio"));
|
||||
extractor = YouTube.getStreamExtractor(URL);
|
||||
extractor.fetchPage();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckOriginalAudio() throws Exception {
|
||||
assertFalse(extractor.getAudioStreams().isEmpty());
|
||||
|
||||
assertTrue(extractor.getAudioStreams()
|
||||
.stream()
|
||||
.anyMatch(s -> s.getAudioTrackType() == AudioTrackType.ORIGINAL));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckDubbedAudio() throws Exception {
|
||||
assertTrue(extractor.getAudioStreams()
|
||||
.stream()
|
||||
.anyMatch(s -> s.getAudioTrackType() == AudioTrackType.DUBBED));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"request": {
|
||||
"httpMethod": "GET",
|
||||
"url": "https://www.youtube.com/iframe_api",
|
||||
"headers": {
|
||||
"Accept-Language": [
|
||||
"en-GB, en;q\u003d0.9"
|
||||
]
|
||||
},
|
||||
"localization": {
|
||||
"languageCode": "en",
|
||||
"countryCode": "GB"
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"responseCode": 200,
|
||||
"responseMessage": "",
|
||||
"responseHeaders": {
|
||||
"alt-svc": [
|
||||
"h3\u003d\":443\"; ma\u003d2592000,h3-29\u003d\":443\"; ma\u003d2592000"
|
||||
],
|
||||
"cache-control": [
|
||||
"private, max-age\u003d0"
|
||||
],
|
||||
"content-type": [
|
||||
"text/javascript; charset\u003dutf-8"
|
||||
],
|
||||
"cross-origin-opener-policy-report-only": [
|
||||
"same-origin; report-to\u003d\"youtube_main\""
|
||||
],
|
||||
"cross-origin-resource-policy": [
|
||||
"cross-origin"
|
||||
],
|
||||
"date": [
|
||||
"Sun, 19 Mar 2023 01:11:13 GMT"
|
||||
],
|
||||
"expires": [
|
||||
"Sun, 19 Mar 2023 01:11:13 GMT"
|
||||
],
|
||||
"p3p": [
|
||||
"CP\u003d\"This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl\u003den-GB for more info.\""
|
||||
],
|
||||
"permissions-policy": [
|
||||
"ch-ua-arch\u003d*, ch-ua-bitness\u003d*, ch-ua-full-version\u003d*, ch-ua-full-version-list\u003d*, ch-ua-model\u003d*, ch-ua-wow64\u003d*, ch-ua-platform\u003d*, ch-ua-platform-version\u003d*"
|
||||
],
|
||||
"report-to": [
|
||||
"{\"group\":\"youtube_main\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/youtube_main\"}]}"
|
||||
],
|
||||
"server": [
|
||||
"ESF"
|
||||
],
|
||||
"set-cookie": [
|
||||
"YSC\u003d57sN-x5lva8; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
|
||||
"VISITOR_INFO1_LIVE\u003d1VebVMxRMHc; Domain\u003d.youtube.com; Expires\u003dFri, 15-Sep-2023 01:11:13 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
|
||||
"CONSENT\u003dPENDING+346; expires\u003dTue, 18-Mar-2025 01:11:13 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
|
||||
],
|
||||
"strict-transport-security": [
|
||||
"max-age\u003d31536000"
|
||||
],
|
||||
"x-content-type-options": [
|
||||
"nosniff"
|
||||
],
|
||||
"x-frame-options": [
|
||||
"SAMEORIGIN"
|
||||
],
|
||||
"x-xss-protection": [
|
||||
"0"
|
||||
]
|
||||
},
|
||||
"responseBody": "var scriptUrl \u003d \u0027https:\\/\\/www.youtube.com\\/s\\/player\\/59acb1f3\\/www-widgetapi.vflset\\/www-widgetapi.js\u0027;try{var ttPolicy\u003dwindow.trustedTypes.createPolicy(\"youtube-widget-api\",{createScriptURL:function(x){return x}});scriptUrl\u003dttPolicy.createScriptURL(scriptUrl)}catch(e){}var YT;if(!window[\"YT\"])YT\u003d{loading:0,loaded:0};var YTConfig;if(!window[\"YTConfig\"])YTConfig\u003d{\"host\":\"https://www.youtube.com\"};\nif(!YT.loading){YT.loading\u003d1;(function(){var l\u003d[];YT.ready\u003dfunction(f){if(YT.loaded)f();else l.push(f)};window.onYTReady\u003dfunction(){YT.loaded\u003d1;for(var i\u003d0;i\u003cl.length;i++)try{l[i]()}catch(e$0){}};YT.setConfig\u003dfunction(c){for(var k in c)if(c.hasOwnProperty(k))YTConfig[k]\u003dc[k]};var a\u003ddocument.createElement(\"script\");a.type\u003d\"text/javascript\";a.id\u003d\"www-widgetapi-script\";a.src\u003dscriptUrl;a.async\u003dtrue;var c\u003ddocument.currentScript;if(c){var n\u003dc.nonce||c.getAttribute(\"nonce\");if(n)a.setAttribute(\"nonce\",n)}var b\u003d\ndocument.getElementsByTagName(\"script\")[0];b.parentNode.insertBefore(a,b)})()};\n",
|
||||
"latestUrl": "https://www.youtube.com/iframe_api"
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,82 @@
|
|||
{
|
||||
"request": {
|
||||
"httpMethod": "GET",
|
||||
"url": "https://www.youtube.com/sw.js",
|
||||
"headers": {
|
||||
"Referer": [
|
||||
"https://www.youtube.com"
|
||||
],
|
||||
"Origin": [
|
||||
"https://www.youtube.com"
|
||||
],
|
||||
"Accept-Language": [
|
||||
"en-GB, en;q\u003d0.9"
|
||||
]
|
||||
},
|
||||
"localization": {
|
||||
"languageCode": "en",
|
||||
"countryCode": "GB"
|
||||
}
|
||||
},
|
||||
"response": {
|
||||
"responseCode": 200,
|
||||
"responseMessage": "",
|
||||
"responseHeaders": {
|
||||
"access-control-allow-credentials": [
|
||||
"true"
|
||||
],
|
||||
"access-control-allow-origin": [
|
||||
"https://www.youtube.com"
|
||||
],
|
||||
"alt-svc": [
|
||||
"h3\u003d\":443\"; ma\u003d2592000,h3-29\u003d\":443\"; ma\u003d2592000"
|
||||
],
|
||||
"cache-control": [
|
||||
"private, max-age\u003d0"
|
||||
],
|
||||
"content-type": [
|
||||
"text/javascript; charset\u003dutf-8"
|
||||
],
|
||||
"cross-origin-opener-policy-report-only": [
|
||||
"same-origin; report-to\u003d\"youtube_main\""
|
||||
],
|
||||
"date": [
|
||||
"Sun, 19 Mar 2023 01:11:14 GMT"
|
||||
],
|
||||
"expires": [
|
||||
"Sun, 19 Mar 2023 01:11:14 GMT"
|
||||
],
|
||||
"p3p": [
|
||||
"CP\u003d\"This is not a P3P policy! See http://support.google.com/accounts/answer/151657?hl\u003den-GB for more info.\""
|
||||
],
|
||||
"permissions-policy": [
|
||||
"ch-ua-arch\u003d*, ch-ua-bitness\u003d*, ch-ua-full-version\u003d*, ch-ua-full-version-list\u003d*, ch-ua-model\u003d*, ch-ua-wow64\u003d*, ch-ua-platform\u003d*, ch-ua-platform-version\u003d*"
|
||||
],
|
||||
"report-to": [
|
||||
"{\"group\":\"youtube_main\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://csp.withgoogle.com/csp/report-to/youtube_main\"}]}"
|
||||
],
|
||||
"server": [
|
||||
"ESF"
|
||||
],
|
||||
"set-cookie": [
|
||||
"YSC\u003dozmmoKNftY8; Domain\u003d.youtube.com; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
|
||||
"VISITOR_INFO1_LIVE\u003d; Domain\u003d.youtube.com; Expires\u003dMon, 22-Jun-2020 01:11:14 GMT; Path\u003d/; Secure; HttpOnly; SameSite\u003dnone",
|
||||
"CONSENT\u003dPENDING+665; expires\u003dTue, 18-Mar-2025 01:11:14 GMT; path\u003d/; domain\u003d.youtube.com; Secure"
|
||||
],
|
||||
"strict-transport-security": [
|
||||
"max-age\u003d31536000"
|
||||
],
|
||||
"x-content-type-options": [
|
||||
"nosniff"
|
||||
],
|
||||
"x-frame-options": [
|
||||
"SAMEORIGIN"
|
||||
],
|
||||
"x-xss-protection": [
|
||||
"0"
|
||||
]
|
||||
},
|
||||
"responseBody": "\n self.addEventListener(\u0027install\u0027, event \u003d\u003e {\n event.waitUntil(self.skipWaiting());\n });\n self.addEventListener(\u0027activate\u0027, event \u003d\u003e {\n event.waitUntil(\n self.clients.claim().then(() \u003d\u003e self.registration.unregister()));\n });\n ",
|
||||
"latestUrl": "https://www.youtube.com/sw.js"
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue