diff --git a/TODO b/TODO index b771493..4d721fa 100644 --- a/TODO +++ b/TODO @@ -2,8 +2,6 @@ ## features -- allow the use of playlists for finding music / TV / movies `https://www.plexopedia.com/plex-media-server/api/playlists/view/` - ## bugs - mandalorian is not showing up on amazon tv search @@ -45,3 +43,4 @@ - allow amazon tv search for indivdual series - improve best match for tv series - vikings, Once Upon a Time in Wonderland, What We Do in the Shadows, The Peter Serafinowicz Show is not showing up on cinema-paradiso tv search +- allow the use of playlists for finding music / TV / movies `https://www.plexopedia.com/plex-media-server/api/playlists/view/` diff --git a/plex/plex.go b/plex/plex.go index d1bea65..d6b8997 100644 --- a/plex/plex.go +++ b/plex/plex.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/http" + "regexp" "slices" "sort" "strconv" @@ -1003,7 +1004,7 @@ func extractTVEpisodes(xmlString string) (episodeList []types.PlexTVEpisode) { } // ================================================================================================= -func GetPlexMusicArtists(ipAddress, libraryID, plexToken string) (artists []types.PlexMusicArtist) { +func GetPlexMusicArtists(ipAddress, plexToken, libraryID string) (artists []types.PlexMusicArtist) { url := fmt.Sprintf("http://%s:32400/library/sections/%s/all", ipAddress, libraryID) response, err := makePlexAPIRequest(url, plexToken) @@ -1106,17 +1107,21 @@ func extractLibraries(xmlString string) (libraryList []types.PlexLibrary, err er // ================================================================================================= -func GetPlaylists(ipAddress, plexToken string) (playlistList []types.PlexPlaylist, err error) { +func GetPlaylists(ipAddress, plexToken, libraryID string) (playlists []types.PlexPlaylist, err error) { + start := time.Now() url := fmt.Sprintf("http://%s:32400/playlists", ipAddress) response, err := makePlexAPIRequest(url, plexToken) if err != nil { fmt.Println("GetPlaylists: Error making request:", err) - return playlistList, err + return playlists, err } - playlistList, err = extractPlaylists(response) - return playlistList, err + playlists, err = extractPlaylists(response) + // filter playlists by library ID + playlists = filterPlaylistsByLibraryID(ipAddress, plexToken, playlists, libraryID) + fmt.Printf("Plex playlists: %d. Duration: %v\n", len(playlists), time.Since(start)) + return playlists, err } func extractPlaylists(xmlString string) (playlistList []types.PlexPlaylist, err error) { @@ -1138,20 +1143,42 @@ func extractPlaylists(xmlString string) (playlistList []types.PlexPlaylist, err return playlistList, nil } -func GetPlaylistItems(ipAddress, plexToken, libraryID, ratingKey string) (playlistItems []types.PlexMusicArtist, err error) { - url := fmt.Sprintf("http://%s:32400/playlists/%s/items", ipAddress, ratingKey) +func filterPlaylistsByLibraryID(ipAddress, plexToken string, playlists []types.PlexPlaylist, + libraryID string) (filteredPlaylists []types.PlexPlaylist) { + for i := range playlists { + url := fmt.Sprintf("http://%s:32400/playlists/%s/items", ipAddress, playlists[i].RatingKey) + response, err := makePlexAPIRequest(url, plexToken) + if err != nil { + fmt.Println("filterPlaylistsByLibraryID: Error making request:", err) + return filteredPlaylists + } + r := regexp.MustCompile(`librarySectionID="(\d+)"`) + matches := r.FindStringSubmatch(response) + if len(matches) == 2 { + if libraryID == matches[1] { + filteredPlaylists = append(filteredPlaylists, playlists[i]) + } + } + } + return filteredPlaylists +} +func GetArtistsFromPlaylist(ipAddress, plexToken, ratingKey string) (playlistItems []types.PlexMusicArtist) { + url := fmt.Sprintf("http://%s:32400/playlists/%s/items", ipAddress, ratingKey) response, err := makePlexAPIRequest(url, plexToken) if err != nil { fmt.Println("GetPlaylistItems: Error making request:", err) - return playlistItems, err + return playlistItems } - playlistItems, err = extractPlaylistItems(response, libraryID) - return playlistItems, err + playlistItems, err = extractPlaylistItems(response) + if err != nil { + fmt.Println("Error extracting playlist items:", err) + } + return playlistItems } -func extractPlaylistItems(xmlString, libraryID string) (playlistItems []types.PlexMusicArtist, err error) { +func extractPlaylistItems(xmlString string) (playlistItems []types.PlexMusicArtist, err error) { var container MusicPlayList err = xml.Unmarshal([]byte(xmlString), &container) if err != nil { @@ -1160,13 +1187,8 @@ func extractPlaylistItems(xmlString, libraryID string) (playlistItems []types.Pl } // verify the library ID matches - fmt.Println("Library ID:", libraryID) artists := make(map[string]types.PlexMusicArtist) for i := range container.Track { - if container.Track[i].LibrarySectionID != libraryID { - fmt.Println("Library ID does not match playlist items library ID.") - return playlistItems, fmt.Errorf("plex music library ID does not match playlist items library ID") - } album := types.PlexMusicAlbum{ Title: container.Track[i].ParentTitle, RatingKey: container.Track[i].ParentRatingKey, diff --git a/plex/plex_test.go b/plex/plex_test.go index c4dc2bf..91a0ad0 100644 --- a/plex/plex_test.go +++ b/plex/plex_test.go @@ -102,7 +102,7 @@ func TestGetPlexMusic(t *testing.T) { if plexIP == "" || plexMusicLibraryID == "" || plexToken == "" { t.Skip("ACCEPTANCE TEST: PLEX environment variables not set") } - result := GetPlexMusicArtists(plexIP, plexMusicLibraryID, plexToken) + result := GetPlexMusicArtists(plexIP, plexToken, plexMusicLibraryID) if len(result) == 0 { t.Errorf("Expected at least one album, but got %d", len(result)) @@ -121,8 +121,7 @@ func TestGetPlaylists(t *testing.T) { if plexIP == "" || plexToken == "" { t.Skip("ACCEPTANCE TEST: PLEX environment variables not set") } - - playlists, err := GetPlaylists(plexIP, plexToken) + playlists, err := GetPlaylists(plexIP, plexToken, "1") if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -136,11 +135,7 @@ func TestGetPlaylistItems(t *testing.T) { if plexIP == "" || plexToken == "" { t.Skip("ACCEPTANCE TEST: PLEX environment variables not set") } - - items, err := GetPlaylistItems(plexIP, plexToken, "1", "111897") - if err != nil { - t.Errorf("Unexpected error: %v", err) - } + items := GetArtistsFromPlaylist(plexIP, plexToken, "111897") // Check the number of items if len(items) == 0 { t.Errorf("Expected at least one item, but got %d", len(items)) diff --git a/web/music/music.go b/web/music/music.go index 6ca8e85..03215b0 100644 --- a/web/music/music.go +++ b/web/music/music.go @@ -52,6 +52,7 @@ func MusicHandler(w http.ResponseWriter, _ *http.Request) { // nolint: lll, nolintlint func (c MusicConfig) ProcessHTML(w http.ResponseWriter, r *http.Request) { + playlist := r.FormValue("playlist") lookup = r.FormValue("lookup") if lookup == "musicbrainz" { if c.Config.MusicBrainzURL == "" { @@ -75,8 +76,10 @@ func (c MusicConfig) ProcessHTML(w http.ResponseWriter, r *http.Request) { } lookupType = r.FormValue("lookuptype") // only get the artists from plex once - if len(plexMusic) == 0 { - plexMusic = plex.GetPlexMusicArtists(c.Config.PlexIP, c.Config.PlexMusicLibraryID, c.Config.PlexToken) + if playlist == "all" { + plexMusic = plex.GetPlexMusicArtists(c.Config.PlexIP, c.Config.PlexToken, c.Config.PlexMusicLibraryID) + } else { + plexMusic = plex.GetArtistsFromPlaylist(c.Config.PlexIP, c.Config.PlexToken, playlist) } //nolint: gocritic // plexMusic = plexMusic[:30] @@ -131,6 +134,26 @@ func (c MusicConfig) ProcessHTML(w http.ResponseWriter, r *http.Request) { fmt.Printf("Processed %d artists in %v\n", totalArtists, time.Since(startTime)) } +func (c MusicConfig) PlaylistHTML(w http.ResponseWriter, _ *http.Request) { + playlistHTML := `
` + fmt.Fprint(w, playlistHTML) +} + func ProgressBarHTML(w http.ResponseWriter, _ *http.Request) { if lookup == spotifyString { numberOfArtistsProcessed = spotify.GetJobProgress() @@ -146,7 +169,7 @@ func ProgressBarHTML(w http.ResponseWriter, _ *http.Request) { tableContents = renderSimilarArtistsTable() } fmt.Fprintf(w, - `