using Newtonsoft.Json; using System; using System.IO; using System.Collections.Generic; using System.Threading.Tasks; using Windows.Storage; using Windows.Storage.AccessCache; using YoutubeExplode.Videos; using YoutubeExplode.Videos.Streams; using FoxTube.Utils; using FoxTube.Models; namespace FoxTube.Services { public static class DownloadsCenter { public static List History { get; private set; } public static List Queue { get; } = new List(); static DownloadsCenter() => Initialize(); private static async void Initialize() { StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync("DownloadHistory.json", CreationCollisionOption.OpenIfExists); try { History = JsonConvert.DeserializeObject>(File.ReadAllText(file.Path) ?? "") ?? new List(); foreach (SavedVideo i in History) try { i.IsPathValid = await StorageApplicationPermissions.MostRecentlyUsedList.GetFileAsync(i.AccessToken) != null; } catch { i.IsPathValid = false; } } catch (Exception e) { History = new List(); await file.DeleteAsync(StorageDeleteOption.PermanentDelete); StorageApplicationPermissions.MostRecentlyUsedList.Clear(); Metrics.SendReport(new Exception("Failed to load downloads history", e)); } } public static Task DownloadVideo(Video meta, IStreamInfo streamInfo) => DownloadVideo(meta, streamInfo, null); public static async Task DownloadVideo(Video meta, IStreamInfo streamInfo, IStorageFile destination) { DownloadItem item = new DownloadItem { Title = $"[{(streamInfo as IVideoStreamInfo)?.VideoQualityLabel ?? "Audio"}] {meta.Title}", Author = meta.Author, Thumbnail = meta.Thumbnails.LowResUrl, Duration = meta.Duration, Id = meta.Id }; Queue.Add(item); if (destination == null) destination = await (await GetDefaultDownloadsFolder()).CreateFileAsync($"{meta.Title.ReplaceInvalidChars('_')}.{streamInfo.Container.Name}", CreationCollisionOption.GenerateUniqueName); item.Path = destination.Path; try { await item.CommenceDownload(streamInfo, destination); SavedVideo savedItem = item as SavedVideo; savedItem.AccessToken = StorageApplicationPermissions.MostRecentlyUsedList.Add(destination); History.Add(savedItem); StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync("DownloadHistory.json", CreationCollisionOption.OpenIfExists); File.WriteAllText(file.Path, JsonConvert.SerializeObject(History)); } catch (OperationCanceledException) { } catch (Exception e) { await destination.DeleteAsync(StorageDeleteOption.PermanentDelete); Metrics.SendReport(new Exception("Failed to download video", e), null, ("Video ID", meta.Id), ("Stream tag", streamInfo.Tag.ToString())); } finally { Queue.Remove(item); } } public static async Task RemoveItems(bool removeFiles, params SavedVideo[] items) { foreach(SavedVideo i in items) { History.Remove(i); try { if (removeFiles) { StorageFile file = await StorageApplicationPermissions.MostRecentlyUsedList.GetFileAsync(i.AccessToken); await file?.DeleteAsync(); } } finally { StorageApplicationPermissions.MostRecentlyUsedList.Remove(i.AccessToken); } } StorageFile historyFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("DownloadHistory.json", CreationCollisionOption.OpenIfExists); File.WriteAllText(historyFile.Path, JsonConvert.SerializeObject(History)); } public static async Task GetDefaultDownloadsFolder() { if (string.IsNullOrWhiteSpace(Settings.DefaultDownloadsFolder)) return await KnownFolders.VideosLibrary.CreateFolderAsync("FoxTube", CreationCollisionOption.OpenIfExists); else return await StorageApplicationPermissions.FutureAccessList.GetFolderAsync(Settings.DefaultDownloadsFolder); } public static async Task CancelAll() { Queue.ForEach(i => i.Cancel()); while (Queue.Count > 0) await Task.Delay(500); } } }