-
-
Save jonchen727/7c71f741bca5b8d5fc60144d72f4807d to your computer and use it in GitHub Desktop.
Updates all metadata in the Tautulli 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 Tautulli 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 Tautulli config.ini file. | |
TAUTULLI_URL = 'http://localhost:8181' | |
TAUTULLI_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 by ID fails | |
DRY_RUN = True # True to dry run without making changes to the Tautulli 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 Tautulli database if needed. | |
if DRY_RUN: | |
print("Dry run enabled. No changes will be made to the Tautulli database.") | |
else: | |
print("Not dry run. Creating a backup of the Tautulli database.") | |
params = {'cmd': 'backup_db', | |
'apikey': TAUTULLI_APIKEY, | |
} | |
requests.post(TAUTULLI_URL.rstrip('/') + '/api/v2', params=params) | |
# Get all old items from the Tautulli database (using raw SQL) | |
print("Retrieving all history items from the Tautulli database...") | |
params = {'cmd': 'sql', | |
'apikey': TAUTULLI_APIKEY, | |
'query': 'SELECT rating_key, grandparent_rating_key, title, grandparent_title, year, media_type, guid FROM session_history_metadata;' | |
} | |
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=params).json() | |
if r['response']['result'] == 'error': | |
print("Error retrieving Tautulli 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 Tautulli database. Guid: {guid}".format(title=title.encode('UTF-8'), 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.encode('UTF-8'))) | |
continue | |
print("...Scanning library: {title}".format(title=library.title.encode('UTF-8'))) | |
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 '{title}' in the Plex library. Skipping...".format(title=item.title.encode('UTF-8'))) | |
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 Tautulli database | |
print("{}Updating all metadata in the Tautulli 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': TAUTULLI_APIKEY, | |
'old_rating_key': old_rating_key, | |
'new_rating_key': new_rating_key, | |
'media_type': new_type} | |
requests.post(TAUTULLI_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 {} items".format(COUNT)) | |
# Clear all recently added items in the Tautulli database | |
print("{}Clearing all recently added items in the Tautulli database...".format("(DRY RUN) " if DRY_RUN else "")) | |
if not DRY_RUN: | |
params = {'cmd': 'sql', | |
'apikey': TAUTULLI_APIKEY, | |
'query': 'DELETE FROM recently_added;' | |
} | |
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=params).json() | |
if r['response']['result'] == 'error': | |
print("Error clearing the Tautulli recently added database table: {}".format(r['response']['message'])) | |
print("Exiting script...") | |
return | |
print("Cleared all items from the Tautulli recently added database table.") | |
if __name__ == "__main__": | |
main() | |
print("Done.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment