mirror of
https://github.com/antebudimir/tempus.git
synced 2026-04-15 16:27:26 +00:00
feat: prefer locally downloaded media vs server stream (#433)
resolves #404 and should address #285
This commit is contained in:
parent
3958cbcc1c
commit
dbd32baa12
5 changed files with 84 additions and 28 deletions
|
|
@ -11,7 +11,7 @@ android {
|
||||||
targetSdk 35
|
targetSdk 35
|
||||||
|
|
||||||
versionCode 19
|
versionCode 19
|
||||||
versionName '4.10.1'
|
versionName '4.10.2'
|
||||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||||
|
|
||||||
javaCompileOptions {
|
javaCompileOptions {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import android.content.ServiceConnection;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
@ -236,43 +237,64 @@ public class PlayerControllerFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setMediaInfo(MediaMetadata mediaMetadata) {
|
private void setMediaInfo(MediaMetadata mediaMetadata) {
|
||||||
|
boolean isLocal = false;
|
||||||
|
|
||||||
|
if (mediaBrowserListenableFuture != null && mediaBrowserListenableFuture.isDone()) {
|
||||||
|
try {
|
||||||
|
MediaBrowser browser = mediaBrowserListenableFuture.get();
|
||||||
|
if (browser != null && browser.getCurrentMediaItem() != null) {
|
||||||
|
android.net.Uri currentUri = browser.getCurrentMediaItem().requestMetadata.mediaUri;
|
||||||
|
if (currentUri != null) {
|
||||||
|
String scheme = currentUri.getScheme();
|
||||||
|
isLocal = "content".equals(scheme) || "file".equals(scheme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("DEBUG_PLAYER", "Error getting browser for UI update", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mediaMetadata.extras != null) {
|
if (mediaMetadata.extras != null) {
|
||||||
String extension = mediaMetadata.extras.getString("suffix", getString(R.string.player_unknown_format));
|
String extension = mediaMetadata.extras.getString("suffix", getString(R.string.player_unknown_format));
|
||||||
String bitrate = mediaMetadata.extras.getInt("bitrate", 0) != 0 ? mediaMetadata.extras.getInt("bitrate", 0) + "kbps" : "Original";
|
int rawBitrate = mediaMetadata.extras.getInt("bitrate", 0);
|
||||||
String samplingRate = mediaMetadata.extras.getInt("samplingRate", 0) != 0 ? new DecimalFormat("0.#").format(mediaMetadata.extras.getInt("samplingRate", 0) / 1000.0) + "kHz" : "";
|
String bitrate = rawBitrate != 0 ? rawBitrate + "kbps" : "Original";
|
||||||
|
String samplingRate = mediaMetadata.extras.getInt("samplingRate", 0) != 0 ?
|
||||||
|
new java.text.DecimalFormat("0.#").format(mediaMetadata.extras.getInt("samplingRate", 0) / 1000.0) + "kHz" : "";
|
||||||
String bitDepth = mediaMetadata.extras.getInt("bitDepth", 0) != 0 ? mediaMetadata.extras.getInt("bitDepth", 0) + "b" : "";
|
String bitDepth = mediaMetadata.extras.getInt("bitDepth", 0) != 0 ? mediaMetadata.extras.getInt("bitDepth", 0) + "b" : "";
|
||||||
|
|
||||||
playerMediaExtension.setText(extension);
|
playerMediaExtension.setText(extension);
|
||||||
|
|
||||||
if (bitrate.equals("Original")) {
|
if (bitrate.equals("Original") && !isLocal) {
|
||||||
playerMediaBitrate.setVisibility(View.GONE);
|
playerMediaBitrate.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
List<String> mediaQualityItems = new ArrayList<>();
|
List<String> items = new ArrayList<>();
|
||||||
|
if (!bitrate.trim().isEmpty()) items.add(bitrate);
|
||||||
if (!bitrate.trim().isEmpty()) mediaQualityItems.add(bitrate);
|
if (!bitDepth.trim().isEmpty()) items.add(bitDepth);
|
||||||
if (!bitDepth.trim().isEmpty()) mediaQualityItems.add(bitDepth);
|
if (!samplingRate.trim().isEmpty()) items.add(samplingRate);
|
||||||
if (!samplingRate.trim().isEmpty()) mediaQualityItems.add(samplingRate);
|
String mediaQuality = TextUtils.join(" • ", items);
|
||||||
|
|
||||||
String mediaQuality = TextUtils.join(" • ", mediaQualityItems);
|
|
||||||
playerMediaBitrate.setVisibility(View.VISIBLE);
|
playerMediaBitrate.setVisibility(View.VISIBLE);
|
||||||
playerMediaBitrate.setText(mediaQuality);
|
playerMediaBitrate.setText(isLocal ? mediaQuality : mediaQuality);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isTranscodingExtension = !MusicUtil.getTranscodingFormatPreference().equals("raw");
|
|
||||||
boolean isTranscodingBitrate = !MusicUtil.getBitratePreference().equals("0");
|
if (!isLocal) {
|
||||||
|
boolean isTranscodingExtension = !MusicUtil.getTranscodingFormatPreference().equals("raw");
|
||||||
|
boolean isTranscodingBitrate = !MusicUtil.getBitratePreference().equals("0");
|
||||||
|
if (isTranscodingExtension || isTranscodingBitrate) {
|
||||||
|
playerMediaExtension.setText(MusicUtil.getTranscodingFormatPreference() + " (" + getString(R.string.player_transcoding) + ")");
|
||||||
|
playerMediaBitrate.setText(!MusicUtil.getBitratePreference().equals("0") ?
|
||||||
|
MusicUtil.getBitratePreference() + "kbps" : getString(R.string.player_transcoding_requested));
|
||||||
|
}
|
||||||
|
|
||||||
if (isTranscodingExtension || isTranscodingBitrate) {
|
|
||||||
playerMediaExtension.setText(MusicUtil.getTranscodingFormatPreference() + " (" + getString(R.string.player_transcoding) + ")");
|
|
||||||
playerMediaBitrate.setText(!MusicUtil.getBitratePreference().equals("0") ? MusicUtil.getBitratePreference() + "kbps" : getString(R.string.player_transcoding_requested));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
playerTrackInfo.setOnClickListener(view -> {
|
playerTrackInfo.setOnClickListener(view -> {
|
||||||
TrackInfoDialog dialog = new TrackInfoDialog(mediaMetadata);
|
TrackInfoDialog dialog = new TrackInfoDialog(mediaMetadata);
|
||||||
dialog.show(activity.getSupportFragmentManager(), null);
|
dialog.show(activity.getSupportFragmentManager(), null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAssetLinkChips(MediaMetadata mediaMetadata) {
|
private void updateAssetLinkChips(MediaMetadata mediaMetadata) {
|
||||||
if (assetLinkChipGroup == null) return;
|
if (assetLinkChipGroup == null) return;
|
||||||
String mediaType = mediaMetadata.extras != null ? mediaMetadata.extras.getString("type", Constants.MEDIA_TYPE_MUSIC) : Constants.MEDIA_TYPE_MUSIC;
|
String mediaType = mediaMetadata.extras != null ? mediaMetadata.extras.getString("type", Constants.MEDIA_TYPE_MUSIC) : Constants.MEDIA_TYPE_MUSIC;
|
||||||
|
|
|
||||||
|
|
@ -288,13 +288,24 @@ public class MappingUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Uri getUri(Child media) {
|
private static Uri getUri(Child media) {
|
||||||
|
// Check if it's in our local SQL Database
|
||||||
|
DownloadRepository repo = new DownloadRepository();
|
||||||
|
Download localDownload = repo.getDownload(media.getId());
|
||||||
|
|
||||||
|
if (localDownload != null && localDownload.getDownloadUri() != null && !localDownload.getDownloadUri().isEmpty()) {
|
||||||
|
Log.d(TAG, "Playing local file for: " + media.getTitle());
|
||||||
|
return Uri.parse(localDownload.getDownloadUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy check for external directory, i think this was broken/buggy
|
||||||
if (Preferences.getDownloadDirectoryUri() != null) {
|
if (Preferences.getDownloadDirectoryUri() != null) {
|
||||||
Uri local = ExternalAudioReader.getUri(media);
|
Uri local = ExternalAudioReader.getUri(media);
|
||||||
return local != null ? local : MusicUtil.getStreamUri(media.getId());
|
if (local != null) return local;
|
||||||
}
|
}
|
||||||
return DownloadUtil.getDownloadTracker(App.getContext()).isDownloaded(media.getId())
|
|
||||||
? getDownloadUri(media.getId())
|
// Fallback to streaming
|
||||||
: MusicUtil.getStreamUri(media.getId());
|
Log.d(TAG, "No local file found. Streaming: " + media.getTitle());
|
||||||
|
return MusicUtil.getStreamUri(media.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Uri getUri(PodcastEpisode podcastEpisode) {
|
private static Uri getUri(PodcastEpisode podcastEpisode) {
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,10 @@ public class MusicUtil {
|
||||||
if (params.containsKey("c") && params.get("c") != null)
|
if (params.containsKey("c") && params.get("c") != null)
|
||||||
uri.append("&c=").append(params.get("c"));
|
uri.append("&c=").append(params.get("c"));
|
||||||
|
|
||||||
|
String selectedBitrate = getBitratePreference();
|
||||||
|
String selectedFormat = getTranscodingFormatPreference();
|
||||||
|
Log.i(TAG, "DEBUG: Requesting Format: " + selectedFormat + " at Bitrate: " + selectedBitrate);
|
||||||
|
|
||||||
if (!Preferences.isServerPrioritized())
|
if (!Preferences.isServerPrioritized())
|
||||||
uri.append("&maxBitRate=").append(getBitratePreference());
|
uri.append("&maxBitRate=").append(getBitratePreference());
|
||||||
if (!Preferences.isServerPrioritized())
|
if (!Preferences.isServerPrioritized())
|
||||||
|
|
@ -73,7 +77,17 @@ public class MusicUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri updateStreamUri(Uri uri) {
|
public static Uri updateStreamUri(Uri uri) {
|
||||||
|
if (uri == null) return null;
|
||||||
|
|
||||||
|
String scheme = uri.getScheme();
|
||||||
|
// If it is local (content:// or file://), return it IMMEDIATELY.
|
||||||
|
// This prevents the code below from appending &maxBitRate to a local path.
|
||||||
|
if (scheme != null && (scheme.equals("content") || scheme.equals("file"))) {
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
String s = uri.toString();
|
String s = uri.toString();
|
||||||
|
|
||||||
Matcher m1 = BITRATE_PATTERN.matcher(s);
|
Matcher m1 = BITRATE_PATTERN.matcher(s);
|
||||||
s = m1.replaceAll("");
|
s = m1.replaceAll("");
|
||||||
Matcher m2 = FORMAT_PATTERN.matcher(s);
|
Matcher m2 = FORMAT_PATTERN.matcher(s);
|
||||||
|
|
@ -157,7 +171,6 @@ public class MusicUtil {
|
||||||
return Uri.parse(uri.toString());
|
return Uri.parse(uri.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static String getReadableDurationString(Long duration, boolean millis) {
|
public static String getReadableDurationString(Long duration, boolean millis) {
|
||||||
long lenght = duration != null ? duration : 0;
|
long lenght = duration != null ? duration : 0;
|
||||||
|
|
||||||
|
|
@ -303,13 +316,17 @@ public class MusicUtil {
|
||||||
|
|
||||||
if (network == null || networkCapabilities == null) return "raw";
|
if (network == null || networkCapabilities == null) return "raw";
|
||||||
|
|
||||||
|
String format;
|
||||||
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
||||||
return Preferences.getAudioTranscodeFormatWifi();
|
format = Preferences.getAudioTranscodeFormatWifi();
|
||||||
|
Log.d(TAG, "DEBUG: Using WIFI Format: " + format);
|
||||||
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||||
return Preferences.getAudioTranscodeFormatMobile();
|
format = Preferences.getAudioTranscodeFormatMobile();
|
||||||
|
Log.d(TAG, "DEBUG: Using MOBILE Format: " + format);
|
||||||
} else {
|
} else {
|
||||||
return Preferences.getAudioTranscodeFormatWifi();
|
format = Preferences.getAudioTranscodeFormatWifi();
|
||||||
}
|
}
|
||||||
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getBitratePreferenceForDownload() {
|
public static String getBitratePreferenceForDownload() {
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,18 @@ class TranscodingMediaSource(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val extras = mediaItem.mediaMetadata.extras
|
val extras = mediaItem.mediaMetadata.extras
|
||||||
if (extras != null && extras.containsKey("duration")) {
|
val uri = mediaItem.localConfiguration?.uri
|
||||||
|
val isLocal = uri?.scheme == "content" || uri?.scheme == "file"
|
||||||
|
|
||||||
|
// Only apply the override if it's NOT a local file
|
||||||
|
if (!isLocal && extras != null && extras.containsKey("duration")) {
|
||||||
val seconds = extras.getInt("duration")
|
val seconds = extras.getInt("duration")
|
||||||
if (seconds > 0) {
|
if (seconds > 0) {
|
||||||
durationUs = Util.msToUs(seconds * 1000L)
|
durationUs = Util.msToUs(seconds * 1000L)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentSource = progressiveMediaSourceFactory.createMediaSource(mediaItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMediaItem() = mediaItem
|
override fun getMediaItem() = mediaItem
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue