beets
                                
                                
                                
                                    beets copied to clipboard
                            
                            
                            
                        Add plexsync plugin to sync with Plex and create/edit playlists on Plex
This plugin introduces the ability to interact with Plex. Currently, it has the following features:
- Introduce 
plexupdatecommand to manually update Plex library. Also, like the currentplexupdateplugin, it automatically updates Plex library when beets database changes. - Introduce 
plexsyncandplexsyncrecentcommands to get track information (e.g., userRating, viewCount, skipCount) from Plex.plexsyncrecentgets the information for tracks played in the last 7 days. - Introduce 
plexplaylistaddandplexplaylistremovecommands 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.rstnear the top of the document.) - [ ] Tests. (Encouraged but not strictly required.)
 
@sampsyo Any chance you can give it a quick look? I have been using it for a while and it is working perfectly.
The errors look unrelated to the current PR. Any thoughts?
@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!
All green again and ready for review.
@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.
@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.
@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?
 
- 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.
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
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 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.
- 
First, we figure out which service is being used and then use the relevant import function (
import_apple_playlistorimport_gaana_playlistorimport_jiosaavn_playlist). - 
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.
 - 
In many cases (especially Bollywood playlists), there are tracks like the following:

 - 
These tracks require cleaning. We need to parse out
titleandalbumfrom the track title. Part of the cleaning is done in theimport_xyz_playlistfunctions and the rest in theparse_titleandcleam_album_namefunctions. note that these may not be relevant to other genres of music. - 
Once we have a clean list of songs from the playlist, I use the
search_plex_songto search for the track in Plex. This function uses thesearchTracksfunction provided by theplexapilibrary. This was one of the reasons I wanted to move toplexapias 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 thefind_closest_matchfunction. This function returns the sorted list (based on the distance), i.e., the closest match will be the first element. - 
All the matched tracks are placed in another list and the list is then added to a Plex playlist using the
_plex_add_playlist_itemfunction. 
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.