Fix - Hardsub not displayed correctly in settings
Fix - Custom Calendar did not always show all episodes
This commit is contained in:
parent
c80af817c7
commit
0d530c6b60
|
@ -0,0 +1,231 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
|
using CRD.Utils;
|
||||||
|
using CRD.Utils.Structs;
|
||||||
|
using HtmlAgilityPack;
|
||||||
|
|
||||||
|
namespace CRD.Downloader;
|
||||||
|
|
||||||
|
public class CalendarManager{
|
||||||
|
#region Calendar Variables
|
||||||
|
|
||||||
|
private Dictionary<string, CalendarWeek> calendar = new();
|
||||||
|
|
||||||
|
private Dictionary<string, string> calendarLanguage = new(){
|
||||||
|
{ "en-us", "https://www.crunchyroll.com/simulcastcalendar" },
|
||||||
|
{ "es", "https://www.crunchyroll.com/es/simulcastcalendar" },
|
||||||
|
{ "es-es", "https://www.crunchyroll.com/es-es/simulcastcalendar" },
|
||||||
|
{ "pt-br", "https://www.crunchyroll.com/pt-br/simulcastcalendar" },
|
||||||
|
{ "pt-pt", "https://www.crunchyroll.com/pt-pt/simulcastcalendar" },
|
||||||
|
{ "fr", "https://www.crunchyroll.com/fr/simulcastcalendar" },
|
||||||
|
{ "de", "https://www.crunchyroll.com/de/simulcastcalendar" },
|
||||||
|
{ "ar", "https://www.crunchyroll.com/ar/simulcastcalendar" },
|
||||||
|
{ "it", "https://www.crunchyroll.com/it/simulcastcalendar" },
|
||||||
|
{ "ru", "https://www.crunchyroll.com/ru/simulcastcalendar" },
|
||||||
|
{ "hi", "https://www.crunchyroll.com/hi/simulcastcalendar" },
|
||||||
|
};
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Singelton
|
||||||
|
|
||||||
|
private static CalendarManager? _instance;
|
||||||
|
private static readonly object Padlock = new();
|
||||||
|
|
||||||
|
public static CalendarManager Instance{
|
||||||
|
get{
|
||||||
|
if (_instance == null){
|
||||||
|
lock (Padlock){
|
||||||
|
if (_instance == null){
|
||||||
|
_instance = new CalendarManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<CalendarWeek> GetCalendarForDate(string weeksMondayDate, bool forceUpdate){
|
||||||
|
if (!forceUpdate && calendar.TryGetValue(weeksMondayDate, out var forDate)){
|
||||||
|
return forDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = calendarLanguage.ContainsKey(CrunchyrollManager.Instance.CrunOptions.SelectedCalendarLanguage ?? "de")
|
||||||
|
? HttpClientReq.CreateRequestMessage($"{calendarLanguage[CrunchyrollManager.Instance.CrunOptions.SelectedCalendarLanguage ?? "de"]}?filter=premium&date={weeksMondayDate}", HttpMethod.Get, false, false, null)
|
||||||
|
: HttpClientReq.CreateRequestMessage($"{calendarLanguage["en-us"]}?filter=premium&date={weeksMondayDate}", HttpMethod.Get, false, false, null);
|
||||||
|
|
||||||
|
|
||||||
|
request.Headers.Accept.ParseAdd("text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8");
|
||||||
|
request.Headers.AcceptEncoding.ParseAdd("gzip, deflate, br");
|
||||||
|
|
||||||
|
var response = await HttpClientReq.Instance.SendHttpRequest(request);
|
||||||
|
|
||||||
|
CalendarWeek week = new CalendarWeek();
|
||||||
|
week.CalendarDays = new List<CalendarDay>();
|
||||||
|
|
||||||
|
// Load the HTML content from a file
|
||||||
|
HtmlDocument doc = new HtmlDocument();
|
||||||
|
doc.LoadHtml(WebUtility.HtmlDecode(response.ResponseContent));
|
||||||
|
|
||||||
|
// Select each 'li' element with class 'day'
|
||||||
|
var dayNodes = doc.DocumentNode.SelectNodes("//li[contains(@class, 'day')]");
|
||||||
|
|
||||||
|
if (dayNodes != null){
|
||||||
|
foreach (var day in dayNodes){
|
||||||
|
// Extract the date and day name
|
||||||
|
var date = day.SelectSingleNode(".//time[@datetime]")?.GetAttributeValue("datetime", "No date");
|
||||||
|
DateTime dayDateTime = DateTime.Parse(date, null, DateTimeStyles.RoundtripKind);
|
||||||
|
|
||||||
|
if (week.FirstDayOfWeek == null){
|
||||||
|
week.FirstDayOfWeek = dayDateTime;
|
||||||
|
week.FirstDayOfWeekString = dayDateTime.ToString("yyyy-MM-dd");
|
||||||
|
}
|
||||||
|
|
||||||
|
var dayName = day.SelectSingleNode(".//h1[@class='day-name']/time")?.InnerText.Trim();
|
||||||
|
|
||||||
|
CalendarDay calDay = new CalendarDay();
|
||||||
|
|
||||||
|
calDay.CalendarEpisodes = new List<CalendarEpisode>();
|
||||||
|
calDay.DayName = dayName;
|
||||||
|
calDay.DateTime = dayDateTime;
|
||||||
|
|
||||||
|
// Iterate through each episode listed under this day
|
||||||
|
var episodes = day.SelectNodes(".//article[contains(@class, 'release')]");
|
||||||
|
if (episodes != null){
|
||||||
|
foreach (var episode in episodes){
|
||||||
|
var episodeTimeStr = episode.SelectSingleNode(".//time[contains(@class, 'available-time')]")?.GetAttributeValue("datetime", null);
|
||||||
|
DateTime episodeTime = DateTime.Parse(episodeTimeStr, null, DateTimeStyles.RoundtripKind);
|
||||||
|
var hasPassed = DateTime.Now > episodeTime;
|
||||||
|
|
||||||
|
var episodeName = episode.SelectSingleNode(".//h1[contains(@class, 'episode-name')]")?.SelectSingleNode(".//cite[@itemprop='name']")?.InnerText.Trim();
|
||||||
|
var seasonLink = episode.SelectSingleNode(".//a[contains(@class, 'js-season-name-link')]")?.GetAttributeValue("href", "No link");
|
||||||
|
var episodeLink = episode.SelectSingleNode(".//a[contains(@class, 'available-episode-link')]")?.GetAttributeValue("href", "No link");
|
||||||
|
var thumbnailUrl = episode.SelectSingleNode(".//img[contains(@class, 'thumbnail')]")?.GetAttributeValue("src", "No image");
|
||||||
|
var isPremiumOnly = episode.SelectSingleNode(".//svg[contains(@class, 'premium-flag')]") != null;
|
||||||
|
var isPremiere = episode.SelectSingleNode(".//div[contains(@class, 'premiere-flag')]") != null;
|
||||||
|
var seasonName = episode.SelectSingleNode(".//a[contains(@class, 'js-season-name-link')]")?.SelectSingleNode(".//cite[@itemprop='name']")?.InnerText.Trim();
|
||||||
|
var episodeNumber = episode.SelectSingleNode(".//meta[contains(@itemprop, 'episodeNumber')]")?.GetAttributeValue("content", "?");
|
||||||
|
|
||||||
|
CalendarEpisode calEpisode = new CalendarEpisode();
|
||||||
|
|
||||||
|
calEpisode.DateTime = episodeTime;
|
||||||
|
calEpisode.HasPassed = hasPassed;
|
||||||
|
calEpisode.EpisodeName = episodeName;
|
||||||
|
calEpisode.SeriesUrl = seasonLink;
|
||||||
|
calEpisode.EpisodeUrl = episodeLink;
|
||||||
|
calEpisode.ThumbnailUrl = thumbnailUrl;
|
||||||
|
calEpisode.IsPremiumOnly = isPremiumOnly;
|
||||||
|
calEpisode.IsPremiere = isPremiere;
|
||||||
|
calEpisode.SeasonName = seasonName;
|
||||||
|
calEpisode.EpisodeNumber = episodeNumber;
|
||||||
|
|
||||||
|
calDay.CalendarEpisodes.Add(calEpisode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
week.CalendarDays.Add(calDay);
|
||||||
|
}
|
||||||
|
} else{
|
||||||
|
Console.Error.WriteLine("No days found in the HTML document.");
|
||||||
|
}
|
||||||
|
|
||||||
|
calendar[weeksMondayDate] = week;
|
||||||
|
|
||||||
|
|
||||||
|
return week;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<CalendarWeek> BuildCustomCalendar(bool forceUpdate){
|
||||||
|
Console.WriteLine("C" + DateTime.Now.ToString("yyyy-MM-dd"));
|
||||||
|
|
||||||
|
if (!forceUpdate && calendar.TryGetValue("C" + DateTime.Now.ToString("yyyy-MM-dd"), out var forDate)){
|
||||||
|
return forDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CalendarWeek week = new CalendarWeek();
|
||||||
|
week.CalendarDays = new List<CalendarDay>();
|
||||||
|
|
||||||
|
DateTime today = DateTime.Now;
|
||||||
|
|
||||||
|
for (int i = 0; i < 7; i++){
|
||||||
|
CalendarDay calDay = new CalendarDay();
|
||||||
|
|
||||||
|
calDay.CalendarEpisodes = new List<CalendarEpisode>();
|
||||||
|
calDay.DateTime = today.AddDays(-i);
|
||||||
|
calDay.DayName = calDay.DateTime.Value.DayOfWeek.ToString();
|
||||||
|
|
||||||
|
week.CalendarDays.Add(calDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
week.CalendarDays.Reverse();
|
||||||
|
|
||||||
|
var firstDayOfWeek = week.CalendarDays.First().DateTime;
|
||||||
|
|
||||||
|
var newEpisodesBase = await CrunchyrollManager.Instance.CrEpisode.GetNewEpisodes(CrunchyrollManager.Instance.CrunOptions.HistoryLang, 200,firstDayOfWeek, true);
|
||||||
|
|
||||||
|
if (newEpisodesBase is{ Data.Count: > 0 }){
|
||||||
|
var newEpisodes = newEpisodesBase.Data;
|
||||||
|
|
||||||
|
foreach (var crBrowseEpisode in newEpisodes){
|
||||||
|
var targetDate = CrunchyrollManager.Instance.CrunOptions.CalendarFilterByAirDate ? crBrowseEpisode.EpisodeMetadata.EpisodeAirDate : crBrowseEpisode.LastPublic;
|
||||||
|
|
||||||
|
if (CrunchyrollManager.Instance.CrunOptions.CalendarHideDubs && crBrowseEpisode.EpisodeMetadata.SeasonTitle != null &&
|
||||||
|
(crBrowseEpisode.EpisodeMetadata.SeasonTitle.EndsWith("Dub)") || crBrowseEpisode.EpisodeMetadata.AudioLocale != Locale.JaJp)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dubFilter = CrunchyrollManager.Instance.CrunOptions.CalendarDubFilter;
|
||||||
|
if (!string.IsNullOrEmpty(dubFilter) && dubFilter != "none"){
|
||||||
|
if (crBrowseEpisode.EpisodeMetadata.AudioLocale != null && crBrowseEpisode.EpisodeMetadata.AudioLocale.GetEnumMemberValue() != dubFilter){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var calendarDay = (from day in week.CalendarDays
|
||||||
|
where day.DateTime.HasValue && day.DateTime.Value.Date == targetDate.Date
|
||||||
|
select day).FirstOrDefault();
|
||||||
|
|
||||||
|
if (calendarDay != null){
|
||||||
|
CalendarEpisode calEpisode = new CalendarEpisode();
|
||||||
|
|
||||||
|
calEpisode.DateTime = targetDate;
|
||||||
|
calEpisode.HasPassed = DateTime.Now > targetDate;
|
||||||
|
calEpisode.EpisodeName = crBrowseEpisode.Title;
|
||||||
|
calEpisode.SeriesUrl = $"https://www.crunchyroll.com/{CrunchyrollManager.Instance.CrunOptions.HistoryLang}/series/" + crBrowseEpisode.EpisodeMetadata.SeriesId;
|
||||||
|
calEpisode.EpisodeUrl = $"https://www.crunchyroll.com/{CrunchyrollManager.Instance.CrunOptions.HistoryLang}/watch/{crBrowseEpisode.Id}/";
|
||||||
|
calEpisode.ThumbnailUrl = crBrowseEpisode.Images.Thumbnail.First().First().Source;
|
||||||
|
calEpisode.IsPremiumOnly = crBrowseEpisode.EpisodeMetadata.IsPremiumOnly;
|
||||||
|
calEpisode.IsPremiere = crBrowseEpisode.EpisodeMetadata.Episode == "1";
|
||||||
|
calEpisode.SeasonName = crBrowseEpisode.EpisodeMetadata.SeasonTitle;
|
||||||
|
calEpisode.EpisodeNumber = crBrowseEpisode.EpisodeMetadata.Episode;
|
||||||
|
|
||||||
|
calendarDay.CalendarEpisodes?.Add(calEpisode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var day in week.CalendarDays){
|
||||||
|
if (day.CalendarEpisodes != null) day.CalendarEpisodes = day.CalendarEpisodes.OrderBy(e => e.DateTime).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
calendar["C" + DateTime.Now.ToString("yyyy-MM-dd")] = week;
|
||||||
|
|
||||||
|
|
||||||
|
return week;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,13 +9,12 @@ using System.Web;
|
||||||
using CRD.Utils;
|
using CRD.Utils;
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using YamlDotNet.Core.Tokens;
|
|
||||||
|
|
||||||
namespace CRD.Downloader;
|
namespace CRD.Downloader.Crunchyroll;
|
||||||
|
|
||||||
public class CrAuth{
|
public class CrAuth{
|
||||||
|
|
||||||
private readonly Crunchyroll crunInstance = Crunchyroll.Instance;
|
private readonly CrunchyrollManager crunInstance = CrunchyrollManager.Instance;
|
||||||
|
|
||||||
public async Task AuthAnonymous(){
|
public async Task AuthAnonymous(){
|
||||||
var formData = new Dictionary<string, string>{
|
var formData = new Dictionary<string, string>{
|
||||||
|
@ -46,7 +45,7 @@ public class CrAuth{
|
||||||
PreferredContentSubtitleLanguage = "de-DE"
|
PreferredContentSubtitleLanguage = "de-DE"
|
||||||
};
|
};
|
||||||
|
|
||||||
Crunchyroll.Instance.CmsToken = new CrCmsToken();
|
CrunchyrollManager.Instance.CmsToken = new CrCmsToken();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
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;
|
|
||||||
|
|
||||||
namespace CRD.Downloader;
|
namespace CRD.Downloader.Crunchyroll;
|
||||||
|
|
||||||
public class CrEpisode(){
|
public class CrEpisode(){
|
||||||
private readonly Crunchyroll crunInstance = Crunchyroll.Instance;
|
private readonly CrunchyrollManager crunInstance = CrunchyrollManager.Instance;
|
||||||
|
|
||||||
public async Task<CrunchyEpisode?> ParseEpisodeById(string id, string crLocale, bool forcedLang = false){
|
public async Task<CrunchyEpisode?> ParseEpisodeById(string id, string crLocale, bool forcedLang = false){
|
||||||
if (crunInstance.CmsToken?.Cms == null){
|
if (crunInstance.CmsToken?.Cms == null){
|
||||||
|
@ -67,11 +64,11 @@ public class CrEpisode(){
|
||||||
CrunchyRollEpisodeData episode = new CrunchyRollEpisodeData();
|
CrunchyRollEpisodeData episode = new CrunchyRollEpisodeData();
|
||||||
|
|
||||||
if (crunInstance.CrunOptions.History && updateHistory){
|
if (crunInstance.CrunOptions.History && updateHistory){
|
||||||
await crunInstance.CrHistory.UpdateWithEpisode(dlEpisode);
|
await crunInstance.History.UpdateWithEpisode(dlEpisode);
|
||||||
var historySeries = crunInstance.HistoryList.FirstOrDefault(series => series.SeriesId == dlEpisode.SeriesId);
|
var historySeries = crunInstance.HistoryList.FirstOrDefault(series => series.SeriesId == dlEpisode.SeriesId);
|
||||||
if (historySeries != null){
|
if (historySeries != null){
|
||||||
Crunchyroll.Instance.CrHistory.MatchHistorySeriesWithSonarr(false);
|
CrunchyrollManager.Instance.History.MatchHistorySeriesWithSonarr(false);
|
||||||
await Crunchyroll.Instance.CrHistory.MatchHistoryEpisodesWithSonarr(false, historySeries);
|
await CrunchyrollManager.Instance.History.MatchHistoryEpisodesWithSonarr(false, historySeries);
|
||||||
CfgManager.UpdateHistoryFile();
|
CfgManager.UpdateHistoryFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,7 +242,7 @@ public class CrEpisode(){
|
||||||
return retMeta;
|
return retMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CrBrowseEpisodeBase?> GetNewEpisodes(string? crLocale, int requestAmount , bool forcedLang = false){
|
public async Task<CrBrowseEpisodeBase?> GetNewEpisodes(string? crLocale, int requestAmount,DateTime? firstWeekDay = null , bool forcedLang = false){
|
||||||
CrBrowseEpisodeBase? complete = new CrBrowseEpisodeBase();
|
CrBrowseEpisodeBase? complete = new CrBrowseEpisodeBase();
|
||||||
complete.Data =[];
|
complete.Data =[];
|
||||||
|
|
||||||
|
@ -279,13 +276,21 @@ public class CrEpisode(){
|
||||||
|
|
||||||
if (series != null){
|
if (series != null){
|
||||||
complete.Total = series.Total;
|
complete.Total = series.Total;
|
||||||
if (series.Data != null) complete.Data.AddRange(series.Data);
|
if (series.Data != null){
|
||||||
|
complete.Data.AddRange(series.Data);
|
||||||
|
if (firstWeekDay != null){
|
||||||
|
if (firstWeekDay.Value.Date <= series.Data.Last().LastPublic && i + 50 == requestAmount){
|
||||||
|
requestAmount += 50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
} else{
|
} else{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
i += 50;
|
i += 50;
|
||||||
} while (i < requestAmount);
|
} while (i < requestAmount && requestAmount < 500);
|
||||||
|
|
||||||
|
|
||||||
return complete;
|
return complete;
|
|
@ -1,24 +1,20 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using CRD.Utils;
|
using CRD.Utils;
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
using CRD.Views;
|
using CRD.Views;
|
||||||
using DynamicData;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace CRD.Downloader;
|
namespace CRD.Downloader.Crunchyroll;
|
||||||
|
|
||||||
public class CrSeries(){
|
public class CrSeries(){
|
||||||
private readonly Crunchyroll crunInstance = Crunchyroll.Instance;
|
private readonly CrunchyrollManager crunInstance = CrunchyrollManager.Instance;
|
||||||
|
|
||||||
public async Task<List<CrunchyEpMeta>> DownloadFromSeriesId(string id, CrunchyMultiDownload data){
|
public async Task<List<CrunchyEpMeta>> DownloadFromSeriesId(string id, CrunchyMultiDownload data){
|
||||||
var series = await ListSeriesId(id, "", data);
|
var series = await ListSeriesId(id, "", data);
|
||||||
|
@ -57,7 +53,7 @@ public class CrSeries(){
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crunInstance.CrunOptions.History){
|
if (crunInstance.CrunOptions.History){
|
||||||
var dubLangList = crunInstance.CrHistory.GetDubList(item.SeriesId, item.SeasonId);
|
var dubLangList = crunInstance.History.GetDubList(item.SeriesId, item.SeasonId);
|
||||||
if (dubLangList.Count > 0){
|
if (dubLangList.Count > 0){
|
||||||
dubLang = dubLangList;
|
dubLang = dubLangList;
|
||||||
}
|
}
|
||||||
|
@ -164,7 +160,7 @@ public class CrSeries(){
|
||||||
var seasonData = await GetSeasonDataById(s.Id, "");
|
var seasonData = await GetSeasonDataById(s.Id, "");
|
||||||
if (seasonData.Data != null){
|
if (seasonData.Data != null){
|
||||||
if (crunInstance.CrunOptions.History){
|
if (crunInstance.CrunOptions.History){
|
||||||
crunInstance.CrHistory.UpdateWithSeasonData(seasonData,false);
|
crunInstance.History.UpdateWithSeasonData(seasonData,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var episode in seasonData.Data){
|
foreach (var episode in seasonData.Data){
|
||||||
|
@ -214,8 +210,8 @@ public class CrSeries(){
|
||||||
if (crunInstance.CrunOptions.History){
|
if (crunInstance.CrunOptions.History){
|
||||||
var historySeries = crunInstance.HistoryList.FirstOrDefault(series => series.SeriesId == id);
|
var historySeries = crunInstance.HistoryList.FirstOrDefault(series => series.SeriesId == id);
|
||||||
if (historySeries != null){
|
if (historySeries != null){
|
||||||
crunInstance.CrHistory.MatchHistorySeriesWithSonarr(false);
|
crunInstance.History.MatchHistorySeriesWithSonarr(false);
|
||||||
await crunInstance.CrHistory.MatchHistoryEpisodesWithSonarr(false, historySeries);
|
await crunInstance.History.MatchHistoryEpisodesWithSonarr(false, historySeries);
|
||||||
CfgManager.UpdateHistoryFile();
|
CfgManager.UpdateHistoryFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,11 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
@ -13,62 +11,27 @@ using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using CRD.Utils;
|
using CRD.Utils;
|
||||||
using CRD.Utils.CustomList;
|
|
||||||
using CRD.Utils.DRM;
|
using CRD.Utils.DRM;
|
||||||
using CRD.Utils.Files;
|
using CRD.Utils.Files;
|
||||||
using CRD.Utils.HLS;
|
using CRD.Utils.HLS;
|
||||||
using CRD.Utils.Muxing;
|
using CRD.Utils.Muxing;
|
||||||
using CRD.Utils.Sonarr;
|
using CRD.Utils.Sonarr;
|
||||||
using CRD.Utils.Sonarr.Models;
|
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
using CRD.Utils.Structs.History;
|
using CRD.Utils.Structs.History;
|
||||||
using CRD.ViewModels;
|
|
||||||
using CRD.Views;
|
using CRD.Views;
|
||||||
using HtmlAgilityPack;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using ReactiveUI;
|
|
||||||
using LanguageItem = CRD.Utils.Structs.LanguageItem;
|
using LanguageItem = CRD.Utils.Structs.LanguageItem;
|
||||||
|
|
||||||
namespace CRD.Downloader;
|
namespace CRD.Downloader.Crunchyroll;
|
||||||
|
|
||||||
public class Crunchyroll{
|
public class CrunchyrollManager{
|
||||||
public CrToken? Token;
|
public CrToken? Token;
|
||||||
public CrCmsToken? CmsToken;
|
public CrCmsToken? CmsToken;
|
||||||
|
|
||||||
public CrProfile Profile = new();
|
public CrProfile Profile = new();
|
||||||
public CrDownloadOptions CrunOptions;
|
public CrDownloadOptions CrunOptions;
|
||||||
|
|
||||||
#region Download Variables
|
|
||||||
|
|
||||||
public RefreshableObservableCollection<CrunchyEpMeta> Queue = new RefreshableObservableCollection<CrunchyEpMeta>();
|
|
||||||
public ObservableCollection<DownloadItemModel> DownloadItemModels = new ObservableCollection<DownloadItemModel>();
|
|
||||||
public int ActiveDownloads;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Calendar Variables
|
|
||||||
|
|
||||||
private Dictionary<string, CalendarWeek> calendar = new();
|
|
||||||
|
|
||||||
private Dictionary<string, string> calendarLanguage = new(){
|
|
||||||
{ "en-us", "https://www.crunchyroll.com/simulcastcalendar" },
|
|
||||||
{ "es", "https://www.crunchyroll.com/es/simulcastcalendar" },
|
|
||||||
{ "es-es", "https://www.crunchyroll.com/es-es/simulcastcalendar" },
|
|
||||||
{ "pt-br", "https://www.crunchyroll.com/pt-br/simulcastcalendar" },
|
|
||||||
{ "pt-pt", "https://www.crunchyroll.com/pt-pt/simulcastcalendar" },
|
|
||||||
{ "fr", "https://www.crunchyroll.com/fr/simulcastcalendar" },
|
|
||||||
{ "de", "https://www.crunchyroll.com/de/simulcastcalendar" },
|
|
||||||
{ "ar", "https://www.crunchyroll.com/ar/simulcastcalendar" },
|
|
||||||
{ "it", "https://www.crunchyroll.com/it/simulcastcalendar" },
|
|
||||||
{ "ru", "https://www.crunchyroll.com/ru/simulcastcalendar" },
|
|
||||||
{ "hi", "https://www.crunchyroll.com/hi/simulcastcalendar" },
|
|
||||||
};
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region History Variables
|
#region History Variables
|
||||||
|
|
||||||
public ObservableCollection<HistorySeries> HistoryList = new();
|
public ObservableCollection<HistorySeries> HistoryList = new();
|
||||||
|
@ -77,8 +40,6 @@ public class Crunchyroll{
|
||||||
Seasons =[]
|
Seasons =[]
|
||||||
};
|
};
|
||||||
|
|
||||||
public List<SonarrSeries> SonarrSeries =[];
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,19 +54,19 @@ public class Crunchyroll{
|
||||||
public CrAuth CrAuth;
|
public CrAuth CrAuth;
|
||||||
public CrEpisode CrEpisode;
|
public CrEpisode CrEpisode;
|
||||||
public CrSeries CrSeries;
|
public CrSeries CrSeries;
|
||||||
public History CrHistory;
|
public History History;
|
||||||
|
|
||||||
#region Singelton
|
#region Singelton
|
||||||
|
|
||||||
private static Crunchyroll? _instance;
|
private static CrunchyrollManager? _instance;
|
||||||
private static readonly object Padlock = new();
|
private static readonly object Padlock = new();
|
||||||
|
|
||||||
public static Crunchyroll Instance{
|
public static CrunchyrollManager Instance{
|
||||||
get{
|
get{
|
||||||
if (_instance == null){
|
if (_instance == null){
|
||||||
lock (Padlock){
|
lock (Padlock){
|
||||||
if (_instance == null){
|
if (_instance == null){
|
||||||
_instance = new Crunchyroll();
|
_instance = new CrunchyrollManager();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,9 +77,8 @@ public class Crunchyroll{
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public Crunchyroll(){
|
public CrunchyrollManager(){
|
||||||
CrunOptions = new CrDownloadOptions();
|
CrunOptions = new CrDownloadOptions();
|
||||||
Queue.CollectionChanged += UpdateItemListOnRemove;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitOptions(){
|
public void InitOptions(){
|
||||||
|
@ -159,7 +119,7 @@ public class Crunchyroll{
|
||||||
CrAuth = new CrAuth();
|
CrAuth = new CrAuth();
|
||||||
CrEpisode = new CrEpisode();
|
CrEpisode = new CrEpisode();
|
||||||
CrSeries = new CrSeries();
|
CrSeries = new CrSeries();
|
||||||
CrHistory = new History();
|
History = new History();
|
||||||
|
|
||||||
Profile = new CrProfile{
|
Profile = new CrProfile{
|
||||||
Username = "???",
|
Username = "???",
|
||||||
|
@ -204,267 +164,15 @@ public class Crunchyroll{
|
||||||
HistoryList =[];
|
HistoryList =[];
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshSonarr();
|
SonarrClient.Instance.RefreshSonarr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void RefreshSonarr(){
|
|
||||||
await SonarrClient.Instance.CheckSonarrSettings();
|
|
||||||
if (CrunOptions.SonarrProperties is{ SonarrEnabled: true }){
|
|
||||||
SonarrSeries = await SonarrClient.Instance.GetSeries();
|
|
||||||
CrHistory.MatchHistorySeriesWithSonarr(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateItemListOnRemove(object? sender, NotifyCollectionChangedEventArgs e){
|
|
||||||
if (e.Action == NotifyCollectionChangedAction.Remove){
|
|
||||||
if (e.OldItems != null)
|
|
||||||
foreach (var eOldItem in e.OldItems){
|
|
||||||
var downloadItem = DownloadItemModels.FirstOrDefault(e => e.epMeta.Equals(eOldItem));
|
|
||||||
if (downloadItem != null){
|
|
||||||
DownloadItemModels.Remove(downloadItem);
|
|
||||||
} else{
|
|
||||||
Console.Error.WriteLine("Failed to Remove Episode from list");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateDownloadListItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateDownloadListItems(){
|
|
||||||
var list = Queue;
|
|
||||||
|
|
||||||
foreach (CrunchyEpMeta crunchyEpMeta in list){
|
|
||||||
var downloadItem = DownloadItemModels.FirstOrDefault(e => e.epMeta.Equals(crunchyEpMeta));
|
|
||||||
if (downloadItem != null){
|
|
||||||
downloadItem.Refresh();
|
|
||||||
} else{
|
|
||||||
downloadItem = new DownloadItemModel(crunchyEpMeta);
|
|
||||||
downloadItem.LoadImage();
|
|
||||||
DownloadItemModels.Add(downloadItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (downloadItem is{ isDownloading: false, Error: false } && CrunOptions.AutoDownload && ActiveDownloads < CrunOptions.SimultaneousDownloads){
|
|
||||||
downloadItem.StartDownload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<CalendarWeek> GetCalendarForDate(string weeksMondayDate, bool forceUpdate){
|
|
||||||
if (!forceUpdate && calendar.TryGetValue(weeksMondayDate, out var forDate)){
|
|
||||||
return forDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
var request = calendarLanguage.ContainsKey(CrunOptions.SelectedCalendarLanguage ?? "de")
|
|
||||||
? HttpClientReq.CreateRequestMessage($"{calendarLanguage[CrunOptions.SelectedCalendarLanguage ?? "de"]}?filter=premium&date={weeksMondayDate}", HttpMethod.Get, false, false, null)
|
|
||||||
: HttpClientReq.CreateRequestMessage($"{calendarLanguage["en-us"]}?filter=premium&date={weeksMondayDate}", HttpMethod.Get, false, false, null);
|
|
||||||
|
|
||||||
|
|
||||||
request.Headers.Accept.ParseAdd("text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8");
|
|
||||||
request.Headers.AcceptEncoding.ParseAdd("gzip, deflate, br");
|
|
||||||
|
|
||||||
var response = await HttpClientReq.Instance.SendHttpRequest(request);
|
|
||||||
|
|
||||||
CalendarWeek week = new CalendarWeek();
|
|
||||||
week.CalendarDays = new List<CalendarDay>();
|
|
||||||
|
|
||||||
// Load the HTML content from a file
|
|
||||||
HtmlDocument doc = new HtmlDocument();
|
|
||||||
doc.LoadHtml(WebUtility.HtmlDecode(response.ResponseContent));
|
|
||||||
|
|
||||||
// Select each 'li' element with class 'day'
|
|
||||||
var dayNodes = doc.DocumentNode.SelectNodes("//li[contains(@class, 'day')]");
|
|
||||||
|
|
||||||
if (dayNodes != null){
|
|
||||||
foreach (var day in dayNodes){
|
|
||||||
// Extract the date and day name
|
|
||||||
var date = day.SelectSingleNode(".//time[@datetime]")?.GetAttributeValue("datetime", "No date");
|
|
||||||
DateTime dayDateTime = DateTime.Parse(date, null, DateTimeStyles.RoundtripKind);
|
|
||||||
|
|
||||||
if (week.FirstDayOfWeek == null){
|
|
||||||
week.FirstDayOfWeek = dayDateTime;
|
|
||||||
week.FirstDayOfWeekString = dayDateTime.ToString("yyyy-MM-dd");
|
|
||||||
}
|
|
||||||
|
|
||||||
var dayName = day.SelectSingleNode(".//h1[@class='day-name']/time")?.InnerText.Trim();
|
|
||||||
|
|
||||||
CalendarDay calDay = new CalendarDay();
|
|
||||||
|
|
||||||
calDay.CalendarEpisodes = new List<CalendarEpisode>();
|
|
||||||
calDay.DayName = dayName;
|
|
||||||
calDay.DateTime = dayDateTime;
|
|
||||||
|
|
||||||
// Iterate through each episode listed under this day
|
|
||||||
var episodes = day.SelectNodes(".//article[contains(@class, 'release')]");
|
|
||||||
if (episodes != null){
|
|
||||||
foreach (var episode in episodes){
|
|
||||||
var episodeTimeStr = episode.SelectSingleNode(".//time[contains(@class, 'available-time')]")?.GetAttributeValue("datetime", null);
|
|
||||||
DateTime episodeTime = DateTime.Parse(episodeTimeStr, null, DateTimeStyles.RoundtripKind);
|
|
||||||
var hasPassed = DateTime.Now > episodeTime;
|
|
||||||
|
|
||||||
var episodeName = episode.SelectSingleNode(".//h1[contains(@class, 'episode-name')]")?.SelectSingleNode(".//cite[@itemprop='name']")?.InnerText.Trim();
|
|
||||||
var seasonLink = episode.SelectSingleNode(".//a[contains(@class, 'js-season-name-link')]")?.GetAttributeValue("href", "No link");
|
|
||||||
var episodeLink = episode.SelectSingleNode(".//a[contains(@class, 'available-episode-link')]")?.GetAttributeValue("href", "No link");
|
|
||||||
var thumbnailUrl = episode.SelectSingleNode(".//img[contains(@class, 'thumbnail')]")?.GetAttributeValue("src", "No image");
|
|
||||||
var isPremiumOnly = episode.SelectSingleNode(".//svg[contains(@class, 'premium-flag')]") != null;
|
|
||||||
var isPremiere = episode.SelectSingleNode(".//div[contains(@class, 'premiere-flag')]") != null;
|
|
||||||
var seasonName = episode.SelectSingleNode(".//a[contains(@class, 'js-season-name-link')]")?.SelectSingleNode(".//cite[@itemprop='name']")?.InnerText.Trim();
|
|
||||||
var episodeNumber = episode.SelectSingleNode(".//meta[contains(@itemprop, 'episodeNumber')]")?.GetAttributeValue("content", "?");
|
|
||||||
|
|
||||||
CalendarEpisode calEpisode = new CalendarEpisode();
|
|
||||||
|
|
||||||
calEpisode.DateTime = episodeTime;
|
|
||||||
calEpisode.HasPassed = hasPassed;
|
|
||||||
calEpisode.EpisodeName = episodeName;
|
|
||||||
calEpisode.SeriesUrl = seasonLink;
|
|
||||||
calEpisode.EpisodeUrl = episodeLink;
|
|
||||||
calEpisode.ThumbnailUrl = thumbnailUrl;
|
|
||||||
calEpisode.IsPremiumOnly = isPremiumOnly;
|
|
||||||
calEpisode.IsPremiere = isPremiere;
|
|
||||||
calEpisode.SeasonName = seasonName;
|
|
||||||
calEpisode.EpisodeNumber = episodeNumber;
|
|
||||||
|
|
||||||
calDay.CalendarEpisodes.Add(calEpisode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
week.CalendarDays.Add(calDay);
|
|
||||||
}
|
|
||||||
} else{
|
|
||||||
Console.Error.WriteLine("No days found in the HTML document.");
|
|
||||||
}
|
|
||||||
|
|
||||||
calendar[weeksMondayDate] = week;
|
|
||||||
|
|
||||||
|
|
||||||
return week;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task AddEpisodeToQue(string epId, string crLocale, List<string> dubLang, bool updateHistory = false){
|
|
||||||
await CrAuth.RefreshToken(true);
|
|
||||||
|
|
||||||
var episodeL = await CrEpisode.ParseEpisodeById(epId, crLocale);
|
|
||||||
|
|
||||||
|
|
||||||
if (episodeL != null){
|
|
||||||
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));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var sList = await CrEpisode.EpisodeData((CrunchyEpisode)episodeL, updateHistory);
|
|
||||||
|
|
||||||
(HistoryEpisode? historyEpisode, List<string> dublist, string downloadDirPath) historyEpisode = (null, [], "");
|
|
||||||
|
|
||||||
if (CrunOptions.History){
|
|
||||||
var episode = sList.EpisodeAndLanguages.Items.First();
|
|
||||||
historyEpisode = CrHistory.GetHistoryEpisodeWithDubListAndDownloadDir(episode.SeriesId, episode.SeasonId, episode.Id);
|
|
||||||
if (historyEpisode.dublist.Count > 0){
|
|
||||||
dubLang = historyEpisode.dublist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var selected = CrEpisode.EpisodeMeta(sList, dubLang);
|
|
||||||
|
|
||||||
if (CrunOptions.IncludeVideoDescription){
|
|
||||||
if (selected.Data is{ Count: > 0 }){
|
|
||||||
var episode = await CrEpisode.ParseEpisodeById(selected.Data.First().MediaId, string.IsNullOrEmpty(CrunOptions.DescriptionLang) ? DefaultLocale : CrunOptions.DescriptionLang, true);
|
|
||||||
selected.Description = episode?.Description ?? selected.Description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (historyEpisode.historyEpisode != null){
|
|
||||||
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrEpisodeNumber)){
|
|
||||||
selected.EpisodeNumber = historyEpisode.historyEpisode.SonarrEpisodeNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrSeasonNumber)){
|
|
||||||
selected.Season = historyEpisode.historyEpisode.SonarrSeasonNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(historyEpisode.downloadDirPath)){
|
|
||||||
selected.DownloadPath = historyEpisode.downloadDirPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selected.DownloadSubs = CrunOptions.DlSubs;
|
|
||||||
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");
|
|
||||||
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 async Task AddSeriesToQueue(CrunchySeriesList list, CrunchyMultiDownload data){
|
|
||||||
var selected = CrSeries.ItemSelectMultiDub(list.Data, data.DubLang, data.But, data.AllEpisodes, data.E);
|
|
||||||
|
|
||||||
bool failed = false;
|
|
||||||
|
|
||||||
foreach (var crunchyEpMeta in selected.Values.ToList()){
|
|
||||||
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 (historyEpisode.historyEpisode != null){
|
|
||||||
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrEpisodeNumber)){
|
|
||||||
crunchyEpMeta.EpisodeNumber = historyEpisode.historyEpisode.SonarrEpisodeNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrSeasonNumber)){
|
|
||||||
crunchyEpMeta.Season = historyEpisode.historyEpisode.SonarrSeasonNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(historyEpisode.downloadDirPath)){
|
|
||||||
crunchyEpMeta.DownloadPath = historyEpisode.downloadDirPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CrunOptions.IncludeVideoDescription){
|
|
||||||
if (crunchyEpMeta.Data is{ Count: > 0 }){
|
|
||||||
var episode = await CrEpisode.ParseEpisodeById(crunchyEpMeta.Data.First().MediaId, string.IsNullOrEmpty(CrunOptions.DescriptionLang) ? DefaultLocale : CrunOptions.DescriptionLang, true);
|
|
||||||
crunchyEpMeta.Description = episode?.Description ?? crunchyEpMeta.Description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crunchyEpMeta.DownloadSubs = CrunOptions.DlSubs;
|
|
||||||
Queue.Add(crunchyEpMeta);
|
|
||||||
} else{
|
|
||||||
failed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failed){
|
|
||||||
MainWindow.Instance.ShowError("Not all episodes could be added – make sure that you are signed in with an account that has an active premium subscription?");
|
|
||||||
} else{
|
|
||||||
MessageBus.Current.SendMessage(new ToastMessage($"Added episodes to the queue", ToastType.Information, 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<bool> DownloadEpisode(CrunchyEpMeta data, CrDownloadOptions options){
|
public async Task<bool> DownloadEpisode(CrunchyEpMeta data, CrDownloadOptions options){
|
||||||
ActiveDownloads++;
|
QueueManager.Instance.ActiveDownloads++;
|
||||||
|
|
||||||
data.DownloadProgress = new DownloadProgress(){
|
data.DownloadProgress = new DownloadProgress(){
|
||||||
IsDownloading = true,
|
IsDownloading = true,
|
||||||
|
@ -474,11 +182,11 @@ public class Crunchyroll{
|
||||||
DownloadSpeed = 0,
|
DownloadSpeed = 0,
|
||||||
Doing = "Starting"
|
Doing = "Starting"
|
||||||
};
|
};
|
||||||
Queue.Refresh();
|
QueueManager.Instance.Queue.Refresh();
|
||||||
var res = await DownloadMediaList(data, options);
|
var res = await DownloadMediaList(data, options);
|
||||||
|
|
||||||
if (res.Error){
|
if (res.Error){
|
||||||
ActiveDownloads--;
|
QueueManager.Instance.ActiveDownloads--;
|
||||||
data.DownloadProgress = new DownloadProgress(){
|
data.DownloadProgress = new DownloadProgress(){
|
||||||
IsDownloading = false,
|
IsDownloading = false,
|
||||||
Error = true,
|
Error = true,
|
||||||
|
@ -487,7 +195,7 @@ public class Crunchyroll{
|
||||||
DownloadSpeed = 0,
|
DownloadSpeed = 0,
|
||||||
Doing = "Download Error" + (!string.IsNullOrEmpty(res.ErrorText) ? " - " + res.ErrorText : ""),
|
Doing = "Download Error" + (!string.IsNullOrEmpty(res.ErrorText) ? " - " + res.ErrorText : ""),
|
||||||
};
|
};
|
||||||
Queue.Refresh();
|
QueueManager.Instance.Queue.Refresh();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,7 +208,7 @@ public class Crunchyroll{
|
||||||
Doing = "Muxing"
|
Doing = "Muxing"
|
||||||
};
|
};
|
||||||
|
|
||||||
Queue.Refresh();
|
QueueManager.Instance.Queue.Refresh();
|
||||||
|
|
||||||
await MuxStreams(res.Data,
|
await MuxStreams(res.Data,
|
||||||
new CrunchyMuxOptions{
|
new CrunchyMuxOptions{
|
||||||
|
@ -532,17 +240,17 @@ public class Crunchyroll{
|
||||||
};
|
};
|
||||||
|
|
||||||
if (CrunOptions.RemoveFinishedDownload){
|
if (CrunOptions.RemoveFinishedDownload){
|
||||||
Queue.Remove(data);
|
QueueManager.Instance.Queue.Remove(data);
|
||||||
}
|
}
|
||||||
} else{
|
} else{
|
||||||
Console.WriteLine("Skipping mux");
|
Console.WriteLine("Skipping mux");
|
||||||
}
|
}
|
||||||
|
|
||||||
ActiveDownloads--;
|
QueueManager.Instance.ActiveDownloads--;
|
||||||
Queue.Refresh();
|
QueueManager.Instance.Queue.Refresh();
|
||||||
|
|
||||||
if (CrunOptions.History && data.Data != null && data.Data.Count > 0){
|
if (CrunOptions.History && data.Data != null && data.Data.Count > 0){
|
||||||
CrHistory.SetAsDownloaded(data.ShowId, data.SeasonId, data.Data.First().MediaId);
|
History.SetAsDownloaded(data.ShowId, data.SeasonId, data.Data.First().MediaId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1190,7 +898,7 @@ public class Crunchyroll{
|
||||||
DownloadSpeed = 0,
|
DownloadSpeed = 0,
|
||||||
Doing = "Decrypting"
|
Doing = "Decrypting"
|
||||||
};
|
};
|
||||||
Queue.Refresh();
|
QueueManager.Instance.Queue.Refresh();
|
||||||
|
|
||||||
var assetIdRegexMatch = Regex.Match(chosenVideoSegments.segments[0].uri, @"/assets/(?:p/)?([^_,]+)");
|
var assetIdRegexMatch = Regex.Match(chosenVideoSegments.segments[0].uri, @"/assets/(?:p/)?([^_,]+)");
|
||||||
var assetId = assetIdRegexMatch.Success ? assetIdRegexMatch.Groups[1].Value : null;
|
var assetId = assetIdRegexMatch.Success ? assetIdRegexMatch.Groups[1].Value : null;
|
||||||
|
@ -1272,7 +980,7 @@ public class Crunchyroll{
|
||||||
DownloadSpeed = 0,
|
DownloadSpeed = 0,
|
||||||
Doing = "Decrypting video"
|
Doing = "Decrypting video"
|
||||||
};
|
};
|
||||||
Queue.Refresh();
|
QueueManager.Instance.Queue.Refresh();
|
||||||
var decryptVideo = await Helpers.ExecuteCommandAsyncWorkDir("mp4decrypt", CfgManager.PathMP4Decrypt, commandVideo, tempTsFileWorkDir);
|
var decryptVideo = await Helpers.ExecuteCommandAsyncWorkDir("mp4decrypt", CfgManager.PathMP4Decrypt, commandVideo, tempTsFileWorkDir);
|
||||||
|
|
||||||
if (!decryptVideo.IsOk){
|
if (!decryptVideo.IsOk){
|
||||||
|
@ -1338,7 +1046,7 @@ public class Crunchyroll{
|
||||||
DownloadSpeed = 0,
|
DownloadSpeed = 0,
|
||||||
Doing = "Decrypting audio"
|
Doing = "Decrypting audio"
|
||||||
};
|
};
|
||||||
Queue.Refresh();
|
QueueManager.Instance.Queue.Refresh();
|
||||||
var decryptAudio = await Helpers.ExecuteCommandAsyncWorkDir("mp4decrypt", CfgManager.PathMP4Decrypt, commandAudio, tempTsFileWorkDir);
|
var decryptAudio = await Helpers.ExecuteCommandAsyncWorkDir("mp4decrypt", CfgManager.PathMP4Decrypt, commandAudio, tempTsFileWorkDir);
|
||||||
|
|
||||||
if (!decryptAudio.IsOk){
|
if (!decryptAudio.IsOk){
|
|
@ -4,6 +4,7 @@ using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils;
|
using CRD.Utils;
|
||||||
using CRD.Utils.Sonarr;
|
using CRD.Utils.Sonarr;
|
||||||
using CRD.Utils.Sonarr.Models;
|
using CRD.Utils.Sonarr.Models;
|
||||||
|
@ -16,9 +17,9 @@ using ReactiveUI;
|
||||||
namespace CRD.Downloader;
|
namespace CRD.Downloader;
|
||||||
|
|
||||||
public class History(){
|
public class History(){
|
||||||
private readonly Crunchyroll crunInstance = Crunchyroll.Instance;
|
private readonly CrunchyrollManager crunInstance = CrunchyrollManager.Instance;
|
||||||
|
|
||||||
public async Task UpdateSeries(string seriesId, string? seasonId){
|
public async Task CRUpdateSeries(string seriesId, string? seasonId){
|
||||||
await crunInstance.CrAuth.RefreshToken(true);
|
await crunInstance.CrAuth.RefreshToken(true);
|
||||||
|
|
||||||
CrSeriesSearch? parsedSeries = await crunInstance.CrSeries.ParseSeriesById(seriesId, "ja-JP", true);
|
CrSeriesSearch? parsedSeries = await crunInstance.CrSeries.ParseSeriesById(seriesId, "ja-JP", true);
|
||||||
|
@ -266,11 +267,11 @@ public class History(){
|
||||||
if (seasonData.Data.First().Versions != null){
|
if (seasonData.Data.First().Versions != null){
|
||||||
var version = seasonData.Data.First().Versions.Find(a => a.Original);
|
var version = seasonData.Data.First().Versions.Find(a => a.Original);
|
||||||
if (version.AudioLocale != seasonData.Data.First().AudioLocale){
|
if (version.AudioLocale != seasonData.Data.First().AudioLocale){
|
||||||
UpdateSeries(seasonData.Data.First().SeriesId, version.SeasonGuid);
|
CRUpdateSeries(seasonData.Data.First().SeriesId, version.SeasonGuid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else{
|
} else{
|
||||||
UpdateSeries(seasonData.Data.First().SeriesId, "");
|
CRUpdateSeries(seasonData.Data.First().SeriesId, "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,18 +381,18 @@ public class History(){
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SortItems(){
|
public void SortItems(){
|
||||||
var currentSortingType = Crunchyroll.Instance.CrunOptions.HistoryPageProperties?.SelectedSorting ?? SortingType.SeriesTitle;
|
var currentSortingType = CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties?.SelectedSorting ?? SortingType.SeriesTitle;
|
||||||
var sortingDir = Crunchyroll.Instance.CrunOptions.HistoryPageProperties != null && Crunchyroll.Instance.CrunOptions.HistoryPageProperties.Ascending;
|
var sortingDir = CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties != null && CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties.Ascending;
|
||||||
DateTime today = DateTime.UtcNow.Date;
|
DateTime today = DateTime.UtcNow.Date;
|
||||||
switch (currentSortingType){
|
switch (currentSortingType){
|
||||||
case SortingType.SeriesTitle:
|
case SortingType.SeriesTitle:
|
||||||
var sortedList = sortingDir
|
var sortedList = sortingDir
|
||||||
? Crunchyroll.Instance.HistoryList.OrderByDescending(s => s.SeriesTitle).ToList()
|
? CrunchyrollManager.Instance.HistoryList.OrderByDescending(s => s.SeriesTitle).ToList()
|
||||||
: Crunchyroll.Instance.HistoryList.OrderBy(s => s.SeriesTitle).ToList();
|
: CrunchyrollManager.Instance.HistoryList.OrderBy(s => s.SeriesTitle).ToList();
|
||||||
|
|
||||||
Crunchyroll.Instance.HistoryList.Clear();
|
CrunchyrollManager.Instance.HistoryList.Clear();
|
||||||
|
|
||||||
Crunchyroll.Instance.HistoryList.AddRange(sortedList);
|
CrunchyrollManager.Instance.HistoryList.AddRange(sortedList);
|
||||||
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -399,7 +400,7 @@ public class History(){
|
||||||
case SortingType.NextAirDate:
|
case SortingType.NextAirDate:
|
||||||
|
|
||||||
var sortedSeriesDates = sortingDir
|
var sortedSeriesDates = sortingDir
|
||||||
? Crunchyroll.Instance.HistoryList
|
? CrunchyrollManager.Instance.HistoryList
|
||||||
.OrderByDescending(s => {
|
.OrderByDescending(s => {
|
||||||
var date = ParseDate(s.SonarrNextAirDate, today);
|
var date = ParseDate(s.SonarrNextAirDate, today);
|
||||||
return date.HasValue ? date.Value : DateTime.MinValue;
|
return date.HasValue ? date.Value : DateTime.MinValue;
|
||||||
|
@ -408,7 +409,7 @@ public class History(){
|
||||||
.ThenBy(s => string.IsNullOrEmpty(s.SonarrNextAirDate) ? 1 : 0)
|
.ThenBy(s => string.IsNullOrEmpty(s.SonarrNextAirDate) ? 1 : 0)
|
||||||
.ThenBy(s => s.SeriesTitle)
|
.ThenBy(s => s.SeriesTitle)
|
||||||
.ToList()
|
.ToList()
|
||||||
: Crunchyroll.Instance.HistoryList
|
: CrunchyrollManager.Instance.HistoryList
|
||||||
.OrderByDescending(s => s.SonarrNextAirDate == "Today")
|
.OrderByDescending(s => s.SonarrNextAirDate == "Today")
|
||||||
.ThenBy(s => s.SonarrNextAirDate == "Today" ? s.SeriesTitle : null)
|
.ThenBy(s => s.SonarrNextAirDate == "Today" ? s.SeriesTitle : null)
|
||||||
.ThenBy(s => {
|
.ThenBy(s => {
|
||||||
|
@ -418,16 +419,16 @@ public class History(){
|
||||||
.ThenBy(s => s.SeriesTitle)
|
.ThenBy(s => s.SeriesTitle)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
Crunchyroll.Instance.HistoryList.Clear();
|
CrunchyrollManager.Instance.HistoryList.Clear();
|
||||||
|
|
||||||
Crunchyroll.Instance.HistoryList.AddRange(sortedSeriesDates);
|
CrunchyrollManager.Instance.HistoryList.AddRange(sortedSeriesDates);
|
||||||
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case SortingType.HistorySeriesAddDate:
|
case SortingType.HistorySeriesAddDate:
|
||||||
|
|
||||||
var sortedSeriesAddDates = Crunchyroll.Instance.HistoryList
|
var sortedSeriesAddDates = CrunchyrollManager.Instance.HistoryList
|
||||||
.OrderBy(s => sortingDir
|
.OrderBy(s => sortingDir
|
||||||
? -(s.HistorySeriesAddDate?.Date.Ticks ?? DateTime.MinValue.Ticks)
|
? -(s.HistorySeriesAddDate?.Date.Ticks ?? DateTime.MinValue.Ticks)
|
||||||
: s.HistorySeriesAddDate?.Date.Ticks ?? DateTime.MaxValue.Ticks)
|
: s.HistorySeriesAddDate?.Date.Ticks ?? DateTime.MaxValue.Ticks)
|
||||||
|
@ -435,9 +436,9 @@ public class History(){
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
|
||||||
Crunchyroll.Instance.HistoryList.Clear();
|
CrunchyrollManager.Instance.HistoryList.Clear();
|
||||||
|
|
||||||
Crunchyroll.Instance.HistoryList.AddRange(sortedSeriesAddDates);
|
CrunchyrollManager.Instance.HistoryList.AddRange(sortedSeriesAddDates);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -668,7 +669,7 @@ public class History(){
|
||||||
SonarrSeries? closestMatch = null;
|
SonarrSeries? closestMatch = null;
|
||||||
double highestSimilarity = 0.0;
|
double highestSimilarity = 0.0;
|
||||||
|
|
||||||
Parallel.ForEach(crunInstance.SonarrSeries, series => {
|
Parallel.ForEach(SonarrClient.Instance.SonarrSeries, series => {
|
||||||
double similarity = CalculateSimilarity(series.Title.ToLower(), title.ToLower());
|
double similarity = CalculateSimilarity(series.Title.ToLower(), title.ToLower());
|
||||||
if (similarity > highestSimilarity){
|
if (similarity > highestSimilarity){
|
||||||
highestSimilarity = similarity;
|
highestSimilarity = similarity;
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
|
using CRD.Utils.CustomList;
|
||||||
|
using CRD.Utils.Structs;
|
||||||
|
using CRD.Utils.Structs.History;
|
||||||
|
using CRD.ViewModels;
|
||||||
|
using CRD.Views;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace CRD.Downloader;
|
||||||
|
|
||||||
|
public class QueueManager{
|
||||||
|
#region Download Variables
|
||||||
|
|
||||||
|
public RefreshableObservableCollection<CrunchyEpMeta> Queue = new RefreshableObservableCollection<CrunchyEpMeta>();
|
||||||
|
public ObservableCollection<DownloadItemModel> DownloadItemModels = new ObservableCollection<DownloadItemModel>();
|
||||||
|
public int ActiveDownloads;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Singelton
|
||||||
|
|
||||||
|
private static QueueManager? _instance;
|
||||||
|
private static readonly object Padlock = new();
|
||||||
|
|
||||||
|
public static QueueManager Instance{
|
||||||
|
get{
|
||||||
|
if (_instance == null){
|
||||||
|
lock (Padlock){
|
||||||
|
if (_instance == null){
|
||||||
|
_instance = new QueueManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public QueueManager(){
|
||||||
|
Queue.CollectionChanged += UpdateItemListOnRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void UpdateItemListOnRemove(object? sender, NotifyCollectionChangedEventArgs e){
|
||||||
|
if (e.Action == NotifyCollectionChangedAction.Remove){
|
||||||
|
if (e.OldItems != null)
|
||||||
|
foreach (var eOldItem in e.OldItems){
|
||||||
|
var downloadItem = DownloadItemModels.FirstOrDefault(e => e.epMeta.Equals(eOldItem));
|
||||||
|
if (downloadItem != null){
|
||||||
|
DownloadItemModels.Remove(downloadItem);
|
||||||
|
} else{
|
||||||
|
Console.Error.WriteLine("Failed to Remove Episode from list");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateDownloadListItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateDownloadListItems(){
|
||||||
|
var list = Queue;
|
||||||
|
|
||||||
|
foreach (CrunchyEpMeta crunchyEpMeta in list){
|
||||||
|
var downloadItem = DownloadItemModels.FirstOrDefault(e => e.epMeta.Equals(crunchyEpMeta));
|
||||||
|
if (downloadItem != null){
|
||||||
|
downloadItem.Refresh();
|
||||||
|
} else{
|
||||||
|
downloadItem = new DownloadItemModel(crunchyEpMeta);
|
||||||
|
downloadItem.LoadImage();
|
||||||
|
DownloadItemModels.Add(downloadItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (downloadItem is{ isDownloading: false, Error: false } && CrunchyrollManager.Instance.CrunOptions.AutoDownload && ActiveDownloads < CrunchyrollManager.Instance.CrunOptions.SimultaneousDownloads){
|
||||||
|
downloadItem.StartDownload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task CRAddEpisodeToQue(string epId, string crLocale, List<string> dubLang, bool updateHistory = false){
|
||||||
|
await CrunchyrollManager.Instance.CrAuth.RefreshToken(true);
|
||||||
|
|
||||||
|
var episodeL = await CrunchyrollManager.Instance.CrEpisode.ParseEpisodeById(epId, crLocale);
|
||||||
|
|
||||||
|
|
||||||
|
if (episodeL != null){
|
||||||
|
if (episodeL.Value.IsPremiumOnly && !CrunchyrollManager.Instance.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));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sList = await CrunchyrollManager.Instance.CrEpisode.EpisodeData((CrunchyEpisode)episodeL, updateHistory);
|
||||||
|
|
||||||
|
(HistoryEpisode? historyEpisode, List<string> dublist, string downloadDirPath) historyEpisode = (null, [], "");
|
||||||
|
|
||||||
|
if (CrunchyrollManager.Instance.CrunOptions.History){
|
||||||
|
var episode = sList.EpisodeAndLanguages.Items.First();
|
||||||
|
historyEpisode = CrunchyrollManager.Instance.History.GetHistoryEpisodeWithDubListAndDownloadDir(episode.SeriesId, episode.SeasonId, episode.Id);
|
||||||
|
if (historyEpisode.dublist.Count > 0){
|
||||||
|
dubLang = historyEpisode.dublist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var selected = CrunchyrollManager.Instance.CrEpisode.EpisodeMeta(sList, dubLang);
|
||||||
|
|
||||||
|
if (CrunchyrollManager.Instance.CrunOptions.IncludeVideoDescription){
|
||||||
|
if (selected.Data is{ Count: > 0 }){
|
||||||
|
var episode = await CrunchyrollManager.Instance.CrEpisode.ParseEpisodeById(selected.Data.First().MediaId,
|
||||||
|
string.IsNullOrEmpty(CrunchyrollManager.Instance.CrunOptions.DescriptionLang) ? CrunchyrollManager.Instance.DefaultLocale : CrunchyrollManager.Instance.CrunOptions.DescriptionLang, true);
|
||||||
|
selected.Description = episode?.Description ?? selected.Description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected.Data is{ Count: > 0 }){
|
||||||
|
if (CrunchyrollManager.Instance.CrunOptions.History){
|
||||||
|
// var historyEpisode = CrHistory.GetHistoryEpisodeWithDownloadDir(selected.ShowId, selected.SeasonId, selected.Data.First().MediaId);
|
||||||
|
if (CrunchyrollManager.Instance.CrunOptions.SonarrProperties is{ SonarrEnabled: true, UseSonarrNumbering: true }){
|
||||||
|
if (historyEpisode.historyEpisode != null){
|
||||||
|
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrEpisodeNumber)){
|
||||||
|
selected.EpisodeNumber = historyEpisode.historyEpisode.SonarrEpisodeNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrSeasonNumber)){
|
||||||
|
selected.Season = historyEpisode.historyEpisode.SonarrSeasonNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(historyEpisode.downloadDirPath)){
|
||||||
|
selected.DownloadPath = historyEpisode.downloadDirPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selected.DownloadSubs = CrunchyrollManager.Instance.CrunOptions.DlSubs;
|
||||||
|
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");
|
||||||
|
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 async Task CRAddSeriesToQueue(CrunchySeriesList list, CrunchyMultiDownload data){
|
||||||
|
var selected = CrunchyrollManager.Instance.CrSeries.ItemSelectMultiDub(list.Data, data.DubLang, data.But, data.AllEpisodes, data.E);
|
||||||
|
|
||||||
|
bool failed = false;
|
||||||
|
|
||||||
|
foreach (var crunchyEpMeta in selected.Values.ToList()){
|
||||||
|
if (crunchyEpMeta.Data?.First().Playback != null){
|
||||||
|
if (CrunchyrollManager.Instance.CrunOptions.History){
|
||||||
|
var historyEpisode = CrunchyrollManager.Instance.History.GetHistoryEpisodeWithDownloadDir(crunchyEpMeta.ShowId, crunchyEpMeta.SeasonId, crunchyEpMeta.Data.First().MediaId);
|
||||||
|
if (CrunchyrollManager.Instance.CrunOptions.SonarrProperties is{ SonarrEnabled: true, UseSonarrNumbering: true }){
|
||||||
|
if (historyEpisode.historyEpisode != null){
|
||||||
|
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrEpisodeNumber)){
|
||||||
|
crunchyEpMeta.EpisodeNumber = historyEpisode.historyEpisode.SonarrEpisodeNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(historyEpisode.historyEpisode.SonarrSeasonNumber)){
|
||||||
|
crunchyEpMeta.Season = historyEpisode.historyEpisode.SonarrSeasonNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(historyEpisode.downloadDirPath)){
|
||||||
|
crunchyEpMeta.DownloadPath = historyEpisode.downloadDirPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CrunchyrollManager.Instance.CrunOptions.IncludeVideoDescription){
|
||||||
|
if (crunchyEpMeta.Data is{ Count: > 0 }){
|
||||||
|
var episode = await CrunchyrollManager.Instance.CrEpisode.ParseEpisodeById(crunchyEpMeta.Data.First().MediaId,
|
||||||
|
string.IsNullOrEmpty(CrunchyrollManager.Instance.CrunOptions.DescriptionLang) ? CrunchyrollManager.Instance.DefaultLocale : CrunchyrollManager.Instance.CrunOptions.DescriptionLang, true);
|
||||||
|
crunchyEpMeta.Description = episode?.Description ?? crunchyEpMeta.Description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crunchyEpMeta.DownloadSubs = CrunchyrollManager.Instance.CrunOptions.DlSubs;
|
||||||
|
Queue.Add(crunchyEpMeta);
|
||||||
|
} else{
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failed){
|
||||||
|
MainWindow.Instance.ShowError("Not all episodes could be added – make sure that you are signed in with an account that has an active premium subscription?");
|
||||||
|
} else{
|
||||||
|
MessageBus.Current.SendMessage(new ToastMessage($"Added episodes to the queue", ToastType.Information, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using YamlDotNet.Core;
|
using YamlDotNet.Core;
|
||||||
|
@ -139,7 +140,7 @@ public class CfgManager{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var yaml = serializer.Serialize(Crunchyroll.Instance.CrunOptions);
|
var yaml = serializer.Serialize(CrunchyrollManager.Instance.CrunOptions);
|
||||||
|
|
||||||
// Write to file
|
// Write to file
|
||||||
File.WriteAllText(PathCrDownloadOptions, yaml);
|
File.WriteAllText(PathCrDownloadOptions, yaml);
|
||||||
|
@ -173,7 +174,7 @@ public class CfgManager{
|
||||||
|
|
||||||
var propertiesPresentInYaml = GetTopLevelPropertiesInYaml(input);
|
var propertiesPresentInYaml = GetTopLevelPropertiesInYaml(input);
|
||||||
var loadedOptions = deserializer.Deserialize<CrDownloadOptions>(new StringReader(input));
|
var loadedOptions = deserializer.Deserialize<CrDownloadOptions>(new StringReader(input));
|
||||||
var instanceOptions = Crunchyroll.Instance.CrunOptions;
|
var instanceOptions = CrunchyrollManager.Instance.CrunOptions;
|
||||||
|
|
||||||
foreach (PropertyInfo property in typeof(CrDownloadOptions).GetProperties()){
|
foreach (PropertyInfo property in typeof(CrDownloadOptions).GetProperties()){
|
||||||
var yamlMemberAttribute = property.GetCustomAttribute<YamlMemberAttribute>();
|
var yamlMemberAttribute = property.GetCustomAttribute<YamlMemberAttribute>();
|
||||||
|
@ -207,7 +208,7 @@ public class CfgManager{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdateHistoryFile(){
|
public static void UpdateHistoryFile(){
|
||||||
WriteJsonToFile(PathCrHistory, Crunchyroll.Instance.HistoryList);
|
WriteJsonToFile(PathCrHistory, CrunchyrollManager.Instance.HistoryList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object fileLock = new object();
|
private static object fileLock = new object();
|
||||||
|
|
|
@ -266,15 +266,15 @@ public class HlsDownloader{
|
||||||
Doing = _isAudio ? "Downloading Audio" : (_isVideo ? "Downloading Video" : "")
|
Doing = _isAudio ? "Downloading Audio" : (_isVideo ? "Downloading Video" : "")
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!Crunchyroll.Instance.Queue.Contains(_currentEpMeta)){
|
if (!QueueManager.Instance.Queue.Contains(_currentEpMeta)){
|
||||||
return (Ok: false, _data.Parts);
|
return (Ok: false, _data.Parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
Crunchyroll.Instance.Queue.Refresh();
|
QueueManager.Instance.Queue.Refresh();
|
||||||
|
|
||||||
while (_currentEpMeta.Paused){
|
while (_currentEpMeta.Paused){
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
if (!Crunchyroll.Instance.Queue.Contains(_currentEpMeta)){
|
if (!QueueManager.Instance.Queue.Contains(_currentEpMeta)){
|
||||||
return (Ok: false, _data.Parts);
|
return (Ok: false, _data.Parts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
|
|
||||||
namespace CRD.Utils.HLS;
|
namespace CRD.Utils.HLS;
|
||||||
|
|
||||||
|
@ -31,11 +32,11 @@ public class GlobalThrottler{
|
||||||
|
|
||||||
public void Throttle(int bytesRead){
|
public void Throttle(int bytesRead){
|
||||||
|
|
||||||
if (Crunchyroll.Instance.CrunOptions.DownloadSpeedLimit == 0) return;
|
if (CrunchyrollManager.Instance.CrunOptions.DownloadSpeedLimit == 0) return;
|
||||||
|
|
||||||
lock (_lock){
|
lock (_lock){
|
||||||
_totalBytesRead += bytesRead;
|
_totalBytesRead += bytesRead;
|
||||||
if (_totalBytesRead >= ((Crunchyroll.Instance.CrunOptions.DownloadSpeedLimit * 1024) / 10)){
|
if (_totalBytesRead >= ((CrunchyrollManager.Instance.CrunOptions.DownloadSpeedLimit * 1024) / 10)){
|
||||||
var timeElapsed = DateTime.Now - _lastReadTime;
|
var timeElapsed = DateTime.Now - _lastReadTime;
|
||||||
if (timeElapsed.TotalMilliseconds < 100){
|
if (timeElapsed.TotalMilliseconds < 100){
|
||||||
Thread.Sleep(100 - (int)timeElapsed.TotalMilliseconds);
|
Thread.Sleep(100 - (int)timeElapsed.TotalMilliseconds);
|
||||||
|
@ -77,8 +78,8 @@ public class ThrottledStream : Stream{
|
||||||
|
|
||||||
public override int Read(byte[] buffer, int offset, int count){
|
public override int Read(byte[] buffer, int offset, int count){
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
if (Crunchyroll.Instance.CrunOptions.DownloadSpeedLimit != 0){
|
if (CrunchyrollManager.Instance.CrunOptions.DownloadSpeedLimit != 0){
|
||||||
int bytesToRead = Math.Min(count, (Crunchyroll.Instance.CrunOptions.DownloadSpeedLimit * 1024) / 10);
|
int bytesToRead = Math.Min(count, (CrunchyrollManager.Instance.CrunOptions.DownloadSpeedLimit * 1024) / 10);
|
||||||
bytesRead = _baseStream.Read(buffer, offset, bytesToRead);
|
bytesRead = _baseStream.Read(buffer, offset, bytesToRead);
|
||||||
_throttler.Throttle(bytesRead);
|
_throttler.Throttle(bytesRead);
|
||||||
} else{
|
} else{
|
||||||
|
|
|
@ -6,6 +6,7 @@ using System.Collections.Specialized;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
|
|
||||||
namespace CRD.Utils;
|
namespace CRD.Utils;
|
||||||
|
|
||||||
|
@ -93,7 +94,7 @@ public class HttpClientReq{
|
||||||
var request = new HttpRequestMessage(requestMethod, uriBuilder.ToString());
|
var request = new HttpRequestMessage(requestMethod, uriBuilder.ToString());
|
||||||
|
|
||||||
if (authHeader){
|
if (authHeader){
|
||||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Crunchyroll.Instance.Token?.access_token);
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", CrunchyrollManager.Instance.Token?.access_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disableDrmHeader){
|
if (disableDrmHeader){
|
||||||
|
|
|
@ -135,7 +135,7 @@ public class SyncingHelper{
|
||||||
|
|
||||||
public static bool AreFramesSimilar(string imagePath1, string imagePath2, double ssimThreshold){
|
public static bool AreFramesSimilar(string imagePath1, string imagePath2, double ssimThreshold){
|
||||||
double ssim = ComputeSSIM(imagePath1, imagePath2, 256, 256);
|
double ssim = ComputeSSIM(imagePath1, imagePath2, 256, 256);
|
||||||
Console.WriteLine($"SSIM: {ssim}");
|
// Console.WriteLine($"SSIM: {ssim}");
|
||||||
return ssim > ssimThreshold;
|
return ssim > ssimThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils.Sonarr.Models;
|
using CRD.Utils.Sonarr.Models;
|
||||||
using CRD.Views;
|
using CRD.Views;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
@ -22,6 +23,8 @@ public class SonarrClient{
|
||||||
|
|
||||||
private SonarrProperties properties;
|
private SonarrProperties properties;
|
||||||
|
|
||||||
|
public List<SonarrSeries> SonarrSeries =[];
|
||||||
|
|
||||||
#region Singelton
|
#region Singelton
|
||||||
|
|
||||||
private static SonarrClient? _instance;
|
private static SonarrClient? _instance;
|
||||||
|
@ -47,8 +50,16 @@ public class SonarrClient{
|
||||||
httpClient = new HttpClient();
|
httpClient = new HttpClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async void RefreshSonarr(){
|
||||||
|
await CheckSonarrSettings();
|
||||||
|
if (CrunchyrollManager.Instance.CrunOptions.SonarrProperties is{ SonarrEnabled: true }){
|
||||||
|
SonarrSeries = await GetSeries();
|
||||||
|
CrunchyrollManager.Instance.History.MatchHistorySeriesWithSonarr(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SetApiUrl(){
|
public void SetApiUrl(){
|
||||||
if (Crunchyroll.Instance.CrunOptions.SonarrProperties != null) properties = Crunchyroll.Instance.CrunOptions.SonarrProperties;
|
if (CrunchyrollManager.Instance.CrunOptions.SonarrProperties != null) properties = CrunchyrollManager.Instance.CrunOptions.SonarrProperties;
|
||||||
|
|
||||||
if (properties != null ){
|
if (properties != null ){
|
||||||
apiUrl = $"http{(properties.UseSsl ? "s" : "")}://{(!string.IsNullOrEmpty(properties.Host) ? properties.Host : "localhost")}:{properties.Port}{(properties.UrlBase ?? "")}/api";
|
apiUrl = $"http{(properties.UseSsl ? "s" : "")}://{(!string.IsNullOrEmpty(properties.Host) ? properties.Host : "localhost")}:{properties.Port}{(properties.UrlBase ?? "")}/api";
|
||||||
|
@ -59,10 +70,10 @@ public class SonarrClient{
|
||||||
|
|
||||||
SetApiUrl();
|
SetApiUrl();
|
||||||
|
|
||||||
if (Crunchyroll.Instance.CrunOptions.SonarrProperties != null){
|
if (CrunchyrollManager.Instance.CrunOptions.SonarrProperties != null){
|
||||||
Crunchyroll.Instance.CrunOptions.SonarrProperties.SonarrEnabled = false;
|
CrunchyrollManager.Instance.CrunOptions.SonarrProperties.SonarrEnabled = false;
|
||||||
} else{
|
} else{
|
||||||
Crunchyroll.Instance.CrunOptions.SonarrProperties = new SonarrProperties(){SonarrEnabled = false};
|
CrunchyrollManager.Instance.CrunOptions.SonarrProperties = new SonarrProperties(){SonarrEnabled = false};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,10 +85,10 @@ public class SonarrClient{
|
||||||
try{
|
try{
|
||||||
response = await httpClient.SendAsync(request);
|
response = await httpClient.SendAsync(request);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
if (Crunchyroll.Instance.CrunOptions.SonarrProperties != null) Crunchyroll.Instance.CrunOptions.SonarrProperties.SonarrEnabled = true;
|
if (CrunchyrollManager.Instance.CrunOptions.SonarrProperties != null) CrunchyrollManager.Instance.CrunOptions.SonarrProperties.SonarrEnabled = true;
|
||||||
} catch (Exception ex){
|
} catch (Exception ex){
|
||||||
Debug.WriteLine($"[ERROR] [SonarrClient.GetJson] Endpoint URL: '{apiUrl}', {ex}");
|
Debug.WriteLine($"[ERROR] [SonarrClient.GetJson] Endpoint URL: '{apiUrl}', {ex}");
|
||||||
if (Crunchyroll.Instance.CrunOptions.SonarrProperties != null) Crunchyroll.Instance.CrunOptions.SonarrProperties.SonarrEnabled = false;
|
if (CrunchyrollManager.Instance.CrunOptions.SonarrProperties != null) CrunchyrollManager.Instance.CrunOptions.SonarrProperties.SonarrEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
|
|
||||||
namespace CRD.Utils.Structs;
|
namespace CRD.Utils.Structs;
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ public partial class CalendarEpisode : INotifyPropertyChanged{
|
||||||
if (match.Success){
|
if (match.Success){
|
||||||
var locale = match.Groups[1].Value; // Capture the locale part
|
var locale = match.Groups[1].Value; // Capture the locale part
|
||||||
var id = match.Groups[2].Value; // Capture the ID part
|
var id = match.Groups[2].Value; // Capture the ID part
|
||||||
Crunchyroll.Instance.AddEpisodeToQue(id, Languages.Locale2language(locale).CrLocale, Crunchyroll.Instance.CrunOptions.DubLang,true);
|
QueueManager.Instance.CRAddEpisodeToQue(id, Languages.Locale2language(locale).CrLocale, CrunchyrollManager.Instance.CrunOptions.DubLang,true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace CRD.Utils.Structs.History;
|
namespace CRD.Utils.Structs.History;
|
||||||
|
@ -66,7 +67,7 @@ public class HistoryEpisode : INotifyPropertyChanged{
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DownloadEpisode(){
|
public async Task DownloadEpisode(){
|
||||||
await Crunchyroll.Instance.AddEpisodeToQue(EpisodeId, string.IsNullOrEmpty(Crunchyroll.Instance.CrunOptions.HistoryLang) ? Crunchyroll.Instance.DefaultLocale : Crunchyroll.Instance.CrunOptions.HistoryLang,
|
await QueueManager.Instance.CRAddEpisodeToQue(EpisodeId, string.IsNullOrEmpty(CrunchyrollManager.Instance.CrunOptions.HistoryLang) ? CrunchyrollManager.Instance.DefaultLocale : CrunchyrollManager.Instance.CrunOptions.HistoryLang,
|
||||||
Crunchyroll.Instance.CrunOptions.DubLang);
|
CrunchyrollManager.Instance.CrunOptions.DubLang);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils.CustomList;
|
using CRD.Utils.CustomList;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
@ -243,10 +244,10 @@ public class HistorySeries : INotifyPropertyChanged{
|
||||||
public async Task FetchData(string? seasonId){
|
public async Task FetchData(string? seasonId){
|
||||||
FetchingData = true;
|
FetchingData = true;
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FetchingData)));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FetchingData)));
|
||||||
await Crunchyroll.Instance.CrHistory.UpdateSeries(SeriesId, seasonId);
|
await CrunchyrollManager.Instance.History.CRUpdateSeries(SeriesId, seasonId);
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SeriesTitle)));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SeriesTitle)));
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SeriesDescription)));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SeriesDescription)));
|
||||||
Crunchyroll.Instance.CrHistory.MatchHistoryEpisodesWithSonarr(false, this);
|
CrunchyrollManager.Instance.History.MatchHistoryEpisodesWithSonarr(false, this);
|
||||||
UpdateNewEpisodes();
|
UpdateNewEpisodes();
|
||||||
FetchingData = false;
|
FetchingData = false;
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FetchingData)));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FetchingData)));
|
||||||
|
@ -262,7 +263,7 @@ public class HistorySeries : INotifyPropertyChanged{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OpenSonarrPage(){
|
public void OpenSonarrPage(){
|
||||||
var sonarrProp = Crunchyroll.Instance.CrunOptions.SonarrProperties;
|
var sonarrProp = CrunchyrollManager.Instance.CrunOptions.SonarrProperties;
|
||||||
|
|
||||||
if (sonarrProp == null) return;
|
if (sonarrProp == null) return;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Avalonia.Data.Converters;
|
using Avalonia.Data.Converters;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
|
|
||||||
namespace CRD.Utils.UI;
|
namespace CRD.Utils.UI;
|
||||||
|
@ -9,7 +10,7 @@ namespace CRD.Utils.UI;
|
||||||
public class UiSonarrIdToVisibilityConverter : IValueConverter{
|
public class UiSonarrIdToVisibilityConverter : IValueConverter{
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture){
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture){
|
||||||
if (value is string stringValue){
|
if (value is string stringValue){
|
||||||
return Crunchyroll.Instance.CrunOptions.SonarrProperties != null && (stringValue.Length > 0 && Crunchyroll.Instance.CrunOptions.SonarrProperties.SonarrEnabled);
|
return CrunchyrollManager.Instance.CrunOptions.SonarrProperties != null && (stringValue.Length > 0 && CrunchyrollManager.Instance.CrunOptions.SonarrProperties.SonarrEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -7,6 +7,7 @@ using Avalonia.Threading;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
using CRD.Views.Utils;
|
using CRD.Views.Utils;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
|
@ -45,28 +46,28 @@ public partial class AccountPageViewModel : ViewModelBase{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdatetProfile(){
|
public void UpdatetProfile(){
|
||||||
ProfileName = Crunchyroll.Instance.Profile.Username; // Default or fetched user name
|
ProfileName = CrunchyrollManager.Instance.Profile.Username; // Default or fetched user name
|
||||||
LoginLogoutText = Crunchyroll.Instance.Profile.Username == "???" ? "Login" : "Logout"; // Default state
|
LoginLogoutText = CrunchyrollManager.Instance.Profile.Username == "???" ? "Login" : "Logout"; // Default state
|
||||||
LoadProfileImage("https://static.crunchyroll.com/assets/avatar/170x170/" + Crunchyroll.Instance.Profile.Avatar);
|
LoadProfileImage("https://static.crunchyroll.com/assets/avatar/170x170/" + CrunchyrollManager.Instance.Profile.Avatar);
|
||||||
|
|
||||||
|
|
||||||
if (Crunchyroll.Instance.Profile.Subscription != null && Crunchyroll.Instance.Profile.Subscription?.SubscriptionProducts != null){
|
if (CrunchyrollManager.Instance.Profile.Subscription != null && CrunchyrollManager.Instance.Profile.Subscription?.SubscriptionProducts != null){
|
||||||
if (Crunchyroll.Instance.Profile.Subscription?.SubscriptionProducts.Count >= 1){
|
if (CrunchyrollManager.Instance.Profile.Subscription?.SubscriptionProducts.Count >= 1){
|
||||||
var sub = Crunchyroll.Instance.Profile.Subscription?.SubscriptionProducts.First();
|
var sub = CrunchyrollManager.Instance.Profile.Subscription?.SubscriptionProducts.First();
|
||||||
if (sub != null){
|
if (sub != null){
|
||||||
IsCancelled = sub.IsCancelled;
|
IsCancelled = sub.IsCancelled;
|
||||||
}
|
}
|
||||||
}else if (Crunchyroll.Instance.Profile.Subscription?.ThirdPartySubscriptionProducts.Count >= 1){
|
}else if (CrunchyrollManager.Instance.Profile.Subscription?.ThirdPartySubscriptionProducts.Count >= 1){
|
||||||
var sub = Crunchyroll.Instance.Profile.Subscription?.ThirdPartySubscriptionProducts.First();
|
var sub = CrunchyrollManager.Instance.Profile.Subscription?.ThirdPartySubscriptionProducts.First();
|
||||||
if (sub != null){
|
if (sub != null){
|
||||||
IsCancelled = !sub.AutoRenew;
|
IsCancelled = !sub.AutoRenew;
|
||||||
}
|
}
|
||||||
}else if(Crunchyroll.Instance.Profile.Subscription?.NonrecurringSubscriptionProducts.Count >= 1){
|
}else if(CrunchyrollManager.Instance.Profile.Subscription?.NonrecurringSubscriptionProducts.Count >= 1){
|
||||||
IsCancelled = true;
|
IsCancelled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Crunchyroll.Instance.Profile.Subscription?.NextRenewalDate != null){
|
if (CrunchyrollManager.Instance.Profile.Subscription?.NextRenewalDate != null){
|
||||||
_targetTime = Crunchyroll.Instance.Profile.Subscription.NextRenewalDate;
|
_targetTime = CrunchyrollManager.Instance.Profile.Subscription.NextRenewalDate;
|
||||||
_timer = new DispatcherTimer{
|
_timer = new DispatcherTimer{
|
||||||
Interval = TimeSpan.FromSeconds(1)
|
Interval = TimeSpan.FromSeconds(1)
|
||||||
};
|
};
|
||||||
|
@ -100,7 +101,7 @@ public partial class AccountPageViewModel : ViewModelBase{
|
||||||
|
|
||||||
_ = await dialog.ShowAsync();
|
_ = await dialog.ShowAsync();
|
||||||
} else{
|
} else{
|
||||||
await Crunchyroll.Instance.CrAuth.AuthAnonymous();
|
await CrunchyrollManager.Instance.CrAuth.AuthAnonymous();
|
||||||
UpdatetProfile();
|
UpdatetProfile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ using Avalonia.Media.Imaging;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils;
|
using CRD.Utils;
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
using CRD.Views;
|
using CRD.Views;
|
||||||
|
@ -75,7 +76,7 @@ public partial class AddDownloadPageViewModel : ViewModelBase{
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateSearch(string value){
|
private async Task UpdateSearch(string value){
|
||||||
var searchResults = await Crunchyroll.Instance.CrSeries.Search(value, Crunchyroll.Instance.CrunOptions.HistoryLang);
|
var searchResults = await CrunchyrollManager.Instance.CrSeries.Search(value, CrunchyrollManager.Instance.CrunOptions.HistoryLang);
|
||||||
|
|
||||||
var searchItems = searchResults?.Data?.First().Items;
|
var searchItems = searchResults?.Data?.First().Items;
|
||||||
SearchItems.Clear();
|
SearchItems.Clear();
|
||||||
|
@ -157,7 +158,7 @@ public partial class AddDownloadPageViewModel : ViewModelBase{
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentSeriesList != null){
|
if (currentSeriesList != null){
|
||||||
await Crunchyroll.Instance.AddSeriesToQueue(currentSeriesList.Value, new CrunchyMultiDownload(Crunchyroll.Instance.CrunOptions.DubLang, AddAllEpisodes, false, selectedEpisodes));
|
await QueueManager.Instance.CRAddSeriesToQueue(currentSeriesList.Value, new CrunchyMultiDownload(CrunchyrollManager.Instance.CrunOptions.DubLang, AddAllEpisodes, false, selectedEpisodes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -186,10 +187,10 @@ public partial class AddDownloadPageViewModel : ViewModelBase{
|
||||||
if (match.Success){
|
if (match.Success){
|
||||||
var locale = match.Groups[1].Value; // Capture the locale part
|
var locale = match.Groups[1].Value; // Capture the locale part
|
||||||
var id = match.Groups[2].Value; // Capture the ID part
|
var id = match.Groups[2].Value; // Capture the ID part
|
||||||
Crunchyroll.Instance.AddEpisodeToQue(id,
|
QueueManager.Instance.CRAddEpisodeToQue(id,
|
||||||
string.IsNullOrEmpty(locale)
|
string.IsNullOrEmpty(locale)
|
||||||
? string.IsNullOrEmpty(Crunchyroll.Instance.CrunOptions.HistoryLang) ? Crunchyroll.Instance.DefaultLocale : Crunchyroll.Instance.CrunOptions.HistoryLang
|
? string.IsNullOrEmpty(CrunchyrollManager.Instance.CrunOptions.HistoryLang) ? CrunchyrollManager.Instance.DefaultLocale : CrunchyrollManager.Instance.CrunOptions.HistoryLang
|
||||||
: Languages.Locale2language(locale).CrLocale, Crunchyroll.Instance.CrunOptions.DubLang, true);
|
: Languages.Locale2language(locale).CrLocale, CrunchyrollManager.Instance.CrunOptions.DubLang, true);
|
||||||
UrlInput = "";
|
UrlInput = "";
|
||||||
selectedEpisodes.Clear();
|
selectedEpisodes.Clear();
|
||||||
SelectedItems.Clear();
|
SelectedItems.Clear();
|
||||||
|
@ -212,9 +213,9 @@ public partial class AddDownloadPageViewModel : ViewModelBase{
|
||||||
|
|
||||||
ButtonEnabled = false;
|
ButtonEnabled = false;
|
||||||
ShowLoading = true;
|
ShowLoading = true;
|
||||||
var list = await Crunchyroll.Instance.CrSeries.ListSeriesId(id, string.IsNullOrEmpty(locale)
|
var list = await CrunchyrollManager.Instance.CrSeries.ListSeriesId(id, string.IsNullOrEmpty(locale)
|
||||||
? string.IsNullOrEmpty(Crunchyroll.Instance.CrunOptions.HistoryLang) ? Crunchyroll.Instance.DefaultLocale : Crunchyroll.Instance.CrunOptions.HistoryLang
|
? string.IsNullOrEmpty(CrunchyrollManager.Instance.CrunOptions.HistoryLang) ? CrunchyrollManager.Instance.DefaultLocale : CrunchyrollManager.Instance.CrunOptions.HistoryLang
|
||||||
: Languages.Locale2language(locale).CrLocale, new CrunchyMultiDownload(Crunchyroll.Instance.CrunOptions.DubLang, true));
|
: Languages.Locale2language(locale).CrLocale, new CrunchyMultiDownload(CrunchyrollManager.Instance.CrunOptions.DubLang, true));
|
||||||
ShowLoading = false;
|
ShowLoading = false;
|
||||||
if (list != null){
|
if (list != null){
|
||||||
currentSeriesList = list;
|
currentSeriesList = list;
|
||||||
|
@ -291,9 +292,9 @@ public partial class AddDownloadPageViewModel : ViewModelBase{
|
||||||
SearchVisible = false;
|
SearchVisible = false;
|
||||||
ButtonEnabled = false;
|
ButtonEnabled = false;
|
||||||
ShowLoading = true;
|
ShowLoading = true;
|
||||||
var list = await Crunchyroll.Instance.CrSeries.ListSeriesId(value.Id,
|
var list = await CrunchyrollManager.Instance.CrSeries.ListSeriesId(value.Id,
|
||||||
string.IsNullOrEmpty(Crunchyroll.Instance.CrunOptions.HistoryLang) ? Crunchyroll.Instance.DefaultLocale : Crunchyroll.Instance.CrunOptions.HistoryLang,
|
string.IsNullOrEmpty(CrunchyrollManager.Instance.CrunOptions.HistoryLang) ? CrunchyrollManager.Instance.DefaultLocale : CrunchyrollManager.Instance.CrunOptions.HistoryLang,
|
||||||
new CrunchyMultiDownload(Crunchyroll.Instance.CrunOptions.DubLang, true));
|
new CrunchyMultiDownload(CrunchyrollManager.Instance.CrunOptions.DubLang, true));
|
||||||
ShowLoading = false;
|
ShowLoading = false;
|
||||||
if (list != null){
|
if (list != null){
|
||||||
currentSeriesList = list;
|
currentSeriesList = list;
|
||||||
|
|
|
@ -6,6 +6,7 @@ using Avalonia.Controls;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils;
|
using CRD.Utils;
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
|
@ -63,14 +64,14 @@ public partial class CalendarPageViewModel : ViewModelBase{
|
||||||
CalendarDubFilter.Add(new ComboBoxItem{ Content = languageItem.CrLocale });
|
CalendarDubFilter.Add(new ComboBoxItem{ Content = languageItem.CrLocale });
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomCalendar = Crunchyroll.Instance.CrunOptions.CustomCalendar;
|
CustomCalendar = CrunchyrollManager.Instance.CrunOptions.CustomCalendar;
|
||||||
HideDubs = Crunchyroll.Instance.CrunOptions.CalendarHideDubs;
|
HideDubs = CrunchyrollManager.Instance.CrunOptions.CalendarHideDubs;
|
||||||
FilterByAirDate = Crunchyroll.Instance.CrunOptions.CalendarFilterByAirDate;
|
FilterByAirDate = CrunchyrollManager.Instance.CrunOptions.CalendarFilterByAirDate;
|
||||||
|
|
||||||
ComboBoxItem? dubfilter = CalendarDubFilter.FirstOrDefault(a => a.Content != null && (string)a.Content == Crunchyroll.Instance.CrunOptions.CalendarDubFilter) ?? null;
|
ComboBoxItem? dubfilter = CalendarDubFilter.FirstOrDefault(a => a.Content != null && (string)a.Content == CrunchyrollManager.Instance.CrunOptions.CalendarDubFilter) ?? null;
|
||||||
CurrentCalendarDubFilter = dubfilter ?? CalendarDubFilter[0];
|
CurrentCalendarDubFilter = dubfilter ?? CalendarDubFilter[0];
|
||||||
|
|
||||||
CurrentCalendarLanguage = CalendarLanguage.FirstOrDefault(a => a.Content != null && (string)a.Content == Crunchyroll.Instance.CrunOptions.SelectedCalendarLanguage) ?? CalendarLanguage[0];
|
CurrentCalendarLanguage = CalendarLanguage.FirstOrDefault(a => a.Content != null && (string)a.Content == CrunchyrollManager.Instance.CrunOptions.SelectedCalendarLanguage) ?? CalendarLanguage[0];
|
||||||
loading = false;
|
loading = false;
|
||||||
LoadCalendar(GetThisWeeksMondayDate(), false);
|
LoadCalendar(GetThisWeeksMondayDate(), false);
|
||||||
}
|
}
|
||||||
|
@ -98,16 +99,18 @@ public partial class CalendarPageViewModel : ViewModelBase{
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void LoadCalendar(string mondayDate, bool forceUpdate){
|
public async void LoadCalendar(string mondayDate, bool forceUpdate){
|
||||||
if (CustomCalendar){
|
|
||||||
BuildCustomCalendar();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShowLoading = true;
|
ShowLoading = true;
|
||||||
CalendarWeek week = await Crunchyroll.Instance.GetCalendarForDate(mondayDate, forceUpdate);
|
|
||||||
if (currentWeek != null && currentWeek == week){
|
CalendarWeek week;
|
||||||
ShowLoading = false;
|
|
||||||
return;
|
if (CustomCalendar){
|
||||||
|
week = await CalendarManager.Instance.BuildCustomCalendar(forceUpdate);
|
||||||
|
} else{
|
||||||
|
week = await CalendarManager.Instance.GetCalendarForDate(mondayDate, forceUpdate);
|
||||||
|
if (currentWeek != null && currentWeek == week){
|
||||||
|
ShowLoading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentWeek = week;
|
currentWeek = week;
|
||||||
|
@ -115,17 +118,26 @@ public partial class CalendarPageViewModel : ViewModelBase{
|
||||||
CalendarDays.AddRange(week.CalendarDays);
|
CalendarDays.AddRange(week.CalendarDays);
|
||||||
RaisePropertyChanged(nameof(CalendarDays));
|
RaisePropertyChanged(nameof(CalendarDays));
|
||||||
ShowLoading = false;
|
ShowLoading = false;
|
||||||
|
if (CustomCalendar){
|
||||||
foreach (var calendarDay in CalendarDays){
|
foreach (var calendarDay in CalendarDays){
|
||||||
var episodesCopy = new List<CalendarEpisode>(calendarDay.CalendarEpisodes);
|
foreach (var calendarDayCalendarEpisode in calendarDay.CalendarEpisodes){
|
||||||
foreach (var calendarDayCalendarEpisode in episodesCopy){
|
if (calendarDayCalendarEpisode.ImageBitmap == null){
|
||||||
if (calendarDayCalendarEpisode.SeasonName != null && HideDubs && calendarDayCalendarEpisode.SeasonName.EndsWith("Dub)")){
|
calendarDayCalendarEpisode.LoadImage();
|
||||||
calendarDay.CalendarEpisodes.Remove(calendarDayCalendarEpisode);
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else{
|
||||||
|
foreach (var calendarDay in CalendarDays){
|
||||||
|
var episodesCopy = new List<CalendarEpisode>(calendarDay.CalendarEpisodes);
|
||||||
|
foreach (var calendarDayCalendarEpisode in episodesCopy){
|
||||||
|
if (calendarDayCalendarEpisode.SeasonName != null && HideDubs && calendarDayCalendarEpisode.SeasonName.EndsWith("Dub)")){
|
||||||
|
calendarDay.CalendarEpisodes.Remove(calendarDayCalendarEpisode);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (calendarDayCalendarEpisode.ImageBitmap == null){
|
if (calendarDayCalendarEpisode.ImageBitmap == null){
|
||||||
calendarDayCalendarEpisode.LoadImage();
|
calendarDayCalendarEpisode.LoadImage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,11 +160,6 @@ public partial class CalendarPageViewModel : ViewModelBase{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CustomCalendar){
|
|
||||||
BuildCustomCalendar();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string mondayDate;
|
string mondayDate;
|
||||||
|
|
||||||
if (currentWeek is{ FirstDayOfWeekString: not null }){
|
if (currentWeek is{ FirstDayOfWeekString: not null }){
|
||||||
|
@ -205,7 +212,7 @@ public partial class CalendarPageViewModel : ViewModelBase{
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value?.Content != null){
|
if (value?.Content != null){
|
||||||
Crunchyroll.Instance.CrunOptions.SelectedCalendarLanguage = value.Content.ToString();
|
CrunchyrollManager.Instance.CrunOptions.SelectedCalendarLanguage = value.Content.ToString();
|
||||||
Refresh();
|
Refresh();
|
||||||
CfgManager.WriteSettingsToFile();
|
CfgManager.WriteSettingsToFile();
|
||||||
}
|
}
|
||||||
|
@ -216,13 +223,10 @@ public partial class CalendarPageViewModel : ViewModelBase{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CustomCalendar){
|
CrunchyrollManager.Instance.CrunOptions.CustomCalendar = value;
|
||||||
BuildCustomCalendar();
|
|
||||||
} else{
|
LoadCalendar(GetThisWeeksMondayDate(), true);
|
||||||
LoadCalendar(GetThisWeeksMondayDate(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.CustomCalendar = value;
|
|
||||||
CfgManager.WriteSettingsToFile();
|
CfgManager.WriteSettingsToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +235,7 @@ public partial class CalendarPageViewModel : ViewModelBase{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.CalendarHideDubs = value;
|
CrunchyrollManager.Instance.CrunOptions.CalendarHideDubs = value;
|
||||||
CfgManager.WriteSettingsToFile();
|
CfgManager.WriteSettingsToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +244,7 @@ public partial class CalendarPageViewModel : ViewModelBase{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.CalendarFilterByAirDate = value;
|
CrunchyrollManager.Instance.CrunOptions.CalendarFilterByAirDate = value;
|
||||||
CfgManager.WriteSettingsToFile();
|
CfgManager.WriteSettingsToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,89 +254,8 @@ public partial class CalendarPageViewModel : ViewModelBase{
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(value?.Content + "")){
|
if (!string.IsNullOrEmpty(value?.Content + "")){
|
||||||
Crunchyroll.Instance.CrunOptions.CalendarDubFilter = value?.Content + "";
|
CrunchyrollManager.Instance.CrunOptions.CalendarDubFilter = value?.Content + "";
|
||||||
CfgManager.WriteSettingsToFile();
|
CfgManager.WriteSettingsToFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void BuildCustomCalendar(){
|
|
||||||
ShowLoading = true;
|
|
||||||
|
|
||||||
var newEpisodesBase = await Crunchyroll.Instance.CrEpisode.GetNewEpisodes(Crunchyroll.Instance.CrunOptions.HistoryLang, 200,true);
|
|
||||||
|
|
||||||
CalendarWeek week = new CalendarWeek();
|
|
||||||
week.CalendarDays = new List<CalendarDay>();
|
|
||||||
|
|
||||||
DateTime today = DateTime.Now;
|
|
||||||
|
|
||||||
for (int i = 0; i < 7; i++){
|
|
||||||
CalendarDay calDay = new CalendarDay();
|
|
||||||
|
|
||||||
calDay.CalendarEpisodes = new List<CalendarEpisode>();
|
|
||||||
calDay.DateTime = today.AddDays(-i);
|
|
||||||
calDay.DayName = calDay.DateTime.Value.DayOfWeek.ToString();
|
|
||||||
|
|
||||||
week.CalendarDays.Add(calDay);
|
|
||||||
}
|
|
||||||
|
|
||||||
week.CalendarDays.Reverse();
|
|
||||||
|
|
||||||
if (newEpisodesBase is{ Data.Count: > 0 }){
|
|
||||||
var newEpisodes = newEpisodesBase.Data;
|
|
||||||
|
|
||||||
foreach (var crBrowseEpisode in newEpisodes){
|
|
||||||
var targetDate = FilterByAirDate ? crBrowseEpisode.EpisodeMetadata.EpisodeAirDate : crBrowseEpisode.LastPublic;
|
|
||||||
|
|
||||||
if (HideDubs && crBrowseEpisode.EpisodeMetadata.SeasonTitle != null && (crBrowseEpisode.EpisodeMetadata.SeasonTitle.EndsWith("Dub)") || crBrowseEpisode.EpisodeMetadata.AudioLocale != Locale.JaJp)){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var dubFilter = CurrentCalendarDubFilter?.Content + "";
|
|
||||||
if (!string.IsNullOrEmpty(dubFilter) && dubFilter != "none"){
|
|
||||||
if (crBrowseEpisode.EpisodeMetadata.AudioLocale != null && crBrowseEpisode.EpisodeMetadata.AudioLocale.GetEnumMemberValue() != dubFilter){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var calendarDay = (from day in week.CalendarDays
|
|
||||||
where day.DateTime.HasValue && day.DateTime.Value.Date == targetDate.Date
|
|
||||||
select day).FirstOrDefault();
|
|
||||||
|
|
||||||
if (calendarDay != null){
|
|
||||||
CalendarEpisode calEpisode = new CalendarEpisode();
|
|
||||||
|
|
||||||
calEpisode.DateTime = targetDate;
|
|
||||||
calEpisode.HasPassed = DateTime.Now > targetDate;
|
|
||||||
calEpisode.EpisodeName = crBrowseEpisode.Title;
|
|
||||||
calEpisode.SeriesUrl = $"https://www.crunchyroll.com/{Crunchyroll.Instance.CrunOptions.HistoryLang}/series/" + crBrowseEpisode.EpisodeMetadata.SeriesId;
|
|
||||||
calEpisode.EpisodeUrl = $"https://www.crunchyroll.com/{Crunchyroll.Instance.CrunOptions.HistoryLang}/watch/{crBrowseEpisode.Id}/";
|
|
||||||
calEpisode.ThumbnailUrl = crBrowseEpisode.Images.Thumbnail.First().First().Source;
|
|
||||||
calEpisode.IsPremiumOnly = crBrowseEpisode.EpisodeMetadata.IsPremiumOnly;
|
|
||||||
calEpisode.IsPremiere = crBrowseEpisode.EpisodeMetadata.Episode == "1";
|
|
||||||
calEpisode.SeasonName = crBrowseEpisode.EpisodeMetadata.SeasonTitle;
|
|
||||||
calEpisode.EpisodeNumber = crBrowseEpisode.EpisodeMetadata.Episode;
|
|
||||||
|
|
||||||
calendarDay.CalendarEpisodes?.Add(calEpisode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var day in week.CalendarDays){
|
|
||||||
if (day.CalendarEpisodes != null) day.CalendarEpisodes = day.CalendarEpisodes.OrderBy(e => e.DateTime).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
currentWeek = week;
|
|
||||||
CalendarDays.Clear();
|
|
||||||
CalendarDays.AddRange(week.CalendarDays);
|
|
||||||
RaisePropertyChanged(nameof(CalendarDays));
|
|
||||||
ShowLoading = false;
|
|
||||||
foreach (var calendarDay in CalendarDays){
|
|
||||||
foreach (var calendarDayCalendarEpisode in calendarDay.CalendarEpisodes){
|
|
||||||
if (calendarDayCalendarEpisode.ImageBitmap == null){
|
|
||||||
calendarDayCalendarEpisode.LoadImage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils;
|
using CRD.Utils;
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
|
@ -31,7 +32,7 @@ public partial class ContentDialogInputLoginViewModel : ViewModelBase{
|
||||||
|
|
||||||
private async void LoginButton(ContentDialog sender, ContentDialogButtonClickEventArgs args){
|
private async void LoginButton(ContentDialog sender, ContentDialogButtonClickEventArgs args){
|
||||||
dialog.PrimaryButtonClick -= LoginButton;
|
dialog.PrimaryButtonClick -= LoginButton;
|
||||||
await Crunchyroll.Instance.CrAuth.Auth(new AuthData{Password = Password,Username = Email});
|
await CrunchyrollManager.Instance.CrAuth.Auth(new AuthData{Password = Password,Username = Email});
|
||||||
accountPageViewModel.UpdatetProfile();
|
accountPageViewModel.UpdatetProfile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ using Avalonia.Media.Imaging;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
|
|
||||||
namespace CRD.ViewModels;
|
namespace CRD.ViewModels;
|
||||||
|
@ -22,23 +23,22 @@ public partial class DownloadsPageViewModel : ViewModelBase{
|
||||||
public bool _removeFinished;
|
public bool _removeFinished;
|
||||||
|
|
||||||
public DownloadsPageViewModel(){
|
public DownloadsPageViewModel(){
|
||||||
Crunchyroll.Instance.UpdateDownloadListItems();
|
QueueManager.Instance.UpdateDownloadListItems();
|
||||||
Items = Crunchyroll.Instance.DownloadItemModels;
|
Items = QueueManager.Instance.DownloadItemModels;
|
||||||
AutoDownload = Crunchyroll.Instance.CrunOptions.AutoDownload;
|
AutoDownload = CrunchyrollManager.Instance.CrunOptions.AutoDownload;
|
||||||
RemoveFinished = Crunchyroll.Instance.CrunOptions.RemoveFinishedDownload;
|
RemoveFinished = CrunchyrollManager.Instance.CrunOptions.RemoveFinishedDownload;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void OnAutoDownloadChanged(bool value){
|
partial void OnAutoDownloadChanged(bool value){
|
||||||
Crunchyroll.Instance.CrunOptions.AutoDownload = value;
|
CrunchyrollManager.Instance.CrunOptions.AutoDownload = value;
|
||||||
if (value){
|
if (value){
|
||||||
Crunchyroll.Instance.UpdateDownloadListItems();
|
QueueManager.Instance.UpdateDownloadListItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void OnRemoveFinishedChanged(bool value){
|
partial void OnRemoveFinishedChanged(bool value){
|
||||||
Crunchyroll.Instance.CrunOptions.RemoveFinishedDownload = value;
|
CrunchyrollManager.Instance.CrunOptions.RemoveFinishedDownload = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class DownloadItemModel : INotifyPropertyChanged{
|
public partial class DownloadItemModel : INotifyPropertyChanged{
|
||||||
|
@ -81,11 +81,6 @@ public partial class DownloadItemModel : INotifyPropertyChanged{
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetDubString(){
|
private string GetDubString(){
|
||||||
var hardSubs = Crunchyroll.Instance.CrunOptions.Hslang != "none" ? "Hardsub: " + Crunchyroll.Instance.CrunOptions.Hslang : "";
|
|
||||||
if (hardSubs != string.Empty){
|
|
||||||
return hardSubs;
|
|
||||||
}
|
|
||||||
|
|
||||||
var dubs = "Dub: ";
|
var dubs = "Dub: ";
|
||||||
|
|
||||||
if (epMeta.SelectedDubs != null)
|
if (epMeta.SelectedDubs != null)
|
||||||
|
@ -97,8 +92,13 @@ public partial class DownloadItemModel : INotifyPropertyChanged{
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetSubtitleString(){
|
private string GetSubtitleString(){
|
||||||
var hardSubs = Crunchyroll.Instance.CrunOptions.Hslang != "none" ? "Hardsub: " + Crunchyroll.Instance.CrunOptions.Hslang : "";
|
var hardSubs = CrunchyrollManager.Instance.CrunOptions.Hslang != "none" ? "Hardsub: " : "";
|
||||||
if (hardSubs != string.Empty){
|
if (hardSubs != string.Empty){
|
||||||
|
var locale = Languages.Locale2language(CrunchyrollManager.Instance.CrunOptions.Hslang).CrLocale;
|
||||||
|
if (epMeta.AvailableSubs != null && epMeta.AvailableSubs.Contains(locale)){
|
||||||
|
hardSubs += locale + " ";
|
||||||
|
}
|
||||||
|
|
||||||
return hardSubs;
|
return hardSubs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,15 +181,15 @@ public partial class DownloadItemModel : INotifyPropertyChanged{
|
||||||
epMeta.DownloadProgress.IsDownloading = true;
|
epMeta.DownloadProgress.IsDownloading = true;
|
||||||
Paused = !epMeta.Paused && !isDownloading || epMeta.Paused;
|
Paused = !epMeta.Paused && !isDownloading || epMeta.Paused;
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Paused)));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Paused)));
|
||||||
await Crunchyroll.Instance.DownloadEpisode(epMeta, Crunchyroll.Instance.CrunOptions);
|
await CrunchyrollManager.Instance.DownloadEpisode(epMeta, CrunchyrollManager.Instance.CrunOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public void RemoveFromQueue(){
|
public void RemoveFromQueue(){
|
||||||
CrunchyEpMeta? downloadItem = Crunchyroll.Instance.Queue.FirstOrDefault(e => e.Equals(epMeta)) ?? null;
|
CrunchyEpMeta? downloadItem = QueueManager.Instance.Queue.FirstOrDefault(e => e.Equals(epMeta)) ?? null;
|
||||||
if (downloadItem != null){
|
if (downloadItem != null){
|
||||||
Crunchyroll.Instance.Queue.Remove(downloadItem);
|
QueueManager.Instance.Queue.Remove(downloadItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ using Avalonia.Threading;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils;
|
using CRD.Utils;
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
using CRD.Utils.Structs.History;
|
using CRD.Utils.Structs.History;
|
||||||
|
@ -86,9 +87,9 @@ public partial class HistoryPageViewModel : ViewModelBase{
|
||||||
public static bool _sortDir = false;
|
public static bool _sortDir = false;
|
||||||
|
|
||||||
public HistoryPageViewModel(){
|
public HistoryPageViewModel(){
|
||||||
Items = Crunchyroll.Instance.HistoryList;
|
Items = CrunchyrollManager.Instance.HistoryList;
|
||||||
|
|
||||||
HistoryPageProperties? properties = Crunchyroll.Instance.CrunOptions.HistoryPageProperties;
|
HistoryPageProperties? properties = CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties;
|
||||||
|
|
||||||
currentViewType = properties?.SelectedView ?? HistoryViewType.Posters;
|
currentViewType = properties?.SelectedView ?? HistoryViewType.Posters;
|
||||||
currentSortingType = properties?.SelectedSorting ?? SortingType.SeriesTitle;
|
currentSortingType = properties?.SelectedSorting ?? SortingType.SeriesTitle;
|
||||||
|
@ -123,17 +124,17 @@ public partial class HistoryPageViewModel : ViewModelBase{
|
||||||
historySeries.UpdateNewEpisodes();
|
historySeries.UpdateNewEpisodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
Crunchyroll.Instance.CrHistory.SortItems();
|
CrunchyrollManager.Instance.History.SortItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void UpdateSettings(){
|
private void UpdateSettings(){
|
||||||
if (Crunchyroll.Instance.CrunOptions.HistoryPageProperties != null){
|
if (CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties != null){
|
||||||
Crunchyroll.Instance.CrunOptions.HistoryPageProperties.ScaleValue = ScaleValue;
|
CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties.ScaleValue = ScaleValue;
|
||||||
Crunchyroll.Instance.CrunOptions.HistoryPageProperties.SelectedView = currentViewType;
|
CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties.SelectedView = currentViewType;
|
||||||
Crunchyroll.Instance.CrunOptions.HistoryPageProperties.SelectedSorting = currentSortingType;
|
CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties.SelectedSorting = currentSortingType;
|
||||||
} else{
|
} else{
|
||||||
Crunchyroll.Instance.CrunOptions.HistoryPageProperties = new HistoryPageProperties(){ ScaleValue = ScaleValue, SelectedView = currentViewType, SelectedSorting = currentSortingType };
|
CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties = new HistoryPageProperties(){ ScaleValue = ScaleValue, SelectedView = currentViewType, SelectedSorting = currentSortingType };
|
||||||
}
|
}
|
||||||
|
|
||||||
CfgManager.WriteSettingsToFile();
|
CfgManager.WriteSettingsToFile();
|
||||||
|
@ -155,9 +156,9 @@ public partial class HistoryPageViewModel : ViewModelBase{
|
||||||
|
|
||||||
partial void OnSelectedSortingChanged(SortingListElement? oldValue, SortingListElement? newValue){
|
partial void OnSelectedSortingChanged(SortingListElement? oldValue, SortingListElement? newValue){
|
||||||
if (newValue == null){
|
if (newValue == null){
|
||||||
if (Crunchyroll.Instance.CrunOptions.HistoryPageProperties != null){
|
if (CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties != null){
|
||||||
Crunchyroll.Instance.CrunOptions.HistoryPageProperties.Ascending = !Crunchyroll.Instance.CrunOptions.HistoryPageProperties.Ascending;
|
CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties.Ascending = !CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties.Ascending;
|
||||||
SortDir = Crunchyroll.Instance.CrunOptions.HistoryPageProperties.Ascending;
|
SortDir = CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties.Ascending;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() => {
|
Dispatcher.UIThread.InvokeAsync(() => {
|
||||||
|
@ -169,8 +170,8 @@ public partial class HistoryPageViewModel : ViewModelBase{
|
||||||
|
|
||||||
if (newValue.SelectedSorting != null){
|
if (newValue.SelectedSorting != null){
|
||||||
currentSortingType = newValue.SelectedSorting;
|
currentSortingType = newValue.SelectedSorting;
|
||||||
if (Crunchyroll.Instance.CrunOptions.HistoryPageProperties != null) Crunchyroll.Instance.CrunOptions.HistoryPageProperties.SelectedSorting = currentSortingType;
|
if (CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties != null) CrunchyrollManager.Instance.CrunOptions.HistoryPageProperties.SelectedSorting = currentSortingType;
|
||||||
Crunchyroll.Instance.CrHistory.SortItems();
|
CrunchyrollManager.Instance.History.SortItems();
|
||||||
} else{
|
} else{
|
||||||
Console.Error.WriteLine("Invalid viewtype selected");
|
Console.Error.WriteLine("Invalid viewtype selected");
|
||||||
}
|
}
|
||||||
|
@ -211,12 +212,12 @@ public partial class HistoryPageViewModel : ViewModelBase{
|
||||||
|
|
||||||
|
|
||||||
partial void OnSelectedSeriesChanged(HistorySeries value){
|
partial void OnSelectedSeriesChanged(HistorySeries value){
|
||||||
Crunchyroll.Instance.SelectedSeries = value;
|
CrunchyrollManager.Instance.SelectedSeries = value;
|
||||||
|
|
||||||
NavToSeries();
|
NavToSeries();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(value.SonarrSeriesId) && Crunchyroll.Instance.CrunOptions.SonarrProperties is{ SonarrEnabled: true }){
|
if (!string.IsNullOrEmpty(value.SonarrSeriesId) && CrunchyrollManager.Instance.CrunOptions.SonarrProperties is{ SonarrEnabled: true }){
|
||||||
Crunchyroll.Instance.CrHistory.MatchHistoryEpisodesWithSonarr(true, SelectedSeries);
|
CrunchyrollManager.Instance.History.MatchHistoryEpisodesWithSonarr(true, SelectedSeries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -225,9 +226,9 @@ public partial class HistoryPageViewModel : ViewModelBase{
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public void RemoveSeries(string? seriesId){
|
public void RemoveSeries(string? seriesId){
|
||||||
HistorySeries? objectToRemove = Crunchyroll.Instance.HistoryList.ToList().Find(se => se.SeriesId == seriesId) ?? null;
|
HistorySeries? objectToRemove = CrunchyrollManager.Instance.HistoryList.ToList().Find(se => se.SeriesId == seriesId) ?? null;
|
||||||
if (objectToRemove != null){
|
if (objectToRemove != null){
|
||||||
Crunchyroll.Instance.HistoryList.Remove(objectToRemove);
|
CrunchyrollManager.Instance.HistoryList.Remove(objectToRemove);
|
||||||
Items.Remove(objectToRemove);
|
Items.Remove(objectToRemove);
|
||||||
CfgManager.UpdateHistoryFile();
|
CfgManager.UpdateHistoryFile();
|
||||||
}
|
}
|
||||||
|
@ -260,7 +261,7 @@ public partial class HistoryPageViewModel : ViewModelBase{
|
||||||
|
|
||||||
FetchingData = false;
|
FetchingData = false;
|
||||||
RaisePropertyChanged(nameof(FetchingData));
|
RaisePropertyChanged(nameof(FetchingData));
|
||||||
Crunchyroll.Instance.CrHistory.SortItems();
|
CrunchyrollManager.Instance.History.SortItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
|
|
|
@ -8,6 +8,7 @@ using Avalonia.Media;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils.Updater;
|
using CRD.Utils.Updater;
|
||||||
using FluentAvalonia.Styling;
|
using FluentAvalonia.Styling;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
@ -48,15 +49,15 @@ public partial class MainWindowViewModel : ViewModelBase{
|
||||||
public async void Init(){
|
public async void Init(){
|
||||||
UpdateAvailable = await Updater.Instance.CheckForUpdatesAsync();
|
UpdateAvailable = await Updater.Instance.CheckForUpdatesAsync();
|
||||||
|
|
||||||
Crunchyroll.Instance.InitOptions();
|
CrunchyrollManager.Instance.InitOptions();
|
||||||
|
|
||||||
if (Crunchyroll.Instance.CrunOptions.AccentColor != null){
|
if (CrunchyrollManager.Instance.CrunOptions.AccentColor != null){
|
||||||
_faTheme.CustomAccentColor = Color.Parse(Crunchyroll.Instance.CrunOptions.AccentColor);
|
_faTheme.CustomAccentColor = Color.Parse(CrunchyrollManager.Instance.CrunOptions.AccentColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Crunchyroll.Instance.CrunOptions.Theme == "System"){
|
if (CrunchyrollManager.Instance.CrunOptions.Theme == "System"){
|
||||||
_faTheme.PreferSystemTheme = true;
|
_faTheme.PreferSystemTheme = true;
|
||||||
} else if (Crunchyroll.Instance.CrunOptions.Theme == "Dark"){
|
} else if (CrunchyrollManager.Instance.CrunOptions.Theme == "Dark"){
|
||||||
_faTheme.PreferSystemTheme = false;
|
_faTheme.PreferSystemTheme = false;
|
||||||
Application.Current.RequestedThemeVariant = ThemeVariant.Dark;
|
Application.Current.RequestedThemeVariant = ThemeVariant.Dark;
|
||||||
} else{
|
} else{
|
||||||
|
@ -64,7 +65,7 @@ public partial class MainWindowViewModel : ViewModelBase{
|
||||||
Application.Current.RequestedThemeVariant = ThemeVariant.Light;
|
Application.Current.RequestedThemeVariant = ThemeVariant.Light;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Crunchyroll.Instance.Init();
|
await CrunchyrollManager.Instance.Init();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,6 +8,7 @@ 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;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils;
|
using CRD.Utils;
|
||||||
using CRD.Utils.Sonarr;
|
using CRD.Utils.Sonarr;
|
||||||
using CRD.Utils.Structs;
|
using CRD.Utils.Structs;
|
||||||
|
@ -37,14 +38,14 @@ public partial class SeriesPageViewModel : ViewModelBase{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_selectedSeries = Crunchyroll.Instance.SelectedSeries;
|
_selectedSeries = CrunchyrollManager.Instance.SelectedSeries;
|
||||||
|
|
||||||
if (_selectedSeries.ThumbnailImage == null){
|
if (_selectedSeries.ThumbnailImage == null){
|
||||||
_selectedSeries.LoadImage();
|
_selectedSeries.LoadImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(SelectedSeries.SonarrSeriesId) && Crunchyroll.Instance.CrunOptions.SonarrProperties != null){
|
if (!string.IsNullOrEmpty(SelectedSeries.SonarrSeriesId) && CrunchyrollManager.Instance.CrunOptions.SonarrProperties != null){
|
||||||
SonarrAvailable = SelectedSeries.SonarrSeriesId.Length > 0 && Crunchyroll.Instance.CrunOptions.SonarrProperties.SonarrEnabled;
|
SonarrAvailable = SelectedSeries.SonarrSeriesId.Length > 0 && CrunchyrollManager.Instance.CrunOptions.SonarrProperties.SonarrEnabled;
|
||||||
} else{
|
} else{
|
||||||
SonarrAvailable = false;
|
SonarrAvailable = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ using Avalonia.Styling;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils;
|
using CRD.Utils;
|
||||||
using CRD.Utils.CustomList;
|
using CRD.Utils.CustomList;
|
||||||
using CRD.Utils.Sonarr;
|
using CRD.Utils.Sonarr;
|
||||||
|
@ -327,7 +328,7 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
||||||
DefaultSubLangList.Add(new ComboBoxItem{ Content = languageItem.CrLocale });
|
DefaultSubLangList.Add(new ComboBoxItem{ Content = languageItem.CrLocale });
|
||||||
}
|
}
|
||||||
|
|
||||||
CrDownloadOptions options = Crunchyroll.Instance.CrunOptions;
|
CrDownloadOptions options = CrunchyrollManager.Instance.CrunOptions;
|
||||||
|
|
||||||
DownloadDirPath = string.IsNullOrEmpty(options.DownloadDirPath) ? CfgManager.PathVIDEOS_DIR : options.DownloadDirPath;
|
DownloadDirPath = string.IsNullOrEmpty(options.DownloadDirPath) ? CfgManager.PathVIDEOS_DIR : options.DownloadDirPath;
|
||||||
|
|
||||||
|
@ -337,7 +338,7 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
||||||
ComboBoxItem? historyLang = HistoryLangList.FirstOrDefault(a => a.Content != null && (string)a.Content == options.HistoryLang) ?? null;
|
ComboBoxItem? historyLang = HistoryLangList.FirstOrDefault(a => a.Content != null && (string)a.Content == options.HistoryLang) ?? null;
|
||||||
SelectedHistoryLang = historyLang ?? HistoryLangList[0];
|
SelectedHistoryLang = historyLang ?? HistoryLangList[0];
|
||||||
|
|
||||||
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 == Languages.Locale2language(options.Hslang).CrLocale) ?? null;
|
||||||
SelectedHSLang = hsLang ?? HardSubLangList[0];
|
SelectedHSLang = hsLang ?? HardSubLangList[0];
|
||||||
|
|
||||||
ComboBoxItem? defaultDubLang = DefaultDubLangList.FirstOrDefault(a => a.Content != null && (string)a.Content == (options.DefaultAudio ?? "")) ?? null;
|
ComboBoxItem? defaultDubLang = DefaultDubLangList.FirstOrDefault(a => a.Content != null && (string)a.Content == (options.DefaultAudio ?? "")) ?? null;
|
||||||
|
@ -441,62 +442,62 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.IncludeVideoDescription = IncludeEpisodeDescription;
|
CrunchyrollManager.Instance.CrunOptions.IncludeVideoDescription = IncludeEpisodeDescription;
|
||||||
Crunchyroll.Instance.CrunOptions.VideoTitle = FileTitle;
|
CrunchyrollManager.Instance.CrunOptions.VideoTitle = FileTitle;
|
||||||
Crunchyroll.Instance.CrunOptions.Novids = !DownloadVideo;
|
CrunchyrollManager.Instance.CrunOptions.Novids = !DownloadVideo;
|
||||||
Crunchyroll.Instance.CrunOptions.Noaudio = !DownloadAudio;
|
CrunchyrollManager.Instance.CrunOptions.Noaudio = !DownloadAudio;
|
||||||
Crunchyroll.Instance.CrunOptions.DlVideoOnce = !DownloadVideoForEveryDub;
|
CrunchyrollManager.Instance.CrunOptions.DlVideoOnce = !DownloadVideoForEveryDub;
|
||||||
Crunchyroll.Instance.CrunOptions.Chapters = DownloadChapters;
|
CrunchyrollManager.Instance.CrunOptions.Chapters = DownloadChapters;
|
||||||
Crunchyroll.Instance.CrunOptions.Mp4 = MuxToMp4;
|
CrunchyrollManager.Instance.CrunOptions.Mp4 = MuxToMp4;
|
||||||
Crunchyroll.Instance.CrunOptions.SyncTiming = SyncTimings;
|
CrunchyrollManager.Instance.CrunOptions.SyncTiming = SyncTimings;
|
||||||
Crunchyroll.Instance.CrunOptions.SkipSubsMux = SkipSubMux;
|
CrunchyrollManager.Instance.CrunOptions.SkipSubsMux = SkipSubMux;
|
||||||
Crunchyroll.Instance.CrunOptions.Numbers = Math.Clamp((int)(LeadingNumbers ?? 0),0,10);
|
CrunchyrollManager.Instance.CrunOptions.Numbers = Math.Clamp((int)(LeadingNumbers ?? 0),0,10);
|
||||||
Crunchyroll.Instance.CrunOptions.FileName = FileName;
|
CrunchyrollManager.Instance.CrunOptions.FileName = FileName;
|
||||||
Crunchyroll.Instance.CrunOptions.IncludeSignsSubs = IncludeSignSubs;
|
CrunchyrollManager.Instance.CrunOptions.IncludeSignsSubs = IncludeSignSubs;
|
||||||
Crunchyroll.Instance.CrunOptions.DownloadSpeedLimit = Math.Clamp((int)(DownloadSpeed ?? 0),0,1000000000);
|
CrunchyrollManager.Instance.CrunOptions.DownloadSpeedLimit = Math.Clamp((int)(DownloadSpeed ?? 0),0,1000000000);
|
||||||
Crunchyroll.Instance.CrunOptions.SimultaneousDownloads = Math.Clamp((int)(SimultaneousDownloads ?? 0),1,10);
|
CrunchyrollManager.Instance.CrunOptions.SimultaneousDownloads = Math.Clamp((int)(SimultaneousDownloads ?? 0),1,10);
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.SubsAddScaledBorder = GetScaledBorderAndShadowSelection();
|
CrunchyrollManager.Instance.CrunOptions.SubsAddScaledBorder = GetScaledBorderAndShadowSelection();
|
||||||
|
|
||||||
List<string> softSubs = new List<string>();
|
List<string> softSubs = new List<string>();
|
||||||
foreach (var listBoxItem in SelectedSubLang){
|
foreach (var listBoxItem in SelectedSubLang){
|
||||||
softSubs.Add(listBoxItem.Content + "");
|
softSubs.Add(listBoxItem.Content + "");
|
||||||
}
|
}
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.DlSubs = softSubs;
|
CrunchyrollManager.Instance.CrunOptions.DlSubs = softSubs;
|
||||||
|
|
||||||
string descLang = SelectedDescriptionLang.Content + "";
|
string descLang = SelectedDescriptionLang.Content + "";
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.DescriptionLang = descLang != "default" ? descLang : Crunchyroll.Instance.DefaultLocale;
|
CrunchyrollManager.Instance.CrunOptions.DescriptionLang = descLang != "default" ? descLang : CrunchyrollManager.Instance.DefaultLocale;
|
||||||
|
|
||||||
string historyLang = SelectedHistoryLang.Content + "";
|
string historyLang = SelectedHistoryLang.Content + "";
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.HistoryLang = historyLang != "default" ? historyLang : Crunchyroll.Instance.DefaultLocale;
|
CrunchyrollManager.Instance.CrunOptions.HistoryLang = historyLang != "default" ? historyLang : CrunchyrollManager.Instance.DefaultLocale;
|
||||||
|
|
||||||
string hslang = SelectedHSLang.Content + "";
|
string hslang = SelectedHSLang.Content + "";
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.Hslang = hslang != "none" ? Languages.FindLang(hslang).Locale : hslang;
|
CrunchyrollManager.Instance.CrunOptions.Hslang = hslang != "none" ? Languages.FindLang(hslang).Locale : hslang;
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.DefaultAudio = SelectedDefaultDubLang.Content + "";
|
CrunchyrollManager.Instance.CrunOptions.DefaultAudio = SelectedDefaultDubLang.Content + "";
|
||||||
Crunchyroll.Instance.CrunOptions.DefaultSub = SelectedDefaultSubLang.Content + "";
|
CrunchyrollManager.Instance.CrunOptions.DefaultSub = SelectedDefaultSubLang.Content + "";
|
||||||
|
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.StreamEndpoint = SelectedStreamEndpoint.Content + "";
|
CrunchyrollManager.Instance.CrunOptions.StreamEndpoint = SelectedStreamEndpoint.Content + "";
|
||||||
|
|
||||||
List<string> dubLangs = new List<string>();
|
List<string> dubLangs = new List<string>();
|
||||||
foreach (var listBoxItem in SelectedDubLang){
|
foreach (var listBoxItem in SelectedDubLang){
|
||||||
dubLangs.Add(listBoxItem.Content + "");
|
dubLangs.Add(listBoxItem.Content + "");
|
||||||
}
|
}
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.DubLang = dubLangs;
|
CrunchyrollManager.Instance.CrunOptions.DubLang = dubLangs;
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.QualityAudio = SelectedAudioQuality?.Content + "";
|
CrunchyrollManager.Instance.CrunOptions.QualityAudio = SelectedAudioQuality?.Content + "";
|
||||||
Crunchyroll.Instance.CrunOptions.QualityVideo = SelectedVideoQuality?.Content + "";
|
CrunchyrollManager.Instance.CrunOptions.QualityVideo = SelectedVideoQuality?.Content + "";
|
||||||
Crunchyroll.Instance.CrunOptions.Theme = CurrentAppTheme?.Content + "";
|
CrunchyrollManager.Instance.CrunOptions.Theme = CurrentAppTheme?.Content + "";
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.AccentColor = _faTheme.CustomAccentColor.ToString();
|
CrunchyrollManager.Instance.CrunOptions.AccentColor = _faTheme.CustomAccentColor.ToString();
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.History = History;
|
CrunchyrollManager.Instance.CrunOptions.History = History;
|
||||||
|
|
||||||
var props = new SonarrProperties();
|
var props = new SonarrProperties();
|
||||||
|
|
||||||
|
@ -513,23 +514,23 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
||||||
props.ApiKey = SonarrApiKey;
|
props.ApiKey = SonarrApiKey;
|
||||||
|
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.SonarrProperties = props;
|
CrunchyrollManager.Instance.CrunOptions.SonarrProperties = props;
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.LogMode = LogMode;
|
CrunchyrollManager.Instance.CrunOptions.LogMode = LogMode;
|
||||||
|
|
||||||
List<string> mkvmergeParams = new List<string>();
|
List<string> mkvmergeParams = new List<string>();
|
||||||
foreach (var mkvmergeParam in MkvMergeOptions){
|
foreach (var mkvmergeParam in MkvMergeOptions){
|
||||||
mkvmergeParams.Add(mkvmergeParam.ParamValue);
|
mkvmergeParams.Add(mkvmergeParam.ParamValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.MkvmergeOptions = mkvmergeParams;
|
CrunchyrollManager.Instance.CrunOptions.MkvmergeOptions = mkvmergeParams;
|
||||||
|
|
||||||
List<string> ffmpegParams = new List<string>();
|
List<string> ffmpegParams = new List<string>();
|
||||||
foreach (var ffmpegParam in FfmpegOptions){
|
foreach (var ffmpegParam in FfmpegOptions){
|
||||||
ffmpegParams.Add(ffmpegParam.ParamValue);
|
ffmpegParams.Add(ffmpegParam.ParamValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.FfmpegOptions = ffmpegParams;
|
CrunchyrollManager.Instance.CrunOptions.FfmpegOptions = ffmpegParams;
|
||||||
|
|
||||||
CfgManager.WriteSettingsToFile();
|
CfgManager.WriteSettingsToFile();
|
||||||
}
|
}
|
||||||
|
@ -604,8 +605,8 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
||||||
var selectedFolder = result[0];
|
var selectedFolder = result[0];
|
||||||
// Do something with the selected folder path
|
// Do something with the selected folder path
|
||||||
Console.WriteLine($"Selected folder: {selectedFolder.Path.LocalPath}");
|
Console.WriteLine($"Selected folder: {selectedFolder.Path.LocalPath}");
|
||||||
Crunchyroll.Instance.CrunOptions.DownloadDirPath = selectedFolder.Path.LocalPath;
|
CrunchyrollManager.Instance.CrunOptions.DownloadDirPath = selectedFolder.Path.LocalPath;
|
||||||
DownloadDirPath = string.IsNullOrEmpty(Crunchyroll.Instance.CrunOptions.DownloadDirPath) ? CfgManager.PathVIDEOS_DIR : Crunchyroll.Instance.CrunOptions.DownloadDirPath;
|
DownloadDirPath = string.IsNullOrEmpty(CrunchyrollManager.Instance.CrunOptions.DownloadDirPath) ? CfgManager.PathVIDEOS_DIR : CrunchyrollManager.Instance.CrunOptions.DownloadDirPath;
|
||||||
CfgManager.WriteSettingsToFile();
|
CfgManager.WriteSettingsToFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using CRD.Downloader;
|
using CRD.Downloader;
|
||||||
|
using CRD.Downloader.Crunchyroll;
|
||||||
using CRD.Utils.Sonarr;
|
using CRD.Utils.Sonarr;
|
||||||
using CRD.ViewModels;
|
using CRD.ViewModels;
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ public partial class SettingsPageView : UserControl{
|
||||||
|
|
||||||
private void OnUnloaded(object? sender, RoutedEventArgs e){
|
private void OnUnloaded(object? sender, RoutedEventArgs e){
|
||||||
if (DataContext is SettingsPageViewModel viewModel){
|
if (DataContext is SettingsPageViewModel viewModel){
|
||||||
Crunchyroll.Instance.RefreshSonarr();
|
SonarrClient.Instance.RefreshSonarr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f7835908cf3cdbf8cdfb33b914d4eb28916359fe89132c72ca3728f4f6e1c00b
|
oid sha256:e616fc7834bbcf6c56692a4e48edd61b24ab25bf0336fd48bf5f0068947d7812
|
||||||
size 26332
|
size 30526
|
||||||
|
|
Loading…
Reference in New Issue