## This scraper reads metadata from a file on Windows using the Shell.Application COM object and outputs it in a format that Stash can understand
## File metadata is stored in the folder object and it's weird as hell

# Read JSON input from stdin
$inputObject = [Console]::In.ReadToEnd() | ConvertFrom-Json


### ALL OF THE BELOW CAN BE REMOVED WHEN STASH SENDS THE FULL METADATA INSTEAD OF JUST THE SCENE ID ###
# We need to make a GraphQL request to get the file path
$filePathQuery = @{ query = "query { findScene(id: `"$($inputObject.id)`") { files { path } } }" } | ConvertTo-Json

# Disgusting horrible hack to find config file in parent directory
$config = Get-Content -Path "../py_common/config.ini" -ErrorAction SilentlyContinue
if ($config) {
    $url = $config | Select-String -Pattern "url = (.*)" | ForEach-Object { $_.Matches.Groups[1].Value }
    if (-not $url) {
        [Console]::Error.WriteLine("$([char]1)w$([char]2) Could not find 'url' in config.ini, defaulting to localhost:9999")
        $url = "http://localhost:9999"
    }
    $api_key = $config | Select-String -Pattern "api_key = (.*)" | ForEach-Object { $_.Matches.Groups[1].Value }
} else {
    [Console]::Error.WriteLine("$([char]1)w$([char]2) Could not read config.ini, defaulting to localhost:9999 with no API key")
    $url = "http://localhost:9999"
    $api_key = ""
}

$filePathResponse = Invoke-WebRequest -Uri "$url/graphql" -Method POST -Body $filePathQuery -ContentType "application/json" -Headers @{ ApiKey = $api_key }

# Ensure the GraphQL request was successful
if ($filePathResponse.StatusCode -ne 200) {
    [Console]::Error.WriteLine("$([char]1)e$([char]2) GraphQL request failed with status code $($filePathResponse.StatusCode): $($filePathResponse.Content)")
    Write-Host "null"
    exit
}

$filePathResponse = $filePathResponse.Content | ConvertFrom-Json

$primaryFile = $filePathResponse.data.findScene.files | Select-Object -First 1 | Select-Object -ExpandProperty path
### END OF DISGUSTING HORRIBLE HACK THAT CAN BE REMOVED ###

# Ensure the file path is provided
if (-not $primaryFile) {
    [Console]::Error.WriteLine("$([char]1)e$([char]2) Could not find a file path for scene '$($inputObject.id)'")
    Write-Host "null"
    exit
}

$file = Get-Item $primaryFile
$shell = New-Object -ComObject Shell.Application
$folder = $shell.Namespace($file.DirectoryName)
$fileObj = $folder.ParseName($file.Name)

$scraped = New-Object PSObject

# The properties can be enumerated by running the following command:
# 320 is arbitrary, there could be properties with higher indexes! I sure hope these are consistent across Windows versions
# foreach ($i in 0..320) {
#     $name = $folder.GetDetailsOf($folder.Items, $i)
#     $value = $folder.GetDetailsOf($fileObj, $i)
#     Write-Host "$i - $name - $value"
# }


# "Title" has index 21 and we'll output it as "title"
$title = $folder.GetDetailsOf($fileObj, 21)
if ($title) {
    $scraped | Add-Member -MemberType NoteProperty -Name "title" -Value $title
}

# "Media created" has index 208 and we'll output it as "date" after cleaning it and formatting it for Stash
$date = $folder.GetDetailsOf($fileObj, 208)
if ($date) {
    $date = $date.Trim() -replace "[^\x20-\x7E]", "" -split " " | Select-Object -First 1
    $date = [datetime]::Parse($date).ToString("dd-MM-yyyy")
    $scraped | Add-Member -MemberType NoteProperty -Name "date" -Value $date
}

# "Tags" has index 18 and we'll output it as "tags", splitting on semicolon and trimming whitespace
$tags = $folder.GetDetailsOf($fileObj, 18)
if ($tags) {
    # Split on semicolon, trim whitespace, turn into {"name": "tag"} objects
    $tags = $tags -split ";" | % { @{ name = $_.Trim() } }
    $scraped | Add-Member -MemberType NoteProperty -Name "tags" -Value $tags
}

# "Contributing artists" has index 13 and we'll output it as "performers", splitting on semicolon and trimming whitespace
$performers = $folder.GetDetailsOf($fileObj, 13)
if ($performers) {
    # Split on semicolon, trim whitespace, turn into {"name": "performer"} objects
    $performers = $performers -split ";" | % { @{ name = $_.Trim() } }
    $scraped | Add-Member -MemberType NoteProperty -Name "performers" -Value $performers
}

# "Directors" has index 312 and we'll output it as "director", replacing semicolons with comma
$director = $folder.GetDetailsOf($fileObj, 312)
if ($director) {
    $director = $director -replace ";", ","
    $scraped | Add-Member -MemberType NoteProperty -Name "director" -Value $director
}

# "Comments" has index 24 and we'll output it as "details" or maybe "url" if it's a URL
$details = $folder.GetDetailsOf($fileObj, 24)
if ($details) {
    # If the details look like a URL, output it as a URL
    if ($details -match "^https?://") {
        $scraped | Add-Member -MemberType NoteProperty -Name "url" -Value $details
    } else {
        $scraped | Add-Member -MemberType NoteProperty -Name "details" -Value $details
    }
}

# No metadata found
if (($scraped | Get-Member -MemberType Properties | Measure-Object).Count -eq 0) {
    [Console]::Error.WriteLine("$([char]1)d$([char]2) Could not find any metadata for '$($file.FullName)'")
    Write-Host "null"
    exit
}

Write-Host ($scraped | ConvertTo-Json -Compress)
