Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,22 @@ public static YoutubeSabrInfo fetchSabrInfo(@Nonnull final String videoId,
@Nullable final String playerPoToken,
@Nullable final String visitorDataOverride)
throws IOException, ExtractionException {
return fetchSabrInfo(videoId, profile, localization, contentCountry, playerPoToken,
visitorDataOverride, null);
}

@Nonnull
public static YoutubeSabrInfo fetchSabrInfo(@Nonnull final String videoId,
@Nonnull final YoutubeSabrClientProfile profile,
@Nonnull final Localization localization,
@Nonnull final ContentCountry contentCountry,
@Nullable final String playerPoToken,
@Nullable final String visitorDataOverride,
@Nullable final Integer startTimeSecs)
throws IOException, ExtractionException {
final String cpn = YoutubeParsingHelper.generateContentPlaybackNonce();
final JsonObject playerResponse = fetchPlayerResponse(videoId, profile, localization,
contentCountry, cpn, playerPoToken, visitorDataOverride);
contentCountry, cpn, playerPoToken, visitorDataOverride, startTimeSecs);
return fromPlayerResponse(videoId, profile, cpn, playerResponse, visitorDataOverride);
}

Expand Down Expand Up @@ -243,13 +256,14 @@ private static YoutubeSabrProbeResult postMediaRequest(
private static JsonObject fetchPlayerResponse(@Nonnull final String videoId,
@Nonnull final YoutubeSabrClientProfile profile,
@Nonnull final Localization localization,
@Nonnull final ContentCountry contentCountry,
@Nonnull final String cpn,
@Nullable final String playerPoToken,
@Nullable final String visitorDataOverride)
@Nonnull final ContentCountry contentCountry,
@Nonnull final String cpn,
@Nullable final String playerPoToken,
@Nullable final String visitorDataOverride,
@Nullable final Integer startTimeSecs)
throws IOException, ExtractionException {
final byte[] body = createPlayerBody(videoId, profile, localization, contentCountry,
cpn, playerPoToken, visitorDataOverride);
cpn, playerPoToken, visitorDataOverride, startTimeSecs);
final String url = getInnertubeBaseUrl(profile) + PLAYER + "?"
+ YoutubeParsingHelper.DISABLE_PRETTY_PRINT_PARAMETER;
final Response response = NewPipe.getDownloader().post(url,
Expand All @@ -265,7 +279,8 @@ private static byte[] createPlayerBody(@Nonnull final String videoId,
@Nonnull final ContentCountry contentCountry,
@Nonnull final String cpn,
@Nullable final String playerPoToken,
@Nullable final String visitorDataOverride)
@Nullable final String visitorDataOverride,
@Nullable final Integer startTimeSecs)
throws ParsingException {
final JsonBuilder<JsonObject> builder = JsonObject.builder()
.object("context")
Expand Down Expand Up @@ -338,6 +353,10 @@ private static byte[] createPlayerBody(@Nonnull final String videoId,
.value(YoutubeParsingHelper.CONTENT_CHECK_OK, true)
.value(YoutubeParsingHelper.RACY_CHECK_OK, true);

if (startTimeSecs != null && startTimeSecs >= 0) {
builder.value("startTimeSecs", startTimeSecs);
}

if (playerPoToken != null && !playerPoToken.isEmpty()) {
builder.object("serviceIntegrityDimensions")
.value("poToken", playerPoToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,21 @@ static byte[] buildFirstMediaRequest(@Nonnull final YoutubeSabrInfo info,
}

final SabrProto.Writer request = new SabrProto.Writer();
request.writeMessage(1, buildClientAbrState(audioFormat, videoFormat, 0, false,
final boolean writeFirstRequestPlaybackState = streamState != null
&& streamState.shouldWriteFirstRequestPlaybackState();
final long playerTimeMs = writeFirstRequestPlaybackState ? streamState.getPlayerTimeMs() : 0;
request.writeMessage(1, buildClientAbrState(audioFormat, videoFormat, playerTimeMs, false,
streamState == null
? ENABLED_TRACK_TYPES_VIDEO_AND_AUDIO
: streamState.getEnabledTrackTypesBitfield(),
streamState));
if (writeFirstRequestPlaybackState) {
writeCurrentFormatSelections(request, audioFormat, videoFormat, streamState);
writeBufferedRanges(request, streamState);
if (streamState.shouldWriteTopLevelPlayerTimeMs()) {
request.writeUInt64(4, playerTimeMs);
}
}
request.writeBytes(5, decodeBase64(ustreamerConfig));
writePreferredFormats(request, info, audioFormat, videoFormat, streamState);
request.writeMessage(19, streamState == null
Expand Down Expand Up @@ -72,6 +82,22 @@ private static byte[] buildFollowUpMediaRequestLocked(@Nonnull final YoutubeSabr
final SabrProto.Writer request = new SabrProto.Writer();
request.writeMessage(1, buildClientAbrState(audioFormat, videoFormat, playerTimeMs,
true, streamState.getEnabledTrackTypesBitfield(), streamState));
writeCurrentFormatSelections(request, audioFormat, videoFormat, streamState);
writeBufferedRanges(request, streamState);
if (streamState.shouldWriteTopLevelPlayerTimeMs()) {
request.writeUInt64(4, playerTimeMs);
}
request.writeBytes(5, decodeBase64(ustreamerConfig));
writePreferredFormats(request, info, audioFormat, videoFormat, streamState);
request.writeMessage(19, buildStreamerContext(info, streamState));
return request.toByteArray();
}

private static void writeCurrentFormatSelections(
@Nonnull final SabrProto.Writer request,
@Nonnull final YoutubeSabrFormat audioFormat,
@Nonnull final YoutubeSabrFormat videoFormat,
@Nonnull final YoutubeSabrStreamState streamState) {
if (streamState.shouldSelectVideoFormatBeforeAudio() && streamState.shouldSelectVideoFormat()) {
request.writeMessage(2, SabrProto.formatId(videoFormat));
}
Expand All @@ -81,47 +107,19 @@ private static byte[] buildFollowUpMediaRequestLocked(@Nonnull final YoutubeSabr
if (!streamState.shouldSelectVideoFormatBeforeAudio() && streamState.shouldSelectVideoFormat()) {
request.writeMessage(2, SabrProto.formatId(videoFormat));
}
}

private static void writeBufferedRanges(@Nonnull final SabrProto.Writer request,
@Nonnull final YoutubeSabrStreamState streamState) {
final List<SabrBufferedRange> bufferedRanges = streamState.getBufferedRanges();
for (final SabrBufferedRange range : bufferedRanges) {
request.writeMessage(3, range.toProto(streamState.shouldWriteBufferedRangeTimeRange()));
}
if (streamState.shouldWriteTopLevelPlayerTimeMs()) {
request.writeUInt64(4, playerTimeMs);
}
request.writeBytes(5, decodeBase64(ustreamerConfig));
writePreferredFormats(request, info, audioFormat, videoFormat, streamState);
request.writeMessage(19, buildStreamerContext(info, streamState));
return request.toByteArray();
}

@Nonnull
private static byte[] buildClientAbrState(@Nonnull final YoutubeSabrFormat audioFormat,
@Nonnull final YoutubeSabrFormat videoFormat) {
return buildClientAbrState(audioFormat, videoFormat, 0, false);
}

@Nonnull
private static byte[] buildClientAbrState(@Nonnull final YoutubeSabrFormat audioFormat,
@Nonnull final YoutubeSabrFormat videoFormat,
final long playerTimeMs,
final boolean includeFollowUpState) {
return buildClientAbrState(audioFormat, videoFormat, playerTimeMs, includeFollowUpState,
ENABLED_TRACK_TYPES_VIDEO_AND_AUDIO);
}

@Nonnull
private static byte[] buildClientAbrState(@Nonnull final YoutubeSabrFormat audioFormat,
@Nonnull final YoutubeSabrFormat videoFormat,
final long playerTimeMs,
final boolean includeFollowUpState,
final int enabledTrackTypesBitfield) {
return buildClientAbrState(audioFormat, videoFormat, playerTimeMs, includeFollowUpState,
enabledTrackTypesBitfield, null);
}

@Nonnull
private static byte[] buildClientAbrState(@Nonnull final YoutubeSabrFormat audioFormat,
@Nonnull final YoutubeSabrFormat videoFormat,
@Nonnull final YoutubeSabrFormat videoFormat,
final long playerTimeMs,
final boolean includeFollowUpState,
final int enabledTrackTypesBitfield,
Expand Down Expand Up @@ -224,21 +222,21 @@ private static void writePreferredFormats(@Nonnull final SabrProto.Writer reques
return;
}
for (final YoutubeSabrFormat format : info.getFormats()) {
if (format.isAudio() && streamState.shouldSelectAudioFormat()) {
if (format.isAudio() && streamState.shouldPreferAudioFormat()) {
request.writeMessage(16, SabrProto.formatId(format));
}
}
for (final YoutubeSabrFormat format : info.getFormats()) {
if (format.isVideo() && streamState.shouldSelectVideoFormat()) {
if (format.isVideo() && streamState.shouldPreferVideoFormat()) {
request.writeMessage(17, SabrProto.formatId(format));
}
}
return;
}
if (streamState == null || streamState.shouldSelectAudioFormat()) {
if (streamState == null || streamState.shouldPreferAudioFormat()) {
request.writeMessage(16, SabrProto.formatId(audioFormat));
}
if (streamState == null || streamState.shouldSelectVideoFormat()) {
if (streamState == null || streamState.shouldPreferVideoFormat()) {
request.writeMessage(17, SabrProto.formatId(videoFormat));
}
}
Expand Down
Loading