kinopoisk.ps1
Write-Verbose "Include script '$PSCommandPath'" ### Includes: . "$PSScriptRoot\network.ps1" . "$PSScriptRoot\text.ps1" ### Types: class FindKinopoiskResult { [string]$Name [string]$NameTranslit [int]$Year [string[]]$CountriesAny [string]$Type $Result = $null $AllResults = @() [bool]$Success = $false [string]$Message = "" } ### Variables: $kinopoisk_content_types = @{ 'movie' = @('movie', 'cartoon') 'film' = @('movie', 'cartoon') 'tvshow' = @('tv-series', 'animated-series', 'anime') 'tv-series' = @('tv-series', 'animated-series', 'anime') 'tvseries' = @('tv-series', 'animated-series', 'anime') } $kinopoisk_country_languages = @{ 'Россия' = 'ru' 'США' = 'en' 'Франция' = 'fr' 'Испания' = 'es' } ### Functions: ### Example: #curl.exe -H "X-API-KEY: ..." "https://api.kinopoisk.dev/v1.4/movie/search?page=1&limit=10&query=farang" -o test_result1.json function Invoke-KinopoiskRequest { [CmdletBinding()] param ( [string]$Url, [ValidateSet('JSON', 'Text', IgnoreCase = $true)] [string]$ResponseType = 'JSON', [System.Collections.Specialized.OrderedDictionary]$Query = @{ } ### ordered - обязательно, чтобы был одинаковый порядок параметров ) Write-Verbose "Invoke-KinopoiskRequest: begin" Write-Verbose "Invoke-KinopoiskRequest: Url: '$Url'" $config = Get-Config $kinopoisk_config = $config.Kinopoisk $api_url = $kinopoisk_config.ApiUrl if (!$api_url) { throw "Kinopoisk API URL is empty" } Write-Verbose "Invoke-KinopoiskRequest: api_url: '$api_url'" $api_key = $kinopoisk_config.ApiKey if (!$api_key) { throw "Kinopoisk API key is empty" } Write-Verbose "Invoke-KinopoiskRequest: api_key: '$($api_key.Substring(0, 2) + "****")'" $full_url = Combine-Url -Segments $api_url, $Url Write-Verbose "Invoke-KinopoiskRequest: full_url: '$full_url'" $headers = @{ 'X-API-KEY' = $api_key } Get-UrlContent -Url $full_url -ResponseType $ResponseType -Headers $headers -Query $Query } ### Возвращает все результаты поиска: function Find-KinopoiskMovie { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string]$Name, [int]$Limit = 10, [ValidateSet('movie', 'film', 'tvshow', 'tv-series', 'tvseries', IgnoreCase = $true)] [string]$Type = 'movie' ) process { Write-Verbose "Find-KinopoiskMovie: Name: '$Name'" if (!$kinopoisk_content_types.ContainsKey($Type)) { throw "Invalid Kinopoisk content type '$Type'" } $kp_types = $kinopoisk_content_types[$Type] # Invoke-KinopoiskRequest -Url "movie/search?page=1&limit=$($Limit)&query=$([URI]::EscapeUriString($Name))" ` # | select -ExpandProperty docs | ? { $_.type -eq $Type } ### [ordered] обязательно, иначе в PS5, PS7 будет разный порядок параметров, из-за этого разный URL и ключ кэша: $order = 100 Invoke-KinopoiskRequest -Url 'movie/search' -Query ([ordered]@{ page = 1 limit = $Limit query = $Name }) | select -ExpandProperty docs | ? { $_.type -in $kp_types } | % { Add-Member -InputObject $_ -MemberType NoteProperty -Name order -Value ($order--) ### Определить язык ru/en/... по стране: $original_language = '' $countries = @($_.countries.name | % { "$_".Trim() } | ? { $_ }) foreach ($country in $countries) { if ($kinopoisk_country_languages.ContainsKey($country)) { $original_language = $kinopoisk_country_languages[$country] break } } Write-Verbose "Find-KinopoiskMovie: original_language: '$original_language'" Add-Member -InputObject $_ -MemberType NoteProperty -Name OriginalLanguage -Value $original_language $_ } } } ### Возвращает один результат поиска: function Find-KinopoiskMovieSingle { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string]$Name, [int]$Year, [string[]]$CountriesAny, [ValidateSet('movie', 'film', 'tvshow', 'tv-series', 'tvseries', IgnoreCase = $true)] [string]$Type = 'movie', [switch]$TryTranslitName ) Write-Verbose "Find-KinopoiskMovieSingle: Name: '$Name', Type: '$Type', Year: $Year, CountriesAny: [$CountriesAny], TryTranslitName: $TryTranslitName" if (!$Year) { Write-Warning "Find-KinopoiskMovieSingle: Year is not specified, result may be inaccurate" } $kp_info_all = @(Find-KinopoiskMovie -Name $Name -Type $Type | ? { $_.name ### Разница в длине имен не более 5: # $_.name -and ([math]::Abs($Name.Length - $_.name.Length) -le 5) ### !!! }) $result = [FindKinopoiskResult]@{ Name = $Name Year = $Year CountriesAny = $CountriesAny Type = $Type } try { ### Если не нашли, пробуем транслитеровать имя eng->rus и искать снова: if (!$kp_info_all) { if ($TryTranslitName) { Write-Verbose "Find-KinopoiskMovieSingle:" $name_translit = Translit-EngToRus $Name Write-Verbose "Find-KinopoiskMovieSingle: try find by transliterated name (begin) '$name_translit'" $result = Find-KinopoiskMovieSingle -Name $name_translit -Year $Year -CountriesAny $CountriesAny -Type $Type $result.NameTranslit = $name_translit $result.Message += ", name transliterated" return $result } else { $result.Message = "Cannot find movie '$($Name)'" return $result } } $result.AllResults = $kp_info_all Write-Host "Find-KinopoiskMovieSingle: Before filtration:`r`n$($kp_info_all | select id, name, alternativeName, type, year, countries | ft -AutoSize | Out-String)" -fo Cyan ### Фильтруем по странам: if ($CountriesAny) { $kp_info_all = @($kp_info_all | ? { $kp_info_countries = @($_.countries.name) $matched_countries = @($CountriesAny | ? { $_ -in $kp_info_countries }) [bool]$matched_countries }) if (!$kp_info_all) { if ($TryTranslitName) { $name_translit = Translit-EngToRus $Name Write-Verbose "Find-KinopoiskMovieSingle: try find by transliterated name (country) '$name_translit'" $result = Find-KinopoiskMovieSingle -Name $name_translit -Year $Year -CountriesAny $CountriesAny -Type $Type $result.NameTranslit = $name_translit $result.Message += ", name transliterated" return $result } else { $result.Message = "Cannot find movie '$($Name)' with filter by any country: [$($CountriesAny -join ", ")]" return $result } } } ### Ищем по году +-1: if ($Year) { $years = @($Year, ($Year - 1), ($Year + 1)) ### !!! скобки обязательно foreach ($y in $years) { Write-Host "Find by year $y" -fo Cyan $delta = $y - $Year $delta_msg = if ($delta) { " ($('{0:+#;-#;0}' -f $delta))" } else { '' } $kp_info_year = @($kp_info_all | ? { $_.year -eq $y }) if ($kp_info_year) { if ($kp_info_year.Length -eq 1) { $result.Result = $kp_info_year[0] $result.Success = $true $result.Message = "Found single by year $($y)$delta_msg" return $result # break } else { $result.Result = $kp_info_year[0] $result.Success = $true $result.Message = "Found multiple by year $($y)$delta_msg, select 1st" return $result # break } } } if ($TryTranslitName) { $name_translit = Translit-EngToRus $Name Write-Verbose "Find-KinopoiskMovieSingle: try find by transliterated name (year) '$name_translit'" $result = Find-KinopoiskMovieSingle -Name $name_translit -Year $Year -CountriesAny $CountriesAny -Type $Type $result.NameTranslit = $name_translit $result.Message += ", name transliterated" return $result } else { $result.Message = "Cannot find movie '$($Name)' by year $Year" return $result } } ### Если результат еще не установлен if ($kp_info_all -and (!$result.Success)) { if ($kp_info_all.Length -eq 1) { $result.Result = $kp_info_all[0] $result.Success = $true $result.Message = "Found single after filtration" } else { $result.Result = $kp_info_all | Sort-Object order, year -Descending | select -First 1 # $result.Result = $kp_info_all | Sort-Object year, order -Descending | select -First 1 $result.Success = $true $result.Message = "Found multiple after filtration, select 1st" } } if (!$result.Success) { if ($TryTranslitName) { $name_translit = Translit-EngToRus $Name Write-Verbose "Find-KinopoiskMovieSingle: try find by transliterated name (end) '$name_translit'" $result = Find-KinopoiskMovieSingle -Name $name_translit -Year $Year -CountriesAny $CountriesAny -Type $Type $result.NameTranslit = $name_translit $result.Message += ", name transliterated" return $result } else { $result.Message = "Cannot find movie '$($Name)' after filtering" # return $result } } return $result } finally { Write-Verbose "Find-KinopoiskMovieSingle: $($result.Message)" } } |