Run futurize --stage1

This commit is contained in:
JonnyWong16 2019-11-23 19:11:42 -08:00
parent 221be380ee
commit ab6196589b
36 changed files with 736 additions and 497 deletions

View file

@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
from builtins import str
import os
import sys

View file

@ -13,13 +13,18 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import range
import datetime
import os
from Queue import Queue
import queue
import sqlite3
import sys
import subprocess
import threading
import datetime
import uuid
# Some cut down versions of Python may not include this module and it's not critical for us
@ -34,24 +39,25 @@ from apscheduler.triggers.interval import IntervalTrigger
from UniversalAnalytics import Tracker
import pytz
import activity_handler
import activity_pinger
import common
import database
import datafactory
import libraries
import logger
import mobile_app
import newsletters
import newsletter_handler
import notification_handler
import notifiers
import plextv
import users
import versioncheck
import web_socket
import webstart
import plexpy.config
from plexpy import activity_handler
from plexpy import activity_pinger
from plexpy import common
from plexpy import database
from plexpy import datafactory
from plexpy import libraries
from plexpy import logger
from plexpy import mobile_app
from plexpy import newsletters
from plexpy import newsletter_handler
from plexpy import notification_handler
from plexpy import notifiers
from plexpy import plextv
from plexpy import users
from plexpy import versioncheck
from plexpy import web_socket
from plexpy import webstart
from plexpy import config
PROG_DIR = None
FULL_PATH = None
@ -74,7 +80,7 @@ DOCKER = False
SCHED = None
SCHED_LOCK = threading.Lock()
NOTIFY_QUEUE = Queue()
NOTIFY_QUEUE = queue.Queue()
INIT_LOCK = threading.Lock()
_INITIALIZED = False
@ -128,7 +134,7 @@ def initialize(config_file):
global UMASK
global _UPDATE
CONFIG = plexpy.config.Config(config_file)
CONFIG = config.Config(config_file)
CONFIG_FILE = config_file
assert CONFIG is not None
@ -137,7 +143,7 @@ def initialize(config_file):
return False
if CONFIG.HTTP_PORT < 21 or CONFIG.HTTP_PORT > 65535:
plexpy.logger.warn("HTTP_PORT out of bounds: 21 < %s < 65535", CONFIG.HTTP_PORT)
logger.warn("HTTP_PORT out of bounds: 21 < %s < 65535", CONFIG.HTTP_PORT)
CONFIG.HTTP_PORT = 8181
if not CONFIG.HTTPS_CERT:
@ -162,7 +168,7 @@ def initialize(config_file):
' - {}'.format(common.PLATFORM_LINUX_DISTRO) if common.PLATFORM_LINUX_DISTRO else ''
))
logger.info("{} (UTC{})".format(
plexpy.SYS_TIMEZONE.zone, plexpy.SYS_UTC_OFFSET
SYS_TIMEZONE.zone, SYS_UTC_OFFSET
))
logger.info("Python {}".format(
sys.version
@ -379,29 +385,29 @@ def win_system_tray():
from systray import SysTrayIcon
def tray_open(sysTrayIcon):
launch_browser(plexpy.CONFIG.HTTP_HOST, plexpy.HTTP_PORT, plexpy.HTTP_ROOT)
launch_browser(CONFIG.HTTP_HOST, HTTP_PORT, HTTP_ROOT)
def tray_check_update(sysTrayIcon):
versioncheck.check_update()
def tray_update(sysTrayIcon):
if plexpy.UPDATE_AVAILABLE:
plexpy.SIGNAL = 'update'
if UPDATE_AVAILABLE:
SIGNAL = 'update'
else:
hover_text = common.PRODUCT + ' - No Update Available'
plexpy.WIN_SYS_TRAY_ICON.update(hover_text=hover_text)
WIN_SYS_TRAY_ICON.update(hover_text=hover_text)
def tray_restart(sysTrayIcon):
plexpy.SIGNAL = 'restart'
SIGNAL = 'restart'
def tray_quit(sysTrayIcon):
plexpy.SIGNAL = 'shutdown'
SIGNAL = 'shutdown'
if plexpy.UPDATE_AVAILABLE:
icon = os.path.join(plexpy.PROG_DIR, 'data/interfaces/', plexpy.CONFIG.INTERFACE, 'images/logo_tray-update.ico')
if UPDATE_AVAILABLE:
icon = os.path.join(PROG_DIR, 'data/interfaces/', CONFIG.INTERFACE, 'images/logo_tray-update.ico')
hover_text = common.PRODUCT + ' - Update Available!'
else:
icon = os.path.join(plexpy.PROG_DIR, 'data/interfaces/', plexpy.CONFIG.INTERFACE, 'images/logo_tray.ico')
icon = os.path.join(PROG_DIR, 'data/interfaces/', CONFIG.INTERFACE, 'images/logo_tray.ico')
hover_text = common.PRODUCT
menu_options = (('Open Tautulli', None, tray_open, 'default'),
@ -413,11 +419,11 @@ def win_system_tray():
logger.info("Launching system tray icon.")
try:
plexpy.WIN_SYS_TRAY_ICON = SysTrayIcon(icon, hover_text, menu_options, on_quit=tray_quit)
plexpy.WIN_SYS_TRAY_ICON.start()
WIN_SYS_TRAY_ICON = SysTrayIcon(icon, hover_text, menu_options, on_quit=tray_quit)
WIN_SYS_TRAY_ICON.start()
except Exception as e:
logger.error("Unable to launch system tray icon: %s." % e)
plexpy.WIN_SYS_TRAY_ICON = None
WIN_SYS_TRAY_ICON = None
def initialize_scheduler():
@ -2055,12 +2061,12 @@ def initialize_tracker():
'dataSource': 'server',
'appName': common.PRODUCT,
'appVersion': common.RELEASE,
'appId': plexpy.INSTALL_TYPE,
'appInstallerId': plexpy.CONFIG.GIT_BRANCH,
'appId': INSTALL_TYPE,
'appInstallerId': CONFIG.GIT_BRANCH,
'dimension1': '{} {}'.format(common.PLATFORM, common.PLATFORM_RELEASE), # App Platform
'dimension2': common.PLATFORM_LINUX_DISTRO, # Linux Distro
'userLanguage': plexpy.SYS_LANGUAGE,
'documentEncoding': plexpy.SYS_ENCODING,
'userLanguage': SYS_LANGUAGE,
'documentEncoding': SYS_ENCODING,
'noninteractive': True
}

View file

@ -13,6 +13,10 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
from builtins import object
import datetime
import os
import time
@ -21,12 +25,12 @@ from apscheduler.triggers.date import DateTrigger
import pytz
import plexpy
import activity_processor
import datafactory
import helpers
import logger
import notification_handler
import pmsconnect
from plexpy import activity_processor
from plexpy import datafactory
from plexpy import helpers
from plexpy import logger
from plexpy import notification_handler
from plexpy import pmsconnect
ACTIVITY_SCHED = None

View file

@ -13,20 +13,23 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
import threading
import time
import plexpy
import activity_handler
import activity_processor
import database
import helpers
import libraries
import logger
import notification_handler
import plextv
import pmsconnect
import web_socket
from plexpy import activity_handler
from plexpy import activity_processor
from plexpy import database
from plexpy import helpers
from plexpy import libraries
from plexpy import logger
from plexpy import notification_handler
from plexpy import plextv
from plexpy import pmsconnect
from plexpy import web_socket
monitor_lock = threading.Lock()

View file

@ -13,17 +13,21 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
from builtins import object
from collections import defaultdict
import json
import time
import plexpy
import database
import helpers
import libraries
import logger
import pmsconnect
import users
from plexpy import database
from plexpy import helpers
from plexpy import libraries
from plexpy import logger
from plexpy import pmsconnect
from plexpy import users
class ActivityProcessor(object):
@ -498,7 +502,7 @@ class ActivityProcessor(object):
if state:
values['state'] = state
for k, v in kwargs.iteritems():
for k, v in kwargs.items():
values[k] = v
keys = {'session_key': session_key}

View file

@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
@ -17,6 +16,10 @@
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
from builtins import object
import hashlib
import inspect
import json
@ -30,22 +33,22 @@ import cherrypy
import xmltodict
import plexpy
import config
import database
import helpers
import libraries
import logger
import mobile_app
import notification_handler
import notifiers
import newsletter_handler
import newsletters
import users
from plexpy import config
from plexpy import database
from plexpy import helpers
from plexpy import libraries
from plexpy import logger
from plexpy import mobile_app
from plexpy import notification_handler
from plexpy import notifiers
from plexpy import newsletter_handler
from plexpy import newsletters
from plexpy import users
class API2:
class API2(object):
def __init__(self, **kwargs):
self._api_valid_methods = self._api_docs().keys()
self._api_valid_methods = list(self._api_docs().keys())
self._api_authenticated = False
self._api_out_type = 'json' # default
self._api_msg = None
@ -201,7 +204,7 @@ class API2:
except IndexError:
# We assume this is a traceback
tl = (len(templog) - 1)
templog[tl]['msg'] += helpers.sanitize(unicode(line.replace('\n', ''), 'utf-8'))
templog[tl]['msg'] += helpers.sanitize(str(line.replace('\n', ''), 'utf-8'))
continue
if len(line) > 1 and temp_loglevel_and_time is not None and loglvl in line:
@ -209,7 +212,7 @@ class API2:
d = {
'time': temp_loglevel_and_time[0],
'loglevel': loglvl,
'msg': helpers.sanitize(unicode(msg.replace('\n', ''), 'utf-8')),
'msg': helpers.sanitize(str(msg.replace('\n', ''), 'utf-8')),
'thread': thread
}
templog.append(d)
@ -227,7 +230,7 @@ class API2:
if search:
logger.api_debug("Tautulli APIv2 :: Searching log values for '%s'" % search)
tt = [d for d in templog for k, v in d.items() if search.lower() in v.lower()]
tt = [d for d in templog for k, v in list(d.items()) if search.lower() in v.lower()]
if len(tt):
templog = tt
@ -235,7 +238,7 @@ class API2:
if regex:
tt = []
for l in templog:
stringdict = ' '.join('{}{}'.format(k, v) for k, v in l.items())
stringdict = ' '.join('{}{}'.format(k, v) for k, v in list(l.items()))
if reg.search(stringdict):
tt.append(l)
@ -271,10 +274,10 @@ class API2:
config = {}
# Truthify the dict
for k, v in conf.iteritems():
for k, v in conf.items():
if isinstance(v, dict):
d = {}
for kk, vv in v.iteritems():
for kk, vv in v.items():
if vv == '0' or vv == '1':
d[kk] = bool(vv)
else:

View file

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
@ -18,12 +20,16 @@
#########################################
import urllib
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from common import USER_AGENT
import urllib.request, urllib.parse, urllib.error
from plexpy.common import USER_AGENT
class PlexPyURLopener(urllib.FancyURLopener):
class PlexPyURLopener(urllib.request.FancyURLopener):
version = USER_AGENT
@ -44,7 +50,7 @@ class AuthURLOpener(PlexPyURLopener):
self.numTries = 0
# call the base class
urllib.FancyURLopener.__init__(self)
urllib.request.FancyURLopener.__init__(self)
def prompt_user_passwd(self, host, realm):
"""

View file

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
@ -13,17 +15,21 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
import distro
import platform
from collections import OrderedDict
import version
from plexpy import version
# Identify Our Application
PRODUCT = 'Tautulli'
PLATFORM = platform.system()
PLATFORM_RELEASE = platform.release()
PLATFORM_VERSION = platform.version()
PLATFORM_LINUX_DISTRO = ' '.join(x for x in platform.linux_distribution() if x)
PLATFORM_LINUX_DISTRO = ' '.join(x for x in distro.linux_distribution() if x)
PLATFORM_DEVICE_NAME = platform.node()
BRANCH = version.PLEXPY_BRANCH
RELEASE = version.PLEXPY_RELEASE_VERSION
@ -98,7 +104,7 @@ PLATFORM_NAMES = {
'xbmc': 'xbmc',
'xbox': 'xbox'
}
PLATFORM_NAMES = OrderedDict(sorted(PLATFORM_NAMES.items(), key=lambda k: k[0], reverse=True))
PLATFORM_NAMES = OrderedDict(sorted(list(PLATFORM_NAMES.items()), key=lambda k: k[0], reverse=True))
MEDIA_FLAGS_AUDIO = {
'ac.?3': 'dolby_digital',
@ -147,7 +153,7 @@ VIDEO_QUALITY_PROFILES = {
96: '0.096 Mbps',
64: '0.064 Mbps'
}
VIDEO_QUALITY_PROFILES = OrderedDict(sorted(VIDEO_QUALITY_PROFILES.items(), key=lambda k: k[0], reverse=True))
VIDEO_QUALITY_PROFILES = OrderedDict(sorted(list(VIDEO_QUALITY_PROFILES.items()), key=lambda k: k[0], reverse=True))
AUDIO_QUALITY_PROFILES = {
512: '512 kbps',
@ -157,7 +163,7 @@ AUDIO_QUALITY_PROFILES = {
128: '128 kbps',
96: '96 kbps'
}
AUDIO_QUALITY_PROFILES = OrderedDict(sorted(AUDIO_QUALITY_PROFILES.items(), key=lambda k: k[0], reverse=True))
AUDIO_QUALITY_PROFILES = OrderedDict(sorted(list(AUDIO_QUALITY_PROFILES.items()), key=lambda k: k[0], reverse=True))
HW_DECODERS = [
'dxva2',

View file

@ -13,6 +13,10 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from past.builtins import basestring
from builtins import object
import arrow
import os
import re
@ -22,7 +26,7 @@ import time
from configobj import ConfigObj
import plexpy
import logger
from plexpy import logger
def bool_int(value):
@ -49,7 +53,7 @@ _CONFIG_DEFINITIONS = {
'PMS_IS_REMOTE': (int, 'PMS', 0),
'PMS_LOGS_FOLDER': (str, 'PMS', ''),
'PMS_LOGS_LINE_CAP': (int, 'PMS', 1000),
'PMS_NAME': (unicode, 'PMS', ''),
'PMS_NAME': (str, 'PMS', ''),
'PMS_PORT': (int, 'PMS', 32400),
'PMS_TOKEN': (str, 'PMS', ''),
'PMS_SSL': (int, 'PMS', 0),
@ -345,35 +349,35 @@ _CONFIG_DEFINITIONS = {
'NOTIFY_CONCURRENT_BY_IP': (int, 'Monitoring', 0),
'NOTIFY_CONCURRENT_THRESHOLD': (int, 'Monitoring', 2),
'NOTIFY_WATCHED_PERCENT': (int, 'Monitoring', 85),
'NOTIFY_ON_START_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_START_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) started playing {title}.'),
'NOTIFY_ON_STOP_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_STOP_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has stopped {title}.'),
'NOTIFY_ON_PAUSE_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_PAUSE_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has paused {title}.'),
'NOTIFY_ON_RESUME_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_RESUME_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has resumed {title}.'),
'NOTIFY_ON_BUFFER_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_BUFFER_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) is buffering {title}.'),
'NOTIFY_ON_WATCHED_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_WATCHED_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has watched {title}.'),
'NOTIFY_ON_CREATED_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_CREATED_BODY_TEXT': (unicode, 'Monitoring', '{title} was recently added to Plex.'),
'NOTIFY_ON_EXTDOWN_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_EXTDOWN_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server remote access is down.'),
'NOTIFY_ON_INTDOWN_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_INTDOWN_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server is down.'),
'NOTIFY_ON_EXTUP_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_EXTUP_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server remote access is back up.'),
'NOTIFY_ON_INTUP_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_INTUP_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server is back up.'),
'NOTIFY_ON_PMSUPDATE_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_PMSUPDATE_BODY_TEXT': (unicode, 'Monitoring', 'An update is available for the Plex Media Server (version {update_version}).'),
'NOTIFY_ON_CONCURRENT_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_CONCURRENT_BODY_TEXT': (unicode, 'Monitoring', '{user} has {user_streams} concurrent streams.'),
'NOTIFY_ON_NEWDEVICE_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_NEWDEVICE_BODY_TEXT': (unicode, 'Monitoring', '{user} is streaming from a new device: {player}.'),
'NOTIFY_SCRIPTS_ARGS_TEXT': (unicode, 'Monitoring', ''),
'NOTIFY_ON_START_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_START_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) started playing {title}.'),
'NOTIFY_ON_STOP_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_STOP_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) has stopped {title}.'),
'NOTIFY_ON_PAUSE_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_PAUSE_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) has paused {title}.'),
'NOTIFY_ON_RESUME_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_RESUME_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) has resumed {title}.'),
'NOTIFY_ON_BUFFER_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_BUFFER_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) is buffering {title}.'),
'NOTIFY_ON_WATCHED_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_WATCHED_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) has watched {title}.'),
'NOTIFY_ON_CREATED_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_CREATED_BODY_TEXT': (str, 'Monitoring', '{title} was recently added to Plex.'),
'NOTIFY_ON_EXTDOWN_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_EXTDOWN_BODY_TEXT': (str, 'Monitoring', 'The Plex Media Server remote access is down.'),
'NOTIFY_ON_INTDOWN_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_INTDOWN_BODY_TEXT': (str, 'Monitoring', 'The Plex Media Server is down.'),
'NOTIFY_ON_EXTUP_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_EXTUP_BODY_TEXT': (str, 'Monitoring', 'The Plex Media Server remote access is back up.'),
'NOTIFY_ON_INTUP_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_INTUP_BODY_TEXT': (str, 'Monitoring', 'The Plex Media Server is back up.'),
'NOTIFY_ON_PMSUPDATE_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_PMSUPDATE_BODY_TEXT': (str, 'Monitoring', 'An update is available for the Plex Media Server (version {update_version}).'),
'NOTIFY_ON_CONCURRENT_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_CONCURRENT_BODY_TEXT': (str, 'Monitoring', '{user} has {user_streams} concurrent streams.'),
'NOTIFY_ON_NEWDEVICE_SUBJECT_TEXT': (str, 'Monitoring', 'Tautulli ({server_name})'),
'NOTIFY_ON_NEWDEVICE_BODY_TEXT': (str, 'Monitoring', '{user} is streaming from a new device: {player}.'),
'NOTIFY_SCRIPTS_ARGS_TEXT': (str, 'Monitoring', ''),
'OSX_NOTIFY_APP': (str, 'OSX_Notify', '/Applications/Tautulli'),
'OSX_NOTIFY_ENABLED': (int, 'OSX_Notify', 0),
'OSX_NOTIFY_ON_PLAY': (int, 'OSX_Notify', 0),
@ -512,7 +516,7 @@ _CONFIG_DEFINITIONS = {
'SLACK_ON_CONCURRENT': (int, 'Slack', 0),
'SLACK_ON_NEWDEVICE': (int, 'Slack', 0),
'SCRIPTS_ENABLED': (int, 'Scripts', 0),
'SCRIPTS_FOLDER': (unicode, 'Scripts', ''),
'SCRIPTS_FOLDER': (str, 'Scripts', ''),
'SCRIPTS_TIMEOUT': (int, 'Scripts', 30),
'SCRIPTS_ON_PLAY': (int, 'Scripts', 0),
'SCRIPTS_ON_STOP': (int, 'Scripts', 0),
@ -528,20 +532,20 @@ _CONFIG_DEFINITIONS = {
'SCRIPTS_ON_PMSUPDATE': (int, 'Scripts', 0),
'SCRIPTS_ON_CONCURRENT': (int, 'Scripts', 0),
'SCRIPTS_ON_NEWDEVICE': (int, 'Scripts', 0),
'SCRIPTS_ON_PLAY_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_STOP_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_PAUSE_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_RESUME_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_BUFFER_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_WATCHED_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_CREATED_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_EXTDOWN_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_EXTUP_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_INTDOWN_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_INTUP_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_PMSUPDATE_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_CONCURRENT_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_NEWDEVICE_SCRIPT': (unicode, 'Scripts', ''),
'SCRIPTS_ON_PLAY_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_STOP_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_PAUSE_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_RESUME_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_BUFFER_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_WATCHED_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_CREATED_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_EXTDOWN_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_EXTUP_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_INTDOWN_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_INTUP_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_PMSUPDATE_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_CONCURRENT_SCRIPT': (str, 'Scripts', ''),
'SCRIPTS_ON_NEWDEVICE_SCRIPT': (str, 'Scripts', ''),
'SYNCHRONOUS_MODE': (str, 'Advanced', 'NORMAL'),
'TELEGRAM_BOT_TOKEN': (str, 'Telegram', ''),
'TELEGRAM_ENABLED': (int, 'Telegram', 0),
@ -680,7 +684,7 @@ class Config(object):
""" Initialize the config with values from a file """
self._config_file = config_file
self._config = ConfigObj(self._config_file, encoding='utf-8')
for key in _CONFIG_DEFINITIONS.keys():
for key in list(_CONFIG_DEFINITIONS.keys()):
self.check_setting(key)
self._upgrade()
self._blacklist()
@ -689,8 +693,8 @@ class Config(object):
""" Add tokens and passwords to blacklisted words in logger """
blacklist = set()
for key, subkeys in self._config.iteritems():
for subkey, value in subkeys.iteritems():
for key, subkeys in self._config.items():
for subkey, value in subkeys.items():
if isinstance(value, basestring) and len(value.strip()) > 5 and \
subkey.upper() not in _WHITELIST_KEYS and any(bk in subkey.upper() for bk in _BLACKLIST_KEYS):
blacklist.add(value.strip())
@ -733,14 +737,14 @@ class Config(object):
# first copy over everything from the old config, even if it is not
# correctly defined to keep from losing data
for key, subkeys in self._config.items():
for key, subkeys in list(self._config.items()):
if key not in new_config:
new_config[key] = {}
for subkey, value in subkeys.items():
for subkey, value in list(subkeys.items()):
new_config[key][subkey] = value
# next make sure that everything we expect to have defined is so
for key in _CONFIG_DEFINITIONS.keys():
for key in list(_CONFIG_DEFINITIONS.keys()):
key, definition_type, section, ini_key, default = self._define(key)
self.check_setting(key)
if section not in new_config:
@ -784,7 +788,7 @@ class Config(object):
"""
Given a big bunch of key value pairs, apply them to the ini.
"""
for name, value in kwargs.items():
for name, value in list(kwargs.items()):
key, definition_type, section, ini_key, default = self._define(name)
self._config[section][ini_key] = definition_type(value)

View file

@ -13,6 +13,9 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import object
import arrow
import os
import sqlite3
@ -21,7 +24,8 @@ import threading
import time
import plexpy
import logger
from plexpy import logger
FILENAME = "tautulli.db"
db_lock = threading.Lock()
@ -198,21 +202,21 @@ class MonitorDatabase(object):
trans_type = 'update'
changes_before = self.connection.total_changes
gen_params = lambda my_dict: [x + " = ?" for x in my_dict.keys()]
gen_params = lambda my_dict: [x + " = ?" for x in list(my_dict.keys())]
update_query = "UPDATE " + table_name + " SET " + ", ".join(gen_params(value_dict)) + \
" WHERE " + " AND ".join(gen_params(key_dict))
self.action(update_query, value_dict.values() + key_dict.values())
self.action(update_query, list(value_dict.values()) + list(key_dict.values()))
if self.connection.total_changes == changes_before:
trans_type = 'insert'
insert_query = (
"INSERT INTO " + table_name + " (" + ", ".join(value_dict.keys() + key_dict.keys()) + ")" +
" VALUES (" + ", ".join(["?"] * len(value_dict.keys() + key_dict.keys())) + ")"
"INSERT INTO " + table_name + " (" + ", ".join(list(value_dict.keys()) + list(key_dict.keys())) + ")" +
" VALUES (" + ", ".join(["?"] * len(list(value_dict.keys()) + list(key_dict.keys()))) + ")"
)
try:
self.action(insert_query, value_dict.values() + key_dict.values())
self.action(insert_query, list(value_dict.values()) + list(key_dict.values()))
except sqlite3.IntegrityError:
logger.info("Tautulli Database :: Queries failed: %s and %s", update_query, insert_query)

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,17 +15,24 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import division
from __future__ import absolute_import
from builtins import next
from builtins import str
from builtins import object
from past.utils import old_div
import json
from itertools import groupby
import plexpy
import common
import database
import datatables
import helpers
import logger
import pmsconnect
import session
from plexpy import common
from plexpy import database
from plexpy import datatables
from plexpy import helpers
from plexpy import logger
from plexpy import pmsconnect
from plexpy import session
class DataFactory(object):
@ -208,7 +217,7 @@ class DataFactory(object):
if item['percent_complete'] >= watched_percent[item['media_type']]:
watched_status = 1
elif item['percent_complete'] >= watched_percent[item['media_type']]/2:
elif item['percent_complete'] >= old_div(watched_percent[item['media_type']],2):
watched_status = 0.5
else:
watched_status = 0
@ -655,7 +664,7 @@ class DataFactory(object):
for item in result:
# Rename Mystery platform names
platform = common.PLATFORM_NAME_OVERRIDES.get(item['platform'], item['platform'])
platform_name = next((v for k, v in common.PLATFORM_NAMES.iteritems() if k in platform.lower()), 'default')
platform_name = next((v for k, v in common.PLATFORM_NAMES.items() if k in platform.lower()), 'default')
row = {'total_plays': item['total_plays'],
'total_duration': item['total_duration'],
@ -985,7 +994,7 @@ class DataFactory(object):
'pre_tautulli': pre_tautulli
}
stream_output = {k: v or '' for k, v in stream_output.iteritems()}
stream_output = {k: v or '' for k, v in stream_output.items()}
return stream_output
def get_metadata_details(self, rating_key):
@ -1518,7 +1527,7 @@ class DataFactory(object):
# function to map rating keys pairs
def get_pairs(old, new):
pairs = {}
for k, v in old.iteritems():
for k, v in old.items():
if k in new:
pairs.update({v['rating_key']: new[k]['rating_key']})
if 'children' in old[k]:
@ -1533,7 +1542,7 @@ class DataFactory(object):
if mapping:
logger.info("Tautulli DataFactory :: Updating metadata in the database.")
for old_key, new_key in mapping.iteritems():
for old_key, new_key in mapping.items():
metadata = pms_connect.get_metadata_details(new_key)
if metadata:

View file

@ -13,11 +13,14 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import object
import re
import database
import helpers
import logger
from plexpy import database
from plexpy import helpers
from plexpy import logger
class DataTables(object):
@ -90,7 +93,7 @@ class DataTables(object):
filtered = self.ssp_db.select(query, args=args)
# Remove NULL rows
filtered = [row for row in filtered if not all(v is None for v in row.values())]
filtered = [row for row in filtered if not all(v is None for v in list(row.values()))]
# Build grand totals
totalcount = self.ssp_db.select('SELECT COUNT(id) as total_count from %s' % table_name)[0]['total_count']

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,13 +15,18 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
from builtins import range
from builtins import object
import datetime
import plexpy
import common
import database
import logger
import session
from plexpy import common
from plexpy import database
from plexpy import logger
from plexpy import session
class Graphs(object):

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,6 +15,16 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import division
from __future__ import absolute_import
from past.builtins import cmp
from future import standard_library
standard_library.install_aliases()
from builtins import zip
from builtins import str
from past.builtins import basestring
from past.utils import old_div
import base64
import cloudinary
from cloudinary.api import delete_resources_by_tag
@ -20,12 +32,15 @@ from cloudinary.uploader import upload
from cloudinary.utils import cloudinary_url
import datetime
from functools import wraps
import geoip2.database, geoip2.errors
import geoip2.database
import geoip2.errors
import gzip
import hashlib
import imghdr
from itertools import izip_longest
import ipwhois, ipwhois.exceptions, ipwhois.utils
from itertools import zip_longest
import ipwhois
import ipwhois.exceptions
import ipwhois.utils
from IPy import IP
import json
import math
@ -38,13 +53,18 @@ import socket
import sys
import time
import unicodedata
import urllib, urllib2
import urllib.request
import urllib.parse
import urllib.error
import urllib.request
import urllib.error
import urllib.parse
from xml.dom import minidom
import xmltodict
import plexpy
import logger
import request
from plexpy import logger
from plexpy import request
from plexpy.api2 import API2
@ -158,7 +178,7 @@ def latinToAscii(unicrap):
def convert_milliseconds(ms):
seconds = ms / 1000
seconds = old_div(ms, 1000)
gmtime = time.gmtime(seconds)
if seconds > 3600:
minutes = time.strftime("%H:%M:%S", gmtime)
@ -172,7 +192,7 @@ def convert_milliseconds_to_minutes(ms):
if str(ms).isdigit():
seconds = float(ms) / 1000
minutes = round(seconds / 60, 0)
minutes = round(old_div(seconds, 60), 0)
return math.trunc(minutes)
@ -224,9 +244,9 @@ def human_duration(s, sig='dhms'):
hd = ''
if str(s).isdigit() and s > 0:
d = int(s / 86400)
h = int((s % 86400) / 3600)
m = int(((s % 86400) % 3600) / 60)
d = int(old_div(s, 86400))
h = int(old_div((s % 86400), 3600))
m = int(old_div(((s % 86400) % 3600), 60))
s = int(((s % 86400) % 3600) % 60)
hd_list = []
@ -277,7 +297,7 @@ def get_age(date):
def bytes_to_mb(bytes):
mb = int(bytes) / 1048576
mb = old_div(int(bytes), 1048576)
size = '%.1f MB' % mb
return size
@ -318,7 +338,7 @@ def replace_all(text, dic, normalize=False):
if not text:
return ''
for i, j in dic.iteritems():
for i, j in dic.items():
if normalize:
try:
if sys.platform == 'darwin':
@ -476,7 +496,7 @@ def get_percent(value1, value2):
value2 = cast_to_float(value2)
if value1 != 0 and value2 != 0:
percent = (value1 / value2) * 100
percent = (old_div(value1, value2)) * 100
else:
percent = 0
@ -543,11 +563,11 @@ def sanitize_out(*dargs, **dkwargs):
def sanitize(obj):
if isinstance(obj, basestring):
return unicode(obj).replace('<', '&lt;').replace('>', '&gt;')
return str(obj).replace('<', '&lt;').replace('>', '&gt;')
elif isinstance(obj, list):
return [sanitize(o) for o in obj]
elif isinstance(obj, dict):
return {k: sanitize(v) for k, v in obj.iteritems()}
return {k: sanitize(v) for k, v in obj.items()}
elif isinstance(obj, tuple):
return tuple(sanitize(list(obj)))
else:
@ -596,9 +616,9 @@ def install_geoip_db():
# Retrieve the GeoLite2 gzip file
logger.debug("Tautulli Helpers :: Downloading GeoLite2 gzip file from MaxMind...")
try:
maxmind = urllib.URLopener()
maxmind = urllib.request.URLopener()
maxmind.retrieve(maxmind_url + geolite2_gz, temp_gz)
md5_checksum = urllib2.urlopen(maxmind_url + geolite2_md5).read()
md5_checksum = urllib.request.urlopen(maxmind_url + geolite2_md5).read()
except Exception as e:
logger.error("Tautulli Helpers :: Failed to download GeoLite2 gzip file from MaxMind: %s" % e)
return False
@ -1151,7 +1171,7 @@ def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
return zip_longest(fillvalue=fillvalue, *args)
def traverse_map(obj, func):
@ -1162,7 +1182,7 @@ def traverse_map(obj, func):
elif isinstance(obj, dict):
new_obj = {}
for k, v in obj.iteritems():
for k, v in obj.items():
new_obj[traverse_map(k, func)] = traverse_map(v, func)
else:
@ -1187,7 +1207,7 @@ def mask_config_passwords(config):
cfg['value'] = ' '
elif isinstance(config, dict):
for cfg, val in config.iteritems():
for cfg, val in config.items():
# Check for a password config keys and if the password is not blank
if 'password' in cfg and val != '':
# Set the password to blank so it is not exposed in the HTML form

View file

@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of PlexPy.
@ -16,16 +15,22 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from past.builtins import basestring
from builtins import object
from functools import partial
from multiprocessing.dummy import Pool as ThreadPool
from urlparse import urljoin
from urllib.parse import urljoin
import certifi
import urllib3
import plexpy
import helpers
import logger
from plexpy import helpers
from plexpy import logger
class HTTPHandler(object):
@ -78,7 +83,7 @@ class HTTPHandler(object):
Output: list
"""
self.uri = uri.encode('utf-8')
self.uri = uri
self.request_type = request_type.upper()
self.output_format = output_format.lower()
self.return_type = return_type

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,18 +15,23 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
from builtins import next
from builtins import object
import json
import os
import plexpy
import common
import database
import datatables
import helpers
import logger
import plextv
import pmsconnect
import session
from plexpy import common
from plexpy import database
from plexpy import datatables
from plexpy import helpers
from plexpy import logger
from plexpy import plextv
from plexpy import pmsconnect
from plexpy import session
def refresh_libraries():
@ -213,7 +220,7 @@ def update_labels():
% section_id)
error_keys = set()
for rating_key, labels in key_mappings.iteritems():
for rating_key, labels in key_mappings.items():
try:
labels = ';'.join(labels)
monitor_db.action('UPDATE session_history_metadata SET labels = ? '
@ -540,7 +547,7 @@ class Libraries(object):
if search_value:
searchable_columns = [d['data'] for d in json_data['columns'] if d['searchable']] + ['title']
for row in rows:
for k,v in row.iteritems():
for k,v in row.items():
if k in searchable_columns and search_value in v.lower():
results.append(row)
break

View file

@ -1,11 +1,28 @@
"""
Locking-related classes
"""
# -*- coding: utf-8 -*-
import plexpy.logger
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Tautulli is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import object
import queue
import time
import threading
import Queue
from plexpy import logger
class TimedLock(object):
@ -28,7 +45,7 @@ class TimedLock(object):
self.lock = threading.Lock()
self.last_used = 0
self.minimum_delta = minimum_delta
self.queue = Queue.Queue()
self.queue = queue.Queue()
def __enter__(self):
"""
@ -39,14 +56,14 @@ class TimedLock(object):
sleep_amount = self.minimum_delta - delta
if sleep_amount >= 0:
# zero sleeps give the cpu a chance to task-switch
plexpy.logger.debug('Sleeping %s (interval)', sleep_amount)
logger.debug('Sleeping %s (interval)', sleep_amount)
time.sleep(sleep_amount)
while not self.queue.empty():
try:
seconds = self.queue.get(False)
plexpy.logger.debug('Sleeping %s (queued)', seconds)
logger.debug('Sleeping %s (queued)', seconds)
time.sleep(seconds)
except Queue.Empty:
except queue.Empty:
continue
self.queue.task_done()
@ -65,7 +82,7 @@ class TimedLock(object):
"""
# We use a queue so that we don't have to synchronize
# across threads and with or without locks
plexpy.logger.info('Adding %s to queue', seconds)
logger.info('Adding %s to queue', seconds)
self.queue.put(seconds)

View file

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
@ -13,11 +15,15 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
import os
import plexpy
import helpers
import logger
from plexpy import helpers
from plexpy import logger
def get_log_tail(window=20, parsed=True, log_type="server"):
@ -45,7 +51,7 @@ def get_log_tail(window=20, parsed=True, log_type="server"):
try:
log_time = i.split(' [')[0]
log_level = i.split('] ', 1)[1].split(' - ', 1)[0]
log_msg = unicode(i.split('] ', 1)[1].split(' - ', 1)[1], 'utf-8')
log_msg = str(i.split('] ', 1)[1].split(' - ', 1)[1], 'utf-8')
full_line = [log_time, log_level, log_msg]
clean_lines.append(full_line)
except:

View file

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
@ -13,6 +15,10 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
from past.builtins import basestring
from logutils.queue import QueueHandler, QueueListener
from logging import handlers
@ -27,9 +33,10 @@ import threading
import traceback
import plexpy
import helpers
from plexpy.helpers import is_public_ip
from plexpy.config import _BLACKLIST_KEYS, _WHITELIST_KEYS
# These settings are for file logging only
FILENAME = "tautulli.log"
FILENAME_API = "tautulli_api.log"
@ -54,7 +61,7 @@ def blacklist_config(config):
blacklist = set()
blacklist_keys = ['HOOK', 'APIKEY', 'KEY', 'PASSWORD', 'TOKEN']
for key, value in config.iteritems():
for key, value in config.items():
if isinstance(value, basestring) and len(value.strip()) > 5 and \
key.upper() not in _WHITELIST_KEYS and (key.upper() in blacklist_keys or
any(bk in key.upper() for bk in _BLACKLIST_KEYS)):
@ -113,14 +120,14 @@ class PublicIPFilter(logging.Filter):
# Currently only checking for ipv4 addresses
ipv4 = re.findall(r'[0-9]+(?:\.[0-9]+){3}(?!\d*-[a-z0-9]{6})', record.msg)
for ip in ipv4:
if helpers.is_public_ip(ip):
if is_public_ip(ip):
record.msg = record.msg.replace(ip, ip.partition('.')[0] + '.***.***.***')
args = []
for arg in record.args:
ipv4 = re.findall(r'[0-9]+(?:\.[0-9]+){3}(?!\d*-[a-z0-9]{6})', arg) if isinstance(arg, basestring) else []
for ip in ipv4:
if helpers.is_public_ip(ip):
if is_public_ip(ip):
arg = arg.replace(ip, ip.partition('.')[0] + '.***.***.***')
args.append(arg)
record.args = tuple(args)

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,12 +15,13 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
import time
import plexpy
import database
import helpers
import logger
from plexpy import database
from plexpy import logger
TEMP_DEVICE_TOKEN = None

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,6 +15,8 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
import os
import time
@ -20,9 +24,9 @@ from apscheduler.triggers.cron import CronTrigger
import email.utils
import plexpy
import database
import logger
import newsletters
from plexpy import database
from plexpy import logger
from plexpy import newsletters
NEWSLETTER_SCHED = None

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,6 +15,11 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import next
from builtins import str
from builtins import object
import arrow
from collections import OrderedDict
import json
@ -23,14 +30,14 @@ import os
import re
import plexpy
import common
import database
import helpers
import libraries
import logger
import newsletter_handler
import pmsconnect
from notifiers import send_notification, EMAIL
from plexpy import common
from plexpy import database
from plexpy import helpers
from plexpy import libraries
from plexpy import logger
from plexpy import newsletter_handler
from plexpy import pmsconnect
from plexpy.notifiers import send_notification, EMAIL
AGENT_IDS = {
@ -229,11 +236,11 @@ def set_newsletter_config(newsletter_id=None, agent_id=None, **kwargs):
email_config_prefix = 'newsletter_email_'
newsletter_config = {k[len(config_prefix):]: kwargs.pop(k)
for k in kwargs.keys() if k.startswith(config_prefix)}
for k in list(kwargs.keys()) if k.startswith(config_prefix)}
email_config = {k[len(email_config_prefix):]: kwargs.pop(k)
for k in kwargs.keys() if k.startswith(email_config_prefix)}
for k in list(kwargs.keys()) if k.startswith(email_config_prefix)}
for cfg, val in email_config.iteritems():
for cfg, val in email_config.items():
# Check for a password config keys and a blank password from the HTML form
if 'password' in cfg and val == ' ':
# Get the previous password so we don't overwrite it with a blank value
@ -418,7 +425,7 @@ class Newsletter(object):
return default
new_config = {}
for k, v in default.iteritems():
for k, v in default.items():
if isinstance(v, int):
new_config[k] = helpers.cast_to_int(config.get(k, v))
elif isinstance(v, list):
@ -602,50 +609,50 @@ class Newsletter(object):
return parameters
def build_text(self):
from notification_handler import CustomFormatter
from plexpy.notification_handler import CustomFormatter
custom_formatter = CustomFormatter()
try:
subject = custom_formatter.format(unicode(self.subject), **self.parameters)
subject = custom_formatter.format(str(self.subject), **self.parameters)
except LookupError as e:
logger.error("Tautulli Newsletter :: Unable to parse parameter %s in newsletter subject. Using fallback." % e)
subject = unicode(self._DEFAULT_SUBJECT).format(**self.parameters)
subject = str(self._DEFAULT_SUBJECT).format(**self.parameters)
except Exception as e:
logger.error("Tautulli Newsletter :: Unable to parse custom newsletter subject: %s. Using fallback." % e)
subject = unicode(self._DEFAULT_SUBJECT).format(**self.parameters)
subject = str(self._DEFAULT_SUBJECT).format(**self.parameters)
try:
body = custom_formatter.format(unicode(self.body), **self.parameters)
body = custom_formatter.format(str(self.body), **self.parameters)
except LookupError as e:
logger.error("Tautulli Newsletter :: Unable to parse parameter %s in newsletter body. Using fallback." % e)
body = unicode(self._DEFAULT_BODY).format(**self.parameters)
body = str(self._DEFAULT_BODY).format(**self.parameters)
except Exception as e:
logger.error("Tautulli Newsletter :: Unable to parse custom newsletter body: %s. Using fallback." % e)
body = unicode(self._DEFAULT_BODY).format(**self.parameters)
body = str(self._DEFAULT_BODY).format(**self.parameters)
try:
message = custom_formatter.format(unicode(self.message), **self.parameters)
message = custom_formatter.format(str(self.message), **self.parameters)
except LookupError as e:
logger.error("Tautulli Newsletter :: Unable to parse parameter %s in newsletter message. Using fallback." % e)
message = unicode(self._DEFAULT_MESSAGE).format(**self.parameters)
message = str(self._DEFAULT_MESSAGE).format(**self.parameters)
except Exception as e:
logger.error("Tautulli Newsletter :: Unable to parse custom newsletter message: %s. Using fallback." % e)
message = unicode(self._DEFAULT_MESSAGE).format(**self.parameters)
message = str(self._DEFAULT_MESSAGE).format(**self.parameters)
return subject, body, message
def build_filename(self):
from notification_handler import CustomFormatter
from plexpy.notification_handler import CustomFormatter
custom_formatter = CustomFormatter()
try:
filename = custom_formatter.format(unicode(self.filename), **self.parameters)
filename = custom_formatter.format(str(self.filename), **self.parameters)
except LookupError as e:
logger.error("Tautulli Newsletter :: Unable to parse parameter %s in newsletter filename. Using fallback." % e)
filename = unicode(self._DEFAULT_FILENAME).format(**self.parameters)
filename = str(self._DEFAULT_FILENAME).format(**self.parameters)
except Exception as e:
logger.error("Tautulli Newsletter :: Unable to parse custom newsletter subject: %s. Using fallback." % e)
filename = unicode(self._DEFAULT_FILENAME).format(**self.parameters)
filename = str(self._DEFAULT_FILENAME).format(**self.parameters)
return filename
@ -682,7 +689,7 @@ class RecentlyAdded(Newsletter):
_TEMPLATE = 'recently_added.html'
def _get_recently_added(self, media_type=None):
from notification_handler import format_group_index
from plexpy.notification_handler import format_group_index
pms_connect = pmsconnect.PmsConnect()
@ -798,7 +805,7 @@ class RecentlyAdded(Newsletter):
return recently_added
def retrieve_data(self):
from notification_handler import get_img_info, set_hash_image_info
from plexpy.notification_handler import get_img_info, set_hash_image_info
if not self.config['incl_libraries']:
logger.warn("Tautulli Newsletters :: Failed to retrieve %s newsletter data: no libraries selected." % self.NAME)

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -14,6 +16,17 @@
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import next
from builtins import map
from builtins import str
from builtins import range
from past.builtins import basestring
from past.utils import old_div
import arrow
import bleach
from collections import Counter, defaultdict
@ -31,19 +44,16 @@ import time
import musicbrainzngs
import plexpy
import activity_processor
import common
import database
import datafactory
import libraries
import logger
import helpers
import notifiers
import plextv
import pmsconnect
import request
import users
from newsletter_handler import notify as notify_newsletter
from plexpy import activity_processor
from plexpy import common
from plexpy import database
from plexpy import datafactory
from plexpy import logger
from plexpy import helpers
from plexpy import notifiers
from plexpy import pmsconnect
from plexpy import request
from plexpy.newsletter_handler import notify as notify_newsletter
def process_queue():
@ -254,7 +264,7 @@ def notify_custom_conditions(notifier_id=None, parameters=None):
# Cast the condition values to the correct type
try:
if parameter_type == 'str':
values = [unicode(v).lower() for v in values]
values = [str(v).lower() for v in values]
elif parameter_type == 'int':
values = [helpers.cast_to_int(v) for v in values]
@ -270,7 +280,7 @@ def notify_custom_conditions(notifier_id=None, parameters=None):
# Cast the parameter value to the correct type
try:
if parameter_type == 'str':
parameter_value = unicode(parameter_value).lower()
parameter_value = str(parameter_value).lower()
elif parameter_type == 'int':
parameter_value = helpers.cast_to_int(parameter_value)
@ -540,9 +550,9 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
transcode_decision = 'Direct Play'
if notify_action != 'on_play':
stream_duration = int((time.time() -
stream_duration = int(old_div((time.time() -
helpers.cast_to_int(session.get('started', 0)) -
helpers.cast_to_int(session.get('paused_counter', 0))) / 60)
helpers.cast_to_int(session.get('paused_counter', 0))), 60))
else:
stream_duration = 0
@ -1137,19 +1147,19 @@ def build_notify_text(subject='', body='', notify_action=None, parameters=None,
subject = str_formatter(subject)
except LookupError as e:
logger.error("Tautulli NotificationHandler :: Unable to parse parameter %s in notification subject. Using fallback." % e)
subject = unicode(default_subject).format(**parameters)
subject = str(default_subject).format(**parameters)
except Exception as e:
logger.error("Tautulli NotificationHandler :: Unable to parse custom notification subject: %s. Using fallback." % e)
subject = unicode(default_subject).format(**parameters)
subject = str(default_subject).format(**parameters)
try:
body = str_formatter(body)
except LookupError as e:
logger.error("Tautulli NotificationHandler :: Unable to parse parameter %s in notification body. Using fallback." % e)
body = unicode(default_body).format(**parameters)
body = str(default_body).format(**parameters)
except Exception as e:
logger.error("Tautulli NotificationHandler :: Unable to parse custom notification body: %s. Using fallback." % e)
body = unicode(default_body).format(**parameters)
body = str(default_body).format(**parameters)
return subject, body, script_args
@ -1165,7 +1175,7 @@ def strip_tag(data, agent_id=None):
'u': [],
'a': ['href'],
'font': ['color']}
data = bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
data = bleach.clean(data, tags=list(whitelist.keys()), attributes=whitelist, strip=True)
elif agent_id in (10, 14, 20):
# Don't remove tags for Email, Slack, and Discord
@ -1178,11 +1188,11 @@ def strip_tag(data, agent_id=None):
'code': [],
'pre': [],
'a': ['href']}
data = bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
data = bleach.clean(data, tags=list(whitelist.keys()), attributes=whitelist, strip=True)
else:
whitelist = {}
data = bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
data = bleach.clean(data, tags=list(whitelist.keys()), attributes=whitelist, strip=True)
# Resubstitute temporary tokens for < and > in parameter prefix and suffix
return data.replace('%temp_lt_token%', '<').replace('%temp_gt_token%', '>')
@ -1194,8 +1204,8 @@ def format_group_index(group_keys):
num = []
num00 = []
for k, g in groupby(enumerate(group_keys), lambda (i, x): i-x):
group = map(itemgetter(1), g)
for k, g in groupby(enumerate(group_keys), lambda i_x: i_x[0]-i_x[1]):
group = list(map(itemgetter(1), g))
g_min, g_max = min(group), max(group)
if g_min == g_max:
@ -1586,7 +1596,7 @@ def lookup_musicbrainz_info(musicbrainz_type=None, rating_key=None, artist=None,
def str_format(s, parameters):
custom_formatter = CustomFormatter()
if isinstance(s, basestring):
return custom_formatter.format(unicode(s), **parameters)
return custom_formatter.format(str(s), **parameters)
return s
@ -1602,11 +1612,11 @@ class CustomFormatter(Formatter):
elif conversion == 'r':
return repr(value)
elif conversion == 'u': # uppercase
return unicode(value).upper()
return str(value).upper()
elif conversion == 'l': # lowercase
return unicode(value).lower()
return str(value).lower()
elif conversion == 'c': # capitalize
return unicode(value).title()
return str(value).title()
else:
return value
@ -1616,7 +1626,7 @@ class CustomFormatter(Formatter):
match = re.match(pattern, format_spec)
if value and match:
groups = match.groupdict()
items = [x.strip() for x in unicode(value).split(',')]
items = [x.strip() for x in str(value).split(',')]
start = groups['start'] or None
end = groups['end'] or None
if start is not None:
@ -1666,7 +1676,7 @@ class CustomFormatter(Formatter):
if prefix or suffix:
real_format_string = '{' + real_format_string + '}'
_, field_name, format_spec, conversion, _, _ = self.parse(real_format_string).next()
_, field_name, format_spec, conversion, _, _ = next(self.parse(real_format_string))
yield literal_text, field_name, format_spec, conversion, prefix, suffix

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,6 +15,13 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import next
from builtins import str
from builtins import object
import base64
import bleach
import json
@ -28,8 +37,8 @@ import subprocess
import sys
import threading
import time
from urllib import urlencode
from urlparse import urlparse
from urllib.parse import urlencode
from urllib.parse import urlparse
import uuid
try:
@ -54,14 +63,14 @@ import twitter
import pynma
import plexpy
import common
import database
import helpers
import logger
import mobile_app
import pmsconnect
import request
import users
from plexpy import common
from plexpy import database
from plexpy import helpers
from plexpy import logger
from plexpy import mobile_app
from plexpy import pmsconnect
from plexpy import request
from plexpy import users
BROWSER_NOTIFIERS = {}
@ -438,7 +447,7 @@ def get_notifiers(notifier_id=None, notify_action=None):
% (', '.join(notify_actions), where), args=args)
for item in result:
item['active'] = int(any([item.pop(k) for k in item.keys() if k in notify_actions]))
item['active'] = int(any([item.pop(k) for k in list(item.keys()) if k in notify_actions]))
return result
@ -483,7 +492,7 @@ def get_notifier_config(notifier_id=None, mask_passwords=False):
notifier_actions = {}
notifier_text = {}
for k in result.keys():
for k in list(result.keys()):
if k in notify_actions:
subject = result.pop(k + '_subject')
body = result.pop(k + '_body')
@ -581,15 +590,15 @@ def set_notifier_config(notifier_id=None, agent_id=None, **kwargs):
config_prefix = agent['name'] + '_'
actions = {k: helpers.cast_to_int(kwargs.pop(k))
for k in kwargs.keys() if k in notify_actions}
for k in list(kwargs.keys()) if k in notify_actions}
subject_text = {k: kwargs.pop(k)
for k in kwargs.keys() if k.startswith(notify_actions) and k.endswith('_subject')}
for k in list(kwargs.keys()) if k.startswith(notify_actions) and k.endswith('_subject')}
body_text = {k: kwargs.pop(k)
for k in kwargs.keys() if k.startswith(notify_actions) and k.endswith('_body')}
for k in list(kwargs.keys()) if k.startswith(notify_actions) and k.endswith('_body')}
notifier_config = {k[len(config_prefix):]: kwargs.pop(k)
for k in kwargs.keys() if k.startswith(config_prefix)}
for k in list(kwargs.keys()) if k.startswith(config_prefix)}
for cfg, val in notifier_config.iteritems():
for cfg, val in notifier_config.items():
# Check for a password config keys and a blank password from the HTML form
if 'password' in cfg and val == ' ':
# Get the previous password so we don't overwrite it with a blank value
@ -793,7 +802,7 @@ class Notifier(object):
return default
new_config = {}
for k, v in default.iteritems():
for k, v in default.items():
if isinstance(v, int):
new_config[k] = helpers.cast_to_int(config.get(k, v))
elif isinstance(v, list):
@ -1404,9 +1413,9 @@ class EMAIL(Notifier):
user_emails_cc.update(emails)
user_emails_bcc.update(emails)
user_emails_to = [{'value': k, 'text': v} for k, v in user_emails_to.iteritems()]
user_emails_cc = [{'value': k, 'text': v} for k, v in user_emails_cc.iteritems()]
user_emails_bcc = [{'value': k, 'text': v} for k, v in user_emails_bcc.iteritems()]
user_emails_to = [{'value': k, 'text': v} for k, v in user_emails_to.items()]
user_emails_cc = [{'value': k, 'text': v} for k, v in user_emails_cc.items()]
user_emails_bcc = [{'value': k, 'text': v} for k, v in user_emails_bcc.items()]
return user_emails_to, user_emails_cc, user_emails_bcc
@ -2019,7 +2028,7 @@ class IFTTT(Notifier):
}
def agent_notify(self, subject='', body='', action='', **kwargs):
event = unicode(self.config['event']).format(action=action)
event = str(self.config['event']).format(action=action)
data = {'value1': subject.encode('utf-8'),
'value2': body.encode('utf-8')}
@ -3043,7 +3052,7 @@ class SCRIPTS(Notifier):
for root, dirs, files in os.walk(scriptdir):
for f in files:
name, ext = os.path.splitext(f)
if ext in self.script_exts.keys():
if ext in list(self.script_exts.keys()):
rfp = os.path.join(os.path.relpath(root, scriptdir), f)
fp = os.path.join(root, f)
scripts[fp] = rfp
@ -3187,7 +3196,7 @@ class SCRIPTS(Notifier):
def _return_config_options(self):
config_option = [{'label': 'Supported File Types',
'description': '<span class="inline-pre">' + \
', '.join(self.script_exts.keys()) + '</span>',
', '.join(list(self.script_exts.keys())) + '</span>',
'input_type': 'help'
},
{'label': 'Script Folder',
@ -3947,7 +3956,7 @@ def upgrade_config_to_db():
# Update the new config with the old config values
notifier_config = {}
for conf, val in notifier_default_config.iteritems():
for conf, val in notifier_default_config.items():
c_key = agent_config_key + '_' + config_key_overrides.get(agent, {}).get(conf, conf)
notifier_config[agent + '_' + conf] = agent_config.get(c_key, val)
@ -3964,15 +3973,15 @@ def upgrade_config_to_db():
# Reverse the dict to {script: [actions]}
script_actions = {}
for k, v in action_scripts.items():
for k, v in list(action_scripts.items()):
if v: script_actions.setdefault(v, set()).add(k)
# Add a new script notifier for each script if the action was enabled
for script, actions in script_actions.items():
for script, actions in list(script_actions.items()):
if any(agent_actions[a] for a in actions):
temp_config = notifier_config
temp_config.update({a: 0 for a in agent_actions.keys()})
temp_config.update({a + '_subject': '' for a in agent_actions.keys()})
temp_config.update({a: 0 for a in list(agent_actions.keys())})
temp_config.update({a + '_subject': '' for a in list(agent_actions.keys())})
for a in actions:
if agent_actions[a]:
temp_config[a] = agent_actions[a]

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,17 +15,20 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
import arrow
import sqlite3
from xml.dom import minidom
import plexpy
import activity_pinger
import activity_processor
import database
import helpers
import logger
import users
from plexpy import activity_pinger
from plexpy import activity_processor
from plexpy import database
from plexpy import helpers
from plexpy import logger
from plexpy import users
def extract_plexivity_xml(xml=None):

View file

@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
@ -16,17 +15,22 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import next
from builtins import str
from builtins import object
import base64
import json
import plexpy
import common
import helpers
import http_handler
import logger
import users
import pmsconnect
import session
from plexpy import common
from plexpy import helpers
from plexpy import http_handler
from plexpy import logger
from plexpy import users
from plexpy import pmsconnect
from plexpy import session
def get_server_resources(return_presence=False, return_server=False, **kwargs):

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,16 +15,19 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
import sqlite3
from xml.dom import minidom
import plexpy
import activity_pinger
import activity_processor
import database
import helpers
import logger
import users
from plexpy import activity_pinger
from plexpy import activity_processor
from plexpy import database
from plexpy import helpers
from plexpy import logger
from plexpy import users
def extract_plexwatch_xml(xml=None):

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,20 +15,27 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import next
from builtins import str
from builtins import object
import json
import os
import time
import urllib
import urllib.request, urllib.parse, urllib.error
import plexpy
import activity_processor
import common
import helpers
import http_handler
import logger
import plextv
import session
import users
from plexpy import activity_processor
from plexpy import common
from plexpy import helpers
from plexpy import http_handler
from plexpy import logger
from plexpy import plextv
from plexpy import session
from plexpy import users
def get_server_friendly_name():
@ -101,7 +110,7 @@ class PmsConnect(object):
Output: array
"""
uri = '/status/sessions/terminate?sessionId=%s&reason=%s' % (session_id, urllib.quote_plus(reason))
uri = '/status/sessions/terminate?sessionId=%s&reason=%s' % (session_id, urllib.parse.quote_plus(reason))
request = self.request_handler.make_request(uri=uri,
request_type='GET',
output_format=output_format)
@ -352,7 +361,7 @@ class PmsConnect(object):
Output: array
"""
uri = '/hubs/search?query=' + urllib.quote(query.encode('utf8')) + '&limit=' + limit + '&includeCollections=1'
uri = '/hubs/search?query=' + urllib.parse.quote(query.encode('utf8')) + '&limit=' + limit + '&includeCollections=1'
request = self.request_handler.make_request(uri=uri,
request_type='GET',
output_format=output_format)
@ -726,7 +735,7 @@ class PmsConnect(object):
# Workaround for for duration sometimes reported in minutes for a show
duration = helpers.get_xml_attr(metadata_main, 'duration')
if duration.isdigit() and int(duration) < 1000:
duration = unicode(int(duration) * 60 * 1000)
duration = str(int(duration) * 60 * 1000)
metadata = {'media_type': metadata_type,
'section_id': section_id,
@ -1534,7 +1543,7 @@ class PmsConnect(object):
if not platform and helpers.get_xml_attr(player_info, 'product') == 'DLNA':
platform = 'DLNA'
platform_name = next((v for k, v in common.PLATFORM_NAMES.iteritems() if k in platform.lower()), 'default')
platform_name = next((v for k, v in common.PLATFORM_NAMES.items() if k in platform.lower()), 'default')
player_details = {'ip_address': helpers.get_xml_attr(player_info, 'address').split('::ffff:')[-1],
'ip_address_public': helpers.get_xml_attr(player_info, 'remotePublicAddress').split('::ffff:')[-1],
@ -2254,7 +2263,7 @@ class PmsConnect(object):
hub_identifier = helpers.get_xml_attr(h, 'hubIdentifier')
if size == '0' or not hub_identifier.startswith('collection.related') or \
media_type not in children_results_list.keys():
media_type not in list(children_results_list.keys()):
continue
result_data = []
@ -2280,7 +2289,7 @@ class PmsConnect(object):
}
children_results_list[media_type].append(children_output)
output = {'results_count': sum(len(s) for s in children_results_list.items()),
output = {'results_count': sum(len(s) for s in list(children_results_list.items())),
'results_list': children_results_list,
}
@ -2648,9 +2657,9 @@ class PmsConnect(object):
img = '{}/{}'.format(img.rstrip('/'), int(time.time()))
if clip:
params = {'url': '%s&%s' % (img, urllib.urlencode({'X-Plex-Token': self.token}))}
params = {'url': '%s&%s' % (img, urllib.parse.urlencode({'X-Plex-Token': self.token}))}
else:
params = {'url': 'http://127.0.0.1:32400%s?%s' % (img, urllib.urlencode({'X-Plex-Token': self.token}))}
params = {'url': 'http://127.0.0.1:32400%s?%s' % (img, urllib.parse.urlencode({'X-Plex-Token': self.token}))}
params['width'] = width
params['height'] = height
@ -2663,7 +2672,7 @@ class PmsConnect(object):
if blur:
params['blur'] = blur
uri = '/photo/:/transcode?%s' % urllib.urlencode(params)
uri = '/photo/:/transcode?%s' % urllib.parse.urlencode(params)
result = self.request_handler.make_request(uri=uri,
request_type='GET',
return_type=True)
@ -2705,7 +2714,7 @@ class PmsConnect(object):
for h in hubs:
if helpers.get_xml_attr(h, 'size') == '0' or \
helpers.get_xml_attr(h, 'type') not in search_results_list.keys():
helpers.get_xml_attr(h, 'type') not in list(search_results_list.keys()):
continue
if h.getElementsByTagName('Video'):
@ -2737,7 +2746,7 @@ class PmsConnect(object):
metadata = self.get_metadata_details(rating_key=rating_key)
search_results_list[metadata['media_type']].append(metadata)
output = {'results_count': sum(len(s) for s in search_results_list.values()),
output = {'results_count': sum(len(s) for s in list(search_results_list.values())),
'results_list': search_results_list
}

View file

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
@ -13,6 +15,9 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
from bs4 import BeautifulSoup
from xml.dom import minidom
@ -21,13 +26,13 @@ import collections
import requests
import plexpy
import plexpy.lock
import logger
from plexpy import lock
from plexpy import logger
# Dictionary with last request times, for rate limiting.
last_requests = collections.defaultdict(int)
fake_lock = plexpy.lock.FakeLock()
fake_lock = lock.FakeLock()
def request_response(url, method="get", auto_raise=True,
@ -319,7 +324,7 @@ def server_message(response, return_msg=False):
if return_msg:
try:
return unicode(message, 'UTF-8')
return str(message, 'UTF-8')
except:
return message

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,10 +15,13 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from builtins import str
import cherrypy
import common
import users
from plexpy import common
from plexpy import users
def get_session_info():
@ -216,14 +221,14 @@ def mask_session_info(list_of_dicts, mask_metadata=True):
for d in list_of_dicts:
if session_user_id and not (str(d.get('user_id')) == session_user_id or d.get('user') == session_user):
for k, v in keys_to_mask.iteritems():
for k, v in keys_to_mask.items():
if k in d: d[k] = keys_to_mask[k]
if not mask_metadata:
continue
if str(d.get('section_id','')) not in session_library_ids:
for k, v in metadata_to_mask.iteritems():
for k, v in metadata_to_mask.items():
if k in d: d[k] = metadata_to_mask[k]
continue
@ -247,7 +252,7 @@ def mask_session_info(list_of_dicts, mask_metadata=True):
if d_content_rating in f_content_rating or set(d_labels).intersection(set(f_labels)):
continue
for k, v in metadata_to_mask.iteritems():
for k, v in metadata_to_mask.items():
if k in d: d[k] = metadata_to_mask[k]
return list_of_dicts

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,18 +15,25 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import next
from builtins import str
from builtins import object
import httpagentparser
import time
import plexpy
import common
import database
import datatables
import helpers
import libraries
import logger
import plextv
import session
from plexpy import common
from plexpy import database
from plexpy import datatables
from plexpy import helpers
from plexpy import libraries
from plexpy import logger
from plexpy import plextv
from plexpy import session
def refresh_users():
@ -509,7 +518,7 @@ class Users(object):
for item in result:
# Rename Mystery platform names
platform = common.PLATFORM_NAME_OVERRIDES.get(item['platform'], item['platform'])
platform_name = next((v for k, v in common.PLATFORM_NAMES.iteritems() if k in platform.lower()), 'default')
platform_name = next((v for k, v in common.PLATFORM_NAMES.items() if k in platform.lower()), 'default')
row = {'player_name': item['player'],
'platform': platform,
@ -757,7 +766,7 @@ class Users(object):
return None
def get_filters(self, user_id=None):
import urlparse
import urllib.parse
if not user_id:
return {}
@ -772,12 +781,12 @@ class Users(object):
result = {}
filters_list = {}
for k, v in result.iteritems():
for k, v in result.items():
filters = {}
for f in v.split('|'):
if 'contentRating=' in f or 'label=' in f:
filters.update(dict(urlparse.parse_qsl(f)))
filters.update(dict(urllib.parse.parse_qsl(f)))
filters['content_rating'] = tuple(f for f in filters.pop('contentRating', '').split(',') if f)
filters['labels'] = tuple(f for f in filters.pop('label', '').split(',') if f)

View file

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
@ -13,6 +15,12 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import division
from __future__ import absolute_import
from builtins import next
from builtins import str
from past.utils import old_div
import os
import platform
import re
@ -20,9 +28,9 @@ import subprocess
import tarfile
import plexpy
import common
import logger
import request
from plexpy import common
from plexpy import logger
from plexpy import request
def runGit(args):
@ -44,7 +52,7 @@ def runGit(args):
logger.debug('Trying to execute: "' + cmd + '" with shell in ' + plexpy.PROG_DIR)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=plexpy.PROG_DIR)
output, err = p.communicate()
output = output.strip()
output = output.strip().decode()
logger.debug('Git output: ' + output)
except OSError:
@ -372,7 +380,7 @@ def read_changelog(latest_only=False, since_prev_release=False):
output[-1] += '<h' + header_level + '>' + header_text + '</h' + header_level + '>'
elif line_list_match:
line_level = len(line_list_match.group(1)) / 2
line_level = old_div(len(line_list_match.group(1)), 2)
line_text = line_list_match.group(2)
if line_level > prev_level:

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -15,6 +17,11 @@
# Mostly borrowed from https://github.com/trakt/Plex-Trakt-Scrobbler
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import str
import json
import threading
import time
@ -22,11 +29,12 @@ import time
import websocket
import plexpy
import activity_handler
import activity_pinger
import activity_processor
import database
import logger
from plexpy import activity_handler
from plexpy import activity_pinger
from plexpy import activity_processor
from plexpy import database
from plexpy import logger
name = 'websocket'
opcode_data = (websocket.ABNF.OPCODE_TEXT, websocket.ABNF.OPCODE_BINARY)

View file

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
@ -18,15 +20,21 @@
# Form based authentication for CherryPy. Requires the
# Session tool to be loaded.
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import str
from builtins import object
from datetime import datetime, timedelta
from urllib import quote, unquote
from urllib.parse import quote, unquote
import cherrypy
from hashing_passwords import check_hash
import jwt
import plexpy
import logger
from plexpy import logger
from plexpy.database import MonitorDatabase
from plexpy.users import Users, refresh_users
from plexpy.plextv import PlexTV

View file

@ -1,4 +1,6 @@
# This file is part of Tautulli.
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -13,11 +15,19 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import next
from builtins import str
from past.builtins import basestring
from builtins import object
import json
import os
import shutil
import threading
import urllib
import urllib.request, urllib.parse, urllib.error
import cherrypy
from cherrypy.lib.static import serve_file, serve_download
@ -30,30 +40,30 @@ from mako import exceptions
import websocket
import plexpy
import activity_pinger
import common
import config
import database
import datafactory
import graphs
import helpers
import http_handler
import libraries
import log_reader
import logger
import newsletter_handler
import newsletters
import mobile_app
import notification_handler
import notifiers
import plextv
import plexivity_import
import plexwatch_import
import pmsconnect
import users
import versioncheck
import web_socket
import webstart
from plexpy import activity_pinger
from plexpy import common
from plexpy import config
from plexpy import database
from plexpy import datafactory
from plexpy import graphs
from plexpy import helpers
from plexpy import http_handler
from plexpy import libraries
from plexpy import log_reader
from plexpy import logger
from plexpy import newsletter_handler
from plexpy import newsletters
from plexpy import mobile_app
from plexpy import notification_handler
from plexpy import notifiers
from plexpy import plextv
from plexpy import plexivity_import
from plexpy import plexwatch_import
from plexpy import pmsconnect
from plexpy import users
from plexpy import versioncheck
from plexpy import web_socket
from plexpy import webstart
from plexpy.api2 import API2
from plexpy.helpers import checked, addtoapi, get_ip, create_https_certificates, build_datatables_json, sanitize_out
from plexpy.session import get_session_info, get_session_user_id, allow_session_user, allow_session_library
@ -288,7 +298,7 @@ class WebInterface(object):
if '{machine_id}' in endpoint:
endpoint = endpoint.format(machine_id=plexpy.CONFIG.PMS_IDENTIFIER)
return base_url + endpoint + '?' + urllib.urlencode(kwargs)
return base_url + endpoint + '?' + urllib.parse.urlencode(kwargs)
@cherrypy.expose
@requireAuth()
@ -2364,13 +2374,13 @@ class WebInterface(object):
try:
temp_loglevel_and_time = l.split(' - ', 1)
loglvl = temp_loglevel_and_time[1].split(' ::', 1)[0].strip()
msg = helpers.sanitize(unicode(l.split(' : ', 1)[1].replace('\n', ''), 'utf-8'))
msg = helpers.sanitize(str(l.split(' : ', 1)[1].replace('\n', ''), 'utf-8'))
fa([temp_loglevel_and_time[0], loglvl, msg])
except IndexError:
# Add traceback message to previous msg.
tl = (len(filt) - 1)
n = len(l) - len(l.lstrip(' '))
ll = '&nbsp;' * (2 * n) + helpers.sanitize(unicode(l[n:], 'utf-8'))
ll = '&nbsp;' * (2 * n) + helpers.sanitize(str(l[n:], 'utf-8'))
filt[tl][2] += '<br>' + ll
continue
@ -2918,14 +2928,14 @@ class WebInterface(object):
# Remove config with 'hsec-' prefix and change home_sections to list
if kwargs.get('home_sections'):
for k in kwargs.keys():
for k in list(kwargs.keys()):
if k.startswith('hsec-'):
del kwargs[k]
kwargs['home_sections'] = kwargs['home_sections'].split(',')
# Remove config with 'hscard-' prefix and change home_stats_cards to list
if kwargs.get('home_stats_cards'):
for k in kwargs.keys():
for k in list(kwargs.keys()):
if k.startswith('hscard-'):
del kwargs[k]
kwargs['home_stats_cards'] = kwargs['home_stats_cards'].split(',')
@ -2935,7 +2945,7 @@ class WebInterface(object):
# Remove config with 'hlcard-' prefix and change home_library_cards to list
if kwargs.get('home_library_cards'):
for k in kwargs.keys():
for k in list(kwargs.keys()):
if k.startswith('hlcard-'):
del kwargs[k]
kwargs['home_library_cards'] = kwargs['home_library_cards'].split(',')

View file

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
@ -13,14 +15,21 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import str
from builtins import object
import os
import sys
from urllib import urlencode
from urllib.parse import urlencode
import cherrypy
import plexpy
import cherrypy
import logger
import webauth
from plexpy import logger
from plexpy import webauth
from plexpy.helpers import create_https_certificates
from plexpy.webserve import WebInterface