Merge pull request #171 from Arcanemagus/style-cleanup

Massive style cleanup
This commit is contained in:
blacktwin 2019-06-25 14:38:05 -04:00 committed by GitHub
commit f011d53d8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 801 additions and 604 deletions

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Description: Create and share playlists based on Most Popular TV/Movies from Tautulli
and Aired this day in history.
@ -106,14 +109,14 @@ import unicodedata
from collections import Counter
from plexapi.server import PlexServer, CONFIG
### EDIT SETTINGS ###
# ### EDIT SETTINGS ###
PLEX_URL = ''
PLEX_TOKEN = ''
TAUTULLI_URL = ''
TAUTULLI_APIKEY = ''
## CODE BELOW ##
# ## CODE BELOW ##
if not PLEX_URL:
PLEX_URL = CONFIG.data['auth'].get('server_baseurl')
@ -150,6 +153,7 @@ playlist_lst = [x.title for x in plex.playlists()]
today = datetime.datetime.now().date()
weeknum = datetime.date(today.year, today.month, today.day).isocalendar()[1]
def actions():
"""
add - create new playlist for admin or users
@ -269,7 +273,7 @@ def sort_by_dates(video, date_type):
return [[video.ratingKey] + [str(video.originallyAvailableAt)]]
# todo-me return object
except Exception as e:
except Exception:
# print(e)
return
@ -327,8 +331,9 @@ def multi_filter_search(keyword_dict, library, search_eps=None):
return list(set(search_lst))
def get_content(libraries, jbop, filters=None, search=None, limit=None):
"""Get all movies or episodes from LIBRARY_NAME
"""Get all movies or episodes from LIBRARY_NAME.
Parameters
----------
@ -342,6 +347,7 @@ def get_content(libraries, jbop, filters=None, search=None, limit=None):
list
Sorted list of Movie and episodes that
aired on today's date.
"""
child_lst = []
filter_lst = []
@ -525,7 +531,8 @@ def show_playlist(playlist_title, playlist_keys):
title = unicodedata.normalize('NFKD', title).encode('ascii', 'ignore').translate(None, "'")
playlist_list.append(title)
print(u"Contents of Playlist {title}:\n{playlist}".format(title=playlist_title,
print(u"Contents of Playlist {title}:\n{playlist}".format(
title=playlist_title,
playlist=', '.join(playlist_list)))
exit()
@ -552,13 +559,13 @@ def create_playlist(playlist_title, playlist_keys, server, user):
playlist_list.append(episode)
else:
playlist_list.append(plex_obj)
except Exception as e:
except Exception:
try:
obj = plex.fetchItem(key)
print("{} may not have permission to this title: {}".format(user, obj.title))
# print("Error: {}".format(e))
pass
except Exception as e:
except Exception:
print('Rating Key: {}, may have been deleted or moved.'.format(key))
# print("Error: {}".format(e))
@ -595,7 +602,7 @@ def delete_playlist(playlist_dict, title):
print("...Deleted Playlist: {playlist.title} for '{user}'."
.format(playlist=playlist, user=user))
except:
except Exception:
# print("Playlist not found on '{user}' account".format(user=user))
pass
@ -672,8 +679,8 @@ def create_title(jbop, libraries, days, filters, search, limit):
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Create, share, and clean Playlists for users.",
parser = argparse.ArgumentParser(
description="Create, share, and clean Playlists for users.",
formatter_class=argparse.RawTextHelpFormatter)
# todo-me use parser grouping instead of choices for action and jbop?
parser.add_argument('--jbop', choices=selectors().keys(), metavar='',
@ -778,7 +785,8 @@ if __name__ == "__main__":
'all_playlists': all_playlists})
if opts.self or not users:
playlist_dict['data'].append({'server': plex,
playlist_dict['data'].append({
'server': plex,
'user': 'admin',
'user_selected': selected_playlists,
'all_playlists': playlist_lst})

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Author: Bailey Belvis (https://github.com/philosowaffle)
#
@ -13,11 +16,9 @@
#
# - Copy paste the following line to each of the Triggers you enabled (found on the Arguments tab):
# -a {action} -mt {media_type} -mi {machine_id} -rk {rating_key} -pu {poster_url}
#
import os
import sys
import logging
import hashlib
import shutil
import numpy
import argparse
@ -196,7 +197,7 @@ logger.debug("Media Guid: " + media_guid)
logger.debug("Poster Url: " + poster_url)
# Only perform action for event play/pause/resume/stop for TV and Movies
if not event in events:
if event not in events:
logger.debug("Invalid action: " + event)
exit()

View File

@ -1,11 +1,14 @@
'''
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
https://gist.github.com/blacktwin/4ccb79c7d01a95176b8e88bf4890cd2b
'''
"""
from plexapi.server import PlexServer
import random
import re
baseurl = 'http://localhost:32400'
token = 'xxxxx'
plex = PlexServer(baseurl, token)
@ -44,8 +47,11 @@ def sylco(word):
if word[-2:] == "es" or word[-2:] == "ed":
doubleAndtripple_1 = len(re.findall(r'[eaoui][eaoui]', word))
if doubleAndtripple_1 > 1 or len(re.findall(r'[eaoui][^eaoui]', word)) > 1:
if word[-3:] == "ted" or word[-3:] == "tes" or word[-3:] == "ses" or word[-3:] == "ied" or word[
-3:] == "ies":
if word[-3:] == "ted" or \
word[-3:] == "tes" or \
word[-3:] == "ses" or \
word[-3:] == "ied" or \
word[-3:] == "ies":
pass
else:
disc += 1
@ -140,7 +146,6 @@ def sylco(word):
if word in exception_add:
syls += 1
# calculate the output
return numVowels - disc + syls

View File

@ -1,4 +1,7 @@
'''
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
If server admin stream is experiencing buffering and there are concurrent transcode streams from
another user, kill concurrent transcode stream that has the lowest percent complete. Message in
kill stream will list why it was killed ('Server Admin's stream take priority and this user has X
@ -11,7 +14,7 @@ Tautulli > Settings > Notification Agents > Scripts > Bell icon:
Tautulli > Settings > Notification Agents > Scripts > Gear icon:
Buffer Warnings: kill_else_if_buffering.py
'''
"""
import requests
from operator import itemgetter
@ -19,7 +22,7 @@ import unicodedata
from plexapi.server import PlexServer
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
PLEX_TOKEN = 'xxxx'
PLEX_URL = 'http://localhost:32400'
@ -27,8 +30,8 @@ DEFAULT_REASON = 'Server Admin\'s stream takes priority and {user}(you) has {x}
' {user}\'s stream of {video} is {time}% complete. Should be finished in {comp} minutes. ' \
'Try again then.'
ADMIN_USER = ('Admin') # additional usernames can be added ('Admin', 'user2')
##
ADMIN_USER = ('Admin') # Additional usernames can be added ('Admin', 'user2')
# ##
sess = requests.Session()
sess.verify = False
@ -71,7 +74,7 @@ def main():
# Remove users with only 1 stream. Targeting users with multiple concurrent streams
filtered_dict = {key: value for key, value in user_dict.items()
if len(value) is not 1}
if len(value) != 1}
# Find who to kill and who will be finishing first.
if filtered_dict:

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Description: Use conditions to kill a stream
Author: Blacktwin, Arcanemagus, Samwiseg0, JonnyWong16, DirtyCajunRice
@ -372,8 +375,8 @@ class Stream:
if self.session_exists is False:
sys.stdout.write(
"Session '{}' from user '{}' is no longer active "
.format(self.session_id, self.username)
+ "on the server, stopping monitoring.\n")
.format(self.session_id, self.username) +
"on the server, stopping monitoring.\n")
return False
now = datetime.now()
@ -392,8 +395,8 @@ class Stream:
elif self.state == 'playing' or self.state == 'buffering':
sys.stdout.write(
"Session '{}' from user '{}' has been resumed, "
.format(self.session_id, self.username)
+ "stopping monitoring.\n")
.format(self.session_id, self.username) +
"stopping monitoring.\n")
return False
@ -562,8 +565,8 @@ if __name__ == "__main__":
parser.add_argument('--sessionId',
help='The unique identifier for the stream.')
parser.add_argument('--notify', type=int,
help='Notification Agent ID number to Agent to send '
+ 'notification.')
help='Notification Agent ID number to Agent to ' +
'send notification.')
parser.add_argument('--limit', type=int, default=(20 * 60), # 20 minutes
help='The time session is allowed to remain paused.')
parser.add_argument('--interval', type=int, default=30,

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Description: Limiting Plex users by plays, watches, or total time from Tautulli.
Author: Blacktwin, Arcanemagus
@ -48,7 +51,7 @@ import argparse
from datetime import datetime
import sys
import os
from plexapi.server import PlexServer, CONFIG
from plexapi.server import PlexServer
from time import time as ttime
from time import sleep
@ -65,6 +68,7 @@ TAUTULLI_APIKEY = os.getenv('TAUTULLI_APIKEY', TAUTULLI_APIKEY)
TAUTULLI_ENCODING = os.getenv('TAUTULLI_ENCODING', 'UTF-8')
# Using CONFIG file
# from plexapi.server import CONFIG
# PLEX_URL = CONFIG.data['auth'].get('server_baseurl', PLEX_URL)
# PLEX_TOKEN = CONFIG.data['auth'].get('server_token', PLEX_TOKEN)
# TAUTULLI_URL = CONFIG.data['auth'].get('tautulli_baseurl', TAUTULLI_URL)
@ -346,16 +350,16 @@ if __name__ == "__main__":
if not message:
message = LIMIT_MESSAGE.format(delay=opts.delay)
ep_watched = [data['watched_status'] for data in history['data']
if data['grandparent_rating_key'] == opts.grandparent_rating_key
and data['watched_status'] == 1]
if data['grandparent_rating_key'] == opts.grandparent_rating_key and
data['watched_status'] == 1]
if not ep_watched:
ep_watched = 0
else:
ep_watched = sum(ep_watched)
stopped_time = [data['stopped'] for data in history['data']
if data['grandparent_rating_key'] == opts.grandparent_rating_key
and data['watched_status'] == 1]
if data['grandparent_rating_key'] == opts.grandparent_rating_key and
data['watched_status'] == 1]
if not stopped_time:
stopped_time = unix_time
else:
@ -366,9 +370,9 @@ if __name__ == "__main__":
sys.exit(1)
if ep_watched >= total_limit:
print("{}'s limit is {} and has watched {} episodes of this show today."
.format(opts.username, total_limit, ep_watched))
print("{}'s limit is {} and has watched {} episodes of this show today.".format(
opts.username, total_limit, ep_watched))
terminate_session(opts.sessionId, message, opts.notify, opts.username)
else:
print("{}'s limit is {} but has only watched {} episodes of this show today."
.format(opts.username, total_limit, ep_watched))
print("{}'s limit is {} but has only watched {} episodes of this show today.".format(
opts.username, total_limit, ep_watched))

View File

@ -59,4 +59,3 @@ Arguments:
```
--jbop time --username {username} --sessionId {session_id} --duration {duration} --limit hours=2 --killMessage "You have met your limit of 3 days and 10 hours."
```

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Use Tautulli draw a map connecting Server to Clients based on IP addresses.
@ -30,12 +33,12 @@ import json
import os
from collections import OrderedDict
import argparse
import numpy as np
# import numpy as np
import time
import webbrowser
import re
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = '' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
@ -259,7 +262,7 @@ def draw_map(map_type, geo_dict, filename, headless, leg_choice):
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
## Map stuff ##
# ## Map stuff ##
plt.figure(figsize=(16, 9), dpi=100, frameon=False)
lon_r = 0
lon_l = 0

View File

@ -1,4 +1,3 @@
# Maps
Maps are created with either Matplotlib/Basemap or as a geojson file on an anonymous gist.
@ -57,6 +56,3 @@ Choose which map type you'd like by using the `-l` argument:
- [ ] Find server's external IP, geolocation. Allow custom location to override
- [ ] Add arg for tracert visualization from server to client
- [ ] Animate tracert visualization? gif?

View File

@ -1,5 +1,7 @@
"""
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Find what was added TFRAME ago and not watched and notify admin using Tautulli.
TAUTULLI_URL + delete_media_info_cache?section_id={section_id}
@ -12,7 +14,7 @@ import time
TFRAME = 1.577e+7 # ~ 6 months in seconds
TODAY = time.time()
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = '' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8183/' # Your Tautulli URL
LIBRARY_NAMES = ['Movies', 'TV Shows'] # Name of libraries you want to check.
@ -162,10 +164,10 @@ for library in libraries:
# Find movie rating_key.
show_lst += [int(lib.rating_key)]
except Exception as e:
print "Rating_key failed: {e}".format(e=e)
print("Rating_key failed: {e}".format(e=e))
except Exception as e:
print "Library media info failed: {e}".format(e=e)
print("Library media info failed: {e}".format(e=e))
for show in show_lst:
try:
@ -181,7 +183,7 @@ for show in show_lst:
u" not been watched.<d/t> <dd>File location: {x.file}</dd> <br>".format(x=meta, when=added)]
except Exception as e:
print "Metadata failed. Likely end of range: {e}".format(e=e)
print("Metadata failed. Likely end of range: {e}".format(e=e))
if notify_lst:
BODY_TEXT = """\

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Send an email with what was added to Plex in the past week using Tautulli.
Email includes title (TV: Show Name: Episode Name; Movie: Movie Title), time added, image, and summary.
@ -35,8 +38,7 @@ import uuid
import argparse
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = '' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
LIBRARY_NAMES = ['Movies', 'TV Shows'] # Name of libraries you want to check.
@ -60,7 +62,8 @@ poster_w = 100
art_h = 100
art_w = 205
## /EDIT THESE SETTINGS ##
# ## /EDIT THESE SETTINGS ##
class METAINFO(object):
def __init__(self, data=None):
@ -223,14 +226,18 @@ def build_html(rating_key, height, width, pic_type):
u"</dt> <dd> <table> <tr> <th>" \
'<img src="cid:{cid}" alt="{alt}" width="{width}" height="{height}"> </th>' \
u" <th id=t11> {x.summary} </th> </tr> </table> </dd> <br>" \
.format(x=meta, when=added, alt=cgi.escape(meta.rating_key), quote=True, width=width, height=height,**image)
.format(
x=meta, when=added, alt=cgi.escape(meta.rating_key),
quote=True, width=width, height=height, **image)
else:
# Shows
notify = u"<dt>{x.grandparent_title}: {x.title} ({x.rating_key}) was added {when}." \
u"</dt> <dd> <table> <tr> <th>" \
'<img src="cid:{cid}" alt="{alt}" width="{width}" height="{height}"> </th>' \
u" <th id=t11> {x.summary} </th> </tr> </table> </dd> <br>" \
.format(x=meta, when=added, alt=cgi.escape(meta.rating_key), quote=True, width=width, height=height, **image)
.format(
x=meta, when=added, alt=cgi.escape(meta.rating_key),
quote=True, width=width, height=height, **image)
image_text = MIMEText(u'[image: {title}]'.format(**image), 'plain', 'utf-8')
@ -258,8 +265,10 @@ def send_email(msg_text_lst, notify_lst, image_lst, to, days):
</p>
</body>
</html>
""".format(notify_lst="\n".join(notify_lst).encode("utf-8"), LIBRARY_NAMES=" & ".join(LIBRARY_NAMES)
, quote=True, ), 'html', 'utf-8')
""".format(
notify_lst="\n".join(notify_lst).encode("utf-8"),
LIBRARY_NAMES=" & ".join(LIBRARY_NAMES),
quote=True), 'html', 'utf-8')
message = MIMEMultipart('related')
message['Subject'] = email_subject.format(days)
@ -291,7 +300,6 @@ def send_email(msg_text_lst, notify_lst, image_lst, to, days):
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Send an email with what was added to Plex in the past week using Tautulli.")
parser.add_argument('-t', '--type', help='Metadata picture type from Plex.',
required=True, choices=['art', 'poster'])
@ -303,7 +311,6 @@ if __name__ == '__main__':
parser.add_argument('-i', '--ignore', help='Which users from Plex to ignore.',
nargs='+', default='None', type=str)
opts = parser.parse_args()
TODAY = int(time.time())
@ -328,8 +335,10 @@ if __name__ == '__main__':
# Gather all users email addresses
if opts.users == ['all']:
[to.append(x['email']) for x in get_users() if x['email'] is not None and x['email'] not in to
and x['username'] not in opts.ignore]
[to.append(x['email']) for x in get_users()
if x['email'] is not None and
x['email'] not in to and
x['username'] not in opts.ignore]
elif opts.users != ['all'] and opts.users != 'self':
for get_users in get_users():
for arg_users in opts.users:

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Delay Notification Agent message for concurrent streams
@ -19,7 +22,7 @@ import sys
import argparse
from time import sleep
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = '' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
CONCURRENT_TOTAL = 2
@ -44,7 +47,7 @@ BODY_TEXT = """\
def get_activity():
# Get the current activity on the PMS.
"""Get the current activity on the PMS."""
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_activity'}
@ -60,7 +63,7 @@ def get_activity():
def send_notification(subject_text, body_text):
# Format notification text
"""Format notification text."""
try:
subject = subject_text.format(p=p, total=cc_total)
body = body_text.format(p=p, total=cc_total, time=TIMEOUT / 60)

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Notify users of recently added episode to show that they have watched at least LIMIT times via email.
Also notify users of new movies.
@ -22,7 +25,7 @@ import smtplib
import sys
import argparse
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'XXXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
@ -74,6 +77,7 @@ TV_BODY = """\
user_dict = {}
class Users(object):
def __init__(self, data=None):
d = data or {}
@ -108,6 +112,7 @@ def get_user(user_id):
except Exception as e:
sys.stderr.write("Tautulli API 'get_user' request failed: {0}.".format(e))
def get_users():
# Get the user list from Tautulli.
payload = {'apikey': TAUTULLI_APIKEY,
@ -134,8 +139,9 @@ def get_history(showkey):
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [UserHIS(data=d) for d in res_data if d['watched_status'] == 1
and d['media_type'].lower() in ('episode', 'show')]
return [UserHIS(data=d) for d in res_data
if d['watched_status'] == 1 and
d['media_type'].lower() in ('episode', 'show')]
except Exception as e:
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
@ -188,7 +194,7 @@ def send_email(to, email_subject, body_html):
mailserver.login(email_username, email_password)
mailserver.sendmail(sender, to, message.as_string())
mailserver.quit()
print 'Email sent'
print('Email sent')
if __name__ == '__main__':

View File

@ -1,4 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Pulling together User IP information and Email.
@ -19,7 +21,7 @@ import argparse
import requests
import sys
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = '' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
NOTIFIER_ID = 12 # The notification notifier ID
@ -69,7 +71,7 @@ class UserEmail(object):
def get_user_ip_addresses(user_id='', ip_address=''):
# Get the user IP list from Tautulli
"""Get the user IP list from Tautulli."""
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_user_ips',
'user_id': user_id,
@ -99,7 +101,7 @@ def get_user_ip_addresses(user_id='', ip_address=''):
def get_geoip_info(ip_address=''):
# Get the geo IP lookup from Tautulli
"""Get the geo IP lookup from Tautulli."""
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_geoip_lookup',
'ip_address': ip_address}
@ -123,7 +125,7 @@ def get_geoip_info(ip_address=''):
def get_user_email(user_id=''):
# Get the user email from Tautulli
"""Get the user email from Tautulli."""
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_user',
'user_id': user_id}
@ -147,7 +149,7 @@ def get_user_email(user_id=''):
def send_notification(arguments=None, geodata=None, useremail=None):
# Format notification text
"""Format notification text."""
try:
subject = SUBJECT_TEXT.format(p=arguments, g=geodata, u=useremail)
body = BODY_TEXT.format(p=arguments, g=geodata, u=useremail)

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Tautulli > Settings > Notification Agents > Scripts > Bell icon:
[X] Notify on Recently Added
@ -13,7 +16,6 @@ You can add more arguments if you want more details in the email body
from email.mime.text import MIMEText
import email.utils
import smtplib
import sys
import argparse
@ -54,7 +56,7 @@ users = [{'email': 'user1@gmail.com',
# Kill script now if show_name is not in lists
too = list('Match' for u in users if p.show_name in u['shows'])
if not too:
print 'Kill script now show_name is not in lists'
print('Kill script now show_name is not in lists')
exit()
# Join email addresses
@ -84,14 +86,13 @@ show_html = """\
</html>
""".format(p=p)
### Do not edit below ###
# ### Do not edit below ###
# Check to see whether it is a tv show
if p.show_type.lower() == 'show' or p.show_type.lower() == 'episode':
message = MIMEText(show_html, 'html')
message['Subject'] = email_subject
message['From'] = email.utils.formataddr((name, sender))
mailserver = smtplib.SMTP(email_server, email_port)
mailserver.starttls()
mailserver.ehlo()

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Description: Notify only if recently aired/released
Author: Blacktwin
@ -64,6 +67,7 @@ aired_date = datetime.strptime(air_date, date_format)
today = date.today()
delta = today - aired_date.date()
def notify_recently_added(rating_key, notifier_id):
# Get the metadata for a media item.
payload = {'apikey': TAUTULLI_APIKEY,
@ -80,6 +84,7 @@ def notify_recently_added(rating_key, notifier_id):
sys.stderr.write("Tautulli API 'notify_recently_added' request failed: {0}.".format(e))
pass
if delta.days < RECENT_DAYS:
notify_recently_added(rating_key, NOTIFIER_ID)
else:

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Notify users of recently added episode to show that they have watched at least LIMIT times via email.
Block users with IGNORE_LST.
@ -21,7 +24,7 @@ import smtplib
import sys
import argparse
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'XXXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
@ -38,6 +41,7 @@ email_password = '' # Your email password
user_dict = {}
class Users(object):
def __init__(self, data=None):
d = data or {}
@ -74,7 +78,10 @@ def get_user(user_id):
def get_history(showkey):
# Get the user history from Tautulli. Length matters!
"""Get the user history from Tautulli.
Length matters!
"""
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'grandparent_rating_key': showkey,
@ -84,8 +91,9 @@ def get_history(showkey):
r = requests.get(TAUTULLI_URL.rstrip('/') + '/api/v2', params=payload)
response = r.json()
res_data = response['response']['data']['data']
return [UserHIS(data=d) for d in res_data if d['watched_status'] == 1
and d['media_type'].lower() in ('episode', 'show')]
return [UserHIS(data=d) for d in res_data
if d['watched_status'] == 1 and
d['media_type'].lower() in ('episode', 'show')]
except Exception as e:
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
@ -199,4 +207,4 @@ if __name__ == '__main__':
mailserver.login(email_username, email_password)
mailserver.sendmail(sender, to, message.as_string())
mailserver.quit()
print 'Email sent'
print('Email sent')

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Pulling together User IP information and Email.
Enable the API under Settings > Access Control and remember your API key.
@ -13,9 +16,9 @@ from email.mime.text import MIMEText
import email.utils
import smtplib
## -sn {show_name} -ena {episode_name} -ssn {season_num00} -enu {episode_num00} -srv {server_name} -med {media_type} -pos {poster_url} -tt {title} -sum {summary} -lbn {library_name} -ip {ip_address} -us {user} -uid {user_id} -pf {platform} -pl {player} -da {datestamp} -ti {timestamp}
# ## -sn {show_name} -ena {episode_name} -ssn {season_num00} -enu {episode_num00} -srv {server_name} -med {media_type} -pos {poster_url} -tt {title} -sum {summary} -lbn {library_name} -ip {ip_address} -us {user} -uid {user_id} -pf {platform} -pl {player} -da {datestamp} -ti {timestamp}
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'xxxxxxxxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
@ -54,7 +57,10 @@ email_subject = "New IP has been detected using Plex."
IGNORE_LST = ['123456', '123456'] # User_id
##Geo Space##
# ##Geo Space##
class GeoData(object):
def __init__(self, data=None):
data = data or {}
@ -62,7 +68,10 @@ class GeoData(object):
self.city = data.get('city', 'N/A')
self.postal_code = data.get('postal_code', 'N/A')
##USER Space##
# ##USER Space##
class UserEmail(object):
def __init__(self, data=None):
data = data or {}
@ -70,7 +79,10 @@ class UserEmail(object):
self.user_id = data.get('user_id', 'N/A')
self.user_thumb = data.get('user_thumb', 'N/A')
##API Space##
# ##API Space##
def get_user_ip_addresses(user_id='', ip_address=''):
# Get the user IP list from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
@ -99,6 +111,7 @@ def get_user_ip_addresses(user_id='', ip_address=''):
except Exception as e:
sys.stderr.write("Tautulli API 'get_user_ip_addresses' request failed: {0}.".format(e))
def get_geoip_info(ip_address=''):
# Get the geo IP lookup from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
@ -146,6 +159,7 @@ def get_user_email(user_id=''):
sys.stderr.write("Tautulli API 'get_user' request failed: {0}.".format(e))
return UserEmail()
def send_notification(arguments=None, geodata=None, useremail=None):
# Format notification text
try:
@ -163,12 +177,12 @@ def send_notification(arguments=None, geodata=None, useremail=None):
mailserver.login(email_username, email_password)
mailserver.sendmail(sender, u.email, message.as_string())
mailserver.quit()
print 'Email sent'
print('Email sent')
except Exception as e:
sys.stderr.write("Email Failure: {0}.".format(e))
def clr_sql(ip):
def clr_sql(ip):
try:
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'sql',
@ -179,6 +193,7 @@ def clr_sql(ip):
except Exception as e:
sys.stderr.write("Tautulli API 'get_sql' request failed: {0}.".format(e))
if __name__ == '__main__':
# Parse arguments from Tautulli
parser = argparse.ArgumentParser()

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
1. Install the requests module for python.
pip install requests
@ -14,12 +17,12 @@ Tautulli > Settings > Notifications > Script > Script Arguments:
https://gist.github.com/blacktwin/261c416dbed08291e6d12f6987d9bafa
"""
from twitter import *
from twitter import Twitter, OAuth
import argparse
import requests
import os
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TOKEN = ''
TOKEN_SECRET = ''
CONSUMER_KEY = ''
@ -80,12 +83,13 @@ if __name__ == '__main__':
p = parser.parse_args()
if p.media_type == 'movie':
BODY_TEXT = MOVIE_TEXT.format(media_type=p.media_type, title=p.title, duration=p.duration)
elif p.media_type == 'episode':
BODY_TEXT = TV_TEXT.format(media_type=p.media_type, show_name=p.show_name, title=p.title,
season_num00=p.season_num, episode_num00=p.episode_num, duration=p.duration)
BODY_TEXT = TV_TEXT.format(
media_type=p.media_type, show_name=p.show_name, title=p.title,
season_num00=p.season_num, episode_num00=p.episode_num,
duration=p.duration)
else:
exit()
@ -101,7 +105,6 @@ if __name__ == '__main__':
for chunk in request:
image.write(chunk)
t_upload = Twitter(domain='upload.twitter.com',
auth=OAuth(TOKEN, TOKEN_SECRET, CONSUMER_KEY, CONSUMER_SECRET))

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Find when media was added between STARTFRAME and ENDFRAME to Plex through Tautulli.
@ -9,7 +12,6 @@ import requests
import sys
import time
STARTFRAME = 1480550400 # 2016, Dec 1 in seconds
ENDFRAME = 1488326400 # 2017, March 1 in seconds
@ -20,8 +22,7 @@ LASTMONTH = int(TODAY - 2629743) # 2629743 = 1 month in seconds
# STARTFRAME = LASTMONTH
# ENDFRAME = TODAY
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'XXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
LIBRARY_NAMES = ['TV Shows', 'Movies'] # Names of your libraries you want to check.
@ -70,6 +71,7 @@ def get_new_rating_keys(rating_key, media_type):
except Exception as e:
sys.stderr.write("Tautulli API 'get_new_rating_keys' request failed: {0}.".format(e))
def get_library_media_info(section_id):
# Get the data on the Tautulli media info tables. Length matters!
payload = {'apikey': TAUTULLI_APIKEY,
@ -88,6 +90,7 @@ def get_library_media_info(section_id):
except Exception as e:
sys.stderr.write("Tautulli API 'get_library_media_info' request failed: {0}.".format(e))
def get_metadata(rating_key):
# Get the metadata for a media item.
payload = {'apikey': TAUTULLI_APIKEY,
@ -106,6 +109,7 @@ def get_metadata(rating_key):
except Exception as e:
sys.stderr.write("Tautulli API 'get_metadata' request failed: {0}.".format(e))
def update_library_media_info(section_id):
# Get the data on the Tautulli media info tables.
payload = {'apikey': TAUTULLI_APIKEY,
@ -122,6 +126,7 @@ def update_library_media_info(section_id):
except Exception as e:
sys.stderr.write("Tautulli API 'update_library_media_info' request failed: {0}.".format(e))
def get_libraries_table():
# Get the data on the Tautulli libraries table.
payload = {'apikey': TAUTULLI_APIKEY,
@ -181,13 +186,14 @@ for i in sorted(show_lst, reverse=True):
# Shows
print(u"{x.grandparent_title}: {x.title} ({x.rating_key}) was added {when}.".format(x=x, when=added))
except Exception as e:
except Exception:
# Remove commented print below to investigate problems.
# print("Metadata failed. Likely end of range: {e}").format(e=e)
# Remove break if not finding files in range
break
print("There were {amount} files added between {start}:{end}".format(amount=len(count_lst),
print("There were {amount} files added between {start}:{end}".format(
amount=len(count_lst),
start=time.ctime(float(STARTFRAME)),
end=time.ctime(float(ENDFRAME))))
print("Total movies: {}".format(count_lst.count('movie')))

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 1. Install the requests module for python.
# pip install requests
# 2. Add script arguments in Tautulli.
@ -10,7 +13,7 @@ import sys
user = sys.argv[1]
title = sys.argv[2]
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'XXXXXXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
NOTIFIER_ID = 10 # The notification notifier ID for Tautulli
@ -35,7 +38,7 @@ class UserHIS(object):
def get_history():
# Get the user IP list from Tautulli
"""Get the history from Tautulli."""
payload = {'apikey': TAUTULLI_APIKEY,
'cmd': 'get_history',
'user': user,

View File

@ -1,19 +1,23 @@
'''
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Run script by itself. Will look for WARN code followed by /library/metadata/ str in Plex logs.
This is find files that are corrupt or having playback issues.
I corrupted a file to test.
'''
"""
import requests
import sys
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'XXXXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
lib_met = []
err_title = []
class PlexLOG(object):
def __init__(self, data=None):
self.error_msg = []
@ -43,6 +47,7 @@ def get_plex_log():
except Exception as e:
sys.stderr.write("Tautulli API 'get_plex_log' request failed: {0}.".format(e))
def get_history(key):
# Get the user IP list from Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
@ -59,6 +64,7 @@ def get_history(key):
except Exception as e:
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
if __name__ == '__main__':
p_log = get_plex_log()
for co, msg in p_log.error_msg:

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import psutil
import requests
@ -16,7 +19,8 @@ disk_check = [True for i in disk if drive in i.mountpoint]
if not disk_check:
# Send the notification through Tautulli
payload = {'apikey': TAUTULLI_APIKEY,
payload = {
'apikey': TAUTULLI_APIKEY,
'cmd': 'notify',
'subject': NOTIFY_SUBJECT,
'body': NOTIFY_BODY}

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Use Tautulli to print plays by library from 0, 1, 7, or 30 days ago. 0 = total
@ -26,14 +29,15 @@ import requests
import sys
import argparse
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'xxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
OUTPUT = 'Library: {section}\nDays: {days}\nPlays: {plays}'
## CODE BELOW ##
# ## CODE BELOW ##
def get_library_names():
# Get a list of new rating keys for the PMS of all of the item's parent/children.

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Use Tautulli to pull plays by library
@ -18,18 +21,17 @@ Usage:
import requests
import sys
import argparse
import json
# import json
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'xxxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
OUTPUT = '{section} - Plays: {plays}'
## CODE BELOW ##
# ## CODE BELOW ##
def get_libraries_table(sections=None):
# Get a list of new rating keys for the PMS of all of the item's parent/children.

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
usage: plex_netflix_check.py [-h] [-l [...]] [-s ] [-t ]
@ -29,15 +32,14 @@ import argparse
from xmljson import badgerfish as bf
from lxml.html import fromstring
from time import sleep
import json
from plexapi.server import PlexServer
# pip install plexapi
## Edit ##
# ## Edit ##
PLEX_URL = 'http://localhost:32400'
PLEX_TOKEN = 'xxxx'
## /Edit ##
# ## /Edit ##
sess = requests.Session()
sess.verify = False
@ -108,7 +110,7 @@ def instantwatch_search(name, media_type, site, search_limit):
pass
for data in results['span']:
if data['@class'] == 'title' and search_limit is not 0:
if data['@class'] == 'title' and search_limit != 0:
if str(data['a']['$']).lower().startswith(name.lower()):
if amazon_id:
if data['a']['@data-title-id'] == amazon_id:
@ -119,10 +121,10 @@ def instantwatch_search(name, media_type, site, search_limit):
print('Page: {}{}'.format(NETFLIX_URL, data['a']['@data-title-id']))
results_count += 1
search_limit -= 1
if search_limit is 0:
if search_limit == 0:
limit = True
elif data['@class'] == 'title' and search_limit is 0 and limit is False:
elif data['@class'] == 'title' and search_limit == 0 and limit is False:
if data['a']['$'].lower().startswith(name.lower()):
if amazon_id:
if data['a']['@data-title-id'] == amazon_id:
@ -223,5 +225,6 @@ def main():
else:
plex_library_search(opts.library[0], opts.site, opts.episodes, opts.search_limit)
if __name__ == '__main__':
main()

View File

@ -1,4 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Description: Comparing content between two or more Plex servers.
Creates .json file in script directory of server compared.
@ -106,7 +108,7 @@ def get_meta(meta):
meta_dict = {'title': meta.title,
'rating': meta.rating if
meta.rating != None else 0.0,
meta.rating is not None else 0.0,
'genres': [x.tag for x in meta.genres],
'server': [meta._server.friendlyName],
'thumb': [thumb_url]
@ -193,7 +195,8 @@ def org_diff(lst_dicts, media_type, main_server):
# Sort item list by Plex rating
# Duplicates will use originals rating
meta_lst = sorted(meta_lst, key=lambda d: d['rating'], reverse=True)
diff_dict[mtype] = {'combined': {'count': len(meta_lst),
diff_dict[mtype] = {'combined': {
'count': len(meta_lst),
'list': meta_lst}}
print('...finding {}s missing from {}'.format(
@ -205,12 +208,14 @@ def org_diff(lst_dicts, media_type, main_server):
# Main Server name is absent in items server list
elif main_server in item['server'] and len(item['server']) == 1:
unique.append(item)
diff_dict[mtype].update({'missing': {'count': len(missing),
diff_dict[mtype].update({'missing': {
'count': len(missing),
'list': missing}})
print('...finding {}s unique to {}'.format(
mtype, main_server))
diff_dict[mtype].update({'unique': {'count': len(unique),
diff_dict[mtype].update({'unique': {
'count': len(unique),
'list': unique}})
return diff_dict
@ -272,7 +277,8 @@ if __name__ == "__main__":
main_dict = org_diff(combined_lst, opts.media_type, main_server.friendlyName)
filename = 'diff_{}_{}_servers.json'.format(opts.server[0],'_'.join(servers))
filename = 'diff_{}_{}_servers.json'.format(
opts.server[0], '_'.join(servers))
with open(filename, 'w') as fp:
json.dump(main_dict, fp, indent=4, sort_keys=True)

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Use Tautulli to count how many plays per user occurred this week.
Notify via Tautulli Notification
@ -10,7 +13,7 @@ import time
TODAY = int(time.time())
LASTWEEK = int(TODAY - 7 * 24 * 60 * 60)
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'XXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
SUBJECT_TEXT = "Tautulli Weekly Plays Per User"
@ -29,6 +32,7 @@ class UserHIS(object):
self.full_title = d['full_title']
self.date = d['date']
def get_history():
# Get the Tautulli history. Count matters!!!
payload = {'apikey': TAUTULLI_APIKEY,
@ -46,6 +50,7 @@ def get_history():
except Exception as e:
sys.stderr.write("Tautulli API 'get_history' request failed: {0}.".format(e))
def send_notification(BODY_TEXT):
# Format notification text
try:
@ -73,12 +78,14 @@ def send_notification(BODY_TEXT):
sys.stderr.write("Tautulli API 'notify' request failed: {0}.".format(e))
return None
def add_to_dictlist(d, key, val):
if key not in d:
d[key] = [val]
else:
d[key].append(val)
user_dict = {}
notify_lst = []
@ -106,7 +113,9 @@ BODY_TEXT = """\
</p>
</body>
</html>
""".format(notify_lst="\n".join(notify_lst).encode("utf-8"),end=time.ctime(float(TODAY)),
""".format(
notify_lst="\n".join(notify_lst).encode("utf-8"),
end=time.ctime(float(TODAY)),
start=time.ctime(float(LASTWEEK)))
send_notification(BODY_TEXT)

View File

@ -1,4 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import argparse
from plexapi.myplex import MyPlexAccount
@ -36,6 +38,7 @@ VERIFY_SSL = False
timestr = time.strftime("%Y%m%d-%H%M%S")
class Connection:
def __init__(self, url=None, apikey=None, verify_ssl=False):
self.url = url
@ -66,7 +69,7 @@ class Library(object):
try:
self.parent_count = d['parent_count']
self.child_count = d['child_count']
except Exception as e:
except Exception:
# print(e)
pass
@ -254,7 +257,6 @@ if __name__ == '__main__':
opts = parser.parse_args()
sections_totals_dict = {}
sections_dict = {}
user_dict = {}

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Pull library and user statistics of last week.
@ -13,7 +16,7 @@ import requests
import sys
import time
import datetime
import json
# import json
from operator import itemgetter
import argparse
@ -72,6 +75,7 @@ BODY_TEXT = """\
# /EDIT THESE SETTINGS #
def get_history(section_id, check_date):
# Get the Tautulli history.
payload = {'apikey': TAUTULLI_APIKEY,
@ -290,5 +294,6 @@ def main():
print('Sending message.')
send_notification(BODY_TEXT)
if __name__ == '__main__':
main()

11
setup.cfg Normal file
View File

@ -0,0 +1,11 @@
; Contains configuration for various linters
; E501: Disable line length limits (for now)
; W504: Require newlines after binary operators, use W503 for requiring the
; operators on the next line
[flake8]
ignore = E501,W504
[pylama]
ignore = E501,W504

View File

@ -1,5 +1,7 @@
#!/usr/bin/env python
'''
# -*- coding: utf-8 -*-
"""
Use Tautulli to pull last IP address from user and add to List of IP addresses and networks that are allowed without auth in Plex.
optional arguments:
@ -13,14 +15,14 @@ optional arguments:
(default: None)
List of IP addresses is cleared before adding new IPs
'''
"""
import requests
import argparse
import sys
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
PLEX_TOKEN = 'xxxx'
PLEX_URL = 'http://localhost:32400'
TAUTULLI_APIKEY = 'xxxx' # Your Tautulli API key

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
From a list of TV shows, check if users in a list has watched shows episodes.
If all users in list have watched an episode of listed show, then delete episode.
@ -9,8 +12,7 @@ import requests
import sys
import os
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'xxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
SHOW_LST = [123456, 123456, 123456, 123456] # Show rating keys.
@ -109,7 +111,8 @@ for user in USER_LST:
for meta_dict in meta_lst:
if set(USER_LST) == set(meta_dict['watched_by']):
print("{} {} has been watched by {}".format(meta_dict['grandparent_title'].encode('UTF-8'),
print("{} {} has been watched by {}".format(
meta_dict['grandparent_title'].encode('UTF-8'),
meta_dict['title'].encode('UTF-8'),
" & ".join(USER_LST)))
print("Removing {}".format(meta_dict['file']))

View File

@ -1,6 +1,8 @@
#!/usr/bin/env python
"""
Description: Enable or disable all users remote access to Tautulli
# -*- coding: utf-8 -*-
"""Enable or disable all users remote access to Tautulli.
Author: DirtyCajunRice
Requires: requests, python3.6+
"""

View File

@ -1,4 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Find location of Plex metadata.
@ -18,7 +20,7 @@ import hashlib
import argparse
import requests
## Edit ##
# ## Edit ##
PLEX_URL = ''
PLEX_TOKEN = ''
PLEX_URL = CONFIG.data['auth'].get('server_baseurl', PLEX_URL)
@ -28,7 +30,7 @@ PLEX_TOKEN = CONFIG.data['auth'].get('server_token', PLEX_TOKEN)
PLEX_LOCAL_TV_PATH = os.path.join(os.getenv('LOCALAPPDATA'), 'Plex Media Server\Metadata\TV Shows')
PLEX_LOCAL_MOVIE_PATH = os.path.join(os.getenv('LOCALAPPDATA'), 'Plex Media Server\Metadata\Movies')
PLEX_LOCAL_ALBUM_PATH = os.path.join(os.getenv('LOCALAPPDATA'), 'Plex Media Server\Metadata\Albums')
## /Edit ##
# ## /Edit ##
sess = requests.Session()
# Ignore verifying the SSL certificate
@ -44,6 +46,7 @@ if sess.verify is False:
plex = PlexServer(PLEX_URL, PLEX_TOKEN, session=sess)
def hash_to_path(hash_str, path, title, media_type, artist=None):
full_hash = hashlib.sha1(hash_str).hexdigest()
hash_path = '{}\{}{}'.format(full_hash[0], full_hash[1::1], '.bundle')
@ -54,12 +57,11 @@ def hash_to_path(hash_str, path, title, media_type, artist=None):
output = "{} titled: {}\nPath: {}".format(media_type.title(), title, full_path)
print(output)
def get_plex_hash(search, mediatype=None):
for searched in plex.search(search, mediatype=mediatype):
# Remove special characters from name
clean_title = re.sub('\W+',' ', searched.title)
if searched.type == 'show':
# Need to find guid.
if searched.type == 'show':
# Get tvdb_if from first episode
db_id = searched.episodes()[0].guid
# Find str to pop
@ -89,6 +91,7 @@ def get_plex_hash(search, mediatype=None):
else:
pass
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Helping navigate Plex's locally stored data.")
parser.add_argument('-s', '--search', required=True, help='Search Plex for title.')

View File

@ -1,7 +1,8 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Find what was added TFRAME ago and not watched using Tautulli.
"""
import requests
@ -13,7 +14,7 @@ TFRAME = 1.577e+7 # ~ 6 months in seconds
TODAY = time.time()
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'XXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
LIBRARY_NAMES = ['My TV Shows', 'My Movies'] # Name of libraries you want to check.
@ -81,7 +82,7 @@ def get_metadata(rating_key):
res_data = response['response']['data']
return METAINFO(data=res_data)
except Exception as e:
except Exception:
# sys.stderr.write("Tautulli API 'get_metadata' request failed: {0}.".format(e))
pass
@ -103,6 +104,7 @@ def get_library_media_info(section_id):
except Exception as e:
sys.stderr.write("Tautulli API 'get_library_media_info' request failed: {0}.".format(e))
def get_libraries_table():
# Get the data on the Tautulli libraries table.
payload = {'apikey': TAUTULLI_APIKEY,
@ -118,6 +120,7 @@ def get_libraries_table():
except Exception as e:
sys.stderr.write("Tautulli API 'get_libraries_table' request failed: {0}.".format(e))
def delete_files(tmp_lst):
del_file = raw_input('Delete all unwatched files? (yes/no)').lower()
if del_file.startswith('y'):
@ -127,6 +130,7 @@ def delete_files(tmp_lst):
else:
print('Ok. doing nothing.')
show_lst = []
path_lst = []

View File

@ -1,6 +1,8 @@
#!/usr/bin/env python3
"""
Description: Get a list of "Serial Transcoders"
# -*- coding: utf-8 -*-
"""Get a list of "Serial Transcoders".
Author: DirtyCajunRice
Requires: requests, plexapi, python3.6+
"""

View File

@ -1,8 +1,9 @@
# -*- encoding: UTF-8 -*-
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
"""
https://gist.github.com/blacktwin/f435aa0ccd498b0840d2407d599bf31d
'''
"""
import os
import httplib2
@ -12,16 +13,12 @@ from oauth2client.file import Storage
from googleapiclient.discovery import build
from oauth2client.client import OAuth2WebServerFlow
import time, shutil, sys
# Copy your credentials from the console
# https://console.developers.google.com
CLIENT_ID = ''
CLIENT_SECRET = ''
OUT_PATH = '' # Output Path
OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive'
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
CREDS_FILE = os.path.join(os.path.dirname(__file__), 'credentials.json')
@ -48,6 +45,7 @@ http = credentials.authorize(http)
drive_service = build('drive', 'v2', http=http)
def list_files(service):
page_token = None
while True:
@ -90,11 +88,11 @@ for item in list_files(drive_service):
if 'mimeType' in item and 'image/jpeg' in item['mimeType'] or 'video/mp4' in item['mimeType']:
download_url = item['downloadUrl']
else:
print 'ERROR getting %s' % item.get('title')
print item
print dir(item)
print('ERROR getting %s' % item.get('title'))
print(item)
print(dir(item))
if download_url:
print "downloading %s" % item.get('title')
print("downloading %s" % item.get('title'))
resp, content = drive_service._http.request(download_url)
if resp.status == 200:
if os.path.isfile(outfile):

View File

@ -1,6 +1,8 @@
#!/usr/bin/env python
"""
Description: Removes Shows from On Deck
# -*- coding: utf-8 -*-
"""Removes Shows from On Deck.
Author: Blacktwin
Requires: requests, plexapi
@ -142,7 +144,8 @@ def get_on_deck(server, off_deck=None):
watched_statuses['grandparent'] = grandparent
watched_statuses['episodes'] = []
for episode in grandparent.episodes():
watched_statuses['episodes'].append({'object': episode,
watched_statuses['episodes'].append({
'object': episode,
'viewCount': episode.viewCount})
else:
if item.type == 'episode':

View File

@ -1,5 +1,7 @@
#!/usr/bin/env python
'''
# -*- coding: utf-8 -*-
"""
Invite new users to share Plex libraries.
optional arguments:
@ -33,7 +35,7 @@ Usage:
plex_api_invite.py --libraries Movies --user USER --movieRatings G, PG-13
- Share Movie library with USER but restrict them to only G and PG-13 titles.
'''
"""
from plexapi.server import PlexServer, CONFIG
import argparse
@ -71,11 +73,11 @@ def invite(user, sections, allowSync, camera, channels, filterMovies, filterTele
allowCameraUpload=camera, allowChannels=channels, filterMovies=filterMovies,
filterTelevision=filterTelevision, filterMusic=filterMusic)
print('Invited {user} to share libraries: \n{sections}'.format(sections=sections, user=user))
if allowSync == True:
if allowSync is True:
print('Sync: Enabled')
if camera == True:
if camera is True:
print('Camera Upload: Enabled')
if channels == True:
if channels is True:
print('Plugins: Enabled')
if filterMovies:
print('Movie Filters: {}'.format(filterMovies))

View File

@ -1,5 +1,7 @@
#!/usr/bin/env python
'''
# -*- coding: utf-8 -*-
"""
Set as cron or task for times of allowing and not allowing user access to server.
Unsharing will kill any current stream from user before unsharing.
@ -33,7 +35,7 @@ Usage:
- Unshared all libraries with USER.
- USER is still exists as a Friend or Home User
'''
"""
import argparse

View File

@ -1,6 +1,11 @@
#!/usr/bin/env python
"""
Description: Pull Movie and TV Show poster images from Plex. Save to Movie and TV Show directories in scripts working directory.
# -*- coding: utf-8 -*-
"""Pull Movie and TV Show poster images from Plex.
Saves the poster images to Movie and TV Show directories in scripts working
directory.
Author: Blacktwin
Requires: plexapi
@ -15,7 +20,7 @@ import re
import os
import urllib
library_name = ['Movies','TV Shows'] # You library names
library_name = ['Movies', 'TV Shows'] # Your library names
PLEX_URL = ''
PLEX_TOKEN = ''

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python
'''
Share or unshare libraries.
# -*- coding: utf-8 -*-
"""Share or unshare libraries.
optional arguments:
-h, --help Show this help message and exit
@ -96,7 +97,7 @@ Usage:
plex_api_share.py --share -u USER --allLibraries --libraries Movies
- Shared [all libraries but Movies] with USER.
'''
"""
from plexapi.server import PlexServer, CONFIG
import time
@ -137,13 +138,14 @@ movies_keys = [x.key for x in plex.library.sections() if x.type == 'movie']
show_keys = [x.key for x in plex.library.sections() if x.type == 'show']
json_check = sorted([f for f in os.listdir('.') if os.path.isfile(f) and
f.endswith(".json") and f.startswith(plex.friendlyName)],
f.endswith(".json") and
f.startswith(plex.friendlyName)],
key=os.path.getmtime)
my_server_names = []
# Find all owners server names. For owners with multiple servers.
for res in plex.myPlexAccount().resources():
if res.provides == 'server' and res.owned == True:
if res.provides == 'server' and res.owned is True:
my_server_names.append(res.name)
@ -166,7 +168,7 @@ def filter_clean(filter_type):
labels = v.replace('%20', ' ')
labels = labels.split('%2C')
clean[k] = labels
except Exception as e:
except Exception:
pass
return clean
@ -193,7 +195,7 @@ def find_shares(user):
if server.name == plex.friendlyName:
sections = []
for section in server.sections():
if section.shared == True:
if section.shared is True:
sections.append(section.title)
user_backup['sections'] = sections
@ -219,17 +221,17 @@ def share(user, sections, allowSync, camera, channels, filterMovies, filterTelev
filterTelevision=filterTelevision, filterMusic=filterMusic)
if sections:
print('{user}\'s updated shared libraries: \n{sections}'.format(sections=sections, user=user))
if allowSync == True:
if allowSync is True:
print('Sync: Enabled')
if allowSync == False:
if allowSync is False:
print('Sync: Disabled')
if camera == True:
if camera is True:
print('Camera Upload: Enabled')
if camera == False:
if camera is False:
print('Camera Upload: Disabled')
if channels == True:
if channels is True:
print('Plugins: Enabled')
if channels == False:
if channels is False:
print('Plugins: Disabled')
if filterMovies:
print('Movie Filters: {}'.format(filterMovies))
@ -241,7 +243,7 @@ def share(user, sections, allowSync, camera, channels, filterMovies, filterTelev
print('Show Filters:')
if filterMusic:
print('Music Filters: {}'.format(filterMusic))
if filterMusic == {} and filterMusic != None:
if filterMusic == {} and filterMusic is not None:
print('Music Filters:')
@ -286,7 +288,7 @@ if __name__ == "__main__":
help='Show all shares by library.')
# For Plex Pass members
if plex.myPlexSubscription == True:
if plex.myPlexSubscription is True:
movie_ratings = []
show_ratings = []
for movie in movies_keys:
@ -400,7 +402,6 @@ if __name__ == "__main__":
for section, users in section_users.items():
print("{} is shared to the following users:\n {}\n".format(section, ", ".join(users)))
# Share, Unshare, Kill, Add, or Remove
for user in users:
user_shares = find_shares(user)

View File

@ -1,4 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Change show deletion settings by library.

View File

@ -1,18 +1,20 @@
#!/usr/bin/env python
'''
# -*- coding: utf-8 -*-
"""
Pull poster images from Imgur and places them inside Shows root folder.
/path/to/show/Show.jpg
Skips download if showname.jpg exists or if show does not exist.
'''
"""
import requests
import urllib
import os
## Edit ##
# ## Edit ##
# Imgur info
CLIENT_ID = 'xxxxx' # Tautulli Settings > Notifications > Imgur Client ID
@ -21,7 +23,8 @@ ALBUM_ID = '7JeSw' # http://imgur.com/a/7JeSw <--- 7JeSw is the ablum_id
# Local info
SHOW_PATH = 'D:\\Shows\\'
## /Edit ##
# ## /Edit ##
class IMGURINFO(object):
def __init__(self, data=None):

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python
'''
Build playlist from popular tracks.
# -*- coding: utf-8 -*-
"""Build playlist from popular tracks.
optional arguments:
-h, --help show this help message and exit
@ -14,7 +15,7 @@ optional arguments:
* LIBRARY_EXCLUDE are excluded from libraries choice.
'''
"""
import requests

View File

@ -1,9 +1,12 @@
#!/usr/bin/env python
'''
Download theme songs from Plex TV Shows. Theme songs are mp3 and named by shows as displayed by Plex.
# -*- coding: utf-8 -*-
"""Download theme songs from Plex TV Shows.
Theme songs are mp3 and named by shows as displayed by Plex.
Songs are saved in a 'Theme Songs' directory located in script's path.
'''
"""
from plexapi.server import PlexServer, CONFIG
@ -13,14 +16,14 @@ import re
import urllib
import requests
## Edit ##
# ## Edit ##
PLEX_URL = ''
PLEX_TOKEN = ''
PLEX_URL = CONFIG.data['auth'].get('server_baseurl', PLEX_URL)
PLEX_TOKEN = CONFIG.data['auth'].get('server_token', PLEX_TOKEN)
TV_LIBRARY = 'TV Shows' # Name of your TV Show library
## /Edit ##
# ## /Edit ##
sess = requests.Session()
# Ignore verifying the SSL certificate

View File

@ -1,5 +1,7 @@
"""
Delete all playlists from Plex using PlexAPI
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Delete all playlists from Plex.
"""

View File

@ -1,6 +1,8 @@
#!/usr/bin/env python3
"""
Description: Purge Tautulli users that no longer exist as a friend in Plex
# -*- coding: utf-8 -*-
"""Purge Tautulli users that no longer exist as a friend in Plex.
Author: DirtyCajunRice
Requires: requests, plexapi, python3.6+
"""

View File

@ -1,6 +1,8 @@
#!/usr/bin/env python
'''
Refresh the next episode of show once current episode is watched.
# -*- coding: utf-8 -*-
"""Refresh the next episode of show once current episode is watched.
Check Tautulli's Watched Percent in Tautulli > Settings > General
1. Tautulli > Settings > Notification Agents > Scripts > Bell icon:
@ -12,7 +14,7 @@ Check Tautulli's Watched Percent in Tautulli > Settings > General
3. Tautulli > Settings > Notifications > Script > Script Arguments:
{show_name} {episode_num00} {season_num00}
'''
"""
import requests
import sys

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python
"""
Unshare or Remove users who have been inactive for X days. Prints out last seen for all users.
# -*- coding: utf-8 -*-
"""Unshare or Remove users who have been inactive for X days. Prints out last seen for all users.
Just run.
@ -114,6 +115,3 @@ for user in TAUTULLI_USERS:
else:
print('{}, and has reached their inactivity limit. Unsharing.'.format(OUTPUT))
ACCOUNT.updateFriend(PLEX_USERS[UID], SERVER, removeSections=True)

View File

@ -1,6 +1,7 @@
"""
Find Movies that have been watched by a list of users.
If all users have watched movie than delete.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Find and delete Movies that have been watched by a list of users.
Deletion is prompted
"""
@ -11,12 +12,13 @@ import os
import shutil
## EDIT THESE SETTINGS ##
# ## EDIT THESE SETTINGS ##
TAUTULLI_APIKEY = 'xxxxxxxx' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
LIBRARY_NAMES = ['My Movies'] # Whatever your movie libraries are called.
USER_LST = ['Joe', 'Alex'] # Name of users
class UserHIS(object):
def __init__(self, data=None):
d = data or {}
@ -81,6 +83,7 @@ def delete_files(tmp_lst):
else:
print('Ok. doing nothing.')
movie_dict = {}
movie_lst = []
delete_lst = []

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python
"""
Share functions from https://gist.github.com/JonnyWong16/f8139216e2748cb367558070c1448636
# -*- coding: utf-8 -*-
"""Share functions from https://gist.github.com/JonnyWong16/f8139216e2748cb367558070c1448636
Once user stream count hits LIMIT they are unshared from libraries expect for banned library.
Once user stream count is below LIMIT and banned library video is watched their shares are restored.
@ -30,7 +31,6 @@ Tautulli will continue displaying that user is watching after unshare is execute
Tautulli will update after ~5 minutes and no longer display user's stream in ACTIVITY.
Tautulli will think that user has stopped.
Create new library with one video.
Name library and video whatever you want.
@ -59,7 +59,7 @@ import email.utils
import smtplib
## EDIT THESE SETTINGS ###
# ## EDIT THESE SETTINGS ###
TAUTULLI_APIKEY = 'XXXXXX' # Your Tautulli API key
TAUTULLI_URL = 'http://localhost:8181/' # Your Tautulli URL
@ -107,7 +107,7 @@ email_username = '' # Your email username
email_password = '' # Your email password
## DO NOT EDIT BELOW ##
# ## DO NOT EDIT BELOW ##
class Activity(object):
def __init__(self, data=None):
@ -216,7 +216,7 @@ def unshare(user_id):
return
elif r.status_code == 400:
print r.content
print(r.content)
return
elif r.status_code == 200:
@ -256,6 +256,7 @@ def get_activity():
except Exception as e:
sys.stderr.write("Tautulli API 'get_activity' request failed: {0}.".format(e))
def send_notification(to=None, friendly=None, val_cnt=None, val_tot=None, mess=None):
# Format notification text
try:
@ -297,7 +298,7 @@ if __name__ == "__main__":
# Trigger for first and next violation
unshare(user) # Remove libraries
share(user, BAN) # Share banned library
sys.stdout.write("Shared BAN_LIBRARY with user {0}".format(i))
sys.stdout.write("Shared BAN_LIBRARY with user {0}".format(user))
if type(history) is int:
# Next violation, history of banned video.
send_notification(mail_add, friendly, history, VIOLATION_LIMIT, FIRST_WARN)

View File

@ -1,6 +1,8 @@
#!/usr/bin/env python
"""
Description: Sync the watch status from one Plex or Tautulli user to other users across any owned server.
# -*- coding: utf-8 -*-
"""Sync the watch status from one Plex or Tautulli user to other users across any owned server.
Author: Blacktwin
Requires: requests, plexapi, argparse
@ -158,7 +160,7 @@ class Tautulli:
return
def get_watched_history(self, user=None, section_id=None, rating_key=None, start=None, length=None):
"""Call Tautulli's get_history api endpoint"""
"""Call Tautulli's get_history api endpoint."""
payload = {"order_column": "full_title",
"order_dir": "asc"}
if user:
@ -177,14 +179,12 @@ class Tautulli:
return [d for d in history['data'] if d['watched_status'] == 1]
def get_metadata(self, rating_key):
"""Call Tautulli's get_metadata api endpoint"""
"""Call Tautulli's get_metadata api endpoint."""
payload = {"rating_key": rating_key}
return self._call_api('get_metadata', payload)
def get_libraries(self):
"""Call Tautulli's get_libraries api endpoint"""
"""Call Tautulli's get_libraries api endpoint."""
payload = {}
return self._call_api('get_libraries', payload)
@ -198,23 +198,27 @@ class Plex:
self.server = PlexServer(baseurl=url, token=token, session=session)
def admin_servers(self):
"""All owned servers
"""Get all owned servers.
Returns
-------
data: dict
"""
resources = {}
for resource in self.account.resources():
if 'server' in [resource.provides] and resource.owned == True:
if 'server' in [resource.provides] and resource.owned is True:
resources[resource.name] = resource
return resources
def all_users(self):
"""All users
"""Get all users.
Returns
-------
data: dict
"""
users = {self.account.title: self.account}
for user in self.account.users():
@ -223,10 +227,12 @@ class Plex:
return users
def all_sections(self):
"""All sections from all owned servers
"""Get all sections from all owned servers.
Returns
-------
data: dict
"""
data = {}
servers = self.admin_servers()
@ -239,10 +245,12 @@ class Plex:
return data
def users_access(self):
"""Users access across all owned servers
"""Get users access across all owned servers.
Returns
-------
data: dict
"""
all_users = self.all_users().values()
admin_servers = self.admin_servers()
@ -257,7 +265,7 @@ class Plex:
if admin_servers.get(server.name):
access = {}
sections = {section.title: section for section in server.sections()
if section.shared == True}
if section.shared is True}
access['server'] = {server.name: admin_servers.get(server.name)}
access['sections'] = sections
servers += [access]
@ -278,7 +286,8 @@ class Plex:
def connect_to_server(server_obj, user_account):
"""Find server url and connect using user token
"""Find server url and connect using user token.
Parameters
----------
server_obj: class
@ -287,6 +296,7 @@ def connect_to_server(server_obj, user_account):
Returns
-------
user_connection.server: class
"""
server_name = server_obj.name
user = user_account.title
@ -308,6 +318,7 @@ def connect_to_server(server_obj, user_account):
def check_users_access(access, user, server_name, libraries=None):
"""Check user's access to server. If allowed connect.
Parameters
----------
access: dict
@ -318,6 +329,7 @@ def check_users_access(access, user, server_name, libraries=None):
Returns
-------
server_connection: class
"""
try:
_user = access.get(user)
@ -349,7 +361,8 @@ def check_users_access(access, user, server_name, libraries=None):
def sync_watch_status(watched, section, accountTo, userTo, same_server=False):
"""
"""Sync watched status between two users.
Parameters
----------
watched: list
@ -362,6 +375,7 @@ def sync_watch_status(watched, section, accountTo, userTo, same_server=False):
User's server class of sync to user
same_server: bool
Are serverFrom and serverTo the same
"""
print('Marking watched...')
sectionTo = accountTo.library.section(section)

View File

@ -1,6 +1,8 @@
#!/usr/bin/env python3
"""
Description: Sync Tautulli friendly names with Ombi aliases (Tautulli as master)
# -*- coding: utf-8 -*-
"""Sync Tautulli friendly names with Ombi aliases (Tautulli as master).
Author: DirtyCajunRice
Requires: requests, python3.6+
"""