using System; using System.IO; using System.IO.Compression; using System.Net; using System.Net.Http; using System.Runtime.InteropServices; using System.Threading.Tasks; using Newtonsoft.Json; using SimpleHelper.Core; using Xabe.FFmpeg; namespace DVEServer.Core.ServiceModel.External { public class BaseBinaries { [JsonProperty(PropertyName = "ffmpeg")] public string Ffmpeg { get; set; } [JsonProperty(PropertyName = "ffplay")] public string Ffplay { get; set; } [JsonProperty(PropertyName = "ffprobe")] public string Ffprobe { get; set; } } public class Windows32 : BaseBinaries { } public class Windows64 : BaseBinaries { } public class Linux32 : BaseBinaries { } public class Linux64 : BaseBinaries { } public class LinuxArmhf : BaseBinaries { } public class LinuxArmel : BaseBinaries { } public class LinuxArm64 : BaseBinaries { } public class Osx64 { [JsonProperty(PropertyName = "ffmpeg")] public string Ffmpeg { get; set; } [JsonProperty(PropertyName = "ffplay")] public string Ffplay { get; set; } [JsonProperty(PropertyName = "ffprobe")] public string Ffprobe { get; set; } } public class Bin { [JsonProperty(PropertyName = "windows-32")] public Windows32 Windows32 { get; set; } [JsonProperty(PropertyName = "windows-64")] public Windows64 Windows64 { get; set; } [JsonProperty(PropertyName = "linux-32")] public Linux32 Linux32 { get; set; } [JsonProperty(PropertyName = "linux-64")] public Linux64 Linux64 { get; set; } [JsonProperty(PropertyName = "linux-armhf")] public LinuxArmhf LinuxArmhf { get; set; } [JsonProperty(PropertyName = "linux-armel")] public LinuxArmel LinuxArmel { get; set; } [JsonProperty(PropertyName = "linux-arm64")] public LinuxArm64 LinuxArm64 { get; set; } [JsonProperty(PropertyName = "osx-64")] public Osx64 Osx64 { get; set; } } public class DownloadedVersion { [JsonProperty(PropertyName = "version")] public string Version { get; set; } } public class LastestFfBinaries { [JsonProperty(PropertyName = "version")] public string Version { get; set; } [JsonProperty(PropertyName = "permalink")] public string Permalink { get; set; } [JsonProperty(PropertyName = "bin")] public Bin BinariesUrl { get; set; } /// /// Acquires the lastests binaries. /// public static void AcquireLastestsBinaries() { // Download lastest version of FFMpeg && FFProbe from "http://ffbinaries.com/api/v1/version/latest" using (var wc = new WebClient()) { var json = wc.DownloadString("http://ffbinaries.com/api/v1/version/latest"); var obj = JsonConvert.DeserializeObject(json); if (obj == null) return; if (!UpgradeIfNecessary(new Version(obj.Version))) return; // Download Files for os version DownloadApplications(obj); } } /// /// Downloads the applications. /// /// The object. private static void DownloadApplications(LastestFfBinaries obj) { var ffMpegZipPath = Path.Combine(Path.GetTempPath(), "FFMpeg.zip"); var ffProbeZipPath = Path.Combine(Path.GetTempPath(), "FFProbe.zip"); string urlFfmpeg = string.Empty, urlFfprobe = string.Empty; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (RuntimeInformation.OSArchitecture == Architecture.X64) { urlFfmpeg = obj.BinariesUrl.Windows64.Ffmpeg; urlFfprobe = obj.BinariesUrl.Windows64.Ffprobe; } else if (RuntimeInformation.OSArchitecture == Architecture.X64) { urlFfmpeg = obj.BinariesUrl.Windows32.Ffmpeg; urlFfprobe = obj.BinariesUrl.Windows32.Ffprobe; } } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { urlFfmpeg = obj.BinariesUrl.Osx64.Ffmpeg; urlFfprobe = obj.BinariesUrl.Osx64.Ffprobe; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { switch (RuntimeInformation.OSArchitecture) { case Architecture.X64: urlFfmpeg = obj.BinariesUrl.Linux64.Ffmpeg; urlFfprobe = obj.BinariesUrl.Linux64.Ffprobe; break; case Architecture.X86: urlFfmpeg = obj.BinariesUrl.Linux32.Ffmpeg; urlFfprobe = obj.BinariesUrl.Linux32.Ffprobe; break; case Architecture.Arm: urlFfmpeg = obj.BinariesUrl.LinuxArmhf.Ffmpeg; urlFfprobe = obj.BinariesUrl.LinuxArmhf.Ffprobe; break; case Architecture.Arm64: urlFfmpeg = obj.BinariesUrl.LinuxArm64.Ffmpeg; urlFfprobe = obj.BinariesUrl.LinuxArm64.Ffprobe; break; } // TODO : How to distinct Tizen / Raspberry architecture // Linux (Armet) (Tizen) // Linux (LinuxArmhf) (for glibc based OS) -> Raspberry Pi } if (!string.IsNullOrEmpty(urlFfmpeg) && DownloadFile(urlFfmpeg, ffMpegZipPath).Result) { ZipFile.ExtractToDirectory(ffMpegZipPath, FFbase.FFmpegDir, true); File.Delete(ffMpegZipPath); } if (!string.IsNullOrEmpty(urlFfprobe) && DownloadFile(urlFfprobe, ffProbeZipPath).Result) { ZipFile.ExtractToDirectory(ffProbeZipPath, FFbase.FFmpegDir, true); File.Delete(ffProbeZipPath); } // Clean Folder if (Directory.Exists(Path.Combine(FFbase.FFmpegDir, "__MACOSX"))) Directory.Delete(Path.Combine(FFbase.FFmpegDir, "__MACOSX"), true); // Save current version SaveVersion(obj); } /// /// Upgrades if necessary. /// /// The remote version. /// private static bool UpgradeIfNecessary(Version remoteVersion) { var versionPath = Path.Combine(FFbase.FFmpegDir, "version.json"); if (!File.Exists(versionPath)) return true; var obj = JsonConvert.DeserializeObject(File.ReadAllText(versionPath)); if (obj != null) { if (remoteVersion > new Version(obj.Version)) return true; } return false; } /// /// Saves the version. /// /// The object. private static void SaveVersion(LastestFfBinaries obj) { var versionPath = Path.Combine(FFbase.FFmpegDir, "version.json"); File.WriteAllText(versionPath, JsonConvert.SerializeObject(new DownloadedVersion() { Version = obj.Version }, Formatting.Indented)); } /// /// Downloads the file. /// /// The URL. /// The path. /// private static async Task DownloadFile(string url, string path) { using (var client = new HttpClient()) { using (var result = await client.GetAsync(url)) { if (!result.IsSuccessStatusCode) return false; var readedData = await result.Content.ReadAsByteArrayAsync(); if (readedData == null) return false; File.WriteAllBytes(path, readedData); return true; } } } } }