Skip to content

Commit

Permalink
(feat) add playlist searching to music page
Browse files Browse the repository at this point in the history
  • Loading branch information
tphoney committed May 31, 2024
1 parent 2bd04e0 commit 78cfcdb
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 31 deletions.
3 changes: 1 addition & 2 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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/`
54 changes: 38 additions & 16 deletions plex/plex.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
"regexp"
"slices"
"sort"
"strconv"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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 {
Expand All @@ -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,
Expand Down
11 changes: 3 additions & 8 deletions plex/plex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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)
}
Expand All @@ -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))
Expand Down
29 changes: 26 additions & 3 deletions web/music/music.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 == "" {
Expand All @@ -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]
Expand Down Expand Up @@ -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 := `<fieldset id="playlist">
<label for="All">
<input type="radio" id="playlist" name="playlist" value="all" checked />
All: dont use a playlist. (SLOW, only use for small libraries)
</label>`
playlists, _ := plex.GetPlaylists(c.Config.PlexIP, c.Config.PlexToken, c.Config.PlexMusicLibraryID)
fmt.Println("Playlists:", len(playlists))
for i := range playlists {
playlistHTML += fmt.Sprintf(
`<label for=%q>
<input type="radio" id="playlist" name="playlist" value=%q/>
%s</label>`,
playlists[i].Title, playlists[i].RatingKey, playlists[i].Title)
}

playlistHTML += `</fieldset>`
fmt.Fprint(w, playlistHTML)
}

func ProgressBarHTML(w http.ResponseWriter, _ *http.Request) {
if lookup == spotifyString {
numberOfArtistsProcessed = spotify.GetJobProgress()
Expand All @@ -146,7 +169,7 @@ func ProgressBarHTML(w http.ResponseWriter, _ *http.Request) {
tableContents = renderSimilarArtistsTable()
}
fmt.Fprintf(w,
`<table class="table-sortable">%s</tbody></table>
`<table class="table-sortable" hx-boost="true">%s</tbody></table>
</script><script>document.querySelector('.table-sortable').tsortable()</script>`,
tableContents)
// reset variables
Expand Down
9 changes: 7 additions & 2 deletions web/music/music.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@
<h1 class="container">Music</h1>
<div hx-get="/settings/plexinfook" class="container" hx-trigger="load"></div>
<form hx-post="/musicprocess" class="container" hx-target="#progress" hx-boost="true" hx-indicator="#indicator">
<fieldset>
<legend><strong>Plex Filter:</strong> only lookup music that matches the following criteria.</legend>
<legend><strong>Plex:</strong></legend>
<fieldset id="playlist" hx-get="/musicplaylists" class="container" name="playlist" hx-trigger="load once"
hx-swap="outerHTML" hx-boost="true" hx-target="this">
<label for="All">
<input type="radio" id="playlist" name="playlist" value="all" checked />
All: dont use a playlist.
</label>
</fieldset>
<fieldset>
<legend><strong>Lookup:</strong></legend>
Expand Down
1 change: 1 addition & 0 deletions web/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func StartServer(startingConfig *types.Configuration) {

mux.HandleFunc("/music", music.MusicHandler)
mux.HandleFunc("/musicprocess", music.MusicConfig{Config: config}.ProcessHTML)
mux.HandleFunc("/musicplaylists", music.MusicConfig{Config: config}.PlaylistHTML)
mux.HandleFunc("/musicprogress", music.ProgressBarHTML)

mux.HandleFunc("/", indexHandler)
Expand Down

0 comments on commit 78cfcdb

Please sign in to comment.