Compare commits
2
Commits
v1.5
...
ios-backports
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cbe3596e4 | ||
|
|
a6d2c8b2d2 |
No files matched your search
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.miniabs"
|
package="com.miniabs"
|
||||||
android:versionCode="6"
|
android:versionCode="7"
|
||||||
android:versionName="1.5"
|
android:versionName="1.6"
|
||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10" />
|
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10" />
|
||||||
|
|||||||
@@ -68,14 +68,15 @@ Android 2.x's media player can't stream https:// URLs, so for HTTPS servers Mini
|
|||||||
- **Shows**: every podcast; tap one for its episodes. Menu key → sort oldest/newest, hide played.
|
- **Shows**: every podcast; tap one for its episodes. Menu key → sort oldest/newest, hide played.
|
||||||
- **Saved**: episodes downloaded to the SD card, plus download progress.
|
- **Saved**: episodes downloaded to the SD card, plus download progress.
|
||||||
- **Tap** an episode to play. **Long-press** for Download, Delete download, Mark as played/unplayed, Go to show.
|
- **Tap** an episode to play. **Long-press** for Download, Delete download, Mark as played/unplayed, Go to show.
|
||||||
- **Player**: skip back/forward (set the amounts in Settings), seek bar, show notes. Menu key → sleep timer, mark as played, download, stop.
|
- **Player**: skip back/forward (set the amounts in Settings), seek bar, show notes. Menu key → sleep timer, mark as played, download, stop, close MiniABS.
|
||||||
|
- **Close**: Menu key → *Pechar MiniABS* (on the Latest/Shows/Saved screen or the player) saves the position, stops playback and closes the app.
|
||||||
- **Headset buttons**: play/pause; next/previous skip forward/back. Playback pauses when headphones are unplugged and during calls.
|
- **Headset buttons**: play/pause; next/previous skip forward/back. Playback pauses when headphones are unplugged and during calls.
|
||||||
|
|
||||||
Colored dots: blue = new, amber = in progress (with a bar), grey = played.
|
Colored dots: blue = new, amber = in progress (with a bar), grey = played.
|
||||||
|
|
||||||
## Progress sync
|
## Progress sync
|
||||||
|
|
||||||
Playback opens an Audiobookshelf session and syncs every 15 seconds and on pause, so progress follows you to other apps. Saved episodes play offline; their positions are kept on the phone and sent to the server next time you're online (or tap refresh on the Saved tab).
|
Playback opens an Audiobookshelf session and syncs every 15 seconds and on pause, so progress follows you to other apps. An episode only counts as played when playback gets within a minute of its end: a stream that drops or a saved file cut short is retried or reported, never marked as played. If playback says it's playing but stops moving for 12 seconds, MiniABS says so. Saved episodes play offline; their positions are kept on the phone and sent to the server next time you're online (or tap refresh on the Saved tab).
|
||||||
|
|
||||||
## Limits
|
## Limits
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import android.os.Build;
|
|||||||
|
|
||||||
/** Audiobookshelf REST client (API as of server 2.x, including the 2.26+ token system). */
|
/** Audiobookshelf REST client (API as of server 2.x, including the 2.26+ token system). */
|
||||||
final class Api {
|
final class Api {
|
||||||
static final String VERSION = "1.5";
|
static final String VERSION = "1.6";
|
||||||
|
|
||||||
static class ApiException extends IOException {
|
static class ApiException extends IOException {
|
||||||
final int code;
|
final int code;
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ public class HomeActivity extends BaseActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onNewIntent(Intent intent) {
|
protected void onNewIntent(Intent intent) {
|
||||||
super.onNewIntent(intent);
|
super.onNewIntent(intent);
|
||||||
|
if (intent.getBooleanExtra("exit", false)) { closeApp(); return; } // "Pechar MiniABS" from the player
|
||||||
if (intent.hasExtra("tab")) selectTab(intent.getIntExtra("tab", TAB_LATEST));
|
if (intent.hasExtra("tab")) selectTab(intent.getIntExtra("tab", TAB_LATEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,9 +496,17 @@ public class HomeActivity extends BaseActivity {
|
|||||||
menu.add(0, 2, 0, "Biblioteca").setIcon(android.R.drawable.ic_menu_agenda);
|
menu.add(0, 2, 0, "Biblioteca").setIcon(android.R.drawable.ic_menu_agenda);
|
||||||
menu.add(0, 3, 0, "En reprodución").setIcon(android.R.drawable.ic_media_play);
|
menu.add(0, 3, 0, "En reprodución").setIcon(android.R.drawable.ic_media_play);
|
||||||
menu.add(0, 4, 0, "Axustes").setIcon(android.R.drawable.ic_menu_preferences);
|
menu.add(0, 4, 0, "Axustes").setIcon(android.R.drawable.ic_menu_preferences);
|
||||||
|
menu.add(0, 5, 0, "Pechar MiniABS").setIcon(android.R.drawable.ic_menu_close_clear_cancel);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Stops playback (saving the position) and closes the app. */
|
||||||
|
private void closeApp() {
|
||||||
|
PlayerService ps = PlayerService.get();
|
||||||
|
if (ps != null) ps.stop();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
@@ -513,6 +522,9 @@ public class HomeActivity extends BaseActivity {
|
|||||||
case 4:
|
case 4:
|
||||||
startActivity(new Intent(this, SettingsActivity.class));
|
startActivity(new Intent(this, SettingsActivity.class));
|
||||||
return true;
|
return true;
|
||||||
|
case 5:
|
||||||
|
closeApp();
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,11 +245,17 @@ public class PlayerActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
menu.add(0, 4, 0, "Ir ao programa").setIcon(android.R.drawable.ic_menu_view);
|
menu.add(0, 4, 0, "Ir ao programa").setIcon(android.R.drawable.ic_menu_view);
|
||||||
if (active) menu.add(0, 5, 0, "Deter").setIcon(android.R.drawable.ic_menu_close_clear_cancel);
|
if (active) menu.add(0, 5, 0, "Deter").setIcon(android.R.drawable.ic_menu_close_clear_cancel);
|
||||||
|
menu.add(0, 6, 0, "Pechar MiniABS").setIcon(android.R.drawable.ic_lock_power_off);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
if (item.getItemId() == 6) { // close the app: HomeActivity (the root) stops playback and finishes
|
||||||
|
startActivity(new Intent(this, HomeActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).putExtra("exit", true));
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
final Episode e = current();
|
final Episode e = current();
|
||||||
if (e == null) return false;
|
if (e == null) return false;
|
||||||
PlayerService ps = PlayerService.get();
|
PlayerService ps = PlayerService.get();
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ public class PlayerService extends Service implements MediaPlayer.OnPreparedList
|
|||||||
private long playingSince;
|
private long playingSince;
|
||||||
|
|
||||||
private long lastTick;
|
private long lastTick;
|
||||||
|
private int stallPos = -1; // position last seen moving
|
||||||
|
private long stallSince;
|
||||||
|
private boolean stallWarned;
|
||||||
private float listened; // seconds listened since the last sync
|
private float listened; // seconds listened since the last sync
|
||||||
private long lastSync;
|
private long lastSync;
|
||||||
private volatile boolean syncing;
|
private volatile boolean syncing;
|
||||||
@@ -552,10 +555,16 @@ public class PlayerService extends Service implements MediaPlayer.OnPreparedList
|
|||||||
public void onCompletion(MediaPlayer p) {
|
public void onCompletion(MediaPlayer p) {
|
||||||
if (p != mp) return;
|
if (p != mp) return;
|
||||||
int pos = positionMs(), dur = durationMs();
|
int pos = positionMs(), dur = durationMs();
|
||||||
// Old Android's streamer "completes" when the connection drops. Treat that as an error.
|
// Only playback that got to (nearly) the end counts as listened; anything else is never
|
||||||
if (!local && dur > 0 && pos < dur - 30000) {
|
// reported as played. Old Android's streamer "completes" when the connection drops, and a
|
||||||
|
// saved file cut short (SD card, interrupted copy) "completes" early too.
|
||||||
|
if (dur > 0 && pos < dur - 60000) {
|
||||||
lastPosMs = pos;
|
lastPosMs = pos;
|
||||||
retryStream("Perdeuse a conexión, reconectando…");
|
if (!local && contentUrl != null) {
|
||||||
|
retryStream("Perdeuse a conexión, reconectando…");
|
||||||
|
} else {
|
||||||
|
fail("O ficheiro rematou antes de tempo (" + Util.clock(pos) + "). Proba a descargalo de novo.");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state = ENDED;
|
state = ENDED;
|
||||||
@@ -672,6 +681,16 @@ public class PlayerService extends Service implements MediaPlayer.OnPreparedList
|
|||||||
App.setProgress(ep.id, lastPosMs / 1000.0, dur, false);
|
App.setProgress(ep.id, lastPosMs / 1000.0, dur, false);
|
||||||
if (now - lastSync > SYNC_EVERY) syncNow(false);
|
if (now - lastSync > SYNC_EVERY) syncNow(false);
|
||||||
if (now - playingSince > 60000) retries = 0;
|
if (now - playingSince > 60000) retries = 0;
|
||||||
|
// "playing" but not moving for 12 s: say so instead of staying silent
|
||||||
|
if (lastPosMs != stallPos) {
|
||||||
|
stallPos = lastPosMs;
|
||||||
|
stallSince = now;
|
||||||
|
stallWarned = false;
|
||||||
|
} else if (!stallWarned && now - stallSince > 12000) {
|
||||||
|
stallWarned = true;
|
||||||
|
status = "A reprodución quedou parada. Proba a pausar e reproducir de novo.";
|
||||||
|
android.widget.Toast.makeText(this, status, android.widget.Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
if (sleepAt > 0 && now >= sleepAt) {
|
if (sleepAt > 0 && now >= sleepAt) {
|
||||||
sleepAt = 0;
|
sleepAt = 0;
|
||||||
pause();
|
pause();
|
||||||
|
|||||||
Reference in new issue
Block a user