module YtPlaylist
Constants
- PRIVACY_VALUES
Public Instance Methods
Source
# File lib/yt_playlist.rb, line 99 def add_video(bot_nick:, account:, playlist_ref:, video_ref:, fetch: nil) return { success: false, error: "Not linked — use !yt auth." } unless account video_id = YtLookup.extract_video_id(video_ref) || video_ref.to_s.strip return { success: false, error: "Could not parse YouTube video URL or ID." } if video_id.to_s.length != 11 resolved = resolve_playlist(bot_nick: bot_nick, account: account, ref: playlist_ref, fetch: fetch) return resolved unless resolved[:success] playlist = resolved[:playlist] YtApi.with_access_token(account: account, fetch: fetch) do |token| response = YtApi.post( "/playlistItems", access_token: token, body: { snippet: { playlistId: playlist[:id], resourceId: { kind: "youtube#video", videoId: video_id } } }, fetch: fetch, params: { part: "snippet" } ) return response unless response[:success] item = normalize_item(response[:data]) { success: true, playlist: playlist, item: item } end end
Source
# File lib/yt_playlist.rb, line 29 def create_playlist(bot_nick:, account:, title:, privacy: "private", fetch: nil) return { success: false, error: "Not linked — use !yt auth." } unless account privacy = normalize_privacy(privacy) return { success: false, error: "Privacy must be public, private, or unlisted." } unless privacy YtApi.with_access_token(account: account, fetch: fetch) do |token| response = YtApi.post( "/playlists", access_token: token, body: { snippet: { title: title.to_s.strip, description: "" }, status: { privacyStatus: privacy } }, fetch: fetch, params: { part: "snippet,status" } ) return response unless response[:success] playlist = normalize_playlist(response[:data]) { success: true, playlist: playlist } end end
Source
# File lib/yt_playlist.rb, line 58 def delete_playlist(bot_nick:, account:, playlist_id:, fetch: nil) return { success: false, error: "Not linked — use !yt auth." } unless account YtApi.with_access_token(account: account, fetch: fetch) do |token| response = YtApi.delete( "/playlists", access_token: token, params: { id: playlist_id }, fetch: fetch ) return response unless response[:success] { success: true, playlist_id: playlist_id } end end
Source
# File lib/yt_playlist.rb, line 178 def find_item(items, target_ref) target = target_ref.to_s.strip if target.match?(/\A#\d+\z/) index = target.delete_prefix("#").to_i return items[index - 1] if index.positive? && index <= items.length end video_id = YtLookup.extract_video_id(target) || target items.find { |item| item[:video_id] == video_id } end
Source
# File lib/yt_playlist.rb, line 12 def list_playlists(bot_nick:, account:, fetch: nil) return { success: false, error: "Not linked — use !yt auth." } unless account YtApi.with_access_token(account: account, fetch: fetch) do |token| response = YtApi.get( "/playlists", access_token: token, params: { part: "snippet", mine: true, maxResults: 50 }, fetch: fetch ) return response unless response[:success] playlists = Array(response[:data]["items"]).map { |item| normalize_playlist(item) } { success: true, playlists: playlists } end end
Source
# File lib/yt_playlist.rb, line 197 def normalize_item(item) { item_id: item["id"], video_id: item.dig("contentDetails", "videoId").to_s, title: item.dig("snippet", "title").to_s } end
Source
# File lib/yt_playlist.rb, line 189 def normalize_playlist(item) { id: item["id"], title: item.dig("snippet", "title").to_s, privacy: item.dig("status", "privacyStatus").to_s } end
Source
# File lib/yt_playlist.rb, line 205 def normalize_privacy(value) privacy = value.to_s.strip.downcase return privacy if PRIVACY_VALUES.include?(privacy) nil end
Source
# File lib/yt_playlist.rb, line 132 def remove_item(bot_nick:, account:, playlist_ref:, target_ref:, fetch: nil) return { success: false, error: "Not linked — use !yt auth." } unless account resolved = resolve_playlist(bot_nick: bot_nick, account: account, ref: playlist_ref, fetch: fetch) return resolved unless resolved[:success] playlist = resolved[:playlist] show = show_playlist(bot_nick: bot_nick, account: account, playlist_ref: playlist[:id], fetch: fetch) return show unless show[:success] item = find_item(show[:items], target_ref) return { success: false, error: "Playlist item not found." } unless item YtApi.with_access_token(account: account, fetch: fetch) do |token| response = YtApi.delete( "/playlistItems", access_token: token, params: { id: item[:item_id] }, fetch: fetch ) return response unless response[:success] { success: true, playlist: playlist, removed: item } end end
Source
# File lib/yt_playlist.rb, line 158 def resolve_playlist(bot_nick:, account:, ref:, fetch: nil) ref = ref.to_s.strip return { success: false, error: "Playlist reference required." } if ref.empty? playlist_id = ref if ref.match?(/\APL[\w\-]+\z/) playlist_id ||= YtLookup.extract_playlist_id(ref) unless playlist_id listed = list_playlists(bot_nick: bot_nick, account: account, fetch: fetch) return listed unless listed[:success] match = listed[:playlists].find { |playlist| playlist[:title].to_s.casecmp?(ref) } return { success: false, error: "Playlist not found — use ID or exact title." } unless match return { success: true, playlist: match } end { success: true, playlist: { id: playlist_id, title: ref, privacy: "" } } end
Source
# File lib/yt_playlist.rb, line 74 def show_playlist(bot_nick:, account:, playlist_ref:, fetch: nil) return { success: false, error: "Not linked — use !yt auth." } unless account resolved = resolve_playlist(bot_nick: bot_nick, account: account, ref: playlist_ref, fetch: fetch) return resolved unless resolved[:success] playlist = resolved[:playlist] YtApi.with_access_token(account: account, fetch: fetch) do |token| response = YtApi.get( "/playlistItems", access_token: token, params: { part: "snippet,contentDetails", playlistId: playlist[:id], maxResults: 25 }, fetch: fetch ) return response unless response[:success] items = Array(response[:data]["items"]).map { |item| normalize_item(item) } { success: true, playlist: playlist, items: items } end end