Skip to content

Commit

Permalink
Random sort. Fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreyPavlenko committed May 15, 2020
1 parent a1c1abc commit f39a7cb
Show file tree
Hide file tree
Showing 19 changed files with 236 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ public FutureSupplier<Intent> startActivityForResult(Intent intent) {
return failed(new UnsupportedOperationException());
}

public void checkPermissions(String... perms) {
public FutureSupplier<int[]> checkPermissions(String... perms) {
return failed(new UnsupportedOperationException());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public MediaEngine createAnotherEngine(@NonNull MediaEngine current, Listener li

private boolean isProviderAvailable(String providerClass) {
try {
Class.forName(providerClass);
Class.forName(providerClass).newInstance();
return true;
} catch (Throwable ex) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,20 @@ private MetadataBuilder load(PlayableItem item) {
if (meta != null) return meta;

MetaBuilder mb = new MetaBuilder();
MediaEngineProvider vlcPlayer = mgr.vlcPlayer;
MediaEngineProvider mp = mgr.mediaPlayer;
MediaEngineProvider vlc = mgr.vlcPlayer;
VirtualResource file = item.getFile();

if (file.isLocalFile() && file.getName().endsWith(".flac")) {
// VLC does not extract images from flac, thus prefer Android extractor for local files
mgr.mediaPlayer.getMediaMetadata(mb, item);
} else if ((vlcPlayer != null) && (!"content".equals(item.getLocation().getScheme()))) {
if (!vlcPlayer.getMediaMetadata(mb, item)) mgr.mediaPlayer.getMediaMetadata(mb, item);
if (!mp.getMediaMetadata(mb, item) && (vlc != null)) {
// Seems flac is not supported, trying VLC
vlc.getMediaMetadata(mb, item);
}
} else if (vlc != null) {
if (!vlc.getMediaMetadata(mb, item)) mp.getMediaMetadata(mb, item);
} else {
mgr.mediaPlayer.getMediaMetadata(mb, item);
mp.getMediaMetadata(mb, item);
}

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,10 @@ private FutureSupplier<Void> loadMetadata(List<Item> children) {
}

protected FutureSupplier<String> buildTitle(int seqNum, BrowsableItemPrefs parentPrefs) {
String name = getName();
try (SharedTextBuilder tb = SharedTextBuilder.get()) {
if (seqNum != 0) tb.append(seqNum).append(". ");
tb.append(getName());
return completed(tb.toString());
return completed(tb.append(name).toString());
}
}

Expand All @@ -173,14 +173,8 @@ protected String buildSubtitle(List<Item> children) {
public FutureSupplier<Iterator<PlayableItem>> getShuffleIterator() {
if ((shuffle == null) || (shuffle.isDone() && !shuffle.get(null).hasNext())) {
shuffle = getPlayableChildren(false, false, Integer.MAX_VALUE).map(list -> {
Random rnd = ThreadLocalRandom.current();
List<PlayableItem> l = new ArrayList<>(list);

for (int i = 0, s = l.size(); i < s; i++) {
int next = rnd.nextInt(s - i);
Collections.swap(l, i, next);
}

shuffle(l);
Iterator<PlayableItem> it = l.iterator();
shuffle = completed(it);
return it;
Expand All @@ -199,37 +193,43 @@ protected String getChildrenIdPattern() {
public FutureSupplier<Void> updateTitles() {
FutureSupplier<List<Item>> list = CHILDREN.get(this);
if (list == null) return super.updateTitles();
return list.then(children -> Async.forEach(Item::updateTitles, children)).then(v -> super.updateTitles());
return list.then(children -> {
for (Item i : children) {
i.updateTitles();
}
return super.updateTitles();
});
}

@NonNull
@Override
public FutureSupplier<Void> refresh() {
updateTitles();
CHILDREN.set(this, null);
return updateTitles();
public FutureSupplier<Void> updateSorting() {
FutureSupplier<List<Item>> list = CHILDREN.get(this);
if (list == null) return completedVoid();
return updateTitles().onSuccess(v -> CHILDREN.compareAndSet(this, list, null));
}

@NonNull
@Override
public FutureSupplier<Void> rescan() {
public FutureSupplier<Void> refresh() {
FutureSupplier<List<Item>> list = CHILDREN.get(this);
String pattern = getChildrenIdPattern();
if (pattern != null) getLib().getMetadataRetriever().clearMetadata(pattern);
if (list == null) return refresh();
CHILDREN.set(this, null);
return list.then(children -> Async.forEach(i -> {
if (i instanceof ItemBase) ((ItemBase) i).reset();
return completedVoid();
}, children)).then(v -> super.updateTitles());
if (list == null) return super.updateTitles();
return list.then(children -> {
for (Item i : children) {
if (i instanceof ItemBase) ((ItemBase) i).reset();
else i.updateTitles();
}
CHILDREN.compareAndSet(this, list, null);
return super.updateTitles();
});
}

@NonNull
@Override
public FutureSupplier<Void> updateSorting() {
FutureSupplier<List<Item>> list = CHILDREN.get(this);
if (list == null) return completedVoid();
return list.map(ArrayList::new).thenReplaceOrClear(CHILDREN, this, list).then(v -> updateTitles());
public FutureSupplier<Void> rescan() {
String pattern = getChildrenIdPattern();
if (pattern != null) getLib().getMetadataRetriever().clearMetadata(pattern);
return refresh();
}

void setChildren(List<Item> c) {
Expand Down Expand Up @@ -263,6 +263,9 @@ private FutureSupplier<List<Item>> sortChildren(List<Item> list) {
setSeqNum(sorted);
return completed(sorted);
});
case BrowsableItemPrefs.SORT_BY_RND:
shuffle(sorted);
break;
}

setSeqNum(sorted);
Expand All @@ -275,6 +278,15 @@ private void setSeqNum(SortedItems sorted) {
}
}

private void shuffle(List<?> l) {
Random rnd = ThreadLocalRandom.current();

for (int i = 0, s = l.size(); i < s; i++) {
int next = rnd.nextInt(s - i);
Collections.swap(l, i, next);
}
}

private int compareByFile(Item i1, Item i2, boolean desc) {
if (i1 instanceof BrowsableItem) {
if (i2 instanceof BrowsableItem) {
Expand Down
70 changes: 47 additions & 23 deletions fermata/src/main/java/me/aap/fermata/media/lib/CueItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import me.aap.fermata.media.lib.MediaLib.BrowsableItem;
import me.aap.fermata.media.lib.MediaLib.Item;
import me.aap.fermata.util.Utils;
import me.aap.utils.app.App;
import me.aap.utils.async.FutureRef;
import me.aap.utils.async.FutureSupplier;
import me.aap.utils.log.Log;
import me.aap.utils.text.SharedTextBuilder;
Expand All @@ -23,21 +25,28 @@

import static java.nio.charset.StandardCharsets.UTF_8;
import static me.aap.fermata.BuildConfig.DEBUG;
import static me.aap.utils.async.Completed.completed;

/**
* @author Andrey Pavlenko
*/
class CueItem extends BrowsableItemBase {
public static final String SCHEME = "cue";
private final String name;
private final String subtitle;
private final List<CueTrackItem> tracks;
private final FutureRef<Data> data = new FutureRef<Data>() {
@Override
protected FutureSupplier<Data> create() {
return App.get().execute(CueItem.this::parse);
}
};

private CueItem(String id, BrowsableItem parent, VirtualFolder dir, VirtualFile cueFile) {
private CueItem(String id, BrowsableItem parent, VirtualFile cueFile) {
super(id, parent, cueFile);
}

Context ctx = parent.getLib().getContext();
private Data parse() {
String id = getId();
VirtualFile cueFile = (VirtualFile) getFile();
VirtualFolder dir = cueFile.getParent().getOrThrow();
Context ctx = getLib().getContext();
List<CueTrackItem> tracks = new ArrayList<>();
VirtualResource file = null;
String fileName = null;
Expand Down Expand Up @@ -122,12 +131,12 @@ private CueItem(String id, BrowsableItem parent, VirtualFolder dir, VirtualFile
Log.e(ex, "Failed to parse cue file: ", getFile());
}

this.tracks = tracks;
this.name = (albumTitle != null) ? albumTitle : cueFile.getName();
this.subtitle = ctx.getResources().getString(R.string.browsable_subtitle, tracks.size());
String name = (albumTitle != null) ? albumTitle : cueFile.getName();
String subtitle = ctx.getResources().getString(R.string.browsable_subtitle, tracks.size());
return new Data(name, subtitle, tracks);
}

static CueItem create(String id, BrowsableItem parent, VirtualFolder dir, VirtualFile cueFile,
static CueItem create(String id, BrowsableItem parent, VirtualFile cueFile,
DefaultMediaLib lib) {
synchronized (lib.cacheLock()) {
Item i = lib.getFromCache(id);
Expand All @@ -138,7 +147,7 @@ static CueItem create(String id, BrowsableItem parent, VirtualFolder dir, Virtua
if (DEBUG && !cueFile.equals(c.getFile())) throw new AssertionError();
return c;
} else {
return new CueItem(id, parent, dir, cueFile);
return new CueItem(id, parent, cueFile);
}
}
}
Expand All @@ -154,7 +163,7 @@ static FutureSupplier<Item> create(DefaultMediaLib lib, String id) {
if (file == null) return null;

FolderItem parent = (FolderItem) file.getParent();
return create(id, parent, parent.getFile(), (VirtualFile) file.getFile(), lib);
return create(id, parent, (VirtualFile) file.getFile(), lib);
});
}

Expand Down Expand Up @@ -207,27 +216,30 @@ private void addTrack(String id, List<CueTrackItem> tracks, VirtualResource file
}
}

public CueTrackItem getTrack(int id) {
if (id > tracks.size()) return null;
FutureSupplier<Item> getTrack(int id) {
return data.get().map(d -> {
if (id > d.tracks.size()) return null;

CueTrackItem t = tracks.get(id - 1);
if (t.getTrackNumber() == id) return t;
CueTrackItem t = d.tracks.get(id - 1);
if (t.getTrackNumber() == id) return t;

for (CueTrackItem c : tracks) {
if (c.getTrackNumber() == id) return c;
}
for (CueTrackItem c : d.tracks) {
if (c.getTrackNumber() == id) return c;
}

return null;
return null;
});
}

@Override
public String getName() {
return name;
Data d = data.get().peek();
return (d == null) ? super.getName() : d.name;
}

@Override
protected FutureSupplier<String> buildSubtitle() {
return completed(subtitle);
return data.get().map(d -> d.subtitle);
}

@Override
Expand All @@ -238,6 +250,18 @@ public int getIcon() {
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public FutureSupplier<List<Item>> listChildren() {
return completed((List) tracks);
return data.get().map(d -> (List) d.tracks);
}

private static final class Data {
final String name;
final String subtitle;
final List<CueTrackItem> tracks;

Data(String name, String subtitle, List<CueTrackItem> tracks) {
this.name = name;
this.subtitle = subtitle;
this.tracks = tracks;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ static FutureSupplier<Item> create(DefaultMediaLib lib, String id) {
SharedTextBuilder tb = SharedTextBuilder.get();
tb.append(CueItem.SCHEME).append(id, i2, id.length());

return lib.getItem(tb.releaseString()).map(i -> {
return lib.getItem(tb.releaseString()).then(i -> {
CueItem cue = (CueItem) i;
if (cue == null) return null;
if (cue == null) return completedNull();

int n = Integer.parseInt(id.substring(i1 + 1, i2));
return cue.getTrack(n);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ private List<Item> ls(List<VirtualResource> ls) {
}

cueBuf.append(name);
i = CueItem.create(cueBuf.toString(), this, getFile(), (VirtualFile) f, lib);
i = CueItem.create(cueBuf.toString(), this, (VirtualFile) f, lib);
} else if (M3uItem.isM3uFile(name)) {
if (m3uBuf == null) {
m3uBuf = new StringBuilder(id.length() + name.length() + 1);
Expand All @@ -159,7 +159,7 @@ private List<Item> ls(List<VirtualResource> ls) {
}

m3uBuf.append(name);
i = M3uItem.create(m3uBuf.toString(), this, getFile(), (VirtualFile) f, lib);
i = M3uItem.create(m3uBuf.toString(), this, (VirtualFile) f, lib);
} else {
if (fileBuf == null) {
fileBuf = new StringBuilder(id.length() + name.length() + 64);
Expand Down
17 changes: 8 additions & 9 deletions fermata/src/main/java/me/aap/fermata/media/lib/ItemBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import androidx.annotation.Nullable;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import me.aap.fermata.media.lib.MediaLib.BrowsableItem;
Expand Down Expand Up @@ -114,22 +115,20 @@ public FutureSupplier<MediaDescriptionCompat> getMediaDescription() {
protected FutureSupplier<String> buildTitle() {
BrowsableItem parent = requireNonNull(getParent());
BrowsableItemPrefs prefs = parent.getPrefs();
int seq = seqNum;

if (prefs.getTitleSeqNumPref()) {
if (seq == 0) {
Promise<String> load = new Promise<>();
FutureSupplier<List<Item>> getChildren = parent.getChildren();

if (getChildren.isDone()) {
return buildTitle(seqNum, prefs);
} else {
Promise<String> load = new Promise<>();
parent.getChildren().then(children -> {
int s = seqNum;
assertNotEquals(s, 0);
return buildTitle(s, prefs);
assertNotEquals(seqNum, 0);
return buildTitle(seqNum, prefs);
}).thenComplete(load);

buildTitle(0, prefs).onSuccess(t -> load.setProgress(t, 1, 2));
return load;
} else {
return buildTitle(seq, prefs);
}
} else {
return buildTitle(0, prefs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import static java.util.Objects.requireNonNull;
import static me.aap.utils.async.Completed.completed;
import static me.aap.utils.async.Completed.completedNull;

/**
* @author Andrey Pavlenko
Expand Down Expand Up @@ -43,9 +44,9 @@ static FutureSupplier<Item> create(DefaultMediaLib lib, String id) {
SharedTextBuilder tb = SharedTextBuilder.get();
tb.append(M3uItem.SCHEME).append(id, end, id.length());

return lib.getItem(tb.releaseString()).map(i -> {
return lib.getItem(tb.releaseString()).then(i -> {
M3uItem m3u = (M3uItem) i;
return (m3u != null) ? m3u.getGroup(gid) : null;
return (m3u != null) ? m3u.getGroup(gid) : completedNull();
});
}

Expand Down
Loading

0 comments on commit f39a7cb

Please sign in to comment.