Issue/play from here (#713)

* Fixes race condition in MediaFileListFragment

The "Play from here" feature previously queued all songs at once using
a loop and did not wait until an add action was confirmed by Kodi
before queueing the next item. This sometimes resulted in a seemingly
random play order on Kodi.

* Fixed play from here adding first item twice

When selecting "Play from here" in the file browser the current
item is started using "playMediaFile" and the subsequent items
 are queued. However, the current item was added to the queue
list as well. Resulting in the first item always being added twice
to the playlist.
This commit is contained in:
Martijn Brekhof 2020-02-20 20:53:00 +01:00 committed by GitHub
parent e92722375c
commit e63fd40d9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 51 additions and 25 deletions

View File

@ -82,7 +82,7 @@ public class MediaFileListFragment extends AbstractListFragment {
ListType.Sort sortMethod = null; ListType.Sort sortMethod = null;
String parentDirectory = null; String parentDirectory = null;
int playlistId = PlaylistType.MUSIC_PLAYLISTID; // this is the ID of the music player int playlistId = PlaylistType.MUSIC_PLAYLISTID; // this is the ID of the music player
// private MediaFileListAdapter adapter = null; // private MediaFileListAdapter adapter = null;
boolean browseRootAlready = false; boolean browseRootAlready = false;
FileLocation loadOnVisible = null; FileLocation loadOnVisible = null;
@ -249,8 +249,8 @@ public class MediaFileListFragment extends AbstractListFragment {
if (!isAdded()) return; if (!isAdded()) return;
Toast.makeText(getActivity(), Toast.makeText(getActivity(),
String.format(getString(R.string.error_getting_source_info), description), String.format(getString(R.string.error_getting_source_info), description),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
}, callbackHandler); }, callbackHandler);
} }
@ -320,9 +320,9 @@ public class MediaFileListFragment extends AbstractListFragment {
}; };
Files.GetDirectory action = new Files.GetDirectory(dir.file, Files.GetDirectory action = new Files.GetDirectory(dir.file,
mediaType, mediaType,
sortMethod, sortMethod,
properties); properties);
action.execute(hostManager.getConnection(), new ApiCallback<List<ListType.ItemFile>>() { action.execute(hostManager.getConnection(), new ApiCallback<List<ListType.ItemFile>>() {
@Override @Override
public void onSuccess(List<ListType.ItemFile> result) { public void onSuccess(List<ListType.ItemFile> result) {
@ -348,8 +348,8 @@ public class MediaFileListFragment extends AbstractListFragment {
if (!isAdded()) return; if (!isAdded()) return;
Toast.makeText(getActivity(), Toast.makeText(getActivity(),
String.format(getString(R.string.error_getting_source_info), description), String.format(getString(R.string.error_getting_source_info), description),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
}, callbackHandler); }, callbackHandler);
@ -366,21 +366,48 @@ public class MediaFileListFragment extends AbstractListFragment {
action.execute(hostManager.getConnection(), new ApiCallback<String>() { action.execute(hostManager.getConnection(), new ApiCallback<String>() {
@Override @Override
public void onSuccess(String result) { public void onSuccess(String result) {
while (!mediaQueueFileLocation.isEmpty()) { HostConnection connection = hostManager.getConnection();
queueMediaFile(mediaQueueFileLocation.poll().file); startPlaylistIfNoActivePlayers(connection, playlistId, callbackHandler);
} callbackHandler.post(queueMediaQueueFileLocations);
} }
@Override @Override
public void onError(int errorCode, String description) { public void onError(int errorCode, String description) {
if (!isAdded()) return; if (!isAdded()) return;
Toast.makeText(getActivity(), Toast.makeText(getActivity(),
String.format(getString(R.string.error_play_media_file), description), String.format(getString(R.string.error_play_media_file), description),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
}, callbackHandler); }, callbackHandler);
} }
private Runnable queueMediaQueueFileLocations = new Runnable() {
@Override
public void run() {
if (!mediaQueueFileLocation.isEmpty()) {
final HostConnection connection = hostManager.getConnection();
PlaylistType.Item item = new PlaylistType.Item();
item.file = mediaQueueFileLocation.poll().file;
Playlist.Add action = new Playlist.Add(playlistId, item);
action.execute(connection, new ApiCallback<String>() {
@Override
public void onSuccess(String result ) {
callbackHandler.post(queueMediaQueueFileLocations);
}
@Override
public void onError(int errorCode, String description) {
if (!isAdded()) return;
Toast.makeText(getActivity(),
String.format(getString(R.string.error_queue_media_file), description),
Toast.LENGTH_SHORT).show();
callbackHandler.post(queueMediaQueueFileLocations);
}
}, callbackHandler);
}
}
};
/** /**
* Starts playing the given media file on the local device * Starts playing the given media file on the local device
* @param filename Filename to start playing * @param filename Filename to start playing
@ -420,8 +447,8 @@ public class MediaFileListFragment extends AbstractListFragment {
public void onError(int errorCode, String description) { public void onError(int errorCode, String description) {
if (!isAdded()) return; if (!isAdded()) return;
Toast.makeText(getActivity(), Toast.makeText(getActivity(),
String.format(getString(R.string.error_queue_media_file), description), String.format(getString(R.string.error_queue_media_file), description),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
}, callbackHandler); }, callbackHandler);
} }
@ -450,8 +477,8 @@ public class MediaFileListFragment extends AbstractListFragment {
public void onError(int errorCode, String description) { public void onError(int errorCode, String description) {
if (!isAdded()) return; if (!isAdded()) return;
Toast.makeText(getActivity(), Toast.makeText(getActivity(),
String.format(getString(R.string.error_play_media_file), description), String.format(getString(R.string.error_play_media_file), description),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
}, callbackHandler); }, callbackHandler);
} }
@ -461,8 +488,8 @@ public class MediaFileListFragment extends AbstractListFragment {
public void onError(int errorCode, String description) { public void onError(int errorCode, String description) {
if (!isAdded()) return; if (!isAdded()) return;
Toast.makeText(getActivity(), Toast.makeText(getActivity(),
String.format(getString(R.string.error_get_active_player), description), String.format(getString(R.string.error_get_active_player), description),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
}, callbackHandler); }, callbackHandler);
@ -554,7 +581,6 @@ public class MediaFileListFragment extends AbstractListFragment {
mediaQueueFileLocation.clear(); mediaQueueFileLocation.clear();
FileLocation fl; FileLocation fl;
// start playing the selected one, then queue the rest // start playing the selected one, then queue the rest
mediaQueueFileLocation.add(loc);
for (int i = position + 1; i < fileLocationItems.size(); i++) { for (int i = position + 1; i < fileLocationItems.size(); i++) {
fl = fileLocationItems.get(i); fl = fileLocationItems.get(i);
if (!fl.isDirectory) { if (!fl.isDirectory) {
@ -582,9 +608,9 @@ public class MediaFileListFragment extends AbstractListFragment {
// Get the art dimensions // Get the art dimensions
Resources resources = context.getResources(); Resources resources = context.getResources();
artWidth = (int)(resources.getDimension(R.dimen.filelist_art_width) / artWidth = (int)(resources.getDimension(R.dimen.filelist_art_width) /
UIUtils.IMAGE_RESIZE_FACTOR); UIUtils.IMAGE_RESIZE_FACTOR);
artHeight = (int)(resources.getDimension(R.dimen.filelist_art_heigth) / artHeight = (int)(resources.getDimension(R.dimen.filelist_art_heigth) /
UIUtils.IMAGE_RESIZE_FACTOR); UIUtils.IMAGE_RESIZE_FACTOR);
} }
@ -616,7 +642,7 @@ public class MediaFileListFragment extends AbstractListFragment {
@Override @Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(ctx) View view = LayoutInflater.from(ctx)
.inflate(resource, parent, false); .inflate(resource, parent, false);
return new ViewHolder(view, getContext(), hostManager, artWidth, artHeight, itemMenuClickListener); return new ViewHolder(view, getContext(), hostManager, artWidth, artHeight, itemMenuClickListener);
} }
@ -781,8 +807,8 @@ public class MediaFileListFragment extends AbstractListFragment {
} }
return new FileLocation(title, itemFile.file, return new FileLocation(title, itemFile.file,
itemFile.filetype.equalsIgnoreCase(ListType.ItemFile.FILETYPE_DIRECTORY), itemFile.filetype.equalsIgnoreCase(ListType.ItemFile.FILETYPE_DIRECTORY),
details, sizeDuration, artUrl); details, sizeDuration, artUrl);
} }
private FileLocation(Parcel in) { private FileLocation(Parcel in) {