Added per-feed playback speed setting

Fixes #375
This commit is contained in:
Jonas Kalderstam 2019-09-12 00:50:07 +02:00
parent ada0101b07
commit 4054c330ac
12 changed files with 169 additions and 14 deletions

View File

@ -24,6 +24,9 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
private final AtomicBoolean isSetup = new AtomicBoolean(false);
// Used to work around race condition in updating the controller speed and receiving the callback that it has changed
private float playbackSpeed = -1;
@Override
protected void onResume() {
super.onResume();
@ -78,7 +81,10 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
}
float speed = 1.0f;
if(controller.canSetPlaybackSpeed()) {
speed = UserPreferences.getPlaybackSpeed();
speed = playbackSpeed;
if (speed == -1) {
speed = getPlaybackSpeedForMedia();
}
}
String speedStr = new DecimalFormat("0.00x").format(speed);
butPlaybackSpeed.setText(speedStr);
@ -102,7 +108,13 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
DecimalFormatSymbols format = new DecimalFormatSymbols(Locale.US);
format.setDecimalSeparator('.');
String currentSpeed = new DecimalFormat("0.00", format).format(UserPreferences.getPlaybackSpeed());
float currentSpeedValue = controller.getCurrentPlaybackSpeedMultiplier();
if (currentSpeedValue == -1) {
currentSpeedValue = getPlaybackSpeedForMedia();
}
String currentSpeed = new DecimalFormat("0.00", format).format(currentSpeedValue);
// Provide initial value in case the speed list has changed
// out from under us
@ -124,8 +136,9 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
break;
}
}
playbackSpeed = Float.parseFloat(newSpeed);
UserPreferences.setPlaybackSpeed(newSpeed);
controller.setPlaybackSpeed(Float.parseFloat(newSpeed));
controller.setPlaybackSpeed(playbackSpeed);
onPositionObserverUpdate();
} else {
VariableSpeedDialog.showGetPluginDialog(this);

View File

@ -872,4 +872,17 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
}
}
}
protected float getPlaybackSpeedForMedia() {
if (controller != null) {
Playable media = controller.getMedia();
boolean isFeedMedia = media instanceof FeedMedia;
if (isFeedMedia) {
return ((FeedMedia) media).getFeedPlaybackSpeed();
}
}
return UserPreferences.getPlaybackSpeed();
}
}

View File

@ -8,14 +8,18 @@ import android.widget.Button;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.TextView;
import com.afollestad.materialdialogs.MaterialDialog;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import java.util.Locale;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
public class PlaybackControlsDialog extends DialogFragment {
private static final float PLAYBACK_SPEED_STEP = 0.05f;
private static final float DEFAULT_MIN_PLAYBACK_SPEED = 0.5f;
@ -209,6 +213,16 @@ public class PlaybackControlsDialog extends DialogFragment {
if (isPlayingVideo) {
return UserPreferences.getVideoPlaybackSpeed();
}
if (controller != null) {
Playable media = controller.getMedia();
boolean isFeedMedia = media instanceof FeedMedia;
if (isFeedMedia) {
return ((FeedMedia) media).getFeedPlaybackSpeed();
}
}
return UserPreferences.getPlaybackSpeed();
}
}

View File

@ -22,6 +22,7 @@ import static de.danoeh.antennapod.activity.FeedSettingsActivity.EXTRA_FEED_ID;
public class FeedSettingsFragment extends PreferenceFragmentCompat {
private static final CharSequence PREF_EPISODE_FILTER = "episodeFilter";
private static final String PREF_FEED_PLAYBACK_SPEED = "feedPlaybackSpeed";
private Feed feed;
private FeedPreferences feedPreferences;
@ -40,12 +41,41 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat {
setupAutoDeletePreference();
setupAuthentificationPreference();
setupEpisodeFilterPreference();
setupPlaybackSpeedPreference();
updateAutoDeleteSummary();
updateAutoDownloadEnabled();
updatePlaybackSpeedPreference();
}).dispose();
}
private void setupPlaybackSpeedPreference() {
ListPreference feedPlaybackSpeedPreference = (ListPreference) findPreference(PREF_FEED_PLAYBACK_SPEED);
String[] speeds = UserPreferences.getPlaybackSpeedArray();
String[] values = new String[speeds.length + 1];
values[0] = "global";
String[] entries = new String[speeds.length + 1];
entries[0] = getString(R.string.feed_auto_download_global);
for (int i = 0; i < speeds.length; i++) {
values[i + 1] = speeds[i];
entries[i + 1] = speeds[i];
}
feedPlaybackSpeedPreference.setEntryValues(values);
feedPlaybackSpeedPreference.setEntries(entries);
feedPlaybackSpeedPreference.setOnPreferenceChangeListener((preference, newValue) -> {
feedPreferences.setFeedPlaybackSpeed((String) newValue);
feed.savePreferences();
updatePlaybackSpeedPreference();
return false;
});
}
private void setupEpisodeFilterPreference() {
findPreference(PREF_EPISODE_FILTER).setOnPreferenceClickListener(preference -> {
new EpisodeFilterDialog(getContext(), feedPreferences.getFilter()) {
@ -95,6 +125,19 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat {
});
}
private void updatePlaybackSpeedPreference() {
ListPreference feedPlaybackSpeedPreference = (ListPreference) findPreference(PREF_FEED_PLAYBACK_SPEED);
String summary = feedPreferences.getFeedPlaybackSpeed();
feedPlaybackSpeedPreference.setValue(summary);
if (summary.equals("global")) {
summary = getString(R.string.feed_auto_download_global);
}
feedPlaybackSpeedPreference.setSummary(summary);
}
private void updateAutoDeleteSummary() {
ListPreference autoDeletePreference = (ListPreference) findPreference("autoDelete");

View File

@ -598,8 +598,8 @@ public class QueueFragment extends Fragment {
String info = queue.size() + getString(R.string.episodes_suffix);
if(queue.size() > 0) {
long timeLeft = 0;
float playbackSpeed = UserPreferences.getPlaybackSpeed();
for(FeedItem item : queue) {
float playbackSpeed = item.getFeedPlaybackSpeed();
if(item.getMedia() != null) {
timeLeft +=
(long) ((item.getMedia().getDuration() - item.getMedia().getPosition())

View File

@ -7,6 +7,10 @@
android:title="@string/keep_updated"
android:summary="@string/keep_updated_summary"/>
<ListPreference
android:title="@string/playback_speed"
android:key="feedPlaybackSpeed"/>
<Preference
android:key="authentication"
android:title="@string/authentication_label"

View File

@ -15,6 +15,7 @@ import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.asynctask.ImageResource;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.ShownotesProvider;
@ -482,4 +483,16 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, ImageR
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
/**
*
* @return playback speed for this feed, or the global setting if no feed-specific setting
*/
public float getFeedPlaybackSpeed() {
Feed feed = getFeed();
if (feed != null) {
return feed.getPreferences().getCurrentPlaybackSpeed();
}
return UserPreferences.getPlaybackSpeed();
}
}

View File

@ -623,4 +623,16 @@ public class FeedMedia extends FeedFile implements Playable {
}
return super.equals(o);
}
/**
*
* @return playback speed for this feed, or the global setting if no feed-specific setting
*/
public float getFeedPlaybackSpeed() {
FeedItem item = getItem();
if (item != null) {
return item.getFeedPlaybackSpeed();
}
return UserPreferences.getPlaybackSpeed();
}
}

View File

@ -28,12 +28,13 @@ public class FeedPreferences {
private AutoDeleteAction auto_delete_action;
private String username;
private String password;
private String feedPlaybackSpeed;
public FeedPreferences(long feedID, boolean autoDownload, AutoDeleteAction auto_delete_action, String username, String password) {
this(feedID, autoDownload, true, auto_delete_action, username, password, new FeedFilter());
this(feedID, autoDownload, true, auto_delete_action, username, password, new FeedFilter(), "global");
}
private FeedPreferences(long feedID, boolean autoDownload, boolean keepUpdated, AutoDeleteAction auto_delete_action, String username, String password, @NonNull FeedFilter filter) {
private FeedPreferences(long feedID, boolean autoDownload, boolean keepUpdated, AutoDeleteAction auto_delete_action, String username, String password, @NonNull FeedFilter filter, String feedPlaybackSpeed) {
this.feedID = feedID;
this.autoDownload = autoDownload;
this.keepUpdated = keepUpdated;
@ -41,6 +42,7 @@ public class FeedPreferences {
this.username = username;
this.password = password;
this.filter = filter;
this.feedPlaybackSpeed = feedPlaybackSpeed;
}
public static FeedPreferences fromCursor(Cursor cursor) {
@ -52,6 +54,7 @@ public class FeedPreferences {
int indexPassword = cursor.getColumnIndex(PodDBAdapter.KEY_PASSWORD);
int indexIncludeFilter = cursor.getColumnIndex(PodDBAdapter.KEY_INCLUDE_FILTER);
int indexExcludeFilter = cursor.getColumnIndex(PodDBAdapter.KEY_EXCLUDE_FILTER);
int indexFeedPlaybackSpeed = cursor.getColumnIndex(PodDBAdapter.KEY_FEED_PLAYBACK_SPEED);
long feedId = cursor.getLong(indexId);
boolean autoDownload = cursor.getInt(indexAutoDownload) > 0;
@ -62,7 +65,8 @@ public class FeedPreferences {
String password = cursor.getString(indexPassword);
String includeFilter = cursor.getString(indexIncludeFilter);
String excludeFilter = cursor.getString(indexExcludeFilter);
return new FeedPreferences(feedId, autoDownload, autoRefresh, autoDeleteAction, username, password, new FeedFilter(includeFilter, excludeFilter));
String feedPlaybackSpeed = cursor.getString(indexFeedPlaybackSpeed);
return new FeedPreferences(feedId, autoDownload, autoRefresh, autoDeleteAction, username, password, new FeedFilter(includeFilter, excludeFilter), feedPlaybackSpeed);
}
/**
@ -175,4 +179,32 @@ public class FeedPreferences {
public void setPassword(String password) {
this.password = password;
}
public float getCurrentPlaybackSpeed() {
float speed = 0.0f;
if (!"global".equals(feedPlaybackSpeed)) {
try {
speed = Float.parseFloat(getFeedPlaybackSpeed());
} catch (NumberFormatException e) {
Log.e(TAG, Log.getStackTraceString(e));
setFeedPlaybackSpeed("global");
}
}
// Either global or error happened
if (speed == 0.0f) {
speed = UserPreferences.getPlaybackSpeed();
}
return speed;
}
public String getFeedPlaybackSpeed() {
return feedPlaybackSpeed;
}
public void setFeedPlaybackSpeed(String playbackSpeed) {
feedPlaybackSpeed = playbackSpeed;
}
}

View File

@ -26,6 +26,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.RewindAfterPauseUtils;
@ -306,6 +307,8 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
acquireWifiLockIfNecessary();
if (media.getMediaType() == MediaType.VIDEO) {
setPlaybackParams(UserPreferences.getVideoPlaybackSpeed(), UserPreferences.isSkipSilence());
} else if (media instanceof FeedMedia) {
setPlaybackParams(((FeedMedia) media).getFeedPlaybackSpeed(), UserPreferences.isSkipSilence());
} else {
setPlaybackParams(UserPreferences.getPlaybackSpeed(), UserPreferences.isSkipSilence());
}

View File

@ -288,6 +288,10 @@ class DBUpgrader {
db.execSQL("DROP TABLE " + PodDBAdapter.TABLE_NAME_FEED_IMAGES);
}
if (oldVersion < 1070306) {
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ " ADD COLUMN " + PodDBAdapter.KEY_FEED_PLAYBACK_SPEED + " TEXT");
}
}
}

View File

@ -114,6 +114,7 @@ public class PodDBAdapter {
public static final String KEY_LAST_PLAYED_TIME = "last_played_time";
public static final String KEY_INCLUDE_FILTER = "include_filter";
public static final String KEY_EXCLUDE_FILTER = "exclude_filter";
public static final String KEY_FEED_PLAYBACK_SPEED = "feed_playback_speed";
// Table names
static final String TABLE_NAME_FEEDS = "Feeds";
@ -146,7 +147,8 @@ public class PodDBAdapter {
+ KEY_NEXT_PAGE_LINK + " TEXT,"
+ KEY_HIDE + " TEXT,"
+ KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0,"
+ KEY_AUTO_DELETE_ACTION + " INTEGER DEFAULT 0)";
+ KEY_AUTO_DELETE_ACTION + " INTEGER DEFAULT 0,"
+ KEY_FEED_PLAYBACK_SPEED + " TEXT)";
private static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE "
+ TABLE_NAME_FEED_ITEMS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
@ -243,7 +245,8 @@ public class PodDBAdapter {
TABLE_NAME_FEEDS + "." + KEY_LAST_UPDATE_FAILED,
TABLE_NAME_FEEDS + "." + KEY_AUTO_DELETE_ACTION,
TABLE_NAME_FEEDS + "." + KEY_INCLUDE_FILTER,
TABLE_NAME_FEEDS + "." + KEY_EXCLUDE_FILTER
TABLE_NAME_FEEDS + "." + KEY_EXCLUDE_FILTER,
TABLE_NAME_FEEDS + "." + KEY_FEED_PLAYBACK_SPEED
};
/**
@ -408,6 +411,7 @@ public class PodDBAdapter {
values.put(KEY_PASSWORD, prefs.getPassword());
values.put(KEY_INCLUDE_FILTER, prefs.getFilter().getIncludeFilter());
values.put(KEY_EXCLUDE_FILTER, prefs.getFilter().getExcludeFilter());
values.put(KEY_FEED_PLAYBACK_SPEED, prefs.getFeedPlaybackSpeed());
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(prefs.getFeedID())});
}
@ -1452,7 +1456,7 @@ public class PodDBAdapter {
*/
private static class PodDBHelper extends SQLiteOpenHelper {
private static final int VERSION = 1060596;
private static final int VERSION = 1070306;
private final Context context;