open System.Net open System open System.IO open System.Threading module Log = let lock = new System.Threading.SemaphoreSlim(1, 1) let printStr line (str : string) = lock.Wait() match line with | true -> Console.WriteLine str | _ -> Console.Write str lock.Release() |> ignore let print line = printStr line << String.concat " " let printColor line color (args : string list) = System.Console.ForegroundColor <- color print line args let Error = printColor false ConsoleColor.Red let Log = printColor false ConsoleColor.White let Info = printColor false ConsoleColor.DarkGray let ErrorLn = printColor true ConsoleColor.Red let LogLn = printColor true ConsoleColor.White let InfoLn = printColor true ConsoleColor.DarkGray let Time _ = "[" + DateTime.Now.ToString() + "]" let rec AutoIndexDownloaderAsync logPath threadNum (url:string) path = let lock = new SemaphoreSlim(threadNum, threadNum) let rec AutoIndexDownloader logPath (url:string) path = try use wc = new WebClient() wc.DownloadString(url) .Split([|"<a href=\""|], StringSplitOptions.RemoveEmptyEntries) |> Seq.ofArray |> Seq.tail |> Seq.map (fun x -> x.Substring(0,x.IndexOf("\""))) |> Seq.filter (fun x -> not <| x.StartsWith("?") && not <| x.StartsWith("..") && not <| x.Equals "/" && not <| url.Substring(0, url.Substring(0, url.Length-1).LastIndexOf("/") + 1).EndsWith(x)) |> Seq.map (fun x -> async { lock.Wait() Log.Info [x] match x.EndsWith("/") with | true -> AutoIndexDownloader logPath (url + x) <| Directory.CreateDirectory( Path.Combine( path, WebUtility.UrlDecode(x.Substring(0,x.Length-1)).Replace('|','l'))) .FullName | _ -> let _decoded = WebUtility.UrlDecode(x).Replace('|','l') let _path = Path.Combine(path, _decoded) match File.Exists _path with | false -> try let _url = url + x let _temp = Path.Combine(Environment.CurrentDirectory, _decoded) Log.Log [_url; "=>"; _path] use wc = new WebClient() wc.DownloadFile(_url, _temp) File.Move(_temp, _path) with | e -> if not <| String.IsNullOrWhiteSpace logPath then use sw = new StreamWriter(logPath, true) sw.WriteLine(x.ToString() + " " + e.Message) Log.Error [e.Message] | _ -> () lock.Release() |> ignore }) |> Async.Parallel |> Async.RunSynchronously |> ignore with | e -> if not <| String.IsNullOrWhiteSpace logPath then use sw = new StreamWriter(logPath, true) sw.WriteLine(url + " " + e.Message) Log.Error [e.Message] AutoIndexDownloader logPath url path [<EntryPoint>] let main argv = match argv.Length with | 3 -> AutoIndexDownloaderAsync "" (Convert.ToInt32(argv.[2])) (argv.[0]) (argv.[1]) | 4 -> AutoIndexDownloaderAsync (argv.[3]) (Convert.ToInt32(argv.[2])) (argv.[0]) (argv.[1]) | _ -> Console.WriteLine "Url Path threadNum [LogPath]" 0