Skip to content

Commit 8d83786

Browse files
committed
[media.ccc.de] Live stream kiosk: detect break "talks" segements
Add and improve tests for MediaCCCLiveStreamKioskExtractor: - test stream items if a live stream is running - use mock tests to check live talk extraction and testing conferences
1 parent 55a2af2 commit 8d83786

File tree

4 files changed

+201
-12
lines changed

4 files changed

+201
-12
lines changed

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import javax.annotation.Nonnull;
1111
import javax.annotation.Nullable;
12+
import java.time.OffsetDateTime;
1213
import java.util.List;
1314

1415
import static org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCParsingHelper.getThumbnailsFromLiveStreamItem;
@@ -19,17 +20,25 @@ public class MediaCCCLiveStreamKioskExtractor implements StreamInfoItemExtractor
1920
private final String group;
2021
private final JsonObject roomInfo;
2122

23+
@Nonnull
24+
private final JsonObject currentTalk;
25+
2226
public MediaCCCLiveStreamKioskExtractor(final JsonObject conferenceInfo,
2327
final String group,
2428
final JsonObject roomInfo) {
2529
this.conferenceInfo = conferenceInfo;
2630
this.group = group;
2731
this.roomInfo = roomInfo;
32+
this.currentTalk = roomInfo.getObject("talks").getObject("current");
2833
}
2934

3035
@Override
3136
public String getName() throws ParsingException {
32-
return roomInfo.getObject("talks").getObject("current").getString("title");
37+
if (isBreak()) {
38+
return roomInfo.getString("display") + " - Pause";
39+
} else {
40+
return currentTalk.getString("title");
41+
}
3342
}
3443

3544
@Override
@@ -95,6 +104,18 @@ public String getTextualUploadDate() throws ParsingException {
95104
@Nullable
96105
@Override
97106
public DateWrapper getUploadDate() throws ParsingException {
98-
return null;
107+
if (isBreak()) {
108+
return new DateWrapper(OffsetDateTime.parse(currentTalk.getString("fstart")));
109+
} else {
110+
return new DateWrapper(OffsetDateTime.parse(conferenceInfo.getString("startsAt")));
111+
}
112+
}
113+
114+
/**
115+
* Whether the current "talk" is a talk or a pause.
116+
*/
117+
private boolean isBreak() {
118+
return OffsetDateTime.parse(currentTalk.getString("fstart")).isBefore(OffsetDateTime.now())
119+
|| "gap".equals(currentTalk.getString("special"));
99120
}
100121
}

extractor/src/test/java/org/schabi/newpipe/extractor/services/media_ccc/MediaCCCLiveStreamListExtractorTest.java

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,103 @@
22

33
import org.junit.jupiter.api.BeforeAll;
44
import org.junit.jupiter.api.Test;
5+
import org.schabi.newpipe.downloader.DownloaderFactory;
56
import org.schabi.newpipe.downloader.DownloaderTestImpl;
7+
import org.schabi.newpipe.downloader.MockOnly;
68
import org.schabi.newpipe.extractor.InfoItem;
9+
import org.schabi.newpipe.extractor.ListExtractor;
710
import org.schabi.newpipe.extractor.NewPipe;
811
import org.schabi.newpipe.extractor.kiosk.KioskExtractor;
12+
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCLiveStreamKiosk;
913

1014
import java.util.List;
1115

16+
import static org.junit.jupiter.api.Assertions.assertEquals;
17+
import static org.junit.jupiter.api.Assertions.assertTrue;
1218
import static org.schabi.newpipe.extractor.ServiceList.MediaCCC;
19+
import static org.schabi.newpipe.extractor.services.DefaultTests.defaultTestListOfItems;
1320

1421
public class MediaCCCLiveStreamListExtractorTest {
15-
private static KioskExtractor extractor;
1622

17-
@BeforeAll
18-
public static void setUpClass() throws Exception {
19-
NewPipe.init(DownloaderTestImpl.getInstance());
20-
extractor = MediaCCC.getKioskList().getExtractorById("live", null);
21-
extractor.fetchPage();
23+
private static final String RESOURCE_PATH = DownloaderFactory.RESOURCE_PATH
24+
+ "services/media.ccc.de/kiosk/live/";
25+
private static final String LIVE_KIOSK_ID = MediaCCCLiveStreamKiosk.KIOSK_ID;
26+
27+
/**
28+
* Test against the media.ccc.de livestream API endpoint
29+
* and ensure that no exceptions are thrown.
30+
*/
31+
public static class LiveDataTest {
32+
private static KioskExtractor extractor;
33+
34+
@BeforeAll
35+
public static void setUpClass() throws Exception {
36+
NewPipe.init(DownloaderTestImpl.getInstance());
37+
extractor = MediaCCC.getKioskList().getExtractorById(LIVE_KIOSK_ID, null);
38+
extractor.fetchPage();
39+
}
40+
41+
@Test
42+
void getConferencesListTest() throws Exception {
43+
final ListExtractor.InfoItemsPage liveStreamPage = extractor.getInitialPage();
44+
final List<InfoItem> items = liveStreamPage.getItems();
45+
if (items.isEmpty()) {
46+
// defaultTestListOfItems() fails, if items is empty.
47+
// This can happen if there are no current live streams.
48+
// In this case, we just check if an exception was thrown
49+
assertTrue(liveStreamPage.getErrors().isEmpty());
50+
} else {
51+
defaultTestListOfItems(MediaCCC, items, liveStreamPage.getErrors());
52+
}
53+
}
2254
}
2355

24-
@Test
25-
public void getConferencesListTest() throws Exception {
26-
final List<InfoItem> items = extractor.getInitialPage().getItems();
27-
// just test if there is an exception thrown
56+
/**
57+
* Test conferences which are available via the API for C3voc internal testing,
58+
* but not intended to be shown to users.
59+
*/
60+
@MockOnly("The live stream API returns different data depending on if and what conferences"
61+
+ " are running. The PreparationTest tests a conference which is used "
62+
+ "for internal testing.")
63+
public static class PreparationTest {
64+
private static KioskExtractor extractor;
65+
66+
@BeforeAll
67+
public static void setUpClass() throws Exception {
68+
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "preparation"));
69+
extractor = MediaCCC.getKioskList().getExtractorById(LIVE_KIOSK_ID, null);
70+
extractor.fetchPage();
71+
}
72+
73+
@Test
74+
void getConferencesListTest() throws Exception {
75+
// Testing conferences and the corresponding talks should not be extracted.
76+
assertTrue(extractor.getInitialPage().getItems().isEmpty());
77+
}
2878
}
2979

80+
/**
81+
* Test a running conference.
82+
*/
83+
@MockOnly("The live stream API returns different data depending on if and what conferences"
84+
+ " are running. Using mocks to ensure that there are conferences & talks to extract.")
85+
public static class LiveConferenceTest {
86+
private static KioskExtractor extractor;
87+
88+
@BeforeAll
89+
public static void setUpClass() throws Exception {
90+
NewPipe.init(DownloaderFactory.getDownloader(RESOURCE_PATH + "running"));
91+
extractor = MediaCCC.getKioskList().getExtractorById(LIVE_KIOSK_ID, null);
92+
extractor.fetchPage();
93+
}
94+
95+
@Test
96+
void getConferencesListTest() throws Exception {
97+
final ListExtractor.InfoItemsPage liveStreamPage = extractor.getInitialPage();
98+
final List<InfoItem> items = liveStreamPage.getItems();
99+
assertEquals(6, items.size());
100+
defaultTestListOfItems(MediaCCC, items, liveStreamPage.getErrors());
101+
102+
}
103+
}
30104
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"request": {
3+
"httpMethod": "GET",
4+
"url": "https://streaming.media.ccc.de/streams/v2.json",
5+
"headers": {
6+
"Accept-Language": [
7+
"en-GB, en;q\u003d0.9"
8+
]
9+
},
10+
"localization": {
11+
"languageCode": "en",
12+
"countryCode": "GB"
13+
}
14+
},
15+
"response": {
16+
"responseCode": 200,
17+
"responseMessage": "OK",
18+
"responseHeaders": {
19+
"access-control-allow-origin": [
20+
"*"
21+
],
22+
"content-type": [
23+
"application/json"
24+
],
25+
"date": [
26+
"Sat, 05 Aug 2023 10:59:09 GMT"
27+
],
28+
"server": [
29+
"nginx"
30+
],
31+
"strict-transport-security": [
32+
"max-age\u003d31536000"
33+
],
34+
"transfer-encoding": [
35+
"chunked"
36+
],
37+
"vary": [
38+
"Accept-Encoding"
39+
],
40+
"x-cache": [
41+
"HIT origin"
42+
]
43+
},
44+
"responseBody": "[\n {\n \"conference\": \"BornHack 2023\",\n \"slug\": \"bornhack2023\",\n \"author\": \"BornHack ApS\",\n \"description\": \"BornHack is a 7 day outdoor tent camp where hackers, makers and people with an interest in technology or security come together to celebrate technology, socialise, learn and have fun.\",\n \"keywords\": \"\",\n \"schedule\": null,\n \"startsAt\": \"2023-08-02T13:00:00+0000\",\n \"endsAt\": \"2023-08-09T18:00:00+0000\",\n \"isCurrentlyStreaming\": false,\n \"groups\": [\n {\n \"group\": \"Lecture Rooms\",\n \"rooms\": [\n {\n \"slug\": \"bornhack1\",\n \"schedulename\": \"Speakers Tent\",\n \"thumb\": \"https://cdn.c3voc.de/thumbnail/bornhack23s1/thumb.jpeg\",\n \"poster\": \"https://cdn.c3voc.de/thumbnail/bornhack23s1/poster.jpeg\",\n \"link\": \"https://streaming.media.ccc.de/bornhack2023/bornhack1\",\n \"display\": \"Speakers Tent\",\n \"stream\": \"bornhack23s1\",\n \"talks\": {\n \"current\": null,\n \"next\": null\n },\n \"streams\": [\n {\n \"slug\": \"hls-native\",\n \"display\": \"Speakers Tent \",\n \"type\": \"hls\",\n \"isTranslated\": false,\n \"videoSize\": null,\n \"urls\": {}\n },\n {\n \"slug\": \"hls-translated\",\n \"display\": \"Speakers Tent (Translated)\",\n \"type\": \"hls\",\n \"isTranslated\": true,\n \"videoSize\": null,\n \"urls\": {}\n },\n {\n \"slug\": \"hd-native\",\n \"display\": \"Speakers Tent FullHD Video\",\n \"type\": \"video\",\n \"isTranslated\": false,\n \"videoSize\": [\n 1920,\n 1080\n ],\n \"urls\": {\n \"hls\": {\n \"display\": \"HLS\",\n \"tech\": \"1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s\",\n \"url\": \"https://cdn.c3voc.de/hls/bornhack23s1/native_hd.m3u8\"\n }\n }\n },\n {\n \"slug\": \"hd-translated\",\n \"display\": \"Speakers Tent FullHD Video (Translated)\",\n \"type\": \"video\",\n \"isTranslated\": true,\n \"videoSize\": [\n 1920,\n 1080\n ],\n \"urls\": {\n \"hls\": {\n \"display\": \"HLS\",\n \"tech\": \"1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s\",\n \"url\": \"https://cdn.c3voc.de/hls/bornhack23s1/translated_hd.m3u8\"\n }\n }\n }\n ]\n },\n {\n \"slug\": \"bornhack2\",\n \"schedulename\": \"Bar Area\",\n \"thumb\": \"https://cdn.c3voc.de/thumbnail/bornhack23s2/thumb.jpeg\",\n \"poster\": \"https://cdn.c3voc.de/thumbnail/bornhack23s2/poster.jpeg\",\n \"link\": \"https://streaming.media.ccc.de/bornhack2023/bornhack2\",\n \"display\": \"Bar Area\",\n \"stream\": \"bornhack23s2\",\n \"talks\": {\n \"current\": null,\n \"next\": null\n },\n \"streams\": [\n {\n \"slug\": \"hls-native\",\n \"display\": \"Bar Area \",\n \"type\": \"hls\",\n \"isTranslated\": false,\n \"videoSize\": null,\n \"urls\": {}\n },\n {\n \"slug\": \"hls-translated\",\n \"display\": \"Bar Area (Translated)\",\n \"type\": \"hls\",\n \"isTranslated\": true,\n \"videoSize\": null,\n \"urls\": {}\n },\n {\n \"slug\": \"hd-native\",\n \"display\": \"Bar Area FullHD Video\",\n \"type\": \"video\",\n \"isTranslated\": false,\n \"videoSize\": [\n 1920,\n 1080\n ],\n \"urls\": {\n \"hls\": {\n \"display\": \"HLS\",\n \"tech\": \"1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s\",\n \"url\": \"https://cdn.c3voc.de/hls/bornhack23s2/native_hd.m3u8\"\n }\n }\n },\n {\n \"slug\": \"hd-translated\",\n \"display\": \"Bar Area FullHD Video (Translated)\",\n \"type\": \"video\",\n \"isTranslated\": true,\n \"videoSize\": [\n 1920,\n 1080\n ],\n \"urls\": {\n \"hls\": {\n \"display\": \"HLS\",\n \"tech\": \"1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s\",\n \"url\": \"https://cdn.c3voc.de/hls/bornhack23s2/translated_hd.m3u8\"\n }\n }\n }\n ]\n },\n {\n \"slug\": \"bornhack3\",\n \"schedulename\": \"Bar Meetup Area\",\n \"thumb\": \"https://cdn.c3voc.de/thumbnail/bornhack23s3/thumb.jpeg\",\n \"poster\": \"https://cdn.c3voc.de/thumbnail/bornhack23s3/poster.jpeg\",\n \"link\": \"https://streaming.media.ccc.de/bornhack2023/bornhack3\",\n \"display\": \"Bar Meetup Area\",\n \"stream\": \"bornhack23s3\",\n \"talks\": {\n \"current\": null,\n \"next\": null\n },\n \"streams\": [\n {\n \"slug\": \"hls-native\",\n \"display\": \"Bar Meetup Area \",\n \"type\": \"hls\",\n \"isTranslated\": false,\n \"videoSize\": null,\n \"urls\": {}\n },\n {\n \"slug\": \"hls-translated\",\n \"display\": \"Bar Meetup Area (Translated)\",\n \"type\": \"hls\",\n \"isTranslated\": true,\n \"videoSize\": null,\n \"urls\": {}\n },\n {\n \"slug\": \"hd-native\",\n \"display\": \"Bar Meetup Area FullHD Video\",\n \"type\": \"video\",\n \"isTranslated\": false,\n \"videoSize\": [\n 1920,\n 1080\n ],\n \"urls\": {\n \"hls\": {\n \"display\": \"HLS\",\n \"tech\": \"1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s\",\n \"url\": \"https://cdn.c3voc.de/hls/bornhack23s3/native_hd.m3u8\"\n }\n }\n },\n {\n \"slug\": \"hd-translated\",\n \"display\": \"Bar Meetup Area FullHD Video (Translated)\",\n \"type\": \"video\",\n \"isTranslated\": true,\n \"videoSize\": [\n 1920,\n 1080\n ],\n \"urls\": {\n \"hls\": {\n \"display\": \"HLS\",\n \"tech\": \"1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s\",\n \"url\": \"https://cdn.c3voc.de/hls/bornhack23s3/translated_hd.m3u8\"\n }\n }\n }\n ]\n }\n ]\n }\n ]\n }\n]",
45+
"latestUrl": "https://streaming.media.ccc.de/streams/v2.json"
46+
}
47+
}

extractor/src/test/resources/org/schabi/newpipe/extractor/services/media.ccc.de/kiosk/live/running/generated_mock_0.json

Lines changed: 47 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)