调整部分代码结构
This commit is contained in:
parent
7d8e7c6402
commit
b9d3b57b39
|
@ -5,8 +5,8 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Entity
|
namespace N_m3u8DL_RE.Common.Entity;
|
||||||
{
|
|
||||||
public class EncryptInfo
|
public class EncryptInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -40,4 +40,3 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
using System;
|
namespace N_m3u8DL_RE.Common.Entity;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Entity
|
|
||||||
{
|
|
||||||
public class MSSData
|
public class MSSData
|
||||||
{
|
{
|
||||||
public string FourCC { get; set; } = "";
|
public string FourCC { get; set; } = "";
|
||||||
|
@ -22,4 +16,3 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
public string ProtectionSystemID { get; set; } = "";
|
public string ProtectionSystemID { get; set; } = "";
|
||||||
public string ProtectionData { get; set; } = "";
|
public string ProtectionData { get; set; } = "";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +1,7 @@
|
||||||
using System;
|
namespace N_m3u8DL_RE.Common.Entity;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Entity
|
|
||||||
{
|
|
||||||
// 主要处理 EXT-X-DISCONTINUITY
|
// 主要处理 EXT-X-DISCONTINUITY
|
||||||
public class MediaPart
|
public class MediaPart
|
||||||
{
|
{
|
||||||
public List<MediaSegment> MediaSegments { get; set; } = new List<MediaSegment>();
|
public List<MediaSegment> MediaSegments { get; set; } = new List<MediaSegment>();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
using System;
|
namespace N_m3u8DL_RE.Common.Entity;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Entity
|
|
||||||
{
|
|
||||||
public class MediaSegment
|
public class MediaSegment
|
||||||
{
|
{
|
||||||
public long Index { get; set; }
|
public long Index { get; set; }
|
||||||
|
@ -14,7 +8,7 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
public DateTime? DateTime { get; set; }
|
public DateTime? DateTime { get; set; }
|
||||||
|
|
||||||
public long? StartRange { get; set; }
|
public long? StartRange { get; set; }
|
||||||
public long? StopRange { get => (StartRange != null && ExpectLength != null) ? StartRange + ExpectLength - 1 : null; }
|
public long? StopRange => (StartRange != null && ExpectLength != null) ? StartRange + ExpectLength - 1 : null;
|
||||||
public long? ExpectLength { get; set; }
|
public long? ExpectLength { get; set; }
|
||||||
|
|
||||||
public EncryptInfo EncryptInfo { get; set; } = new EncryptInfo();
|
public EncryptInfo EncryptInfo { get; set; } = new EncryptInfo();
|
||||||
|
@ -27,7 +21,7 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
{
|
{
|
||||||
return obj is MediaSegment segment &&
|
return obj is MediaSegment segment &&
|
||||||
Index == segment.Index &&
|
Index == segment.Index &&
|
||||||
Duration == segment.Duration &&
|
Math.Abs(Duration - segment.Duration) < 0.001 &&
|
||||||
Title == segment.Title &&
|
Title == segment.Title &&
|
||||||
StartRange == segment.StartRange &&
|
StartRange == segment.StartRange &&
|
||||||
StopRange == segment.StopRange &&
|
StopRange == segment.StopRange &&
|
||||||
|
@ -40,4 +34,3 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
return HashCode.Combine(Index, Duration, Title, StartRange, StopRange, ExpectLength, Url);
|
return HashCode.Combine(Index, Duration, Title, StartRange, StopRange, ExpectLength, Url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,12 +1,5 @@
|
||||||
using N_m3u8DL_RE.Common.Enum;
|
namespace N_m3u8DL_RE.Common.Entity;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Entity
|
|
||||||
{
|
|
||||||
public class Playlist
|
public class Playlist
|
||||||
{
|
{
|
||||||
// 对应Url信息
|
// 对应Url信息
|
||||||
|
@ -24,4 +17,3 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
// 分片信息
|
// 分片信息
|
||||||
public List<MediaPart> MediaParts { get; set; } = new List<MediaPart>();
|
public List<MediaPart> MediaParts { get; set; } = new List<MediaPart>();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
using N_m3u8DL_RE.Common.Enum;
|
using N_m3u8DL_RE.Common.Enum;
|
||||||
using N_m3u8DL_RE.Common.Util;
|
using N_m3u8DL_RE.Common.Util;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Entity
|
namespace N_m3u8DL_RE.Common.Entity;
|
||||||
{
|
|
||||||
public class StreamSpec
|
public class StreamSpec
|
||||||
{
|
{
|
||||||
public MediaType? MediaType { get; set; }
|
public MediaType? MediaType { get; set; }
|
||||||
|
@ -185,4 +180,3 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
return returnStr.TrimEnd().TrimEnd('|').TrimEnd();
|
return returnStr.TrimEnd().TrimEnd('|').TrimEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
using System;
|
namespace N_m3u8DL_RE.Common.Entity;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Entity
|
|
||||||
{
|
|
||||||
public class SubCue
|
public class SubCue
|
||||||
{
|
{
|
||||||
public TimeSpan StartTime { get; set; }
|
public TimeSpan StartTime { get; set; }
|
||||||
|
@ -27,4 +21,3 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
return HashCode.Combine(StartTime, EndTime, Payload, Settings);
|
return HashCode.Combine(StartTime, EndTime, Payload, Settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
using System;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Entity
|
namespace N_m3u8DL_RE.Common.Entity;
|
||||||
{
|
|
||||||
public partial class WebVttSub
|
public partial class WebVttSub
|
||||||
{
|
{
|
||||||
[GeneratedRegex("X-TIMESTAMP-MAP.*")]
|
[GeneratedRegex("X-TIMESTAMP-MAP.*")]
|
||||||
|
@ -273,4 +269,3 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
return srt;
|
return srt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +1,7 @@
|
||||||
using System;
|
namespace N_m3u8DL_RE.Common.Enum;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Enum
|
|
||||||
{
|
|
||||||
public enum Choise
|
public enum Choise
|
||||||
{
|
{
|
||||||
YES = 1,
|
YES = 1,
|
||||||
NO = 0
|
NO = 0
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
using System;
|
namespace N_m3u8DL_RE.Common.Enum;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Enum
|
|
||||||
{
|
|
||||||
public enum EncryptMethod
|
public enum EncryptMethod
|
||||||
{
|
{
|
||||||
NONE,
|
NONE,
|
||||||
|
@ -17,4 +11,3 @@ namespace N_m3u8DL_RE.Common.Enum
|
||||||
CHACHA20,
|
CHACHA20,
|
||||||
UNKNOWN
|
UNKNOWN
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
using System;
|
namespace N_m3u8DL_RE.Common.Enum;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Enum
|
|
||||||
{
|
|
||||||
public enum ExtractorType
|
public enum ExtractorType
|
||||||
{
|
{
|
||||||
MPEG_DASH,
|
MPEG_DASH,
|
||||||
|
@ -13,4 +7,3 @@ namespace N_m3u8DL_RE.Common.Enum
|
||||||
HTTP_LIVE,
|
HTTP_LIVE,
|
||||||
MSS
|
MSS
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
using System;
|
namespace N_m3u8DL_RE.Common.Enum;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Enum
|
|
||||||
{
|
|
||||||
public enum MediaType
|
public enum MediaType
|
||||||
{
|
{
|
||||||
AUDIO = 0,
|
AUDIO = 0,
|
||||||
|
@ -13,4 +7,3 @@ namespace N_m3u8DL_RE.Common.Enum
|
||||||
SUBTITLES = 2,
|
SUBTITLES = 2,
|
||||||
CLOSED_CAPTIONS = 3
|
CLOSED_CAPTIONS = 3
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
namespace N_m3u8DL_RE.Common.Enum
|
namespace N_m3u8DL_RE.Common.Enum;
|
||||||
{
|
|
||||||
public enum RoleType
|
public enum RoleType
|
||||||
{
|
{
|
||||||
Subtitle = 0,
|
Subtitle = 0,
|
||||||
|
@ -12,4 +12,3 @@
|
||||||
Sign = 7,
|
Sign = 7,
|
||||||
Metadata = 8,
|
Metadata = 8,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
using N_m3u8DL_RE.Common.Enum;
|
using N_m3u8DL_RE.Common.Enum;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common
|
namespace N_m3u8DL_RE.Common;
|
||||||
{
|
|
||||||
[JsonSourceGenerationOptions(
|
[JsonSourceGenerationOptions(
|
||||||
WriteIndented = true,
|
WriteIndented = true,
|
||||||
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
||||||
|
@ -19,4 +19,3 @@ namespace N_m3u8DL_RE.Common
|
||||||
[JsonSerializable(typeof(List<MediaSegment>))]
|
[JsonSerializable(typeof(List<MediaSegment>))]
|
||||||
[JsonSerializable(typeof(Dictionary<string, string>))]
|
[JsonSerializable(typeof(Dictionary<string, string>))]
|
||||||
internal partial class JsonContext : JsonSerializerContext { }
|
internal partial class JsonContext : JsonSerializerContext { }
|
||||||
}
|
|
||||||
|
|
|
@ -6,12 +6,11 @@ using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.JsonConverter
|
namespace N_m3u8DL_RE.Common.JsonConverter;
|
||||||
{
|
|
||||||
internal class BytesBase64Converter : JsonConverter<byte[]>
|
internal class BytesBase64Converter : JsonConverter<byte[]>
|
||||||
{
|
{
|
||||||
public override byte[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => reader.GetBytesFromBase64();
|
public override byte[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => reader.GetBytesFromBase64();
|
||||||
|
|
||||||
public override void Write(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options) => writer.WriteStringValue(Convert.ToBase64String(value));
|
public override void Write(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options) => writer.WriteStringValue(Convert.ToBase64String(value));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -8,27 +8,27 @@ public class NonAnsiWriter : TextWriter
|
||||||
{
|
{
|
||||||
public override Encoding Encoding => Console.OutputEncoding;
|
public override Encoding Encoding => Console.OutputEncoding;
|
||||||
|
|
||||||
private string lastOut = "";
|
private string? _lastOut = "";
|
||||||
|
|
||||||
public override void Write(char value)
|
public override void Write(char value)
|
||||||
{
|
{
|
||||||
Console.Write(value);
|
Console.Write(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write(string value)
|
public override void Write(string? value)
|
||||||
{
|
{
|
||||||
if (lastOut == value)
|
if (_lastOut == value)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastOut = value;
|
_lastOut = value;
|
||||||
RemoveAnsiEscapeSequences(value);
|
RemoveAnsiEscapeSequences(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveAnsiEscapeSequences(string input)
|
private void RemoveAnsiEscapeSequences(string? input)
|
||||||
{
|
{
|
||||||
// Use regular expression to remove ANSI escape sequences
|
// Use regular expression to remove ANSI escape sequences
|
||||||
string output = Regex.Replace(input, @"\x1B\[(\d+;?)+m", "");
|
string output = Regex.Replace(input ?? "", @"\x1B\[(\d+;?)+m", "");
|
||||||
output = Regex.Replace(output, @"\[\??\d+[AKlh]", "");
|
output = Regex.Replace(output, @"\[\??\d+[AKlh]", "");
|
||||||
output = Regex.Replace(output,"[\r\n] +","");
|
output = Regex.Replace(output,"[\r\n] +","");
|
||||||
if (string.IsNullOrWhiteSpace(output))
|
if (string.IsNullOrWhiteSpace(output))
|
||||||
|
|
|
@ -4,8 +4,8 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Log
|
namespace N_m3u8DL_RE.Common.Log;
|
||||||
{
|
|
||||||
public enum LogLevel
|
public enum LogLevel
|
||||||
{
|
{
|
||||||
OFF,
|
OFF,
|
||||||
|
@ -14,4 +14,3 @@ namespace N_m3u8DL_RE.Common.Log
|
||||||
INFO,
|
INFO,
|
||||||
DEBUG,
|
DEBUG,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Log
|
namespace N_m3u8DL_RE.Common.Log;
|
||||||
{
|
|
||||||
public partial class Logger
|
public partial class Logger
|
||||||
{
|
{
|
||||||
[GeneratedRegex("{}")]
|
[GeneratedRegex("{}")]
|
||||||
|
@ -240,4 +234,3 @@ namespace N_m3u8DL_RE.Common.Log
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -1,138 +1,131 @@
|
||||||
using System;
|
namespace N_m3u8DL_RE.Common.Resource;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Resource
|
|
||||||
{
|
|
||||||
public class ResString
|
public class ResString
|
||||||
{
|
{
|
||||||
public readonly static string ReLiveTs = "<RE_LIVE_TS>";
|
public static readonly string ReLiveTs = "<RE_LIVE_TS>";
|
||||||
public static string singleFileRealtimeDecryptWarn { get => GetText("singleFileRealtimeDecryptWarn"); }
|
public static string singleFileRealtimeDecryptWarn => GetText("singleFileRealtimeDecryptWarn");
|
||||||
public static string singleFileSplitWarn { get => GetText("singleFileSplitWarn"); }
|
public static string singleFileSplitWarn => GetText("singleFileSplitWarn");
|
||||||
public static string customRangeWarn { get => GetText("customRangeWarn"); }
|
public static string customRangeWarn => GetText("customRangeWarn");
|
||||||
public static string customRangeFound { get => GetText("customRangeFound"); }
|
public static string customRangeFound => GetText("customRangeFound");
|
||||||
public static string customAdKeywordsFound { get => GetText("customAdKeywordsFound"); }
|
public static string customAdKeywordsFound => GetText("customAdKeywordsFound");
|
||||||
public static string customRangeInvalid { get => GetText("customRangeInvalid"); }
|
public static string customRangeInvalid => GetText("customRangeInvalid");
|
||||||
public static string consoleRedirected { get => GetText("consoleRedirected"); }
|
public static string consoleRedirected => GetText("consoleRedirected");
|
||||||
public static string autoBinaryMerge { get => GetText("autoBinaryMerge"); }
|
public static string autoBinaryMerge => GetText("autoBinaryMerge");
|
||||||
public static string autoBinaryMerge2 { get => GetText("autoBinaryMerge2"); }
|
public static string autoBinaryMerge2 => GetText("autoBinaryMerge2");
|
||||||
public static string autoBinaryMerge3 { get => GetText("autoBinaryMerge3"); }
|
public static string autoBinaryMerge3 => GetText("autoBinaryMerge3");
|
||||||
public static string autoBinaryMerge4 { get => GetText("autoBinaryMerge4"); }
|
public static string autoBinaryMerge4 => GetText("autoBinaryMerge4");
|
||||||
public static string autoBinaryMerge5 { get => GetText("autoBinaryMerge5"); }
|
public static string autoBinaryMerge5 => GetText("autoBinaryMerge5");
|
||||||
public static string autoBinaryMerge6 { get => GetText("autoBinaryMerge6"); }
|
public static string autoBinaryMerge6 => GetText("autoBinaryMerge6");
|
||||||
public static string badM3u8 { get => GetText("badM3u8"); }
|
public static string badM3u8 => GetText("badM3u8");
|
||||||
public static string binaryMerge { get => GetText("binaryMerge"); }
|
public static string binaryMerge => GetText("binaryMerge");
|
||||||
public static string checkingLast { get => GetText("checkingLast"); }
|
public static string checkingLast => GetText("checkingLast");
|
||||||
public static string cmd_appendUrlParams { get => GetText("cmd_appendUrlParams"); }
|
public static string cmd_appendUrlParams => GetText("cmd_appendUrlParams");
|
||||||
public static string cmd_autoSelect { get => GetText("cmd_autoSelect"); }
|
public static string cmd_autoSelect => GetText("cmd_autoSelect");
|
||||||
public static string cmd_binaryMerge { get => GetText("cmd_binaryMerge"); }
|
public static string cmd_binaryMerge => GetText("cmd_binaryMerge");
|
||||||
public static string cmd_useFFmpegConcatDemuxer { get => GetText("cmd_useFFmpegConcatDemuxer"); }
|
public static string cmd_useFFmpegConcatDemuxer => GetText("cmd_useFFmpegConcatDemuxer");
|
||||||
public static string cmd_checkSegmentsCount { get => GetText("cmd_checkSegmentsCount"); }
|
public static string cmd_checkSegmentsCount => GetText("cmd_checkSegmentsCount");
|
||||||
public static string cmd_decryptionBinaryPath { get => GetText("cmd_decryptionBinaryPath"); }
|
public static string cmd_decryptionBinaryPath => GetText("cmd_decryptionBinaryPath");
|
||||||
public static string cmd_delAfterDone { get => GetText("cmd_delAfterDone"); }
|
public static string cmd_delAfterDone => GetText("cmd_delAfterDone");
|
||||||
public static string cmd_ffmpegBinaryPath { get => GetText("cmd_ffmpegBinaryPath"); }
|
public static string cmd_ffmpegBinaryPath => GetText("cmd_ffmpegBinaryPath");
|
||||||
public static string cmd_mkvmergeBinaryPath { get => GetText("cmd_mkvmergeBinaryPath"); }
|
public static string cmd_mkvmergeBinaryPath => GetText("cmd_mkvmergeBinaryPath");
|
||||||
public static string cmd_baseUrl { get => GetText("cmd_baseUrl"); }
|
public static string cmd_baseUrl => GetText("cmd_baseUrl");
|
||||||
public static string cmd_maxSpeed { get => GetText("cmd_maxSpeed"); }
|
public static string cmd_maxSpeed => GetText("cmd_maxSpeed");
|
||||||
public static string cmd_adKeyword { get => GetText("cmd_adKeyword"); }
|
public static string cmd_adKeyword => GetText("cmd_adKeyword");
|
||||||
public static string cmd_moreHelp { get => GetText("cmd_moreHelp"); }
|
public static string cmd_moreHelp => GetText("cmd_moreHelp");
|
||||||
public static string cmd_header { get => GetText("cmd_header"); }
|
public static string cmd_header => GetText("cmd_header");
|
||||||
public static string cmd_muxImport { get => GetText("cmd_muxImport"); }
|
public static string cmd_muxImport => GetText("cmd_muxImport");
|
||||||
public static string cmd_muxImport_more { get => GetText("cmd_muxImport_more"); }
|
public static string cmd_muxImport_more => GetText("cmd_muxImport_more");
|
||||||
public static string cmd_selectVideo { get => GetText("cmd_selectVideo"); }
|
public static string cmd_selectVideo => GetText("cmd_selectVideo");
|
||||||
public static string cmd_dropVideo { get => GetText("cmd_dropVideo"); }
|
public static string cmd_dropVideo => GetText("cmd_dropVideo");
|
||||||
public static string cmd_selectVideo_more { get => GetText("cmd_selectVideo_more"); }
|
public static string cmd_selectVideo_more => GetText("cmd_selectVideo_more");
|
||||||
public static string cmd_selectAudio { get => GetText("cmd_selectAudio"); }
|
public static string cmd_selectAudio => GetText("cmd_selectAudio");
|
||||||
public static string cmd_dropAudio { get => GetText("cmd_dropAudio"); }
|
public static string cmd_dropAudio => GetText("cmd_dropAudio");
|
||||||
public static string cmd_selectAudio_more { get => GetText("cmd_selectAudio_more"); }
|
public static string cmd_selectAudio_more => GetText("cmd_selectAudio_more");
|
||||||
public static string cmd_selectSubtitle { get => GetText("cmd_selectSubtitle"); }
|
public static string cmd_selectSubtitle => GetText("cmd_selectSubtitle");
|
||||||
public static string cmd_dropSubtitle { get => GetText("cmd_dropSubtitle"); }
|
public static string cmd_dropSubtitle => GetText("cmd_dropSubtitle");
|
||||||
public static string cmd_selectSubtitle_more { get => GetText("cmd_selectSubtitle_more"); }
|
public static string cmd_selectSubtitle_more => GetText("cmd_selectSubtitle_more");
|
||||||
public static string cmd_custom_range { get => GetText("cmd_custom_range"); }
|
public static string cmd_custom_range => GetText("cmd_custom_range");
|
||||||
public static string cmd_customHLSMethod { get => GetText("cmd_customHLSMethod"); }
|
public static string cmd_customHLSMethod => GetText("cmd_customHLSMethod");
|
||||||
public static string cmd_customHLSKey { get => GetText("cmd_customHLSKey"); }
|
public static string cmd_customHLSKey => GetText("cmd_customHLSKey");
|
||||||
public static string cmd_customHLSIv { get => GetText("cmd_customHLSIv"); }
|
public static string cmd_customHLSIv => GetText("cmd_customHLSIv");
|
||||||
public static string cmd_Input { get => GetText("cmd_Input"); }
|
public static string cmd_Input => GetText("cmd_Input");
|
||||||
public static string cmd_forceAnsiConsole { get => GetText("cmd_forceAnsiConsole"); }
|
public static string cmd_forceAnsiConsole => GetText("cmd_forceAnsiConsole");
|
||||||
public static string cmd_noAnsiColor { get => GetText("cmd_noAnsiColor"); }
|
public static string cmd_noAnsiColor => GetText("cmd_noAnsiColor");
|
||||||
public static string cmd_keys { get => GetText("cmd_keys"); }
|
public static string cmd_keys => GetText("cmd_keys");
|
||||||
public static string cmd_keyText { get => GetText("cmd_keyText"); }
|
public static string cmd_keyText => GetText("cmd_keyText");
|
||||||
public static string cmd_loadKeyFailed { get => GetText("cmd_loadKeyFailed"); }
|
public static string cmd_loadKeyFailed => GetText("cmd_loadKeyFailed");
|
||||||
public static string cmd_logLevel { get => GetText("cmd_logLevel"); }
|
public static string cmd_logLevel => GetText("cmd_logLevel");
|
||||||
public static string cmd_MP4RealTimeDecryption { get => GetText("cmd_MP4RealTimeDecryption"); }
|
public static string cmd_MP4RealTimeDecryption => GetText("cmd_MP4RealTimeDecryption");
|
||||||
public static string cmd_saveDir { get => GetText("cmd_saveDir"); }
|
public static string cmd_saveDir => GetText("cmd_saveDir");
|
||||||
public static string cmd_saveName { get => GetText("cmd_saveName"); }
|
public static string cmd_saveName => GetText("cmd_saveName");
|
||||||
public static string cmd_savePattern { get => GetText("cmd_savePattern"); }
|
public static string cmd_savePattern => GetText("cmd_savePattern");
|
||||||
public static string cmd_skipDownload { get => GetText("cmd_skipDownload"); }
|
public static string cmd_skipDownload => GetText("cmd_skipDownload");
|
||||||
public static string cmd_noDateInfo { get => GetText("cmd_noDateInfo"); }
|
public static string cmd_noDateInfo => GetText("cmd_noDateInfo");
|
||||||
public static string cmd_noLog { get => GetText("cmd_noLog"); }
|
public static string cmd_noLog => GetText("cmd_noLog");
|
||||||
public static string cmd_skipMerge { get => GetText("cmd_skipMerge"); }
|
public static string cmd_skipMerge => GetText("cmd_skipMerge");
|
||||||
public static string cmd_subFormat { get => GetText("cmd_subFormat"); }
|
public static string cmd_subFormat => GetText("cmd_subFormat");
|
||||||
public static string cmd_subOnly { get => GetText("cmd_subOnly"); }
|
public static string cmd_subOnly => GetText("cmd_subOnly");
|
||||||
public static string cmd_subtitleFix { get => GetText("cmd_subtitleFix"); }
|
public static string cmd_subtitleFix => GetText("cmd_subtitleFix");
|
||||||
public static string cmd_threadCount { get => GetText("cmd_threadCount"); }
|
public static string cmd_threadCount => GetText("cmd_threadCount");
|
||||||
public static string cmd_downloadRetryCount { get => GetText("cmd_downloadRetryCount"); }
|
public static string cmd_downloadRetryCount => GetText("cmd_downloadRetryCount");
|
||||||
public static string cmd_tmpDir { get => GetText("cmd_tmpDir"); }
|
public static string cmd_tmpDir => GetText("cmd_tmpDir");
|
||||||
public static string cmd_uiLanguage { get => GetText("cmd_uiLanguage"); }
|
public static string cmd_uiLanguage => GetText("cmd_uiLanguage");
|
||||||
public static string cmd_urlProcessorArgs { get => GetText("cmd_urlProcessorArgs"); }
|
public static string cmd_urlProcessorArgs => GetText("cmd_urlProcessorArgs");
|
||||||
public static string cmd_useShakaPackager { get => GetText("cmd_useShakaPackager"); }
|
public static string cmd_useShakaPackager => GetText("cmd_useShakaPackager");
|
||||||
public static string cmd_concurrentDownload { get => GetText("cmd_concurrentDownload"); }
|
public static string cmd_concurrentDownload => GetText("cmd_concurrentDownload");
|
||||||
public static string cmd_useSystemProxy { get => GetText("cmd_useSystemProxy"); }
|
public static string cmd_useSystemProxy => GetText("cmd_useSystemProxy");
|
||||||
public static string cmd_customProxy { get => GetText("cmd_customProxy"); }
|
public static string cmd_customProxy => GetText("cmd_customProxy");
|
||||||
public static string cmd_customRange { get => GetText("cmd_customRange"); }
|
public static string cmd_customRange => GetText("cmd_customRange");
|
||||||
public static string cmd_liveKeepSegments { get => GetText("cmd_liveKeepSegments"); }
|
public static string cmd_liveKeepSegments => GetText("cmd_liveKeepSegments");
|
||||||
public static string cmd_livePipeMux { get => GetText("cmd_livePipeMux"); }
|
public static string cmd_livePipeMux => GetText("cmd_livePipeMux");
|
||||||
public static string cmd_liveRecordLimit { get => GetText("cmd_liveRecordLimit"); }
|
public static string cmd_liveRecordLimit => GetText("cmd_liveRecordLimit");
|
||||||
public static string cmd_taskStartAt { get => GetText("cmd_taskStartAt"); }
|
public static string cmd_taskStartAt => GetText("cmd_taskStartAt");
|
||||||
public static string cmd_liveWaitTime { get => GetText("cmd_liveWaitTime"); }
|
public static string cmd_liveWaitTime => GetText("cmd_liveWaitTime");
|
||||||
public static string cmd_liveTakeCount { get => GetText("cmd_liveTakeCount"); }
|
public static string cmd_liveTakeCount => GetText("cmd_liveTakeCount");
|
||||||
public static string cmd_liveFixVttByAudio { get => GetText("cmd_liveFixVttByAudio"); }
|
public static string cmd_liveFixVttByAudio => GetText("cmd_liveFixVttByAudio");
|
||||||
public static string cmd_liveRealTimeMerge { get => GetText("cmd_liveRealTimeMerge"); }
|
public static string cmd_liveRealTimeMerge => GetText("cmd_liveRealTimeMerge");
|
||||||
public static string cmd_livePerformAsVod { get => GetText("cmd_livePerformAsVod"); }
|
public static string cmd_livePerformAsVod => GetText("cmd_livePerformAsVod");
|
||||||
public static string cmd_muxAfterDone { get => GetText("cmd_muxAfterDone"); }
|
public static string cmd_muxAfterDone => GetText("cmd_muxAfterDone");
|
||||||
public static string cmd_muxAfterDone_more { get => GetText("cmd_muxAfterDone_more"); }
|
public static string cmd_muxAfterDone_more => GetText("cmd_muxAfterDone_more");
|
||||||
public static string cmd_writeMetaJson { get => GetText("cmd_writeMetaJson"); }
|
public static string cmd_writeMetaJson => GetText("cmd_writeMetaJson");
|
||||||
public static string liveLimit { get => GetText("liveLimit"); }
|
public static string liveLimit => GetText("liveLimit");
|
||||||
public static string realTimeDecMessage { get => GetText("realTimeDecMessage"); }
|
public static string realTimeDecMessage => GetText("realTimeDecMessage");
|
||||||
public static string liveLimitReached { get => GetText("liveLimitReached"); }
|
public static string liveLimitReached => GetText("liveLimitReached");
|
||||||
public static string saveName { get => GetText("saveName"); }
|
public static string saveName => GetText("saveName");
|
||||||
public static string taskStartAt { get => GetText("taskStartAt"); }
|
public static string taskStartAt => GetText("taskStartAt");
|
||||||
public static string namedPipeCreated { get => GetText("namedPipeCreated"); }
|
public static string namedPipeCreated => GetText("namedPipeCreated");
|
||||||
public static string namedPipeMux { get => GetText("namedPipeMux"); }
|
public static string namedPipeMux => GetText("namedPipeMux");
|
||||||
public static string partMerge { get => GetText("partMerge"); }
|
public static string partMerge => GetText("partMerge");
|
||||||
public static string fetch { get => GetText("fetch"); }
|
public static string fetch => GetText("fetch");
|
||||||
public static string ffmpegMerge { get => GetText("ffmpegMerge"); }
|
public static string ffmpegMerge => GetText("ffmpegMerge");
|
||||||
public static string ffmpegNotFound { get => GetText("ffmpegNotFound"); }
|
public static string ffmpegNotFound => GetText("ffmpegNotFound");
|
||||||
public static string fixingTTML { get => GetText("fixingTTML"); }
|
public static string fixingTTML => GetText("fixingTTML");
|
||||||
public static string fixingTTMLmp4 { get => GetText("fixingTTMLmp4"); }
|
public static string fixingTTMLmp4 => GetText("fixingTTMLmp4");
|
||||||
public static string fixingVTT { get => GetText("fixingVTT"); }
|
public static string fixingVTT => GetText("fixingVTT");
|
||||||
public static string fixingVTTmp4 { get => GetText("fixingVTTmp4"); }
|
public static string fixingVTTmp4 => GetText("fixingVTTmp4");
|
||||||
public static string keyProcessorNotFound { get => GetText("keyProcessorNotFound"); }
|
public static string keyProcessorNotFound => GetText("keyProcessorNotFound");
|
||||||
public static string liveFound { get => GetText("liveFound"); }
|
public static string liveFound => GetText("liveFound");
|
||||||
public static string loadingUrl { get => GetText("loadingUrl"); }
|
public static string loadingUrl => GetText("loadingUrl");
|
||||||
public static string masterM3u8Found { get => GetText("masterM3u8Found"); }
|
public static string masterM3u8Found => GetText("masterM3u8Found");
|
||||||
public static string matchDASH { get => GetText("matchDASH"); }
|
public static string matchDASH => GetText("matchDASH");
|
||||||
public static string matchMSS { get => GetText("matchMSS"); }
|
public static string matchMSS => GetText("matchMSS");
|
||||||
public static string matchTS { get => GetText("matchTS"); }
|
public static string matchTS => GetText("matchTS");
|
||||||
public static string matchHLS { get => GetText("matchHLS"); }
|
public static string matchHLS => GetText("matchHLS");
|
||||||
public static string notSupported { get => GetText("notSupported"); }
|
public static string notSupported => GetText("notSupported");
|
||||||
public static string parsingStream { get => GetText("parsingStream"); }
|
public static string parsingStream => GetText("parsingStream");
|
||||||
public static string promptChoiceText { get => GetText("promptChoiceText"); }
|
public static string promptChoiceText => GetText("promptChoiceText");
|
||||||
public static string promptInfo { get => GetText("promptInfo"); }
|
public static string promptInfo => GetText("promptInfo");
|
||||||
public static string promptTitle { get => GetText("promptTitle"); }
|
public static string promptTitle => GetText("promptTitle");
|
||||||
public static string readingInfo { get => GetText("readingInfo"); }
|
public static string readingInfo => GetText("readingInfo");
|
||||||
public static string searchKey { get => GetText("searchKey"); }
|
public static string searchKey => GetText("searchKey");
|
||||||
public static string segmentCountCheckNotPass { get => GetText("segmentCountCheckNotPass"); }
|
public static string segmentCountCheckNotPass => GetText("segmentCountCheckNotPass");
|
||||||
public static string selectedStream { get => GetText("selectedStream"); }
|
public static string selectedStream => GetText("selectedStream");
|
||||||
public static string startDownloading { get => GetText("startDownloading"); }
|
public static string startDownloading => GetText("startDownloading");
|
||||||
public static string streamsInfo { get => GetText("streamsInfo"); }
|
public static string streamsInfo => GetText("streamsInfo");
|
||||||
public static string writeJson { get => GetText("writeJson"); }
|
public static string writeJson => GetText("writeJson");
|
||||||
public static string noStreamsToDownload { get => GetText("noStreamsToDownload"); }
|
public static string noStreamsToDownload => GetText("noStreamsToDownload");
|
||||||
public static string newVersionFound { get => GetText("newVersionFound"); }
|
public static string newVersionFound => GetText("newVersionFound");
|
||||||
public static string processImageSub { get => GetText("processImageSub"); }
|
public static string processImageSub => GetText("processImageSub");
|
||||||
|
|
||||||
private static string GetText(string key)
|
private static string GetText(string key)
|
||||||
{
|
{
|
||||||
|
@ -142,10 +135,8 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
var current = Thread.CurrentThread.CurrentUICulture.Name;
|
var current = Thread.CurrentThread.CurrentUICulture.Name;
|
||||||
if (current == "zh-CN" || current == "zh-SG" || current == "zh-Hans")
|
if (current == "zh-CN" || current == "zh-SG" || current == "zh-Hans")
|
||||||
return StaticText.LANG_DIC[key].ZH_CN;
|
return StaticText.LANG_DIC[key].ZH_CN;
|
||||||
else if (current.StartsWith("zh-"))
|
if (current.StartsWith("zh-"))
|
||||||
return StaticText.LANG_DIC[key].ZH_TW;
|
return StaticText.LANG_DIC[key].ZH_TW;
|
||||||
else
|
|
||||||
return StaticText.LANG_DIC[key].EN_US;
|
return StaticText.LANG_DIC[key].EN_US;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Resource
|
namespace N_m3u8DL_RE.Common.Resource;
|
||||||
{
|
|
||||||
internal class StaticText
|
internal class StaticText
|
||||||
{
|
{
|
||||||
public static Dictionary<string, TextContainer> LANG_DIC = new()
|
public static Dictionary<string, TextContainer> LANG_DIC = new()
|
||||||
|
@ -919,4 +919,3 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
using System;
|
namespace N_m3u8DL_RE.Common.Resource;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Resource
|
|
||||||
{
|
|
||||||
internal class TextContainer
|
internal class TextContainer
|
||||||
{
|
{
|
||||||
public string ZH_CN { get; set; }
|
public string ZH_CN { get; }
|
||||||
public string ZH_TW { get; set; }
|
public string ZH_TW { get; }
|
||||||
public string EN_US { get; set; }
|
public string EN_US { get; }
|
||||||
|
|
||||||
public TextContainer(string zhCN, string zhTW, string enUS)
|
public TextContainer(string zhCN, string zhTW, string enUS)
|
||||||
{
|
{
|
||||||
|
@ -19,4 +13,3 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
EN_US = enUS;
|
EN_US = enUS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
using N_m3u8DL_RE.Common.Entity;
|
using N_m3u8DL_RE.Common.Entity;
|
||||||
using N_m3u8DL_RE.Common.JsonConverter;
|
using N_m3u8DL_RE.Common.JsonConverter;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Common.Util;
|
namespace N_m3u8DL_RE.Common.Util;
|
||||||
|
|
||||||
public static class GlobalUtil
|
public static class GlobalUtil
|
||||||
{
|
{
|
||||||
private static readonly JsonSerializerOptions Options = new JsonSerializerOptions
|
private static readonly JsonSerializerOptions Options = new()
|
||||||
{
|
{
|
||||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||||
WriteIndented = true,
|
WriteIndented = true,
|
||||||
|
@ -27,15 +22,15 @@ public static class GlobalUtil
|
||||||
{
|
{
|
||||||
return JsonSerializer.Serialize(s, Context.StreamSpec);
|
return JsonSerializer.Serialize(s, Context.StreamSpec);
|
||||||
}
|
}
|
||||||
else if (o is IOrderedEnumerable<StreamSpec> ss)
|
if (o is IOrderedEnumerable<StreamSpec> ss)
|
||||||
{
|
{
|
||||||
return JsonSerializer.Serialize(ss, Context.IOrderedEnumerableStreamSpec);
|
return JsonSerializer.Serialize(ss, Context.IOrderedEnumerableStreamSpec);
|
||||||
}
|
}
|
||||||
else if (o is List<StreamSpec> sList)
|
if (o is List<StreamSpec> sList)
|
||||||
{
|
{
|
||||||
return JsonSerializer.Serialize(sList, Context.ListStreamSpec);
|
return JsonSerializer.Serialize(sList, Context.ListStreamSpec);
|
||||||
}
|
}
|
||||||
else if (o is IEnumerable<MediaSegment> mList)
|
if (o is IEnumerable<MediaSegment> mList)
|
||||||
{
|
{
|
||||||
return JsonSerializer.Serialize(mList, Context.IEnumerableMediaSegment);
|
return JsonSerializer.Serialize(mList, Context.IEnumerableMediaSegment);
|
||||||
}
|
}
|
||||||
|
@ -47,10 +42,10 @@ public static class GlobalUtil
|
||||||
return fileSize switch
|
return fileSize switch
|
||||||
{
|
{
|
||||||
< 0 => throw new ArgumentOutOfRangeException(nameof(fileSize)),
|
< 0 => throw new ArgumentOutOfRangeException(nameof(fileSize)),
|
||||||
>= 1024 * 1024 * 1024 => string.Format("{0:########0.00}GB", (double)fileSize / (1024 * 1024 * 1024)),
|
>= 1024 * 1024 * 1024 => $"{fileSize / (1024 * 1024 * 1024):########0.00}GB",
|
||||||
>= 1024 * 1024 => string.Format("{0:####0.00}MB", (double)fileSize / (1024 * 1024)),
|
>= 1024 * 1024 => $"{fileSize / (1024 * 1024):####0.00}MB",
|
||||||
>= 1024 => string.Format("{0:####0.00}KB", (double)fileSize / 1024),
|
>= 1024 => $"{fileSize / 1024:####0.00}KB",
|
||||||
_ => string.Format("{0:####0.00}B", fileSize)
|
_ => $"{fileSize:####0.00}B"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +69,6 @@ public static class GlobalUtil
|
||||||
var searchPath = new[] { Environment.CurrentDirectory, Path.GetDirectoryName(Environment.ProcessPath) };
|
var searchPath = new[] { Environment.CurrentDirectory, Path.GetDirectoryName(Environment.ProcessPath) };
|
||||||
var envPath = Environment.GetEnvironmentVariable("PATH")?.Split(Path.PathSeparator) ??
|
var envPath = Environment.GetEnvironmentVariable("PATH")?.Split(Path.PathSeparator) ??
|
||||||
Array.Empty<string>();
|
Array.Empty<string>();
|
||||||
return searchPath.Concat(envPath).Select(p => Path.Combine(p, name + fileExt)).FirstOrDefault(File.Exists);
|
return searchPath.Concat(envPath).Select(p => Path.Combine(p!, name + fileExt)).FirstOrDefault(File.Exists);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -43,7 +43,7 @@ public static class HTTPUtil
|
||||||
{
|
{
|
||||||
HttpResponseHeaders respHeaders = webResponse.Headers;
|
HttpResponseHeaders respHeaders = webResponse.Headers;
|
||||||
Logger.Debug(respHeaders.ToString());
|
Logger.Debug(respHeaders.ToString());
|
||||||
if (respHeaders != null && respHeaders.Location != null)
|
if (respHeaders.Location != null)
|
||||||
{
|
{
|
||||||
var redirectedUrl = "";
|
var redirectedUrl = "";
|
||||||
if (!respHeaders.Location.IsAbsoluteUri)
|
if (!respHeaders.Location.IsAbsoluteUri)
|
||||||
|
@ -76,9 +76,8 @@ public static class HTTPUtil
|
||||||
{
|
{
|
||||||
return await File.ReadAllBytesAsync(new Uri(url).LocalPath);
|
return await File.ReadAllBytesAsync(new Uri(url).LocalPath);
|
||||||
}
|
}
|
||||||
byte[] bytes = new byte[0];
|
|
||||||
var webResponse = await DoGetAsync(url, headers);
|
var webResponse = await DoGetAsync(url, headers);
|
||||||
bytes = await webResponse.Content.ReadAsByteArrayAsync();
|
var bytes = await webResponse.Content.ReadAsByteArrayAsync();
|
||||||
Logger.Debug(HexUtil.BytesToHex(bytes, " "));
|
Logger.Debug(HexUtil.BytesToHex(bytes, " "));
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
@ -91,9 +90,8 @@ public static class HTTPUtil
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<string> GetWebSourceAsync(string url, Dictionary<string, string>? headers = null)
|
public static async Task<string> GetWebSourceAsync(string url, Dictionary<string, string>? headers = null)
|
||||||
{
|
{
|
||||||
string htmlCode = string.Empty;
|
|
||||||
var webResponse = await DoGetAsync(url, headers);
|
var webResponse = await DoGetAsync(url, headers);
|
||||||
htmlCode = await webResponse.Content.ReadAsStringAsync();
|
string htmlCode = await webResponse.Content.ReadAsStringAsync();
|
||||||
Logger.Debug(htmlCode);
|
Logger.Debug(htmlCode);
|
||||||
return htmlCode;
|
return htmlCode;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +110,7 @@ public static class HTTPUtil
|
||||||
/// <returns>(Source Code, RedirectedUrl)</returns>
|
/// <returns>(Source Code, RedirectedUrl)</returns>
|
||||||
public static async Task<(string, string)> GetWebSourceAndNewUrlAsync(string url, Dictionary<string, string>? headers = null)
|
public static async Task<(string, string)> GetWebSourceAndNewUrlAsync(string url, Dictionary<string, string>? headers = null)
|
||||||
{
|
{
|
||||||
string htmlCode = string.Empty;
|
string htmlCode;
|
||||||
var webResponse = await DoGetAsync(url, headers);
|
var webResponse = await DoGetAsync(url, headers);
|
||||||
if (CheckMPEG2TS(webResponse))
|
if (CheckMPEG2TS(webResponse))
|
||||||
{
|
{
|
||||||
|
@ -128,7 +126,7 @@ public static class HTTPUtil
|
||||||
|
|
||||||
public static async Task<string> GetPostResponseAsync(string Url, byte[] postData)
|
public static async Task<string> GetPostResponseAsync(string Url, byte[] postData)
|
||||||
{
|
{
|
||||||
string htmlCode = string.Empty;
|
string htmlCode;
|
||||||
using HttpRequestMessage request = new(HttpMethod.Post, Url);
|
using HttpRequestMessage request = new(HttpMethod.Post, Url);
|
||||||
request.Headers.TryAddWithoutValidation("Content-Type", "application/json");
|
request.Headers.TryAddWithoutValidation("Content-Type", "application/json");
|
||||||
request.Headers.TryAddWithoutValidation("Content-Length", postData.Length.ToString());
|
request.Headers.TryAddWithoutValidation("Content-Length", postData.Length.ToString());
|
||||||
|
|
|
@ -31,7 +31,7 @@ public static class HexUtil
|
||||||
var hexSpan = hex.AsSpan().Trim();
|
var hexSpan = hex.AsSpan().Trim();
|
||||||
if (hexSpan.StartsWith("0x") || hexSpan.StartsWith("0X"))
|
if (hexSpan.StartsWith("0x") || hexSpan.StartsWith("0X"))
|
||||||
{
|
{
|
||||||
hexSpan = hexSpan.Slice(2);
|
hexSpan = hexSpan[2..];
|
||||||
}
|
}
|
||||||
|
|
||||||
return Convert.FromHexString(hexSpan);
|
return Convert.FromHexString(hexSpan);
|
||||||
|
|
|
@ -3,8 +3,8 @@ using N_m3u8DL_RE.Parser.Processor;
|
||||||
using N_m3u8DL_RE.Parser.Processor.DASH;
|
using N_m3u8DL_RE.Parser.Processor.DASH;
|
||||||
using N_m3u8DL_RE.Parser.Processor.HLS;
|
using N_m3u8DL_RE.Parser.Processor.HLS;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Config
|
namespace N_m3u8DL_RE.Parser.Config;
|
||||||
{
|
|
||||||
public class ParserConfig
|
public class ParserConfig
|
||||||
{
|
{
|
||||||
public string Url { get; set; }
|
public string Url { get; set; }
|
||||||
|
@ -65,4 +65,3 @@ namespace N_m3u8DL_RE.Parser.Config
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int KeyRetryCount { get; set; } = 3;
|
public int KeyRetryCount { get; set; } = 3;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Constants
|
namespace N_m3u8DL_RE.Parser.Constants;
|
||||||
{
|
|
||||||
internal class DASHTags
|
internal class DASHTags
|
||||||
{
|
{
|
||||||
public static string TemplateRepresentationID = "$RepresentationID$";
|
public static string TemplateRepresentationID = "$RepresentationID$";
|
||||||
|
@ -13,4 +13,3 @@ namespace N_m3u8DL_RE.Parser.Constants
|
||||||
public static string TemplateNumber = "$Number$";
|
public static string TemplateNumber = "$Number$";
|
||||||
public static string TemplateTime = "$Time$";
|
public static string TemplateTime = "$Time$";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Constants
|
namespace N_m3u8DL_RE.Parser.Constants;
|
||||||
{
|
|
||||||
internal class HLSTags
|
internal class HLSTags
|
||||||
{
|
{
|
||||||
public static string ext_m3u = "#EXTM3U";
|
public static string ext_m3u = "#EXTM3U";
|
||||||
|
@ -35,4 +35,3 @@ namespace N_m3u8DL_RE.Parser.Constants
|
||||||
public static string ext_x_map = "#EXT-X-MAP";
|
public static string ext_x_map = "#EXT-X-MAP";
|
||||||
public static string ext_x_start = "#EXT-X-START";
|
public static string ext_x_start = "#EXT-X-START";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Constants
|
namespace N_m3u8DL_RE.Parser.Constants;
|
||||||
{
|
|
||||||
internal class MSSTags
|
internal class MSSTags
|
||||||
{
|
{
|
||||||
public static string Bitrate = "{Bitrate}";
|
public static string Bitrate = "{Bitrate}";
|
||||||
|
@ -13,4 +13,3 @@ namespace N_m3u8DL_RE.Parser.Constants
|
||||||
public static string StartTime = "{start_time}";
|
public static string StartTime = "{start_time}";
|
||||||
public static string StartTime_BK = "{start time}";
|
public static string StartTime_BK = "{start time}";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Extractor
|
namespace N_m3u8DL_RE.Parser.Extractor;
|
||||||
{
|
|
||||||
// https://blog.csdn.net/leek5533/article/details/117750191
|
// https://blog.csdn.net/leek5533/article/details/117750191
|
||||||
internal class DASHExtractor2 : IExtractor
|
internal class DASHExtractor2 : IExtractor
|
||||||
{
|
{
|
||||||
|
@ -66,7 +66,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<StreamSpec>> ExtractStreamsAsync(string rawText)
|
public Task<List<StreamSpec>> ExtractStreamsAsync(string rawText)
|
||||||
{
|
{
|
||||||
var streamList = new List<StreamSpec>();
|
var streamList = new List<StreamSpec>();
|
||||||
|
|
||||||
|
@ -530,7 +530,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return streamList;
|
return Task.FromResult(streamList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -579,7 +579,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
await ProcessUrlAsync(streamSpecs);
|
await ProcessUrlAsync(streamSpecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessUrlAsync(List<StreamSpec> streamSpecs)
|
private Task ProcessUrlAsync(List<StreamSpec> streamSpecs)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < streamSpecs.Count; i++)
|
for (int i = 0; i < streamSpecs.Count; i++)
|
||||||
{
|
{
|
||||||
|
@ -600,6 +600,8 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task FetchPlayListAsync(List<StreamSpec> streamSpecs)
|
public async Task FetchPlayListAsync(List<StreamSpec> streamSpecs)
|
||||||
|
@ -632,4 +634,3 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using N_m3u8DL_RE.Common.Util;
|
using N_m3u8DL_RE.Common.Util;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Extractor
|
namespace N_m3u8DL_RE.Parser.Extractor;
|
||||||
{
|
|
||||||
internal class HLSExtractor : IExtractor
|
internal class HLSExtractor : IExtractor
|
||||||
{
|
{
|
||||||
public ExtractorType ExtractorType => ExtractorType.HLS;
|
public ExtractorType ExtractorType => ExtractorType.HLS;
|
||||||
|
@ -83,7 +83,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<StreamSpec>> ParseMasterListAsync()
|
private Task<List<StreamSpec>> ParseMasterListAsync()
|
||||||
{
|
{
|
||||||
MasterM3u8Flag = true;
|
MasterM3u8Flag = true;
|
||||||
|
|
||||||
|
@ -214,12 +214,12 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return streams;
|
return Task.FromResult(streams);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Playlist> ParseListAsync()
|
private Task<Playlist> ParseListAsync()
|
||||||
{
|
{
|
||||||
//标记是否已清除优酷广告分片
|
// 标记是否已清除广告分片
|
||||||
bool hasAd = false;
|
bool hasAd = false;
|
||||||
|
|
||||||
using StringReader sr = new StringReader(M3u8Content);
|
using StringReader sr = new StringReader(M3u8Content);
|
||||||
|
@ -295,7 +295,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
// 解析不连续标记,需要单独合并(timestamp不同)
|
// 解析不连续标记,需要单独合并(timestamp不同)
|
||||||
else if (line.StartsWith(HLSTags.ext_x_discontinuity))
|
else if (line.StartsWith(HLSTags.ext_x_discontinuity))
|
||||||
{
|
{
|
||||||
//修复优酷去除广告后的遗留问题
|
// 修复YK去除广告后的遗留问题
|
||||||
if (hasAd && mediaParts.Count > 0)
|
if (hasAd && mediaParts.Count > 0)
|
||||||
{
|
{
|
||||||
segments = mediaParts[mediaParts.Count - 1].MediaSegments;
|
segments = mediaParts[mediaParts.Count - 1].MediaSegments;
|
||||||
|
@ -410,7 +410,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
segment.Url = segUrl;
|
segment.Url = segUrl;
|
||||||
segments.Add(segment);
|
segments.Add(segment);
|
||||||
segment = new();
|
segment = new();
|
||||||
//优酷的广告分段则清除此分片
|
// YK的广告分段则清除此分片
|
||||||
// 需要注意,遇到广告说明程序对上文的#EXT-X-DISCONTINUITY做出的动作是不必要的,
|
// 需要注意,遇到广告说明程序对上文的#EXT-X-DISCONTINUITY做出的动作是不必要的,
|
||||||
// 其实上下文是同一种编码,需要恢复到原先的part上
|
// 其实上下文是同一种编码,需要恢复到原先的part上
|
||||||
if (segUrl.Contains("ccode=") && segUrl.Contains("/ad/") && segUrl.Contains("duration="))
|
if (segUrl.Contains("ccode=") && segUrl.Contains("/ad/") && segUrl.Contains("duration="))
|
||||||
|
@ -419,7 +419,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
segIndex--;
|
segIndex--;
|
||||||
hasAd = true;
|
hasAd = true;
|
||||||
}
|
}
|
||||||
//优酷广告(4K分辨率测试)
|
// YK广告(4K分辨率测试)
|
||||||
if (segUrl.Contains("ccode=0902") && segUrl.Contains("duration="))
|
if (segUrl.Contains("ccode=0902") && segUrl.Contains("duration="))
|
||||||
{
|
{
|
||||||
segments.RemoveAt(segments.Count - 1);
|
segments.RemoveAt(segments.Count - 1);
|
||||||
|
@ -449,7 +449,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
playlist.RefreshIntervalMs = (int)((playlist.TargetDuration ?? 5) * 2 * 1000);
|
playlist.RefreshIntervalMs = (int)((playlist.TargetDuration ?? 5) * 2 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return playlist;
|
return Task.FromResult(playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
private EncryptInfo ParseKey(string keyLine)
|
private EncryptInfo ParseKey(string keyLine)
|
||||||
|
@ -477,12 +477,11 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
lists = lists.DistinctBy(p => p.Url).ToList();
|
lists = lists.DistinctBy(p => p.Url).ToList();
|
||||||
return lists;
|
return lists;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
var playlist = await ParseListAsync();
|
var playlist = await ParseListAsync();
|
||||||
return new List<StreamSpec>()
|
return new List<StreamSpec>
|
||||||
{
|
{
|
||||||
new StreamSpec()
|
new()
|
||||||
{
|
{
|
||||||
Url = ParserConfig.Url,
|
Url = ParserConfig.Url,
|
||||||
Playlist = playlist,
|
Playlist = playlist,
|
||||||
|
@ -490,7 +489,6 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LoadM3u8FromUrlAsync(string url)
|
private async Task LoadM3u8FromUrlAsync(string url)
|
||||||
{
|
{
|
||||||
|
@ -531,7 +529,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
newStreams = newStreams.DistinctBy(p => p.Url).ToList();
|
newStreams = newStreams.DistinctBy(p => p.Url).ToList();
|
||||||
foreach (var l in lists)
|
foreach (var l in lists)
|
||||||
{
|
{
|
||||||
var match = newStreams.Where(n => n.ToShortString() == l.ToShortString());
|
var match = newStreams.Where(n => n.ToShortString() == l.ToShortString()).ToList();
|
||||||
if (match.Any())
|
if (match.Any())
|
||||||
{
|
{
|
||||||
Logger.DebugMarkUp($"{l.Url} => {match.First().Url}");
|
Logger.DebugMarkUp($"{l.Url} => {match.First().Url}");
|
||||||
|
@ -582,4 +580,3 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
await FetchPlayListAsync(streamSpecs);
|
await FetchPlayListAsync(streamSpecs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using N_m3u8DL_RE.Common.Enum;
|
using N_m3u8DL_RE.Common.Enum;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Extractor
|
namespace N_m3u8DL_RE.Parser.Extractor;
|
||||||
{
|
|
||||||
public interface IExtractor
|
public interface IExtractor
|
||||||
{
|
{
|
||||||
ExtractorType ExtractorType { get; }
|
ExtractorType ExtractorType { get; }
|
||||||
|
@ -24,4 +24,3 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
|
|
||||||
void PreProcessContent();
|
void PreProcessContent();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ using N_m3u8DL_RE.Common.Enum;
|
||||||
using N_m3u8DL_RE.Common.Resource;
|
using N_m3u8DL_RE.Common.Resource;
|
||||||
using N_m3u8DL_RE.Parser.Config;
|
using N_m3u8DL_RE.Parser.Config;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Extractor
|
namespace N_m3u8DL_RE.Parser.Extractor;
|
||||||
{
|
|
||||||
internal class LiveTSExtractor : IExtractor
|
internal class LiveTSExtractor : IExtractor
|
||||||
{
|
{
|
||||||
public ExtractorType ExtractorType => ExtractorType.HTTP_LIVE;
|
public ExtractorType ExtractorType => ExtractorType.HTTP_LIVE;
|
||||||
|
@ -16,26 +16,26 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
this.ParserConfig = parserConfig;
|
this.ParserConfig = parserConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<StreamSpec>> ExtractStreamsAsync(string rawText)
|
public Task<List<StreamSpec>> ExtractStreamsAsync(string rawText)
|
||||||
{
|
{
|
||||||
return new List<StreamSpec>()
|
return Task.FromResult(new List<StreamSpec>
|
||||||
{
|
{
|
||||||
new StreamSpec()
|
new()
|
||||||
{
|
{
|
||||||
OriginalUrl = ParserConfig.OriginalUrl,
|
OriginalUrl = ParserConfig.OriginalUrl,
|
||||||
Url = ParserConfig.Url,
|
Url = ParserConfig.Url,
|
||||||
Playlist = new Playlist(),
|
Playlist = new Playlist(),
|
||||||
GroupId = ResString.ReLiveTs
|
GroupId = ResString.ReLiveTs
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task FetchPlayListAsync(List<StreamSpec> streamSpecs)
|
public Task FetchPlayListAsync(List<StreamSpec> streamSpecs)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void PreProcessContent()
|
public void PreProcessContent()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -50,4 +50,3 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Extractor
|
namespace N_m3u8DL_RE.Parser.Extractor;
|
||||||
{
|
|
||||||
// Microsoft Smooth Streaming
|
// Microsoft Smooth Streaming
|
||||||
// https://test.playready.microsoft.com/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/manifest
|
// https://test.playready.microsoft.com/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/manifest
|
||||||
// file:///C:/Users/nilaoda/Downloads/[MS-SSTR]-180316.pdf
|
// file:///C:/Users/nilaoda/Downloads/[MS-SSTR]-180316.pdf
|
||||||
|
@ -52,7 +52,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
this.BaseUrl = this.IsmUrl;
|
this.BaseUrl = this.IsmUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<StreamSpec>> ExtractStreamsAsync(string rawText)
|
public Task<List<StreamSpec>> ExtractStreamsAsync(string rawText)
|
||||||
{
|
{
|
||||||
var streamList = new List<StreamSpec>();
|
var streamList = new List<StreamSpec>();
|
||||||
this.IsmContent = rawText;
|
this.IsmContent = rawText;
|
||||||
|
@ -243,7 +243,6 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.WarnMarkUp($"[green]{fourCC}[/] not supported! Skiped.");
|
Logger.WarnMarkUp($"[green]{fourCC}[/] not supported! Skiped.");
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,7 +265,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return streamList;
|
return Task.FromResult(streamList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -317,7 +316,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
await ProcessUrlAsync(streamSpecs);
|
await ProcessUrlAsync(streamSpecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessUrlAsync(List<StreamSpec> streamSpecs)
|
private Task ProcessUrlAsync(List<StreamSpec> streamSpecs)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < streamSpecs.Count; i++)
|
for (int i = 0; i < streamSpecs.Count; i++)
|
||||||
{
|
{
|
||||||
|
@ -338,6 +337,8 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string PreProcessUrl(string url)
|
public string PreProcessUrl(string url)
|
||||||
|
@ -398,4 +399,3 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
await ProcessUrlAsync(streamSpecs);
|
await ProcessUrlAsync(streamSpecs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -129,8 +129,7 @@ namespace Mp4SubtitleParser
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoxHandler boxDefinition = null;
|
this.BoxDefinitions.TryGetValue(type, out BoxHandler? boxDefinition);
|
||||||
this.BoxDefinitions.TryGetValue(type, out boxDefinition);
|
|
||||||
|
|
||||||
if (boxDefinition != null)
|
if (boxDefinition != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,8 +10,8 @@ namespace Mp4SubtitleParser
|
||||||
public string Begin { get; set; }
|
public string Begin { get; set; }
|
||||||
public string End { get; set; }
|
public string End { get; set; }
|
||||||
public string Region { get; set; }
|
public string Region { get; set; }
|
||||||
public List<XmlElement> Contents { get; set; } = new List<XmlElement>();
|
public List<XmlElement> Contents { get; set; } = new();
|
||||||
public List<string> ContentStrings { get; set; } = new List<string>();
|
public List<string> ContentStrings { get; set; } = new();
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
{
|
{
|
||||||
|
@ -161,10 +161,7 @@ namespace Mp4SubtitleParser
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var datas = SplitMultipleRootElements(Encoding.UTF8.GetString(data));
|
var datas = SplitMultipleRootElements(Encoding.UTF8.GetString(data));
|
||||||
foreach (var item in datas)
|
xmls.AddRange(datas);
|
||||||
{
|
|
||||||
xmls.Add(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
.Parse(dataSeg,/* partialOkay= */ false);
|
.Parse(dataSeg,/* partialOkay= */ false);
|
||||||
|
@ -372,7 +369,7 @@ namespace Mp4SubtitleParser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StringBuilder vtt = new StringBuilder();
|
var vtt = new StringBuilder();
|
||||||
vtt.AppendLine("WEBVTT");
|
vtt.AppendLine("WEBVTT");
|
||||||
foreach (var item in dic)
|
foreach (var item in dic)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
using N_m3u8DL_RE.Common.Entity;
|
using N_m3u8DL_RE.Common.Entity;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Mp4SubtitleParser
|
namespace Mp4SubtitleParser;
|
||||||
{
|
|
||||||
public class MP4VttUtil
|
public class MP4VttUtil
|
||||||
{
|
{
|
||||||
public static (bool, uint) CheckInit(byte[] data)
|
public static (bool, uint) CheckInit(byte[] data)
|
||||||
|
@ -213,4 +213,3 @@ namespace Mp4SubtitleParser
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ using System.Text.RegularExpressions;
|
||||||
// https://github.com/yt-dlp/yt-dlp/blob/3639df54c3298e35b5ae2a96a25bc4d3c38950d0/yt_dlp/downloader/ism.py
|
// https://github.com/yt-dlp/yt-dlp/blob/3639df54c3298e35b5ae2a96a25bc4d3c38950d0/yt_dlp/downloader/ism.py
|
||||||
// https://github.com/google/ExoPlayer/blob/a9444c880230d2c2c79097e89259ce0b9f80b87d/library/extractor/src/main/java/com/google/android/exoplayer2/video/HevcConfig.java#L38
|
// https://github.com/google/ExoPlayer/blob/a9444c880230d2c2c79097e89259ce0b9f80b87d/library/extractor/src/main/java/com/google/android/exoplayer2/video/HevcConfig.java#L38
|
||||||
// https://github.com/sannies/mp4parser/blob/master/isoparser/src/main/java/org/mp4parser/boxes/iso14496/part15/HevcDecoderConfigurationRecord.java
|
// https://github.com/sannies/mp4parser/blob/master/isoparser/src/main/java/org/mp4parser/boxes/iso14496/part15/HevcDecoderConfigurationRecord.java
|
||||||
namespace N_m3u8DL_RE.Parser.Mp4
|
namespace N_m3u8DL_RE.Parser.Mp4;
|
||||||
{
|
|
||||||
public partial class MSSMoovProcessor
|
public partial class MSSMoovProcessor
|
||||||
{
|
{
|
||||||
[GeneratedRegex("\\<KID\\>(.*?)\\<")]
|
[GeneratedRegex("\\<KID\\>(.*?)\\<")]
|
||||||
|
@ -24,8 +24,8 @@ namespace N_m3u8DL_RE.Parser.Mp4
|
||||||
private int Timesacle;
|
private int Timesacle;
|
||||||
private long Duration;
|
private long Duration;
|
||||||
private string Language { get => StreamSpec.Language ?? "und"; }
|
private string Language { get => StreamSpec.Language ?? "und"; }
|
||||||
private int Width { get => int.Parse((StreamSpec.Resolution ?? "0x0").Split('x').First()); }
|
private int Width => int.Parse((StreamSpec.Resolution ?? "0x0").Split('x').First());
|
||||||
private int Height { get => int.Parse((StreamSpec.Resolution ?? "0x0").Split('x').Last()); }
|
private int Height => int.Parse((StreamSpec.Resolution ?? "0x0").Split('x').Last());
|
||||||
private string StreamType;
|
private string StreamType;
|
||||||
private int Channels;
|
private int Channels;
|
||||||
private int BitsPerSample;
|
private int BitsPerSample;
|
||||||
|
@ -60,7 +60,7 @@ namespace N_m3u8DL_RE.Parser.Mp4
|
||||||
private static byte TRACK_IN_MOVIE = 0x2;
|
private static byte TRACK_IN_MOVIE = 0x2;
|
||||||
private static byte TRACK_IN_PREVIEW = 0x4;
|
private static byte TRACK_IN_PREVIEW = 0x4;
|
||||||
private static byte SELF_CONTAINED = 0x1;
|
private static byte SELF_CONTAINED = 0x1;
|
||||||
private static List<string> SupportedFourCC = new List<string>()
|
private static List<string> SupportedFourCC = new()
|
||||||
{
|
{
|
||||||
"HVC1","HEV1","AACL","AACH","EC-3","H264","AVC1","DAVC","AVC1","TTML","DVHE","DVH1"
|
"HVC1","HEV1","AACL","AACH","EC-3","H264","AVC1","DAVC","AVC1","TTML","DVHE","DVH1"
|
||||||
};
|
};
|
||||||
|
@ -888,4 +888,3 @@ namespace N_m3u8DL_RE.Parser.Mp4
|
||||||
return stream.ToArray();
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -6,11 +6,10 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Processor
|
namespace N_m3u8DL_RE.Parser.Processor;
|
||||||
{
|
|
||||||
public abstract class ContentProcessor
|
public abstract class ContentProcessor
|
||||||
{
|
{
|
||||||
public abstract bool CanProcess(ExtractorType extractorType, string rawText, ParserConfig parserConfig);
|
public abstract bool CanProcess(ExtractorType extractorType, string rawText, ParserConfig parserConfig);
|
||||||
public abstract string Process(string rawText, ParserConfig parserConfig);
|
public abstract string Process(string rawText, ParserConfig parserConfig);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -7,10 +7,10 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Processor.DASH
|
namespace N_m3u8DL_RE.Parser.Processor.DASH;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 西瓜视频处理
|
/// XG视频处理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DefaultDASHContentProcessor : ContentProcessor
|
public class DefaultDASHContentProcessor : ContentProcessor
|
||||||
{
|
{
|
||||||
|
@ -33,4 +33,3 @@ namespace N_m3u8DL_RE.Parser.Processor.DASH
|
||||||
return mpdContent;
|
return mpdContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Processor
|
namespace N_m3u8DL_RE.Parser.Processor;
|
||||||
{
|
|
||||||
public class DefaultUrlProcessor : UrlProcessor
|
public class DefaultUrlProcessor : UrlProcessor
|
||||||
{
|
{
|
||||||
public override bool CanProcess(ExtractorType extractorType, string oriUrl, ParserConfig paserConfig) => paserConfig.AppendUrlParams;
|
public override bool CanProcess(ExtractorType extractorType, string oriUrl, ParserConfig paserConfig) => paserConfig.AppendUrlParams;
|
||||||
|
@ -43,4 +43,3 @@ namespace N_m3u8DL_RE.Parser.Processor
|
||||||
return oriUrl;
|
return oriUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Processor.HLS
|
namespace N_m3u8DL_RE.Parser.Processor.HLS;
|
||||||
{
|
|
||||||
public partial class DefaultHLSContentProcessor : ContentProcessor
|
public partial class DefaultHLSContentProcessor : ContentProcessor
|
||||||
{
|
{
|
||||||
[GeneratedRegex("#EXT-X-DISCONTINUITY\\s+#EXT-X-MAP:URI=\\\"(.*?)\\\",BYTERANGE=\\\"(.*?)\\\"")]
|
[GeneratedRegex("#EXT-X-DISCONTINUITY\\s+#EXT-X-MAP:URI=\\\"(.*?)\\\",BYTERANGE=\\\"(.*?)\\\"")]
|
||||||
|
@ -36,7 +36,7 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
|
||||||
}
|
}
|
||||||
|
|
||||||
var m3u8Url = parserConfig.Url;
|
var m3u8Url = parserConfig.Url;
|
||||||
//央视频回放
|
// YSP回放
|
||||||
if (m3u8Url.Contains("tlivecloud-playback-cdn.ysp.cctv.cn") && m3u8Url.Contains("endtime="))
|
if (m3u8Url.Contains("tlivecloud-playback-cdn.ysp.cctv.cn") && m3u8Url.Contains("endtime="))
|
||||||
{
|
{
|
||||||
m3u8Content += Environment.NewLine + HLSTags.ext_x_endlist;
|
m3u8Content += Environment.NewLine + HLSTags.ext_x_endlist;
|
||||||
|
@ -48,13 +48,7 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
|
||||||
// M3u8Content = DecodeImooc.DecodeM3u8(M3u8Content);
|
// M3u8Content = DecodeImooc.DecodeM3u8(M3u8Content);
|
||||||
}
|
}
|
||||||
|
|
||||||
//iqy
|
// 针对YK #EXT-X-VERSION:7杜比视界片源修正
|
||||||
if (m3u8Content.StartsWith("{\"payload\""))
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
//针对优酷#EXT-X-VERSION:7杜比视界片源修正
|
|
||||||
if (m3u8Content.Contains("#EXT-X-DISCONTINUITY") && m3u8Content.Contains("#EXT-X-MAP") && m3u8Content.Contains("ott.cibntv.net") && m3u8Content.Contains("ccode="))
|
if (m3u8Content.Contains("#EXT-X-DISCONTINUITY") && m3u8Content.Contains("#EXT-X-MAP") && m3u8Content.Contains("ott.cibntv.net") && m3u8Content.Contains("ccode="))
|
||||||
{
|
{
|
||||||
Regex ykmap = YkDVRegex();
|
Regex ykmap = YkDVRegex();
|
||||||
|
@ -105,4 +99,3 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
|
||||||
return m3u8Content;
|
return m3u8Content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -6,14 +6,9 @@ using N_m3u8DL_RE.Common.Util;
|
||||||
using N_m3u8DL_RE.Parser.Config;
|
using N_m3u8DL_RE.Parser.Config;
|
||||||
using N_m3u8DL_RE.Parser.Util;
|
using N_m3u8DL_RE.Parser.Util;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Processor.HLS
|
namespace N_m3u8DL_RE.Parser.Processor.HLS;
|
||||||
{
|
|
||||||
public class DefaultHLSKeyProcessor : KeyProcessor
|
public class DefaultHLSKeyProcessor : KeyProcessor
|
||||||
{
|
{
|
||||||
public override bool CanProcess(ExtractorType extractorType, string m3u8Url, string keyLine, string m3u8Content, ParserConfig paserConfig) => extractorType == ExtractorType.HLS;
|
public override bool CanProcess(ExtractorType extractorType, string m3u8Url, string keyLine, string m3u8Content, ParserConfig paserConfig) => extractorType == ExtractorType.HLS;
|
||||||
|
@ -35,7 +30,7 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
|
||||||
encryptInfo.IV = HexUtil.HexToBytes(iv);
|
encryptInfo.IV = HexUtil.HexToBytes(iv);
|
||||||
}
|
}
|
||||||
// 自定义IV
|
// 自定义IV
|
||||||
if (parserConfig.CustomeIV != null && parserConfig.CustomeIV.Length > 0)
|
if (parserConfig.CustomeIV is { Length: > 0 })
|
||||||
{
|
{
|
||||||
encryptInfo.IV = parserConfig.CustomeIV;
|
encryptInfo.IV = parserConfig.CustomeIV;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +38,7 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
|
||||||
// KEY
|
// KEY
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (parserConfig.CustomeKey != null && parserConfig.CustomeKey.Length > 0)
|
if (parserConfig.CustomeKey is { Length: > 0 })
|
||||||
{
|
{
|
||||||
encryptInfo.Key = parserConfig.CustomeKey;
|
encryptInfo.Key = parserConfig.CustomeKey;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +73,7 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
|
||||||
Logger.WarnMarkUp($"[grey]{_ex.Message.EscapeMarkup()} retryCount: {retryCount}[/]");
|
Logger.WarnMarkUp($"[grey]{_ex.Message.EscapeMarkup()} retryCount: {retryCount}[/]");
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
if (retryCount-- > 0) goto getHttpKey;
|
if (retryCount-- > 0) goto getHttpKey;
|
||||||
else throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,4 +109,3 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -7,11 +7,10 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Processor
|
namespace N_m3u8DL_RE.Parser.Processor;
|
||||||
{
|
|
||||||
public abstract class KeyProcessor
|
public abstract class KeyProcessor
|
||||||
{
|
{
|
||||||
public abstract bool CanProcess(ExtractorType extractorType, string keyLine, string m3u8Url, string m3u8Content, ParserConfig parserConfig);
|
public abstract bool CanProcess(ExtractorType extractorType, string keyLine, string m3u8Url, string m3u8Content, ParserConfig parserConfig);
|
||||||
public abstract EncryptInfo Process(string keyLine, string m3u8Url, string m3u8Content, ParserConfig parserConfig);
|
public abstract EncryptInfo Process(string keyLine, string m3u8Url, string m3u8Content, ParserConfig parserConfig);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
using N_m3u8DL_RE.Common.Enum;
|
using N_m3u8DL_RE.Common.Enum;
|
||||||
using N_m3u8DL_RE.Parser.Config;
|
using N_m3u8DL_RE.Parser.Config;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Processor
|
namespace N_m3u8DL_RE.Parser.Processor;
|
||||||
{
|
|
||||||
public abstract class UrlProcessor
|
public abstract class UrlProcessor
|
||||||
{
|
{
|
||||||
public abstract bool CanProcess(ExtractorType extractorType, string oriUrl, ParserConfig parserConfig);
|
public abstract bool CanProcess(ExtractorType extractorType, string oriUrl, ParserConfig parserConfig);
|
||||||
public abstract string Process(string oriUrl, ParserConfig parserConfig);
|
public abstract string Process(string oriUrl, ParserConfig parserConfig);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -6,17 +6,16 @@ using N_m3u8DL_RE.Parser.Constants;
|
||||||
using N_m3u8DL_RE.Parser.Extractor;
|
using N_m3u8DL_RE.Parser.Extractor;
|
||||||
using N_m3u8DL_RE.Common.Util;
|
using N_m3u8DL_RE.Common.Util;
|
||||||
using N_m3u8DL_RE.Common.Enum;
|
using N_m3u8DL_RE.Common.Enum;
|
||||||
using Spectre.Console;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser
|
namespace N_m3u8DL_RE.Parser;
|
||||||
{
|
|
||||||
public class StreamExtractor
|
public class StreamExtractor
|
||||||
{
|
{
|
||||||
public ExtractorType ExtractorType { get => extractor.ExtractorType; }
|
public ExtractorType ExtractorType => extractor.ExtractorType;
|
||||||
private IExtractor extractor;
|
private IExtractor extractor;
|
||||||
private ParserConfig parserConfig = new ParserConfig();
|
private ParserConfig parserConfig = new();
|
||||||
private string rawText;
|
private string rawText;
|
||||||
private static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
|
private static SemaphoreSlim semaphore = new(1, 1);
|
||||||
|
|
||||||
public Dictionary<string, string> RawFiles { get; set; } = new(); // 存储(文件名,文件内容)
|
public Dictionary<string, string> RawFiles { get; set; } = new(); // 存储(文件名,文件内容)
|
||||||
|
|
||||||
|
@ -146,4 +145,3 @@ namespace N_m3u8DL_RE.Parser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
using N_m3u8DL_RE.Parser.Constants;
|
using N_m3u8DL_RE.Parser.Constants;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Parser.Util
|
namespace N_m3u8DL_RE.Parser.Util;
|
||||||
{
|
|
||||||
public partial class ParserUtil
|
public partial class ParserUtil
|
||||||
{
|
{
|
||||||
[GeneratedRegex("\\$Number%([^$]+)d\\$")]
|
[GeneratedRegex("\\$Number%([^$]+)d\\$")]
|
||||||
|
@ -28,13 +23,13 @@ namespace N_m3u8DL_RE.Parser.Util
|
||||||
|
|
||||||
var index = -1;
|
var index = -1;
|
||||||
var result = string.Empty;
|
var result = string.Empty;
|
||||||
if ((index = line.IndexOf(key + "=\"")) > -1)
|
if ((index = line.IndexOf(key + "=\"", StringComparison.Ordinal)) > -1)
|
||||||
{
|
{
|
||||||
var startIndex = index + (key + "=\"").Length;
|
var startIndex = index + (key + "=\"").Length;
|
||||||
var endIndex = startIndex + line[startIndex..].IndexOf('\"');
|
var endIndex = startIndex + line[startIndex..].IndexOf('\"');
|
||||||
result = line[startIndex..endIndex];
|
result = line[startIndex..endIndex];
|
||||||
}
|
}
|
||||||
else if ((index = line.IndexOf(key + "=")) > -1)
|
else if ((index = line.IndexOf(key + "=", StringComparison.Ordinal)) > -1)
|
||||||
{
|
{
|
||||||
var startIndex = index + (key + "=").Length;
|
var startIndex = index + (key + "=").Length;
|
||||||
var endIndex = startIndex + line[startIndex..].IndexOf(',');
|
var endIndex = startIndex + line[startIndex..].IndexOf(',');
|
||||||
|
@ -94,11 +89,11 @@ namespace N_m3u8DL_RE.Parser.Util
|
||||||
|
|
||||||
// 处理特殊形式数字 如 $Number%05d$
|
// 处理特殊形式数字 如 $Number%05d$
|
||||||
var regex = VarsNumberRegex();
|
var regex = VarsNumberRegex();
|
||||||
if (regex.IsMatch(text) && keyValuePairs.ContainsKey(DASHTags.TemplateNumber))
|
if (regex.IsMatch(text) && keyValuePairs.TryGetValue(DASHTags.TemplateNumber, out var keyValuePair))
|
||||||
{
|
{
|
||||||
foreach (Match m in regex.Matches(text))
|
foreach (Match m in regex.Matches(text))
|
||||||
{
|
{
|
||||||
text = text.Replace(m.Value, keyValuePairs[DASHTags.TemplateNumber]?.ToString()?.PadLeft(Convert.ToInt32(m.Groups[1].Value), '0'));
|
text = text.Replace(m.Value, keyValuePair?.ToString()?.PadLeft(Convert.ToInt32(m.Groups[1].Value), '0'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,4 +118,3 @@ namespace N_m3u8DL_RE.Parser.Util
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
using N_m3u8DL_RE.Common.Log;
|
using N_m3u8DL_RE.Entity;
|
||||||
using N_m3u8DL_RE.Entity;
|
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using N_m3u8DL_RE.Common.Util;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
namespace N_m3u8DL_RE.Column;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Column
|
|
||||||
{
|
|
||||||
internal sealed class DownloadSpeedColumn : ProgressColumn
|
internal sealed class DownloadSpeedColumn : ProgressColumn
|
||||||
{
|
{
|
||||||
private long _stopSpeed = 0;
|
private long _stopSpeed = 0;
|
||||||
|
@ -48,19 +43,6 @@ namespace N_m3u8DL_RE.Column
|
||||||
}
|
}
|
||||||
DateTimeStringDic[taskId] = now;
|
DateTimeStringDic[taskId] = now;
|
||||||
var style = flag ? Style.Plain : MyStyle;
|
var style = flag ? Style.Plain : MyStyle;
|
||||||
return flag ? new Text("-", style).Centered() : new Text(FormatFileSize(speedContainer.NowSpeed) + (speedContainer.LowSpeedCount > 0 ? $"({speedContainer.LowSpeedCount})" : ""), style).Centered();
|
return flag ? new Text("-", style).Centered() : new Text(GlobalUtil.FormatFileSize(speedContainer.NowSpeed) + (speedContainer.LowSpeedCount > 0 ? $"({speedContainer.LowSpeedCount})" : ""), style).Centered();
|
||||||
}
|
|
||||||
|
|
||||||
private static string FormatFileSize(double fileSize)
|
|
||||||
{
|
|
||||||
return fileSize switch
|
|
||||||
{
|
|
||||||
< 0 => throw new ArgumentOutOfRangeException(nameof(fileSize)),
|
|
||||||
>= 1024 * 1024 * 1024 => string.Format("{0:########0.00}GBps", (double)fileSize / (1024 * 1024 * 1024)),
|
|
||||||
>= 1024 * 1024 => string.Format("{0:####0.00}MBps", (double)fileSize / (1024 * 1024)),
|
|
||||||
>= 1024 => string.Format("{0:####0.00}KBps", (double)fileSize / 1024),
|
|
||||||
_ => string.Format("{0:####0.00}Bps", fileSize)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,15 +2,10 @@
|
||||||
using N_m3u8DL_RE.Entity;
|
using N_m3u8DL_RE.Entity;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Column
|
namespace N_m3u8DL_RE.Column;
|
||||||
{
|
|
||||||
internal class DownloadStatusColumn : ProgressColumn
|
internal class DownloadStatusColumn : ProgressColumn
|
||||||
{
|
{
|
||||||
private ConcurrentDictionary<int, SpeedContainer> SpeedContainerDic { get; set; }
|
private ConcurrentDictionary<int, SpeedContainer> SpeedContainerDic { get; set; }
|
||||||
|
@ -46,4 +41,3 @@ namespace N_m3u8DL_RE.Column
|
||||||
return new Text(sizeStr ?? "-", MyStyle).RightJustified();
|
return new Text(sizeStr ?? "-", MyStyle).RightJustified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Column
|
namespace N_m3u8DL_RE.Column;
|
||||||
{
|
|
||||||
internal class MyPercentageColumn : ProgressColumn
|
internal class MyPercentageColumn : ProgressColumn
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -28,4 +23,3 @@ namespace N_m3u8DL_RE.Column
|
||||||
return new Text($"{task.Value}/{task.MaxValue} {percentage:F2}%", style).RightJustified();
|
return new Text($"{task.Value}/{task.MaxValue} {percentage:F2}%", style).RightJustified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
using N_m3u8DL_RE.Common.Util;
|
using N_m3u8DL_RE.Common.Util;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Column
|
namespace N_m3u8DL_RE.Column;
|
||||||
{
|
|
||||||
internal class RecordingDurationColumn : ProgressColumn
|
internal class RecordingDurationColumn : ProgressColumn
|
||||||
{
|
{
|
||||||
protected override bool NoWrap => true;
|
protected override bool NoWrap => true;
|
||||||
|
@ -36,4 +31,3 @@ namespace N_m3u8DL_RE.Column
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
using N_m3u8DL_RE.Common.Util;
|
using N_m3u8DL_RE.Common.Util;
|
||||||
using N_m3u8DL_RE.Entity;
|
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Column
|
namespace N_m3u8DL_RE.Column;
|
||||||
{
|
|
||||||
internal class RecordingSizeColumn : ProgressColumn
|
internal class RecordingSizeColumn : ProgressColumn
|
||||||
{
|
{
|
||||||
protected override bool NoWrap => true;
|
protected override bool NoWrap => true;
|
||||||
|
@ -36,4 +30,3 @@ namespace N_m3u8DL_RE.Column
|
||||||
return new Text(GlobalUtil.FormatFileSize(flag ? size : 0), MyStyle).LeftJustified();
|
return new Text(GlobalUtil.FormatFileSize(flag ? size : 0), MyStyle).LeftJustified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using Spectre.Console.Rendering;
|
using Spectre.Console.Rendering;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Column
|
namespace N_m3u8DL_RE.Column;
|
||||||
{
|
|
||||||
internal class RecordingStatusColumn : ProgressColumn
|
internal class RecordingStatusColumn : ProgressColumn
|
||||||
{
|
{
|
||||||
protected override bool NoWrap => true;
|
protected override bool NoWrap => true;
|
||||||
|
@ -20,4 +15,3 @@ namespace N_m3u8DL_RE.Column
|
||||||
return new Text($"{task.Value}/{task.MaxValue} Recording", MyStyle).LeftJustified();
|
return new Text($"{task.Value}/{task.MaxValue} Recording", MyStyle).LeftJustified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ using N_m3u8DL_RE.Common.Util;
|
||||||
using N_m3u8DL_RE.Entity;
|
using N_m3u8DL_RE.Entity;
|
||||||
using N_m3u8DL_RE.Enum;
|
using N_m3u8DL_RE.Enum;
|
||||||
using N_m3u8DL_RE.Util;
|
using N_m3u8DL_RE.Util;
|
||||||
using NiL.JS.Expressions;
|
|
||||||
using System.CommandLine;
|
using System.CommandLine;
|
||||||
using System.CommandLine.Binding;
|
using System.CommandLine.Binding;
|
||||||
using System.CommandLine.Builder;
|
using System.CommandLine.Builder;
|
||||||
|
@ -14,97 +13,97 @@ using System.Globalization;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.CommandLine
|
namespace N_m3u8DL_RE.CommandLine;
|
||||||
{
|
|
||||||
internal partial class CommandInvoker
|
internal partial class CommandInvoker
|
||||||
{
|
{
|
||||||
public const string VERSION_INFO = "N_m3u8DL-RE (Beta version) 20241020";
|
public const string VERSION_INFO = "N_m3u8DL-RE (Beta version) 20241110";
|
||||||
|
|
||||||
[GeneratedRegex("((best|worst)\\d*|all)")]
|
[GeneratedRegex("((best|worst)\\d*|all)")]
|
||||||
private static partial Regex ForStrRegex();
|
private static partial Regex ForStrRegex();
|
||||||
[GeneratedRegex("(\\d*)-(\\d*)")]
|
[GeneratedRegex("(\\d*)-(\\d*)")]
|
||||||
private static partial Regex RangeRegex();
|
private static partial Regex RangeRegex();
|
||||||
|
|
||||||
private readonly static Argument<string> Input = new(name: "input", description: ResString.cmd_Input);
|
private static readonly Argument<string> Input = new(name: "input", description: ResString.cmd_Input);
|
||||||
private readonly static Option<string?> TmpDir = new(new string[] { "--tmp-dir" }, description: ResString.cmd_tmpDir);
|
private static readonly Option<string?> TmpDir = new(["--tmp-dir"], description: ResString.cmd_tmpDir);
|
||||||
private readonly static Option<string?> SaveDir = new(new string[] { "--save-dir" }, description: ResString.cmd_saveDir);
|
private static readonly Option<string?> SaveDir = new(["--save-dir"], description: ResString.cmd_saveDir);
|
||||||
private readonly static Option<string?> SaveName = new(new string[] { "--save-name" }, description: ResString.cmd_saveName, parseArgument: ParseSaveName);
|
private static readonly Option<string?> SaveName = new(["--save-name"], description: ResString.cmd_saveName, parseArgument: ParseSaveName);
|
||||||
private readonly static Option<string?> SavePattern = new(new string[] { "--save-pattern" }, description: ResString.cmd_savePattern, getDefaultValue: () => "<SaveName>_<Id>_<Codecs>_<Language>_<Ext>");
|
private static readonly Option<string?> SavePattern = new(["--save-pattern"], description: ResString.cmd_savePattern, getDefaultValue: () => "<SaveName>_<Id>_<Codecs>_<Language>_<Ext>");
|
||||||
private readonly static Option<string?> UILanguage = new Option<string?>(new string[] { "--ui-language" }, description: ResString.cmd_uiLanguage).FromAmong("en-US", "zh-CN", "zh-TW");
|
private static readonly Option<string?> UILanguage = new Option<string?>(["--ui-language"], description: ResString.cmd_uiLanguage).FromAmong("en-US", "zh-CN", "zh-TW");
|
||||||
private readonly static Option<string?> UrlProcessorArgs = new(new string[] { "--urlprocessor-args" }, description: ResString.cmd_urlProcessorArgs);
|
private static readonly Option<string?> UrlProcessorArgs = new(["--urlprocessor-args"], description: ResString.cmd_urlProcessorArgs);
|
||||||
private readonly static Option<string[]?> Keys = new(new string[] { "--key" }, description: ResString.cmd_keys) { Arity = ArgumentArity.OneOrMore, AllowMultipleArgumentsPerToken = false };
|
private static readonly Option<string[]?> Keys = new(["--key"], description: ResString.cmd_keys) { Arity = ArgumentArity.OneOrMore, AllowMultipleArgumentsPerToken = false };
|
||||||
private readonly static Option<string> KeyTextFile = new(new string[] { "--key-text-file" }, description: ResString.cmd_keyText);
|
private static readonly Option<string> KeyTextFile = new(["--key-text-file"], description: ResString.cmd_keyText);
|
||||||
private readonly static Option<Dictionary<string, string>> Headers = new(new string[] { "-H", "--header" }, description: ResString.cmd_header, parseArgument: ParseHeaders) { Arity = ArgumentArity.OneOrMore, AllowMultipleArgumentsPerToken = false };
|
private static readonly Option<Dictionary<string, string>> Headers = new(["-H", "--header"], description: ResString.cmd_header, parseArgument: ParseHeaders) { Arity = ArgumentArity.OneOrMore, AllowMultipleArgumentsPerToken = false };
|
||||||
private readonly static Option<LogLevel> LogLevel = new(name: "--log-level", description: ResString.cmd_logLevel, getDefaultValue: () => Common.Log.LogLevel.INFO);
|
private static readonly Option<LogLevel> LogLevel = new(name: "--log-level", description: ResString.cmd_logLevel, getDefaultValue: () => Common.Log.LogLevel.INFO);
|
||||||
private readonly static Option<SubtitleFormat> SubtitleFormat = new(name: "--sub-format", description: ResString.cmd_subFormat, getDefaultValue: () => Enum.SubtitleFormat.SRT);
|
private static readonly Option<SubtitleFormat> SubtitleFormat = new(name: "--sub-format", description: ResString.cmd_subFormat, getDefaultValue: () => Enum.SubtitleFormat.SRT);
|
||||||
private readonly static Option<bool> AutoSelect = new(new string[] { "--auto-select" }, description: ResString.cmd_autoSelect, getDefaultValue: () => false);
|
private static readonly Option<bool> AutoSelect = new(["--auto-select"], description: ResString.cmd_autoSelect, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> SubOnly = new(new string[] { "--sub-only" }, description: ResString.cmd_subOnly, getDefaultValue: () => false);
|
private static readonly Option<bool> SubOnly = new(["--sub-only"], description: ResString.cmd_subOnly, getDefaultValue: () => false);
|
||||||
private readonly static Option<int> ThreadCount = new(new string[] { "--thread-count" }, description: ResString.cmd_threadCount, getDefaultValue: () => Environment.ProcessorCount) { ArgumentHelpName = "number" };
|
private static readonly Option<int> ThreadCount = new(["--thread-count"], description: ResString.cmd_threadCount, getDefaultValue: () => Environment.ProcessorCount) { ArgumentHelpName = "number" };
|
||||||
private readonly static Option<int> DownloadRetryCount = new(new string[] { "--download-retry-count" }, description: ResString.cmd_downloadRetryCount, getDefaultValue: () => 3) { ArgumentHelpName = "number" };
|
private static readonly Option<int> DownloadRetryCount = new(["--download-retry-count"], description: ResString.cmd_downloadRetryCount, getDefaultValue: () => 3) { ArgumentHelpName = "number" };
|
||||||
private readonly static Option<bool> SkipMerge = new(new string[] { "--skip-merge" }, description: ResString.cmd_skipMerge, getDefaultValue: () => false);
|
private static readonly Option<bool> SkipMerge = new(["--skip-merge"], description: ResString.cmd_skipMerge, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> SkipDownload = new(new string[] { "--skip-download" }, description: ResString.cmd_skipDownload, getDefaultValue: () => false);
|
private static readonly Option<bool> SkipDownload = new(["--skip-download"], description: ResString.cmd_skipDownload, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> NoDateInfo = new(new string[] { "--no-date-info" }, description: ResString.cmd_noDateInfo, getDefaultValue: () => false);
|
private static readonly Option<bool> NoDateInfo = new(["--no-date-info"], description: ResString.cmd_noDateInfo, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> BinaryMerge = new(new string[] { "--binary-merge" }, description: ResString.cmd_binaryMerge, getDefaultValue: () => false);
|
private static readonly Option<bool> BinaryMerge = new(["--binary-merge"], description: ResString.cmd_binaryMerge, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> UseFFmpegConcatDemuxer = new(new string[] { "--use-ffmpeg-concat-demuxer" }, description: ResString.cmd_useFFmpegConcatDemuxer, getDefaultValue: () => false);
|
private static readonly Option<bool> UseFFmpegConcatDemuxer = new(["--use-ffmpeg-concat-demuxer"], description: ResString.cmd_useFFmpegConcatDemuxer, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> DelAfterDone = new(new string[] { "--del-after-done" }, description: ResString.cmd_delAfterDone, getDefaultValue: () => true);
|
private static readonly Option<bool> DelAfterDone = new(["--del-after-done"], description: ResString.cmd_delAfterDone, getDefaultValue: () => true);
|
||||||
private readonly static Option<bool> AutoSubtitleFix = new(new string[] { "--auto-subtitle-fix" }, description: ResString.cmd_subtitleFix, getDefaultValue: () => true);
|
private static readonly Option<bool> AutoSubtitleFix = new(["--auto-subtitle-fix"], description: ResString.cmd_subtitleFix, getDefaultValue: () => true);
|
||||||
private readonly static Option<bool> CheckSegmentsCount = new(new string[] { "--check-segments-count" }, description: ResString.cmd_checkSegmentsCount, getDefaultValue: () => true);
|
private static readonly Option<bool> CheckSegmentsCount = new(["--check-segments-count"], description: ResString.cmd_checkSegmentsCount, getDefaultValue: () => true);
|
||||||
private readonly static Option<bool> WriteMetaJson = new(new string[] { "--write-meta-json" }, description: ResString.cmd_writeMetaJson, getDefaultValue: () => true);
|
private static readonly Option<bool> WriteMetaJson = new(["--write-meta-json"], description: ResString.cmd_writeMetaJson, getDefaultValue: () => true);
|
||||||
private readonly static Option<bool> AppendUrlParams = new(new string[] { "--append-url-params" }, description: ResString.cmd_appendUrlParams, getDefaultValue: () => false);
|
private static readonly Option<bool> AppendUrlParams = new(["--append-url-params"], description: ResString.cmd_appendUrlParams, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> MP4RealTimeDecryption = new (new string[] { "--mp4-real-time-decryption" }, description: ResString.cmd_MP4RealTimeDecryption, getDefaultValue: () => false);
|
private static readonly Option<bool> MP4RealTimeDecryption = new (["--mp4-real-time-decryption"], description: ResString.cmd_MP4RealTimeDecryption, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> UseShakaPackager = new (new string[] { "--use-shaka-packager" }, description: ResString.cmd_useShakaPackager, getDefaultValue: () => false);
|
private static readonly Option<bool> UseShakaPackager = new (["--use-shaka-packager"], description: ResString.cmd_useShakaPackager, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> ForceAnsiConsole = new(new string[] { "--force-ansi-console" }, description: ResString.cmd_forceAnsiConsole);
|
private static readonly Option<bool> ForceAnsiConsole = new(["--force-ansi-console"], description: ResString.cmd_forceAnsiConsole);
|
||||||
private readonly static Option<bool> NoAnsiColor = new(new string[] { "--no-ansi-color" }, description: ResString.cmd_noAnsiColor);
|
private static readonly Option<bool> NoAnsiColor = new(["--no-ansi-color"], description: ResString.cmd_noAnsiColor);
|
||||||
private readonly static Option<string?> DecryptionBinaryPath = new(new string[] { "--decryption-binary-path" }, description: ResString.cmd_decryptionBinaryPath) { ArgumentHelpName = "PATH" };
|
private static readonly Option<string?> DecryptionBinaryPath = new(["--decryption-binary-path"], description: ResString.cmd_decryptionBinaryPath) { ArgumentHelpName = "PATH" };
|
||||||
private readonly static Option<string?> FFmpegBinaryPath = new(new string[] { "--ffmpeg-binary-path" }, description: ResString.cmd_ffmpegBinaryPath) { ArgumentHelpName = "PATH" };
|
private static readonly Option<string?> FFmpegBinaryPath = new(["--ffmpeg-binary-path"], description: ResString.cmd_ffmpegBinaryPath) { ArgumentHelpName = "PATH" };
|
||||||
private readonly static Option<string?> BaseUrl = new(new string[] { "--base-url" }, description: ResString.cmd_baseUrl);
|
private static readonly Option<string?> BaseUrl = new(["--base-url"], description: ResString.cmd_baseUrl);
|
||||||
private readonly static Option<bool> ConcurrentDownload = new(new string[] { "-mt", "--concurrent-download" }, description: ResString.cmd_concurrentDownload, getDefaultValue: () => false);
|
private static readonly Option<bool> ConcurrentDownload = new(["-mt", "--concurrent-download"], description: ResString.cmd_concurrentDownload, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> NoLog = new(new string[] { "--no-log" }, description: ResString.cmd_noLog, getDefaultValue: () => false);
|
private static readonly Option<bool> NoLog = new(["--no-log"], description: ResString.cmd_noLog, getDefaultValue: () => false);
|
||||||
private readonly static Option<string[]?> AdKeywords = new(new string[] { "--ad-keyword" }, description: ResString.cmd_adKeyword) { ArgumentHelpName = "REG" };
|
private static readonly Option<string[]?> AdKeywords = new(["--ad-keyword"], description: ResString.cmd_adKeyword) { ArgumentHelpName = "REG" };
|
||||||
private readonly static Option<long?> MaxSpeed = new(new string[] { "-R", "--max-speed" }, description: ResString.cmd_maxSpeed, parseArgument: ParseSpeedLimit) { ArgumentHelpName = "SPEED" };
|
private static readonly Option<long?> MaxSpeed = new(["-R", "--max-speed"], description: ResString.cmd_maxSpeed, parseArgument: ParseSpeedLimit) { ArgumentHelpName = "SPEED" };
|
||||||
|
|
||||||
|
|
||||||
// 代理选项
|
// 代理选项
|
||||||
private readonly static Option<bool> UseSystemProxy = new(new string[] { "--use-system-proxy" }, description: ResString.cmd_useSystemProxy, getDefaultValue: () => true);
|
private static readonly Option<bool> UseSystemProxy = new(["--use-system-proxy"], description: ResString.cmd_useSystemProxy, getDefaultValue: () => true);
|
||||||
private readonly static Option<WebProxy?> CustomProxy = new(new string[] { "--custom-proxy" }, description: ResString.cmd_customProxy, parseArgument: ParseProxy) { ArgumentHelpName = "URL" };
|
private static readonly Option<WebProxy?> CustomProxy = new(["--custom-proxy"], description: ResString.cmd_customProxy, parseArgument: ParseProxy) { ArgumentHelpName = "URL" };
|
||||||
|
|
||||||
// 只下载部分分片
|
// 只下载部分分片
|
||||||
private readonly static Option<CustomRange?> CustomRange = new(new string[] { "--custom-range" }, description: ResString.cmd_customRange, parseArgument: ParseCustomRange) { ArgumentHelpName = "RANGE" };
|
private static readonly Option<CustomRange?> CustomRange = new(["--custom-range"], description: ResString.cmd_customRange, parseArgument: ParseCustomRange) { ArgumentHelpName = "RANGE" };
|
||||||
|
|
||||||
|
|
||||||
// morehelp
|
// morehelp
|
||||||
private readonly static Option<string?> MoreHelp = new(new string[] { "--morehelp" }, description: ResString.cmd_moreHelp) { ArgumentHelpName = "OPTION" };
|
private static readonly Option<string?> MoreHelp = new(["--morehelp"], description: ResString.cmd_moreHelp) { ArgumentHelpName = "OPTION" };
|
||||||
|
|
||||||
// 自定义KEY等
|
// 自定义KEY等
|
||||||
private readonly static Option<EncryptMethod?> CustomHLSMethod = new(name: "--custom-hls-method", description: ResString.cmd_customHLSMethod) { ArgumentHelpName = "METHOD" };
|
private static readonly Option<EncryptMethod?> CustomHLSMethod = new(name: "--custom-hls-method", description: ResString.cmd_customHLSMethod) { ArgumentHelpName = "METHOD" };
|
||||||
private readonly static Option<byte[]?> CustomHLSKey = new(name: "--custom-hls-key", description: ResString.cmd_customHLSKey, parseArgument: ParseHLSCustomKey) { ArgumentHelpName = "FILE|HEX|BASE64" };
|
private static readonly Option<byte[]?> CustomHLSKey = new(name: "--custom-hls-key", description: ResString.cmd_customHLSKey, parseArgument: ParseHLSCustomKey) { ArgumentHelpName = "FILE|HEX|BASE64" };
|
||||||
private readonly static Option<byte[]?> CustomHLSIv = new(name: "--custom-hls-iv", description: ResString.cmd_customHLSIv, parseArgument: ParseHLSCustomKey) { ArgumentHelpName = "FILE|HEX|BASE64" };
|
private static readonly Option<byte[]?> CustomHLSIv = new(name: "--custom-hls-iv", description: ResString.cmd_customHLSIv, parseArgument: ParseHLSCustomKey) { ArgumentHelpName = "FILE|HEX|BASE64" };
|
||||||
|
|
||||||
// 任务开始时间
|
// 任务开始时间
|
||||||
private readonly static Option<DateTime?> TaskStartAt = new(new string[] { "--task-start-at" }, description: ResString.cmd_taskStartAt, parseArgument: ParseStartTime) { ArgumentHelpName = "yyyyMMddHHmmss" };
|
private static readonly Option<DateTime?> TaskStartAt = new(["--task-start-at"], description: ResString.cmd_taskStartAt, parseArgument: ParseStartTime) { ArgumentHelpName = "yyyyMMddHHmmss" };
|
||||||
|
|
||||||
|
|
||||||
// 直播相关
|
// 直播相关
|
||||||
private readonly static Option<bool> LivePerformAsVod = new(new string[] { "--live-perform-as-vod" }, description: ResString.cmd_livePerformAsVod, getDefaultValue: () => false);
|
private static readonly Option<bool> LivePerformAsVod = new(["--live-perform-as-vod"], description: ResString.cmd_livePerformAsVod, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> LiveRealTimeMerge = new(new string[] { "--live-real-time-merge" }, description: ResString.cmd_liveRealTimeMerge, getDefaultValue: () => false);
|
private static readonly Option<bool> LiveRealTimeMerge = new(["--live-real-time-merge"], description: ResString.cmd_liveRealTimeMerge, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> LiveKeepSegments = new(new string[] { "--live-keep-segments" }, description: ResString.cmd_liveKeepSegments, getDefaultValue: () => true);
|
private static readonly Option<bool> LiveKeepSegments = new(["--live-keep-segments"], description: ResString.cmd_liveKeepSegments, getDefaultValue: () => true);
|
||||||
private readonly static Option<bool> LivePipeMux = new(new string[] { "--live-pipe-mux" }, description: ResString.cmd_livePipeMux, getDefaultValue: () => false);
|
private static readonly Option<bool> LivePipeMux = new(["--live-pipe-mux"], description: ResString.cmd_livePipeMux, getDefaultValue: () => false);
|
||||||
private readonly static Option<TimeSpan?> LiveRecordLimit = new(new string[] { "--live-record-limit" }, description: ResString.cmd_liveRecordLimit, parseArgument: ParseLiveLimit) { ArgumentHelpName = "HH:mm:ss" };
|
private static readonly Option<TimeSpan?> LiveRecordLimit = new(["--live-record-limit"], description: ResString.cmd_liveRecordLimit, parseArgument: ParseLiveLimit) { ArgumentHelpName = "HH:mm:ss" };
|
||||||
private readonly static Option<int?> LiveWaitTime = new(new string[] { "--live-wait-time" }, description: ResString.cmd_liveWaitTime) { ArgumentHelpName = "SEC" };
|
private static readonly Option<int?> LiveWaitTime = new(["--live-wait-time"], description: ResString.cmd_liveWaitTime) { ArgumentHelpName = "SEC" };
|
||||||
private readonly static Option<int> LiveTakeCount = new(new string[] { "--live-take-count" }, description: ResString.cmd_liveTakeCount, getDefaultValue: () => 16) { ArgumentHelpName = "NUM" };
|
private static readonly Option<int> LiveTakeCount = new(["--live-take-count"], description: ResString.cmd_liveTakeCount, getDefaultValue: () => 16) { ArgumentHelpName = "NUM" };
|
||||||
private readonly static Option<bool> LiveFixVttByAudio = new(new string[] { "--live-fix-vtt-by-audio" }, description: ResString.cmd_liveFixVttByAudio, getDefaultValue: () => false);
|
private static readonly Option<bool> LiveFixVttByAudio = new(["--live-fix-vtt-by-audio"], description: ResString.cmd_liveFixVttByAudio, getDefaultValue: () => false);
|
||||||
|
|
||||||
|
|
||||||
// 复杂命令行如下
|
// 复杂命令行如下
|
||||||
private readonly static Option<MuxOptions?> MuxAfterDone = new(new string[] { "-M", "--mux-after-done" }, description: ResString.cmd_muxAfterDone, parseArgument: ParseMuxAfterDone) { ArgumentHelpName = "OPTIONS" };
|
private static readonly Option<MuxOptions?> MuxAfterDone = new(["-M", "--mux-after-done"], description: ResString.cmd_muxAfterDone, parseArgument: ParseMuxAfterDone) { ArgumentHelpName = "OPTIONS" };
|
||||||
private readonly static Option<List<OutputFile>> MuxImports = new("--mux-import", description: ResString.cmd_muxImport, parseArgument: ParseImports) { Arity = ArgumentArity.OneOrMore, AllowMultipleArgumentsPerToken = false, ArgumentHelpName = "OPTIONS" };
|
private static readonly Option<List<OutputFile>> MuxImports = new("--mux-import", description: ResString.cmd_muxImport, parseArgument: ParseImports) { Arity = ArgumentArity.OneOrMore, AllowMultipleArgumentsPerToken = false, ArgumentHelpName = "OPTIONS" };
|
||||||
private readonly static Option<StreamFilter?> VideoFilter = new(new string[] { "-sv", "--select-video" }, description: ResString.cmd_selectVideo, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
private static readonly Option<StreamFilter?> VideoFilter = new(["-sv", "--select-video"], description: ResString.cmd_selectVideo, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
||||||
private readonly static Option<StreamFilter?> AudioFilter = new(new string[] { "-sa", "--select-audio" }, description: ResString.cmd_selectAudio, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
private static readonly Option<StreamFilter?> AudioFilter = new(["-sa", "--select-audio"], description: ResString.cmd_selectAudio, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
||||||
private readonly static Option<StreamFilter?> SubtitleFilter = new(new string[] { "-ss", "--select-subtitle" }, description: ResString.cmd_selectSubtitle, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
private static readonly Option<StreamFilter?> SubtitleFilter = new(["-ss", "--select-subtitle"], description: ResString.cmd_selectSubtitle, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
||||||
|
|
||||||
private readonly static Option<StreamFilter?> DropVideoFilter = new(new string[] { "-dv", "--drop-video" }, description: ResString.cmd_dropVideo, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
private static readonly Option<StreamFilter?> DropVideoFilter = new(["-dv", "--drop-video"], description: ResString.cmd_dropVideo, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
||||||
private readonly static Option<StreamFilter?> DropAudioFilter = new(new string[] { "-da", "--drop-audio" }, description: ResString.cmd_dropAudio, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
private static readonly Option<StreamFilter?> DropAudioFilter = new(["-da", "--drop-audio"], description: ResString.cmd_dropAudio, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
||||||
private readonly static Option<StreamFilter?> DropSubtitleFilter = new(new string[] { "-ds", "--drop-subtitle" }, description: ResString.cmd_dropSubtitle, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
private static readonly Option<StreamFilter?> DropSubtitleFilter = new(["-ds", "--drop-subtitle"], description: ResString.cmd_dropSubtitle, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 解析录制直播时长限制
|
/// 解析录制直播时长限制
|
||||||
|
@ -640,4 +639,3 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
return await parser.InvokeAsync(args);
|
return await parser.InvokeAsync(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
using System;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
namespace N_m3u8DL_RE.CommandLine;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.CommandLine
|
|
||||||
{
|
|
||||||
internal class ComplexParamParser
|
internal class ComplexParamParser
|
||||||
{
|
{
|
||||||
private string _arg;
|
private string _arg;
|
||||||
|
@ -58,4 +54,3 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ using N_m3u8DL_RE.Entity;
|
||||||
using N_m3u8DL_RE.Enum;
|
using N_m3u8DL_RE.Enum;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.CommandLine
|
namespace N_m3u8DL_RE.CommandLine;
|
||||||
{
|
|
||||||
internal class MyOption
|
internal class MyOption
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -244,7 +244,7 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
/// See: <see cref="CommandInvoker.LiveTakeCount"/>.
|
/// See: <see cref="CommandInvoker.LiveTakeCount"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int LiveTakeCount { get; set; }
|
public int LiveTakeCount { get; set; }
|
||||||
public MuxOptions MuxOptions { get; set; }
|
public MuxOptions? MuxOptions { get; set; }
|
||||||
// public bool LiveWriteHLS { get; set; } = true;
|
// public bool LiveWriteHLS { get; set; } = true;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// See: <see cref="CommandInvoker.LivePipeMux"/>.
|
/// See: <see cref="CommandInvoker.LivePipeMux"/>.
|
||||||
|
@ -255,4 +255,3 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool LiveFixVttByAudio { get; set; }
|
public bool LiveFixVttByAudio { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -1,14 +1,7 @@
|
||||||
using N_m3u8DL_RE.CommandLine;
|
using N_m3u8DL_RE.CommandLine;
|
||||||
using N_m3u8DL_RE.Enum;
|
|
||||||
using N_m3u8DL_RE.Parser.Config;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Config
|
namespace N_m3u8DL_RE.Config;
|
||||||
{
|
|
||||||
internal class DownloaderConfig
|
internal class DownloaderConfig
|
||||||
{
|
{
|
||||||
public required MyOption MyOptions { get; set; }
|
public required MyOption MyOptions { get; set; }
|
||||||
|
@ -30,4 +23,3 @@ namespace N_m3u8DL_RE.Config
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
|
public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
using System;
|
using System.Security.Cryptography;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
namespace N_m3u8DL_RE.Crypto;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Crypto
|
|
||||||
{
|
|
||||||
internal class AESUtil
|
internal class AESUtil
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -41,4 +36,3 @@ namespace N_m3u8DL_RE.Crypto
|
||||||
return resultArray;
|
return resultArray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
using CSChaCha20;
|
using CSChaCha20;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Crypto
|
namespace N_m3u8DL_RE.Crypto;
|
||||||
{
|
|
||||||
internal class ChaCha20Util
|
internal class ChaCha20Util
|
||||||
{
|
{
|
||||||
public static byte[] DecryptPer1024Bytes(byte[] encryptedBuff, byte[] keyBytes, byte[] nonceBytes)
|
public static byte[] DecryptPer1024Bytes(byte[] encryptedBuff, byte[] keyBytes, byte[] nonceBytes)
|
||||||
|
@ -40,4 +35,3 @@ namespace N_m3u8DL_RE.Crypto
|
||||||
return decStream.ToArray();
|
return decStream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
using Mp4SubtitleParser;
|
using N_m3u8DL_RE.Column;
|
||||||
using N_m3u8DL_RE.Column;
|
|
||||||
using N_m3u8DL_RE.Common.Entity;
|
using N_m3u8DL_RE.Common.Entity;
|
||||||
using N_m3u8DL_RE.Common.Enum;
|
|
||||||
using N_m3u8DL_RE.Common.Log;
|
using N_m3u8DL_RE.Common.Log;
|
||||||
using N_m3u8DL_RE.Common.Resource;
|
using N_m3u8DL_RE.Common.Resource;
|
||||||
using N_m3u8DL_RE.Common.Util;
|
using N_m3u8DL_RE.Common.Util;
|
||||||
|
@ -11,20 +9,11 @@ using N_m3u8DL_RE.Entity;
|
||||||
using N_m3u8DL_RE.Parser;
|
using N_m3u8DL_RE.Parser;
|
||||||
using N_m3u8DL_RE.Util;
|
using N_m3u8DL_RE.Util;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using Spectre.Console.Rendering;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.IO;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Reflection.PortableExecutable;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Threading.Tasks.Dataflow;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.DownloadManager
|
namespace N_m3u8DL_RE.DownloadManager;
|
||||||
{
|
|
||||||
internal class HTTPLiveRecordManager
|
internal class HTTPLiveRecordManager
|
||||||
{
|
{
|
||||||
IDownloader Downloader;
|
IDownloader Downloader;
|
||||||
|
@ -84,9 +73,9 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
var size = 0;
|
var size = 0;
|
||||||
|
|
||||||
// 计时器
|
// 计时器
|
||||||
TimeCounterAsync();
|
_ = TimeCounterAsync();
|
||||||
// 读取INFO
|
// 读取INFO
|
||||||
ReadInfoAsync();
|
_ = ReadInfoAsync();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -251,4 +240,3 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ using Spectre.Console;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.DownloadManager
|
namespace N_m3u8DL_RE.DownloadManager;
|
||||||
{
|
|
||||||
internal class SimpleDownloadManager
|
internal class SimpleDownloadManager
|
||||||
{
|
{
|
||||||
IDownloader Downloader;
|
IDownloader Downloader;
|
||||||
|
@ -715,7 +715,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
{
|
{
|
||||||
OutputFiles = OutputFiles.OrderBy(o => o.Index).ToList();
|
OutputFiles = OutputFiles.OrderBy(o => o.Index).ToList();
|
||||||
// 是否跳过字幕
|
// 是否跳过字幕
|
||||||
if (DownloaderConfig.MyOptions.MuxOptions.SkipSubtitle)
|
if (DownloaderConfig.MyOptions.MuxOptions!.SkipSubtitle)
|
||||||
{
|
{
|
||||||
OutputFiles = OutputFiles.Where(o => o.MediaType != MediaType.SUBTITLES).ToList();
|
OutputFiles = OutputFiles.Where(o => o.MediaType != MediaType.SUBTITLES).ToList();
|
||||||
}
|
}
|
||||||
|
@ -761,4 +761,3 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -12,19 +12,13 @@ using N_m3u8DL_RE.Parser;
|
||||||
using N_m3u8DL_RE.Parser.Mp4;
|
using N_m3u8DL_RE.Parser.Mp4;
|
||||||
using N_m3u8DL_RE.Util;
|
using N_m3u8DL_RE.Util;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using Spectre.Console.Rendering;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.IO.Pipes;
|
using System.IO.Pipes;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Threading.Tasks.Dataflow;
|
using System.Threading.Tasks.Dataflow;
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.DownloadManager
|
namespace N_m3u8DL_RE.DownloadManager;
|
||||||
{
|
|
||||||
internal class SimpleLiveRecordManager2
|
internal class SimpleLiveRecordManager2
|
||||||
{
|
{
|
||||||
IDownloader Downloader;
|
IDownloader Downloader;
|
||||||
|
@ -886,7 +880,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
{
|
{
|
||||||
OutputFiles = OutputFiles.OrderBy(o => o.Index).ToList();
|
OutputFiles = OutputFiles.OrderBy(o => o.Index).ToList();
|
||||||
// 是否跳过字幕
|
// 是否跳过字幕
|
||||||
if (DownloaderConfig.MyOptions.MuxOptions.SkipSubtitle)
|
if (DownloaderConfig.MyOptions.MuxOptions!.SkipSubtitle)
|
||||||
{
|
{
|
||||||
OutputFiles = OutputFiles.Where(o => o.MediaType != MediaType.SUBTITLES).ToList();
|
OutputFiles = OutputFiles.Where(o => o.MediaType != MediaType.SUBTITLES).ToList();
|
||||||
}
|
}
|
||||||
|
@ -932,4 +926,3 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
using N_m3u8DL_RE.Common.Entity;
|
using N_m3u8DL_RE.Common.Entity;
|
||||||
using N_m3u8DL_RE.Entity;
|
using N_m3u8DL_RE.Entity;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Downloader
|
namespace N_m3u8DL_RE.Downloader;
|
||||||
{
|
|
||||||
internal interface IDownloader
|
internal interface IDownloader
|
||||||
{
|
{
|
||||||
Task<DownloadResult?> DownloadSegmentAsync(MediaSegment segment, string savePath, SpeedContainer speedContainer, Dictionary<string, string>? headers = null);
|
Task<DownloadResult?> DownloadSegmentAsync(MediaSegment segment, string savePath, SpeedContainer speedContainer, Dictionary<string, string>? headers = null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -6,18 +6,9 @@ using N_m3u8DL_RE.Crypto;
|
||||||
using N_m3u8DL_RE.Entity;
|
using N_m3u8DL_RE.Entity;
|
||||||
using N_m3u8DL_RE.Util;
|
using N_m3u8DL_RE.Util;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Downloader
|
namespace N_m3u8DL_RE.Downloader;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 简单下载器
|
/// 简单下载器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -158,4 +149,3 @@ namespace N_m3u8DL_RE.Downloader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
using System;
|
namespace N_m3u8DL_RE.Entity;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Entity
|
|
||||||
{
|
|
||||||
public class CustomRange
|
public class CustomRange
|
||||||
{
|
{
|
||||||
public required string InputStr { get; set; }
|
public required string InputStr { get; set; }
|
||||||
|
@ -20,4 +14,3 @@ namespace N_m3u8DL_RE.Entity
|
||||||
return $"StartSec: {StartSec}, EndSec: {EndSec}, StartSegIndex: {StartSegIndex}, EndSegIndex: {EndSegIndex}";
|
return $"StartSec: {StartSec}, EndSec: {EndSec}, StartSegIndex: {StartSegIndex}, EndSegIndex: {EndSegIndex}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Entity
|
namespace N_m3u8DL_RE.Entity;
|
||||||
{
|
|
||||||
internal class DownloadResult
|
internal class DownloadResult
|
||||||
{
|
{
|
||||||
public bool Success { get => (ActualContentLength != null && RespContentLength != null) ? (RespContentLength == ActualContentLength) : (ActualContentLength == null ? false : true); }
|
public bool Success { get => (ActualContentLength != null && RespContentLength != null) ? (RespContentLength == ActualContentLength) : (ActualContentLength == null ? false : true); }
|
||||||
|
@ -16,4 +16,3 @@ namespace N_m3u8DL_RE.Entity
|
||||||
public bool GzipHeader { get; set; } = false; // GZip压缩
|
public bool GzipHeader { get; set; } = false; // GZip压缩
|
||||||
public required string ActualFilePath { get; set; }
|
public required string ActualFilePath { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
using System;
|
using Spectre.Console;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
namespace N_m3u8DL_RE.Entity;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Spectre.Console;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Entity
|
|
||||||
{
|
|
||||||
internal class Mediainfo
|
internal class Mediainfo
|
||||||
{
|
{
|
||||||
public string? Id { get; set; }
|
public string? Id { get; set; }
|
||||||
|
@ -30,4 +25,3 @@ namespace N_m3u8DL_RE.Entity
|
||||||
return "[steelblue]" + ToString().EscapeMarkup() + ((HDR && !DolbyVison) ? " [darkorange3_1][[HDR]][/]" : "") + (DolbyVison ? " [darkorange3_1][[DOVI]][/]" : "") + "[/]";
|
return "[steelblue]" + ToString().EscapeMarkup() + ((HDR && !DolbyVison) ? " [darkorange3_1][[HDR]][/]" : "") + (DolbyVison ? " [darkorange3_1][[DOVI]][/]" : "") + "[/]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using N_m3u8DL_RE.Enum;
|
using N_m3u8DL_RE.Enum;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Entity
|
namespace N_m3u8DL_RE.Entity;
|
||||||
{
|
|
||||||
internal class MuxOptions
|
internal class MuxOptions
|
||||||
{
|
{
|
||||||
public bool UseMkvmerge { get; set; } = false;
|
public bool UseMkvmerge { get; set; } = false;
|
||||||
|
@ -10,4 +10,3 @@ namespace N_m3u8DL_RE.Entity
|
||||||
public bool SkipSubtitle { get; set; } = false;
|
public bool SkipSubtitle { get; set; } = false;
|
||||||
public string? BinPath { get; set; }
|
public string? BinPath { get; set; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
using N_m3u8DL_RE.Common.Enum;
|
using N_m3u8DL_RE.Common.Enum;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Entity
|
namespace N_m3u8DL_RE.Entity;
|
||||||
{
|
|
||||||
internal class OutputFile
|
internal class OutputFile
|
||||||
{
|
{
|
||||||
public MediaType? MediaType { get; set; }
|
public MediaType? MediaType { get; set; }
|
||||||
|
@ -16,4 +11,3 @@ namespace N_m3u8DL_RE.Entity
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
public List<Mediainfo> Mediainfos { get; set; } = new();
|
public List<Mediainfo> Mediainfos { get; set; } = new();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -7,18 +7,18 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Entity
|
namespace N_m3u8DL_RE.Entity;
|
||||||
{
|
|
||||||
internal class SpeedContainer
|
internal class SpeedContainer
|
||||||
{
|
{
|
||||||
public bool SingleSegment { get; set; } = false;
|
public bool SingleSegment { get; set; } = false;
|
||||||
public long NowSpeed { get; set; } = 0L; // 当前每秒速度
|
public long NowSpeed { get; set; } = 0L; // 当前每秒速度
|
||||||
public long SpeedLimit { get; set; } = long.MaxValue; // 限速设置
|
public long SpeedLimit { get; set; } = long.MaxValue; // 限速设置
|
||||||
public long? ResponseLength { get; set; }
|
public long? ResponseLength { get; set; }
|
||||||
public long RDownloaded { get => _Rdownloaded; }
|
public long RDownloaded => _Rdownloaded;
|
||||||
private int _zeroSpeedCount = 0;
|
private int _zeroSpeedCount = 0;
|
||||||
public int LowSpeedCount { get => _zeroSpeedCount; }
|
public int LowSpeedCount => _zeroSpeedCount;
|
||||||
public bool ShouldStop { get => LowSpeedCount >= 20; }
|
public bool ShouldStop => LowSpeedCount >= 20;
|
||||||
|
|
||||||
///////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -56,4 +56,3 @@ namespace N_m3u8DL_RE.Entity
|
||||||
_Rdownloaded = 0L;
|
_Rdownloaded = 0L;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
using N_m3u8DL_RE.Common.Enum;
|
using N_m3u8DL_RE.Common.Enum;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Entity
|
namespace N_m3u8DL_RE.Entity;
|
||||||
{
|
|
||||||
public class StreamFilter
|
public class StreamFilter
|
||||||
{
|
{
|
||||||
public Regex? GroupIdReg { get; set; }
|
public Regex? GroupIdReg { get; set; }
|
||||||
|
@ -53,4 +49,3 @@ namespace N_m3u8DL_RE.Entity
|
||||||
return sb.ToString() + $"For: {For}";
|
return sb.ToString() + $"For: {For}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -2,14 +2,9 @@
|
||||||
using N_m3u8DL_RE.Common.Log;
|
using N_m3u8DL_RE.Common.Log;
|
||||||
using N_m3u8DL_RE.Parser.Config;
|
using N_m3u8DL_RE.Parser.Config;
|
||||||
using N_m3u8DL_RE.Parser.Processor;
|
using N_m3u8DL_RE.Parser.Processor;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Processor
|
namespace N_m3u8DL_RE.Processor;
|
||||||
{
|
|
||||||
internal class DemoProcessor : ContentProcessor
|
internal class DemoProcessor : ContentProcessor
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -24,4 +19,3 @@ namespace N_m3u8DL_RE.Processor
|
||||||
return rawText;
|
return rawText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -5,14 +5,9 @@ using N_m3u8DL_RE.Common.Util;
|
||||||
using N_m3u8DL_RE.Parser.Config;
|
using N_m3u8DL_RE.Parser.Config;
|
||||||
using N_m3u8DL_RE.Parser.Processor;
|
using N_m3u8DL_RE.Parser.Processor;
|
||||||
using N_m3u8DL_RE.Parser.Processor.HLS;
|
using N_m3u8DL_RE.Parser.Processor.HLS;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Processor
|
namespace N_m3u8DL_RE.Processor;
|
||||||
{
|
|
||||||
internal class DemoProcessor2 : KeyProcessor
|
internal class DemoProcessor2 : KeyProcessor
|
||||||
{
|
{
|
||||||
public override bool CanProcess(ExtractorType extractorType, string keyLine, string m3u8Url, string m3u8Content, ParserConfig parserConfig)
|
public override bool CanProcess(ExtractorType extractorType, string keyLine, string m3u8Url, string m3u8Content, ParserConfig parserConfig)
|
||||||
|
@ -28,4 +23,3 @@ namespace N_m3u8DL_RE.Processor
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -6,16 +6,9 @@ using N_m3u8DL_RE.Parser.Util;
|
||||||
using NiL.JS.BaseLibrary;
|
using NiL.JS.BaseLibrary;
|
||||||
using NiL.JS.Core;
|
using NiL.JS.Core;
|
||||||
using NiL.JS.Extensions;
|
using NiL.JS.Extensions;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Processor
|
namespace N_m3u8DL_RE.Processor;
|
||||||
{
|
|
||||||
// "https://1429754964.rsc.cdn77.org/r/nh22/2022/VNUS_DE_NYKE/19_07_22_2302_skt/h264.mpd?secure=mSvVfvuciJt9wufUyzuBnA==,1658505709774" --urlprocessor-args "nowehoryzonty:timeDifference=-2274,filminfo.secureToken=vx54axqjal4f0yy2"
|
// "https://1429754964.rsc.cdn77.org/r/nh22/2022/VNUS_DE_NYKE/19_07_22_2302_skt/h264.mpd?secure=mSvVfvuciJt9wufUyzuBnA==,1658505709774" --urlprocessor-args "nowehoryzonty:timeDifference=-2274,filminfo.secureToken=vx54axqjal4f0yy2"
|
||||||
internal class NowehoryzontyUrlProcessor : UrlProcessor
|
internal class NowehoryzontyUrlProcessor : UrlProcessor
|
||||||
{
|
{
|
||||||
|
@ -221,4 +214,3 @@ namespace N_m3u8DL_RE.Processor
|
||||||
|
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ using N_m3u8DL_RE.CommandLine;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE
|
namespace N_m3u8DL_RE;
|
||||||
{
|
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
static async Task Main(string[] args)
|
static async Task Main(string[] args)
|
||||||
|
@ -78,7 +78,7 @@ namespace N_m3u8DL_RE
|
||||||
}
|
}
|
||||||
CustomAnsiConsole.InitConsole(option.ForceAnsiConsole, option.NoAnsiColor);
|
CustomAnsiConsole.InitConsole(option.ForceAnsiConsole, option.NoAnsiColor);
|
||||||
// 检测更新
|
// 检测更新
|
||||||
CheckUpdateAsync();
|
_ = CheckUpdateAsync();
|
||||||
|
|
||||||
Logger.IsWriteFile = !option.NoLog;
|
Logger.IsWriteFile = !option.NoLog;
|
||||||
Logger.InitLogFile();
|
Logger.InitLogFile();
|
||||||
|
@ -305,7 +305,7 @@ namespace N_m3u8DL_RE
|
||||||
}
|
}
|
||||||
|
|
||||||
// 无法识别的加密方式,自动开启二进制合并
|
// 无法识别的加密方式,自动开启二进制合并
|
||||||
if (selectedStreams.Any(s => s.Playlist.MediaParts.Any(p => p.MediaSegments.Any(m => m.EncryptInfo.Method == EncryptMethod.UNKNOWN))))
|
if (selectedStreams.Any(s => s.Playlist!.MediaParts.Any(p => p.MediaSegments.Any(m => m.EncryptInfo.Method == EncryptMethod.UNKNOWN))))
|
||||||
{
|
{
|
||||||
Logger.WarnMarkUp($"[darkorange3_1]{ResString.autoBinaryMerge3}[/]");
|
Logger.WarnMarkUp($"[darkorange3_1]{ResString.autoBinaryMerge3}[/]");
|
||||||
option.BinaryMerge = true;
|
option.BinaryMerge = true;
|
||||||
|
@ -449,4 +449,3 @@ namespace N_m3u8DL_RE
|
||||||
return redirectedUrl;
|
return redirectedUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -2,8 +2,6 @@
|
||||||
using N_m3u8DL_RE.Common.Resource;
|
using N_m3u8DL_RE.Common.Resource;
|
||||||
using N_m3u8DL_RE.Common.Util;
|
using N_m3u8DL_RE.Common.Util;
|
||||||
using N_m3u8DL_RE.Entity;
|
using N_m3u8DL_RE.Entity;
|
||||||
using System.IO;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Util;
|
namespace N_m3u8DL_RE.Util;
|
||||||
|
|
|
@ -4,12 +4,7 @@ using N_m3u8DL_RE.Common.Log;
|
||||||
using N_m3u8DL_RE.Common.Resource;
|
using N_m3u8DL_RE.Common.Resource;
|
||||||
using N_m3u8DL_RE.Entity;
|
using N_m3u8DL_RE.Entity;
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Util;
|
namespace N_m3u8DL_RE.Util;
|
||||||
|
|
||||||
|
@ -17,7 +12,7 @@ public static class FilterUtil
|
||||||
{
|
{
|
||||||
public static List<StreamSpec> DoFilterKeep(IEnumerable<StreamSpec> lists, StreamFilter? filter)
|
public static List<StreamSpec> DoFilterKeep(IEnumerable<StreamSpec> lists, StreamFilter? filter)
|
||||||
{
|
{
|
||||||
if (filter == null) return new List<StreamSpec>();
|
if (filter == null) return [];
|
||||||
|
|
||||||
var inputs = lists.Where(_ => true);
|
var inputs = lists.Where(_ => true);
|
||||||
if (filter.GroupIdReg != null)
|
if (filter.GroupIdReg != null)
|
||||||
|
@ -56,13 +51,13 @@ public static class FilterUtil
|
||||||
var bestNumberStr = filter.For.Replace("best", "");
|
var bestNumberStr = filter.For.Replace("best", "");
|
||||||
var worstNumberStr = filter.For.Replace("worst", "");
|
var worstNumberStr = filter.For.Replace("worst", "");
|
||||||
|
|
||||||
if (filter.For == "best" && inputs.Count() > 0)
|
if (filter.For == "best" && inputs.Any())
|
||||||
inputs = inputs.Take(1).ToList();
|
inputs = inputs.Take(1).ToList();
|
||||||
else if (filter.For == "worst" && inputs.Count() > 0)
|
else if (filter.For == "worst" && inputs.Any())
|
||||||
inputs = inputs.TakeLast(1).ToList();
|
inputs = inputs.TakeLast(1).ToList();
|
||||||
else if (int.TryParse(bestNumberStr, out int bestNumber) && inputs.Count() > 0)
|
else if (int.TryParse(bestNumberStr, out int bestNumber) && inputs.Any())
|
||||||
inputs = inputs.Take(bestNumber).ToList();
|
inputs = inputs.Take(bestNumber).ToList();
|
||||||
else if (int.TryParse(worstNumberStr, out int worstNumber) && inputs.Count() > 0)
|
else if (int.TryParse(worstNumberStr, out int worstNumber) && inputs.Any())
|
||||||
inputs = inputs.TakeLast(worstNumber).ToList();
|
inputs = inputs.TakeLast(worstNumber).ToList();
|
||||||
|
|
||||||
return inputs.ToList();
|
return inputs.ToList();
|
||||||
|
@ -82,15 +77,16 @@ public static class FilterUtil
|
||||||
|
|
||||||
public static List<StreamSpec> SelectStreams(IEnumerable<StreamSpec> lists)
|
public static List<StreamSpec> SelectStreams(IEnumerable<StreamSpec> lists)
|
||||||
{
|
{
|
||||||
if (lists.Count() == 1)
|
var streamSpecs = lists.ToList();
|
||||||
return new List<StreamSpec>(lists);
|
if (streamSpecs.Count == 1)
|
||||||
|
return [..streamSpecs];
|
||||||
|
|
||||||
// 基本流
|
// 基本流
|
||||||
var basicStreams = lists.Where(x => x.MediaType == null);
|
var basicStreams = streamSpecs.Where(x => x.MediaType == null).ToList();
|
||||||
// 可选音频轨道
|
// 可选音频轨道
|
||||||
var audios = lists.Where(x => x.MediaType == MediaType.AUDIO);
|
var audios = streamSpecs.Where(x => x.MediaType == MediaType.AUDIO).ToList();
|
||||||
// 可选字幕轨道
|
// 可选字幕轨道
|
||||||
var subs = lists.Where(x => x.MediaType == MediaType.SUBTITLES);
|
var subs = streamSpecs.Where(x => x.MediaType == MediaType.SUBTITLES).ToList();
|
||||||
|
|
||||||
var prompt = new MultiSelectionPrompt<StreamSpec>()
|
var prompt = new MultiSelectionPrompt<StreamSpec>()
|
||||||
.Title(ResString.promptTitle)
|
.Title(ResString.promptTitle)
|
||||||
|
@ -108,7 +104,7 @@ public static class FilterUtil
|
||||||
;
|
;
|
||||||
|
|
||||||
// 默认选中第一个
|
// 默认选中第一个
|
||||||
var first = lists.First();
|
var first = streamSpecs.First();
|
||||||
prompt.Select(first);
|
prompt.Select(first);
|
||||||
|
|
||||||
if (basicStreams.Any())
|
if (basicStreams.Any())
|
||||||
|
@ -147,7 +143,7 @@ public static class FilterUtil
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 直播使用。对齐各个轨道的起始。
|
/// 直播使用。对齐各个轨道的起始。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="streams"></param>
|
/// <param name="selectedSteams"></param>
|
||||||
/// <param name="takeLastCount"></param>
|
/// <param name="takeLastCount"></param>
|
||||||
public static void SyncStreams(List<StreamSpec> selectedSteams, int takeLastCount = 15)
|
public static void SyncStreams(List<StreamSpec> selectedSteams, int takeLastCount = 15)
|
||||||
{
|
{
|
||||||
|
@ -198,17 +194,15 @@ public static class FilterUtil
|
||||||
/// <param name="customRange"></param>
|
/// <param name="customRange"></param>
|
||||||
public static void ApplyCustomRange(List<StreamSpec> selectedSteams, CustomRange? customRange)
|
public static void ApplyCustomRange(List<StreamSpec> selectedSteams, CustomRange? customRange)
|
||||||
{
|
{
|
||||||
var resultList = selectedSteams.Select(x => 0d).ToList();
|
|
||||||
|
|
||||||
if (customRange == null) return;
|
if (customRange == null) return;
|
||||||
|
|
||||||
Logger.InfoMarkUp($"{ResString.customRangeFound}[Cyan underline]{customRange.InputStr}[/]");
|
Logger.InfoMarkUp($"{ResString.customRangeFound}[Cyan underline]{customRange.InputStr}[/]");
|
||||||
Logger.WarnMarkUp($"[darkorange3_1]{ResString.customRangeWarn}[/]");
|
Logger.WarnMarkUp($"[darkorange3_1]{ResString.customRangeWarn}[/]");
|
||||||
|
|
||||||
var filteByIndex = customRange.StartSegIndex != null && customRange.EndSegIndex != null;
|
var filterByIndex = customRange is { StartSegIndex: not null, EndSegIndex: not null };
|
||||||
var filteByTime = customRange.StartSec != null && customRange.EndSec != null;
|
var filterByTime = customRange is { StartSec: not null, EndSec: not null };
|
||||||
|
|
||||||
if (!filteByIndex && !filteByTime)
|
if (!filterByIndex && !filterByTime)
|
||||||
{
|
{
|
||||||
Logger.ErrorMarkUp(ResString.customRangeInvalid);
|
Logger.ErrorMarkUp(ResString.customRangeInvalid);
|
||||||
return;
|
return;
|
||||||
|
@ -220,8 +214,8 @@ public static class FilterUtil
|
||||||
if (stream.Playlist == null) continue;
|
if (stream.Playlist == null) continue;
|
||||||
foreach (var part in stream.Playlist.MediaParts)
|
foreach (var part in stream.Playlist.MediaParts)
|
||||||
{
|
{
|
||||||
var newSegments = new List<MediaSegment>();
|
List<MediaSegment> newSegments;
|
||||||
if (filteByIndex)
|
if (filterByIndex)
|
||||||
newSegments = part.MediaSegments.Where(seg => seg.Index >= customRange.StartSegIndex && seg.Index <= customRange.EndSegIndex).ToList();
|
newSegments = part.MediaSegments.Where(seg => seg.Index >= customRange.StartSegIndex && seg.Index <= customRange.EndSegIndex).ToList();
|
||||||
else
|
else
|
||||||
newSegments = part.MediaSegments.Where(seg => stream.Playlist.MediaParts.SelectMany(p => p.MediaSegments).Where(x => x.Index < seg.Index).Sum(x => x.Duration) >= customRange.StartSec
|
newSegments = part.MediaSegments.Where(seg => stream.Playlist.MediaParts.SelectMany(p => p.MediaSegments).Where(x => x.Index < seg.Index).Sum(x => x.Duration) >= customRange.StartSec
|
||||||
|
@ -239,11 +233,11 @@ public static class FilterUtil
|
||||||
/// 根据用户输入,清除广告分片
|
/// 根据用户输入,清除广告分片
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="selectedSteams"></param>
|
/// <param name="selectedSteams"></param>
|
||||||
/// <param name="customRange"></param>
|
/// <param name="keywords"></param>
|
||||||
public static void CleanAd(List<StreamSpec> selectedSteams, string[]? keywords)
|
public static void CleanAd(List<StreamSpec> selectedSteams, string[]? keywords)
|
||||||
{
|
{
|
||||||
if (keywords == null) return;
|
if (keywords == null) return;
|
||||||
var regList = keywords.Select(s => new Regex(s));
|
var regList = keywords.Select(s => new Regex(s)).ToList();
|
||||||
foreach ( var reg in regList)
|
foreach ( var reg in regList)
|
||||||
{
|
{
|
||||||
Logger.InfoMarkUp($"{ResString.customAdKeywordsFound}[Cyan underline]{reg}[/]");
|
Logger.InfoMarkUp($"{ResString.customAdKeywordsFound}[Cyan underline]{reg}[/]");
|
||||||
|
@ -263,11 +257,8 @@ public static class FilterUtil
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 找到广告分片 清理
|
// 找到广告分片 清理
|
||||||
else
|
|
||||||
{
|
|
||||||
part.MediaSegments = part.MediaSegments.Where(x => regList.All(reg => !reg.IsMatch(x.Url))).ToList();
|
part.MediaSegments = part.MediaSegments.Where(x => regList.All(reg => !reg.IsMatch(x.Url))).ToList();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 清理已经为空的 part
|
// 清理已经为空的 part
|
||||||
stream.Playlist.MediaParts = stream.Playlist.MediaParts.Where(x => x.MediaSegments.Count > 0).ToList();
|
stream.Playlist.MediaParts = stream.Playlist.MediaParts.Where(x => x.MediaSegments.Count > 0).ToList();
|
||||||
|
|
|
@ -9,13 +9,13 @@ internal static class ImageHeaderUtil
|
||||||
if (size > 3 && 137 == bArr[0] && 80 == bArr[1] && 78 == bArr[2] && 71 == bArr[3])
|
if (size > 3 && 137 == bArr[0] && 80 == bArr[1] && 78 == bArr[2] && 71 == bArr[3])
|
||||||
return true;
|
return true;
|
||||||
// GIF HEADER检测
|
// GIF HEADER检测
|
||||||
else if (size > 3 && 0x47 == bArr[0] && 0x49 == bArr[1] && 0x46 == bArr[2] && 0x38 == bArr[3])
|
if (size > 3 && 0x47 == bArr[0] && 0x49 == bArr[1] && 0x46 == bArr[2] && 0x38 == bArr[3])
|
||||||
return true;
|
return true;
|
||||||
// BMP HEADER检测
|
// BMP HEADER检测
|
||||||
else if (size > 10 && 0x42 == bArr[0] && 0x4D == bArr[1] && 0x00 == bArr[5] && 0x00 == bArr[6] && 0x00 == bArr[7] && 0x00 == bArr[8])
|
if (size > 10 && 0x42 == bArr[0] && 0x4D == bArr[1] && 0x00 == bArr[5] && 0x00 == bArr[6] && 0x00 == bArr[7] && 0x00 == bArr[8])
|
||||||
return true;
|
return true;
|
||||||
// JPEG HEADER检测
|
// JPEG HEADER检测
|
||||||
else if (size > 3 && 0xFF == bArr[0] && 0xD8 == bArr[1] && 0xFF == bArr[2])
|
if (size > 3 && 0xFF == bArr[0] && 0xD8 == bArr[1] && 0xFF == bArr[2])
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,19 @@
|
||||||
using N_m3u8DL_RE.Entity;
|
using N_m3u8DL_RE.Entity;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Util;
|
namespace N_m3u8DL_RE.Util;
|
||||||
|
|
||||||
class Language
|
internal class Language(string extendCode, string code, string desc, string descA)
|
||||||
{
|
{
|
||||||
public string Code;
|
public readonly string Code = code;
|
||||||
public string ExtendCode;
|
public readonly string ExtendCode = extendCode;
|
||||||
public string Description;
|
public readonly string Description = desc;
|
||||||
public string DescriptionAudio;
|
public readonly string DescriptionAudio = descA;
|
||||||
|
|
||||||
public Language(string extendCode, string code, string desc, string descA)
|
|
||||||
{
|
|
||||||
Code = code;
|
|
||||||
ExtendCode = extendCode;
|
|
||||||
Description = desc;
|
|
||||||
DescriptionAudio = descA;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class LanguageCodeUtil
|
internal static class LanguageCodeUtil
|
||||||
{
|
{
|
||||||
|
|
||||||
private readonly static List<Language> ALL_LANGS = @"
|
private static readonly List<Language> ALL_LANGS = @"
|
||||||
af;afr;Afrikaans;Afrikaans
|
af;afr;Afrikaans;Afrikaans
|
||||||
af-ZA;afr;Afrikaans (South Africa);Afrikaans (South Africa)
|
af-ZA;afr;Afrikaans (South Africa);Afrikaans (South Africa)
|
||||||
am;amh;Amharic;Amharic
|
am;amh;Amharic;Amharic
|
||||||
|
@ -389,8 +375,8 @@ MA;msa;Melayu;Melayu
|
||||||
"
|
"
|
||||||
.Trim().Replace("\r", "").Split('\n').Where(x => !string.IsNullOrWhiteSpace(x)).Select(x =>
|
.Trim().Replace("\r", "").Split('\n').Where(x => !string.IsNullOrWhiteSpace(x)).Select(x =>
|
||||||
{
|
{
|
||||||
var arr = x.Trim().Split(';');
|
var arr = x.Trim().Split(';', StringSplitOptions.TrimEntries);
|
||||||
return new Language(arr[0].Trim(), arr[1].Trim(), arr[2].Trim(), arr[3].Trim());
|
return new Language(arr[0], arr[1], arr[2], arr[3]);
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
private static Dictionary<string, string> CODE_MAP = @"
|
private static Dictionary<string, string> CODE_MAP = @"
|
||||||
|
@ -504,8 +490,7 @@ sr;srp
|
||||||
|
|
||||||
private static string ConvertTwoToThree(string input)
|
private static string ConvertTwoToThree(string input)
|
||||||
{
|
{
|
||||||
if (CODE_MAP.TryGetValue(input, out var code)) return code;
|
return CODE_MAP.GetValueOrDefault(input, input);
|
||||||
return input;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
using N_m3u8DL_RE.Common.Entity;
|
using N_m3u8DL_RE.Common.Entity;
|
||||||
using N_m3u8DL_RE.Common.Log;
|
using N_m3u8DL_RE.Common.Log;
|
||||||
using N_m3u8DL_RE.Common.Util;
|
using N_m3u8DL_RE.Common.Util;
|
||||||
using NiL.JS.Expressions;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Util;
|
namespace N_m3u8DL_RE.Util;
|
||||||
|
|
||||||
|
@ -15,17 +8,16 @@ internal static class LargeSingleFileSplitUtil
|
||||||
{
|
{
|
||||||
class Clip
|
class Clip
|
||||||
{
|
{
|
||||||
public required int index;
|
public required int Index;
|
||||||
public required long from;
|
public required long From;
|
||||||
public required long to;
|
public required long To;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// URL大文件切片处理
|
/// URL大文件切片处理
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="url"></param>
|
/// <param name="segment"></param>
|
||||||
/// <param name="headers"></param>
|
/// <param name="headers"></param>
|
||||||
/// <param name="splitSegments"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<List<MediaSegment>?> SplitUrlAsync(MediaSegment segment, Dictionary<string,string> headers)
|
public static async Task<List<MediaSegment>?> SplitUrlAsync(MediaSegment segment, Dictionary<string,string> headers)
|
||||||
{
|
{
|
||||||
|
@ -43,10 +35,10 @@ internal static class LargeSingleFileSplitUtil
|
||||||
{
|
{
|
||||||
splitSegments.Add(new MediaSegment()
|
splitSegments.Add(new MediaSegment()
|
||||||
{
|
{
|
||||||
Index = clip.index,
|
Index = clip.Index,
|
||||||
Url = url,
|
Url = url,
|
||||||
StartRange = clip.from,
|
StartRange = clip.From,
|
||||||
ExpectLength = clip.to == -1 ? null : clip.to - clip.from + 1,
|
ExpectLength = clip.To == -1 ? null : clip.To - clip.From + 1,
|
||||||
EncryptInfo = segment.EncryptInfo,
|
EncryptInfo = segment.EncryptInfo,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -96,9 +88,9 @@ internal static class LargeSingleFileSplitUtil
|
||||||
{
|
{
|
||||||
Clip c = new()
|
Clip c = new()
|
||||||
{
|
{
|
||||||
index = index,
|
Index = index,
|
||||||
from = counter,
|
From = counter,
|
||||||
to = counter + perSize
|
To = counter + perSize
|
||||||
};
|
};
|
||||||
// 没到最后
|
// 没到最后
|
||||||
if (fileSize - perSize > 0)
|
if (fileSize - perSize > 0)
|
||||||
|
@ -111,7 +103,7 @@ internal static class LargeSingleFileSplitUtil
|
||||||
// 已到最后
|
// 已到最后
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
c.to = -1;
|
c.To = -1;
|
||||||
clips.Add(c);
|
clips.Add(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace N_m3u8DL_RE.Util;
|
||||||
|
|
||||||
internal static class MP4DecryptUtil
|
internal static class MP4DecryptUtil
|
||||||
{
|
{
|
||||||
private static string ZeroKid = "00000000000000000000000000000000";
|
private static readonly string ZeroKid = "00000000000000000000000000000000";
|
||||||
public static async Task<bool> DecryptAsync(bool shakaPackager, string bin, string[]? keys, string source, string dest, string? kid, string init = "", bool isMultiDRM=false)
|
public static async Task<bool> DecryptAsync(bool shakaPackager, string bin, string[]? keys, string source, string dest, string? kid, string init = "", bool isMultiDRM=false)
|
||||||
{
|
{
|
||||||
if (keys == null || keys.Length == 0) return false;
|
if (keys == null || keys.Length == 0) return false;
|
||||||
|
@ -25,7 +25,7 @@ internal static class MP4DecryptUtil
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(kid))
|
if (!string.IsNullOrEmpty(kid))
|
||||||
{
|
{
|
||||||
var test = keyPairs.Where(k => k.StartsWith(kid));
|
var test = keyPairs.Where(k => k.StartsWith(kid)).ToList();
|
||||||
if (test.Any()) keyPair = test.First();
|
if (test.Any()) keyPair = test.First();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ internal static class MP4DecryptUtil
|
||||||
// shakaPackager 无法单独解密init文件
|
// shakaPackager 无法单独解密init文件
|
||||||
if (source.EndsWith("_init.mp4") && shakaPackager) return false;
|
if (source.EndsWith("_init.mp4") && shakaPackager) return false;
|
||||||
|
|
||||||
var cmd = "";
|
string cmd;
|
||||||
|
|
||||||
var tmpFile = "";
|
var tmpFile = "";
|
||||||
if (shakaPackager)
|
if (shakaPackager)
|
||||||
|
@ -124,8 +124,7 @@ internal static class MP4DecryptUtil
|
||||||
Logger.InfoMarkUp(ResString.searchKey);
|
Logger.InfoMarkUp(ResString.searchKey);
|
||||||
using var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
|
using var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
using var reader = new StreamReader(stream);
|
using var reader = new StreamReader(stream);
|
||||||
var line = "";
|
while (await reader.ReadLineAsync() is { } line)
|
||||||
while ((line = await reader.ReadLineAsync()) != null)
|
|
||||||
{
|
{
|
||||||
if (line.Trim().StartsWith(kid))
|
if (line.Trim().StartsWith(kid))
|
||||||
{
|
{
|
||||||
|
@ -152,17 +151,15 @@ internal static class MP4DecryptUtil
|
||||||
|
|
||||||
public static ParsedMP4Info GetMP4Info(string output)
|
public static ParsedMP4Info GetMP4Info(string output)
|
||||||
{
|
{
|
||||||
using (var fs = File.OpenRead(output))
|
using var fs = File.OpenRead(output);
|
||||||
{
|
|
||||||
var header = new byte[1 * 1024 * 1024]; // 1MB
|
var header = new byte[1 * 1024 * 1024]; // 1MB
|
||||||
fs.Read(header);
|
fs.Read(header);
|
||||||
return GetMP4Info(header);
|
return GetMP4Info(header);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static string? ReadInitShaka(string output, string bin)
|
public static string? ReadInitShaka(string output, string bin)
|
||||||
{
|
{
|
||||||
Regex ShakaKeyIDRegex = new Regex("Key for key_id=([0-9a-f]+) was not found");
|
Regex shakaKeyIdRegex = new("Key for key_id=([0-9a-f]+) was not found");
|
||||||
|
|
||||||
// TODO: handle the case that shaka packager actually decrypted (key ID == ZeroKid)
|
// TODO: handle the case that shaka packager actually decrypted (key ID == ZeroKid)
|
||||||
// - stop process
|
// - stop process
|
||||||
|
@ -182,6 +179,6 @@ internal static class MP4DecryptUtil
|
||||||
p.Start();
|
p.Start();
|
||||||
var errorOutput = p.StandardError.ReadToEnd();
|
var errorOutput = p.StandardError.ReadToEnd();
|
||||||
p.WaitForExit();
|
p.WaitForExit();
|
||||||
return ShakaKeyIDRegex.Match(errorOutput).Groups[1].Value;
|
return shakaKeyIdRegex.Match(errorOutput).Groups[1].Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,6 @@
|
||||||
using N_m3u8DL_RE.Entity;
|
using N_m3u8DL_RE.Entity;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Util;
|
namespace N_m3u8DL_RE.Util;
|
||||||
|
|
||||||
|
@ -48,7 +42,7 @@ internal static partial class MediainfoUtil
|
||||||
RedirectStandardError = true,
|
RedirectStandardError = true,
|
||||||
UseShellExecute = false
|
UseShellExecute = false
|
||||||
})!;
|
})!;
|
||||||
var output = p.StandardError.ReadToEnd();
|
var output = await p.StandardError.ReadToEndAsync();
|
||||||
await p.WaitForExitAsync();
|
await p.WaitForExitAsync();
|
||||||
|
|
||||||
foreach (Match stream in TextRegex().Matches(output))
|
foreach (Match stream in TextRegex().Matches(output))
|
||||||
|
@ -87,7 +81,7 @@ internal static partial class MediainfoUtil
|
||||||
|
|
||||||
if (result.Count == 0)
|
if (result.Count == 0)
|
||||||
{
|
{
|
||||||
result.Add(new Mediainfo()
|
result.Add(new Mediainfo
|
||||||
{
|
{
|
||||||
Type = "Unknown"
|
Type = "Unknown"
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,20 +27,16 @@ internal static class MergeUtil
|
||||||
if (!Directory.Exists(Path.GetDirectoryName(outputFilePath)))
|
if (!Directory.Exists(Path.GetDirectoryName(outputFilePath)))
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(outputFilePath)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(outputFilePath)!);
|
||||||
|
|
||||||
string[] inputFilePaths = files;
|
var inputFilePaths = files;
|
||||||
using (var outputStream = File.Create(outputFilePath))
|
using var outputStream = File.Create(outputFilePath);
|
||||||
{
|
|
||||||
foreach (var inputFilePath in inputFilePaths)
|
foreach (var inputFilePath in inputFilePaths)
|
||||||
{
|
{
|
||||||
if (inputFilePath == "")
|
if (inputFilePath == "")
|
||||||
continue;
|
continue;
|
||||||
using (var inputStream = File.OpenRead(inputFilePath))
|
using var inputStream = File.OpenRead(inputFilePath);
|
||||||
{
|
|
||||||
inputStream.CopyTo(outputStream);
|
inputStream.CopyTo(outputStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int InvokeFFmpeg(string binary, string command, string workingDirectory)
|
private static int InvokeFFmpeg(string binary, string command, string workingDirectory)
|
||||||
{
|
{
|
||||||
|
@ -85,7 +81,7 @@ internal static class MergeUtil
|
||||||
string[][] li = Enumerable.Range(0, files.Count() / div + 1).Select(x => files.Skip(x * div).Take(div).ToArray()).ToArray();
|
string[][] li = Enumerable.Range(0, files.Count() / div + 1).Select(x => files.Skip(x * div).Take(div).ToArray()).ToArray();
|
||||||
foreach (var items in li)
|
foreach (var items in li)
|
||||||
{
|
{
|
||||||
if (items.Count() == 0)
|
if (!items.Any())
|
||||||
continue;
|
continue;
|
||||||
var output = outputName + index.ToString("0000") + ".ts";
|
var output = outputName + index.ToString("0000") + ".ts";
|
||||||
CombineMultipleFilesIntoSingleFile(items, output);
|
CombineMultipleFilesIntoSingleFile(items, output);
|
||||||
|
|
|
@ -1,21 +1,16 @@
|
||||||
using N_m3u8DL_RE.Common.Entity;
|
using N_m3u8DL_RE.Enum;
|
||||||
using N_m3u8DL_RE.Common.Log;
|
|
||||||
using N_m3u8DL_RE.Enum;
|
|
||||||
using System.CommandLine;
|
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Util;
|
namespace N_m3u8DL_RE.Util;
|
||||||
|
|
||||||
internal class OtherUtil
|
internal static class OtherUtil
|
||||||
{
|
{
|
||||||
public static Dictionary<string, string> SplitHeaderArrayToDic(string[]? headers)
|
public static Dictionary<string, string> SplitHeaderArrayToDic(string[]? headers)
|
||||||
{
|
{
|
||||||
Dictionary<string, string> dic = new();
|
Dictionary<string, string> dic = new();
|
||||||
|
if (headers == null) return dic;
|
||||||
|
|
||||||
if (headers != null)
|
|
||||||
{
|
|
||||||
foreach (string header in headers)
|
foreach (string header in headers)
|
||||||
{
|
{
|
||||||
var index = header.IndexOf(':');
|
var index = header.IndexOf(':');
|
||||||
|
@ -24,12 +19,11 @@ internal class OtherUtil
|
||||||
dic[header[..index].Trim().ToLower()] = header[(index + 1)..].Trim();
|
dic[header[..index].Trim().ToLower()] = header[(index + 1)..].Trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return dic;
|
return dic;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static char[] InvalidChars = "34,60,62,124,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,58,42,63,92,47"
|
private static readonly char[] InvalidChars = "34,60,62,124,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,58,42,63,92,47"
|
||||||
.Split(',').Select(s => (char)int.Parse(s)).ToArray();
|
.Split(',').Select(s => (char)int.Parse(s)).ToArray();
|
||||||
public static string GetValidFileName(string input, string re = ".", bool filterSlash = false)
|
public static string GetValidFileName(string input, string re = ".", bool filterSlash = false)
|
||||||
{
|
{
|
||||||
|
@ -50,6 +44,7 @@ internal class OtherUtil
|
||||||
/// 从输入自动获取文件名
|
/// 从输入自动获取文件名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input"></param>
|
/// <param name="input"></param>
|
||||||
|
/// <param name="addSuffix"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GetFileNameFromInput(string input, bool addSuffix = true)
|
public static string GetFileNameFromInput(string input, bool addSuffix = true)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,14 +1,8 @@
|
||||||
using N_m3u8DL_RE.Common.Log;
|
using N_m3u8DL_RE.Common.Log;
|
||||||
using N_m3u8DL_RE.Common.Resource;
|
|
||||||
using Spectre.Console;
|
using Spectre.Console;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.CommandLine;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO.Pipes;
|
using System.IO.Pipes;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Util;
|
namespace N_m3u8DL_RE.Util;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
using N_m3u8DL_RE.Common.Entity;
|
using N_m3u8DL_RE.Common.Entity;
|
||||||
using N_m3u8DL_RE.Common.Log;
|
using N_m3u8DL_RE.Common.Log;
|
||||||
using N_m3u8DL_RE.Common.Resource;
|
using N_m3u8DL_RE.Common.Resource;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_RE.Util;
|
namespace N_m3u8DL_RE.Util;
|
||||||
|
|
||||||
|
@ -17,23 +12,21 @@ internal static class SubtitleUtil
|
||||||
/// <param name="finalVtt"></param>
|
/// <param name="finalVtt"></param>
|
||||||
/// <param name="tmpDir">临时目录</param>
|
/// <param name="tmpDir">临时目录</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<bool> TryWriteImagePngsAsync(WebVttSub? finalVtt, string tmpDir)
|
public static async Task TryWriteImagePngsAsync(WebVttSub? finalVtt, string tmpDir)
|
||||||
{
|
{
|
||||||
if (finalVtt != null && finalVtt.Cues.Any(v => v.Payload.StartsWith("Base64::")))
|
if (finalVtt != null && finalVtt.Cues.Any(v => v.Payload.StartsWith("Base64::")))
|
||||||
{
|
{
|
||||||
Logger.WarnMarkUp(ResString.processImageSub);
|
Logger.WarnMarkUp(ResString.processImageSub);
|
||||||
var _i = 0;
|
var i = 0;
|
||||||
foreach (var img in finalVtt.Cues.Where(v => v.Payload.StartsWith("Base64::")))
|
foreach (var img in finalVtt.Cues.Where(v => v.Payload.StartsWith("Base64::")))
|
||||||
{
|
{
|
||||||
var name = $"{_i++}.png";
|
var name = $"{i++}.png";
|
||||||
var dest = "";
|
var dest = "";
|
||||||
for (; File.Exists(dest = Path.Combine(tmpDir, name)); name = $"{_i++}.png") ;
|
for (; File.Exists(dest = Path.Combine(tmpDir, name)); name = $"{i++}.png") ;
|
||||||
var base64 = img.Payload[8..];
|
var base64 = img.Payload[8..];
|
||||||
await File.WriteAllBytesAsync(dest, Convert.FromBase64String(base64));
|
await File.WriteAllBytesAsync(dest, Convert.FromBase64String(base64));
|
||||||
img.Payload = name;
|
img.Payload = name;
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
else return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue