#region license // This file is part of Vocaluxe. // // Vocaluxe is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Vocaluxe is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Vocaluxe. If not, see . #endregion using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; namespace VocaluxeLib.Songs { /// /// Access to the files of a song (audio, video, cover, backgrounds). /// Songs from a song server exist locally only as their text file at first; their other files are /// downloaded on demand. Everything that opens a song file should check and /// call (or on background threads) first. /// public interface ISongFileProvider { /// True if the file exists locally or can be downloaded. bool Exists(string path); /// True if the file can be opened now (exists locally and is complete). bool IsLocal(string path); /// Downloads the files that are not local yet. The task completes when all are local (or failed). Task RequestAsync(IEnumerable paths); /// Progress of the downloads of these files in [0..1], 1 if all are local. float GetProgress(IEnumerable paths); } /// The default provider: plain local files. public class CLocalSongFileProvider : ISongFileProvider { public bool Exists(string path) { return File.Exists(path); } public bool IsLocal(string path) { return File.Exists(path); } public Task RequestAsync(IEnumerable paths) { return Task.CompletedTask; } public float GetProgress(IEnumerable paths) { return 1f; } } public static class CSongFiles { public static ISongFileProvider Provider { get; set; } = new CLocalSongFileProvider(); public static bool Exists(string path) { return !string.IsNullOrEmpty(path) && Provider.Exists(path); } public static bool IsLocal(string path) { return !string.IsNullOrEmpty(path) && Provider.IsLocal(path); } public static bool AreLocal(IEnumerable paths) { return paths.All(IsLocal); } public static Task RequestAsync(IEnumerable paths) { var missing = paths.Where(p => !string.IsNullOrEmpty(p) && !Provider.IsLocal(p)).Distinct().ToList(); return missing.Count == 0 ? Task.CompletedTask : Provider.RequestAsync(missing); } /// Blocks until the file is local. Only for background threads (e.g. cover loading). public static bool EnsureLocal(string path) { if (IsLocal(path)) { return true; } if (!Exists(path)) { return false; } try { RequestAsync(new[] { path }).Wait(); } catch { // A failed download is reported by the provider; the caller handles the missing file. } return IsLocal(path); } public static float GetProgress(IEnumerable paths) { return Provider.GetProgress(paths.Where(p => !string.IsNullOrEmpty(p))); } } }