-
-
Save Hellowlol/5a1355fbb0ab71ac25f4f8ee232be36d to your computer and use it in GitHub Desktop.
Updates all metadata in the PlexPy database after moving Plex libraries.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
# | |
# Description: Updates all metadata in the PlexPy database after moving Plex libraries. | |
# Author: /u/SwiftPanda16 | |
# Requires: plexapi, requests | |
from plexapi.server import PlexServer | |
import requests | |
### EDIT SETTINGS ### | |
## NOTE: Only works with movie and tv show libraries. | |
## NOTE: Script requires 'api_sql = 1' to be enabled in the PlexPy config.ini file. | |
PLEXPY_URL = 'http://localhost:8181' | |
PLEXPY_APIKEY = 'xxxxxxxxxx' | |
PLEX_URL = 'http://localhost:32400' | |
PLEX_TOKEN = 'xxxxxxxxxx' | |
FALLBACK_MATCH_TITLE_YEAR = True # True or False, fallback to matching by title and year if matching my ID fails | |
DRY_RUN = True # True to dry run without making changes to the PlexPy database, False to make changes | |
## CODE BELOW ## | |
def get_id_from_guid(guid): | |
id = None | |
if 'imdb://' in guid: | |
id = guid.split('imdb://')[1].split('?')[0] | |
elif 'themoviedb://' in guid: | |
id = guid.split('themoviedb://')[1].split('?')[0] | |
elif 'thetvdb://' in guid: | |
id = guid.split('thetvdb://')[1].split('?')[0].split('/')[0] | |
elif 'thetvdbdvdorder://' in guid: | |
id = guid.split('thetvdbdvdorder://')[1].split('?')[0].split('/')[0] | |
return id | |
def main(): | |
new_key_map = {} | |
old_key_map = {} | |
COUNT = 0 | |
# Check for DRY_RUN. Backup PlexPy database if needed. | |
if DRY_RUN: | |
print("Dry run enabled. No changes will be made to the PlexPy database.") | |
else: | |
print("Not dry run. Creating a backup of the PlexPy database.") | |
params = {'cmd': 'backup_db', | |
'apikey': PLEXPY_APIKEY, | |
} | |
requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=params) | |
# Get all old items from the PlexPy database (using raw SQL) | |
print("Retrieving all history items from the PlexPy database...") | |
params = {'cmd': 'sql', | |
'apikey': PLEXPY_APIKEY, | |
'query': 'SELECT rating_key, grandparent_rating_key, title, grandparent_title, year, media_type, guid FROM session_history_metadata;' | |
} | |
r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=params).json() | |
if r['response']['result'] == 'error': | |
print("Error retrieving PlexPy history: {}".format(r['response']['message'])) | |
print("Exiting script...") | |
return | |
else: | |
for row in r['response']['data']: | |
if row['media_type'] not in ('movie', 'episode'): | |
continue | |
id = get_id_from_guid(row['guid']) | |
if id: | |
key = row['grandparent_rating_key'] or row['rating_key'] | |
media_type = 'show' if row['media_type'] == 'episode' else row['media_type'] | |
title = row['grandparent_title'] or row['title'] | |
year = row['year'] | |
old_key_map[id] = (key, media_type, title, year) | |
#print(id, key, title) | |
else: | |
title = row['grandparent_title'] or row['title'] | |
print("...Invalid guid for '{title}' in the PlexPy database. Guid: {guid}".format(title=title, guid=row['guid'])) | |
old_title_map = {(title, year): (id, key, media_type) for id, (key, media_type, title, year) in old_key_map.items()} | |
# Get all new items from the Plex server | |
print("Retrieving all library items from the Plex server...") | |
plex = PlexServer(PLEX_URL, PLEX_TOKEN) | |
for library in plex.library.sections(): | |
if library.type not in ('movie', 'show') or library.agent == 'com.plexapp.agents.none': | |
print("...Skipping library: {title}".format(title=library.title)) | |
continue | |
print("...Scanning library: {title}".format(title=library.title)) | |
for item in library.all(): | |
id = get_id_from_guid(item.guid) | |
if id: | |
new_key_map[id] = (item.ratingKey, item.type, item.title, str(item.year)) | |
else: | |
print("Missing guid for '{item.title}' in the Plex library. Skipping...".format(item=item)) | |
new_title_map = {(title, year): (id, key, media_type) for id, (key, media_type, title, year) in new_key_map.items()} | |
# Update metadata in the PlexPy database | |
print("{}Updating all metadata in the PlexPy database...".format("(DRY RUN) " if DRY_RUN else "")) | |
for id, (old_rating_key, old_type, title, year) in old_key_map.items(): | |
new_rating_key, new_type, _, _ = new_key_map.get(id, (None, None, None, None)) | |
if not new_rating_key and FALLBACK_MATCH_TITLE_YEAR: | |
_, new_rating_key, new_type = new_title_map.get((title, year), (None, None, None)) | |
if new_rating_key: | |
if new_rating_key != old_rating_key and new_type == old_type: | |
if not DRY_RUN: | |
params = {'cmd': 'update_metadata_details', | |
'apikey': PLEXPY_APIKEY, | |
'old_rating_key': old_rating_key, | |
'new_rating_key': new_rating_key, | |
'media_type': new_type} | |
requests.post(PLEXPY_URL + '/api/v2', params=params) | |
print("...Updated '{title} {year}' ({old} --> {new})".format(title=title.encode('UTF-8'), | |
year=year, old=old_rating_key, new=new_rating_key)) | |
COUNT += 1 | |
else: | |
print("...No mapping for the '{title} {year}' ({old}). Metadata not updated.".format(title=title.encode('UTF-8'), year=year, old=old_rating_key)) | |
print('Updated metadata for %s items' % COUNT) | |
if __name__ == "__main__": | |
main() | |
print("Done.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment