tmdb.ps1
### Includes: . "$PSScriptRoot\network.ps1" . "$PSScriptRoot\text.ps1" ### Types: class FindTmdbResult { [string]$Name [string]$NameTranslit [int]$Year [string[]]$CountriesAny [string]$Type $Result = $null [bool]$Success = $false [string]$Message = "" } ### Variables: ### Functions: function Invoke-TmdbRequest { [CmdletBinding()] param ( [string]$Url, [ValidateSet('JSON', 'Text', IgnoreCase = $true)] [string]$ResponseType = 'JSON', [System.Collections.Specialized.OrderedDictionary]$Query = @{ } ### ordered - обязательно, чтобы был одинаковый порядок параметров ) Write-Verbose "Invoke-TmdbRequest: begin" Write-Verbose "Invoke-TmdbRequest: ErrorActionPreference: '$ErrorActionPreference'" Write-Verbose "Invoke-TmdbRequest: Url: '$Url'" $config = Get-Config $tmdb_config = $config.Tmdb $api_url = $tmdb_config.ApiUrl if (!$api_url) { throw "TMDB API URL is not set" } Write-Verbose "Invoke-TmdbRequest: api_url: '$api_url'" $access_token = $tmdb_config.AccessToken if (!$access_token) { throw "TMDB access token is not set" } Write-Verbose "Invoke-TmdbRequest: access_token: '$($access_token.Substring(0, 2) + "****")'" $full_url = Combine-Url -Segments $api_url, $Url Write-Verbose "Invoke-TmdbRequest: full_url: '$full_url'" $headers = @{ "Authorization" = "Bearer $access_token" "accept" = "application/json" } Get-UrlContent -Url $full_url -ResponseType $ResponseType -Headers $headers -Query $Query } ### Поиск фильма по имени и году: function Find-TmdbMovies { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string]$Name, [int]$Year, [string]$Language = 'ru-RU' ) process { Write-Verbose "Find-TmdbMovies: Name: '$Name'" Write-Verbose "Find-TmdbMovies: ErrorActionPreference: '$ErrorActionPreference'" ### [ordered] обязательно, иначе в PS5, PS7 будет разный порядок параметров, из-за этого разный URL и ключ кэша: $query = [ordered]@{ page = 1 include_adult = 'true' query = [URI]::EscapeUriString($Name) } if ($Year) { $query.year = $Year } if ($Language) { $query.language = $Language } Invoke-TmdbRequest -Url 'search/movie' -Query $query | select -ExpandProperty results | % { if ((!$_.year) -and $_.release_date) { $y = (Get-Date $_.release_date).Year Write-Verbose "Find-TmdbMovies: add year $y" Add-Member -InputObject $_ -MemberType NoteProperty -Name year -Value $y } if ($_.poster_path) { Add-Member -InputObject $_ -MemberType NoteProperty -Name poster_url -Value "https://image.tmdb.org/t/p/original/$($_.poster_path)" } if ($_.backdrop_path) { Add-Member -InputObject $_ -MemberType NoteProperty -Name backdrop_url -Value "https://image.tmdb.org/t/p/original/$($_.backdrop_path)" } $_ } } } function Find-TmdbMovieSingle { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Name, [string]$OriginalName, [int]$Year # [string[]]$CountriesAny # [switch]$TryTranslitName ) Write-Verbose "Find-TmdbMovieSingle: Name: '$Name', Year: '$Year'" Write-Verbose "Find-TmdbMovieSingle: ErrorActionPreference: '$ErrorActionPreference'" $result = [FindTmdbResult]@{ Name = $Name Year = $Year # CountriesAny = $CountriesAny Type = 'Movie' Success = $false } $find_results = @() # $err = $null try { $find_results = @(Find-TmdbMovies -Name $Name) } catch { $err = $_ if ($ErrorActionPreference -eq 'Stop') { throw } elseif ($ErrorActionPreference -ne 'SilentlyContinue') { Write-Host ($_ | fl * -Force | Out-String).Trim() -ForegroundColor 'Red' Write-Host ($_.Exception | fl * -Force | Out-String).Trim() -ForegroundColor 'Red' Write-Host ("Parameters:`r`n" + (New-Object "PSObject" -Property $PSBoundParameters | fl * | Out-String).Trim()) -ForegroundColor 'Cyan' } $result.Message = "Find-TmdbMovies: " + $_.Exception.Message return $result } # Write-Host "[DEBUG #2]" # Write-Host ("`r`n=== err:`r`n" + ($err | fl * -Force | Out-String).Trim()) -ForegroundColor 'Cyan' ### Если не нашли, пробуем транслитеровать имя eng->rus и искать снова: if (!$find_results) { $result.Message = "Cannot find movie '$($Name)'" # if ($err) { # $result.Message += ": $($err.Exception.Message)" # } Write-Verbose "Find-TmdbMovieSingle: $($result.Message)" return $result } # $result.AllResults = $tmdb_info_all Write-Host "Find-TmdbMovieSingle: Before filtration:`r`n$($find_results | select id, title, original_title, original_language, release_date, year | ft -AutoSize | Out-String)" -fo Cyan if ($OriginalName) { $find_results = @($find_results | ? { $_.original_title -eq $OriginalName }) if ($find_results.Length -eq 1) { $result.Result = $find_results[0] $result.Success = $true $result.Message = "Found by original name '$OriginalName'" return $result } } ### Если указан год, ищем по году +-1: if ($Year) { ### !!! скобки обязательно foreach ($y in @($Year, ($Year - 1), ($Year + 1))) { Write-Host "Find by year $y" -fo Cyan $delta = $y - $Year $delta_msg = if ($delta) { " ($('{0:+#;-#;0}' -f $delta))" } else { '' } $find_results_year = @($find_results | ? { $_.year -eq $y }) if ($find_results_year) { if ($find_results_year.Length -eq 1) { $result.Result = $find_results_year[0] $result.Success = $true $result.Message = "Found single by year $($y)$delta_msg" return $result } else { $result.Result = $find_results_year[0] $result.Success = $true $result.Message = "Found multiple by year $($y)$delta_msg, select 1st" return $result } } } $result.Message = "Cannot find movie '$($Name)' by year $Year" return $result } ### Если результат еще не установлен if ($find_results) { if ($find_results.Length -eq 1) { $result.Result = $find_results[0] $result.Success = $true $result.Message = "Found single after filtration" } else { $result.Result = $find_results | Sort-Object year -Descending | select -First 1 $result.Success = $true $result.Message = "Found multiple after filtration, select 1st" } } return $result } ### Поиск сериала по имени и году: function Find-TmdbTVShows { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string]$Name, [int]$Year, [string]$Language = 'ru-RU' ) process { Write-Verbose "Find-TmdbTVShows: Name: '$Name'" ### [ordered] обязательно, иначе в PS5, PS7 будет разный порядок параметров, из-за этого разный URL и ключ кэша: $query = [ordered]@{ page = 1 include_adult = 'true' query = [URI]::EscapeUriString($Name) } if ($Year) { $query.year = $Year } if ($Language) { $query.language = $Language } Invoke-TmdbRequest -Url 'search/tv' -Query $query | select -ExpandProperty results | % { if ((!$_.year) -and $_.first_air_date) { $y = (Get-Date $_.first_air_date).Year Write-Verbose "Find-TmdbTVShows: add year $y" Add-Member -InputObject $_ -MemberType NoteProperty -Name year -Value $y } $_ } # }) | select -ExpandProperty docs | ? { $_.type -in $kp_types } } } ### Возвращает один результат поиска: function Find-TmdbTVShowSingle { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Name, [string]$OriginalName, [int]$Year, [string[]]$CountriesAny # [switch]$TryTranslitName ) Write-Verbose "Find-TmdbTVShowSingle: Name: '$Name', OriginalName: '$OriginalName', Year: '$Year'" $find_results = @(Find-TmdbTVShows -Name $Name | ? { $_.name }) $result = [FindTmdbResult]@{ Name = $Name Year = $Year CountriesAny = $CountriesAny Type = 'TVShow' } ### Если не нашли, пробуем транслитеровать имя eng->rus и искать снова: if (!$find_results) { # if ($TryTranslitName) { # Write-Verbose "Find-TmdbTVShowSingle:" # $name_translit = Translit-EngToRus $Name # Write-Verbose "Find-TmdbTVShowSingle: try find by transliterated name (begin) '$name_translit'" # $result = Find-TmdbTVShowSingle -Name $name_translit -Year $Year -CountriesAny $CountriesAny # $result.NameTranslit = $name_translit # $result.Message += ", name transliterated" # return $result # } else { $result.Message = "Cannot find movie '$($Name)'" Write-Verbose "Find-TmdbTVShowSingle: $($result.Message)" return $result # } } # $result.AllResults = $tmdb_info_all Write-Host "Find-TmdbTVShowSingle: Before filtration:`r`n$($find_results | select id, name, original_name, year, origin_country | ft -AutoSize | Out-String)" -fo Cyan if ($OriginalName) { # Write-Verbose "Find-TmdbTVShowSingle: find by original name '$OriginalName'" # $find_results = @($find_results | ? { $_.original_name -eq $OriginalName }) # $find_results_original_name = @($find_results | ? { $_.original_name -eq $OriginalName }) # if ($find_results_original_name.Length -eq 1) { # $result.Result = $find_results_original_name[0] # $result.Success = $true # $result.Message = "Found by original name '$OriginalName'" # return $result # } } ### Фильтруем по странам: # if ($CountriesAny) { # $tmdb_info_all = @($tmdb_info_all | ? { # $kp_info_countries = @($_.countries.name) # $matched_countries = @($CountriesAny | ? { $_ -in $kp_info_countries }) # [bool]$matched_countries # }) # # if (!$tmdb_info_all) { # if ($TryTranslitName) { # $name_translit = Translit-EngToRus $Name # Write-Verbose "Find-TmdbTVShowSingle: try find by transliterated name (country) '$name_translit'" # $result = Find-TmdbTVShowSingle -Name $name_translit -Year $Year -CountriesAny $CountriesAny # $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 { '' } $tmdb_info_year = @($find_results | ? { $_.year -eq $y }) if ($tmdb_info_year) { if ($tmdb_info_year.Length -eq 1) { $result.Result = $tmdb_info_year[0] $result.Success = $true $result.Message = "Found single by year $($y)$delta_msg" return $result # break } else { $result.Result = $tmdb_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-TmdbTVShowSingle: try find by transliterated name (year) '$name_translit'" # $result = Find-TmdbTVShowSingle -Name $name_translit -Year $Year -CountriesAny $CountriesAny # $result.NameTranslit = $name_translit # $result.Message += ", name transliterated" # return $result # } else { $result.Message = "Cannot find movie '$($Name)' by year $Year" return $result # } } ### Если результат еще не установлен if ($find_results -and (!$result.Success)) { if ($find_results.Length -eq 1) { $result.Result = $find_results[0] $result.Success = $true $result.Message = "Found single after filtration" } else { $result.Result = $find_results | Sort-Object year -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-TmdbTVShowSingle: try find by transliterated name (end) '$name_translit'" # $result = Find-TmdbTVShowSingle -Name $name_translit -Year $Year -CountriesAny $CountriesAny # $result.NameTranslit = $name_translit # $result.Message += ", name transliterated" # return $result # } else { $result.Message = "Cannot find movie '$($Name)' after filtering" # return $result # } } return $result } ### Поиск трейлеров: <# curl.exe -v %HEADERS% --url "https://api.themoviedb.org/3/tv/90027/videos?language=en-US" -o result_carnival_row_videos_en.json <trailer>https://www.youtube.com/watch?v=uCUAr1mei4I</trailer> Джон Уик 4: <trailer>plugin://plugin.video.youtube/?action=play_video&videoid=3Ol0ptL_ppk</trailer> <trailer>plugin://plugin.video.tubed/?mode=play&video_id=6_WIy6KaEy4</trailer> #> function Get-TmdbVideos { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Id, [Parameter(Mandatory = $true)] [ValidateSet('Movie', 'TVShow')] [string]$ContentType, [string[]]$Languages = @('ru-RU', 'en-US'), [string[]]$Types ) Write-Verbose "Get-TmdbVideos: Id: '$Id', Languages: [$Languages], Types: [$Types]" $type_order = @{ 'Trailer' = 10 'Teaser' = 20 'Featurette' = 30 'Behind the Scenes' = 40 } $url = if ($ContentType -eq 'Movie') { "movie/$Id/videos" } else { "tv/$Id/videos" } $Languages | % { Invoke-TmdbRequest -Url $url -Query ([ordered]@{ language = $_ } ) | select -ExpandProperty results | ? { if ($Types) { $_.type -in $Types } else { $true } } | % { Add-Member -InputObject $_ -MemberType NoteProperty -Name Order -Value $type_order[$_.type] if ($_.site -eq "YouTube") { Add-Member -InputObject $_ -MemberType NoteProperty -Name Url -Value "https://www.youtube.com/watch?v=$($_.key)" ### Не работает в Kodi Add-Member -InputObject $_ -MemberType NoteProperty -Name KodiUrl -Value "plugin://plugin.video.youtube/?action=play_video&videoid=$($_.key)" } $_ } | Sort-Object order, name } } function Get-TmdbTrailers { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Id, [ValidateSet('Movie', 'TVShow')] [string]$ContentType, [string[]]$Languages = @('ru-RU', 'en-US'), [string[]]$Types = @("Trailer", "Teaser") ) Write-Verbose "Get-TmdbTrailers: Id: '$Id', Languages: [$Languages], Types: [$Types]" Get-TmdbVideos -Id $Id -Languages $Languages -Types $Types -ContentType $ContentType } |