mirror of
https://github.com/playmusicexporter/playmusicexporter
synced 2024-05-02 07:06:44 +00:00
Merge branch 'release/v0.9.6.0'
This commit is contained in:
commit
f28e4cbd48
18
README.md
18
README.md
|
@ -34,15 +34,31 @@ by [Michael Patricios (mpatric)](https://github.com/mpatric).
|
|||
|
||||
### Contributing
|
||||
|
||||
#### What can you contribute?
|
||||
|
||||
Implement features you want to see, or take a look at the issue tracker and fix broken things. Before making bigger changes, see that a contributor is supporting the inclusion, so that you can be sure it will be merged. (See Discuss Ideas below)
|
||||
|
||||
#### How to contribute:
|
||||
|
||||
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.
|
||||
You might want to discuss your ideas with us first though:
|
||||
|
||||
### Discuss Ideas
|
||||
#### Discuss Ideas
|
||||
|
||||
If you have any questions, the easiest way to get help is asking in the #playmusicexporter IRC channel on freenode. You can join that on webchat.freenode.net, or preferably, if you are not really an IRC guy anyway, try the corresponding matrix room [#playmusicexporter:jcg.re](https://matrix.to/#/#playmusicexporter:jcg.re). They are bridged together, so everything that happens in one of the rooms gets automatically transfered to the other one too.
|
||||
|
||||
### Supporting this project
|
||||
|
||||
If you want to support this project, the best way to do so is contributing source code to the project (see above), or help with illustrations, if that is something you're good at! (I am most certainly not good at creating icons and such things)
|
||||
|
||||
If you are unable to do that, but you still want to support this project, you could send me some bitcoins instead: 1NdzpDWPQ53xWT5fraGPZX5F9XrKiPBXjp
|
||||
|
||||
I will distribute bitcoins send to me to others helping on the project too, so that other people contributing also have a piece of the cake.
|
||||
|
||||
I might later set up [BitHub](https://github.com/WhisperSystems/BitHub) for this purpose later (if there are a lot of donations to distribute), but this project is a little small for that, and BitHub works based on the commit count only, which I would like to modify before setting that up.
|
||||
|
||||
### Copyright
|
||||
|
||||
Copyright (c) 2016 Jan Christian Grünhage. See LICENSE.txt for details.
|
||||
|
|
|
@ -42,5 +42,5 @@ android {
|
|||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile 'com.android.support:appcompat-v7:25.2.0'
|
||||
compile 'com.android.support:appcompat-v7:25.3.1'
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -309,9 +310,7 @@ public class FileTools {
|
|||
}
|
||||
|
||||
// Remove all blacklisted paths
|
||||
for (String blacklistPath : mountPointBlacklist) {
|
||||
storages.remove(blacklistPath);
|
||||
}
|
||||
storages.removeAll(Arrays.asList(mountPointBlacklist));
|
||||
|
||||
// Sort the list
|
||||
Collections.sort(storages);
|
||||
|
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
#Sun Jan 22 21:19:51 CET 2017
|
||||
#Tue Mar 28 12:22:37 CEST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
|
@ -33,8 +31,8 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
// TODO Change Version with releases
|
||||
versionCode 109
|
||||
versionName '0.9.5.2'
|
||||
versionCode 110
|
||||
versionName '0.9.6.0'
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
||||
jackOptions {
|
||||
|
@ -58,9 +56,10 @@ dependencies {
|
|||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile project(':framework')
|
||||
compile project(':playmusiclib')
|
||||
compile 'com.android.support:appcompat-v7:25.2.0'
|
||||
compile 'com.android.support:support-v4:25.2.0'
|
||||
compile 'com.android.support:design:25.2.0'
|
||||
compile 'com.android.support:support-vector-drawable:25.2.0'
|
||||
compile 'com.android.support:appcompat-v7:25.3.1'
|
||||
compile 'com.android.support:support-v4:25.3.1'
|
||||
compile 'com.android.support:design:25.3.1'
|
||||
compile 'com.android.support:support-vector-drawable:25.3.1'
|
||||
compile 'com.github.paolorotolo:appintro:4.1.0'
|
||||
compile 'ly.count.android:sdk:16.12.2'
|
||||
}
|
||||
|
|
|
@ -24,8 +24,9 @@
|
|||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
@ -51,7 +52,7 @@
|
|||
</activity>
|
||||
<activity
|
||||
android:name=".activities.Intro"
|
||||
android:label="Play Music Exporter Intro"/>
|
||||
android:label="Play Music Exporter Intro" />
|
||||
|
||||
<service android:name=".services.ExportService" />
|
||||
<service android:name=".services.ExportAllService" />
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.Manifest;
|
|||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
|
|
|
@ -43,9 +43,10 @@ import android.widget.EditText;
|
|||
import android.widget.Toast;
|
||||
|
||||
import de.arcus.framework.logger.Logger;
|
||||
import de.arcus.framework.crashhandler.CrashHandler;
|
||||
import de.arcus.playmusiclib.exceptions.CouldNotOpenDatabaseException;
|
||||
import de.arcus.playmusiclib.exceptions.NoSuperUserException;
|
||||
import ly.count.android.sdk.Countly;
|
||||
import ly.count.android.sdk.DeviceId;
|
||||
import re.jcg.playmusicexporter.R;
|
||||
import re.jcg.playmusicexporter.fragments.MusicTrackListFragment;
|
||||
import re.jcg.playmusicexporter.fragments.MusicContainerListFragment;
|
||||
|
@ -108,8 +109,9 @@ public class MusicContainerListActivity extends AppCompatActivity
|
|||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
//Adds the crash handler to this class
|
||||
CrashHandler.addCrashHandler(this);
|
||||
Countly.sharedInstance().init(this, getString(R.string.countly_url), getString(R.string.countly_token), null, DeviceId.Type.OPEN_UDID);
|
||||
Countly.sharedInstance().enableCrashReporting();
|
||||
|
||||
|
||||
PlayMusicExporterPreferences.init(this);
|
||||
if (!PlayMusicExporterPreferences.getSetupDone()) {
|
||||
|
@ -195,11 +197,11 @@ public class MusicContainerListActivity extends AppCompatActivity
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the PlayMusicExporter lib and shows the list
|
||||
*/
|
||||
private void loadPlayMusicExporter()
|
||||
{
|
||||
private void loadPlayMusicExporter() {
|
||||
// Gets the running instance
|
||||
mPlayMusicManager = PlayMusicManager.getInstance();
|
||||
|
||||
|
@ -261,7 +263,7 @@ public class MusicContainerListActivity extends AppCompatActivity
|
|||
MusicContainerListFragment musicTrackListFragment = (MusicContainerListFragment) getSupportFragmentManager()
|
||||
.findFragmentById(R.id.fragment_main);
|
||||
|
||||
switch(mViewType) {
|
||||
switch (mViewType) {
|
||||
case Album:
|
||||
// Load all albums to the list
|
||||
AlbumDataSource dataSourceAlbum = new AlbumDataSource(mPlayMusicManager);
|
||||
|
@ -331,24 +333,21 @@ public class MusicContainerListActivity extends AppCompatActivity
|
|||
MenuItem itemRefreshLibrary = menu.findItem(R.id.action_refresh);
|
||||
itemRefreshLibrary.setOnMenuItemClickListener(item ->
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
mPlayMusicManager.reloadDatabase();
|
||||
mPlayMusicManager = null;
|
||||
loadPlayMusicExporter();
|
||||
Toast.makeText( this, R.string.database_reloaded, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
catch (NoSuperUserException | CouldNotOpenDatabaseException e)
|
||||
{
|
||||
Toast.makeText( this, R.string.dialog_superuser_access_denied_title, Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, R.string.database_reloaded, Toast.LENGTH_SHORT).show();
|
||||
} catch (NoSuperUserException | CouldNotOpenDatabaseException e) {
|
||||
Toast.makeText(this, R.string.dialog_superuser_access_denied_title, Toast.LENGTH_SHORT).show();
|
||||
e.printStackTrace();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// Finds the search item and create the search view
|
||||
MenuItem itemSearch = menu. findItem(R.id.action_search);
|
||||
mSearchView = (SearchView)MenuItemCompat.getActionView(itemSearch);
|
||||
MenuItem itemSearch = menu.findItem(R.id.action_search);
|
||||
mSearchView = (SearchView) MenuItemCompat.getActionView(itemSearch);
|
||||
|
||||
if (mSearchView != null) {
|
||||
// Sets the search listener
|
||||
|
@ -376,4 +375,16 @@ public class MusicContainerListActivity extends AppCompatActivity
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
Countly.sharedInstance().onStart(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
Countly.sharedInstance().onStop();
|
||||
super.onStop();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,31 +46,28 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
|||
* A preference value change listener that updates the preference's summary
|
||||
* to reflect its new value.
|
||||
*/
|
||||
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object value) {
|
||||
String stringValue = value.toString();
|
||||
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = (preference, value) -> {
|
||||
String stringValue = value.toString();
|
||||
|
||||
if (preference instanceof ListPreference) {
|
||||
// For list preferences, look up the correct display value in
|
||||
// the preference's 'entries' list.
|
||||
ListPreference listPreference = (ListPreference) preference;
|
||||
int index = listPreference.findIndexOfValue(stringValue);
|
||||
if (preference instanceof ListPreference) {
|
||||
// For list preferences, look up the correct display value in
|
||||
// the preference's 'entries' list.
|
||||
ListPreference listPreference = (ListPreference) preference;
|
||||
int index = listPreference.findIndexOfValue(stringValue);
|
||||
|
||||
// Set the summary to reflect the new value.
|
||||
preference.setSummary(
|
||||
index >= 0
|
||||
? listPreference.getEntries()[index]
|
||||
: null);
|
||||
// Set the summary to reflect the new value.
|
||||
preference.setSummary(
|
||||
index >= 0
|
||||
? listPreference.getEntries()[index]
|
||||
: null);
|
||||
|
||||
} else {
|
||||
// For all other preferences, set the summary to the value's
|
||||
// simple string representation.
|
||||
preference.setSummary(stringValue);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
// For all other preferences, set the summary to the value's
|
||||
// simple string representation.
|
||||
preference.setSummary(stringValue);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -127,15 +124,8 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
|||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public void onBuildHeaders(List<Header> target) {
|
||||
loadHeadersFromResource(R.xml.pref_headers, target);
|
||||
|
||||
// Remove the Debug Fragment
|
||||
if (!BuildConfig.DEBUG) {
|
||||
for (int i = 0; i < target.size(); i++) {
|
||||
if ("Debug".equals(target.get(i).title)) {
|
||||
target.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
loadHeadersFromResource(R.xml.pref_debug_header, target);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,19 +150,13 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
|||
setHasOptionsMenu(true);
|
||||
|
||||
|
||||
findPreference("preference_alba_export_path").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
startActivityForResult(new Intent("android.intent.action.OPEN_DOCUMENT_TREE"), REQUEST_CODE_OPEN_DOCUMENT_TREE_ALBA_PATH);
|
||||
return true;
|
||||
}
|
||||
findPreference("preference_alba_export_path").setOnPreferenceClickListener(preference -> {
|
||||
startActivityForResult(new Intent("android.intent.action.OPEN_DOCUMENT_TREE"), REQUEST_CODE_OPEN_DOCUMENT_TREE_ALBA_PATH);
|
||||
return true;
|
||||
});
|
||||
findPreference("preference_groups_export_path").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
startActivityForResult(new Intent("android.intent.action.OPEN_DOCUMENT_TREE"), REQUEST_CODE_OPEN_DOCUMENT_TREE_GROUPS_PATH);
|
||||
return true;
|
||||
}
|
||||
findPreference("preference_groups_export_path").setOnPreferenceClickListener(preference -> {
|
||||
startActivityForResult(new Intent("android.intent.action.OPEN_DOCUMENT_TREE"), REQUEST_CODE_OPEN_DOCUMENT_TREE_GROUPS_PATH);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -246,12 +230,9 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
|||
}
|
||||
|
||||
private void setupOnClickListeners() {
|
||||
findPreference(PlayMusicExporterPreferences.AUTO_EXPORT_PATH).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
startActivityForResult(new Intent("android.intent.action.OPEN_DOCUMENT_TREE"), REQUEST_CODE_OPEN_DOCUMENT_TREE_AUTO_PATH);
|
||||
return true;
|
||||
}
|
||||
findPreference(PlayMusicExporterPreferences.AUTO_EXPORT_PATH).setOnPreferenceClickListener(preference -> {
|
||||
startActivityForResult(new Intent("android.intent.action.OPEN_DOCUMENT_TREE"), REQUEST_CODE_OPEN_DOCUMENT_TREE_AUTO_PATH);
|
||||
return true;
|
||||
});
|
||||
|
||||
//For every setting that is used to define the export job, setup a listener that
|
||||
|
@ -262,12 +243,9 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
|||
}
|
||||
|
||||
private void setupRescheduler(String preference) {
|
||||
findPreference(preference).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
ExportAllJob.scheduleExport(getContext());
|
||||
return false;
|
||||
}
|
||||
findPreference(preference).setOnPreferenceClickListener(preference1 -> {
|
||||
ExportAllJob.scheduleExport(getContext());
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -79,10 +79,7 @@ public class MusicContainerListFragment extends ListFragment {
|
|||
* A dummy implementation of the {@link Callbacks} interface that does
|
||||
* nothing. Used only when this fragment is not attached to an activity.
|
||||
*/
|
||||
private static Callbacks sDummyCallbacks = new Callbacks() {
|
||||
@Override
|
||||
public void onItemSelected(MusicTrackList musicTrackList) {
|
||||
}
|
||||
private static Callbacks sDummyCallbacks = musicTrackList -> {
|
||||
};
|
||||
|
||||
private MusicContainerListAdapter mMusicTrackListAdapter;
|
||||
|
@ -112,9 +109,7 @@ public class MusicContainerListFragment extends ListFragment {
|
|||
// Null check
|
||||
if (list != null) {
|
||||
// Copy the list
|
||||
for (MusicTrackList musicTrackList : list) {
|
||||
newList.add(musicTrackList);
|
||||
}
|
||||
newList.addAll(list);
|
||||
}
|
||||
|
||||
// Set the list in the adapter
|
||||
|
@ -145,7 +140,8 @@ public class MusicContainerListFragment extends ListFragment {
|
|||
setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
|
||||
}
|
||||
}
|
||||
// DEPRECATED
|
||||
|
||||
// DEPRECATED
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
|
|
|
@ -32,7 +32,6 @@ import android.text.TextUtils;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
@ -197,43 +196,36 @@ public class MusicTrackListFragment extends Fragment {
|
|||
mListView.setAdapter(mMusicTrackAdapter);
|
||||
|
||||
// Click on one list item
|
||||
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
// The header is not clicked
|
||||
if (position > 0) {
|
||||
// We need to subtract the header view
|
||||
position -= 1;
|
||||
mListView.setOnItemClickListener((parent, view, position, id) -> {
|
||||
// The header is not clicked
|
||||
if (position > 0) {
|
||||
// We need to subtract the header view
|
||||
position -= 1;
|
||||
|
||||
// Gets the selected track
|
||||
MusicTrack musicTrack = mMusicTrackAdapter.getItem(position);
|
||||
// Gets the selected track
|
||||
MusicTrack musicTrack = mMusicTrackAdapter.getItem(position);
|
||||
|
||||
// Toggle the track
|
||||
selectTrack(musicTrack, view, TrackSelectionState.Toggle);
|
||||
}
|
||||
// Toggle the track
|
||||
selectTrack(musicTrack, view, TrackSelectionState.Toggle);
|
||||
}
|
||||
});
|
||||
|
||||
// The floating action button
|
||||
mFloatingButtonExport = (FloatingActionButton) rootView.findViewById(R.id.floating_button_export);
|
||||
mFloatingButtonExport.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
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);
|
||||
mFloatingButtonExport.setOnClickListener(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);
|
||||
});
|
||||
updateFloatingButton();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
package re.jcg.playmusicexporter.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
|
@ -160,47 +159,24 @@ public class NavigationDrawerFragment extends Fragment {
|
|||
setViewType(mViewType);
|
||||
|
||||
// Click on album
|
||||
mButtonTypeAlbum.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setViewType(ViewType.Album);
|
||||
}
|
||||
});
|
||||
mButtonTypeAlbum.setOnClickListener(v -> setViewType(ViewType.Album));
|
||||
|
||||
// Click on artist
|
||||
mButtonTypeArtist.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setViewType(ViewType.Artist);
|
||||
}
|
||||
});
|
||||
mButtonTypeArtist.setOnClickListener(v -> setViewType(ViewType.Artist));
|
||||
|
||||
// Click on playlist
|
||||
mButtonTypePlaylist.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setViewType(ViewType.Playlist);
|
||||
}
|
||||
});
|
||||
mButtonTypePlaylist.setOnClickListener(v -> setViewType(ViewType.Playlist));
|
||||
|
||||
// Click on rated
|
||||
mButtonTypeRated.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setViewType(ViewType.Rated);
|
||||
}
|
||||
});
|
||||
mButtonTypeRated.setOnClickListener(v -> setViewType(ViewType.Rated));
|
||||
|
||||
// Click on settings
|
||||
mButtonSettings.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intentSettings = new Intent(getActivity(), SettingsActivity.class);
|
||||
startActivity(intentSettings);
|
||||
mButtonSettings.setOnClickListener(v -> {
|
||||
Intent intentSettings = new Intent(getActivity(), SettingsActivity.class);
|
||||
startActivity(intentSettings);
|
||||
|
||||
// Close the drawer
|
||||
mDrawerLayout.closeDrawers();
|
||||
}
|
||||
// Close the drawer
|
||||
mDrawerLayout.closeDrawers();
|
||||
});
|
||||
|
||||
// Color the settings button
|
||||
|
@ -307,12 +283,7 @@ public class NavigationDrawerFragment extends Fragment {
|
|||
}
|
||||
|
||||
// Defer code dependent on restoration of previous instance state.
|
||||
mDrawerLayout.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mDrawerToggle.syncState();
|
||||
}
|
||||
});
|
||||
mDrawerLayout.post(mDrawerToggle::syncState);
|
||||
|
||||
mDrawerLayout.setDrawerListener(mDrawerToggle);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.util.Log;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import ly.count.android.sdk.Countly;
|
||||
import re.jcg.playmusicexporter.settings.PlayMusicExporterPreferences;
|
||||
import re.jcg.playmusicexporter.utils.MusicPathBuilder;
|
||||
import de.arcus.playmusiclib.PlayMusicManager;
|
||||
|
@ -34,8 +35,7 @@ public class ExportAllService extends IntentService {
|
|||
Log.i(TAG, "Intent sent!");
|
||||
}
|
||||
|
||||
public ExportAllService()
|
||||
{
|
||||
public ExportAllService() {
|
||||
super("AutoGPME-ExportService");
|
||||
}
|
||||
|
||||
|
@ -75,10 +75,11 @@ public class ExportAllService extends IntentService {
|
|||
try {
|
||||
if (lPlayMusicManager.exportMusicTrack(lTrack, lUri, lPath, PlayMusicExporterPreferences.getFileOverwritePreference())) {
|
||||
Log.i(TAG, "Exported Music Track: " + getStringForTrack(lTrack));
|
||||
Countly.sharedInstance().recordEvent("Exported Song", 1);
|
||||
} else {
|
||||
Log.i(TAG, "Failed to export Music Track: " + getStringForTrack(lTrack));
|
||||
}
|
||||
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (e.getMessage().contains("Invalid URI:")) {
|
||||
/*
|
||||
|
@ -88,19 +89,14 @@ 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();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Countly.sharedInstance().logException(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( CPULock.isHeld())
|
||||
{
|
||||
if (CPULock.isHeld()) {
|
||||
CPULock.release();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import android.os.Bundle;
|
|||
import android.support.v4.app.NotificationCompat;
|
||||
|
||||
import de.arcus.framework.logger.Logger;
|
||||
import ly.count.android.sdk.Countly;
|
||||
import re.jcg.playmusicexporter.R;
|
||||
import de.arcus.playmusiclib.PlayMusicManager;
|
||||
import de.arcus.playmusiclib.datasources.MusicTrackDataSource;
|
||||
|
@ -200,9 +201,16 @@ public class ExportService extends IntentService {
|
|||
updateNotification();
|
||||
|
||||
// Exports the song
|
||||
if(!playMusicManager.exportMusicTrack(mTrackCurrent, uri, path, PlayMusicExporterPreferences.getFileOverwritePreference())) {
|
||||
// Export failed
|
||||
mTracksFailed ++;
|
||||
try {
|
||||
if (playMusicManager.exportMusicTrack(mTrackCurrent, uri, path, PlayMusicExporterPreferences.getFileOverwritePreference())) {
|
||||
Countly.sharedInstance().recordEvent("Exported Song", 1);
|
||||
} else {
|
||||
// Export failed
|
||||
mTracksFailed ++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Countly.sharedInstance().logException(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
// Export failed
|
||||
|
|
|
@ -22,14 +22,12 @@
|
|||
|
||||
package re.jcg.playmusicexporter.utils;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import re.jcg.playmusicexporter.R;
|
||||
import de.arcus.playmusiclib.ArtworkLoader;
|
||||
import de.arcus.playmusiclib.ArtworkLoaderCallback;
|
||||
import de.arcus.playmusiclib.items.ArtworkEntry;
|
||||
|
||||
/**
|
||||
|
@ -121,13 +119,10 @@ public class ArtworkViewLoader {
|
|||
maximalArtworkSize = imageViewDefault.getContext().getResources().getDimensionPixelSize(R.dimen.music_track_artwork_loading_size);
|
||||
|
||||
// Sets the bitmap in the UI thread
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Default icon
|
||||
imageViewDefault.setImageResource(mDefaultImage);
|
||||
Runnable runnable = () -> {
|
||||
// Default icon
|
||||
imageViewDefault.setImageResource(mDefaultImage);
|
||||
|
||||
}
|
||||
};
|
||||
imageViewDefault.post(runnable);
|
||||
}
|
||||
|
@ -138,36 +133,30 @@ public class ArtworkViewLoader {
|
|||
mIsLoading = true;
|
||||
|
||||
// Load the artwork
|
||||
ArtworkLoader.loadArtworkAsync(mArtworkEntry, maximalArtworkSize, new ArtworkLoaderCallback() {
|
||||
@Override
|
||||
public void onFinished(final Bitmap bitmap) {
|
||||
final ImageView imageView = mImageView.get();
|
||||
ArtworkLoader.loadArtworkAsync(mArtworkEntry, maximalArtworkSize, bitmap -> {
|
||||
final ImageView imageView = mImageView.get();
|
||||
|
||||
if (imageViewDefault != null) {
|
||||
// Sets the bitmap in the UI thread
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Bitmap is valid
|
||||
if (bitmap != null)
|
||||
imageView.setImageBitmap(bitmap);
|
||||
else
|
||||
imageView.setImageResource(mDefaultImage);
|
||||
}
|
||||
};
|
||||
imageView.post(runnable);
|
||||
}
|
||||
if (imageViewDefault != null) {
|
||||
// Sets the bitmap in the UI thread
|
||||
Runnable runnable = () -> {
|
||||
// Bitmap is valid
|
||||
if (bitmap != null)
|
||||
imageView.setImageBitmap(bitmap);
|
||||
else
|
||||
imageView.setImageResource(mDefaultImage);
|
||||
};
|
||||
imageView.post(runnable);
|
||||
}
|
||||
|
||||
// Loading is done
|
||||
mIsLoading = false;
|
||||
// Loading is done
|
||||
mIsLoading = false;
|
||||
|
||||
// Loads the next image
|
||||
if (mNewArtworkEntry != null) {
|
||||
mArtworkEntry = mNewArtworkEntry;
|
||||
mNewArtworkEntry = null;
|
||||
// Loads the next image
|
||||
if (mNewArtworkEntry != null) {
|
||||
mArtworkEntry = mNewArtworkEntry;
|
||||
mNewArtworkEntry = null;
|
||||
|
||||
loadImage();
|
||||
}
|
||||
loadImage();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2015 David Schulte
|
||||
~
|
||||
~ Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
~ of this software and associated documentation files (the "Software"), to deal
|
||||
~ in the Software without restriction, including without limitation the rights
|
||||
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
~ copies of the Software, and to permit persons to whom the Software is
|
||||
~ furnished to do so, subject to the following conditions:
|
||||
~
|
||||
~ The above copyright notice and this permission notice shall be included in
|
||||
~ all copies or substantial portions of the Software.
|
||||
~
|
||||
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
~ THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/button_navigation_drawer_hover">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/button_navigation_drawer_normal"/>
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
|
@ -1,31 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2015 David Schulte
|
||||
~
|
||||
~ Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
~ of this software and associated documentation files (the "Software"), to deal
|
||||
~ in the Software without restriction, including without limitation the rights
|
||||
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
~ copies of the Software, and to permit persons to whom the Software is
|
||||
~ furnished to do so, subject to the following conditions:
|
||||
~
|
||||
~ The above copyright notice and this permission notice shall be included in
|
||||
~ all copies or substantial portions of the Software.
|
||||
~
|
||||
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
~ THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/button_navigation_drawer_hover">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/button_navigation_drawer_selected"/>
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
|
@ -21,7 +21,11 @@
|
|||
~ THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/button_navigation_drawer_normal"/>
|
||||
</shape>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/button_navigation_drawer_hover">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/button_navigation_drawer_normal"/>
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
|
@ -21,7 +21,11 @@
|
|||
~ THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/button_navigation_drawer_selected"/>
|
||||
</shape>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/button_navigation_drawer_hover">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/button_navigation_drawer_selected"/>
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
5
playmusicexporter/src/main/res/values/constants.xml
Normal file
5
playmusicexporter/src/main/res/values/constants.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="countly_url">https://countly.jcg.re/</string>
|
||||
<string name="countly_token">82a1d9405388c4dd73dc9835f84c59cf4274086d</string>
|
||||
</resources>
|
7
playmusicexporter/src/main/res/xml/pref_debug_header.xml
Normal file
7
playmusicexporter/src/main/res/xml/pref_debug_header.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<header
|
||||
android:fragment="re.jcg.playmusicexporter.activities.SettingsActivity$DebugPreferenceFragment"
|
||||
android:icon="@drawable/ic_action_settings"
|
||||
android:title="@string/pref_header_debug" />
|
||||
|
||||
</preference-headers>
|
|
@ -16,9 +16,5 @@
|
|||
android:fragment="re.jcg.playmusicexporter.activities.SettingsActivity$AboutPreferenceFragment"
|
||||
android:icon="@drawable/ic_info_black_24dp"
|
||||
android:title="@string/pref_header_about" />
|
||||
<header
|
||||
android:fragment="re.jcg.playmusicexporter.activities.SettingsActivity$DebugPreferenceFragment"
|
||||
android:icon="@drawable/ic_action_settings"
|
||||
android:title="@string/pref_header_debug" />
|
||||
|
||||
</preference-headers>
|
||||
|
|
|
@ -25,7 +25,6 @@ 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;
|
||||
|
@ -33,10 +32,8 @@ 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;
|
||||
|
@ -44,7 +41,10 @@ import com.mpatric.mp3agic.ID3v2;
|
|||
import com.mpatric.mp3agic.ID3v22Tag;
|
||||
import com.mpatric.mp3agic.ID3v23Tag;
|
||||
import com.mpatric.mp3agic.ID3v24Tag;
|
||||
import com.mpatric.mp3agic.InvalidDataException;
|
||||
import com.mpatric.mp3agic.Mp3File;
|
||||
import com.mpatric.mp3agic.NotSupportedException;
|
||||
import com.mpatric.mp3agic.UnsupportedTagException;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
|
@ -138,6 +138,7 @@ public class PlayMusicManager {
|
|||
|
||||
/**
|
||||
* The database will be copied to a temp folder to access from the app
|
||||
*
|
||||
* @return Gets the temp path to the database
|
||||
*/
|
||||
private String getTempDatabasePath() {
|
||||
|
@ -297,6 +298,7 @@ public class PlayMusicManager {
|
|||
|
||||
/**
|
||||
* Creates a new PlayMusic manager
|
||||
*
|
||||
* @param context App context
|
||||
*/
|
||||
public PlayMusicManager(Context context) {
|
||||
|
@ -307,8 +309,9 @@ public class PlayMusicManager {
|
|||
|
||||
/**
|
||||
* Loads all needed information and opens the database
|
||||
* @throws PlayMusicNotFoundException PlayMusic is not installed
|
||||
* @throws NoSuperUserException No super user permissions
|
||||
*
|
||||
* @throws PlayMusicNotFoundException PlayMusic is not installed
|
||||
* @throws NoSuperUserException No super user permissions
|
||||
* @throws CouldNotOpenDatabaseException Could not open the database
|
||||
*/
|
||||
public void startUp() throws PlayMusicNotFoundException, NoSuperUserException, CouldNotOpenDatabaseException {
|
||||
|
@ -345,7 +348,8 @@ public class PlayMusicManager {
|
|||
|
||||
/**
|
||||
* Copies the database to a temp directory and opens it
|
||||
* @throws NoSuperUserException No super user permissions
|
||||
*
|
||||
* @throws NoSuperUserException No super user permissions
|
||||
* @throws de.arcus.playmusiclib.exceptions.CouldNotOpenDatabaseException Could not open the database
|
||||
*/
|
||||
private void loadDatabase() throws NoSuperUserException, CouldNotOpenDatabaseException {
|
||||
|
@ -370,7 +374,8 @@ public class PlayMusicManager {
|
|||
|
||||
/**
|
||||
* Reloads the database from PlayMusic
|
||||
* @throws NoSuperUserException No super user permissions
|
||||
*
|
||||
* @throws NoSuperUserException No super user permissions
|
||||
* @throws CouldNotOpenDatabaseException Could not open the database
|
||||
*/
|
||||
public void reloadDatabase() throws NoSuperUserException, CouldNotOpenDatabaseException {
|
||||
|
@ -403,6 +408,7 @@ public class PlayMusicManager {
|
|||
|
||||
/**
|
||||
* Gets the path to the music track
|
||||
*
|
||||
* @param localCopyPath The local copy path
|
||||
* @return The path to the music file
|
||||
*/
|
||||
|
@ -437,6 +443,7 @@ public class PlayMusicManager {
|
|||
|
||||
/**
|
||||
* Gets the full path to the artwork
|
||||
*
|
||||
* @param artworkPath The artwork path
|
||||
* @return The full path to the artwork
|
||||
*/
|
||||
|
@ -469,12 +476,13 @@ 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
|
||||
*
|
||||
* @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, boolean forceOverwrite ) {
|
||||
public boolean exportMusicTrack(MusicTrack musicTrack, String dest, boolean forceOverwrite) throws InvalidDataException, IOException, UnsupportedTagException, NotSupportedException {
|
||||
// Creates the destination directory
|
||||
File directory = new File(dest).getParentFile();
|
||||
|
||||
|
@ -487,12 +495,13 @@ public class PlayMusicManager {
|
|||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @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, boolean forceOverwrite) {
|
||||
public boolean exportMusicTrack(MusicTrack musicTrack, Uri uri, String path, boolean forceOverwrite) throws InvalidDataException, IOException, UnsupportedTagException, NotSupportedException {
|
||||
|
||||
// Check for null
|
||||
if (musicTrack == null) return false;
|
||||
|
@ -504,10 +513,9 @@ public class PlayMusicManager {
|
|||
|
||||
String uniqueID = UUID.randomUUID().toString();
|
||||
|
||||
if ( forceOverwrite || !isAlreadyThere(uri, path) )
|
||||
{
|
||||
if (forceOverwrite || !isAlreadyThere(uri, path)) {
|
||||
|
||||
String fileTmp = getTempPath() + uniqueID +"_tmp.mp3";
|
||||
String fileTmp = getTempPath() + uniqueID + "_tmp.mp3";
|
||||
|
||||
// Copy to temp path failed
|
||||
if (!SuperUserTools.fileCopy(srcFile, fileTmp))
|
||||
|
@ -515,7 +523,7 @@ public class PlayMusicManager {
|
|||
|
||||
// Encrypt the file
|
||||
if (musicTrack.isEncoded()) {
|
||||
String fileTmpCrypt = getTempPath() + uniqueID +"_crypt.mp3";
|
||||
String fileTmpCrypt = getTempPath() + uniqueID + "_crypt.mp3";
|
||||
|
||||
// Encrypts the file
|
||||
if (trackEncrypt(musicTrack, fileTmp, fileTmpCrypt)) {
|
||||
|
@ -530,7 +538,6 @@ public class PlayMusicManager {
|
|||
}
|
||||
|
||||
|
||||
|
||||
String dest;
|
||||
Uri copyUri = null;
|
||||
if (uri.toString().startsWith("file://")) {
|
||||
|
@ -541,19 +548,19 @@ public class PlayMusicManager {
|
|||
FileTools.directoryCreate(parentDirectory);
|
||||
} else {
|
||||
// Complex uri (Lollipop)
|
||||
dest = getTempPath() + uniqueID +"_final.mp3";
|
||||
dest = getTempPath() + uniqueID + "_final.mp3";
|
||||
|
||||
// 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[] 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()) {
|
||||
for (DocumentFile subDocument : document.listFiles()) {
|
||||
// Directory exists
|
||||
if (subDocument.isDirectory() && subDocument.getName().equalsIgnoreCase(directoryName)) {
|
||||
document = subDocument;
|
||||
|
@ -571,12 +578,12 @@ public class PlayMusicManager {
|
|||
// Gets the filename
|
||||
String filename = directories[directories.length - 1];
|
||||
|
||||
for (DocumentFile subDocument: document.listFiles()) {
|
||||
for (DocumentFile subDocument : document.listFiles()) {
|
||||
// Directory exists
|
||||
if (subDocument.isFile() ){
|
||||
if ( filename != null && subDocument.getName().equalsIgnoreCase(filename)) {
|
||||
if (subDocument.isFile()) {
|
||||
if (filename != null && subDocument.getName().equalsIgnoreCase(filename)) {
|
||||
// Delete the file
|
||||
if ( forceOverwrite ) {
|
||||
if (forceOverwrite) {
|
||||
Logger.getInstance().logWarning("ExportMusicTrack", "(forceOverwrite) Deleting original file: " + filename);
|
||||
}
|
||||
subDocument.delete();
|
||||
|
@ -660,7 +667,7 @@ public class PlayMusicManager {
|
|||
//new MediaScanner(mContext, dest);
|
||||
|
||||
} else {
|
||||
Logger.getInstance().logInfo("exportMusicTrack", path + " already exists, skipping." );
|
||||
Logger.getInstance().logInfo("exportMusicTrack", path + " already exists, skipping.");
|
||||
}
|
||||
|
||||
// Done
|
||||
|
@ -669,9 +676,10 @@ public class PlayMusicManager {
|
|||
|
||||
/**
|
||||
* Checks if the destination file already exists
|
||||
* @param pUri the source file
|
||||
*
|
||||
* @param pUri the source file
|
||||
* @param pPath The destination
|
||||
* return true if the file already exists
|
||||
* return true if the file already exists
|
||||
*/
|
||||
private boolean isAlreadyThere(Uri pUri, String pPath) {
|
||||
if (pUri.toString().startsWith("file://")) {
|
||||
|
@ -683,8 +691,8 @@ public class PlayMusicManager {
|
|||
for (String lDisplayName : pPath.split("/")) {
|
||||
if (lDocumentFile.findFile(lDisplayName) != null) {
|
||||
lDocumentFile = lDocumentFile.findFile(lDisplayName);
|
||||
if ( lDocumentFile.length() == 0 ) {
|
||||
if ( !lDocumentFile.isDirectory() ) {
|
||||
if (lDocumentFile.length() == 0) {
|
||||
if (!lDocumentFile.isDirectory()) {
|
||||
Logger.getInstance().logInfo("isAlreadyThere", pPath + " File exists, but is 0 bytes in size.");
|
||||
}
|
||||
}
|
||||
|
@ -699,122 +707,117 @@ public class PlayMusicManager {
|
|||
|
||||
/**
|
||||
* Copies the music file to a new path and adds the mp3 meta data
|
||||
*
|
||||
* @param musicTrack Track information
|
||||
* @param src The source mp3 file
|
||||
* @param dest The destination path
|
||||
* return Return if the operation was successful
|
||||
* @param src The source mp3 file
|
||||
* @param dest The destination path
|
||||
* return Return if the operation was successful
|
||||
*/
|
||||
private boolean trackWriteID3(MusicTrack musicTrack, String src, String dest) {
|
||||
try {
|
||||
// Opens the mp3
|
||||
Mp3File mp3File = new Mp3File(src);
|
||||
private boolean trackWriteID3(MusicTrack musicTrack, String src, String dest) throws InvalidDataException, IOException, UnsupportedTagException, NotSupportedException {
|
||||
// Opens the mp3
|
||||
Mp3File mp3File = new Mp3File(src);
|
||||
|
||||
// Removes all existing tags
|
||||
mp3File.removeId3v1Tag();
|
||||
mp3File.removeId3v2Tag();
|
||||
mp3File.removeCustomTag();
|
||||
|
||||
// We want to add a fallback ID3v1 tag
|
||||
if (mID3EnableFallback) {
|
||||
// Create a new tag with ID3v1
|
||||
ID3v1Tag tagID3v1 = new ID3v1Tag();
|
||||
|
||||
// Set all tag values
|
||||
tagID3v1.setTrack(musicTrack.getTitle());
|
||||
tagID3v1.setArtist(musicTrack.getArtist());
|
||||
tagID3v1.setAlbum(musicTrack.getAlbum());
|
||||
tagID3v1.setYear(musicTrack.getYear());
|
||||
|
||||
// Search the genre
|
||||
for(int n=0; n<ID3v1Genres.GENRES.length; n++) {
|
||||
// Genre found
|
||||
if (ID3v1Genres.GENRES[n].equals(musicTrack.getGenre())) {
|
||||
tagID3v1.setGenre(n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mp3File.setId3v1Tag(tagID3v1);
|
||||
}
|
||||
|
||||
// It can't be null
|
||||
final ID3v2 tagID3v2;
|
||||
|
||||
// Creates the requested version
|
||||
switch(mID3v2Version) {
|
||||
case ID3v22:
|
||||
tagID3v2 = new ID3v22Tag();
|
||||
break;
|
||||
case ID3v23:
|
||||
tagID3v2 = new ID3v23Tag();
|
||||
break;
|
||||
case ID3v24:
|
||||
tagID3v2 = new ID3v24Tag();
|
||||
break;
|
||||
default:
|
||||
tagID3v2 = null;
|
||||
break;
|
||||
}
|
||||
// Removes all existing tags
|
||||
mp3File.removeId3v1Tag();
|
||||
mp3File.removeId3v2Tag();
|
||||
mp3File.removeCustomTag();
|
||||
|
||||
// We want to add a fallback ID3v1 tag
|
||||
if (mID3EnableFallback) {
|
||||
// Create a new tag with ID3v1
|
||||
ID3v1Tag tagID3v1 = new ID3v1Tag();
|
||||
|
||||
// Set all tag values
|
||||
tagID3v2.setTitle(musicTrack.getTitle());
|
||||
tagID3v2.setArtist(musicTrack.getArtist());
|
||||
tagID3v2.setAlbum(musicTrack.getAlbum());
|
||||
tagID3v2.setAlbumArtist(musicTrack.getAlbumArtist());
|
||||
tagID3v2.setTrack("" + musicTrack.getTrackNumber());
|
||||
tagID3v2.setPartOfSet("" + musicTrack.getDiscNumber());
|
||||
tagID3v2.setYear(musicTrack.getYear());
|
||||
tagID3v1.setTrack(musicTrack.getTitle());
|
||||
tagID3v1.setArtist(musicTrack.getArtist());
|
||||
tagID3v1.setAlbum(musicTrack.getAlbum());
|
||||
tagID3v1.setYear(musicTrack.getYear());
|
||||
|
||||
if (!TextUtils.isEmpty(musicTrack.getGenre())) {
|
||||
try {
|
||||
// Maybe the genre is not supported
|
||||
tagID3v2.setGenreDescription(musicTrack.getGenre());
|
||||
} catch (IllegalArgumentException e) {
|
||||
Logger.getInstance().logWarning("TrackWriteID3", e.getMessage());
|
||||
// Search the genre
|
||||
for (int n = 0; n < ID3v1Genres.GENRES.length; n++) {
|
||||
// Genre found
|
||||
if (ID3v1Genres.GENRES[n].equals(musicTrack.getGenre())) {
|
||||
tagID3v1.setGenre(n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the artwork to the meta data
|
||||
if (mID3EnableArtwork) {
|
||||
// Load the artwork
|
||||
Bitmap bitmap = ArtworkLoader.loadArtwork(musicTrack, mID3ArtworkMaximumSize);
|
||||
|
||||
if (bitmap != null) {
|
||||
// JPEG is default
|
||||
String mimeType = "image/jpeg";
|
||||
|
||||
// Load the bitmap into a byte array
|
||||
ByteArrayOutputStream artworkDataStream = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, artworkDataStream);
|
||||
|
||||
// Adds the artwork to the meta data
|
||||
tagID3v2.setAlbumImage(artworkDataStream.toByteArray(), mimeType);
|
||||
}
|
||||
}
|
||||
|
||||
mp3File.setId3v2Tag(tagID3v2);
|
||||
|
||||
|
||||
// Save the file
|
||||
mp3File.save(dest);
|
||||
|
||||
|
||||
// Done
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Logger.getInstance().logError("TrackWriteId3", e.toString());
|
||||
mp3File.setId3v1Tag(tagID3v1);
|
||||
}
|
||||
|
||||
// Failed
|
||||
return false;
|
||||
// It can't be null
|
||||
final ID3v2 tagID3v2;
|
||||
|
||||
// Creates the requested version
|
||||
switch (mID3v2Version) {
|
||||
case ID3v22:
|
||||
tagID3v2 = new ID3v22Tag();
|
||||
break;
|
||||
case ID3v23:
|
||||
tagID3v2 = new ID3v23Tag();
|
||||
break;
|
||||
case ID3v24:
|
||||
tagID3v2 = new ID3v24Tag();
|
||||
break;
|
||||
default:
|
||||
tagID3v2 = null;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Set all tag values
|
||||
tagID3v2.setTitle(musicTrack.getTitle());
|
||||
tagID3v2.setArtist(musicTrack.getArtist());
|
||||
tagID3v2.setAlbum(musicTrack.getAlbum());
|
||||
tagID3v2.setAlbumArtist(musicTrack.getAlbumArtist());
|
||||
tagID3v2.setTrack("" + musicTrack.getTrackNumber());
|
||||
tagID3v2.setPartOfSet("" + musicTrack.getDiscNumber());
|
||||
tagID3v2.setYear(musicTrack.getYear());
|
||||
|
||||
if (!TextUtils.isEmpty(musicTrack.getGenre())) {
|
||||
try {
|
||||
// Maybe the genre is not supported
|
||||
tagID3v2.setGenreDescription(musicTrack.getGenre());
|
||||
} catch (IllegalArgumentException e) {
|
||||
Logger.getInstance().logWarning("TrackWriteID3", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Add the artwork to the meta data
|
||||
if (mID3EnableArtwork) {
|
||||
// Load the artwork
|
||||
Bitmap bitmap = ArtworkLoader.loadArtwork(musicTrack, mID3ArtworkMaximumSize);
|
||||
|
||||
if (bitmap != null) {
|
||||
// JPEG is default
|
||||
String mimeType = "image/jpeg";
|
||||
|
||||
// Load the bitmap into a byte array
|
||||
ByteArrayOutputStream artworkDataStream = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, artworkDataStream);
|
||||
|
||||
// Adds the artwork to the meta data
|
||||
tagID3v2.setAlbumImage(artworkDataStream.toByteArray(), mimeType);
|
||||
}
|
||||
}
|
||||
|
||||
mp3File.setId3v2Tag(tagID3v2);
|
||||
|
||||
|
||||
// Save the file
|
||||
mp3File.save(dest);
|
||||
|
||||
|
||||
// Done
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a track and save it to a new path
|
||||
*
|
||||
* @param musicTrack The music track
|
||||
* @param src The source mp3 file
|
||||
* @param dest The destination path
|
||||
* @param src The source mp3 file
|
||||
* @param dest The destination path
|
||||
* @return Return if the operation was successful
|
||||
*/
|
||||
private boolean trackEncrypt(MusicTrack musicTrack, String src, String dest) {
|
||||
|
@ -843,8 +846,8 @@ public class PlayMusicManager {
|
|||
* Deletes all cache files
|
||||
*/
|
||||
private void cleanUp(String theUniqueID) {
|
||||
FileTools.fileDelete( getTempPath() + theUniqueID +"_final.mp3");
|
||||
FileTools.fileDelete( getTempPath() + theUniqueID +"_tmp.mp3");
|
||||
FileTools.fileDelete( getTempPath() + theUniqueID +"_crypt.mp3");
|
||||
FileTools.fileDelete(getTempPath() + theUniqueID + "_final.mp3");
|
||||
FileTools.fileDelete(getTempPath() + theUniqueID + "_tmp.mp3");
|
||||
FileTools.fileDelete(getTempPath() + theUniqueID + "_crypt.mp3");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue