Private/Invoke-YtmApi.ps1
|
function Invoke-YtmApi { <# .SYNOPSIS Makes authenticated API calls to YouTube Music. .DESCRIPTION Sends HTTP requests to the YouTube Music API with proper authentication headers and client context. Handles response parsing and error handling. .PARAMETER Endpoint The API endpoint to call (e.g., 'browse', 'search') .PARAMETER Body The request body as a hashtable. Will be merged with client context. .PARAMETER Cookies Optional cookie object. If not provided, uses stored cookies. .PARAMETER ContinuationToken Optional continuation token for pagination. .OUTPUTS PSCustomObject The parsed JSON response from the API .EXAMPLE $body = @{ browseId = 'FEmusic_liked_videos' } $response = Invoke-YtmApi -Endpoint 'browse' -Body $body #> [CmdletBinding()] [OutputType([PSCustomObject])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Endpoint, [Parameter(Mandatory = $false)] [hashtable]$Body = @{}, [Parameter(Mandatory = $false)] [PSCustomObject]$Cookies, [Parameter(Mandatory = $false)] [string]$ContinuationToken ) # Constants $ytmBaseApi = 'https://music.youtube.com/youtubei/v1/' # This is YouTube Music's public web client API key, extracted from the official web app. # It is safe to expose as it is publicly visible in YouTube Music's JavaScript bundle. $ytmParams = '?alt=json&key=AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30' $userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' $origin = 'https://music.youtube.com' # Get cookies if not provided if (-not $Cookies) { $Cookies = Get-YtmStoredCookies if (-not $Cookies) { throw 'Not authenticated. Please run Connect-YtmAccount first.' } } # Build authorization header $authorization = Get-YtmSapiSidHash -SapiSid $Cookies.SapiSid -Origin $origin # Build headers $headers = @{ 'User-Agent' = $userAgent 'Origin' = $origin 'Authorization' = $authorization 'Cookie' = $Cookies.Cookies } # Get client context and merge with body $context = Get-YtmClientContext $requestBody = $context.Clone() foreach ($key in $Body.Keys) { $requestBody[$key] = $Body[$key] } # Build URL $url = $ytmBaseApi + $Endpoint + $ytmParams if ($ContinuationToken) { $url += "&ctoken=$ContinuationToken&continuation=$ContinuationToken" } Write-Verbose "Making request to: $url" try { $jsonBody = $requestBody | ConvertTo-Json -Depth 10 Write-Verbose "Request body: $jsonBody" $response = Invoke-RestMethod -Uri $url -Method Post -Headers $headers -Body $jsonBody -ContentType 'application/json' -ErrorAction Stop return $response } catch { $statusCode = $null if ($_.Exception.Response) { $statusCode = [int]$_.Exception.Response.StatusCode } if ($statusCode -eq 401 -or $statusCode -eq 403) { throw "Authentication failed. Your cookies may have expired. Please run Connect-YtmAccount again." } throw "YouTube Music API request failed: $($_.Exception.Message)" } } |