diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
new file mode 100644
index 0000000..d2e26ae
Binary files /dev/null and b/.idea/caches/build_file_checksums.ser differ
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..30aa626
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..7ac24c7
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..dc34569
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..4cfe290
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..7f68460
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/app.iml b/app/app.iml
index f70e089..3115a87 100644
--- a/app/app.iml
+++ b/app/app.iml
@@ -1,5 +1,5 @@
-
+
@@ -9,13 +9,9 @@
-
-
-
- generateDebugAndroidTestSources
generateDebugSources
@@ -26,74 +22,117 @@
-
+
-
+
+
-
+
+
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 68d6639..97e5069 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,14 +2,14 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 23
- buildToolsVersion "23.0.3"
+ buildToolsVersion '27.0.3'
defaultConfig {
applicationId "max.music_cyclon"
minSdkVersion 14
targetSdkVersion 23
versionCode 2
- versionName "0.2"
+ versionName "0.3"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
diff --git a/app/src/main/java/max/music_cyclon/service/BeetsFetcher.java b/app/src/main/java/max/music_cyclon/service/BeetsFetcher.java
index ec6e3a4..0f24170 100644
--- a/app/src/main/java/max/music_cyclon/service/BeetsFetcher.java
+++ b/app/src/main/java/max/music_cyclon/service/BeetsFetcher.java
@@ -10,8 +10,10 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Random;
+import java.util.Set;
import max.music_cyclon.SynchronizeConfig;
import okhttp3.OkHttpClient;
@@ -29,45 +31,48 @@ public class BeetsFetcher {
this.resources = resources;
}
- public List- fetch(SynchronizeConfig config) throws IOException {
+ public Set
- fetch(SynchronizeConfig config,
+ String username, String password) throws IOException {
StringBuilder get;
if (config.isAlbum(resources)) {
- get = new StringBuilder("/album");
+ get = new StringBuilder("/album/");
} else {
- get = new StringBuilder("/item");
+ get = new StringBuilder("/item/");
}
String query = config.getQuery(resources);
if (!query.isEmpty()) {
- get.append("/query/").append(query);
+ get.append("query/").append(query);
}
get.append("?expand");
OkHttpClient client = new OkHttpClient();
+ String auth = okhttp3.Credentials.basic(username != null ? username : "",
+ password != null ? password : "");
Request request = new Request.Builder()
.url(address + get)
+ .header("Authorization", auth)
.build();
Response response = client.newCall(request).execute();
if (response.code() != 200) {
Log.e("ERROR", "Server returned HTTP " + response.message());
- return Collections.emptyList();
+ return Collections.emptySet();
}
InputStream stream = response.body().byteStream();
- List
- items = parseJson(stream, config.getSize(resources), config.isAlbum(resources));
+ Set
- items = parseJson(stream, config.getSize(resources), config.isAlbum(resources));
stream.close();
return items;
}
- private List
- parseJson(InputStream stream, int size, boolean isAlbums) throws IOException {
+ private Set
- parseJson(InputStream stream, int size, boolean isAlbums) throws IOException {
JsonReader reader = new JsonReader(new BufferedReader(new InputStreamReader(stream, "UTF-8")));
-
List
- items = new ArrayList<>();
List> albums = new ArrayList<>();
@@ -87,28 +92,31 @@ public class BeetsFetcher {
// Select random
if (isAlbums) {
- List> randomAlbums = selectRandom(albums, size);
+ Set> randomAlbums = selectRandom(albums, size);
- for (ArrayList
- album : randomAlbums) {
+ for (List
- album : randomAlbums) {
items.addAll(album);
}
- return Collections.unmodifiableList(items);
+
+ return Collections.unmodifiableSet(new HashSet
- (items));
} else {
return selectRandom(items, size);
}
}
- public List selectRandom(List list, int n) {
+ public Set selectRandom(List list, int n) {
if (list.isEmpty()) {
- return Collections.emptyList();
+ return Collections.emptySet();
}
- ArrayList out = new ArrayList<>();
+ Set out = new HashSet();
+
for (int i = 0; i < n; i++) {
- out.add(list.get(RANDOM.nextInt(list.size() - 1)));
+ int item = list.size() > 1 ? RANDOM.nextInt(list.size() - 1) : 0;
+ out.add(list.get(item));
}
- return Collections.unmodifiableList(out);
+ return Collections.unmodifiableSet(out);
}
private ArrayList
- parseAlbum(JsonReader reader) throws IOException {
@@ -144,8 +152,14 @@ public class BeetsFetcher {
case "id":
item.setID(reader.nextInt());
break;
- case "path":
- item.setPath(reader.nextString());
+ case "format":
+ item.setFormat(reader.nextString());
+ break;
+ case "title":
+ item.setTitle(reader.nextString());
+ break;
+ case "artist":
+ item.setArtist(reader.nextString());
break;
default:
reader.skipValue();
diff --git a/app/src/main/java/max/music_cyclon/service/DownloadTask.java b/app/src/main/java/max/music_cyclon/service/DownloadTask.java
index 70905f7..0745429 100644
--- a/app/src/main/java/max/music_cyclon/service/DownloadTask.java
+++ b/app/src/main/java/max/music_cyclon/service/DownloadTask.java
@@ -23,26 +23,38 @@ public class DownloadTask implements Runnable {
private final SynchronizeConfig config;
private final String url;
private final String itemPath;
-
+ private final String libraryPath;
+ private final String username;
+ private final String password;
private final FileTracker tracker;
private final ProgressUpdater progressUpdater;
private CountDownLatch itemsLeftLatch;
public static final OkHttpClient CLIENT = new OkHttpClient();
- public DownloadTask(SynchronizeConfig config, String url, String itemPath,
- FileTracker tracker, ProgressUpdater progressUpdater) {
+ public DownloadTask(SynchronizeConfig config, String url,
+ String libraryPath, String itemPath,
+ FileTracker tracker, ProgressUpdater progressUpdater,
+ String username, String password
+ ) {
this.config = config;
this.url = url;
this.itemPath = itemPath;
+ this.libraryPath = libraryPath;
+
+ this.username = username;
+ this.password = password;
this.tracker = tracker;
this.progressUpdater = progressUpdater;
}
private InputStream prepareConnection() throws IOException {
+ String auth = okhttp3.Credentials.basic(username != null ? username : "",
+ password != null ? password : "");
Request request = new Request.Builder()
.url(url)
+ .header("Authorization", auth)
.build();
Response response = CLIENT.newCall(request).execute();
@@ -61,35 +73,41 @@ public class DownloadTask implements Runnable {
@Override
public void run() {
- File root = new File(Environment.getExternalStorageDirectory(), "library");
+ File root = new File(Environment.getExternalStorageDirectory(),
+ libraryPath);
+ if (itemPath != null) {
+ try {
+ File target = new File(root, itemPath);
+ if (! target.exists()) {
+ Adler32 checksum = new Adler32();
- try {
- File target = new File(root, itemPath);
- Adler32 checksum = new Adler32();
+ InputStream input = prepareConnection();
- InputStream input = prepareConnection();
+ if (input != null) {
+ Log.d("DOWNLOAD", "Writing file: " + target);
+ FileOutputStream output = FileUtils.openOutputStream(target);
- if (input != null) {
+ byte[] buffer = new byte[4 * 1024];
+ int n;
+ while (-1 != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ checksum.update(buffer, 0, n);
+ }
- FileOutputStream output = FileUtils.openOutputStream(target);
+ output.flush();
+ output.close();
+ input.close();
+ }
- byte[] buffer = new byte[4 * 1024];
- int n;
- while (-1 != (n = input.read(buffer))) {
- output.write(buffer, 0, n);
- checksum.update(buffer, 0, n);
+ tracker.track(config, target, checksum.getValue());
}
-
- output.flush();
- output.close();
- input.close();
+ } catch (IOException e) {
+ Log.e("DOWNLOAD", "Failed to download", e);
}
-
- tracker.track(config, target, checksum.getValue());
- } catch (IOException e) {
- Log.e("DOWNLOAD", "Failed to download", e);
+ Log.i("DOWNLOAD", "Success");
+ } else {
+ Log.e("DOWNLOAD", "Missing download path, FAILED!");
}
-
progressUpdater.increment();
itemsLeftLatch.countDown();
}
diff --git a/app/src/main/java/max/music_cyclon/service/Item.java b/app/src/main/java/max/music_cyclon/service/Item.java
index 6d47458..a512a28 100644
--- a/app/src/main/java/max/music_cyclon/service/Item.java
+++ b/app/src/main/java/max/music_cyclon/service/Item.java
@@ -4,6 +4,9 @@ public class Item {
private int id;
private String path;
+ private String artist;
+ private String title;
+ private String format;
public int getID() {
return id;
@@ -14,10 +17,32 @@ public class Item {
}
public String getPath() {
- return path;
+ if (path != null) {
+ return path;
+ } else {
+ return "/" + artist + "/" + title + "_" + id + "." + format.toLowerCase();
+ }
+ }
+ public String getArtist() {
+ return artist;
+ }
+ public String getTitle() {
+ return title;
+ }
+ public String getFormat() {
+ return format;
}
public void setPath(String path) {
this.path = path;
}
+ public void setTitle(String title) {
+ this.title = title;
+ }
+ public void setFormat(String format) {
+ this.format = format;
+ }
+ public void setArtist(String artist) {
+ this.artist = artist;
+ }
}
diff --git a/app/src/main/java/max/music_cyclon/service/LibraryService.java b/app/src/main/java/max/music_cyclon/service/LibraryService.java
index 1903b63..668b6ca 100644
--- a/app/src/main/java/max/music_cyclon/service/LibraryService.java
+++ b/app/src/main/java/max/music_cyclon/service/LibraryService.java
@@ -18,13 +18,15 @@ import android.support.v4.app.NotificationCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
-import com.maxmpz.poweramp.player.PowerampAPI;
+// Poweramp support
+// import com.maxmpz.poweramp.player.PowerampAPI;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -133,10 +135,14 @@ public class LibraryService extends IntentService {
for (Parcelable parcelable : configs) {
SynchronizeConfig config = (SynchronizeConfig) parcelable;
- List
- items;
+ Set
- items;
try {
updater.showOngoingMessage("Fetching music information for %s", config.getName());
- items = fetcher.fetch(config);
+ items = fetcher.fetch(config,
+ globalSettings.getString("username", null),
+ globalSettings.getString("password", null));
+ Log.d("LISTOUT", "Length: " + items.size());
+
} catch (IOException e) {
Log.wtf("WTF", e);
updater.showMessage("Remote not available");
@@ -149,7 +155,12 @@ public class LibraryService extends IntentService {
for (Item item : items) {
String url = address + "/item/" + item.getID() + "/file";
- tasks.add(new DownloadTask(config, url, item.getPath(), tracker, updater));
+ tasks.add(new DownloadTask(config, url,
+ globalSettings.getString("library_path", "library"),
+ config.getName() + item.getPath(), tracker, updater,
+ globalSettings.getString("username", null),
+ globalSettings.getString("password", null)
+ ));
}
}
@@ -168,14 +179,14 @@ public class LibraryService extends IntentService {
e.printStackTrace();
}
- updater.showMessage("Musik aktualisiert");
-
- // Poweramp support
- Intent poweramp = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS);
- poweramp.setPackage(PowerampAPI.PACKAGE_NAME);
- poweramp.putExtra(PowerampAPI.Scanner.EXTRA_FULL_RESCAN, true);
- startService(poweramp);
+ updater.showMessage(getResources().getString(R.string.music_updated));
+ // I don't want to support proprietary things
+ // If you need to enable Poweramp support, uncomment this
+ // Intent poweramp = new Intent(PowerampAPI.Scanner.ACTION_SCAN_DIRS);
+ // poweramp.setPackage(PowerampAPI.PACKAGE_NAME);
+ // poweramp.putExtra(PowerampAPI.Scanner.EXTRA_FULL_RESCAN, true);
+ // startService(poweramp);
finished();
}
diff --git a/app/src/main/res/values/default_config.xml b/app/src/main/res/values/default_config.xml
index a3c2da4..1b2d867 100644
--- a/app/src/main/res/values/default_config.xml
+++ b/app/src/main/res/values/default_config.xml
@@ -2,6 +2,8 @@
http://localhost:8337
2
+
+
10
true
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7eb7b29..dab879d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -7,6 +7,9 @@
Version
Synchronizing
Already synchronizing!
+ Music Updated!
+
+ library
Default
Rename
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 51cf3af..8500ff7 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -7,12 +7,32 @@
android:key="address"
android:summary="Address of the synchronisation server"
android:title="Address" />
-
+
+
+
-
\ No newline at end of file
+
diff --git a/build.gradle b/build.gradle
index e220f0b..0291d45 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,12 +3,10 @@
buildscript {
repositories {
jcenter()
+ google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.1.2'
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
+ classpath 'com.android.tools.build:gradle:3.1.2'
}
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 6553df6..fa04b38 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Jun 01 15:28:51 CEST 2016
+#Thu May 24 16:50:41 GMT 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/music-cyclon.iml b/music-cyclon.iml
new file mode 100644
index 0000000..2f126a7
--- /dev/null
+++ b/music-cyclon.iml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file