Public/Remove-PatCollectionItem.ps1
|
function Remove-PatCollectionItem { <# .SYNOPSIS Removes an item from a collection on a Plex server. .DESCRIPTION Removes one or more media items from a collection. Items are identified by their rating keys. Use Get-PatCollection -IncludeItems to retrieve the RatingKey values of items in a collection. .PARAMETER CollectionId The unique identifier of the collection containing the item. .PARAMETER CollectionName The name of the collection to remove items from. Supports tab completion. Requires LibraryName or LibraryId to be specified. .PARAMETER LibraryName The name of the library containing the collection. Supports tab completion. Required when using -CollectionName. This is the preferred way to specify a library. .PARAMETER LibraryId The library section ID containing the collection. Required when using -CollectionName. Use Get-PatLibrary to find library IDs. .PARAMETER RatingKey One or more rating keys of the items to remove from the collection. Obtain these values from Get-PatCollection -IncludeItems. .PARAMETER ServerUri The base URI of the Plex server (e.g., http://plex.example.com:32400). If not specified, uses the default stored server. .PARAMETER PassThru If specified, returns the updated collection object. .EXAMPLE Remove-PatCollectionItem -CollectionId 12345 -RatingKey 67890 Removes the item with rating key 67890 from collection 12345. .EXAMPLE Remove-PatCollectionItem -CollectionName 'Marvel Movies' -LibraryName 'Movies' -RatingKey 111, 222 Removes two items from the 'Marvel Movies' collection in the Movies library. .EXAMPLE Get-PatCollection -CollectionName 'Horror' -LibraryName 'Movies' -IncludeItems | Select-Object -ExpandProperty Items | Where-Object { $_.Title -like '*Remake*' } | Remove-PatCollectionItem -CollectionId 12345 Removes items matching 'Remake' from the collection by piping item objects. .EXAMPLE $collection = Get-PatCollection -CollectionId 12345 -IncludeItems $collection.Items | Select-Object -First 1 | Remove-PatCollectionItem -PassThru Removes the first item from a collection and returns the updated collection. .EXAMPLE Remove-PatCollectionItem -CollectionId 12345 -RatingKey 67890 -WhatIf Shows what would be removed without actually removing it. .OUTPUTS PlexAutomationToolkit.Collection (when -PassThru is specified) Returns the updated collection object showing the new item count. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSReviewUnusedParameter', 'commandName', Justification = 'Standard ArgumentCompleter parameter, not always used' )] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSReviewUnusedParameter', 'parameterName', Justification = 'Standard ArgumentCompleter parameter, not always used' )] [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSReviewUnusedParameter', 'commandAst', Justification = 'Standard ArgumentCompleter parameter, not always used' )] [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'ById')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'ById', ValueFromPipelineByPropertyName)] [ValidateRange(1, [int]::MaxValue)] [int] $CollectionId, [Parameter(Mandatory = $true, ParameterSetName = 'ByNameWithLibraryName')] [Parameter(Mandatory = $true, ParameterSetName = 'ByNameWithLibraryId')] [ValidateNotNullOrEmpty()] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $quoteChar = '' $strippedWord = $wordToComplete if ($wordToComplete -match "^([`"'])(.*)$") { $quoteChar = $Matches[1] $strippedWord = $Matches[2] } $getParams = @{ ErrorAction = 'SilentlyContinue' } if ($fakeBoundParameters.ContainsKey('ServerUri')) { $getParams['ServerUri'] = $fakeBoundParameters['ServerUri'] } if ($fakeBoundParameters.ContainsKey('LibraryName')) { $getParams['LibraryName'] = $fakeBoundParameters['LibraryName'] } elseif ($fakeBoundParameters.ContainsKey('LibraryId')) { $getParams['LibraryId'] = $fakeBoundParameters['LibraryId'] } else { return } $collections = Get-PatCollection @getParams foreach ($collection in $collections) { if ($collection.Title -ilike "$strippedWord*") { $title = $collection.Title if ($quoteChar) { $text = "$quoteChar$title$quoteChar" } elseif ($title -match '\s') { $text = "'$title'" } else { $text = $title } [System.Management.Automation.CompletionResult]::new( $text, $title, 'ParameterValue', $title ) } } })] [string] $CollectionName, [Parameter(Mandatory = $true, ParameterSetName = 'ByNameWithLibraryName')] [ValidateNotNullOrEmpty()] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $quoteChar = '' $strippedWord = $wordToComplete if ($wordToComplete -match "^([`"'])(.*)$") { $quoteChar = $Matches[1] $strippedWord = $Matches[2] } $getParams = @{ ErrorAction = 'SilentlyContinue' } if ($fakeBoundParameters.ContainsKey('ServerUri')) { $getParams['ServerUri'] = $fakeBoundParameters['ServerUri'] } $libraries = Get-PatLibrary @getParams foreach ($lib in $libraries.Directory) { if ($lib.title -ilike "$strippedWord*") { $title = $lib.title if ($quoteChar) { $text = "$quoteChar$title$quoteChar" } elseif ($title -match '\s') { $text = "'$title'" } else { $text = $title } [System.Management.Automation.CompletionResult]::new( $text, $title, 'ParameterValue', $title ) } } })] [string] $LibraryName, [Parameter(Mandatory = $true, ParameterSetName = 'ByNameWithLibraryId')] [ValidateRange(1, [int]::MaxValue)] [int] $LibraryId, [Parameter(Mandatory = $true, ValueFromPipeline, ValueFromPipelineByPropertyName)] [ValidateRange(1, [int]::MaxValue)] [int[]] $RatingKey, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [ValidateScript({ Test-PatServerUri -Uri $_ })] [string] $ServerUri, [Parameter(Mandatory = $false)] [switch] $PassThru ) begin { try { $script:serverContext = Resolve-PatServerContext -ServerUri $ServerUri } catch { throw "Failed to resolve server: $($_.Exception.Message)" } $effectiveUri = $script:serverContext.Uri $headers = $script:serverContext.Headers $resolvedId = $CollectionId $collectionInfo = $null if ($PSCmdlet.ParameterSetName -like 'ByName*') { # Only pass ServerUri if explicitly specified, otherwise let Get-PatCollection use default server with auth $getParams = @{ CollectionName = $CollectionName ErrorAction = 'Stop' } if ($script:serverContext.WasExplicitUri) { $getParams['ServerUri'] = $effectiveUri } if ($LibraryName) { $getParams['LibraryName'] = $LibraryName } else { $getParams['LibraryId'] = $LibraryId } $collection = Get-PatCollection @getParams if (-not $collection) { $libDesc = if ($LibraryName) { "library '$LibraryName'" } else { "library $LibraryId" } throw "No collection found with name '$CollectionName' in $libDesc" } $resolvedId = $collection.CollectionId $collectionInfo = $collection } else { try { # Only pass ServerUri if explicitly specified, otherwise let Get-PatCollection use default server with auth $getParams = @{ CollectionId = $CollectionId; ErrorAction = 'Stop' } if ($script:serverContext.WasExplicitUri) { $getParams['ServerUri'] = $effectiveUri } $collectionInfo = Get-PatCollection @getParams } catch { Write-Verbose "Could not retrieve collection info for ID $CollectionId" } } $allRatingKeys = [System.Collections.ArrayList]::new() } process { foreach ($key in $RatingKey) { $null = $allRatingKeys.Add($key) } } end { if ($allRatingKeys.Count -eq 0) { Write-Verbose "No rating keys provided, nothing to remove" return } $collectionDesc = if ($collectionInfo) { "'$($collectionInfo.Title)'" } else { "Collection $resolvedId" } $target = "$($allRatingKeys.Count) item(s) from $collectionDesc" if (-not $PSCmdlet.ShouldProcess($target, 'Remove from collection')) { return } try { # Remove each item individually (API requires separate DELETE calls per item) foreach ($key in $allRatingKeys) { $endpoint = "/library/collections/$resolvedId/items/$key" $uri = Join-PatUri -BaseUri $effectiveUri -Endpoint $endpoint Write-Verbose "Removing item $key from collection $resolvedId" $null = Invoke-PatApi -Uri $uri -Method 'DELETE' -Headers $headers -ErrorAction 'Stop' } if ($PassThru) { # Only pass ServerUri if explicitly specified $getParams = @{ CollectionId = $resolvedId; ErrorAction = 'Stop' } if ($script:serverContext.WasExplicitUri) { $getParams['ServerUri'] = $effectiveUri } Get-PatCollection @getParams } } catch { throw "Failed to remove items from collection: $($_.Exception.Message)" } } } |