Merge branch 'release/v0.9.4'

This commit is contained in:
Jan Christian Grünhage 2017-02-01 13:32:01 +01:00
commit 1af76ee43d
Signed by: jcgruenhage
GPG key ID: 321A67D9EE8BC3E1
25 changed files with 286 additions and 619 deletions

2
.gitignore vendored
View file

@ -30,6 +30,7 @@ hs_err_pid*
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
.idea/misc.xml
# Gradle:
.idea/gradle.xml
@ -107,3 +108,4 @@ captures/
# Keystore files
*.jks
gradle/wrapper/gradle-wrapper.properties

View file

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View file

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="PlayMusicExporter" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="PlayMusicExporterGit" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -1,21 +1,38 @@
# Play Music Exporter
This Android app exports your Play Music mp3 files directly to your sdcard using root permissions.
This Android app exports your Play Music mp3 files directly to your sdcard
or a documents provider using root permissions.
You can also setup automatic export, that exports all currently cached not yet exported music.
## About
This AndroidStudio project allow you to access the database from Google's PlayMusic and also allows you to export the music files as mp3 to your sdcard. There is also a nice library you can simply use in your projects.
This AndroidStudio project allow you to access the database from Google's PlayMusic
and also allows you to export the music files as mp3 to your sdcard or a documents provider.
There is also a nice library you can simply use in your projects.
### Requirements
**This app and its library will require root access to your device! If your device is not rooted you can't use this app neither the lib.**
**This app and the included library will require root access to your device!
If your device is not rooted you can neither use this app nor the library.**
This project uses the [mp3agic library](https://github.com/mpatric/mp3agic) by [Michael Patricios (mpatric)](https://github.com/mpatric).
This app uses API Level 21, which has been introduced by Android Lollipop. If you use KitKat
or lower, this app will not work.
### Notice
### Credits
I recently forked this repository and most of the work has been done by [David Schulte](https://www.david-schulte.de/).
You can find his old/inactive repository [here](https://github.com/Arcus92/PlayMusicExporter).
This is a fork off [David Schulte's original project](https://github.com/Arcus92/PlayMusicExporter).
Most of the work has been done by him, me and the other collaborators just have improved his work
in some minor ways, like making the app more usable and configurable. The exporting itself, the hard
part, has been done by him.
This project uses the [mp3agic library](https://github.com/mpatric/mp3agic)
by [Michael Patricios (mpatric)](https://github.com/mpatric).
### Contributing
If you want to contribute to this project, fork off of develop,
implement what you want to implement, and submit a pull request back into develop.
After testing it, if enough of the collaborators like it, we will merge it.
### Copyright

Binary file not shown.

View file

@ -29,7 +29,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
classpath 'com.android.tools.build:gradle:2.3.0-beta3'
}
}

View file

@ -42,5 +42,5 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.1.0'
compile 'com.android.support:appcompat-v7:25.1.1'
}

View file

@ -1,121 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":framework" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="PlayMusicExporter" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":framework" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
<option name="PROJECT_TYPE" value="1" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotations" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/animated-vector-drawable/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-compat/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-ui/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-utils/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-fragment/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-media-compat/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-vector-drawable/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/typedefs.txt" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="support-compat-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-fragment-25.1.0" level="project" />
<orderEntry type="library" exported="" name="animated-vector-drawable-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-v4-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-core-ui-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-media-compat-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-vector-drawable-25.1.0" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-core-utils-25.1.0" level="project" />
</component>
</module>

View file

@ -1,6 +1,6 @@
#Fri Nov 25 23:05:46 CET 2016
#Sun Jan 22 21:19:51 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip

View file

@ -57,9 +57,9 @@ dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':framework')
compile project(':playmusiclib')
compile 'com.android.support:appcompat-v7:25.1.0'
compile 'com.android.support:support-v4:25.1.0'
compile 'com.android.support:design:25.1.0'
compile 'com.android.support:support-vector-drawable:25.1.0'
compile 'com.android.support:appcompat-v7:25.1.1'
compile 'com.android.support:support-v4:25.1.1'
compile 'com.android.support:design:25.1.1'
compile 'com.android.support:support-vector-drawable:25.1.1'
compile "com.github.paolorotolo:appintro:4.1.0"
}

View file

@ -1,131 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":playmusicexporter" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="PlayMusicExporter" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":playmusicexporter" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/animated-vector-drawable/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-compat/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-ui/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-utils/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-fragment/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-media-compat/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-vector-drawable/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/transition/25.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.github.paolorotolo/appintro/4.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/packaged" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="support-annotations-25.1.0" level="project" />
<orderEntry type="library" exported="" name="design-25.1.0" level="project" />
<orderEntry type="library" exported="" name="transition-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-compat-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-fragment-25.1.0" level="project" />
<orderEntry type="library" exported="" name="animated-vector-drawable-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-v4-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-core-ui-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-media-compat-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-vector-drawable-25.1.0" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-25.1.0" level="project" />
<orderEntry type="library" exported="" name="recyclerview-v7-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-core-utils-25.1.0" level="project" />
<orderEntry type="library" exported="" name="appintro-4.1.0" level="project" />
<orderEntry type="module" module-name="playmusiclib" exported="" />
<orderEntry type="module" module-name="framework" exported="" />
<orderEntry type="library" exported="" name="mp3agic-0.8.4" level="project" />
</component>
</module>

View file

@ -25,6 +25,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application
android:allowBackup="true"

View file

@ -22,8 +22,10 @@
package re.jcg.playmusicexporter.fragments;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.PowerManager;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
@ -63,6 +65,7 @@ public class MusicTrackListFragment extends Fragment {
*/
public static final String ARG_MUSIC_TRACK_LIST_ID = "music_track_list_id";
public static final String ARG_MUSIC_TRACK_LIST_TYPE = "music_track_list_type";
private PowerManager.WakeLock m_CPULock;
/**
* The track list
@ -138,6 +141,8 @@ public class MusicTrackListFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PowerManager powerManager = (PowerManager)this.getContext().getSystemService(Context.POWER_SERVICE);
m_CPULock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ExportAllService");
if (getArguments().containsKey(ARG_MUSIC_TRACK_LIST_ID)
&& getArguments().containsKey(ARG_MUSIC_TRACK_LIST_TYPE)) {
@ -213,12 +218,19 @@ public class MusicTrackListFragment extends Fragment {
mFloatingButtonExport = (FloatingActionButton) rootView.findViewById(R.id.floating_button_export);
mFloatingButtonExport.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
public void onClick(View v)
{
m_CPULock.acquire();
// Export all selected tracks
for (SelectedTrack selectedTrack : SelectedTrackList.getInstance().getSelectedItems()) {
selectedTrack.export(getActivity());
}
if ( m_CPULock.isHeld())
{
m_CPULock.release();
}
// Clear the selection
SelectedTrackList.getInstance().clear(true);
}

View file

@ -12,6 +12,7 @@ import re.jcg.playmusicexporter.settings.PlayMusicExporterPreferences;
public class ExportAllJob extends JobService {
public static final String TAG = "AutoGPME_ExportJob";
public static final int AUTO_EXPORT_JOB_ID = 0;
/**
@ -21,27 +22,33 @@ public class ExportAllJob extends JobService {
*/
public static void scheduleExport(final Context pContext) {
PlayMusicExporterPreferences.init(pContext);
JobScheduler lJobScheduler = (JobScheduler) pContext.getSystemService(JOB_SCHEDULER_SERVICE);
if (PlayMusicExporterPreferences.getAutoExportEnabled()) {
long lInterval = PlayMusicExporterPreferences.getAutoExportFrequency();
boolean lRequireUnmeteredNetwork = PlayMusicExporterPreferences.getAutoExportRequireUnmetered();
boolean lRequireCharging = PlayMusicExporterPreferences.getAutoExportRequireCharging();
JobScheduler lJobScheduler = (JobScheduler) pContext.getSystemService(JOB_SCHEDULER_SERVICE);
ComponentName lComponentName = new ComponentName(pContext, ExportAllJob.class);
JobInfo.Builder lBuilder = new JobInfo.Builder(42, lComponentName);
JobInfo.Builder lBuilder = new JobInfo.Builder(AUTO_EXPORT_JOB_ID, lComponentName);
lBuilder.setPeriodic(lInterval);
lBuilder.setPersisted(true);
if (lRequireUnmeteredNetwork)
lBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
lBuilder.setRequiresCharging(lRequireCharging);
lJobScheduler.schedule(lBuilder.build());
} else {
lJobScheduler.cancel(AUTO_EXPORT_JOB_ID);
}
}
@Override
public boolean onStartJob(JobParameters params) {
PlayMusicExporterPreferences.init(this.getApplicationContext());
Log.i(TAG, "Started Job: " + params.toString());
ExportAllService.startExport(this);
if (PlayMusicExporterPreferences.getAutoExportEnabled()) {
ExportAllService.startExport(this);
} else {
scheduleExport(getApplicationContext());
}
return true;
}

View file

@ -4,7 +4,7 @@ import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.provider.DocumentFile;
import android.os.PowerManager;
import android.util.Log;
import java.util.List;
@ -24,15 +24,18 @@ public class ExportAllService extends IntentService {
public static final String TAG = "AutoGPME_ExportService";
public static final String ACTION_EXPORT = "re.jcg.playmusicexporter.action.EXPORT";
public static final String ACTION_SET_EXPORT_JOB = "re.jcg.playmusicexporter.action.SET_EXPORT_JOB";
private static PowerManager m_powerManager;
public static void startExport(Context pContext) {
m_powerManager = (PowerManager) pContext.getSystemService(POWER_SERVICE);
Intent lIntent = new Intent(pContext, ExportAllService.class);
lIntent.setAction(ACTION_EXPORT);
pContext.startService(lIntent);
Log.i(TAG, "Intent sent!");
}
public ExportAllService() {
public ExportAllService()
{
super("AutoGPME-ExportService");
}
@ -62,21 +65,20 @@ public class ExportAllService extends IntentService {
Log.i(TAG, lUri.toString());
AlbumDataSource lAlbumDataSource = new AlbumDataSource(lPlayMusicManager);
lAlbumDataSource.setOfflineOnly(true);
PowerManager.WakeLock CPULock = m_powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ExportAllService");
CPULock.acquire();
List<Album> lAlba = lAlbumDataSource.getAll();
for (Album lAlbum : lAlba) {
for (MusicTrack lTrack : lAlbum.getMusicTrackList()) {
if (lTrack.isOfflineAvailable()) {
String lPath = MusicPathBuilder.Build(lTrack, lExportStructure);
try {
if (!isAlreadyThere(lUri, lPath)) {
if (lPlayMusicManager.exportMusicTrack(lTrack, lUri, lPath)) {
Log.i(TAG, "Exported Music Track: " + getStringForTrack(lTrack));
} else {
Log.i(TAG, "Failed to export Music Track: " + getStringForTrack(lTrack));
}
if (lPlayMusicManager.exportMusicTrack(lTrack, lUri, lPath, PlayMusicExporterPreferences.getFileOverwritePreference())) {
Log.i(TAG, "Exported Music Track: " + getStringForTrack(lTrack));
} else {
Log.i(TAG, lPath + " already exists.");
Log.i(TAG, "Failed to export Music Track: " + getStringForTrack(lTrack));
}
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Invalid URI:")) {
/*
@ -87,22 +89,20 @@ public class ExportAllService extends IntentService {
Log.i(TAG, "Automatic export failed, because the URI is invalid.");
} else throw e;
}
finally
{
if ( CPULock.isHeld())
{
CPULock.release();
}
}
}
}
}
}
private boolean isAlreadyThere(Uri pUri, String pPath) {
DocumentFile lDocumentFile = DocumentFile.fromTreeUri(this, pUri);
for (String lDisplayName: pPath.split("/")) {
if (lDocumentFile.findFile(lDisplayName) != null) {
lDocumentFile = lDocumentFile.findFile(lDisplayName);
} else {
Log.i(TAG, pPath + " does not exist yet.");
return false;
}
if ( CPULock.isHeld())
{
CPULock.release();
}
return true;
}
private String getStringForTrack(MusicTrack pTrack) {

View file

@ -35,6 +35,7 @@ import re.jcg.playmusicexporter.R;
import de.arcus.playmusiclib.PlayMusicManager;
import de.arcus.playmusiclib.datasources.MusicTrackDataSource;
import de.arcus.playmusiclib.items.MusicTrack;
import re.jcg.playmusicexporter.settings.PlayMusicExporterPreferences;
/**
* The export service
@ -199,7 +200,7 @@ public class ExportService extends IntentService {
updateNotification();
// Exports the song
if(!playMusicManager.exportMusicTrack(mTrackCurrent, uri, path)) {
if(!playMusicManager.exportMusicTrack(mTrackCurrent, uri, path, PlayMusicExporterPreferences.getFileOverwritePreference())) {
// Export failed
mTracksFailed ++;
}

View file

@ -16,6 +16,8 @@ public class PlayMusicExporterPreferences {
public static final boolean AUTO_EXPORT_ENABLED_DEFAULT = false;
public static final String AUTO_EXPORT_USES_DIFFERENT_PATH = "preference_auto_export_use_different_path";
public static final boolean AUTO_EXPORT_USES_DIFFERENT_PATH_DEFAULT = false;
private static final String FORCE_EXPORT_OVERWRITE = "preference_overwrite_existing_files";
private static final boolean FORCE_EXPORT_OVERWRITE_DEFAULT = false;
public static final String AUTO_EXPORT_USES_DIFFERENT_STRUCTURE = "preference_auto_export_use_different_structure";
public static final boolean AUTO_EXPORT_USES_DIFFERENT_STRUCTURE_DEFAULT = false;
public static final String AUTO_EXPORT_FREQUENCY = "preference_auto_export_frequency";
@ -63,6 +65,10 @@ public class PlayMusicExporterPreferences {
}
}
public static boolean getFileOverwritePreference() {
return preferences.getBoolean(FORCE_EXPORT_OVERWRITE, FORCE_EXPORT_OVERWRITE_DEFAULT);
}
public static boolean getAutoExportUsesDifferentPath() {
return preferences.getBoolean(AUTO_EXPORT_USES_DIFFERENT_PATH, AUTO_EXPORT_USES_DIFFERENT_PATH_DEFAULT);
}

View file

@ -85,7 +85,8 @@ public class MusicPathBuilder {
if (!TextUtils.isEmpty(musicTrack.getAlbum()))
value = musicTrack.getAlbum();
break;
case "group":
case "playlist":
case "group": //previous name, for compatability
if (!TextUtils.isEmpty(musicTrack.getContainerName()))
value = musicTrack.getContainerName();
break;

View file

@ -75,7 +75,8 @@
<string name="settings_export_structure_alba">Verzeichnisbaum für Alben</string>
<string name="settings_export_structure_alba_dialog_title">Setze den Verzeichnisbaum</string>
<string name="settings_export_subdirectory_structure_album_example">Beispiel: Beatles/Help!/13. Yesterday.mp3</string>
<string name="settings_export_subdirectory_structure_dialog_message">"Nutze / für einen neuen Order. Available Tags: - {album-artist} - {album} - {artist} - {title} - {disc=CD $} - {no=$$.} - {year} - {genre} "</string>
<string name="settings_export_subdirectory_structure_dialog_message">Nutze / für einen neuen Order \n Available Tags: \n - {album-artist} \n - {album} \n - {artist} \n - {title} \n - {disc=CD $} \n - {no=$$.} \n - {year} \n - {genre} \n</string>
<string name="settings_playlist_export_subdirectory_structure_dialog_message">Nutze / für einen neuen Order \n Available Tags: \n - {playlist} \n - {album-artist} \n - {album} \n - {artist} \n - {title} \n - {disc=CD $} \n - {no=$$.} \n - {year} \n - {genre} \n</string>
<string name="settings_export_structure_groups_dialog_title">Setze den Verzeichnisbaum</string>
<string name="settings_export_subdirectory_structure_group_example">Beispiel: Great Songs/4. Beatles - Yesterday.mp3</string>
<string name="settings_version_number">Versionsnummer</string>
@ -101,4 +102,8 @@
<string name="dialog_superuser_access_denied_title">Administrator-Zugriff verweigert</string>
<string name="dialog_superuser_access_denied">Der Play Music Exporter benötigt Administrator Rechte, ohne diese Rechte kann die App nicht genutzt werden.</string>
<string name="settings_auto_export_different_structure_dialog_title">Verzeichnisbaum</string>
<string name="settings_export_overwrite_existing">Bestehende Dateien überschreiben</string>
<string name="file_handling_category">Dateiverarbeitung</string>
<string name="overwrite_summary">Überschreiben Sie die exportierte Datei immer, auch wenn sie bereits existiert.</string>
<string name="overwrite_title">Bestehende Dateien überschreiben.</string>
</resources>

View file

@ -73,7 +73,7 @@
<string name="settings_category_auto_export_path_subdir">Export path and subdirectory structure</string>
<string name="settings_category_debug">Debug</string>
<string name="settings_category_alba_export">Export location albums</string>
<string name="settings_category_groups_export">Export location groups</string>
<string name="settings_category_groups_export">Export location playlists</string>
<string name="settings_version_number">Version Number</string>
@ -94,14 +94,14 @@
<string name="settings_category_export_location">Export Location</string>
<string name="settings_export_path">Export Base Path</string>
<string name="settings_export_subdirectory_structure_dialog_message">Use / for a new folder \n Available Tags: \n - {album-artist} \n - {album} \n - {artist} \n - {title} \n - {disc=CD $} \n - {no=$$.} \n - {year} \n - {genre} \n</string>
<string name="settings_playlist_export_subdirectory_structure_dialog_message">Use / for a new folder \n Available Tags: \n - {playlist} \n - {album-artist} \n - {album} \n - {artist} \n - {title} \n - {disc=CD $} \n - {no=$$.} \n - {year} \n - {genre} \n</string>
<string name="settings_export_path_alba">Export path for albums</string>
<string name="settings_export_structure_alba">Subdirectory structure for albums</string>
<string name="settings_export_structure_alba_dialog_title">Set your subdirectory structure</string>
<string name="settings_export_subdirectory_structure_album_example">Example: Beatles/Help!/13. Yesterday.mp3</string>
<string name="settings_export_path_groups">Export path for groups</string>
<string name="settings_export_path_groups">Export path for playlists</string>
<string name="settings_export_structure_groups">Subdirectory structure for playlists</string>
<string name="settings_export_structure_groups_dialog_title">Set your subdirectory structure</string>
<string name="settings_export_subdirectory_structure_group_example">Example: Great Songs/4. Beatles - Yesterday.mp3</string>
@ -116,6 +116,7 @@
<string name="settings_export_id3_artwork_size_summary">If the artwork original size is larger than this setting the app will size down the artwork to this size.</string>
<string name="settings_export_path_custom">Custom path</string>
<string name="settings_export_overwrite_existing">Overwrite existing files</string>
<string name="settings_open_old_homepage_title" translatable="false">David-Schulte.de</string>
<string name="settings_open_old_homepage_url" translatable="false"><![CDATA[http://www.david-schulte.de/]]></string>
@ -139,7 +140,10 @@
<string name="pref_header_debug">Debug</string>
<string name="settings_export_structure_alba_default_value" translatable="false">{album-artist}/{album}/{disc=CD $}/{no=$$.} {title}.mp3</string>
<string name="settings_export_structure_groups_default_value" translatable="false">{group}/{group-no=$$.} {artist} - {title}.mp3</string>
<string name="settings_export_structure_groups_default_value" translatable="false">{playlist}/{artist} - {title}.mp3</string>
<string name="debug_trigger_export_all_title">Trigger ExportAllService now</string>
<string name="file_handling_category">File Handling</string>
<string name="overwrite_summary">Always overwrite the exported file, even if it already exists.</string>
<string name="overwrite_title">Overwrite Existing Files</string>
</resources>

View file

@ -24,7 +24,7 @@
<!-- Path structure for groups -->
<EditTextPreference
android:defaultValue="@string/settings_export_structure_groups_default_value"
android:dialogMessage="@string/settings_export_subdirectory_structure_dialog_message"
android:dialogMessage="@string/settings_playlist_export_subdirectory_structure_dialog_message"
android:dialogTitle="@string/settings_export_structure_groups_dialog_title"
android:hint="@string/settings_export_structure_groups_default_value"
android:key="preference_groups_export_structure"
@ -49,4 +49,10 @@
android:summary="@string/settings_export_id3_artwork_size_summary"
android:title="@string/settings_export_id3_artwork_size" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/file_handling_category">
<SwitchPreference
android:key="preference_overwrite_existing_files"
android:summary="@string/overwrite_summary"
android:title="@string/overwrite_title" />
</PreferenceCategory>
</PreferenceScreen>

View file

@ -1,114 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":playmusiclib" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="PlayMusicExporter" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":playmusiclib" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
<option name="PROJECT_TYPE" value="1" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotations" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/typedefs.txt" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="mp3agic-0.8.4" level="project" />
<orderEntry type="module" module-name="framework" exported="" />
<orderEntry type="library" exported="" name="support-compat-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-fragment-25.1.0" level="project" />
<orderEntry type="library" exported="" name="animated-vector-drawable-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-v4-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-core-ui-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-media-compat-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-vector-drawable-25.1.0" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-25.1.0" level="project" />
<orderEntry type="library" exported="" name="support-core-utils-25.1.0" level="project" />
</component>
</module>

View file

@ -69,8 +69,13 @@ public class ArtworkLoader {
if (!TextUtils.isEmpty(artworkUrl)) {
// Tries to load the artwork via internet
try {
URL url = new URL(artworkUrl);
bitmap = BitmapFactory.decodeStream(url.openStream());
if (artworkUrl.contains("mediastore")) {
Logger.getInstance().logError("LoadArtwork", "mediastore artwork");
//TODO handle mediastore album art using ContentResolver
} else {
URL url = new URL(artworkUrl);
bitmap = BitmapFactory.decodeStream(url.openStream());
}
} catch (Exception e) {
// Error
Logger.getInstance().logError("LoadArtwork", e.toString());

View file

@ -25,6 +25,7 @@ package de.arcus.playmusiclib;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
@ -32,8 +33,10 @@ import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.support.v4.content.FileProvider;
import android.support.v4.provider.DocumentFile;
import android.text.TextUtils;
import android.util.Log;
import com.mpatric.mp3agic.ID3v1Genres;
import com.mpatric.mp3agic.ID3v1Tag;
@ -51,6 +54,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import de.arcus.framework.logger.Logger;
import de.arcus.framework.superuser.SuperUser;
@ -137,7 +141,7 @@ public class PlayMusicManager {
* @return Gets the temp path to the database
*/
private String getTempDatabasePath() {
return getTempPath() + "/music.db";
return getTempPath() + "music.db";
}
/**
@ -443,8 +447,8 @@ public class PlayMusicManager {
String path;
// Fix the path for Play Music 5.9.1854
if (!artworkPath.startsWith("artwork2/folder/"))
artworkPath = "artwork2/folder/" + artworkPath;
if (!artworkPath.startsWith("artwork/"))
artworkPath = "artwork/" + artworkPath;
// Search in the public data
for (String publicData : mPathPublicData) {
@ -467,9 +471,10 @@ public class PlayMusicManager {
* Exports a track to the sd card
* @param musicTrack The music track you want to export
* @param dest The destination path
* @param forceOverwrite Forces overwrite of the destination file
* @return Returns whether the export was successful
*/
public boolean exportMusicTrack(MusicTrack musicTrack, String dest) {
public boolean exportMusicTrack(MusicTrack musicTrack, String dest, boolean forceOverwrite ) {
// Creates the destination directory
File directory = new File(dest).getParentFile();
@ -477,16 +482,17 @@ public class PlayMusicManager {
// Filename
String filename = new File(dest).getName();
return exportMusicTrack(musicTrack, Uri.fromFile(directory), filename);
return exportMusicTrack(musicTrack, Uri.fromFile(directory), filename, forceOverwrite);
}
/**
* Exports a track to the sd card
* @param musicTrack The music track you want to export
* @param uri The document tree
* @param forceOverwrite Forces overwrite of the destination file
* @return Returns whether the export was successful
*/
public boolean exportMusicTrack(MusicTrack musicTrack, Uri uri, String path) {
public boolean exportMusicTrack(MusicTrack musicTrack, Uri uri, String path, boolean forceOverwrite) {
// Check for null
if (musicTrack == null) return false;
@ -496,94 +502,113 @@ public class PlayMusicManager {
// Could not find the source file
if (srcFile == null) return false;
String fileTmp = getTempPath() + "/tmp.mp3";
String uniqueID = UUID.randomUUID().toString();
// Copy to temp path failed
if (!SuperUserTools.fileCopy(srcFile, fileTmp))
return false;
if ( forceOverwrite || !isAlreadyThere(uri, path) )
{
// Encrypt the file
if (musicTrack.isEncoded()) {
String fileTmpCrypt = getTempPath() + "/crypt.mp3";
String fileTmp = getTempPath() + uniqueID +"_tmp.mp3";
// Encrypts the file
if (trackEncrypt(musicTrack, fileTmp, fileTmpCrypt)) {
// Remove the old tmp file
FileTools.fileDelete(fileTmp);
// Copy to temp path failed
if (!SuperUserTools.fileCopy(srcFile, fileTmp))
return false;
// New tmp file
fileTmp = fileTmpCrypt;
} else {
Logger.getInstance().logWarning("ExportMusicTrack", "Encrypting failed! Continue with decrypted file.");
// Encrypt the file
if (musicTrack.isEncoded()) {
String fileTmpCrypt = getTempPath() + uniqueID +"_crypt.mp3";
// Encrypts the file
if (trackEncrypt(musicTrack, fileTmp, fileTmpCrypt)) {
// Remove the old tmp file
FileTools.fileDelete(fileTmp);
// New tmp file
fileTmp = fileTmpCrypt;
} else {
Logger.getInstance().logWarning("ExportMusicTrack", "Encrypting failed! Continue with decrypted file.");
}
}
}
String dest;
Uri copyUri = null;
if (uri.toString().startsWith("file://")) {
// Build the full path
dest = uri.buildUpon().appendPath(path).build().getPath();
String dest;
Uri copyUri = null;
if (uri.toString().startsWith("file://")) {
// Build the full path
dest = uri.buildUpon().appendPath(path).build().getPath();
String parentDirectory = new File(dest).getParent();
FileTools.directoryCreate(parentDirectory);
} else {
// Complex uri (Lollipop)
dest = getTempPath() + "/final.mp3";
String parentDirectory = new File(dest).getParent();
FileTools.directoryCreate(parentDirectory);
} else {
// Complex uri (Lollipop)
dest = getTempPath() + uniqueID +"_final.mp3";
// The root
DocumentFile document = DocumentFile.fromTreeUri(mContext, uri);
// The root
DocumentFile document = DocumentFile.fromTreeUri(mContext, uri);
// Creates the subdirectories
String[] directories = path.split("\\/");
for(int i=0; i<directories.length - 1; i++) {
String directoryName = directories[i];
boolean found = false;
// Creates the subdirectories
String[] directories = path.split("\\/");
for(int i=0; i<directories.length - 1; i++) {
String directoryName = directories[i];
boolean found = false;
// Search all sub elements
for (DocumentFile subDocument: document.listFiles()) {
// Directory exists
if (subDocument.isDirectory() && subDocument.getName().equals(directoryName)) {
document = subDocument;
found = true;
break;
// Search all sub elements
for (DocumentFile subDocument: document.listFiles()) {
// Directory exists
if (subDocument.isDirectory() && subDocument.getName().equalsIgnoreCase(directoryName)) {
document = subDocument;
found = true;
break;
}
}
if (!found) {
// Create the directory
document = document.createDirectory(directoryName);
}
}
if (!found) {
// Create the directory
document = document.createDirectory(directoryName);
// Gets the filename
String filename = directories[directories.length - 1];
for (DocumentFile subDocument: document.listFiles()) {
// Directory exists
if (subDocument.isFile() ){
if ( filename != null && subDocument.getName().equalsIgnoreCase(filename)) {
// Delete the file
if ( forceOverwrite ) {
Logger.getInstance().logWarning("ExportMusicTrack", "(forceOverwrite) Deleting original file: " + filename);
}
subDocument.delete();
break;
}
}
}
// Create the mp3 file
document = document.createFile("music/mp3", filename);
// Create the directories
copyUri = document.getUri();
}
// Gets the filename
String filename = directories[directories.length - 1];
for (DocumentFile subDocument: document.listFiles()) {
// Directory exists
if (subDocument.isFile() && subDocument.getName().equals(filename)) {
// Delete the file
subDocument.delete();
break;
// We want to export the ID3 tags
if (mID3Enable) {
// Adds the meta data
if (!trackWriteID3(musicTrack, fileTmp, dest)) {
Logger.getInstance().logWarning("ExportMusicTrack", "ID3 writer failed! Continue without ID3 tags.");
// Failed, moving without meta data
if (!FileTools.fileMove(fileTmp, dest)) {
Logger.getInstance().logError("ExportMusicTrack", "Moving the raw file failed!");
// Could not copy the file
return false;
}
}
}
// Create the mp3 file
document = document.createFile("music/mp3", filename);
// Create the directories
copyUri = document.getUri();
}
// We want to export the ID3 tags
if (mID3Enable) {
// Adds the meta data
if (!trackWriteID3(musicTrack, fileTmp, dest)) {
Logger.getInstance().logWarning("ExportMusicTrack", "ID3 writer failed! Continue without ID3 tags.");
// Failed, moving without meta data
} else {
// Moving the file
if (!FileTools.fileMove(fileTmp, dest)) {
Logger.getInstance().logError("ExportMusicTrack", "Moving the raw file failed!");
@ -591,62 +616,87 @@ public class PlayMusicManager {
return false;
}
}
} else {
// Moving the file
if (!FileTools.fileMove(fileTmp, dest)) {
Logger.getInstance().logError("ExportMusicTrack", "Moving the raw file failed!");
// Could not copy the file
return false;
}
}
// We need to copy the file to a uri
if (copyUri != null) {
// Lollipop only
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
// Gets the file descriptor
ParcelFileDescriptor parcelFileDescriptor = mContext.getContentResolver().openFileDescriptor(copyUri, "w");
// We need to copy the file to a uri
if (copyUri != null) {
// Lollipop only
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
// Gets the file descriptor
ParcelFileDescriptor parcelFileDescriptor = mContext.getContentResolver().openFileDescriptor(copyUri, "w");
// Gets the output stream
FileOutputStream fileOutputStream = new FileOutputStream(parcelFileDescriptor.getFileDescriptor());
// Gets the output stream
FileOutputStream fileOutputStream = new FileOutputStream(parcelFileDescriptor.getFileDescriptor());
// Gets the input stream
FileInputStream fileInputStream = new FileInputStream(dest);
// Gets the input stream
FileInputStream fileInputStream = new FileInputStream(dest);
// Copy the stream
FileTools.fileCopy(fileInputStream, fileOutputStream);
// Copy the stream
FileTools.fileCopy(fileInputStream, fileOutputStream);
// Close all streams
fileOutputStream.close();
fileInputStream.close();
parcelFileDescriptor.close();
// Close all streams
fileOutputStream.close();
fileInputStream.close();
parcelFileDescriptor.close();
} catch (FileNotFoundException e) {
Logger.getInstance().logError("ExportMusicTrack", "File not found!");
} catch (FileNotFoundException e) {
Logger.getInstance().logError("ExportMusicTrack", "File not found!");
// Could not copy the file
return false;
} catch (IOException e) {
Logger.getInstance().logError("ExportMusicTrack", "Failed to write the document: " + e.toString());
// Could not copy the file
return false;
} catch (IOException e) {
Logger.getInstance().logError("ExportMusicTrack", "Failed to write the document: " + e.toString());
// Could not copy the file
return false;
// Could not copy the file
return false;
}
}
}
// Delete temp files
cleanUp(uniqueID);
// Adds the file to the media system
//new MediaScanner(mContext, dest);
} else {
Logger.getInstance().logInfo("exportMusicTrack", path + " already exists, skipping." );
}
// Delete temp files
cleanUp();
// Adds the file to the media system
//new MediaScanner(mContext, dest);
// Done
return true;
}
/**
* Checks if the destination file already exists
* @param pUri the source file
* @param pPath The destination
* return true if the file already exists
*/
private boolean isAlreadyThere(Uri pUri, String pPath) {
if (pUri.toString().startsWith("file://")) {
//Old sdcard URI
return FileTools.fileExists(pUri.buildUpon().appendPath(pPath).build().toString());
} else {
//Documents Provider URI
DocumentFile lDocumentFile = DocumentFile.fromTreeUri(mContext, pUri);
for (String lDisplayName : pPath.split("/")) {
if (lDocumentFile.findFile(lDisplayName) != null) {
lDocumentFile = lDocumentFile.findFile(lDisplayName);
if ( lDocumentFile.length() == 0 ) {
if ( !lDocumentFile.isDirectory() ) {
Logger.getInstance().logInfo("isAlreadyThere", pPath + " File exists, but is 0 bytes in size.");
}
}
} else {
Logger.getInstance().logInfo("isAlreadyThere", pPath + " does not exist yet.");
return false;
}
}
return true;
}
}
/**
* Copies the music file to a new path and adds the mp3 meta data
* @param musicTrack Track information
@ -792,9 +842,9 @@ public class PlayMusicManager {
/**
* Deletes all cache files
*/
private void cleanUp() {
FileTools.fileDelete(getTempPath() + "/final.mp3");
FileTools.fileDelete(getTempPath() + "/tmp.mp3");
FileTools.fileDelete(getTempPath() + "/crypt.mp3");
private void cleanUp(String theUniqueID) {
FileTools.fileDelete( getTempPath() + theUniqueID +"_final.mp3");
FileTools.fileDelete( getTempPath() + theUniqueID +"_tmp.mp3");
FileTools.fileDelete( getTempPath() + theUniqueID +"_crypt.mp3");
}
}