commit
4f1627876b
23 changed files with 267 additions and 247 deletions
31
app/app.iml
31
app/app.iml
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,5 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
|
@ -143,4 +144,11 @@ dependencies {
|
|||
implementation 'com.github.hannesa2:AndroidSlidingUpPanel:3.5.0'
|
||||
implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3'
|
||||
implementation 'org.nanohttpd:nanohttpd:2.3.1'
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
|
|
@ -409,7 +409,7 @@ public class MusicPlayerRemote {
|
|||
MediaStore.Audio.AudioColumns._ID + "=?",
|
||||
new String[]{songId}
|
||||
));*/
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
musicService,
|
||||
MediaStore.Audio.AudioColumns._ID + "=?",
|
||||
new String[]{songId}))
|
||||
|
@ -431,7 +431,7 @@ public class MusicPlayerRemote {
|
|||
songFile = new File(uri.getPath());
|
||||
}
|
||||
if (songFile != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
musicService,
|
||||
MediaStore.Audio.AudioColumns.DATA + "=?",
|
||||
new String[]{songFile.getAbsolutePath()}
|
||||
|
|
|
@ -36,51 +36,51 @@ public class SearchQueryHelper {
|
|||
|
||||
ArrayList<Song> songs = new ArrayList<>();
|
||||
if (artistName != null && albumName != null && titleName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), albumName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), albumName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
if (artistName != null && titleName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION + AND + TITLE_SELECTION, new String[]{artistName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
if (albumName != null && titleName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{albumName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ALBUM_SELECTION + AND + TITLE_SELECTION, new String[]{albumName.toLowerCase(), titleName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
if (artistName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, new String[]{artistName.toLowerCase()})).blockingFirst();
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION, new String[]{artistName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
if (albumName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, new String[]{albumName.toLowerCase()})).blockingFirst();
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ALBUM_SELECTION, new String[]{albumName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
if (titleName != null) {
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, new String[]{titleName.toLowerCase()})).blockingFirst();
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, TITLE_SELECTION, new String[]{titleName.toLowerCase()})).blockingFirst();
|
||||
}
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ARTIST_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ARTIST_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
||||
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, ALBUM_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, ALBUM_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
songs = SongLoader.getSongs(SongLoader.makeSongCursor(context, TITLE_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
||||
songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, TITLE_SELECTION, new String[]{query.toLowerCase()})).blockingFirst();
|
||||
if (!songs.isEmpty()) {
|
||||
return songs;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import java.util.ArrayList;
|
|||
public class AlbumLoader {
|
||||
|
||||
public static Observable<ArrayList<Album>> getAllAlbums(@NonNull Context context) {
|
||||
Observable<ArrayList<Song>> songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
Observable<ArrayList<Song>> songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
null,
|
||||
null,
|
||||
|
@ -30,7 +30,7 @@ public class AlbumLoader {
|
|||
@NonNull
|
||||
public static Observable<ArrayList<Album>> getAlbums(@NonNull final Context context,
|
||||
String query) {
|
||||
Observable<ArrayList<Song>> songs = SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
Observable<ArrayList<Song>> songs = SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
AudioColumns.ALBUM + " LIKE ?",
|
||||
new String[]{"%" + query + "%"},
|
||||
|
@ -42,7 +42,7 @@ public class AlbumLoader {
|
|||
@NonNull
|
||||
public static Observable<Album> getAlbum(@NonNull final Context context, int albumId) {
|
||||
return Observable.create(e -> {
|
||||
Observable<ArrayList<Song>> songs = SongLoader.getSongs(SongLoader
|
||||
Observable<ArrayList<Song>> songs = SongLoader.Companion.getSongs(SongLoader.Companion
|
||||
.makeSongCursor(context, AudioColumns.ALBUM_ID + "=?",
|
||||
new String[]{String.valueOf(albumId)}, getSongLoaderSortOrder(context)));
|
||||
songs.subscribe(songs1 -> {
|
||||
|
|
|
@ -22,7 +22,7 @@ public class ArtistLoader {
|
|||
|
||||
@NonNull
|
||||
public static Observable<Artist> getArtist(@NonNull final Context context, int artistId) {
|
||||
return Observable.create(e -> SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
return Observable.create(e -> SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
AudioColumns.ARTIST_ID + "=?",
|
||||
new String[]{String.valueOf(artistId)},
|
||||
|
@ -36,8 +36,8 @@ public class ArtistLoader {
|
|||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Artist>> getAllArtists(@NonNull final Context context) {
|
||||
return Observable.create(e -> SongLoader
|
||||
.getSongs(SongLoader.makeSongCursor(
|
||||
return Observable.create(e -> SongLoader.Companion
|
||||
.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
null,
|
||||
null,
|
||||
|
@ -51,7 +51,7 @@ public class ArtistLoader {
|
|||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Artist>> getArtists(@NonNull final Context context, String query) {
|
||||
return Observable.create(e -> SongLoader.getSongs(SongLoader.makeSongCursor(
|
||||
return Observable.create(e -> SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
AudioColumns.ARTIST + " LIKE ?",
|
||||
new String[]{"%" + query + "%"},
|
||||
|
|
|
@ -17,12 +17,12 @@ public class ArtistSongLoader extends SongLoader {
|
|||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getArtistSongList(@NonNull final Context context, final int artistId) {
|
||||
return getSongs(makeArtistSongCursor(context, artistId));
|
||||
return Companion.getSongs(makeArtistSongCursor(context, artistId));
|
||||
}
|
||||
|
||||
public static Cursor makeArtistSongCursor(@NonNull final Context context, final int artistId) {
|
||||
try {
|
||||
return makeSongCursor(
|
||||
return Companion.makeSongCursor(
|
||||
context,
|
||||
MediaStore.Audio.AudioColumns.ARTIST_ID + "=?",
|
||||
new String[]{
|
||||
|
|
|
@ -5,11 +5,11 @@ import android.database.Cursor;
|
|||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
import android.provider.MediaStore.Audio.Genres;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import code.name.monkey.retromusic.model.Genre;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
|
@ -30,7 +30,7 @@ public class GenreLoader {
|
|||
return getSongsWithNoGenre(context);
|
||||
}
|
||||
|
||||
return SongLoader.getSongs(makeGenreSongCursor(context, genreId));
|
||||
return SongLoader.Companion.getSongs(makeGenreSongCursor(context, genreId));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -46,11 +46,11 @@ public class GenreLoader {
|
|||
private static Observable<ArrayList<Song>> getSongsWithNoGenre(@NonNull final Context context) {
|
||||
String selection = BaseColumns._ID + " NOT IN " +
|
||||
"(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)";
|
||||
return SongLoader.getSongs(SongLoader.makeSongCursor(context, selection, null));
|
||||
return SongLoader.Companion.getSongs(SongLoader.Companion.makeSongCursor(context, selection, null));
|
||||
}
|
||||
|
||||
private static boolean hasSongsWithNoGenre(@NonNull final Context context) {
|
||||
final Cursor allSongsCursor = SongLoader.makeSongCursor(context, null, null);
|
||||
final Cursor allSongsCursor = SongLoader.Companion.makeSongCursor(context, null, null);
|
||||
final Cursor allSongsWithGenreCursor = makeAllSongsWithGenreCursor(context);
|
||||
|
||||
if (allSongsCursor == null || allSongsWithGenreCursor == null) {
|
||||
|
@ -79,7 +79,7 @@ public class GenreLoader {
|
|||
try {
|
||||
return context.getContentResolver().query(
|
||||
Genres.Members.getContentUri("external", genreId),
|
||||
SongLoader.BASE_PROJECTION, SongLoader.BASE_SELECTION, null, PreferenceUtil.getInstance().getSongSortOrder());
|
||||
SongLoader.Companion.getBASE_PROJECTION(), SongLoader.BASE_SELECTION, null, PreferenceUtil.getInstance().getSongSortOrder());
|
||||
} catch (SecurityException e) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -21,13 +21,13 @@ public class LastAddedSongsLoader {
|
|||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getLastAddedSongs(@NonNull Context context) {
|
||||
return SongLoader.getSongs(makeLastAddedCursor(context));
|
||||
return SongLoader.Companion.getSongs(makeLastAddedCursor(context));
|
||||
}
|
||||
|
||||
public static Cursor makeLastAddedCursor(@NonNull final Context context) {
|
||||
long cutoff = PreferenceUtil.getInstance().getLastAddedCutoff();
|
||||
|
||||
return SongLoader.makeSongCursor(
|
||||
return SongLoader.Companion.makeSongCursor(
|
||||
context,
|
||||
MediaStore.Audio.Media.DATE_ADDED + ">?",
|
||||
new String[]{String.valueOf(cutoff)},
|
||||
|
|
|
@ -14,7 +14,7 @@ public class SearchLoader {
|
|||
ArrayList<Object> results = new ArrayList<>();
|
||||
return Observable.create(e -> {
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
SongLoader.getSongs(context, query)
|
||||
SongLoader.Companion.getSongs(context, query)
|
||||
.subscribe(songs -> {
|
||||
if (!songs.isEmpty()) {
|
||||
results.add(context.getResources().getString(R.string.songs));
|
||||
|
|
|
@ -1,196 +0,0 @@
|
|||
package code.name.monkey.retromusic.loaders;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.provider.BaseColumns;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.MediaStore.Audio.AudioColumns;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import code.name.monkey.retromusic.helper.ShuffleHelper;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
import code.name.monkey.retromusic.providers.BlacklistStore;
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.ObservableSource;
|
||||
import io.reactivex.functions.Function;
|
||||
|
||||
/**
|
||||
* Created by hemanths on 10/08/17.
|
||||
*/
|
||||
|
||||
public class SongLoader {
|
||||
|
||||
protected static final String BASE_SELECTION =
|
||||
AudioColumns.IS_MUSIC + "=1" + " AND " + AudioColumns.TITLE + " != ''";
|
||||
protected static final String[] BASE_PROJECTION = new String[]{
|
||||
BaseColumns._ID,// 0
|
||||
AudioColumns.TITLE,// 1
|
||||
AudioColumns.TRACK,// 2
|
||||
AudioColumns.YEAR,// 3
|
||||
AudioColumns.DURATION,// 4
|
||||
AudioColumns.DATA,// 5
|
||||
AudioColumns.DATE_MODIFIED,// 6
|
||||
AudioColumns.ALBUM_ID,// 7
|
||||
AudioColumns.ALBUM,// 8
|
||||
AudioColumns.ARTIST_ID,// 9
|
||||
AudioColumns.ARTIST,// 10
|
||||
};
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getAllSongs(@NonNull Context context) {
|
||||
Cursor cursor = makeSongCursor(context, null, null);
|
||||
return getSongs(cursor);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getSongs(@NonNull final Context context,
|
||||
final String query) {
|
||||
Cursor cursor = makeSongCursor(context, AudioColumns.TITLE + " LIKE ?",
|
||||
new String[]{"%" + query + "%"});
|
||||
return getSongs(cursor);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getSongs(@Nullable final Cursor cursor) {
|
||||
return Observable.create(e -> {
|
||||
ArrayList<Song> songs = new ArrayList<>();
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
songs.add(getSongFromCursorImpl(cursor));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
e.onNext(songs);
|
||||
e.onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Song getSongFromCursorImpl(@NonNull Cursor cursor) {
|
||||
final int id = cursor.getInt(0);
|
||||
final String title = cursor.getString(1);
|
||||
final int trackNumber = cursor.getInt(2);
|
||||
final int year = cursor.getInt(3);
|
||||
final long duration = cursor.getLong(4);
|
||||
final String data = cursor.getString(5);
|
||||
final long dateModified = cursor.getLong(6);
|
||||
final int albumId = cursor.getInt(7);
|
||||
final String albumName = cursor.getString(8);
|
||||
final int artistId = cursor.getInt(9);
|
||||
final String artistName = cursor.getString(10);
|
||||
|
||||
return new Song(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName,
|
||||
artistId, artistName);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Cursor makeSongCursor(@NonNull final Context context,
|
||||
@Nullable final String selection, final String[] selectionValues) {
|
||||
return makeSongCursor(context, selection, selectionValues,
|
||||
PreferenceUtil.getInstance().getSongSortOrder());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Cursor makeSongCursor(@NonNull final Context context, @Nullable String selection,
|
||||
String[] selectionValues, final String sortOrder) {
|
||||
if (selection != null && !selection.trim().equals("")) {
|
||||
selection = BASE_SELECTION + " AND " + selection;
|
||||
} else {
|
||||
selection = BASE_SELECTION;
|
||||
}
|
||||
|
||||
// Blacklist
|
||||
ArrayList<String> paths = BlacklistStore.getInstance(context).getPaths();
|
||||
if (!paths.isEmpty()) {
|
||||
selection = generateBlacklistSelection(selection, paths.size());
|
||||
selectionValues = addBlacklistSelectionValues(selectionValues, paths);
|
||||
}
|
||||
|
||||
try {
|
||||
return context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
|
||||
BASE_PROJECTION, selection, selectionValues, sortOrder);
|
||||
} catch (SecurityException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateBlacklistSelection(String selection, int pathCount) {
|
||||
StringBuilder newSelection = new StringBuilder(
|
||||
selection != null && !selection.trim().equals("") ? selection + " AND " : "");
|
||||
newSelection.append(AudioColumns.DATA + " NOT LIKE ?");
|
||||
for (int i = 0; i < pathCount - 1; i++) {
|
||||
newSelection.append(" AND " + AudioColumns.DATA + " NOT LIKE ?");
|
||||
}
|
||||
return newSelection.toString();
|
||||
}
|
||||
|
||||
private static String[] addBlacklistSelectionValues(String[] selectionValues,
|
||||
ArrayList<String> paths) {
|
||||
if (selectionValues == null) {
|
||||
selectionValues = new String[0];
|
||||
}
|
||||
String[] newSelectionValues = new String[selectionValues.length + paths.size()];
|
||||
System.arraycopy(selectionValues, 0, newSelectionValues, 0, selectionValues.length);
|
||||
for (int i = selectionValues.length; i < newSelectionValues.length; i++) {
|
||||
newSelectionValues[i] = paths.get(i - selectionValues.length) + "%";
|
||||
}
|
||||
return newSelectionValues;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<Song> getSong(@Nullable Cursor cursor) {
|
||||
return Observable.create(e -> {
|
||||
Song song;
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
song = getSongFromCursorImpl(cursor);
|
||||
} else {
|
||||
song = Song.EMPTY_SONG;
|
||||
}
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
e.onNext(song);
|
||||
e.onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<Song> getSong(@NonNull final Context context, final int queryId) {
|
||||
Cursor cursor = makeSongCursor(context, AudioColumns._ID + "=?",
|
||||
new String[]{String.valueOf(queryId)});
|
||||
return getSong(cursor);
|
||||
}
|
||||
|
||||
public static Observable<ArrayList<Song>> suggestSongs(@NonNull Context context) {
|
||||
return SongLoader.getAllSongs(context)
|
||||
.flatMap((Function<ArrayList<Song>, ObservableSource<ArrayList<Song>>>) songs -> {
|
||||
ArrayList<Song> list = new ArrayList<>();
|
||||
ShuffleHelper.makeShuffleList(songs, -1);
|
||||
if (songs.size() > 9) {
|
||||
list.addAll(songs.subList(0, 9));
|
||||
}
|
||||
return Observable.just(list);
|
||||
});
|
||||
/*.subscribe(songs -> {
|
||||
ArrayList<Song> list = new ArrayList<>();
|
||||
if (songs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ShuffleHelper.makeShuffleList(songs, -1);
|
||||
if (songs.size() > 10) {
|
||||
list.addAll(songs.subList(0, 10));
|
||||
} else {
|
||||
list.addAll(songs);
|
||||
}
|
||||
return;
|
||||
});*/
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
package code.name.monkey.retromusic.loaders
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.provider.BaseColumns
|
||||
import android.provider.MediaStore
|
||||
import android.provider.MediaStore.Audio.AudioColumns
|
||||
import code.name.monkey.retromusic.helper.ShuffleHelper
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.providers.BlacklistStore
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import io.reactivex.Observable
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by hemanths on 10/08/17.
|
||||
*/
|
||||
|
||||
open class SongLoader {
|
||||
companion object {
|
||||
|
||||
const val BASE_SELECTION = AudioColumns.IS_MUSIC + "=1" + " AND " + AudioColumns.TITLE + " != ''"
|
||||
val BASE_PROJECTION = arrayOf(BaseColumns._ID, // 0
|
||||
AudioColumns.TITLE, // 1
|
||||
AudioColumns.TRACK, // 2
|
||||
AudioColumns.YEAR, // 3
|
||||
AudioColumns.DURATION, // 4
|
||||
AudioColumns.DATA, // 5
|
||||
AudioColumns.DATE_MODIFIED, // 6
|
||||
AudioColumns.ALBUM_ID, // 7
|
||||
AudioColumns.ALBUM, // 8
|
||||
AudioColumns.ARTIST_ID, // 9
|
||||
AudioColumns.ARTIST)// 10
|
||||
|
||||
fun getAllSongs(context: Context): Observable<ArrayList<Song>> {
|
||||
val cursor = makeSongCursor(context, null, null)
|
||||
return getSongs(cursor)
|
||||
}
|
||||
|
||||
fun getSongs(context: Context, query: String): Observable<ArrayList<Song>> {
|
||||
val cursor = makeSongCursor(context, AudioColumns.TITLE + " LIKE ?", arrayOf("%$query%"))
|
||||
return getSongs(cursor)
|
||||
}
|
||||
|
||||
fun getSongs(cursor: Cursor?): Observable<ArrayList<Song>> {
|
||||
return Observable.create { e ->
|
||||
val songs = ArrayList<Song>()
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
songs.add(getSongFromCursorImpl(cursor))
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
|
||||
cursor?.close()
|
||||
e.onNext(songs)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSongFromCursorImpl(cursor: Cursor): Song {
|
||||
val id = cursor.getInt(0)
|
||||
val title = cursor.getString(1)
|
||||
val trackNumber = cursor.getInt(2)
|
||||
val year = cursor.getInt(3)
|
||||
val duration = cursor.getLong(4)
|
||||
val data = cursor.getString(5)
|
||||
val dateModified = cursor.getLong(6)
|
||||
val albumId = cursor.getInt(7)
|
||||
val albumName = cursor.getString(8)
|
||||
val artistId = cursor.getInt(9)
|
||||
val artistName = cursor.getString(10)
|
||||
|
||||
return Song(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName,
|
||||
artistId, artistName)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun makeSongCursor(context: Context, selection: String?, selectionValues: Array<String>?, sortOrder: String = PreferenceUtil.getInstance().songSortOrder): Cursor? {
|
||||
var selectionFinal = selection
|
||||
var selectionValuesFinal = selectionValues
|
||||
selectionFinal = if (selection != null && selection.trim { it <= ' ' } != "") {
|
||||
"$BASE_SELECTION AND $selectionFinal"
|
||||
} else {
|
||||
BASE_SELECTION
|
||||
}
|
||||
|
||||
// Blacklist
|
||||
val paths = BlacklistStore.getInstance(context).paths
|
||||
if (!paths.isEmpty()) {
|
||||
selectionFinal = generateBlacklistSelection(selectionFinal, paths.size)
|
||||
selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths)
|
||||
}
|
||||
|
||||
try {
|
||||
return context.contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
|
||||
BASE_PROJECTION, selectionFinal, selectionValuesFinal, sortOrder)
|
||||
} catch (e: SecurityException) {
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun generateBlacklistSelection(selection: String?, pathCount: Int): String {
|
||||
val newSelection = StringBuilder(
|
||||
if (selection != null && selection.trim { it <= ' ' } != "") "$selection AND " else "")
|
||||
newSelection.append(AudioColumns.DATA + " NOT LIKE ?")
|
||||
for (i in 0 until pathCount - 1) {
|
||||
newSelection.append(" AND " + AudioColumns.DATA + " NOT LIKE ?")
|
||||
}
|
||||
return newSelection.toString()
|
||||
}
|
||||
|
||||
private fun addBlacklistSelectionValues(selectionValues: Array<String>?,
|
||||
paths: ArrayList<String>): Array<String>? {
|
||||
var selectionValuesFinal = selectionValues
|
||||
if (selectionValuesFinal == null) {
|
||||
selectionValuesFinal = emptyArray()
|
||||
}
|
||||
val newSelectionValues = Array(selectionValuesFinal.size + paths.size) {
|
||||
"n = $it"
|
||||
}
|
||||
System.arraycopy(selectionValuesFinal, 0, newSelectionValues, 0, selectionValuesFinal.size)
|
||||
for (i in selectionValuesFinal.size until newSelectionValues.size) {
|
||||
newSelectionValues[i] = paths[i - selectionValuesFinal.size] + "%"
|
||||
}
|
||||
return newSelectionValues
|
||||
}
|
||||
|
||||
fun getSong(cursor: Cursor?): Observable<Song> {
|
||||
return Observable.create { e ->
|
||||
val song: Song
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
song = getSongFromCursorImpl(cursor)
|
||||
} else {
|
||||
song = Song.EMPTY_SONG
|
||||
}
|
||||
cursor?.close()
|
||||
e.onNext(song)
|
||||
e.onComplete()
|
||||
}
|
||||
}
|
||||
|
||||
fun getSong(context: Context, queryId: Int): Observable<Song> {
|
||||
val cursor = makeSongCursor(context, AudioColumns._ID + "=?",
|
||||
arrayOf(queryId.toString()))
|
||||
return getSong(cursor)
|
||||
}
|
||||
|
||||
fun suggestSongs(context: Context): Observable<ArrayList<Song>> {
|
||||
return SongLoader.getAllSongs(context)
|
||||
.flatMap {
|
||||
val list = ArrayList<Song>()
|
||||
ShuffleHelper.makeShuffleList(it, -1)
|
||||
if (it.size > 9) {
|
||||
list.addAll(it.subList(0, 9))
|
||||
}
|
||||
return@flatMap Observable.just(list)
|
||||
}
|
||||
/*.flatMap({ songs ->
|
||||
val list = ArrayList<Song>()
|
||||
ShuffleHelper.makeShuffleList(songs, -1)
|
||||
if (songs.size > 9) {
|
||||
list.addAll(songs.subList(0, 9))
|
||||
}
|
||||
Observable.just(list)
|
||||
} as Function<ArrayList<Song>, ObservableSource<ArrayList<Song>>>)*/
|
||||
/*.subscribe(songs -> {
|
||||
ArrayList<Song> list = new ArrayList<>();
|
||||
if (songs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ShuffleHelper.makeShuffleList(songs, -1);
|
||||
if (songs.size() > 10) {
|
||||
list.addAll(songs.subList(0, 10));
|
||||
} else {
|
||||
list.addAll(songs);
|
||||
}
|
||||
return;
|
||||
});*/
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,12 +23,12 @@ public class TopAndRecentlyPlayedTracksLoader {
|
|||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getRecentlyPlayedTracks(@NonNull Context context) {
|
||||
return SongLoader.getSongs(makeRecentTracksCursorAndClearUpDatabase(context));
|
||||
return SongLoader.Companion.getSongs(makeRecentTracksCursorAndClearUpDatabase(context));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Observable<ArrayList<Song>> getTopTracks(@NonNull Context context) {
|
||||
return SongLoader.getSongs(makeTopTracksCursorAndClearUpDatabase(context));
|
||||
return SongLoader.Companion.getSongs(makeTopTracksCursorAndClearUpDatabase(context));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -122,7 +122,7 @@ public class TopAndRecentlyPlayedTracksLoader {
|
|||
selection.append(")");
|
||||
|
||||
// get a list of songs with the data given the selection statement
|
||||
Cursor songCursor = SongLoader.makeSongCursor(context, selection.toString(), null);
|
||||
Cursor songCursor = SongLoader.Companion.makeSongCursor(context, selection.toString(), null);
|
||||
if (songCursor != null) {
|
||||
// now return the wrapped TopTracksCursor to handle sorting given order
|
||||
return new SortedLongCursor(songCursor, order, BaseColumns._ID);
|
||||
|
|
|
@ -37,7 +37,7 @@ public class ShuffleAllPlaylist extends AbsSmartPlaylist {
|
|||
@NonNull
|
||||
@Override
|
||||
public Observable<ArrayList<Song>> getSongs(@NonNull Context context) {
|
||||
return SongLoader.getAllSongs(context);
|
||||
return SongLoader.Companion.getAllSongs(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -198,6 +198,6 @@ public class MusicPlaybackQueueStore extends SQLiteOpenHelper {
|
|||
private Observable<ArrayList<Song>> getQueue(@NonNull final String tableName) {
|
||||
Cursor cursor = getReadableDatabase().query(tableName, null,
|
||||
null, null, null, null, null);
|
||||
return SongLoader.getSongs(cursor);
|
||||
return SongLoader.Companion.getSongs(cursor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,17 +48,17 @@ public class RepositoryImpl implements Repository {
|
|||
|
||||
@Override
|
||||
public Observable<ArrayList<Song>> getAllSongs() {
|
||||
return SongLoader.getAllSongs(context);
|
||||
return SongLoader.Companion.getAllSongs(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<ArrayList<Song>> getSuggestionSongs() {
|
||||
return SongLoader.suggestSongs(context);
|
||||
return SongLoader.Companion.suggestSongs(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<Song> getSong(int id) {
|
||||
return SongLoader.getSong(context, id);
|
||||
return SongLoader.Companion.getSong(context, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -238,7 +238,7 @@ public class WearBrowserService extends MediaBrowserService {
|
|||
}
|
||||
break;
|
||||
case TYPE_SONG:
|
||||
List<Song> songList = SongLoader.getAllSongs(mContext).blockingFirst();
|
||||
List<Song> songList = SongLoader.Companion.getAllSongs(mContext).blockingFirst();
|
||||
for (Song song : songList) {
|
||||
fillMediaItems(mediaItems,
|
||||
String.valueOf(song.id),
|
||||
|
@ -326,7 +326,7 @@ public class WearBrowserService extends MediaBrowserService {
|
|||
long songId = Long.parseLong(mediaId);
|
||||
setSessionActive();
|
||||
ArrayList<Song> songs = new ArrayList<>();
|
||||
songs.add(SongLoader.getSong(mContext, Integer.parseInt(mediaId)).blockingFirst());
|
||||
songs.add(SongLoader.Companion.getSong(mContext, Integer.parseInt(mediaId)).blockingFirst());
|
||||
MusicPlayerRemote.openQueue(songs, 0, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ public class RetroMusicAlbums extends DreamService {
|
|||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.flatMap((Function<ArrayList<Song>, ObservableSource<ArrayList<Song>>>) songs -> Observable.create(e -> {
|
||||
if (songs.isEmpty()) {
|
||||
e.onNext(SongLoader.getAllSongs(RetroMusicAlbums.this).blockingFirst());
|
||||
e.onNext(SongLoader.Companion.getAllSongs(RetroMusicAlbums.this).blockingFirst());
|
||||
} else {
|
||||
e.onNext(songs);
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ public class SongTagEditorActivity extends AbsTagEditorActivity implements TextW
|
|||
@Override
|
||||
protected List<String> getSongPaths() {
|
||||
ArrayList<String> paths = new ArrayList<>(1);
|
||||
paths.add(SongLoader.getSong(this, getId()).blockingFirst().data);
|
||||
paths.add(SongLoader.Companion.getSong(this, getId()).blockingFirst().data);
|
||||
return paths;
|
||||
}
|
||||
|
||||
|
|
|
@ -363,7 +363,7 @@ public class LibraryFragment extends AbsMainActivityFragment implements CabHolde
|
|||
CreatePlaylistDialog.create().show(getChildFragmentManager(), "CREATE_PLAYLIST");
|
||||
return true;
|
||||
case R.id.action_shuffle_all:
|
||||
MusicPlayerRemote.openAndShuffleQueue(SongLoader.getAllSongs(getContext())
|
||||
MusicPlayerRemote.openAndShuffleQueue(SongLoader.Companion.getAllSongs(getContext())
|
||||
.blockingFirst(), true);
|
||||
return true;
|
||||
case R.id.action_equalizer:
|
||||
|
|
|
@ -341,7 +341,7 @@ public class BannerHomeFragment extends AbsMainActivityFragment implements MainA
|
|||
if (activity != null) {
|
||||
switch (view.getId()) {
|
||||
case R.id.action_shuffle:
|
||||
MusicPlayerRemote.openAndShuffleQueue(SongLoader.getAllSongs(activity).blockingFirst(), true);
|
||||
MusicPlayerRemote.openAndShuffleQueue(SongLoader.Companion.getAllSongs(activity).blockingFirst(), true);
|
||||
break;
|
||||
case R.id.last_added:
|
||||
NavigationUtil.goToPlaylistNew(activity, new LastAddedPlaylist(activity));
|
||||
|
|
|
@ -4,8 +4,6 @@ import android.content.Context;
|
|||
import android.database.Cursor;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
@ -22,6 +20,8 @@ import java.util.Collections;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import code.name.monkey.retromusic.loaders.SongLoader;
|
||||
import code.name.monkey.retromusic.loaders.SortedCursor;
|
||||
import code.name.monkey.retromusic.model.Song;
|
||||
|
@ -47,7 +47,7 @@ public final class FileUtil {
|
|||
@NonNull
|
||||
public static Observable<ArrayList<Song>> matchFilesWithMediaStore(@NonNull Context context,
|
||||
@Nullable List<File> files) {
|
||||
return SongLoader.getSongs(makeSongCursor(context, files));
|
||||
return SongLoader.Companion.getSongs(makeSongCursor(context, files));
|
||||
}
|
||||
|
||||
public static String safeGetCanonicalPath(File file) {
|
||||
|
@ -75,8 +75,7 @@ public final class FileUtil {
|
|||
}
|
||||
}
|
||||
|
||||
Cursor songCursor = SongLoader
|
||||
.makeSongCursor(context, selection, selection == null ? null : paths);
|
||||
Cursor songCursor = SongLoader.Companion.makeSongCursor(context, selection, selection == null ? null : paths);
|
||||
|
||||
return songCursor == null ? null
|
||||
: new SortedCursor(songCursor, paths, MediaStore.Audio.AudioColumns.DATA);
|
||||
|
|
|
@ -224,7 +224,7 @@ public class MusicUtil {
|
|||
cursor.moveToFirst();
|
||||
while (!cursor.isAfterLast()) {
|
||||
final int id = cursor.getInt(0);
|
||||
Song song = SongLoader.getSong(activity, id).blockingFirst();
|
||||
Song song = SongLoader.Companion.getSong(activity, id).blockingFirst();
|
||||
MusicPlayerRemote.removeFromQueue(song);
|
||||
cursor.moveToNext();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue