Compare commits

...

8 Commits

Author SHA1 Message Date
Niels van Velzen
429b6601d6 Don't wait for bitrate detection on launch
Also catch errors

(cherry picked from commit 7fc63f56d8)
2021-10-21 18:45:54 +02:00
Niels van Velzen
4ebc3e1f50 Change default video player to ExoPlayer instead of auto detect
(cherry picked from commit 65f4b75673)
2021-10-21 18:40:43 +02:00
Cameron
9a41127a4d "select" button on controller can now pause/unpause without extra navigation (#1207)
* fixed issue #1101

overrides PlaybackTransportRowPresenter's onProgressBarClicked to use CustomPlaybackTransportControlGlue's playPauseAction. Perhaps the lowercase 'p' is to blame for the default implementation not working.

* Update app/src/main/java/org/jellyfin/androidtv/ui/playback/overlay/CustomPlaybackTransportControlGlue.java

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>
(cherry picked from commit b59543c05e)
2021-10-21 18:40:32 +02:00
Niels van Velzen
4010c2e839 Fix trailing slashes causing connection issues in apiclient
(cherry picked from commit cb43e9024b)
2021-10-21 18:40:11 +02:00
Niels van Velzen
d8af891489 Act when setActiveSession returns false during login
(cherry picked from commit 283f75f5c7)
2021-10-21 18:40:01 +02:00
Niels van Velzen
b4753ebeae Fix skipBackwardLength instead of skipBackLength (#1182)
(cherry picked from commit 379e3e7c2c)
2021-10-07 18:51:42 +02:00
Niels van Velzen
e300dd4187 Check nullability for mFragment in PlaybackController
(cherry picked from commit f9fa23953f)
2021-10-07 18:51:28 +02:00
Niels van Velzen
f7dee09fd3 Remove build number from internal version reference
This fixes the "server version not supported" toast from showing the build number. 10.7.7.0 now shows as 10.7.7

(cherry picked from commit 9e48578366)
2021-10-07 18:51:19 +02:00
8 changed files with 55 additions and 41 deletions

View File

@@ -6,8 +6,10 @@ import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.work.*
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.acra.config.dialog
import org.acra.config.httpSender
import org.acra.config.limiter
@@ -87,6 +89,7 @@ class JellyfinApplication : TvApp(), LifecycleObserver {
/**
* Called from the StartupActivity when the user session is started.
*/
@DelicateCoroutinesApi
suspend fun onSessionStart() {
val workManager by inject<WorkManager>()
val autoBitrate by inject<AutoBitrate>()
@@ -104,9 +107,7 @@ class JellyfinApplication : TvApp(), LifecycleObserver {
).await()
// Detect auto bitrate
withContext(Dispatchers.IO) {
autoBitrate.detect()
}
GlobalScope.launch(Dispatchers.IO) { autoBitrate.detect() }
}
override fun attachBaseContext(base: Context?) {

View File

@@ -51,7 +51,7 @@ class ApiBinder(
api.EnableAutomaticNetworking(ServerInfo().apply {
id = session.serverId.toString()
name = server.name
address = server.address
address = server.address.removeSuffix("/")
userId = session.userId.toString()
accessToken = session.accessToken
})

View File

@@ -219,7 +219,8 @@ class AuthenticationRepositoryImpl(
)
authenticationStore.putUser(server.id, userId, updatedUser)
accountManagerHelper.putAccount(AccountManagerAccount(userId, server.id, updatedUser.name, result.accessToken))
val accountManagerAccount = AccountManagerAccount(userId, server.id, updatedUser.name, result.accessToken)
accountManagerHelper.putAccount(accountManagerAccount)
val user = PrivateUser(
id = userId,
@@ -230,8 +231,15 @@ class AuthenticationRepositoryImpl(
imageTag = userInfo.primaryImageTag,
lastUsed = Date().time,
)
setActiveSession(user, server)
emit(AuthenticatedState)
// We just added the account so it should activate properly although in rare cases it doesn't.
// this is often caused by issues in the platforms account manager
if (setActiveSession(user, server)) emit(AuthenticatedState)
else {
// Try to remove the account and ask for sign in
accountManagerHelper.removeAccount(accountManagerAccount)
emit(RequireSignInState)
}
}
override fun logout(user: User) {

View File

@@ -31,7 +31,7 @@ interface ServerRepository {
suspend fun refreshServerInfo(server: Server): Boolean
companion object {
val minimumServerVersion = Jellyfin.minimumVersion
val minimumServerVersion = Jellyfin.minimumVersion.copy(build = null)
}
}

View File

@@ -4,14 +4,7 @@ import android.content.Context
import android.view.KeyEvent
import androidx.preference.PreferenceManager
import org.acra.ACRA
import org.jellyfin.androidtv.preference.constant.AppTheme
import org.jellyfin.androidtv.preference.constant.AudioBehavior
import org.jellyfin.androidtv.preference.constant.ClockBehavior
import org.jellyfin.androidtv.preference.constant.NextUpBehavior
import org.jellyfin.androidtv.preference.constant.PreferredVideoPlayer
import org.jellyfin.androidtv.preference.constant.RatingType
import org.jellyfin.androidtv.preference.constant.WatchedIndicatorBehavior
import org.jellyfin.androidtv.preference.constant.defaultAudioBehavior
import org.jellyfin.androidtv.preference.constant.*
import org.jellyfin.androidtv.util.DeviceUtils
/**
@@ -87,7 +80,7 @@ class UserPreferences(context: Context) : SharedPreferenceStore(
/**
* Preferred video player.
*/
var videoPlayer = Preference.enum("video_player", PreferredVideoPlayer.AUTO)
var videoPlayer = Preference.enum("video_player", PreferredVideoPlayer.EXOPLAYER)
/**
* Enable refresh rate switching when device supports it

View File

@@ -79,6 +79,7 @@ public class PlaybackController {
private StreamInfo mCurrentStreamInfo;
private List<SubtitleStreamInfo> mSubtitleStreams;
@Nullable
private IPlaybackOverlayFragment mFragment;
private Boolean spinnerOff = false;
@@ -227,7 +228,8 @@ public class PlaybackController {
Utils.showToast(TvApp.getApplication(), TvApp.getApplication().getString(R.string.too_many_errors));
mPlaybackState = PlaybackState.ERROR;
stop();
mFragment.finish();
if (mFragment != null) mFragment.finish();
}
}
@@ -631,7 +633,7 @@ public class PlaybackController {
// get subtitle info
mSubtitleStreams = response.GetSubtitleProfiles(false, apiClient.getValue().getApiUrl(), apiClient.getValue().getAccessToken());
mFragment.updateDisplay();
if (mFragment != null) mFragment.updateDisplay();
// when using VLC if source is stereo or we're on the Fire platform with AC3 - use most compatible output
if (!mVideoManager.isNativeMode() &&
@@ -711,7 +713,7 @@ public class PlaybackController {
play(mCurrentPosition);
burningSubs = false;
} else {
mFragment.addManualSubtitles(null);
if (mFragment != null) mFragment.addManualSubtitles(null);
mVideoManager.disableSubs();
}
return;
@@ -741,7 +743,7 @@ public class PlaybackController {
break;
case Embed:
if (!mVideoManager.isNativeMode()) {
mFragment.addManualSubtitles(null); // in case these were on
if (mFragment != null) mFragment.addManualSubtitles(null); // in case these were on
if (!mVideoManager.setSubtitleTrack(index, getCurrentlyPlayingItem().getMediaStreams())) {
// error selecting internal subs
Utils.showToast(TvApp.getApplication(), TvApp.getApplication().getResources().getString(R.string.msg_unable_load_subs));
@@ -750,9 +752,9 @@ public class PlaybackController {
}
// not using vlc - fall through to external handling
case External:
mFragment.addManualSubtitles(null);
if (mFragment != null) mFragment.addManualSubtitles(null);
mVideoManager.disableSubs();
mFragment.showSubLoadingMsg(true);
if (mFragment != null) mFragment.showSubLoadingMsg(true);
stream.setDeliveryMethod(SubtitleDeliveryMethod.External);
stream.setDeliveryUrl(String.format("%1$s/Videos/%2$s/%3$s/Subtitles/%4$s/0/Stream.JSON", apiClient.getValue().getApiUrl(), mCurrentStreamInfo.getItemId(), mCurrentStreamInfo.getMediaSourceId(), String.valueOf(stream.getIndex())));
apiClient.getValue().getSubtitles(stream.getDeliveryUrl(), new Response<SubtitleTrackInfo>() {
@@ -762,11 +764,11 @@ public class PlaybackController {
if (info != null) {
Timber.d("Adding json subtitle track to player");
mFragment.addManualSubtitles(info);
if (mFragment != null) mFragment.addManualSubtitles(info);
} else {
Timber.e("Empty subtitle result");
Utils.showToast(TvApp.getApplication(), TvApp.getApplication().getResources().getString(R.string.msg_unable_load_subs));
mFragment.showSubLoadingMsg(false);
if (mFragment != null) mFragment.showSubLoadingMsg(false);
}
}
@@ -774,7 +776,7 @@ public class PlaybackController {
public void onError(Exception ex) {
Timber.e(ex, "Error downloading subtitles");
Utils.showToast(TvApp.getApplication(), TvApp.getApplication().getResources().getString(R.string.msg_unable_load_subs));
mFragment.showSubLoadingMsg(false);
if (mFragment != null) mFragment.showSubLoadingMsg(false);
}
});
@@ -865,8 +867,8 @@ public class PlaybackController {
DisplayPreferences cachedPrefs = TvApp.getApplication() != null ?
TvApp.getApplication().getCachedDisplayPrefs("usersettings", "emby") : null;
int skipMS = cachedPrefs != null && cachedPrefs.getCustomPrefs().get("skipBackwardLength") != null ?
Integer.parseInt(cachedPrefs.getCustomPrefs().get("skipBackwardLength")) : 10000;
int skipMS = cachedPrefs != null && cachedPrefs.getCustomPrefs().get("skipBackLength") != null ?
Integer.parseInt(cachedPrefs.getCustomPrefs().get("skipBackLength")) : 10000;
skip(-skipMS);
}
@@ -926,7 +928,7 @@ public class PlaybackController {
if (currentSkipPos < 0) currentSkipPos = 0;
Timber.d("Duration reported as: %s current pos: %s",mVideoManager.getDuration(), mVideoManager.getCurrentPosition());
if (currentSkipPos > mVideoManager.getDuration()) currentSkipPos = mVideoManager.getDuration() - 1000;
mFragment.setCurrentTime(currentSkipPos);
if (mFragment != null) mFragment.setCurrentTime(currentSkipPos);
if (getPlaybackMethod().equals(PlayMethod.DirectPlay)) {
seek(currentSkipPos);
currentSkipPos = 0;
@@ -954,7 +956,7 @@ public class PlaybackController {
channel.setCurrentProgram(program);
mCurrentProgramEndTime = channel.getEndDate() != null ? TimeUtils.convertToLocalDate(channel.getEndDate()).getTime() : 0;
mCurrentProgramStartTime = channel.getPremiereDate() != null ? TimeUtils.convertToLocalDate(channel.getPremiereDate()).getTime() : 0;
mFragment.updateDisplay();
if (mFragment != null) mFragment.updateDisplay();
}
}
});
@@ -1006,7 +1008,7 @@ public class PlaybackController {
}
long currentTime = isLiveTv ? getTimeShiftedProgress() : mVideoManager.getCurrentPosition();
if (isLiveTv && !directStreamLiveTv) {
if (isLiveTv && !directStreamLiveTv && mFragment != null) {
mFragment.setSecondaryTime(getRealTimeProgress());
}
@@ -1082,7 +1084,7 @@ public class PlaybackController {
// Show "Next Up" fragment
spinnerOff = false;
mediaManager.getValue().setCurrentVideoQueue(mItems);
mFragment.showNextUp(nextItem.getId());
if (mFragment != null) mFragment.showNextUp(nextItem.getId());
} else {
mCurrentIndex++;
play(0);
@@ -1090,7 +1092,7 @@ public class PlaybackController {
} else {
// exit activity
Timber.d("Last item completed. Finishing activity.");
mFragment.finish();
if (mFragment != null) mFragment.finish();
}
}
@@ -1106,7 +1108,7 @@ public class PlaybackController {
Utils.showToast(TvApp.getApplication(), TvApp.getApplication().getString(R.string.msg_error_live_stream));
directStreamLiveTv = false;
PlaybackHelper.retrieveAndPlay(getCurrentlyPlayingItem().getId(), false, TvApp.getApplication());
mFragment.finish();
if (mFragment != null) mFragment.finish();
} else {
String msg = TvApp.getApplication().getString(R.string.video_error_unknown_error);
Timber.e("Playback error - %s", msg);
@@ -1188,10 +1190,10 @@ public class PlaybackController {
updateTvProgramInfo();
}
final Long currentTime = isLiveTv && mCurrentProgramStartTime > 0 ? getRealTimeProgress() : mVideoManager.getCurrentPosition();
mFragment.setCurrentTime(currentTime);
if (mFragment != null) mFragment.setCurrentTime(currentTime);
//if (isLiveTv && !directStreamLiveTv) mFragment.setSecondaryTime(getRealTimeProgress());
mCurrentPosition = currentTime;
mFragment.updateSubtitles(currentTime);
if (mFragment != null) mFragment.updateSubtitles(currentTime);
}
updateProgress = continueUpdate;

View File

@@ -144,6 +144,12 @@ public class CustomPlaybackTransportControlGlue extends PlaybackTransportControl
return vh;
}
@Override
protected void onProgressBarClicked(PlaybackTransportRowPresenter.ViewHolder vh) {
CustomPlaybackTransportControlGlue controlglue = CustomPlaybackTransportControlGlue.this;
controlglue.onActionClicked(controlglue.playPauseAction);
}
@Override
protected void onBindRowViewHolder(RowPresenter.ViewHolder vh, Object item) {
super.onBindRowViewHolder(vh, item);

View File

@@ -1,6 +1,7 @@
package org.jellyfin.androidtv.util
import org.jellyfin.sdk.api.client.KtorClient
import org.jellyfin.sdk.api.client.exception.ApiClientException
import org.jellyfin.sdk.api.client.extensions.detectBitrate
import org.jellyfin.sdk.api.operations.MediaInfoApi
import timber.log.Timber
@@ -17,9 +18,12 @@ class AutoBitrate(
private set
suspend fun detect() {
val measurement = mediaInfoApi.detectBitrate()
bitrate = measurement.bitrate
Timber.i("Auto bitrate set to: %d", bitrate)
try {
val measurement = mediaInfoApi.detectBitrate()
bitrate = measurement.bitrate
Timber.i("Auto bitrate set to: %d", bitrate)
} catch (err: ApiClientException) {
Timber.e(err, "Failed to detect bitrate")
}
}
}