-
-
Save rustymyers/a68f405909224e023088c8cac6834c32 to your computer and use it in GitHub Desktop.
#!/usr/bin/python3 | |
""" | |
#------------------------------------------------------------------------------------------------ | |
#-- Movie Tag Updater for Radarr | |
#-------------------------------------------------------------------------------------------------- | |
# Program : Radarr_tagarr | |
# To Complie : n/a | |
# | |
# Purpose : Add tags and profiles to radarr movies. Tags are retreived from Radarr. | |
# Say Y to add a tag. N to skip a tag. N for all tags will remove all tags. | |
# | |
# Called By : | |
# Calls : | |
# | |
# Author : Rusty Myers <[email protected]> | |
# Based Upon : | |
# | |
# Note : | |
# | |
# Revisions : | |
# 2017-05-03 <rusty> Initial Version | |
# 2017-05-03 <rusty> Updated to dynamically retreive tags and bulk set the ones chosen | |
# 2018-02-13 <rusty> New method to check for matching tags without concern for order, | |
# Adding code to combine tags with existing movie tags instead of replace, | |
# Updating hostname fields to make it easier to support http or https | |
# 2019-07-26 <rusty> Updating to Python3 | |
# 2020-08-25 <rusty> Adding --dry-run for testing changes | |
# 2020-09-01 <rusty> Adding name resolution for hostname | |
# | |
# Version : 1.5 | |
#------------------------------------------------------------------------------------------------""" | |
# | |
from __future__ import print_function | |
import requests, argparse, socket | |
# Function to return json of all movies | |
def get_data(radarrhost): | |
"""Get data from API""" | |
response = requests.get(radarrhost) | |
return response.json() | |
# function to put updated data | |
def put_data(radarrhost, moviedata): | |
"""Put data into API""" | |
result = requests.put(radarrhost, json=moviedata) | |
return result | |
# Variables | |
# Radarr API Key, get it in Settings->General->Security of Sonarr pages | |
APIKEY = "" | |
# Radarr Host Name: Add reverse proxy or direct IP:port, no trailing slash | |
HOSTNAME = "" | |
# Set dryrun default to false | |
dryrun = False | |
# Get our arguments | |
parser = argparse.ArgumentParser(description='Check, Print, and Save DHCP & BSDP Information.') | |
parser.add_argument('-d', '--dry-run', action='store_true', \ | |
dest='dryrun', help='Dry run of tagging, displays expected outcomes.') | |
parser.add_argument('-k', '-apikey' , action='store', default=APIKEY, \ | |
dest='APIKEY', help='Path to plist for saving results to plist. Default: /Library/Preferences/edu.psu.sdt.plist') | |
parser.add_argument('-n', '--hostname', action='store', default=HOSTNAME, \ | |
dest='HOSTNAME', help='Test code with stored BSDP response from OS X Server, writing to /tmp/org.network.plist.') | |
args = parser.parse_args() | |
if args.dryrun: | |
print("!!! Dry Run...not making any changes...") | |
dryrun = True | |
if args.APIKEY: | |
APIKEY = args.APIKEY | |
if args.HOSTNAME: | |
HOSTNAME = args.HOSTNAME | |
host_address = "" | |
HOST = "".join(HOSTNAME.split("/")[2:3]) | |
try: | |
host_address = socket.gethostbyname(HOST) | |
except: | |
print("Unable to resolve hostname! {}".format(HOST)) | |
exit(1) | |
# Get All Tags | |
ALLTAGSJSON = get_data(HOSTNAME + "/api/tag?apikey=" + APIKEY) | |
# Get all Profiles | |
ALLPROFILESJSON = get_data(HOSTNAME + "/api/profile?apikey=" + APIKEY) | |
print("Connecting to: {}".format(HOSTNAME + "/api/tag?apikey=" + APIKEY)) | |
# Set a profile | |
PROFILEINT = "" | |
PROFILENAMES = {} | |
# Print Profiles | |
for profile in ALLPROFILESJSON: | |
if profile == "error": | |
print("Could not connect to Radarr!") | |
exit(0) | |
print("Which profile should we add to the movie?") | |
print("ID: {1} Name: {0}".format(profile["name"], profile["id"])) | |
# Add tag to lookup by it's id | |
PROFILENAMES[profile["id"]] = profile["name"] | |
# Ask if we should add it to all movies? | |
ADDPROFILE = input('Which profile to all movies? [1-{0}] : '.format(len(PROFILENAMES))) | |
# Add the profiles to our list of tag numbers | |
PROFILEINT = int(ADDPROFILE) | |
ADDPROFILE = input('Are you sure you want to set all movies to profile \"{0}\"? [y/n] : '.format(PROFILENAMES[PROFILEINT])) | |
# If the answer not starts with any case Y | |
if not ADDPROFILE.lower().startswith("y"): | |
print("Skipping profile...") | |
else: | |
print("Adding profile {0}...".format(PROFILENAMES[PROFILEINT])) | |
# Make list of tags to add | |
TAGS = [] | |
# Make a tag lookup for later | |
TAGNAMES = {} | |
# For each tag | |
for tag in ALLTAGSJSON: | |
# Add tag to lookup by it's id | |
TAGNAMES[tag['id']] = tag['label'] | |
# Ask if we should add it to all movies? | |
ADDTAG = input('Add Tag \"{0}\" to all movies? [y/n] : '.format(tag['label'])) | |
# If the answer starts with any case Y | |
if ADDTAG.lower().startswith("y"): | |
# Add the tag to our list of tag numbers | |
TAGS.append(int(tag['id'])) | |
# Ask if we should contiunue? | |
ADDTAG = input("Add Tag(s) '{0}' to all movies? [y/n] : ".format(", ".join(TAGNAMES[int(p)] for p in TAGS))) | |
# If the answer starts with any case Y | |
if ADDTAG.lower().startswith("y"): | |
# Get All Movies | |
ALLMOVIESJSON = get_data(HOSTNAME + "/api/movie?apikey=" + APIKEY) | |
# for each movie | |
for movie in ALLMOVIESJSON: | |
# get movie ID for updating data with put_data | |
movieID = movie['id'] | |
# Set tagMissing to false and check each tag | |
dataMissing = False | |
# For each tag we want to add | |
for tag in TAGS: | |
# If that tag does not exist currenlty | |
if tag not in movie['tags']: | |
# Set boolean to update tags | |
dataMissing = True | |
else: | |
TAGLIST = ", ".join(TAGNAMES[int(p)] for p in movie['tags']) | |
print("Found existing tags: {}".format(TAGLIST)) | |
if movie['profileId'] != PROFILEINT: | |
dataMissing = True | |
if dryrun: | |
TAGLIST = ", ".join(TAGNAMES[int(p)] for p in movie['tags']) | |
MOVIETITLE = movie['title'].encode('utf-8') | |
print("!!! Dry-Run: Movie {0} has existing tags: {1} ".format(MOVIETITLE, TAGLIST)) | |
if not dataMissing: | |
# Print movies that have the correct tags | |
TAGLIST = ", ".join(TAGNAMES[int(p)] for p in movie['tags']) | |
MOVIETITLE = movie['title'].encode('utf-8') | |
print("Skipping {0} with existing tags: {1} ".format(MOVIETITLE, TAGLIST)) | |
else: | |
# Print name to statisfy user something is happening | |
TAGLIST = ", ".join(TAGNAMES[int(p)] for p in TAGS) | |
MOVIETITLE = movie['title'].encode('utf-8') | |
PNAMES = PROFILENAMES[PROFILEINT] | |
print("Adding '{0}' tags and {2} profile to Movie: {1}"\ | |
.format(TAGLIST, MOVIETITLE, PNAMES)) | |
# Combine movie tags and new tags | |
tag_set = list(set(movie['tags']+TAGS)) | |
# Add unique tags | |
movie['tags'] = tag_set | |
movie['profileId'] = PROFILEINT | |
# Update radarrHost to include movie ID | |
radarrHost = HOSTNAME + "/api/movie/" + str(movieID) + "?apikey=" + APIKEY | |
if dryrun: | |
print("!!! Dry-run, not updating movie: {}!".format(MOVIETITLE)) | |
print("CHANGES: Adding '{0}' tags and '{2}' profile to Movie: {1}".format(TAGLIST, MOVIETITLE, PNAMES)) | |
# print(movie) | |
else: | |
# Put movie back to radarr | |
updateMovie = put_data(radarrHost, movie) | |
# If the update worked, just tell 'em that | |
if updateMovie.status_code == 202: | |
print("Sucessfully updated \"{0}\"".format(movie['title'].encode('utf-8'))) | |
else: | |
# If the update didn't work, let 'em know | |
MOVIETITLE = movie['title'].encode('utf-8') | |
STATUSCODE = updateMovie.status_code | |
print("Failed: \"{0}\" returned response code: {1}".format(MOVIETITLE, STATUSCODE)) | |
if b"Dragnet" in movie['title'].encode(): | |
exit(0) |
@ak2766 Try version 1.4. You can now pass variables to the command line, including --dry-run or -d:
./radarr_tagarr3.py --dry-run -k "myAPIkey21384y01h" -n "https://radarr.com/myhost"
@rustymyers I've tried running this:
./radarr_tagarr3.py --dry-run -k "mykey" -n "https://radarr.mydomain.co.uk"
But I get an error on conn=connection.create_connection... Any ideas?
My radarr is behind a reverse proxy.
@hughesjs Can you load a URL like this in your browser: https://radarr.mydomain.co.uk/api/profile?apikey=mykey
It returns some JSON aye.
Here's the full error:
Traceback (most recent call last):
File "/usr/lib/python3.8/site-packages/urllib3/connection.py", line 159, in _new_conn
conn = connection.create_connection(
File "/usr/lib/python3.8/site-packages/urllib3/util/connection.py", line 61, in create_connection
for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
File "/usr/lib/python3.8/socket.py", line 918, in getaddrinfo
for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -2] Name or service not known
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.8/site-packages/urllib3/connectionpool.py", line 670, in urlopen
httplib_response = self._make_request(
File "/usr/lib/python3.8/site-packages/urllib3/connectionpool.py", line 381, in _make_request
self._validate_conn(conn)
File "/usr/lib/python3.8/site-packages/urllib3/connectionpool.py", line 978, in _validate_conn
conn.connect()
File "/usr/lib/python3.8/site-packages/urllib3/connection.py", line 309, in connect
conn = self._new_conn()
File "/usr/lib/python3.8/site-packages/urllib3/connection.py", line 171, in _new_conn
raise NewConnectionError(
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPSConnection object at 0x7fdc0ca7cbe0>: Failed to establish a new connection: [Errno -2] Name or service not known
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.8/site-packages/requests/adapters.py", line 439, in send
resp = conn.urlopen(
File "/usr/lib/python3.8/site-packages/urllib3/connectionpool.py", line 726, in urlopen
retries = retries.increment(
File "/usr/lib/python3.8/site-packages/urllib3/util/retry.py", line 439, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='hostname', port=443): Max retries exceeded with url: /api/tag?apikey=API (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fdc0ca7cbe0>: Failed to establish a new connection: [Errno -2] Name or service not known'))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "./radarr_tagarr3.py", line 53, in <module>
ALLTAGSJSON = get_data(HOSTNAME + "/api/tag?apikey=" + APIKEY)
File "./radarr_tagarr3.py", line 36, in get_data
response = requests.get(radarrhost)
File "/usr/lib/python3.8/site-packages/requests/api.py", line 76, in get
return request('get', url, params=params, **kwargs)
File "/usr/lib/python3.8/site-packages/requests/api.py", line 61, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/lib/python3.8/site-packages/requests/sessions.py", line 530, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python3.8/site-packages/requests/sessions.py", line 643, in send
r = adapter.send(request, **kwargs)
File "/usr/lib/python3.8/site-packages/requests/adapters.py", line 516, in send
raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='hostname', port=443): Max retries exceeded with url: /api/tag?apikey=API (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fdc0ca7cbe0>: Failed to establish a new connection: [Errno -2] Name or service not known'))
@hughesjs Looks like it's your host name not being able to resolve to an IP address. I can reproduce this is I use a HOSTNAME that doesn't exist. For example: radarr_tagarr3.py -d -k "KEY" -n "http://1234example.com/radarr"
Make sure you can resolve your hostname from the terminal or try using the IP address. Hope that helps!
Rusty
@hughesjs Try version 1.5. I added a check to see if it could resolve the hostname when run:
/radarr_tagarr3.py -d -k "KEY" -n "http://1234example.com/radarr"
!!! Dry Run...not making any changes...
Unable to resolve hostname! 1234example.com
See if you get a similar error for your host. Feel free to email me directly your hostname, too, if you want me to see if I can determine the issue.
Thanks
@ak2766 Try version 1.4. You can now pass variables to the command line, including --dry-run or -d:
./radarr_tagarr3.py --dry-run -k "myAPIkey21384y01h" -n "https://radarr.com/myhost"
I've just downloaded v1.5 - it works beautifully.
Many thanks.
Any chance of adding a dry-run switch?
The reasoning is that if I've already set a tag, I want to make sure that it is not overwritten.