Pixiv Downloader Ver II

open System
open System.IO
open Microsoft.WindowsAPICodePack.Dialogs
open System.Net
open System.Threading

let UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0"
let Referer = "https://www.pixiv.net/member_illust.php?mode="

let (|>>) x f = f x |> ignore ; x

let LogSystem = 
    new MailboxProcessor<ConsoleColor * string>(fun x ->
        let rec loop count = 
            async{
                let! c,s = x.Receive()
                Console.ForegroundColor <- c
                Console.WriteLine s
                return! loop (count + 1)
            }
        loop 0)

let Log (e : string) =
    LogSystem.Post(ConsoleColor.White,"[*] " + e)

let LogInfo (e : string) =
    LogSystem.Post(ConsoleColor.DarkGray,"[i] " + e)

let LogError (e : string) =
    LogSystem.Post(ConsoleColor.Red,"[!] " + e)

let LogFile path (e : string) =
    let sw = new StreamWriter(path, true)
    sw.WriteLine e
    sw.Close()

let PathSeparator = Path.DirectorySeparatorChar.ToString()

let DirectoryPick _ =
    let dialog = new CommonOpenFileDialog()
    dialog.IsFolderPicker <- true
    match dialog.ShowDialog() with
    | CommonFileDialogResult.Ok -> dialog.FileName
    | _ -> failwith "Empty Path"

type UrlType =
    | Picture
    | Pictures
    | Zip

type Pid = 
    { url : string;
    urlType : UrlType }

let rec Input _ =
    match Console.ReadLine().Trim().ToLower() with
    | "" -> []
    | s -> s::Input()

let PixivUrlDownloadAsync directory url = 
    async {
        let path = 
            match url.urlType with
            | UrlType.Pictures -> 
                (directory + PathSeparator + (Path.GetFileNameWithoutExtension url.url).Split('_').[0] 
                |>> (fun p -> 
                        match Directory.Exists p with
                        | false -> Some(Directory.CreateDirectory p)
                        | _ -> None)) + PathSeparator
            | _ -> directory + PathSeparator
            + Path.GetFileName url.url
        use webClient = new WebClient()
        webClient.Headers.Add("User-Agent",UserAgent)
        webClient.Headers.Add("Referer",Referer + (match url.urlType with
                                                    | UrlType.Pictures -> "manga"
                                                    | _ -> "medium") 
                                                    + "&illust_id=" 
                                                    + Path.GetFileNameWithoutExtension url.url)
        webClient.DownloadProgressChanged.Add (fun e -> 
            Console.WriteLine("         [i] Progress " + e.ProgressPercentage.ToString() + " " + url.url))
        webClient.Headers.Add(HttpRequestHeader.Cookie,"")
        webClient.DownloadFileCompleted.Add (fun e -> 
            match e.Error with
            | null -> 
                Console.WriteLine("[*] Completed " + url.url)
            | error -> 
                webClient.CancelAsync()
                Console.Write("[!] Error ")
                Console.WriteLine(error)
                Thread.Sleep(10000)
                Console.WriteLine("[!] Redownloading " + url.url)
                webClient.DownloadFileAsync(Uri(url.url), path))
        Console.WriteLine("[*] Downloading " + url.url)
        try
            webClient.DownloadFileAsync(Uri(url.url), path)
        with
        | e -> 
            Console.WriteLine(e)
            webClient.CancelAsync()
        return true
    }

let PixivUrlsDownloadAsync rawUrls = 
    rawUrls 
    |> Seq.ofList
    |> Seq.map (fun raw -> 
        {url=raw;
        urlType=
            (match ('/' 
                |> raw.Split 
                |> List.ofArray 
                |> List.rev) with
            | head::_ when head.Split('.').[1] = "zip" -> 
                UrlType.Zip
            | head::_ when (rawUrls 
                |> List.exists (fun ru -> 
                    ("p0","p1") 
                    |> head.Replace 
                    |> ru.Contains)) -> 
                        UrlType.Pictures
            | _ -> UrlType.Picture)})
    |> Seq.map (fun u -> 
        PixivUrlDownloadAsync (DirectoryPick()) u)
    |> Async.Parallel
    |> Async.RunSynchronously

let PixivUrlDownload directory url index length =
    let path = 
        match url.urlType with
        | UrlType.Pictures -> 
            (directory + PathSeparator + (Path.GetFileNameWithoutExtension url.url).Split('_').[0] 
            |>> (fun p -> 
                    match Directory.Exists p with
                    | false -> Some(Directory.CreateDirectory p)
                    | _ -> None)) + PathSeparator
        | _ -> directory + PathSeparator
        + Path.GetFileName url.url
    let webClient = new WebClient()
    webClient.Headers.Add("User-Agent",UserAgent)
    webClient.Headers.Add("Referer",Referer + (match url.urlType with
                                                | UrlType.Pictures -> "manga"
                                                | _ -> "medium") 
                                                + "&illust_id=" 
                                                + Path.GetFileNameWithoutExtension url.url)
    webClient.Headers.Add(HttpRequestHeader.Cookie,"")
    Log("[-] Downloading " + url.url)
    try
        webClient.DownloadFile(Uri(url.url), path)
        LogInfo(" |  " + (index + 1).ToString() + "/" + length.ToString() + " Succeed!")
    with
    | e -> 
        (" |  " + Path.GetFileName url.url + " " + e.Message) 
        |>> LogError
        |> LogFile (directory + PathSeparator + "Error.log")

let PixivUrlsDownload rawUrls =
    let directory = DirectoryPick()
    rawUrls 
    |> List.map (fun raw -> 
        {url=raw;
        urlType=
            (match ('/' 
                |> raw.Split 
                |> List.ofArray 
                |> List.rev) with
            | head::_ when head.Split('.').[1] = "zip" -> 
                UrlType.Zip
            | head::_ when (rawUrls 
                |> List.exists (fun ru -> 
                    ("p0","p1") 
                    |> head.Replace 
                    |> ru.Contains)) -> 
                        UrlType.Pictures
            | _ -> UrlType.Picture)})
    |> List.iteri (fun i u ->
        PixivUrlDownload directory u i rawUrls.Length)

[<STAThread>]
[<EntryPoint>]
let main argv= 
    LogSystem.Start()
    match argv.Length with
    | 0 -> Input() |> PixivUrlsDownload
    | _ -> PixivUrlsDownload [argv.[0]]
    Log "Done."
    Console.Read() |> ignore
    0

 

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注