mirror of
https://github.com/zoriya/Opus.git
synced 2026-05-31 13:23:01 +00:00
Download playlist now add songs to a local playlist
This commit is contained in:
@@ -373,6 +373,57 @@ namespace MusicApp.Resources.Portable_Class
|
||||
builder.Show();
|
||||
}
|
||||
|
||||
public static long GetPlaylistID(string playlistName)
|
||||
{
|
||||
Android.Net.Uri uri = MediaStore.Audio.Playlists.ExternalContentUri;
|
||||
Looper.Prepare();
|
||||
CursorLoader loader = new CursorLoader(Android.App.Application.Context, uri, null, null, null, null);
|
||||
ICursor cursor = (ICursor)loader.LoadInBackground();
|
||||
|
||||
if (cursor != null && cursor.MoveToFirst())
|
||||
{
|
||||
int nameID = cursor.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Name);
|
||||
int plID = cursor.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Id);
|
||||
do
|
||||
{
|
||||
string name = cursor.GetString(nameID);
|
||||
|
||||
if (name != playlistName)
|
||||
continue;
|
||||
|
||||
return cursor.GetLong(plID);
|
||||
}
|
||||
while (cursor.MoveToNext());
|
||||
cursor.Close();
|
||||
}
|
||||
|
||||
//Playlist do not exist, create it
|
||||
ContentResolver resolver = act.ContentResolver;
|
||||
ContentValues value = new ContentValues();
|
||||
value.Put(MediaStore.Audio.Playlists.InterfaceConsts.Name, playlistName);
|
||||
resolver.Insert(uri, value);
|
||||
|
||||
CursorLoader loaderBis = new CursorLoader(Android.App.Application.Context, uri, null, null, null, null);
|
||||
ICursor cursorBis = (ICursor)loader.LoadInBackground();
|
||||
|
||||
if (cursorBis != null && cursorBis.MoveToFirst())
|
||||
{
|
||||
int nameID = cursorBis.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Name);
|
||||
int getplaylistID = cursorBis.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Id);
|
||||
do
|
||||
{
|
||||
string name = cursorBis.GetString(nameID);
|
||||
long id = cursorBis.GetLong(getplaylistID);
|
||||
|
||||
if (playlistName == name)
|
||||
return id;
|
||||
}
|
||||
while (cursorBis.MoveToNext());
|
||||
cursorBis.Close();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public async static Task CheckWritePermission()
|
||||
{
|
||||
const string permission = Manifest.Permission.WriteExternalStorage;
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.Database;
|
||||
using Android.Media;
|
||||
using Android.Net;
|
||||
using Android.OS;
|
||||
using Android.Provider;
|
||||
using Android.Support.Design.Widget;
|
||||
using Android.Support.V4.App;
|
||||
using MusicApp.Resources.values;
|
||||
using System.Collections.Generic;
|
||||
@@ -19,7 +24,7 @@ using File = System.IO.File;
|
||||
namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
[Service]
|
||||
public class Downloader : Service
|
||||
public class Downloader : Service, MediaScannerConnection.IOnScanCompletedListener
|
||||
{
|
||||
public static Downloader instance;
|
||||
public string downloadPath;
|
||||
@@ -28,8 +33,8 @@ namespace MusicApp.Resources.Portable_Class
|
||||
private int currentStrike = 0;
|
||||
private static bool isDownloading = false;
|
||||
private NotificationCompat.Builder notification;
|
||||
private int notificationID = 1001;
|
||||
private int RequestCode = 5465;
|
||||
private const int notificationID = 1001;
|
||||
private const int RequestCode = 5465;
|
||||
|
||||
|
||||
public override IBinder OnBind(Intent intent)
|
||||
@@ -83,20 +88,31 @@ namespace MusicApp.Resources.Portable_Class
|
||||
currentStrike++;
|
||||
CreateNotification(file.name);
|
||||
|
||||
if (YoutubeEngine.FileIsAlreadyDownloaded(file.videoID) && !file.skipCheck)
|
||||
{
|
||||
Snackbar.Make(MainActivity.instance.FindViewById(Resource.Id.snackBar), file.name + " is already on your device.", Snackbar.LengthShort).SetAction("Download Anyway", (v) =>
|
||||
{
|
||||
file.skipCheck = true;
|
||||
Download(file);
|
||||
}).Show();
|
||||
}
|
||||
|
||||
YoutubeClient client = new YoutubeClient();
|
||||
Video videoInfo = await client.GetVideoAsync(file.videoID);
|
||||
MediaStreamInfoSet mediaStreamInfo = await client.GetVideoMediaStreamInfosAsync(file.videoID);
|
||||
AudioStreamInfo streamInfo = mediaStreamInfo.Audio.Where(x => x.Container == Container.M4A).OrderBy(s => s.Bitrate).Last();
|
||||
|
||||
System.Console.WriteLine("&" + streamInfo.Url);
|
||||
//With Where container == Container.M4A, output file should be a m4a file, so ffmpeg is usless
|
||||
|
||||
string fileExtension = streamInfo.Container.GetFileExtension();
|
||||
string fileName = $"{videoInfo.Title}.{fileExtension}";
|
||||
|
||||
string filePath = Path.Combine(path, fileName);
|
||||
string outpath = path;
|
||||
if(file.playlist != null)
|
||||
{
|
||||
outpath = Path.Combine(path, file.playlist);
|
||||
Directory.CreateDirectory(outpath);
|
||||
}
|
||||
|
||||
System.Console.WriteLine("&Client and path created");
|
||||
string filePath = Path.Combine(outpath, fileName);
|
||||
|
||||
MediaStream input = await client.GetMediaStreamAsync(streamInfo);
|
||||
|
||||
@@ -104,18 +120,16 @@ namespace MusicApp.Resources.Portable_Class
|
||||
await input.CopyToAsync(output);
|
||||
output.Dispose();
|
||||
|
||||
System.Console.WriteLine("&Webm Output created");
|
||||
|
||||
SetMetaData(filePath, videoInfo.Title, videoInfo.Author, videoInfo.Thumbnails.HighResUrl, file.videoID);
|
||||
SetMetaData(filePath, videoInfo.Title, videoInfo.Author, videoInfo.Thumbnails.HighResUrl, file.videoID, file.playlist);
|
||||
isDownloading = false;
|
||||
|
||||
if (queue.Count != 0)
|
||||
DownloadAudio(queue[0], path);
|
||||
}
|
||||
|
||||
private void SetMetaData(string filePath, string title, string artist, string album, string youtubeID)
|
||||
private void SetMetaData(string filePath, string title, string artist, string album, string youtubeID, string playlist)
|
||||
{
|
||||
Stream stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);
|
||||
System.IO.Stream stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);
|
||||
var meta = TagLib.File.Create(new StreamFileAbstraction(filePath, stream, stream));
|
||||
|
||||
meta.Tag.Title = title;
|
||||
@@ -130,9 +144,24 @@ namespace MusicApp.Resources.Portable_Class
|
||||
meta.Tag.Pictures = pictures;
|
||||
meta.Save();
|
||||
stream.Dispose();
|
||||
Android.Media.MediaScannerConnection.ScanFile(this, new string[] { filePath }, null, null);
|
||||
MediaScannerConnection.ScanFile(this, new string[] { filePath }, null, this);
|
||||
|
||||
StopForeground(true);
|
||||
if (queue.Count == 0)
|
||||
StopForeground(true);
|
||||
}
|
||||
|
||||
public void OnScanCompleted(string path, Uri uri)
|
||||
{
|
||||
long id = long.Parse(uri.ToString().Substring(uri.ToString().IndexOf("audio/media/") + 12, uri.ToString().Length - uri.ToString().IndexOf("audio/media/") - 12));
|
||||
string playlist = path.Substring(downloadPath.Length + 1, path.IndexOf("/", downloadPath.Length) - downloadPath.Length + 1);
|
||||
|
||||
Browse.act = MainActivity.instance;
|
||||
long playlistID = Browse.GetPlaylistID(playlist);
|
||||
|
||||
ContentValues value = new ContentValues();
|
||||
value.Put(MediaStore.Audio.Playlists.Members.AudioId, id);
|
||||
value.Put(MediaStore.Audio.Playlists.Members.PlayOrder, 0);
|
||||
ContentResolver.Insert(MediaStore.Audio.Playlists.Members.GetContentUri("external", playlistID), value);
|
||||
}
|
||||
|
||||
void CreateNotification(string title)
|
||||
|
||||
@@ -348,8 +348,6 @@ namespace MusicApp.Resources.Portable_Class
|
||||
CursorLoader cursorLoader = new CursorLoader(Android.App.Application.Context, musicUri, null, null, null, null);
|
||||
ICursor musicCursor = (ICursor)cursorLoader.LoadInBackground();
|
||||
|
||||
System.Console.WriteLine("&Path: " + path + " URI: " + musicUri.ToString());
|
||||
|
||||
if (musicCursor != null && musicCursor.MoveToFirst())
|
||||
{
|
||||
int thisID = musicCursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Id);
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
public static Playlist instance;
|
||||
public RecyclerView ListView;
|
||||
private bool populated = false;
|
||||
|
||||
//Local playlists
|
||||
private List<string> playList = new List<string>();
|
||||
@@ -32,7 +33,6 @@ namespace MusicApp.Resources.Portable_Class
|
||||
private List<Google.Apis.YouTube.v3.Data.Playlist> YtPlaylists = new List<Google.Apis.YouTube.v3.Data.Playlist>();
|
||||
|
||||
private PlaylistAdapter adapter;
|
||||
private bool isEmpty = false;
|
||||
private View emptyView;
|
||||
|
||||
public override void OnActivityCreated(Bundle savedInstanceState)
|
||||
@@ -43,20 +43,6 @@ namespace MusicApp.Resources.Portable_Class
|
||||
MainActivity.instance.OnPaddingChanged += OnPaddingChanged;
|
||||
}
|
||||
|
||||
public void AddEmptyView()
|
||||
{
|
||||
if (emptyView.Parent != null)
|
||||
((ViewGroup)emptyView.Parent).RemoveView(emptyView);
|
||||
|
||||
Activity.AddContentView(emptyView, View.LayoutParameters);
|
||||
}
|
||||
|
||||
public void RemoveEmptyView()
|
||||
{
|
||||
ViewGroup rootView = Activity.FindViewById<ViewGroup>(Android.Resource.Id.Content);
|
||||
rootView.RemoveView(emptyView);
|
||||
}
|
||||
|
||||
private void OnPaddingChanged(object sender, PaddingChange e)
|
||||
{
|
||||
if (MainActivity.paddingBot > e.oldPadding)
|
||||
@@ -69,8 +55,6 @@ namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
MainActivity.instance.contentRefresh.Refresh -= OnRefresh;
|
||||
MainActivity.instance.OnPaddingChanged -= OnPaddingChanged;
|
||||
if (isEmpty)
|
||||
RemoveEmptyView();
|
||||
|
||||
base.OnDestroy();
|
||||
instance = null;
|
||||
@@ -90,6 +74,8 @@ namespace MusicApp.Resources.Portable_Class
|
||||
|
||||
public async Task PopulateView()
|
||||
{
|
||||
populated = false;
|
||||
|
||||
//Local playlists
|
||||
playList.Clear();
|
||||
playlistId.Clear();
|
||||
@@ -145,6 +131,9 @@ namespace MusicApp.Resources.Portable_Class
|
||||
|
||||
YouTubeService youtube = YoutubeEngine.youtubeService;
|
||||
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
PlaylistsResource.ListRequest request = youtube.Playlists.List("snippet,contentDetails");
|
||||
request.Mine = true;
|
||||
request.MaxResults = 25;
|
||||
@@ -185,6 +174,9 @@ namespace MusicApp.Resources.Portable_Class
|
||||
PlaylistsResource.ListRequest plRequest = youtube.Playlists.List("snippet, contentDetails");
|
||||
plRequest.Id = section.ContentDetails.Playlists[i];
|
||||
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
PlaylistListResponse plResponse = await plRequest.ExecuteAsync();
|
||||
|
||||
if (instance == null)
|
||||
@@ -209,6 +201,8 @@ namespace MusicApp.Resources.Portable_Class
|
||||
adapter.SetYtPlaylists(ytPlaylists, true);
|
||||
else
|
||||
adapter.SetYtPlaylists(ytPlaylists, true);
|
||||
|
||||
populated = true;
|
||||
}
|
||||
|
||||
public static Fragment NewInstance()
|
||||
@@ -225,7 +219,8 @@ namespace MusicApp.Resources.Portable_Class
|
||||
|
||||
public async Task Refresh()
|
||||
{
|
||||
await PopulateView();
|
||||
if(populated)
|
||||
await PopulateView();
|
||||
}
|
||||
|
||||
private void ListView_ItemClick(object sender, int Position)
|
||||
@@ -290,8 +285,6 @@ namespace MusicApp.Resources.Portable_Class
|
||||
act.SupportActionBar.Title = playlist.GetName();
|
||||
instance = null;
|
||||
MainActivity.instance.contentRefresh.Refresh -= OnRefresh;
|
||||
if (isEmpty)
|
||||
RemoveEmptyView();
|
||||
|
||||
if (local)
|
||||
MainActivity.instance.Transition(Resource.Id.contentView, PlaylistTracks.NewInstance(playlist.GetID(), playlist.GetName()), true);
|
||||
@@ -352,7 +345,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
RemoveYoutubePlaylist(Position, playlist.GetPath());
|
||||
break;
|
||||
case 4:
|
||||
YoutubeEngine.DownloadPlaylist(playlist.GetPath());
|
||||
YoutubeEngine.DownloadPlaylist(playlist.GetName(), playlist.GetPath());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -373,7 +366,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
Unfork(Position, playlist.GetPath());
|
||||
break;
|
||||
case 3:
|
||||
YoutubeEngine.DownloadPlaylist(playlist.GetPath());
|
||||
YoutubeEngine.DownloadPlaylist(playlist.GetName(), playlist.GetPath());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -417,19 +417,11 @@ namespace MusicApp.Resources.Portable_Class
|
||||
parseProgress.Visibility = ViewStates.Gone;
|
||||
}
|
||||
|
||||
public async static void Download(string name, string videoID, bool skipExistVerification = false)
|
||||
public async static void Download(string name, string videoID)
|
||||
{
|
||||
ISharedPreferences prefManager = PreferenceManager.GetDefaultSharedPreferences(Android.App.Application.Context);
|
||||
if (prefManager.GetString("downloadPath", null) != null)
|
||||
{
|
||||
if (FileIsAlreadyDownloaded(videoID) && !skipExistVerification)
|
||||
{
|
||||
Snackbar.Make(MainActivity.instance.FindViewById(Resource.Id.snackBar), name + " is already on your device.", Snackbar.LengthShort).SetAction("Download Anyway", (v) =>
|
||||
{
|
||||
Download(name, videoID, true);
|
||||
}).Show();
|
||||
}
|
||||
|
||||
Toast.MakeText(Android.App.Application.Context, "Downloading...", ToastLength.Short).Show();
|
||||
Context context = Android.App.Application.Context;
|
||||
Intent intent = new Intent(context, typeof(Downloader));
|
||||
@@ -439,7 +431,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
await Task.Delay(10);
|
||||
|
||||
Downloader.instance.downloadPath = prefManager.GetString("downloadPath", null);
|
||||
Downloader.instance.Download(new DownloadFile(name, videoID));
|
||||
Downloader.instance.Download(new DownloadFile(name, videoID, null));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -451,56 +443,56 @@ namespace MusicApp.Resources.Portable_Class
|
||||
}
|
||||
}
|
||||
|
||||
public static async void DownloadFiles(string[] names, string[] videoIDs, bool skipExistVerification = false)
|
||||
public static async void DownloadFiles(string[] names, string[] videoIDs, string playlist)
|
||||
{
|
||||
ISharedPreferences prefManager = PreferenceManager.GetDefaultSharedPreferences(Android.App.Application.Context);
|
||||
if (prefManager.GetString("downloadPath", null) != null)
|
||||
{
|
||||
if (!skipExistVerification)
|
||||
{
|
||||
List<string> downloadedName = new List<string>();
|
||||
List<string> downloadedID = new List<string>();
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
if (FileIsAlreadyDownloaded(videoIDs[i]))
|
||||
{
|
||||
downloadedName.Add(names[i]);
|
||||
downloadedID.Add(videoIDs[i]);
|
||||
}
|
||||
}
|
||||
//if (!skipExistVerification)
|
||||
//{
|
||||
// List<string> downloadedName = new List<string>();
|
||||
// List<string> downloadedID = new List<string>();
|
||||
// for (int i = 0; i < names.Length; i++)
|
||||
// {
|
||||
// if (FileIsAlreadyDownloaded(videoIDs[i]))
|
||||
// {
|
||||
// downloadedName.Add(names[i]);
|
||||
// downloadedID.Add(videoIDs[i]);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (downloadedName.Count > 0)
|
||||
{
|
||||
List<string> namesList = names.ToList();
|
||||
List<string> idList = videoIDs.ToList();
|
||||
// if (downloadedName.Count > 0)
|
||||
// {
|
||||
// List<string> namesList = names.ToList();
|
||||
// List<string> idList = videoIDs.ToList();
|
||||
|
||||
for(int i = 0; i < downloadedName.Count; i++)
|
||||
{
|
||||
namesList.Remove(downloadedName[i]);
|
||||
idList.Remove(downloadedID[i]);
|
||||
}
|
||||
// for(int i = 0; i < downloadedName.Count; i++)
|
||||
// {
|
||||
// namesList.Remove(downloadedName[i]);
|
||||
// idList.Remove(downloadedID[i]);
|
||||
// }
|
||||
|
||||
names = namesList.ToArray();
|
||||
videoIDs = idList.ToArray();
|
||||
// names = namesList.ToArray();
|
||||
// videoIDs = idList.ToArray();
|
||||
|
||||
if (downloadedName.Count == 1)
|
||||
{
|
||||
Snackbar.Make(MainActivity.instance.FindViewById(Resource.Id.snackBar), downloadedName[0] + " is already on your device.", Snackbar.LengthShort).SetAction("Download this file anyway", (v) =>
|
||||
{
|
||||
Downloader.instance.Download(new DownloadFile(downloadedName[0], downloadedID[0]));
|
||||
}).Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
Snackbar.Make(MainActivity.instance.FindViewById(Resource.Id.snackBar), downloadedName.Count + " files are already on your device", Snackbar.LengthShort).SetAction("Download all this files anyway", (v) =>
|
||||
{
|
||||
for(int i = 0; i < downloadedName.Count; i++)
|
||||
Downloader.instance.Download(new DownloadFile(downloadedName[i], downloadedID[i]));
|
||||
// if (downloadedName.Count == 1)
|
||||
// {
|
||||
// Snackbar.Make(MainActivity.instance.FindViewById(Resource.Id.snackBar), downloadedName[0] + " is already on your device.", Snackbar.LengthShort).SetAction("Download this file anyway", (v) =>
|
||||
// {
|
||||
// Downloader.instance.Download(new DownloadFile(downloadedName[0], downloadedID[0], playlist));
|
||||
// }).Show();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Snackbar.Make(MainActivity.instance.FindViewById(Resource.Id.snackBar), downloadedName.Count + " files are already on your device", Snackbar.LengthShort).SetAction("Download all this files anyway", (v) =>
|
||||
// {
|
||||
// for(int i = 0; i < downloadedName.Count; i++)
|
||||
// Downloader.instance.Download(new DownloadFile(downloadedName[i], downloadedID[i], playlist));
|
||||
|
||||
}).Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
// }).Show();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
Toast.MakeText(Android.App.Application.Context, "Downloading...", ToastLength.Short).Show();
|
||||
Context context = Android.App.Application.Context;
|
||||
@@ -513,7 +505,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
Downloader.instance.downloadPath = prefManager.GetString("downloadPath", null);
|
||||
|
||||
for(int i = 0; i < names.Length; i++)
|
||||
Downloader.instance.Download(new DownloadFile(names[i], videoIDs[i]));
|
||||
Downloader.instance.Download(new DownloadFile(names[i], videoIDs[i], playlist));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -772,7 +764,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
PlayFiles(tracks.ToArray());
|
||||
}
|
||||
|
||||
public static async void DownloadPlaylist(string playlistID)
|
||||
public static async void DownloadPlaylist(string playlist, string playlistID)
|
||||
{
|
||||
List<string> names = new List<string>();
|
||||
List<string> videoIDs = new List<string>();
|
||||
@@ -794,7 +786,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
|
||||
nextPageToken = ytPlaylist.NextPageToken;
|
||||
}
|
||||
DownloadFiles(names.ToArray(), videoIDs.ToArray());
|
||||
DownloadFiles(names.ToArray(), videoIDs.ToArray(), playlist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
YoutubeEngine.ForkPlaylist(playlist.GetPath());
|
||||
break;
|
||||
case 2:
|
||||
YoutubeEngine.DownloadPlaylist(playlist.GetPath());
|
||||
YoutubeEngine.DownloadPlaylist(playlist.GetName(), playlist.GetPath());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
{
|
||||
public string name;
|
||||
public string videoID;
|
||||
public string playlist;
|
||||
public bool skipCheck = false;
|
||||
|
||||
public DownloadFile(string name, string videoID)
|
||||
public DownloadFile(string name, string videoID, string playlist)
|
||||
{
|
||||
this.name = name;
|
||||
this.videoID = videoID;
|
||||
this.playlist = playlist;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user