static void Main(string[] args) { M3CpyFlags flags = new M3CpyFlags(); // Parse the options and setup the M3CpyFlags struct for later use. var opt = new NDesk.Options.OptionSet() { { "f|m3u=", v => flags.M3uPath = (v) }, { "o|out=", v => flags.OutputPath = (v) }, { "h|?|help", v => flags.ShowHelp = (v != null) }, { "rm", v => flags.TryErase = (v != null) }, { "v|verbose", v => flags.Verbose = (v != null) }, { "replace", v => flags.Overwrite = (v != null) } }; opt.Parse(args); // First sanity checks, ensure that some arguments were passed and that they're not empty. if (args.Length == 0 || flags.M3uPath == "" || flags.OutputPath == "") { flags.ShowHelp = true; } if (flags.ShowHelp) { DisplayHelp(); } else { ReadM3UAndCopy(flags); } }
/// <summary> /// Read the files from a .m3u and apply the appropriate operation on each one. /// </summary> /// <param name="settings">Settings to use.</param> static void ReadM3UAndCopy(M3CpyFlags settings) { // Check if both handles exist if (!Directory.Exists(settings.OutputPath)) { Console.WriteLine("The folder '{0}' does not exist. Aborting.", settings.OutputPath); return; } if (!File.Exists(settings.M3uPath)) { Console.WriteLine("The file '{0}' does not exist. Aborting.", settings.M3uPath); return; } // Ensure we have a trailing / if (settings.OutputPath[settings.OutputPath.Length - 1] != '/') { settings.OutputPath += '/'; } // Parse line per line, copying files as it goes. using (StreamReader m3uHandle = File.OpenText(settings.M3uPath)) { int filesCopied = 0; int filesTotal = 0; bool res = false; string line = ""; while (!m3uHandle.EndOfStream) { line = m3uHandle.ReadLine(); // Ignore comment lines and empty lines if (line.Length == 0 || (line.Length != 0 && line[0] == '#')) { continue; } res = HandleSingleFile(line, settings); if (res) { filesCopied++; } filesTotal++; } Console.WriteLine("Operation successful on {0}/{1} files", filesCopied, filesTotal); } }
/// <summary> /// Apply the appropriate operations on a single file from its path (as a string). /// </summary> /// <param name="line">Path to the original file.</param> /// <param name="settings">Settings to use.</param> /// <returns></returns> static bool HandleSingleFile(string line, M3CpyFlags settings) { string log = ""; // Remove file:/// URIs because File.Copy chokes on them. string file = HttpUtility.UrlDecode(line).Replace("file:///", "") .Replace("file://", ""); FileInfo finfo = new FileInfo(file); string fullpath = settings.OutputPath + finfo.Name; // ======================================================================================================== // File.Copy does not handle http:// links, and we don't want to support them. // TODO: support them ? if (line.StartsWith("http://")) { Console.WriteLine("HTTP URIs are not supported. ({0})", line); return(false); } // Check for an already existing file in case the user does not want to overwrite // Otherwise, File.Copy throws an IOException if we don't overwrite. if (File.Exists(fullpath) && !settings.Overwrite) { Console.WriteLine("{0} already exists, skipping (ow is {1})", finfo.Name, settings.Overwrite); return(true); // Consider it as a success, we can assume it's gonna be 99% of the time. } // ======================================================================================================== // Attempt to copy. We'll handle the two most likely exceptions (don't have the right to read or plain old // IO error. Everything else is truly crash territory and should stop anyways. try { File.Copy(file, fullpath, settings.Overwrite); } catch (UnauthorizedAccessException) { if (settings.Verbose) { Console.WriteLine("Not authorized to copy {0}", finfo.Name); } return(false); } catch (IOException ex) { if (settings.Verbose) { Console.WriteLine("Unknown error on {0} ({1})", finfo.Name, ex.Message); } return(false); } log += (String.Format("{0} copied", finfo.Name)); // Deletes the original if the user wants to. if (settings.TryErase) { // Once again, try to delete and check both most likely exceptions. try { File.Delete(file); } catch (UnauthorizedAccessException) { if (settings.Verbose) { Console.WriteLine("Not authorized to delete {0}", finfo.Name); } return(false); } catch (IOException ex) { if (settings.Verbose) { Console.WriteLine("Error on {0} ({1})", finfo.Name, ex.Message); } return(false); } log += ", deleted"; } if (settings.Verbose) { Console.WriteLine(log); } return(true); }