Danbooru

Powershell script to deal with downloaded danbooru files.

Posted under General

Created this script to deal with a collection of files that I had collected from danbooru.
Quite easy to use and works pretty well.

Powershell Script
<#
.SYNOPSIS
    Script to deal with files from danbooru.donmai.us.
.DESCRIPTION
    A Script that has multiple functions to deal with files from danbooru.donmai.us.
    Can download file information and translations from danbooru and can sort and find wallpapers.
    NOTE! All filenames MUST be md5!  This script will only work if the filenames are md5.
    NOTE! You must execute -xml first before using any other function.
.PARAMETER Path
    Where the folder the script should work with
.PARAMETER xmldir
    Where the xml data of each file are.
    Defaults to being within the Path parameter as a xml folder.
.PARAMETER dryrun
    Do a dry run of the script.
    Does not modify or download anything.
.PARAMETER xml
    Download each file's xml data.
    Note! This must be executed first before executing any other function.
.PARAMETER sort
    Sort the files into a folder based on the tag parameter.
.PARAMETER tag
    Check to see if a file has this tag and sort it into the folder of that tag.
.PARAMETER translations
    Download translations of the files.
.PARAMETER translationsdir
    Where to save the translations.
    Defaults to being within the Path parameter as a translation folder.
.PARAMETER wallpaper
    Check for potential wallpapers.
.PARAMETER wallpaperdir
    Where to move the wallpapers.
    Defaults to being within the Path parameter as a wallpaper folder.
.PARAMETER redownloaddata
    Force a redownload of each file's data.
.PARAMETER delaydownload
    Delays download each file's data by X milliseconds.
    Defaults to 1000ms (1 second).
.EXAMPLE
    C:\PS> .\danbooru.ps1 "<path to files>" -xml
    Downloads file information.
.EXAMPLE    
    C:\PS> .\danbooru.ps1 "<path to files>" -wallpaper
    Find wallpapers from the files.
.EXAMPLE    
    C:\PS> .\danbooru.ps1 "<path to files>" -sort -tag vocaloid
    Move files that have the tag vocaloid into a subfolder vocaloid.
.EXAMPLE
    C:\PS> .\danbooru.ps1 <path to files> -sort -tag gundam -xmldir <path to xml directory>
    Move files that have the tag gundam into a subfolder gundam based on xml data in a different directory.
#>

param (
    #where the folder is
    [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
    [ValidateScript({Test-Path $_})]
    [string]$Path = ".\",

    #where the xml data folder is
    [Parameter(ValueFromPipelineByPropertyName)]
    [string]$xmldir = ($Path.trim('\')+"\xml"),
    
    #do a dry run and dont modify anything
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]$dryrun = $false,

    #download post xml data
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]$xml = $false,

    #sort the files into a folder based on tag provided
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]$sort = $false,

    #check to see if a post xml tag has this tag and sort it in the folder of that tag
    [Parameter(ValueFromPipelineByPropertyName)]
    [string]$tag = "",

    #download the translations of the images
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]$translations = $false,
    
    #where to save the translations
    [Parameter(ValueFromPipelineByPropertyName)]
    [string]$translationsdir = ($Path.trim('\')+"\translations"),
    
    #check for potentiall wallpapers
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]$wallpaper = $false,

    #where to save the wallpapers
    [Parameter(ValueFromPipelineByPropertyName)]
    [string]$wallpaperdir = ($Path.trim('\')+"\wallpaper"),
    
    #Force a redownload of various data
    [Parameter(ValueFromPipelineByPropertyName)]
    [switch]$redownloaddata = $false,

    #delay downloading each file's data by X milliseconds
    [Parameter(ValueFromPipelineByPropertyName)]
    [int]$delaydownload = 1000
)

if (($delaydownload -lt 250) -and ($xml -or $translations -or $redownloaddata)){
    Write-Warning "It looks like you are trying to have this script download xml data too fast.  This has the potential for you being banned." -WarningAction Inquire
}

#get all of the files in the folder
$files=(gci -File $Path).Basename

#must be executed first before running other commands
if ($xml){
    $url="https://danbooru.donmai.us/posts.xml" #where the posts data is

    #create the folder
    if (-Not (Test-Path ($xmldir.trim("\")))){
	    New-Item -ItemType directory -Path $xmldir.trim("\")
        $v = "Creating Directory: " + $xmldir.trim("\")
        Write-Verbose $v
    }

    for ($i=0;$i -lt $files.Length; $i++){
	    $percentComplete = ($i / $files.Length) * 100

	    $body=@{
		    md5=$files[$i]
	    }

	    $out = $files[$i]+".xml"

	    Write-Progress -Activity 'Getting information...' -Status $out -PercentComplete $percentComplete

	    if (-Not ($dryrun)){
	        $outfolder = $xmldir.trim('\')+"\"+$out
            if (-Not (Test-Path $outfolder)){
                $v = "Downloading xml data: " + $files[$i]
                Write-Verbose $v

		        Invoke-RestMethod $url -Body $body -Method 'GET' -OutFile $outfolder
                if ($delaydownload -gt 0){
                    Start-Sleep -Milliseconds $delaydownload
                }
            }elseif($redownloaddata){
                $v = "Downloading xml data: " + $files[$i]
                Write-Verbose $v

		        Invoke-RestMethod $url -Body $body -Method 'GET' -OutFile $outfolder
                if ($delaydownload -gt 0){
                    Start-Sleep -Milliseconds $delaydownload
                }
            }
	    }
    }
}

if ($sort -and $tag.Length -gt 0){
    #create the folder
    if (-Not (Test-Path ($Path.trim('\')+"\"+$tag))){
	    New-Item -ItemType directory -Path ($Path.trim('\')+"\"+$tag)
        $v = "Creating Directory: " + ($Path.trim('\')+"\"+$tag)
        Write-Verbose $v
    }

    for ($i=0;$i -lt $files.Length; $i++){
	    $percentComplete = ($i / $files.Length) * 100

        [xml]$xmlDoc = Get-Content ($xmldir.trim('\')+"\"+$files[$i]+".xml")
        
	    Write-Progress -Activity 'Sorting...' -Status $files[$i] -PercentComplete $percentComplete

        if ($xmlDoc.post."tag-string".Contains($tag)){
            $file = $Path.trim('\')+"\"+$files[$i]+"."+$xmlDoc.post."file-ext"
            $dest = $Path.trim('\')+"\"+$tag+"\"+$files[$i]+"."+$xmlDoc.post."file-ext"

            if (-Not ($dryrun)){
                $v = "Moving  " + $file + " to " + $dest
                Write-Verbose $v

                #move the file
                Move-Item -Path $file -Destination $dest
            }
        }
    }
}

if ($translations){
    if (-Not (Test-Path ($translationsdir.trim("\")))){
	    New-Item -ItemType directory -Path ($translationsdir.trim("\"))

        $v = "Creating Directory: " + ($translationsdir.trim("\"))
        Write-Verbose $v
    }

    $xmlfiles=(gci -File $xmldir)

    for ($i=0;$i -lt $xmlfiles.Length; $i++){
        [xml]$xmlDoc = Get-Content ($xmldir.trim('\')+"\"+$xmlfiles[$i])
        
        if ($xmlDoc.post."tag-string".Contains("translated") -or $xmlDoc.post."tag-string".Contains("partially_translated")){
            if (-Not ($dryrun)){
                $url="https://danbooru.donmai.us/notes.xml?search[post_id]="+$xmlDoc.post.id.'#text'

                $outfolder = $translationsdir+"\"+$xmlfiles[$i]

                if (-Not (Test-Path $outfolder)){
                    $v = "Downloading translation data: " + $xmlfiles[$i]
                    Write-Verbose $v

		            Invoke-RestMethod $url -Method 'GET' -OutFile $outfolder
                    if ($delaydownload -gt 0){
                        Start-Sleep -Milliseconds $delaydownload
                    }
                }elseif($redownloaddata){
                    $v = "Downloading translation data: " + $xmlfiles[$i]
                    Write-Verbose $v

		            Invoke-RestMethod $url -Method 'GET' -OutFile $outfolder
                    if ($delaydownload -gt 0){
                        Start-Sleep -Milliseconds $delaydownload
                    }
                }
	        }
        }

	    $percentComplete = ($i / $xmlfiles.Length) * 100
	    Write-Progress -Activity 'Getting translation information' -Status $xmlfiles[$i] -PercentComplete $percentComplete
    }
}

if ($wallpaper){
    if (-Not (Test-Path ($wallpaperdir.trim("\")))){
	    New-Item -ItemType directory -Path $wallpaperdir.trim("\")

        $v = "Creating Directory: " + $wallpaperdir.trim("\")
        Write-Verbose $v
    }

    $wallpaperRatios = @(
        [single](4/3),   #standard
        [single](16/10), #widescreen
        [single](16/9),  #HD
        [single](5/3)    #widescreen alt
    )

    for ($i=0;$i -lt $files.Length; $i++){
        [xml]$xmlDoc = Get-Content ($xmldir.trim('\')+"\"+$files[$i]+".xml")

        [single]$width = $xmlDoc.post."image-width"."#text"
        [single]$height = $xmlDoc.post."image-height"."#text"
        [bool]$isImg = ($xmlDoc.post."file-ext".Contains("png") -or $xmlDoc.post."file-ext".Contains("jpg"))
        
        if ((($wallpaperRatios -contains ([single]($width/$height))) -and $isImg) -or $xmlDoc.post."tag-string".Contains("wallpaper")){
            $file = $Path.trim('\')+"\"+$files[$i]+"."+$xmlDoc.post."file-ext"
            $dest = $wallpaperdir.trim('\')+"\"+$files[$i]+"."+$xmlDoc.post."file-ext"

            if (-Not ($dryrun)){
                $v = "Moving  " + $file + " to " + $dest
                Write-Verbose $v

                #move the file
                Move-Item -Path $file -Destination $dest
            }else{
                $e = "Potential wallpaper ("+$width+"x"+$height+"): "+$files[$i]+"."+$xmlDoc.post."file-ext"
                echo $e
            }
        }

	    $percentComplete = ($i / $files.Length) * 100
        $filename = $files[$i]+"."+$xmlDoc.post."file-ext"
	    Write-Progress -Activity 'Checking for potential wallpapers...' -Status $filename -PercentComplete $percentComplete
    }
}
Edits

-added file checking for xml or translations to prevent redownloading already acquired data.
-added forcing redownloading of xml or translations.
-added a delay on downloading xml or translations (defaults to 1000ms, or 1 second).
-changed folder parameter to path.
-added parameter validation for path and xmldir.
-added warning if delay is less than 250ms.
-added verbose logging.

Updated

1