You've already forked N_m3u8DL-CLI
							
							
				mirror of
				https://github.com/nilaoda/N_m3u8DL-CLI
				synced 2025-11-04 04:02:28 +01:00 
			
		
		
		
	Compare commits
	
		
			125 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					e700edba56 | ||
| 
						 | 
					aad948da7c | ||
| 
						 | 
					14f7b20176 | ||
| 
						 | 
					a66a9a4096 | ||
| 
						 | 
					c862f23a9c | ||
| 
						 | 
					1a722e80de | ||
| 
						 | 
					eff43e8ac3 | ||
| 
						 | 
					7648f8f8dc | ||
| 
						 | 
					1edc1a43fe | ||
| 
						 | 
					01e7735018 | ||
| 
						 | 
					a0c41d6116 | ||
| 
						 | 
					c3c25774de | ||
| 
						 | 
					ba40641a21 | ||
| 
						 | 
					5d76418780 | ||
| 
						 | 
					fd48b766b5 | ||
| 
						 | 
					0f25cc0ae8 | ||
| 
						 | 
					1c6bd688e3 | ||
| 
						 | 
					480857cc3b | ||
| 
						 | 
					52af9a44a8 | ||
| 
						 | 
					84d137b504 | ||
| 
						 | 
					a4f1064c81 | ||
| 
						 | 
					eac08b12f8 | ||
| 
						 | 
					c81c911888 | ||
| 
						 | 
					361e901e5b | ||
| 
						 | 
					3567f4c4cc | ||
| 
						 | 
					2f7b0f7304 | ||
| 
						 | 
					000d0db4ae | ||
| 
						 | 
					d551ad52c1 | ||
| 
						 | 
					c064c83c21 | ||
| 
						 | 
					f6ed0f9e4d | ||
| 
						 | 
					f65fee94ca | ||
| 
						 | 
					ce64a92b0d | ||
| 
						 | 
					42790ce540 | ||
| 
						 | 
					83d8ca1c8c | ||
| 
						 | 
					4b5a64eb98 | ||
| 
						 | 
					2b5af09c3b | ||
| 
						 | 
					6368adc2ab | ||
| 
						 | 
					fcd7840091 | ||
| 
						 | 
					d77cb62dff | ||
| 
						 | 
					34394c6a2b | ||
| 
						 | 
					091cba8555 | ||
| 
						 | 
					b02b6b7168 | ||
| 
						 | 
					b7408b0599 | ||
| 
						 | 
					b83cb35170 | ||
| 
						 | 
					ed0a7b71a7 | ||
| 
						 | 
					50eae19bf3 | ||
| 
						 | 
					cba8f3ea52 | ||
| 
						 | 
					7fd93e1232 | ||
| 
						 | 
					74a7e3c3ec | ||
| 
						 | 
					849d712e11 | ||
| 
						 | 
					7544f3a02c | ||
| 
						 | 
					0120736c53 | ||
| 
						 | 
					e4bde4926c | ||
| 
						 | 
					d42cd6a60d | ||
| 
						 | 
					175f13adc9 | ||
| 
						 | 
					72f1c043b1 | ||
| 
						 | 
					a2e2070f5d | ||
| 
						 | 
					6c96deb366 | ||
| 
						 | 
					2bd900ee5d | ||
| 
						 | 
					1261810510 | ||
| 
						 | 
					26823dbd7e | ||
| 
						 | 
					698699d9fc | ||
| 
						 | 
					ebed7fa1e3 | ||
| 
						 | 
					73a8348155 | ||
| 
						 | 
					5ace0b3a4f | ||
| 
						 | 
					5abe889da0 | ||
| 
						 | 
					f1070fd1b4 | ||
| 
						 | 
					4af82cc7f9 | ||
| 
						 | 
					809380b7ab | ||
| 
						 | 
					ab57420507 | ||
| 
						 | 
					80230f12fe | ||
| 
						 | 
					a6c7c0fd8c | ||
| 
						 | 
					bd6df6b58c | ||
| 
						 | 
					e0a9071d62 | ||
| 
						 | 
					5c9bcf72d2 | ||
| 
						 | 
					7cf2c12d0c | ||
| 
						 | 
					1b35fe2d2c | ||
| 
						 | 
					ed3aae1cb9 | ||
| 
						 | 
					01c2ecbeb5 | ||
| 
						 | 
					9993ec8177 | ||
| 
						 | 
					464300c860 | ||
| 
						 | 
					45fa58a46f | ||
| 
						 | 
					f93ddc7107 | ||
| 
						 | 
					05f450fa6d | ||
| 
						 | 
					580c374d7b | ||
| 
						 | 
					b58dc5d8e0 | ||
| 
						 | 
					f50cf7862a | ||
| 
						 | 
					fdad68d483 | ||
| 
						 | 
					d7aaa5323b | ||
| 
						 | 
					6c2e13b800 | ||
| 
						 | 
					086fc57958 | ||
| 
						 | 
					bc349b8977 | ||
| 
						 | 
					cc4efed3c6 | ||
| 
						 | 
					cf958e833b | ||
| 
						 | 
					fb09add0cd | ||
| 
						 | 
					5a3c5baefd | ||
| 
						 | 
					839afd8e61 | ||
| 
						 | 
					338c7a25d0 | ||
| 
						 | 
					f57ce8c2da | ||
| 
						 | 
					a5009e1683 | ||
| 
						 | 
					66933da9de | ||
| 
						 | 
					136389e248 | ||
| 
						 | 
					7971104bd4 | ||
| 
						 | 
					cc4941554d | ||
| 
						 | 
					c50371080a | ||
| 
						 | 
					154c5f84a1 | ||
| 
						 | 
					1556ee42df | ||
| 
						 | 
					121ff9f226 | ||
| 
						 | 
					e5b84c2f04 | ||
| 
						 | 
					7e562a06bb | ||
| 
						 | 
					1eae19c3ea | ||
| 
						 | 
					ba33049b99 | ||
| 
						 | 
					9773087bf9 | ||
| 
						 | 
					b60d39ad0d | ||
| 
						 | 
					e89705a370 | ||
| 
						 | 
					4aea16d672 | ||
| 
						 | 
					afc69eae1a | ||
| 
						 | 
					2446a25b35 | ||
| 
						 | 
					d37524180d | ||
| 
						 | 
					b02a29fbb7 | ||
| 
						 | 
					e87d02230d | ||
| 
						 | 
					63609a0970 | ||
| 
						 | 
					1fe798ab19 | ||
| 
						 | 
					21b9977501 | ||
| 
						 | 
					fbe37be499 | 
							
								
								
									
										63
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
###############################################################################
 | 
			
		||||
# Set default behavior to automatically normalize line endings.
 | 
			
		||||
###############################################################################
 | 
			
		||||
* text=auto
 | 
			
		||||
 | 
			
		||||
###############################################################################
 | 
			
		||||
# Set default behavior for command prompt diff.
 | 
			
		||||
#
 | 
			
		||||
# This is need for earlier builds of msysgit that does not have it on by
 | 
			
		||||
# default for csharp files.
 | 
			
		||||
# Note: This is only used by command line
 | 
			
		||||
###############################################################################
 | 
			
		||||
#*.cs     diff=csharp
 | 
			
		||||
 | 
			
		||||
###############################################################################
 | 
			
		||||
# Set the merge driver for project and solution files
 | 
			
		||||
#
 | 
			
		||||
# Merging from the command prompt will add diff markers to the files if there
 | 
			
		||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
 | 
			
		||||
# the diff markers are never inserted). Diff markers may cause the following 
 | 
			
		||||
# file extensions to fail to load in VS. An alternative would be to treat
 | 
			
		||||
# these files as binary and thus will always conflict and require user
 | 
			
		||||
# intervention with every merge. To do so, just uncomment the entries below
 | 
			
		||||
###############################################################################
 | 
			
		||||
#*.sln       merge=binary
 | 
			
		||||
#*.csproj    merge=binary
 | 
			
		||||
#*.vbproj    merge=binary
 | 
			
		||||
#*.vcxproj   merge=binary
 | 
			
		||||
#*.vcproj    merge=binary
 | 
			
		||||
#*.dbproj    merge=binary
 | 
			
		||||
#*.fsproj    merge=binary
 | 
			
		||||
#*.lsproj    merge=binary
 | 
			
		||||
#*.wixproj   merge=binary
 | 
			
		||||
#*.modelproj merge=binary
 | 
			
		||||
#*.sqlproj   merge=binary
 | 
			
		||||
#*.wwaproj   merge=binary
 | 
			
		||||
 | 
			
		||||
###############################################################################
 | 
			
		||||
# behavior for image files
 | 
			
		||||
#
 | 
			
		||||
# image files are treated as binary by default.
 | 
			
		||||
###############################################################################
 | 
			
		||||
#*.jpg   binary
 | 
			
		||||
#*.png   binary
 | 
			
		||||
#*.gif   binary
 | 
			
		||||
 | 
			
		||||
###############################################################################
 | 
			
		||||
# diff behavior for common document formats
 | 
			
		||||
# 
 | 
			
		||||
# Convert binary document formats to text before diffing them. This feature
 | 
			
		||||
# is only available from the command line. Turn it on by uncommenting the 
 | 
			
		||||
# entries below.
 | 
			
		||||
###############################################################################
 | 
			
		||||
#*.doc   diff=astextplain
 | 
			
		||||
#*.DOC   diff=astextplain
 | 
			
		||||
#*.docx  diff=astextplain
 | 
			
		||||
#*.DOCX  diff=astextplain
 | 
			
		||||
#*.dot   diff=astextplain
 | 
			
		||||
#*.DOT   diff=astextplain
 | 
			
		||||
#*.pdf   diff=astextplain
 | 
			
		||||
#*.PDF   diff=astextplain
 | 
			
		||||
#*.rtf   diff=astextplain
 | 
			
		||||
#*.RTF   diff=astextplain
 | 
			
		||||
							
								
								
									
										30
									
								
								.github/workflows/build_latest.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								.github/workflows/build_latest.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
name: Build_Latest
 | 
			
		||||
 
 | 
			
		||||
on: [push]
 | 
			
		||||
 
 | 
			
		||||
jobs:
 | 
			
		||||
  build:
 | 
			
		||||
 
 | 
			
		||||
    runs-on: windows-latest
 | 
			
		||||
 
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v1
 | 
			
		||||
      name: Checkout Code
 | 
			
		||||
     
 | 
			
		||||
    - name: Setup MSBuild Path
 | 
			
		||||
      uses: warrenbuckley/Setup-MSBuild@v1
 | 
			
		||||
       
 | 
			
		||||
    - name: Setup NuGet
 | 
			
		||||
      uses: NuGet/setup-nuget@v1.0.2
 | 
			
		||||
     
 | 
			
		||||
    - name: Restore NuGet Packages
 | 
			
		||||
      run: nuget restore N_m3u8DL-CLI.sln
 | 
			
		||||
 
 | 
			
		||||
    - name: Build 
 | 
			
		||||
      run: msbuild N_m3u8DL-CLI.sln /p:Configuration=Release /p:DebugSymbols=false /p:DebugType=None
 | 
			
		||||
 
 | 
			
		||||
    - name: Upload Artifact
 | 
			
		||||
      uses: actions/upload-artifact@v1.0.0
 | 
			
		||||
      with:
 | 
			
		||||
        name: N_m3u8DL-CLI_latest
 | 
			
		||||
        path: N_m3u8DL-CLI\bin\Release\
 | 
			
		||||
							
								
								
									
										261
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
MIT License
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2019 nilaoda
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
SOFTWARE.
 | 
			
		||||
							
								
								
									
										25
									
								
								N_m3u8DL-CLI.sln
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								N_m3u8DL-CLI.sln
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
 | 
			
		||||
Microsoft Visual Studio Solution File, Format Version 12.00
 | 
			
		||||
# Visual Studio Version 16
 | 
			
		||||
VisualStudioVersion = 16.0.29215.179
 | 
			
		||||
MinimumVisualStudioVersion = 10.0.40219.1
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "N_m3u8DL-CLI", "N_m3u8DL-CLI\N_m3u8DL-CLI.csproj", "{4FB61439-B738-46AC-B3AF-2BF72150D057}"
 | 
			
		||||
EndProject
 | 
			
		||||
Global
 | 
			
		||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
			
		||||
		Debug|Any CPU = Debug|Any CPU
 | 
			
		||||
		Release|Any CPU = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 | 
			
		||||
		{4FB61439-B738-46AC-B3AF-2BF72150D057}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{4FB61439-B738-46AC-B3AF-2BF72150D057}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{4FB61439-B738-46AC-B3AF-2BF72150D057}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{4FB61439-B738-46AC-B3AF-2BF72150D057}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ExtensibilityGlobals) = postSolution
 | 
			
		||||
		SolutionGuid = {82B9270D-B7B2-4591-BF8A-5B4EBCD0EA8A}
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
EndGlobal
 | 
			
		||||
							
								
								
									
										6
									
								
								N_m3u8DL-CLI/App.config
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								N_m3u8DL-CLI/App.config
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<configuration>
 | 
			
		||||
    <startup> 
 | 
			
		||||
        
 | 
			
		||||
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup>
 | 
			
		||||
</configuration>
 | 
			
		||||
							
								
								
									
										80
									
								
								N_m3u8DL-CLI/CommandLineArgument.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								N_m3u8DL-CLI/CommandLineArgument.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * https://www.cnblogs.com/linxuanchen/p/c-sharp-command-line-argument-parser.html
 | 
			
		||||
     */
 | 
			
		||||
    public class CommandLineArgument
 | 
			
		||||
    {
 | 
			
		||||
        List<CommandLineArgument> _arguments;
 | 
			
		||||
 | 
			
		||||
        int _index;
 | 
			
		||||
 | 
			
		||||
        string _argumentText;
 | 
			
		||||
 | 
			
		||||
        public CommandLineArgument Next
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                if (_index < _arguments.Count - 1)
 | 
			
		||||
                {
 | 
			
		||||
                    return _arguments[_index + 1];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        public CommandLineArgument Previous
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                if (_index > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    return _arguments[_index - 1];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        internal CommandLineArgument(List<CommandLineArgument> args, int index, string argument)
 | 
			
		||||
        {
 | 
			
		||||
            _arguments = args;
 | 
			
		||||
            _index = index;
 | 
			
		||||
            _argumentText = argument;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public CommandLineArgument Take()
 | 
			
		||||
        {
 | 
			
		||||
            return Next;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IEnumerable<CommandLineArgument> Take(int count)
 | 
			
		||||
        {
 | 
			
		||||
            var list = new List<CommandLineArgument>();
 | 
			
		||||
            var parent = this;
 | 
			
		||||
            for (int i = 0; i < count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                var next = parent.Next;
 | 
			
		||||
                if (next == null)
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                list.Add(next);
 | 
			
		||||
 | 
			
		||||
                parent = next;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return list;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static implicit operator string(CommandLineArgument argument)
 | 
			
		||||
        {
 | 
			
		||||
            return argument._argumentText;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override string ToString()
 | 
			
		||||
        {
 | 
			
		||||
            return _argumentText;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								N_m3u8DL-CLI/CommandLineArgumentParser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								N_m3u8DL-CLI/CommandLineArgumentParser.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    public class CommandLineArgumentParser
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        List<CommandLineArgument> _arguments;
 | 
			
		||||
        public static CommandLineArgumentParser Parse(string[] args)
 | 
			
		||||
        {
 | 
			
		||||
            return new CommandLineArgumentParser(args);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public CommandLineArgumentParser(string[] args)
 | 
			
		||||
        {
 | 
			
		||||
            _arguments = new List<CommandLineArgument>();
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < args.Length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                _arguments.Add(new CommandLineArgument(_arguments, i, args[i]));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public CommandLineArgument Get(string argumentName)
 | 
			
		||||
        {
 | 
			
		||||
            return _arguments.FirstOrDefault(p => p == argumentName);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool Has(string argumentName)
 | 
			
		||||
        {
 | 
			
		||||
            return _arguments.Count(p => p == argumentName) > 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										318
									
								
								N_m3u8DL-CLI/Decode51CtoKey.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								N_m3u8DL-CLI/Decode51CtoKey.cs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										41
									
								
								N_m3u8DL-CLI/DecodeDdyun.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								N_m3u8DL-CLI/DecodeDdyun.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
using System.Security.Cryptography;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    class DecodeDdyun
 | 
			
		||||
    {
 | 
			
		||||
        public static string DecryptM3u8(byte[] byteArray)
 | 
			
		||||
        {
 | 
			
		||||
            string tmp = DecodeNfmovies.DecryptM3u8(byteArray);
 | 
			
		||||
            if (tmp.StartsWith("duoduo.key"))
 | 
			
		||||
            {
 | 
			
		||||
                tmp = Regex.Replace(tmp, @"#EXT-X-BYTERANGE:.*\s", "");
 | 
			
		||||
                tmp = tmp.Replace("https:", "jump/https:")
 | 
			
		||||
                    .Replace("inews.gtimg.com", "puui.qpic.cn");
 | 
			
		||||
            }
 | 
			
		||||
            return tmp;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //https://player.ddyunp.com/jQuery.min.js?v1.5
 | 
			
		||||
        public static string GetVaildM3u8Url(string url)
 | 
			
		||||
        {
 | 
			
		||||
            //url: https://hls.ddyunp.com/ddyun/id/1/key/playlist.m3u8
 | 
			
		||||
            string id = Regex.Match(url, @"\w{20,}").Value;
 | 
			
		||||
            string tm = Global.GetTimeStamp(false);
 | 
			
		||||
            string t = ((long.Parse(tm) / 0x186a0) * 0x64).ToString();
 | 
			
		||||
            string tmp = id + "duoduo" + "1" + t;
 | 
			
		||||
            MD5 md5 = MD5.Create();
 | 
			
		||||
            byte[] bs = Encoding.UTF8.GetBytes(tmp);
 | 
			
		||||
            byte[] hs = md5.ComputeHash(bs);
 | 
			
		||||
            StringBuilder sb = new StringBuilder();
 | 
			
		||||
            foreach (byte b in hs)
 | 
			
		||||
            {
 | 
			
		||||
                sb.Append(b.ToString("x2"));
 | 
			
		||||
            }
 | 
			
		||||
            string key = sb.ToString();
 | 
			
		||||
            return Regex.Replace(url, @"1/\w{20,}", "1/" + key);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										203
									
								
								N_m3u8DL-CLI/DecodeImooc.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								N_m3u8DL-CLI/DecodeImooc.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
			
		||||
using NiL.JS.BaseLibrary;
 | 
			
		||||
using NiL.JS.Core;
 | 
			
		||||
using NiL.JS.Extensions;
 | 
			
		||||
using System;
 | 
			
		||||
using Array = System.Array;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    /*
 | 
			
		||||
     * js代码来自:https://www.imooc.com/static/moco/player/3.0.6.3/mocoplayer.js?v=202006122046
 | 
			
		||||
     * 
 | 
			
		||||
     */
 | 
			
		||||
    class DecodeImooc
 | 
			
		||||
    {
 | 
			
		||||
        private static string JS = @"
 | 
			
		||||
function n(t, e) {
 | 
			
		||||
                function r(t, e) {
 | 
			
		||||
                    var r = '';
 | 
			
		||||
                    if ('object' == typeof t)
 | 
			
		||||
                        for (var n = 0; n < t.length; n++)
 | 
			
		||||
                            r += String.fromCharCode(t[n]);
 | 
			
		||||
                    t = r || t;
 | 
			
		||||
                    for (var i, o, a = new Uint8Array(t.length), s = e.length, n = 0; n < t.length; n++)
 | 
			
		||||
                        o = n % s,
 | 
			
		||||
                        i = t[n],
 | 
			
		||||
                        i = i.toString().charCodeAt(0),
 | 
			
		||||
                        a[n] = i ^ e.charCodeAt(o);
 | 
			
		||||
                    return a
 | 
			
		||||
                }
 | 
			
		||||
                function n(t) {
 | 
			
		||||
                    var e = '';
 | 
			
		||||
                    if ('object' == typeof t)
 | 
			
		||||
                        for (var r = 0; r < t.length; r++)
 | 
			
		||||
                            e += String.fromCharCode(t[r]);
 | 
			
		||||
                    t = e || t;
 | 
			
		||||
                    var n = new Uint8Array(t.length);
 | 
			
		||||
                    for (r = 0; r < t.length; r++)
 | 
			
		||||
                        n[r] = t[r].toString().charCodeAt(0);
 | 
			
		||||
                    var i, o, r = 0;
 | 
			
		||||
                    for (r = 0; r < n.length; r++)
 | 
			
		||||
                        0 != (i = n[r] % 3) && r + i < n.length && (o = n[r + 1],
 | 
			
		||||
                        n[r + 1] = n[r + i],
 | 
			
		||||
                        n[r + i] = o,
 | 
			
		||||
                        r = r + i + 1);
 | 
			
		||||
                    return n
 | 
			
		||||
                }
 | 
			
		||||
                function i(t) {
 | 
			
		||||
                    var e = '';
 | 
			
		||||
                    if ('object' == typeof t)
 | 
			
		||||
                        for (var r = 0; r < t.length; r++)
 | 
			
		||||
                            e += String.fromCharCode(t[r]);
 | 
			
		||||
                    t = e || t;
 | 
			
		||||
                    var n = new Uint8Array(t.length);
 | 
			
		||||
                    for (r = 0; r < t.length; r++)
 | 
			
		||||
                        n[r] = t[r].toString().charCodeAt(0);
 | 
			
		||||
                    var r = 0
 | 
			
		||||
                      , i = 0
 | 
			
		||||
                      , o = 0
 | 
			
		||||
                      , a = 0;
 | 
			
		||||
                    for (r = 0; r < n.length; r++)
 | 
			
		||||
                        o = n[r] % 2,
 | 
			
		||||
                        o && r++,
 | 
			
		||||
                        a++;
 | 
			
		||||
                    var s = new Uint8Array(a);
 | 
			
		||||
                    for (r = 0; r < n.length; r++)
 | 
			
		||||
                        o = n[r] % 2,
 | 
			
		||||
                        s[i++] = o ? n[r++] : n[r];
 | 
			
		||||
                    return s
 | 
			
		||||
                }
 | 
			
		||||
                function o(t, e) {
 | 
			
		||||
                    var r = 0
 | 
			
		||||
                      , n = 0
 | 
			
		||||
                      , i = 0
 | 
			
		||||
                      , o = 0
 | 
			
		||||
                      , a = '';
 | 
			
		||||
                    if ('object' == typeof t)
 | 
			
		||||
                        for (var r = 0; r < t.length; r++)
 | 
			
		||||
                            a += String.fromCharCode(t[r]);
 | 
			
		||||
                    t = a || t;
 | 
			
		||||
                    var s = new Uint8Array(t.length);
 | 
			
		||||
                    for (r = 0; r < t.length; r++)
 | 
			
		||||
                        s[r] = t[r].toString().charCodeAt(0);
 | 
			
		||||
                    for (r = 0; r < t.length; r++)
 | 
			
		||||
                        if (0 != (o = s[r] % 5) && 1 != o && r + o < s.length && (i = s[r + 1],
 | 
			
		||||
                        n = r + 2,
 | 
			
		||||
                        s[r + 1] = s[r + o],
 | 
			
		||||
                        s[o + r] = i,
 | 
			
		||||
                        (r = r + o + 1) - 2 > n))
 | 
			
		||||
                            for (; n < r - 2; n++)
 | 
			
		||||
                                s[n] = s[n] ^ e.charCodeAt(n % e.length);
 | 
			
		||||
                    for (r = 0; r < t.length; r++)
 | 
			
		||||
                        s[r] = s[r] ^ e.charCodeAt(r % e.length);
 | 
			
		||||
                    return s
 | 
			
		||||
                }
 | 
			
		||||
                for (var a = {
 | 
			
		||||
                    data: {
 | 
			
		||||
                        info: t
 | 
			
		||||
                    }
 | 
			
		||||
                }, s = {
 | 
			
		||||
                    q: r,
 | 
			
		||||
                    h: n,
 | 
			
		||||
                    m: i,
 | 
			
		||||
                    k: o
 | 
			
		||||
                }, l = a.data.info, u = l.substring(l.length - 4).split(''), c = 0; c < u.length; c++)
 | 
			
		||||
                    u[c] = u[c].toString().charCodeAt(0) % 4;
 | 
			
		||||
                u.reverse();
 | 
			
		||||
                for (var d = [], c = 0; c < u.length; c++)
 | 
			
		||||
                    d.push(l.substring(u[c] + 1, u[c] + 2)),
 | 
			
		||||
                    l = l.substring(0, u[c] + 1) + l.substring(u[c] + 2);
 | 
			
		||||
                a.data.encrypt_table = d,
 | 
			
		||||
                a.data.key_table = [];
 | 
			
		||||
                for (var c in a.data.encrypt_table)
 | 
			
		||||
                    'q' != a.data.encrypt_table[c] && 'k' != a.data.encrypt_table[c] || (a.data.key_table.push(l.substring(l.length - 12)),
 | 
			
		||||
                    l = l.substring(0, l.length - 12));
 | 
			
		||||
                a.data.key_table.reverse(),
 | 
			
		||||
                a.data.info = l;
 | 
			
		||||
                var f = new Array(-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1);
 | 
			
		||||
                a.data.info = function(t) {
 | 
			
		||||
                    var e, r, n, i, o, a, s;
 | 
			
		||||
                    for (a = t.length,
 | 
			
		||||
                    o = 0,
 | 
			
		||||
                    s = ''; o < a; ) {
 | 
			
		||||
                        do {
 | 
			
		||||
                            e = f[255 & t.charCodeAt(o++)]
 | 
			
		||||
                        } while (o < a && -1 == e);if (-1 == e)
 | 
			
		||||
                            break;
 | 
			
		||||
                        do {
 | 
			
		||||
                            r = f[255 & t.charCodeAt(o++)]
 | 
			
		||||
                        } while (o < a && -1 == r);if (-1 == r)
 | 
			
		||||
                            break;
 | 
			
		||||
                        s += String.fromCharCode(e << 2 | (48 & r) >> 4);
 | 
			
		||||
                        do {
 | 
			
		||||
                            if (61 == (n = 255 & t.charCodeAt(o++)))
 | 
			
		||||
                                return s;
 | 
			
		||||
                            n = f[n]
 | 
			
		||||
                        } while (o < a && -1 == n);if (-1 == n)
 | 
			
		||||
                            break;
 | 
			
		||||
                        s += String.fromCharCode((15 & r) << 4 | (60 & n) >> 2);
 | 
			
		||||
                        do {
 | 
			
		||||
                            if (61 == (i = 255 & t.charCodeAt(o++)))
 | 
			
		||||
                                return s;
 | 
			
		||||
                            i = f[i]
 | 
			
		||||
                        } while (o < a && -1 == i);if (-1 == i)
 | 
			
		||||
                            break;
 | 
			
		||||
                        s += String.fromCharCode((3 & n) << 6 | i)
 | 
			
		||||
                    }
 | 
			
		||||
                    return s
 | 
			
		||||
                }(a.data.info);
 | 
			
		||||
                for (var c in a.data.encrypt_table) {
 | 
			
		||||
                    var h = a.data.encrypt_table[c];
 | 
			
		||||
                    if ('q' == h || 'k' == h) {
 | 
			
		||||
                        var p = a.data.key_table.pop();
 | 
			
		||||
                        a.data.info = s[a.data.encrypt_table[c]](a.data.info, p)
 | 
			
		||||
                    } else
 | 
			
		||||
                        a.data.info = s[a.data.encrypt_table[c]](a.data.info)
 | 
			
		||||
                }
 | 
			
		||||
                if (e)
 | 
			
		||||
                    return a.data.info;
 | 
			
		||||
                var g = '';
 | 
			
		||||
                for (c = 0; c < a.data.info.length; c++)
 | 
			
		||||
                    g += String.fromCharCode(a.data.info[c]);
 | 
			
		||||
                return g
 | 
			
		||||
            }
 | 
			
		||||
            function Uint8ArrayToString(fileData){
 | 
			
		||||
              var dataString = '';
 | 
			
		||||
              for (var i = 0; i < fileData.length; i++) {
 | 
			
		||||
                dataString += Number(fileData[i]) + ',';
 | 
			
		||||
              }
 | 
			
		||||
              return dataString;
 | 
			
		||||
            }
 | 
			
		||||
            function decodeKey(resp){
 | 
			
		||||
                var string = eval('('+resp+')');
 | 
			
		||||
                //return btoa(String.fromCharCode.apply(null, new Uint8Array(n(string.data.info, 1))));
 | 
			
		||||
                return Uint8ArrayToString(new Uint8Array(n(string.data.info, 1)));
 | 
			
		||||
            }
 | 
			
		||||
            function decodeM3u8(resp){
 | 
			
		||||
                var string = eval('('+resp+')');
 | 
			
		||||
                return n(string.data.info);
 | 
			
		||||
            }
 | 
			
		||||
            ";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public static string DecodeM3u8(string resp)
 | 
			
		||||
        {
 | 
			
		||||
            var context = new Context();
 | 
			
		||||
            context.Eval(JS);
 | 
			
		||||
            var concatFunction = context.GetVariable("decodeM3u8").As<Function>();
 | 
			
		||||
            string m3u8 = concatFunction.Call(new Arguments { resp }).ToString();
 | 
			
		||||
            return m3u8;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static string DecodeKey(string resp)
 | 
			
		||||
        {
 | 
			
		||||
            var context = new Context();
 | 
			
		||||
            context.Eval(JS);
 | 
			
		||||
            var concatFunction = context.GetVariable("decodeKey").As<Function>();
 | 
			
		||||
            string key = concatFunction.Call(new Arguments { resp }).ToString();
 | 
			
		||||
            byte[] v = Array.ConvertAll(key.Trim(',').Split(','), s => (byte)int.Parse(s));
 | 
			
		||||
            string realKey = Convert.ToBase64String(v);
 | 
			
		||||
            return realKey;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								N_m3u8DL-CLI/DecodeNfmovies.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								N_m3u8DL-CLI/DecodeNfmovies.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    class DecodeNfmovies
 | 
			
		||||
    {
 | 
			
		||||
        //https://jx.nfmovies.com/hls.min.js
 | 
			
		||||
        public static string DecryptM3u8(byte[] byteArray)
 | 
			
		||||
        {
 | 
			
		||||
            var t = byteArray;
 | 
			
		||||
            var decrypt = "";
 | 
			
		||||
            if (137 == t[0] && 80 == t[1] && 130 == t[354] && 96 == t[353]) t = t.Skip(355).ToArray();
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (137 != t[0] || 80 != t[1] || 130 != t[394] || 96 != t[393])
 | 
			
		||||
                {
 | 
			
		||||
                    for (var i = 0; i < t.Length; i++) decrypt += Convert.ToChar(t[i]);
 | 
			
		||||
                    return decrypt;
 | 
			
		||||
                }
 | 
			
		||||
                t = t.Skip(395).ToArray();
 | 
			
		||||
            }
 | 
			
		||||
            using (var zipStream =
 | 
			
		||||
                new System.IO.Compression.GZipStream(new MemoryStream(t), System.IO.Compression.CompressionMode.Decompress))
 | 
			
		||||
            {
 | 
			
		||||
                using (StreamReader sr = new StreamReader(zipStream, Encoding.UTF8))
 | 
			
		||||
                {
 | 
			
		||||
                    decrypt = sr.ReadToEnd();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return decrypt;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								N_m3u8DL-CLI/Decrypter.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								N_m3u8DL-CLI/Decrypter.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Security.Cryptography;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    class Decrypter
 | 
			
		||||
    {
 | 
			
		||||
        public static byte[] AES128Decrypt(string filePath, byte[] keyByte, byte[] ivByte, CipherMode mode = CipherMode.CBC)
 | 
			
		||||
        {
 | 
			
		||||
            FileStream fs = new FileStream(filePath, FileMode.Open);
 | 
			
		||||
            //获取文件大小
 | 
			
		||||
            long size = fs.Length;
 | 
			
		||||
            byte[] inBuff = new byte[size];
 | 
			
		||||
            fs.Read(inBuff, 0, inBuff.Length);
 | 
			
		||||
            fs.Close();
 | 
			
		||||
 | 
			
		||||
            Aes dcpt = Aes.Create();
 | 
			
		||||
            dcpt.BlockSize = 128;
 | 
			
		||||
            dcpt.KeySize = 128;
 | 
			
		||||
            dcpt.Key = keyByte;
 | 
			
		||||
            dcpt.IV = ivByte;
 | 
			
		||||
            dcpt.Mode = mode;
 | 
			
		||||
            dcpt.Padding = PaddingMode.PKCS7;
 | 
			
		||||
 | 
			
		||||
            ICryptoTransform cTransform = dcpt.CreateDecryptor();
 | 
			
		||||
            Byte[] resultArray = cTransform.TransformFinalBlock(inBuff, 0, inBuff.Length);
 | 
			
		||||
            return resultArray;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static byte[] AES128Decrypt(byte[] encryptedBuff, byte[] keyByte, byte[] ivByte, CipherMode mode = CipherMode.CBC)
 | 
			
		||||
        {
 | 
			
		||||
            byte[] inBuff = encryptedBuff;
 | 
			
		||||
 | 
			
		||||
            Aes dcpt = Aes.Create();
 | 
			
		||||
            dcpt.BlockSize = 128;
 | 
			
		||||
            dcpt.KeySize = 128;
 | 
			
		||||
            dcpt.Key = keyByte;
 | 
			
		||||
            dcpt.IV = ivByte;
 | 
			
		||||
            dcpt.Mode = mode;
 | 
			
		||||
            dcpt.Padding = PaddingMode.PKCS7;
 | 
			
		||||
 | 
			
		||||
            ICryptoTransform cTransform = dcpt.CreateDecryptor();
 | 
			
		||||
            Byte[] resultArray = cTransform.TransformFinalBlock(inBuff, 0, inBuff.Length);
 | 
			
		||||
            return resultArray;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static byte[] HexStringToBytes(string hexStr)
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrEmpty(hexStr))
 | 
			
		||||
            {
 | 
			
		||||
                return new byte[0];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (hexStr.StartsWith("0x") || hexStr.StartsWith("0X")) 
 | 
			
		||||
            {
 | 
			
		||||
                hexStr = hexStr.Remove(0, 2);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int count = hexStr.Length;
 | 
			
		||||
 | 
			
		||||
            if (count % 2 == 1)
 | 
			
		||||
            {
 | 
			
		||||
                throw new ArgumentException("Invalid length of bytes:" + count);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int byteCount = count / 2;
 | 
			
		||||
            byte[] result = new byte[byteCount];
 | 
			
		||||
            for (int ii = 0; ii < byteCount; ++ii)
 | 
			
		||||
            {
 | 
			
		||||
                var tempBytes = Byte.Parse(hexStr.Substring(2 * ii, 2), System.Globalization.NumberStyles.HexNumber);
 | 
			
		||||
                result[ii] = tempBytes;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										696
									
								
								N_m3u8DL-CLI/DownloadManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										696
									
								
								N_m3u8DL-CLI/DownloadManager.cs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										252
									
								
								N_m3u8DL-CLI/Downloader.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								N_m3u8DL-CLI/Downloader.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,252 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.ComponentModel;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    class Downloader
 | 
			
		||||
    {
 | 
			
		||||
        private int timeOut = 0;
 | 
			
		||||
        private int retry = 5;
 | 
			
		||||
        private int count = 0;
 | 
			
		||||
        private int segIndex = 0;
 | 
			
		||||
        private double segDur = 0;
 | 
			
		||||
        private string fileUrl = string.Empty;
 | 
			
		||||
        private string savePath = string.Empty;
 | 
			
		||||
        private string headers = string.Empty;
 | 
			
		||||
        private string method = string.Empty;
 | 
			
		||||
        private string key = string.Empty;
 | 
			
		||||
        private string iv = string.Empty;
 | 
			
		||||
        private string liveFile = string.Empty;
 | 
			
		||||
        private long expectByte = -1;
 | 
			
		||||
        private long startByte = 0;
 | 
			
		||||
        private bool isLive = false;
 | 
			
		||||
        private bool isDone = false;
 | 
			
		||||
        private bool firstSeg = true;
 | 
			
		||||
        private FileStream liveStream = null;
 | 
			
		||||
 | 
			
		||||
        public string FileUrl { get => fileUrl; set => fileUrl = value; }
 | 
			
		||||
        public string SavePath { get => savePath; set => savePath = value; }
 | 
			
		||||
        public string Headers { get => headers; set => headers = value; }
 | 
			
		||||
        public string Method { get => method; set => method = value; }
 | 
			
		||||
        public string Key { get => key; set => key = value; }
 | 
			
		||||
        public string Iv { get => iv; set => iv = value; }
 | 
			
		||||
        public bool IsLive { get => isLive; set => isLive = value; }
 | 
			
		||||
        public int Retry { get => retry; set => retry = value; }
 | 
			
		||||
        public bool IsDone { get => isDone; set => isDone = value; }
 | 
			
		||||
        public int SegIndex { get => segIndex; set => segIndex = value; }
 | 
			
		||||
        public int TimeOut { get => timeOut; set => timeOut = value; }
 | 
			
		||||
        public FileStream LiveStream { get => liveStream; set => liveStream = value; }
 | 
			
		||||
        public string LiveFile { get => liveFile; set => liveFile = value; }
 | 
			
		||||
        public long ExpectByte { get => expectByte; set => expectByte = value; }
 | 
			
		||||
        public long StartByte { get => startByte; set => startByte = value; }
 | 
			
		||||
        public double SegDur { get => segDur; set => segDur = value; }
 | 
			
		||||
 | 
			
		||||
        //重写WebClinet
 | 
			
		||||
        //private class WebClient : System.Net.WebClient
 | 
			
		||||
        //{
 | 
			
		||||
        //    protected override WebRequest GetWebRequest(Uri uri)
 | 
			
		||||
        //    {
 | 
			
		||||
        //        WebRequest lWebRequest = base.GetWebRequest(uri);
 | 
			
		||||
        //        lWebRequest.Timeout = TimeOut;
 | 
			
		||||
        //        ((HttpWebRequest)lWebRequest).ReadWriteTimeout = TimeOut;
 | 
			
		||||
        //        return lWebRequest;
 | 
			
		||||
        //    }
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        //WebClient client = new WebClient();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public void Down()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                //直播下载
 | 
			
		||||
                if (IsLive)
 | 
			
		||||
                {
 | 
			
		||||
                    IsDone = false;  //设置为未完成下载
 | 
			
		||||
 | 
			
		||||
                    if (Method == "NONE" || method.Contains("NOTSUPPORTED")) 
 | 
			
		||||
                    {
 | 
			
		||||
                        LOGGER.PrintLine("<" + SegIndex + " Downloading>");
 | 
			
		||||
                        LOGGER.WriteLine("<" + SegIndex + " Downloading>");
 | 
			
		||||
                        byte[] segBuff = Global.HttpDownloadFileToBytes(fileUrl, Headers, TimeOut);
 | 
			
		||||
                        //byte[] segBuff = Global.WebClientDownloadToBytes(fileUrl, Headers);
 | 
			
		||||
                        Global.AppendBytesToFileStreamAndDoNotClose(LiveStream, segBuff);
 | 
			
		||||
                        LOGGER.PrintLine("<" + SegIndex + " Complete>\r\n");
 | 
			
		||||
                        LOGGER.WriteLine("<" + SegIndex + " Complete>");
 | 
			
		||||
                        IsDone = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (Method == "AES-128")
 | 
			
		||||
                    {
 | 
			
		||||
                        LOGGER.PrintLine("<" + SegIndex + " Downloading>");
 | 
			
		||||
                        LOGGER.WriteLine("<" + SegIndex + " Downloading>");
 | 
			
		||||
                        byte[] encryptedBuff = Global.HttpDownloadFileToBytes(fileUrl, Headers, TimeOut);
 | 
			
		||||
                        //byte[] encryptedBuff = Global.WebClientDownloadToBytes(fileUrl, Headers);
 | 
			
		||||
                        byte[] decryptBuff = null;
 | 
			
		||||
                        decryptBuff = Decrypter.AES128Decrypt(
 | 
			
		||||
                            encryptedBuff,
 | 
			
		||||
                            Convert.FromBase64String(Key),
 | 
			
		||||
                            Decrypter.HexStringToBytes(Iv)
 | 
			
		||||
                            );
 | 
			
		||||
                        Global.AppendBytesToFileStreamAndDoNotClose(LiveStream, decryptBuff);
 | 
			
		||||
                        LOGGER.PrintLine("<" + SegIndex + " Complete>\r\n");
 | 
			
		||||
                        LOGGER.WriteLine("<" + SegIndex + " Complete>");
 | 
			
		||||
                        IsDone = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //LOGGER.PrintLine("不支持这种加密方式!", LOGGER.Error);
 | 
			
		||||
                        IsDone = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    if (firstSeg && Global.FileSize(LiveFile) != 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        //LOGGER.STOPLOG = false;  //记录日志
 | 
			
		||||
                        foreach (string ss in (string[])Global.GetVideoInfo(LiveFile).ToArray(typeof(string)))
 | 
			
		||||
                        {
 | 
			
		||||
                            LOGGER.WriteLine(ss.Trim());
 | 
			
		||||
                        }
 | 
			
		||||
                        firstSeg = false;
 | 
			
		||||
                        //LOGGER.STOPLOG = true;  //停止记录日志
 | 
			
		||||
                    }
 | 
			
		||||
                    HLSLiveDownloader.REC_DUR += SegDur;
 | 
			
		||||
                    if (HLSLiveDownloader.REC_DUR_LIMIT != -1 && HLSLiveDownloader.REC_DUR >= HLSLiveDownloader.REC_DUR_LIMIT) 
 | 
			
		||||
                    {
 | 
			
		||||
                        LOGGER.PrintLine(strings.recordLimitReached, LOGGER.Warning);
 | 
			
		||||
                        LOGGER.WriteLine(strings.recordLimitReached);
 | 
			
		||||
                        Environment.Exit(0); //正常退出
 | 
			
		||||
                    }
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                //点播下载
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    if (!Directory.Exists(Path.GetDirectoryName(SavePath)))
 | 
			
		||||
                        Directory.CreateDirectory(Path.GetDirectoryName(SavePath)); //新建文件夹  
 | 
			
		||||
                    //是否存在文件,存在则不下载
 | 
			
		||||
                    if (File.Exists(Path.GetDirectoryName(savePath) + "\\" + Path.GetFileNameWithoutExtension(savePath) + ".ts"))
 | 
			
		||||
                    {
 | 
			
		||||
                        Global.BYTEDOWN++; //防止被速度监控程序杀死
 | 
			
		||||
                        //Console.WriteLine("Exists " + Path.GetFileNameWithoutExtension(savePath) + ".ts");
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    //Console.WriteLine("开始下载 " + fileUrl);
 | 
			
		||||
                    //本地文件
 | 
			
		||||
                    if (fileUrl.StartsWith("file:"))
 | 
			
		||||
                    {
 | 
			
		||||
                        Uri t = new Uri(fileUrl);
 | 
			
		||||
                        fileUrl = t.LocalPath;
 | 
			
		||||
                        if (File.Exists(fileUrl))
 | 
			
		||||
                        {
 | 
			
		||||
                            if (ExpectByte == -1)  //没有RANGE
 | 
			
		||||
                            {
 | 
			
		||||
                                FileInfo fi = new FileInfo(fileUrl);
 | 
			
		||||
                                fi.CopyTo(savePath);
 | 
			
		||||
                                Global.BYTEDOWN += fi.Length;
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                FileStream stream = new FileInfo(fileUrl).OpenRead();
 | 
			
		||||
                                //seek文件
 | 
			
		||||
                                stream.Seek(StartByte, SeekOrigin.Begin);
 | 
			
		||||
                                Byte[] buffer = new Byte[ExpectByte];
 | 
			
		||||
                                //从流中读取字节块并将该数据写入给定缓冲区buffer中
 | 
			
		||||
                                stream.Read(buffer, 0, Convert.ToInt32(buffer.Length));
 | 
			
		||||
                                stream.Close();
 | 
			
		||||
                                //写出文件
 | 
			
		||||
                                MemoryStream m = new MemoryStream(buffer);
 | 
			
		||||
                                FileStream fs = new FileStream(savePath, FileMode.OpenOrCreate);
 | 
			
		||||
                                m.WriteTo(fs);
 | 
			
		||||
                                m.Close();
 | 
			
		||||
                                fs.Close();
 | 
			
		||||
                                m = null;
 | 
			
		||||
                                fs = null;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //下载
 | 
			
		||||
                        Global.HttpDownloadFile(fileUrl, savePath, TimeOut, Headers, StartByte, ExpectByte);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if (File.Exists(savePath) && Global.ShouldStop == false) 
 | 
			
		||||
                {
 | 
			
		||||
                    FileInfo fi = new FileInfo(savePath);
 | 
			
		||||
                    if (Method == "NONE" || method.Contains("NOTSUPPORTED"))
 | 
			
		||||
                    {
 | 
			
		||||
                        fi.MoveTo(Path.GetDirectoryName(savePath) + "\\" + Path.GetFileNameWithoutExtension(savePath) + ".ts");
 | 
			
		||||
                        DownloadManager.DownloadedSize += fi.Length;
 | 
			
		||||
                        //Console.WriteLine(Path.GetFileNameWithoutExtension(savePath) + " Completed.");
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (File.Exists(fi.FullName)
 | 
			
		||||
                        && Method == "AES-128") 
 | 
			
		||||
                    {
 | 
			
		||||
                        //解密
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            byte[] decryptBuff = null;
 | 
			
		||||
                            if(fileUrl.Contains(".51cto.com/")) //使用AES-128-ECB模式解密
 | 
			
		||||
                            {
 | 
			
		||||
                                decryptBuff = Decrypter.AES128Decrypt(
 | 
			
		||||
                                    fi.FullName,
 | 
			
		||||
                                    Convert.FromBase64String(Key),
 | 
			
		||||
                                    Decrypter.HexStringToBytes(Iv),
 | 
			
		||||
                                    System.Security.Cryptography.CipherMode.ECB
 | 
			
		||||
                                    );
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                decryptBuff = Decrypter.AES128Decrypt(
 | 
			
		||||
                                    fi.FullName,
 | 
			
		||||
                                    Convert.FromBase64String(Key),
 | 
			
		||||
                                    Decrypter.HexStringToBytes(Iv)
 | 
			
		||||
                                    );
 | 
			
		||||
                            }
 | 
			
		||||
                            FileStream fs = new FileStream(Path.GetDirectoryName(savePath) + "\\" + Path.GetFileNameWithoutExtension(savePath) + ".ts", FileMode.Create);
 | 
			
		||||
                            fs.Write(decryptBuff, 0, decryptBuff.Length);
 | 
			
		||||
                            fs.Close();
 | 
			
		||||
                            DownloadManager.DownloadedSize += fi.Length;
 | 
			
		||||
                            fi.Delete();
 | 
			
		||||
                            //Console.WriteLine(Path.GetFileNameWithoutExtension(savePath) + " Completed & Decrypted.");
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (Exception ex)
 | 
			
		||||
                        {
 | 
			
		||||
                            LOGGER.PrintLine(ex.Message, LOGGER.Error);
 | 
			
		||||
                            LOGGER.WriteLineError(ex.Message);
 | 
			
		||||
                            Thread.Sleep(3000);
 | 
			
		||||
                            Environment.Exit(-1);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        LOGGER.WriteLineError(strings.SomethingWasWrong);
 | 
			
		||||
                        LOGGER.PrintLine(strings.SomethingWasWrong, LOGGER.Error);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                LOGGER.WriteLineError(ex.Message);
 | 
			
		||||
                if (ex.Message.Contains("404") || ex.Message.Contains("400"))//(400) 错误的请求,片段过期会提示400错误
 | 
			
		||||
                {
 | 
			
		||||
                    IsDone = true;
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                else if (IsLive && count++ < Retry) 
 | 
			
		||||
                {
 | 
			
		||||
                    Thread.Sleep(2000);//直播一般3-6秒一个片段
 | 
			
		||||
                    Down();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										178
									
								
								N_m3u8DL-CLI/FFmpeg.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								N_m3u8DL-CLI/FFmpeg.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    class FFmpeg
 | 
			
		||||
    {
 | 
			
		||||
        public static string FFMPEG_PATH = "ffmpeg";
 | 
			
		||||
 | 
			
		||||
        private static string outPutPath = string.Empty;
 | 
			
		||||
        private static string reportFile = string.Empty;
 | 
			
		||||
        private static bool useAACFilter = false;  //是否启用滤镜
 | 
			
		||||
        private static bool writeDate = true;  //是否写入录制日期
 | 
			
		||||
        public static string OutPutPath { get => outPutPath; set => outPutPath = value; }
 | 
			
		||||
        public static string ReportFile { get => reportFile; set => reportFile = value; }
 | 
			
		||||
        public static bool UseAACFilter { get => useAACFilter; set => useAACFilter = value; }
 | 
			
		||||
        public static bool WriteDate { get => writeDate; set => writeDate = value; }
 | 
			
		||||
 | 
			
		||||
        public static void Merge(string[] files, string muxFormat, bool fastStart,
 | 
			
		||||
            string poster = "", string audioName = "", string title = "",
 | 
			
		||||
            string copyright = "", string comment = "", string encodingTool = "")
 | 
			
		||||
        {
 | 
			
		||||
            //同名文件已存在的共存策略
 | 
			
		||||
            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=\"" + DateTime.Now.ToString("o") + "\"" : "") +
 | 
			
		||||
                        " -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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void ConvertToMPEGTS(string file)
 | 
			
		||||
        {
 | 
			
		||||
            if (Global.VIDEO_TYPE == "H264")
 | 
			
		||||
            {
 | 
			
		||||
                Run(FFMPEG_PATH,
 | 
			
		||||
                    "-loglevel quiet -i \"" + file + "\" -map 0 -c copy -copy_unknown -f mpegts -bsf:v h264_mp4toannexb \""
 | 
			
		||||
                    + Path.GetFileNameWithoutExtension(file) + "[MPEGTS].ts\"", 
 | 
			
		||||
                    Path.GetDirectoryName(file));
 | 
			
		||||
                if (File.Exists(Path.GetDirectoryName(file) + "\\" + Path.GetFileNameWithoutExtension(file) + "[MPEGTS].ts"))
 | 
			
		||||
                {
 | 
			
		||||
                    File.Delete(file);
 | 
			
		||||
                    File.Move(Path.GetDirectoryName(file) + "\\" + Path.GetFileNameWithoutExtension(file) + "[MPEGTS].ts", file);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else if (Global.VIDEO_TYPE == "H265")
 | 
			
		||||
            {
 | 
			
		||||
                Run(FFMPEG_PATH,
 | 
			
		||||
                    "-loglevel quiet -i \"" + file + "\" -map 0 -c copy -copy_unknown -f mpegts -bsf:v hevc_mp4toannexb \""
 | 
			
		||||
                    + Path.GetFileNameWithoutExtension(file) + "[MPEGTS].ts\"",
 | 
			
		||||
                    Path.GetDirectoryName(file));
 | 
			
		||||
                if (File.Exists(Path.GetDirectoryName(file) + "\\" + Path.GetFileNameWithoutExtension(file) + "[MPEGTS].ts"))
 | 
			
		||||
                {
 | 
			
		||||
                    File.Delete(file);
 | 
			
		||||
                    File.Move(Path.GetDirectoryName(file) + "\\" + Path.GetFileNameWithoutExtension(file) + "[MPEGTS].ts", file);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                LOGGER.WriteLineError("Unkown Video Type");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Run(string path, string args, string workDir)
 | 
			
		||||
        {
 | 
			
		||||
            string nowDir = Directory.GetCurrentDirectory();  //当前工作路径
 | 
			
		||||
            Directory.SetCurrentDirectory(workDir);
 | 
			
		||||
            Process p = new Process();//建立外部调用线程
 | 
			
		||||
            p.StartInfo.FileName = path;//要调用外部程序的绝对路径
 | 
			
		||||
            Environment.SetEnvironmentVariable("FFREPORT", "file=" + ReportFile + ":level=32"); //兼容XP系统
 | 
			
		||||
            //p.StartInfo.Environment.Add("FFREPORT", "file=" + ReportFile + ":level=32");
 | 
			
		||||
            p.StartInfo.Arguments = args;//参数(这里就是FFMPEG的参数了)
 | 
			
		||||
            p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN)
 | 
			
		||||
            p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的)
 | 
			
		||||
            p.StartInfo.CreateNoWindow = false;//不创建进程窗口
 | 
			
		||||
            p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
 | 
			
		||||
            p.StartInfo.StandardErrorEncoding = Encoding.UTF8;
 | 
			
		||||
            p.Start();//启动线程
 | 
			
		||||
            p.BeginErrorReadLine();//开始异步读取
 | 
			
		||||
            p.WaitForExit();//阻塞等待进程结束
 | 
			
		||||
            p.Close();//关闭进程
 | 
			
		||||
            p.Dispose();//释放资源
 | 
			
		||||
            Environment.SetEnvironmentVariable("FFREPORT", null); //兼容XP系统
 | 
			
		||||
            Directory.SetCurrentDirectory(nowDir);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void Output(object sendProcess, DataReceivedEventArgs output)
 | 
			
		||||
        {
 | 
			
		||||
            if (!String.IsNullOrEmpty(output.Data))
 | 
			
		||||
            {
 | 
			
		||||
                LOGGER.PrintLine(output.Data, LOGGER.Warning);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static bool CheckMPEGTS(string file)
 | 
			
		||||
        {
 | 
			
		||||
            //放行杜比视界或纯音频文件
 | 
			
		||||
            if (Global.VIDEO_TYPE == "DV" || Global.AUDIO_TYPE != "")
 | 
			
		||||
                return true;
 | 
			
		||||
            //如果是多分片,也认为不是MPEGTS
 | 
			
		||||
            if (DownloadManager.PartsCount > 1)
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read)) 
 | 
			
		||||
            {
 | 
			
		||||
                byte[] firstByte = new byte[1];
 | 
			
		||||
                fs.Read(firstByte, 0, 1);
 | 
			
		||||
                //第一字节的16进制字符串
 | 
			
		||||
                string _1_byte_str = Convert.ToString(firstByte[0], 16);
 | 
			
		||||
                //syncword不为47就不处理
 | 
			
		||||
                if (_1_byte_str != "47")
 | 
			
		||||
                    return false;
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1124
									
								
								N_m3u8DL-CLI/Global.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1124
									
								
								N_m3u8DL-CLI/Global.cs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										153
									
								
								N_m3u8DL-CLI/HLSLiveDownloader.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								N_m3u8DL-CLI/HLSLiveDownloader.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,153 @@
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Timers;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    class HLSLiveDownloader
 | 
			
		||||
    {
 | 
			
		||||
        public static int REC_DUR_LIMIT = -1; //默认不限制录制时长
 | 
			
		||||
        public static double REC_DUR = 0; //已录制时长
 | 
			
		||||
        private string liveFile = string.Empty;
 | 
			
		||||
        private string jsonFile = string.Empty;
 | 
			
		||||
        private string headers = string.Empty;
 | 
			
		||||
        private string downDir = string.Empty;
 | 
			
		||||
        private FileStream liveStream = null;
 | 
			
		||||
        private double targetduration = 10;
 | 
			
		||||
        private bool isFirstJson = true;
 | 
			
		||||
 | 
			
		||||
        public double TotalDuration { get; set; }
 | 
			
		||||
        public string Headers { get => headers; set => headers = value; }
 | 
			
		||||
        public string DownDir { get => downDir; set => downDir = value; }
 | 
			
		||||
        public FileStream LiveStream { get => liveStream; set => liveStream = value; }
 | 
			
		||||
        public string LiveFile { get => liveFile; set => liveFile = value; }
 | 
			
		||||
 | 
			
		||||
        ArrayList toDownList = new ArrayList();  //所有待下载的列表
 | 
			
		||||
        System.Timers.Timer timer = new System.Timers.Timer();
 | 
			
		||||
        Downloader sd = new Downloader();  //只有一个实例
 | 
			
		||||
 | 
			
		||||
        public void TimerStart()
 | 
			
		||||
        {
 | 
			
		||||
            timer.Enabled = true;
 | 
			
		||||
            //timer.Interval = (targetduration - 2) * 1000; //执行间隔时间,单位为毫秒
 | 
			
		||||
            timer.Start();
 | 
			
		||||
            timer.Elapsed += new ElapsedEventHandler(UpdateList);
 | 
			
		||||
            UpdateList(timer, new EventArgs());  //立即执行一次
 | 
			
		||||
            Record();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void TimerStop()
 | 
			
		||||
        {
 | 
			
		||||
            timer.Stop();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //更新列表
 | 
			
		||||
        private void UpdateList(object source, EventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            jsonFile = Path.Combine(DownDir, "meta.json");
 | 
			
		||||
            if (!File.Exists(jsonFile)) 
 | 
			
		||||
            {
 | 
			
		||||
                TimerStop();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            string jsonContent = File.ReadAllText(jsonFile);
 | 
			
		||||
            JObject initJson = JObject.Parse(jsonContent);
 | 
			
		||||
            string m3u8Url = initJson["m3u8"].Value<string>();
 | 
			
		||||
            targetduration = initJson["m3u8Info"]["targetDuration"].Value<double>();
 | 
			
		||||
            TotalDuration = initJson["m3u8Info"]["totalDuration"].Value<double>();
 | 
			
		||||
            timer.Interval = (TotalDuration - targetduration) * 1000;//设置定时器运行间隔
 | 
			
		||||
            JArray lastSegments = JArray.Parse(initJson["m3u8Info"]["segments"][0].ToString().Trim());  //上次的分段,用于比对新分段
 | 
			
		||||
            ArrayList tempList = new ArrayList();  //所有待下载的列表
 | 
			
		||||
            tempList.Clear();
 | 
			
		||||
            foreach (JObject seg in lastSegments)
 | 
			
		||||
            {
 | 
			
		||||
                tempList.Add(seg.ToString());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(isFirstJson)
 | 
			
		||||
            {
 | 
			
		||||
                toDownList = tempList;
 | 
			
		||||
                isFirstJson = false;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Parser parser = new Parser();
 | 
			
		||||
            parser.DownDir = Path.GetDirectoryName(jsonFile);
 | 
			
		||||
            parser.M3u8Url = m3u8Url;
 | 
			
		||||
            parser.LiveStream = true;
 | 
			
		||||
            parser.Parse();  //产生新的json文件
 | 
			
		||||
 | 
			
		||||
            jsonContent = File.ReadAllText(jsonFile);
 | 
			
		||||
            initJson = JObject.Parse(jsonContent);
 | 
			
		||||
            JArray segments = JArray.Parse(initJson["m3u8Info"]["segments"][0].ToString());  //大分组
 | 
			
		||||
            foreach (JObject seg in segments)
 | 
			
		||||
            {
 | 
			
		||||
                if (!tempList.Contains(seg.ToString()))
 | 
			
		||||
                {
 | 
			
		||||
                    toDownList.Add(seg.ToString());  //加入真正的待下载队列
 | 
			
		||||
                    //Console.WriteLine(seg.ToString());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (toDownList.Count > 0)
 | 
			
		||||
                Record();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //public void TryDownload()
 | 
			
		||||
        //{
 | 
			
		||||
        //    Thread t = new Thread(Download);
 | 
			
		||||
        //    while (toDownList.Count != 0)
 | 
			
		||||
        //    {
 | 
			
		||||
        //        t = new Thread(Download);
 | 
			
		||||
        //        t.Start();
 | 
			
		||||
        //        t.Join();
 | 
			
		||||
        //        while (sd.IsDone != true) ;  //忙等待
 | 
			
		||||
        //        if (toDownList.Count > 0)
 | 
			
		||||
        //            toDownList.RemoveAt(0);  //下完删除一项
 | 
			
		||||
        //    }
 | 
			
		||||
        //    Console.WriteLine("Waiting...");
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        private void Record()
 | 
			
		||||
        {
 | 
			
		||||
            while (toDownList.Count > 0 && (sd.FileUrl != "" ? sd.IsDone : true)) 
 | 
			
		||||
            {
 | 
			
		||||
                JObject info = JObject.Parse(toDownList[0].ToString());
 | 
			
		||||
                int index = info["index"].Value<int>();
 | 
			
		||||
                sd.FileUrl = info["segUri"].Value<string>();
 | 
			
		||||
                sd.Method = info["method"].Value<string>();
 | 
			
		||||
                if (sd.Method != "NONE")
 | 
			
		||||
                {
 | 
			
		||||
                    sd.Key = info["key"].Value<string>();
 | 
			
		||||
                    sd.Iv = info["iv"].Value<string>();
 | 
			
		||||
                }
 | 
			
		||||
                sd.TimeOut = (int)timer.Interval - 1000;//超时时间不超过下次执行时间
 | 
			
		||||
                sd.SegIndex = index;
 | 
			
		||||
                sd.Headers = Headers;
 | 
			
		||||
                sd.SegDur = info["duration"].Value<double>();
 | 
			
		||||
                sd.IsLive = true;  //标记为直播
 | 
			
		||||
                sd.LiveFile = LiveFile;
 | 
			
		||||
                sd.LiveStream = LiveStream;
 | 
			
		||||
                sd.Down();  //开始下载
 | 
			
		||||
                while (sd.IsDone != true) { Thread.Sleep(1); };  //忙等待 Thread.Sleep(1) 可防止cpu 100% 防止电脑风扇狂转
 | 
			
		||||
                if (toDownList.Count > 0)
 | 
			
		||||
                    toDownList.RemoveAt(0);  //下完删除一项
 | 
			
		||||
            }
 | 
			
		||||
            LOGGER.PrintLine("Waiting...", LOGGER.Warning);
 | 
			
		||||
            LOGGER.WriteLine("Waiting...");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //检测是否有新分片
 | 
			
		||||
        private bool isNewSeg()
 | 
			
		||||
        {
 | 
			
		||||
            if (toDownList.Count > 0)
 | 
			
		||||
                return true;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								N_m3u8DL-CLI/HLSTags.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								N_m3u8DL-CLI/HLSTags.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    class HLSTags
 | 
			
		||||
    {
 | 
			
		||||
        public static string ext_m3u = "#EXTM3U";
 | 
			
		||||
        public static string ext_x_targetduration = "#EXT-X-TARGETDURATION";
 | 
			
		||||
        public static string ext_x_media_sequence = "#EXT-X-MEDIA-SEQUENCE";
 | 
			
		||||
        public static string ext_x_discontinuity_sequence = "#EXT-X-DISCONTINUITY-SEQUENCE";
 | 
			
		||||
        public static string ext_x_program_date_time = "#EXT-X-PROGRAM-DATE-TIME";
 | 
			
		||||
        public static string ext_x_media = "#EXT-X-MEDIA";
 | 
			
		||||
        public static string ext_x_playlist_type = "#EXT-X-PLAYLIST-TYPE";
 | 
			
		||||
        public static string ext_x_key = "#EXT-X-KEY";
 | 
			
		||||
        public static string ext_x_stream_inf = "#EXT-X-STREAM-INF";
 | 
			
		||||
        public static string ext_x_version = "#EXT-X-VERSION";
 | 
			
		||||
        public static string ext_x_allow_cache = "#EXT-X-ALLOW-CACHE";
 | 
			
		||||
        public static string ext_x_endlist = "#EXT-X-ENDLIST";
 | 
			
		||||
        public static string extinf = "#EXTINF";
 | 
			
		||||
        public static string ext_i_frames_only = "#EXT-X-I-FRAMES-ONLY";
 | 
			
		||||
        public static string ext_x_byterange = "#EXT-X-BYTERANGE";
 | 
			
		||||
        public static string ext_x_i_frame_stream_inf = "#EXT-X-I-FRAME-STREAM-INF";
 | 
			
		||||
        public static string ext_x_discontinuity = "#EXT-X-DISCONTINUITY";
 | 
			
		||||
        public static string ext_x_cue_out_start = "#EXT-X-CUE-OUT";
 | 
			
		||||
        public static string ext_x_cue_out = "#EXT-X-CUE-OUT-CONT";
 | 
			
		||||
        public static string ext_is_independent_segments = "#EXT-X-INDEPENDENT-SEGMENTS";
 | 
			
		||||
        public static string ext_x_scte35 = "#EXT-OATCLS-SCTE35";
 | 
			
		||||
        public static string ext_x_cue_start = "#EXT-X-CUE-OUT";
 | 
			
		||||
        public static string ext_x_cue_end = "#EXT-X-CUE-IN";
 | 
			
		||||
        public static string ext_x_cue_span = "#EXT-X-CUE-SPAN";
 | 
			
		||||
        public static string ext_x_map = "#EXT-X-MAP";
 | 
			
		||||
        public static string ext_x_start = "#EXT-X-START";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										163
									
								
								N_m3u8DL-CLI/LOGGER.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								N_m3u8DL-CLI/LOGGER.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,163 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    class LOGGER
 | 
			
		||||
    {
 | 
			
		||||
        public static int CursorIndex = 5;
 | 
			
		||||
        public static int FFmpegCorsorIndex = 5;
 | 
			
		||||
        public const int Default = 1;
 | 
			
		||||
        public const int Error = 2;
 | 
			
		||||
        public const int Warning = 3;
 | 
			
		||||
 | 
			
		||||
        public static string LOGFILE;
 | 
			
		||||
        public static bool STOPLOG = false;
 | 
			
		||||
        public static string FindLog(string dir)
 | 
			
		||||
        {
 | 
			
		||||
            DirectoryInfo d = new DirectoryInfo(dir);
 | 
			
		||||
            foreach (FileInfo fi in d.GetFiles())
 | 
			
		||||
            {
 | 
			
		||||
                if (fi.Extension.ToUpper() == ".LOG")
 | 
			
		||||
                {
 | 
			
		||||
                    return fi.FullName;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void InitLog()
 | 
			
		||||
        {
 | 
			
		||||
            if (!Directory.Exists(Path.GetDirectoryName(LOGFILE)))//若文件夹不存在则新建文件夹   
 | 
			
		||||
                Directory.CreateDirectory(Path.GetDirectoryName(LOGFILE)); //新建文件夹
 | 
			
		||||
            if (File.Exists(LOGFILE))//若文件存在则删除
 | 
			
		||||
                File.Delete(LOGFILE);
 | 
			
		||||
            string file = LOGFILE;
 | 
			
		||||
            string now = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
 | 
			
		||||
            string init = "LOG " + DateTime.Now.ToString("yyyy/MM/dd") + "\r\n"
 | 
			
		||||
                + "Save Path: " + Path.GetDirectoryName(LOGFILE) + "\r\n"
 | 
			
		||||
                + "Task Start: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + "\r\n"
 | 
			
		||||
                + "Task CommandLine: " + Environment.CommandLine;
 | 
			
		||||
 | 
			
		||||
            if (File.Exists(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "N_m3u8DL-CLI.args.txt")))
 | 
			
		||||
            {
 | 
			
		||||
                init += "\r\nAdditional Args: " + File.ReadAllText(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "N_m3u8DL-CLI.args.txt"));  //解析命令行
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            init += "\r\n\r\n";
 | 
			
		||||
            File.WriteAllText(file, init, Encoding.UTF8);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //读写锁机制,当资源被占用,其他线程等待
 | 
			
		||||
        static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
 | 
			
		||||
 | 
			
		||||
        public static void PrintLine(string text, int printLevel = 1, int cursorIndex = 0)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (CursorIndex > 1000)
 | 
			
		||||
                {
 | 
			
		||||
                    Console.Clear();
 | 
			
		||||
                    CursorIndex = 0;
 | 
			
		||||
                }
 | 
			
		||||
                if (cursorIndex == 0)
 | 
			
		||||
                    Console.SetCursorPosition(0, CursorIndex++);
 | 
			
		||||
                else
 | 
			
		||||
                    Console.SetCursorPosition(0, cursorIndex);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
            {
 | 
			
		||||
                ;
 | 
			
		||||
            }
 | 
			
		||||
            switch (printLevel)
 | 
			
		||||
            {
 | 
			
		||||
                case 0:
 | 
			
		||||
                    Console.WriteLine(" ".PadRight(12) + " " + text);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    Console.Write(DateTime.Now.ToString("HH:mm:ss.fff") + " ");
 | 
			
		||||
                    Console.WriteLine(text);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    Console.Write(DateTime.Now.ToString("HH:mm:ss.fff") + " ");
 | 
			
		||||
                    Console.ForegroundColor = ConsoleColor.Red;
 | 
			
		||||
                    Console.WriteLine(text);
 | 
			
		||||
                    Console.ResetColor();
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    Console.Write(DateTime.Now.ToString("HH:mm:ss.fff") + " ");
 | 
			
		||||
                    Console.ForegroundColor = ConsoleColor.DarkYellow;
 | 
			
		||||
                    Console.WriteLine(text);
 | 
			
		||||
                    Console.ResetColor();
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void WriteLine(string text)
 | 
			
		||||
        {
 | 
			
		||||
            if (STOPLOG)
 | 
			
		||||
                return;
 | 
			
		||||
            if (!File.Exists(LOGFILE))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                string file = LOGFILE;
 | 
			
		||||
                //进入写入
 | 
			
		||||
                LogWriteLock.EnterWriteLock();
 | 
			
		||||
                using (StreamWriter sw = File.AppendText(file))
 | 
			
		||||
                {
 | 
			
		||||
                    sw.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") + " / (NORMAL) " + text, Encoding.UTF8);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
            {
 | 
			
		||||
                
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                //释放占用
 | 
			
		||||
                LogWriteLock.ExitWriteLock();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void WriteLineError(string text)
 | 
			
		||||
        {
 | 
			
		||||
            if (!File.Exists(LOGFILE))
 | 
			
		||||
                return;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                string file = LOGFILE;
 | 
			
		||||
                //进入写入
 | 
			
		||||
                LogWriteLock.EnterWriteLock();
 | 
			
		||||
                using (StreamWriter sw = File.AppendText(file))
 | 
			
		||||
                {
 | 
			
		||||
                    sw.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") + " / (ERROR) " + text, Encoding.UTF8);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception)
 | 
			
		||||
            {
 | 
			
		||||
                
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                //释放占用
 | 
			
		||||
                LogWriteLock.ExitWriteLock();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Show(string text)
 | 
			
		||||
        {
 | 
			
		||||
            Console.ForegroundColor = ConsoleColor.Red;
 | 
			
		||||
            Console.WriteLine(DateTime.Now.ToString("o") + "  " + text);
 | 
			
		||||
            while (Console.ForegroundColor == ConsoleColor.Red) 
 | 
			
		||||
                Console.ResetColor();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										132
									
								
								N_m3u8DL-CLI/N_m3u8DL-CLI.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								N_m3u8DL-CLI/N_m3u8DL-CLI.csproj
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 | 
			
		||||
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
 | 
			
		||||
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
 | 
			
		||||
    <ProjectGuid>{4FB61439-B738-46AC-B3AF-2BF72150D057}</ProjectGuid>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
    <RootNamespace>N_m3u8DL_CLI</RootNamespace>
 | 
			
		||||
    <AssemblyName>N_m3u8DL-CLI</AssemblyName>
 | 
			
		||||
    <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
 | 
			
		||||
    <FileAlignment>512</FileAlignment>
 | 
			
		||||
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
 | 
			
		||||
    <TargetFrameworkProfile />
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
 | 
			
		||||
    <PlatformTarget>x86</PlatformTarget>
 | 
			
		||||
    <DebugSymbols>true</DebugSymbols>
 | 
			
		||||
    <DebugType>full</DebugType>
 | 
			
		||||
    <Optimize>false</Optimize>
 | 
			
		||||
    <OutputPath>bin\Debug\</OutputPath>
 | 
			
		||||
    <DefineConstants>DEBUG;TRACE</DefineConstants>
 | 
			
		||||
    <ErrorReport>prompt</ErrorReport>
 | 
			
		||||
    <WarningLevel>4</WarningLevel>
 | 
			
		||||
    <Prefer32Bit>false</Prefer32Bit>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
 | 
			
		||||
    <PlatformTarget>AnyCPU</PlatformTarget>
 | 
			
		||||
    <DebugType>pdbonly</DebugType>
 | 
			
		||||
    <Optimize>true</Optimize>
 | 
			
		||||
    <OutputPath>bin\Release\</OutputPath>
 | 
			
		||||
    <DefineConstants>TRACE</DefineConstants>
 | 
			
		||||
    <ErrorReport>prompt</ErrorReport>
 | 
			
		||||
    <WarningLevel>4</WarningLevel>
 | 
			
		||||
    <Prefer32Bit>false</Prefer32Bit>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <ApplicationIcon>logo_3Iv_icon.ico</ApplicationIcon>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Reference Include="Microsoft.JScript" />
 | 
			
		||||
    <Reference Include="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
 | 
			
		||||
    <Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="NiL.JS, Version=2.5.1428.0, Culture=neutral, PublicKeyToken=fa941a7c2a4de689, processorArchitecture=MSIL">
 | 
			
		||||
      <HintPath>..\packages\NiL.JS.2.5.1428\lib\net45\NiL.JS.dll</HintPath>
 | 
			
		||||
    </Reference>
 | 
			
		||||
    <Reference Include="PresentationFramework" />
 | 
			
		||||
    <Reference Include="System" />
 | 
			
		||||
    <Reference Include="System.Collections" />
 | 
			
		||||
    <Reference Include="System.Core" />
 | 
			
		||||
    <Reference Include="System.IO" />
 | 
			
		||||
    <Reference Include="System.Web" />
 | 
			
		||||
    <Reference Include="System.Xml.Linq" />
 | 
			
		||||
    <Reference Include="System.Data.DataSetExtensions" />
 | 
			
		||||
    <Reference Include="Microsoft.CSharp" />
 | 
			
		||||
    <Reference Include="System.Data" />
 | 
			
		||||
    <Reference Include="System.Net.Http" />
 | 
			
		||||
    <Reference Include="System.Xml" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Include="CommandLineArgument.cs" />
 | 
			
		||||
    <Compile Include="CommandLineArgumentParser.cs" />
 | 
			
		||||
    <Compile Include="Decode51CtoKey.cs" />
 | 
			
		||||
    <Compile Include="DecodeDdyun.cs" />
 | 
			
		||||
    <Compile Include="DecodeImooc.cs" />
 | 
			
		||||
    <Compile Include="DecodeNfmovies.cs" />
 | 
			
		||||
    <Compile Include="Decrypter.cs" />
 | 
			
		||||
    <Compile Include="FFmpeg.cs" />
 | 
			
		||||
    <Compile Include="Global.cs" />
 | 
			
		||||
    <Compile Include="HLSLiveDownloader.cs" />
 | 
			
		||||
    <Compile Include="HLSTags.cs" />
 | 
			
		||||
    <Compile Include="LOGGER.cs" />
 | 
			
		||||
    <Compile Include="DownloadManager.cs" />
 | 
			
		||||
    <Compile Include="Parser.cs" />
 | 
			
		||||
    <Compile Include="Program.cs" />
 | 
			
		||||
    <Compile Include="Properties\AssemblyInfo.cs" />
 | 
			
		||||
    <Compile Include="Downloader.cs" />
 | 
			
		||||
    <Compile Include="strings.Designer.cs">
 | 
			
		||||
      <AutoGen>True</AutoGen>
 | 
			
		||||
      <DesignTime>True</DesignTime>
 | 
			
		||||
      <DependentUpon>strings.resx</DependentUpon>
 | 
			
		||||
    </Compile>
 | 
			
		||||
    <Compile Include="strings.en-US.Designer.cs">
 | 
			
		||||
      <AutoGen>True</AutoGen>
 | 
			
		||||
      <DesignTime>True</DesignTime>
 | 
			
		||||
      <DependentUpon>strings.en-US.resx</DependentUpon>
 | 
			
		||||
    </Compile>
 | 
			
		||||
    <Compile Include="strings.zh-TW.Designer.cs">
 | 
			
		||||
      <AutoGen>True</AutoGen>
 | 
			
		||||
      <DesignTime>True</DesignTime>
 | 
			
		||||
      <DependentUpon>strings.zh-TW.resx</DependentUpon>
 | 
			
		||||
    </Compile>
 | 
			
		||||
    <Compile Include="Watcher.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Include="App.config">
 | 
			
		||||
      <SubType>Designer</SubType>
 | 
			
		||||
    </None>
 | 
			
		||||
    <None Include="packages.config" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <COMReference Include="Scripting">
 | 
			
		||||
      <Guid>{420B2830-E718-11CF-893D-00A0C9054228}</Guid>
 | 
			
		||||
      <VersionMajor>1</VersionMajor>
 | 
			
		||||
      <VersionMinor>0</VersionMinor>
 | 
			
		||||
      <Lcid>0</Lcid>
 | 
			
		||||
      <WrapperTool>tlbimp</WrapperTool>
 | 
			
		||||
      <Isolated>False</Isolated>
 | 
			
		||||
      <EmbedInteropTypes>True</EmbedInteropTypes>
 | 
			
		||||
    </COMReference>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Content Include="logo_3Iv_icon.ico" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <EmbeddedResource Include="strings.en-US.resx">
 | 
			
		||||
      <Generator>ResXFileCodeGenerator</Generator>
 | 
			
		||||
      <LastGenOutput>strings.en-US.Designer.cs</LastGenOutput>
 | 
			
		||||
    </EmbeddedResource>
 | 
			
		||||
    <EmbeddedResource Include="strings.resx">
 | 
			
		||||
      <Generator>ResXFileCodeGenerator</Generator>
 | 
			
		||||
      <LastGenOutput>strings.Designer.cs</LastGenOutput>
 | 
			
		||||
    </EmbeddedResource>
 | 
			
		||||
    <EmbeddedResource Include="strings.zh-TW.resx">
 | 
			
		||||
      <Generator>ResXFileCodeGenerator</Generator>
 | 
			
		||||
      <LastGenOutput>strings.zh-TW.Designer.cs</LastGenOutput>
 | 
			
		||||
    </EmbeddedResource>
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 | 
			
		||||
</Project>
 | 
			
		||||
							
								
								
									
										870
									
								
								N_m3u8DL-CLI/Parser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										870
									
								
								N_m3u8DL-CLI/Parser.cs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										801
									
								
								N_m3u8DL-CLI/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										801
									
								
								N_m3u8DL-CLI/Program.cs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										36
									
								
								N_m3u8DL-CLI/Properties/AssemblyInfo.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								N_m3u8DL-CLI/Properties/AssemblyInfo.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Runtime.CompilerServices;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
 | 
			
		||||
// 有关程序集的一般信息由以下
 | 
			
		||||
// 控制。更改这些特性值可修改
 | 
			
		||||
// 与程序集关联的信息。
 | 
			
		||||
[assembly: AssemblyTitle("N_m3u8DL-CLI")]
 | 
			
		||||
[assembly: AssemblyDescription("一款命令行m3u8下载器")]
 | 
			
		||||
[assembly: AssemblyConfiguration("")]
 | 
			
		||||
[assembly: AssemblyCompany("nilaoda")]
 | 
			
		||||
[assembly: AssemblyProduct("N_m3u8DL-CLI")]
 | 
			
		||||
[assembly: AssemblyCopyright("Copyright ©  2020")]
 | 
			
		||||
[assembly: AssemblyTrademark("")]
 | 
			
		||||
[assembly: AssemblyCulture("")]
 | 
			
		||||
 | 
			
		||||
// 将 ComVisible 设置为 false 会使此程序集中的类型
 | 
			
		||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
 | 
			
		||||
//请将此类型的 ComVisible 特性设置为 true。
 | 
			
		||||
[assembly: ComVisible(false)]
 | 
			
		||||
 | 
			
		||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
 | 
			
		||||
[assembly: Guid("4fb61439-b738-46ac-b3af-2bf72150d057")]
 | 
			
		||||
 | 
			
		||||
// 程序集的版本信息由下列四个值组成: 
 | 
			
		||||
//
 | 
			
		||||
//      主版本
 | 
			
		||||
//      次版本
 | 
			
		||||
//      生成号
 | 
			
		||||
//      修订号
 | 
			
		||||
//
 | 
			
		||||
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
 | 
			
		||||
// 方法是按如下所示使用“*”: :
 | 
			
		||||
// [assembly: AssemblyVersion("1.0.*")]
 | 
			
		||||
[assembly: AssemblyVersion("1.0.0.0")]
 | 
			
		||||
[assembly: AssemblyFileVersion("2.7.0.0")]
 | 
			
		||||
							
								
								
									
										104
									
								
								N_m3u8DL-CLI/Watcher.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								N_m3u8DL-CLI/Watcher.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.Timers;
 | 
			
		||||
 | 
			
		||||
namespace N_m3u8DL_CLI
 | 
			
		||||
{
 | 
			
		||||
    class Watcher
 | 
			
		||||
    {
 | 
			
		||||
        private string dir = string.Empty;
 | 
			
		||||
        private int total = 0;
 | 
			
		||||
        private static double totalDuration = 0; //总时长
 | 
			
		||||
        private int now = 0;
 | 
			
		||||
        private int partsCount = 0;
 | 
			
		||||
        FileSystemWatcher watcher = new FileSystemWatcher();
 | 
			
		||||
 | 
			
		||||
        public int Total { get => total; set => total = value; }
 | 
			
		||||
        public int Now { get => now; set => now = value; }
 | 
			
		||||
        public int PartsCount { get => partsCount; set => partsCount = value; }
 | 
			
		||||
        public static double TotalDuration { get => totalDuration; set => totalDuration = value; }
 | 
			
		||||
 | 
			
		||||
        public Watcher(string Dir)
 | 
			
		||||
        {
 | 
			
		||||
            this.dir = Dir;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void WatcherStrat()
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < PartsCount; i++)
 | 
			
		||||
            {
 | 
			
		||||
                Now += Global.GetFileCount(dir + "\\Part_" + i.ToString(DownloadManager.partsPadZero), ".ts");
 | 
			
		||||
            }
 | 
			
		||||
            watcher.Path = dir;
 | 
			
		||||
            watcher.Filter = "*.ts";
 | 
			
		||||
            watcher.IncludeSubdirectories = true;  //包括子目录
 | 
			
		||||
            watcher.EnableRaisingEvents = true;    //开启提交事件
 | 
			
		||||
            watcher.Created += new FileSystemEventHandler(OnCreated);
 | 
			
		||||
            watcher.Renamed += new RenamedEventHandler(OnCreated);
 | 
			
		||||
            watcher.Deleted += new FileSystemEventHandler(OnDeleted);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void WatcherStop()
 | 
			
		||||
        {
 | 
			
		||||
            watcher.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void OnCreated(object source, FileSystemEventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            if (Path.GetFileNameWithoutExtension(e.FullPath).StartsWith("Part"))
 | 
			
		||||
                return;
 | 
			
		||||
            Now++;
 | 
			
		||||
            if (Now > Total)
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            //Console.Title = Now + "   /   " + Total;
 | 
			
		||||
            string downloadedSize = Global.FormatFileSize(DownloadManager.DownloadedSize);
 | 
			
		||||
            string estimatedSize = Global.FormatFileSize(DownloadManager.DownloadedSize * total / now);
 | 
			
		||||
            string percent = (Convert.ToDouble(now) / Convert.ToDouble(total) * 100).ToString("0.00") + "%";
 | 
			
		||||
            Console.SetCursorPosition(0, 2);
 | 
			
		||||
            Console.Write(("Progress: " + Now + " of " + Total
 | 
			
		||||
                + $" ({percent}/{downloadedSize}/{estimatedSize}/{Global.FormatTime(Convert.ToInt32(TotalDuration))})").PadRight(62));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void OnRenamed(object source, RenamedEventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            if (Path.GetFileNameWithoutExtension(e.FullPath).StartsWith("Part"))
 | 
			
		||||
                return;
 | 
			
		||||
            Now++;
 | 
			
		||||
            if (Now > Total)
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            //Console.Title = Now + "   /   " + Total;
 | 
			
		||||
            string downloadedSize = Global.FormatFileSize(DownloadManager.DownloadedSize);
 | 
			
		||||
            string estimatedSize = Global.FormatFileSize(DownloadManager.DownloadedSize * total / now);
 | 
			
		||||
            string percent = (Convert.ToDouble(now) / Convert.ToDouble(total) * 100).ToString("0.00") + "%";
 | 
			
		||||
            Console.SetCursorPosition(0, 2);
 | 
			
		||||
            Console.Write(("Progress: " + Now + " of " + Total
 | 
			
		||||
                + $" ({percent}/{downloadedSize}/{estimatedSize}/{Global.FormatTime(Convert.ToInt32(TotalDuration))})").PadRight(62));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void OnDeleted(object source, FileSystemEventArgs e)
 | 
			
		||||
        {
 | 
			
		||||
            if (Path.GetFileNameWithoutExtension(e.FullPath).StartsWith("Part"))
 | 
			
		||||
                return;
 | 
			
		||||
            Now--;
 | 
			
		||||
            if (Now > Total)
 | 
			
		||||
            {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            //Console.Title = Now + "   /   " + Total;
 | 
			
		||||
            string downloadedSize = Global.FormatFileSize(DownloadManager.DownloadedSize);
 | 
			
		||||
            string estimatedSize = Global.FormatFileSize(DownloadManager.DownloadedSize * total / now);
 | 
			
		||||
            string percent = (Convert.ToDouble(now) / Convert.ToDouble(total) * 100).ToString("0.00") + "%";
 | 
			
		||||
            Console.SetCursorPosition(0, 2);
 | 
			
		||||
            Console.Write(("Progress: " + Now + " of " + Total
 | 
			
		||||
                + $" ({percent}/{downloadedSize}/{estimatedSize}/{Global.FormatTime(Convert.ToInt32(TotalDuration))})").PadRight(62));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								N_m3u8DL-CLI/logo_3Iv_icon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								N_m3u8DL-CLI/logo_3Iv_icon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 25 KiB  | 
							
								
								
									
										5
									
								
								N_m3u8DL-CLI/packages.config
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								N_m3u8DL-CLI/packages.config
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<packages>
 | 
			
		||||
  <package id="Newtonsoft.Json" version="12.0.3" targetFramework="net46" />
 | 
			
		||||
  <package id="NiL.JS" version="2.5.1428" targetFramework="net46" />
 | 
			
		||||
</packages>
 | 
			
		||||
							
								
								
									
										541
									
								
								N_m3u8DL-CLI/strings.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										541
									
								
								N_m3u8DL-CLI/strings.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										0
									
								
								N_m3u8DL-CLI/strings.en-US.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								N_m3u8DL-CLI/strings.en-US.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
								
								
									
										301
									
								
								N_m3u8DL-CLI/strings.en-US.resx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										301
									
								
								N_m3u8DL-CLI/strings.en-US.resx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										302
									
								
								N_m3u8DL-CLI/strings.resx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								N_m3u8DL-CLI/strings.resx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										0
									
								
								N_m3u8DL-CLI/strings.zh-TW.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								N_m3u8DL-CLI/strings.zh-TW.Designer.cs
									
									
									
										generated
									
									
									
										Normal file
									
								
							Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user