extracte module common
|
@ -1,91 +0,0 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion "25.0.2"
|
||||
defaultConfig {
|
||||
applicationId "de.nicidienase.chaosflix"
|
||||
minSdkVersion 22
|
||||
targetSdkVersion 25
|
||||
versionCode 5
|
||||
versionName "0.2.0"
|
||||
multiDexEnabled true
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
minifyEnabled false
|
||||
useProguard false
|
||||
}
|
||||
release {
|
||||
shrinkResources true
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
||||
'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
exclude 'META-INF/ASL2.0'
|
||||
exclude 'META-INF/LICENSE'
|
||||
exclude 'META-INF/license.txt'
|
||||
exclude 'META-INF/NOTICE'
|
||||
exclude 'META-INF/notice.txt'
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
defaultConfig {
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation 'com.android.support:support-v4:25.4.0'
|
||||
implementation 'com.android.support:recyclerview-v7:25.4.0'
|
||||
implementation 'com.android.support:cardview-v7:25.4.0'
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile 'com.android.support:leanback-v17:25.4.0'
|
||||
compile 'com.android.support:appcompat-v7:25.4.0'
|
||||
compile 'com.android.support:multidex:1.0.2'
|
||||
compile 'com.android.support:design:25.4.0'
|
||||
|
||||
compile 'com.google.android.exoplayer:exoplayer:r2.5.2'
|
||||
compile 'com.github.bumptech.glide:glide:3.7.0'
|
||||
compile 'joda-time:joda-time:2.9.9'
|
||||
compile 'org.joda:joda-convert:1.8'
|
||||
|
||||
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
|
||||
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
|
||||
compile 'com.squareup.retrofit2:retrofit:2.2.0'
|
||||
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
|
||||
compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
|
||||
|
||||
compile 'com.github.satyan:sugar:1.4'
|
||||
compile 'com.jakewharton:butterknife:8.5.1'
|
||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
|
||||
|
||||
debugCompile 'com.facebook.stetho:stetho:1.4.2'
|
||||
debugCompile 'com.facebook.stetho:stetho-okhttp:1.4.2'
|
||||
debugCompile 'com.facebook.stetho:stetho-okhttp3:1.4.2'
|
||||
|
||||
androidTestCompile('com.android.support.test:rules:0.5') {
|
||||
exclude module: 'support-annotations'
|
||||
}
|
||||
androidTestCompile('com.android.support.test:runner:0.5') {
|
||||
exclude module: 'support-annotations'
|
||||
}
|
||||
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3'
|
||||
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
|
||||
androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.6.0'
|
||||
//androidTestCompile group: 'commons-io', name: 'commons-io', version: '2.4'
|
||||
testCompile 'org.mockito:mockito-core:1.10.19'
|
||||
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
}
|
||||
}
|
||||
|
||||
|
36
app/proguard-rules.pro
vendored
|
@ -1,36 +0,0 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /opt/android-sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
# Platform used when running on Java 8 VMs. Will not be used at runtime.
|
||||
-dontwarn retrofit2.Platform$Java8
|
||||
# Retain generic type information for use by reflection by converters and adapters.
|
||||
-keepattributes Signature
|
||||
# Retain declared checked exceptions for use by a Proxy instance.
|
||||
-keepattributes Exceptions
|
||||
-dontwarn javax.annotation.**
|
||||
-dontwarn sun.misc.Unsafe
|
||||
-dontwarn okio.**
|
||||
-keep class de.nicidienase.chaosflix.shared.entities.** { *; }
|
||||
#retrofit
|
||||
-dontwarn retrofit2.**
|
||||
-keep class retrofit2.** { *; }
|
||||
-keepattributes *Annotation*,Signature, Exceptions
|
||||
|
||||
-keepclasseswithmembers class * {
|
||||
@retrofit2.http.* <methods>;
|
||||
}
|
||||
#endRetrofit
|
|
@ -1,58 +0,0 @@
|
|||
package de.nicidienase.chaosflix;
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
import android.support.test.rule.ActivityTestRule;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.support.test.uiautomator.UiDevice;
|
||||
import android.test.suitebuilder.annotation.LargeTest;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import de.nicidienase.chaosflix.test.R;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import de.nicidienase.chaosflix.leanback.activities.ConferencesActivity;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
|
||||
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ConferencesActivityTest {
|
||||
|
||||
@Rule
|
||||
public ActivityTestRule<ConferencesActivity> mActivityTestRule
|
||||
= new ActivityTestRule<>(ConferencesActivity.class, false, false);
|
||||
private static MockWebServer server;
|
||||
private UiDevice mDevice;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException, TimeoutException {
|
||||
mDevice = UiDevice.getInstance(getInstrumentation());
|
||||
|
||||
server = new MockWebServer();
|
||||
server.start();
|
||||
String serverUrl = server.url("").toString();
|
||||
|
||||
server.enqueue(TestHelper.getResponseForRaw(R.raw.conferences_json));
|
||||
server.enqueue(TestHelper.getResponseForRaw(R.raw.conferences_101_33c3_json));
|
||||
|
||||
Intent i = new Intent();
|
||||
i.putExtra("server_url",serverUrl);
|
||||
mActivityTestRule.launchActivity(i);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void conferencesActivityTest() throws InterruptedException {
|
||||
mDevice.pressDPadRight();
|
||||
mDevice.pressDPadRight();
|
||||
mDevice.pressDPadCenter();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
package de.nicidienase.chaosflix;
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.rule.ServiceTestRule;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import de.nicidienase.chaosflix.test.R;
|
||||
import de.nicidienase.chaosflix.shared.network.MediaApiService;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
|
||||
import static junit.framework.Assert.fail;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
|
||||
/**
|
||||
* Created by felix on 17.03.17.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MediaApiServiceTest {
|
||||
|
||||
@ClassRule
|
||||
public static final ServiceTestRule mServiceRule = new ServiceTestRule();
|
||||
|
||||
private static final String TAG = MediaApiServiceTest.class.getSimpleName();
|
||||
private static MockWebServer server;
|
||||
private static String serverUrl;
|
||||
private static MediaApiService service;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws IOException, TimeoutException {
|
||||
server = new MockWebServer();
|
||||
server.start();
|
||||
serverUrl = server.url("").toString();
|
||||
|
||||
Intent s = new Intent(InstrumentationRegistry.getTargetContext(),
|
||||
MediaApiService.class);
|
||||
s.putExtra(MediaApiService.RECORDING_URL,serverUrl);
|
||||
s.putExtra(MediaApiService.STREAMING_URL,serverUrl);
|
||||
IBinder binder = mServiceRule.bindService(s);
|
||||
service = ((MediaApiService.LocalBinder) binder).getService();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup(){
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getConferenceTest() throws IOException {
|
||||
server.enqueue(TestHelper.getResponseForRaw(R.raw.conferences_101_33c3_json));
|
||||
|
||||
service.getConference(101)
|
||||
.doOnError(throwable -> fail())
|
||||
.blockingSubscribe
|
||||
(conference -> assertThat(conference.getAcronym(),is("33c3")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sortAllEvents() throws IOException {
|
||||
server.enqueue(TestHelper.getResponseForRaw(R.raw.events_json));
|
||||
|
||||
service.getEvents()
|
||||
.doOnError(throwable -> fail())
|
||||
.blockingSubscribe(events -> Collections.sort(events));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getEventTest() throws IOException {
|
||||
server.enqueue(TestHelper.getResponseForRaw(R.raw.events_2837_json));
|
||||
|
||||
service.getEvent(2837)
|
||||
.doOnError(throwable -> fail())
|
||||
.blockingSubscribe(
|
||||
event -> assertThat(event.getGuid(), is("9f2e9ff0-1555-470b-8743-9f07f54e9097")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStreamingConferences() throws IOException {
|
||||
server.enqueue(TestHelper.getResponseForRaw(R.raw.streams_v2_json));
|
||||
|
||||
service.getStreamingConferences()
|
||||
.doOnError(throwable -> fail())
|
||||
.blockingSubscribe(liveConferences -> assertThat(1,is(liveConferences.size())));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() throws IOException {
|
||||
server.enqueue(TestHelper.getResponseForRaw(R.raw.streams_v2_json));
|
||||
|
||||
service.getStreamingConferences()
|
||||
.doOnError(throwable -> fail())
|
||||
.blockingSubscribe(liveConferences -> assertThat("FOSSGIS 2017",is(liveConferences.get(0).getConference())));
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package de.nicidienase.chaosflix;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
|
||||
import okhttp3.mockwebserver.Dispatcher;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.RecordedRequest;
|
||||
|
||||
/**
|
||||
* Created by felix on 25.03.17.
|
||||
*/
|
||||
public class TestHelper {
|
||||
|
||||
static String getStringFromRaw(int resourceID) throws IOException {
|
||||
InputStream inputStream = InstrumentationRegistry
|
||||
.getContext().getResources().openRawResource(resourceID);
|
||||
StringWriter writer = new StringWriter();
|
||||
IOUtils.copy(inputStream, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
static MockResponse getResponseForRaw(int resourceID) throws IOException {
|
||||
return new MockResponse().setBody(
|
||||
getStringFromRaw(resourceID));
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{"acronym":"mrmcd101b","aspect_ratio":"4:3","updated_at":"2015-12-30T12:39:19.125+01:00","title":"mrmcd101b","schedule_url":null,"slug":"conferences/mrmcd/mrmcd101b","webgen_location":"conferences/mrmcd/mrmcd101b","logo_url":"https://static.media.ccc.de/media/conferences/mrmcd/mrmcd101b/folder-mrmcd-2006.png","images_url":"https://static.media.ccc.de/media/conferences/mrmcd/mrmcd101b","recordings_url":"http://cdn.media.ccc.de/events/mrmcd/mrmcd101b","url":"https://api.media.ccc.de/public/conferences/13","events":[]}
|
|
@ -1 +0,0 @@
|
|||
{"acronym":"18c3","aspect_ratio":"4:3","updated_at":"2015-12-30T12:39:22.463+01:00","title":"18C3: Hacking Is Not A Crime","schedule_url":null,"slug":"congress/2001","webgen_location":"congress/2001","logo_url":"https://static.media.ccc.de/media/congress/2001/folder-18c3.png","images_url":"https://static.media.ccc.de/media/congress/2001","recordings_url":"http://cdn.media.ccc.de/congress/2001","url":"https://api.media.ccc.de/public/conferences/21","events":[{"guid":"import-86dcc5d427d763434f","title":"Final","subtitle":null,"slug":"18c3_final_divx","link":"http://ccc.de","description":"\n","original_language":"eng","persons":[],"tags":["18c3"],"date":"2001-01-01T01:00:00.000+01:00","release_date":"2008-01-01","updated_at":"2017-03-24T22:45:05.035+01:00","length":259,"thumb_url":"https://static.media.ccc.de/media/congress/2001/creative/18c3_final_divx.jpg","poster_url":"https://static.media.ccc.de/media/congress/2001/creative/18c3_final_divx_preview.jpg","frontend_link":"https://media.ccc.de/v/18c3_final_divx","url":"https://api.media.ccc.de/public/events/709","conference_url":"https://api.media.ccc.de/public/conferences/21"},{"guid":"import-996ee6767784dc2e88","title":"Blinkenlights ISDN","subtitle":null,"slug":"Blinkenlights_isdn","link":"http://ccc.de","description":"\n","original_language":"eng","persons":[],"tags":["blinkenlights"," 18c3"],"date":"2001-01-01T01:00:00.000+01:00","release_date":"2008-01-01","updated_at":"2017-03-24T11:45:06.628+01:00","length":4771,"thumb_url":"https://static.media.ccc.de/media/congress/2001/video/vortraege/tag2/saal2/Blinkenlights_isdn.jpg","poster_url":"https://static.media.ccc.de/media/congress/2001/video/vortraege/tag2/saal2/Blinkenlights_isdn_preview.jpg","frontend_link":"https://media.ccc.de/v/Blinkenlights_isdn","url":"https://api.media.ccc.de/public/events/710","conference_url":"https://api.media.ccc.de/public/conferences/21"}]}
|
|
@ -1 +0,0 @@
|
|||
{"guid":"f30baa0f-e541-4dc7-88cb-c6617efe659d","title":"From USA to DE.","subtitle":"A safe place for US hackers","slug":"gpn16-7677-from_usa_to_de","link":"https://entropia.de/GPN16:Fahrplan:XML?action=raw","description":"An overview of the possibilities US citisens have to live in Germany.\n","original_language":"eng","persons":["Sarah"],"tags":[],"date":"2016-05-26T20:00:00.000+02:00","release_date":"2016-05-27","updated_at":"2017-02-24T16:45:06.321+01:00","length":2267,"thumb_url":"https://static.media.ccc.de/media/events/gpn/gpn16/7677-hd.jpg","poster_url":"https://static.media.ccc.de/media/events/gpn/gpn16/7677-hd_preview.jpg","frontend_link":"https://media.ccc.de/v/gpn16-7677-from_usa_to_de","url":"https://api.media.ccc.de/public/events/3062","conference_url":"https://api.media.ccc.de/public/conferences/85","recordings":[{"size":28,"length":2261,"mime_type":"audio/opus","language":"eng","filename":"gpn16-7677-eng-From_USA_to_DE.opus","state":"new","folder":"opus","high_quality":false,"width":0,"height":0,"updated_at":"2016-05-29T02:35:04.442+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/opus/gpn16-7677-eng-From_USA_to_DE.opus","url":"https://api.media.ccc.de/public/recordings/10684","event_url":"https://api.media.ccc.de/public/events/3062","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":231,"length":2267,"mime_type":"video/mp4","language":"eng","filename":"gpn16-7677-eng-From_USA_to_DE_hd.mp4","state":"new","folder":"h264-hd","high_quality":true,"width":1920,"height":1080,"updated_at":"2016-05-28T21:26:18.554+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/h264-hd/gpn16-7677-eng-From_USA_to_DE_hd.mp4","url":"https://api.media.ccc.de/public/recordings/10618","event_url":"https://api.media.ccc.de/public/events/3062","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":34,"length":2261,"mime_type":"audio/mpeg","language":"eng","filename":"gpn16-7677-eng-From_USA_to_DE.mp3","state":"new","folder":"mp3","high_quality":false,"width":0,"height":0,"updated_at":"2016-05-29T02:35:30.027+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/mp3/gpn16-7677-eng-From_USA_to_DE.mp3","url":"https://api.media.ccc.de/public/recordings/10685","event_url":"https://api.media.ccc.de/public/events/3062","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":78,"length":2267,"mime_type":"video/webm","language":"eng","filename":"gpn16-7677-eng-From_USA_to_DE_webm-sd.webm","state":"new","folder":"webm-sd","high_quality":false,"width":720,"height":576,"updated_at":"2016-05-29T02:36:04.124+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/webm-sd/gpn16-7677-eng-From_USA_to_DE_webm-sd.webm","url":"https://api.media.ccc.de/public/recordings/10686","event_url":"https://api.media.ccc.de/public/events/3062","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":292,"length":2267,"mime_type":"video/webm","language":"eng","filename":"gpn16-7677-eng-From_USA_to_DE_webm-hd.webm","state":"new","folder":"webm-hd","high_quality":true,"width":1920,"height":1080,"updated_at":"2016-05-29T02:37:37.853+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/webm-hd/gpn16-7677-eng-From_USA_to_DE_webm-hd.webm","url":"https://api.media.ccc.de/public/recordings/10688","event_url":"https://api.media.ccc.de/public/events/3062","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":74,"length":2267,"mime_type":"video/mp4","language":"eng","filename":"gpn16-7677-eng-From_USA_to_DE_sd.mp4","state":"new","folder":"h264-sd","high_quality":false,"width":720,"height":576,"updated_at":"2016-05-29T02:38:17.634+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/h264-sd/gpn16-7677-eng-From_USA_to_DE_sd.mp4","url":"https://api.media.ccc.de/public/recordings/10689","event_url":"https://api.media.ccc.de/public/events/3062","conference_url":"https://api.media.ccc.de/public/conferences/85"}]}
|
|
@ -1 +0,0 @@
|
|||
{"guid":"7b59ca9e-7c40-4942-be90-2fd9acfea55b","title":"OSPAC","subtitle":"Open Source Podcast Audio Chain","slug":"gpn16-7675-ospac","link":"https://entropia.de/GPN16:Fahrplan:XML?action=raw","description":"Mit der Open-Source-Software Ospac kann man Mehrkanal-Aufnahmen für einen Podcast in veröffentlichbare Audio-Dateien abmischen. ","original_language":"deu","persons":["Sebastian Ritterbusch"],"tags":[],"date":"2016-05-26T21:30:00.000+02:00","release_date":"2016-05-27","updated_at":"2017-03-24T10:00:06.767+01:00","length":3306,"thumb_url":"https://static.media.ccc.de/media/events/gpn/gpn16/7675-hd.jpg","poster_url":"https://static.media.ccc.de/media/events/gpn/gpn16/7675-hd_preview.jpg","frontend_link":"https://media.ccc.de/v/gpn16-7675-ospac","url":"https://api.media.ccc.de/public/events/3066","conference_url":"https://api.media.ccc.de/public/conferences/85","recordings":[{"size":541,"length":3306,"mime_type":"video/mp4","language":"deu","filename":"gpn16-7675-deu-OSPAC_hd.mp4","state":"new","folder":"h264-hd","high_quality":true,"width":1920,"height":1080,"updated_at":"2016-05-27T02:28:51.224+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/h264-hd/gpn16-7675-deu-OSPAC_hd.mp4","url":"https://api.media.ccc.de/public/recordings/10477","event_url":"https://api.media.ccc.de/public/events/3066","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":159,"length":3306,"mime_type":"video/webm","language":"deu","filename":"gpn16-7675-deu-OSPAC_webm-sd.webm","state":"new","folder":"webm-sd","high_quality":false,"width":720,"height":576,"updated_at":"2016-05-27T14:17:36.490+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/webm-sd/gpn16-7675-deu-OSPAC_webm-sd.webm","url":"https://api.media.ccc.de/public/recordings/10486","event_url":"https://api.media.ccc.de/public/events/3066","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":50,"length":3300,"mime_type":"audio/mpeg","language":"deu","filename":"gpn16-7675-deu-OSPAC.mp3","state":"new","folder":"mp3","high_quality":false,"width":0,"height":0,"updated_at":"2016-05-27T14:18:08.501+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/mp3/gpn16-7675-deu-OSPAC.mp3","url":"https://api.media.ccc.de/public/recordings/10487","event_url":"https://api.media.ccc.de/public/events/3066","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":42,"length":3300,"mime_type":"audio/opus","language":"deu","filename":"gpn16-7675-deu-OSPAC.opus","state":"new","folder":"opus","high_quality":false,"width":0,"height":0,"updated_at":"2016-05-27T14:14:24.605+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/opus/gpn16-7675-deu-OSPAC.opus","url":"https://api.media.ccc.de/public/recordings/10484","event_url":"https://api.media.ccc.de/public/events/3066","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":145,"length":3306,"mime_type":"video/mp4","language":"deu","filename":"gpn16-7675-deu-OSPAC_sd.mp4","state":"new","folder":"h264-sd","high_quality":false,"width":720,"height":576,"updated_at":"2016-05-27T14:16:07.606+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/h264-sd/gpn16-7675-deu-OSPAC_sd.mp4","url":"https://api.media.ccc.de/public/recordings/10485","event_url":"https://api.media.ccc.de/public/events/3066","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":507,"length":3306,"mime_type":"video/webm","language":"deu","filename":"gpn16-7675-deu-OSPAC_webm-hd.webm","state":"new","folder":"webm-hd","high_quality":true,"width":1920,"height":1080,"updated_at":"2016-05-27T14:13:52.563+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/webm-hd/gpn16-7675-deu-OSPAC_webm-hd.webm","url":"https://api.media.ccc.de/public/recordings/10483","event_url":"https://api.media.ccc.de/public/events/3066","conference_url":"https://api.media.ccc.de/public/conferences/85"}]}
|
|
@ -1 +0,0 @@
|
|||
{"guid":"b2bc162c-1745-4f45-ba56-766b4174095b","title":"Run your own fucking infrastructure","subtitle":"Why you should consider running your own shit","slug":"gpn16-7582-run_your_own_fucking_infrastructure","link":"https://entropia.de/GPN16:Fahrplan:XML?action=raw","description":null,"original_language":"deu","persons":["mc.fly"],"tags":[],"date":"2016-05-29T13:15:00.000+02:00","release_date":"2016-05-29","updated_at":"2017-03-24T14:45:04.540+01:00","length":3505,"thumb_url":"https://static.media.ccc.de/media/events/gpn/gpn16/7582-hd.jpg","poster_url":"https://static.media.ccc.de/media/events/gpn/gpn16/7582-hd_preview.jpg","frontend_link":"https://media.ccc.de/v/gpn16-7582-run_your_own_fucking_infrastructure","url":"https://api.media.ccc.de/public/events/3104","conference_url":"https://api.media.ccc.de/public/conferences/85","recordings":[{"size":590,"length":3505,"mime_type":"video/mp4","language":"deu","filename":"gpn16-7582-deu-Run_your_own_fucking_infrastructure_hd.mp4","state":"new","folder":"h264-hd","high_quality":true,"width":1920,"height":1080,"updated_at":"2016-05-29T16:19:48.040+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/h264-hd/gpn16-7582-deu-Run_your_own_fucking_infrastructure_hd.mp4","url":"https://api.media.ccc.de/public/recordings/10726","event_url":"https://api.media.ccc.de/public/events/3104","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":144,"length":3505,"mime_type":"video/webm","language":"deu","filename":"gpn16-7582-deu-Run_your_own_fucking_infrastructure_webm-sd.webm","state":"new","folder":"webm-sd","high_quality":false,"width":720,"height":576,"updated_at":"2016-06-02T20:28:37.637+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/webm-sd/gpn16-7582-deu-Run_your_own_fucking_infrastructure_webm-sd.webm","url":"https://api.media.ccc.de/public/recordings/10736","event_url":"https://api.media.ccc.de/public/events/3104","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":537,"length":3505,"mime_type":"video/webm","language":"deu","filename":"gpn16-7582-deu-Run_your_own_fucking_infrastructure_webm-hd.webm","state":"new","folder":"webm-hd","high_quality":true,"width":1920,"height":1080,"updated_at":"2016-06-02T20:33:18.238+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/webm-hd/gpn16-7582-deu-Run_your_own_fucking_infrastructure_webm-hd.webm","url":"https://api.media.ccc.de/public/recordings/10738","event_url":"https://api.media.ccc.de/public/events/3104","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":53,"length":3499,"mime_type":"audio/mpeg","language":"deu","filename":"gpn16-7582-deu-Run_your_own_fucking_infrastructure.mp3","state":"new","folder":"mp3","high_quality":false,"width":0,"height":0,"updated_at":"2016-05-29T16:26:01.895+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/mp3/gpn16-7582-deu-Run_your_own_fucking_infrastructure.mp3","url":"https://api.media.ccc.de/public/recordings/10728","event_url":"https://api.media.ccc.de/public/events/3104","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":136,"length":3505,"mime_type":"video/mp4","language":"deu","filename":"gpn16-7582-deu-Run_your_own_fucking_infrastructure_sd.mp4","state":"new","folder":"h264-sd","high_quality":false,"width":720,"height":576,"updated_at":"2016-05-29T16:31:11.730+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/h264-sd/gpn16-7582-deu-Run_your_own_fucking_infrastructure_sd.mp4","url":"https://api.media.ccc.de/public/recordings/10730","event_url":"https://api.media.ccc.de/public/events/3104","conference_url":"https://api.media.ccc.de/public/conferences/85"},{"size":47,"length":3499,"mime_type":"audio/opus","language":"deu","filename":"gpn16-7582-deu-Run_your_own_fucking_infrastructure.opus","state":"new","folder":"opus","high_quality":false,"width":0,"height":0,"updated_at":"2016-05-29T16:26:33.792+02:00","recording_url":"http://cdn.media.ccc.de/events/gpn/gpn16/opus/gpn16-7582-deu-Run_your_own_fucking_infrastructure.opus","url":"https://api.media.ccc.de/public/recordings/10729","event_url":"https://api.media.ccc.de/public/events/3104","conference_url":"https://api.media.ccc.de/public/conferences/85"}]}
|
|
@ -1 +0,0 @@
|
|||
{"guid":"import-86dcc5d427d763434f","title":"Final","subtitle":null,"slug":"18c3_final_divx","link":"http://ccc.de","description":"\n","original_language":"eng","persons":[],"tags":["18c3"],"date":"2001-01-01T01:00:00.000+01:00","release_date":"2008-01-01","updated_at":"2017-03-24T22:45:05.035+01:00","length":259,"thumb_url":"https://static.media.ccc.de/media/congress/2001/creative/18c3_final_divx.jpg","poster_url":"https://static.media.ccc.de/media/congress/2001/creative/18c3_final_divx_preview.jpg","frontend_link":"https://media.ccc.de/v/18c3_final_divx","url":"https://api.media.ccc.de/public/events/709","conference_url":"https://api.media.ccc.de/public/conferences/21","recordings":[{"size":null,"length":259,"mime_type":"video/mp4","language":"eng","filename":"18c3_final_divx.mp4","state":"downloaded","folder":"mp4","high_quality":true,"width":360,"height":280,"updated_at":"2016-01-27T11:03:09.279+01:00","recording_url":"http://cdn.media.ccc.de/congress/2001/mp4/18c3_final_divx.mp4","url":"https://api.media.ccc.de/public/recordings/4207","event_url":"https://api.media.ccc.de/public/events/709","conference_url":"https://api.media.ccc.de/public/conferences/21"}]}
|
|
@ -1 +0,0 @@
|
|||
{"guid":"import-996ee6767784dc2e88","title":"Blinkenlights ISDN","subtitle":null,"slug":"Blinkenlights_isdn","link":"http://ccc.de","description":"\n","original_language":"eng","persons":[],"tags":["blinkenlights"," 18c3"],"date":"2001-01-01T01:00:00.000+01:00","release_date":"2008-01-01","updated_at":"2017-03-24T11:45:06.628+01:00","length":4771,"thumb_url":"https://static.media.ccc.de/media/congress/2001/video/vortraege/tag2/saal2/Blinkenlights_isdn.jpg","poster_url":"https://static.media.ccc.de/media/congress/2001/video/vortraege/tag2/saal2/Blinkenlights_isdn_preview.jpg","frontend_link":"https://media.ccc.de/v/Blinkenlights_isdn","url":"https://api.media.ccc.de/public/events/710","conference_url":"https://api.media.ccc.de/public/conferences/21","recordings":[{"size":null,"length":4771,"mime_type":"video/mp4","language":"eng","filename":"Blinkenlights_isdn.mp4","state":"downloaded","folder":"video/vortraege/tag2/saal2","high_quality":false,"width":192,"height":144,"updated_at":"2016-02-03T14:06:10.016+01:00","recording_url":"http://cdn.media.ccc.de/congress/2001/video/vortraege/tag2/saal2/Blinkenlights_isdn.mp4","url":"https://api.media.ccc.de/public/recordings/4303","event_url":"https://api.media.ccc.de/public/events/710","conference_url":"https://api.media.ccc.de/public/conferences/21"}]}
|
|
@ -1,948 +0,0 @@
|
|||
[
|
||||
{
|
||||
"conference": "32C3",
|
||||
"group": "Lecture Rooms",
|
||||
"rooms": [
|
||||
{
|
||||
"slug": "hall1",
|
||||
"schedulename": "Hall 1",
|
||||
"thumb": "https://streaming.media.ccc.de/32c3/../thumbs/s1.png",
|
||||
"link": "https://streaming.media.ccc.de/32c3/hall1/",
|
||||
"display": "Hall 1",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "hd-native",
|
||||
"display": "Hall 1 FullHD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 2.8 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s1_native_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s1_native_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "hd-translated",
|
||||
"display": "Hall 1 FullHD Video (Translation)",
|
||||
"type": "video",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 2.8 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s1_translated_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s1_translated_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-native",
|
||||
"display": "Hall 1 SD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s1_native_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s1_native_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-translated",
|
||||
"display": "Hall 1 SD Video (Translation)",
|
||||
"type": "video",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s1_translated_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s1_translated_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "slides-native",
|
||||
"display": "Hall 1 Slides",
|
||||
"type": "slides",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s1_native_slides.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s1_native_slides.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "slides-translated",
|
||||
"display": "Hall 1 Slides (Translation)",
|
||||
"type": "slides",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s1_translated_slides.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s1_translated_slides.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-native",
|
||||
"display": "Hall 1 Audio",
|
||||
"type": "audio",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s1_native.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s1_native.opus"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-translated",
|
||||
"display": "Hall 1 Audio (Translation)",
|
||||
"type": "audio",
|
||||
"isTranslated": true,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s1_translated.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s1_translated.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "hall2",
|
||||
"schedulename": "Hall 2",
|
||||
"thumb": "https://streaming.media.ccc.de/32c3/../thumbs/s2.png",
|
||||
"link": "https://streaming.media.ccc.de/32c3/hall2/",
|
||||
"display": "Hall 2",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "hd-native",
|
||||
"display": "Hall 2 FullHD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 2.8 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s2_native_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s2_native_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "hd-translated",
|
||||
"display": "Hall 2 FullHD Video (Translation)",
|
||||
"type": "video",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 2.8 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s2_translated_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s2_translated_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-native",
|
||||
"display": "Hall 2 SD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s2_native_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s2_native_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-translated",
|
||||
"display": "Hall 2 SD Video (Translation)",
|
||||
"type": "video",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s2_translated_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s2_translated_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "slides-native",
|
||||
"display": "Hall 2 Slides",
|
||||
"type": "slides",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s2_native_slides.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s2_native_slides.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "slides-translated",
|
||||
"display": "Hall 2 Slides (Translation)",
|
||||
"type": "slides",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s2_translated_slides.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s2_translated_slides.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-native",
|
||||
"display": "Hall 2 Audio",
|
||||
"type": "audio",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s2_native.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s2_native.opus"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-translated",
|
||||
"display": "Hall 2 Audio (Translation)",
|
||||
"type": "audio",
|
||||
"isTranslated": true,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s2_translated.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s2_translated.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "hallg",
|
||||
"schedulename": "Hall G",
|
||||
"thumb": "https://streaming.media.ccc.de/32c3/../thumbs/s3.png",
|
||||
"link": "https://streaming.media.ccc.de/32c3/hallg/",
|
||||
"display": "Hall G",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "hd-native",
|
||||
"display": "Hall G FullHD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 2.8 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s3_native_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s3_native_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "hd-translated",
|
||||
"display": "Hall G FullHD Video (Translation)",
|
||||
"type": "video",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 2.8 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s3_translated_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s3_translated_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-native",
|
||||
"display": "Hall G SD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s3_native_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s3_native_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-translated",
|
||||
"display": "Hall G SD Video (Translation)",
|
||||
"type": "video",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s3_translated_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s3_translated_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "slides-native",
|
||||
"display": "Hall G Slides",
|
||||
"type": "slides",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s3_native_slides.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s3_native_slides.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "slides-translated",
|
||||
"display": "Hall G Slides (Translation)",
|
||||
"type": "slides",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s3_translated_slides.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s3_translated_slides.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-native",
|
||||
"display": "Hall G Audio",
|
||||
"type": "audio",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s3_native.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s3_native.opus"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-translated",
|
||||
"display": "Hall G Audio (Translation)",
|
||||
"type": "audio",
|
||||
"isTranslated": true,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s3_translated.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s3_translated.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "hall6",
|
||||
"schedulename": "Hall 6",
|
||||
"thumb": "https://streaming.media.ccc.de/32c3/../thumbs/s4.png",
|
||||
"link": "https://streaming.media.ccc.de/32c3/hall6/",
|
||||
"display": "Hall 6",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "hd-native",
|
||||
"display": "Hall 6 FullHD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 2.8 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s4_native_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "hd-translated",
|
||||
"display": "Hall 6 FullHD Video (Translation)",
|
||||
"type": "video",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 2.8 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_translated_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s4_translated_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-native",
|
||||
"display": "Hall 6 SD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s4_native_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-translated",
|
||||
"display": "Hall 6 SD Video (Translation)",
|
||||
"type": "video",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_translated_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s4_translated_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "slides-native",
|
||||
"display": "Hall 6 Slides",
|
||||
"type": "slides",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native_slides.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s4_native_slides.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "slides-translated",
|
||||
"display": "Hall 6 Slides (Translation)",
|
||||
"type": "slides",
|
||||
"isTranslated": true,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_translated_slides.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, XXX kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s4_translated_slides.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-native",
|
||||
"display": "Hall 6 Audio",
|
||||
"type": "audio",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native.opus"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-translated",
|
||||
"display": "Hall 6 Audio (Translation)",
|
||||
"type": "audio",
|
||||
"isTranslated": true,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_translated.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_translated.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conference": "32C3",
|
||||
"group": "Live Music",
|
||||
"rooms": [
|
||||
{
|
||||
"slug": "lounge",
|
||||
"schedulename": "lounge",
|
||||
"thumb": "https://streaming.media.ccc.de/32c3/../thumbs/lounge.png",
|
||||
"link": "https://streaming.media.ccc.de/32c3/lounge/",
|
||||
"display": "Lounge",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "music-native",
|
||||
"display": "Lounge Radio",
|
||||
"type": "music",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 192 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/lounge.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/lounge.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "ambient",
|
||||
"schedulename": "ambient",
|
||||
"thumb": "https://streaming.media.ccc.de/32c3/../thumbs/ambient.png",
|
||||
"link": "https://streaming.media.ccc.de/32c3/ambient/",
|
||||
"display": "Ambient",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "music-native",
|
||||
"display": "Ambient Radio",
|
||||
"type": "music",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 192 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/ambient.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/ambient.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "dome",
|
||||
"schedulename": "dome",
|
||||
"thumb": "https://streaming.media.ccc.de/32c3/../thumbs/dome.png",
|
||||
"link": "https://streaming.media.ccc.de/32c3/dome/",
|
||||
"display": "Dome",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "music-native",
|
||||
"display": "Dome Radio",
|
||||
"type": "music",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 192 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/dome.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/dome.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "chaos-west",
|
||||
"schedulename": "chaos-west",
|
||||
"thumb": "https://streaming.media.ccc.de/32c3/../thumbs/chaos-west.png",
|
||||
"link": "https://streaming.media.ccc.de/32c3/chaos-west/",
|
||||
"display": "Chaos-West",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "music-native",
|
||||
"display": "Chaos-West Radio",
|
||||
"type": "music",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 192 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/chaos-west.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/chaos-west.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conference": "32C3",
|
||||
"group": "Live Podcasts",
|
||||
"rooms": [
|
||||
{
|
||||
"slug": "sendezentrum",
|
||||
"schedulename": "Bühne",
|
||||
"thumb": "https://streaming.media.ccc.de/32c3/../thumbs/s5.png",
|
||||
"link": "https://streaming.media.ccc.de/32c3/sendezentrum/",
|
||||
"display": "Sendezentrum",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "hd-stereo",
|
||||
"display": "Sendezentrum FullHD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 2.8 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s5_stereo_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s5_stereo_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-stereo",
|
||||
"display": "Sendezentrum SD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s5_stereo_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s5_stereo_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-stereo",
|
||||
"display": "Sendezentrum Audio",
|
||||
"type": "audio",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s5_stereo.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s5_stereo.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "podcastertisch",
|
||||
"schedulename": "Podcaster-Tisch",
|
||||
"thumb": "https://streaming.media.ccc.de/32c3/../thumbs/podcastertisch.png",
|
||||
"link": "https://streaming.media.ccc.de/32c3/podcastertisch/",
|
||||
"display": "Sendezentrum - Podcastertisch",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "music-native",
|
||||
"display": "Sendezentrum - Podcastertisch Radio",
|
||||
"type": "music",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 192 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/podcastertisch.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/podcastertisch.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -1,186 +0,0 @@
|
|||
[
|
||||
{
|
||||
"conference": "Easterhegg 2017",
|
||||
"group": "Für die Glupscher",
|
||||
"rooms": [
|
||||
{
|
||||
"slug": "vortragssaal",
|
||||
"schedulename": "Vortragssaal",
|
||||
"thumb": "http://streaming.media.ccc.de/thumbs/s6.png",
|
||||
"link": "http://streaming.media.ccc.de/eh17/vortragssaal",
|
||||
"display": "Vortragssaal",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "hd-native",
|
||||
"display": "Vortragssaal FullHD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 3.5 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s6_native_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s6_native_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-native",
|
||||
"display": "Vortragssaal SD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 1 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s6_native_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s6_native_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-native",
|
||||
"display": "Vortragssaal Audio",
|
||||
"type": "audio",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s6_native.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s6_native.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "grosses-kolleg",
|
||||
"schedulename": "Großes Kolleg",
|
||||
"thumb": "http://streaming.media.ccc.de/thumbs/s4.png",
|
||||
"link": "http://streaming.media.ccc.de/eh17/grosses-kolleg",
|
||||
"display": "Großes Kolleg",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "hd-native",
|
||||
"display": "Großes Kolleg FullHD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 3.5 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s4_native_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-native",
|
||||
"display": "Großes Kolleg SD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 1 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s4_native_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-native",
|
||||
"display": "Großes Kolleg Audio",
|
||||
"type": "audio",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"conference": "Easterhegg 2017",
|
||||
"group": "Auf die Lauscher",
|
||||
"rooms": [
|
||||
{
|
||||
"slug": "lounge",
|
||||
"schedulename": "Lounge",
|
||||
"thumb": "http://streaming.media.ccc.de/thumbs/lounge.png",
|
||||
"link": "http://streaming.media.ccc.de/eh17/lounge",
|
||||
"display": "Lounge",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "music-native",
|
||||
"display": "Lounge Radio",
|
||||
"type": "music",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 192 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/lounge.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/lounge.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -1,195 +0,0 @@
|
|||
[
|
||||
{
|
||||
"conference": "Easterhegg 2017",
|
||||
"slug": "eh17",
|
||||
"author": "Easterhegg, you know!",
|
||||
"description": "Ist das Zufall oder kann das weg?",
|
||||
"keywords": "Easterhegg, Ostern, Hack, CCC, Zufall, Mühlheim, Video, Streaming, Live, Livestream",
|
||||
"startsAt": "2017-04-14T11:30:00+0000",
|
||||
"endsAt": "2017-04-17T14:30:00+0000",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Für die Glupscher",
|
||||
"rooms": [
|
||||
{
|
||||
"slug": "vortragssaal",
|
||||
"schedulename": "Vortragssaal",
|
||||
"thumb": "http://streaming.media.ccc.de/thumbs/s6.png",
|
||||
"link": "http://streaming.media.ccc.de/eh17/vortragssaal",
|
||||
"display": "Vortragssaal",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "hd-native",
|
||||
"display": "Vortragssaal FullHD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 3.5 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s6_native_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s6_native_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-native",
|
||||
"display": "Vortragssaal SD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 1 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s6_native_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s6_native_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-native",
|
||||
"display": "Vortragssaal Audio",
|
||||
"type": "audio",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s6_native.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s6_native.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "grosses-kolleg",
|
||||
"schedulename": "Großes Kolleg",
|
||||
"thumb": "http://streaming.media.ccc.de/thumbs/s4.png",
|
||||
"link": "http://streaming.media.ccc.de/eh17/grosses-kolleg",
|
||||
"display": "Großes Kolleg",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "hd-native",
|
||||
"display": "Großes Kolleg FullHD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 3.5 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native_hd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s4_native_hd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-native",
|
||||
"display": "Großes Kolleg SD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 1 MBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native_sd.webm"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/hls/s4_native_sd.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-native",
|
||||
"display": "Großes Kolleg Audio",
|
||||
"type": "audio",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/s4_native.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Auf die Lauscher",
|
||||
"rooms": [
|
||||
{
|
||||
"slug": "lounge",
|
||||
"schedulename": "Lounge",
|
||||
"thumb": "http://streaming.media.ccc.de/thumbs/lounge.png",
|
||||
"link": "http://streaming.media.ccc.de/eh17/lounge",
|
||||
"display": "Lounge",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "music-native",
|
||||
"display": "Lounge Radio",
|
||||
"type": "music",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 192 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/lounge.mp3"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 96 kBit/s",
|
||||
"url": "http://cdn.c3voc.de/lounge.opus"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -1,234 +0,0 @@
|
|||
[
|
||||
{
|
||||
"conference": "FOSSGIS 2017",
|
||||
"slug": "fossgis17",
|
||||
"author": "FOSSGIS e.V.",
|
||||
"description": "Die FOSSGIS-Konferenz ist im D-A-CH Raum die führende Konferenz für Freie und Open Source Software für Geoinformationssysteme OpenStreetMap.",
|
||||
"keywords": "FOSSGIS, FOSSGIS-Konferenz, 2017, FOSSGIS-Konferenz 2017, Open Source, GIS, Konferenz, Geoinformatik, OpenStreetMap, Passau, Video, Streaming, Live, Livestream",
|
||||
"startsAt": "2017-03-22T08:30:00+0000",
|
||||
"endsAt": "2017-03-25T14:00:00+0000",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Lecture Rooms",
|
||||
"rooms": [
|
||||
{
|
||||
"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",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 3.5 MBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.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://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-native",
|
||||
"display": "AM HS 9 Audio",
|
||||
"type": "audio",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "IM-HS-11",
|
||||
"schedulename": "IM HS 11",
|
||||
"thumb": "https://streaming.media.ccc.de/thumbs/s4.png",
|
||||
"link": "https://streaming.media.ccc.de/fossgis17/IM-HS-11",
|
||||
"display": "IM-HS-11",
|
||||
"streams": [
|
||||
{
|
||||
"slug": "hd-native",
|
||||
"display": "IM-HS-11 FullHD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1920,
|
||||
1080
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1920x1080, VP8+Vorbis in WebM, 3.5 MBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "sd-native",
|
||||
"display": "IM-HS-11 SD Video",
|
||||
"type": "video",
|
||||
"isTranslated": false,
|
||||
"videoSize": [
|
||||
1024,
|
||||
576
|
||||
],
|
||||
"urls": {
|
||||
"webm": {
|
||||
"display": "WebM",
|
||||
"tech": "1024x576, VP8+Vorbis in WebM, 1 MBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"slug": "audio-native",
|
||||
"display": "IM-HS-11 Audio",
|
||||
"type": "audio",
|
||||
"isTranslated": false,
|
||||
"videoSize": null,
|
||||
"urls": {
|
||||
"mp3": {
|
||||
"display": "MP3",
|
||||
"tech": "MP3-Audio, 96 kBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "IM-HS-13",
|
||||
"schedulename": "IM HS 13",
|
||||
"thumb": "https://streaming.media.ccc.de/thumbs/s5.png",
|
||||
"link": "https://streaming.media.ccc.de/fossgis17/IM-HS-13",
|
||||
"display": "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, VP8+Vorbis in WebM, 3.5 MBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.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://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
},
|
||||
"hls": {
|
||||
"display": "HLS",
|
||||
"tech": "1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.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://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
},
|
||||
"opus": {
|
||||
"display": "Opus",
|
||||
"tech": "Opus-Audio, 64 kBit/s",
|
||||
"url": "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -1,31 +0,0 @@
|
|||
package de.nicidienase.chaosflix;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.support.multidex.MultiDex;
|
||||
|
||||
import com.orm.SugarContext;
|
||||
|
||||
/**
|
||||
* Created by felix on 18.03.17.
|
||||
*/
|
||||
|
||||
public class ChaosflixApplication extends Application {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
SugarContext.init(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTerminate() {
|
||||
SugarContext.terminate();
|
||||
super.onTerminate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
MultiDex.install(base);
|
||||
super.attachBaseContext(base);
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="de.nicidienase.chaosflix"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false"/>
|
||||
<uses-feature
|
||||
android:name="android.software.leanback"
|
||||
android:required="true"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:name=".ChaosflixApplication">
|
||||
<activity
|
||||
android:name=".leanback.activities.ConferencesActivity"
|
||||
android:banner="@drawable/banner"
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name"
|
||||
android:logo="@drawable/icon"
|
||||
android:theme="@style/Theme.Leanback"
|
||||
android:screenOrientation="landscape">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".touch.activities.ConferencesActivity"
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Base.Theme.AppCompat.Light">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".leanback.activities.EventsActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Leanback"/>
|
||||
<activity android:name=".leanback.activities.EventDetailsActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Leanback"/>
|
||||
<activity android:name=".leanback.activities.DetailsActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Leanback"/>
|
||||
<activity android:name=".leanback.activities.PlayerActivity"
|
||||
android:theme="@style/Theme.Leanback"/>
|
||||
<service android:name=".shared.network.MediaApiService"/>
|
||||
|
||||
<meta-data android:name="DATABASE" android:value="mediaccc.db" />
|
||||
<meta-data android:name="VERSION" android:value="4" />
|
||||
<meta-data android:name="QUERY_LOG" android:value="false" />
|
||||
<meta-data android:name="DOMAIN_PACKAGE_NAME" android:value="de.nicidienase.chaosflix" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package de.nicidienase.chaosflix.leanback;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v17.leanback.widget.ImageCardView;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Conference;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Event;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.LiveConference;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.Room;
|
||||
|
||||
/*
|
||||
* A CardPresenter is used to generate Views and bind Objects to them on demand.
|
||||
* It contains an Image CardView
|
||||
*/
|
||||
public class CardPresenter extends Presenter {
|
||||
private static final String TAG = "CardPresenter";
|
||||
|
||||
private static final int CARD_WIDTH = 313;
|
||||
private static final int CARD_HEIGHT_4 = 235;
|
||||
private static final int CARD_HEIGHT_16 = 177;
|
||||
private static int sSelectedBackgroundColor;
|
||||
private static int sDefaultBackgroundColor;
|
||||
private Drawable mDefaultCardImage;
|
||||
|
||||
private static void updateCardBackgroundColor(ImageCardView view, boolean selected) {
|
||||
int color = selected ? sSelectedBackgroundColor : sDefaultBackgroundColor;
|
||||
// Both background colors should be set because the view's background is temporarily visible
|
||||
// during animations.
|
||||
view.setBackgroundColor(color);
|
||||
view.findViewById(R.id.info_field).setBackgroundColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
sDefaultBackgroundColor = parent.getResources().getColor(R.color.default_background);
|
||||
sSelectedBackgroundColor = parent.getResources().getColor(R.color.selected_background);
|
||||
mDefaultCardImage = parent.getResources().getDrawable(R.drawable.default_background);
|
||||
|
||||
ImageCardView cardView = new ImageCardView(parent.getContext()) {
|
||||
@Override
|
||||
public void setSelected(boolean selected) {
|
||||
updateCardBackgroundColor(this, selected);
|
||||
super.setSelected(selected);
|
||||
}
|
||||
};
|
||||
|
||||
cardView.setFocusable(true);
|
||||
cardView.setFocusableInTouchMode(true);
|
||||
updateCardBackgroundColor(cardView, false);
|
||||
return new ViewHolder(cardView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
|
||||
ImageCardView cardView = (ImageCardView) viewHolder.view;
|
||||
cardView.setMainImageScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
if (item instanceof Conference) {
|
||||
cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT_4);
|
||||
Conference conference = (Conference) item;
|
||||
cardView.setTitleText(conference.getTitle());
|
||||
cardView.setContentText(conference.getAcronym());
|
||||
if (conference.getLogoUrl() != null) {
|
||||
|
||||
Glide.with(viewHolder.view.getContext())
|
||||
.load(conference.getLogoUrl())
|
||||
.fitCenter()
|
||||
.error(mDefaultCardImage)
|
||||
.into(cardView.getMainImageView());
|
||||
}
|
||||
} else if (item instanceof Event) {
|
||||
cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT_16);
|
||||
Event event = (Event) item;
|
||||
cardView.setTitleText(event.getTitle());
|
||||
cardView.setContentText(event.getSubtitle());
|
||||
// cardView.setContentText(android.text.TextUtils.join(", ",event.getPersons()));
|
||||
if (event.getThumbUrl() != null) {
|
||||
Glide.with(viewHolder.view.getContext())
|
||||
.load(event.getThumbUrl())
|
||||
.fitCenter()
|
||||
.error(mDefaultCardImage)
|
||||
.into(cardView.getMainImageView());
|
||||
}
|
||||
} else if (item instanceof LiveConference) {
|
||||
cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT_4);
|
||||
LiveConference con = (LiveConference) item;
|
||||
cardView.setTitleText(con.getConference());
|
||||
cardView.setMainImage(mDefaultCardImage);
|
||||
cardView.setContentText(con.getDescription());
|
||||
} else if (item instanceof Room) {
|
||||
cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT_16);
|
||||
Room room = (Room) item;
|
||||
cardView.setTitleText(room.getDisplay());
|
||||
cardView.setContentText(room.getShedulename());
|
||||
if (room.getThumb() != null) {
|
||||
Glide.with(viewHolder.view.getContext())
|
||||
.load(room.getThumb())
|
||||
.fitCenter()
|
||||
.error(mDefaultCardImage)
|
||||
.into(cardView.getMainImageView());
|
||||
}
|
||||
} else if(item instanceof String) {
|
||||
cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT_4);
|
||||
cardView.setTitleText((String) item);
|
||||
Glide.with(viewHolder.view.getContext())
|
||||
.load(R.drawable.icon)
|
||||
.into(cardView.getMainImageView());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
|
||||
ImageCardView cardView = (ImageCardView) viewHolder.view;
|
||||
// Remove references to images so that the garbage collector can free up memory
|
||||
cardView.setBadgeImage(null);
|
||||
cardView.setMainImage(null);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Event;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.Room;
|
||||
|
||||
/**
|
||||
* Created by felix on 18.03.17.
|
||||
*/
|
||||
|
||||
public class EventDetailsDescriptionPresenter extends Presenter {
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public EventDetailsDescriptionPresenter(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
View view = LayoutInflater.from(mContext).inflate(R.layout.detail_view_content, null);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder vh, Object item) {
|
||||
TextView titleText = ButterKnife.findById(vh.view, R.id.title_text);
|
||||
TextView speakersText = ButterKnife.findById(vh.view, R.id.speakers_text);
|
||||
TextView subtitleText = ButterKnife.findById(vh.view, R.id.subtitle_text);
|
||||
TextView descriptionText = ButterKnife.findById(vh.view, R.id.description_text);
|
||||
if (item instanceof Event) {
|
||||
Event event = (Event) item;
|
||||
|
||||
titleText.setText(event.getTitle());
|
||||
subtitleText.setText(event.getSubtitle());
|
||||
String speaker = TextUtils.join(", ", event.getPersons());
|
||||
speakersText.setText(speaker);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(event.getDescription())
|
||||
.append("\n")
|
||||
.append("\nreleased at: ").append(event.getReleaseDate())
|
||||
.append("\nTags: ").append(android.text.TextUtils.join(", ", event.getTags()));
|
||||
descriptionText.setText(sb.toString());
|
||||
} else if (item instanceof Room) {
|
||||
Room room = (Room) item;
|
||||
titleText.setText(room.getDisplay());
|
||||
subtitleText.setText(room.getShedulename());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnbindViewHolder(ViewHolder viewHolder) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v17.leanback.widget.HeaderItem;
|
||||
import android.support.v17.leanback.widget.ListRow;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.support.v17.leanback.widget.RowHeaderPresenter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import de.nicidienase.chaosflix.R;
|
||||
|
||||
/**
|
||||
* Created by felix on 16.04.17.
|
||||
*/
|
||||
|
||||
public class HeaderItemPresenter extends RowHeaderPresenter {
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
LayoutInflater inflater = (LayoutInflater) parent.getContext()
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View view = inflater.inflate(R.layout.header_item_layout, null);
|
||||
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
|
||||
HeaderItem headerItem = ((ListRow) item).getHeaderItem();
|
||||
View view = viewHolder.view;
|
||||
ImageView headerIcon = (ImageView) view.findViewById(R.id.header_icon);
|
||||
TextView headerLabel = (TextView) view.findViewById(R.id.header_label);
|
||||
|
||||
Resources resources = view.getContext().getResources();
|
||||
String streamingPrefix = resources.getString(R.string.streaming_prefix);
|
||||
if (headerItem.getName().startsWith(streamingPrefix)) {
|
||||
Drawable camIcon = resources.getDrawable(R.drawable.ic_videocam_white_24dp);
|
||||
headerIcon.setImageDrawable(camIcon);
|
||||
((ListRow) item).setHeaderItem(new HeaderItem(headerItem.getName()
|
||||
.substring(streamingPrefix.length())));
|
||||
} else {
|
||||
Drawable movieIcon = resources.getDrawable(R.drawable.ic_local_movies_white_24dp);
|
||||
headerIcon.setImageDrawable(movieIcon);
|
||||
headerLabel.setText(headerItem.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v17.leanback.widget.ImageCardView;
|
||||
import android.support.v17.leanback.widget.OnItemViewClickedListener;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.support.v17.leanback.widget.Row;
|
||||
import android.support.v17.leanback.widget.RowPresenter;
|
||||
import android.support.v4.app.ActivityOptionsCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import de.nicidienase.chaosflix.leanback.activities.DetailsActivity;
|
||||
import de.nicidienase.chaosflix.leanback.activities.EventDetailsActivity;
|
||||
import de.nicidienase.chaosflix.leanback.activities.EventsActivity;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Conference;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Event;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.Room;
|
||||
|
||||
/**
|
||||
* Created by felix on 21.03.17.
|
||||
*/
|
||||
public class ItemViewClickedListener implements OnItemViewClickedListener {
|
||||
|
||||
private static final String TAG = ItemViewClickedListener.class.getSimpleName();
|
||||
private Fragment fragment;
|
||||
|
||||
public ItemViewClickedListener(Fragment fragment) {
|
||||
this.fragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
|
||||
RowPresenter.ViewHolder rowViewHolder, Row row) {
|
||||
Log.d(TAG, "onItemClicked");
|
||||
if (item instanceof Conference) {
|
||||
Conference conference = (Conference) item;
|
||||
// Start EventsActivity for this conference
|
||||
Intent i = new Intent(fragment.getActivity(), EventsActivity.class);
|
||||
i.putExtra(EventsActivity.CONFERENCE, conference);
|
||||
i.putExtra(EventsActivity.CONFERENCE_ID, conference.getApiID());
|
||||
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
|
||||
fragment.getActivity(),
|
||||
((ImageCardView) itemViewHolder.view).getMainImageView(),
|
||||
EventsActivity.SHARED_ELEMENT_NAME).toBundle();
|
||||
fragment.startActivity(i, bundle);
|
||||
} else if (item instanceof Event) {
|
||||
Event event = (Event) item;
|
||||
Intent i = new Intent(fragment.getActivity(), DetailsActivity.class);
|
||||
i.putExtra(DetailsActivity.TYPE, DetailsActivity.TYPE_RECORDING);
|
||||
i.putExtra(DetailsActivity.EVENT, event);
|
||||
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
|
||||
fragment.getActivity(),
|
||||
((ImageCardView) itemViewHolder.view).getMainImageView(),
|
||||
EventDetailsActivity.SHARED_ELEMENT_NAME).toBundle();
|
||||
fragment.getActivity().startActivity(i, bundle);
|
||||
} else if (item instanceof Room) {
|
||||
Room room = (Room) item;
|
||||
Intent i = new Intent(fragment.getActivity(), DetailsActivity.class);
|
||||
i.putExtra(DetailsActivity.TYPE, DetailsActivity.TYPE_STREAM);
|
||||
i.putExtra(DetailsActivity.ROOM, room);
|
||||
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
|
||||
fragment.getActivity(),
|
||||
((ImageCardView) itemViewHolder.view).getMainImageView(),
|
||||
EventDetailsActivity.SHARED_ELEMENT_NAME).toBundle();
|
||||
fragment.getActivity().startActivity(i, bundle);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,338 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback;
|
||||
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.MediaMetadata;
|
||||
import android.media.session.MediaController;
|
||||
import android.media.session.PlaybackState;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v17.leanback.app.PlaybackControlGlue;
|
||||
import android.support.v17.leanback.widget.Action;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
|
||||
import android.support.v17.leanback.widget.OnActionClickedListener;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
|
||||
import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
|
||||
import android.util.Log;
|
||||
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Event;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Recording;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.Room;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.StreamUrl;
|
||||
import de.nicidienase.chaosflix.leanback.fragments.OverlayFragment;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
/**
|
||||
* Created by felix on 26.03.17.
|
||||
*/
|
||||
|
||||
public class PlaybackHelper extends PlaybackControlGlue {
|
||||
|
||||
private static final int[] SEEK_SPEEDS = {2, 4, 8, 16};
|
||||
private static final int DEFAULT_UPDATE_PERIOD = 500;
|
||||
private static final int UPDATE_PERIOD = 16;
|
||||
private static final String TAG = PlaybackHelper.class.getSimpleName();
|
||||
private Disposable thumbDisposable;
|
||||
private OverlayFragment.PlaybackControlListener mControlListener;
|
||||
private BitmapDrawable mDrawable = null;
|
||||
private Room room;
|
||||
private StreamUrl stream;
|
||||
private OverlayFragment fragment;
|
||||
private Event event;
|
||||
private Recording recording;
|
||||
private Runnable mUpdateProgressRunnable;
|
||||
private Handler mHandler = new Handler();
|
||||
|
||||
PlaybackControlsRow.PlayPauseAction mPlayPauseAction;
|
||||
PlaybackControlsRow.FastForwardAction mFastForwardAction;
|
||||
PlaybackControlsRow.RewindAction mRewindAction;
|
||||
PlaybackControlsRow.SkipNextAction mSkipNextAction;
|
||||
PlaybackControlsRow.SkipPreviousAction mSkipPreviousAction;
|
||||
private OverlayFragment.PlaybackControlListener mCallback;
|
||||
|
||||
private MediaController mMediaController;
|
||||
private MediaController.TransportControls mTransportControls;
|
||||
private ArrayObjectAdapter adapter;
|
||||
|
||||
public PlaybackHelper(Context context, OverlayFragment fragment, Event event, Recording recording) {
|
||||
super(context, SEEK_SPEEDS);
|
||||
mControlListener = (OverlayFragment.PlaybackControlListener) context;
|
||||
this.fragment = fragment;
|
||||
this.event = event;
|
||||
this.recording = recording;
|
||||
// thumbDisposable = Observable.fromCallable(() ->
|
||||
// new BitmapDrawable(
|
||||
// fragment.getResources(),
|
||||
// Glide.with(getContext())
|
||||
// .load(event.getThumbUrl())
|
||||
// .asBitmap()
|
||||
// .into(-1, -1)
|
||||
// .get()))
|
||||
// .subscribeOn(Schedulers.io())
|
||||
// .observeOn(AndroidSchedulers.mainThread())
|
||||
// .doOnError(Throwable::printStackTrace)
|
||||
// .subscribe(bitmapDrawable -> mDrawable = bitmapDrawable);
|
||||
|
||||
setup();
|
||||
}
|
||||
|
||||
public PlaybackHelper(Context context, OverlayFragment fragment, Room room, StreamUrl stream) {
|
||||
super(context, SEEK_SPEEDS);
|
||||
mControlListener = (OverlayFragment.PlaybackControlListener) context;
|
||||
this.fragment = fragment;
|
||||
this.room = room;
|
||||
this.stream = stream;
|
||||
|
||||
setup();
|
||||
}
|
||||
|
||||
private void setup() {
|
||||
mMediaController = fragment.getActivity().getMediaController();
|
||||
if (mMediaController != null) {
|
||||
mTransportControls = mMediaController.getTransportControls();
|
||||
} else {
|
||||
Log.d(TAG, "Could not get MediaController");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
|
||||
PlaybackControlsRowPresenter presenter = super.createControlsRowAndPresenter();
|
||||
adapter = new ArrayObjectAdapter(new ControlButtonPresenterSelector());
|
||||
getControlsRow().setSecondaryActionsAdapter(adapter);
|
||||
|
||||
mFastForwardAction = (PlaybackControlsRow.FastForwardAction) getPrimaryActionsAdapter()
|
||||
.lookup(ACTION_FAST_FORWARD);
|
||||
|
||||
mRewindAction = (PlaybackControlsRow.RewindAction) getPrimaryActionsAdapter()
|
||||
.lookup(ACTION_REWIND);
|
||||
|
||||
presenter.setOnActionClickedListener(new OnActionClickedListener() {
|
||||
@Override
|
||||
public void onActionClicked(Action action) {
|
||||
dispatchAction(action);
|
||||
}
|
||||
});
|
||||
return presenter;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
public void dispatchAction(Action action) {
|
||||
if (action instanceof PlaybackControlsRow.MultiAction) {
|
||||
PlaybackControlsRow.MultiAction multiAction = (PlaybackControlsRow.MultiAction) action;
|
||||
multiAction.nextIndex();
|
||||
notifyActionChanged(multiAction);
|
||||
}
|
||||
if (action == mFastForwardAction) {
|
||||
mTransportControls.fastForward();
|
||||
} else if (action == mRewindAction) {
|
||||
mTransportControls.rewind();
|
||||
} else {
|
||||
super.onActionClicked(action);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyActionChanged(PlaybackControlsRow.MultiAction multiAction) {
|
||||
int index;
|
||||
index = getPrimaryActionsAdapter().indexOf(multiAction);
|
||||
if (index >= 0) {
|
||||
getPrimaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
|
||||
} else {
|
||||
index = getSecondaryActionsAdapter().indexOf(multiAction);
|
||||
if (index >= 0) {
|
||||
getSecondaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableProgressUpdating(boolean enable) {
|
||||
mHandler.removeCallbacks(mUpdateProgressRunnable);
|
||||
if (enable) {
|
||||
mHandler.post(mUpdateProgressRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProgress() {
|
||||
if (mUpdateProgressRunnable == null) {
|
||||
mUpdateProgressRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int totalTime = getControlsRow().getTotalTime();
|
||||
long currentPosition = mControlListener.getCurrentPosition();
|
||||
getControlsRow().setCurrentTimeLong(currentPosition);
|
||||
|
||||
long bufferedPosition = mControlListener.getBufferedPosition();
|
||||
getControlsRow().setBufferedProgressLong(bufferedPosition);
|
||||
|
||||
if (totalTime > 0 && totalTime <= currentPosition) {
|
||||
stopProgressAnimation();
|
||||
} else {
|
||||
updateProgress();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
mHandler.postDelayed(mUpdateProgressRunnable, getUpdatePeriod());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasValidMedia() {
|
||||
return mediaIsRecording() || mediaIsStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMediaPlaying() {
|
||||
return mControlListener.isMediaPlaying();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getMediaTitle() {
|
||||
if (mediaIsRecording()) {
|
||||
return event.getTitle();
|
||||
}
|
||||
if (mediaIsStream()) {
|
||||
return room.getDisplay();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getMediaSubtitle() {
|
||||
if (mediaIsRecording()) {
|
||||
return event.getSubtitle();
|
||||
}
|
||||
if (mediaIsStream()) {
|
||||
return stream.getDisplay();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMediaDuration() {
|
||||
if (mediaIsRecording()) {
|
||||
return event.getLength() * 1000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getMediaArt() {
|
||||
return mDrawable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startPlayback(int speed) {
|
||||
if (getCurrentSpeedId() == speed) {
|
||||
return;
|
||||
}
|
||||
if (mTransportControls != null) {
|
||||
mTransportControls.play();
|
||||
} else {
|
||||
mControlListener.play();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void pausePlayback() {
|
||||
if (mTransportControls != null) {
|
||||
mTransportControls.pause();
|
||||
} else {
|
||||
mControlListener.pause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void skipToNext() {
|
||||
mTransportControls.skipToNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void skipToPrevious() {
|
||||
mTransportControls.skipToPrevious();
|
||||
}
|
||||
|
||||
private void stopProgressAnimation() {
|
||||
if (mHandler != null && mUpdateProgressRunnable != null) {
|
||||
mHandler.removeCallbacks(mUpdateProgressRunnable);
|
||||
mUpdateProgressRunnable = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSupportedActions() {
|
||||
return ACTION_PLAY_PAUSE | ACTION_FAST_FORWARD | ACTION_REWIND | ACTION_SKIP_TO_PREVIOUS |
|
||||
ACTION_SKIP_TO_NEXT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentSpeedId() {
|
||||
return isMediaPlaying() ? PLAYBACK_SPEED_NORMAL : PLAYBACK_SPEED_PAUSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentPosition() {
|
||||
if (mControlListener != null) {
|
||||
return (int) mControlListener.getCurrentPosition();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long getCurrentPositionLong() {
|
||||
if (mControlListener != null) {
|
||||
return mControlListener.getCurrentPosition();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private boolean mediaIsStream() {
|
||||
return (room != null && stream != null);
|
||||
}
|
||||
|
||||
private boolean mediaIsRecording() {
|
||||
return (event != null && recording != null);
|
||||
}
|
||||
|
||||
public MediaController.Callback createMediaControllerCallback() {
|
||||
return new ChaosflixMediaControllerCallback();
|
||||
}
|
||||
|
||||
private SparseArrayObjectAdapter getPrimaryActionsAdapter() {
|
||||
return (SparseArrayObjectAdapter) getControlsRow().getPrimaryActionsAdapter();
|
||||
}
|
||||
|
||||
private ArrayObjectAdapter getSecondaryActionsAdapter() {
|
||||
return (ArrayObjectAdapter) getControlsRow().getSecondaryActionsAdapter();
|
||||
}
|
||||
|
||||
private class ChaosflixMediaControllerCallback extends MediaController.Callback {
|
||||
|
||||
@Override
|
||||
public void onPlaybackStateChanged(@NonNull PlaybackState state) {
|
||||
if (state.getState() != PlaybackState.STATE_NONE) {
|
||||
updateProgress();
|
||||
}
|
||||
onStateChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMetadataChanged(@Nullable MediaMetadata metadata) {
|
||||
PlaybackHelper.this.onMetadataChanged();
|
||||
PlaybackHelper.this.adapter.notifyArrayItemRangeChanged(0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void onStop() {
|
||||
if (thumbDisposable != null) {
|
||||
thumbDisposable.dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.ChaosflixBaseActivity;
|
||||
|
||||
/**
|
||||
* Created by felix on 18.03.17.
|
||||
*/
|
||||
|
||||
public class ConferencesActivity extends ChaosflixBaseActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// setContentView(R.layout.activity_conferences_grid);
|
||||
setContentView(R.layout.activity_conferences_browse);
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package de.nicidienase.chaosflix.leanback.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.ChaosflixBaseActivity;
|
||||
|
||||
/*
|
||||
* Details activity class that loads LeanbackDetailsFragment class
|
||||
*/
|
||||
public class DetailsActivity extends ChaosflixBaseActivity {
|
||||
|
||||
public static final String SHARED_ELEMENT_NAME = "hero";
|
||||
public static final String EVENT = "event";
|
||||
public static final String ROOM = "room";
|
||||
public static final String STREAM_URL = "stream_url";
|
||||
public static final String RECORDING = "recording";
|
||||
public static final String TYPE = "event_type";
|
||||
public static final int TYPE_RECORDING = 0;
|
||||
public static final int TYPE_STREAM = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_event_details);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.PersistableBundle;
|
||||
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.ChaosflixBaseActivity;
|
||||
|
||||
/**
|
||||
* Created by felix on 18.03.17.
|
||||
*/
|
||||
|
||||
public class EventDetailsActivity extends ChaosflixBaseActivity {
|
||||
|
||||
public static final String EVENT = "event";
|
||||
public static final String SHARED_ELEMENT_NAME = "transision_element";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
|
||||
super.onCreate(savedInstanceState, persistentState);
|
||||
setContentView(R.layout.activity_event_details);
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.ChaosflixBaseActivity;
|
||||
|
||||
public class EventsActivity extends ChaosflixBaseActivity {
|
||||
|
||||
public static final String CONFERENCE_ID = "conference_id";
|
||||
public static final String CONFERENCE = "conference";
|
||||
public static final String SHARED_ELEMENT_NAME = "shared_element";
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
|
@ -1,327 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback.activities;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||
import com.google.android.exoplayer2.LoadControl;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.source.dash.DashMediaSource;
|
||||
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
|
||||
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
|
||||
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.leanback.fragments.OverlayFragment;
|
||||
import de.nicidienase.chaosflix.shared.ChaosflixBaseActivity;
|
||||
|
||||
/**
|
||||
* Created by felix on 26.03.17.
|
||||
*/
|
||||
|
||||
public class PlayerActivity extends ChaosflixBaseActivity
|
||||
implements OverlayFragment.PlaybackControlListener {
|
||||
|
||||
private static final String TAG = PlayerActivity.class.getSimpleName();
|
||||
@BindView(R.id.videoView)
|
||||
SurfaceView mSurfaceView;
|
||||
@BindView(R.id.loading_player)
|
||||
ProgressBar loadingSpinner;
|
||||
OverlayFragment mPlaybackControllFragment;
|
||||
private DefaultBandwidthMeter bandwidthMeter;
|
||||
private SimpleExoPlayer player;
|
||||
private String mUserAgent;
|
||||
|
||||
private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
|
||||
private Handler mainHandler;
|
||||
private DefaultTrackSelector trackSelector;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_playback);
|
||||
ButterKnife.bind(this);
|
||||
mSurfaceView.setKeepScreenOn(true);
|
||||
|
||||
mPlaybackControllFragment = (OverlayFragment) getFragmentManager().findFragmentById(R.id.playback_controls_fragment);
|
||||
|
||||
mUserAgent = Util.getUserAgent(this, getResources().getString(R.string.app_name));
|
||||
synchronized (this) {
|
||||
if (player == null) {
|
||||
setupPlayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
showLoadingSpinner();
|
||||
// TODO get persisted playback progress
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
pause();
|
||||
// TODO persist playback progress
|
||||
}
|
||||
|
||||
private void setupPlayer() {
|
||||
mUserAgent = Util.getUserAgent(this, getResources().getString(R.string.app_name));
|
||||
|
||||
mainHandler = new Handler();
|
||||
bandwidthMeter = new DefaultBandwidthMeter();
|
||||
TrackSelection.Factory videoTrackSelectionFactory
|
||||
= new AdaptiveTrackSelection.Factory(bandwidthMeter);
|
||||
trackSelector
|
||||
= new DefaultTrackSelector(videoTrackSelectionFactory);
|
||||
LoadControl loadControl = new DefaultLoadControl();
|
||||
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
|
||||
player.setVideoSurfaceView(mSurfaceView);
|
||||
|
||||
player.setVideoListener(new SimpleExoPlayer.VideoListener() {
|
||||
@Override
|
||||
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRenderedFirstFrame() {
|
||||
hideLoadingSpinner();
|
||||
}
|
||||
});
|
||||
player.addListener(new ExoPlayer.EventListener() {
|
||||
@Override
|
||||
public void onTimelineChanged(Timeline timeline, Object manifest) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadingChanged(boolean isLoading) {
|
||||
if(isLoading && player.getPlaybackState() != ExoPlayer.STATE_READY){
|
||||
showLoadingSpinner();
|
||||
} else{
|
||||
hideLoadingSpinner();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
|
||||
switch (playbackState){
|
||||
case ExoPlayer.STATE_BUFFERING:
|
||||
if(player.isLoading()){
|
||||
showLoadingSpinner();
|
||||
}
|
||||
break;
|
||||
case ExoPlayer.STATE_ENDED:
|
||||
Log.d(TAG,"Finished Playback");
|
||||
finish();
|
||||
break;
|
||||
case ExoPlayer.STATE_IDLE:
|
||||
case ExoPlayer.STATE_READY:
|
||||
default:
|
||||
hideLoadingSpinner();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeatModeChanged(int repeatMode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerError(ExoPlaybackException error) {
|
||||
String errorMessage = error.getCause().getMessage();
|
||||
Toast.makeText(PlayerActivity.this,errorMessage,Toast.LENGTH_SHORT).show();
|
||||
Log.d(TAG,errorMessage,error);
|
||||
PlayerActivity.this.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionDiscontinuity() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showLoadingSpinner() {
|
||||
loadingSpinner.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void hideLoadingSpinner(){
|
||||
loadingSpinner.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVideoSource(String source) {
|
||||
Log.d(TAG, "Source: " + source);
|
||||
synchronized (this) {
|
||||
if (player == null) {
|
||||
setupPlayer();
|
||||
}
|
||||
}
|
||||
MediaSource mediaSource = buildMediaSource(Uri.parse(source), "");
|
||||
player.prepare(mediaSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void play() {
|
||||
player.setPlayWhenReady(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
player.setPlayWhenReady(false);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playPause() {
|
||||
player.setPlayWhenReady(!player.getPlayWhenReady());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekTo(long sec) {
|
||||
player.seekTo(sec * 1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMediaPlaying() {
|
||||
if (player != null) {
|
||||
return player.getPlayWhenReady();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCurrentPosition() {
|
||||
if (player != null) {
|
||||
return player.getCurrentPosition();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releasePlayer() {
|
||||
if (player != null) {
|
||||
player.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBufferedPosition() {
|
||||
if (player != null) {
|
||||
return player.getBufferedPosition();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mute(boolean state) {
|
||||
if (player != null) {
|
||||
player.setVolume(state ? 0.0f : 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
if (player != null) {
|
||||
return player.getDuration();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextAudioStream() {
|
||||
// TODO cycle through audio streams
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skipForward(int sec) {
|
||||
player.seekTo(player.getCurrentPosition() + (sec * 1000));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skipBackward(int sec) {
|
||||
player.seekTo(player.getCurrentPosition() - (sec * 1000));
|
||||
}
|
||||
|
||||
private MediaSource buildMediaSource(Uri uri, String overrideExtension) {
|
||||
DataSource.Factory mediaDataSourceFactory = buildDataSourceFactory(true);
|
||||
int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(uri)
|
||||
: Util.inferContentType("." + overrideExtension);
|
||||
switch (type) {
|
||||
case C.TYPE_SS:
|
||||
return new SsMediaSource(uri, buildDataSourceFactory(false),
|
||||
new DefaultSsChunkSource.Factory(mediaDataSourceFactory), mainHandler, null);
|
||||
case C.TYPE_DASH:
|
||||
return new DashMediaSource(uri, buildDataSourceFactory(false),
|
||||
new DefaultDashChunkSource.Factory(mediaDataSourceFactory), mainHandler, null);
|
||||
case C.TYPE_HLS:
|
||||
return new HlsMediaSource(uri, mediaDataSourceFactory, mainHandler, null);
|
||||
case C.TYPE_OTHER:
|
||||
return new ExtractorMediaSource(uri, mediaDataSourceFactory, new DefaultExtractorsFactory(),
|
||||
mainHandler, null);
|
||||
default: {
|
||||
throw new IllegalStateException("Unsupported type: " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DataSource.Factory buildDataSourceFactory(boolean useBandwidthMeter) {
|
||||
return buildDataSourceFactory(useBandwidthMeter ? BANDWIDTH_METER : null);
|
||||
}
|
||||
|
||||
private DataSource.Factory buildDataSourceFactory(DefaultBandwidthMeter bandwidthMeter) {
|
||||
return new DefaultDataSourceFactory(this, bandwidthMeter,
|
||||
buildHttpDataSourceFactory(bandwidthMeter));
|
||||
}
|
||||
|
||||
private HttpDataSource.Factory buildHttpDataSourceFactory(DefaultBandwidthMeter bandwidthMeter) {
|
||||
return new DefaultHttpDataSourceFactory(mUserAgent, bandwidthMeter);
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback.fragments;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v17.leanback.app.ErrorFragment;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import de.nicidienase.chaosflix.R;
|
||||
|
||||
/**
|
||||
* Created by felix on 22.03.17.
|
||||
*/
|
||||
|
||||
public class BrowseErrorFragment extends ErrorFragment {
|
||||
|
||||
private static final boolean TRANSLUCENT = true;
|
||||
public static final String FRAGMENT = "fragmentId";
|
||||
private SpinnerFragment mSpinnerFragment;
|
||||
|
||||
public static BrowseErrorFragment showErrorFragment(FragmentManager manager, int fragmentId) {
|
||||
BrowseErrorFragment errorFragment = new BrowseErrorFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(BrowseErrorFragment.FRAGMENT, fragmentId);
|
||||
errorFragment.setArguments(args);
|
||||
manager.beginTransaction().replace(fragmentId, errorFragment)
|
||||
.addToBackStack(null).commit();
|
||||
return errorFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
int fragmentId = getArguments().getInt(FRAGMENT);
|
||||
mSpinnerFragment = new SpinnerFragment();
|
||||
getFragmentManager().beginTransaction().add(fragmentId, mSpinnerFragment).commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
getFragmentManager().beginTransaction().remove(mSpinnerFragment).commit();
|
||||
}
|
||||
|
||||
public void setErrorContent(int resourceId) {
|
||||
setErrorContent(getResources().getString(resourceId));
|
||||
}
|
||||
|
||||
public void setErrorContent(String message) {
|
||||
setImageDrawable(getResources().getDrawable(R.drawable.lb_ic_sad_cloud, null));
|
||||
setMessage(message);
|
||||
setDefaultBackground(TRANSLUCENT);
|
||||
|
||||
setButtonText(getResources().getString(R.string.dismiss_error));
|
||||
setButtonClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
if (fragmentManager != null) {
|
||||
fragmentManager.beginTransaction().remove(BrowseErrorFragment.this).commit();
|
||||
fragmentManager.popBackStack();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class SpinnerFragment extends Fragment {
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
ProgressBar progressBar = new ProgressBar(container.getContext());
|
||||
if (container instanceof FrameLayout) {
|
||||
Resources res = getResources();
|
||||
int width = res.getDimensionPixelSize(R.dimen.spinner_width);
|
||||
int height = res.getDimensionPixelSize(R.dimen.spinner_height);
|
||||
FrameLayout.LayoutParams layoutParams =
|
||||
new FrameLayout.LayoutParams(width, height, Gravity.CENTER);
|
||||
progressBar.setLayoutParams(layoutParams);
|
||||
}
|
||||
return progressBar;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v17.leanback.app.BrowseFragment;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.HeaderItem;
|
||||
import android.support.v17.leanback.widget.ListRow;
|
||||
import android.support.v17.leanback.widget.ListRowPresenter;
|
||||
import android.support.v17.leanback.widget.SectionRow;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import de.nicidienase.chaosflix.BuildConfig;
|
||||
import de.nicidienase.chaosflix.leanback.CardPresenter;
|
||||
import de.nicidienase.chaosflix.leanback.ItemViewClickedListener;
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.ChaosflixBaseActivity;
|
||||
import de.nicidienase.chaosflix.shared.entities.WatchlistItem;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Conference;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.ConferencesWrapper;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.Group;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.LiveConference;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
/**
|
||||
* Created by felix on 21.03.17.
|
||||
*/
|
||||
|
||||
public class ConferencesBrowseFragment extends BrowseFragment {
|
||||
|
||||
private static final String TAG = ConferencesBrowseFragment.class.getSimpleName();
|
||||
public static final int FRAGMENT = R.id.browse_fragment;
|
||||
private ArrayObjectAdapter mRowsAdapter;
|
||||
private Map<String, List<Conference>> mConferences;
|
||||
CompositeDisposable mDisposables = new CompositeDisposable();
|
||||
private ArrayObjectAdapter watchListAdapter;
|
||||
private ListRow mWatchlistRow;
|
||||
private boolean streamsAvailable = false;
|
||||
private SectionRow mStreamingSection;
|
||||
private SectionRow mRecomendationsSectionsRow;
|
||||
private SectionRow mConferencesSection;
|
||||
private boolean mWatchlistVisible = false;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(getResources().getString(R.string.app_name));
|
||||
|
||||
// setHeaderPresenterSelector(new PresenterSelector() {
|
||||
// @Override
|
||||
// public Presenter getPresenter(Object item) {
|
||||
// return new HeaderItemPresenter();
|
||||
// }
|
||||
// });
|
||||
|
||||
final BrowseErrorFragment errorFragment =
|
||||
BrowseErrorFragment.showErrorFragment(getFragmentManager(), FRAGMENT);
|
||||
CardPresenter cardPresenter = new CardPresenter();
|
||||
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
|
||||
watchListAdapter = new ArrayObjectAdapter(cardPresenter);
|
||||
|
||||
Disposable disposable = ((ChaosflixBaseActivity) getActivity()).getApiServiceObservable()
|
||||
.subscribe(mediaApiService -> {
|
||||
mDisposables.add(Observable.zip(mediaApiService.getStreamingConferences(),
|
||||
mediaApiService.getConferences(),
|
||||
(liveConferences, conferencesWrapper) -> {
|
||||
ArrayList<Object> list = new ArrayList<>();
|
||||
list.add(liveConferences);
|
||||
list.add(conferencesWrapper);
|
||||
return list;
|
||||
})
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(objects -> {
|
||||
List<LiveConference> liveConferences = (List<LiveConference>) objects.get(0);
|
||||
ConferencesWrapper conferences = (ConferencesWrapper) objects.get(1);
|
||||
if (BuildConfig.DEBUG) {
|
||||
liveConferences.add(LiveConference.getDummyObject());
|
||||
}
|
||||
streamsAvailable = liveConferences.size() > 0;
|
||||
addStreams(cardPresenter, liveConferences);
|
||||
addRecordings(cardPresenter, conferences);
|
||||
errorFragment.dismiss();
|
||||
setOnItemViewClickedListener(new ItemViewClickedListener(this));
|
||||
setAdapter(mRowsAdapter);
|
||||
setSelectedPosition(1);
|
||||
}));
|
||||
});
|
||||
mDisposables.add(disposable);
|
||||
}
|
||||
|
||||
private void addRecordings(CardPresenter cardPresenter, ConferencesWrapper conferences) {
|
||||
mConferencesSection = new SectionRow(getString(R.string.conferences));
|
||||
mRowsAdapter.add(mConferencesSection);
|
||||
mConferences = conferences.getConferencesBySeries();
|
||||
Set<String> keySet = mConferences.keySet();
|
||||
for (String tag : ConferencesWrapper.getOrderedConferencesList()) {
|
||||
if (keySet.contains(tag)) {
|
||||
ListRow row = getRow(mConferences, cardPresenter, tag, "");
|
||||
mRowsAdapter.add(row);
|
||||
}
|
||||
}
|
||||
for (String tag : keySet) {
|
||||
if (!ConferencesWrapper.getOrderedConferencesList().contains(tag)) {
|
||||
mRowsAdapter.add(getRow(mConferences, cardPresenter, tag, ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addStreams(CardPresenter cardPresenter, List<LiveConference> liveConferences) {
|
||||
if (liveConferences.size() > 0) {
|
||||
HeaderItem streamingHeader = new HeaderItem(getString(R.string.livestreams));
|
||||
mStreamingSection = new SectionRow(streamingHeader);
|
||||
mRowsAdapter.add(0, mStreamingSection);
|
||||
for (LiveConference con : liveConferences) {
|
||||
int i = -1;
|
||||
for (i = 0; i < con.getGroups().size(); i++) {
|
||||
Group g = con.getGroups().get(i);
|
||||
// setup header
|
||||
String group = g.getGroup().length() > 0 ? g.getGroup() : con.getConference();
|
||||
HeaderItem header = new HeaderItem(group);
|
||||
header.setDescription(con.getConference() + " - " + con.getDescription());
|
||||
header.setContentDescription(group);
|
||||
// setup list
|
||||
ArrayObjectAdapter listRowAdapter
|
||||
= new ArrayObjectAdapter(cardPresenter);
|
||||
listRowAdapter.addAll(listRowAdapter.size(), g.getRooms());
|
||||
mRowsAdapter.add(i + 1, new ListRow(header, listRowAdapter));
|
||||
}
|
||||
// mRowsAdapter.add(i + 1, new DividerRow());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
List<WatchlistItem> watchlistItems
|
||||
= Lists.newArrayList(WatchlistItem.findAll(WatchlistItem.class));
|
||||
// setup and list items
|
||||
updateWatchlist(watchlistItems);
|
||||
}
|
||||
|
||||
private void showWatchlist() {
|
||||
if(mWatchlistRow == null && mRecomendationsSectionsRow == null){
|
||||
mRecomendationsSectionsRow = new SectionRow(getString(R.string.recomendations));
|
||||
HeaderItem header = new HeaderItem(getString(R.string.watchlist));
|
||||
mWatchlistRow = new ListRow(header, watchListAdapter);
|
||||
}
|
||||
int offset = getWatchlistOffset();
|
||||
if(!mWatchlistVisible){
|
||||
mRowsAdapter.add(offset, mRecomendationsSectionsRow);
|
||||
mRowsAdapter.add(offset + 1, mWatchlistRow);
|
||||
mWatchlistVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private Disposable updateWatchlist(List<WatchlistItem> watchlistItems) {
|
||||
return ((ChaosflixBaseActivity) getActivity()).getApiServiceObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(mediaApiService -> {
|
||||
showWatchlist();
|
||||
watchListAdapter.clear();
|
||||
if(watchlistItems.size() > 0){
|
||||
// int i = Math.max(0,mRowsAdapter.indexOf(mConferencesSection));
|
||||
// mRowsAdapter.add(i,mRecomendationsSectionsRow);
|
||||
// mRowsAdapter.add(i+1,watchListAdapter);
|
||||
Observable.fromIterable(watchlistItems)
|
||||
.flatMap(watchlistItem -> mediaApiService.getEvent(watchlistItem.getEventId()))
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(event -> watchListAdapter.add(event));
|
||||
} else {
|
||||
// watchListAdapter.add("Watchlist empty");
|
||||
hideWatchlist();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void hideWatchlist() {
|
||||
if(mWatchlistVisible){
|
||||
int i = mRowsAdapter.indexOf(mRecomendationsSectionsRow);
|
||||
mRowsAdapter.removeItems(i,2);
|
||||
mWatchlistVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private int getWatchlistOffset() {
|
||||
if(mRowsAdapter.size()>0 || streamsAvailable){
|
||||
int i = mRowsAdapter.indexOf(mConferencesSection);
|
||||
return Math.max(i,0);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mDisposables.dispose();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
private ListRow getRow(Map<String, List<Conference>> conferences, CardPresenter cardPresenter, String tag, String description) {
|
||||
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
|
||||
listRowAdapter.addAll(0, conferences.get(tag));
|
||||
HeaderItem header = new HeaderItem(ConferencesWrapper.getStringForTag(tag));
|
||||
header.setDescription(description);
|
||||
return new ListRow(header, listRowAdapter);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v17.leanback.app.VerticalGridFragment;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.VerticalGridPresenter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import de.nicidienase.chaosflix.leanback.CardPresenter;
|
||||
import de.nicidienase.chaosflix.leanback.ItemViewClickedListener;
|
||||
import de.nicidienase.chaosflix.shared.ChaosflixBaseActivity;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Conference;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
|
||||
/**
|
||||
* Created by felix on 20.03.17.
|
||||
*/
|
||||
|
||||
public class ConferencesGridFragment extends VerticalGridFragment {
|
||||
|
||||
private static final int NUM_COLUMNS = 5;
|
||||
private static final String TAG = ConferencesGridFragment.class.getSimpleName();
|
||||
private final ArrayObjectAdapter mConferenceAdapter =
|
||||
new ArrayObjectAdapter(new CardPresenter());
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
((ChaosflixBaseActivity) getActivity()).getApiServiceObservable()
|
||||
.subscribe(mediaApiService -> {
|
||||
mediaApiService.getConferences()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(conferences -> {
|
||||
List<Conference> conferenceList = conferences.getConferences();
|
||||
Collections.sort(conferenceList);
|
||||
Collections.reverse(conferenceList);
|
||||
mConferenceAdapter.addAll(0, conferenceList);
|
||||
setAdapter(mConferenceAdapter);
|
||||
});
|
||||
});
|
||||
setTitle("Chaosflix");
|
||||
|
||||
VerticalGridPresenter gridPresenter = new VerticalGridPresenter();
|
||||
gridPresenter.setNumberOfColumns(NUM_COLUMNS);
|
||||
setGridPresenter(gridPresenter);
|
||||
|
||||
// After 500ms, start the animation to transition the cards into view.
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
public void run() {
|
||||
startEntranceTransition();
|
||||
}
|
||||
}, 500);
|
||||
|
||||
setOnItemViewClickedListener(new ItemViewClickedListener(this));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,230 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package de.nicidienase.chaosflix.leanback.fragments;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v17.leanback.app.BackgroundManager;
|
||||
import android.support.v17.leanback.app.BrowseFragment;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.HeaderItem;
|
||||
import android.support.v17.leanback.widget.ListRow;
|
||||
import android.support.v17.leanback.widget.ListRowPresenter;
|
||||
import android.support.v17.leanback.widget.OnItemViewSelectedListener;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.support.v17.leanback.widget.Row;
|
||||
import android.support.v17.leanback.widget.RowPresenter;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
|
||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import de.nicidienase.chaosflix.leanback.CardPresenter;
|
||||
import de.nicidienase.chaosflix.leanback.ItemViewClickedListener;
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.ChaosflixBaseActivity;
|
||||
import de.nicidienase.chaosflix.leanback.activities.EventsActivity;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Conference;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Event;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
|
||||
public class EventsBrowseFragment extends BrowseFragment {
|
||||
private static final String TAG = EventsBrowseFragment.class.getSimpleName();
|
||||
|
||||
private static final int BACKGROUND_UPDATE_DELAY = 300;
|
||||
private static final int FRAGMENT = R.id.browse_fragment;
|
||||
|
||||
private final Handler mHandler = new Handler();
|
||||
private ArrayObjectAdapter mRowsAdapter;
|
||||
private Drawable mDefaultBackground;
|
||||
private DisplayMetrics mMetrics;
|
||||
private Timer mBackgroundTimer;
|
||||
private URI mBackgroundURI;
|
||||
private BackgroundManager mBackgroundManager;
|
||||
private Conference mConference;
|
||||
private int conferenceId;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
Log.i(TAG, "onCreate");
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
final BrowseErrorFragment errorFragment =
|
||||
BrowseErrorFragment.showErrorFragment(getFragmentManager(), FRAGMENT);
|
||||
conferenceId = this.getActivity().getIntent().getIntExtra(EventsActivity.CONFERENCE_ID, 0);
|
||||
mConference = this.getActivity().getIntent().getParcelableExtra(EventsActivity.CONFERENCE);
|
||||
|
||||
((ChaosflixBaseActivity) getActivity()).getApiServiceObservable()
|
||||
.subscribe(mediaApiService -> {
|
||||
mediaApiService.getConference(mConference.getApiID())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnError(t -> errorFragment.setErrorContent(t.getMessage()))
|
||||
.subscribe(conference -> {
|
||||
mConference = conference;
|
||||
setupUIElements();
|
||||
loadRows();
|
||||
errorFragment.dismiss();
|
||||
});
|
||||
});
|
||||
|
||||
prepareBackgroundManager();
|
||||
setOnItemViewClickedListener(new ItemViewClickedListener(this));
|
||||
setOnItemViewSelectedListener(new ItemViewSelectedListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (null != mBackgroundTimer) {
|
||||
Log.d(TAG, "onDestroy: " + mBackgroundTimer.toString());
|
||||
mBackgroundTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadRows() {
|
||||
HashMap<String, List<Event>> eventsByTags = mConference.getEventsByTags();
|
||||
|
||||
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
|
||||
CardPresenter cardPresenter = new CardPresenter();
|
||||
|
||||
List<Event> other = new LinkedList<Event>();
|
||||
List<String> keys = Lists.newArrayList(eventsByTags.keySet());
|
||||
Collections.sort(keys);
|
||||
for (String tag : keys) {
|
||||
List<Event> items = eventsByTags.get(tag);
|
||||
Collections.sort(items);
|
||||
if (android.text.TextUtils.isDigitsOnly(tag)) {
|
||||
other.addAll(items);
|
||||
} else {
|
||||
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
|
||||
listRowAdapter.addAll(0, items);
|
||||
HeaderItem header = new HeaderItem(tag);
|
||||
mRowsAdapter.add(new ListRow(header, listRowAdapter));
|
||||
}
|
||||
}
|
||||
if (other.size() > 0) {
|
||||
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
|
||||
listRowAdapter.addAll(0, other);
|
||||
HeaderItem header = new HeaderItem("other");
|
||||
mRowsAdapter.add(new ListRow(header, listRowAdapter));
|
||||
}
|
||||
setAdapter(mRowsAdapter);
|
||||
}
|
||||
|
||||
private void prepareBackgroundManager() {
|
||||
mBackgroundManager = BackgroundManager.getInstance(getActivity());
|
||||
mBackgroundManager.attach(getActivity().getWindow());
|
||||
mDefaultBackground = getResources().getDrawable(R.drawable.default_background);
|
||||
mMetrics = new DisplayMetrics();
|
||||
getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
|
||||
}
|
||||
|
||||
private void setupUIElements() {
|
||||
Glide.with(getActivity())
|
||||
.load(mConference.getLogoUrl())
|
||||
.centerCrop()
|
||||
.error(mDefaultBackground)
|
||||
.into(new SimpleTarget<GlideDrawable>(432, 243) {
|
||||
@Override
|
||||
public void onResourceReady(GlideDrawable resource,
|
||||
GlideAnimation<? super GlideDrawable>
|
||||
glideAnimation) {
|
||||
setBadgeDrawable(resource);
|
||||
}
|
||||
});
|
||||
setTitle(mConference.getTitle()); // Badge, when set, takes precedent
|
||||
// over title
|
||||
setHeadersState(HEADERS_ENABLED);
|
||||
setHeadersTransitionOnBackEnabled(true);
|
||||
|
||||
// set fastLane (or headers) background color
|
||||
setBrandColor(getResources().getColor(R.color.fastlane_background));
|
||||
// set search icon color
|
||||
setSearchAffordanceColor(getResources().getColor(R.color.search_opaque));
|
||||
|
||||
}
|
||||
|
||||
protected void updateBackground(String uri) {
|
||||
int width = mMetrics.widthPixels;
|
||||
int height = mMetrics.heightPixels;
|
||||
Glide.with(getActivity())
|
||||
.load(uri)
|
||||
.centerCrop()
|
||||
.error(mDefaultBackground)
|
||||
.into(new SimpleTarget<GlideDrawable>(width, height) {
|
||||
@Override
|
||||
public void onResourceReady(GlideDrawable resource,
|
||||
GlideAnimation<? super GlideDrawable>
|
||||
glideAnimation) {
|
||||
mBackgroundManager.setDrawable(resource);
|
||||
}
|
||||
});
|
||||
mBackgroundTimer.cancel();
|
||||
}
|
||||
|
||||
private void startBackgroundTimer() {
|
||||
if (null != mBackgroundTimer) {
|
||||
mBackgroundTimer.cancel();
|
||||
}
|
||||
mBackgroundTimer = new Timer();
|
||||
mBackgroundTimer.schedule(new UpdateBackgroundTask(), BACKGROUND_UPDATE_DELAY);
|
||||
}
|
||||
|
||||
private final class ItemViewSelectedListener implements OnItemViewSelectedListener {
|
||||
@Override
|
||||
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
|
||||
RowPresenter.ViewHolder rowViewHolder, Row row) {
|
||||
if (item instanceof Event) {
|
||||
try {
|
||||
mBackgroundURI = new URI(((Event) item).getPosterUrl());
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// TODO make configurable (enable/disable)
|
||||
// startBackgroundTimer();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateBackgroundTask extends TimerTask {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mBackgroundURI != null) {
|
||||
updateBackground(mBackgroundURI.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,443 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v17.leanback.app.BackgroundManager;
|
||||
import android.support.v17.leanback.app.DetailsFragment;
|
||||
import android.support.v17.leanback.widget.Action;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.ClassPresenterSelector;
|
||||
import android.support.v17.leanback.widget.DetailsOverviewLogoPresenter;
|
||||
import android.support.v17.leanback.widget.DetailsOverviewRow;
|
||||
import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
|
||||
import android.support.v17.leanback.widget.FullWidthDetailsOverviewSharedElementHelper;
|
||||
import android.support.v17.leanback.widget.HeaderItem;
|
||||
import android.support.v17.leanback.widget.ListRow;
|
||||
import android.support.v17.leanback.widget.ListRowPresenter;
|
||||
import android.support.v17.leanback.widget.OnActionClickedListener;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.app.AlertDialog;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import de.nicidienase.chaosflix.leanback.CardPresenter;
|
||||
import de.nicidienase.chaosflix.leanback.EventDetailsDescriptionPresenter;
|
||||
import de.nicidienase.chaosflix.leanback.ItemViewClickedListener;
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.ChaosflixBaseActivity;
|
||||
import de.nicidienase.chaosflix.leanback.activities.ConferencesActivity;
|
||||
import de.nicidienase.chaosflix.leanback.activities.DetailsActivity;
|
||||
import de.nicidienase.chaosflix.leanback.activities.EventDetailsActivity;
|
||||
import de.nicidienase.chaosflix.leanback.activities.PlayerActivity;
|
||||
import de.nicidienase.chaosflix.shared.entities.WatchlistItem;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Conference;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Event;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Recording;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.Group;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.LiveConference;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.Room;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.Stream;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.StreamUrl;
|
||||
import de.nicidienase.chaosflix.shared.network.MediaApiService;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
|
||||
/**
|
||||
* Created by felix on 18.03.17.
|
||||
*/
|
||||
|
||||
public class EventsDetailsFragment extends DetailsFragment {
|
||||
private static final int DETAIL_THUMB_WIDTH = 254;
|
||||
private static final int DETAIL_THUMB_HEIGHT = 143;
|
||||
private static final int NUM_RELATED_TALKS = 5;
|
||||
private static final int NUM_RANDOM_TALKS = NUM_RELATED_TALKS;
|
||||
|
||||
private static final String TAG = EventsDetailsFragment.class.getSimpleName();
|
||||
public static final int FRAGMENT = R.id.details_fragment;
|
||||
public static final int DUMMY_ID = 1646465164;
|
||||
public static final int DEFAULT_DRAWABLE = R.drawable.default_background;
|
||||
private static final long ADD_WATCHLIST_ACTION = 1646465165;
|
||||
private static final long REMOVE_WATCHLIST_ACTION = 1646465166;
|
||||
private Event mSelectedEvent;
|
||||
private MediaApiService mMediaApiService;
|
||||
private Room mRoom;
|
||||
private int eventType;
|
||||
private ArrayList<StreamUrl> streamUrlList;
|
||||
private BackgroundManager mBackgroundmanager;
|
||||
private DisplayMetrics mMetrics;
|
||||
private WatchlistItem mWatchlistItem;
|
||||
private ArrayObjectAdapter mRecordingActionsAdapter;
|
||||
private OnActionClickedListener mOnActionClickedListener = new OnActionClickedListener() {
|
||||
@Override
|
||||
public void onActionClicked(Action action) {
|
||||
Log.d(TAG, "OnActionClicked");
|
||||
if (action.getId() == ADD_WATCHLIST_ACTION) {
|
||||
new WatchlistItem(mSelectedEvent.getApiID()).save();
|
||||
mRecordingActionsAdapter.replace(0, new Action(REMOVE_WATCHLIST_ACTION, EventsDetailsFragment.this.getString(R.string.remove_from_watchlist)));
|
||||
SharedPreferences preferences = getActivity().getSharedPreferences(getString(R.string.watchlist_preferences_key), Context.MODE_PRIVATE);
|
||||
if(preferences.getBoolean(getString(R.string.watchlist_dialog_needed), true)) { // new item
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setTitle(R.string.watchlist_message);
|
||||
builder.setNegativeButton(R.string.return_to_homescreen,(dialog, which) -> {
|
||||
Intent i = new Intent(getActivity(), ConferencesActivity.class);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(i);
|
||||
getActivity().finish();
|
||||
});
|
||||
builder.setPositiveButton("OK",(dialog, which) -> {});
|
||||
SharedPreferences.Editor edit = preferences.edit();
|
||||
edit.putBoolean(getString(R.string.watchlist_dialog_needed), false);
|
||||
edit.commit();
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
} else if (action.getId() == REMOVE_WATCHLIST_ACTION) {
|
||||
if (mWatchlistItem != null) {
|
||||
mWatchlistItem.delete();
|
||||
}
|
||||
mRecordingActionsAdapter.replace(0, new Action(ADD_WATCHLIST_ACTION, EventsDetailsFragment.this.getString(R.string.add_to_watchlist)));
|
||||
} else {
|
||||
Intent i = new Intent(EventsDetailsFragment.this.getActivity(), PlayerActivity.class);
|
||||
i.putExtra(DetailsActivity.TYPE, eventType);
|
||||
if (eventType == DetailsActivity.TYPE_RECORDING) {
|
||||
i.putExtra(DetailsActivity.EVENT, mSelectedEvent);
|
||||
if (action.getId() == DUMMY_ID) {
|
||||
Recording dummy = new Recording();
|
||||
dummy.setRecordingUrl("https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8");
|
||||
dummy.setMimeType("video/hls");
|
||||
dummy.setLanguage("eng");
|
||||
dummy.setHighQuality(true);
|
||||
i.putExtra(DetailsActivity.RECORDING, dummy);
|
||||
} else {
|
||||
for (Recording r : mSelectedEvent.getRecordings()) {
|
||||
if (r.getApiID() == action.getId()) {
|
||||
i.putExtra(DetailsActivity.RECORDING, r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (eventType == DetailsActivity.TYPE_STREAM) {
|
||||
i.putExtra(DetailsActivity.ROOM, mRoom);
|
||||
StreamUrl streamUrl = EventsDetailsFragment.this.getStreamUrlForActionId((int) action.getId());
|
||||
if (streamUrl != null) {
|
||||
i.putExtra(DetailsActivity.STREAM_URL, streamUrl);
|
||||
} else {
|
||||
// TODO handle missing Stream
|
||||
return;
|
||||
}
|
||||
}
|
||||
EventsDetailsFragment.this.getActivity().startActivity(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onCreate");
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
prepareBackgroundManager();
|
||||
final BrowseErrorFragment browseErrorFragment =
|
||||
BrowseErrorFragment.showErrorFragment(getFragmentManager(), FRAGMENT);
|
||||
eventType = getActivity().getIntent().getIntExtra(DetailsActivity.TYPE, -1);
|
||||
|
||||
if (eventType == DetailsActivity.TYPE_RECORDING) {
|
||||
mSelectedEvent = getActivity().getIntent()
|
||||
.getParcelableExtra(DetailsActivity.EVENT);
|
||||
mWatchlistItem = WatchlistItem.findById(WatchlistItem.class, mSelectedEvent.getApiID());
|
||||
} else if (eventType == DetailsActivity.TYPE_STREAM) {
|
||||
mRoom = getActivity().getIntent()
|
||||
.getParcelableExtra(DetailsActivity.ROOM);
|
||||
}
|
||||
|
||||
FullWidthDetailsOverviewRowPresenter mDetailsPresenter
|
||||
= setupDetailsOverviewRowPresenter();
|
||||
ClassPresenterSelector mPresenterSelector = new ClassPresenterSelector();
|
||||
mPresenterSelector.addClassPresenter(DetailsOverviewRow.class, mDetailsPresenter);
|
||||
mPresenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());
|
||||
final ArrayObjectAdapter adapter = new ArrayObjectAdapter(mPresenterSelector);
|
||||
|
||||
((ChaosflixBaseActivity) getActivity()).getApiServiceObservable()
|
||||
.doOnError(t -> browseErrorFragment.setErrorContent(t.getMessage()))
|
||||
.subscribe(mediaApiService -> {
|
||||
mMediaApiService = mediaApiService;
|
||||
if (eventType == DetailsActivity.TYPE_RECORDING) {
|
||||
final DetailsOverviewRow detailsOverviewRow = setupDetailsOverviewRow(mSelectedEvent);
|
||||
mediaApiService.getEvent(mSelectedEvent.getApiID())
|
||||
.doOnError(t -> browseErrorFragment.setErrorContent(t.getMessage()))
|
||||
.subscribe(event -> {
|
||||
mSelectedEvent = event;
|
||||
mRecordingActionsAdapter =
|
||||
getRecordingActionsAdapter(mSelectedEvent.getRecordings());
|
||||
detailsOverviewRow.setActionsAdapter(mRecordingActionsAdapter);
|
||||
adapter.add(detailsOverviewRow);
|
||||
mediaApiService.getConference(
|
||||
mSelectedEvent.getConferenceId())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(conference -> {
|
||||
String tag = null;
|
||||
if (mSelectedEvent.getTags().size() > 0) {
|
||||
tag = mSelectedEvent.getTags().get(0);
|
||||
List<Event> relatedEvents = conference.getEventsByTags().get(tag);
|
||||
relatedEvents.remove(mSelectedEvent);
|
||||
Collections.shuffle(relatedEvents);
|
||||
if (relatedEvents.size() > 5) {
|
||||
relatedEvents = relatedEvents.subList(0, NUM_RELATED_TALKS);
|
||||
}
|
||||
ArrayObjectAdapter relatedEventsAdapter
|
||||
= new ArrayObjectAdapter(new CardPresenter());
|
||||
relatedEventsAdapter.addAll(0, relatedEvents);
|
||||
HeaderItem header = new HeaderItem(getString(R.string.random_talks_on_this_track));
|
||||
adapter.add(new ListRow(header, relatedEventsAdapter));
|
||||
}
|
||||
|
||||
List<Event> selectedEvents = getRandomEvents(conference, tag);
|
||||
if (selectedEvents.size() > 0) {
|
||||
ArrayObjectAdapter randomEventAdapter
|
||||
= new ArrayObjectAdapter(new CardPresenter());
|
||||
randomEventAdapter.addAll(0, selectedEvents);
|
||||
HeaderItem header = new HeaderItem(getString(R.string.random_talks));
|
||||
adapter.add(new ListRow(header, randomEventAdapter));
|
||||
}
|
||||
|
||||
setOnItemViewClickedListener(new ItemViewClickedListener(this));
|
||||
setAdapter(adapter);
|
||||
browseErrorFragment.dismiss();
|
||||
});
|
||||
});
|
||||
} else if (eventType == DetailsActivity.TYPE_STREAM) {
|
||||
mediaApiService.getStreamingConferences()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(liveConferences -> {
|
||||
if(mRoom.getStreams() == null){
|
||||
mRoom = getRoom(mRoom, liveConferences);
|
||||
}
|
||||
final DetailsOverviewRow detailsOverviewRow = setupDetailsOverviewRow(mRoom);
|
||||
ArrayObjectAdapter actionsAdapter = getStreamActionsAdapter(mRoom.getStreams());
|
||||
detailsOverviewRow.setActionsAdapter(actionsAdapter);
|
||||
adapter.add(detailsOverviewRow);
|
||||
setOnItemViewClickedListener(new ItemViewClickedListener(EventsDetailsFragment.this));
|
||||
setAdapter(adapter);
|
||||
browseErrorFragment.dismiss();
|
||||
// TODO add other streams
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
startEntranceTransition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mBackgroundmanager.release();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
private void prepareBackgroundManager() {
|
||||
mBackgroundmanager = BackgroundManager.getInstance(getActivity());
|
||||
mBackgroundmanager.attach(getActivity().getWindow());
|
||||
mMetrics = new DisplayMetrics();
|
||||
getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
|
||||
}
|
||||
|
||||
private void updateBackground(String uri) {
|
||||
Glide.with(this)
|
||||
.load(uri)
|
||||
.asBitmap()
|
||||
.centerCrop()
|
||||
.into(new SimpleTarget<Bitmap>() {
|
||||
@Override
|
||||
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
|
||||
mBackgroundmanager.setBitmap(resource);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Room getRoom(Room room, List<LiveConference> liveConferences) {
|
||||
for (LiveConference con : liveConferences) {
|
||||
for (Group g : con.getGroups()) {
|
||||
for (Room r : g.getRooms()) {
|
||||
if (r.getSlug().equals(room.getSlug())) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Event> getRandomEvents(Conference conference, String tag) {
|
||||
List<Event> randomEvents = conference.getEvents();
|
||||
Collections.shuffle(randomEvents);
|
||||
List<Event> selectedEvents;
|
||||
if (tag != null) {
|
||||
selectedEvents = new ArrayList<Event>();
|
||||
for (Event e : randomEvents) {
|
||||
if (!e.getTags().contains(tag)) {
|
||||
selectedEvents.add(e);
|
||||
}
|
||||
if (selectedEvents.size() == 5) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selectedEvents = randomEvents.subList(0, NUM_RANDOM_TALKS);
|
||||
}
|
||||
return selectedEvents;
|
||||
}
|
||||
|
||||
private FullWidthDetailsOverviewRowPresenter setupDetailsOverviewRowPresenter() {
|
||||
FullWidthDetailsOverviewRowPresenter mDetailsPresenter = new FullWidthDetailsOverviewRowPresenter(
|
||||
new EventDetailsDescriptionPresenter(getActivity()),
|
||||
new EventDetailsOverviewLogoPresenter());
|
||||
mDetailsPresenter.setBackgroundColor(getResources().getColor(R.color.selected_background));
|
||||
mDetailsPresenter.setInitialState(FullWidthDetailsOverviewRowPresenter.STATE_HALF);
|
||||
mDetailsPresenter.setAlignmentMode(FullWidthDetailsOverviewRowPresenter.ALIGN_MODE_START);
|
||||
|
||||
FullWidthDetailsOverviewSharedElementHelper helper
|
||||
= new FullWidthDetailsOverviewSharedElementHelper();
|
||||
helper.setSharedElementEnterTransition(getActivity(),
|
||||
EventDetailsActivity.SHARED_ELEMENT_NAME);
|
||||
mDetailsPresenter.setListener(helper);
|
||||
prepareEntranceTransition();
|
||||
|
||||
mDetailsPresenter.setOnActionClickedListener(mOnActionClickedListener);
|
||||
return mDetailsPresenter;
|
||||
}
|
||||
|
||||
private DetailsOverviewRow setupDetailsOverviewRow(Object event) {
|
||||
final DetailsOverviewRow row = new DetailsOverviewRow(event);
|
||||
String thumbUrl;
|
||||
if (event instanceof Event) {
|
||||
thumbUrl = ((Event) event).getThumbUrl();
|
||||
} else {
|
||||
thumbUrl = ((Room) event).getThumb();
|
||||
}
|
||||
Glide.with(getActivity())
|
||||
.load(thumbUrl)
|
||||
.asBitmap()
|
||||
.into(new SimpleTarget<Bitmap>(DETAIL_THUMB_WIDTH, DETAIL_THUMB_HEIGHT) {
|
||||
@Override
|
||||
public void onResourceReady(Bitmap resource,
|
||||
GlideAnimation<? super Bitmap> glideAnimation) {
|
||||
row.setImageBitmap(getActivity(), resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
||||
// super.onLoadFailed(e, errorDrawable);
|
||||
row.setImageDrawable(getResources().getDrawable(DEFAULT_DRAWABLE));
|
||||
}
|
||||
});
|
||||
return row;
|
||||
}
|
||||
|
||||
private ArrayObjectAdapter getRecordingActionsAdapter(List<Recording> recordings) {
|
||||
ArrayObjectAdapter actionsAdapter = new ArrayObjectAdapter();
|
||||
if(mWatchlistItem != null){
|
||||
actionsAdapter.add(new Action(REMOVE_WATCHLIST_ACTION,getString(R.string.remove_from_watchlist)));
|
||||
} else {
|
||||
actionsAdapter.add(new Action(ADD_WATCHLIST_ACTION,getString(R.string.add_to_watchlist)));
|
||||
}
|
||||
if (recordings != null) {
|
||||
for (int i = 0; i < recordings.size(); i++) {
|
||||
Recording recording = recordings.get(i);
|
||||
if (recording.getMimeType().startsWith("video/") || true) {
|
||||
String quality = recording.isHighQuality() ? "HD" : "SD";
|
||||
String title = quality + " (" + recording.getLanguage() + ")";
|
||||
actionsAdapter.add(new Action(recording.getApiID(), title, recording.getMimeType().substring(6)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
actionsAdapter.add(new Action(DUMMY_ID, "Dummy", "HLS"));
|
||||
}
|
||||
return actionsAdapter;
|
||||
}
|
||||
|
||||
private ArrayObjectAdapter getStreamActionsAdapter(List<Stream> streams) {
|
||||
ArrayObjectAdapter actionsAdapter = new ArrayObjectAdapter();
|
||||
streamUrlList = new ArrayList<StreamUrl>();
|
||||
for (Stream s : streams) {
|
||||
if (s.getType().equals("video") || true)
|
||||
for (String key : s.getUrls().keySet()) {
|
||||
StreamUrl url = s.getUrls().get(key);
|
||||
int index = streamUrlList.size();
|
||||
streamUrlList.add(url);
|
||||
actionsAdapter.add(new Action(index, s.getDisplay(), url.getDisplay()));
|
||||
}
|
||||
}
|
||||
return actionsAdapter;
|
||||
}
|
||||
|
||||
private StreamUrl getStreamUrlForActionId(int actionId) {
|
||||
if (streamUrlList != null && streamUrlList.size() > actionId) {
|
||||
return streamUrlList.get(actionId);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class EventDetailsOverviewLogoPresenter extends DetailsOverviewLogoPresenter {
|
||||
static class ViewHolder extends DetailsOverviewLogoPresenter.ViewHolder {
|
||||
public ViewHolder(View view) {
|
||||
super(view);
|
||||
}
|
||||
|
||||
public FullWidthDetailsOverviewRowPresenter getParentPresenter() {
|
||||
return mParentPresenter;
|
||||
}
|
||||
|
||||
public FullWidthDetailsOverviewRowPresenter.ViewHolder getParentViewHolder() {
|
||||
return mParentViewHolder;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
ImageView imageView = (ImageView) LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.lb_fullwidth_details_overview_logo, parent, false);
|
||||
|
||||
Resources res = parent.getResources();
|
||||
int width = res.getDimensionPixelSize(R.dimen.detail_thumb_width);
|
||||
int height = res.getDimensionPixelSize(R.dimen.detail_thumb_height);
|
||||
imageView.setLayoutParams(new ViewGroup.MarginLayoutParams(width, height));
|
||||
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||
|
||||
return new ViewHolder(imageView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
|
||||
DetailsOverviewRow row = (DetailsOverviewRow) item;
|
||||
ImageView imageView = ((ImageView) viewHolder.view);
|
||||
imageView.setImageDrawable(row.getImageDrawable());
|
||||
if (isBoundToImage((ViewHolder) viewHolder, row)) {
|
||||
EventDetailsOverviewLogoPresenter.ViewHolder vh =
|
||||
(EventDetailsOverviewLogoPresenter.ViewHolder) viewHolder;
|
||||
vh.getParentPresenter().notifyOnBindLogo(vh.getParentViewHolder());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,484 +0,0 @@
|
|||
package de.nicidienase.chaosflix.leanback.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
import android.media.session.MediaController;
|
||||
import android.media.session.MediaSession;
|
||||
import android.media.session.PlaybackState;
|
||||
import android.os.Bundle;
|
||||
import android.support.v17.leanback.app.PlaybackFragment;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.ClassPresenterSelector;
|
||||
import android.support.v17.leanback.widget.HeaderItem;
|
||||
import android.support.v17.leanback.widget.ListRow;
|
||||
import android.support.v17.leanback.widget.ListRowPresenter;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
|
||||
import android.support.v17.leanback.widget.Row;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.nicidienase.chaosflix.leanback.CardPresenter;
|
||||
import de.nicidienase.chaosflix.leanback.ItemViewClickedListener;
|
||||
import de.nicidienase.chaosflix.leanback.PlaybackHelper;
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.ChaosflixBaseActivity;
|
||||
import de.nicidienase.chaosflix.leanback.activities.DetailsActivity;
|
||||
import de.nicidienase.chaosflix.shared.entities.PlaybackProgress;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Event;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Recording;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.Room;
|
||||
import de.nicidienase.chaosflix.shared.entities.streaming.StreamUrl;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
||||
import static android.support.v4.media.session.MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS;
|
||||
import static android.support.v4.media.session.MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS;
|
||||
|
||||
/**
|
||||
* Created by felix on 26.03.17.
|
||||
*/
|
||||
|
||||
public class OverlayFragment extends PlaybackFragment {
|
||||
|
||||
private static final String TAG = OverlayFragment.class.getSimpleName();
|
||||
private static final long RESUME_SKIP = 5; // seconds to skip back on resume
|
||||
public static final int MAX_REMAINING = 30;
|
||||
|
||||
private Recording mSelectedRecording;
|
||||
private Event mSelectedEvent;
|
||||
private PlaybackProgress mPlaybackProgress;
|
||||
|
||||
private Room mSelectedRoom;
|
||||
private PlaybackHelper mHelper;
|
||||
private PlaybackControlListener mCallback;
|
||||
private ArrayObjectAdapter mRowsAdapter;
|
||||
private MediaSession mSession;
|
||||
private boolean mHasAudioFocus;
|
||||
private boolean mPauseTransient;
|
||||
private AudioManager mAudioManager;
|
||||
private MediaController mMediaControler;
|
||||
private int eventType;
|
||||
|
||||
private StreamUrl mSelectedStream;
|
||||
|
||||
private MediaController.Callback mMediaControllerCallback;
|
||||
private CompositeDisposable mDisposables = new CompositeDisposable();
|
||||
private final AudioManager.OnAudioFocusChangeListener mOnAudioFocusChangeListener =
|
||||
new AudioManager.OnAudioFocusChangeListener() {
|
||||
@Override
|
||||
public void onAudioFocusChange(int focusChange) {
|
||||
switch (focusChange) {
|
||||
case AudioManager.AUDIOFOCUS_LOSS:
|
||||
abandonAudioFocus();
|
||||
pause();
|
||||
break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
||||
if (mHelper.isMediaPlaying()) {
|
||||
pause();
|
||||
mPauseTransient = true;
|
||||
}
|
||||
break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
||||
mCallback.mute(true);
|
||||
break;
|
||||
case AudioManager.AUDIOFOCUS_GAIN:
|
||||
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
|
||||
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
|
||||
if (mPauseTransient) {
|
||||
play();
|
||||
}
|
||||
mCallback.mute(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public interface PlaybackControlListener {
|
||||
void play();
|
||||
|
||||
void pause();
|
||||
|
||||
void playPause();
|
||||
|
||||
void setVideoSource(String source);
|
||||
|
||||
void skipForward(int sec);
|
||||
|
||||
void skipBackward(int sec);
|
||||
|
||||
void seekTo(long sec);
|
||||
|
||||
boolean isMediaPlaying();
|
||||
|
||||
long getLength();
|
||||
|
||||
long getCurrentPosition();
|
||||
|
||||
long getBufferedPosition();
|
||||
|
||||
void releasePlayer();
|
||||
|
||||
void mute(boolean state);
|
||||
|
||||
void nextAudioStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Log.d(TAG, "OnCreate");
|
||||
|
||||
Intent intent = getActivity()
|
||||
.getIntent();
|
||||
eventType = intent.getIntExtra(DetailsActivity.TYPE, -1);
|
||||
if (eventType == DetailsActivity.TYPE_RECORDING) {
|
||||
mSelectedEvent = intent.getParcelableExtra(DetailsActivity.EVENT);
|
||||
mSelectedRecording = intent.getParcelableExtra(DetailsActivity.RECORDING);
|
||||
mHelper = new PlaybackHelper(getActivity(), this, mSelectedEvent, mSelectedRecording);
|
||||
|
||||
List<PlaybackProgress> progressList = PlaybackProgress.find(PlaybackProgress.class, "event_id = ?", String.valueOf(mSelectedEvent.getApiID()));
|
||||
if (progressList.size() > 0) {
|
||||
mPlaybackProgress = progressList.get(0);
|
||||
}
|
||||
} else if (eventType == DetailsActivity.TYPE_STREAM) {
|
||||
mSelectedRoom = intent.getParcelableExtra(DetailsActivity.ROOM);
|
||||
mSelectedStream = intent.getParcelableExtra(DetailsActivity.STREAM_URL);
|
||||
mHelper = new PlaybackHelper(getActivity(), this, mSelectedRoom, mSelectedStream);
|
||||
} else {
|
||||
Log.d(TAG, "No Media found, finishing");
|
||||
getActivity().finish();
|
||||
}
|
||||
mAudioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
|
||||
|
||||
setBackgroundType(PlaybackFragment.BG_LIGHT);
|
||||
setFadingEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onStart() {
|
||||
super.onStart();
|
||||
Log.d(TAG, "OnStart");
|
||||
|
||||
PlaybackControlsRowPresenter playbackControlsRowPresenter = mHelper.createControlsRowAndPresenter();
|
||||
PlaybackControlsRow controlsRow = mHelper.getControlsRow();
|
||||
mMediaControllerCallback = mHelper.createMediaControllerCallback();
|
||||
requestAudioFocus();
|
||||
mMediaControler = getActivity().getMediaController();
|
||||
if (mMediaControler != null) {
|
||||
mMediaControler.registerCallback(mMediaControllerCallback);
|
||||
} else {
|
||||
Log.d(TAG, "MediaController is null");
|
||||
getActivity().finish();
|
||||
}
|
||||
ClassPresenterSelector ps = new ClassPresenterSelector();
|
||||
ps.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter);
|
||||
ps.addClassPresenter(ListRow.class, new ListRowPresenter());
|
||||
mRowsAdapter = new ArrayObjectAdapter(ps);
|
||||
mRowsAdapter.add(controlsRow);
|
||||
if (eventType == DetailsActivity.TYPE_RECORDING) {
|
||||
if (mSelectedEvent.getMetadata() != null && mSelectedEvent.getMetadata().getRelated() != null) {
|
||||
mRowsAdapter.add(getRelatedItems());
|
||||
setOnItemViewClickedListener(new ItemViewClickedListener(this));
|
||||
}
|
||||
} else if (eventType == DetailsActivity.TYPE_STREAM) {
|
||||
// TODO add other streams as related events
|
||||
}
|
||||
setAdapter(mRowsAdapter);
|
||||
|
||||
if (mCallback != null && eventType == DetailsActivity.TYPE_STREAM) {
|
||||
mCallback.setVideoSource(mSelectedStream.getUrl());
|
||||
} else if (mCallback != null && eventType == DetailsActivity.TYPE_RECORDING) {
|
||||
mCallback.setVideoSource(mSelectedRecording.getRecordingUrl());
|
||||
} else {
|
||||
Log.d(TAG, "Callback not set or not event/stream");
|
||||
}
|
||||
requestAudioFocus();
|
||||
if (mPlaybackProgress != null) {
|
||||
showContinueOrRestartDialog();
|
||||
} else {
|
||||
play();
|
||||
}
|
||||
}
|
||||
|
||||
private void showContinueOrRestartDialog() {
|
||||
AlertDialog alertDialog = new AlertDialog.Builder(getActivity())
|
||||
.setMessage(R.string.resume_question)
|
||||
.setPositiveButton(R.string.start_again, (dialog, which) -> play())
|
||||
.setNegativeButton(R.string.resume, (dialog, which) -> {
|
||||
mCallback.seekTo(getProgress());
|
||||
play();
|
||||
})
|
||||
.create();
|
||||
alertDialog.show();
|
||||
}
|
||||
|
||||
private long getProgress() {
|
||||
long progress = mPlaybackProgress.getProgress() / 1000;
|
||||
if (progress >= mSelectedEvent.getLength()) {
|
||||
return 0;
|
||||
} else {
|
||||
return Math.max(0, progress - RESUME_SKIP);
|
||||
}
|
||||
}
|
||||
|
||||
private Row getRelatedItems() {
|
||||
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
|
||||
final long[] related = mSelectedEvent.getMetadata().getRelated();
|
||||
mDisposables.add(((ChaosflixBaseActivity) getActivity()).getApiServiceObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
mediaApiService -> {
|
||||
for (long id : related) {
|
||||
mDisposables.add(mediaApiService.getEvent(id)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(event -> listRowAdapter.add(event)));
|
||||
}
|
||||
listRowAdapter.notifyArrayItemRangeChanged(0, listRowAdapter.size());
|
||||
}
|
||||
)
|
||||
);
|
||||
HeaderItem header = new HeaderItem(0, getString(R.string.related_talks));
|
||||
return new ListRow(header, listRowAdapter);
|
||||
}
|
||||
|
||||
public boolean isMediaPlaying() {
|
||||
if (mCallback != null) {
|
||||
return mCallback.isMediaPlaying();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getCurrentPosition() {
|
||||
if (eventType == DetailsActivity.TYPE_RECORDING) {
|
||||
if (mCallback != null) {
|
||||
return (int) mCallback.getCurrentPosition();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long getCurrentPositionLong() {
|
||||
if (eventType == DetailsActivity.TYPE_RECORDING) {
|
||||
if (mCallback != null) {
|
||||
return mCallback.getCurrentPosition();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long getCurrentBufferedPosition() {
|
||||
if (mCallback != null) {
|
||||
return mCallback.getBufferedPosition();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
if (mSession != null) {
|
||||
mSession.release();
|
||||
}
|
||||
mDisposables.dispose();
|
||||
abandonAudioFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (mSelectedEvent != null) {
|
||||
if (mPlaybackProgress != null) {
|
||||
if ((mSelectedEvent.getLength() - mCallback.getCurrentPosition() / 1000) > MAX_REMAINING) {
|
||||
mPlaybackProgress.setProgress(mCallback.getCurrentPosition());
|
||||
mPlaybackProgress.save();
|
||||
} else {
|
||||
mPlaybackProgress.delete();
|
||||
}
|
||||
} else if ((mSelectedEvent.getLength() - mCallback.getCurrentPosition() / 1000) > MAX_REMAINING) {
|
||||
mPlaybackProgress = new PlaybackProgress(mSelectedEvent.getApiID(),
|
||||
mCallback.getCurrentPosition(), mSelectedRecording.getApiID());
|
||||
mPlaybackProgress.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mSession != null) {
|
||||
mSession.release();
|
||||
}
|
||||
mCallback.releasePlayer();
|
||||
mHelper.onStop();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
setupMediaSession(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
setupMediaSession(activity);
|
||||
}
|
||||
|
||||
@SuppressWarnings("WrongConstant")
|
||||
private void setupMediaSession(Context context) {
|
||||
Log.d(TAG, "OnAttach");
|
||||
if (context instanceof PlaybackControlListener) {
|
||||
mCallback = (PlaybackControlListener) context;
|
||||
} else {
|
||||
throw (new RuntimeException("Activity must implement PlaybackControlListener"));
|
||||
}
|
||||
|
||||
if (mSession == null) {
|
||||
mSession = new MediaSession(getActivity(), "chaosflix");
|
||||
mSession.setCallback(new ChaosflixSessionCallback());
|
||||
mSession.setFlags(FLAG_HANDLES_MEDIA_BUTTONS | FLAG_HANDLES_TRANSPORT_CONTROLS);
|
||||
mSession.setActive(true);
|
||||
|
||||
setPlaybackState(PlaybackState.STATE_NONE);
|
||||
|
||||
getActivity().setMediaController(
|
||||
new MediaController(getActivity(), mSession.getSessionToken()));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("WrongConstant")
|
||||
private void setPlaybackState(int state) {
|
||||
long currentPosition = getCurrentPositionLong();
|
||||
PlaybackState.Builder stateBuilder = new PlaybackState.Builder()
|
||||
.setActions(getAvailableActions(state))
|
||||
.setState(PlaybackState.STATE_PLAYING, currentPosition, 0);
|
||||
|
||||
if (mSession != null) {
|
||||
mSession.setPlaybackState(stateBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
private int getPlaybackState() {
|
||||
Activity activity = getActivity();
|
||||
|
||||
if (activity != null) {
|
||||
PlaybackState state = activity.getMediaController().getPlaybackState();
|
||||
if (state != null) {
|
||||
return state.getState();
|
||||
} else {
|
||||
return PlaybackState.STATE_NONE;
|
||||
}
|
||||
}
|
||||
return PlaybackState.STATE_NONE;
|
||||
}
|
||||
|
||||
private long getAvailableActions(int nextState) {
|
||||
long actions = PlaybackState.ACTION_PLAY |
|
||||
PlaybackState.ACTION_SKIP_TO_NEXT |
|
||||
PlaybackState.ACTION_SKIP_TO_PREVIOUS |
|
||||
PlaybackState.ACTION_FAST_FORWARD |
|
||||
PlaybackState.ACTION_REWIND |
|
||||
PlaybackState.ACTION_PAUSE;
|
||||
|
||||
if (nextState == PlaybackState.STATE_PLAYING) {
|
||||
actions |= PlaybackState.ACTION_PAUSE;
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
private void requestAudioFocus() {
|
||||
if (mHasAudioFocus) {
|
||||
return;
|
||||
}
|
||||
int result = mAudioManager.requestAudioFocus(mOnAudioFocusChangeListener,
|
||||
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||
mHasAudioFocus = true;
|
||||
} else {
|
||||
pause();
|
||||
}
|
||||
}
|
||||
|
||||
private void abandonAudioFocus() {
|
||||
mHasAudioFocus = false;
|
||||
mAudioManager.abandonAudioFocus(mOnAudioFocusChangeListener);
|
||||
}
|
||||
|
||||
private void play() {
|
||||
if (mCallback != null) {
|
||||
setPlaybackState(PlaybackState.STATE_PLAYING);
|
||||
setFadingEnabled(true);
|
||||
mCallback.play();
|
||||
}
|
||||
}
|
||||
|
||||
private void pause() {
|
||||
if (mCallback != null) {
|
||||
setPlaybackState(PlaybackState.STATE_PAUSED);
|
||||
setFadingEnabled(false);
|
||||
mCallback.pause();
|
||||
}
|
||||
}
|
||||
|
||||
private void rewind() {
|
||||
if (mCallback != null) {
|
||||
int prevState = getPlaybackState();
|
||||
setPlaybackState(PlaybackState.STATE_FAST_FORWARDING);
|
||||
mCallback.skipBackward(30);
|
||||
setPlaybackState(prevState);
|
||||
}
|
||||
}
|
||||
|
||||
private void fastForward() {
|
||||
if (mCallback != null) {
|
||||
int prevState = getPlaybackState();
|
||||
setPlaybackState(PlaybackState.STATE_FAST_FORWARDING);
|
||||
mCallback.skipForward(30);
|
||||
setPlaybackState(prevState);
|
||||
}
|
||||
}
|
||||
|
||||
private class ChaosflixSessionCallback extends MediaSession.Callback {
|
||||
@Override
|
||||
public void onPlay() {
|
||||
play();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
pause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFastForward() {
|
||||
fastForward();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRewind() {
|
||||
rewind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSkipToNext() {
|
||||
mCallback.skipForward(5 * 60);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSkipToPrevious() {
|
||||
mCallback.skipBackward(5 * 60);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSeekTo(long pos) {
|
||||
mCallback.seekTo(pos);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
package de.nicidienase.chaosflix.shared;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.PersistableBundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import de.nicidienase.chaosflix.shared.network.MediaApiService;
|
||||
import io.reactivex.Single;
|
||||
|
||||
/**
|
||||
* Created by felix on 24.03.17.
|
||||
*/
|
||||
|
||||
public class ChaosflixBaseActivity extends AppCompatActivity {
|
||||
private MediaApiService mMediaApiService = null;
|
||||
private ServiceConnection conn;
|
||||
private boolean mConnected = false;
|
||||
private String serverUrl = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
|
||||
super.onCreate(savedInstanceState, persistentState);
|
||||
serverUrl = getIntent().getStringExtra("server_url");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (mConnected) {
|
||||
unbindService(conn);
|
||||
conn = null;
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
public Single<MediaApiService> getApiServiceObservable() {
|
||||
Intent s = new Intent(this, MediaApiService.class);
|
||||
if (serverUrl != null) {
|
||||
s.putExtra(MediaApiService.RECORDING_URL, serverUrl);
|
||||
s.putExtra(MediaApiService.STREAMING_URL, serverUrl);
|
||||
}
|
||||
return Single.create(e -> {
|
||||
if (mMediaApiService != null) {
|
||||
e.onSuccess(mMediaApiService);
|
||||
} else {
|
||||
conn = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
mConnected = true;
|
||||
mMediaApiService = ((MediaApiService.LocalBinder) service).getService();
|
||||
e.onSuccess(mMediaApiService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
mMediaApiService = null;
|
||||
mConnected = false;
|
||||
}
|
||||
};
|
||||
ChaosflixBaseActivity.this.bindService(s, conn, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
package de.nicidienase.chaosflix.touch;
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Conference;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.ConferencesWrapper;
|
||||
import de.nicidienase.chaosflix.touch.fragments.ConferenceFragment;
|
||||
|
||||
/**
|
||||
* Created by felix on 18.09.17.
|
||||
*/
|
||||
public class ConferenceGroupsFragmentPager extends FragmentPagerAdapter {
|
||||
|
||||
private static final String TAG = ConferenceGroupsFragmentPager.class.getSimpleName();
|
||||
private List<String> orderedConferencesList = new ArrayList<>();
|
||||
private Map<String, List<Conference>> mConferenceMap;
|
||||
|
||||
public ConferenceGroupsFragmentPager(FragmentManager fm) {
|
||||
super(fm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
ConferenceFragment conferenceFragment = new ConferenceFragment();
|
||||
List<Conference> conferences = mConferenceMap.get(orderedConferencesList.get(position));
|
||||
conferenceFragment.setContent(conferences);
|
||||
return conferenceFragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return orderedConferencesList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
String string = ConferencesWrapper.getStringForTag(orderedConferencesList.get(position));
|
||||
Log.d(TAG,string);
|
||||
return string;
|
||||
}
|
||||
|
||||
public void setContent(Map<String, List<Conference>> conferenceMap) {
|
||||
mConferenceMap = conferenceMap;
|
||||
// orderedConferencesList = new ArrayList<>(conferenceMap.keySet());
|
||||
orderedConferencesList = new ArrayList<>();
|
||||
for (String tag : ConferencesWrapper.getOrderedConferencesList()) {
|
||||
if (conferenceMap.keySet().contains(tag)) {
|
||||
orderedConferencesList.add(tag);
|
||||
}
|
||||
}
|
||||
for (String tag : conferenceMap.keySet()) {
|
||||
if (!orderedConferencesList.contains(tag)) {
|
||||
orderedConferencesList.add(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package de.nicidienase.chaosflix.touch.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.TabLayout;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.util.Log;
|
||||
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.ChaosflixBaseActivity;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Conference;
|
||||
import de.nicidienase.chaosflix.touch.ConferenceGroupsFragmentPager;
|
||||
import de.nicidienase.chaosflix.touch.fragments.ConferenceFragment;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
||||
/**
|
||||
* Created by felix on 17.09.17.
|
||||
*/
|
||||
|
||||
public class ConferencesActivity extends ChaosflixBaseActivity implements ConferenceFragment.OnListFragmentInteractionListener{
|
||||
|
||||
private static final String TAG = ConferencesActivity.class.getSimpleName();
|
||||
CompositeDisposable mDisposables = new CompositeDisposable();
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// setContentView(R.layout.touch_browse);
|
||||
setContentView(R.layout.tab_layout);
|
||||
Disposable disposable = getApiServiceObservable()
|
||||
.subscribe(mediaApiService -> {
|
||||
mediaApiService.getConferences()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(conferencesWrapper -> {
|
||||
ConferenceGroupsFragmentPager fragmentPager
|
||||
= new ConferenceGroupsFragmentPager(getSupportFragmentManager());
|
||||
fragmentPager.setContent(conferencesWrapper.getConferencesBySeries());
|
||||
|
||||
ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
|
||||
pager.setAdapter(fragmentPager);
|
||||
|
||||
TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
|
||||
tabLayout.setupWithViewPager(pager);
|
||||
});
|
||||
});
|
||||
mDisposables.add(disposable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
mDisposables.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListFragmentInteraction(Conference item) {
|
||||
Log.d(TAG,"ListItem clicked");
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
package de.nicidienase.chaosflix.touch.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Conference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
* <p/>
|
||||
* Activities containing this fragment MUST implement the {@link OnListFragmentInteractionListener}
|
||||
* interface.
|
||||
*/
|
||||
public class ConferenceFragment extends Fragment {
|
||||
|
||||
// TODO: Customize parameter argument names
|
||||
private static final String ARG_COLUMN_COUNT = "column-count";
|
||||
// TODO: Customize parameters
|
||||
private int mColumnCount = 1;
|
||||
private OnListFragmentInteractionListener mListener;
|
||||
private List<Conference> mConferences = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Mandatory empty constructor for the fragment manager to instantiate the
|
||||
* fragment (e.g. upon screen orientation changes).
|
||||
*/
|
||||
public ConferenceFragment() {
|
||||
}
|
||||
|
||||
public void setContent(List<Conference> conferences){
|
||||
mConferences = conferences;
|
||||
}
|
||||
|
||||
// TODO: Customize parameter initialization
|
||||
@SuppressWarnings("unused")
|
||||
public static ConferenceFragment newInstance(int columnCount) {
|
||||
ConferenceFragment fragment = new ConferenceFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(ARG_COLUMN_COUNT, columnCount);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getArguments() != null) {
|
||||
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_conference_list, container, false);
|
||||
|
||||
// Set the adapter
|
||||
if (view instanceof RecyclerView) {
|
||||
Context context = view.getContext();
|
||||
RecyclerView recyclerView = (RecyclerView) view;
|
||||
if (mColumnCount <= 1) {
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||
} else {
|
||||
recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));
|
||||
}
|
||||
|
||||
recyclerView.setAdapter(new ConferenceRecyclerViewAdapter(mConferences, mListener));
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof OnListFragmentInteractionListener) {
|
||||
mListener = (OnListFragmentInteractionListener) context;
|
||||
} else {
|
||||
throw new RuntimeException(context.toString()
|
||||
+ " must implement OnListFragmentInteractionListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This interface must be implemented by activities that contain this
|
||||
* fragment to allow an interaction in this fragment to be communicated
|
||||
* to the activity and potentially other fragments contained in that
|
||||
* activity.
|
||||
* <p/>
|
||||
* See the Android Training lesson <a href=
|
||||
* "http://developer.android.com/training/basics/fragments/communicating.html"
|
||||
* >Communicating with Other Fragments</a> for more information.
|
||||
*/
|
||||
public interface OnListFragmentInteractionListener {
|
||||
// TODO: Update argument type and name
|
||||
void onListFragmentInteraction(Conference item);
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
package de.nicidienase.chaosflix.touch.fragments;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
import de.nicidienase.chaosflix.R;
|
||||
import de.nicidienase.chaosflix.shared.entities.recording.Conference;
|
||||
import de.nicidienase.chaosflix.touch.fragments.ConferenceFragment.OnListFragmentInteractionListener;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ConferenceRecyclerViewAdapter extends RecyclerView.Adapter<ConferenceRecyclerViewAdapter.ViewHolder> {
|
||||
|
||||
private final List<Conference> mConferences;
|
||||
private final OnListFragmentInteractionListener mListener;
|
||||
|
||||
public ConferenceRecyclerViewAdapter(List<Conference> items, OnListFragmentInteractionListener listener) {
|
||||
mConferences = items;
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.fragment_conference, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||
holder.mItem = mConferences.get(position);
|
||||
holder.mTitleText.setText(mConferences.get(position).getTitle());
|
||||
holder.mAcronym.setText(mConferences.get(position).getAcronym());
|
||||
Glide.with(holder.mIcon.getContext())
|
||||
.load(mConferences.get(position).getLogoUrl())
|
||||
.fitCenter()
|
||||
.into(holder.mIcon);
|
||||
|
||||
holder.mView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (null != mListener) {
|
||||
// Notify the active callbacks interface (the activity, if the
|
||||
// fragment is attached to one) that an item has been selected.
|
||||
mListener.onListFragmentInteraction(holder.mItem);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mConferences.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public final View mView;
|
||||
public final ImageView mIcon;
|
||||
public final TextView mTitleText;
|
||||
public final TextView mAcronym;
|
||||
public Conference mItem;
|
||||
|
||||
public ViewHolder(View view) {
|
||||
super(view);
|
||||
mView = view;
|
||||
mIcon = (ImageView) view.findViewById(R.id.imageView);
|
||||
mTitleText = (TextView) view.findViewById(R.id.title_text);
|
||||
mAcronym = (TextView) view.findViewById(R.id.acronym_text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " '" + mTitleText.getText() + "'";
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 15 KiB |
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="-270"
|
||||
android:endColor="@color/background_gradient_end"
|
||||
android:startColor="@color/background_gradient_start"/>
|
||||
</shape>
|
Before Width: | Height: | Size: 391 KiB |
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="-270"
|
||||
android:endColor="@color/background_gradient_end"
|
||||
android:startColor="@color/background_gradient_start"/>
|
||||
</shape>
|
Before Width: | Height: | Size: 391 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 3.5 KiB |
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M18,3v2h-2L16,3L8,3v2L6,5L6,3L4,3v18h2v-2h2v2h8v-2h2v2h2L20,3h-2zM8,17L6,17v-2h2v2zM8,13L6,13v-2h2v2zM8,9L6,9L6,7h2v2zM18,17h-2v-2h2v2zM18,13h-2v-2h2v2zM18,9h-2L16,7h2v2z"/>
|
||||
</vector>
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l4,4v-11l-4,4z"/>
|
||||
</vector>
|
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 30 KiB |
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<gradient
|
||||
android:angle="90"
|
||||
android:centerColor="#00000000"
|
||||
android:endColor="#B2000000"
|
||||
android:startColor="#B2000000"
|
||||
android:type="linear"/>
|
||||
|
||||
</shape>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="de.nicidienase.chaosflix.leanback.fragments.ConferencesBrowseFragment"
|
||||
android:id="@+id/browse_fragment"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="de.nicidienase.chaosflix.leanback.fragments.ConferencesGridFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<fragment android:id="@+id/details_fragment"
|
||||
android:name="de.nicidienase.chaosflix.leanback.fragments.EventsDetailsFragment"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".leanback.activities.DetailsActivity"
|
||||
tools:deviceIds="tv"/>
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<fragment android:id="@+id/browse_fragment"
|
||||
android:name="de.nicidienase.chaosflix.leanback.fragments.EventsBrowseFragment"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".leanback.activities.EventsActivity"
|
||||
tools:deviceIds="tv"
|
||||
tools:ignore="MergeRootFrame"/>
|
|
@ -1,27 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<SurfaceView
|
||||
android:id="@+id/videoView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<fragment
|
||||
android:name="de.nicidienase.chaosflix.leanback.fragments.OverlayFragment"
|
||||
android:id="@+id/playback_controls_fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_player"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal|center"
|
||||
android:indeterminate="true"
|
||||
android:visibility="invisible"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -1,60 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:card_view="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<android.support.v7.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginRight="4dp"
|
||||
card_view:cardCornerRadius="4dp"
|
||||
android:focusable="true"
|
||||
android:clickable="true"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
app:srcCompat="@drawable/default_background"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_weight="1"
|
||||
android:text="Title"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/acronym_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Acronym"
|
||||
android:textAppearance="@style/Base.TextAppearance.AppCompat.Small"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</android.support.v7.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,38 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title_text"
|
||||
style="@style/Widget.Leanback.DetailsDescriptionTitleStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:fontFamily="sans-serif-light"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle_text"
|
||||
style="@style/Widget.Leanback.DetailsDescriptionSubtitleStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="16dp"
|
||||
android:fontFamily="sans-serif-condensed"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/speakers_text"
|
||||
style="@style/Widget.Leanback.DetailsDescriptionSubtitleStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="16dp"
|
||||
android:fontFamily="sans-serif-condensed"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description_text"
|
||||
style="@style/Widget.Leanback.DetailsDescriptionBodyStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-regular"/>
|
||||
</LinearLayout>
|
|
@ -1,60 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:card_view="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<android.support.v7.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginRight="4dp"
|
||||
card_view:cardCornerRadius="4dp"
|
||||
android:focusable="true"
|
||||
android:clickable="true"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
app:srcCompat="@drawable/default_background"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_weight="1"
|
||||
android:text="Title"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/acronym_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Acronym"
|
||||
android:textAppearance="@style/Base.TextAppearance.AppCompat.Small"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</android.support.v7.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/list"
|
||||
android:name="de.nicidienase.chaosflix.touch.fragments.ConferenceFragment"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="4dp"
|
||||
app:layoutManager="LinearLayoutManager"
|
||||
tools:context="de.nicidienase.chaosflix.touch.fragments.ConferenceFragment"
|
||||
tools:listitem="@layout/fragment_conference"/>
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/header_icon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/header_label"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/sliding_tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabMode="scrollable" />
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0px"
|
||||
android:layout_weight="1"/>
|
||||
</LinearLayout>
|
|
@ -1,18 +0,0 @@
|
|||
<resources>
|
||||
<color name="background_gradient_start">#000000</color>
|
||||
<color name="background_gradient_end">#DDDDDD</color>
|
||||
<color name="fastlane_background">#0096a6</color>
|
||||
<color name="search_opaque">#ffaa3f</color>
|
||||
<color name="selected_background">#ffaa3f</color>
|
||||
<color name="detail_background">#0096a6</color>
|
||||
<color name="soft_opaque">#30000000</color>
|
||||
<color name="img_soft_opaque">#30FF0000</color>
|
||||
<color name="img_full_opaque">#00000000</color>
|
||||
<color name="black_opaque">#AA000000</color>
|
||||
<color name="black">#59000000</color>
|
||||
<color name="white">#FFFFFF</color>
|
||||
<color name="orange_transparent">#AAFADCA7</color>
|
||||
<color name="orange">#FADCA7</color>
|
||||
<color name="yellow">#EEFF41</color>
|
||||
<color name="default_background">#3d3d3d</color>
|
||||
</resources>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="detail_thumb_width">274dp</dimen>
|
||||
<dimen name="detail_thumb_height">274dp</dimen>
|
||||
<dimen name="spinner_width">50dp</dimen>
|
||||
<dimen name="spinner_height">50dp</dimen>
|
||||
</resources>
|
|
@ -1,40 +0,0 @@
|
|||
<resources>
|
||||
<string name="api_media_ccc_url">https://api.media.ccc.de</string>
|
||||
<string name="streaming_media_ccc_url">https://streaming.media.ccc.de</string>
|
||||
<!--<string name="streaming_media_ccc_url">http://192.168.178.98:8000</string>-->
|
||||
|
||||
<string name="app_name">Chaosflix</string>
|
||||
<string name="related_movies">Related Videos</string>
|
||||
<string name="error">Error</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="pause">Pause</string>
|
||||
<string name="play">Play</string>
|
||||
<string name="stop">Stop</string>
|
||||
|
||||
|
||||
<string name="video_error_media_load_timeout">Media loading timed out</string>
|
||||
<string name="video_error_server_inaccessible">Media server was not reachable</string>
|
||||
<string name="video_error_unknown_error">Failed to load video</string>
|
||||
<string name="error_fragment_message">An error occurred</string>
|
||||
<string name="dismiss_error">Dismiss</string>
|
||||
<string name="oops">Oops</string>
|
||||
<string name="random_talks_on_this_track">Random Talks in the same Track</string>
|
||||
<string name="random_talks">Other random Talks at this Conference</string>
|
||||
<string name="resume_question">Resume previous position or start from beginning</string>
|
||||
<string name="start_again">Start again</string>
|
||||
<string name="resume">Resume</string>
|
||||
<string name="related_talks">Related Talks</string>
|
||||
<string name="recomendations">Recomendations</string>
|
||||
<string name="watchlist">Watchlist</string>
|
||||
<string name="recordings">Recordings</string>
|
||||
<string name="streaming_prefix">[streaming]</string>
|
||||
<string name="conferences">Conferences</string>
|
||||
<string name="remove_from_watchlist">Remove from Watchlist</string>
|
||||
<string name="add_to_watchlist">Add to Watchlist</string>
|
||||
<string name="streams">Streams</string>
|
||||
<string name="livestreams">Livestreams</string>
|
||||
<string name="watchlist_message">You can find you watchlist on the Homescreen of Chaosflix</string>
|
||||
<string name="watchlist_preferences_key">watchlist</string>
|
||||
<string name="watchlist_dialog_needed">new-watchlist</string>
|
||||
<string name="return_to_homescreen">Return to Homescreen</string>
|
||||
</resources>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme" parent="@style/Theme.Leanback">
|
||||
</style>
|
||||
</resources>
|
|
@ -1,14 +0,0 @@
|
|||
<resources>
|
||||
|
||||
<style name="Theme.Example.Leanback" parent="Theme.Leanback">
|
||||
<item name="android:windowEnterTransition">@android:transition/fade</item>
|
||||
<item name="android:windowExitTransition">@android:transition/fade</item>
|
||||
<item name="android:windowSharedElementExitTransition">@android:transition/move</item>
|
||||
<item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
|
||||
<item name="android:windowAllowReturnTransitionOverlap">true</item>
|
||||
<item name="android:windowAllowEnterTransitionOverlap">true</item>
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
<item name="android:colorPrimary">@color/search_opaque</item>
|
||||
|
||||
</style>
|
||||
</resources>
|
|
@ -1,31 +0,0 @@
|
|||
package de.nicidienase.chaosflix;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.support.multidex.MultiDex;
|
||||
|
||||
import com.orm.SugarContext;
|
||||
|
||||
/**
|
||||
* Created by felix on 18.03.17.
|
||||
*/
|
||||
|
||||
public class ChaosflixApplication extends Application {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
SugarContext.init(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTerminate() {
|
||||
SugarContext.terminate();
|
||||
super.onTerminate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
MultiDex.install(base);
|
||||
super.attachBaseContext(base);
|
||||
}
|
||||
}
|
0
app/.gitignore → common/.gitignore
vendored
49
common/build.gradle
Normal file
|
@ -0,0 +1,49 @@
|
|||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion "25.0.2"
|
||||
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 25
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'com.android.support:appcompat-v7:25.4.0'
|
||||
compile 'com.github.satyan:sugar:1.4'
|
||||
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
|
||||
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
|
||||
|
||||
compile 'com.squareup.retrofit2:retrofit:2.2.0'
|
||||
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
|
||||
compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
|
||||
compile 'joda-time:joda-time:2.9.9'
|
||||
compile 'org.joda:joda-convert:1.8'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.1', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
|
||||
}
|
21
common/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
2
common/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<manifest package="de.nicidienase.chaosflix"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"/>
|
|
@ -74,8 +74,8 @@ public class ConferencesWrapper {
|
|||
|
||||
public static List<String> getOrderedConferencesList() {
|
||||
return Arrays.asList("congress", "sendezentrum", "camp",
|
||||
"broadcast/chaosradio", "eh", "gpn",
|
||||
"froscon", "mrmcd", "sigint",
|
||||
"gpn", "mrmcd", "broadcast/chaosradio",
|
||||
"eh", "froscon", "sigint",
|
||||
"datenspuren", "fiffkon", "cryptocon");
|
||||
}
|
||||
|
5
common/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<resources>
|
||||
<string name="app_name">Chaosflix-Common</string>
|
||||
<string name="api_media_ccc_url">https://api.media.ccc.de</string>
|
||||
<string name="streaming_media_ccc_url">https://streaming.media.ccc.de</string>
|
||||
</resources>
|