Add - Added download speed limit to settings
Chg - Replace special characters in name with nothing instead of _ Chg - Adjusted estimated time calculation Chg - Adjusted download speed calculation Fix - Initial calendar loading didn't work always
This commit is contained in:
parent
baf90f546b
commit
aee8a20450
@ -243,7 +243,12 @@ public class Crunchyroll{
|
|||||||
return forDate;
|
return forDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
var request = HttpClientReq.CreateRequestMessage($"{calendarLanguage[CrunOptions.SelectedCalendarLanguage ?? "de"]}?filter=premium&date={weeksMondayDate}", HttpMethod.Get, true, true, null);
|
var request = HttpClientReq.CreateRequestMessage($"{calendarLanguage[CrunOptions.SelectedCalendarLanguage ?? "de"]}?filter=premium&date={weeksMondayDate}", HttpMethod.Get, false, false, null);
|
||||||
|
|
||||||
|
request.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36");
|
||||||
|
request.Headers.AcceptEncoding.ParseAdd("gzip, deflate");
|
||||||
|
request.Headers.AcceptLanguage.ParseAdd("en-US,en;q=0.9");
|
||||||
|
request.Headers.Referrer = new Uri("https://www.crunchyroll.com/");
|
||||||
|
|
||||||
var response = await HttpClientReq.Instance.SendHttpRequest(request);
|
var response = await HttpClientReq.Instance.SendHttpRequest(request);
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ public class FileNameManager{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static string CleanupFilename(string filename){
|
public static string CleanupFilename(string filename){
|
||||||
string fixingChar = "_";
|
string fixingChar = "";
|
||||||
Regex illegalRe = new Regex(@"[\/\?<>\\:\*\|"":]"); // Illegal Characters on most Operating Systems
|
Regex illegalRe = new Regex(@"[\/\?<>\\:\*\|"":]"); // Illegal Characters on most Operating Systems
|
||||||
Regex controlRe = new Regex(@"[\x00-\x1f\x80-\x9f]"); // Unicode Control codes: C0 and C1
|
Regex controlRe = new Regex(@"[\x00-\x1f\x80-\x9f]"); // Unicode Control codes: C0 and C1
|
||||||
Regex reservedRe = new Regex(@"^\.\.?$"); // Reserved filenames on Unix-based systems (".", "..")
|
Regex reservedRe = new Regex(@"^\.\.?$"); // Reserved filenames on Unix-based systems (".", "..")
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@ -71,11 +72,9 @@ public class HlsDownloader{
|
|||||||
_data.Offset = resumeData.Completed;
|
_data.Offset = resumeData.Completed;
|
||||||
_data.IsResume = true;
|
_data.IsResume = true;
|
||||||
} else{
|
} else{
|
||||||
|
|
||||||
if (resumeData.Total == _data.M3U8Json?.Segments.Count &&
|
if (resumeData.Total == _data.M3U8Json?.Segments.Count &&
|
||||||
resumeData.Completed == resumeData.Total &&
|
resumeData.Completed == resumeData.Total &&
|
||||||
!double.IsNaN(resumeData.Completed)){
|
!double.IsNaN(resumeData.Completed)){
|
||||||
|
|
||||||
Console.WriteLine("Already finished");
|
Console.WriteLine("Already finished");
|
||||||
return (Ok: true, _data.Parts);
|
return (Ok: true, _data.Parts);
|
||||||
}
|
}
|
||||||
@ -118,8 +117,7 @@ public class HlsDownloader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Start time
|
|
||||||
_data.DateStart = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
|
||||||
|
|
||||||
if (_data.M3U8Json != null){
|
if (_data.M3U8Json != null){
|
||||||
List<dynamic> segments = _data.M3U8Json.Segments;
|
List<dynamic> segments = _data.M3U8Json.Segments;
|
||||||
@ -158,6 +156,8 @@ public class HlsDownloader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int p = 0; p < Math.Ceiling((double)segments.Count / _data.Threads); p++){
|
for (int p = 0; p < Math.Ceiling((double)segments.Count / _data.Threads); p++){
|
||||||
|
// Start time
|
||||||
|
_data.DateStart = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
||||||
int offset = p * _data.Threads;
|
int offset = p * _data.Threads;
|
||||||
int dlOffset = Math.Min(offset + _data.Threads, segments.Count);
|
int dlOffset = Math.Min(offset + _data.Threads, segments.Count);
|
||||||
|
|
||||||
@ -248,14 +248,15 @@ public class HlsDownloader{
|
|||||||
int downloadedSeg = Math.Min(dlOffset, totalSeg);
|
int downloadedSeg = Math.Min(dlOffset, totalSeg);
|
||||||
_data.Parts.Completed = downloadedSeg + _data.Offset; //
|
_data.Parts.Completed = downloadedSeg + _data.Offset; //
|
||||||
|
|
||||||
var dataLog = GetDownloadInfo(_data.DateStart, _data.Parts.Completed, totalSeg, _data.BytesDownloaded);
|
var dataLog = GetDownloadInfo(_data.DateStart, _data.Parts.Completed, totalSeg, _data.BytesDownloaded,_data.TotalBytes);
|
||||||
|
_data.BytesDownloaded = 0;
|
||||||
|
|
||||||
// Save resume data to file
|
// Save resume data to file
|
||||||
string resumeDataJson = JsonConvert.SerializeObject(new{ _data.Parts.Completed, Total = totalSeg });
|
string resumeDataJson = JsonConvert.SerializeObject(new{ _data.Parts.Completed, Total = totalSeg });
|
||||||
File.WriteAllText($"{fn}.resume", resumeDataJson);
|
File.WriteAllText($"{fn}.resume", resumeDataJson);
|
||||||
|
|
||||||
// Log progress
|
// Log progress
|
||||||
Console.WriteLine($"{_data.Parts.Completed} of {totalSeg} parts downloaded [{dataLog.Percent}%] ({FormatTime(dataLog.Time / 1000)} | {dataLog.DownloadSpeed / 1000000.0:F2}Mb/s)");
|
Console.WriteLine($"{_data.Parts.Completed} of {totalSeg} parts downloaded [{dataLog.Percent}%] ({FormatTime(dataLog.Time)} | {dataLog.DownloadSpeed / 1000000.0:F2}Mb/s)");
|
||||||
|
|
||||||
_currentEpMeta.DownloadProgress = new DownloadProgress(){
|
_currentEpMeta.DownloadProgress = new DownloadProgress(){
|
||||||
IsDownloading = true,
|
IsDownloading = true,
|
||||||
@ -283,7 +284,7 @@ public class HlsDownloader{
|
|||||||
return (Ok: true, _data.Parts);
|
return (Ok: true, _data.Parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Info GetDownloadInfo(long dateStartUnix, int partsDownloaded, int partsTotal, long downloadedBytes){
|
public static Info GetDownloadInfo(long dateStartUnix, int partsDownloaded, int partsTotal, long downloadedBytes,long totalDownloadedBytes){
|
||||||
// Convert Unix timestamp to DateTime
|
// Convert Unix timestamp to DateTime
|
||||||
DateTime dateStart = DateTimeOffset.FromUnixTimeMilliseconds(dateStartUnix).UtcDateTime;
|
DateTime dateStart = DateTimeOffset.FromUnixTimeMilliseconds(dateStartUnix).UtcDateTime;
|
||||||
double dateElapsed = (DateTime.UtcNow - dateStart).TotalMilliseconds;
|
double dateElapsed = (DateTime.UtcNow - dateStart).TotalMilliseconds;
|
||||||
@ -292,12 +293,14 @@ public class HlsDownloader{
|
|||||||
int percentFixed = (int)((double)partsDownloaded / partsTotal * 100);
|
int percentFixed = (int)((double)partsDownloaded / partsTotal * 100);
|
||||||
int percent = percentFixed < 100 ? percentFixed : (partsTotal == partsDownloaded ? 100 : 99);
|
int percent = percentFixed < 100 ? percentFixed : (partsTotal == partsDownloaded ? 100 : 99);
|
||||||
|
|
||||||
// Calculate remaining time estimate
|
|
||||||
double remainingTime = dateElapsed * (partsTotal / (double)partsDownloaded - 1);
|
|
||||||
|
|
||||||
// Calculate download speed (bytes per second)
|
// Calculate download speed (bytes per second)
|
||||||
double downloadSpeed = downloadedBytes / (dateElapsed / 1000);
|
double downloadSpeed = downloadedBytes / (dateElapsed / 1000);
|
||||||
|
|
||||||
|
// Calculate remaining time estimate
|
||||||
|
// double remainingTime = dateElapsed * (partsTotal / (double)partsDownloaded - 1);
|
||||||
|
int partsLeft = partsTotal - partsDownloaded;
|
||||||
|
double remainingTime = (partsLeft * (totalDownloadedBytes / partsDownloaded)) / downloadSpeed;
|
||||||
|
|
||||||
return new Info{
|
return new Info{
|
||||||
Percent = percent,
|
Percent = percent,
|
||||||
Time = remainingTime,
|
Time = remainingTime,
|
||||||
@ -324,11 +327,17 @@ public class HlsDownloader{
|
|||||||
if (partContent != null) dec = decipher.TransformFinalBlock(partContent, 0, partContent.Length);
|
if (partContent != null) dec = decipher.TransformFinalBlock(partContent, 0, partContent.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dec != null) _data.BytesDownloaded += dec.Length;
|
if (dec != null){
|
||||||
|
_data.BytesDownloaded += dec.Length;
|
||||||
|
_data.TotalBytes += dec.Length;
|
||||||
|
}
|
||||||
} else{
|
} else{
|
||||||
part = await GetData(p, sUri, seg.ByteRange != null ? seg.ByteRange.ToDictionary() : new Dictionary<string, string>(), segOffset, false, _data.Timeout, _data.Retries);
|
part = await GetData(p, sUri, seg.ByteRange != null ? seg.ByteRange.ToDictionary() : new Dictionary<string, string>(), segOffset, false, _data.Timeout, _data.Retries);
|
||||||
dec = part;
|
dec = part;
|
||||||
if (dec != null) _data.BytesDownloaded += dec.Length;
|
if (dec != null){
|
||||||
|
_data.BytesDownloaded += dec.Length;
|
||||||
|
_data.TotalBytes += dec.Length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ex){
|
} catch (Exception ex){
|
||||||
throw new Exception($"Error at segment {p}: {ex.Message}", ex);
|
throw new Exception($"Error at segment {p}: {ex.Message}", ex);
|
||||||
@ -428,7 +437,7 @@ public class HlsDownloader{
|
|||||||
for (int attempt = 0; attempt < retryCount + 1; attempt++){
|
for (int attempt = 0; attempt < retryCount + 1; attempt++){
|
||||||
using (var request = CloneHttpRequestMessage(requestPara)){
|
using (var request = CloneHttpRequestMessage(requestPara)){
|
||||||
try{
|
try{
|
||||||
response = await HttpClientReq.Instance.GetHttpClient().SendAsync(request, HttpCompletionOption.ResponseContentRead);
|
response = await HttpClientReq.Instance.GetHttpClient().SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
return await ReadContentAsByteArrayAsync(response.Content);
|
return await ReadContentAsByteArrayAsync(response.Content);
|
||||||
} catch (HttpRequestException ex){
|
} catch (HttpRequestException ex){
|
||||||
@ -448,8 +457,14 @@ public class HlsDownloader{
|
|||||||
|
|
||||||
private async Task<byte[]> ReadContentAsByteArrayAsync(HttpContent content){
|
private async Task<byte[]> ReadContentAsByteArrayAsync(HttpContent content){
|
||||||
using (var memoryStream = new MemoryStream())
|
using (var memoryStream = new MemoryStream())
|
||||||
using (var contentStream = await content.ReadAsStreamAsync()){
|
using (var contentStream = await content.ReadAsStreamAsync())
|
||||||
await contentStream.CopyToAsync(memoryStream, 81920);
|
using (var throttledStream = new ThrottledStream(contentStream)){
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = await throttledStream.ReadAsync(buffer, 0, buffer.Length)) > 0){
|
||||||
|
await memoryStream.WriteAsync(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
|
||||||
return memoryStream.ToArray();
|
return memoryStream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -567,6 +582,7 @@ public class Data{
|
|||||||
public int WaitTime{ get; set; }
|
public int WaitTime{ get; set; }
|
||||||
public string? Override{ get; set; }
|
public string? Override{ get; set; }
|
||||||
public long DateStart{ get; set; }
|
public long DateStart{ get; set; }
|
||||||
|
public long TotalBytes{ get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ProgressData{
|
public class ProgressData{
|
||||||
|
97
CRD/Utils/HLS/ThrottledStream.cs
Normal file
97
CRD/Utils/HLS/ThrottledStream.cs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
using CRD.Downloader;
|
||||||
|
|
||||||
|
namespace CRD.Utils.HLS;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
public class GlobalThrottler{
|
||||||
|
private static GlobalThrottler _instance;
|
||||||
|
private static readonly object _lock = new object();
|
||||||
|
private long _totalBytesRead;
|
||||||
|
private DateTime _lastReadTime;
|
||||||
|
|
||||||
|
private GlobalThrottler(){
|
||||||
|
_totalBytesRead = 0;
|
||||||
|
_lastReadTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GlobalThrottler Instance(){
|
||||||
|
if (_instance == null){
|
||||||
|
lock (_lock){
|
||||||
|
if (_instance == null){
|
||||||
|
_instance = new GlobalThrottler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Throttle(int bytesRead){
|
||||||
|
|
||||||
|
if (Crunchyroll.Instance.CrunOptions.DownloadSpeedLimit == 0) return;
|
||||||
|
|
||||||
|
lock (_lock){
|
||||||
|
_totalBytesRead += bytesRead;
|
||||||
|
if (_totalBytesRead >= ((Crunchyroll.Instance.CrunOptions.DownloadSpeedLimit * 1024) / 10)){
|
||||||
|
var timeElapsed = DateTime.Now - _lastReadTime;
|
||||||
|
if (timeElapsed.TotalMilliseconds < 100){
|
||||||
|
Thread.Sleep(100 - (int)timeElapsed.TotalMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
_totalBytesRead = 0;
|
||||||
|
_lastReadTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ThrottledStream : Stream{
|
||||||
|
private readonly Stream _baseStream;
|
||||||
|
private readonly GlobalThrottler _throttler;
|
||||||
|
|
||||||
|
public ThrottledStream(Stream baseStream){
|
||||||
|
_baseStream = baseStream ?? throw new ArgumentNullException(nameof(baseStream));
|
||||||
|
_throttler = GlobalThrottler.Instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanRead => _baseStream.CanRead;
|
||||||
|
public override bool CanSeek => _baseStream.CanSeek;
|
||||||
|
public override bool CanWrite => _baseStream.CanWrite;
|
||||||
|
public override long Length => _baseStream.Length;
|
||||||
|
|
||||||
|
public override long Position{
|
||||||
|
get => _baseStream.Position;
|
||||||
|
set => _baseStream.Position = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Flush() => _baseStream.Flush();
|
||||||
|
|
||||||
|
public override long Seek(long offset, SeekOrigin origin) => _baseStream.Seek(offset, origin);
|
||||||
|
|
||||||
|
public override void SetLength(long value) => _baseStream.SetLength(value);
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count) => _baseStream.Write(buffer, offset, count);
|
||||||
|
|
||||||
|
public override int Read(byte[] buffer, int offset, int count){
|
||||||
|
int bytesRead = 0;
|
||||||
|
if (Crunchyroll.Instance.CrunOptions.DownloadSpeedLimit != 0){
|
||||||
|
int bytesToRead = Math.Min(count, (Crunchyroll.Instance.CrunOptions.DownloadSpeedLimit * 1024) / 10);
|
||||||
|
bytesRead = _baseStream.Read(buffer, offset, bytesToRead);
|
||||||
|
_throttler.Throttle(bytesRead);
|
||||||
|
} else{
|
||||||
|
bytesRead = _baseStream.Read(buffer, offset, count);
|
||||||
|
}
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing){
|
||||||
|
if (disposing){
|
||||||
|
_baseStream.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -40,6 +40,7 @@ public class HttpClientReq{
|
|||||||
handler = new HttpClientHandler();
|
handler = new HttpClientHandler();
|
||||||
handler.CookieContainer = new CookieContainer();
|
handler.CookieContainer = new CookieContainer();
|
||||||
handler.UseCookies = true;
|
handler.UseCookies = true;
|
||||||
|
handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
|
||||||
|
|
||||||
// Initialize the HttpClient with the handler
|
// Initialize the HttpClient with the handler
|
||||||
client = new HttpClient(handler);
|
client = new HttpClient(handler);
|
||||||
@ -95,8 +96,7 @@ public class HttpClientReq{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (disableDrmHeader){
|
if (disableDrmHeader){
|
||||||
request.Headers.Add("X-Cr-Disable-Drm", "true");
|
|
||||||
request.Headers.Add("x-cr-stream-limits", "false");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,4 +153,7 @@ public class CrDownloadOptions{
|
|||||||
[YamlMember(Alias = "history_page_properties", ApplyNamingConventions = false)]
|
[YamlMember(Alias = "history_page_properties", ApplyNamingConventions = false)]
|
||||||
public HistoryPageProperties? HistoryPageProperties{ get; set; }
|
public HistoryPageProperties? HistoryPageProperties{ get; set; }
|
||||||
|
|
||||||
|
[YamlMember(Alias = "download_speed_limit", ApplyNamingConventions = false)]
|
||||||
|
public int DownloadSpeedLimit{ get; set; }
|
||||||
|
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ using System.Net.Http;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CRD.Utils.HLS;
|
||||||
using CRD.ViewModels;
|
using CRD.ViewModels;
|
||||||
using CRD.Views.Utils;
|
using CRD.Views.Utils;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
@ -80,9 +81,6 @@ public class Updater : INotifyPropertyChanged{
|
|||||||
|
|
||||||
|
|
||||||
public async Task DownloadAndUpdateAsync(){
|
public async Task DownloadAndUpdateAsync(){
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
using (var client = new HttpClient()){
|
using (var client = new HttpClient()){
|
||||||
// Download the zip file
|
// Download the zip file
|
||||||
|
@ -70,7 +70,7 @@ public partial class DownloadItemModel : INotifyPropertyChanged{
|
|||||||
|
|
||||||
Done = epMeta.DownloadProgress.Done;
|
Done = epMeta.DownloadProgress.Done;
|
||||||
Percent = epMeta.DownloadProgress.Percent;
|
Percent = epMeta.DownloadProgress.Percent;
|
||||||
Time = "Estimated Time: " + TimeSpan.FromSeconds(epMeta.DownloadProgress.Time / 1000).ToString(@"hh\:mm\:ss");
|
Time = "Estimated Time: " + TimeSpan.FromSeconds(epMeta.DownloadProgress.Time).ToString(@"hh\:mm\:ss");
|
||||||
DownloadSpeed = $"{epMeta.DownloadProgress.DownloadSpeed / 1000000.0:F2}Mb/s";
|
DownloadSpeed = $"{epMeta.DownloadProgress.DownloadSpeed / 1000000.0:F2}Mb/s";
|
||||||
Paused = epMeta.Paused || !isDownloading && !epMeta.Paused;
|
Paused = epMeta.Paused || !isDownloading && !epMeta.Paused;
|
||||||
DoingWhat = epMeta.Paused ? "Paused" : Done ? "Done" : epMeta.DownloadProgress.Doing != string.Empty ? epMeta.DownloadProgress.Doing : "Waiting";
|
DoingWhat = epMeta.Paused ? "Paused" : Done ? "Done" : epMeta.DownloadProgress.Doing != string.Empty ? epMeta.DownloadProgress.Doing : "Waiting";
|
||||||
@ -127,7 +127,7 @@ public partial class DownloadItemModel : INotifyPropertyChanged{
|
|||||||
isDownloading = epMeta.DownloadProgress.IsDownloading || Done;
|
isDownloading = epMeta.DownloadProgress.IsDownloading || Done;
|
||||||
Done = epMeta.DownloadProgress.Done;
|
Done = epMeta.DownloadProgress.Done;
|
||||||
Percent = epMeta.DownloadProgress.Percent;
|
Percent = epMeta.DownloadProgress.Percent;
|
||||||
Time = "Estimated Time: " + TimeSpan.FromSeconds(epMeta.DownloadProgress.Time / 1000).ToString(@"hh\:mm\:ss");
|
Time = "Estimated Time: " + TimeSpan.FromSeconds(epMeta.DownloadProgress.Time).ToString(@"hh\:mm\:ss");
|
||||||
DownloadSpeed = $"{epMeta.DownloadProgress.DownloadSpeed / 1000000.0:F2}Mb/s";
|
DownloadSpeed = $"{epMeta.DownloadProgress.DownloadSpeed / 1000000.0:F2}Mb/s";
|
||||||
|
|
||||||
Paused = epMeta.Paused || !isDownloading && !epMeta.Paused;
|
Paused = epMeta.Paused || !isDownloading && !epMeta.Paused;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
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.Collections.Specialized;
|
||||||
@ -65,10 +65,13 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
|||||||
private bool _history;
|
private bool _history;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private int _leadingNumbers;
|
private double? _leadingNumbers;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private int _simultaneousDownloads;
|
private double? _simultaneousDownloads;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private double? _downloadSpeed;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _fileName = "";
|
private string _fileName = "";
|
||||||
@ -371,6 +374,7 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
|||||||
AddScaledBorderAndShadow = options.SubsAddScaledBorder is ScaledBorderAndShadowSelection.ScaledBorderAndShadowNo or ScaledBorderAndShadowSelection.ScaledBorderAndShadowYes;
|
AddScaledBorderAndShadow = options.SubsAddScaledBorder is ScaledBorderAndShadowSelection.ScaledBorderAndShadowNo or ScaledBorderAndShadowSelection.ScaledBorderAndShadowYes;
|
||||||
SelectedScaledBorderAndShadow = GetScaledBorderAndShadowFromOptions(options);
|
SelectedScaledBorderAndShadow = GetScaledBorderAndShadowFromOptions(options);
|
||||||
|
|
||||||
|
DownloadSpeed = options.DownloadSpeedLimit;
|
||||||
IncludeEpisodeDescription = options.IncludeVideoDescription;
|
IncludeEpisodeDescription = options.IncludeVideoDescription;
|
||||||
FileTitle = options.VideoTitle ?? "";
|
FileTitle = options.VideoTitle ?? "";
|
||||||
IncludeSignSubs = options.IncludeSignsSubs;
|
IncludeSignSubs = options.IncludeSignsSubs;
|
||||||
@ -438,9 +442,11 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
|||||||
Crunchyroll.Instance.CrunOptions.Chapters = DownloadChapters;
|
Crunchyroll.Instance.CrunOptions.Chapters = DownloadChapters;
|
||||||
Crunchyroll.Instance.CrunOptions.Mp4 = MuxToMp4;
|
Crunchyroll.Instance.CrunOptions.Mp4 = MuxToMp4;
|
||||||
Crunchyroll.Instance.CrunOptions.SkipSubsMux = SkipSubMux;
|
Crunchyroll.Instance.CrunOptions.SkipSubsMux = SkipSubMux;
|
||||||
Crunchyroll.Instance.CrunOptions.Numbers = LeadingNumbers;
|
Crunchyroll.Instance.CrunOptions.Numbers = Math.Clamp((int)(LeadingNumbers ?? 0),0,10);
|
||||||
Crunchyroll.Instance.CrunOptions.FileName = FileName;
|
Crunchyroll.Instance.CrunOptions.FileName = FileName;
|
||||||
Crunchyroll.Instance.CrunOptions.IncludeSignsSubs = IncludeSignSubs;
|
Crunchyroll.Instance.CrunOptions.IncludeSignsSubs = IncludeSignSubs;
|
||||||
|
Crunchyroll.Instance.CrunOptions.DownloadSpeedLimit = Math.Clamp((int)(DownloadSpeed ?? 0),0,1000000000);
|
||||||
|
Crunchyroll.Instance.CrunOptions.SimultaneousDownloads = Math.Clamp((int)(SimultaneousDownloads ?? 0),1,10);
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.SubsAddScaledBorder = GetScaledBorderAndShadowSelection();
|
Crunchyroll.Instance.CrunOptions.SubsAddScaledBorder = GetScaledBorderAndShadowSelection();
|
||||||
|
|
||||||
@ -477,7 +483,7 @@ public partial class SettingsPageViewModel : ViewModelBase{
|
|||||||
Crunchyroll.Instance.CrunOptions.DubLang = dubLangs;
|
Crunchyroll.Instance.CrunOptions.DubLang = dubLangs;
|
||||||
|
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.SimultaneousDownloads = SimultaneousDownloads;
|
|
||||||
|
|
||||||
Crunchyroll.Instance.CrunOptions.QualityAudio = SelectedAudioQuality?.Content + "";
|
Crunchyroll.Instance.CrunOptions.QualityAudio = SelectedAudioQuality?.Content + "";
|
||||||
Crunchyroll.Instance.CrunOptions.QualityVideo = SelectedVideoQuality?.Content + "";
|
Crunchyroll.Instance.CrunOptions.QualityVideo = SelectedVideoQuality?.Content + "";
|
||||||
|
@ -151,6 +151,17 @@
|
|||||||
Description="Adjust download settings"
|
Description="Adjust download settings"
|
||||||
IsExpanded="False">
|
IsExpanded="False">
|
||||||
|
|
||||||
|
<controls:SettingsExpanderItem Content="Max Download Speed"
|
||||||
|
Description="Download in Kb/s - 0 is full speed">
|
||||||
|
<controls:SettingsExpanderItem.Footer>
|
||||||
|
<controls:NumberBox Minimum="0" Maximum="1000000000"
|
||||||
|
Value="{Binding DownloadSpeed}"
|
||||||
|
SpinButtonPlacementMode="Hidden"
|
||||||
|
HorizontalAlignment="Stretch" />
|
||||||
|
</controls:SettingsExpanderItem.Footer>
|
||||||
|
</controls:SettingsExpanderItem>
|
||||||
|
|
||||||
|
|
||||||
<controls:SettingsExpanderItem Content="Stream Endpoint ">
|
<controls:SettingsExpanderItem Content="Stream Endpoint ">
|
||||||
<controls:SettingsExpanderItem.Footer>
|
<controls:SettingsExpanderItem.Footer>
|
||||||
<ComboBox HorizontalContentAlignment="Center" MinWidth="210" MaxDropDownHeight="400"
|
<ComboBox HorizontalContentAlignment="Center" MinWidth="210" MaxDropDownHeight="400"
|
||||||
@ -181,7 +192,7 @@
|
|||||||
|
|
||||||
<controls:SettingsExpanderItem Content="Simultaneous Downloads">
|
<controls:SettingsExpanderItem Content="Simultaneous Downloads">
|
||||||
<controls:SettingsExpanderItem.Footer>
|
<controls:SettingsExpanderItem.Footer>
|
||||||
<controls:NumberBox Minimum="0" Maximum="5"
|
<controls:NumberBox Minimum="0" Maximum="10"
|
||||||
Value="{Binding SimultaneousDownloads}"
|
Value="{Binding SimultaneousDownloads}"
|
||||||
SpinButtonPlacementMode="Inline"
|
SpinButtonPlacementMode="Inline"
|
||||||
HorizontalAlignment="Stretch" />
|
HorizontalAlignment="Stretch" />
|
||||||
|
Loading…
Reference in New Issue
Block a user