mirror of
https://github.com/Crunchy-DL/Crunchy-Downloader.git
synced 2026-01-11 20:10:26 +00:00
Add - Added **Shutdown PC toggle** to the Download Queue page [#298](https://github.com/Crunchy-DL/Crunchy-Downloader/issues/298)
Add - Added **Download Duplicate Subs** option to the softsub settings [#294](https://github.com/Crunchy-DL/Crunchy-Downloader/issues/294) Chg - Changed **ScaledBorderAndShadow** setting to now also apply to **CC subtitles** [#293](https://github.com/Crunchy-DL/Crunchy-Downloader/issues/293) Fix - Fixed **crash with certain manifest versions** [#288](https://github.com/Crunchy-DL/Crunchy-Downloader/issues/288) Fix - Fixed **infinite loading bug with Sonarr**
This commit is contained in:
parent
1f96ab731e
commit
65200147a0
12 changed files with 184 additions and 50 deletions
|
|
@ -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<string, StreamDetails>{
|
||||
[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<string, string> 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<string, ServerData> playListData = new Dictionary<string, ServerData>();
|
||||
|
||||
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<DownloadedMedia> 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<SubtitleInfo> subsData = pbData.Meta.Subtitles?.Values.ToList() ??[];
|
||||
List<Caption> 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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -105,6 +105,12 @@
|
|||
</StackPanel>
|
||||
</controls:SettingsExpander.Footer>
|
||||
|
||||
<controls:SettingsExpanderItem Content="Download Duplicate" Description="Download subtitles from all dubs where they're available">
|
||||
<controls:SettingsExpanderItem.Footer>
|
||||
<CheckBox IsChecked="{Binding SubsDownloadDuplicate}"> </CheckBox>
|
||||
</controls:SettingsExpanderItem.Footer>
|
||||
</controls:SettingsExpanderItem>
|
||||
|
||||
<controls:SettingsExpanderItem Content="Add ScaledBorderAndShadow ">
|
||||
<controls:SettingsExpanderItem.Footer>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,7 @@ public class FontsManager{
|
|||
{ "Times New Roman", new List<string>{ "times.ttf", "timesbd.ttf", "timesbi.ttf", "timesi.ttf" } },
|
||||
{ "Trebuchet MS", new List<string>{ "trebuc.ttf", "trebucbd.ttf", "trebucbi.ttf", "trebucit.ttf" } },
|
||||
{ "Verdana", new List<string>{ "verdana.ttf", "verdanab.ttf", "verdanai.ttf", "verdanaz.ttf" } },
|
||||
{ "Vrinda", new List<string>{ "vrinda.ttf", "vrindab.ttf"} },
|
||||
{ "Webdings", new List<string>{ "webdings.ttf" } },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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}";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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<SonarrEpisode>? episodes = await GetEpisodes(int.Parse(historySeries.SonarrSeriesId));
|
||||
historySeries.SonarrNextAirDate = CrunchyrollManager.Instance.History.GetNextAirDate(episodes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ namespace CRD.ViewModels;
|
|||
public partial class DownloadsPageViewModel : ViewModelBase{
|
||||
public ObservableCollection<DownloadItemModel> 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;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@
|
|||
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<ToggleSwitch HorizontalAlignment="Right" Margin="0 0 10 0 " IsChecked="{Binding RemoveFinished}" OffContent="Remove Finished" OnContent="Remove Finished"></ToggleSwitch>
|
||||
<ToggleSwitch HorizontalAlignment="Right" Margin="0 0 10 0 " IsChecked="{Binding AutoDownload}" OffContent="Auto Download" OnContent="Auto Download"></ToggleSwitch>
|
||||
<ToggleSwitch HorizontalAlignment="Right" Margin="0 0 10 0 " IsChecked="{Binding ShutdownWhenQueueEmpty}" OffContent="Shutdown PC" OnContent="Shutdown PC">
|
||||
<ToolTip.Tip>
|
||||
<TextBlock Text="Automatically shut down the PC when the queue is empty" FontSize="16" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap"></TextBlock>
|
||||
</ToolTip.Tip>
|
||||
</ToggleSwitch>
|
||||
|
||||
<Button BorderThickness="0"
|
||||
HorizontalAlignment="Right"
|
||||
|
|
|
|||
Loading…
Reference in a new issue