Skip to content

Commit 2f2b188

Browse files
committed
Rewrote extractors part 1
1 parent 7c1f53f commit 2f2b188

File tree

6 files changed

+464
-561
lines changed

6 files changed

+464
-561
lines changed

extractor/src/main/java/org/schabi/newpipe/extractor/services/bandcamp/extractors/BandcampStreamExtractor.java

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,31 @@
1212
import org.jsoup.Jsoup;
1313
import org.jsoup.nodes.Document;
1414
import org.jsoup.nodes.Element;
15-
import org.schabi.newpipe.extractor.MediaFormat;
1615
import org.schabi.newpipe.extractor.StreamingService;
1716
import org.schabi.newpipe.extractor.downloader.Downloader;
1817
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
1918
import org.schabi.newpipe.extractor.exceptions.ParsingException;
2019
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
2120
import org.schabi.newpipe.extractor.localization.DateWrapper;
2221
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItemsCollector;
23-
import org.schabi.newpipe.extractor.stream.AudioStream;
2422
import org.schabi.newpipe.extractor.stream.Description;
2523
import org.schabi.newpipe.extractor.stream.StreamExtractor;
2624
import org.schabi.newpipe.extractor.stream.StreamType;
27-
import org.schabi.newpipe.extractor.stream.VideoStream;
25+
import org.schabi.newpipe.extractor.streamdata.delivery.simpleimpl.SimpleProgressiveHTTPDeliveryDataImpl;
26+
import org.schabi.newpipe.extractor.streamdata.format.registry.AudioFormatRegistry;
27+
import org.schabi.newpipe.extractor.streamdata.stream.AudioStream;
28+
import org.schabi.newpipe.extractor.streamdata.stream.simpleimpl.SimpleAudioStreamImpl;
2829
import org.schabi.newpipe.extractor.utils.JsonUtils;
2930
import org.schabi.newpipe.extractor.utils.Utils;
3031

31-
import javax.annotation.Nonnull;
32-
import javax.annotation.Nullable;
3332
import java.io.IOException;
34-
import java.util.ArrayList;
3533
import java.util.Collections;
3634
import java.util.List;
3735
import java.util.stream.Collectors;
3836

37+
import javax.annotation.Nonnull;
38+
import javax.annotation.Nullable;
39+
3940
public class BandcampStreamExtractor extends StreamExtractor {
4041
private JsonObject albumJson;
4142
private JsonObject current;
@@ -149,17 +150,17 @@ public Description getDescription() {
149150

150151
@Override
151152
public List<AudioStream> getAudioStreams() {
152-
final List<AudioStream> audioStreams = new ArrayList<>();
153-
audioStreams.add(new AudioStream.Builder()
154-
.setId("mp3-128")
155-
.setContent(albumJson.getArray("trackinfo")
156-
.getObject(0)
157-
.getObject("file")
158-
.getString("mp3-128"), true)
159-
.setMediaFormat(MediaFormat.MP3)
160-
.setAverageBitrate(128)
161-
.build());
162-
return audioStreams;
153+
return Collections.singletonList(
154+
new SimpleAudioStreamImpl(
155+
new SimpleProgressiveHTTPDeliveryDataImpl(albumJson
156+
.getArray("trackinfo")
157+
.getObject(0)
158+
.getObject("file")
159+
.getString("mp3-128")),
160+
AudioFormatRegistry.MP3,
161+
128
162+
)
163+
);
163164
}
164165

165166
@Override
@@ -168,16 +169,6 @@ public long getLength() throws ParsingException {
168169
.getDouble("duration");
169170
}
170171

171-
@Override
172-
public List<VideoStream> getVideoStreams() {
173-
return Collections.emptyList();
174-
}
175-
176-
@Override
177-
public List<VideoStream> getVideoOnlyStreams() {
178-
return Collections.emptyList();
179-
}
180-
181172
@Override
182173
public StreamType getStreamType() {
183174
return StreamType.AUDIO_STREAM;

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

Lines changed: 59 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,32 @@
33
import com.grack.nanojson.JsonArray;
44
import com.grack.nanojson.JsonObject;
55

6-
import org.schabi.newpipe.extractor.MediaFormat;
76
import org.schabi.newpipe.extractor.StreamingService;
87
import org.schabi.newpipe.extractor.downloader.Downloader;
98
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
109
import org.schabi.newpipe.extractor.exceptions.ParsingException;
1110
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
12-
import org.schabi.newpipe.extractor.stream.AudioStream;
13-
import org.schabi.newpipe.extractor.stream.DeliveryMethod;
1411
import org.schabi.newpipe.extractor.stream.Description;
15-
import org.schabi.newpipe.extractor.stream.Stream;
1612
import org.schabi.newpipe.extractor.stream.StreamExtractor;
1713
import org.schabi.newpipe.extractor.stream.StreamType;
18-
import org.schabi.newpipe.extractor.stream.VideoStream;
14+
import org.schabi.newpipe.extractor.streamdata.delivery.DeliveryData;
15+
import org.schabi.newpipe.extractor.streamdata.delivery.simpleimpl.SimpleDASHUrlDeliveryDataImpl;
16+
import org.schabi.newpipe.extractor.streamdata.delivery.simpleimpl.SimpleHLSDeliveryDataImpl;
17+
import org.schabi.newpipe.extractor.streamdata.delivery.simpleimpl.SimpleProgressiveHTTPDeliveryDataImpl;
18+
import org.schabi.newpipe.extractor.streamdata.format.registry.AudioFormatRegistry;
19+
import org.schabi.newpipe.extractor.streamdata.format.registry.VideoAudioFormatRegistry;
20+
import org.schabi.newpipe.extractor.streamdata.stream.AudioStream;
21+
import org.schabi.newpipe.extractor.streamdata.stream.VideoAudioStream;
22+
import org.schabi.newpipe.extractor.streamdata.stream.simpleimpl.SimpleAudioStreamImpl;
23+
import org.schabi.newpipe.extractor.streamdata.stream.simpleimpl.SimpleVideoAudioStreamImpl;
1924

2025
import java.io.IOException;
21-
import java.util.Collections;
2226
import java.util.List;
23-
import java.util.function.Function;
2427
import java.util.stream.Collectors;
28+
import java.util.stream.Stream;
2529

2630
import javax.annotation.Nonnull;
2731

28-
import static org.schabi.newpipe.extractor.stream.AudioStream.UNKNOWN_BITRATE;
29-
import static org.schabi.newpipe.extractor.stream.Stream.ID_UNKNOWN;
30-
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
31-
3232
public class MediaCCCLiveStreamExtractor extends StreamExtractor {
3333
private static final String STREAMS = "streams";
3434
private static final String URLS = "urls";
@@ -46,7 +46,8 @@ public MediaCCCLiveStreamExtractor(final StreamingService service,
4646
@Override
4747
public void onFetchPage(@Nonnull final Downloader downloader)
4848
throws IOException, ExtractionException {
49-
final JsonArray doc = MediaCCCParsingHelper.getLiveStreams(downloader,
49+
final JsonArray doc = MediaCCCParsingHelper.getLiveStreams(
50+
downloader,
5051
getExtractorLocalization());
5152
// Find the correct room
5253
for (int c = 0; c < doc.size(); c++) {
@@ -138,7 +139,7 @@ public String getDashMpdUrl() throws ParsingException {
138139
*/
139140
@Nonnull
140141
@Override
141-
public String getHlsUrl() {
142+
public String getHlsMasterPlaylistUrl() {
142143
return getManifestOfDeliveryMethodWanted("hls");
143144
}
144145

@@ -149,84 +150,61 @@ private String getManifestOfDeliveryMethodWanted(@Nonnull final String deliveryM
149150
.map(JsonObject.class::cast)
150151
.map(streamObject -> streamObject.getObject(URLS))
151152
.filter(urls -> urls.has(deliveryMethod))
152-
.map(urls -> urls.getObject(deliveryMethod).getString(URL, EMPTY_STRING))
153+
.map(urls -> urls.getObject(deliveryMethod).getString(URL, ""))
153154
.findFirst()
154-
.orElse(EMPTY_STRING);
155+
.orElse("");
155156
}
156157

157158
@Override
158159
public List<AudioStream> getAudioStreams() throws IOException, ExtractionException {
159-
return getStreams("audio",
160-
dto -> {
161-
final AudioStream.Builder builder = new AudioStream.Builder()
162-
.setId(dto.urlValue.getString("tech", ID_UNKNOWN))
163-
.setContent(dto.urlValue.getString(URL), true)
164-
.setAverageBitrate(UNKNOWN_BITRATE);
165-
166-
if ("hls".equals(dto.urlKey)) {
167-
// We don't know with the type string what media format will
168-
// have HLS streams.
169-
// However, the tech string may contain some information
170-
// about the media format used.
171-
return builder.setDeliveryMethod(DeliveryMethod.HLS)
172-
.build();
160+
return getStreamDTOs("audio")
161+
.map(dto -> {
162+
final String url = dto.getUrlValue().getString(URL);
163+
final DeliveryData deliveryData;
164+
if ("hls".equals(dto.getUrlKey())) {
165+
deliveryData = new SimpleHLSDeliveryDataImpl(url);
166+
} else if ("dash".equals(dto.getUrlKey())) {
167+
deliveryData = new SimpleDASHUrlDeliveryDataImpl(url);
168+
} else {
169+
deliveryData = new SimpleProgressiveHTTPDeliveryDataImpl(url);
173170
}
174171

175-
return builder.setMediaFormat(MediaFormat.getFromSuffix(dto.urlKey))
176-
.build();
177-
});
172+
return new SimpleAudioStreamImpl(
173+
deliveryData,
174+
// TODO: This looks wrong
175+
new AudioFormatRegistry().getFromSuffix(dto.getUrlKey())
176+
);
177+
})
178+
.collect(Collectors.toList());
178179
}
179180

180181
@Override
181-
public List<VideoStream> getVideoStreams() throws IOException, ExtractionException {
182-
return getStreams("video",
183-
dto -> {
184-
final JsonArray videoSize = dto.streamJsonObj.getArray("videoSize");
185-
186-
final VideoStream.Builder builder = new VideoStream.Builder()
187-
.setId(dto.urlValue.getString("tech", ID_UNKNOWN))
188-
.setContent(dto.urlValue.getString(URL), true)
189-
.setIsVideoOnly(false)
190-
.setResolution(videoSize.getInt(0) + "x" + videoSize.getInt(1));
191-
192-
if ("hls".equals(dto.urlKey)) {
193-
// We don't know with the type string what media format will
194-
// have HLS streams.
195-
// However, the tech string may contain some information
196-
// about the media format used.
197-
return builder.setDeliveryMethod(DeliveryMethod.HLS)
198-
.build();
182+
public List<VideoAudioStream> getVideoStreams() throws IOException, ExtractionException {
183+
return getStreamDTOs("video")
184+
.map(dto -> {
185+
final String url = dto.getUrlValue().getString(URL);
186+
final DeliveryData deliveryData;
187+
if ("hls".equals(dto.getUrlKey())) {
188+
deliveryData = new SimpleHLSDeliveryDataImpl(url);
189+
} else if ("dash".equals(dto.getUrlKey())) {
190+
deliveryData = new SimpleDASHUrlDeliveryDataImpl(url);
191+
} else {
192+
deliveryData = new SimpleProgressiveHTTPDeliveryDataImpl(url);
199193
}
200194

201-
return builder.setMediaFormat(MediaFormat.getFromSuffix(dto.urlKey))
202-
.build();
203-
});
204-
}
205-
195+
final JsonArray videoSize = dto.getStreamJsonObj().getArray("videoSize");
206196

207-
/**
208-
* This is just an internal class used in {@link #getStreams(String, Function)} to tie together
209-
* the stream json object, its URL key and its URL value. An object of this class would be
210-
* temporary and the three values it holds would be <b>convert</b>ed to a proper {@link Stream}
211-
* object based on the wanted stream type.
212-
*/
213-
private static final class MediaCCCLiveStreamMapperDTO {
214-
final JsonObject streamJsonObj;
215-
final String urlKey;
216-
final JsonObject urlValue;
217-
218-
MediaCCCLiveStreamMapperDTO(final JsonObject streamJsonObj,
219-
final String urlKey,
220-
final JsonObject urlValue) {
221-
this.streamJsonObj = streamJsonObj;
222-
this.urlKey = urlKey;
223-
this.urlValue = urlValue;
224-
}
197+
return new SimpleVideoAudioStreamImpl(
198+
deliveryData,
199+
// TODO: This looks wrong
200+
new VideoAudioFormatRegistry().getFromSuffix(dto.getUrlKey()),
201+
videoSize.getInt(0) + "x" + videoSize.getInt(1)
202+
);
203+
})
204+
.collect(Collectors.toList());
225205
}
226206

227-
private <T extends Stream> List<T> getStreams(
228-
@Nonnull final String streamType,
229-
@Nonnull final Function<MediaCCCLiveStreamMapperDTO, T> converter) {
207+
private Stream<MediaCCCLiveStreamMapperDTO> getStreamDTOs(@Nonnull final String streamType) {
230208
return room.getArray(STREAMS).stream()
231209
// Ensure that we use only process JsonObjects
232210
.filter(JsonObject.class::isInstance)
@@ -239,22 +217,17 @@ private <T extends Stream> List<T> getStreams(
239217
.map(e -> new MediaCCCLiveStreamMapperDTO(
240218
streamJsonObj,
241219
e.getKey(),
242-
(JsonObject) e.getValue())))
243-
// The DASH manifest will be extracted with getDashMpdUrl
244-
.filter(dto -> !"dash".equals(dto.urlKey))
245-
// Convert
246-
.map(converter)
247-
.collect(Collectors.toList());
220+
(JsonObject) e.getValue())));
248221
}
249222

250223
@Override
251-
public List<VideoStream> getVideoOnlyStreams() {
252-
return Collections.emptyList();
224+
public StreamType getStreamType() throws ParsingException {
225+
return StreamType.LIVE_STREAM;
253226
}
254227

255228
@Override
256-
public StreamType getStreamType() throws ParsingException {
257-
return StreamType.LIVE_STREAM;
229+
public boolean isLive() {
230+
return true;
258231
}
259232

260233
@Nonnull

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

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.grack.nanojson.JsonArray;
44
import com.grack.nanojson.JsonParser;
55
import com.grack.nanojson.JsonParserException;
6+
67
import org.schabi.newpipe.extractor.downloader.Downloader;
78
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
89
import org.schabi.newpipe.extractor.exceptions.ParsingException;
@@ -43,13 +44,21 @@ public static boolean isLiveStreamId(final String id) {
4344
/**
4445
* Get currently available live streams from
4546
* <a href="https://streaming.media.ccc.de/streams/v2.json">
46-
* https://streaming.media.ccc.de/streams/v2.json</a>.
47+
* https://streaming.media.ccc.de/streams/v2.json</a>.
48+
* <p>
4749
* Use this method to cache requests, because they can get quite big.
50+
* </p>
51+
*
52+
* <p>
53+
* For more information see also: <a href="https://github.com/voc/streaming-website#json-api">
54+
* https://github.com/voc/streaming-website#json-api</a>.
55+
* </p>
4856
* TODO: implement better caching policy (max-age: 3 min)
49-
* @param downloader The downloader to use for making the request
57+
*
58+
* @param downloader The downloader to use for making the request
5059
* @param localization The localization to be used. Will most likely be ignored.
5160
* @return {@link JsonArray} containing current conferences and info about their rooms and
52-
* streams.
61+
* streams.
5362
* @throws ExtractionException if the data could not be fetched or the retrieved data could not
5463
* be parsed to a {@link JsonArray}
5564
*/
@@ -58,13 +67,14 @@ public static JsonArray getLiveStreams(final Downloader downloader,
5867
throws ExtractionException {
5968
if (liveStreams == null) {
6069
try {
61-
final String site = downloader.get("https://streaming.media.ccc.de/streams/v2.json",
62-
localization).responseBody();
70+
final String site = downloader
71+
.get("https://streaming.media.ccc.de/streams/v2.json", localization)
72+
.responseBody();
6373
liveStreams = JsonParser.array().from(site);
6474
} catch (final IOException | ReCaptchaException e) {
65-
throw new ExtractionException("Could not get live stream JSON.", e);
75+
throw new ExtractionException("Could not get live stream JSON", e);
6676
} catch (final JsonParserException e) {
67-
throw new ExtractionException("Could not parse JSON.", e);
77+
throw new ExtractionException("Could not parse JSON", e);
6878
}
6979
}
7080
return liveStreams;

0 commit comments

Comments
 (0)