open System open System.IO open Microsoft.WindowsAPICodePack.Dialogs open System.Net let (|>>) x f = f x; x module IO = let rec Input _ = match Console.ReadLine().Trim() with | s when s <> "" -> s::Input() | _ -> [] let DirectoryPick _ = let dialog = new CommonOpenFileDialog() dialog.IsFolderPicker <- true match dialog.ShowDialog() with | CommonFileDialogResult.Ok -> dialog.FileName | _ -> failwith "Empty Path" module Log = open System.Threading type Level = | Log | Error | Info type Type = | ConsoleType of ConsoleColor | FileType of string let output = let lockObj = obj() fun logType level (s:string) -> lock lockObj (fun _ -> let msg = match level with | Log -> "[*] " | Error -> "[!] " | Info -> "[i] " + s match logType with | ConsoleType(c) -> Console.ForegroundColor <- c Console.WriteLine msg | FileType(p) -> use log = new StreamWriter(p, true) log.WriteLine msg) let Log = output (ConsoleType ConsoleColor.White) Log let Error = output (ConsoleType ConsoleColor.Red) Error let Info = output (ConsoleType ConsoleColor.DarkGray) Info let File path = output (FileType path) let LogAsync msg = (new Thread(fun () -> Log msg)).Start() let ErrorAsync msg = (new Thread(fun () -> Error msg)).Start() let InfoAsync msg = (new Thread(fun () -> Info msg)).Start() let FileAsync path level msg = (new Thread(fun () -> File path level msg)).Start() let DownloadAsync path lst = let tempPath = path + "\\" + "temp" Directory.CreateDirectory tempPath |> ignore let logPath = path + "\\" + "Error.log" lst |> Seq.ofList |> Seq.map (fun url -> async{ let filename = (Path.GetFileName url).Split('?').[0] let downloadPath = path + "\\" + filename let tempDownloadPath = tempPath + "\\" + filename if not <| File.Exists downloadPath then try use wc = new WebClient() wc.DownloadFile(Uri(url), tempDownloadPath) File.Move(tempDownloadPath,downloadPath) url + " -> " + filename + " done." |> Log.InfoAsync with | e -> url + " " + e.Message |>> Log.Error |> Log.FileAsync (logPath) Log.Level.Error }) |> Async.Parallel |> Async.RunSynchronously |> ignore [<STAThread>] [<EntryPoint>] let main argv = match argv.Length with | 0 -> DownloadAsync (IO.DirectoryPick()) (IO.Input()) | _ -> use sr = new StreamReader(argv.[1]) sr.ReadToEnd().Split('\n') |> List.ofArray |> DownloadAsync argv.[0] Log.LogAsync "done." Console.ReadLine() |> ignore 0