beets icon indicating copy to clipboard operation
beets copied to clipboard

Add plexsync plugin to sync with Plex and create/edit playlists on Plex

Open arsaboo opened this issue 3 years ago • 3 comments

This plugin introduces the ability to interact with Plex. Currently, it has the following features:

  1. Introduce plexupdate command to manually update Plex library. Also, like the current plexupdate plugin, it automatically updates Plex library when beets database changes.
  2. Introduce plexsync and plexsyncrecent commands to get track information (e.g., userRating, viewCount, skipCount) from Plex. plexsyncrecent gets the information for tracks played in the last 7 days.
  3. Introduce plexplaylistadd and plexplaylistremove commands to add or remove tracks from Plex playlist. Both these commands accept queries, so we can easily create smart playlists.

Instead of using requests, I am using plexapi to create a more robust plugin that will allow future extensions.

The plugin uses the same configuration as the existing plexupdate plugin. So, you can get started with the following configuration (instructions to obtain the plex token here):

plex:
    host: 192.168.2.25
    port: 32400
    token: TOKEN

Fixes #4410

To Do

  • [ ] Documentation. (If you've add a new command-line flag, for example, find the appropriate page under docs/ to describe it.)
  • [ ] Changelog. (Add an entry to docs/changelog.rst near the top of the document.)
  • [ ] Tests. (Encouraged but not strictly required.)

arsaboo avatar Jul 18 '22 17:07 arsaboo

@sampsyo Any chance you can give it a quick look? I have been using it for a while and it is working perfectly.

arsaboo avatar Aug 14 '22 21:08 arsaboo

The errors look unrelated to the current PR. Any thoughts?

arsaboo avatar Sep 21 '22 14:09 arsaboo

@sampsyo I reverted all the changes that I made to the last working version, but the tests are still failing. Looks like something is wrong elsewhere. Can you please check...thanks!

arsaboo avatar Sep 21 '22 16:09 arsaboo

All green again and ready for review.

arsaboo avatar Oct 04 '22 13:10 arsaboo

@sampsyo Gentle reminder...any chance you can take a look at this? I would like to close this out before I take off during the winter. I have been using this for the last few months and it works perfectly.

arsaboo avatar Oct 19 '22 20:10 arsaboo

@JOJ0 can I bribe you to look at this 😜

I have a few playlist-related features (importing and conversion) in mind that I would love to get through once this PR is merged.

arsaboo avatar Mar 01 '23 18:03 arsaboo

@JOJ0 can I bribe you to look at this stuck_out_tongue_winking_eye

Hahaha :-) Fortunately there is things in life that you can't buy with money!

I have a few playlist-related features (importing and conversion) in mind that I would love to get through once this PR is merged.

I'll try to look into it but there is a couple of things which make it difficult and I would like to give some suggestions on how we could move forward with getting it merged (I'm sure some of these steps you just didn't do yet because you were waiting for a first review before moving on!):

  • I don't use plex and don't know any other beets users that might want to test it. Do you know some?
  • Speaking of testing, do you think you could at least add some tests to this PR
  • Move the documentation of the configuration to a separate docs chapter instead of stating it in the docstring.
  • This PR is consisting of 160 commits, a lot of them have non-specific names like "Update ....". Do you think it's possible to squash and rebase some of those to have commits plus commit-messages that fit together, as well as reduce the commit count overall?

JOJ0 avatar Mar 04 '23 14:03 JOJ0

  • I don't use plex and don't know any other beets users that might want to test it. Do you know some?

I extensively use Plex and have been using this for the last 6-8 months. It works flawlessly under different conditions. In any case I am here to fix any bugs that may still be present.

  • Speaking of testing, do you think you could at least add some tests to this PR

I wish I could write tests. Unfortunately, this is well beyond what I can do with Python.

  • Move the documentation of the configuration to a separate docs chapter instead of stating it in the docstring.

Sure....can you give an example of such PR that I can follow? My plan was just to update the docs when the PR is close to getting merged to indicate the features. Most of the commits are me trying a few things to improve the code. As I said, I am still learning Python and many of these extra commits are the result of my trials.

  • Do you think it's possible to squash and rebase some of those

I am happy to close this PR and open a new clean one if that will help. Again, as I said earlier, many commits are the results of my trials and my improving the code over the last 8 months.

arsaboo avatar Mar 04 '23 15:03 arsaboo

I am closing this in favor of an external plugin. I have also added a playlist import feature there - currently supports importing Apple Music and Spotify (JioSaavn to come soon) playlists.

https://github.com/beetbox/beets/pull/4694

arsaboo avatar Mar 07 '23 20:03 arsaboo

Hi, sorry for letting you wait. I am little slow here, since I'm distracted with another one of my FOSS projects but had planned to give you another reply as soon as I can regarding documentation and maybe tests.

Anyway, now I see how huge this plugin is, probably it was a good decision to go down the route of hosting it yourself. I'm sure it's easier for you now to move on with your many ideas. If I would use plex I definitely would give your plugin a try :-)

One question about the functionality though since I'm curious and always interested how to interact with other services and we had talked about your ideas of importing e.g a spotify playlist into beets and saving to m3u. (I think now you skipped the m3u part and directly import it to plex, right?)

Can you elaborate what the process is to achieve that. Especially I'm curious what happens if a track you have in a spotify list is not found in the beets library or not even existing there. What happens then?

I tried to follow your code but I'm too lazy to understand all the details. Maybe you can list the process in a short list?

  • You are importing a playlist from spotify using spotipy and generating a dict from it containing album, artist, title, year
  • ...
  • At some point you are doing a levenstein distance thing to match to the beets library? Or the plex library?
  • ...

JOJ0 avatar Mar 08 '23 07:03 JOJ0

@JOJ0 no worries at all. I see you are already working on a lot of things. I figured it may be faster for me to have it outside.

Anyways, here's the process I am following right now.

  1. First, we figure out which service is being used and then use the relevant import function (import_apple_playlist or import_gaana_playlist or import_jiosaavn_playlist).

  2. Within those functions, I scrape (Apple and Gaana rely on scraping the playlists) or use the API (Spotify provides an API) to get the song list.

  3. In many cases (especially Bollywood playlists), there are tracks like the following: image

  4. These tracks require cleaning. We need to parse out title and album from the track title. Part of the cleaning is done in the import_xyz_playlist functions and the rest in the parse_title and cleam_album_name functions. note that these may not be relevant to other genres of music.

  5. Once we have a clean list of songs from the playlist, I use the search_plex_song to search for the track in Plex. This function uses the searchTracks function provided by the plexapi library. This was one of the reasons I wanted to move to plexapi as it offers so many such features. Given that the tracks may not be perfectly matched, I used the Levenstein distance to find the closest match and return the matched tracks in descending order using the find_closest_match function. This function returns the sorted list (based on the distance), i.e., the closest match will be the first element.

  6. All the matched tracks are placed in another list and the list is then added to a Plex playlist using the _plex_add_playlist_item function.

I hope this makes the process clear. As you know by now, I am by no means a Python expert and I am sure there are a lot of ways in which the code or the process could be improved. I would love your thoughts/inputs.

Instead of searching for songs in Plex, we can have another function to search in beets. In fact, I already have something close in the _update_recently_played function that uses MatchQuery to search for items in the beets library.

arsaboo avatar Mar 08 '23 13:03 arsaboo