From 51e3102503dd5b28aa920e8a7e14564dad5e11e5 Mon Sep 17 00:00:00 2001 From: Elwador <75888166+Elwador@users.noreply.github.com> Date: Sun, 5 Jan 2025 02:10:52 +0100 Subject: [PATCH] Add - Added sorting to seasons tab Add - Added a download subs button to the history Chg - Changed CDM error message to include a GitHub wiki link Chg - Changed the style of settings tabs Chg - Changed the date format in the seasons tab Fix - Fixed Crunchyroll seasons numbering issue (e.g., Blue Exorcist) Fix - Fixed window slightly moving on startup Fix - Fixed a bug in the upcoming episodes display for the next week --- CRD/Downloader/CalendarManager.cs | 115 ++++++++++++------ .../Crunchyroll/CrunchyrollManager.cs | 111 +++++++++-------- CRD/Downloader/History.cs | 4 +- CRD/Downloader/QueueManager.cs | 16 ++- CRD/Styling/ControlsGalleryStyles.axaml | 7 +- CRD/Utils/DRM/Widevine.cs | 2 + CRD/Utils/Helpers.cs | 27 ++-- CRD/Utils/Muxing/Merger.cs | 1 + CRD/Utils/Structs/AnilistUpcoming.cs | 43 +++++-- .../Structs/Crunchyroll/CrDownloadOptions.cs | 8 +- .../Crunchyroll/Episode/EpisodeStructs.cs | 2 + CRD/Utils/Structs/History/HistoryEpisode.cs | 12 +- CRD/ViewModels/CalendarPageViewModel.cs | 13 ++ CRD/ViewModels/DownloadsPageViewModel.cs | 10 +- CRD/ViewModels/HistoryPageViewModel.cs | 12 +- CRD/ViewModels/SeriesPageViewModel.cs | 2 +- CRD/ViewModels/SettingsPageViewModel.cs | 1 + .../UpcomingSeasonsPageViewModel.cs | 104 +++++++++++++++- CRD/Views/CalendarPageView.axaml | 6 +- CRD/Views/MainWindow.axaml.cs | 18 ++- CRD/Views/SeriesPageView.axaml | 103 +++++++++------- CRD/Views/SeriesPageView.axaml.cs | 3 + CRD/Views/SettingsPageView.axaml | 19 ++- CRD/Views/UpcomingSeasonsPageView.axaml | 104 +++++++++++++--- CRD/Views/Utils/GeneralSettingsView.axaml | 2 +- 25 files changed, 540 insertions(+), 205 deletions(-) diff --git a/CRD/Downloader/CalendarManager.cs b/CRD/Downloader/CalendarManager.cs index 64affd5..8ecf115 100644 --- a/CRD/Downloader/CalendarManager.cs +++ b/CRD/Downloader/CalendarManager.cs @@ -153,7 +153,9 @@ public class CalendarManager{ public async Task BuildCustomCalendar(DateTime calTargetDate, bool forceUpdate){ - await LoadAnilistUpcoming(); + if (CrunchyrollManager.Instance.CrunOptions.CalendarShowUpcomingEpisodes){ + await LoadAnilistUpcoming(); + } if (!forceUpdate && calendar.TryGetValue("C" + calTargetDate.ToString("yyyy-MM-dd"), out var forDate)){ return forDate; @@ -303,15 +305,16 @@ public class CalendarManager{ } } + if (CrunchyrollManager.Instance.CrunOptions.CalendarShowUpcomingEpisodes){ + foreach (var calendarDay in week.CalendarDays){ + if (calendarDay.DateTime.Date >= DateTime.Now.Date){ + if (ProgramManager.Instance.AnilistUpcoming.ContainsKey(calendarDay.DateTime.ToString("yyyy-MM-dd"))){ + var list = ProgramManager.Instance.AnilistUpcoming[calendarDay.DateTime.ToString("yyyy-MM-dd")]; - foreach (var calendarDay in week.CalendarDays){ - if (calendarDay.DateTime.Date >= DateTime.Now.Date){ - if (ProgramManager.Instance.AnilistUpcoming.ContainsKey(calendarDay.DateTime.ToString("yyyy-MM-dd"))){ - var list = ProgramManager.Instance.AnilistUpcoming[calendarDay.DateTime.ToString("yyyy-MM-dd")]; - - foreach (var calendarEpisode in list.Where(calendarEpisode => calendarDay.DateTime.Date == calendarEpisode.DateTime.Date) - .Where(calendarEpisode => calendarDay.CalendarEpisodes.All(ele => ele.CrSeriesID != calendarEpisode.CrSeriesID))){ - calendarDay.CalendarEpisodes.Add(calendarEpisode); + foreach (var calendarEpisode in list.Where(calendarEpisode => calendarDay.DateTime.Date == calendarEpisode.DateTime.Date) + .Where(calendarEpisode => calendarDay.CalendarEpisodes.All(ele => ele.CrSeriesID != calendarEpisode.CrSeriesID))){ + calendarDay.CalendarEpisodes.Add(calendarEpisode); + } } } } @@ -320,7 +323,8 @@ public class CalendarManager{ foreach (var weekCalendarDay in week.CalendarDays){ if (weekCalendarDay.CalendarEpisodes.Count > 0) weekCalendarDay.CalendarEpisodes = weekCalendarDay.CalendarEpisodes - .OrderBy(e => e.DateTime) + .OrderBy(e => e.AnilistEpisode) // False first, then true + .ThenBy(e => e.DateTime) .ThenBy(e => e.SeasonName) .ThenBy(e => { double parsedNumber; @@ -331,9 +335,9 @@ public class CalendarManager{ } - foreach (var day in week.CalendarDays){ - if (day.CalendarEpisodes != null) day.CalendarEpisodes = day.CalendarEpisodes.OrderBy(e => e.DateTime).ToList(); - } + // foreach (var day in week.CalendarDays){ + // if (day.CalendarEpisodes != null) day.CalendarEpisodes = day.CalendarEpisodes.OrderBy(e => e.DateTime).ToList(); + // } calendar["C" + calTargetDate.ToString("yyyy-MM-dd")] = week; @@ -437,38 +441,32 @@ public class CalendarManager{ if (match.Success){ crunchyrollID = match.Groups[1].Value; - calEp.CrSeriesID = crunchyrollID; + AdjustReleaseTimeToHistory(calEp, crunchyrollID); + } else{ + Uri uri = new Uri(url); - if (CrunchyrollManager.Instance.CrunOptions.History){ - var historySeries = CrunchyrollManager.Instance.HistoryList.FirstOrDefault(item => item.SeriesId == crunchyrollID); + if (uri.Host == "www.crunchyroll.com" + && uri.AbsolutePath != "/" + && (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)){ + HttpRequestMessage getUrlRequest = new HttpRequestMessage(HttpMethod.Head, url); - if (historySeries != null){ - var oldestRelease = DateTime.MinValue; - foreach (var historySeriesSeason in historySeries.Seasons){ - if (historySeriesSeason.EpisodesList.Any()){ - var releaseDate = historySeriesSeason.EpisodesList.Last().EpisodeCrPremiumAirDate; + string? finalUrl = ""; - if (releaseDate.HasValue && oldestRelease < releaseDate.Value){ - oldestRelease = releaseDate.Value; - } - } - } + try{ + HttpResponseMessage getUrlResponse = await HttpClientReq.Instance.GetHttpClient().SendAsync(getUrlRequest); - if (oldestRelease != DateTime.MinValue){ - calEp.DateTime = new DateTime( - calEp.DateTime.Year, - calEp.DateTime.Month, - calEp.DateTime.Day, - oldestRelease.Hour, - oldestRelease.Minute, - oldestRelease.Second, - calEp.DateTime.Kind - ); - } + finalUrl = getUrlResponse.RequestMessage?.RequestUri?.ToString(); + } catch (Exception ex){ + Console.WriteLine($"Error: {ex.Message}"); + } + + Match match2 = Regex.Match(finalUrl ?? string.Empty, pattern); + if (match2.Success){ + crunchyrollID = match2.Groups[1].Value; + + AdjustReleaseTimeToHistory(calEp, crunchyrollID); } } - } else{ - crunchyrollID = ""; } } @@ -487,6 +485,45 @@ public class CalendarManager{ } } + private static void AdjustReleaseTimeToHistory(CalendarEpisode calEp, string crunchyrollId){ + calEp.CrSeriesID = crunchyrollId; + + if (CrunchyrollManager.Instance.CrunOptions.History){ + var historySeries = CrunchyrollManager.Instance.HistoryList.FirstOrDefault(item => item.SeriesId == crunchyrollId); + + if (historySeries != null){ + var oldestRelease = DateTime.MinValue; + foreach (var historySeriesSeason in historySeries.Seasons){ + if (historySeriesSeason.EpisodesList.Any()){ + var releaseDate = historySeriesSeason.EpisodesList.Last().EpisodeCrPremiumAirDate; + + if (releaseDate.HasValue && oldestRelease < releaseDate.Value){ + oldestRelease = releaseDate.Value; + } + } + } + + if (oldestRelease != DateTime.MinValue){ + var adjustedDate = new DateTime( + calEp.DateTime.Year, + calEp.DateTime.Month, + calEp.DateTime.Day, + oldestRelease.Hour, + oldestRelease.Minute, + oldestRelease.Second, + calEp.DateTime.Kind + ); + + if ((adjustedDate - oldestRelease).TotalDays is < 6 and > 1){ + adjustedDate = oldestRelease.AddDays(7); + } + + calEp.DateTime = adjustedDate; + } + } + } + } + #region Query private string query = @"query ($weekStart: Int, $weekEnd: Int, $page: Int) { diff --git a/CRD/Downloader/Crunchyroll/CrunchyrollManager.cs b/CRD/Downloader/Crunchyroll/CrunchyrollManager.cs index 1f70c7e..2c75036 100644 --- a/CRD/Downloader/Crunchyroll/CrunchyrollManager.cs +++ b/CRD/Downloader/Crunchyroll/CrunchyrollManager.cs @@ -108,6 +108,8 @@ public class CrunchyrollManager{ options.FfmpegOptions = new(); options.DefaultAudio = "ja-JP"; options.DefaultSub = "en-US"; + options.QualityAudio = "best"; + options.QualityVideo = "best"; options.CcTag = "CC"; options.CcSubsFont = "Trebuchet MS"; options.FsRetryTime = 5; @@ -150,11 +152,9 @@ public class CrunchyrollManager{ Username = "???", Avatar = "crbrand_avatars_logo_marks_mangagirl_taupe.png", PreferredContentAudioLanguage = "ja-JP", - PreferredContentSubtitleLanguage = "de-DE", + PreferredContentSubtitleLanguage = DefaultLocale, HasPremium = false, }; - - Console.WriteLine($"CDM available: {_widevine.canDecrypt}"); } public async Task Init(){ @@ -254,10 +254,10 @@ public class CrunchyrollManager{ QueueManager.Instance.Queue.Refresh(); - var fileNameAndPath = CrunOptions.DownloadToTempFolder + var fileNameAndPath = options.DownloadToTempFolder ? Path.Combine(res.TempFolderPath ?? string.Empty, res.FileName ?? string.Empty) : Path.Combine(res.FolderPath ?? string.Empty, res.FileName ?? string.Empty); - if (CrunOptions is{ DlVideoOnce: false, KeepDubsSeperate: true }){ + if (options is{ DlVideoOnce: false, KeepDubsSeperate: true }){ var groupByDub = Helpers.GroupByLanguageWithSubtitles(res.Data); var mergers = new List(); foreach (var keyValue in groupByDub){ @@ -277,7 +277,8 @@ public class CrunchyrollManager{ SyncTiming = options.SyncTiming, CcTag = options.CcTag, KeepAllVideos = true, - MuxDescription = options.IncludeVideoDescription + MuxDescription = options.IncludeVideoDescription, + DlVideoOnce = options.DlVideoOnce }, fileNameAndPath); @@ -293,7 +294,7 @@ public class CrunchyrollManager{ foreach (var merger in mergers){ merger.CleanUp(); - if (CrunOptions.IsEncodeEnabled){ + if (options.IsEncodeEnabled){ data.DownloadProgress = new DownloadProgress(){ IsDownloading = true, Percent = 100, @@ -304,11 +305,11 @@ public class CrunchyrollManager{ QueueManager.Instance.Queue.Refresh(); - await Helpers.RunFFmpegWithPresetAsync(merger?.options.Output, FfmpegEncoding.GetPreset(CrunOptions.EncodingPresetName), data); + await Helpers.RunFFmpegWithPresetAsync(merger?.options.Output, FfmpegEncoding.GetPreset(options.EncodingPresetName), data); } - if (CrunOptions.DownloadToTempFolder){ - await MoveFromTempFolder(merger, data, res.TempFolderPath, res.Data.Where(e => e.Type == DownloadMediaType.Subtitle)); + if (options.DownloadToTempFolder){ + await MoveFromTempFolder(merger, data, options, res.TempFolderPath, res.Data.Where(e => e.Type == DownloadMediaType.Subtitle)); } } } else{ @@ -328,7 +329,8 @@ public class CrunchyrollManager{ SyncTiming = options.SyncTiming, CcTag = options.CcTag, KeepAllVideos = true, - MuxDescription = options.IncludeVideoDescription + MuxDescription = options.IncludeVideoDescription, + DlVideoOnce = options.DlVideoOnce }, fileNameAndPath); @@ -338,7 +340,7 @@ public class CrunchyrollManager{ result.merger.CleanUp(); } - if (CrunOptions.IsEncodeEnabled){ + if (options.IsEncodeEnabled){ data.DownloadProgress = new DownloadProgress(){ IsDownloading = true, Percent = 100, @@ -349,11 +351,11 @@ public class CrunchyrollManager{ QueueManager.Instance.Queue.Refresh(); - await Helpers.RunFFmpegWithPresetAsync(result.merger?.options.Output, FfmpegEncoding.GetPreset(CrunOptions.EncodingPresetName), data); + await Helpers.RunFFmpegWithPresetAsync(result.merger?.options.Output, FfmpegEncoding.GetPreset(options.EncodingPresetName), data); } - if (CrunOptions.DownloadToTempFolder){ - await MoveFromTempFolder(result.merger, data, res.TempFolderPath, res.Data.Where(e => e.Type == DownloadMediaType.Subtitle)); + if (options.DownloadToTempFolder){ + await MoveFromTempFolder(result.merger, data, options, res.TempFolderPath, res.Data.Where(e => e.Type == DownloadMediaType.Subtitle)); } } @@ -367,19 +369,19 @@ public class CrunchyrollManager{ Doing = "Done" + (syncError ? " - Couldn't sync dubs" : "") }; - if (CrunOptions.RemoveFinishedDownload && !syncError){ + if (options.RemoveFinishedDownload && !syncError){ QueueManager.Instance.Queue.Remove(data); } } else{ Console.WriteLine("Skipping mux"); res.Data.ForEach(file => Helpers.DeleteFile(file.Path + ".resume")); - if (CrunOptions.DownloadToTempFolder){ + if (options.DownloadToTempFolder){ if (string.IsNullOrEmpty(res.TempFolderPath) || !Directory.Exists(res.TempFolderPath)){ Console.WriteLine("Invalid or non-existent temp folder path."); } else{ // Move files foreach (var downloadedMedia in res.Data){ - await MoveFile(downloadedMedia.Path ?? string.Empty, res.TempFolderPath, data.DownloadPath ?? CfgManager.PathVIDEOS_DIR); + await MoveFile(downloadedMedia.Path ?? string.Empty, res.TempFolderPath, data.DownloadPath ?? CfgManager.PathVIDEOS_DIR, options); } } } @@ -393,7 +395,7 @@ public class CrunchyrollManager{ Doing = "Done - Skipped muxing" }; - if (CrunOptions.RemoveFinishedDownload){ + if (options.RemoveFinishedDownload){ QueueManager.Instance.Queue.Remove(data); } } @@ -402,7 +404,7 @@ public class CrunchyrollManager{ QueueManager.Instance.ActiveDownloads--; QueueManager.Instance.Queue.Refresh(); - if (CrunOptions.History && data.Data != null && data.Data.Count > 0){ + if (options.History && data.Data != null && data.Data.Count > 0){ History.SetAsDownloaded(data.ShowId, data.SeasonId, data.Data.First().MediaId); } @@ -412,8 +414,8 @@ public class CrunchyrollManager{ #region Temp Files Move - private async Task MoveFromTempFolder(Merger? merger, CrunchyEpMeta data, string tempFolderPath, IEnumerable subtitles){ - if (!CrunOptions.DownloadToTempFolder) return; + private async Task MoveFromTempFolder(Merger? merger, CrunchyEpMeta data, CrDownloadOptions options, string tempFolderPath, IEnumerable subtitles){ + if (!options.DownloadToTempFolder) return; data.DownloadProgress = new DownloadProgress{ IsDownloading = true, @@ -431,15 +433,15 @@ public class CrunchyrollManager{ } // Move the main output file - await MoveFile(merger?.options.Output ?? string.Empty, tempFolderPath, data.DownloadPath ?? CfgManager.PathVIDEOS_DIR); + await MoveFile(merger?.options.Output ?? string.Empty, tempFolderPath, data.DownloadPath ?? CfgManager.PathVIDEOS_DIR, options); // Move the subtitle files foreach (var downloadedMedia in subtitles){ - await MoveFile(downloadedMedia.Path ?? string.Empty, tempFolderPath, data.DownloadPath ?? CfgManager.PathVIDEOS_DIR); + await MoveFile(downloadedMedia.Path ?? string.Empty, tempFolderPath, data.DownloadPath ?? CfgManager.PathVIDEOS_DIR, options); } } - private async Task MoveFile(string sourcePath, string tempFolderPath, string downloadPath){ + private async Task MoveFile(string sourcePath, string tempFolderPath, string downloadPath, CrDownloadOptions options){ if (string.IsNullOrEmpty(sourcePath) || !File.Exists(sourcePath)){ // Console.Error.WriteLine("Source file does not exist or path is invalid."); return; @@ -454,8 +456,8 @@ public class CrunchyrollManager{ var fileName = sourcePath[tempFolderPath.Length..].TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); var destinationFolder = !string.IsNullOrEmpty(downloadPath) ? downloadPath - : !string.IsNullOrEmpty(CrunOptions.DownloadDirPath) - ? CrunOptions.DownloadDirPath + : !string.IsNullOrEmpty(options.DownloadDirPath) + ? options.DownloadDirPath : CfgManager.PathVIDEOS_DIR; var destinationPath = Path.Combine(destinationFolder ?? string.Empty, fileName ?? string.Empty); @@ -539,7 +541,7 @@ public class CrunchyrollManager{ 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(), KeepAllVideos = options.KeepAllVideos, - Fonts = FontsManager.Instance.MakeFontsList(CfgManager.PathFONTS_DIR, subsList), + Fonts = FontsManager.Instance.MakeFontsList(CfgManager.PathFONTS_DIR, subsList), Chapters = data.Where(a => a.Type == DownloadMediaType.Chapters).Select(a => new MergerInput{ Language = a.Lang, Path = a.Path ?? string.Empty }).ToList(), VideoTitle = options.VideoTitle, Options = new MuxOptions(){ @@ -565,7 +567,7 @@ public class CrunchyrollManager{ bool isMuxed, syncError = false; - if (options.SyncTiming && CrunOptions.DlVideoOnce){ + if (options is{ SyncTiming: true, DlVideoOnce: true }){ var basePath = merger.options.OnlyVid.First().Path; var syncVideosList = data.Where(a => a.Type == DownloadMediaType.SyncVideo).ToList(); @@ -666,13 +668,13 @@ public class CrunchyrollManager{ } if (!_widevine.canDecrypt){ - Console.Error.WriteLine("L3 key files missing"); - MainWindow.Instance.ShowError("Can't find CDM files in the Widevine folder.\nFor more information, please check the FAQ section in the Wiki on the GitHub page."); + Console.Error.WriteLine("CDM files missing"); + MainWindow.Instance.ShowError("Can't find CDM files in the Widevine folder.\nFor more information, please check the FAQ section in the Wiki on the GitHub page.", true); return new DownloadResponse{ Data = new List(), Error = true, FileName = "./unknown", - ErrorText = "Missing L3 Key" + ErrorText = "Missing CDM files" }; } @@ -715,8 +717,8 @@ public class CrunchyrollManager{ string currentMediaId = (epMeta.MediaId.Contains(':') ? epMeta.MediaId.Split(':')[1] : epMeta.MediaId); - fileDir = CrunOptions.DownloadToTempFolder ? !string.IsNullOrEmpty(CrunOptions.DownloadTempDirPath) - ? Path.Combine(CrunOptions.DownloadTempDirPath, Helpers.GetValidFolderName(currentMediaId)) + fileDir = options.DownloadToTempFolder ? !string.IsNullOrEmpty(options.DownloadTempDirPath) + ? Path.Combine(options.DownloadTempDirPath, Helpers.GetValidFolderName(currentMediaId)) : Path.Combine(CfgManager.PathTEMP_DIR, Helpers.GetValidFolderName(currentMediaId)) : !string.IsNullOrEmpty(data.DownloadPath) ? data.DownloadPath : !string.IsNullOrEmpty(options.DownloadDirPath) ? options.DownloadDirPath : CfgManager.PathVIDEOS_DIR; @@ -788,7 +790,7 @@ public class CrunchyrollManager{ #endregion - var fetchPlaybackData = await FetchPlaybackData(mediaId, mediaGuid, data.Music); + var fetchPlaybackData = await FetchPlaybackData(options, mediaId, mediaGuid, data.Music); if (!fetchPlaybackData.IsOk){ if (!fetchPlaybackData.IsOk && fetchPlaybackData.error != string.Empty){ @@ -888,7 +890,7 @@ public class CrunchyrollManager{ Console.Error.WriteLine("Try hardsubs stream: " + string.Join(", ", hsLangs)); } - if (dlVideoOnce && CrunOptions.DlVideoOnce){ + if (dlVideoOnce && options.DlVideoOnce){ streams = streams.Where((s) => { if (s.HardsubLang != "-"){ return false; @@ -1054,6 +1056,11 @@ public class CrunchyrollManager{ videos.Sort((a, b) => a.quality.width.CompareTo(b.quality.width)); audios.Sort((a, b) => a.bandwidth.CompareTo(b.bandwidth)); + if (string.IsNullOrEmpty(data.VideoQuality)){ + Console.Error.WriteLine("Warning: VideoQuality is null or empty. Defaulting to 'best' quality."); + data.VideoQuality = "best"; + } + int chosenVideoQuality; if (options.DlVideoOnce && dlVideoOnce && options.SyncTiming){ chosenVideoQuality = 1; @@ -1062,7 +1069,7 @@ public class CrunchyrollManager{ } else if (data.VideoQuality == "worst"){ chosenVideoQuality = 1; } else{ - var tempIndex = videos.FindIndex(a => a.quality.height + "" == data.VideoQuality.Replace("p", "")); + var tempIndex = videos.FindIndex(a => a.quality.height + "" == data.VideoQuality?.Replace("p", "")); if (tempIndex < 0){ chosenVideoQuality = videos.Count; } else{ @@ -1473,11 +1480,15 @@ public class CrunchyrollManager{ Console.WriteLine("Downloading skipped!"); } } - } else if (options.Novids && options.Noaudio){ + } else if (options is{ Novids: true, Noaudio: true }){ + + 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.Override).ToArray()); } - if (compiledChapters.Count > 0){ + 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.Override).ToArray()); @@ -1536,16 +1547,12 @@ public class CrunchyrollManager{ } else{ Console.WriteLine("Subtitles downloading skipped!"); } - } - + } + // await Task.Delay(options.Waittime); } } - // variables.Add(new Variable("height", quality == 0 ? plQuality.Last().RESOLUTION.Height : plQuality[quality - 1].RESOLUTION.Height, false)); - // variables.Add(new Variable("width", quality == 0 ? plQuality.Last().RESOLUTION.Width : plQuality[quality - 1].RESOLUTION.Width, false)); - - if (options.IncludeVideoDescription){ string fullPath = (Path.IsPathRooted(fileName) ? fileName : Path.Combine(fileDir, fileName)) + ".xml"; @@ -1590,7 +1597,7 @@ public class CrunchyrollManager{ } var tempFolderPath = ""; - if (CrunOptions.DownloadToTempFolder){ + if (options.DownloadToTempFolder){ tempFolderPath = fileDir; fileDir = !string.IsNullOrEmpty(data.DownloadPath) ? data.DownloadPath : !string.IsNullOrEmpty(options.DownloadDirPath) ? options.DownloadDirPath : CfgManager.PathVIDEOS_DIR; @@ -1745,7 +1752,7 @@ public class CrunchyrollManager{ } File.WriteAllText(sxData.Path, subsAssReqResponse.ResponseContent); - Console.WriteLine($"Subtitle downloaded: ${sxData.File}"); + Console.WriteLine($"Subtitle downloaded: {sxData.File}"); files.Add(new DownloadedMedia{ Type = DownloadMediaType.Subtitle, Cc = isCc, @@ -1788,10 +1795,10 @@ public class CrunchyrollManager{ M3U8Json videoJson = new M3U8Json{ Segments = chosenVideoSegments.segments.Cast().ToList() }; - + data.downloadedFiles.Add(chosenVideoSegments.pssh != null ? $"{tempTsFile}.video.enc.m4s" : $"{tsFile}.video.m4s"); data.downloadedFiles.Add(chosenVideoSegments.pssh != null ? $"{tempTsFile}.video.enc.m4s.resume" : $"{tsFile}.video.m4s.resume"); - + var videoDownloader = new HlsDownloader(new HlsOptions{ Output = chosenVideoSegments.pssh != null ? $"{tempTsFile}.video.enc.m4s" : $"{tsFile}.video.m4s", Timeout = options.Timeout, @@ -1844,7 +1851,7 @@ public class CrunchyrollManager{ M3U8Json audioJson = new M3U8Json{ Segments = chosenAudioSegments.segments.Cast().ToList() }; - + data.downloadedFiles.Add(chosenAudioSegments.pssh != null ? $"{tempTsFile}.audio.enc.m4s" : $"{tsFile}.audio.m4s"); data.downloadedFiles.Add(chosenAudioSegments.pssh != null ? $"{tempTsFile}.audio.enc.m4s.resume" : $"{tsFile}.audio.m4s.resume"); @@ -1866,13 +1873,13 @@ public class CrunchyrollManager{ #region Fetch Playback Data - private async Task<(bool IsOk, PlaybackData pbData, string error)> FetchPlaybackData(string mediaId, string mediaGuidId, bool music){ + private async Task<(bool IsOk, PlaybackData pbData, string error)> FetchPlaybackData(CrDownloadOptions options, string mediaId, string mediaGuidId, bool music){ var temppbData = new PlaybackData{ Total = 0, Data = new Dictionary() }; - var playbackEndpoint = $"https://cr-play-service.prd.crunchyrollsvc.com/v1/{(music ? "music/" : "")}{mediaGuidId}/{CrunOptions.StreamEndpoint}/play"; + var playbackEndpoint = $"https://cr-play-service.prd.crunchyrollsvc.com/v1/{(music ? "music/" : "")}{mediaGuidId}/{options.StreamEndpoint}/play"; var playbackRequestResponse = await SendPlaybackRequestAsync(playbackEndpoint); if (!playbackRequestResponse.IsOk){ diff --git a/CRD/Downloader/History.cs b/CRD/Downloader/History.cs index 3ee691c..bebf800 100644 --- a/CRD/Downloader/History.cs +++ b/CRD/Downloader/History.cs @@ -302,6 +302,7 @@ public class History(){ historyEpisode.EpisodeId = crunchyEpisode.Id; historyEpisode.Episode = crunchyEpisode.Episode; historyEpisode.EpisodeSeasonNum = Helpers.ExtractNumberAfterS(crunchyEpisode.Identifier) ?? crunchyEpisode.SeasonNumber + ""; + historyEpisode.EpisodeCrPremiumAirDate = crunchyEpisode.PremiumAvailableDate; historyEpisode.HistoryEpisodeAvailableDubLang = Languages.SortListByLangList(langList); historyEpisode.HistoryEpisodeAvailableSoftSubs = Languages.SortListByLangList(crunchyEpisode.SubtitleLocales); @@ -333,8 +334,7 @@ public class History(){ newSeason.EpisodesList.Sort(new NumericStringPropertyComparer()); await RefreshSeriesData(seriesId, historySeries); - - + historySeries.Seasons.Add(newSeason); historySeries.UpdateNewEpisodes(); historySeries.Init(); diff --git a/CRD/Downloader/QueueManager.cs b/CRD/Downloader/QueueManager.cs index 725d391..b71fc09 100644 --- a/CRD/Downloader/QueueManager.cs +++ b/CRD/Downloader/QueueManager.cs @@ -86,7 +86,7 @@ public class QueueManager{ } - public async Task CrAddEpisodeToQueue(string epId, string crLocale, List dubLang, bool updateHistory = false){ + public async Task CrAddEpisodeToQueue(string epId, string crLocale, List dubLang, bool updateHistory = false, bool onlySubs = false){ await CrunchyrollManager.Instance.CrAuth.RefreshToken(true); var episodeL = await CrunchyrollManager.Instance.CrEpisode.ParseEpisodeById(epId, crLocale); @@ -100,7 +100,7 @@ public class QueueManager{ var sList = await CrunchyrollManager.Instance.CrEpisode.EpisodeData((CrunchyEpisode)episodeL, updateHistory); - (HistoryEpisode? historyEpisode, List dublist, List sublist, string downloadDirPath,string videoQuality) historyEpisode = (null, [], [], "",""); + (HistoryEpisode? historyEpisode, List dublist, List sublist, string downloadDirPath, string videoQuality) historyEpisode = (null, [], [], "", ""); if (CrunchyrollManager.Instance.CrunOptions.History){ var episode = sList.EpisodeAndLanguages.Items.First(); @@ -142,9 +142,11 @@ public class QueueManager{ } selected.VideoQuality = !string.IsNullOrEmpty(historyEpisode.videoQuality) ? historyEpisode.videoQuality : CrunchyrollManager.Instance.CrunOptions.QualityVideo; - + selected.DownloadSubs = historyEpisode.sublist.Count > 0 ? historyEpisode.sublist : CrunchyrollManager.Instance.CrunOptions.DlSubs; + selected.OnlySubs = onlySubs; + Queue.Add(selected); if (selected.Data.Count < dubLang.Count){ @@ -154,7 +156,8 @@ public class QueueManager{ var languages = sList.EpisodeAndLanguages.Items.Select((a, index) => $"{(a.IsPremiumOnly ? "+ " : "")}{sList.EpisodeAndLanguages.Langs.ElementAtOrDefault(index).CrLocale ?? "Unknown"}").ToArray(); - Console.Error.WriteLine($"{selected.SeasonTitle} - Season {selected.Season} - {selected.EpisodeTitle} dubs - [{string.Join(", ", languages)}] subs - [{string.Join(", ", selected.AvailableSubs ?? [])}]"); + Console.Error.WriteLine( + $"{selected.SeasonTitle} - Season {selected.Season} - {selected.EpisodeTitle} dubs - [{string.Join(", ", languages)}] subs - [{string.Join(", ", selected.AvailableSubs ??[])}]"); MessageBus.Current.SendMessage(new ToastMessage($"Added episode to the queue but couldn't find all selected dubs", ToastType.Warning, 2)); } else{ Console.WriteLine("Added Episode to Queue"); @@ -167,7 +170,7 @@ public class QueueManager{ var languages = sList.EpisodeAndLanguages.Items.Select((a, index) => $"{(a.IsPremiumOnly ? "+ " : "")}{sList.EpisodeAndLanguages.Langs.ElementAtOrDefault(index).CrLocale ?? "Unknown"}").ToArray(); - Console.Error.WriteLine($"{selected.SeasonTitle} - Season {selected.Season} - {selected.EpisodeTitle} dubs - [{string.Join(", ", languages)}] subs - [{string.Join(", ", selected.AvailableSubs ?? [])}]"); + Console.Error.WriteLine($"{selected.SeasonTitle} - Season {selected.Season} - {selected.EpisodeTitle} dubs - [{string.Join(", ", languages)}] subs - [{string.Join(", ", selected.AvailableSubs ??[])}]"); MessageBus.Current.SendMessage(new ToastMessage($"Couldn't add episode to the queue with current dub settings", ToastType.Error, 2)); } } else{ @@ -180,6 +183,7 @@ public class QueueManager{ if (movieMeta != null){ movieMeta.DownloadSubs = CrunchyrollManager.Instance.CrunOptions.DlSubs; + movieMeta.OnlySubs = onlySubs; Queue.Add(movieMeta); Console.WriteLine("Added Movie to Queue"); @@ -255,7 +259,7 @@ public class QueueManager{ } var subLangList = CrunchyrollManager.Instance.History.GetSubList(crunchyEpMeta.ShowId, crunchyEpMeta.SeasonId); - + crunchyEpMeta.VideoQuality = !string.IsNullOrEmpty(subLangList.videoQuality) ? subLangList.videoQuality : CrunchyrollManager.Instance.CrunOptions.QualityVideo; crunchyEpMeta.DownloadSubs = subLangList.sublist.Count > 0 ? subLangList.sublist : CrunchyrollManager.Instance.CrunOptions.DlSubs; diff --git a/CRD/Styling/ControlsGalleryStyles.axaml b/CRD/Styling/ControlsGalleryStyles.axaml index d587586..d4a190e 100644 --- a/CRD/Styling/ControlsGalleryStyles.axaml +++ b/CRD/Styling/ControlsGalleryStyles.axaml @@ -2,12 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="using:FluentAvalonia.UI.Controls" xmlns:uip="using:FluentAvalonia.UI.Controls.Primitives"> - + + + + + + + + \ No newline at end of file diff --git a/CRD/Views/UpcomingSeasonsPageView.axaml b/CRD/Views/UpcomingSeasonsPageView.axaml index 543e666..4594a02 100644 --- a/CRD/Views/UpcomingSeasonsPageView.axaml +++ b/CRD/Views/UpcomingSeasonsPageView.axaml @@ -16,8 +16,13 @@ - - + + + + + + + @@ -45,7 +50,65 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IsVisible="{Binding IsInHistory}" Margin="0 5 5 5"> - + - + - + - + - + - + - + - - + + @@ -190,6 +254,6 @@ - + \ No newline at end of file diff --git a/CRD/Views/Utils/GeneralSettingsView.axaml b/CRD/Views/Utils/GeneralSettingsView.axaml index 8fec208..3ca390d 100644 --- a/CRD/Views/Utils/GeneralSettingsView.axaml +++ b/CRD/Views/Utils/GeneralSettingsView.axaml @@ -14,7 +14,7 @@ - +