mirror of
https://github.com/NiciDieNase/chaosflix
synced 2024-11-23 12:53:08 +00:00
implement Client for StreamingAPI + simple Tests
This commit is contained in:
parent
ee5e21f4d8
commit
1fd9698abd
14 changed files with 481 additions and 12 deletions
|
@ -41,6 +41,7 @@ dependencies {
|
|||
androidTestCompile ('com.android.support.test:runner:0.5') {
|
||||
exclude module: 'support-annotations'
|
||||
}
|
||||
testCompile 'com.squareup.okhttp3:mockwebserver:3.6.0'
|
||||
// testCompile 'org.mockito:mockito-core:1.10.19'
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ public class EventsActivity extends Activity {
|
|||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// TODO determin if we should use a Browse or a Grid layout
|
||||
setContentView(R.layout.activity_events_browse);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package de.nicidienase.chaosflix.entities;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by felix on 23.03.17.
|
||||
*/
|
||||
|
||||
class Group {
|
||||
String group;
|
||||
List<Room> rooms;
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public void setGroup(String group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public List<Room> getRooms() {
|
||||
return rooms;
|
||||
}
|
||||
|
||||
public void setRooms(List<Room> rooms) {
|
||||
this.rooms = rooms;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package de.nicidienase.chaosflix.entities;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by felix on 23.03.17.
|
||||
*/
|
||||
|
||||
class Room {
|
||||
String slug;
|
||||
String shedulename;
|
||||
String thumb;
|
||||
String link;
|
||||
String display;
|
||||
List<Stream> streams;
|
||||
|
||||
public String getSlug() {
|
||||
return slug;
|
||||
}
|
||||
|
||||
public void setSlug(String slug) {
|
||||
this.slug = slug;
|
||||
}
|
||||
|
||||
public String getShedulename() {
|
||||
return shedulename;
|
||||
}
|
||||
|
||||
public void setShedulename(String shedulename) {
|
||||
this.shedulename = shedulename;
|
||||
}
|
||||
|
||||
public String getThumb() {
|
||||
return thumb;
|
||||
}
|
||||
|
||||
public void setThumb(String thumb) {
|
||||
this.thumb = thumb;
|
||||
}
|
||||
|
||||
public String getLink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
public void setLink(String link) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
public void setDisplay(String display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
public List<Stream> getStreams() {
|
||||
return streams;
|
||||
}
|
||||
|
||||
public void setStreams(List<Stream> streams) {
|
||||
this.streams = streams;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package de.nicidienase.chaosflix.entities;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by felix on 23.03.17.
|
||||
*/
|
||||
|
||||
class Stream {
|
||||
String slug;
|
||||
String display;
|
||||
String type;
|
||||
boolean isTranslated;
|
||||
int[] videoSize;
|
||||
Map<String,StreamUrl> urls;
|
||||
|
||||
public String getSlug() {
|
||||
return slug;
|
||||
}
|
||||
|
||||
public void setSlug(String slug) {
|
||||
this.slug = slug;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
public void setDisplay(String display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public boolean isTranslated() {
|
||||
return isTranslated;
|
||||
}
|
||||
|
||||
public void setTranslated(boolean translated) {
|
||||
isTranslated = translated;
|
||||
}
|
||||
|
||||
public int[] getVideoSize() {
|
||||
return videoSize;
|
||||
}
|
||||
|
||||
public void setVideoSize(int[] videoSize) {
|
||||
this.videoSize = videoSize;
|
||||
}
|
||||
|
||||
public Map<String, StreamUrl> getUrls() {
|
||||
return urls;
|
||||
}
|
||||
|
||||
public void setUrls(Map<String, StreamUrl> urls) {
|
||||
this.urls = urls;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package de.nicidienase.chaosflix.entities;
|
||||
|
||||
/**
|
||||
* Created by felix on 23.03.17.
|
||||
*/
|
||||
|
||||
class StreamUrl {
|
||||
String display;
|
||||
String tech;
|
||||
String url;
|
||||
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
public void setDisplay(String display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
public String getTech() {
|
||||
return tech;
|
||||
}
|
||||
|
||||
public void setTech(String tech) {
|
||||
this.tech = tech;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package de.nicidienase.chaosflix.entities;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by felix on 23.03.17.
|
||||
*/
|
||||
|
||||
public class StreamingConference {
|
||||
String conference;
|
||||
String slug;
|
||||
String author;
|
||||
String description;
|
||||
String keywords;
|
||||
String startsAt;
|
||||
String endsAt;
|
||||
List<Group> groups;
|
||||
|
||||
public String getConference() {
|
||||
return conference;
|
||||
}
|
||||
|
||||
public void setConference(String conference) {
|
||||
this.conference = conference;
|
||||
}
|
||||
|
||||
public String getSlug() {
|
||||
return slug;
|
||||
}
|
||||
|
||||
public void setSlug(String slug) {
|
||||
this.slug = slug;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getKeywords() {
|
||||
return keywords;
|
||||
}
|
||||
|
||||
public void setKeywords(String keywords) {
|
||||
this.keywords = keywords;
|
||||
}
|
||||
|
||||
public String getStartsAt() {
|
||||
return startsAt;
|
||||
}
|
||||
|
||||
public void setStartsAt(String startsAt) {
|
||||
this.startsAt = startsAt;
|
||||
}
|
||||
|
||||
public String getEndsAt() {
|
||||
return endsAt;
|
||||
}
|
||||
|
||||
public void setEndsAt(String endsAt) {
|
||||
this.endsAt = endsAt;
|
||||
}
|
||||
|
||||
public List<Group> getGroups() {
|
||||
return groups;
|
||||
}
|
||||
|
||||
public void setGroups(List<Group> groups) {
|
||||
this.groups = groups;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package de.nicidienase.chaosflix.network;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.nicidienase.chaosflix.entities.StreamingConference;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
/**
|
||||
* Created by felix on 23.03.17.
|
||||
*/
|
||||
|
||||
public class StreamingClient implements StreamingService {
|
||||
|
||||
private StreamingService service;
|
||||
|
||||
public StreamingClient(){
|
||||
this("https://api.media.ccc.de");
|
||||
}
|
||||
|
||||
public StreamingClient(String serviceUrl){
|
||||
Retrofit retrofit = new Retrofit.Builder()
|
||||
.baseUrl(serviceUrl)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build();
|
||||
service = retrofit.create(StreamingService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Call<List<StreamingConference>> getStreamingConferences() {
|
||||
return service.getStreamingConferences();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package de.nicidienase.chaosflix.network;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.nicidienase.chaosflix.entities.StreamingConference;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
|
||||
/**
|
||||
* Created by felix on 23.03.17.
|
||||
*/
|
||||
|
||||
public interface StreamingService {
|
||||
|
||||
@GET("streams/v2.json")
|
||||
Call<List<StreamingConference>> getStreamingConferences();
|
||||
}
|
|
@ -2,8 +2,6 @@ package de.nicidienase.chaosflix;
|
|||
|
||||
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
@ -14,17 +12,13 @@ import org.junit.Test;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import de.nicidienase.chaosflix.entities.Conference;
|
||||
import de.nicidienase.chaosflix.entities.Conferences;
|
||||
import de.nicidienase.chaosflix.entities.Event;
|
||||
import de.nicidienase.chaosflix.entities.Recording;
|
||||
import de.nicidienase.chaosflix.network.MediaCCCClient;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
import de.nicidienase.chaosflix.network.RecordingClient;
|
||||
|
||||
/**
|
||||
* Created by felix on 17.03.17.
|
||||
|
@ -33,11 +27,11 @@ import retrofit2.Response;
|
|||
public class MediaCCCClientTest{
|
||||
|
||||
private static final String TAG = MediaCCCClientTest.class.getSimpleName();
|
||||
private MediaCCCClient client;
|
||||
private RecordingClient client;
|
||||
|
||||
@Before
|
||||
public void beforeTest(){
|
||||
this.client = new MediaCCCClient();
|
||||
this.client = new RecordingClient();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -79,7 +73,7 @@ public class MediaCCCClientTest{
|
|||
|
||||
@Test
|
||||
public void sortTest() throws IOException {
|
||||
final MediaCCCClient client = this.client;
|
||||
final RecordingClient client = this.client;
|
||||
Conferences conferences = client.listConferences().execute().body();
|
||||
Collections.sort(conferences.getConferences());
|
||||
for (Conference conf : conferences.getConferences()) {
|
||||
|
@ -91,15 +85,33 @@ public class MediaCCCClientTest{
|
|||
|
||||
@Test
|
||||
public void sortAllEvents() throws IOException {
|
||||
MediaCCCClient client = this.client;
|
||||
RecordingClient client = this.client;
|
||||
Collections.sort(client.getEvents().execute().body());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mrmcd13() throws IOException {
|
||||
MediaCCCClient client = this.client;
|
||||
RecordingClient client = this.client;
|
||||
Conference conference = client.getConference(38).execute().body();
|
||||
ArrayList<String> keyList = Lists.newArrayList(conference.getEventsByTags().keySet());
|
||||
Collections.sort(keyList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTagsToTalksRation() throws IOException {
|
||||
List<Conference> conferences = client.listConferences().execute().body().getConferences();
|
||||
for(Conference conf : conferences){
|
||||
Conference con = client.getConference(conf.getApiID()).execute().body();
|
||||
System.out.print(con.getAcronym() + ": " + con.getEventsByTags().keySet());
|
||||
float sum = 0;
|
||||
for(Event e : con.getEvents()){
|
||||
sum += e.getTags().size();
|
||||
}
|
||||
// System.out.println("\t\t " + sum/con.getEvents().size() + "\n\t" + con.getEventsByTags().keySet());
|
||||
// HashMap<String, List<Event>> events = con.getEventsByTags();
|
||||
// for(String tag: events.keySet()){
|
||||
// System.out.println("Ration: " + events.keySet().size() + "/" + events.get(tag).size());
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package de.nicidienase.chaosflix;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import de.nicidienase.chaosflix.entities.StreamingConference;
|
||||
import de.nicidienase.chaosflix.network.StreamingClient;
|
||||
import de.nicidienase.chaosflix.network.StreamingService;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import retrofit2.Response;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
/**
|
||||
* Created by felix on 23.03.17.
|
||||
*/
|
||||
|
||||
public class StreamingClientTest {
|
||||
|
||||
private static MockWebServer server;
|
||||
private static StreamingService service;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void setupClass() throws IOException {
|
||||
server = new MockWebServer();
|
||||
server.start();
|
||||
String serverUrl = server.url("/").toString();
|
||||
service = new StreamingClient(serverUrl);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupTest() throws IOException {
|
||||
server.enqueue(new MockResponse().setResponseCode(200).setBody(TestResources.testJson));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() throws IOException {
|
||||
List<StreamingConference> streamingConferences
|
||||
= service.getStreamingConferences().execute().body();
|
||||
assertEquals(1,streamingConferences.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() throws IOException {
|
||||
List<StreamingConference> streamingConferences
|
||||
= service.getStreamingConferences().execute().body();
|
||||
StreamingConference streamingConference = streamingConferences.get(0);
|
||||
assertEquals("FOSSGIS 2017",streamingConference.getConference());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package de.nicidienase.chaosflix;
|
||||
|
||||
/**
|
||||
* Created by felix on 23.03.17.
|
||||
*/
|
||||
|
||||
public class TestResources {
|
||||
public static final String testJson =
|
||||
"[{\"conference\": \"FOSSGIS 2017\",\"slug\": \"fossgis17\",\"author\": \"FOSSGIS e.V.\"" +
|
||||
",\"description\": \"Die FOSSGIS-Konferenz ist im D-A-CH Raum die führende Konfe" +
|
||||
"renz für Freie und Open Source Software für Geoinformationssysteme OpenStreetMa" +
|
||||
"p.\",\"keywords\": \"FOSSGIS, FOSSGIS-Konferenz, 2017, FOSSGIS-Konferenz 2017, " +
|
||||
"Open Source, GIS, Konferenz, Geoinformatik, OpenStreetMap, Passau, Video, Strea" +
|
||||
"ming, Live, Livestream\",\"startsAt\": \"2017-03-22T08:30:00+0000\",\"endsAt\":" +
|
||||
" \"2017-03-25T14:00:00+0000\",\"groups\": [{\"group\": \"Lecture Rooms\",\"room" +
|
||||
"s\": [{\"slug\": \"AM-HS-9\",\"schedulename\": \"AM HS 9\",\"thumb\": \"https:/" +
|
||||
"/streaming.media.ccc.de/thumbs/s6.png\",\"link\": \"https://streaming.media.ccc" +
|
||||
".de/fossgis17/AM-HS-9\",\"display\": \"AM HS 9\",\"streams\": [{\"slug\": \"hd-" +
|
||||
"native\",\"display\": \"AM HS 9 FullHD Video\",\"type\": \"video\",\"isTranslat" +
|
||||
"ed\": false,\"videoSize\": [1920,1080],\"urls\": {\"webm\": {\"display\": \"Web" +
|
||||
"M\",\"tech\": \"1920x1080, VP8+Vorbis in WebM, 3.5 MBit/s\",\"url\": \"https://" +
|
||||
"cdn.c3voc.de/s6_native_hd.webm\"},\"hls\": {\"display\": \"HLS\",\"tech\": \"19" +
|
||||
"20x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s\",\"url\": \"https://" +
|
||||
"cdn.c3voc.de/hls/s6_native_hd.m3u8\"}}},{\"slug\": \"sd-native\",\"display\": \"" +
|
||||
"AM HS 9 SD Video\",\"type\": \"video\",\"isTranslated\": false,\"videoSize\": [" +
|
||||
"1024,576],\"urls\": {\"webm\": {\"display\": \"WebM\",\"tech\": \"1024x576, VP8" +
|
||||
"+Vorbis in WebM, 1 MBit/s\",\"url\": \"https://cdn.c3voc.de/s6_native_sd.webm\"" +
|
||||
"},\"hls\": {\"display\": \"HLS\",\"tech\": \"1024x576, h264+AAC im MPEG-TS-Cont" +
|
||||
"ainer via HTTP, 800 kBit/s\",\"url\": \"https://cdn.c3voc.de/hls/s6_native_sd.m" +
|
||||
"3u8\"}}},{\"slug\": \"audio-native\",\"display\": \"AM HS 9 Audio\",\"type\": \"" +
|
||||
"audio\",\"isTranslated\": false,\"videoSize\": null,\"urls\": {\"mp3\": {\"disp" +
|
||||
"lay\": \"MP3\",\"tech\": \"MP3-Audio, 96 kBit/s\",\"url\": \"https://cdn.c3voc." +
|
||||
"de/s6_native.mp3\"},\"opus\": {\"display\": \"Opus\",\"tech\": \"Opus-Audio, 64" +
|
||||
" kBit/s\",\"url\": \"https://cdn.c3voc.de/s6_native.opus\"}}}]},{\"slug\": \"IM" +
|
||||
"-HS-11\",\"schedulename\": \"IM HS 11\",\"thumb\": \"https://streaming.media.cc" +
|
||||
"c.de/thumbs/s4.png\",\"link\": \"https://streaming.media.ccc.de/fossgis17/IM-HS" +
|
||||
"-11\",\"display\": \"IM-HS-11\",\"streams\": [{\"slug\": \"hd-native\",\"displa" +
|
||||
"y\": \"IM-HS-11 FullHD Video\",\"type\": \"video\",\"isTranslated\": false,\"vi" +
|
||||
"deoSize\": [1920,1080],\"urls\": {\"webm\": {\"display\": \"WebM\",\"tech\": \"" +
|
||||
"1920x1080, VP8+Vorbis in WebM, 3.5 MBit/s\",\"url\": \"https://cdn.c3voc.de/s4_" +
|
||||
"native_hd.webm\"},\"hls\": {\"display\": \"HLS\",\"tech\": \"1920x1080, h264+AA" +
|
||||
"C im MPEG-TS-Container via HTTP, 3 MBit/s\",\"url\": \"https://cdn.c3voc.de/hls" +
|
||||
"/s4_native_hd.m3u8\"}}},{\"slug\": \"sd-native\",\"display\": \"IM-HS-11 SD Vid" +
|
||||
"eo\",\"type\": \"video\",\"isTranslated\": false,\"videoSize\": [1024,576],\"ur" +
|
||||
"ls\": {\"webm\": {\"display\": \"WebM\",\"tech\": \"1024x576, VP8+Vorbis in Web" +
|
||||
"M, 1 MBit/s\",\"url\": \"https://cdn.c3voc.de/s4_native_sd.webm\"},\"hls\": {\"" +
|
||||
"display\": \"HLS\",\"tech\": \"1024x576, h264+AAC im MPEG-TS-Container via HTTP" +
|
||||
", 800 kBit/s\",\"url\": \"https://cdn.c3voc.de/hls/s4_native_sd.m3u8\"}}},{\"sl" +
|
||||
"ug\": \"audio-native\",\"display\": \"IM-HS-11 Audio\",\"type\": \"audio\",\"is" +
|
||||
"Translated\": false,\"videoSize\": null,\"urls\": {\"mp3\": {\"display\": \"MP3" +
|
||||
"\",\"tech\": \"MP3-Audio, 96 kBit/s\",\"url\": \"https://cdn.c3voc.de/s4_native" +
|
||||
".mp3\"},\"opus\": {\"display\": \"Opus\",\"tech\": \"Opus-Audio, 64 kBit/s\",\"" +
|
||||
"url\": \"https://cdn.c3voc.de/s4_native.opus\"}}}]},{\"slug\": \"IM-HS-13\",\"s" +
|
||||
"chedulename\": \"IM HS 13\",\"thumb\": \"https://streaming.media.ccc.de/thumbs/" +
|
||||
"s5.png\",\"link\": \"https://streaming.media.ccc.de/fossgis17/IM-HS-13\",\"disp" +
|
||||
"lay\": \"IM HS 13\",\"streams\": [{\"slug\": \"hd-native\",\"display\": \"IM HS" +
|
||||
" 13 FullHD Video\",\"type\": \"video\",\"isTranslated\": false,\"videoSize\": [" +
|
||||
"1920,1080],\"urls\": {\"webm\": {\"display\": \"WebM\",\"tech\": \"1920x1080, V" +
|
||||
"P8+Vorbis in WebM, 3.5 MBit/s\",\"url\": \"https://cdn.c3voc.de/s5_native_hd.we" +
|
||||
"bm\"},\"hls\": {\"display\": \"HLS\",\"tech\": \"1920x1080, h264+AAC im MPEG-TS" +
|
||||
"-Container via HTTP, 3 MBit/s\",\"url\": \"https://cdn.c3voc.de/hls/s5_native_h" +
|
||||
"d.m3u8\"}}},{\"slug\": \"sd-native\",\"display\": \"IM HS 13 SD Video\",\"type\"" +
|
||||
": \"video\",\"isTranslated\": false,\"videoSize\": [1024,576],\"urls\": {\"webm" +
|
||||
"\": {\"display\": \"WebM\",\"tech\": \"1024x576, VP8+Vorbis in WebM, 1 MBit/s\"" +
|
||||
",\"url\": \"https://cdn.c3voc.de/s5_native_sd.webm\"},\"hls\": {\"display\": \"" +
|
||||
"HLS\",\"tech\": \"1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s\"" +
|
||||
",\"url\": \"https://cdn.c3voc.de/hls/s5_native_sd.m3u8\"}}},{\"slug\": \"audio-" +
|
||||
"native\",\"display\": \"IM HS 13 Audio\",\"type\": \"audio\",\"isTranslated\": " +
|
||||
"false,\"videoSize\": null,\"urls\": {\"mp3\": {\"display\": \"MP3\",\"tech\": \"" +
|
||||
"MP3-Audio, 96 kBit/s\",\"url\": \"https://cdn.c3voc.de/s5_native.mp3\"},\"opus\"" +
|
||||
": {\"display\": \"Opus\",\"tech\": \"Opus-Audio, 64 kBit/s\",\"url\": \"https:/" +
|
||||
"/cdn.c3voc.de/s5_native.opus\"}}}]}]}]}]";
|
||||
}
|
Loading…
Reference in a new issue