diff --git a/CRD/Downloader/Crunchyroll/CrunchyrollManager.cs b/CRD/Downloader/Crunchyroll/CrunchyrollManager.cs index 7fb5767..cc4272c 100644 --- a/CRD/Downloader/Crunchyroll/CrunchyrollManager.cs +++ b/CRD/Downloader/Crunchyroll/CrunchyrollManager.cs @@ -516,6 +516,12 @@ public class CrunchyrollManager{ } catch (Exception exception){ Console.Error.WriteLine("Failed to play sound: " + exception); } + + if (CrunOptions.ShutdownWhenQueueEmpty){ + Helpers.ShutdownComputer(); + } + + } return true; @@ -603,7 +609,7 @@ public class CrunchyrollManager{ if (data.FindAll(a => a.Type == DownloadMediaType.Audio).Count > 0){ if (options.Mp3){ Console.WriteLine("Mux to MP3"); - muxToMp3 = true; + muxToMp3 = true; } } else{ Console.WriteLine("Skip muxing since no videos are downloaded"); @@ -647,9 +653,9 @@ public class CrunchyrollManager{ var merger = new Merger(new MergerOptions{ DubLangList = options.DubLangList, SubLangList = options.SubLangList, - OnlyVid = data.Where(a => a.Type == DownloadMediaType.Video).Select(a => new MergerInput{ Language = a.Lang, Path = a.Path ?? string.Empty ,Bitrate = a.bitrate}).ToList(), + OnlyVid = data.Where(a => a.Type == DownloadMediaType.Video).Select(a => new MergerInput{ Language = a.Lang, Path = a.Path ?? string.Empty, Bitrate = a.bitrate }).ToList(), SkipSubMux = options.SkipSubMux, - OnlyAudio = data.Where(a => a.Type == DownloadMediaType.Audio).Select(a => new MergerInput{ Language = a.Lang, Path = a.Path ?? string.Empty ,Bitrate = a.bitrate}).ToList(), + OnlyAudio = data.Where(a => a.Type == DownloadMediaType.Audio).Select(a => new MergerInput{ Language = a.Lang, Path = a.Path ?? string.Empty, Bitrate = a.bitrate }).ToList(), Output = $"{filename}.{(muxToMp3 ? "mp3" : options.Mp4 ? "mp4" : "mkv")}", Subtitles = data.Where(a => a.Type == DownloadMediaType.Subtitle).Select(a => new SubtitleInput { File = a.Path ?? string.Empty, Language = a.Language, ClosedCaption = a.Cc ?? false, Signs = a.Signs ?? false, RelatedVideoDownloadMedia = a.RelatedVideoDownloadMedia }).ToList(), @@ -920,7 +926,7 @@ public class CrunchyrollManager{ if (mediaGuid.Contains(':')){ mediaGuid = mediaGuid.Split(':')[1]; } - + Console.WriteLine("MediaGuid: " + mediaId); #region Chapters @@ -937,7 +943,7 @@ public class CrunchyrollManager{ } #endregion - + var fetchPlaybackData = await FetchPlaybackData(options.StreamEndpoint ?? "web/firefox", mediaId, mediaGuid, data.Music); (bool IsOk, PlaybackData pbData, string error) fetchPlaybackData2 = default; if (!string.IsNullOrEmpty(options.StreamEndpointSecondary) && !(options.StreamEndpoint ?? "web/firefox").Equals(options.StreamEndpointSecondary)){ @@ -989,18 +995,30 @@ public class CrunchyrollManager{ ErrorText = "Playback data not found" }; } - + if (fetchPlaybackData2.IsOk){ - if (fetchPlaybackData.pbData.Data != null) - foreach (var keyValuePair in fetchPlaybackData.pbData.Data){ - var value = fetchPlaybackData2.pbData?.Data?[keyValuePair.Key]; - var url = value?.Url.First() ?? ""; + if (fetchPlaybackData.pbData.Data != null && fetchPlaybackData2.pbData?.Data != null) + foreach (var keyValuePair in fetchPlaybackData2.pbData.Data){ + var pbDataFirstEndpoint = fetchPlaybackData.pbData?.Data; + if (pbDataFirstEndpoint != null && pbDataFirstEndpoint.TryGetValue(keyValuePair.Key, out var value)){ + var urlSecondEndpoint = keyValuePair.Value.Url.First() ?? ""; - var match = Regex.Match(url, @"(.*\.urlset\/)"); - var shortendUrl = match.Success ? match.Value : url; + var match = Regex.Match(urlSecondEndpoint, @"(https?:\/\/.*?\/(?:dash\/|\.urlset\/))"); + var shortendUrl = match.Success ? match.Value : urlSecondEndpoint; - if (!keyValuePair.Value.Url.Any(arrayUrl => arrayUrl != null && arrayUrl.Contains(shortendUrl))){ - keyValuePair.Value.Url.Add(url); + if (!value.Url.Any(arrayUrl => arrayUrl != null && arrayUrl.Contains(shortendUrl))){ + value.Url.Add(urlSecondEndpoint); + } + } else{ + if (pbDataFirstEndpoint != null){ + pbDataFirstEndpoint[keyValuePair.Key] = keyValuePair.Value; + } else{ + if (fetchPlaybackData.pbData != null){ + fetchPlaybackData.pbData.Data = new Dictionary{ + [keyValuePair.Key] = keyValuePair.Value + }; + } + } } } } @@ -1158,21 +1176,19 @@ public class CrunchyrollManager{ Console.WriteLine("Downloading video..."); curStream = streams[options.Kstream - 1]; - Console.WriteLine($"Playlists URL: {string.Join(", ",curStream.Url)} ({curStream.Type})"); + Console.WriteLine($"Playlists URL: {string.Join(", ", curStream.Url)} ({curStream.Type})"); } string tsFile = ""; var videoDownloadMedia = new DownloadedMedia(){ Lang = Languages.DEFAULT_lang }; if (!dlFailed && curStream != null && options is not{ Novids: true, Noaudio: true }){ - - Dictionary streamPlaylistsReqResponseList =[]; foreach (var streamUrl in curStream.Url){ var streamPlaylistsReq = HttpClientReq.CreateRequestMessage(streamUrl ?? string.Empty, HttpMethod.Get, true, true, null); var streamPlaylistsReqResponse = await HttpClientReq.Instance.SendHttpRequest(streamPlaylistsReq); - + if (!streamPlaylistsReqResponse.IsOk){ dlFailed = true; return new DownloadResponse{ @@ -1185,9 +1201,9 @@ public class CrunchyrollManager{ if (streamPlaylistsReqResponse.ResponseContent.Contains("MPD")){ streamPlaylistsReqResponseList[streamUrl ?? ""] = streamPlaylistsReqResponse.ResponseContent; - } + } } - + //Use again when cr has all endpoints with new encoding // var streamPlaylistsReq = HttpClientReq.CreateRequestMessage(curStream.Url ?? string.Empty, HttpMethod.Get, true, true, null); // @@ -1223,18 +1239,23 @@ public class CrunchyrollManager{ Dictionary playListData = new Dictionary(); foreach (var curStreams in streamPlaylistsReqResponseList){ - var match = Regex.Match(curStreams.Key ?? string.Empty, @"(.*\.urlset\/)"); + var match = Regex.Match(curStreams.Key ?? string.Empty, @"(https?:\/\/.*?\/(?:dash\/|\.urlset\/))"); var matchedUrl = match.Success ? match.Value : null; //Parse MPD Playlists var crLocal = ""; if (pbData.Meta != null){ crLocal = pbData.Meta.AudioLocale.CrLocale; } - MPDParsed streamPlaylists = MPDParser.Parse(curStreams.Value, Languages.FindLang(crLocal), matchedUrl); - streamServers.UnionWith(streamPlaylists.Data.Keys); - Helpers.MergePlaylistData(playListData, streamPlaylists.Data); + + try{ + MPDParsed streamPlaylists = MPDParser.Parse(curStreams.Value, Languages.FindLang(crLocal), matchedUrl); + streamServers.UnionWith(streamPlaylists.Data.Keys); + Helpers.MergePlaylistData(playListData, streamPlaylists.Data); + } catch (Exception e){ + Console.Error.WriteLine(e); + } } - + options.StreamServer = options.StreamServer > streamServers.Count ? 1 : options.StreamServer; if (streamServers.Count == 0){ @@ -1252,7 +1273,7 @@ public class CrunchyrollManager{ // string selectedServer = streamServers[options.StreamServer - 1]; // ServerData selectedList = streamPlaylists.Data[selectedServer]; - + string selectedServer = streamServers.ToList()[options.StreamServer - 1]; ServerData selectedList = playListData[selectedServer]; @@ -1380,7 +1401,7 @@ public class CrunchyrollManager{ Console.WriteLine("Stream URL:" + chosenVideoSegments.segments[0].uri.Split(new[]{ ",.urlset" }, StringSplitOptions.None)[0]); - fileName = Path.Combine(FileNameManager.ParseFileName(options.FileName, variables, options.Numbers,options.FileNameWhitespaceSubstitute, options.Override).ToArray()); + fileName = Path.Combine(FileNameManager.ParseFileName(options.FileName, variables, options.Numbers, options.FileNameWhitespaceSubstitute, options.Override).ToArray()); string onlyFileName = Path.GetFileName(fileName); int maxLength = 220; @@ -1395,7 +1416,7 @@ public class CrunchyrollManager{ if (excessLength > 0 && ((string)titleVariable.ReplaceWith).Length > excessLength){ titleVariable.ReplaceWith = ((string)titleVariable.ReplaceWith).Substring(0, ((string)titleVariable.ReplaceWith).Length - excessLength); - fileName = Path.Combine(FileNameManager.ParseFileName(options.FileName, variables, options.Numbers,options.FileNameWhitespaceSubstitute, options.Override).ToArray()); + fileName = Path.Combine(FileNameManager.ParseFileName(options.FileName, variables, options.Numbers, options.FileNameWhitespaceSubstitute, options.Override).ToArray()); onlyFileName = Path.GetFileName(fileName); if (onlyFileName.Length > maxLength){ @@ -1414,7 +1435,8 @@ public class CrunchyrollManager{ string outFile = fileName + "." + (epMeta.Lang?.CrLocale ?? lang.CrLocale); string tempFile = Path.Combine(FileNameManager - .ParseFileName($"temp-{(!string.IsNullOrEmpty(currentVersion.Guid) ? currentVersion.Guid : currentMediaId)}", variables, options.Numbers,options.FileNameWhitespaceSubstitute, options.Override) + .ParseFileName($"temp-{(!string.IsNullOrEmpty(currentVersion.Guid) ? currentVersion.Guid : currentMediaId)}", variables, options.Numbers, options.FileNameWhitespaceSubstitute, + options.Override) .ToArray()); string tempTsFile = Path.IsPathRooted(tempFile) ? tempFile : Path.Combine(fileDir, tempFile); @@ -1718,7 +1740,7 @@ public class CrunchyrollManager{ } } } else if (options.Novids){ - fileName = Path.Combine(FileNameManager.ParseFileName(options.FileName, variables, options.Numbers,options.FileNameWhitespaceSubstitute, options.Override).ToArray()); + fileName = Path.Combine(FileNameManager.ParseFileName(options.FileName, variables, options.Numbers, options.FileNameWhitespaceSubstitute, options.Override).ToArray()); Console.WriteLine("Downloading skipped!"); } } @@ -1726,14 +1748,15 @@ public class CrunchyrollManager{ variables.Add(new Variable("height", 360, false)); variables.Add(new Variable("width", 640, false)); - fileName = Path.Combine(FileNameManager.ParseFileName(options.FileName, variables, options.Numbers,options.FileNameWhitespaceSubstitute, options.Override).ToArray()); + fileName = Path.Combine(FileNameManager.ParseFileName(options.FileName, variables, options.Numbers, options.FileNameWhitespaceSubstitute, options.Override).ToArray()); } if (compiledChapters.Count > 0 && options is not{ Novids: true, Noaudio: true }){ try{ // Parsing and constructing the file names - fileName = Path.Combine(FileNameManager.ParseFileName(options.FileName, variables, options.Numbers,options.FileNameWhitespaceSubstitute, options.Override).ToArray()); - var outFile = Path.Combine(FileNameManager.ParseFileName(options.FileName + "." + (epMeta.Lang?.CrLocale), variables, options.Numbers,options.FileNameWhitespaceSubstitute, options.Override).ToArray()); + fileName = Path.Combine(FileNameManager.ParseFileName(options.FileName, variables, options.Numbers, options.FileNameWhitespaceSubstitute, options.Override).ToArray()); + var outFile = Path.Combine(FileNameManager.ParseFileName(options.FileName + "." + (epMeta.Lang?.CrLocale), variables, options.Numbers, options.FileNameWhitespaceSubstitute, options.Override) + .ToArray()); if (Path.IsPathRooted(outFile)){ tsFile = outFile; } else{ @@ -1855,7 +1878,7 @@ public class CrunchyrollManager{ Error = dlFailed, FileName = fileName.Length > 0 ? fileName : "unknown - " + Guid.NewGuid(), ErrorText = "", - VideoTitle = FileNameManager.ParseFileName(options.VideoTitle ?? "", variables, options.Numbers,options.FileNameWhitespaceSubstitute, options.Override).Last(), + VideoTitle = FileNameManager.ParseFileName(options.VideoTitle ?? "", variables, options.Numbers, options.FileNameWhitespaceSubstitute, options.Override).Last(), FolderPath = fileDir, TempFolderPath = tempFolderPath }; @@ -1864,6 +1887,10 @@ public class CrunchyrollManager{ private static async Task DownloadSubtitles(CrDownloadOptions options, PlaybackData pbData, LanguageItem audDub, string fileName, List files, string fileDir, CrunchyEpMeta data, DownloadedMedia videoDownloadMedia){ if (pbData.Meta != null && (pbData.Meta.Subtitles is{ Count: > 0 } || pbData.Meta.Captions is{ Count: > 0 })){ + if (videoDownloadMedia.Lang == Languages.DEFAULT_lang){ + videoDownloadMedia.Lang = pbData.Meta.AudioLocale; + } + List subsData = pbData.Meta.Subtitles?.Values.ToList() ??[]; List capsData = pbData.Meta.Captions?.Values.ToList() ??[]; var subsDataMapped = subsData.Select(s => { @@ -1899,20 +1926,31 @@ public class CrunchyrollManager{ sxData.Language = langItem; var isSigns = langItem.CrLocale == audDub.CrLocale && !subsItem.isCC; var isCc = subsItem.isCC; + var isDuplicate = false; - sxData.File = Languages.SubsFile(fileName, index + "", langItem, isCc, options.CcTag, isSigns, subsItem.format, !(data.DownloadSubs.Count == 1 && !data.DownloadSubs.Contains("all"))); + + + if ((!options.IncludeSignsSubs && isSigns) || (!options.IncludeCcSubs && isCc)){ + continue; + } + + var matchingSubs = files.Where(a => a.Type == DownloadMediaType.Subtitle && + (a.Language.CrLocale == langItem.CrLocale || a.Language.Locale == langItem.Locale) && + a.Cc == isCc && + a.Signs == isSigns).ToList(); + + if (matchingSubs.Count > 0){ + isDuplicate = true; + if (!options.SubsDownloadDuplicate || matchingSubs.Any(a => a.RelatedVideoDownloadMedia?.Lang == videoDownloadMedia.Lang)){ + continue; + } + } + + sxData.File = Languages.SubsFile(fileName, index + "", langItem, isDuplicate ? videoDownloadMedia.Lang.CrLocale : "",isCc, options.CcTag, isSigns, subsItem.format, !(data.DownloadSubs.Count == 1 && !data.DownloadSubs.Contains("all"))); sxData.Path = Path.Combine(fileDir, sxData.File); Helpers.EnsureDirectoriesExist(sxData.Path); - // Check if any file matches the specified conditions - if (files.Any(a => a.Type == DownloadMediaType.Subtitle && - (a.Language.CrLocale == langItem.CrLocale || a.Language.Locale == langItem.Locale) && - a.Cc == isCc && - a.Signs == isSigns) || (!options.IncludeSignsSubs && isSigns) || (!options.IncludeCcSubs && isCc)){ - continue; - } - if (data.DownloadSubs.Contains("all") || data.DownloadSubs.Contains(langItem.CrLocale)){ if (string.IsNullOrEmpty(subsItem.url)){ continue; @@ -1953,6 +1991,12 @@ public class CrunchyrollManager{ assBuilder.AppendLine("PlayResX: 640"); assBuilder.AppendLine("PlayResY: 360"); assBuilder.AppendLine("Timer: 0.0"); + if (options.SubsAddScaledBorder == ScaledBorderAndShadowSelection.ScaledBorderAndShadowYes){ + assBuilder.AppendLine("ScaledBorderAndShadow: yes"); + } else if (options.SubsAddScaledBorder == ScaledBorderAndShadowSelection.ScaledBorderAndShadowNo){ + assBuilder.AppendLine("ScaledBorderAndShadow: no"); + } + assBuilder.AppendLine(); assBuilder.AppendLine("[V4+ Styles]"); assBuilder.AppendLine("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, " @@ -2197,7 +2241,7 @@ public class CrunchyrollManager{ foreach (var hardsub in playStream.HardSubs){ var stream = hardsub.Value; derivedPlayCrunchyStreams[hardsub.Key] = new StreamDetails{ - Url = [stream.Url], + Url =[stream.Url], IsHardsubbed = true, HardsubLocale = stream.Hlang, HardsubLang = Languages.FixAndFindCrLc((stream.Hlang ?? Locale.DefaulT).GetEnumMemberValue()) @@ -2206,7 +2250,7 @@ public class CrunchyrollManager{ } derivedPlayCrunchyStreams[""] = new StreamDetails{ - Url = [playStream.Url], + Url =[playStream.Url], IsHardsubbed = false, HardsubLocale = Locale.DefaulT, HardsubLang = Languages.DEFAULT_lang diff --git a/CRD/Downloader/Crunchyroll/ViewModels/CrunchyrollSettingsViewModel.cs b/CRD/Downloader/Crunchyroll/ViewModels/CrunchyrollSettingsViewModel.cs index 84242cd..4367077 100644 --- a/CRD/Downloader/Crunchyroll/ViewModels/CrunchyrollSettingsViewModel.cs +++ b/CRD/Downloader/Crunchyroll/ViewModels/CrunchyrollSettingsViewModel.cs @@ -40,7 +40,10 @@ public partial class CrunchyrollSettingsViewModel : ViewModelBase{ [ObservableProperty] private bool _addScaledBorderAndShadow; - + + [ObservableProperty] + private bool _subsDownloadDuplicate; + [ObservableProperty] private bool _includeSignSubs; @@ -332,6 +335,7 @@ public partial class CrunchyrollSettingsViewModel : ViewModelBase{ AddScaledBorderAndShadow = options.SubsAddScaledBorder is ScaledBorderAndShadowSelection.ScaledBorderAndShadowNo or ScaledBorderAndShadowSelection.ScaledBorderAndShadowYes; SelectedScaledBorderAndShadow = GetScaledBorderAndShadowFromOptions(options); + SubsDownloadDuplicate = options.SubsDownloadDuplicate; MarkAsWatched = options.MarkAsWatched; DownloadFirstAvailableDub = options.DownloadFirstAvailableDub; UseCrBetaApi = options.UseCrBetaApi; @@ -402,6 +406,7 @@ public partial class CrunchyrollSettingsViewModel : ViewModelBase{ return; } + CrunchyrollManager.Instance.CrunOptions.SubsDownloadDuplicate = SubsDownloadDuplicate; CrunchyrollManager.Instance.CrunOptions.MarkAsWatched = MarkAsWatched; CrunchyrollManager.Instance.CrunOptions.DownloadFirstAvailableDub = DownloadFirstAvailableDub; CrunchyrollManager.Instance.CrunOptions.UseCrBetaApi = UseCrBetaApi; diff --git a/CRD/Downloader/Crunchyroll/Views/CrunchyrollSettingsView.axaml b/CRD/Downloader/Crunchyroll/Views/CrunchyrollSettingsView.axaml index 8b54821..12f434e 100644 --- a/CRD/Downloader/Crunchyroll/Views/CrunchyrollSettingsView.axaml +++ b/CRD/Downloader/Crunchyroll/Views/CrunchyrollSettingsView.axaml @@ -105,6 +105,12 @@ + + + + + + diff --git a/CRD/Utils/Helpers.cs b/CRD/Utils/Helpers.cs index 1d94792..158cf84 100644 --- a/CRD/Utils/Helpers.cs +++ b/CRD/Utils/Helpers.cs @@ -8,6 +8,7 @@ using System.Net.Http; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; @@ -21,6 +22,7 @@ using CRD.Utils.HLS; using CRD.Utils.JsonConv; using CRD.Utils.Structs; using CRD.Utils.Structs.Crunchyroll; +using FluentAvalonia.UI.Controls; using Microsoft.Win32; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; @@ -806,4 +808,56 @@ public class Helpers{ } } } + + private static readonly SemaphoreSlim ShutdownLock = new(1, 1); + + public static async Task ShutdownComputer(){ + if (!await ShutdownLock.WaitAsync(0)) + return; + try{ + var timer = new System.Timers.Timer(30000); // 30 seconds + timer.Elapsed += (sender, e) => { PerformShutdown(); }; + timer.AutoReset = false; + timer.Start(); + + var dialog = new ContentDialog{ + Title = "Shutdown Pending", + Content = "The PC will shut down in 30 seconds.\nClick 'Cancel' to abort.", + PrimaryButtonText = "Cancel Shutdown", + CloseButtonText = "Close", + DefaultButton = ContentDialogButton.Primary + }; + + var result = await dialog.ShowAsync(); + + if (result == ContentDialogResult.Primary){ + timer.Stop(); + } + } finally{ + ShutdownLock.Release(); + } + } + + private static void PerformShutdown(){ + string shutdownCmd; + string shutdownArgs; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)){ + shutdownCmd = "shutdown"; + shutdownArgs = "/s /t 0"; + } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX)){ + shutdownCmd = "shutdown"; + shutdownArgs = "-h now"; + } else{ + throw new PlatformNotSupportedException(); + } + + Process.Start(new ProcessStartInfo{ + FileName = shutdownCmd, + Arguments = shutdownArgs, + CreateNoWindow = true, + UseShellExecute = false + }); + } } \ No newline at end of file diff --git a/CRD/Utils/Muxing/FontsManager.cs b/CRD/Utils/Muxing/FontsManager.cs index 7ae82b8..b2bede7 100644 --- a/CRD/Utils/Muxing/FontsManager.cs +++ b/CRD/Utils/Muxing/FontsManager.cs @@ -52,6 +52,7 @@ public class FontsManager{ { "Times New Roman", new List{ "times.ttf", "timesbd.ttf", "timesbi.ttf", "timesi.ttf" } }, { "Trebuchet MS", new List{ "trebuc.ttf", "trebucbd.ttf", "trebucbi.ttf", "trebucit.ttf" } }, { "Verdana", new List{ "verdana.ttf", "verdanab.ttf", "verdanai.ttf", "verdanaz.ttf" } }, + { "Vrinda", new List{ "vrinda.ttf", "vrindab.ttf"} }, { "Webdings", new List{ "webdings.ttf" } }, }; diff --git a/CRD/Utils/Parser/M3u8/ToM3u8Class.cs b/CRD/Utils/Parser/M3u8/ToM3u8Class.cs index ec44ace..c558e8d 100644 --- a/CRD/Utils/Parser/M3u8/ToM3u8Class.cs +++ b/CRD/Utils/Parser/M3u8/ToM3u8Class.cs @@ -378,7 +378,7 @@ public class ToM3u8Class{ var language = ObjectUtilities.GetMemberValue(playlist.attributes, "lang") ?? string.Empty; var label = ObjectUtilities.GetMemberValue(playlist.attributes, "label") ?? "main"; - if (!string.IsNullOrEmpty(language) && string.IsNullOrEmpty(playlist.attributes.label)){ + if (!string.IsNullOrEmpty(language) && string.IsNullOrEmpty(label)){ var roleLabel = !string.IsNullOrEmpty(role) ? $" ({role})" : string.Empty; label = $"{language}{roleLabel}"; } diff --git a/CRD/Utils/Parser/MPDTransformer.cs b/CRD/Utils/Parser/MPDTransformer.cs index b695741..9e8da0c 100644 --- a/CRD/Utils/Parser/MPDTransformer.cs +++ b/CRD/Utils/Parser/MPDTransformer.cs @@ -87,7 +87,7 @@ public static class MPDParser{ throw new NotImplementedException(); } - var foundLanguage = Languages.FindLang(Languages.languages.FirstOrDefault(a => a.Code == item.language)?.CrLocale ?? "unknown"); + var foundLanguage = Languages.FindLang(Languages.languages.FirstOrDefault(a => a.CrLocale == item.language)?.CrLocale ?? "unknown"); LanguageItem? audioLang = item.language != null ? foundLanguage : (language != null ? language : foundLanguage); var pItem = new AudioPlaylist{ diff --git a/CRD/Utils/Sonarr/SonarrClient.cs b/CRD/Utils/Sonarr/SonarrClient.cs index 8472e0c..cd9120c 100644 --- a/CRD/Utils/Sonarr/SonarrClient.cs +++ b/CRD/Utils/Sonarr/SonarrClient.cs @@ -54,7 +54,7 @@ public class SonarrClient{ CrunchyrollManager.Instance.History.MatchHistorySeriesWithSonarr(true); foreach (var historySeries in CrunchyrollManager.Instance.HistoryList){ - if (historySeries.SonarrSeriesId != null){ + if (!string.IsNullOrEmpty(historySeries.SonarrSeriesId)){ List? episodes = await GetEpisodes(int.Parse(historySeries.SonarrSeriesId)); historySeries.SonarrNextAirDate = CrunchyrollManager.Instance.History.GetNextAirDate(episodes); } diff --git a/CRD/Utils/Structs/Crunchyroll/CrDownloadOptions.cs b/CRD/Utils/Structs/Crunchyroll/CrDownloadOptions.cs index 93b134d..d55dbbb 100644 --- a/CRD/Utils/Structs/Crunchyroll/CrDownloadOptions.cs +++ b/CRD/Utils/Structs/Crunchyroll/CrDownloadOptions.cs @@ -9,6 +9,9 @@ namespace CRD.Utils.Structs.Crunchyroll; public class CrDownloadOptions{ #region General Settings + [JsonProperty("shutdown_when_queue_empty")] + public bool ShutdownWhenQueueEmpty{ get; set; } + [JsonProperty("auto_download")] public bool AutoDownload{ get; set; } @@ -179,6 +182,9 @@ public class CrDownloadOptions{ [JsonProperty("subs_add_scaled_border")] public ScaledBorderAndShadowSelection SubsAddScaledBorder{ get; set; } + [JsonProperty("subs_download_duplicate")] + public bool SubsDownloadDuplicate{ get; set; } + [JsonProperty("include_signs_subs")] public bool IncludeSignsSubs{ get; set; } diff --git a/CRD/Utils/Structs/Languages.cs b/CRD/Utils/Structs/Languages.cs index 9c5baf0..9a57e72 100644 --- a/CRD/Utils/Structs/Languages.cs +++ b/CRD/Utils/Structs/Languages.cs @@ -90,10 +90,14 @@ public class Languages{ return FindLang(str); } - public static string SubsFile(string fnOutput, string subsIndex, LanguageItem langItem, bool isCC, string ccTag, bool? isSigns = false, string? format = "ass", bool addIndexAndLangCode = true){ + public static string SubsFile(string fnOutput, string subsIndex, LanguageItem langItem,string insert, bool isCC, string ccTag, bool? isSigns = false, string? format = "ass", bool addIndexAndLangCode = true){ subsIndex = (int.Parse(subsIndex) + 1).ToString().PadLeft(2, '0'); string fileName = $"{fnOutput}"; + if (!string.IsNullOrEmpty(insert)){ + fileName += $".{insert}"; + } + if (addIndexAndLangCode){ fileName += $".{langItem.Locale}"; //.{subsIndex} } diff --git a/CRD/ViewModels/DownloadsPageViewModel.cs b/CRD/ViewModels/DownloadsPageViewModel.cs index bb5d20f..23a3024 100644 --- a/CRD/ViewModels/DownloadsPageViewModel.cs +++ b/CRD/ViewModels/DownloadsPageViewModel.cs @@ -19,6 +19,9 @@ namespace CRD.ViewModels; public partial class DownloadsPageViewModel : ViewModelBase{ public ObservableCollection Items{ get; } + [ObservableProperty] + private bool _shutdownWhenQueueEmpty; + [ObservableProperty] private bool _autoDownload; @@ -34,6 +37,7 @@ public partial class DownloadsPageViewModel : ViewModelBase{ Items = QueueManagerIns.DownloadItemModels; AutoDownload = CrunchyrollManager.Instance.CrunOptions.AutoDownload; RemoveFinished = CrunchyrollManager.Instance.CrunOptions.RemoveFinishedDownload; + ShutdownWhenQueueEmpty = CrunchyrollManager.Instance.CrunOptions.ShutdownWhenQueueEmpty; } @@ -51,6 +55,11 @@ public partial class DownloadsPageViewModel : ViewModelBase{ CfgManager.WriteCrSettings(); } + partial void OnShutdownWhenQueueEmptyChanged(bool value){ + CrunchyrollManager.Instance.CrunOptions.ShutdownWhenQueueEmpty = value; + CfgManager.WriteCrSettings(); + } + [RelayCommand] public void ClearQueue(){ var items = QueueManagerIns.Queue; diff --git a/CRD/Views/DownloadsPageView.axaml b/CRD/Views/DownloadsPageView.axaml index d118730..0cd28df 100644 --- a/CRD/Views/DownloadsPageView.axaml +++ b/CRD/Views/DownloadsPageView.axaml @@ -23,6 +23,11 @@ + + + + +