mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-29 19:20:28 +00:00
Fixed StreamProxy filename generation to take url params into account.
Also converted StreamProxy to kotlin.
This commit is contained in:
parent
8a04959d6b
commit
1d8cfd8c7c
@ -44,7 +44,7 @@ public abstract class OfflineDb extends RoomDatabase {
|
||||
List<String> toDelete = new ArrayList<>();
|
||||
|
||||
for (final String uri : uris) {
|
||||
if (!StreamProxy.isCached(uri)) {
|
||||
if (!StreamProxy.Companion.isCached(uri)) {
|
||||
toDelete.add(uri);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import com.danikula.videocache.CacheListener
|
||||
import com.google.android.exoplayer2.*
|
||||
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
|
||||
@ -61,7 +62,7 @@ class ExoPlayerWrapper : PlayerWrapper() {
|
||||
}
|
||||
|
||||
val builder = OkHttpClient.Builder()
|
||||
.cache(Cache(path, CACHE_SETTING_TO_BYTES[diskCacheIndex] ?: MINIMUM_CACHE_SIZE_BYTES))
|
||||
.cache(Cache(path, StreamProxy.CACHE_SETTING_TO_BYTES[diskCacheIndex] ?: StreamProxy.MINIMUM_CACHE_SIZE_BYTES))
|
||||
.addInterceptor { chain ->
|
||||
var request = chain.request()
|
||||
val userPass = "default:" + prefs.getString(Prefs.Key.PASSWORD, Prefs.Default.PASSWORD)!!
|
||||
@ -110,7 +111,7 @@ class ExoPlayerWrapper : PlayerWrapper() {
|
||||
|
||||
this.metadata = metadata
|
||||
this.originalUri = uri
|
||||
this.proxyUri = StreamProxy.getProxyUrl(context, uri)
|
||||
this.proxyUri = StreamProxy.getProxyUrl(uri)
|
||||
Log.d("ExoPlayerWrapper", "originalUri: ${this.originalUri} proxyUri: ${this.proxyUri}")
|
||||
|
||||
addCacheListener()
|
||||
@ -131,7 +132,7 @@ class ExoPlayerWrapper : PlayerWrapper() {
|
||||
|
||||
this.metadata = metadata
|
||||
this.originalUri = uri
|
||||
this.proxyUri = StreamProxy.getProxyUrl(context, uri)
|
||||
this.proxyUri = StreamProxy.getProxyUrl(uri)
|
||||
Log.d("ExoPlayerWrapper", "originalUri: ${this.originalUri} proxyUri: ${this.proxyUri}")
|
||||
|
||||
this.prefetch = true
|
||||
@ -251,7 +252,7 @@ class ExoPlayerWrapper : PlayerWrapper() {
|
||||
|
||||
private fun addCacheListener() {
|
||||
if (StreamProxy.ENABLED) {
|
||||
if (StreamProxy.isCached(this.originalUri)) {
|
||||
if (StreamProxy.isCached(this.originalUri!!)) {
|
||||
percentAvailable = 100
|
||||
|
||||
if (originalUri != null && metadata != null) {
|
||||
@ -259,7 +260,7 @@ class ExoPlayerWrapper : PlayerWrapper() {
|
||||
}
|
||||
}
|
||||
else {
|
||||
StreamProxy.registerCacheListener(this.cacheListener, this.originalUri)
|
||||
StreamProxy.registerCacheListener(this.cacheListener, this.originalUri!!)
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -273,13 +274,13 @@ class ExoPlayerWrapper : PlayerWrapper() {
|
||||
}
|
||||
}
|
||||
|
||||
private val cacheListener = { _: File, _: String, percent: Int ->
|
||||
private val cacheListener = CacheListener { _: File, _: String, percent: Int ->
|
||||
//Log.e("CLCLCL", String.format("%d", percent));
|
||||
percentAvailable = percent
|
||||
|
||||
if (percentAvailable >= 100) {
|
||||
if (originalUri != null && metadata != null) {
|
||||
PlayerWrapper.storeOffline(originalUri!!, metadata!!)
|
||||
storeOffline(originalUri!!, metadata!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ class MediaPlayerWrapper : PlayerWrapper() {
|
||||
|
||||
this.metadata = metadata
|
||||
this.originalUri = uri
|
||||
this.proxyUri = StreamProxy.getProxyUrl(context, uri)
|
||||
this.proxyUri = StreamProxy.getProxyUrl(uri)
|
||||
|
||||
player.setDataSource(context, Uri.parse(proxyUri), headers)
|
||||
player.setAudioStreamType(AudioManager.STREAM_MUSIC)
|
||||
|
@ -1,124 +0,0 @@
|
||||
package io.casey.musikcube.remote.playback;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.util.Base64;
|
||||
|
||||
import com.danikula.videocache.CacheListener;
|
||||
import com.danikula.videocache.HttpProxyCacheServer;
|
||||
import com.danikula.videocache.file.FileNameGenerator;
|
||||
import com.danikula.videocache.file.Md5FileNameGenerator;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.casey.musikcube.remote.util.NetworkUtil;
|
||||
import io.casey.musikcube.remote.websocket.Prefs;
|
||||
|
||||
public class StreamProxy {
|
||||
public static final boolean ENABLED = true;
|
||||
public static final long BYTES_PER_MEGABYTE = 1048576L;
|
||||
public static final long BYTES_PER_GIGABYTE = 1073741824L;
|
||||
public static final long MINIMUM_CACHE_SIZE_BYTES = BYTES_PER_MEGABYTE * 32;
|
||||
public static final Map<Integer, Long> CACHE_SETTING_TO_BYTES;
|
||||
private static final FileNameGenerator DEFAULT_FILENAME_GENERATOR = new Md5FileNameGenerator();
|
||||
|
||||
static {
|
||||
CACHE_SETTING_TO_BYTES = new HashMap<>();
|
||||
CACHE_SETTING_TO_BYTES.put(0, MINIMUM_CACHE_SIZE_BYTES);
|
||||
CACHE_SETTING_TO_BYTES.put(1, BYTES_PER_GIGABYTE / 2);
|
||||
CACHE_SETTING_TO_BYTES.put(2, BYTES_PER_GIGABYTE);
|
||||
CACHE_SETTING_TO_BYTES.put(3, BYTES_PER_GIGABYTE * 2);
|
||||
CACHE_SETTING_TO_BYTES.put(4, BYTES_PER_GIGABYTE * 3);
|
||||
CACHE_SETTING_TO_BYTES.put(5, BYTES_PER_GIGABYTE * 4);
|
||||
}
|
||||
|
||||
private static StreamProxy INSTANCE;
|
||||
|
||||
private HttpProxyCacheServer proxy;
|
||||
private SharedPreferences prefs;
|
||||
|
||||
private StreamProxy(final Context context) {
|
||||
prefs = context.getSharedPreferences(Prefs.NAME, Context.MODE_PRIVATE);
|
||||
|
||||
if (this.prefs.getBoolean(Prefs.Key.CERT_VALIDATION_DISABLED, Prefs.Default.CERT_VALIDATION_DISABLED)) {
|
||||
NetworkUtil.disableCertificateValidation();
|
||||
}
|
||||
else {
|
||||
NetworkUtil.enableCertificateValidation();
|
||||
}
|
||||
|
||||
int diskCacheIndex = this.prefs.getInt(
|
||||
Prefs.Key.DISK_CACHE_SIZE_INDEX, Prefs.Default.DISK_CACHE_SIZE_INDEX);
|
||||
|
||||
if (diskCacheIndex < 0 || diskCacheIndex > CACHE_SETTING_TO_BYTES.size()) {
|
||||
diskCacheIndex = 0;
|
||||
}
|
||||
|
||||
final File cachePath = new File(context.getExternalCacheDir(), "audio");
|
||||
|
||||
proxy = new HttpProxyCacheServer.Builder(context.getApplicationContext())
|
||||
.cacheDirectory(cachePath)
|
||||
.maxCacheSize(CACHE_SETTING_TO_BYTES.get(diskCacheIndex))
|
||||
.headerInjector((url) -> {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
final String userPass = "default:" + prefs.getString(Prefs.Key.PASSWORD, Prefs.Default.PASSWORD);
|
||||
final String encoded = Base64.encodeToString(userPass.getBytes(), Base64.NO_WRAP);
|
||||
headers.put("Authorization", "Basic " + encoded);
|
||||
return headers;
|
||||
})
|
||||
.fileNameGenerator((url) -> {
|
||||
try {
|
||||
final Uri uri = Uri.parse(url);
|
||||
/* format is: audio/external_id/<id> */
|
||||
final List<String> segments = uri.getPathSegments();
|
||||
if (segments.size() == 3 && "external_id".equals(segments.get(1))) {
|
||||
return segments.get(2); /* id, should be globally unique. */
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
/* eh... */
|
||||
}
|
||||
return DEFAULT_FILENAME_GENERATOR.generate(url);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public static synchronized void init(final Context context) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new StreamProxy(context.getApplicationContext());
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void registerCacheListener(final CacheListener cl, final String uri) {
|
||||
if (INSTANCE != null && cl != null) {
|
||||
INSTANCE.proxy.registerCacheListener(cl, uri); /* let it throw */
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void unregisterCacheListener(final CacheListener cl) {
|
||||
if (INSTANCE != null && cl != null) {
|
||||
INSTANCE.proxy.unregisterCacheListener(cl);
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized boolean isCached(final String url) {
|
||||
return INSTANCE != null && INSTANCE.proxy.isCached(url);
|
||||
}
|
||||
|
||||
public static synchronized String getProxyUrl(final Context context, final String url) {
|
||||
init(context);
|
||||
return ENABLED ? INSTANCE.proxy.getProxyUrl(url) : url;
|
||||
}
|
||||
|
||||
public static synchronized void reload() {
|
||||
if (INSTANCE != null) {
|
||||
INSTANCE.proxy.shutdown();
|
||||
INSTANCE = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package io.casey.musikcube.remote.playback
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.util.Base64
|
||||
import com.danikula.videocache.CacheListener
|
||||
import com.danikula.videocache.HttpProxyCacheServer
|
||||
import com.danikula.videocache.file.Md5FileNameGenerator
|
||||
import io.casey.musikcube.remote.Application
|
||||
import io.casey.musikcube.remote.util.NetworkUtil
|
||||
import io.casey.musikcube.remote.util.Strings
|
||||
import io.casey.musikcube.remote.websocket.Prefs
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class StreamProxy private constructor(context: Context) {
|
||||
private val proxy: HttpProxyCacheServer
|
||||
private val prefs: SharedPreferences
|
||||
|
||||
init {
|
||||
prefs = context.getSharedPreferences(Prefs.NAME, Context.MODE_PRIVATE)
|
||||
|
||||
if (this.prefs.getBoolean(Prefs.Key.CERT_VALIDATION_DISABLED, Prefs.Default.CERT_VALIDATION_DISABLED)) {
|
||||
NetworkUtil.disableCertificateValidation()
|
||||
}
|
||||
else {
|
||||
NetworkUtil.enableCertificateValidation()
|
||||
}
|
||||
|
||||
var diskCacheIndex = this.prefs.getInt(
|
||||
Prefs.Key.DISK_CACHE_SIZE_INDEX, Prefs.Default.DISK_CACHE_SIZE_INDEX)
|
||||
|
||||
if (diskCacheIndex < 0 || diskCacheIndex > CACHE_SETTING_TO_BYTES.size) {
|
||||
diskCacheIndex = 0
|
||||
}
|
||||
|
||||
val cachePath = File(context.externalCacheDir, "audio")
|
||||
|
||||
proxy = HttpProxyCacheServer.Builder(context.applicationContext)
|
||||
.cacheDirectory(cachePath)
|
||||
.maxCacheSize(CACHE_SETTING_TO_BYTES[diskCacheIndex] ?: MINIMUM_CACHE_SIZE_BYTES)
|
||||
.headerInjector { url ->
|
||||
val headers = HashMap<String, String>()
|
||||
val userPass = "default:" + prefs.getString(Prefs.Key.PASSWORD, Prefs.Default.PASSWORD)!!
|
||||
val encoded = Base64.encodeToString(userPass.toByteArray(), Base64.NO_WRAP)
|
||||
headers.put("Authorization", "Basic " + encoded)
|
||||
headers
|
||||
}
|
||||
.fileNameGenerator { url ->
|
||||
try {
|
||||
val uri = Uri.parse(url)
|
||||
/* format is: audio/external_id/<id> */
|
||||
val segments = uri.pathSegments
|
||||
if (segments.size == 3 && "external_id" == segments[1]) {
|
||||
/* url params, hyphen separated */
|
||||
var params = uri.query
|
||||
if (Strings.notEmpty(params)) {
|
||||
params = "-" + params
|
||||
.replace("?", "-")
|
||||
.replace("&", "-")
|
||||
.replace("=", "-")
|
||||
}
|
||||
else {
|
||||
params = ""
|
||||
}
|
||||
|
||||
"${segments[2]}-$params"
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
/* eh... */
|
||||
}
|
||||
|
||||
DEFAULT_FILENAME_GENERATOR.generate(url)
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ENABLED = true
|
||||
val BYTES_PER_MEGABYTE = 1048576L
|
||||
val BYTES_PER_GIGABYTE = 1073741824L
|
||||
val MINIMUM_CACHE_SIZE_BYTES = BYTES_PER_MEGABYTE * 128
|
||||
val CACHE_SETTING_TO_BYTES: MutableMap<Int, Long>
|
||||
private val DEFAULT_FILENAME_GENERATOR = Md5FileNameGenerator()
|
||||
|
||||
init {
|
||||
CACHE_SETTING_TO_BYTES = HashMap<Int, Long>()
|
||||
CACHE_SETTING_TO_BYTES.put(0, MINIMUM_CACHE_SIZE_BYTES)
|
||||
CACHE_SETTING_TO_BYTES.put(1, BYTES_PER_GIGABYTE / 2)
|
||||
CACHE_SETTING_TO_BYTES.put(2, BYTES_PER_GIGABYTE)
|
||||
CACHE_SETTING_TO_BYTES.put(3, BYTES_PER_GIGABYTE * 2)
|
||||
CACHE_SETTING_TO_BYTES.put(4, BYTES_PER_GIGABYTE * 3)
|
||||
CACHE_SETTING_TO_BYTES.put(5, BYTES_PER_GIGABYTE * 4)
|
||||
}
|
||||
|
||||
private var INSTANCE: StreamProxy? = null
|
||||
|
||||
@Synchronized fun init(context: Context) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = StreamProxy(context.applicationContext)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized fun registerCacheListener(cl: CacheListener, uri: String) {
|
||||
if (INSTANCE != null) {
|
||||
INSTANCE!!.proxy.registerCacheListener(cl, uri) /* let it throw */
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized fun unregisterCacheListener(cl: CacheListener) {
|
||||
if (INSTANCE != null) {
|
||||
INSTANCE!!.proxy.unregisterCacheListener(cl)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized fun isCached(url: String): Boolean {
|
||||
return INSTANCE != null && INSTANCE!!.proxy.isCached(url)
|
||||
}
|
||||
|
||||
@Synchronized fun getProxyUrl(url: String): String {
|
||||
init(Application.instance!!)
|
||||
return if (ENABLED) INSTANCE!!.proxy.getProxyUrl(url) else url
|
||||
}
|
||||
|
||||
@Synchronized fun reload() {
|
||||
if (INSTANCE != null) {
|
||||
INSTANCE!!.proxy.shutdown()
|
||||
INSTANCE = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -211,7 +211,7 @@ public class SettingsActivity extends AppCompatActivity {
|
||||
PlaybackServiceFactory.streaming(this).stop();
|
||||
}
|
||||
|
||||
StreamProxy.reload();
|
||||
StreamProxy.Companion.reload();
|
||||
WebSocketService.getInstance(this).disconnect();
|
||||
|
||||
finish();
|
||||
|
Loading…
x
Reference in New Issue
Block a user