Skip to content

Instantly share code, notes, and snippets.

@ReenigneArcher
Forked from blacktwin/sync_playlists_to_users.py
Last active February 21, 2020 23:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ReenigneArcher/2b518233db5b3e05c8894503dce0715f to your computer and use it in GitHub Desktop.
Save ReenigneArcher/2b518233db5b3e05c8894503dce0715f to your computer and use it in GitHub Desktop.
Sync Plex playlists to shared users.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Description: Sync Plex playlists to shared users.
# Author: /u/SwiftPanda16
# Requires: plexapi, requests, xmltodict
import requests
import xmltodict
from plexapi.server import PlexServer
from plexapi.server import CONFIG
import sys
### EDIT SETTINGS ###
PLEX_URL = ''
PLEX_TOKEN = ''
PLAYLISTS = [str(sys.argv[1])] # List of playlists to sync, comma separated
USERS = [str(sys.argv[2])] # List of users to sync the playlists to, comma separated
if not PLEX_URL:
PLEX_URL = CONFIG.data['auth'].get('server_baseurl')
if not PLEX_TOKEN:
PLEX_TOKEN = CONFIG.data['auth'].get('server_token')
## CODE BELOW ##
def fetch_plex_api(path='', method='GET', plextv=False, **kwargs):
"""Fetches data from the Plex API"""
url = 'https://plex.tv' if plextv else PLEX_URL.rstrip('/')
headers = {'X-Plex-Token': PLEX_TOKEN,
'Accept': 'application/json'}
params = {}
if kwargs:
params.update(kwargs)
try:
if method.upper() == 'GET':
r = requests.get(url + path,
headers=headers, params=params, verify=False)
elif method.upper() == 'POST':
r = requests.post(url + path,
headers=headers, params=params, verify=False)
elif method.upper() == 'PUT':
r = requests.put(url + path,
headers=headers, params=params, verify=False)
elif method.upper() == 'DELETE':
r = requests.delete(url + path,
headers=headers, params=params, verify=False)
else:
print("Invalid request method provided: {method}".format(method=method))
return
if r and len(r.content):
if 'application/json' in r.headers['Content-Type']:
return r.json()
elif 'application/xml' in r.headers['Content-Type']:
return xmltodict.parse(r.content)
else:
return r.content
else:
return r.content
except Exception as e:
print("Error fetching from Plex API: {err}".format(err=e))
def get_user_tokens(server_id):
api_users = fetch_plex_api('/api/users', plextv=True)
api_shared_servers = fetch_plex_api('/api/servers/{server_id}/shared_servers'.format(server_id=server_id), plextv=True)
user_ids = {user['@id']: user.get('@username', user.get('@title')) for user in api_users['MediaContainer']['User']}
users = {user_ids[user['@userID']]: user['@accessToken'] for user in api_shared_servers['MediaContainer']['SharedServer']}
return users
def main():
"""Main script"""
plex = PlexServer(PLEX_URL, PLEX_TOKEN)
plex_users = get_user_tokens(plex.machineIdentifier)
plex_playlists = {playlist.title: playlist.items() for playlist in plex.playlists()}
for playlist in PLAYLISTS:
playlist_items = plex_playlists.get(playlist)
if not playlist_items:
print("Playlist '{playlist}' not found on the server. Skipping.".format(playlist=playlist))
continue
print("Cloning the '{title}' playlist...".format(title=playlist))
for user in USERS:
user_token = plex_users.get(user)
if not user_token:
print("...User '{user}' not found in shared users. Skipping.".format(user=user))
continue
user_plex = PlexServer(PLEX_URL, user_token)
# Delete the old playlist
try:
user_playlist = user_plex.playlist(playlist)
user_playlist.delete()
except:
pass
# Create a new playlist
user_plex.createPlaylist(playlist, playlist_items)
print("...Created playlist for '{user}'.".format(user=user))
return
if __name__ == "__main__":
main()
print("Done.")
@ReenigneArcher
Copy link
Author

Modified to import PLEX_URL and PLEX_TOKEN from config.ini if not manually entered in this script.

Also playlist and user are passed using arguments. Can only have on playlist and one user though. If anyone knows a better way to pass the arguments please let me know.

Example usage.

sync_playlists_to_users.py "Playlist Name" "User Name"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment