@@ -1027,26 +1027,44 @@ final class YTMusicClient: YTMusicClientProtocol {
10271027 APICache . shared. invalidate ( matching: " browse: " )
10281028 }
10291029
1030+ // MARK: - Podcast ID Conversion
1031+
1032+ /// Converts a podcast show ID (MPSPP prefix) to a playlist ID (PL prefix) for the like/unlike API.
1033+ /// - Podcast show IDs use "MPSPP" + "L" + {idSuffix}, e.g. "MPSPPLXz2p9...".
1034+ /// - The corresponding playlist ID is "PL" + {idSuffix}, e.g. "PLXz2p9...".
1035+ /// - We strip "MPSPP" (5 chars) leaving "LXz2p9...", then prepend "P" to get "PLXz2p9...".
1036+ /// - Parameter showId: The podcast show ID to convert
1037+ /// - Returns: The playlist ID for the like API
1038+ /// - Throws: YTMusicError.invalidInput if the ID format is invalid
1039+ private func convertPodcastShowIdToPlaylistId( _ showId: String ) throws -> String {
1040+ guard showId. hasPrefix ( " MPSPP " ) else {
1041+ self . logger. warning ( " ShowId does not have MPSPP prefix, using as-is: \( showId) " )
1042+ return showId
1043+ }
1044+
1045+ let suffix = String ( showId. dropFirst ( 5 ) ) // "LXz2p9..."
1046+
1047+ guard !suffix. isEmpty else {
1048+ self . logger. error ( " Invalid podcast show ID (missing suffix after MPSPP): \( showId) " )
1049+ throw YTMusicError . invalidInput ( " Invalid podcast show ID: \( showId) " )
1050+ }
1051+
1052+ guard suffix. hasPrefix ( " L " ) else {
1053+ self . logger. error ( " Invalid podcast show ID (suffix must start with 'L'): \( showId) " )
1054+ throw YTMusicError . invalidInput ( " Invalid podcast show ID format: \( showId) " )
1055+ }
1056+
1057+ return " P " + suffix // "P" + "LXz2p9..." = "PLXz2p9..."
1058+ }
1059+
10301060 /// Subscribes to a podcast show (adds to library).
1031- /// This uses the playlist-style "like" subscription API (`like/like` endpoint) by treating podcast shows as playlist-like entities.
1061+ /// This uses the like/like endpoint with the playlist ID (PL prefix).
1062+ /// Podcast shows have an MPSPP prefix that maps to PL for the like API.
10321063 /// - Parameter showId: The podcast show ID (MPSPP prefix)
10331064 func subscribeToPodcast( showId: String ) async throws {
10341065 self . logger. info ( " Subscribing to podcast: \( showId) " )
10351066
1036- // Extract the playlist ID portion from MPSPP prefix.
1037- // Podcast show IDs use the form "MPSPP" + {idSuffix}, where the corresponding
1038- // playlist ID is "PL" + {idSuffix}. We validate the suffix is non-empty.
1039- let playlistId : String
1040- if showId. hasPrefix ( " MPSPP " ) {
1041- let suffix = String ( showId. dropFirst ( 5 ) )
1042- if suffix. isEmpty {
1043- self . logger. error ( " Invalid podcast show ID (missing suffix after MPSPP): \( showId) " )
1044- throw YTMusicError . invalidInput ( " Invalid podcast show ID: \( showId) " )
1045- }
1046- playlistId = " PL " + suffix
1047- } else {
1048- playlistId = showId
1049- }
1067+ let playlistId = try self . convertPodcastShowIdToPlaylistId ( showId)
10501068
10511069 let body : [ String : Any ] = [
10521070 " target " : [ " playlistId " : playlistId] ,
@@ -1060,23 +1078,13 @@ final class YTMusicClient: YTMusicClientProtocol {
10601078 }
10611079
10621080 /// Unsubscribes from a podcast show (removes from library).
1063- /// This uses the playlist-style "like" subscription API (`like/removelike` endpoint).
1081+ /// This uses the like/removelike endpoint with the playlist ID (PL prefix).
1082+ /// Podcast shows have an MPSPP prefix that maps to PL for the like API.
10641083 /// - Parameter showId: The podcast show ID (MPSPP prefix)
10651084 func unsubscribeFromPodcast( showId: String ) async throws {
10661085 self . logger. info ( " Unsubscribing from podcast: \( showId) " )
10671086
1068- // Extract the playlist ID portion from MPSPP prefix.
1069- let playlistId : String
1070- if showId. hasPrefix ( " MPSPP " ) {
1071- let suffix = String ( showId. dropFirst ( 5 ) )
1072- if suffix. isEmpty {
1073- self . logger. error ( " Invalid podcast show ID (missing suffix after MPSPP): \( showId) " )
1074- throw YTMusicError . invalidInput ( " Invalid podcast show ID: \( showId) " )
1075- }
1076- playlistId = " PL " + suffix
1077- } else {
1078- playlistId = showId
1079- }
1087+ let playlistId = try self . convertPodcastShowIdToPlaylistId ( showId)
10801088
10811089 let body : [ String : Any ] = [
10821090 " target " : [ " playlistId " : playlistId] ,
0 commit comments