Crunchy-Downloader/CRD/Utils/Parser/MPDTransformer.cs
Elwador 95cd06a523 Add - Added path reset buttons to Temp Folder Path, Download Folder, and Background Image settings
Add - Added background image option to the Appearance settings
Add - Background Image Settings - Added new options to control opacity and blur radius
Add - Added "Couldn't sync dubs" status if the syncing failed
Add - Added functionality to combine multiple episodes from the same season into a single entry in the calendar
Add - Added video resolution display next to dubs/subs in the downloads tab
Add - Added Cloudflare check to image loading
Add - Added hardsub selection if the current is not available
Add - Added part size setting to configure the size of parts downloaded at the same time
Add - Added quality override to history series
Add - Added history marker to search results to indicate if a series is already in the user's history
Add - Added seasons tab for seasonal releases (Spring, Summer, Fall, Winter)
Add - Added potential releases and release times for the current day and the next week to the custom calendar
Chg - Changed Calendar cards background color for improved visibility
Chg - Combined Appearance settings into a single section in the settings tab
Chg - Consolidated Debug settings into one settings expander for better organization
Chg - Changed time sync to now check both the start and end of the video
Chg - Changed encoding progress to be displayed by the progress bar
Chg - Updated the functionality for hiding dubs in the custom calendar
Chg - Adjusted Dub sync to improve accuracy, resolving issues where it failed for more episodes than expected
Chg - Subtitles and dubs are now sorted according to the order selected in the MKV file
Chg - Changed logout behavior to correctly log out if login fails when starting the downloader
Chg - Changed that all downloaded files are removed if an in-progress download is removed from the queue
Chg - Changed default profile image
Chg - Updated used packages to the newest version
Chg - Separated settings to separate tabs
Fix - Fixed some series didn't get added to the history
Fix - Fixed an issue with file path length that prevented some files from being accessed properly
Fix - Fixed an issue where file names exceeded the maximum allowable length, causing errors
Fix - Fixed an issue where refreshing a series could get stuck
Fix - Fixed a crash that could happen with the syncing
Fix - Fixed an issue where the download status showed "Done" while moving files from the temp folder
Fix - Fixed an issue where cookies were not being utilized correctly
Fix - Resolved issues with displaying dates in UTC format
Fix - Fixed an issue with incorrect calendar grouping
Fix - Fixed an issue with the previous week navigation in the calendar
Fix - Fixed an issue where the calendar would not display correctly when not logged in
Fix - Fixed incorrect FFmpeg check for other OS (Linux/macOS)
Fix - Fixed an issue where image loading used a different HTTP client
2024-12-19 19:01:50 +01:00

166 lines
No EOL
6.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using CRD.Utils.HLS;
using CRD.Utils.Parser;
using CRD.Utils.Parser.Utils;
using CRD.Utils.Structs;
namespace CRD.Utils;
public class Segment{
public string uri{ get; set; }
public double timeline{ get; set; }
public double duration{ get; set; }
public Map map{ get; set; }
public ByteRange? byteRange { get; set; }
public double? number{ get; set; }
public double? presentationTime{ get; set; }
}
public class Map{
public string uri { get; set; }
public ByteRange? byteRange { get; set; }
}
public class PlaylistItem{
public string? pssh{ get; set; }
public int bandwidth{ get; set; }
public List<Segment> segments{ get; set; }
}
public class AudioPlaylist : PlaylistItem{
public LanguageItem? language{ get; set; }
public bool @default{ get; set; }
}
public class VideoPlaylist : PlaylistItem{
public Quality quality{ get; set; }
}
public class VideoItem: VideoPlaylist{
public string resolutionText{ get; set; }
}
public class AudioItem: AudioPlaylist{
public string resolutionText{ get; set; }
}
public class Quality{
public int width{ get; set; }
public int height{ get; set; }
}
public class MPDParsed{
public Dictionary<string, ServerData> Data{ get; set; }
}
public class ServerData{
public List<AudioPlaylist> audio{ get; set; }
public List<VideoPlaylist> video{ get; set; }
}
public static class MPDParser{
public static MPDParsed Parse(string manifest, LanguageItem? language, string? url){
if (!manifest.Contains("BaseURL") && url != null){
XDocument doc = XDocument.Parse(manifest);
XElement mpd = doc.Element("MPD");
mpd.AddFirst(new XElement("BaseURL", url));
manifest = doc.ToString();
}
dynamic parsed = DashParser.Parse(manifest);
MPDParsed ret = new MPDParsed{ Data = new Dictionary<string, ServerData>() };
foreach (var item in parsed.mediaGroups.AUDIO.audio.Values){
foreach (var playlist in item.playlists){
var host = new Uri(playlist.resolvedUri).Host;
EnsureHostEntryExists(ret, host);
List<dynamic> segments = playlist.segments;
if (ObjectUtilities.GetMemberValue(playlist,"sidx") != null && segments.Count == 0){
throw new NotImplementedException();
}
var foundLanguage = Languages.FindLang(Languages.languages.FirstOrDefault(a => a.Code == item.language).CrLocale ?? "unknown");
LanguageItem? audioLang = item.language != null ? foundLanguage : (language != null ? language : foundLanguage);
var pItem = new AudioPlaylist{
bandwidth = playlist.attributes.BANDWIDTH,
language = audioLang,
@default = item.@default,
segments = segments.Select(segment => new Segment{
duration = segment.duration,
map = new Map{uri = segment.map.resolvedUri,byteRange = ObjectUtilities.GetMemberValue(segment.map,"byterange")},
number = segment.number,
presentationTime = segment.presentationTime,
timeline = segment.timeline,
uri = segment.resolvedUri,
byteRange = ObjectUtilities.GetMemberValue(segment,"byterange")
}).ToList()
};
var contentProtectionDict = (IDictionary<string, dynamic>)ObjectUtilities.GetMemberValue(playlist,"contentProtection");
if (contentProtectionDict != null && contentProtectionDict.ContainsKey("com.widevine.alpha") && contentProtectionDict["com.widevine.alpha"].pssh != null)
pItem.pssh = ArrayBufferToBase64(contentProtectionDict["com.widevine.alpha"].pssh);
ret.Data[host].audio.Add(pItem);
}
}
foreach (var playlist in parsed.playlists){
var host = new Uri(playlist.resolvedUri).Host;
EnsureHostEntryExists(ret, host);
List<dynamic> segments = playlist.segments;
if (ObjectUtilities.GetMemberValue(playlist,"sidx") != null && segments.Count == 0){
throw new NotImplementedException();
}
dynamic resolution = ObjectUtilities.GetMemberValue(playlist.attributes,"RESOLUTION");
resolution = resolution != null ? resolution : new Quality();
var pItem = new VideoPlaylist{
bandwidth = playlist.attributes.BANDWIDTH,
quality = new Quality{height = resolution.height,width = resolution.width},
segments = segments.Select(segment => new Segment{
duration = segment.duration,
map = new Map{uri = segment.map.resolvedUri,byteRange = ObjectUtilities.GetMemberValue(segment.map,"byterange")},
number = segment.number,
presentationTime = segment.presentationTime,
timeline = segment.timeline,
uri = segment.resolvedUri,
byteRange = ObjectUtilities.GetMemberValue(segment,"byterange")
}).ToList()
};
var contentProtectionDict = (IDictionary<string, dynamic>)ObjectUtilities.GetMemberValue(playlist,"contentProtection");
if (contentProtectionDict != null && contentProtectionDict.ContainsKey("com.widevine.alpha") && contentProtectionDict["com.widevine.alpha"].pssh != null)
pItem.pssh = ArrayBufferToBase64(contentProtectionDict["com.widevine.alpha"].pssh);
ret.Data[host].video.Add(pItem);
}
return ret;
}
private static void EnsureHostEntryExists(MPDParsed ret, string host){
if (!ret.Data.ContainsKey(host)){
ret.Data[host] = new ServerData{ audio = new List<AudioPlaylist>(), video = new List<VideoPlaylist>() };
}
}
public static string ArrayBufferToBase64(byte[] buffer){
return Convert.ToBase64String(buffer);
}
}