示例#1
0
        } = true;                                           //是否写入录制日期

        public static void Merge(string[] files, string muxFormat, bool fastStart,
                                 string poster    = "", string audioName = "", string title        = "",
                                 string copyright = "", string comment   = "", string encodingTool = "")
        {
            string dateString = string.IsNullOrEmpty(REC_TIME) ? DateTime.Now.ToString("o") : REC_TIME;

            //同名文件已存在的共存策略
            if (File.Exists($"{OutPutPath}.{muxFormat.ToLower()}"))
            {
                OutPutPath = Path.Combine(Path.GetDirectoryName(OutPutPath),
                                          Path.GetFileName(OutPutPath) + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
            }

            string command   = "-loglevel warning -i concat:\"";
            string data      = string.Empty;
            string ddpAudio  = string.Empty;
            string addPoster = "-map 1 -c:v:1 copy -disposition:v:1 attached_pic";

            ddpAudio = (File.Exists($"{Path.GetFileNameWithoutExtension(OutPutPath + ".mp4")}.txt") ? File.ReadAllText($"{Path.GetFileNameWithoutExtension(OutPutPath + ".mp4")}.txt") : "");
            if (!string.IsNullOrEmpty(ddpAudio))
            {
                UseAACFilter = false;
            }


            foreach (string t in files)
            {
                command += Path.GetFileName(t) + "|";
            }

            switch (muxFormat.ToUpper())
            {
            case ("MP4"):
                command += "\" " + (string.IsNullOrEmpty(poster) ? "" : "-i \"" + poster + "\"");
                command += " " + (string.IsNullOrEmpty(ddpAudio) ? "" : "-i \"" + ddpAudio + "\"");
                command +=
                    $" -map 0:v? {(string.IsNullOrEmpty(ddpAudio) ? "-map 0:a?" : $"-map {(string.IsNullOrEmpty(poster) ? "1" : "2")}:a -map 0:a?")} -map 0:s? " + (string.IsNullOrEmpty(poster) ? "" : addPoster)
                    + (WriteDate ? " -metadata date=\"" + dateString + "\"" : "") +
                    " -metadata encoding_tool=\"" + encodingTool + "\" -metadata title=\"" + title +
                    "\" -metadata copyright=\"" + copyright + "\" -metadata comment=\"" + comment +
                    $"\" -metadata:s:a:{(string.IsNullOrEmpty(ddpAudio) ? "0" : "1")} handler_name=\"" + audioName + $"\" -metadata:s:a:{(string.IsNullOrEmpty(ddpAudio) ? "0" : "1")} handler=\"" + audioName + "\" ";
                command += (string.IsNullOrEmpty(ddpAudio) ? "" : " -metadata:s:a:0 handler_name=\"DD+\" -metadata:s:a:0 handler=\"DD+\" ");
                if (fastStart)
                {
                    command += "-movflags +faststart";
                }
                command += "  -c copy -y " + (UseAACFilter ? "-bsf:a aac_adtstoasc" : "") + " \"" + OutPutPath + ".mp4\"";
                break;

            case ("MKV"):
                command += "\" -map 0  -c copy -y " + (UseAACFilter ? "-bsf:a aac_adtstoasc" : "") + " \"" + OutPutPath + ".mkv\"";
                break;

            case ("FLV"):
                command += "\" -map 0  -c copy -y " + (UseAACFilter ? "-bsf:a aac_adtstoasc" : "") + " \"" + OutPutPath + ".flv\"";
                break;

            case ("TS"):
                command += "\" -map 0  -c copy -y -f mpegts -bsf:v h264_mp4toannexb \"" + OutPutPath + ".ts\"";
                break;

            case ("VTT"):
                command += "\" -map 0  -y \"" + OutPutPath + ".srt\"";      //Convert To Srt
                break;

            case ("EAC3"):
                command += "\" -map 0:a -c copy -y \"" + OutPutPath + ".eac3\"";
                break;

            case ("AAC"):
                command += "\" -map 0:a -c copy -y \"" + OutPutPath + ".m4a\"";
                break;

            case ("AC3"):
                command += "\" -map 0:a -c copy -y \"" + OutPutPath + ".ac3\"";
                break;
            }

            Run(FFMPEG_PATH, command, Path.GetDirectoryName(files[0]));
            LOGGER.WriteLine(strings.ffmpegDone);
            //Console.WriteLine(command);
        }
示例#2
0
        public void IsComplete(int segCount)
        {
            int tsCount = 0;

            if (DisableIntegrityCheck)
            {
                tsCount = segCount;
                goto ll;
            }

            for (int i = 0; i < PartsCount; i++)
            {
                tsCount += Global.GetFileCount(DownDir + "\\Part_" + i.ToString(partsPadZero), ".ts");
            }

ll:
            if (tsCount != segCount)
            {
                LOGGER.PrintLine(strings.downloadedCount + tsCount + " / " + segCount);
                LOGGER.WriteLine(strings.downloadedCount + tsCount + " of " + segCount);
                if (Count <= RetryCount)
                {
                    Count++;
                    LOGGER.WriteLine(strings.retryCount + Count + " / " + RetryCount);
                    LOGGER.PrintLine(strings.retryCount + Count + " / " + RetryCount, LOGGER.Warning);
                    Thread.Sleep(3000);
                    DoDownload();
                }
            }
            else  //开始合并
            {
                LOGGER.PrintLine(strings.downloadComplete + (DisableIntegrityCheck ? "(" + strings.disableIntegrityCheck + ")" : ""));
                if (NoMerge == false)
                {
                    string exePath    = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
                    string driverName = exePath.Remove(exePath.IndexOf(':'));
                    Console.Title = "Done.";
                    LOGGER.WriteLine(strings.startMerging);
                    LOGGER.PrintLine(strings.startMerging, LOGGER.Warning);
                    //VTT字幕
                    if (isVTT == true)
                    {
                        MuxFormat = "vtt";
                        Global.ReAdjustVtt(Global.GetFiles(DownDir + "\\Part_0", ".ts"));
                    }
                    //只有一个Part直接用ffmpeg合并
                    if (PartsCount == 1)
                    {
                        /*
                         * FFREPORT=file=C\:/Users/nilao/Desktop/新建文件夹/3.log:level=32
                         * Test with Powershell, its C:/Users/nilao/Desktop/新建文件夹/3.log
                         */
                        FFmpeg.OutPutPath = Path.Combine(Directory.GetParent(DownDir).FullName, DownName);
                        FFmpeg.ReportFile = driverName + "\\:" + exePath.Remove(0, exePath.IndexOf(':') + 1).Replace("\\", "/") + "/Logs/" + Path.GetFileNameWithoutExtension(LOGGER.LOGFILE) + fflogName;
                        if (File.Exists(DownDir + "\\!MAP.ts"))
                        {
                            File.Move(DownDir + "\\!MAP.ts", DownDir + "\\Part_0\\!MAP.ts");
                        }

                        if (BinaryMerge)
                        {
                            LOGGER.PrintLine(strings.binaryMergingPleaseWait);
                            MuxFormat = "ts";
                            //有MAP文件,一般为mp4,采取默认动作
                            if (File.Exists(DownDir + "\\Part_0\\!MAP.ts"))
                            {
                                MuxFormat = "mp4";
                            }
                            if (isVTT)
                            {
                                MuxFormat = "vtt";
                            }

                            if (Global.AUDIO_TYPE != "")
                            {
                                MuxFormat = Global.AUDIO_TYPE;
                            }
                            Global.CombineMultipleFilesIntoSingleFile(Global.GetFiles(DownDir + "\\Part_0", ".ts"), FFmpeg.OutPutPath + $".{MuxFormat}");
                        }
                        else
                        {
                            if (Global.VIDEO_TYPE != "DV") //不是杜比视界
                            {
                                //检测是否为MPEG-TS封装,不是的话就转换为TS封装
                                foreach (string s in Global.GetFiles(DownDir + "\\Part_0", ".ts"))
                                {
                                    //跳过有MAP的情况
                                    if (!isVTT && !File.Exists(DownDir + "\\Part_0\\!MAP.ts") && !FFmpeg.CheckMPEGTS(s))
                                    {
                                        //转换
                                        LOGGER.PrintLine(strings.remuxToMPEGTS + Path.GetFileName(s));
                                        LOGGER.WriteLine(strings.remuxToMPEGTS + Path.GetFileName(s));
                                        FFmpeg.ConvertToMPEGTS(s);
                                    }
                                }

                                //分片过多的情况
                                if (tsCount >= 1800)
                                {
                                    LOGGER.WriteLine(strings.partialMergingPleaseWait);
                                    LOGGER.PrintLine(strings.partialMergingPleaseWait, LOGGER.Warning);
                                    Global.PartialCombineMultipleFiles(Global.GetFiles(DownDir + "\\Part_0", ".ts"));
                                }

                                if (Global.AUDIO_TYPE != "")
                                {
                                    MuxFormat = Global.AUDIO_TYPE;
                                }

                                LOGGER.PrintLine(strings.ffmpegMergingPleaseWait);
                                if (!File.Exists(MuxSetJson))
                                {
                                    FFmpeg.Merge(Global.GetFiles(DownDir + "\\Part_0", ".ts"), MuxFormat, MuxFastStart);
                                }
                                else
                                {
                                    JObject json         = JObject.Parse(File.ReadAllText(MuxSetJson, Encoding.UTF8));
                                    string  muxFormat    = json["muxFormat"].Value <string>();
                                    bool    fastStart    = Convert.ToBoolean(json["fastStart"].Value <string>());
                                    string  poster       = json["poster"].Value <string>();
                                    string  audioName    = json["audioName"].Value <string>();
                                    string  title        = json["title"].Value <string>();
                                    string  copyright    = json["copyright"].Value <string>();
                                    string  comment      = json["comment"].Value <string>();
                                    string  encodingTool = "";
                                    try { encodingTool = json["encodingTool"].Value <string>(); } catch (Exception) {; }
                                    FFmpeg.Merge(Global.GetFiles(DownDir + "\\Part_0", ".ts"), muxFormat, fastStart, poster, audioName, title, copyright, comment, encodingTool);
                                }
                                //Global.CombineMultipleFilesIntoSingleFile(Global.GetFiles(DownDir + "\\Part_0", ".ts"), FFmpeg.OutPutPath + ".ts");

                                //Global.ExplorerFile(FFmpeg.OutPutPath + ".mp4");
                            }
                            else
                            {
                                LOGGER.PrintLine(strings.dolbyVisionContentMerging);
                                Global.CombineMultipleFilesIntoSingleFile(Global.GetFiles(DownDir + "\\Part_0", ".ts"), FFmpeg.OutPutPath + ".mp4");
                            }
                        }

                        LOGGER.WriteLine(strings.taskDone
                                         + "\r\n\r\nTask End: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")
                                         + "\r\nFile: " + FFmpeg.OutPutPath + "." + (MuxFormat == "aac" ? "m4a" : MuxFormat) + "\r\n\r\n");

                        //删除文件夹
                        if (DelAfterDone)
                        {
                            try
                            {
                                DirectoryInfo directoryInfo = new DirectoryInfo(DownDir);
                                directoryInfo.Delete(true);
                            }
                            catch (Exception) { }
                        }
                        if (externalAudio)  //下载独立音轨
                        {
                            externalAudio  = false;
                            DownloadedSize = 0;
                            Global.WriteInit();
                            LOGGER.PrintLine(strings.downloadingExternalAudioTrack, LOGGER.Warning);
                            Parser parser = new Parser();
                            parser.Headers  = Headers; //继承Header
                            parser.BaseUrl  = "";
                            parser.M3u8Url  = externalAudioUrl;
                            parser.DownName = DownName + "(Audio)";
                            parser.DownDir  = Path.Combine(Path.GetDirectoryName(DownDir), parser.DownName);
                            LOGGER.WriteLine(strings.startParsing + externalAudioUrl);
                            LOGGER.WriteLine(strings.downloadingExternalAudioTrack);
                            DownName  = DownName + "(Audio)";
                            fflogName = "_ffreport(Audio).log";
                            DownDir   = parser.DownDir;
                            parser.Parse();  //开始解析
                            Thread.Sleep(1000);
                            Global.HadReadInfo = false;
                            Global.VIDEO_TYPE  = "";
                            Global.AUDIO_TYPE  = "";
                            DoDownload();
                        }
                        if (externalSub)  //下载独立字幕
                        {
                            externalSub    = false;
                            DownloadedSize = 0;
                            Global.WriteInit();
                            LOGGER.PrintLine(strings.downloadingExternalSubtitleTrack, LOGGER.Warning);
                            Parser parser = new Parser();
                            parser.Headers  = Headers; //继承Header
                            parser.BaseUrl  = "";
                            parser.M3u8Url  = externalSubUrl;
                            parser.DownName = DownName.Replace("(Audio)", "") + "(Subtitle)";
                            parser.DownDir  = Path.Combine(Path.GetDirectoryName(DownDir), parser.DownName);
                            LOGGER.WriteLine(strings.startParsing + externalSubUrl);
                            LOGGER.WriteLine(strings.downloadingExternalSubtitleTrack);
                            DownName  = parser.DownName;
                            fflogName = "_ffreport(Subtitle).log";
                            DownDir   = parser.DownDir;
                            parser.Parse();  //开始解析
                            Thread.Sleep(1000);
                            Global.HadReadInfo = false;
                            Global.VIDEO_TYPE  = "";
                            Global.AUDIO_TYPE  = "";
                            DoDownload();
                        }
                        LOGGER.PrintLine(strings.taskDone, LOGGER.Warning);
                        Environment.Exit(0);  //正常退出程序
                        return;
                    }

                    FFmpeg.OutPutPath = Path.Combine(Directory.GetParent(DownDir).FullName, DownName);
                    FFmpeg.ReportFile = driverName + "\\:" + exePath.Remove(0, exePath.IndexOf(':') + 1).Replace("\\", "/") + "/Logs/" + Path.GetFileNameWithoutExtension(LOGGER.LOGFILE) + fflogName;

                    //合并分段
                    LOGGER.PrintLine(strings.startMerging);
                    for (int i = 0; i < PartsCount; i++)
                    {
                        string outputFilePath = DownDir + "\\Part_" + i.ToString(partsPadZero) + ".ts";
                        Global.CombineMultipleFilesIntoSingleFile(
                            Global.GetFiles(DownDir + "\\Part_" + i.ToString(partsPadZero), ".ts"),
                            outputFilePath);
                        try
                        {
                            DirectoryInfo directoryInfo = new DirectoryInfo(DownDir + "\\Part_" + i.ToString(partsPadZero));
                            directoryInfo.Delete(true);
                        }
                        catch (Exception) { }
                    }


                    if (BinaryMerge)
                    {
                        LOGGER.PrintLine(strings.binaryMergingPleaseWait);
                        MuxFormat = "ts";
                        //有MAP文件,一般为mp4,采取默认动作
                        if (File.Exists(DownDir + "\\!MAP.ts"))
                        {
                            MuxFormat = "mp4";
                        }
                        if (isVTT)
                        {
                            MuxFormat = "vtt";
                        }
                        Global.CombineMultipleFilesIntoSingleFile(Global.GetFiles(DownDir, ".ts"), FFmpeg.OutPutPath + $".{MuxFormat}");
                    }
                    else
                    {
                        if (Global.VIDEO_TYPE != "DV")  //不是爱奇艺杜比视界
                        {
                            //检测是否为MPEG-TS封装,不是的话就转换为TS封装
                            foreach (string s in Global.GetFiles(DownDir, ".ts"))
                            {
                                //跳过有MAP的情况
                                if (!isVTT && !File.Exists(DownDir + "\\!MAP.ts") && !FFmpeg.CheckMPEGTS(s))
                                {
                                    //转换
                                    LOGGER.PrintLine(strings.remuxToMPEGTS + Path.GetFileName(s));
                                    LOGGER.WriteLine(strings.remuxToMPEGTS + Path.GetFileName(s));
                                    FFmpeg.ConvertToMPEGTS(s);
                                }
                            }

                            if (Global.AUDIO_TYPE != "")
                            {
                                MuxFormat = Global.AUDIO_TYPE;
                            }

                            LOGGER.PrintLine(strings.ffmpegMergingPleaseWait);
                            if (!File.Exists(MuxSetJson))
                            {
                                FFmpeg.Merge(Global.GetFiles(DownDir, ".ts"), MuxFormat, MuxFastStart);
                            }
                            else
                            {
                                JObject json         = JObject.Parse(File.ReadAllText(MuxSetJson, Encoding.UTF8));
                                string  muxFormat    = json["muxFormat"].Value <string>();
                                bool    fastStart    = Convert.ToBoolean(json["fastStart"].Value <string>());
                                string  poster       = json["poster"].Value <string>();
                                string  audioName    = json["audioName"].Value <string>();
                                string  title        = json["title"].Value <string>();
                                string  copyright    = json["copyright"].Value <string>();
                                string  comment      = json["comment"].Value <string>();
                                string  encodingTool = "";
                                try { encodingTool = json["encodingTool"].Value <string>(); } catch (Exception) {; }
                                FFmpeg.Merge(Global.GetFiles(DownDir, ".ts"), muxFormat, fastStart, poster, audioName, title, copyright, comment, encodingTool);
                            }
                        }
                        else
                        {
                            LOGGER.PrintLine(strings.dolbyVisionContentMerging);
                            Global.CombineMultipleFilesIntoSingleFile(Global.GetFiles(DownDir, ".ts"), FFmpeg.OutPutPath + ".mp4");
                        }
                    }

                    LOGGER.WriteLine(strings.taskDone
                                     + "\r\n\r\nTask End: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")
                                     + "\r\nFile: " + FFmpeg.OutPutPath + "." + (MuxFormat == "aac" ? "m4a" : MuxFormat) + "\r\n\r\n");
                    //Global.ExplorerFile(FFmpeg.OutPutPath + ".mp4");
                    //删除文件夹
                    if (DelAfterDone)
                    {
                        try
                        {
                            DirectoryInfo directoryInfo = new DirectoryInfo(DownDir);
                            directoryInfo.Delete(true);
                        }
                        catch (Exception) { }
                    }
                    if (externalAudio)  //下载独立音轨
                    {
                        externalAudio  = false;
                        DownloadedSize = 0;
                        Global.WriteInit();
                        LOGGER.PrintLine(strings.downloadingExternalAudioTrack, LOGGER.Warning);
                        Parser parser = new Parser();
                        parser.Headers  = Headers; //继承Header
                        parser.BaseUrl  = "";
                        parser.M3u8Url  = externalAudioUrl;
                        parser.DownName = DownName + "(Audio)";
                        parser.DownDir  = Path.Combine(Path.GetDirectoryName(DownDir), parser.DownName);
                        LOGGER.WriteLine(strings.startParsing + externalAudioUrl);
                        LOGGER.WriteLine(strings.downloadingExternalAudioTrack);
                        DownName  = parser.DownName;
                        fflogName = "_ffreport(Audio).log";
                        DownDir   = parser.DownDir;
                        parser.Parse();  //开始解析
                        Thread.Sleep(1000);
                        Global.HadReadInfo = false;
                        Global.VIDEO_TYPE  = "";
                        Global.AUDIO_TYPE  = "";
                        DoDownload();
                    }
                    if (externalSub)  //下载独立字幕
                    {
                        externalSub    = false;
                        DownloadedSize = 0;
                        Global.WriteInit();
                        LOGGER.PrintLine(strings.downloadingExternalSubtitleTrack, LOGGER.Warning);
                        Parser parser = new Parser();
                        parser.Headers  = Headers; //继承Header
                        parser.BaseUrl  = "";
                        parser.M3u8Url  = externalSubUrl;
                        parser.DownName = DownName.Replace("(Audio)", "") + "(Subtitle)";
                        parser.DownDir  = Path.Combine(Path.GetDirectoryName(DownDir), parser.DownName);
                        LOGGER.WriteLine(strings.startParsing + externalSubUrl);
                        LOGGER.WriteLine(strings.downloadingExternalSubtitleTrack);
                        DownName  = parser.DownName;
                        fflogName = "_ffreport(Subtitle).log";
                        DownDir   = parser.DownDir;
                        parser.Parse();  //开始解析
                        Thread.Sleep(1000);
                        Global.HadReadInfo = false;
                        Global.VIDEO_TYPE  = "";
                        Global.AUDIO_TYPE  = "";
                        DoDownload();
                    }
                    LOGGER.PrintLine(strings.taskDone, LOGGER.Warning);
                    Environment.Exit(0);  //正常退出程序
                }
                else
                {
                    Console.Title = "Done.";
                    LOGGER.PrintLine(strings.taskDone, LOGGER.Warning);
                    LOGGER.WriteLine(strings.taskDone
                                     + "\r\n\r\nTask End: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
                    Environment.Exit(0);  //正常退出程序
                }
            }
        }
示例#3
0
        /// <summary>
        /// 返回生成的master文件地址
        /// </summary>
        /// <param name="downDir">文件存储目录</param>
        /// <param name="mpdUrl">MPD链接</param>
        /// <param name="mpdContent">MPD内容</param>
        /// <param name="defaultBase">BaseUrl</param>
        /// <returns></returns>
        public static string Parse(string downDir, string mpdUrl, string mpdContent, string defaultBase = "")
        {
            //XiGua
            if (mpdContent.Contains("<mas:") && !mpdContent.Contains("xmlns:mas"))
            {
                mpdContent = mpdContent.Replace("<MPD ", "<MPD xmlns:mas=\"urn:marlin:mas:1-0:services:schemas:mpd\" ");
            }

            XmlDocument mpdDoc = new XmlDocument();

            mpdDoc.LoadXml(mpdContent);

            XmlNode xn = mpdDoc.LastChild;
            var     mediaPresentationDuration = ((XmlElement)xn).GetAttribute("mediaPresentationDuration");
            var     ns = ((XmlElement)xn).GetAttribute("xmlns");

            XmlNamespaceManager nsMgr = new XmlNamespaceManager(mpdDoc.NameTable);

            nsMgr.AddNamespace("ns", ns);

            TimeSpan ts = XmlConvert.ToTimeSpan(mediaPresentationDuration); //时长

            var formatList = new List <Dictionary <string, dynamic> >();    //存放所有音视频清晰度

            foreach (XmlElement period in xn.SelectNodes("ns:Period", nsMgr))
            {
                var periodDuration = string.IsNullOrEmpty(period.GetAttribute("duration")) ? XmlConvert.ToTimeSpan(mediaPresentationDuration) : XmlConvert.ToTimeSpan(period.GetAttribute("duration"));
                var periodMsInfo   = ExtractMultisegmentInfo(period, nsMgr, new Dictionary <string, dynamic>()
                {
                    ["StartNumber"] = 1,
                    ["Timescale"]   = 1
                });
                foreach (XmlElement adaptationSet in period.SelectNodes("ns:AdaptationSet", nsMgr))
                {
                    var adaptionSetMsInfo = ExtractMultisegmentInfo(adaptationSet, nsMgr, periodMsInfo);
                    foreach (XmlElement representation in adaptationSet.SelectNodes("ns:Representation", nsMgr))
                    {
                        string GetAttribute(string key)
                        {
                            var v1 = representation.GetAttribute(key);

                            if (string.IsNullOrEmpty(v1))
                            {
                                return(adaptationSet.GetAttribute(key));
                            }
                            return(v1);
                        }

                        var mimeType    = GetAttribute("mimeType");
                        var contentType = mimeType.Split('/')[0];
                        if (contentType == "text")
                        {
                            continue; //暂不支持字幕下载
                        }
                        else if (contentType == "video" || contentType == "audio")
                        {
                            var baseUrl = "";
                            bool CheckBaseUrl()
                            {
                                return(Regex.IsMatch(baseUrl, @"^https?://"));
                            }

                            var list = new List <XmlNodeList>()
                            {
                                representation.ChildNodes,
                                adaptationSet.ChildNodes,
                                period.ChildNodes,
                                mpdDoc.ChildNodes
                            };

                            foreach (XmlNodeList xmlNodeList in list)
                            {
                                foreach (XmlNode node in xmlNodeList)
                                {
                                    if (node.Name == "BaseURL")
                                    {
                                        baseUrl = node.InnerText + baseUrl;
                                        if (CheckBaseUrl())
                                        {
                                            break;
                                        }
                                    }
                                }
                                if (CheckBaseUrl())
                                {
                                    break;
                                }
                            }

                            string GetBaseUrl(string url)
                            {
                                if (url.Contains("?"))
                                {
                                    url = url.Remove(url.LastIndexOf('?'));
                                }
                                url = url.Substring(0, url.LastIndexOf('/') + 1);
                                return(url);
                            }

                            var mpdBaseUrl = string.IsNullOrEmpty(defaultBase) ? GetBaseUrl(mpdUrl) : defaultBase;
                            if (!string.IsNullOrEmpty(mpdBaseUrl) && !CheckBaseUrl())
                            {
                                if (!mpdBaseUrl.EndsWith("/") && !baseUrl.StartsWith("/"))
                                {
                                    mpdBaseUrl += "/";
                                }
                                baseUrl = mpdBaseUrl + baseUrl;
                            }
                            var representationId = GetAttribute("id");
                            var lang             = GetAttribute("lang");
                            var bandwidth        = IntOrNull(GetAttribute("bandwidth"));
                            var f = new Dictionary <string, dynamic>
                            {
                                ["FormatId"]    = representationId,
                                ["ManifestUrl"] = mpdUrl,
                                ["Width"]       = IntOrNull(GetAttribute("width")),
                                ["Height"]      = IntOrNull(GetAttribute("height")),
                                ["Tbr"]         = DoubleOrNull(bandwidth, 1000),
                                ["Asr"]         = IntOrNull(GetAttribute("audioSamplingRate")),
                                ["Fps"]         = IntOrNull(GetAttribute("frameRate")),
                                ["Language"]    = lang,
                                ["Codecs"]      = GetAttribute("codecs")
                            };

                            var representationMsInfo = ExtractMultisegmentInfo(representation, nsMgr, adaptionSetMsInfo);

                            string PrepareTemplate(string templateName, string[] identifiers)
                            {
                                var tmpl       = representationMsInfo[templateName];
                                var t          = new StringBuilder();
                                var inTemplate = false;

                                foreach (var ch in tmpl)
                                {
                                    t.Append(ch);
                                    if (ch == '$')
                                    {
                                        inTemplate = !inTemplate;
                                    }
                                    else if (ch == '%' && !inTemplate)
                                    {
                                        t.Append(ch);
                                    }
                                }
                                var str = t.ToString();

                                str = str.Replace("$RepresentationID$", representationId);
                                str = Regex.Replace(str, "\\$(" + string.Join("|", identifiers) + ")\\$", "{{$1}}");
                                str = Regex.Replace(str, "\\$(" + string.Join("|", identifiers) + ")%([^$]+)d\\$", "{{$1}}{0:D$2}");
                                str = str.Replace("$$", "$");
                                return(str);
                            }

                            string PadNumber(string template, string key, long value)
                            {
                                string ReplaceFirst(string text, string search, string replace)
                                {
                                    int pos = text.IndexOf(search);

                                    if (pos < 0)
                                    {
                                        return(text);
                                    }
                                    return(text.Substring(0, pos) + replace + text.Substring(pos + search.Length));
                                }

                                template = template.Replace("{{" + key + "}}", "");
                                var m = Regex.Match(template, "{0:D(\\d+)}");

                                return(ReplaceFirst(template, m.Value, value.ToString("0".PadRight(Convert.ToInt32(m.Groups[1].Value), '0'))));
                            }

                            if (representationMsInfo.ContainsKey("Initialization"))
                            {
                                var initializationTemplate = PrepareTemplate("Initialization", new string[] { "Bandwidth" });
                                var initializationUrl      = "";
                                if (initializationTemplate.Contains("{0:D"))
                                {
                                    if (initializationTemplate.Contains("{{Bandwidth}}"))
                                    {
                                        initializationUrl = PadNumber(initializationTemplate, "Bandwidth", bandwidth);
                                    }
                                }
                                else
                                {
                                    initializationUrl = initializationTemplate.Replace("{{Bandwidth}}", bandwidth.ToString());
                                }
                                representationMsInfo["InitializationUrl"] = CombineURL(baseUrl, initializationUrl);
                            }

                            string LocationKey(string location)
                            {
                                return(Regex.IsMatch(location, "^https?://") ? "url" : "path");
                            }

                            if (!representationMsInfo.ContainsKey("SegmentUrls") && representationMsInfo.ContainsKey("Media"))
                            {
                                var mediaTemplate    = PrepareTemplate("Media", new string[] { "Number", "Bandwidth", "Time" });
                                var mediaLocationKey = LocationKey(mediaTemplate);

                                if (mediaTemplate.Contains("{{Number") && !representationMsInfo.ContainsKey("S"))
                                {
                                    var segmentDuration = 0.0;
                                    if (!representationMsInfo.ContainsKey("TotalNumber") && representationMsInfo.ContainsKey("SegmentDuration"))
                                    {
                                        segmentDuration = DoubleOrNull(representationMsInfo["SegmentDuration"], representationMsInfo["Timescale"]);
                                        representationMsInfo["TotalNumber"] = (int)Math.Ceiling(periodDuration.TotalSeconds / segmentDuration);
                                    }
                                    var fragments = new List <Dictionary <string, dynamic> >();
                                    for (int i = representationMsInfo["StartNumber"]; i < representationMsInfo["StartNumber"] + representationMsInfo["TotalNumber"]; i++)
                                    {
                                        var segUrl = "";
                                        if (mediaTemplate.Contains("{0:D"))
                                        {
                                            if (mediaTemplate.Contains("{{Bandwidth}}"))
                                            {
                                                segUrl = PadNumber(mediaTemplate, "Bandwidth", bandwidth);
                                            }
                                            if (mediaTemplate.Contains("{{Number}}"))
                                            {
                                                segUrl = PadNumber(mediaTemplate, "Number", i);
                                            }
                                        }
                                        else
                                        {
                                            segUrl = mediaTemplate.Replace("{{Bandwidth}}", bandwidth.ToString());
                                            segUrl = segUrl.Replace("{{Number}}", i.ToString());
                                        }
                                        fragments.Add(new Dictionary <string, dynamic>()
                                        {
                                            [mediaLocationKey] = CombineURL(baseUrl, segUrl),
                                            ["duration"]       = segmentDuration
                                        });
                                    }
                                    representationMsInfo["Fragments"] = fragments;
                                }
                                else
                                {
                                    var fragments = new List <Dictionary <string, dynamic> >();

                                    var segmentTime   = 0L;
                                    var segmentD      = 0L;
                                    var segmentNumber = representationMsInfo["StartNumber"];

                                    void addSegmentUrl()
                                    {
                                        var segUrl = "";

                                        if (mediaTemplate.Contains("{0:D"))
                                        {
                                            if (mediaTemplate.Contains("{{Bandwidth}}"))
                                            {
                                                segUrl = PadNumber(mediaTemplate, "Bandwidth", bandwidth);
                                            }
                                            if (mediaTemplate.Contains("{{Number}}"))
                                            {
                                                segUrl = PadNumber(mediaTemplate, "Number", segmentNumber);
                                            }
                                            if (mediaTemplate.Contains("{{Time}}"))
                                            {
                                                segUrl = PadNumber(mediaTemplate, "Time", segmentTime);
                                            }
                                        }
                                        else
                                        {
                                            segUrl = mediaTemplate.Replace("{{Bandwidth}}", bandwidth.ToString());
                                            segUrl = segUrl.Replace("{{Number}}", segmentNumber.ToString());
                                            segUrl = segUrl.Replace("{{Time}}", segmentTime.ToString());
                                        }
                                        fragments.Add(new Dictionary <string, dynamic>()
                                        {
                                            [mediaLocationKey] = CombineURL(baseUrl, segUrl),
                                            ["duration"]       = DoubleOrNull(segmentD, representationMsInfo["Timescale"])
                                        });
                                    }

                                    if (representationMsInfo.ContainsKey("S"))
                                    {
                                        for (int i = 0; i < representationMsInfo["S"].Count; i++)
                                        {
                                            var s = representationMsInfo["S"][i];
                                            segmentTime = s["t"] == 0 ? segmentTime : s["t"];
                                            segmentD    = s["d"];
                                            addSegmentUrl();
                                            segmentNumber++;
                                            for (int j = 0; j < s["r"]; j++)
                                            {
                                                segmentTime += segmentD;
                                                addSegmentUrl();
                                                segmentNumber++;
                                            }
                                            segmentTime += segmentD;
                                        }
                                    }
                                    representationMsInfo["Fragments"] = fragments;
                                }
                            }
                            else if (representationMsInfo.ContainsKey("SegmentUrls") && representationMsInfo.ContainsKey("S"))
                            {
                                var fragments = new List <Dictionary <string, dynamic> >();

                                var segmentIndex = 0;
                                var timescale    = representationMsInfo["Timescale"];
                                foreach (var s in representationMsInfo["S"])
                                {
                                    var duration = DoubleOrNull(s["d"], timescale);
                                    for (int j = 0; j < s["r"] + 1; j++)
                                    {
                                        var segmentUri = representationMsInfo["SegmentUrls"][segmentIndex];
                                        fragments.Add(new Dictionary <string, dynamic>()
                                        {
                                            [LocationKey(segmentUri)] = CombineURL(baseUrl, segmentUri),
                                            ["duration"] = duration
                                        });
                                        segmentIndex++;
                                    }
                                }

                                representationMsInfo["Fragments"] = fragments;
                            }
                            else if (representationMsInfo.ContainsKey("SegmentUrls"))
                            {
                                var fragments = new List <Dictionary <string, dynamic> >();

                                var segmentDuration = DoubleOrNull(representationMsInfo["SegmentDuration"], representationMsInfo.ContainsKey("SegmentDuration") ? representationMsInfo["Timescale"] : 1);
                                foreach (var segmentUrl in representationMsInfo["SegmentUrls"])
                                {
                                    if (segmentDuration != null)
                                    {
                                        fragments.Add(new Dictionary <string, dynamic>()
                                        {
                                            [LocationKey(segmentUrl)] = CombineURL(baseUrl, segmentUrl),
                                            ["duration"] = segmentDuration
                                        });
                                    }
                                    else
                                    {
                                        fragments.Add(new Dictionary <string, dynamic>()
                                        {
                                            [LocationKey(segmentUrl)] = CombineURL(baseUrl, segmentUrl)
                                        });
                                    }
                                }

                                representationMsInfo["Fragments"] = fragments;
                            }

                            if (representationMsInfo.ContainsKey("Fragments"))
                            {
                                f["Url"]             = string.IsNullOrEmpty(mpdUrl) ? baseUrl : mpdUrl;
                                f["FragmentBaseUrl"] = baseUrl;
                                if (representationMsInfo.ContainsKey("InitializationUrl"))
                                {
                                    f["InitializationUrl"] = representationMsInfo["InitializationUrl"];
                                    f["Fragments"]         = representationMsInfo["Fragments"];
                                }
                            }
                            else
                            {
                                //整段mp4
                                f["Fragments"] = new List <Dictionary <string, dynamic> > {
                                    new Dictionary <string, dynamic>()
                                    {
                                        ["url"]      = baseUrl,
                                        ["duration"] = ts.TotalSeconds
                                    }
                                };
                            }

                            //处理同一ID分散在不同Period的情况
                            if (formatList.Any(_f => _f["FormatId"] == f["FormatId"] && _f["Width"] == f["Width"]))
                            {
                                for (int i = 0; i < formatList.Count; i++)
                                {
                                    if (formatList[i]["FormatId"] == f["FormatId"] && formatList[i]["Width"] == f["Width"])
                                    {
                                        formatList[i]["Fragments"].AddRange(f["Fragments"]);
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                formatList.Add(f);
                            }
                        }
                    }
                }
            }

            //排序
            formatList.Sort((a, b) =>
            {
                return((a["Width"] + a["Height"]) * 1000 + a["Tbr"] > (b["Width"] + b["Height"]) * 1000 + b["Tbr"] ? -1 : 1);
            });

            //默认为最高码率的视频和音频
            var bestVideo = SelectBestVideo(formatList);
            var bestAudio = SelectBestAudio(formatList);

            var audioLangList = new List <string>();

            formatList.ForEach(f =>
            {
                if (f["Width"] == -1 && !audioLangList.Contains(f["Language"]))
                {
                    audioLangList.Add(f["Language"]);
                }
            });

            if (audioLangList.Count > 1)
            {
                string Stringify(Dictionary <string, dynamic> f)
                {
                    var type   = f["Width"] == -1 && f["Height"] == -1 ? "Audio" : "Video";
                    var res    = type == "Video" ? $"[{f["Width"]}x{f["Height"]}]" : "";
                    var id     = $"[{f["FormatId"]}] ";
                    var tbr    = $"[{((int)f["Tbr"]).ToString().PadLeft(4)} Kbps] ";
                    var asr    = f["Asr"] != -1 ? $"[{f["Asr"]} Hz] " : "";
                    var fps    = f["Fps"] != -1 ? $"[{f["Fps"]} fps] " : "";
                    var lang   = string.IsNullOrEmpty(f["Language"]) ? "" : $"[{f["Language"]}] ";
                    var codecs = $"[{f["Codecs"]}] ";

                    return($"{type} => {id}{tbr}{asr}{fps}{lang}{codecs}{res}");
                }

                for (int i = 0; i < formatList.Count; i++)
                {
                    Console.WriteLine("".PadRight(13) + $"[{i.ToString().PadLeft(2)}]. {Stringify(formatList[i])}");
                    LOGGER.CursorIndex++;
                }
                Console.CursorVisible = true;
                LOGGER.PrintLine("Found Multiple Language Audio Tracks.\r\n" + "".PadRight(13) + "Please Select What You Want(Up to 1 Video and 1 Audio).");
                Console.Write("".PadRight(13) + "Enter Numbers Separated By A Space: ");
                var input = Console.ReadLine();
                LOGGER.CursorIndex   += 2;
                Console.CursorVisible = false;
                if (!string.IsNullOrEmpty(input))
                {
                    bestVideo = new Dictionary <string, dynamic>()
                    {
                        ["Tbr"] = 0
                    };
                    bestAudio = new Dictionary <string, dynamic>()
                    {
                        ["Tbr"] = 0
                    };
                    foreach (var index in input.Split())
                    {
                        var n = 0;
                        int.TryParse(index, out n);
                        if (formatList[n]["Width"] == -1)
                        {
                            bestAudio = formatList[n];
                        }
                        else
                        {
                            bestVideo = formatList[n];
                        }
                    }
                }
            }

            if (bestVideo.Keys.Count > 1 && bestAudio.Keys.Count > 1)  //音视频
            {
                return(GenerateMasterList(downDir, bestVideo, bestAudio));
            }
            else if (bestAudio.Keys.Count > 1)  //仅有音频
            {
                return(GenerateMasterList(downDir, bestAudio));
            }
            else if (bestVideo.Keys.Count > 1)  //仅有视频
            {
                return(GenerateMasterList(downDir, bestVideo));
            }
            else
            {
                return("ERROR");
            }
        }
示例#4
0
        public void DoDownload()
        {
            jsonFile = Path.Combine(DownDir, "meta.json");
            if (!File.Exists(jsonFile))
            {
                return;
            }

            string  jsonContent = File.ReadAllText(jsonFile);
            JObject initJson    = JObject.Parse(jsonContent);
            JArray  parts       = JArray.Parse(initJson["m3u8Info"]["segments"].ToString()); //大分组
            string  segCount    = initJson["m3u8Info"]["count"].ToString();
            string  oriCount    = initJson["m3u8Info"]["originalCount"].ToString();          //原始分片数量
            string  isVOD       = initJson["m3u8Info"]["vod"].ToString();

            try
            {
                if (initJson["m3u8Info"]["audio"].ToString() != "")
                {
                    externalAudio = true;
                }
                externalAudioUrl = initJson["m3u8Info"]["audio"].ToString();
                LOGGER.WriteLine(strings.hasExternalAudioTrack);
                LOGGER.PrintLine(strings.hasExternalAudioTrack, LOGGER.Warning);
            }
            catch (Exception) {}
            try
            {
                if (initJson["m3u8Info"]["sub"].ToString() != "")
                {
                    externalSub = true;
                }
                externalSubUrl = initJson["m3u8Info"]["sub"].ToString();
                LOGGER.WriteLine(strings.hasExternalSubtitleTrack);
                LOGGER.PrintLine(strings.hasExternalSubtitleTrack, LOGGER.Warning);
            }
            catch (Exception) { }
            total        = Convert.ToInt32(segCount);
            PartsCount   = parts.Count;
            segsPadZero  = string.Empty.PadRight(oriCount.Length, '0');
            partsPadZero = string.Empty.PadRight(Convert.ToString(parts.Count).Length, '0');

            //是直播视频
            if (isVOD == "False")
            {
                return;
            }

            Global.ShouldStop = false; //是否该停止下载

            if (!Directory.Exists(DownDir))
            {
                Directory.CreateDirectory(DownDir); //新建文件夹
            }
            Watcher watcher = new Watcher(DownDir);

            watcher.Total      = total;
            watcher.PartsCount = PartsCount;
            watcher.WatcherStrat();

            cts = new CancellationTokenSource();

            //开始调用下载
            LOGGER.WriteLine(strings.startDownloading);
            LOGGER.PrintLine(strings.startDownloading, LOGGER.Warning);

            //下载MAP文件(若有)
downloadMap:
            if (HasExtMap)
            {
                LOGGER.PrintLine(strings.downloadingMapFile);
                Downloader sd = new Downloader();
                sd.TimeOut = TimeOut;
                sd.FileUrl = initJson["m3u8Info"]["extMAP"].Value <string>();
                sd.Headers = Headers;
                sd.Method  = "NONE";
                if (sd.FileUrl.Contains("|"))  //有range
                {
                    string[] tmp = sd.FileUrl.Split('|');
                    sd.FileUrl    = tmp[0];
                    sd.StartByte  = Convert.ToUInt32(tmp[1].Split('@')[1]);
                    sd.ExpectByte = Convert.ToUInt32(tmp[1].Split('@')[0]);
                }
                sd.SavePath = DownDir + "\\!MAP.tsdownloading";
                if (File.Exists(sd.SavePath))
                {
                    File.Delete(sd.SavePath);
                }
                if (File.Exists(DownDir + "\\Part_0\\!MAP.ts"))
                {
                    File.Delete(DownDir + "\\Part_0\\!MAP.ts");
                }
                sd.Down();                               //开始下载
                if (!File.Exists(DownDir + "\\!MAP.ts")) //检测是否成功下载
                {
                    Thread.Sleep(1000);
                    goto downloadMap;
                }
            }

            //首先下载第一个分片
            JToken firstSeg = JArray.Parse(parts[0].ToString())[0];

            if (!File.Exists(DownDir + "\\Part_" + 0.ToString(partsPadZero) + "\\" + firstSeg["index"].Value <int>().ToString(segsPadZero) + ".ts"))
            {
                try
                {
                    Downloader sd = new Downloader();
                    sd.TimeOut = TimeOut;
                    sd.SegDur  = firstSeg["duration"].Value <double>();
                    if (sd.SegDur < 0)
                    {
                        sd.SegDur = 0;                //防止负数
                    }
                    sd.FileUrl = firstSeg["segUri"].Value <string>();
                    //VTT字幕
                    if (isVTT == false && (sd.FileUrl.Trim('\"').EndsWith(".vtt") || sd.FileUrl.Trim('\"').EndsWith(".webvtt")))
                    {
                        isVTT = true;
                    }
                    sd.Method = firstSeg["method"].Value <string>();
                    if (sd.Method != "NONE")
                    {
                        sd.Key = firstSeg["key"].Value <string>();
                        sd.Iv  = firstSeg["iv"].Value <string>();
                    }
                    if (firstSeg["expectByte"] != null)
                    {
                        sd.ExpectByte = firstSeg["expectByte"].Value <long>();
                    }
                    if (firstSeg["startByte"] != null)
                    {
                        sd.StartByte = firstSeg["startByte"].Value <long>();
                    }
                    sd.Headers  = Headers;
                    sd.SavePath = DownDir + "\\Part_" + 0.ToString(partsPadZero) + "\\" + firstSeg["index"].Value <int>().ToString(segsPadZero) + ".tsdownloading";
                    if (File.Exists(sd.SavePath))
                    {
                        File.Delete(sd.SavePath);
                    }
                    LOGGER.PrintLine(strings.downloadingFirstSegement);
                    //开始计算速度
                    timer.Enabled = true;
                    if (!Global.ShouldStop)
                    {
                        sd.Down();  //开始下载
                    }
                }
                catch (Exception e)
                {
                    //LOG.WriteLineError(e.ToString());
                }
            }

            if (Global.HadReadInfo == false)
            {
                string href = DownDir + "\\Part_" + 0.ToString(partsPadZero) + "\\" + firstSeg["index"].Value <int>().ToString(segsPadZero) + ".ts";
                if (File.Exists(DownDir + "\\!MAP.ts"))
                {
                    href = DownDir + "\\!MAP.ts";
                }
                Global.GzipHandler(href);
                bool flag = false;
                foreach (string ss in (string[])Global.GetVideoInfo(href).ToArray(typeof(string)))
                {
                    LOGGER.WriteLine(ss.Trim());
                    LOGGER.PrintLine(ss.Trim(), 0);
                    if (ss.Trim().Contains("Error in reading file"))
                    {
                        flag = true;
                    }
                }
                LOGGER.PrintLine(strings.waitForCompletion, LOGGER.Warning);
                if (!flag)
                {
                    Global.HadReadInfo = true;
                }
            }

            //多线程设置
            ParallelOptions parallelOptions = new ParallelOptions
            {
                MaxDegreeOfParallelism = Threads,
                CancellationToken      = cts.Token
            };

            //构造包含所有分片的新的segments
            JArray segments = new JArray();

            for (int i = 0; i < parts.Count; i++)
            {
                var tmp = JArray.Parse(parts[i].ToString());
                for (int j = 0; j < tmp.Count; j++)
                {
                    JObject t = (JObject)tmp[j];
                    t.Add("part", i);
                    segments.Add(t);
                }
            }

            //剔除第一个分片(已下载过)
            segments.RemoveAt(0);

            try
            {
                ParallelLoopResult result = Parallel.ForEach(segments,
                                                             parallelOptions,
                                                             () => new Downloader(),
                                                             (info, loopstate, index, sd) =>
                {
                    if (Global.ShouldStop)
                    {
                        loopstate.Stop();
                    }
                    else
                    {
                        sd.TimeOut = TimeOut;
                        sd.SegDur  = info["duration"].Value <double>();
                        if (sd.SegDur < 0)
                        {
                            sd.SegDur = 0;                    //防止负数
                        }
                        sd.FileUrl = info["segUri"].Value <string>();
                        //VTT字幕
                        if (isVTT == false && (sd.FileUrl.Trim('\"').EndsWith(".vtt") || sd.FileUrl.Trim('\"').EndsWith(".webvtt")))
                        {
                            isVTT = true;
                        }
                        sd.Method = info["method"].Value <string>();
                        if (sd.Method != "NONE")
                        {
                            sd.Key = info["key"].Value <string>();
                            sd.Iv  = info["iv"].Value <string>();
                        }
                        if (firstSeg["expectByte"] != null)
                        {
                            sd.ExpectByte = info["expectByte"].Value <long>();
                        }
                        if (firstSeg["startByte"] != null)
                        {
                            sd.StartByte = info["startByte"].Value <long>();
                        }
                        sd.Headers  = Headers;
                        sd.SavePath = DownDir + "\\Part_" + info["part"].Value <int>().ToString(partsPadZero) + "\\" + info["index"].Value <int>().ToString(segsPadZero) + ".tsdownloading";
                        if (File.Exists(sd.SavePath))
                        {
                            File.Delete(sd.SavePath);
                        }
                        if (!Global.ShouldStop)
                        {
                            sd.Down();      //开始下载
                        }
                    }
                    return(sd);
                },
                                                             (sd) => { });

                if (result.IsCompleted)
                {
                    //LOGGER.WriteLine("Part " + (info["part"].Value<int>() + 1).ToString(partsPadZero) + " of " + parts.Count + " Completed");
                }
            }
            catch (Exception)
            {
                ;//捕获取消循环产生的异常
            }
            finally
            {
                cts.Dispose();
            }

            watcher.WatcherStop();

            //停止速度监测
            timer.Enabled = false;

            //检测是否下完
            IsComplete(Convert.ToInt32(segCount));
        }
示例#5
0
        static string GenerateM3u8(Dictionary <string, dynamic> f)
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine("#EXTM3U");
            sb.AppendLine("#EXT-X-VERSION:3");
            sb.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");
            sb.AppendLine("#CREATED-BY:N_m3u8DL-CLI");

            //Video
            if (f["ContentType"] != "audio")
            {
                sb.AppendLine($"#EXT-VIDEO-WIDTH:{f["Width"]}");
                sb.AppendLine($"#EXT-VIDEO-HEIGHT:{f["Height"]}");
            }

            sb.AppendLine($"#EXT-CODEC:{f["Codecs"]}");
            sb.AppendLine($"#EXT-TBR:{f["Tbr"]}");
            if (f.ContainsKey("InitializationUrl"))
            {
                string initUrl = f["InitializationUrl"];
                if (Regex.IsMatch(initUrl, "\\$\\$Range=(\\d+)-(\\d+)"))
                {
                    var    match    = Regex.Match(initUrl, "\\$\\$Range=(\\d+)-(\\d+)");
                    string rangeStr = match.Value;
                    long   start    = Convert.ToInt64(match.Groups[1].Value);
                    long   end      = Convert.ToInt64(match.Groups[2].Value);
                    sb.AppendLine($"#EXT-X-MAP:URI=\"{initUrl.Replace(rangeStr, "")}\",BYTERANGE=\"{end + 1 - start}@{start}\"");
                }
                else
                {
                    sb.AppendLine($"#EXT-X-MAP:URI=\"{initUrl}\"");
                }
            }
            sb.AppendLine("#EXT-X-KEY:METHOD=PLZ-KEEP-RAW,URI=\"None\""); //使下载器使用二进制合并

            List <Dictionary <string, dynamic> > fragments = f["Fragments"];

            //检测最后一片的有效性
            if (fragments.Count > 1)
            {
                bool checkValid(string url)
                {
                    try
                    {
                        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
                        request.Timeout = 120000;
                        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                        if (((int)response.StatusCode).ToString().StartsWith("2"))
                        {
                            return(true);
                        }
                        else
                        {
                            return(false);
                        }
                    }
                    catch (Exception) { return(false); }
                }

                var last            = fragments.Last();
                var secondToLast    = fragments[fragments.Count - 2];
                var urlLast         = last.ContainsKey("url") ? last["url"] : last["path"];
                var urlSecondToLast = secondToLast.ContainsKey("url") ? secondToLast["url"] : secondToLast["path"];
                //普通分段才判断
                if (urlLast.StartsWith("http") && !Regex.IsMatch(urlLast, "\\$\\$Range=(\\d+)-(\\d+)"))
                {
                    LOGGER.PrintLine(strings.checkingLast + (f["ContentType"] != "audio" ? "(Video)" : "(Audio)"));
                    LOGGER.WriteLine(strings.checkingLast + (f["ContentType"] != "audio" ? "(Video)" : "(Audio)"));
                    //倒数第二段正常,倒数第一段不正常
                    if (checkValid(urlSecondToLast) && !checkValid(urlLast))
                    {
                        fragments.RemoveAt(fragments.Count - 1);
                    }
                }
            }

            //添加分段
            foreach (var seg in fragments)
            {
                var dur = seg.ContainsKey("duration") ? seg["duration"] : 0.0;
                var url = seg.ContainsKey("url") ? seg["url"] : seg["path"];
                sb.AppendLine($"#EXTINF:{dur.ToString("0.00")}");
                if (Regex.IsMatch(url, "\\$\\$Range=(\\d+)-(\\d+)"))
                {
                    var    match    = Regex.Match(url, "\\$\\$Range=(\\d+)-(\\d+)");
                    string rangeStr = match.Value;
                    long   start    = Convert.ToInt64(match.Groups[1].Value);
                    long   end      = Convert.ToInt64(match.Groups[2].Value);
                    sb.AppendLine($"#EXT-X-BYTERANGE:{end + 1 - start}@{start}");
                    sb.AppendLine(url.Replace(rangeStr, ""));
                }
                else
                {
                    sb.AppendLine(url);
                }
            }

            sb.AppendLine("#EXT-X-ENDLIST");

            return(sb.ToString());
        }
示例#6
0
        public void Parse()
        {
            FFmpeg.REC_TIME = "";

            m3u8SavePath = Path.Combine(DownDir, "raw.m3u8");
            jsonSavePath = Path.Combine(DownDir, "meta.json");

            if (!Directory.Exists(DownDir))         //若文件夹不存在则新建文件夹
            {
                Directory.CreateDirectory(DownDir); //新建文件夹
            }
            //存放分部的所有信息(#EXT-X-DISCONTINUITY)
            JArray parts = new JArray();
            //存放分片的所有信息
            JArray  segments = new JArray();
            JObject segInfo  = new JObject();

            extLists.Clear();
            string m3u8Content = string.Empty;
            string m3u8Method  = string.Empty;

            string[] extMAP = { "", "" };
            string[] extList = new string[10];
            long     segIndex = 0;
            long     startIndex = 0;
            int      targetDuration = 0;
            double   totalDuration = 0;
            bool     expectSegment = false, expectPlaylist = false, isIFramesOnly = false,
                     isIndependentSegments = false, isEndlist = false, isAd = false, isM3u = false;


            //获取m3u8内容
            if (!LiveStream)
            {
                LOGGER.PrintLine(strings.downloadingM3u8, LOGGER.Warning);
            }

            if (M3u8Url.StartsWith("http"))
            {
                if (M3u8Url.Contains("nfmovies.com/hls"))
                {
                    m3u8Content = DecodeNfmovies.DecryptM3u8(Global.HttpDownloadFileToBytes(M3u8Url, Headers));
                }
                else if (M3u8Url.Contains("hls.ddyunp.com/ddyun"))
                {
                    m3u8Content = DecodeDdyun.DecryptM3u8(Global.HttpDownloadFileToBytes(DecodeDdyun.GetVaildM3u8Url(M3u8Url), Headers));
                }
                else
                {
                    m3u8Content = Global.GetWebSource(M3u8Url, Headers);
                }
            }
            else if (M3u8Url.StartsWith("file:"))
            {
                Uri t = new Uri(M3u8Url);
                m3u8Content = File.ReadAllText(t.LocalPath);
            }
            else if (File.Exists(M3u8Url))
            {
                m3u8Content = File.ReadAllText(M3u8Url);
                if (!M3u8Url.Contains("\\"))
                {
                    M3u8Url = Path.Combine(Environment.CurrentDirectory, M3u8Url);
                }
                Uri t = new Uri(M3u8Url);
                M3u8Url = t.ToString();
            }

            if (m3u8Content == "")
            {
                return;
            }

            if (m3u8Content.Contains("qiqiuyun.net/") || m3u8Content.Contains("aliyunedu.net/") || m3u8Content.Contains("qncdn.edusoho.net/")) //气球云
            {
                isQiQiuYun = true;
            }

            if (M3u8Url.Contains("tlivecloud-playback-cdn.ysp.cctv.cn") && M3u8Url.Contains("endtime="))
            {
                isEndlist = true;
            }

            if (M3u8Url.Contains("imooc.com/"))
            {
                m3u8Content = DecodeImooc.DecodeM3u8(m3u8Content);
            }

            if (m3u8Content.Contains("</MPD>") && m3u8Content.Contains("<MPD"))
            {
                var mpdSavePath = Path.Combine(DownDir, "dash.mpd");
                //输出mpd文件
                File.WriteAllText(mpdSavePath, m3u8Content);
                //分析mpd文件
                M3u8Url = Global.Get302(M3u8Url, Headers);
                var newUri = MPDParser.Parse(DownDir, M3u8Url, m3u8Content, BaseUrl);
                M3u8Url     = newUri;
                m3u8Content = File.ReadAllText(new Uri(M3u8Url).LocalPath);
            }

            //输出m3u8文件
            File.WriteAllText(m3u8SavePath, m3u8Content);

            //针对优酷#EXT-X-VERSION:7杜比视界片源修正
            if (m3u8Content.Contains("#EXT-X-DISCONTINUITY") && m3u8Content.Contains("#EXT-X-MAP") && m3u8Content.Contains("ott.cibntv.net") && m3u8Content.Contains("ccode="))
            {
                Regex ykmap = new Regex("#EXT-X-DISCONTINUITY\\s+#EXT-X-MAP:URI=\\\"(.*?)\\\",BYTERANGE=\\\"(.*?)\\\"");
                foreach (Match m in ykmap.Matches(m3u8Content))
                {
                    m3u8Content = m3u8Content.Replace(m.Value, $"#EXTINF:0.000000,\n#EXT-X-BYTERANGE:{m.Groups[2].Value}\n{m.Groups[1].Value}");
                }
            }

            //如果BaseUrl为空则截取字符串充当
            if (BaseUrl == "")
            {
                if (new Regex("#YUMING\\|(.*)").IsMatch(m3u8Content))
                {
                    BaseUrl = new Regex("#YUMING\\|(.*)").Match(m3u8Content).Groups[1].Value;
                }
                else
                {
                    BaseUrl = GetBaseUrl(M3u8Url, Headers);
                }
            }

            if (!LiveStream)
            {
                LOGGER.WriteLine(strings.parsingM3u8);
                LOGGER.PrintLine(strings.parsingM3u8);
            }

            if (!string.IsNullOrEmpty(KeyBase64))
            {
                string line = "";
                if (string.IsNullOrEmpty(KeyIV))
                {
                    line = $"#EXT-X-KEY:METHOD=AES-128,URI=\"base64:{KeyBase64}\"";
                }
                else
                {
                    line = $"#EXT-X-KEY:METHOD=AES-128,URI=\"base64:{KeyBase64}\",IV=0x{KeyIV.Replace("0x", "")}";
                }
                m3u8CurrentKey = ParseKey(line);
            }
            if (!string.IsNullOrEmpty(KeyFile))
            {
                string line = "";
                Uri    u    = new Uri(KeyFile);
                if (string.IsNullOrEmpty(KeyIV))
                {
                    line = $"#EXT-X-KEY:METHOD=AES-128,URI=\"{u.ToString()}\"";
                }
                else
                {
                    line = $"#EXT-X-KEY:METHOD=AES-128,URI=\"{u.ToString()}\",IV=0x{KeyIV.Replace("0x", "")}";
                }

                m3u8CurrentKey = ParseKey(line);
            }

            //逐行分析
            using (StringReader sr = new StringReader(m3u8Content))
            {
                string line;
                double segDuration = 0;
                string segUrl      = string.Empty;
                //#EXT-X-BYTERANGE:<n>[@<o>]
                long expectByte = -1; //parm n
                long startByte  = 0;  //parm o

                while ((line = sr.ReadLine()) != null)
                {
                    if (string.IsNullOrEmpty(line))
                    {
                        continue;
                    }
                    if (line.StartsWith(HLSTags.ext_m3u))
                    {
                        isM3u = true;
                    }
                    //只下载部分字节
                    else if (line.StartsWith(HLSTags.ext_x_byterange))
                    {
                        string[] t = line.Replace(HLSTags.ext_x_byterange + ":", "").Split('@');
                        if (t.Length > 0)
                        {
                            if (t.Length == 1)
                            {
                                expectByte = Convert.ToInt64(t[0]);
                                segInfo.Add("expectByte", expectByte);
                            }
                            if (t.Length == 2)
                            {
                                expectByte = Convert.ToInt64(t[0]);
                                startByte  = Convert.ToInt64(t[1]);
                                segInfo.Add("expectByte", expectByte);
                                segInfo.Add("startByte", startByte);
                            }
                        }
                        expectSegment = true;
                    }
                    //国家地理去广告
                    else if (line.StartsWith("#UPLYNK-SEGMENT"))
                    {
                        if (line.Contains(",ad"))
                        {
                            isAd = true;
                        }
                        else if (line.Contains(",segment"))
                        {
                            isAd = false;
                        }
                    }
                    //国家地理去广告
                    else if (isAd)
                    {
                        continue;
                    }
                    //解析定义的分段长度
                    else if (line.StartsWith(HLSTags.ext_x_targetduration))
                    {
                        targetDuration = Convert.ToInt32(Convert.ToDouble(line.Replace(HLSTags.ext_x_targetduration + ":", "").Trim()));
                    }
                    //解析起始编号
                    else if (line.StartsWith(HLSTags.ext_x_media_sequence))
                    {
                        segIndex   = Convert.ToInt64(line.Replace(HLSTags.ext_x_media_sequence + ":", "").Trim());
                        startIndex = segIndex;
                    }
                    else if (line.StartsWith(HLSTags.ext_x_discontinuity_sequence))
                    {
                    }
                    else if (line.StartsWith(HLSTags.ext_x_program_date_time))
                    {
                        if (string.IsNullOrEmpty(FFmpeg.REC_TIME))
                        {
                            FFmpeg.REC_TIME = line.Replace(HLSTags.ext_x_program_date_time + ":", "").Trim();
                        }
                    }
                    //解析不连续标记,需要单独合并(timestamp不同)
                    else if (line.StartsWith(HLSTags.ext_x_discontinuity))
                    {
                        //修复优酷去除广告后的遗留问题
                        if (hasAd && parts.Count > 0)
                        {
                            segments = (JArray)parts[parts.Count - 1];
                            parts.RemoveAt(parts.Count - 1);
                            hasAd = false;
                            continue;
                        }
                        //常规情况的#EXT-X-DISCONTINUITY标记,新建part
                        if (!hasAd && segments.Count > 1)
                        {
                            parts.Add(segments);
                            segments = new JArray();
                        }
                    }
                    else if (line.StartsWith(HLSTags.ext_x_cue_out))
                    {
                        ;
                    }
                    else if (line.StartsWith(HLSTags.ext_x_cue_out_start))
                    {
                        ;
                    }
                    else if (line.StartsWith(HLSTags.ext_x_cue_span))
                    {
                        ;
                    }
                    else if (line.StartsWith(HLSTags.ext_x_version))
                    {
                        ;
                    }
                    else if (line.StartsWith(HLSTags.ext_x_allow_cache))
                    {
                        ;
                    }
                    //解析KEY
                    else if (line.StartsWith(HLSTags.ext_x_key))
                    {
                        //自定义KEY情况 判断是否需要读取IV
                        if (!string.IsNullOrEmpty(KeyFile) || !string.IsNullOrEmpty(KeyBase64))
                        {
                            if (m3u8CurrentKey[2] == "" && line.Contains("IV=0x"))
                            {
                                var temp = ParseKey(line);   //{METHOD,Key,IV}
                                m3u8CurrentKey[2] = temp[2]; //使用m3u8中的IV
                            }
                        }
                        else
                        {
                            m3u8CurrentKey = ParseKey(line);//获取method,key,iv
                            //存储为上一行的key信息
                            lastKeyLine = line;
                        }
                    }
                    //解析分片时长(暂时不考虑标题属性)
                    else if (line.StartsWith(HLSTags.extinf))
                    {
                        string[] tmp = line.Replace(HLSTags.extinf + ":", "").Split(',');
                        segDuration = Convert.ToDouble(tmp[0]);
                        segInfo.Add("index", segIndex);
                        segInfo.Add("method", m3u8CurrentKey[0]);
                        //是否有加密,有的话写入KEY和IV
                        if (m3u8CurrentKey[0] != "NONE")
                        {
                            segInfo.Add("key", m3u8CurrentKey[1]);
                            //没有读取到IV,自己生成
                            if (m3u8CurrentKey[2] == "")
                            {
                                segInfo.Add("iv", "0x" + Convert.ToString(segIndex, 16).PadLeft(32, '0'));
                            }
                            else
                            {
                                segInfo.Add("iv", m3u8CurrentKey[2]);
                            }
                        }
                        totalDuration += segDuration;
                        segInfo.Add("duration", segDuration);
                        expectSegment = true;
                        segIndex++;
                    }
                    //解析STREAM属性
                    else if (line.StartsWith(HLSTags.ext_x_stream_inf))
                    {
                        expectPlaylist = true;
                        string bandwidth         = Global.GetTagAttribute(line, "BANDWIDTH");
                        string average_bandwidth = Global.GetTagAttribute(line, "AVERAGE-BANDWIDTH");
                        string codecs            = Global.GetTagAttribute(line, "CODECS");
                        string resolution        = Global.GetTagAttribute(line, "RESOLUTION");
                        string frame_rate        = Global.GetTagAttribute(line, "FRAME-RATE");
                        string hdcp_level        = Global.GetTagAttribute(line, "HDCP-LEVEL");
                        string audio             = Global.GetTagAttribute(line, "AUDIO");
                        string video             = Global.GetTagAttribute(line, "VIDEO");
                        string subtitles         = Global.GetTagAttribute(line, "SUBTITLES");
                        string closed_captions   = Global.GetTagAttribute(line, "CLOSED-CAPTIONS");
                        extList = new string[] { bandwidth, average_bandwidth, codecs, resolution,
                                                 frame_rate, hdcp_level, audio, video, subtitles, closed_captions };
                    }
                    else if (line.StartsWith(HLSTags.ext_x_i_frame_stream_inf))
                    {
                        ;
                    }
                    else if (line.StartsWith(HLSTags.ext_x_media))
                    {
                        if (Global.GetTagAttribute(line, "TYPE") == "AUDIO" && !MEDIA_AUDIO.ContainsKey(Global.GetTagAttribute(line, "GROUP-ID")))
                        {
                            MEDIA_AUDIO.Add(Global.GetTagAttribute(line, "GROUP-ID"), CombineURL(BaseUrl, Global.GetTagAttribute(line, "URI")));
                        }
                        if (Global.GetTagAttribute(line, "TYPE") == "SUBTITLES")
                        {
                            if (!MEDIA_SUB.ContainsKey(Global.GetTagAttribute(line, "GROUP-ID")))
                            {
                                MEDIA_SUB.Add(Global.GetTagAttribute(line, "GROUP-ID"), CombineURL(BaseUrl, Global.GetTagAttribute(line, "URI")));
                            }
                        }
                    }
                    else if (line.StartsWith(HLSTags.ext_x_playlist_type))
                    {
                        ;
                    }
                    else if (line.StartsWith(HLSTags.ext_i_frames_only))
                    {
                        isIFramesOnly = true;
                    }
                    else if (line.StartsWith(HLSTags.ext_is_independent_segments))
                    {
                        isIndependentSegments = true;
                    }
                    //m3u8主体结束
                    else if (line.StartsWith(HLSTags.ext_x_endlist))
                    {
                        if (segments.Count > 0)
                        {
                            parts.Add(segments);
                        }
                        segments  = new JArray();
                        isEndlist = true;
                    }
                    //#EXT-X-MAP
                    else if (line.StartsWith(HLSTags.ext_x_map))
                    {
                        if (extMAP[0] == "")
                        {
                            extMAP[0] = Global.GetTagAttribute(line, "URI");
                            if (line.Contains("BYTERANGE"))
                            {
                                extMAP[1] = Global.GetTagAttribute(line, "BYTERANGE");
                            }
                            if (!extMAP[0].StartsWith("http"))
                            {
                                extMAP[0] = CombineURL(BaseUrl, extMAP[0]);
                            }
                        }
                        //遇到了其他的map,说明已经不是一个视频了,全部丢弃即可
                        else
                        {
                            if (segments.Count > 0)
                            {
                                parts.Add(segments);
                            }
                            segments  = new JArray();
                            isEndlist = true;
                            break;
                        }
                    }
                    else if (line.StartsWith(HLSTags.ext_x_start))
                    {
                        ;
                    }
                    //评论行不解析
                    else if (line.StartsWith("#"))
                    {
                        continue;
                    }
                    //空白行不解析
                    else if (line.StartsWith("\r\n"))
                    {
                        continue;
                    }
                    //解析分片的地址
                    else if (expectSegment)
                    {
                        segUrl = CombineURL(BaseUrl, line);
                        if (M3u8Url.Contains("?__gda__"))
                        {
                            segUrl += new Regex("\\?__gda__.*").Match(M3u8Url).Value;
                        }
                        if (M3u8Url.Contains("//dlsc.hcs.cmvideo.cn") && (segUrl.EndsWith(".ts") || segUrl.EndsWith(".mp4")))
                        {
                            segUrl += new Regex("\\?.*").Match(M3u8Url).Value;
                        }
                        segInfo.Add("segUri", segUrl);
                        segments.Add(segInfo);
                        segInfo = new JObject();
                        //优酷的广告分段则清除此分片
                        //需要注意,遇到广告说明程序对上文的#EXT-X-DISCONTINUITY做出的动作是不必要的,
                        //其实上下文是同一种编码,需要恢复到原先的part上
                        if (DelAd && segUrl.Contains("ccode=") && segUrl.Contains("/ad/") && segUrl.Contains("duration="))
                        {
                            segments.RemoveAt(segments.Count - 1);
                            segIndex--;
                            hasAd = true;
                        }
                        //优酷广告(4K分辨率测试)
                        if (DelAd && segUrl.Contains("ccode=0902") && segUrl.Contains("duration="))
                        {
                            segments.RemoveAt(segments.Count - 1);
                            segIndex--;
                            hasAd = true;
                        }
                        expectSegment = false;
                    }
                    //解析STREAM属性的URI
                    else if (expectPlaylist)
                    {
                        string listUrl;
                        listUrl = CombineURL(BaseUrl, line);
                        if (M3u8Url.Contains("?__gda__"))
                        {
                            listUrl += new Regex("\\?__gda__.*").Match(M3u8Url).Value;
                        }
                        StringBuilder sb = new StringBuilder();
                        sb.Append("{");
                        sb.Append("\"URL\":\"" + listUrl + "\",");
                        for (int i = 0; i < 10; i++)
                        {
                            if (extList[i] != "")
                            {
                                switch (i)
                                {
                                case 0:
                                    sb.Append("\"BANDWIDTH\":\"" + extList[i] + "\",");
                                    break;

                                case 1:
                                    sb.Append("\"AVERAGE-BANDWIDTH\":\"" + extList[i] + "\",");
                                    break;

                                case 2:
                                    sb.Append("\"CODECS\":\"" + extList[i] + "\",");
                                    break;

                                case 3:
                                    sb.Append("\"RESOLUTION\":\"" + extList[i] + "\",");
                                    break;

                                case 4:
                                    sb.Append("\"FRAME-RATE\":\"" + extList[i] + "\",");
                                    break;

                                case 5:
                                    sb.Append("\"HDCP-LEVEL\":\"" + extList[i] + "\",");
                                    break;

                                case 6:
                                    sb.Append("\"AUDIO\":\"" + extList[i] + "\",");
                                    break;

                                case 7:
                                    sb.Append("\"VIDEO\":\"" + extList[i] + "\",");
                                    break;

                                case 8:
                                    sb.Append("\"SUBTITLES\":\"" + extList[i] + "\",");
                                    break;

                                case 9:
                                    sb.Append("\"CLOSED-CAPTIONS\":\"" + extList[i] + "\",");
                                    break;
                                }
                            }
                        }
                        sb.Append("}");
                        extLists.Add(sb.ToString().Replace(",}", "}"));
                        if (Convert.ToInt64(extList[0]) > bestBandwidth)
                        {
                            bestBandwidth = Convert.ToInt64(extList[0]);
                            bestUrl       = listUrl;
                            bestUrlAudio  = extList[6];
                            bestUrlSub    = extList[8];
                        }
                        extList        = new string[8];
                        expectPlaylist = false;
                    }
                }
            }

            if (isM3u == false)
            {
                LOGGER.WriteLineError(strings.invalidM3u8);
                LOGGER.PrintLine(strings.invalidM3u8, LOGGER.Error);
                return;
            }

            //直播的情况,无法遇到m3u8结束标记,需要手动将segments加入parts
            if (parts.HasValues == false)
            {
                parts.Add(segments);
            }


            //构造JSON文件
            JObject jsonResult = new JObject();

            jsonResult.Add("m3u8", M3u8Url);
            jsonResult.Add("m3u8BaseUri", BaseUrl);
            jsonResult.Add("updateTime", DateTime.Now.ToString("o"));
            JObject jsonM3u8Info = new JObject();

            jsonM3u8Info.Add("originalCount", segIndex - startIndex);
            jsonM3u8Info.Add("count", segIndex - startIndex);
            jsonM3u8Info.Add("vod", isEndlist);
            jsonM3u8Info.Add("targetDuration", targetDuration);
            jsonM3u8Info.Add("totalDuration", totalDuration);
            if (bestUrlAudio != "" && MEDIA_AUDIO.ContainsKey(bestUrlAudio))
            {
                jsonM3u8Info.Add("audio", MEDIA_AUDIO[bestUrlAudio]);
            }
            if (bestUrlSub != "" && MEDIA_SUB.ContainsKey(bestUrlSub))
            {
                jsonM3u8Info.Add("sub", MEDIA_SUB[bestUrlSub]);
            }
            if (extMAP[0] != "")
            {
                if (extMAP[1] == "")
                {
                    jsonM3u8Info.Add("extMAP", extMAP[0]);
                }
                else
                {
                    jsonM3u8Info.Add("extMAP", extMAP[0] + "|" + extMAP[1]);
                }
            }

            //根据DurRange来生成分片Range
            if (DurStart != "" || DurEnd != "")
            {
                double secStart = 0;
                double secEnd   = -1;

                if (DurEnd == "")
                {
                    secEnd = totalDuration;
                }

                //时间码
                Regex reg2 = new Regex(@"(\d+):(\d+):(\d+)");
                if (reg2.IsMatch(DurStart))
                {
                    int HH = Convert.ToInt32(reg2.Match(DurStart).Groups[1].Value);
                    int MM = Convert.ToInt32(reg2.Match(DurStart).Groups[2].Value);
                    int SS = Convert.ToInt32(reg2.Match(DurStart).Groups[3].Value);
                    secStart = SS + MM * 60 + HH * 60 * 60;
                }
                if (reg2.IsMatch(DurEnd))
                {
                    int HH = Convert.ToInt32(reg2.Match(DurEnd).Groups[1].Value);
                    int MM = Convert.ToInt32(reg2.Match(DurEnd).Groups[2].Value);
                    int SS = Convert.ToInt32(reg2.Match(DurEnd).Groups[3].Value);
                    secEnd = SS + MM * 60 + HH * 60 * 60;
                }

                bool flag1 = false;
                bool flag2 = false;
                if (secEnd - secStart > 0)
                {
                    double dur = 0; //当前时间
                    foreach (JArray part in parts)
                    {
                        foreach (var seg in part)
                        {
                            dur += Convert.ToDouble(seg["duration"].ToString());
                            if (flag1 == false && dur > secStart)
                            {
                                RangeStart = seg["index"].Value <int>();
                                flag1      = true;
                            }

                            if (flag2 == false && dur >= secEnd)
                            {
                                RangeEnd = seg["index"].Value <int>();
                                flag2    = true;
                            }
                        }
                    }
                }
            }


            //根据Range来清除部分分片
            if (RangeStart != 0 || RangeEnd != -1)
            {
                if (RangeEnd == -1)
                {
                    RangeEnd = (int)(segIndex - startIndex - 1);
                }
                int    newCount         = 0;
                double newTotalDuration = 0;
                JArray newParts         = new JArray();
                foreach (JArray part in parts)
                {
                    JArray newPart = new JArray();
                    foreach (var seg in part)
                    {
                        if (RangeStart <= seg["index"].Value <int>() && seg["index"].Value <int>() <= RangeEnd)
                        {
                            newPart.Add(seg);
                            newCount++;
                            newTotalDuration += Convert.ToDouble(seg["duration"].ToString());
                        }
                    }
                    if (newPart.Count != 0)
                    {
                        newParts.Add(newPart);
                    }
                }
                parts = newParts;
                jsonM3u8Info["count"]         = newCount;
                jsonM3u8Info["totalDuration"] = newTotalDuration;
            }


            //添加
            jsonM3u8Info.Add("segments", parts);
            jsonResult.Add("m3u8Info", jsonM3u8Info);


            //输出JSON文件
            if (!LiveStream)
            {
                LOGGER.WriteLine(strings.wrtingMeta);
                LOGGER.PrintLine(strings.wrtingMeta);
            }
            File.WriteAllText(jsonSavePath, jsonResult.ToString());
            //检测是否为master list
            MasterListCheck();
        }
示例#7
0
        public string[] ParseKey(string line)
        {
            if (!downloadingM3u8KeyTip)
            {
                LOGGER.PrintLine(strings.downloadingM3u8Key, LOGGER.Warning);
                downloadingM3u8KeyTip = true;
            }
            string[] tmp    = line.Replace(HLSTags.ext_x_key + ":", "").Split(',');
            string[] key    = new string[] { "NONE", "", "" };
            string   u_l    = Global.GetTagAttribute(lastKeyLine.Replace(HLSTags.ext_x_key + ":", ""), "URI");
            string   method = Global.GetTagAttribute(line.Replace(HLSTags.ext_x_key + ":", ""), "METHOD");
            string   uri    = Global.GetTagAttribute(line.Replace(HLSTags.ext_x_key + ":", ""), "URI");
            string   iv     = Global.GetTagAttribute(line.Replace(HLSTags.ext_x_key + ":", ""), "IV");

            //存在加密
            if (method != "")
            {
                if (method != "AES-128")
                {
                    LOGGER.PrintLine(string.Format(strings.notSupportMethod, method), LOGGER.Error);
                    DownloadManager.BinaryMerge = true;
                    return(new string[] { $"{method}(NOTSUPPORTED)", "", "" });
                }
                //METHOD
                key[0] = method;
                //URI
                key[1] = uri;
                if (u_l == uri)
                {
                    key[1] = m3u8CurrentKey[1];
                }
                else
                {
                    LOGGER.WriteLine(strings.downloadingM3u8Key + " " + key[1]);
                    if (key[1].StartsWith("http"))
                    {
                        string keyUrl = key[1];
                        if (isQiQiuYun)
                        {
                            /*string encKey = Encoding.Default.GetString(Global.HttpDownloadFileToBytes(keyUrl, Headers));
                             * var indexs = "0-1-2-3-4-5-6-7-8-10-11-12-14-15-16-18".Split('-');
                             * if (encKey.Length == 20)
                             * {
                             *  var algorithmCharCode = (int)Encoding.ASCII.GetBytes(encKey)[0];
                             *  var algorithmChar = Encoding.ASCII.GetString(new byte[] { (byte)algorithmCharCode });
                             *  var algorithmCharStart = Global.GetNum(algorithmChar, 36) % 7;
                             *  var firstAlgorithmCharCode = (int)Encoding.ASCII.GetBytes(encKey)[algorithmCharStart];
                             *  var firstAlgorithmChar = Encoding.ASCII.GetString(new byte[] { (byte)firstAlgorithmCharCode });
                             *  var secondAlgorithmCharCode = (int)Encoding.ASCII.GetBytes(encKey)[algorithmCharStart + 1];
                             *  var secondAlgorithmChar = Encoding.ASCII.GetString(new byte[] { (byte)secondAlgorithmCharCode });
                             *  var algorithmNum = Global.GetNum(firstAlgorithmChar + secondAlgorithmChar, 36) % 3;
                             *
                             *  if (algorithmNum == 1)
                             *  {
                             *      indexs = "0-1-2-3-4-5-6-7-18-16-15-13-12-11-10-8".Split('-');
                             *  }
                             *  else if (algorithmNum == 0)
                             *  {
                             *      indexs = "0-1-2-3-4-5-6-7-8-10-11-12-14-15-16-18".Split('-');
                             *  }
                             *  else if (algorithmNum == 2)
                             *  {
                             *      var a_CODE = (int)Encoding.ASCII.GetBytes("a")[0];
                             *
                             *      var c9 = (int)Encoding.ASCII.GetBytes(encKey)[8];
                             *      var c9t = (int)Encoding.ASCII.GetBytes(encKey)[9];
                             *      var c10 = (int)Encoding.ASCII.GetBytes(encKey)[10];
                             *      var c10t = (int)Encoding.ASCII.GetBytes(encKey)[11];
                             *      var c14 = (int)Encoding.ASCII.GetBytes(encKey)[15];
                             *      var c14t = (int)Encoding.ASCII.GetBytes(encKey)[16];
                             *      var c15 = (int)Encoding.ASCII.GetBytes(encKey)[17];
                             *      var c15t = (int)Encoding.ASCII.GetBytes(encKey)[18];
                             *
                             *      var c9r = c9 - a_CODE + (Global.GetNum(Encoding.ASCII.GetString(new byte[] { (byte)c9t }), 10) + 1) * 26 - a_CODE;
                             *      var c10r = c10 - a_CODE + (Global.GetNum(Encoding.ASCII.GetString(new byte[] { (byte)c10t }), 10) + 1) * 26 - a_CODE;
                             *      var c14r = c14 - a_CODE + (Global.GetNum(Encoding.ASCII.GetString(new byte[] { (byte)c14t }), 10) + 1) * 26 - a_CODE;
                             *      var c15r = c15 - a_CODE + (Global.GetNum(Encoding.ASCII.GetString(new byte[] { (byte)c15t }), 10) + 2) * 26 - a_CODE;
                             *
                             *      //构造key
                             *      key[1] = Convert.ToBase64String(
                             *          new byte[]
                             *          {
                             *              Encoding.ASCII.GetBytes(encKey)[0],
                             *              Encoding.ASCII.GetBytes(encKey)[1],
                             *              Encoding.ASCII.GetBytes(encKey)[2],
                             *              Encoding.ASCII.GetBytes(encKey)[3],
                             *              Encoding.ASCII.GetBytes(encKey)[4],
                             *              Encoding.ASCII.GetBytes(encKey)[5],
                             *              Encoding.ASCII.GetBytes(encKey)[6],
                             *              Encoding.ASCII.GetBytes(encKey)[7],
                             *              (byte)c9r,
                             *              (byte)c10r,
                             *              Encoding.ASCII.GetBytes(encKey)[12],
                             *              Encoding.ASCII.GetBytes(encKey)[13],
                             *              Encoding.ASCII.GetBytes(encKey)[14],
                             *              (byte)c14r,
                             *              (byte)c15r,
                             *              Encoding.ASCII.GetBytes(encKey)[19]
                             *          }
                             *      );
                             *      //IV
                             *      key[2] = i;
                             *      return key;
                             *  }
                             * }
                             * else if (encKey.Length == 17)
                             * {
                             *  indexs = "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16".Split('-');
                             * }
                             * else
                             * {
                             *  indexs = "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16".Split('-');
                             * }
                             *
                             * string decKey = "";
                             * foreach (var _i in indexs)
                             * {
                             *  decKey += encKey[Convert.ToInt32(_i)];
                             * }
                             * key[1] = Convert.ToBase64String(Encoding.Default.GetBytes(decKey));*/

                            key[1] = Convert.ToBase64String(Global.HttpDownloadFileToBytes(keyUrl, "User-Agent:Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; 15 Plus Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/9.4 Mobile Safari/537.36"));
                        } //气球云
                        else if (key[1].Contains("imooc.com/"))
                        {
                            key[1] = DecodeImooc.DecodeKey(Global.GetWebSource(key[1], Headers));
                        }
                        else
                        {
                            if (keyUrl.Contains("https://keydeliver.linetv.tw/jurassicPark"))  //linetv
                            {
                                keyUrl = keyUrl + "?time=" + Global.GetTimeStamp(false);
                            }
                            key[1] = Convert.ToBase64String(Global.HttpDownloadFileToBytes(keyUrl, Headers));
                        }
                    }
                    //DMM网站
                    else if (key[1].StartsWith("base64:"))
                    {
                        key[1] = key[1].Replace("base64:", "");
                    }
                    else
                    {
                        string keyUrl = CombineURL(BaseUrl, key[1]);
                        if (keyUrl.Contains("edu.51cto.com")) //51cto
                        {
                            string lessonId = Global.GetQueryString("lesson_id", keyUrl);
                            keyUrl = keyUrl + "&sign=" + Decode51CtoKey.GetSign(lessonId);
                            var encodeKey = Encoding.UTF8.GetString(Global.HttpDownloadFileToBytes(keyUrl, Headers));
                            key[1] = Decode51CtoKey.GetDecodeKey(encodeKey, lessonId);
                        }
                        else
                        {
                            key[1] = Convert.ToBase64String(Global.HttpDownloadFileToBytes(keyUrl, Headers));//keyUrl读取key
                        }
                    }
                }
                //IV
                key[2] = iv;
            }

            return(key);
        }
示例#8
0
        public string[] ParseKey(string line)
        {
            if (!downloadingM3u8KeyTip)
            {
                LOGGER.PrintLine(strings.downloadingM3u8Key, LOGGER.Warning);
                downloadingM3u8KeyTip = true;
            }
            string[] tmp = line.Replace(HLSTags.ext_x_key + ":", "").Split(',');
            string[] key = new string[] { "NONE", "", "" };
            string   u_l = Global.GetTagAttribute(lastKeyLine.Replace(HLSTags.ext_x_key + ":", ""), "URI");
            string   m   = Global.GetTagAttribute(line.Replace(HLSTags.ext_x_key + ":", ""), "METHOD");
            string   u   = Global.GetTagAttribute(line.Replace(HLSTags.ext_x_key + ":", ""), "URI");
            string   i   = Global.GetTagAttribute(line.Replace(HLSTags.ext_x_key + ":", ""), "IV");

            //存在加密
            if (m != "")
            {
                if (m != "AES-128")
                {
                    LOGGER.PrintLine(string.Format(strings.notSupportMethod, m), LOGGER.Error);
                    DownloadManager.BinaryMerge = true;
                    return(new string[] { $"{m}(NOTSUPPORTED)", "", "" });
                }
                //METHOD
                key[0] = m;
                //URI
                key[1] = u;
                if (u_l == u)
                {
                    key[1] = m3u8CurrentKey[1];
                }
                else
                {
                    LOGGER.WriteLine(strings.downloadingM3u8Key + " " + key[1]);
                    if (key[1].StartsWith("http"))
                    {
                        string keyUrl = key[1];
                        if (isQiQiuYun)
                        {
                            string encKey = Encoding.Default.GetString(Global.HttpDownloadFileToBytes(keyUrl, Headers));
                            var    indexs = "0-1-2-3-4-5-6-7-8-10-11-12-14-15-16-18".Split('-');
                            if (encKey.Length == 20)
                            {
                                var algorithmCharCode       = (int)Encoding.ASCII.GetBytes(encKey)[0];
                                var algorithmChar           = Encoding.ASCII.GetString(new byte[] { (byte)algorithmCharCode });
                                var algorithmCharStart      = Global.GetNum(algorithmChar, 36) % 7;
                                var firstAlgorithmCharCode  = (int)Encoding.ASCII.GetBytes(encKey)[algorithmCharStart];
                                var firstAlgorithmChar      = Encoding.ASCII.GetString(new byte[] { (byte)firstAlgorithmCharCode });
                                var secondAlgorithmCharCode = (int)Encoding.ASCII.GetBytes(encKey)[algorithmCharStart + 1];
                                var secondAlgorithmChar     = Encoding.ASCII.GetString(new byte[] { (byte)secondAlgorithmCharCode });
                                var algorithmNum            = Global.GetNum(firstAlgorithmChar + secondAlgorithmChar, 36) % 3;

                                if (algorithmNum == 1)
                                {
                                    indexs = "0-1-2-3-4-5-6-7-18-16-15-13-12-11-10-8".Split('-');
                                }
                                else if (algorithmNum == 0)
                                {
                                    indexs = "0-1-2-3-4-5-6-7-8-10-11-12-14-15-16-18".Split('-');
                                }
                                else if (algorithmNum == 2)
                                {
                                    var a_CODE = (int)Encoding.ASCII.GetBytes("a")[0];

                                    var c9   = (int)Encoding.ASCII.GetBytes(encKey)[8];
                                    var c9t  = (int)Encoding.ASCII.GetBytes(encKey)[9];
                                    var c10  = (int)Encoding.ASCII.GetBytes(encKey)[10];
                                    var c10t = (int)Encoding.ASCII.GetBytes(encKey)[11];
                                    var c14  = (int)Encoding.ASCII.GetBytes(encKey)[15];
                                    var c14t = (int)Encoding.ASCII.GetBytes(encKey)[16];
                                    var c15  = (int)Encoding.ASCII.GetBytes(encKey)[17];
                                    var c15t = (int)Encoding.ASCII.GetBytes(encKey)[18];

                                    var c9r  = c9 - a_CODE + (Global.GetNum(Encoding.ASCII.GetString(new byte[] { (byte)c9t }), 10) + 1) * 26 - a_CODE;
                                    var c10r = c10 - a_CODE + (Global.GetNum(Encoding.ASCII.GetString(new byte[] { (byte)c10t }), 10) + 1) * 26 - a_CODE;
                                    var c14r = c14 - a_CODE + (Global.GetNum(Encoding.ASCII.GetString(new byte[] { (byte)c14t }), 10) + 1) * 26 - a_CODE;
                                    var c15r = c15 - a_CODE + (Global.GetNum(Encoding.ASCII.GetString(new byte[] { (byte)c15t }), 10) + 2) * 26 - a_CODE;

                                    //构造key
                                    key[1] = Convert.ToBase64String(
                                        new byte[]
                                    {
                                        Encoding.ASCII.GetBytes(encKey)[0],
                                        Encoding.ASCII.GetBytes(encKey)[1],
                                        Encoding.ASCII.GetBytes(encKey)[2],
                                        Encoding.ASCII.GetBytes(encKey)[3],
                                        Encoding.ASCII.GetBytes(encKey)[4],
                                        Encoding.ASCII.GetBytes(encKey)[5],
                                        Encoding.ASCII.GetBytes(encKey)[6],
                                        Encoding.ASCII.GetBytes(encKey)[7],
                                        (byte)c9r,
                                        (byte)c10r,
                                        Encoding.ASCII.GetBytes(encKey)[12],
                                        Encoding.ASCII.GetBytes(encKey)[13],
                                        Encoding.ASCII.GetBytes(encKey)[14],
                                        (byte)c14r,
                                        (byte)c15r,
                                        Encoding.ASCII.GetBytes(encKey)[19]
                                    }
                                        );
                                    //IV
                                    key[2] = i;
                                    return(key);
                                }
                            }
                            else if (encKey.Length == 17)
                            {
                                indexs = "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16".Split('-');
                            }
                            else
                            {
                                indexs = "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16".Split('-');
                            }

                            string decKey = "";
                            foreach (var _i in indexs)
                            {
                                decKey += encKey[Convert.ToInt32(_i)];
                            }
                            key[1] = Convert.ToBase64String(Encoding.Default.GetBytes(decKey));
                        } //气球云
                        else if (key[1].Contains("imooc.com/"))
                        {
                            key[1] = DecodeImooc.DecodeKey(Global.GetWebSource(key[1], Headers));
                        }
                        else
                        {
                            if (keyUrl.Contains("https://keydeliver.linetv.tw/jurassicPark"))  //linetv
                            {
                                keyUrl = keyUrl + "?time=" + Global.GetTimeStamp(false);
                            }
                            key[1] = Convert.ToBase64String(Global.HttpDownloadFileToBytes(keyUrl, Headers));
                        }
                    }
                    //DMM网站
                    else if (key[1].StartsWith("base64:"))
                    {
                        key[1] = key[1].Replace("base64:", "");
                    }
                    else
                    {
                        string keyUrl = CombineURL(BaseUrl, key[1]);
                        if (keyUrl.Contains("edu.51cto.com")) //51cto
                        {
                            string lessonId = Global.GetQueryString("lesson_id", keyUrl);
                            keyUrl = keyUrl + "&sign=" + Decode51CtoKey.GetSign(lessonId);
                            var encodeKey = Encoding.UTF8.GetString(Global.HttpDownloadFileToBytes(keyUrl, Headers));
                            key[1] = Decode51CtoKey.GetDecodeKey(encodeKey, lessonId);
                        }
                        else
                        {
                            key[1] = Convert.ToBase64String(Global.HttpDownloadFileToBytes(keyUrl, Headers));
                        }
                    }
                }
                //IV
                key[2] = i;
            }

            return(key);
        }