├── .gitattributes ├── .gitignore ├── LICENSE ├── Project files ├── M3U8-downloader.sln └── M3U8-downloader │ ├── AssemblyInfo.cs │ ├── DDebug.cs │ ├── Descargador.cs │ ├── FileHelper.cs │ ├── GetILocalFileBytes.cs │ ├── HTML.cs │ ├── HTMLEnglish.cs │ ├── HTMLSpanish.cs │ ├── M3U8-downloader.csproj │ ├── MainClass.cs │ ├── NetworkHelper.cs │ ├── NetworkServer.cs │ ├── Utilidades.cs │ ├── ayuda_img.png │ └── bin │ ├── Debug │ └── ffmpeg │ │ └── ffmpeg.exe │ └── Release │ └── ffmpeg │ └── ffmpeg.exe └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pidb 2 | *.userprefs 3 | *.swp 4 | *.DS_Store 5 | *.nib 6 | *.suo 7 | *.user 8 | *.pfx 9 | 10 | */bin/* 11 | */obj/* 12 | */*/bin/* 13 | */*/obj/* 14 | */*/*/bin/* 15 | */*/*/obj/* 16 | *_ReSharper.*/ 17 | 18 | */*/Resource.designer.cs 19 | */*/*/Resource.designer.cs 20 | */*/*/*/Resource.designer.cs 21 | 22 | InAppPurchase/ComponentSample/Components/ 23 | 24 | RazorTodoList/packages/ 25 | RazorTodoList/Components/ 26 | RazorTodoADO/packages/ 27 | RazorTodoADO/Components/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Andrés 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M3U8-downloader", "M3U8-downloader\M3U8-downloader.csproj", "{4B78A828-6021-4F83-A159-B78972AF24BB}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x86 = Debug|x86 11 | Release|x86 = Release|x86 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {4B78A828-6021-4F83-A159-B78972AF24BB}.Debug|x86.ActiveCfg = Debug|x86 15 | {4B78A828-6021-4F83-A159-B78972AF24BB}.Debug|x86.Build.0 = Debug|x86 16 | {4B78A828-6021-4F83-A159-B78972AF24BB}.Release|x86.ActiveCfg = Release|x86 17 | {4B78A828-6021-4F83-A159-B78972AF24BB}.Release|x86.Build.0 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(MonoDevelopProperties) = preSolution 23 | StartupItem = M3U8-downloader\M3U8-downloader.csproj 24 | Policies = $0 25 | $0.DotNetNamingPolicy = $1 26 | $1.DirectoryNamespaceAssociation = None 27 | $1.ResourceNamePolicy = FileFormatDefault 28 | version = 0.4 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // Information about this assembly is defined by the following attributes. 5 | // Change them to the values specific to your project. 6 | 7 | [assembly: AssemblyTitle("M3U8-downloader")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("")] 12 | [assembly: AssemblyCopyright("yop")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 19 | 20 | [assembly: AssemblyVersion("1.0.*")] 21 | 22 | // The following attributes are used to specify the signing key for the assembly, 23 | // if desired. See the Mono documentation for more information about signing. 24 | 25 | //[assembly: AssemblyDelaySign(false)] 26 | //[assembly: AssemblyKeyFile("")] 27 | 28 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/DDebug.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace M3U8downloader 5 | { 6 | public static class DDebug 7 | { 8 | public static void WriteLine(String s) { 9 | /*Debug.WriteLine (s); 10 | Console.WriteLine (s);*/ 11 | } 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/Descargador.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Net; 4 | using System.Text.RegularExpressions; 5 | 6 | namespace M3U8downloader 7 | { 8 | public class Descargador 9 | { 10 | public string url = "a"; 11 | public string nombre = "b"; 12 | public string headers = ""; 13 | 14 | public double tiempoTotal = -1; 15 | public double tiempoActual = -1; 16 | public double horaInicio = -1; 17 | 18 | public int porcentajeInt = 0; 19 | public double porcentaje = 0; 20 | public string horaRestanteString = ""; 21 | 22 | Boolean cancelado = false; 23 | public String fallado = ""; 24 | 25 | ProcessStartInfo procesoFFMPEG; 26 | Process exeProcessProcesoFFMPEG; 27 | 28 | public bool Comienza (string url, string nombre) 29 | { 30 | this.url = url; 31 | this.nombre = nombre; 32 | 33 | return download (); 34 | } 35 | public bool Comienza (string url, string headers, string nombre) 36 | { 37 | this.url = url; 38 | this.headers = headers; 39 | this.nombre = nombre; 40 | 41 | return download (); 42 | } 43 | 44 | public void Cancelar () 45 | { 46 | if(exeProcessProcesoFFMPEG!=null) 47 | if(!exeProcessProcesoFFMPEG.HasExited) 48 | exeProcessProcesoFFMPEG.Kill(); 49 | cancelado = true; 50 | } 51 | 52 | public bool download () 53 | { 54 | 55 | if (url.IndexOf ("http://") != 0 && url.IndexOf ("https://") != 0) { 56 | Console.WriteLine ("URL invalida. La URL debe comenzar por \"http://\" o \"https://\""); 57 | fallado = MainClass.html.GetTXTInvalidURL(); 58 | MainClass.descargasEnProceso.Add (this); 59 | return false; 60 | } 61 | 62 | string m3u8 = ""; 63 | try { 64 | WebClient webClient = new WebClient (); 65 | m3u8 = webClient.DownloadString (url); 66 | } catch (Exception e) { 67 | Console.WriteLine ("No se pudo descargar la URL: \"" + url + "\""); 68 | fallado = MainClass.html.GetTXTErrorDownloadingURL(); 69 | MainClass.descargasEnProceso.Add (this); 70 | return false; 71 | } 72 | 73 | 74 | 75 | //remove all \r 76 | m3u8 = m3u8.Replace ("\r", String.Empty); 77 | 78 | 79 | 80 | Regex regex = new Regex (@"^[a-zA-Z0-9/\-_](.*?)$", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Multiline); 81 | 82 | MatchCollection matches = regex.Matches (m3u8); 83 | 84 | if (matches.Count > 0) { 85 | if (matches [0].Value.IndexOf (".ts") < 0) { 86 | 87 | //FFMPEG se encargara de elegir que descargar 88 | Console.WriteLine ("Has introducido una lista de m3u8 o un archivo m3u8 sin archivos .ts"); 89 | 90 | //Abre navegador 91 | Process.Start("http://127.0.0.1:" + MainClass.puerto + "/?accion=seleccionarlista&urlm3u8=" + Uri.EscapeDataString(url) ); 92 | 93 | MainClass.borraDescarga(this); 94 | 95 | return false; 96 | } 97 | } else { 98 | Console.WriteLine ("Formato de m3u8 no soportado"); 99 | fallado = MainClass.html.GetTXTM3U8Unsupported(); 100 | MainClass.descargasEnProceso.Add (this); 101 | return false; 102 | } 103 | 104 | MainClass.descargasEnProceso.Add (this); 105 | 106 | try { 107 | Console.WriteLine ("Descargando y uniendo partes. Espere por favor..."); 108 | 109 | procesoFFMPEG = new ProcessStartInfo (); 110 | procesoFFMPEG.FileName = MainClass.ffmpegfile; 111 | procesoFFMPEG.Arguments = "-i \""+url+"\" -c copy -bsf:a aac_adtstoasc \""+nombre+"\""; 112 | if(headers != "") 113 | procesoFFMPEG.Arguments += " -headers \""+headers+"\""; 114 | 115 | procesoFFMPEG.UseShellExecute = false; 116 | procesoFFMPEG.RedirectStandardOutput = true; 117 | procesoFFMPEG.RedirectStandardError = true; 118 | procesoFFMPEG.CreateNoWindow = true; 119 | 120 | 121 | exeProcessProcesoFFMPEG = Process.Start (procesoFFMPEG); 122 | 123 | exeProcessProcesoFFMPEG.OutputDataReceived += p_OutputDataReceived; 124 | exeProcessProcesoFFMPEG.ErrorDataReceived += p_ErrorDataReceived; 125 | 126 | exeProcessProcesoFFMPEG.BeginOutputReadLine(); 127 | exeProcessProcesoFFMPEG.BeginErrorReadLine(); 128 | 129 | exeProcessProcesoFFMPEG.WaitForExit (); 130 | } catch (Exception e) { 131 | //En caso de que FFmpeg falle no siempre dara excepcion (por ejemplo, cuando es necesario cambiar de proxy el server los enlaces no funcionan bien, pero no se activa este fallo) 132 | Console.WriteLine ("FFMPEG ha fallado."); 133 | fallado = MainClass.html.GetTXTFFMPEGFail(); 134 | return false; 135 | } 136 | 137 | /* 138 | if(!cancelado) 139 | return true; 140 | else 141 | return true; 142 | */ 143 | 144 | if (porcentajeInt == 0) 145 | fallado = MainClass.html.GetTXTFail(); 146 | else { 147 | porcentaje = 100; 148 | porcentajeInt = 100; 149 | horaRestanteString = "Completado"; 150 | } 151 | 152 | return !cancelado; 153 | } 154 | 155 | public void p_OutputDataReceived(object sender, DataReceivedEventArgs e) 156 | { 157 | //FFMPEG NO USA ESTO 158 | //Console.WriteLine("Received from standard out: " + e.Data); 159 | } 160 | 161 | public void p_ErrorDataReceived(object sender, DataReceivedEventArgs e) 162 | { 163 | //Console.WriteLine("Received from standard error: " + e.Data); 164 | //Console.WriteLine (e.Data); 165 | if (!String.IsNullOrEmpty(e.Data)) { 166 | if (tiempoTotal == -1) { 167 | if (e.Data.IndexOf ("Duration: ") >= 0) { 168 | int inicio = e.Data.IndexOf ("Duration: ") + 10; 169 | int final = e.Data.IndexOf (",", inicio); 170 | //tiempo = 00:00:00.00 171 | string tiempo = e.Data.Substring (inicio, final - inicio); 172 | tiempoTotal = double.Parse (tiempo.Substring (6, 2)); 173 | tiempoTotal += double.Parse (tiempo.Substring (3, 2)) * 60; 174 | tiempoTotal += double.Parse (tiempo.Substring (0, 2)) * 60 * 60; 175 | 176 | //Console.WriteLine (tiempo); 177 | //Console.WriteLine (tiempoTotal); 178 | 179 | horaInicio = Utilidades.UnixTimestamp(); 180 | } 181 | } else { 182 | //Console.WriteLine(e.Data); 183 | if (e.Data.IndexOf ("frame=") == 0 && e.Data.IndexOf ("time=") >= 0) { 184 | int inicio = e.Data.IndexOf ("time=") + 5; 185 | int final = e.Data.IndexOf (" ", inicio); 186 | string tiempo = e.Data.Substring (inicio, final - inicio); 187 | 188 | tiempoActual = double.Parse (tiempo.Substring (6, 2)); 189 | tiempoActual += double.Parse (tiempo.Substring (3, 2)) * 60; 190 | tiempoActual += double.Parse (tiempo.Substring (0, 2)) * 60 * 60; 191 | 192 | //Console.WriteLine (tiempo); 193 | //Console.WriteLine (tiempoActual); 194 | 195 | porcentaje = Math.Round (tiempoActual / tiempoTotal * 100.0, 196 | 2, MidpointRounding.AwayFromZero); 197 | 198 | porcentajeInt = (int)porcentaje; 199 | 200 | int horaActual = Utilidades.UnixTimestamp(); 201 | 202 | int horaTranscurrida = (int)horaActual - (int)horaInicio; 203 | int horaRestante = (int)((horaTranscurrida/porcentaje)*(100-porcentaje)); 204 | 205 | horaRestanteString = segundosATiempo (horaRestante); 206 | 207 | 208 | if (MainClass.desdeServidor) { 209 | Console.WriteLine (nombre + " - " + porcentajeInt + "%" + " - Quedan: " + horaRestanteString); 210 | } else { 211 | string linea = "["; 212 | int size = 60; 213 | for (int i = 0; i < size; i++) { 214 | if ((porcentaje * size) / 100 > i) 215 | linea += "="; 216 | else if ((porcentaje * size) / 100 > i - 1) 217 | linea += ">"; 218 | else 219 | linea += " "; 220 | } 221 | linea += "]"; 222 | 223 | Console.Clear (); 224 | Console.WriteLine ("Descargando, por favor espere...\n"+ 225 | "Nombre del archivo: " + nombre + "\n"+ 226 | "\n"+ 227 | "No cierre esta ventana hasta que la descarga no haya terminado.\n"+ 228 | "\n"+ 229 | "\n"+ 230 | linea + " " + porcentajeInt + "%" + "\n"+ 231 | "\n"+ 232 | "Tiempo restante para finalizar: " + horaRestanteString); 233 | } 234 | 235 | 236 | } 237 | } 238 | } 239 | } 240 | 241 | public string segundosATiempo(int seg_ini) { 242 | int horas = (int)Math.Floor((double)(seg_ini/3600)); 243 | int minutos = (int)Math.Floor((double)((seg_ini-(horas*3600))/60)); 244 | int segundos = seg_ini-(horas*3600)-(minutos*60); 245 | if(horas > 0) 246 | return horas+" horas, "+minutos+"min, "+segundos+"seg"; 247 | if(minutos > 0) 248 | return minutos+" min, "+segundos+" seg"; 249 | return segundos+" seg"; 250 | } 251 | } 252 | } 253 | 254 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/FileHelper.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.17929 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | using System; 11 | using System.IO; 12 | 13 | 14 | namespace M3U8downloader 15 | { 16 | public class FileHelper 17 | { 18 | public FileHelper () 19 | { 20 | } 21 | 22 | public static void DeleteDirectory (string target_dir) 23 | { 24 | string[] files = Directory.GetFiles (target_dir); 25 | string[] dirs = Directory.GetDirectories (target_dir); 26 | 27 | foreach (string file in files) { 28 | File.SetAttributes (file, FileAttributes.Normal); 29 | File.Delete (file); 30 | } 31 | 32 | foreach (string dir in dirs) { 33 | DeleteDirectory (dir); 34 | } 35 | 36 | Directory.Delete (target_dir, false); 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/GetILocalFileBytes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | 5 | namespace M3U8downloader 6 | { 7 | public class GetILocalFileBytes 8 | { 9 | public GetILocalFileBytes (){} 10 | 11 | public static byte[] Get(String resourceIDName){ 12 | Stream file = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceIDName); 13 | byte[] fileBytes = new byte[file.Length]; 14 | file.Read(fileBytes, 0, (int)file.Length); 15 | return fileBytes; 16 | } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/HTML.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace M3U8downloader 4 | { 5 | public abstract class HTML { 6 | public static KeyValuePair[] availableLanguages = new KeyValuePair[] { 7 | new KeyValuePair("es", new HTMLSpanish()), 8 | new KeyValuePair("en", new HTMLEnglish()) 9 | }; 10 | 11 | public virtual string GetName() { return ""; } 12 | public virtual string GetIndex() { return ""; } 13 | public virtual string GetProgress(string mensaje) { return ""; } 14 | public virtual string CloseWithJS() { return ""; } 15 | public virtual string GetHelp() { return ""; } 16 | public virtual string GetListSelection(string options) { return ""; } 17 | public virtual string GetClosed() { return ""; } 18 | public virtual string GetHelpImageName() { return ""; } 19 | public virtual string GetTXTInvalidURL() { return ""; } 20 | public virtual string GetTXTErrorDownloadingURL() { return ""; } 21 | public virtual string GetTXTM3U8Unsupported() { return ""; } 22 | public virtual string GetTXTFFMPEGFail() { return ""; } 23 | public virtual string GetTXTFail() { return ""; } 24 | 25 | 26 | public string GetLanguageList() { 27 | string txt = "Change language:
"; 28 | for (int i = 0; i < HTML.availableLanguages.Length; i++) { 29 | txt += "" + HTML.availableLanguages[i].Value.GetName() + ""; 30 | } 31 | return txt; 32 | } 33 | 34 | public virtual string GetProgress() { 35 | return GetProgress(""); 36 | } 37 | 38 | public virtual string GetAllcss() { 39 | //RESET.css 40 | return "html, body, div, span, applet, object, iframe," + 41 | "h1, h2, h3, h4, h5, h6, p, blockquote, pre," + 42 | "a, abbr, acronym, address, big, cite, code," + 43 | "del, dfn, em, img, ins, kbd, q, s, samp," + 44 | "small, strike, strong, sub, sup, tt, var," + 45 | "b, u, i, center,\ndl, dt, dd, ol, ul, li," + 46 | "fieldset, form, label, legend," + 47 | "table, caption, tbody, tfoot, thead, tr, th, td," + 48 | "article, aside, canvas, details, embed," + 49 | "figure, figcaption, footer, header, hgroup," + 50 | "menu, nav, output, ruby, section, summary," + 51 | "time, mark, audio, video {" + 52 | "margin: 0;" + 53 | "padding: 0;" + 54 | "border: 0;" + 55 | "font-size: 100%;" + 56 | "vertical-align: baseline;" + 57 | "}" + 58 | "article, aside, details, figcaption, figure," + 59 | "footer, header, hgroup, menu, nav, section {" + 60 | "display: block;" + 61 | "}" + 62 | "body {" + 63 | "line-height: 1;" + 64 | "}" + 65 | "ol, ul {" + 66 | "list-style: none;" + 67 | "}" + 68 | "blockquote, q {" + 69 | "quotes: none;" + 70 | "}" + 71 | "blockquote:before, blockquote:after," + 72 | "q:before, q:after {" + 73 | "content: '';" + 74 | "content: none;" + 75 | "}" + 76 | "table {" + 77 | "border-collapse: collapse;" + 78 | "border-spacing: 0;" + 79 | "}" + 80 | 81 | //All.css 82 | "body {" + 83 | "background-color: #6E9500;" + 84 | "font-family: Tahoma;" + 85 | "}" + 86 | "a {" + 87 | "color: #0FF;" + 88 | "}" + 89 | "a:hover {" + 90 | "color: #FFF;" + 91 | "}" + 92 | "#cerrarAplicacion > a:hover {" + 93 | "background-color: #FF0000;" + 94 | "}" + 95 | "#cerrarAplicacion > a {" + 96 | "background: none repeat scroll 0 0 #9C0000;" + 97 | "border: 1px double #FFFFFF;" + 98 | "border-radius: 10px;" + 99 | "color: #FFFFFF;" + 100 | "margin: 5px;" + 101 | "padding: 10px;" + 102 | "position: fixed;" + 103 | "right: 0;" + 104 | "text-decoration: none;" + 105 | "top: 0;" + 106 | "}" + 107 | "#menu {" + 108 | "background-color: #1A1A1A;" + 109 | "box-shadow: 0 0 15px 0 #000000;" + 110 | "color: #FFFFFF;" + 111 | "height: 100%;" + 112 | "padding: 30px 0;" + 113 | "position: fixed;" + 114 | "text-align: center;" + 115 | "width: 230px;" + 116 | "}" + 117 | "#menu a {" + 118 | "color: #B2F100;" + 119 | "display: block;" + 120 | "font-size: 16px;" + 121 | "font-weight: bold;" + 122 | "line-height: 20px;" + 123 | "padding: 10px 0;" + 124 | "text-decoration: none;" + 125 | "}" + 126 | "#menu a:hover {" + 127 | "background-color: #EEEEEE;" + 128 | "box-shadow: 0 0 9px #929292 inset;" + 129 | "color: #333333;" + 130 | "}" + 131 | "#menu .titulo_menu {" + 132 | "background-color: #990000;" + 133 | "color: #FFFFFF;" + 134 | "font-size: 18px;" + 135 | "font-weight: normal;" + 136 | "line-height: 18px;" + 137 | "margin-bottom: 35px;" + 138 | "padding: 20px;" + 139 | "}" + 140 | "#menu .titulo_menu:hover {" + 141 | "background-color: #FFFFFF;" + 142 | "box-shadow: none;" + 143 | "color: #000000;" + 144 | "}" + 145 | "#contenido {" + 146 | "color: #FFFFFF;" + 147 | "display: inline-block;" + 148 | "margin: 25px 20px 0 270px;" + 149 | "padding: 0 0 50px;" + 150 | "}" + 151 | "#descargando {" + 152 | "width: 100%;" + 153 | "}" + 154 | "#descargando .n{" + 155 | "width: 18%;" + 156 | "}" + 157 | "#descargando .u{" + 158 | "width: 27%;" + 159 | "}" + 160 | "#descargando .p{" + 161 | "width: 27%;" + 162 | "}" + 163 | "#descargando .t{" + 164 | "width: 19%;" + 165 | "}" + 166 | "#descargando .q{" + 167 | "width: 9%;" + 168 | "}" + 169 | "#descargando .q a {" + 170 | "background-color: #FF0000;" + 171 | "border: 1px solid #FFFFFF;" + 172 | "border-radius: 10px;" + 173 | "color: #FFFFFF;" + 174 | "display: inline-block;" + 175 | "padding: 4px;" + 176 | "text-decoration: none;" + 177 | "}" + 178 | "#descargando .q a:hover {" + 179 | "background-color: #FFFFFF;" + 180 | "color: #F00;" + 181 | "border-color: #F00;" + 182 | "}" + 183 | ".tabla{" + 184 | "display: table;" + 185 | "margin: 15px 0 50px;" + 186 | "position: relative;" + 187 | "table-layout: fixed;" + 188 | "word-break: break-all;" + 189 | "word-wrap: break-word;" + 190 | "}" + 191 | ".tabla > .elemento:nth-child(odd) {" + 192 | "background-color: #B6CCAF;" + 193 | "}" + 194 | ".tabla > .elemento:nth-child(even) {" + 195 | "background-color: #CBE1A4;" + 196 | "}" + 197 | ".tabla > .elemento {" + 198 | "border-bottom: 1px solid #000000;" + 199 | "color: #000000;" + 200 | "display: table-row;" + 201 | "line-height: 22px;" + 202 | "}" + 203 | ".tabla > .titulos:first-child {" + 204 | "background-color: #24302A;" + 205 | "color: #ECFFC9;" + 206 | "font-weight: bold;" + 207 | "}" + 208 | ".tabla > .elemento > div {" + 209 | "display: table-cell;" + 210 | "font-size: 14px;" + 211 | "line-height: 14px;" + 212 | "padding: 5px 10px;" + 213 | "}" + 214 | ".progressBar {" + 215 | "background-color: #000000;" + 216 | "border-radius: 10px;" + 217 | "box-shadow: 0 -9px 10px -5px #858585 inset;" + 218 | "display: inline-block;" + 219 | "height: 10px;" + 220 | "margin: 0 8px 0 0;" + 221 | "padding: 1px;" + 222 | "width: calc(100% - 60px);" + 223 | "}" + 224 | ".progressBar > div {" + 225 | "background-color: #FFC8C8;" + 226 | "box-shadow: 0 -2px 4px 2px #FF0000 inset;" + 227 | "border-radius: 10px;" + 228 | "height: 10px;" + 229 | "}" + 230 | "ol {" + 231 | "list-style: decimal outside none;" + 232 | "}" + 233 | "li {" + 234 | "margin-bottom: 1em;" + 235 | "}" + 236 | ".img_ayuda{" + 237 | "background-color: #C2C2C2;" + 238 | "border: 1px solid #FFFFFF;" + 239 | "padding: 10px;" + 240 | "width: 80%" + 241 | "}"; 242 | } 243 | 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/HTMLEnglish.cs: -------------------------------------------------------------------------------- 1 | // Translation by veso266 2 | 3 | using System; 4 | 5 | namespace M3U8downloader { 6 | public class HTMLEnglish : HTML { 7 | public override string GetName() { 8 | return "English"; 9 | } 10 | 11 | public override string GetIndex() { 12 | return "" + 13 | "" + 14 | "M3U8-Downloader V" + MainClass.version + "" + 15 | "" + 16 | "" + 17 | "" + 18 | "" + 19 | "
" + 20 | "Close M3U8-Downloader" + 21 | "
" + 22 | "
" + 23 | "M3U8-Downloader V" + MainClass.version + "" + 24 | "Descargavideos.TV" + 25 | "Check updates" + 26 | "Help" + 27 | "

" + 28 | GetLanguageList() + 29 | "
" + 30 | "
" + 31 | "New Download:" + 32 | "
" + 33 | "" + 34 | "" + 35 | "
" + 36 | "
URL:
" + 37 | "
" + 38 | "
" + 39 | "
File Name:
" + 40 | "
" + 41 | "
" + 42 | "
" + 43 | "
" + 44 | "
" + 45 | "Downloads in progress:" + 46 | "
" + 47 | GetProgress() + 48 | "
" + 49 | "
" + 50 | "" + 61 | "" + 62 | ""; 63 | } 64 | 65 | public override string GetProgress(string mensaje) { 66 | String resp = "
" + 67 | "
Name
" + 68 | "
URL
" + 69 | "
Progress
" + 70 | "
Time left
" + 71 | "
Remove
" + 72 | "
"; 73 | for (int i = 0; i < MainClass.descargasEnProceso.Count; i++) { 74 | if (MainClass.descargasEnProceso[i].fallado != "") { 75 | resp += "
" + 76 | "
" + MainClass.descargasEnProceso[i].nombre + "
" + 77 | "
" + MainClass.descargasEnProceso[i].url + "
" + 78 | "
" + MainClass.descargasEnProceso[i].fallado + "
" + 79 | "
" + 80 | "" + 81 | "
"; 82 | } else { 83 | resp += "
" + 84 | "
" + MainClass.descargasEnProceso[i].nombre + "
" + 85 | "
" + MainClass.descargasEnProceso[i].url + "
" + 86 | "
" + MainClass.descargasEnProceso[i].porcentajeInt + "%
" + 87 | "
" + MainClass.descargasEnProceso[i].horaRestanteString + "
" + 88 | "" + 89 | "
"; 90 | } 91 | } 92 | 93 | if (mensaje != "") { 94 | resp += ""; 95 | } 96 | 97 | return resp; 98 | } 99 | 100 | public override string CloseWithJS() { 101 | return "You can close this window/tab." + 102 | ""; 107 | } 108 | 109 | public override string GetHelp() { 110 | return "" + 111 | "" + 112 | "M3U8-Downloader V" + MainClass.version + "" + 113 | "" + 114 | "" + 115 | "" + 116 | "" + 117 | "
" + 118 | "Close M3U8-Downloader" + 119 | "
" + 120 | "
" + 121 | "M3U8-Downloader V" + MainClass.version + "" + 122 | "Descargavideos.TV" + 123 | "Search for updates" + 124 | "Help" + 125 | "
" + 126 | "
" + 127 | "" + 128 | "
    " + 129 | "
  1. Program Version." + 130 | "
    In the case of the image it is version 0.3.
    " + 131 | "If we want to check for updates, it will be understood as a superior version of one that has a value greater than the current number, with version 2.0, for example greater than 1.5 and higher than version 0.3.
  2. " + 132 | "
  3. Link to the section of the program versions.
    " + 133 | "Clicking on the link a page with the list of all published versions where you can download the latest or any of the earlier versions will open.
  4. " + 134 | "
  5. In this form you add new Downloads.
    " + 135 | "If you want to manually add a download, enter the URL of the file m3u8 in the URL field and type the name you want to have the video in the Name field. The name of the video must have the file extension, to be a valid name such asvideo.mp4 or Chapter 15.mp4. The name can be left blank.
    Once completed the form when clickingAddstart downloading the video.
  6. " + 136 | "
  7. File name as it appears in the folder that contains it.
  8. " + 137 | "
  9. URL of the file you are downloading.
  10. " + 138 | "
  11. Download Progress.
    " + 139 | "After completing each download folder containing the video opens. Until then, you should not move or delete the file.
  12. " + 140 | "
  13. Time remaining to complete the download.
    " + 141 | "The time is calculated from the percentage downloaded and elapsed time so it is only approximate.
  14. " + 142 | "
  15. Remove the download list.
    " + 143 | "If the download is not yet completed it will stop downloading and be removed from the list, leaving the incomplete file in the download folder.
    " + 144 | "If the download is completed it will be removed from the list automatically
  16. " + 145 | "
  17. Close the Program.
    " + 146 | "To close the program you must click the button. In doing so, a question is displayed. If you accept, all incomplete downloads in progress will be discontinued and then the program will close. Otherwise the program will not be closed. Once done it will load a new page that will indicate that the program has been successfully closed.
    If you close the console (black window) instead of clicking on the close button it will stop the discharges in open process, so to stop them it would be necessary to close the process in question.
  18. " + 147 | "
" + 148 | "Back" + 149 | "
" + 150 | "" + 151 | ""; 152 | } 153 | 154 | public override string GetListSelection(string options) { 155 | return "

Found several download options


A greater BANDWIDTH and/or resolution, higher image quality
Please click on the option you want to download:


" + options; 156 | } 157 | 158 | public override string GetClosed() { 159 | return "You have closed the program
Now you can close the console."; 160 | } 161 | 162 | public override string GetHelpImageName() { 163 | return "M3U8downloader.ayuda_img.png"; 164 | } 165 | 166 | public override string GetTXTInvalidURL() { 167 | return "Invalid URL"; 168 | } 169 | 170 | public override string GetTXTErrorDownloadingURL() { 171 | return "Error downloading the URL"; 172 | } 173 | 174 | public override string GetTXTM3U8Unsupported() { 175 | return "M3U8 not supported"; 176 | } 177 | 178 | public override string GetTXTFFMPEGFail() { 179 | return "FFMPEG failed"; 180 | } 181 | 182 | public override string GetTXTFail() { 183 | return "Error"; 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/HTMLSpanish.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace M3U8downloader 4 | { 5 | public class HTMLSpanish : HTML 6 | { 7 | public override string GetName() { 8 | return "Español"; 9 | } 10 | 11 | public override string GetIndex(){ 12 | return "" + 13 | "" + 14 | "M3U8-Downloader V" + MainClass.version + "" + 15 | "" + 16 | "" + 17 | "" + 18 | "" + 19 | "
" + 20 | "Cerrar M3U8-Downloader" + 21 | "
" + 22 | "
" + 23 | "M3U8-Downloader V" + MainClass.version + "" + 24 | "Descargavideos.TV" + 25 | "Buscar actualizaciones" + 26 | "Ayuda" + 27 | "

" + 28 | GetLanguageList() + 29 | "
" + 30 | "
" + 31 | "Nueva descarga:" + 32 | "
" + 33 | "" + 34 | "" + 35 | "
" + 36 | "
URL:
" + 37 | "
" + 38 | "
" + 39 | "
Nombre:
" + 40 | "
" + 41 | "
" + 42 | "
" + 43 | "
" + 44 | "
" + 45 | "Descargas en progreso:" + 46 | "
" + 47 | GetProgress() + 48 | "
" + 49 | "
" + 50 | "" + 61 | "" + 62 | ""; 63 | } 64 | 65 | public override string GetProgress(string mensaje){ 66 | String resp = "
" + 67 | "
Nombre
" + 68 | "
URL
" + 69 | "
Progreso
" + 70 | "
Tiempo restante
" + 71 | "
Quitar
" + 72 | "
"; 73 | for (int i=0; i" + 76 | "
" + MainClass.descargasEnProceso [i].nombre + "
" + 77 | "
" + MainClass.descargasEnProceso [i].url + "
" + 78 | "
"+MainClass.descargasEnProceso [i].fallado+"
" + 79 | "
" + 80 | "" + 81 | ""; 82 | } else { 83 | resp += "
" + 84 | "
" + MainClass.descargasEnProceso [i].nombre + "
" + 85 | "
" + MainClass.descargasEnProceso [i].url + "
" + 86 | "
" + MainClass.descargasEnProceso [i].porcentajeInt + "%
" + 87 | "
" + MainClass.descargasEnProceso [i].horaRestanteString + "
" + 88 | "" + 89 | "
"; 90 | } 91 | } 92 | 93 | if(mensaje != ""){ 94 | resp += ""; 95 | } 96 | 97 | return resp; 98 | } 99 | 100 | public override string CloseWithJS(){ 101 | return "Puedes cerrar esta ventana/pestaña."+ 102 | ""; 107 | } 108 | 109 | public override string GetHelp(){ 110 | return "" + 111 | "" + 112 | "M3U8-Downloader V" + MainClass.version + "" + 113 | "" + 114 | "" + 115 | "" + 116 | "" + 117 | "
" + 118 | "Cerrar M3U8-Downloader" + 119 | "
" + 120 | "" + 126 | "
" + 127 | "" + 128 | "
    " + 129 | "
  1. Versión del programa." + 130 | "
    En el caso de la imagen se trata de la versión 0.3.
    " + 131 | "Si queremos buscar actualizaciones, se entenderá como una versión superior aquella que tenga un número mayor que el actual, siendo por ejemplo la versión 2.0 superior a la 1.5 y a su vez superior a la versión 0.3.
  2. " + 132 | "
  3. Enlace a la sección de versiones del programa en Descargavideos.
    " + 133 | "Al hacer clic en el enlace se abrirá una página con el listado de versiones publicadas donde podrás descargar la más reciente o cualquiera de las versiones anteriores.
  4. " + 134 | "
  5. Formulario para agregar nuevas descargas.
    " + 135 | "En caso de querer agregar manualmente una descarga, introduce la URL del archivo m3u8 en el campo URL y escribe el nombre que quieres que tenga el vídeo en el campo Nombre. El nombre del vídeo debe tener la extensión del archivo, siendo un nombre válido por ejemplo video.mp4 o capítulo 15.mp4. El nombre puede dejarse en blanco.
    Una vez completado el formulario al clicar Agregar comenzará la descarga del vídeo.
  6. " + 136 | "
  7. Nombre del archivo tal y como figura en la carpeta que lo contiene.
  8. " + 137 | "
  9. URL del archivo que se está descargando.
  10. " + 138 | "
  11. Progreso de la descarga.
    " + 139 | "Una vez completada cada descarga se abrirá la carpeta que contiene el vídeo. Hasta entonces, no debe moverse o borrarse el archivo.
  12. " + 140 | "
  13. Tiempo restante para completar la descarga.
    " + 141 | "El tiempo es calculado a partir del porcentaje descargado y el tiempo transcurrido por lo que únicamente es aproximado.
  14. " + 142 | "
  15. Quitar la descarga de la lista.
    " + 143 | "En caso de que la descarga no esté finalizada detendrá la descarga y la quitará de la lista, dejando el archivo incompleto en la carpeta de descargas.
    " + 144 | "En caso de que la descarga esté finalizada, únicamente la quitará de la lista.
  16. " + 145 | "
  17. Cerrar el programa.
    " + 146 | "Para cerrar el programa se debe de hacer clic en el botón. Al hacerlo, se mostrará una pregunta. En caso de que aceptemos, todas las descargas incompletas en curso se interrumpirán y después se cerrará el programa. De lo contrario no se cerrará el programa. Una vez hecho esto cargará una nueva página en la que indicará que el programa se ha cerrado con éxito.
    En caso de cerrar la consola (la ventana negra) en lugar de clicar en el botón de cerrar dejará las descargas en proceso abiertas, por lo que para detenerlas sería necesario cerrar el proceso en cuestión.
  18. " + 147 | "
" + 148 | "atras" + 149 | "
" + 150 | "" + 151 | ""; 152 | } 153 | 154 | public override string GetListSelection(string options){ 155 | return "

Se han encontrado varias opciones de descarga


A mayor BANDWIDTH Y/O RESOLUTION, mayor calidad de imagen
Por favor, clica en la opción que quieras descargar:


"+options; 156 | } 157 | 158 | public override string GetClosed(){ 159 | return "Has cerrado el programa
Ahora puedes cerrar la consola."; 160 | } 161 | 162 | public override string GetHelpImageName() { 163 | return "M3U8downloader.ayuda_img.png"; 164 | } 165 | 166 | public override string GetTXTInvalidURL() { 167 | return "URL inválida"; 168 | } 169 | 170 | public override string GetTXTErrorDownloadingURL() { 171 | return "Error al descargar la URL"; 172 | } 173 | 174 | public override string GetTXTM3U8Unsupported() { 175 | return "M3U8 no soportado"; 176 | } 177 | 178 | public override string GetTXTFFMPEGFail() { 179 | return "FFMPEG ha fallado"; 180 | } 181 | 182 | public override string GetTXTFail() { 183 | return "Fallo"; 184 | } 185 | } 186 | } 187 | 188 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/M3U8-downloader.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 9.0.21022 7 | 2.0 8 | {4B78A828-6021-4F83-A159-B78972AF24BB} 9 | Exe 10 | M3U8downloader 11 | M3U8-downloader 12 | v3.5 13 | 0.4 14 | 15 | 16 | 17 | 18 | 3.5 19 | publish\ 20 | true 21 | Disk 22 | false 23 | Foreground 24 | 7 25 | Days 26 | false 27 | false 28 | true 29 | 0 30 | 1.0.0.%2a 31 | false 32 | false 33 | true 34 | 35 | 36 | True 37 | full 38 | False 39 | bin\Debug 40 | DEBUG; 41 | prompt 42 | 4 43 | x86 44 | True 45 | 46 | 47 | none 48 | False 49 | bin\Release 50 | prompt 51 | 4 52 | x86 53 | True 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | False 82 | .NET Framework 3.5 SP1 83 | true 84 | 85 | 86 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/MainClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Text.RegularExpressions; 4 | using System.IO; 5 | using System.Collections.Generic; 6 | using System.Threading; 7 | using System.Diagnostics; 8 | using System.Net; 9 | using System.Globalization; 10 | 11 | namespace M3U8downloader 12 | { 13 | 14 | public static class MainClass 15 | { 16 | public static string ffmpegfile = ""; 17 | public static string m3u8downloaderPath = ""; 18 | public static string relativePath = ""; 19 | public static bool desdeServidor = false; 20 | 21 | public static string version = "0.5.2"; 22 | 23 | public static int puerto = 25430; 24 | 25 | public static List descargasEnProceso = new List(); 26 | public static int TempDescargasEnProcesoCantidad = 0; 27 | 28 | 29 | public static void Main (string[] cmdLine) 30 | { 31 | Console.Title = "M3U8-Downloader V" + version + " - http://www.descargavideos.TV"; 32 | Console.WriteLine ("M3U8-Downloader V" + version + " - http://www.descargavideos.TV"); 33 | Console.WriteLine (""); 34 | 35 | MainClass.m3u8downloaderPath = AppDomain.CurrentDomain.BaseDirectory; 36 | MainClass.relativePath = Directory.GetCurrentDirectory(); 37 | 38 | if (File.Exists (MainClass.m3u8downloaderPath + "\\ffmpeg\\ffmpeg.exe")) { 39 | MainClass.ffmpegfile = MainClass.m3u8downloaderPath + "\\ffmpeg\\ffmpeg.exe"; 40 | } else if (File.Exists (MainClass.m3u8downloaderPath + "\\ffmpeg.exe")) { 41 | MainClass.ffmpegfile = MainClass.m3u8downloaderPath + "\\ffmpeg.exe"; 42 | } 43 | if (MainClass.ffmpegfile == "") { 44 | //No tsmuxer files 45 | Console.WriteLine ("Por favor descarga ffmpeg y coloca el archivo ffmpeg.exe dentro de la siguiente carpeta:"); 46 | Console.WriteLine (MainClass.m3u8downloaderPath); 47 | Console.WriteLine (""); 48 | Console.WriteLine ("Descargalo aqui:"); 49 | Console.WriteLine ("http://www.ffmpeg.org/download.html"); 50 | Console.WriteLine (""); 51 | Console.WriteLine ("Tambien puedes encontrar el archivo en el ZIP de M3U8-Downloader"); 52 | Console.WriteLine ("Pulsa cualquier tecla para continuar..."); 53 | Console.ReadKey(); 54 | return; 55 | } 56 | 57 | 58 | 59 | //Todo http aqui 60 | if (cmdLine.Length == 0) { 61 | desdeServidor = true; 62 | operaDesdeServidor (); 63 | return; 64 | } 65 | 66 | 67 | 68 | //Desde consola 69 | Descargador myDownloader = new Descargador (); 70 | if (cmdLine.Length == 2) { 71 | myDownloader.Comienza (cmdLine [0], cmdLine [1]); 72 | } else if (cmdLine.Length == 3) { 73 | myDownloader.Comienza (cmdLine [0], cmdLine [1], cmdLine [2]); 74 | } else { 75 | //incorrect start parameters 76 | Console.WriteLine ("Uso: M3U8-Downloader "); 77 | Console.WriteLine ("Ejemplo: M3U8-Downloader http://web.com/video.m3u8 C:\\video.mp4"); 78 | Console.WriteLine (""); 79 | Console.WriteLine ("Uso: M3U8-Downloader "); 80 | Console.WriteLine ("Ejemplo: M3U8-Downloader http://web.com/video.m3u8 00112233445566778899AABBCCDDEEFF C:\\video.mp4"); 81 | return; 82 | } 83 | } 84 | 85 | public static NetworkServer myServer; 86 | 87 | public static HTML html = new HTMLSpanish(); // default 88 | 89 | //Manejo desde HTTP. Todo desde aqui. Una vez terminada la funcion acabara el programa 90 | public static void operaDesdeServidor() { 91 | SelectLanguage(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName); 92 | 93 | //create server and listen from port 25430 94 | Console.WriteLine ("Para usar el programa abre en un navegador la siguiente URL:"); 95 | Console.WriteLine ("http://127.0.0.1:"+puerto+"/"); 96 | Console.WriteLine (""); 97 | 98 | 99 | myServer = new NetworkServer (); 100 | 101 | if (!myServer.Abre (puerto)) { 102 | Console.WriteLine ("No se ha podido abrir servidor."); 103 | Console.WriteLine ("Es posible que ya tengas el programa abierto."); 104 | Console.WriteLine (""); 105 | 106 | return; 107 | } 108 | 109 | //Abre navegador 110 | Process.Start("http://127.0.0.1:"+puerto+"/"); 111 | 112 | while(true) { 113 | RespuestaHTTP GETurl = myServer.Escucha(); 114 | 115 | if (!GETurl.correcto) { 116 | myServer.CierraCliente (); 117 | continue; 118 | } 119 | 120 | string path = GETurl.path; 121 | 122 | string accion = GETurl.getParametro ("accion"); 123 | 124 | string nombre = GETurl.getParametro ("nombre"); 125 | string url = GETurl.getParametro ("url"); 126 | string headers = GETurl.getParametro ("headers"); 127 | 128 | if (accion == "" || accion == "descargar") { 129 | if (url != "") { 130 | string cerrarVentana = GETurl.getParametro ("cerrarVentana"); 131 | if(cerrarVentana == "" || cerrarVentana == "1"){ 132 | myServer.Envia(html.CloseWithJS()); 133 | } 134 | //else if(cerrarVentana == "0" || true){ 135 | else{ 136 | myServer.EnviaLocation ("/"); 137 | } 138 | var t = new Thread(() => lanzaDescarga(url, headers, nombre)); 139 | t.Start(); 140 | continue; 141 | } 142 | } 143 | 144 | if(path == "/ayuda"){ 145 | myServer.Envia (html.GetHelp()); 146 | continue; 147 | } 148 | 149 | if(path == "/ayuda/ayuda_prev.png"){ 150 | byte[] imgBytes = GetILocalFileBytes.Get(html.GetHelpImageName()); 151 | myServer.EnviaRaw ("image/png", imgBytes); 152 | continue; 153 | } 154 | 155 | if(path == "/all.css"){ 156 | myServer.Envia (html.GetAllcss()); 157 | continue; 158 | } 159 | 160 | if (path.IndexOf("/lang/") == 0) { 161 | SelectLanguage(path.Substring("/lang/".Length)); 162 | myServer.EnviaLocation ("/"); 163 | continue; 164 | } 165 | 166 | if (path == "/" && accion == "") { 167 | myServer.Envia (html.GetIndex()); 168 | continue; 169 | } 170 | 171 | if (accion == "seleccionarlista" && GETurl.existeParametro("urlm3u8")) { 172 | //Mostrar un alert en caso de que se agregue una nueva descarga para conseguir el focus de la pestaña 173 | String opciones = desglosaListaM3U8(GETurl.getParametro("urlm3u8")); 174 | if (opciones != "") { 175 | myServer.Envia (html.GetListSelection (opciones)); 176 | } else { 177 | myServer.Envia("No se ha podido descargar la lista m3u8."); 178 | } 179 | continue; 180 | } 181 | 182 | if (accion == "progreso") { 183 | //Mostrar un alert en caso de que se agregue una nueva descarga para conseguir el focus de la pestaña 184 | if(descargasEnProceso.Count > TempDescargasEnProcesoCantidad){ 185 | myServer.Envia (html.GetProgress("Descarga agregada")); 186 | TempDescargasEnProcesoCantidad = descargasEnProceso.Count; 187 | } 188 | else{ 189 | myServer.Envia (html.GetProgress()); 190 | } 191 | continue; 192 | } 193 | 194 | if (accion == "cancelarDescarga") { 195 | int elem = Convert.ToInt32(GETurl.getParametro ("elem")); 196 | if(elem >= 0 && elem < descargasEnProceso.Count){ 197 | borraDescarga(descargasEnProceso[elem]); 198 | } 199 | myServer.EnviaLocation("/"); 200 | continue; 201 | } 202 | 203 | if (accion == "cerrarPrograma") { 204 | for(int i=0; i< descargasEnProceso.Count; i++){ 205 | descargasEnProceso[i].Cancelar(); 206 | } 207 | myServer.Envia(html.GetClosed()); 208 | 209 | myServer.Cierra(); 210 | 211 | return; 212 | } 213 | 214 | 215 | myServer.Envia ("Na que hacer"); 216 | } 217 | } 218 | 219 | public static void SelectLanguage(string twoLetterLang) { 220 | for (int i = 0; i < HTML.availableLanguages.Length; i++) { 221 | if (twoLetterLang == HTML.availableLanguages[i].Key) { 222 | html = HTML.availableLanguages[i].Value; 223 | return; 224 | } 225 | } 226 | } 227 | 228 | public static string desglosaListaM3U8(string url){ 229 | if (url.IndexOf ("http://") != 0 && url.IndexOf ("https://") != 0) { 230 | Console.WriteLine ("URL invalida. La URL debe comenzar por \"http://\" o \"https://\""); 231 | return ""; 232 | } 233 | 234 | string m3u8List = ""; 235 | try { 236 | WebClient webClient = new WebClient (); 237 | m3u8List = webClient.DownloadString (url); 238 | } catch (Exception e) { 239 | Console.WriteLine ("No se pudo descargar la URL: \"" + url + "\""); 240 | return ""; 241 | } 242 | 243 | string pattern = "\n([^#\n\r$]+)"; 244 | MatchCollection matchesURL = Regex.Matches (m3u8List, pattern); 245 | pattern = "\n#EXT-X-STREAM-INF:(.*?(RESOLUTION|BANDWIDTH)=(.*?)[,\r\n].*?)*"; 246 | MatchCollection matchesDESC = Regex.Matches (m3u8List, pattern); 247 | //myServer.Envia(Utilidades.print_r_regex(matchesDESC)); 248 | 249 | string resp = ""; 250 | 251 | if (matchesURL.Count > 0) { 252 | string extra = ""; 253 | if (matchesURL[0].Groups[1].Captures[0].Value.IndexOf ("http") != 0) { 254 | //no es una url completa. completar a partir de la url original. dependiendo de si es relativo o absoluto. 255 | if (matchesURL[0].Groups[1].Captures[0].Value.IndexOf ("/") == 0) { 256 | //absoluto 257 | extra = url.Substring (0, url.IndexOf ("/")) + "/"; 258 | } else { 259 | //relativo 260 | extra = url.Substring (0, url.LastIndexOf ("/", url.IndexOf("?")>=0?url.IndexOf("?"):url.Length-1)) + "/"; 261 | } 262 | } 263 | 264 | resp = ""; 265 | 266 | if(matchesDESC.Count == matchesURL.Count){ 267 | for(int i=0; i"; 269 | for(int j=0; j" + extra + matchesURL[i].Groups[1].Captures[0].Value + ""; 273 | } 274 | } 275 | else{ 276 | for(int i=0; i" + extra + matchesURL[i].Groups[1].Captures[0].Value + ""; 278 | } 279 | } 280 | } 281 | else{ 282 | resp = "No se ha encontrado nada. Forzar descarga (poner enlace con parametro get que sea forzar = 1. poner en Descargador.cs el detectar ese get, en caso de estar saltar comprobacion)"; 283 | } 284 | 285 | 286 | return resp; 287 | } 288 | 289 | public static void borraDescarga(Descargador cual){ 290 | cual.Cancelar(); 291 | descargasEnProceso.Remove(cual); 292 | 293 | TempDescargasEnProcesoCantidad = descargasEnProceso.Count; 294 | } 295 | 296 | public static void lanzaDescarga(string url, string nombre){ 297 | lanzaDescarga (url, "", nombre); 298 | } 299 | public static void lanzaDescarga(string url, string headers, string nombre){ 300 | Descargador miDescargador = new Descargador (); 301 | 302 | if (nombre == "") { 303 | nombre = "video.mp4"; 304 | } 305 | for (int j=1; File.Exists(nombre); j++) { 306 | nombre = "video" + j + ".mp4"; 307 | } 308 | 309 | if (miDescargador.Comienza (url, headers, nombre)) { 310 | //Abrir carpeta que tiene el video 311 | //string myDocspath = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments); 312 | string windir = Environment.GetEnvironmentVariable ("WINDIR"); 313 | System.Diagnostics.Process prc = new System.Diagnostics.Process (); 314 | prc.StartInfo.FileName = windir + @"\explorer.exe"; 315 | prc.StartInfo.Arguments = MainClass.relativePath; 316 | prc.Start (); 317 | } 318 | } 319 | } 320 | } -------------------------------------------------------------------------------- /Project files/M3U8-downloader/NetworkHelper.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.17929 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | using System; 11 | using System.IO; 12 | 13 | 14 | namespace M3U8downloader 15 | { 16 | public class NetworkHelper 17 | { 18 | public NetworkHelper () 19 | { 20 | } 21 | 22 | public static void CopyTo(Stream source, Stream destination) 23 | { 24 | // TODO: Argument validation 25 | byte[] buffer = new byte[16384]; // For example... 26 | int bytesRead; 27 | while ((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) 28 | { 29 | destination.Write(buffer, 0, bytesRead); 30 | } 31 | } 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/NetworkServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Sockets; 3 | using System.Net; 4 | using System.IO; 5 | using System.Text.RegularExpressions; 6 | 7 | namespace M3U8downloader 8 | { 9 | public class NetworkServer 10 | { 11 | TcpListener listener; 12 | TcpClient client; 13 | NetworkStream stream; 14 | StreamReader reader; 15 | StreamWriter writer; 16 | 17 | public NetworkServer (){} 18 | 19 | public bool Abre(int puerto){ 20 | try{ 21 | Console.WriteLine ("Abriendo servidor en \"127.0.0.1:" + puerto + "\"..."); 22 | listener = new TcpListener (IPAddress.Loopback, puerto); 23 | listener.Start (); 24 | 25 | Console.WriteLine ("Servidor abierto."); 26 | return true; 27 | } 28 | catch(Exception e){ 29 | Console.WriteLine ("h0"); 30 | Console.WriteLine (e); 31 | return false; 32 | } 33 | } 34 | 35 | public RespuestaHTTP Escucha () 36 | { 37 | 38 | try{ 39 | 40 | client = listener.AcceptTcpClient (); 41 | DDebug.WriteLine ("Conexion establecida"); 42 | 43 | stream = client.GetStream (); 44 | reader = new StreamReader (stream); 45 | writer = new StreamWriter (stream); 46 | stream.ReadTimeout = 30000; 47 | 48 | // limpiar stream 49 | string entrada = ""; 50 | while (entrada.Length < 4 || entrada.Substring(entrada.Length - 4, 4) != "\r\n\r\n") { 51 | entrada += (char) reader.Read(); 52 | } 53 | DDebug.WriteLine(entrada); 54 | stream.Flush(); 55 | 56 | string GETurl = entrada.Substring(0, entrada.IndexOf("\r\n")); 57 | 58 | if(GETurl != null){ 59 | string pattern = " (.*?) HTTP"; 60 | MatchCollection matches = Regex.Matches (GETurl, pattern); 61 | 62 | string url=""; 63 | 64 | if (matches.Count > 0) { 65 | GroupCollection gc = matches[0].Groups; 66 | CaptureCollection cc = gc[1].Captures; 67 | url = cc[0].Value; 68 | } 69 | DDebug.WriteLine (url); 70 | 71 | 72 | pattern = "\\?(&?([^=^&]+?)=([^&]*))*"; 73 | matches = Regex.Matches (url, pattern); 74 | //Utilidades.print_r_regex(matches); 75 | if (matches.Count > 0) { 76 | GroupCollection gc = matches[0].Groups; 77 | CaptureCollection variables = gc[2].Captures; 78 | CaptureCollection valores = gc[3].Captures; 79 | 80 | ParametroGet[] parametros = new ParametroGet[variables.Count]; 81 | for(int i = 0; i < variables.Count; i++){ 82 | parametros[i] = new ParametroGet( 83 | Uri.UnescapeDataString(variables[i].Value).Replace("+", " "), 84 | Uri.UnescapeDataString(valores[i].Value).Replace("+", " ")); 85 | } 86 | return new RespuestaHTTP (url, parametros); 87 | } 88 | return new RespuestaHTTP (url); 89 | } 90 | return new RespuestaHTTP (false); 91 | 92 | } 93 | catch(Exception e){ 94 | Console.WriteLine ("h1"); 95 | Console.WriteLine (e); 96 | CierraCliente (); 97 | return new RespuestaHTTP (false); 98 | } 99 | } 100 | 101 | public bool Envia (String que) 102 | { 103 | try { 104 | DDebug.WriteLine ("Enviando desde Envia"); 105 | 106 | writer.WriteLine ("HTTP/1.1 200 OK"); 107 | writer.WriteLine ("Connection: Close"); 108 | writer.WriteLine ("Content-Type: text/html; charset=utf-8"); 109 | 110 | writer.WriteLine (""); 111 | writer.Write (que); 112 | writer.Flush(); 113 | 114 | CierraCliente (); 115 | return true; 116 | } catch (Exception e) { 117 | Console.WriteLine ("h2"); 118 | Console.WriteLine (e); 119 | return false; 120 | } 121 | } 122 | 123 | public bool EnviaRaw(String contentType, byte[] contenido){ 124 | try { 125 | DDebug.WriteLine ("Enviando desde EnviaRaw"); 126 | 127 | writer.WriteLine ("HTTP/1.1 200 OK"); 128 | writer.WriteLine ("Connection: Close"); 129 | writer.WriteLine ("Content-Type: "+contentType); 130 | 131 | writer.WriteLine (""); 132 | writer.Flush(); 133 | stream.Write(contenido, 0, contenido.Length); 134 | 135 | CierraCliente (); 136 | return true; 137 | } catch (Exception e) { 138 | Console.WriteLine ("h10"); 139 | Console.WriteLine (e); 140 | return false; 141 | } 142 | } 143 | 144 | public bool EnviaLocation (String que) 145 | { 146 | try { 147 | DDebug.WriteLine ("EnviaLocation"); 148 | 149 | writer.WriteLine ("HTTP/1.1 302 OK"); 150 | writer.WriteLine ("Location: " + que); 151 | writer.WriteLine ("Content-Length: 0"); 152 | 153 | writer.WriteLine (""); 154 | writer.Flush(); 155 | 156 | CierraCliente (); 157 | return true; 158 | } catch (Exception e) { 159 | Console.WriteLine("h3"); 160 | Console.WriteLine (e); 161 | return false; 162 | } 163 | } 164 | 165 | public void CierraCliente () 166 | { 167 | try{ 168 | DDebug.WriteLine ("CierraCliente"); 169 | 170 | this.writer.Close (); 171 | this.stream.Close (); 172 | DDebug.WriteLine("Cliente cerrado."); 173 | } 174 | catch(Exception e){ 175 | Console.WriteLine("h4"); 176 | Console.WriteLine (e); 177 | } 178 | } 179 | 180 | public void Cierra () 181 | { 182 | try{ 183 | DDebug.WriteLine ("Cierra"); 184 | 185 | CierraCliente(); 186 | this.listener.Stop (); 187 | Console.WriteLine("Servidor cerrado."); 188 | } 189 | catch(Exception e){ 190 | Console.WriteLine("h5"); 191 | Console.WriteLine (e); 192 | } 193 | } 194 | } 195 | 196 | public class RespuestaHTTP 197 | { 198 | public String url; 199 | public String path; 200 | public ParametroGet[] parametros; 201 | bool _correcto; 202 | public bool correcto{ 203 | get{ 204 | return _correcto; 205 | } 206 | set{ } 207 | } 208 | 209 | public RespuestaHTTP (String url) 210 | { 211 | this._correcto = true; 212 | 213 | this.setURL(url); 214 | } 215 | 216 | public RespuestaHTTP (bool correcto) 217 | { 218 | this.correcto = correcto; 219 | } 220 | 221 | public RespuestaHTTP (String url, ParametroGet[] parametros) 222 | { 223 | this.setURL(url); 224 | this.parametros = parametros; 225 | this._correcto = true; 226 | } 227 | 228 | void setURL(String url){ 229 | this.url = url; 230 | 231 | String pattern = "[^\\?]*"; 232 | MatchCollection matches = Regex.Matches (url, pattern); 233 | //Utilidades.print_r_regex(matches); 234 | 235 | this.path = matches[0].Groups[0].Captures[0].Value; 236 | } 237 | 238 | public bool tieneParametros(){ 239 | return parametros != null; 240 | } 241 | 242 | public bool existeParametro(String variable){ 243 | if (!tieneParametros()) 244 | return false; 245 | 246 | for(int i = 0; i < parametros.Length; i++){ 247 | if (parametros[i].variable == variable) 248 | return true; 249 | } 250 | return false; 251 | } 252 | 253 | public String getParametro(String variable){ 254 | if (!tieneParametros()) 255 | return ""; 256 | 257 | for (int i = 0; i < parametros.Length; i++) { 258 | if (parametros [i].variable == variable) 259 | return parametros [i].valor; 260 | } 261 | return ""; 262 | } 263 | } 264 | 265 | public class ParametroGet{ 266 | String _variable; 267 | String _valor; 268 | 269 | public String variable{ 270 | get{ 271 | return _variable; 272 | } 273 | set{ } 274 | } 275 | public String valor{ 276 | get{ 277 | return _valor; 278 | } 279 | set{ } 280 | } 281 | 282 | 283 | public ParametroGet (String variable, String valor) 284 | { 285 | this._variable = variable; 286 | this._valor = valor; 287 | } 288 | } 289 | } 290 | 291 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/Utilidades.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace M3U8downloader 5 | { 6 | public class Utilidades 7 | { 8 | public static int UnixTimestamp() 9 | { 10 | return (int)(DateTime.Now - new DateTime(1970, 1, 1).ToLocalTime()).TotalSeconds; 11 | } 12 | 13 | //Tan solo para ver si el pregmatch tira lo que quiero 14 | public static string print_r_regex(MatchCollection mc){ 15 | string resp = ""; 16 | if(mc.Count > 0) 17 | { 18 | resp += "Printing matches..."; 19 | for(int i =0; i < mc.Count; i++) 20 | { 21 | resp += "\n"; 22 | resp += "Match["+i+"]: " + mc[i].Value + "\n"; 23 | resp += "Printing groups for this match...\n"; 24 | GroupCollection gc = mc[i].Groups; 25 | for(int j =0; j < gc.Count; j++) 26 | { 27 | resp += "\tGroup["+j+"]: "+ gc[j].Value + "\n"; 28 | resp += "\tPrinting captures for this group...\n"; 29 | CaptureCollection cc = gc[j].Captures; 30 | for(int k =0; k < cc.Count; k++) 31 | { 32 | resp += "\t\tCapture["+k+"]: "+ cc[k].Value + "\n"; 33 | } 34 | } 35 | } 36 | } 37 | return resp; 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Project files/M3U8-downloader/ayuda_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forestrf/M3U8-Downloader/1d2f0ac5a94ec39fec846f1ce20e7ba9f8cd862b/Project files/M3U8-downloader/ayuda_img.png -------------------------------------------------------------------------------- /Project files/M3U8-downloader/bin/Debug/ffmpeg/ffmpeg.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forestrf/M3U8-Downloader/1d2f0ac5a94ec39fec846f1ce20e7ba9f8cd862b/Project files/M3U8-downloader/bin/Debug/ffmpeg/ffmpeg.exe -------------------------------------------------------------------------------- /Project files/M3U8-downloader/bin/Release/ffmpeg/ffmpeg.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forestrf/M3U8-Downloader/1d2f0ac5a94ec39fec846f1ce20e7ba9f8cd862b/Project files/M3U8-downloader/bin/Release/ffmpeg/ffmpeg.exe -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | M3U8-Downloader 2 | =============== 3 | 4 | Programa para facilitar la descarga de enlaces M3U8 5 | --------------------------------------------------------------------------------