Skip to content

Commit ab9dea6

Browse files
Merge pull request #542 from thornbill/eleven-four
Release 0.11.4
2 parents f7dafcb + 178fe80 commit ab9dea6

File tree

9 files changed

+186
-52
lines changed

9 files changed

+186
-52
lines changed

.ci/azure-pipelines.yml

+124-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
variables:
2+
- group: 'jellyfin'
3+
14
trigger:
5+
batch: true
26
branches:
37
include:
48
- master
@@ -12,15 +16,123 @@ pr:
1216
include:
1317
- '*'
1418

15-
pool:
16-
vmImage: 'ubuntu-latest'
17-
18-
steps:
19-
- task: Gradle@2
20-
inputs:
21-
gradleWrapperFile: 'gradlew'
22-
tasks: 'build'
23-
publishJUnitResults: true
24-
testResultsFiles: '**/TEST-*.xml'
25-
javaHomeOption: 'JDKVersion'
26-
sonarQubeRunAnalysis: false
19+
jobs:
20+
- job: Test
21+
displayName: 'Test'
22+
23+
pool:
24+
vmImage: 'ubuntu-latest'
25+
26+
steps:
27+
- task: Gradle@2
28+
displayName: 'Run Tests'
29+
inputs:
30+
gradleWrapperFile: 'gradlew'
31+
tasks: 'test'
32+
publishJUnitResults: true
33+
testResultsFiles: '**/TEST-*.xml'
34+
javaHomeOption: 'JDKVersion'
35+
sonarQubeRunAnalysis: false
36+
37+
- job: Build
38+
displayName: 'Build'
39+
40+
pool:
41+
vmImage: 'ubuntu-latest'
42+
43+
steps:
44+
- task: Gradle@2
45+
displayName: 'Build Debug'
46+
inputs:
47+
gradleWrapperFile: 'gradlew'
48+
tasks: 'assembleDebug'
49+
publishJUnitResults: false
50+
testResultsFiles: '**/TEST-*.xml'
51+
javaHomeOption: 'JDKVersion'
52+
sonarQubeRunAnalysis: false
53+
54+
- task: Gradle@2
55+
displayName: 'Build Release'
56+
inputs:
57+
gradleWrapperFile: 'gradlew'
58+
tasks: 'assembleRelease'
59+
publishJUnitResults: false
60+
testResultsFiles: '**/TEST-*.xml'
61+
javaHomeOption: 'JDKVersion'
62+
sonarQubeRunAnalysis: false
63+
64+
- task: CopyFiles@2
65+
displayName: 'Copy APKs'
66+
inputs:
67+
SourceFolder: 'app/build/outputs/apk/'
68+
Contents: '**/*.apk'
69+
TargetFolder: '$(Build.ArtifactStagingDirectory)'
70+
flattenFolders: true
71+
72+
- task: PublishBuildArtifacts@1
73+
displayName: 'Publish APKs'
74+
inputs:
75+
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
76+
ArtifactName: 'jellyfin-androidtv'
77+
publishLocation: 'Container'
78+
79+
- job: Publish
80+
displayName: 'Publish'
81+
82+
dependsOn: Build
83+
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
84+
85+
pool:
86+
vmImage: 'ubuntu-latest'
87+
88+
steps:
89+
- script: 'echo "##vso[task.setvariable variable=TAG]$(git describe --tags)"'
90+
displayName: 'Set Tag Variable'
91+
92+
- task: DownloadPipelineArtifact@2
93+
displayName: 'Download APKs'
94+
inputs:
95+
source: 'current'
96+
artifact: 'jellyfin-androidtv'
97+
path: '$(System.ArtifactsDirectory)'
98+
runVersion: 'latest'
99+
100+
- task: DownloadSecureFile@1
101+
displayName: 'Download KeyStore'
102+
name: 'KeyStore'
103+
inputs:
104+
secureFile: 'keystore'
105+
106+
- script: '$(find / -name apksigner -print -quit) sign --ks ${KEYSTORE_SECUREFILEPATH} --ks-pass pass:${PASSWORD} --out ${SYSTEM_ARTIFACTSDIRECTORY}/jellyfin-androidtv_release_${TAG}.apk ${SYSTEM_ARTIFACTSDIRECTORY}/jellyfin-androidtv_release-unsigned_${TAG}.apk'
107+
displayName: 'Sign Release APK'
108+
env:
109+
PASSWORD: $(KeyStorePassword)
110+
111+
- task: DeleteFiles@1
112+
displayName: 'Remove Unsigned APK'
113+
inputs:
114+
sourceFolder: '$(System.ArtifactsDirectory)'
115+
contents: 'jellyfin-androidtv_release-unsigned_$(TAG).apk'
116+
117+
- task: GithubRelease@0
118+
displayName: 'GitHub Upload'
119+
inputs:
120+
gitHubConnection: Jellyfin Release Download
121+
repositoryName: jellyfin/jellyfin-androidtv
122+
assets: '$(System.ArtifactsDirectory)/*.apk'
123+
action: 'edit'
124+
assetUploadMode: 'replace'
125+
tag: '$(TAG)'
126+
127+
- task: CopyFilesOverSSH@0
128+
inputs:
129+
sshEndpoint: repository
130+
sourceFolder: '$(System.ArtifactsDirectory)'
131+
contents: '**'
132+
targetFolder: '/srv/repository/releases/client/androidtv/versions/$(TAG)'
133+
134+
- task: SSH@0
135+
inputs:
136+
sshEndpoint: repository
137+
runOptions: 'inline'
138+
inline: 'cd /srv/repository/releases/client/androidtv && rm -rf *.apk && ln -s versions/$(TAG)/jellyfin-androidtv_*_$(TAG).apk .'

app/build.gradle.kts

+13-5
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ android {
1313
targetSdkVersion(29)
1414

1515
// Release version
16-
versionCode = 908
17-
versionName = "0.11.3"
16+
versionCode = 909
17+
versionName = "0.11.4"
1818
}
1919

2020
compileOptions {
@@ -34,13 +34,21 @@ android {
3434
applicationIdSuffix = ".debug"
3535
}
3636
}
37+
38+
applicationVariants.all {
39+
val variant = this
40+
variant.outputs.all {
41+
val output = this as com.android.build.gradle.internal.api.BaseVariantOutputImpl
42+
output.outputFileName = output.outputFileName
43+
.replace("app-", "jellyfin-androidtv_")
44+
.replace(".apk", "_${variant.versionName}.apk")
45+
}
46+
}
3747
}
3848

3949
dependencies {
4050
// Jellyfin
41-
val jellyfinApiclientVersion= "v0.6.0"
42-
implementation("com.github.jellyfin.jellyfin-apiclient-java:android:$jellyfinApiclientVersion")
43-
implementation("com.github.jellyfin.jellyfin-apiclient-java:library:$jellyfinApiclientVersion")
51+
implementation("com.github.jellyfin.jellyfin-apiclient-java:android:v0.6.4")
4452

4553
// Kotlin
4654
implementation(kotlin("stdlib-jdk8"))

app/src/main/java/org/jellyfin/androidtv/channels/ChannelManager.kt

+3
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ class ChannelManager {
106106
item.canResume -> {
107107
setWatchNextType(WatchNextPrograms.WATCH_NEXT_TYPE_CONTINUE)
108108
setLastPlaybackPositionMillis((item.resumePositionTicks / TICKS_IN_MILLISECOND).toInt())
109+
}
110+
// Episode runtime has been determined
111+
item.runTimeTicks != null -> {
109112
setDurationMillis((item.runTimeTicks / TICKS_IN_MILLISECOND).toInt())
110113
}
111114
// First episode of the season

app/src/main/java/org/jellyfin/androidtv/playback/PlaybackController.java

+13-2
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public void setPlaybackMethod(PlayMethod value) {
137137
}
138138

139139
public BaseItemDto getCurrentlyPlayingItem() {
140-
return mItems.get(mCurrentIndex);
140+
return mItems.size() > mCurrentIndex ? mItems.get(mCurrentIndex) : null;
141141
}
142142
public MediaSourceInfo getCurrentMediaSource() { return mCurrentStreamInfo != null && mCurrentStreamInfo.getMediaSource() != null ? mCurrentStreamInfo.getMediaSource() : getCurrentlyPlayingItem().getMediaSources().get(0);}
143143
public StreamInfo getCurrentStreamInfo() { return mCurrentStreamInfo; }
@@ -998,13 +998,24 @@ private void startPauseReportLoop() {
998998
mReportLoop = new Runnable() {
999999
@Override
10001000
public void run() {
1001+
BaseItemDto currentItem = getCurrentlyPlayingItem();
1002+
if (currentItem == null) {
1003+
// Loop was called while nothing was playing!
1004+
stopReportLoop();
1005+
return;
1006+
}
1007+
1008+
if (mPlaybackState != PlaybackState.PLAYING) {
1009+
// Playback was stopped, don't report progress anymore
1010+
return;
1011+
}
10011012

10021013
long currentTime = isLiveTv ? getTimeShiftedProgress() : mVideoManager.getCurrentPosition();
10031014
if (isLiveTv && !directStreamLiveTv) {
10041015
mFragment.setSecondaryTime(getRealTimeProgress());
10051016
}
10061017

1007-
ReportingHelper.reportProgress(getCurrentlyPlayingItem(), getCurrentStreamInfo(), currentTime * 10000, true);
1018+
ReportingHelper.reportProgress(currentItem, getCurrentStreamInfo(), currentTime * 10000, true);
10081019
mHandler.postDelayed(this, PROGRESS_REPORTING_PAUSE_INTERVAL);
10091020
}
10101021
};

app/src/main/java/org/jellyfin/androidtv/util/ProfileHelper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public static DeviceProfile getBaseProfile(boolean isLiveTv) {
3333

3434
profile.setName("Android");
3535
profile.setMaxStreamingBitrate(20000000);
36-
profile.setMaxStaticBitrate(30000000);
36+
profile.setMaxStaticBitrate(100000000);
3737

3838
List<TranscodingProfile> transcodingProfiles = new ArrayList<>();
3939

app/src/main/java/org/jellyfin/androidtv/util/TimeUtils.java

+18-28
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.jellyfin.androidtv.util;
22

3+
import android.annotation.SuppressLint;
34
import android.text.format.DateFormat;
45

56
import org.jellyfin.androidtv.R;
@@ -9,14 +10,18 @@
910
import java.util.Date;
1011
import java.util.Locale;
1112
import java.util.TimeZone;
13+
import java.util.concurrent.TimeUnit;
1214

1315
public class TimeUtils {
1416
private static final int MILLIS_PER_SEC = 1000;
15-
private static final int MILLIS_PER_MIN = 60 * MILLIS_PER_SEC;
16-
private static final int MILLIS_PER_HR = 60 * MILLIS_PER_MIN;
17+
private static final long MILLIS_PER_MIN = TimeUnit.MINUTES.toMillis(1);
18+
private static final long MILLIS_PER_HR = TimeUnit.HOURS.toMillis(1);
1719

1820
private static final int SECS_PER_MIN = 60;
19-
private static final int SECS_PER_HR = 60 * SECS_PER_MIN;
21+
private static final long SECS_PER_HR = TimeUnit.HOURS.toSeconds(1);
22+
23+
private static final String DURATION_TIME_FORMAT_NO_HOURS = "%d:%02d";
24+
private static final String DURATION_TIME_FORMAT_WITH_HOURS = "%d:%02d:%02d";
2025

2126
public static long secondsToMillis(double seconds) {
2227
return Math.round(seconds * MILLIS_PER_SEC);
@@ -33,37 +38,22 @@ public static long hoursToMillis(double hours) {
3338
/**
3439
* Formats time in milliseconds to hh:mm:ss string format.
3540
*
36-
* @param millis
37-
* @return
41+
* @param millis Time in milliseconds
42+
* @return Formatted time
3843
*/
44+
@SuppressLint("DefaultLocale")
3945
public static String formatMillis(long millis) {
40-
long hr = millis / MILLIS_PER_HR;
46+
long hr = TimeUnit.MILLISECONDS.toHours(millis);
4147
millis %= MILLIS_PER_HR;
42-
long min = millis / MILLIS_PER_MIN;
48+
long min = TimeUnit.MILLISECONDS.toMinutes(millis);
4349
millis %= MILLIS_PER_MIN;
44-
long sec = millis / MILLIS_PER_SEC;
50+
long sec = TimeUnit.MILLISECONDS.toSeconds(millis);
4551

46-
StringBuilder builder = new StringBuilder();
47-
// Hours
48-
if (hr > 0) {
49-
builder.append(hr)
50-
.append(":");
51-
}
52-
// Minutes
53-
if (min >= 0) {
54-
if (min < 9 && hr > 0) {
55-
builder.append("0");
56-
}
57-
builder.append(min)
58-
.append(":");
59-
}
60-
// Seconds
61-
if (sec < 10) {
62-
builder.append("0");
52+
if(hr > 0) {
53+
return String.format(DURATION_TIME_FORMAT_WITH_HOURS, hr, min, sec);
54+
} else {
55+
return String.format(DURATION_TIME_FORMAT_NO_HOURS, min, sec);
6356
}
64-
builder.append(sec);
65-
66-
return builder.toString();
6757
}
6858

6959
public static String formatSeconds(int seconds) {

app/src/test/java/org/jellyfin/androidtv/util/TimeUtilsTest.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package org.jellyfin.androidtv.util;
22

3-
import static org.junit.Assert.assertEquals;
43
import org.junit.Test;
54

5+
import static org.junit.Assert.assertEquals;
6+
67
public class TimeUtilsTest {
78

89
@Test
@@ -28,9 +29,18 @@ public void hoursToMillis() {
2829

2930
@Test
3031
public void formatMillis() {
32+
assertEquals("0:00", TimeUtils.formatMillis(0));
3133
assertEquals("0:13", TimeUtils.formatMillis(13000));
3234
assertEquals("5:00", TimeUtils.formatMillis(300000));
35+
assertEquals("9:01", TimeUtils.formatMillis(541000));
36+
assertEquals("9:59", TimeUtils.formatMillis(599000));
37+
assertEquals("26:00", TimeUtils.formatMillis(1560000));
38+
assertEquals("26:01", TimeUtils.formatMillis(1561000));
39+
assertEquals("26:43", TimeUtils.formatMillis(1603000));
3340
assertEquals("1:00:00", TimeUtils.formatMillis(3600000));
41+
assertEquals("1:01:01", TimeUtils.formatMillis(3661000));
42+
assertEquals("1:09:15", TimeUtils.formatMillis(4155000));
3443
assertEquals("1:16:03", TimeUtils.formatMillis(4563489));
44+
assertEquals("12:00:00", TimeUtils.formatMillis(43200000));
3545
}
36-
}
46+
}

docker-build.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ bash gradlew ${RFLAG}
2626

2727
# Move the artifacts out
2828
mkdir -p ${ARTIFACT_DIR}/apk
29-
mmv "${SOURCE_DIR}/app/build/outputs/apk/*/app-*.apk" "${ARTIFACT_DIR}/apk/jellyfin-androidtv_#2.apk"
29+
mmv "${SOURCE_DIR}/app/build/outputs/apk/*/jellyfin-androidtv_*.apk" "${ARTIFACT_DIR}/apk/"

settings.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ val apiclientLocation = "../jellyfin-apiclient-java"
1515
if (File(apiclientLocation).exists() && enableDependencySubstitution) {
1616
includeBuild(apiclientLocation) {
1717
dependencySubstitution {
18-
substitute(module("com.github.jellyfin.jellyfin-apiclient-java:library")).with(project(":library"))
18+
substitute(module("com.github.jellyfin.jellyfin-apiclient-java:android")).with(project(":android"))
1919
}
2020
}
2121
}

0 commit comments

Comments
 (0)