Add - Added download path to download settings
Add - Added download path to history series and also to each season Fix - When adding an episode it always showed "Added to Queue" even if it wasn't added
This commit is contained in:
parent
cd4ceea38a
commit
3d74fa7667
|
@ -7,6 +7,7 @@ using System.Net.Http;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
|
using Avalonia.Remote.Protocol.Input;
|
||||||
using CRD.Utils;
|
using CRD.Utils;
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
@ -14,10 +15,9 @@ using Newtonsoft.Json;
|
||||||
namespace CRD.Downloader;
|
namespace CRD.Downloader;
|
||||||
|
|
||||||
public class CrEpisode(){
|
public class CrEpisode(){
|
||||||
|
|
||||||
private readonly Crunchyroll crunInstance = Crunchyroll.Instance;
|
private readonly Crunchyroll crunInstance = Crunchyroll.Instance;
|
||||||
|
|
||||||
public async Task<CrunchyEpisodeList?> ParseEpisodeById(string id,string locale){
|
public async Task<CrunchyEpisode?> ParseEpisodeById(string id, string locale){
|
||||||
if (crunInstance.CmsToken?.Cms == null){
|
if (crunInstance.CmsToken?.Cms == null){
|
||||||
Console.Error.WriteLine("Missing CMS Access Token");
|
Console.Error.WriteLine("Missing CMS Access Token");
|
||||||
return null;
|
return null;
|
||||||
|
@ -43,148 +43,122 @@ public class CrEpisode(){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return epsidoe;
|
if (epsidoe.Total == 1 && epsidoe.Data != null){
|
||||||
|
return epsidoe.Data.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.Error.WriteLine("Multiple episodes returned with one ID?");
|
||||||
|
if (epsidoe.Data != null) return epsidoe.Data.First();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<CrunchySeriesList> EpisodeData(CrunchyEpisodeList dlEpisodes){
|
public async Task<CrunchyRollEpisodeData> EpisodeData(CrunchyEpisode dlEpisode){
|
||||||
bool serieshasversions = true;
|
bool serieshasversions = true;
|
||||||
|
|
||||||
Dictionary<string, EpisodeAndLanguage> episodes = new Dictionary<string, EpisodeAndLanguage>();
|
// Dictionary<string, EpisodeAndLanguage> episodes = new Dictionary<string, EpisodeAndLanguage>();
|
||||||
|
|
||||||
if (dlEpisodes.Data != null){
|
CrunchyRollEpisodeData episode = new CrunchyRollEpisodeData();
|
||||||
foreach (var episode in dlEpisodes.Data){
|
|
||||||
|
|
||||||
if (crunInstance.CrunOptions.History){
|
if (crunInstance.CrunOptions.History){
|
||||||
await crunInstance.CrHistory.UpdateWithEpisode(episode);
|
await crunInstance.CrHistory.UpdateWithEpisode(dlEpisode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the episode array
|
var seasonIdentifier = !string.IsNullOrEmpty(dlEpisode.Identifier) ? dlEpisode.Identifier.Split('|')[1] : $"S{dlEpisode.SeasonNumber}";
|
||||||
EpisodeAndLanguage item;
|
episode.Key = $"{seasonIdentifier}E{dlEpisode.Episode ?? (dlEpisode.EpisodeNumber + "")}";
|
||||||
var seasonIdentifier = !string.IsNullOrEmpty(episode.Identifier) ? episode.Identifier.Split('|')[1] : $"S{episode.SeasonNumber}";
|
episode.EpisodeAndLanguages = new EpisodeAndLanguage{
|
||||||
var episodeKey = $"{seasonIdentifier}E{episode.Episode ?? (episode.EpisodeNumber + "")}";
|
|
||||||
|
|
||||||
if (!episodes.ContainsKey(episodeKey)){
|
|
||||||
item = new EpisodeAndLanguage{
|
|
||||||
Items = new List<CrunchyEpisode>(),
|
Items = new List<CrunchyEpisode>(),
|
||||||
Langs = new List<LanguageItem>()
|
Langs = new List<LanguageItem>()
|
||||||
};
|
};
|
||||||
episodes[episodeKey] = item;
|
|
||||||
} else{
|
|
||||||
item = episodes[episodeKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (episode.Versions != null){
|
if (dlEpisode.Versions != null){
|
||||||
foreach (var version in episode.Versions){
|
foreach (var version in dlEpisode.Versions){
|
||||||
// Ensure there is only one of the same language
|
// Ensure there is only one of the same language
|
||||||
if (item.Langs.All(a => a.CrLocale != version.AudioLocale)){
|
if (episode.EpisodeAndLanguages.Langs.All(a => a.CrLocale != version.AudioLocale)){
|
||||||
// Push to arrays if there are no duplicates of the same language
|
// Push to arrays if there are no duplicates of the same language
|
||||||
item.Items.Add(episode);
|
episode.EpisodeAndLanguages.Items.Add(dlEpisode);
|
||||||
item.Langs.Add(Array.Find(Languages.languages, a => a.CrLocale == version.AudioLocale));
|
episode.EpisodeAndLanguages.Langs.Add(Array.Find(Languages.languages, a => a.CrLocale == version.AudioLocale));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else{
|
} else{
|
||||||
// Episode didn't have versions, mark it as such to be logged.
|
// Episode didn't have versions, mark it as such to be logged.
|
||||||
serieshasversions = false;
|
serieshasversions = false;
|
||||||
// Ensure there is only one of the same language
|
// Ensure there is only one of the same language
|
||||||
if (item.Langs.All(a => a.CrLocale != episode.AudioLocale)){
|
if (episode.EpisodeAndLanguages.Langs.All(a => a.CrLocale != dlEpisode.AudioLocale)){
|
||||||
// Push to arrays if there are no duplicates of the same language
|
// Push to arrays if there are no duplicates of the same language
|
||||||
item.Items.Add(episode);
|
episode.EpisodeAndLanguages.Items.Add(dlEpisode);
|
||||||
item.Langs.Add(Array.Find(Languages.languages, a => a.CrLocale == episode.AudioLocale));
|
episode.EpisodeAndLanguages.Langs.Add(Array.Find(Languages.languages, a => a.CrLocale == dlEpisode.AudioLocale));
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int specialIndex = 1;
|
int specialIndex = 1;
|
||||||
int epIndex = 1;
|
int epIndex = 1;
|
||||||
|
|
||||||
var keys = new List<string>(episodes.Keys); // Copying the keys to a new list to avoid modifying the collection while iterating.
|
|
||||||
|
|
||||||
foreach (var key in keys){
|
var isSpecial = !Regex.IsMatch(episode.EpisodeAndLanguages.Items[0].Episode ?? string.Empty, @"^\d+$"); // Checking if the episode is not a number (i.e., special).
|
||||||
EpisodeAndLanguage item = episodes[key];
|
|
||||||
var isSpecial = !Regex.IsMatch(item.Items[0].Episode ?? string.Empty, @"^\d+$"); // Checking if the episode is not a number (i.e., special).
|
|
||||||
string newKey;
|
string newKey;
|
||||||
if (isSpecial && !string.IsNullOrEmpty(item.Items[0].Episode)){
|
if (isSpecial && !string.IsNullOrEmpty(episode.EpisodeAndLanguages.Items[0].Episode)){
|
||||||
newKey = item.Items[0].Episode ?? "SP" + (specialIndex + " " + item.Items[0].Id);
|
newKey = episode.EpisodeAndLanguages.Items[0].Episode ?? "SP" + (specialIndex + " " + episode.EpisodeAndLanguages.Items[0].Id);
|
||||||
} else{
|
} else{
|
||||||
newKey = $"{(isSpecial ? "SP" : 'E')}{(isSpecial ? (specialIndex + " " + item.Items[0].Id) : epIndex + "")}";
|
newKey = $"{(isSpecial ? "SP" : 'E')}{(isSpecial ? (specialIndex + " " + episode.EpisodeAndLanguages.Items[0].Id) : episode.EpisodeAndLanguages.Items[0].Episode ?? epIndex + "")}";
|
||||||
}
|
}
|
||||||
|
|
||||||
episodes.Remove(key);
|
episode.Key = newKey;
|
||||||
episodes.Add(newKey, item);
|
|
||||||
|
|
||||||
if (isSpecial){
|
var seasonTitle = episode.EpisodeAndLanguages.Items.FirstOrDefault(a => !Regex.IsMatch(a.SeasonTitle, @"\(\w+ Dub\)")).SeasonTitle
|
||||||
specialIndex++;
|
?? Regex.Replace(episode.EpisodeAndLanguages.Items[0].SeasonTitle, @"\(\w+ Dub\)", "").TrimEnd();
|
||||||
} else{
|
|
||||||
epIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var specials = episodes.Where(e => e.Key.StartsWith("SP")).ToList();
|
var title = episode.EpisodeAndLanguages.Items[0].Title;
|
||||||
var normal = episodes.Where(e => e.Key.StartsWith("E")).ToList();
|
var seasonNumber = Helpers.ExtractNumberAfterS(episode.EpisodeAndLanguages.Items[0].Identifier) ?? episode.EpisodeAndLanguages.Items[0].SeasonNumber.ToString();
|
||||||
|
|
||||||
// Combining and sorting episodes with normal first, then specials.
|
var languages = episode.EpisodeAndLanguages.Items.Select((a, index) =>
|
||||||
var sortedEpisodes = new Dictionary<string, EpisodeAndLanguage>(normal.Concat(specials));
|
$"{(a.IsPremiumOnly ? "+ " : "")}{episode.EpisodeAndLanguages.Langs.ElementAtOrDefault(index).Name ?? "Unknown"}").ToArray(); //☆
|
||||||
|
|
||||||
foreach (var kvp in sortedEpisodes){
|
Console.WriteLine($"[{episode.Key}] {seasonTitle} - Season {seasonNumber} - {title} [{string.Join(", ", languages)}]");
|
||||||
var key = kvp.Key;
|
|
||||||
var item = kvp.Value;
|
|
||||||
|
|
||||||
var seasonTitle = item.Items.FirstOrDefault(a => !Regex.IsMatch(a.SeasonTitle, @"\(\w+ Dub\)")).SeasonTitle
|
|
||||||
?? Regex.Replace(item.Items[0].SeasonTitle, @"\(\w+ Dub\)", "").TrimEnd();
|
|
||||||
|
|
||||||
var title = item.Items[0].Title;
|
|
||||||
var seasonNumber = Helpers.ExtractNumberAfterS(item.Items[0].Identifier) ?? item.Items[0].SeasonNumber.ToString();
|
|
||||||
|
|
||||||
var languages = item.Items.Select((a, index) =>
|
|
||||||
$"{(a.IsPremiumOnly ? "+ " : "")}{item.Langs.ElementAtOrDefault(index).Name ?? "Unknown"}").ToArray(); //☆
|
|
||||||
|
|
||||||
Console.WriteLine($"[{key}] {seasonTitle} - Season {seasonNumber} - {title} [{string.Join(", ", languages)}]");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serieshasversions){
|
if (!serieshasversions){
|
||||||
Console.WriteLine("Couldn\'t find versions on some episodes, fell back to old method.");
|
Console.WriteLine("Couldn\'t find versions on episode, fell back to old method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
CrunchySeriesList crunchySeriesList = new CrunchySeriesList();
|
|
||||||
crunchySeriesList.Data = sortedEpisodes;
|
|
||||||
|
|
||||||
crunchySeriesList.List = sortedEpisodes.Select(kvp => {
|
// crunchySeriesList.Data = sortedEpisodes;
|
||||||
var key = kvp.Key;
|
//
|
||||||
var value = kvp.Value;
|
//
|
||||||
var images = (value.Items[0].Images?.Thumbnail ?? new List<List<Image>>{ new List<Image>{ new Image{ Source = "/notFound.png" } } });
|
// var images = (episode.EpisodeAndLanguages.Items[0].Images?.Thumbnail ?? new List<List<Image>>{ new List<Image>{ new Image{ Source = "/notFound.png" } } });
|
||||||
var seconds = (int)Math.Floor(value.Items[0].DurationMs / 1000.0);
|
// var seconds = (int)Math.Floor(episode.EpisodeAndLanguages.Items[0].DurationMs / 1000.0);
|
||||||
return new Episode{
|
//
|
||||||
E = key.StartsWith("E") ? key.Substring(1) : key,
|
// var newEpisode = new Episode{
|
||||||
Lang = value.Langs.Select(a => a.Code).ToList(),
|
// E = episode.Key.StartsWith("E") ? episode.Key.Substring(1) : episode.Key,
|
||||||
Name = value.Items[0].Title,
|
// Lang = episode.EpisodeAndLanguages.Langs.Select(a => a.Code).ToList(),
|
||||||
Season = Helpers.ExtractNumberAfterS(value.Items[0].Identifier) ?? value.Items[0].SeasonNumber.ToString(),
|
// Name = episode.EpisodeAndLanguages.Items[0].Title,
|
||||||
SeriesTitle = Regex.Replace(value.Items[0].SeriesTitle, @"\(\w+ Dub\)", "").TrimEnd(),
|
// Season = Helpers.ExtractNumberAfterS(episode.EpisodeAndLanguages.Items[0].Identifier) ?? episode.EpisodeAndLanguages.Items[0].SeasonNumber.ToString(),
|
||||||
SeasonTitle = Regex.Replace(value.Items[0].SeasonTitle, @"\(\w+ Dub\)", "").TrimEnd(),
|
// SeriesTitle = Regex.Replace(episode.EpisodeAndLanguages.Items[0].SeriesTitle, @"\(\w+ Dub\)", "").TrimEnd(),
|
||||||
EpisodeNum = value.Items[0].EpisodeNumber?.ToString() ?? value.Items[0].Episode ?? "?",
|
// SeasonTitle = Regex.Replace(episode.EpisodeAndLanguages.Items[0].SeasonTitle, @"\(\w+ Dub\)", "").TrimEnd(),
|
||||||
Id = value.Items[0].SeasonId,
|
// EpisodeNum = episode.EpisodeAndLanguages.Items[0].EpisodeNumber?.ToString() ?? episode.EpisodeAndLanguages.Items[0].Episode ?? "?",
|
||||||
Img = images[images.Count / 2].FirstOrDefault().Source,
|
// Id = episode.EpisodeAndLanguages.Items[0].SeasonId,
|
||||||
Description = value.Items[0].Description,
|
// Img = images[images.Count / 2].FirstOrDefault().Source,
|
||||||
Time = $"{seconds / 60}:{seconds % 60:D2}" // Ensures two digits for seconds.
|
// Description = episode.EpisodeAndLanguages.Items[0].Description,
|
||||||
};
|
// Time = $"{seconds / 60}:{seconds % 60:D2}" // Ensures two digits for seconds.
|
||||||
}).ToList();
|
// };
|
||||||
|
//
|
||||||
|
// CrunchySeriesList crunchySeriesList = new CrunchySeriesList();
|
||||||
|
|
||||||
return crunchySeriesList;
|
return episode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, CrunchyEpMeta> EpisodeMeta(Dictionary<string, EpisodeAndLanguage> eps, List<string> dubLang){
|
public CrunchyEpMeta EpisodeMeta(CrunchyRollEpisodeData episodeP, List<string> dubLang){
|
||||||
var ret = new Dictionary<string, CrunchyEpMeta>();
|
// var ret = new Dictionary<string, CrunchyEpMeta>();
|
||||||
|
|
||||||
|
var retMeta = new CrunchyEpMeta();
|
||||||
|
|
||||||
|
|
||||||
foreach (var kvp in eps){
|
|
||||||
var key = kvp.Key;
|
|
||||||
var episode = kvp.Value;
|
|
||||||
|
|
||||||
for (int index = 0; index < episode.Items.Count; index++){
|
for (int index = 0; index < episodeP.EpisodeAndLanguages.Items.Count; index++){
|
||||||
var item = episode.Items[index];
|
var item = episodeP.EpisodeAndLanguages.Items[index];
|
||||||
|
|
||||||
if (!dubLang.Contains(episode.Langs[index].CrLocale))
|
if (!dubLang.Contains(episodeP.EpisodeAndLanguages.Langs[index].CrLocale))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
item.HideSeasonTitle = true;
|
item.HideSeasonTitle = true;
|
||||||
|
@ -199,15 +173,15 @@ public class CrEpisode(){
|
||||||
item.SeriesTitle = "NO_TITLE";
|
item.SeriesTitle = "NO_TITLE";
|
||||||
}
|
}
|
||||||
|
|
||||||
var epNum = key.StartsWith('E') ? key[1..] : key;
|
var epNum = episodeP.Key.StartsWith('E') ? episodeP.Key[1..] : episodeP.Key;
|
||||||
var images = (item.Images?.Thumbnail ?? new List<List<Image>>{ new List<Image>{ new Image{ Source = "/notFound.png" } } });
|
var images = (item.Images?.Thumbnail ?? new List<List<Image>>{ new List<Image>{ new Image{ Source = "/notFound.png" } } });
|
||||||
|
|
||||||
Regex dubPattern = new Regex(@"\(\w+ Dub\)");
|
Regex dubPattern = new Regex(@"\(\w+ Dub\)");
|
||||||
|
|
||||||
var epMeta = new CrunchyEpMeta();
|
var epMeta = new CrunchyEpMeta();
|
||||||
epMeta.Data = new List<CrunchyEpMetaData>{ new(){ MediaId = item.Id, Versions = item.Versions, IsSubbed = item.IsSubbed, IsDubbed = item.IsDubbed } };
|
epMeta.Data = new List<CrunchyEpMetaData>{ new(){ MediaId = item.Id, Versions = item.Versions, IsSubbed = item.IsSubbed, IsDubbed = item.IsDubbed } };
|
||||||
epMeta.SeriesTitle = episode.Items.FirstOrDefault(a => !dubPattern.IsMatch(a.SeriesTitle)).SeriesTitle ?? Regex.Replace(episode.Items[0].SeriesTitle, @"\(\w+ Dub\)", "").TrimEnd();
|
epMeta.SeriesTitle = episodeP.EpisodeAndLanguages.Items.FirstOrDefault(a => !dubPattern.IsMatch(a.SeriesTitle)).SeriesTitle ?? Regex.Replace(episodeP.EpisodeAndLanguages.Items[0].SeriesTitle, @"\(\w+ Dub\)", "").TrimEnd();
|
||||||
epMeta.SeasonTitle = episode.Items.FirstOrDefault(a => !dubPattern.IsMatch(a.SeasonTitle)).SeasonTitle ?? Regex.Replace(episode.Items[0].SeasonTitle, @"\(\w+ Dub\)", "").TrimEnd();
|
epMeta.SeasonTitle = episodeP.EpisodeAndLanguages.Items.FirstOrDefault(a => !dubPattern.IsMatch(a.SeasonTitle)).SeasonTitle ?? Regex.Replace(episodeP.EpisodeAndLanguages.Items[0].SeasonTitle, @"\(\w+ Dub\)", "").TrimEnd();
|
||||||
epMeta.EpisodeNumber = item.Episode;
|
epMeta.EpisodeNumber = item.Episode;
|
||||||
epMeta.EpisodeTitle = item.Title;
|
epMeta.EpisodeTitle = item.Title;
|
||||||
epMeta.SeasonId = item.SeasonId;
|
epMeta.SeasonId = item.SeasonId;
|
||||||
|
@ -224,9 +198,9 @@ public class CrEpisode(){
|
||||||
DownloadSpeed = 0
|
DownloadSpeed = 0
|
||||||
};
|
};
|
||||||
epMeta.AvailableSubs = item.SubtitleLocales;
|
epMeta.AvailableSubs = item.SubtitleLocales;
|
||||||
if (episode.Langs.Count > 0){
|
if (episodeP.EpisodeAndLanguages.Langs.Count > 0){
|
||||||
epMeta.SelectedDubs = dubLang
|
epMeta.SelectedDubs = dubLang
|
||||||
.Where(language => episode.Langs.Any(epLang => epLang.CrLocale == language))
|
.Where(language => episodeP.EpisodeAndLanguages.Langs.Any(epLang => epLang.CrLocale == language))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,22 +212,22 @@ public class CrEpisode(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret.TryGetValue(key, out var epMe)){
|
if (retMeta.Data != null){
|
||||||
epMetaData.Lang = episode.Langs[index];
|
epMetaData.Lang = episodeP.EpisodeAndLanguages.Langs[index];
|
||||||
epMe.Data?.Add(epMetaData);
|
retMeta.Data.Add(epMetaData);
|
||||||
|
|
||||||
} else{
|
} else{
|
||||||
epMetaData.Lang = episode.Langs[index];
|
epMetaData.Lang = episodeP.EpisodeAndLanguages.Langs[index];
|
||||||
epMeta.Data[0] = epMetaData;
|
epMeta.Data[0] = epMetaData;
|
||||||
ret.Add(key, epMeta);
|
retMeta = epMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// show ep
|
// show ep
|
||||||
item.SeqId = epNum;
|
item.SeqId = epNum;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return ret;
|
return retMeta;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -286,35 +286,49 @@ public class Crunchyroll{
|
||||||
|
|
||||||
|
|
||||||
if (episodeL != null){
|
if (episodeL != null){
|
||||||
if (episodeL.Value.Data != null && episodeL.Value.Data.First().IsPremiumOnly && !Profile.HasPremium){
|
if (episodeL.Value.IsPremiumOnly && !Profile.HasPremium){
|
||||||
MessageBus.Current.SendMessage(new ToastMessage($"Episode is a premium episode – make sure that you are signed in with an account that has an active premium subscription", ToastType.Error, 3));
|
MessageBus.Current.SendMessage(new ToastMessage($"Episode is a premium episode – make sure that you are signed in with an account that has an active premium subscription", ToastType.Error, 3));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sList = await CrEpisode.EpisodeData((CrunchyEpisodeList)episodeL);
|
var sList = await CrEpisode.EpisodeData((CrunchyEpisode)episodeL);
|
||||||
var selected = CrEpisode.EpisodeMeta(sList.Data, dubLang);
|
var selected = CrEpisode.EpisodeMeta(sList, dubLang);
|
||||||
var metas = selected.Values.ToList();
|
|
||||||
|
|
||||||
foreach (var crunchyEpMeta in metas){
|
if (selected.Data is{ Count: > 0 }){
|
||||||
|
if (CrunOptions.History){
|
||||||
|
var historyEpisode = CrHistory.GetHistoryEpisodeWithDownloadDir(selected.ShowId, selected.SeasonId, selected.Data.First().MediaId);
|
||||||
if (CrunOptions.SonarrProperties is{ SonarrEnabled: true, UseSonarrNumbering: true }){
|
if (CrunOptions.SonarrProperties is{ SonarrEnabled: true, UseSonarrNumbering: true }){
|
||||||
var historyEpisode = CrHistory.GetHistoryEpisode(crunchyEpMeta.ShowId, crunchyEpMeta.SeasonId, crunchyEpMeta.Data.First().MediaId);
|
if (historyEpisode.historyEpisode != null){
|
||||||
if (historyEpisode != null){
|
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrEpisodeNumber)){
|
||||||
if (!string.IsNullOrEmpty(historyEpisode.SonarrEpisodeNumber)){
|
selected.EpisodeNumber = historyEpisode.historyEpisode.SonarrEpisodeNumber;
|
||||||
crunchyEpMeta.EpisodeNumber = historyEpisode.SonarrEpisodeNumber;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(historyEpisode.SonarrSeasonNumber)){
|
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrSeasonNumber)){
|
||||||
crunchyEpMeta.Season = historyEpisode.SonarrSeasonNumber;
|
selected.Season = historyEpisode.historyEpisode.SonarrSeasonNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Queue.Add(crunchyEpMeta);
|
if (!string.IsNullOrEmpty(historyEpisode.downloadDirPath)){
|
||||||
|
selected.DownloadPath = historyEpisode.downloadDirPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Queue.Add(selected);
|
||||||
|
|
||||||
|
|
||||||
|
if (selected.Data.Count < dubLang.Count){
|
||||||
|
Console.WriteLine("Added Episode to Queue but couldn't find all selected dubs");
|
||||||
|
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");
|
Console.WriteLine("Added Episode to Queue");
|
||||||
MessageBus.Current.SendMessage(new ToastMessage($"Added episode to the queue", ToastType.Information, 1));
|
MessageBus.Current.SendMessage(new ToastMessage($"Added episode to the queue", ToastType.Information, 1));
|
||||||
}
|
}
|
||||||
|
} else{
|
||||||
|
Console.WriteLine("Episode couldn't be added to Queue");
|
||||||
|
MessageBus.Current.SendMessage(new ToastMessage($"Couldn't add episode to the queue with current dub settings", ToastType.Error, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSeriesToQueue(CrunchySeriesList list, CrunchyMultiDownload data){
|
public void AddSeriesToQueue(CrunchySeriesList list, CrunchyMultiDownload data){
|
||||||
|
@ -324,19 +338,25 @@ public class Crunchyroll{
|
||||||
|
|
||||||
foreach (var crunchyEpMeta in selected.Values.ToList()){
|
foreach (var crunchyEpMeta in selected.Values.ToList()){
|
||||||
if (crunchyEpMeta.Data?.First().Playback != null){
|
if (crunchyEpMeta.Data?.First().Playback != null){
|
||||||
|
if (CrunOptions.History){
|
||||||
|
var historyEpisode = CrHistory.GetHistoryEpisodeWithDownloadDir(crunchyEpMeta.ShowId, crunchyEpMeta.SeasonId, crunchyEpMeta.Data.First().MediaId);
|
||||||
if (CrunOptions.SonarrProperties is{ SonarrEnabled: true, UseSonarrNumbering: true }){
|
if (CrunOptions.SonarrProperties is{ SonarrEnabled: true, UseSonarrNumbering: true }){
|
||||||
var historyEpisode = CrHistory.GetHistoryEpisode(crunchyEpMeta.ShowId, crunchyEpMeta.SeasonId, crunchyEpMeta.Data.First().MediaId);
|
if (historyEpisode.historyEpisode != null){
|
||||||
if (historyEpisode != null){
|
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrEpisodeNumber)){
|
||||||
if (!string.IsNullOrEmpty(historyEpisode.SonarrEpisodeNumber)){
|
crunchyEpMeta.EpisodeNumber = historyEpisode.historyEpisode.SonarrEpisodeNumber;
|
||||||
crunchyEpMeta.EpisodeNumber = historyEpisode.SonarrEpisodeNumber;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(historyEpisode.SonarrSeasonNumber)){
|
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrSeasonNumber)){
|
||||||
crunchyEpMeta.Season = historyEpisode.SonarrSeasonNumber;
|
crunchyEpMeta.Season = historyEpisode.historyEpisode.SonarrSeasonNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(historyEpisode.downloadDirPath)){
|
||||||
|
crunchyEpMeta.DownloadPath = historyEpisode.downloadDirPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Queue.Add(crunchyEpMeta);
|
Queue.Add(crunchyEpMeta);
|
||||||
} else{
|
} else{
|
||||||
failed = true;
|
failed = true;
|
||||||
|
@ -596,7 +616,7 @@ public class Crunchyroll{
|
||||||
return new DownloadResponse{
|
return new DownloadResponse{
|
||||||
Data = files,
|
Data = files,
|
||||||
Error = true,
|
Error = true,
|
||||||
FileName = fileName.Length > 0 ? (Path.IsPathRooted(fileName) ? fileName : Path.Combine(CfgManager.PathVIDEOS_DIR, fileName)) : "./unknown",
|
FileName = "./unknown",
|
||||||
ErrorText = "Video Data not found"
|
ErrorText = "Video Data not found"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -604,11 +624,18 @@ public class Crunchyroll{
|
||||||
|
|
||||||
bool dlFailed = false;
|
bool dlFailed = false;
|
||||||
bool dlVideoOnce = false;
|
bool dlVideoOnce = false;
|
||||||
|
string fileDir = CfgManager.PathVIDEOS_DIR;
|
||||||
|
|
||||||
if (data.Data != null){
|
if (data.Data != null){
|
||||||
foreach (CrunchyEpMetaData epMeta in data.Data){
|
foreach (CrunchyEpMetaData epMeta in data.Data){
|
||||||
Console.WriteLine($"Requesting: [{epMeta.MediaId}] {mediaName}");
|
Console.WriteLine($"Requesting: [{epMeta.MediaId}] {mediaName}");
|
||||||
|
|
||||||
|
fileDir = !string.IsNullOrEmpty(data.DownloadPath) ? data.DownloadPath : !string.IsNullOrEmpty(options.DownloadDirPath) ? options.DownloadDirPath : CfgManager.PathVIDEOS_DIR;
|
||||||
|
|
||||||
|
if (!Helpers.IsValidPath(fileDir)){
|
||||||
|
fileDir = CfgManager.PathVIDEOS_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
string currentMediaId = (epMeta.MediaId.Contains(':') ? epMeta.MediaId.Split(':')[1] : epMeta.MediaId);
|
string currentMediaId = (epMeta.MediaId.Contains(':') ? epMeta.MediaId.Split(':')[1] : epMeta.MediaId);
|
||||||
|
|
||||||
await CrAuth.RefreshToken(true);
|
await CrAuth.RefreshToken(true);
|
||||||
|
@ -964,12 +991,13 @@ public class Crunchyroll{
|
||||||
Console.WriteLine($"\tServer: {selectedServer}");
|
Console.WriteLine($"\tServer: {selectedServer}");
|
||||||
Console.WriteLine("Stream URL:" + chosenVideoSegments.segments[0].uri.Split(new[]{ ",.urlset" }, StringSplitOptions.None)[0]);
|
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.Override).ToArray());
|
fileName = Path.Combine(FileNameManager.ParseFileName(options.FileName, variables, options.Numbers, options.Override).ToArray());
|
||||||
string outFile = Path.Combine(FileNameManager.ParseFileName(options.FileName + "." + (epMeta.Lang?.Name ?? lang.Value.Name), variables, options.Numbers, options.Override).ToArray());
|
string outFile = Path.Combine(FileNameManager.ParseFileName(options.FileName + "." + (epMeta.Lang?.Name ?? lang.Value.Name), variables, options.Numbers, options.Override).ToArray());
|
||||||
|
|
||||||
string tempFile = Path.Combine(FileNameManager.ParseFileName($"temp-{(currentVersion.Guid != null ? currentVersion.Guid : currentMediaId)}", variables, options.Numbers, options.Override)
|
string tempFile = Path.Combine(FileNameManager.ParseFileName($"temp-{(currentVersion.Guid != null ? currentVersion.Guid : currentMediaId)}", variables, options.Numbers, options.Override)
|
||||||
.ToArray());
|
.ToArray());
|
||||||
string tempTsFile = Path.IsPathRooted(tempFile) ? tempFile : Path.Combine(CfgManager.PathVIDEOS_DIR, tempFile);
|
string tempTsFile = Path.IsPathRooted(tempFile) ? tempFile : Path.Combine(fileDir, tempFile);
|
||||||
|
|
||||||
bool audioDownloaded = false, videoDownloaded = false;
|
bool audioDownloaded = false, videoDownloaded = false;
|
||||||
|
|
||||||
|
@ -978,7 +1006,7 @@ public class Crunchyroll{
|
||||||
} else if (options.Novids){
|
} else if (options.Novids){
|
||||||
Console.WriteLine("Skipping video download...");
|
Console.WriteLine("Skipping video download...");
|
||||||
} else{
|
} else{
|
||||||
var videoDownloadResult = await DownloadVideo(chosenVideoSegments, options, outFile, tsFile, tempTsFile, data);
|
var videoDownloadResult = await DownloadVideo(chosenVideoSegments, options, outFile, tsFile, tempTsFile, data, fileDir);
|
||||||
|
|
||||||
tsFile = videoDownloadResult.tsFile;
|
tsFile = videoDownloadResult.tsFile;
|
||||||
|
|
||||||
|
@ -993,7 +1021,7 @@ public class Crunchyroll{
|
||||||
|
|
||||||
|
|
||||||
if (chosenAudioSegments.segments.Count > 0 && !options.Noaudio && !dlFailed){
|
if (chosenAudioSegments.segments.Count > 0 && !options.Noaudio && !dlFailed){
|
||||||
var audioDownloadResult = await DownloadAudio(chosenAudioSegments, options, outFile, tsFile, tempTsFile, data);
|
var audioDownloadResult = await DownloadAudio(chosenAudioSegments, options, outFile, tsFile, tempTsFile, data, fileDir);
|
||||||
|
|
||||||
tsFile = audioDownloadResult.tsFile;
|
tsFile = audioDownloadResult.tsFile;
|
||||||
|
|
||||||
|
@ -1011,7 +1039,7 @@ public class Crunchyroll{
|
||||||
return new DownloadResponse{
|
return new DownloadResponse{
|
||||||
Data = files,
|
Data = files,
|
||||||
Error = dlFailed,
|
Error = dlFailed,
|
||||||
FileName = fileName.Length > 0 ? (Path.IsPathRooted(fileName) ? fileName : Path.Combine(CfgManager.PathVIDEOS_DIR, fileName)) : "./unknown",
|
FileName = fileName.Length > 0 ? (Path.IsPathRooted(fileName) ? fileName : Path.Combine(fileDir, fileName)) : "./unknown",
|
||||||
ErrorText = ""
|
ErrorText = ""
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1037,7 +1065,7 @@ public class Crunchyroll{
|
||||||
return new DownloadResponse{
|
return new DownloadResponse{
|
||||||
Data = files,
|
Data = files,
|
||||||
Error = dlFailed,
|
Error = dlFailed,
|
||||||
FileName = fileName.Length > 0 ? (Path.IsPathRooted(fileName) ? fileName : Path.Combine(CfgManager.PathVIDEOS_DIR, fileName)) : "./unknown",
|
FileName = fileName.Length > 0 ? (Path.IsPathRooted(fileName) ? fileName : Path.Combine(fileDir, fileName)) : "./unknown",
|
||||||
ErrorText = "Decryption Needed but couldn't find CDM files"
|
ErrorText = "Decryption Needed but couldn't find CDM files"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1065,7 +1093,7 @@ public class Crunchyroll{
|
||||||
return new DownloadResponse{
|
return new DownloadResponse{
|
||||||
Data = files,
|
Data = files,
|
||||||
Error = dlFailed,
|
Error = dlFailed,
|
||||||
FileName = fileName.Length > 0 ? (Path.IsPathRooted(fileName) ? fileName : Path.Combine(CfgManager.PathVIDEOS_DIR, fileName)) : "./unknown",
|
FileName = fileName.Length > 0 ? (Path.IsPathRooted(fileName) ? fileName : Path.Combine(fileDir, fileName)) : "./unknown",
|
||||||
ErrorText = "DRM Authentication failed"
|
ErrorText = "DRM Authentication failed"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1083,7 +1111,7 @@ public class Crunchyroll{
|
||||||
return new DownloadResponse{
|
return new DownloadResponse{
|
||||||
Data = files,
|
Data = files,
|
||||||
Error = dlFailed,
|
Error = dlFailed,
|
||||||
FileName = fileName.Length > 0 ? (Path.IsPathRooted(fileName) ? fileName : Path.Combine(CfgManager.PathVIDEOS_DIR, fileName)) : "./unknown",
|
FileName = fileName.Length > 0 ? (Path.IsPathRooted(fileName) ? fileName : Path.Combine(fileDir, fileName)) : "./unknown",
|
||||||
ErrorText = "Couldn't get DRM encryption keys"
|
ErrorText = "Couldn't get DRM encryption keys"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1249,7 +1277,7 @@ public class Crunchyroll{
|
||||||
if (Path.IsPathRooted(outFile)){
|
if (Path.IsPathRooted(outFile)){
|
||||||
tsFile = outFile;
|
tsFile = outFile;
|
||||||
} else{
|
} else{
|
||||||
tsFile = Path.Combine(CfgManager.PathVIDEOS_DIR, outFile);
|
tsFile = Path.Combine(fileDir, outFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the path is absolute
|
// Check if the path is absolute
|
||||||
|
@ -1259,7 +1287,7 @@ public class Crunchyroll{
|
||||||
string[] directories = Path.GetDirectoryName(outFile)?.Split(Path.DirectorySeparatorChar) ?? Array.Empty<string>();
|
string[] directories = Path.GetDirectoryName(outFile)?.Split(Path.DirectorySeparatorChar) ?? Array.Empty<string>();
|
||||||
|
|
||||||
// Initialize the cumulative path based on whether the original path is absolute or not
|
// Initialize the cumulative path based on whether the original path is absolute or not
|
||||||
string cumulativePath = isAbsolute ? "" : CfgManager.PathVIDEOS_DIR;
|
string cumulativePath = isAbsolute ? "" : fileDir;
|
||||||
for (int i = 0; i < directories.Length; i++){
|
for (int i = 0; i < directories.Length; i++){
|
||||||
// Build the path incrementally
|
// Build the path incrementally
|
||||||
cumulativePath = Path.Combine(cumulativePath, directories[i]);
|
cumulativePath = Path.Combine(cumulativePath, directories[i]);
|
||||||
|
@ -1295,7 +1323,7 @@ public class Crunchyroll{
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.SkipSubs && options.DlSubs.IndexOf("none") == -1){
|
if (!options.SkipSubs && options.DlSubs.IndexOf("none") == -1){
|
||||||
await DownloadSubtitles(options, pbData, audDub, fileName, files);
|
await DownloadSubtitles(options, pbData, audDub, fileName, files, fileDir);
|
||||||
} else{
|
} else{
|
||||||
Console.WriteLine("Subtitles downloading skipped!");
|
Console.WriteLine("Subtitles downloading skipped!");
|
||||||
}
|
}
|
||||||
|
@ -1311,12 +1339,12 @@ public class Crunchyroll{
|
||||||
return new DownloadResponse{
|
return new DownloadResponse{
|
||||||
Data = files,
|
Data = files,
|
||||||
Error = dlFailed,
|
Error = dlFailed,
|
||||||
FileName = fileName.Length > 0 ? (Path.IsPathRooted(fileName) ? fileName : Path.Combine(CfgManager.PathVIDEOS_DIR, fileName)) : "./unknown",
|
FileName = fileName.Length > 0 ? (Path.IsPathRooted(fileName) ? fileName : Path.Combine(fileDir, fileName)) : "./unknown",
|
||||||
ErrorText = ""
|
ErrorText = ""
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task DownloadSubtitles(CrDownloadOptions options, PlaybackData pbData, string audDub, string fileName, List<DownloadedMedia> files){
|
private static async Task DownloadSubtitles(CrDownloadOptions options, PlaybackData pbData, string audDub, string fileName, List<DownloadedMedia> files, string fileDir){
|
||||||
if (pbData.Meta != null && pbData.Meta.Subtitles != null && pbData.Meta.Subtitles.Count > 0){
|
if (pbData.Meta != null && pbData.Meta.Subtitles != null && pbData.Meta.Subtitles.Count > 0){
|
||||||
List<SubtitleInfo> subsData = pbData.Meta.Subtitles.Values.ToList();
|
List<SubtitleInfo> subsData = pbData.Meta.Subtitles.Values.ToList();
|
||||||
List<SubtitleInfo> capsData = pbData.Meta.ClosedCaptions?.Values.ToList() ?? new List<SubtitleInfo>();
|
List<SubtitleInfo> capsData = pbData.Meta.ClosedCaptions?.Values.ToList() ?? new List<SubtitleInfo>();
|
||||||
|
@ -1354,26 +1382,9 @@ public class Crunchyroll{
|
||||||
var isSigns = langItem.Code == audDub && !subsItem.isCC;
|
var isSigns = langItem.Code == audDub && !subsItem.isCC;
|
||||||
var isCc = subsItem.isCC;
|
var isCc = subsItem.isCC;
|
||||||
sxData.File = Languages.SubsFile(fileName, index + "", langItem, isCc, options.CcTag, isSigns, subsItem.format);
|
sxData.File = Languages.SubsFile(fileName, index + "", langItem, isCc, options.CcTag, isSigns, subsItem.format);
|
||||||
sxData.Path = Path.Combine(CfgManager.PathVIDEOS_DIR, sxData.File);
|
sxData.Path = Path.Combine(fileDir, sxData.File);
|
||||||
|
|
||||||
// Check if the path is absolute
|
Helpers.EnsureDirectoriesExist(sxData.Path);
|
||||||
bool isAbsolute = Path.IsPathRooted(sxData.Path);
|
|
||||||
|
|
||||||
// Get all directory parts of the path except the last segment (assuming it's a file)
|
|
||||||
string[] directories = Path.GetDirectoryName(sxData.Path)?.Split(Path.DirectorySeparatorChar) ?? Array.Empty<string>();
|
|
||||||
|
|
||||||
// Initialize the cumulative path based on whether the original path is absolute or not
|
|
||||||
string cumulativePath = isAbsolute ? "" : CfgManager.PathVIDEOS_DIR;
|
|
||||||
for (int i = 0; i < directories.Length; i++){
|
|
||||||
// Build the path incrementally
|
|
||||||
cumulativePath = Path.Combine(cumulativePath, directories[i]);
|
|
||||||
|
|
||||||
// Check if the directory exists and create it if it does not
|
|
||||||
if (!Directory.Exists(cumulativePath)){
|
|
||||||
Directory.CreateDirectory(cumulativePath);
|
|
||||||
Console.WriteLine($"Created directory: {cumulativePath}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if any file matches the specified conditions
|
// Check if any file matches the specified conditions
|
||||||
if (files.Any(a => a.Type == DownloadMediaType.Subtitle &&
|
if (files.Any(a => a.Type == DownloadMediaType.Subtitle &&
|
||||||
|
@ -1437,7 +1448,8 @@ public class Crunchyroll{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<(bool Ok, PartsData Parts, string tsFile)> DownloadVideo(VideoItem chosenVideoSegments, CrDownloadOptions options, string outFile, string tsFile, string tempTsFile, CrunchyEpMeta data){
|
private async Task<(bool Ok, PartsData Parts, string tsFile)> DownloadVideo(VideoItem chosenVideoSegments, CrDownloadOptions options, string outFile, string tsFile, string tempTsFile, CrunchyEpMeta data,
|
||||||
|
string fileDir){
|
||||||
// Prepare for video download
|
// Prepare for video download
|
||||||
int totalParts = chosenVideoSegments.segments.Count;
|
int totalParts = chosenVideoSegments.segments.Count;
|
||||||
int mathParts = (int)Math.Ceiling((double)totalParts / options.Partsize);
|
int mathParts = (int)Math.Ceiling((double)totalParts / options.Partsize);
|
||||||
|
@ -1447,28 +1459,10 @@ public class Crunchyroll{
|
||||||
if (Path.IsPathRooted(outFile)){
|
if (Path.IsPathRooted(outFile)){
|
||||||
tsFile = outFile;
|
tsFile = outFile;
|
||||||
} else{
|
} else{
|
||||||
tsFile = Path.Combine(CfgManager.PathVIDEOS_DIR, outFile);
|
tsFile = Path.Combine(fileDir, outFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// var split = outFile.Split(Path.DirectorySeparatorChar).AsSpan().Slice(0, -1).ToArray();
|
Helpers.EnsureDirectoriesExist(outFile);
|
||||||
// Check if the path is absolute
|
|
||||||
bool isAbsolute = Path.IsPathRooted(outFile);
|
|
||||||
|
|
||||||
// Get all directory parts of the path except the last segment (assuming it's a file)
|
|
||||||
string[] directories = Path.GetDirectoryName(outFile)?.Split(Path.DirectorySeparatorChar) ?? Array.Empty<string>();
|
|
||||||
|
|
||||||
// Initialize the cumulative path based on whether the original path is absolute or not
|
|
||||||
string cumulativePath = isAbsolute ? "" : CfgManager.PathVIDEOS_DIR;
|
|
||||||
for (int i = 0; i < directories.Length; i++){
|
|
||||||
// Build the path incrementally
|
|
||||||
cumulativePath = Path.Combine(cumulativePath, directories[i]);
|
|
||||||
|
|
||||||
// Check if the directory exists and create it if it does not
|
|
||||||
if (!Directory.Exists(cumulativePath)){
|
|
||||||
Directory.CreateDirectory(cumulativePath);
|
|
||||||
Console.WriteLine($"Created directory: {cumulativePath}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
M3U8Json videoJson = new M3U8Json{
|
M3U8Json videoJson = new M3U8Json{
|
||||||
Segments = chosenVideoSegments.segments.Cast<dynamic>().ToList()
|
Segments = chosenVideoSegments.segments.Cast<dynamic>().ToList()
|
||||||
|
@ -1489,7 +1483,8 @@ public class Crunchyroll{
|
||||||
return (videoDownloadResult.Ok, videoDownloadResult.Parts, tsFile);
|
return (videoDownloadResult.Ok, videoDownloadResult.Parts, tsFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<(bool Ok, PartsData Parts, string tsFile)> DownloadAudio(AudioItem chosenAudioSegments, CrDownloadOptions options, string outFile, string tsFile, string tempTsFile, CrunchyEpMeta data){
|
private async Task<(bool Ok, PartsData Parts, string tsFile)> DownloadAudio(AudioItem chosenAudioSegments, CrDownloadOptions options, string outFile, string tsFile, string tempTsFile, CrunchyEpMeta data,
|
||||||
|
string fileDir){
|
||||||
// Prepare for audio download
|
// Prepare for audio download
|
||||||
int totalParts = chosenAudioSegments.segments.Count;
|
int totalParts = chosenAudioSegments.segments.Count;
|
||||||
int mathParts = (int)Math.Ceiling((double)totalParts / options.Partsize);
|
int mathParts = (int)Math.Ceiling((double)totalParts / options.Partsize);
|
||||||
|
@ -1499,7 +1494,7 @@ public class Crunchyroll{
|
||||||
if (Path.IsPathRooted(outFile)){
|
if (Path.IsPathRooted(outFile)){
|
||||||
tsFile = outFile;
|
tsFile = outFile;
|
||||||
} else{
|
} else{
|
||||||
tsFile = Path.Combine(CfgManager.PathVIDEOS_DIR, outFile);
|
tsFile = Path.Combine(fileDir, outFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the path is absolute
|
// Check if the path is absolute
|
||||||
|
@ -1509,7 +1504,7 @@ public class Crunchyroll{
|
||||||
string[] directories = Path.GetDirectoryName(outFile)?.Split(Path.DirectorySeparatorChar) ?? Array.Empty<string>();
|
string[] directories = Path.GetDirectoryName(outFile)?.Split(Path.DirectorySeparatorChar) ?? Array.Empty<string>();
|
||||||
|
|
||||||
// Initialize the cumulative path based on whether the original path is absolute or not
|
// Initialize the cumulative path based on whether the original path is absolute or not
|
||||||
string cumulativePath = isAbsolute ? "" : CfgManager.PathVIDEOS_DIR;
|
string cumulativePath = isAbsolute ? "" : fileDir;
|
||||||
for (int i = 0; i < directories.Length; i++){
|
for (int i = 0; i < directories.Length; i++){
|
||||||
// Build the path incrementally
|
// Build the path incrementally
|
||||||
cumulativePath = Path.Combine(cumulativePath, directories[i]);
|
cumulativePath = Path.Combine(cumulativePath, directories[i]);
|
||||||
|
|
|
@ -90,7 +90,6 @@ public class History(){
|
||||||
var historyEpisode = historySeason.EpisodesList.Find(e => e.EpisodeId == episodeId);
|
var historyEpisode = historySeason.EpisodesList.Find(e => e.EpisodeId == episodeId);
|
||||||
|
|
||||||
if (historyEpisode != null){
|
if (historyEpisode != null){
|
||||||
|
|
||||||
return historyEpisode;
|
return historyEpisode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +98,32 @@ public class History(){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public (HistoryEpisode? historyEpisode, string downloadDirPath) GetHistoryEpisodeWithDownloadDir(string? seriesId, string? seasonId, string episodeId){
|
||||||
|
var historySeries = crunInstance.HistoryList.FirstOrDefault(series => series.SeriesId == seriesId);
|
||||||
|
|
||||||
|
var downloadDirPath = "";
|
||||||
|
|
||||||
|
if (historySeries != null){
|
||||||
|
var historySeason = historySeries.Seasons.Find(s => s.SeasonId == seasonId);
|
||||||
|
if (!string.IsNullOrEmpty(historySeries.SeriesDownloadPath)){
|
||||||
|
downloadDirPath = historySeries.SeriesDownloadPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (historySeason != null){
|
||||||
|
var historyEpisode = historySeason.EpisodesList.Find(e => e.EpisodeId == episodeId);
|
||||||
|
if (!string.IsNullOrEmpty(historySeason.SeasonDownloadPath)){
|
||||||
|
downloadDirPath = historySeason.SeasonDownloadPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (historyEpisode != null){
|
||||||
|
return (historyEpisode, downloadDirPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (null, downloadDirPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task UpdateWithEpisode(CrunchyEpisode episodeParam){
|
public async Task UpdateWithEpisode(CrunchyEpisode episodeParam){
|
||||||
var episode = episodeParam;
|
var episode = episodeParam;
|
||||||
|
@ -106,15 +131,13 @@ public class History(){
|
||||||
if (episode.Versions != null){
|
if (episode.Versions != null){
|
||||||
var version = episode.Versions.Find(a => a.Original);
|
var version = episode.Versions.Find(a => a.Original);
|
||||||
if (version.AudioLocale != episode.AudioLocale){
|
if (version.AudioLocale != episode.AudioLocale){
|
||||||
var episodeById = await crunInstance.CrEpisode.ParseEpisodeById(version.Guid, "");
|
var crEpisode = await crunInstance.CrEpisode.ParseEpisodeById(version.Guid, "");
|
||||||
if (episodeById?.Data != null){
|
if (crEpisode != null){
|
||||||
if (episodeById.Value.Total != 1){
|
episode = crEpisode.Value;
|
||||||
|
} else{
|
||||||
MessageBus.Current.SendMessage(new ToastMessage($"Couldn't update download History", ToastType.Warning, 1));
|
MessageBus.Current.SendMessage(new ToastMessage($"Couldn't update download History", ToastType.Warning, 1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
episode = episodeById.Value.Data.First();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,6 +285,7 @@ public class History(){
|
||||||
|
|
||||||
historySeries.UpdateNewEpisodes();
|
historySeries.UpdateNewEpisodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
var sortedList = crunInstance.HistoryList.OrderBy(item => item.SeriesTitle).ToList();
|
var sortedList = crunInstance.HistoryList.OrderBy(item => item.SeriesTitle).ToList();
|
||||||
crunInstance.HistoryList.Clear();
|
crunInstance.HistoryList.Clear();
|
||||||
foreach (var item in sortedList){
|
foreach (var item in sortedList){
|
||||||
|
@ -341,7 +365,6 @@ public class History(){
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MatchHistorySeriesWithSonarr(bool updateAll){
|
public void MatchHistorySeriesWithSonarr(bool updateAll){
|
||||||
|
|
||||||
if (crunInstance.CrunOptions.SonarrProperties is{ SonarrEnabled: false }){
|
if (crunInstance.CrunOptions.SonarrProperties is{ SonarrEnabled: false }){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -551,6 +574,9 @@ public class HistorySeries : INotifyPropertyChanged{
|
||||||
[JsonProperty("series_season_list")]
|
[JsonProperty("series_season_list")]
|
||||||
public required List<HistorySeason> Seasons{ get; set; }
|
public required List<HistorySeason> Seasons{ get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("series_download_path")]
|
||||||
|
public string? SeriesDownloadPath{ get; set; }
|
||||||
|
|
||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
|
@ -662,6 +688,9 @@ public class HistorySeason : INotifyPropertyChanged{
|
||||||
[JsonProperty("season_episode_list")]
|
[JsonProperty("season_episode_list")]
|
||||||
public required List<HistoryEpisode> EpisodesList{ get; set; }
|
public required List<HistoryEpisode> EpisodesList{ get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("series_download_path")]
|
||||||
|
public string? SeasonDownloadPath{ get; set; }
|
||||||
|
|
||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
public void UpdateDownloaded(string? EpisodeId){
|
public void UpdateDownloaded(string? EpisodeId){
|
||||||
|
|
|
@ -27,6 +27,64 @@ public class Helpers{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void EnsureDirectoriesExist(string path){
|
||||||
|
// Check if the path is absolute
|
||||||
|
bool isAbsolute = Path.IsPathRooted(path);
|
||||||
|
|
||||||
|
// Get all directory parts of the path except the last segment (assuming it's a file)
|
||||||
|
string directoryPath = Path.GetDirectoryName(path);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(directoryPath)){
|
||||||
|
Console.WriteLine("The provided path does not contain any directory information.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the cumulative path based on whether the original path is absolute or not
|
||||||
|
string cumulativePath = isAbsolute ? Path.GetPathRoot(directoryPath) : Environment.CurrentDirectory;
|
||||||
|
|
||||||
|
// Get all directory parts
|
||||||
|
string[] directories = directoryPath.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||||
|
|
||||||
|
// Start the loop from the correct initial index
|
||||||
|
int startIndex = isAbsolute && directories.Length > 0 && string.IsNullOrEmpty(directories[0]) ? 2 : 0;
|
||||||
|
|
||||||
|
for (int i = startIndex; i < directories.Length; i++){
|
||||||
|
// Skip empty parts (which can occur with UNC paths)
|
||||||
|
if (string.IsNullOrEmpty(directories[i])){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the path incrementally
|
||||||
|
cumulativePath = Path.Combine(cumulativePath, directories[i]);
|
||||||
|
|
||||||
|
// Check if the directory exists and create it if it does not
|
||||||
|
if (!Directory.Exists(cumulativePath)){
|
||||||
|
Directory.CreateDirectory(cumulativePath);
|
||||||
|
Console.WriteLine($"Created directory: {cumulativePath}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsValidPath(string path){
|
||||||
|
char[] invalidChars = Path.GetInvalidPathChars();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(path)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.Any(ch => invalidChars.Contains(ch))){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
// Use Path.GetFullPath to ensure that the path can be fully qualified
|
||||||
|
string fullPath = Path.GetFullPath(path);
|
||||||
|
return true;
|
||||||
|
} catch (Exception){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Locale ConvertStringToLocale(string? value){
|
public static Locale ConvertStringToLocale(string? value){
|
||||||
foreach (Locale locale in Enum.GetValues(typeof(Locale))){
|
foreach (Locale locale in Enum.GetValues(typeof(Locale))){
|
||||||
var type = typeof(Locale);
|
var type = typeof(Locale);
|
||||||
|
|
|
@ -125,4 +125,7 @@ public class CrDownloadOptions{
|
||||||
[YamlMember(Alias = "stream_endpoint", ApplyNamingConventions = false)]
|
[YamlMember(Alias = "stream_endpoint", ApplyNamingConventions = false)]
|
||||||
public string? StreamEndpoint{ get; set; }
|
public string? StreamEndpoint{ get; set; }
|
||||||
|
|
||||||
|
[YamlMember(Alias = "download_dir_path", ApplyNamingConventions = false)]
|
||||||
|
public string? DownloadDirPath{ get; set; }
|
||||||
|
|
||||||
}
|
}
|
|
@ -247,6 +247,9 @@ public class CrunchyEpMeta{
|
||||||
public List<string>? SelectedDubs{ get; set; }
|
public List<string>? SelectedDubs{ get; set; }
|
||||||
|
|
||||||
public List<string>? AvailableSubs{ get; set; }
|
public List<string>? AvailableSubs{ get; set; }
|
||||||
|
|
||||||
|
public string? DownloadPath{ get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DownloadProgress{
|
public class DownloadProgress{
|
||||||
|
@ -267,4 +270,10 @@ public struct CrunchyEpMetaData{
|
||||||
public List<EpisodeVersion>? Versions{ get; set; }
|
public List<EpisodeVersion>? Versions{ get; set; }
|
||||||
public bool IsSubbed{ get; set; }
|
public bool IsSubbed{ get; set; }
|
||||||
public bool IsDubbed{ get; set; }
|
public bool IsDubbed{ get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct CrunchyRollEpisodeData{
|
||||||
|
public string Key{ get; set; }
|
||||||
|
public EpisodeAndLanguage EpisodeAndLanguages{ get; set; }
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia.Platform.Storage;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
@ -21,6 +22,8 @@ public partial class SeriesPageViewModel : ViewModelBase{
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public static bool _sonarrAvailable;
|
public static bool _sonarrAvailable;
|
||||||
|
|
||||||
|
private IStorageProvider _storageProvider;
|
||||||
|
|
||||||
public SeriesPageViewModel(){
|
public SeriesPageViewModel(){
|
||||||
_selectedSeries = Crunchyroll.Instance.SelectedSeries;
|
_selectedSeries = Crunchyroll.Instance.SelectedSeries;
|
||||||
|
|
||||||
|
@ -38,6 +41,38 @@ public partial class SeriesPageViewModel : ViewModelBase{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public async Task OpenFolderDialogAsync(HistorySeason? season){
|
||||||
|
if (_storageProvider == null){
|
||||||
|
Console.Error.WriteLine("StorageProvider must be set before using the dialog.");
|
||||||
|
throw new InvalidOperationException("StorageProvider must be set before using the dialog.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions{
|
||||||
|
Title = "Select Folder"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.Count > 0){
|
||||||
|
var selectedFolder = result[0];
|
||||||
|
// Do something with the selected folder path
|
||||||
|
Console.WriteLine($"Selected folder: {selectedFolder.Path.LocalPath}");
|
||||||
|
|
||||||
|
if (season != null){
|
||||||
|
season.SeasonDownloadPath = selectedFolder.Path.LocalPath;
|
||||||
|
} else{
|
||||||
|
SelectedSeries.SeriesDownloadPath = selectedFolder.Path.LocalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
CfgManager.WriteJsonToFile(CfgManager.PathCrHistory, Crunchyroll.Instance.HistoryList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetStorageProvider(IStorageProvider storageProvider){
|
||||||
|
_storageProvider = storageProvider ?? throw new ArgumentNullException(nameof(storageProvider));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public void OpenSonarrPage(){
|
public void OpenSonarrPage(){
|
||||||
var sonarrProp = Crunchyroll.Instance.CrunOptions.SonarrProperties;
|
var sonarrProp = Crunchyroll.Instance.CrunOptions.SonarrProperties;
|
||||||
|
|
|
@ -6,9 +6,11 @@ using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Platform.Storage;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
@ -249,15 +251,19 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
||||||
new ComboBoxItem(){ Content = "tv/samsung" },
|
new ComboBoxItem(){ Content = "tv/samsung" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _downloadDirPath;
|
||||||
|
|
||||||
private readonly FluentAvaloniaTheme _faTheme;
|
private readonly FluentAvaloniaTheme _faTheme;
|
||||||
|
|
||||||
private bool settingsLoaded;
|
private bool settingsLoaded;
|
||||||
|
|
||||||
|
private IStorageProvider _storageProvider;
|
||||||
|
|
||||||
public SettingsPageViewModel(){
|
public SettingsPageViewModel(){
|
||||||
var version = Assembly.GetExecutingAssembly().GetName().Version;
|
var version = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
_currentVersion = $"{version?.Major}.{version?.Minor}.{version?.Build}";
|
_currentVersion = $"{version?.Major}.{version?.Minor}.{version?.Build}";
|
||||||
|
|
||||||
|
|
||||||
_faTheme = App.Current.Styles[0] as FluentAvaloniaTheme;
|
_faTheme = App.Current.Styles[0] as FluentAvaloniaTheme;
|
||||||
|
|
||||||
foreach (var languageItem in Languages.languages){
|
foreach (var languageItem in Languages.languages){
|
||||||
|
@ -270,6 +276,8 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
||||||
|
|
||||||
CrDownloadOptions options = Crunchyroll.Instance.CrunOptions;
|
CrDownloadOptions options = Crunchyroll.Instance.CrunOptions;
|
||||||
|
|
||||||
|
DownloadDirPath = string.IsNullOrEmpty(options.DownloadDirPath) ? CfgManager.PathVIDEOS_DIR : options.DownloadDirPath;
|
||||||
|
|
||||||
ComboBoxItem? hsLang = HardSubLangList.FirstOrDefault(a => a.Content != null && (string)a.Content == options.Hslang) ?? null;
|
ComboBoxItem? hsLang = HardSubLangList.FirstOrDefault(a => a.Content != null && (string)a.Content == options.Hslang) ?? null;
|
||||||
SelectedHSLang = hsLang ?? HardSubLangList[0];
|
SelectedHSLang = hsLang ?? HardSubLangList[0];
|
||||||
|
|
||||||
|
@ -524,6 +532,32 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
||||||
RaisePropertyChanged(nameof(FfmpegOptions));
|
RaisePropertyChanged(nameof(FfmpegOptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public async Task OpenFolderDialogAsync(){
|
||||||
|
if (_storageProvider == null){
|
||||||
|
Console.Error.WriteLine("StorageProvider must be set before using the dialog.");
|
||||||
|
throw new InvalidOperationException("StorageProvider must be set before using the dialog.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions{
|
||||||
|
Title = "Select Folder"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.Count > 0){
|
||||||
|
var selectedFolder = result[0];
|
||||||
|
// Do something with the selected folder path
|
||||||
|
Console.WriteLine($"Selected folder: {selectedFolder.Path.LocalPath}");
|
||||||
|
Crunchyroll.Instance.CrunOptions.DownloadDirPath = selectedFolder.Path.LocalPath;
|
||||||
|
DownloadDirPath = string.IsNullOrEmpty(Crunchyroll.Instance.CrunOptions.DownloadDirPath) ? CfgManager.PathVIDEOS_DIR : Crunchyroll.Instance.CrunOptions.DownloadDirPath;
|
||||||
|
CfgManager.WriteSettingsToFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetStorageProvider(IStorageProvider storageProvider){
|
||||||
|
_storageProvider = storageProvider ?? throw new ArgumentNullException(nameof(storageProvider));
|
||||||
|
}
|
||||||
|
|
||||||
partial void OnCurrentAppThemeChanged(ComboBoxItem? value){
|
partial void OnCurrentAppThemeChanged(ComboBoxItem? value){
|
||||||
if (value?.Content?.ToString() == "System"){
|
if (value?.Content?.ToString() == "System"){
|
||||||
_faTheme.PreferSystemTheme = true;
|
_faTheme.PreferSystemTheme = true;
|
||||||
|
|
|
@ -58,10 +58,16 @@ public partial class MainWindow : AppWindow{
|
||||||
if (message.Refresh){
|
if (message.Refresh){
|
||||||
navigationStack.Pop();
|
navigationStack.Pop();
|
||||||
var viewModel = Activator.CreateInstance(message.ViewModelType);
|
var viewModel = Activator.CreateInstance(message.ViewModelType);
|
||||||
|
if (viewModel is SeriesPageViewModel){
|
||||||
|
((SeriesPageViewModel)viewModel).SetStorageProvider(StorageProvider);
|
||||||
|
}
|
||||||
navigationStack.Push(viewModel);
|
navigationStack.Push(viewModel);
|
||||||
nv.Content = viewModel;
|
nv.Content = viewModel;
|
||||||
} else if (!message.Back && message.ViewModelType != null){
|
} else if (!message.Back && message.ViewModelType != null){
|
||||||
var viewModel = Activator.CreateInstance(message.ViewModelType);
|
var viewModel = Activator.CreateInstance(message.ViewModelType);
|
||||||
|
if (viewModel is SeriesPageViewModel){
|
||||||
|
((SeriesPageViewModel)viewModel).SetStorageProvider(StorageProvider);
|
||||||
|
}
|
||||||
navigationStack.Push(viewModel);
|
navigationStack.Push(viewModel);
|
||||||
nv.Content = viewModel;
|
nv.Content = viewModel;
|
||||||
} else{
|
} else{
|
||||||
|
@ -119,7 +125,9 @@ public partial class MainWindow : AppWindow{
|
||||||
selectedNavVieItem = selectedItem;
|
selectedNavVieItem = selectedItem;
|
||||||
break;
|
break;
|
||||||
case "Settings":
|
case "Settings":
|
||||||
navView.Content = Activator.CreateInstance(typeof(SettingsPageViewModel));
|
var viewModel = (SettingsPageViewModel)Activator.CreateInstance(typeof(SettingsPageViewModel));
|
||||||
|
viewModel.SetStorageProvider(StorageProvider);
|
||||||
|
navView.Content = viewModel;
|
||||||
selectedNavVieItem = selectedItem;
|
selectedNavVieItem = selectedItem;
|
||||||
break;
|
break;
|
||||||
case "UpdateAvailable":
|
case "UpdateAvailable":
|
||||||
|
|
|
@ -66,7 +66,19 @@
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<Button Command="{Binding UpdateData}" Margin="0 0 5 10">Fetch Series</Button>
|
<Button Command="{Binding UpdateData}" Margin="0 0 5 10">Fetch Series</Button>
|
||||||
<ToggleButton IsChecked="{Binding EditMode}" Margin="0 0 0 10">Edit</ToggleButton>
|
<ToggleButton IsChecked="{Binding EditMode}" Margin="0 0 5 10">Edit</ToggleButton>
|
||||||
|
|
||||||
|
<Button Margin="0 0 5 10" FontStyle="Italic"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Command="{Binding OpenFolderDialogAsync}">
|
||||||
|
<ToolTip.Tip>
|
||||||
|
<TextBlock Text="{Binding SelectedSeries.SeriesDownloadPath}" FontSize="15" />
|
||||||
|
</ToolTip.Tip>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<controls:SymbolIcon Symbol="Folder" FontSize="18" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
|
||||||
|
@ -111,10 +123,12 @@
|
||||||
IsVisible="{Binding $parent[ItemsControl].((vm:SeriesPageViewModel)DataContext).SonarrAvailable}">
|
IsVisible="{Binding $parent[ItemsControl].((vm:SeriesPageViewModel)DataContext).SonarrAvailable}">
|
||||||
|
|
||||||
|
|
||||||
<controls:ImageIcon IsVisible="{Binding SonarrHasFile}" Source="../Assets/sonarr.png" Width="25"
|
<controls:ImageIcon IsVisible="{Binding SonarrHasFile}"
|
||||||
|
Source="../Assets/sonarr.png" Width="25"
|
||||||
Height="25" />
|
Height="25" />
|
||||||
|
|
||||||
<controls:ImageIcon IsVisible="{Binding !SonarrHasFile}" Source="../Assets/sonarr_inactive.png" Width="25"
|
<controls:ImageIcon IsVisible="{Binding !SonarrHasFile}"
|
||||||
|
Source="../Assets/sonarr_inactive.png" Width="25"
|
||||||
Height="25" />
|
Height="25" />
|
||||||
|
|
||||||
|
|
||||||
|
@ -171,6 +185,19 @@
|
||||||
<controls:SymbolIcon Symbol="Refresh" FontSize="18" />
|
<controls:SymbolIcon Symbol="Refresh" FontSize="18" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<Button Margin="10 0 0 0" FontStyle="Italic"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Command="{Binding $parent[UserControl].((vm:SeriesPageViewModel)DataContext).OpenFolderDialogAsync}"
|
||||||
|
CommandParameter="{Binding .}">
|
||||||
|
<ToolTip.Tip>
|
||||||
|
<TextBlock Text="{Binding SeasonDownloadPath}" FontSize="15" />
|
||||||
|
</ToolTip.Tip>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<controls:SymbolIcon Symbol="Folder" FontSize="18" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
<Button Margin="10 0 0 0" FontStyle="Italic"
|
<Button Margin="10 0 0 0" FontStyle="Italic"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Command="{Binding $parent[UserControl].((vm:SeriesPageViewModel)DataContext).RemoveSeason}"
|
Command="{Binding $parent[UserControl].((vm:SeriesPageViewModel)DataContext).RemoveSeason}"
|
||||||
|
|
|
@ -145,6 +145,25 @@
|
||||||
</controls:SettingsExpanderItem.Footer>
|
</controls:SettingsExpanderItem.Footer>
|
||||||
</controls:SettingsExpanderItem>
|
</controls:SettingsExpanderItem>
|
||||||
|
|
||||||
|
<controls:SettingsExpanderItem Content="Download Folder">
|
||||||
|
<controls:SettingsExpanderItem.Footer>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock FontSize="15" Opacity="0.8" TextWrapping="NoWrap" Text="{Binding DownloadDirPath, Mode=OneWay}" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" />
|
||||||
|
<Button Margin="10 0 0 0" FontStyle="Italic"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Command="{Binding OpenFolderDialogAsync}">
|
||||||
|
<ToolTip.Tip>
|
||||||
|
<TextBlock Text="Set Download Directory" FontSize="15" />
|
||||||
|
</ToolTip.Tip>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<controls:SymbolIcon Symbol="Folder" FontSize="18" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</controls:SettingsExpanderItem.Footer>
|
||||||
|
</controls:SettingsExpanderItem>
|
||||||
|
|
||||||
<controls:SettingsExpanderItem Content="Simultaneous Downloads">
|
<controls:SettingsExpanderItem Content="Simultaneous Downloads">
|
||||||
<controls:SettingsExpanderItem.Footer>
|
<controls:SettingsExpanderItem.Footer>
|
||||||
<controls:NumberBox Minimum="0" Maximum="5"
|
<controls:NumberBox Minimum="0" Maximum="5"
|
||||||
|
|
|
@ -19,5 +19,4 @@ public partial class SettingsPageView : UserControl{
|
||||||
Crunchyroll.Instance.RefreshSonarr();
|
Crunchyroll.Instance.RefreshSonarr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue