From fa7ff57fae4c471ce45424badd5389fce5c99f27 Mon Sep 17 00:00:00 2001
From: nilaoda <nilaoda@live.com>
Date: Mon, 19 Dec 2022 15:29:18 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=A7=A3=E5=AF=86=E9=80=BB?=
 =?UTF-8?q?=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../HLS/DefaultHLSContentProcessor.cs         |  4 ++-
 .../Downloader/SimpleDownloader.cs            |  9 +++++-
 src/N_m3u8DL-RE/Util/MP4DecryptUtil.cs        | 28 +++++++++++++++----
 3 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/src/N_m3u8DL-RE.Parser/Processor/HLS/DefaultHLSContentProcessor.cs b/src/N_m3u8DL-RE.Parser/Processor/HLS/DefaultHLSContentProcessor.cs
index 260fbca..47535f4 100644
--- a/src/N_m3u8DL-RE.Parser/Processor/HLS/DefaultHLSContentProcessor.cs
+++ b/src/N_m3u8DL-RE.Parser/Processor/HLS/DefaultHLSContentProcessor.cs
@@ -22,6 +22,8 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
         private static partial Regex OrderFixRegex();
         [GeneratedRegex("#EXT-X-MAP.*\\.apple\\.com/")]
         private static partial Regex ATVRegex();
+        [GeneratedRegex("(#EXT-X-KEY:[\\s\\S]*?)(#EXT-X-DISCONTINUITY|#EXT-X-ENDLIST)")]
+        private static partial Regex ATVRegex2();
 
         public override bool CanProcess(ExtractorType extractorType, string rawText, ParserConfig parserConfig) => extractorType == ExtractorType.HLS;
 
@@ -80,7 +82,7 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
             if (m3u8Content.Contains("#EXT-X-DISCONTINUITY") && m3u8Content.Contains("#EXT-X-MAP") && (m3u8Url.Contains(".apple.com/") || ATVRegex().IsMatch(m3u8Content)))
             {
                 //只取加密部分即可
-                Regex ykmap = DNSPRegex();
+                Regex ykmap = ATVRegex2();
                 if (ykmap.IsMatch(m3u8Content))
                 {
                     m3u8Content = "#EXTM3U\r\n" + ykmap.Match(m3u8Content).Groups[1].Value + "\r\n#EXT-X-ENDLIST";
diff --git a/src/N_m3u8DL-RE/Downloader/SimpleDownloader.cs b/src/N_m3u8DL-RE/Downloader/SimpleDownloader.cs
index b8113e9..1fe73a2 100644
--- a/src/N_m3u8DL-RE/Downloader/SimpleDownloader.cs
+++ b/src/N_m3u8DL-RE/Downloader/SimpleDownloader.cs
@@ -85,12 +85,19 @@ namespace N_m3u8DL_RE.Downloader
                 cancellationTokenSource = new();
                 var des = Path.ChangeExtension(path, null);
 
-                //已下载过跳过
+                //已下载跳过
                 if (File.Exists(des))
                 {
                     return new DownloadResult() { ActualContentLength = 0, ActualFilePath = des };
                 }
 
+                //已解密跳过
+                var dec = Path.Combine(Path.GetDirectoryName(des)!, Path.GetFileNameWithoutExtension(des) + "_dec" + Path.GetExtension(des));
+                if (File.Exists(dec))
+                {
+                    return new DownloadResult() { ActualContentLength = 0, ActualFilePath = dec };
+                }
+
                 //另起线程进行监控
                 using var watcher = Task.Factory.StartNew(async () =>
                 {
diff --git a/src/N_m3u8DL-RE/Util/MP4DecryptUtil.cs b/src/N_m3u8DL-RE/Util/MP4DecryptUtil.cs
index cab5038..e715bda 100644
--- a/src/N_m3u8DL-RE/Util/MP4DecryptUtil.cs
+++ b/src/N_m3u8DL-RE/Util/MP4DecryptUtil.cs
@@ -7,17 +7,26 @@ namespace N_m3u8DL_RE.Util
 {
     internal class MP4DecryptUtil
     {
+        private static string ZeroKid = "00000000000000000000000000000000";
         public static async Task<bool> DecryptAsync(bool shakaPackager, string bin, string[]? keys, string source, string dest, string? kid, string init = "")
         {
             if (keys == null || keys.Length == 0) return false;
 
-            var keyPair = keys.First();
+            string? keyPair = null;
+            string? trackId = null;
             if (!string.IsNullOrEmpty(kid))
             {
                 var test = keys.Where(k => k.StartsWith(kid));
                 if (test.Any()) keyPair = test.First();
             }
 
+            //Apple
+            if (kid == ZeroKid)
+            {
+                keyPair = keys.First();
+                trackId = "1";
+            }
+
             if (keyPair == null) return false;
 
             //shakaPackager 无法单独解密init文件
@@ -37,12 +46,19 @@ namespace N_m3u8DL_RE.Util
                     enc = tmpFile;
                 }
 
-                cmd = $"--enable_raw_key_decryption input=\"{enc}\",stream=0,output=\"{dest}\" " +
-                    $"--keys key_id={keyPair.Split(':')[0]}:key={keyPair.Split(':')[1]}";
+                cmd = $"--quiet --enable_raw_key_decryption input=\"{enc}\",stream=0,output=\"{dest}\" " +
+                    $"--keys {(trackId != null ? $"label={trackId}:" : "")}key_id={ZeroKid}:key={keyPair.Split(':')[1]}";
             }
             else
             {
-                cmd = string.Join(" ", keys.Select(k => $"--key {k}"));
+                if (trackId == null)
+                {
+                    cmd = string.Join(" ", keys.Select(k => $"--key {k}"));
+                }
+                else
+                {
+                    cmd = string.Join(" ", keys.Select(k => $"--key {trackId}:{k.Split(':')[1]}"));
+                }
                 if (init != "")
                 {
                     cmd += $" --fragments-info \"{init}\" ";
@@ -69,8 +85,8 @@ namespace N_m3u8DL_RE.Util
             {
                 FileName = name,
                 Arguments = arg,
-                RedirectStandardOutput = true,
-                RedirectStandardError = true,
+                //RedirectStandardOutput = true,
+                //RedirectStandardError = true,
                 CreateNoWindow = true,
                 UseShellExecute = false
             })!.WaitForExitAsync();