using CommandLine; using System; using System.IO; using System.IO.Pipes; using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading; using TessesYoutubeDownloader.Server.Models; namespace youtube_downloader { class Program { static void SendStringArray(System.IO.Stream s, string[] array) { s.Write(BitConverter.GetBytes(array.Length), 0, 4); foreach (var item in array) { byte[] lenOfitem = BitConverter.GetBytes(item.Length); byte[] argtext = System.Text.Encoding.UTF8.GetBytes(item); s.Write(lenOfitem, 0, lenOfitem.Length); s.Write(argtext, 0, argtext.Length); } } static string[] GetStringArray(System.IO.Stream s) { byte[] items = new byte[4]; s.Read(items, 0, items.Length); int items2 = BitConverter.ToInt32(items, 0); string[] arraydata = new string[items2]; for (int i = 0; i < items2; i++) { s.Read(items, 0, 4); int item3 = BitConverter.ToInt32(items, 0); byte[] v = new byte[item3]; s.Read(v, 0, item3); arraydata[i] = System.Text.Encoding.UTF8.GetString(v); } return arraydata; } static string _AppName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().GetName().Name); static void Main(string[] args) { // we need to get our app name so that // we can create unique names for our mutex and our pipe var notAlreadyRunning = true; // wrap the meat of the application code with a named mutex so it runs only once using (var mutex = new Mutex(true, _AppName + "Singleton", out notAlreadyRunning)) { if (notAlreadyRunning) { // do additional work here, startup stuff // Console.WriteLine("Running. Press any key to exit..."); // ... // now process our initial main command line _ProcessCommandLine(args); // start the IPC sink. var srv = new NamedPipeServerStream(_AppName + "IPC", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); // it's easier to use the AsyncCallback than it is to use Tasks here: // this can't block, so some form of async is a must srv.BeginWaitForConnection(new AsyncCallback(_ConnectionHandler), srv); // block here until exit Console.ReadKey(); // if this was a windows forms app you would put your // "Applicantion.Run(new MyForm());" here // finally, run any teardown code and exit srv.Close(); } else // another instance is running { // connect to the main app var cli = new NamedPipeClientStream(".", _AppName + "IPC", PipeDirection.InOut); cli.Connect(); SendStringArray(cli, args); byte[] leng = new byte[4]; cli.Read(leng, 0, 4); int sz = BitConverter.ToInt32(leng); byte[] sdata = new byte[sz]; cli.Read(sdata, 0, sz); string strdata = System.Text.Encoding.UTF8.GetString(sdata); Console.Write(strdata); // serialize and send the command line cli.Close(); // and exit } } } static void _ConnectionHandler(IAsyncResult result) { var srv = result.AsyncState as NamedPipeServerStream; srv.EndWaitForConnection(result); // we're connected, now deserialize the incoming command line var inargs = GetStringArray(srv); r = new RESPONSE(srv); // process incoming command line _ProcessCommandLine(inargs); r.SendResponse(); srv = new NamedPipeServerStream(_AppName + "IPC", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); srv.BeginWaitForConnection(new AsyncCallback(_ConnectionHandler), srv); } [Verb("exit", HelpText = "Download Video")] public class ExitApp { } [Verb("video", true, HelpText = "Download Video")] public class DownloadVideo { [Value(0, Required = true, HelpText = "The id or url of video")] public string Id { get; set; } [Option('f', "format", Default = Resolution.NoConvert, HelpText = "possible values are (NoConvert,Convert,Audio)")] public Resolution Format { get; set; } } [Verb("playlist", HelpText = "Download entire Playlist")] public class DownloadPlaylist { [Value(0, Required = true, HelpText = "The id or url of playlist")] public string Id { get; set; } [Option('f', "format", Default = Resolution.NoConvert, HelpText = "possible values are (NoConvert,Convert,Audio)")] public Resolution Format { get; set; } } [Verb("channel", HelpText = "Download entire Channel (using channel id)")] public class DownloadChannel { [Value(0, Required = true, HelpText = "The id or url of channel")] public string Id { get; set; } [Option('f', "format", Default = Resolution.NoConvert, HelpText = "possible values are (NoConvert,Convert,Audio)")] public Resolution Format { get; set; } } [Verb("user", HelpText = "Download entire Channel (using username)")] public class DownloadUser { [Value(0, Required = true, HelpText = "The name or url of the user")] public string Id { get; set; } [Option('f', "format", Default = Resolution.NoConvert, HelpText = "possible values are (NoConvert,Convert,Audio)")] public Resolution Format { get; set; } } [Verb("move", HelpText = "Move item in queue")] public class MoveQueue { [Option('d', "moveto", HelpText = "can be (up,down,top,bottom,remove)")] public string MoveTo { get; set; } [Option('s', "movefrom", HelpText = "Can be number (index) or \"last\"")] public string MoveFrom { get; set; } } [Verb("info", HelpText = "Get info")] public class Info { [Option('m', "machine", Default = false, HelpText = "In json")] public bool ForMachine { get; set; } [Option('p', "page", Required = true, HelpText = "can be (progress,queue,location)")] public string Page { get; set; } } static RESPONSE r=null; static void _ProcessCommandLine(string[] args) { CommandLine.Parser.Default.ParseArguments(args) .MapResult( (DownloadVideo opts) => RunDownloadVideo(opts), (DownloadPlaylist opts) => RunDownloadPlaylist(opts), (DownloadChannel opts) => RunDownloadChannel(opts), (DownloadUser opts) => RunDownloadUser(opts), (MoveQueue opts) => RunMoveQueue(opts), (Info opts) => RunInfo(opts), (ExitApp opts) => RunExitApp(opts), errs => 1); } static void WriteVideoInfo(StringBuilder b,SavedVideo v,bool description) { //v.AuthorChannelId //v.AuthorTitle //v.Dislikes //v.Duration //v.Id //v.Keywords //v.Likes //v.Title //v.UploadDate //v.Views //v.Description b.AppendLine($"Title: {v.Title}"); b.AppendLine($"AuthorName: {v.AuthorTitle}"); b.AppendLine($"AuthorID: {v.AuthorChannelId}"); b.AppendLine($"Duration: {TimeSpan.FromSeconds(v.Duration).ToString()}"); b.AppendLine($"Id: {v.Id}"); b.AppendLine($"UploadDate: {v.UploadDate}"); b.AppendLine($"Views: {v.Views}, Likes: {v.Likes}, Dislikes: {v.Dislikes}"); b.AppendLine("Keywords:"); foreach(var kw in v.Keywords) { b.AppendLine($"\t{kw}"); } if (description) { b.AppendLine("Description:"); b.AppendLine(v.Description); } } private static int RunInfo(Info opts) { if (r != null) { switch (opts.Page) { case "progress": if (opts.ForMachine) { string jsonData = Newtonsoft.Json.JsonConvert.SerializeObject(Server.Functions.Downloader.GetProgress()); r.SendResponse(jsonData); } else { var s=Server.Functions.Downloader.GetProgress(); StringBuilder sb = new StringBuilder(); sb.AppendLine("=======Progress======="); sb.AppendLine($"Progress: {s.Progress}%"); sb.AppendLine($"Size: {Math.Round((double)s.Length / (double)(1000 * 1000), 2)} MB"); sb.AppendLine(); sb.AppendLine("=======Video Info======="); WriteVideoInfo(sb, s.Saved, false); r.SendResponse(sb.ToString()); } break; case "queue": if (opts.ForMachine) { string jsonData = Server.Functions.Downloader.GetQueue(); r.SendResponse(jsonData); } else { var s = Server.Functions.Downloader.GetQueueItems(); StringBuilder sb = new StringBuilder(); foreach(var item in s) { WriteVideoInfo(sb, item.Video, false); sb.AppendLine(); } r.SendResponse(sb.ToString()); } break; case "location": r.SendResponse(Server.Functions.Downloader.DL.StorageLocation); break; } } return 0; } private static int RunMoveQueue(MoveQueue opts) { Server.Functions.Downloader.ModQueue(opts.MoveTo, opts.MoveFrom); return 0; } private static int RunDownloadUser(DownloadUser opts) { Server.Functions.Downloader.DownloadUser(opts.Id, opts.Format); return 0; } private static int RunExitApp(ExitApp opts) { Environment.Exit(0); return 0; } private static int RunDownloadVideo(DownloadVideo opts) { Server.Functions.Downloader.DownloadVideo(opts.Id, opts.Format); return 0; } private static int RunDownloadPlaylist(DownloadPlaylist opts) { Server.Functions.Downloader.DownloadPlaylist(opts.Id, opts.Format); return 0; } private static int RunDownloadChannel(DownloadChannel opts) { Server.Functions.Downloader.DownloadChannel(opts.Id, opts.Format); return 0; } } }