Skip to content

Commit d3eea4f

Browse files
committed
Add stream segments to StreamInfo
1 parent b3835bd commit d3eea4f

7 files changed

Lines changed: 169 additions & 0 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCStreamExtractor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.schabi.newpipe.extractor.stream.Description;
1717
import org.schabi.newpipe.extractor.stream.StreamExtractor;
1818
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
19+
import org.schabi.newpipe.extractor.stream.StreamSegment;
1920
import org.schabi.newpipe.extractor.stream.StreamType;
2021
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
2122
import org.schabi.newpipe.extractor.stream.VideoStream;
@@ -294,4 +295,10 @@ public List<String> getTags() {
294295
public String getSupportInfo() {
295296
return "";
296297
}
298+
299+
@Nonnull
300+
@Override
301+
public List<StreamSegment> getStreamSegments() {
302+
return Collections.emptyList();
303+
}
297304
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeStreamExtractor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.schabi.newpipe.extractor.stream.Stream;
2424
import org.schabi.newpipe.extractor.stream.StreamExtractor;
2525
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
26+
import org.schabi.newpipe.extractor.stream.StreamSegment;
2627
import org.schabi.newpipe.extractor.stream.StreamType;
2728
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
2829
import org.schabi.newpipe.extractor.stream.VideoStream;
@@ -302,6 +303,12 @@ public String getSupportInfo() {
302303
}
303304
}
304305

306+
@Nonnull
307+
@Override
308+
public List<StreamSegment> getStreamSegments() {
309+
return Collections.emptyList();
310+
}
311+
305312
private String getRelatedStreamsUrl(final List<String> tags) throws UnsupportedEncodingException {
306313
final String url = baseUrl + PeertubeSearchQueryHandlerFactory.SEARCH_ENDPOINT;
307314
final StringBuilder params = new StringBuilder();

extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudStreamExtractor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.schabi.newpipe.extractor.stream.Description;
2121
import org.schabi.newpipe.extractor.stream.StreamExtractor;
2222
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
23+
import org.schabi.newpipe.extractor.stream.StreamSegment;
2324
import org.schabi.newpipe.extractor.stream.StreamType;
2425
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
2526
import org.schabi.newpipe.extractor.stream.VideoStream;
@@ -320,4 +321,10 @@ public List<String> getTags() {
320321
public String getSupportInfo() {
321322
return "";
322323
}
324+
325+
@Nonnull
326+
@Override
327+
public List<StreamSegment> getStreamSegments() {
328+
return Collections.emptyList();
329+
}
323330
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.schabi.newpipe.extractor.stream.StreamExtractor;
3636
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
3737
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
38+
import org.schabi.newpipe.extractor.stream.StreamSegment;
3839
import org.schabi.newpipe.extractor.stream.StreamType;
3940
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
4041
import org.schabi.newpipe.extractor.stream.VideoStream;
@@ -1061,4 +1062,58 @@ public List<String> getTags() {
10611062
public String getSupportInfo() {
10621063
return "";
10631064
}
1065+
1066+
@Nonnull
1067+
@Override
1068+
public List<StreamSegment> getStreamSegments() throws ParsingException {
1069+
final ArrayList<StreamSegment> segments = new ArrayList<>();
1070+
if (initialData.has("engagementPanels")) {
1071+
final JsonArray panels = initialData.getArray("engagementPanels");
1072+
JsonArray segmentsArray = null;
1073+
1074+
// Search for correct panel containing the data
1075+
for (int i = 0; i < panels.size(); i++) {
1076+
if (panels.getObject(i).getObject("engagementPanelSectionListRenderer")
1077+
.getString("panelIdentifier").equals("engagement-panel-macro-markers")) {
1078+
segmentsArray = panels.getObject(i).getObject("engagementPanelSectionListRenderer")
1079+
.getObject("content").getObject("macroMarkersListRenderer").getArray("contents");
1080+
break;
1081+
}
1082+
}
1083+
1084+
if (segmentsArray != null) {
1085+
final long duration = getLength();
1086+
for (final Object object : segmentsArray) {
1087+
final JsonObject segmentJson = ((JsonObject) object).getObject("macroMarkersListItemRenderer");
1088+
1089+
final int startTimeSeconds = segmentJson.getObject("onTap").getObject("watchEndpoint")
1090+
.getInt("startTimeSeconds", -1);
1091+
1092+
if (startTimeSeconds == -1) {
1093+
throw new ParsingException("Could not get stream segment start time.");
1094+
}
1095+
if (startTimeSeconds > duration) {
1096+
break;
1097+
}
1098+
1099+
final String title = getTextFromObject(segmentJson.getObject("title"));
1100+
if (isNullOrEmpty(title)) {
1101+
throw new ParsingException("Could not get stream segment title.");
1102+
}
1103+
1104+
final StreamSegment segment = new StreamSegment(title, startTimeSeconds);
1105+
segment.setUrl(getUrl() + "?t=" + startTimeSeconds);
1106+
if (segmentJson.has("thumbnail")) {
1107+
final JsonArray previewsArray = segmentJson.getObject("thumbnail").getArray("thumbnails");
1108+
if (!previewsArray.isEmpty()) {
1109+
// Assume that the thumbnail with the highest resolution is at the last position
1110+
segment.setPreviewUrl(previewsArray.getObject(previewsArray.size() - 1).getString("url"));
1111+
}
1112+
}
1113+
segments.add(segment);
1114+
}
1115+
}
1116+
}
1117+
return segments;
1118+
}
10641119
}

extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamExtractor.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,4 +476,14 @@ protected long getTimestampSeconds(String regexPattern) throws ParsingException
476476
*/
477477
@Nonnull
478478
public abstract String getSupportInfo() throws ParsingException;
479+
480+
/**
481+
* The list of stream segments by timestamps for the stream.
482+
* If the segment list is not available you can simply return an empty list.
483+
*
484+
* @return The list of segments of the stream or an empty list.
485+
* @throws ParsingException
486+
*/
487+
@Nonnull
488+
public abstract List<StreamSegment> getStreamSegments() throws ParsingException;
479489
}

extractor/src/main/java/org/schabi/newpipe/extractor/stream/StreamInfo.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,11 @@ private static StreamInfo extractOptionalData(StreamInfo streamInfo, StreamExtra
324324
} catch (Exception e) {
325325
streamInfo.addError(e);
326326
}
327+
try {
328+
streamInfo.setStreamSegments(extractor.getStreamSegments());
329+
} catch (Exception e) {
330+
streamInfo.addError(e);
331+
}
327332

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

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

377383
/**
378384
* Get the stream type
@@ -670,4 +676,12 @@ public void setSupportInfo(String support) {
670676
public String getSupportInfo() {
671677
return this.support;
672678
}
679+
680+
public List<StreamSegment> getStreamSegments() {
681+
return streamSegments;
682+
}
683+
684+
public void setStreamSegments(List<StreamSegment> streamSegments) {
685+
this.streamSegments = streamSegments;
686+
}
673687
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package org.schabi.newpipe.extractor.stream;
2+
3+
4+
import javax.annotation.Nullable;
5+
import java.io.Serializable;
6+
7+
public class StreamSegment implements Serializable {
8+
/**
9+
* Title of this segment
10+
*/
11+
private String title;
12+
13+
/**
14+
* Timestamp of the starting point in seconds
15+
*/
16+
private int startTimeSeconds;
17+
18+
/**
19+
* Direct url to this segment. This can be null if the service doesn't provide such function.
20+
*/
21+
@Nullable
22+
public String url;
23+
24+
/**
25+
* Preview url for this segment. This can be null if the service doesn't provide such function
26+
* or there is no resource found.
27+
*/
28+
@Nullable
29+
private String previewUrl = null;
30+
31+
public StreamSegment(String title, int startTimeSeconds) {
32+
this.title = title;
33+
this.startTimeSeconds = startTimeSeconds;
34+
}
35+
36+
public String getTitle() {
37+
return title;
38+
}
39+
40+
public void setTitle(final String title) {
41+
this.title = title;
42+
}
43+
44+
public int getStartTimeSeconds() {
45+
return startTimeSeconds;
46+
}
47+
48+
public void setStartTimeSeconds(final int startTimeSeconds) {
49+
this.startTimeSeconds = startTimeSeconds;
50+
}
51+
52+
@Nullable
53+
public String getUrl() {
54+
return url;
55+
}
56+
57+
public void setUrl(@Nullable final String url) {
58+
this.url = url;
59+
}
60+
61+
@Nullable
62+
public String getPreviewUrl() {
63+
return previewUrl;
64+
}
65+
66+
public void setPreviewUrl(@Nullable final String previewUrl) {
67+
this.previewUrl = previewUrl.replaceAll("\\u0026", "&");
68+
}
69+
}

0 commit comments

Comments
 (0)