Skip to content

Commit

Permalink
Merge pull request #479 from vkay94/stream-segments
Browse files Browse the repository at this point in the history
Extract stream segments for YouTube
  • Loading branch information
TobiGr authored Dec 19, 2020
2 parents e8cc302 + 2ba27b3 commit 22a4151
Show file tree
Hide file tree
Showing 12 changed files with 274 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.schabi.newpipe.extractor.stream.Description;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import org.schabi.newpipe.extractor.stream.StreamSegment;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
Expand Down Expand Up @@ -294,4 +295,10 @@ public List<String> getTags() {
public String getSupportInfo() {
return "";
}

@Nonnull
@Override
public List<StreamSegment> getStreamSegments() {
return Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import org.schabi.newpipe.extractor.stream.StreamSegment;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
Expand Down Expand Up @@ -302,6 +303,12 @@ public String getSupportInfo() {
}
}

@Nonnull
@Override
public List<StreamSegment> getStreamSegments() {
return Collections.emptyList();
}

private String getRelatedStreamsUrl(final List<String> tags) throws UnsupportedEncodingException {
final String url = baseUrl + PeertubeSearchQueryHandlerFactory.SEARCH_ENDPOINT;
final StringBuilder params = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.schabi.newpipe.extractor.stream.Description;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import org.schabi.newpipe.extractor.stream.StreamSegment;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
Expand Down Expand Up @@ -320,4 +321,10 @@ public List<String> getTags() {
public String getSupportInfo() {
return "";
}

@Nonnull
@Override
public List<StreamSegment> getStreamSegments() {
return Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
import org.schabi.newpipe.extractor.stream.StreamSegment;
import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
import org.schabi.newpipe.extractor.stream.VideoStream;
Expand Down Expand Up @@ -1062,4 +1063,59 @@ public List<String> getTags() {
public String getSupportInfo() {
return "";
}

@Nonnull
@Override
public List<StreamSegment> getStreamSegments() throws ParsingException {
final ArrayList<StreamSegment> segments = new ArrayList<>();
if (initialData.has("engagementPanels")) {
final JsonArray panels = initialData.getArray("engagementPanels");
JsonArray segmentsArray = null;

// Search for correct panel containing the data
for (int i = 0; i < panels.size(); i++) {
if (panels.getObject(i).getObject("engagementPanelSectionListRenderer")
.getString("panelIdentifier").equals("engagement-panel-macro-markers")) {
segmentsArray = panels.getObject(i).getObject("engagementPanelSectionListRenderer")
.getObject("content").getObject("macroMarkersListRenderer").getArray("contents");
break;
}
}

if (segmentsArray != null) {
final long duration = getLength();
for (final Object object : segmentsArray) {
final JsonObject segmentJson = ((JsonObject) object).getObject("macroMarkersListItemRenderer");

final int startTimeSeconds = segmentJson.getObject("onTap").getObject("watchEndpoint")
.getInt("startTimeSeconds", -1);

if (startTimeSeconds == -1) {
throw new ParsingException("Could not get stream segment start time.");
}
if (startTimeSeconds > duration) {
break;
}

final String title = getTextFromObject(segmentJson.getObject("title"));
if (isNullOrEmpty(title)) {
throw new ParsingException("Could not get stream segment title.");
}

final StreamSegment segment = new StreamSegment(title, startTimeSeconds);
segment.setUrl(getUrl() + "?t=" + startTimeSeconds);
if (segmentJson.has("thumbnail")) {
final JsonArray previewsArray = segmentJson.getObject("thumbnail").getArray("thumbnails");
if (!previewsArray.isEmpty()) {
// Assume that the thumbnail with the highest resolution is at the last position
final String url = previewsArray.getObject(previewsArray.size() - 1).getString("url");
segment.setPreviewUrl(fixThumbnailUrl(url));
}
}
segments.add(segment);
}
}
}
return segments;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -476,4 +476,14 @@ protected long getTimestampSeconds(String regexPattern) throws ParsingException
*/
@Nonnull
public abstract String getSupportInfo() throws ParsingException;

/**
* The list of stream segments by timestamps for the stream.
* If the segment list is not available you can simply return an empty list.
*
* @return The list of segments of the stream or an empty list.
* @throws ParsingException
*/
@Nonnull
public abstract List<StreamSegment> getStreamSegments() throws ParsingException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,11 @@ private static StreamInfo extractOptionalData(StreamInfo streamInfo, StreamExtra
} catch (Exception e) {
streamInfo.addError(e);
}
try {
streamInfo.setStreamSegments(extractor.getStreamSegments());
} catch (Exception e) {
streamInfo.addError(e);
}

streamInfo.setRelatedStreams(ExtractorHelper.getRelatedVideosOrLogError(streamInfo, extractor));

Expand Down Expand Up @@ -373,6 +378,7 @@ private static StreamInfo extractOptionalData(StreamInfo streamInfo, StreamExtra
private String support = "";
private Locale language = null;
private List<String> tags = new ArrayList<>();
private List<StreamSegment> streamSegments = new ArrayList<>();

/**
* Get the stream type
Expand Down Expand Up @@ -670,4 +676,12 @@ public void setSupportInfo(String support) {
public String getSupportInfo() {
return this.support;
}

public List<StreamSegment> getStreamSegments() {
return streamSegments;
}

public void setStreamSegments(List<StreamSegment> streamSegments) {
this.streamSegments = streamSegments;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.schabi.newpipe.extractor.stream;


import javax.annotation.Nullable;
import java.io.Serializable;

public class StreamSegment implements Serializable {
/**
* Title of this segment
*/
private String title;

/**
* Timestamp of the starting point in seconds
*/
private int startTimeSeconds;

/**
* Direct url to this segment. This can be null if the service doesn't provide such function.
*/
@Nullable
public String url;

/**
* Preview url for this segment. This can be null if the service doesn't provide such function
* or there is no resource found.
*/
@Nullable
private String previewUrl = null;

public StreamSegment(String title, int startTimeSeconds) {
this.title = title;
this.startTimeSeconds = startTimeSeconds;
}

public String getTitle() {
return title;
}

public void setTitle(final String title) {
this.title = title;
}

public int getStartTimeSeconds() {
return startTimeSeconds;
}

public void setStartTimeSeconds(final int startTimeSeconds) {
this.startTimeSeconds = startTimeSeconds;
}

@Nullable
public String getUrl() {
return url;
}

public void setUrl(@Nullable final String url) {
this.url = url;
}

@Nullable
public String getPreviewUrl() {
return previewUrl;
}

public void setPreviewUrl(@Nullable final String previewUrl) {
this.previewUrl = previewUrl;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public abstract class DefaultStreamExtractorTest extends DefaultExtractorTest<St
public Locale expectedLanguageInfo() { return null; } // default: no language info available
public List<String> expectedTags() { return Collections.emptyList(); } // default: no tags
public String expectedSupportInfo() { return ""; } // default: no support info available
public int expectedStreamSegmentsCount() { return -1; } // return 0 or greater to test (default is -1 to ignore)

@Test
@Override
Expand Down Expand Up @@ -379,4 +380,11 @@ public void testTags() throws Exception {
public void testSupportInfo() throws Exception {
assertEquals(expectedSupportInfo(), extractor().getSupportInfo());
}

@Test
public void testStreamSegmentsCount() throws Exception {
if (expectedStreamSegmentsCount() >= 0) {
assertEquals(expectedStreamSegmentsCount(), extractor().getStreamSegments().size());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public static void setUp() throws Exception {
@Override public boolean expectedHasSubtitles() { return false; }
@Override public boolean expectedHasFrames() { return false; }
@Override public List<String> expectedTags() { return Arrays.asList("gpn18", "105"); }
@Override public int expectedStreamSegmentsCount() { return 0; }

@Override
@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public void testGetLanguageInformation() throws ParsingException {
@Override public String expectedLicence() { return "Attribution - Share Alike"; }
@Override public Locale expectedLanguageInfo() { return Locale.forLanguageTag("en"); }
@Override public List<String> expectedTags() { return Arrays.asList("framasoft", "peertube"); }
@Override public int expectedStreamSegmentsCount() { return 0; }
}

public static class AgeRestricted extends DefaultStreamExtractorTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public static void setUp() throws Exception {
@Override public boolean expectedHasVideoStreams() { return false; }
@Override public boolean expectedHasSubtitles() { return false; }
@Override public boolean expectedHasFrames() { return false; }
@Override public int expectedStreamSegmentsCount() { return 0; }
}

}
Loading

0 comments on commit 22a4151

Please sign in to comment.