using System; using YoutubeExplode; using YoutubeExplode.Videos; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Net.Http; using YoutubeExplode.Playlists; using YoutubeExplode.Channels; using System.IO; using System.Globalization; namespace Tesses.YouTubeDownloader { public class TYTDDownloaderStorageProxy : IStorage { public bool AddIfCompletedInStorage {get;set;}=true; public bool ThumbnailsFromDownloader {get;set;}=true; public IDownloader Downloader {get{return _downloader;} set { SetDownloader(value); } } private IDownloader _downloader=null; public ITYTDBase Storage {get;set;} private int SetEVT_ERR=0; private int SetEVT_VFIN=0; private int SetEVT_VSTAR=0; private int SetEVT_VPROG=0; private int SetEVT_BELL=0; private void SetDownloader(IDownloader downloader) { if(_downloader !=null) { if(SetEVT_BELL > 0)_downloader.Bell -= _EVT_BELL; if(SetEVT_VFIN > 0)_downloader.VideoFinished -= _EVT_VFIN; if(SetEVT_VPROG > 0)_downloader.VideoProgress -= _EVT_VPROG; if(SetEVT_VSTAR > 0)_downloader.VideoStarted -= _EVT_VSTAR; if(SetEVT_ERR > 0)_downloader.Error -= _EVT_ERR; } _downloader=downloader; if(downloader != null) { if(SetEVT_BELL > 0)_downloader.Bell += _EVT_BELL; if(SetEVT_VFIN > 0)_downloader.VideoFinished += _EVT_VFIN; if(SetEVT_VPROG > 0)_downloader.VideoProgress += _EVT_VPROG; if(SetEVT_VSTAR > 0)_downloader.VideoStarted += _EVT_VSTAR; if(SetEVT_ERR > 0)_downloader.Error += _EVT_ERR; } } private void _EVT_VSTAR(object sender,VideoStartedEventArgs evt) { _vstar?.Invoke(this,evt); } private void _EVT_VPROG(object sender,VideoProgressEventArgs evt) { _vprog?.Invoke(this,evt); } private void _EVT_VFIN(object sender,VideoFinishedEventArgs evt) { _vfin?.Invoke(this,evt); } private event EventHandler _bell; private event EventHandler _vstar; private event EventHandler _vprog; private event EventHandler _vfin; private event EventHandler _error; private void _EVT_BELL(object sender,BellEventArgs evt) { _bell?.Invoke(this,evt); } private void _EVT_ERR(object sender,TYTDErrorEventArgs evt) { _error?.Invoke(this,evt); } public LegacyConverter Legacy { get{ LegacyConverter conv=null; StorageAsStorage((e)=>{ conv=e.Legacy; }); return conv; } } public bool CanDownload { get { bool dl=false; StorageAsStorage((e)=>{ dl=e.CanDownload; }); return dl; } set {StorageAsStorage((e)=>{e.CanDownload=value;});} } public IExtensionContext ExtensionContext { get {IExtensionContext ctx=null;StorageAsStorage((e)=>{ctx=e.ExtensionContext;});return ctx;} set {StorageAsStorage((e)=>{e.ExtensionContext=value;});} } public HttpClient HttpClient { get { HttpClient clt=null; StorageAsStorage((e)=>{ clt=e.HttpClient; }); return clt; } set { StorageAsStorage((e)=>{ e.HttpClient=value; }); } } public YoutubeClient YoutubeClient { get { YoutubeClient clt=null; StorageAsStorage((e)=>{ clt=e.YoutubeClient; }); return clt; } set { StorageAsStorage((e)=>{ e.YoutubeClient=value; }); } } public event EventHandler Bell { add { if(SetEVT_BELL == 0) { Downloader.Bell += _EVT_BELL; } _bell += value; SetEVT_BELL++; } remove { SetEVT_BELL--; if(SetEVT_BELL <= 0) { SetEVT_BELL=0; Downloader.Bell -= _EVT_BELL; } _bell -= value; } } public event EventHandler VideoStarted { add { if(SetEVT_VSTAR == 0) { Downloader.VideoStarted += _EVT_VSTAR; } _vstar += value; SetEVT_VSTAR++; } remove { SetEVT_VSTAR--; if(SetEVT_VSTAR <= 0) { SetEVT_VSTAR=0; Downloader.VideoStarted -= _EVT_VSTAR; } _vstar -= value; } } public event EventHandler VideoProgress { add { if(SetEVT_VPROG == 0) { Downloader.VideoProgress += _EVT_VPROG; } _vprog += value; SetEVT_VPROG++; } remove { SetEVT_VPROG--; if(SetEVT_VPROG <= 0) { SetEVT_VPROG=0; Downloader.VideoProgress -= _EVT_VPROG; } _vprog -= value; } } public event EventHandler VideoFinished { add { if(SetEVT_VFIN == 0) { Downloader.VideoFinished += _EVT_VFIN; } _vfin += value; SetEVT_VFIN++; } remove { SetEVT_VFIN--; if(SetEVT_VFIN <= 0) { SetEVT_VFIN=0; Downloader.VideoFinished -= _EVT_VFIN; } _vfin -= value; } } public event EventHandler Error { add { if(SetEVT_ERR == 0) { Downloader.Error += _EVT_ERR; } _error += value; SetEVT_ERR++; } remove { SetEVT_ERR--; if(SetEVT_ERR <= 0) { SetEVT_ERR=0; Downloader.Error -= _EVT_ERR; } _error -= value; } } public async Task StorageAsStorageAsync(Func callback) { var store = Storage as IStorage; if(store != null && callback != null) await callback(store); } public void StorageAsStorage(Action callback) { var store = Storage as IStorage; if(store != null && callback != null) callback(store); } public async Task StorageAsWritableAsync(Func callback) { var store = Storage as IWritable; if(store != null && callback != null) await callback(store); } public async Task DownloaderAsITYTDBaseAsync(Func callback) { var store = Downloader as ITYTDBase; if(store != null && callback != null) await callback(store); } public void DownloaderAsITYTDBase(Action callback) { var store = Downloader as ITYTDBase; if(store != null && callback != null) callback(store); } public DownloaderMigration Migration { get{ return new DownloaderMigration(this); } } public async Task OpenOrCreateAsync(string path) { Stream strm=Stream.Null; await StorageAsStorageAsync(async(e)=>{ strm=await e.OpenOrCreateAsync(path); }); return strm; } public void RenameFile(string src, string dest) { StorageAsStorage((e)=>{ e.RenameFile(src,dest); }); } public async Task CreateAsync(string path) { Stream strm=Stream.Null; await StorageAsStorageAsync(async(e)=>{ strm=await e.CreateAsync(path); }); return strm; } public void CreateDirectory(string path) { StorageAsStorage((e)=>{ e.CreateDirectory(path); }); } public void MoveDirectory(string src, string dest) { StorageAsStorage((e)=>{e.MoveDirectory(src,dest);}); } public void DeleteFile(string file) { StorageAsStorage((e)=>{e.DeleteFile(file);}); } public void DeleteDirectory(string dir, bool recursive = false) { StorageAsStorage((e)=>{e.DeleteDirectory(dir,recursive);}); } public async Task OpenReadAsync(string path) { if(Storage ==null) return Stream.Null; return await Storage.OpenReadAsync(path); } public async Task FileExistsAsync(string path) { if(Storage ==null) return false; return await Storage.FileExistsAsync(path); } public async Task DirectoryExistsAsync(string path) { if(Storage ==null) return false; return await Storage.DirectoryExistsAsync(path); } public async IAsyncEnumerable EnumerateFilesAsync(string path) { if(Storage == null) yield break; await foreach(var item in Storage.EnumerateFilesAsync(path)) { yield return item; } } public async IAsyncEnumerable EnumerateDirectoriesAsync(string path) { if(Storage == null) yield break; await foreach(var item in Storage.EnumerateDirectoriesAsync(path)) { yield return item; } } public async Task WriteAllTextAsync(string path, string data) { await StorageAsWritableAsync(async(e)=>{await e.WriteAllTextAsync(path,data);}); } public async Task MuxVideosAsync(SavedVideo video, string videoSrc, string audioSrc, string videoDest, IProgress progress = null, CancellationToken token = default) { bool res=false; await StorageAsStorageAsync(async (e)=>{ res=await e.MuxVideosAsync(video,videoSrc,audioSrc,videoDest,progress,token); }); return res; } public async Task Continue(string path) { bool res=false; await StorageAsStorageAsync(async (e)=>{ res=await e.Continue(path); }); return res; } public async Task WriteVideoInfoAsync(SavedVideo channel) { await StorageAsStorageAsync(async (e)=>{ await e.WriteVideoInfoAsync(channel); }); } public async Task WritePlaylistInfoAsync(SavedPlaylist channel) { await StorageAsStorageAsync(async (e)=>{ await e.WritePlaylistInfoAsync(channel); }); } public async Task WriteChannelInfoAsync(SavedChannel channel) { await StorageAsStorageAsync(async (e)=>{ await e.WriteChannelInfoAsync(channel); }); } public void CreateDirectoryIfNotExist(string path) { StorageAsStorage((e)=>{ e.CreateDirectoryIfNotExist(path); }); } public void WaitTillMediaContentQueueEmpty() { StorageAsStorage((e)=>e.WaitTillMediaContentQueueEmpty()); } public Logger GetLogger() { Logger logger=null; StorageAsStorage((e)=>{ logger=e.GetLogger(); }); return logger; } public LoggerProperties GetLoggerProperties() { LoggerProperties properties=null; StorageAsStorage((e)=>{ properties=e.GetLoggerProperties(); }); return properties; } public async Task DownloadVideoOnlyAsync(SavedVideo video, CancellationToken token, IProgress progress, bool report = true) { bool res=false; await StorageAsStorageAsync(async(e)=>{ res= await e.DownloadVideoOnlyAsync(video,token,progress,report); }); return res; } public async Task MoveLegacyStreams(SavedVideo video, BestStreams streams) { await StorageAsStorageAsync(async(e)=>{ await e.MoveLegacyStreams(video,streams); }); } public async IAsyncEnumerable GetPersonalPlaylistContentsAsync(string name) { if(Downloader == null) yield break; await foreach(var item in Downloader.GetPersonalPlaylistContentsAsync(name)) { yield return await Task.FromResult(item); } } private async Task SkipVideoAsync(VideoId id,Resolution resolution) { if(AddIfCompletedInStorage) return false; if(await this.VideoExistsAsync(id,resolution)) { return true; } return false; } public async Task AddVideoAsync(VideoId id, Resolution resolution = Resolution.PreMuxed) { if(await SkipVideoAsync(id,resolution)) return; if(Downloader != null) await Downloader.AddVideoAsync(id,resolution); } public async Task AddFileAsync(string url,bool download=true) { if(Downloader != null) await Downloader.AddFileAsync(url,download); } public async Task AddPlaylistAsync(PlaylistId id, Resolution resolution = Resolution.PreMuxed) { if(Downloader != null) await Downloader.AddPlaylistAsync(id,resolution); } public async Task AddChannelAsync(ChannelId id, Resolution resolution = Resolution.PreMuxed) { if(Downloader != null) await Downloader.AddChannelAsync(id,resolution); } public async Task AddUserAsync(UserName userName, Resolution resolution = Resolution.PreMuxed) { if(Downloader != null) await Downloader.AddUserAsync(userName,resolution); } public async Task AddHandleAsync(ChannelHandle handle, Resolution resolution = Resolution.PreMuxed) { if(Downloader != null) await Downloader.AddHandleAsync(handle,resolution); } public async Task AddSlugAsync(ChannelSlug slug, Resolution resolution = Resolution.PreMuxed) { if(Downloader != null) await Downloader.AddSlugAsync(slug,resolution); } public IReadOnlyList<(SavedVideo Video, Resolution Resolution)> GetQueueList() { if(Downloader == null) return new List<(SavedVideo Video,Resolution Resolution)>(); return Downloader.GetQueueList(); } public SavedVideoProgress GetProgress() { if(Downloader == null)return new SavedVideoProgress(); return Downloader.GetProgress(); } public async IAsyncEnumerable GetSubscriptionsAsync() { Func> subscriptions=null; StorageAsStorage((e)=>{ subscriptions= e.GetSubscriptionsAsync; }); if(subscriptions == null) yield break; await foreach(var item in subscriptions()) { yield return await Task.FromResult(item); } } public async Task UnsubscribeAsync(ChannelId id) { await StorageAsStorageAsync(async(e)=>{ await e.UnsubscribeAsync(id); }); } public async Task SubscribeAsync(ChannelId id, ChannelBellInfo bellInfo = ChannelBellInfo.NotifyAndDownload) { await StorageAsStorageAsync(async(e)=>{ await e.SubscribeAsync(id,bellInfo); }); } public async Task SubscribeAsync(UserName name, ChannelBellInfo info = ChannelBellInfo.NotifyAndDownload) { await StorageAsStorageAsync(async(e)=>{ await e.SubscribeAsync(name,info); }); } public async Task ResubscribeAsync(ChannelId id, ChannelBellInfo info = ChannelBellInfo.NotifyAndDownload) { await StorageAsStorageAsync(async(e)=>{ await e.ResubscribeAsync(id,info); }); } public async IAsyncEnumerable GetPersonalPlaylistsAsync() { if(Downloader == null) yield break; Func> items=null; DownloaderAsITYTDBase((e)=>{ items=e.GetPersonalPlaylistsAsync; }); if(items == null) yield break; await foreach(var item in items()) { yield return await Task.FromResult(item); } } public async Task<(string Path, bool Delete)> GetRealUrlOrPathAsync(string path) { if(Storage == null) return ("",false); return await Storage.GetRealUrlOrPathAsync(path); } public bool FileExists(string path) { if(Storage == null) return false; return Storage.FileExists(path); } public async IAsyncEnumerable GetVideoIdsAsync() { if(Storage == null) yield break; await foreach(var id in Storage.GetVideoIdsAsync()) { yield return await Task.FromResult(id); } } public async Task GetVideoInfoAsync(VideoId id) { if(Storage == null) return new SavedVideo(); return await Storage.GetVideoInfoAsync(id); } public async IAsyncEnumerable GetVideosAsync() { if(Storage ==null) yield break; await foreach(var vid in Storage.GetVideosAsync()) { yield return await Task.FromResult(vid); } } public async IAsyncEnumerable GetLegacyVideosAsync() { if(Storage ==null) yield break; await foreach(var item in Storage.GetLegacyVideosAsync()) { yield return await Task.FromResult(item); } } public async Task GetLegacyVideoInfoAsync(VideoId id) { if(Storage == null) return new SavedVideoLegacy(); return await Storage.GetLegacyVideoInfoAsync(id); } public async IAsyncEnumerable GetPlaylistsAsync() { if(Storage ==null) yield break; await foreach(var item in Storage.GetPlaylistsAsync()) { yield return await Task.FromResult(item); } } public async Task ReadAllBytesAsync(string path, CancellationToken token = default) { if(Storage ==null) return new byte[0]; return await Storage.ReadAllBytesAsync(path,token); } public async IAsyncEnumerable GetPlaylistIdsAsync() { if(Storage ==null) yield break; await foreach(var item in Storage.GetPlaylistIdsAsync()) { yield return await Task.FromResult(item); } } public async IAsyncEnumerable GetChannelIdsAsync() { if(Storage ==null) yield break; await foreach(var item in Storage.GetChannelIdsAsync()) { yield return await Task.FromResult(item); } } public async IAsyncEnumerable GetYouTubeExplodeVideoIdsAsync() { if(Storage ==null) yield break; await foreach(var item in Storage.GetYouTubeExplodeVideoIdsAsync()) { yield return await Task.FromResult(item); } } public async Task GetChannelInfoAsync(ChannelId id) { if(Storage ==null) return new SavedChannel(); return await Storage.GetChannelInfoAsync(id); } public async IAsyncEnumerable GetChannelsAsync() { if(Storage ==null) yield break; await foreach(var item in Storage.GetChannelsAsync()) { yield return await Task.FromResult(item); } } public bool PlaylistInfoExists(PlaylistId id) { if(Storage ==null) return false; return Storage.PlaylistInfoExists(id); } public bool VideoInfoExists(VideoId id) { if(Storage ==null) return false; return Storage.VideoInfoExists(id); } public bool ChannelInfoExists(ChannelId id) { if(Storage ==null) return false; return Storage.ChannelInfoExists(id); } public async Task GetPlaylistInfoAsync(PlaylistId id) { if(Storage ==null) return new SavedPlaylist(); return await Storage.GetPlaylistInfoAsync(id); } public async Task ReadAllTextAsync(string file) { if(Storage ==null) return ""; return await Storage.ReadAllTextAsync(file); } public bool DirectoryExists(string path) { if(Storage ==null) return false; return Storage.DirectoryExists(path); } public IEnumerable EnumerateFiles(string path) { if(Storage ==null) yield break; foreach(var item in Storage.EnumerateFiles(path)) { yield return item; } } public IEnumerable EnumerateDirectories(string path) { if(Storage ==null) yield break; foreach(var item in Storage.EnumerateDirectories(path)) { yield return item; } } public IReadOnlyList GetLoadedSubscriptions() { IReadOnlyList subs=new List(); StorageAsStorage((e)=>{ subs=e.GetLoadedSubscriptions(); }); return subs; } public void Unsubscribe(ChannelId id) { StorageAsStorage((e)=>{ e.Unsubscribe(id); }); } public void StartLoop(CancellationToken token = default) { StorageAsStorage((e)=>{ e.StartLoop(token); }); } public async Task AddToPersonalPlaylistAsync(string name, IEnumerable items) { if(Downloader ==null) return; await Downloader.AddToPersonalPlaylistAsync(name,items); } public async Task ReplacePersonalPlaylistAsync(string name, IEnumerable items) { if(Downloader ==null) return; await Downloader.ReplacePersonalPlaylistAsync(name,items); } public async Task RemoveItemFromPersonalPlaylistAsync(string name, VideoId id) { if(Downloader ==null) return; await Downloader.RemoveItemFromPersonalPlaylistAsync(name,id); } public async Task SetResolutionForItemInPersonalPlaylistAsync(string name, VideoId id, Resolution resolution) { if(Downloader ==null) return; await Downloader.SetResolutionForItemInPersonalPlaylistAsync(name,id,resolution); } public bool PersonalPlaylistExists(string name) { if(Downloader ==null) return false; return Downloader.PersonalPlaylistExists(name); } public void DeletePersonalPlaylist(string name) { if(Downloader ==null) return; Downloader.DeletePersonalPlaylist(name); } public async Task WriteBestStreamInfoAsync(VideoId id, BestStreamInfo.BestStreamsSerialized serialized) { await StorageAsStorageAsync(async(e)=>{ await e.WriteBestStreamInfoAsync(id,serialized); }); } public async Task GetBestStreamInfoAsync(VideoId id) { return await Storage.GetBestStreamInfoAsync(id); } public bool BestStreamInfoExists(VideoId id) { return Storage.BestStreamInfoExists(id); } public bool DownloadExists(string p) { return Storage.DownloadExists(p); } public async IAsyncEnumerable GetDownloadUrlsAsync() { await foreach(var url in Storage.GetDownloadUrlsAsync()) { yield return url; } } public async IAsyncEnumerable GetDownloadsAsync() { await foreach(var item in Storage.GetDownloadsAsync()) { yield return item; } } public async Task GetDownloadInfoAsync(string url) { return await Storage.GetDownloadInfoAsync(url); } public void CancelDownload(bool restart = false) { Downloader.CancelDownload(restart); } public ExtraData GetExtraData() { return Downloader.GetExtraData(); } public bool ThumbnailExists(VideoId videoId, string res) { bool exists=false; if(ThumbnailsFromDownloader) { DownloaderAsITYTDBase((s)=>{ exists = s.ThumbnailExists(videoId,res); }); }else{ StorageAsStorage((s)=>{ exists = s.ThumbnailExists(videoId,res); }); } return exists; } public async Task ReadThumbnailAsync(VideoId videoId, string res,CancellationToken token=default) { byte[] data=new byte[0]; if(ThumbnailsFromDownloader) { await DownloaderAsITYTDBaseAsync(async (s)=>{ data = await s.ReadThumbnailAsync(videoId,res,token); }); }else{ await StorageAsStorageAsync(async(s)=>{ data = await s.ReadThumbnailAsync(videoId,res,token); }); } return data; } public async Task WriteThumbnailAsync(VideoId videoId, string res, byte[] data, CancellationToken token = default) { await StorageAsStorageAsync(async(s)=>{ await s.WriteThumbnailAsync(videoId,res,data,token); }); } public async Task ThumbnailExistsAsync(VideoId videoId, string res) { bool exists=false; if(ThumbnailsFromDownloader) { await DownloaderAsITYTDBaseAsync(async(s)=>{ exists = await s.ThumbnailExistsAsync(videoId,res); }); }else{ await StorageAsStorageAsync(async(s)=>{ exists = await s.ThumbnailExistsAsync(videoId,res); }); } return exists; } public async Task VideoInfoExistsAsync(VideoId id) { if(Storage ==null) return await Task.FromResult(false); return await Storage.VideoInfoExistsAsync(id); } public async Task PlaylistInfoExistsAsync(PlaylistId id) { if(Storage ==null) return await Task.FromResult(false); return await Storage.PlaylistInfoExistsAsync(id); } public async Task ChannelInfoExistsAsync(ChannelId id) { if(Storage ==null) return await Task.FromResult(false); return await Storage.ChannelInfoExistsAsync(id); } public async Task PersonalPlaylistExistsAsync(string name) { if(Storage ==null) return await Task.FromResult(false); return await Storage.PersonalPlaylistExistsAsync(name); } public async Task BestStreamInfoExistsAsync(VideoId id) { if(Storage ==null) return await Task.FromResult(false); return await Storage.BestStreamInfoExistsAsync(id); } } public class DownloaderMigration { private TYTDDownloaderStorageProxy proxy; public DownloaderMigration(TYTDDownloaderStorageProxy proxy) { this.proxy = proxy; } public async Task DownloaderAsBaseAsync(Func callback) { var dl = proxy.Downloader as ITYTDBase; if(dl != null && callback !=null) await callback(dl); } public void DownloaderAsBase(Action callback) { var dl = proxy.Downloader as ITYTDBase; if(dl != null && callback !=null) callback(dl); } public async Task CopyVideoAsync(VideoId id,Resolution res=Resolution.PreMuxed,IProgress progress=null,CancellationToken token=default(CancellationToken),bool copyThumbnails=true) { await DownloaderAsBaseAsync(async(e)=>{ await proxy.StorageAsStorageAsync(async(f)=>{ await TYTDManager.CopyVideoAsync(id,e,f,res,progress,token,copyThumbnails); }); }); } public async Task CopyAllVideosAsync(Resolution res=Resolution.PreMuxed,IProgress progress=null,CancellationToken token=default(CancellationToken),bool copyThumbnails=true) { await DownloaderAsBaseAsync(async(e)=>{ await proxy.StorageAsStorageAsync(async(f)=>{ await TYTDManager.CopyAllVideosAsync(e,f,res,progress,token,copyThumbnails); }); }); } public async Task CopyPlaylistAsync(PlaylistId id,Resolution res=Resolution.PreMuxed,IProgress progress=null,CancellationToken token=default(CancellationToken),bool copyThumbnails=true,bool copyContents=true) { await DownloaderAsBaseAsync(async(e)=>{ await proxy.StorageAsStorageAsync(async(f)=>{ await TYTDManager.CopyPlaylistAsync(id,e,f,res,progress,token,copyThumbnails,copyContents); }); }); } public async Task CopyChannelAsync(ChannelId id,Resolution res=Resolution.PreMuxed,IProgress progress=null,CancellationToken token=default(CancellationToken),bool copyThumbnails=true,bool copyContents=false) { await DownloaderAsBaseAsync(async(e)=>{ await proxy.StorageAsStorageAsync(async(f)=>{ await TYTDManager.CopyChannelAsync(id,e,f,res,progress,token,copyThumbnails,copyContents); }); }); } public async Task CopyAllPlaylistsAsync(Resolution res=Resolution.PreMuxed,IProgress progress=null,CancellationToken token=default(CancellationToken),bool copyThumbnails=true,bool copyContents=true) { await DownloaderAsBaseAsync(async(e)=>{ await proxy.StorageAsStorageAsync(async(f)=>{ await TYTDManager.CopyAllPlaylistsAsync(e,f,res,progress,token,copyThumbnails,copyContents); }); }); } public async Task CopyAllChannelsAsync(Resolution res=Resolution.PreMuxed,IProgress progress=null,CancellationToken token=default(CancellationToken),bool copyThumbnails=true,bool copyContents=false) { await DownloaderAsBaseAsync(async(e)=>{ await proxy.StorageAsStorageAsync(async(f)=>{ await TYTDManager.CopyAllChannelsAsync(e,f,res,progress,token,copyThumbnails,copyContents); }); }); } public async Task CopyEverythingAsync(Resolution res,IProgress progress=null,CancellationToken token=default(CancellationToken),bool copyThumbnails=true) { await DownloaderAsBaseAsync(async(e)=>{ await proxy.StorageAsStorageAsync(async(f)=>{ await TYTDManager.CopyEverythingAsync(e,f,res,progress,token,copyThumbnails); }); }); } public async Task CopyEverythingAsync(IProgress progress=null,CancellationToken token=default(CancellationToken),bool copyThumbnails=true) { await DownloaderAsBaseAsync(async(e)=>{ await proxy.StorageAsStorageAsync(async(f)=>{ await TYTDManager.CopyEverythingAsync(e,f,progress,token,copyThumbnails); }); }); } } }