mirror of
https://github.com/Crunchy-DL/Crunchy-Downloader.git
synced 2026-03-11 17:45:39 +00:00
Fix - Fix download issues
This commit is contained in:
parent
e80568cbb0
commit
28c452d537
7 changed files with 112 additions and 43 deletions
|
|
@ -189,8 +189,8 @@ public class CrEpisode(){
|
||||||
epMeta.Season = Helpers.ExtractNumberAfterS(item.Identifier) ?? item.SeasonNumber + "";
|
epMeta.Season = Helpers.ExtractNumberAfterS(item.Identifier) ?? item.SeasonNumber + "";
|
||||||
epMeta.SeriesId = item.SeriesId;
|
epMeta.SeriesId = item.SeriesId;
|
||||||
epMeta.AbsolutEpisodeNumberE = epNum;
|
epMeta.AbsolutEpisodeNumberE = epNum;
|
||||||
epMeta.Image = images[images.Count / 2].FirstOrDefault()?.Source;
|
epMeta.Image = images.FirstOrDefault()?.FirstOrDefault()?.Source ?? string.Empty;
|
||||||
epMeta.ImageBig = images[images.Count / 2].LastOrDefault()?.Source;
|
epMeta.ImageBig = images.FirstOrDefault()?.LastOrDefault()?.Source ?? string.Empty;
|
||||||
epMeta.DownloadProgress = new DownloadProgress(){
|
epMeta.DownloadProgress = new DownloadProgress(){
|
||||||
IsDownloading = false,
|
IsDownloading = false,
|
||||||
Done = false,
|
Done = false,
|
||||||
|
|
@ -290,7 +290,6 @@ public class CrEpisode(){
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task MarkAsWatched(string episodeId){
|
public async Task MarkAsWatched(string episodeId){
|
||||||
|
|
||||||
var request = HttpClientReq.CreateRequestMessage($"{ApiUrls.Content}/discover/{crunInstance.Token?.account_id}/mark_as_watched/{episodeId}", HttpMethod.Post, true, false, null);
|
var request = HttpClientReq.CreateRequestMessage($"{ApiUrls.Content}/discover/{crunInstance.Token?.account_id}/mark_as_watched/{episodeId}", HttpMethod.Post, true, false, null);
|
||||||
|
|
||||||
var response = await HttpClientReq.Instance.SendHttpRequest(request);
|
var response = await HttpClientReq.Instance.SendHttpRequest(request);
|
||||||
|
|
@ -298,8 +297,5 @@ public class CrEpisode(){
|
||||||
if (!response.IsOk){
|
if (!response.IsOk){
|
||||||
Console.Error.WriteLine($"Mark as watched for {episodeId} failed");
|
Console.Error.WriteLine($"Mark as watched for {episodeId} failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -73,8 +73,8 @@ public class CrMovies{
|
||||||
epMeta.Season = "";
|
epMeta.Season = "";
|
||||||
epMeta.SeriesId = "";
|
epMeta.SeriesId = "";
|
||||||
epMeta.AbsolutEpisodeNumberE = "";
|
epMeta.AbsolutEpisodeNumberE = "";
|
||||||
epMeta.Image = images[images.Count / 2].FirstOrDefault()?.Source;
|
epMeta.Image = images.FirstOrDefault()?.FirstOrDefault()?.Source;
|
||||||
epMeta.ImageBig = images[images.Count / 2].LastOrDefault()?.Source;
|
epMeta.ImageBig = images.FirstOrDefault()?.LastOrDefault()?.Source;
|
||||||
epMeta.DownloadProgress = new DownloadProgress(){
|
epMeta.DownloadProgress = new DownloadProgress(){
|
||||||
IsDownloading = false,
|
IsDownloading = false,
|
||||||
Done = false,
|
Done = false,
|
||||||
|
|
|
||||||
|
|
@ -178,8 +178,8 @@ public class CrMusic{
|
||||||
epMeta.Season = "";
|
epMeta.Season = "";
|
||||||
epMeta.SeriesId = episodeP.GetSeriesId();
|
epMeta.SeriesId = episodeP.GetSeriesId();
|
||||||
epMeta.AbsolutEpisodeNumberE = "";
|
epMeta.AbsolutEpisodeNumberE = "";
|
||||||
epMeta.Image = images[images.Count / 2].Source;
|
epMeta.Image = images.FirstOrDefault()?.Source ?? string.Empty;
|
||||||
epMeta.ImageBig = images[images.Count / 2].Source;
|
epMeta.ImageBig = images.FirstOrDefault()?.Source ?? string.Empty;
|
||||||
epMeta.DownloadProgress = new DownloadProgress(){
|
epMeta.DownloadProgress = new DownloadProgress(){
|
||||||
IsDownloading = false,
|
IsDownloading = false,
|
||||||
Done = false,
|
Done = false,
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,8 @@ public class CrSeries{
|
||||||
epMeta.Season = Helpers.ExtractNumberAfterS(item.Identifier) ?? item.SeasonNumber + "";
|
epMeta.Season = Helpers.ExtractNumberAfterS(item.Identifier) ?? item.SeasonNumber + "";
|
||||||
epMeta.SeriesId = item.SeriesId;
|
epMeta.SeriesId = item.SeriesId;
|
||||||
epMeta.AbsolutEpisodeNumberE = epNum;
|
epMeta.AbsolutEpisodeNumberE = epNum;
|
||||||
epMeta.Image = images[images.Count / 2].FirstOrDefault()?.Source ?? "";
|
epMeta.Image = images.FirstOrDefault()?.FirstOrDefault()?.Source ?? string.Empty;
|
||||||
epMeta.ImageBig = images[images.Count / 2].LastOrDefault()?.Source;
|
epMeta.ImageBig = images.FirstOrDefault()?.LastOrDefault()?.Source ?? string.Empty;
|
||||||
epMeta.DownloadProgress = new DownloadProgress(){
|
epMeta.DownloadProgress = new DownloadProgress(){
|
||||||
IsDownloading = false,
|
IsDownloading = false,
|
||||||
Done = false,
|
Done = false,
|
||||||
|
|
@ -266,22 +266,22 @@ public class CrSeries{
|
||||||
crunchySeriesList.List = sortedEpisodes.Select(kvp => {
|
crunchySeriesList.List = sortedEpisodes.Select(kvp => {
|
||||||
var key = kvp.Key;
|
var key = kvp.Key;
|
||||||
var value = kvp.Value;
|
var value = kvp.Value;
|
||||||
var images = (value.Items[0].Images?.Thumbnail ??[new List<Image>{ new(){ Source = "/notFound.jpg" } }]);
|
var images = (value.Items.FirstOrDefault()?.Images?.Thumbnail ??[new List<Image>{ new(){ Source = "/notFound.jpg" } }]);
|
||||||
var seconds = (int)Math.Floor(value.Items[0].DurationMs / 1000.0);
|
var seconds = (int)Math.Floor((value.Items.FirstOrDefault()?.DurationMs ?? 0) / 1000.0);
|
||||||
var langList = value.Langs.Select(a => a.CrLocale).ToList();
|
var langList = value.Langs.Select(a => a.CrLocale).ToList();
|
||||||
Languages.SortListByLangList(langList);
|
Languages.SortListByLangList(langList);
|
||||||
|
|
||||||
return new Episode{
|
return new Episode{
|
||||||
E = key.StartsWith("E") ? key.Substring(1) : key,
|
E = key.StartsWith("E") ? key.Substring(1) : key,
|
||||||
Lang = langList,
|
Lang = langList,
|
||||||
Name = value.Items[0].Title,
|
Name = value.Items.FirstOrDefault()?.Title ?? string.Empty,
|
||||||
Season = Helpers.ExtractNumberAfterS(value.Items[0].Identifier) ?? value.Items[0].SeasonNumber.ToString(),
|
Season = (Helpers.ExtractNumberAfterS(value.Items.FirstOrDefault()?.Identifier?? string.Empty) ?? value.Items.FirstOrDefault()?.SeasonNumber.ToString()) ?? string.Empty,
|
||||||
SeriesTitle = Regex.Replace(value.Items[0].SeriesTitle, @"\(\w+ Dub\)", "").TrimEnd(),
|
SeriesTitle = Regex.Replace(value.Items.FirstOrDefault()?.SeriesTitle?? string.Empty, @"\(\w+ Dub\)", "").TrimEnd(),
|
||||||
SeasonTitle = Regex.Replace(value.Items[0].SeasonTitle, @"\(\w+ Dub\)", "").TrimEnd(),
|
SeasonTitle = Regex.Replace(value.Items.FirstOrDefault()?.SeasonTitle?? string.Empty, @"\(\w+ Dub\)", "").TrimEnd(),
|
||||||
EpisodeNum = key.StartsWith("SP") ? key : value.Items[0].EpisodeNumber?.ToString() ?? value.Items[0].Episode ?? "?",
|
EpisodeNum = key.StartsWith("SP") ? key : value.Items.FirstOrDefault()?.EpisodeNumber?.ToString() ?? value.Items.FirstOrDefault()?.Episode ?? "?",
|
||||||
Id = value.Items[0].SeasonId,
|
Id = value.Items.FirstOrDefault()?.SeasonId ?? string.Empty,
|
||||||
Img = images[images.Count / 2].FirstOrDefault()?.Source ?? "",
|
Img = images.FirstOrDefault()?.FirstOrDefault()?.Source ?? string.Empty,
|
||||||
Description = value.Items[0].Description,
|
Description = value.Items.FirstOrDefault()?.Description ?? string.Empty,
|
||||||
EpisodeType = EpisodeType.Episode,
|
EpisodeType = EpisodeType.Episode,
|
||||||
Time = $"{seconds / 60}:{seconds % 60:D2}" // Ensures two digits for seconds.
|
Time = $"{seconds / 60}:{seconds % 60:D2}" // Ensures two digits for seconds.
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -333,15 +333,27 @@ public class HlsDownloader{
|
||||||
|
|
||||||
var _lastUiUpdate = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
var _lastUiUpdate = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
||||||
|
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
var token = cts.Token;
|
||||||
|
|
||||||
for (int i = 0; i < segments.Count; i++){
|
for (int i = 0; i < segments.Count; i++){
|
||||||
if (File.Exists(Path.Combine(tempDir, $"part_{i:D6}.tmp")))
|
try{
|
||||||
|
await semaphore.WaitAsync(token);
|
||||||
|
} catch (OperationCanceledException){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(Path.Combine(tempDir, $"part_{i:D6}.tmp"))){
|
||||||
|
semaphore.Release();
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int index = i;
|
int index = i;
|
||||||
await semaphore.WaitAsync();
|
|
||||||
|
|
||||||
downloadTasks.Add(Task.Run(async () => {
|
downloadTasks.Add(Task.Run(async () => {
|
||||||
try{
|
try{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
var segment = new Segment{
|
var segment = new Segment{
|
||||||
Uri = ObjectUtilities.GetMemberValue(segments[index], "uri"),
|
Uri = ObjectUtilities.GetMemberValue(segments[index], "uri"),
|
||||||
Key = ObjectUtilities.GetMemberValue(segments[index], "key"),
|
Key = ObjectUtilities.GetMemberValue(segments[index], "key"),
|
||||||
|
|
@ -385,32 +397,53 @@ public class HlsDownloader{
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!QueueManager.Instance.Queue.Contains(_currentEpMeta))
|
if (!QueueManager.Instance.Queue.Contains(_currentEpMeta)){
|
||||||
|
cts.Cancel();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QueueManager.Instance.Queue.Refresh();
|
QueueManager.Instance.Queue.Refresh();
|
||||||
|
|
||||||
while (_currentEpMeta.Paused){
|
while (_currentEpMeta.Paused){
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
if (!QueueManager.Instance.Queue.Contains(_currentEpMeta))
|
if (!QueueManager.Instance.Queue.Contains(_currentEpMeta)){
|
||||||
|
cts.Cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (Exception ex){
|
} catch (Exception ex){
|
||||||
Console.Error.WriteLine($"Error downloading part {index}: {ex.Message}");
|
Console.Error.WriteLine($"Error downloading part {index}: {ex.Message}");
|
||||||
errorOccurred = true;
|
errorOccurred = true;
|
||||||
|
cts.Cancel();
|
||||||
} finally{
|
} finally{
|
||||||
semaphore.Release();
|
semaphore.Release();
|
||||||
}
|
}
|
||||||
}));
|
}, token));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
await Task.WhenAll(downloadTasks);
|
await Task.WhenAll(downloadTasks);
|
||||||
|
} catch (OperationCanceledException){
|
||||||
|
if (!QueueManager.Instance.Queue.Contains(_currentEpMeta)){
|
||||||
|
if (!_currentEpMeta.DownloadProgress.Done){
|
||||||
|
CleanupNewDownloadMethod(tempDir, resumeFile, true);
|
||||||
|
}
|
||||||
|
} else{
|
||||||
|
Console.Error.WriteLine("Download cancelled due to error.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, _data.Parts);
|
||||||
|
}
|
||||||
|
|
||||||
if (errorOccurred)
|
if (errorOccurred)
|
||||||
return (false, _data.Parts);
|
return (false, _data.Parts);
|
||||||
|
|
||||||
using (var output = new FileStream(fn, FileMode.Append, FileAccess.Write, FileShare.None)){
|
using (var output = new FileStream(fn, FileMode.Append, FileAccess.Write, FileShare.None)){
|
||||||
for (int i = mergedParts; i < segments.Count; i++){
|
for (int i = mergedParts; i < segments.Count; i++){
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
return (false, _data.Parts);
|
||||||
|
|
||||||
string tempFile = Path.Combine(tempDir, $"part_{i:D6}.tmp");
|
string tempFile = Path.Combine(tempDir, $"part_{i:D6}.tmp");
|
||||||
if (!File.Exists(tempFile)){
|
if (!File.Exists(tempFile)){
|
||||||
Console.Error.WriteLine($"Missing temp file for part {i}, aborting merge.");
|
Console.Error.WriteLine($"Missing temp file for part {i}, aborting merge.");
|
||||||
|
|
@ -439,19 +472,51 @@ public class HlsDownloader{
|
||||||
Doing = _isAudio ? "Merging Audio" : (_isVideo ? "Merging Video" : "")
|
Doing = _isAudio ? "Merging Audio" : (_isVideo ? "Merging Video" : "")
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!QueueManager.Instance.Queue.Contains(_currentEpMeta))
|
if (!QueueManager.Instance.Queue.Contains(_currentEpMeta)){
|
||||||
return (false, _data.Parts);
|
if (!_currentEpMeta.DownloadProgress.Done){
|
||||||
|
CleanupNewDownloadMethod(tempDir, resumeFile, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, _data.Parts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup temp files
|
// Cleanup temp files
|
||||||
Directory.Delete(tempDir, true);
|
CleanupNewDownloadMethod(tempDir, resumeFile);
|
||||||
File.Delete(resumeFile);
|
|
||||||
|
|
||||||
return (true, _data.Parts);
|
return (true, _data.Parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CleanupNewDownloadMethod(string tempDir, string resumeFile, bool cleanAll = false){
|
||||||
|
if (cleanAll){
|
||||||
|
// Delete downloaded files
|
||||||
|
foreach (var file in _currentEpMeta.downloadedFiles){
|
||||||
|
try{
|
||||||
|
File.Delete(file); // Safe: File.Delete does nothing if file doesn't exist
|
||||||
|
} catch (Exception ex){
|
||||||
|
Console.Error.WriteLine($"Failed to delete file '{file}': {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete temp directory
|
||||||
|
try{
|
||||||
|
if (Directory.Exists(tempDir))
|
||||||
|
Directory.Delete(tempDir, true);
|
||||||
|
} catch (Exception ex){
|
||||||
|
Console.Error.WriteLine($"Failed to delete temp dir '{tempDir}': {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete resume file
|
||||||
|
try{
|
||||||
|
if (File.Exists(resumeFile))
|
||||||
|
File.Delete(resumeFile);
|
||||||
|
} catch (Exception ex){
|
||||||
|
Console.Error.WriteLine($"Failed to delete resume file '{resumeFile}': {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Info GetDownloadInfo(long dateStartUnix, int partsDownloaded, int partsTotal, long incrementalBytes, long totalDownloadedBytes){
|
public static Info GetDownloadInfo(long dateStartUnix, int partsDownloaded, int partsTotal, long incrementalBytes, long totalDownloadedBytes){
|
||||||
DateTime lastStart = DateTimeOffset.FromUnixTimeMilliseconds(dateStartUnix).UtcDateTime;
|
DateTime lastStart = DateTimeOffset.FromUnixTimeMilliseconds(dateStartUnix).UtcDateTime;
|
||||||
|
|
|
||||||
|
|
@ -623,7 +623,7 @@ public class Helpers{
|
||||||
public static Dictionary<string, List<DownloadedMedia>> GroupByLanguageWithSubtitles(List<DownloadedMedia> allMedia){
|
public static Dictionary<string, List<DownloadedMedia>> GroupByLanguageWithSubtitles(List<DownloadedMedia> allMedia){
|
||||||
//Group by language
|
//Group by language
|
||||||
var languageGroups = allMedia
|
var languageGroups = allMedia
|
||||||
.Where(media => media.Type != DownloadMediaType.Description &&
|
.Where(media => media.Type != DownloadMediaType.Description && media.Type != DownloadMediaType.Cover &&
|
||||||
(!string.IsNullOrEmpty(media.Lang?.CrLocale) ||
|
(!string.IsNullOrEmpty(media.Lang?.CrLocale) ||
|
||||||
(media is{ Type: DownloadMediaType.Subtitle, RelatedVideoDownloadMedia: not null } &&
|
(media is{ Type: DownloadMediaType.Subtitle, RelatedVideoDownloadMedia: not null } &&
|
||||||
!string.IsNullOrEmpty(media.RelatedVideoDownloadMedia.Lang?.CrLocale)))
|
!string.IsNullOrEmpty(media.RelatedVideoDownloadMedia.Lang?.CrLocale)))
|
||||||
|
|
@ -646,6 +646,15 @@ public class Helpers{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Find and add Cover media to each group
|
||||||
|
var coverMedia = allMedia.Where(media => media.Type == DownloadMediaType.Cover).ToList();
|
||||||
|
|
||||||
|
if (coverMedia.Count > 0){
|
||||||
|
foreach (var group in languageGroups.Values){
|
||||||
|
group.Add(coverMedia[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return languageGroups;
|
return languageGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -291,11 +291,10 @@ public class CrunchyEpisode : IHistorySource{
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetImageUrl(){
|
public string GetImageUrl(){
|
||||||
if (Images != null){
|
return Images?.Thumbnail?
|
||||||
return Images.Thumbnail?.First().First().Source ?? string.Empty;
|
.FirstOrDefault()?
|
||||||
}
|
.FirstOrDefault()?
|
||||||
|
.Source ?? string.Empty;
|
||||||
return string.Empty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue