[media.ccc.de] Fix live streams extraction

The API was slightly changed and only HLS streams are provided anymore.

Add a basic test for to check whether the required streamInfo fields are available.

Closes #766
This commit is contained in:
TobiGr 2021-12-27 19:18:36 +01:00
parent 10f6cc7194
commit 752825ced2
3 changed files with 69 additions and 14 deletions

View File

@ -93,17 +93,14 @@ public class MediaCCCLiveStreamExtractor extends StreamExtractor {
@Override @Override
public String getHlsUrl() { public String getHlsUrl() {
// TODO: There are multiple HLS streams. // TODO: There are multiple HLS streams.
// Make getHlsUrl() and getDashMpdUrl() return lists of VideoStreams, so the user can choose a resolution. // Make getHlsUrl() and getDashMpdUrl() return lists of VideoStreams
// to allow selecting a resolution.
for (int s = 0; s < room.getArray("streams").size(); s++) { for (int s = 0; s < room.getArray("streams").size(); s++) {
final JsonObject stream = room.getArray("streams").getObject(s); final JsonObject stream = room.getArray("streams").getObject(s);
if (stream.getString("type").equals("video")) { if (stream.getString("type").equals("video") && stream.getObject("urls").has("hls")) {
final String resolution = stream.getArray("videoSize").getInt(0) + "x"
+ stream.getArray("videoSize").getInt(1);
if (stream.has("hls")) {
return stream.getObject("urls").getObject("hls").getString("url"); return stream.getObject("urls").getObject("hls").getString("url");
} }
} }
}
return ""; return "";
} }
@ -114,8 +111,11 @@ public class MediaCCCLiveStreamExtractor extends StreamExtractor {
final JsonObject stream = room.getArray("streams").getObject(s); final JsonObject stream = room.getArray("streams").getObject(s);
if (stream.getString("type").equals("audio")) { if (stream.getString("type").equals("audio")) {
for (final String type : stream.getObject("urls").keySet()) { for (final String type : stream.getObject("urls").keySet()) {
if (!type.equals("hls")) {
final JsonObject url = stream.getObject("urls").getObject(type); final JsonObject url = stream.getObject("urls").getObject(type);
audioStreams.add(new AudioStream(url.getString("url"), MediaFormat.getFromSuffix(type), -1)); audioStreams.add(new AudioStream(
url.getString("url"), MediaFormat.getFromSuffix(type), -1));
}
} }
} }
} }

View File

@ -139,13 +139,13 @@ public class StreamInfo extends Info {
} catch (Exception e) { } catch (Exception e) {
streamInfo.addError(new ExtractionException("Couldn't get audio streams", e)); streamInfo.addError(new ExtractionException("Couldn't get audio streams", e));
} }
/* Extract video stream url */ /* Extract video streams */
try { try {
streamInfo.setVideoStreams(extractor.getVideoStreams()); streamInfo.setVideoStreams(extractor.getVideoStreams());
} catch (Exception e) { } catch (Exception e) {
streamInfo.addError(new ExtractionException("Couldn't get video streams", e)); streamInfo.addError(new ExtractionException("Couldn't get video streams", e));
} }
/* Extract video only stream url */ /* Extract video only streams */
try { try {
streamInfo.setVideoOnlyStreams(extractor.getVideoOnlyStreams()); streamInfo.setVideoOnlyStreams(extractor.getVideoOnlyStreams());
} catch (Exception e) { } catch (Exception e) {
@ -181,13 +181,16 @@ public class StreamInfo extends Info {
// Either audio or video has to be available, otherwise we didn't get a stream // Either audio or video has to be available, otherwise we didn't get a stream
// (since videoOnly are optional, they don't count). // (since videoOnly are optional, they don't count).
if ((streamInfo.videoStreams.isEmpty()) && (streamInfo.audioStreams.isEmpty())) { if (streamInfo.videoStreams.isEmpty()
&& streamInfo.audioStreams.isEmpty()
&& isNullOrEmpty(streamInfo.getHlsUrl())
&& isNullOrEmpty(streamInfo.getDashMpdUrl())) {
if (dashMpdError != null) { if (dashMpdError != null) {
// If we don't have any video or audio and the dashMpd 'errored', add it to the // If we don't have any video or audio and the dashMpd 'errored', add it to the
// error list // error list
// (it's optional and it don't get added automatically, but it's good to have // (It's optional, and it is not added automatically,
// some additional error context) // but it's good to have some additional error context).
streamInfo.addError(dashMpdError); streamInfo.addError(dashMpdError);
} }

View File

@ -0,0 +1,52 @@
package org.schabi.newpipe.extractor.services.media_ccc;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.schabi.newpipe.downloader.DownloaderTestImpl;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import java.io.IOException;
import java.util.List;
import static org.schabi.newpipe.extractor.ServiceList.MediaCCC;
public class MediaCCCLiveStreamExtractorTest {
private static KioskExtractor liveKiosk;
private static StreamExtractor extractor;
private static List<InfoItem> liveItems;
@BeforeClass
public static void setUp() throws Exception {
NewPipe.init(DownloaderTestImpl.getInstance());
liveKiosk = MediaCCC.getKioskList().getExtractorById("live", null);
liveKiosk.fetchPage();
liveItems = liveKiosk.getInitialPage().getItems();
Assume.assumeFalse(
"Received an empty list of live streams. Skipping MediaCCCLiveStreamExtractorTest",
liveItems.isEmpty());
}
@Test
public void testRequiredStreamInfo() {
// Try to get the StreamInfo for each live stream.
// If some required info is not present an exception will be thrown.
try {
for (final InfoItem item : liveItems) {
StreamInfo.getInfo(item.getUrl());
}
} catch (ExtractionException | IOException e) {
e.printStackTrace();
Assert.fail("An exception was thrown while getting a StreamInfo for a livestream.");
}
}
}