From 5de2cf85c380e09bb2614dbaf952dd61ff9f951c Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Thu, 9 May 2024 20:49:06 -0700 Subject: [PATCH 001/141] Workaround users remaining in friends list without shared libraries --- plexpy/users.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plexpy/users.py b/plexpy/users.py index 974d30cd..67293800 100644 --- a/plexpy/users.py +++ b/plexpy/users.py @@ -63,13 +63,15 @@ def refresh_users(): new_users = [] for item in result: - user_ids.append(helpers.cast_to_int(item['user_id'])) - if item.get('shared_libraries'): item['shared_libraries'] = ';'.join(item['shared_libraries']) + # Only add user if libraries are shared + user_ids.add(helpers.cast_to_int(item['user_id'])) elif item.get('server_token'): libs = libraries.Libraries().get_sections() item['shared_libraries'] = ';'.join([str(l['section_id']) for l in libs]) + # Only add user if libraries are shared + user_ids.add(helpers.cast_to_int(item['user_id'])) keys_dict = {"user_id": item.pop('user_id')} @@ -101,7 +103,7 @@ def refresh_users(): query = "UPDATE users SET is_active = 0 WHERE user_id NOT IN ({})".format(", ".join(["?"] * len(user_ids))) monitor_db.action(query=query, args=user_ids) - # Add new users to loger username filter + # Add new users to logger username filter logger.filter_usernames(new_users) logger.info("Tautulli Users :: Users list refreshed.") From 65905a6647de6a52a87a357c2f144d5ed567783f Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Thu, 9 May 2024 21:52:39 -0700 Subject: [PATCH 002/141] Fix escaping regex string --- plexpy/helpers.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plexpy/helpers.py b/plexpy/helpers.py index c2594412..b2be62e2 100644 --- a/plexpy/helpers.py +++ b/plexpy/helpers.py @@ -345,7 +345,7 @@ def bytes_to_mb(bytes): def mb_to_bytes(mb_str): - result = re.search('^(\d+(?:\.\d+)?)\s?(?:mb)?', mb_str, flags=re.I) + result = re.search(r'^(\d+(?:\.\d+)?)\s?(?:mb)?', mb_str, flags=re.I) if result: return int(float(result.group(1)) * 1048576) @@ -395,9 +395,9 @@ def replace_all(text, dic, normalize=False): def replace_illegal_chars(string, type="file"): if type == "file": - string = re.sub('[\?"*:|<>/]', '_', string) + string = re.sub(r'[\?"*:|<>/]', '_', string) if type == "folder": - string = re.sub('[:\?<>"|]', '_', string) + string = re.sub(r'[:\?<>"|]', '_', string) return string @@ -405,14 +405,14 @@ def replace_illegal_chars(string, type="file"): def cleanName(string): pass1 = latinToAscii(string).lower() - out_string = re.sub('[\.\-\/\!\@\#\$\%\^\&\*\(\)\+\-\"\'\,\;\:\[\]\{\}\<\>\=\_]', '', pass1).encode('utf-8') + out_string = re.sub(r'[\.\-\/\!\@\#\$\%\^\&\*\(\)\+\-\"\'\,\;\:\[\]\{\}\<\>\=\_]', '', pass1).encode('utf-8') return out_string def cleanTitle(title): - title = re.sub('[\.\-\/\_]', ' ', title).lower() + title = re.sub(r'[\.\-\/\_]', ' ', title).lower() # Strip out extra whitespace title = ' '.join(title.split()) From dcec1f6f5f661164ef39856cc01f9b91b1b9158a Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Thu, 9 May 2024 21:55:26 -0700 Subject: [PATCH 003/141] Update snapcraft git data folder --- snap/snapcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 612b189d..6f76e8cc 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -38,7 +38,7 @@ parts: - python3-pkg-resources override-pull: | craftctl default - git config --global --add safe.directory /root/parts/tautulli/src + git config --global --add safe.directory /data/parts/tautulli/src TAG_FULL=$(git describe --tag) TAG=$(echo $TAG_FULL | grep -oP '(v\d+\.\d+\.\d+(?>-beta)?)') BRANCH=$(git rev-parse --abbrev-ref HEAD) From de3393d62b3bef3c83a1f368ab12bc77b0114a87 Mon Sep 17 00:00:00 2001 From: Tom Niget Date: Fri, 10 May 2024 07:18:08 +0200 Subject: [PATCH 004/141] Remove Python 2 handling code (#2098) * Remove Python 2 update modal * Remove Python 2 handling code * Remove backports dependencies * Remove uses of future and __future__ * Fix import * Remove requirements * Update lib folder * Clean up imports and blank lines --------- Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> --- Tautulli.py | 1 - data/interfaces/default/index.html | 34 - .../default/newsletter_preview.html | 2 +- lib/backports/__init__.py | 2 +- lib/backports/csv.py | 979 ------ lib/backports/functools_lru_cache.py | 243 -- lib/backports/tarfile/__init__.py | 2902 +++++++++++++++++ lib/backports/tarfile/__main__.py | 5 + .../tarfile}/compat/__init__.py | 0 lib/backports/tarfile/compat/py38.py | 24 + lib/future/__init__.py | 19 +- lib/future/backports/datetime.py | 2 +- .../backports/email/_header_value_parser.py | 2 +- lib/future/backports/email/parser.py | 4 +- lib/future/backports/http/cookiejar.py | 2 +- lib/future/backports/test/support.py | 32 - lib/future/backports/xmlrpc/client.py | 9 +- lib/future/builtins/__init__.py | 2 +- lib/future/moves/_dummy_thread.py | 11 +- lib/future/moves/multiprocessing.py | 7 + lib/future/moves/test/support.py | 9 + lib/future/standard_library/__init__.py | 14 +- lib/future/types/newint.py | 8 +- lib/future/types/newrange.py | 2 +- lib/inflect/__init__.py | 313 +- lib/inflect/compat/pydantic.py | 19 - lib/inflect/compat/pydantic1.py | 8 - lib/jaraco/classes/ancestry.py | 68 - lib/jaraco/classes/meta.py | 66 - lib/jaraco/classes/properties.py | 170 - lib/jaraco/collections/__init__.py | 56 +- lib/jaraco/context.py | 137 +- lib/jaraco/functools/__init__.pyi | 3 - lib/libfuturize/fixer_util.py | 12 +- lib/libfuturize/fixes/fix_metaclass.py | 4 +- lib/libpasteurize/fixes/fix_imports.py | 1 + lib/libpasteurize/fixes/fix_unpacking.py | 8 +- lib/past/__init__.py | 4 +- lib/past/builtins/misc.py | 9 +- lib/past/translation/__init__.py | 258 +- lib/typeguard/__init__.py | 48 + lib/typeguard/_checkers.py | 910 ++++++ lib/typeguard/_config.py | 108 + lib/typeguard/_decorators.py | 235 ++ lib/typeguard/_exceptions.py | 42 + lib/typeguard/_functions.py | 308 ++ lib/typeguard/_importhook.py | 213 ++ lib/typeguard/_memo.py | 48 + lib/typeguard/_pytest_plugin.py | 126 + lib/typeguard/_suppression.py | 86 + lib/typeguard/_transformer.py | 1229 +++++++ lib/typeguard/_union_transformer.py | 55 + lib/typeguard/_utils.py | 163 + lib/typeguard/py.typed | 0 lib/typing_extensions.py | 203 +- plexpy/__init__.py | 82 +- plexpy/activity_handler.py | 27 +- plexpy/activity_pinger.py | 34 +- plexpy/activity_processor.py | 24 +- plexpy/api2.py | 46 +- plexpy/classes.py | 75 - plexpy/common.py | 8 +- plexpy/config.py | 12 +- plexpy/database.py | 12 +- plexpy/datafactory.py | 34 +- plexpy/datatables.py | 14 +- plexpy/exceptions.py | 2 - plexpy/exporter.py | 25 +- plexpy/graphs.py | 27 +- plexpy/helpers.py | 34 +- plexpy/http_handler.py | 14 +- plexpy/libraries.py | 38 +- plexpy/lock.py | 10 +- plexpy/log_reader.py | 9 +- plexpy/logger.py | 12 +- plexpy/macos.py | 11 +- plexpy/mobile_app.py | 15 +- plexpy/newsletter_handler.py | 16 +- plexpy/newsletters.py | 38 +- plexpy/notification_handler.py | 61 +- plexpy/notifiers.py | 53 +- plexpy/plex.py | 9 - plexpy/plexivity_import.py | 24 +- plexpy/plextv.py | 33 +- plexpy/plexwatch_import.py | 21 +- plexpy/pmsconnect.py | 36 +- plexpy/request.py | 15 +- plexpy/session.py | 11 +- plexpy/users.py | 33 +- plexpy/version.py | 2 - plexpy/versioncheck.py | 26 +- plexpy/web_socket.py | 20 +- plexpy/webauth.py | 21 +- plexpy/webserve.py | 119 +- plexpy/webstart.py | 14 +- plexpy/windows.py | 12 +- requirements.txt | 6 +- 97 files changed, 7443 insertions(+), 2917 deletions(-) delete mode 100644 lib/backports/csv.py delete mode 100644 lib/backports/functools_lru_cache.py create mode 100644 lib/backports/tarfile/__init__.py create mode 100644 lib/backports/tarfile/__main__.py rename lib/{inflect => backports/tarfile}/compat/__init__.py (100%) create mode 100644 lib/backports/tarfile/compat/py38.py create mode 100644 lib/future/moves/multiprocessing.py delete mode 100644 lib/inflect/compat/pydantic.py delete mode 100644 lib/inflect/compat/pydantic1.py delete mode 100644 lib/jaraco/classes/ancestry.py delete mode 100644 lib/jaraco/classes/meta.py delete mode 100644 lib/jaraco/classes/properties.py create mode 100644 lib/typeguard/__init__.py create mode 100644 lib/typeguard/_checkers.py create mode 100644 lib/typeguard/_config.py create mode 100644 lib/typeguard/_decorators.py create mode 100644 lib/typeguard/_exceptions.py create mode 100644 lib/typeguard/_functions.py create mode 100644 lib/typeguard/_importhook.py create mode 100644 lib/typeguard/_memo.py create mode 100644 lib/typeguard/_pytest_plugin.py create mode 100644 lib/typeguard/_suppression.py create mode 100644 lib/typeguard/_transformer.py create mode 100644 lib/typeguard/_union_transformer.py create mode 100644 lib/typeguard/_utils.py create mode 100644 lib/typeguard/py.typed delete mode 100644 plexpy/classes.py diff --git a/Tautulli.py b/Tautulli.py index 04a6778e..8616df81 100755 --- a/Tautulli.py +++ b/Tautulli.py @@ -23,7 +23,6 @@ import sys # Ensure lib added to path, before any other imports sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'lib')) -from future.builtins import str import argparse import datetime diff --git a/data/interfaces/default/index.html b/data/interfaces/default/index.html index 4a74b2e4..6e4818c7 100644 --- a/data/interfaces/default/index.html +++ b/data/interfaces/default/index.html @@ -212,28 +212,6 @@ -<% from plexpy.helpers import anon_url %> - % endif -
- -

Check this if your Plex Server is not on the same local network as Tautulli.

-
@@ -2597,7 +2589,6 @@ $(document).ready(function() { return '
' + @@ -2611,7 +2602,6 @@ $(document).ready(function() { return '
' + @@ -2634,7 +2624,6 @@ $(document).ready(function() { var identifier = $(pms_ip_selected).data('identifier'); var ip = $(pms_ip_selected).data('ip'); var port = $(pms_ip_selected).data('port'); - var local = $(pms_ip_selected).data('local'); var ssl = $(pms_ip_selected).data('ssl'); var is_cloud = $(pms_ip_selected).data('is_cloud'); var value = $(pms_ip_selected).data('value'); @@ -2642,8 +2631,6 @@ $(document).ready(function() { $("#pms_identifier").val(identifier !== 'undefined' ? identifier : ''); $('#pms_ip').val(ip !== 'undefined' ? ip : value); $('#pms_port').val(port !== 'undefined' ? port : 32400); - $('#pms_is_remote_checkbox').prop('checked', (local !== 'undefined' && local === 0)); - $('#pms_is_remote').val(local !== 'undefined' && local === 0 ? 1 : 0); $('#pms_ssl_checkbox').prop('checked', (ssl !== 'undefined' && ssl === 1)); $('#pms_ssl').val(ssl !== 'undefined' && ssl === 1 ? 1 : 0); $('#pms_is_cloud').val(is_cloud !== 'undefined' && is_cloud === true ? 1 : 0); @@ -2681,7 +2668,6 @@ $(document).ready(function() { var pms_port = $("#pms_port").val(); var pms_identifier = $("#pms_identifier").val(); var pms_ssl = $("#pms_ssl").val(); - var pms_is_remote = $("#pms_is_remote").val(); var pms_url_manual = $("#pms_url_manual").is(':checked') ? 1 : 0; if (($("#pms_ip").val() !== '') || ($("#pms_port").val() !== '')) { @@ -2693,7 +2679,6 @@ $(document).ready(function() { hostname: pms_ip, port: pms_port, ssl: pms_ssl, - remote: pms_is_remote, manual: pms_url_manual, get_url: true, test_websocket: true diff --git a/data/interfaces/default/welcome.html b/data/interfaces/default/welcome.html index 39fc19b4..e3b4bc56 100644 --- a/data/interfaces/default/welcome.html +++ b/data/interfaces/default/welcome.html @@ -135,7 +135,6 @@ data-identifier="${config['pms_identifier']}" data-ip="${config['pms_ip']}" data-port="${config['pms_port']}" - data-local="${int(not int(config['pms_is_remote']))}" data-ssl="${config['pms_ssl']}" data-is_cloud="${config['pms_is_cloud']}" data-label="${config['pms_name'] or 'Local'}" @@ -159,14 +158,6 @@
-
-
- -
-
@@ -391,7 +382,6 @@ $(document).ready(function() { return '
' + @@ -405,7 +395,6 @@ $(document).ready(function() { return '
' + @@ -428,7 +417,6 @@ $(document).ready(function() { var identifier = $(pms_ip_selected).data('identifier'); var ip = $(pms_ip_selected).data('ip'); var port = $(pms_ip_selected).data('port'); - var local = $(pms_ip_selected).data('local'); var ssl = $(pms_ip_selected).data('ssl'); var is_cloud = $(pms_ip_selected).data('is_cloud'); var value = $(pms_ip_selected).data('value'); @@ -439,19 +427,15 @@ $(document).ready(function() { $("#pms_identifier").val(identifier !== 'undefined' ? identifier : ''); $('#pms_ip').val(ip !== 'undefined' ? ip : value); $('#pms_port').val(port !== 'undefined' ? port : 32400); - $('#pms_is_remote_checkbox').prop('checked', (local !== 'undefined' && local === 0)); - $('#pms_is_remote').val(local !== 'undefined' && local === 0 ? 1 : 0); $('#pms_ssl_checkbox').prop('checked', (ssl !== 'undefined' && ssl === 1)); $('#pms_ssl').val(ssl !== 'undefined' && ssl === 1 ? 1 : 0); $('#pms_is_cloud').val(is_cloud !== 'undefined' && is_cloud === true ? 1 : 0); if (is_cloud === true) { $('#pms_port').prop('readonly', true); - $('#pms_is_remote_checkbox').prop('disabled', true); $('#pms_ssl_checkbox').prop('disabled', true); } else { $('#pms_port').prop('readonly', false); - $('#pms_is_remote_checkbox').prop('disabled', false); $('#pms_ssl_checkbox').prop('disabled', false); } }, @@ -488,7 +472,6 @@ $(document).ready(function() { var pms_port = $("#pms_port").val().trim(); var pms_identifier = $("#pms_identifier").val(); var pms_ssl = $("#pms_ssl").val(); - var pms_is_remote = $("#pms_is_remote").val(); if ((pms_ip !== '') || (pms_port !== '')) { $("#pms-verify-status").html('  Verifying server...'); $('#pms-verify-status').fadeIn('fast'); @@ -498,8 +481,7 @@ $(document).ready(function() { hostname: pms_ip, port: pms_port, identifier: pms_identifier, - ssl: pms_ssl, - remote: pms_is_remote + ssl: pms_ssl }, cache: true, async: true, diff --git a/plexpy/plextv.py b/plexpy/plextv.py index d45ce785..eed9d50e 100644 --- a/plexpy/plextv.py +++ b/plexpy/plextv.py @@ -39,7 +39,6 @@ def get_server_resources(return_presence=False, return_server=False, return_info 'pms_ip': plexpy.CONFIG.PMS_IP, 'pms_port': plexpy.CONFIG.PMS_PORT, 'pms_ssl': plexpy.CONFIG.PMS_SSL, - 'pms_is_remote': plexpy.CONFIG.PMS_IS_REMOTE, 'pms_is_cloud': plexpy.CONFIG.PMS_IS_CLOUD, 'pms_url': plexpy.CONFIG.PMS_URL, 'pms_url_manual': plexpy.CONFIG.PMS_URL_MANUAL, @@ -52,7 +51,7 @@ def get_server_resources(return_presence=False, return_server=False, return_info if kwargs: server.update(kwargs) - for k in ['pms_ssl', 'pms_is_remote', 'pms_is_cloud', 'pms_url_manual']: + for k in ['pms_ssl', 'pms_is_cloud', 'pms_url_manual']: server[k] = int(server[k]) if server['pms_url_manual'] and server['pms_ssl'] or server['pms_is_cloud']: @@ -88,30 +87,25 @@ def get_server_resources(return_presence=False, return_server=False, return_info # Only need to retrieve PMS_URL if using SSL if not server['pms_url_manual'] and server['pms_ssl']: if connections: - if server['pms_is_remote']: - # Get all remote connections - conns = [c for c in connections if - c['local'] == '0' and ('plex.direct' in c['uri'] or 'plex.service' in c['uri'])] - else: - # Get all local connections - conns = [c for c in connections if - c['local'] == '1' and ('plex.direct' in c['uri'] or 'plex.service' in c['uri'])] - - if conns: - # Get connection with matching address, otherwise return first connection - conn = next((c for c in conns if c['address'] == server['pms_ip'] - and c['port'] == str(server['pms_port'])), conns[0]) - server['pms_url'] = conn['uri'] - logger.info("Tautulli PlexTV :: Server URL retrieved.") + # Get connection with matching address, otherwise return first connection + connection = next( + (c for c in connections if c['address'] == server['pms_ip'] and c['port'] == str(server['pms_port'])), + connections[0] + ) + server['pms_url'] = connection['uri'] + server['pms_is_remote'] = int(connection['local'] == '0') + logger.info("Tautulli PlexTV :: Server URL retrieved.") # get_server_urls() failed or PMS_URL not found, fallback url doesn't use SSL if not server['pms_url']: server['pms_url'] = fallback_url + server['pms_is_remote'] = 0 logger.warn("Tautulli PlexTV :: Unable to retrieve server URLs. Using user-defined value without SSL.") - # Not using SSL, remote has no effect + # Not using SSL else: server['pms_url'] = fallback_url + server['pms_is_remote'] = 0 logger.info("Tautulli PlexTV :: Using user-defined URL.") if return_server: diff --git a/plexpy/webserve.py b/plexpy/webserve.py index ec98baf2..150bc18d 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -175,7 +175,6 @@ class WebInterface(object): "pms_identifier": plexpy.CONFIG.PMS_IDENTIFIER, "pms_ip": plexpy.CONFIG.PMS_IP, "pms_port": plexpy.CONFIG.PMS_PORT, - "pms_is_remote": plexpy.CONFIG.PMS_IS_REMOTE, "pms_ssl": plexpy.CONFIG.PMS_SSL, "pms_is_cloud": plexpy.CONFIG.PMS_IS_CLOUD, "pms_name": helpers.pms_name(), @@ -3247,7 +3246,6 @@ class WebInterface(object): # If we change the SSL setting for PMS or PMS remote setting, make sure we grab the new url. if kwargs.get('pms_ssl') != str(plexpy.CONFIG.PMS_SSL) or \ - kwargs.get('pms_is_remote') != str(plexpy.CONFIG.PMS_IS_REMOTE) or \ kwargs.get('pms_url_manual') != plexpy.CONFIG.PMS_URL_MANUAL: server_changed = True @@ -4060,7 +4058,7 @@ class WebInterface(object): @cherrypy.tools.json_out() @requireAuth(member_of("admin")) @addtoapi() - def get_server_id(self, hostname=None, port=None, identifier=None, ssl=0, remote=0, manual=0, + def get_server_id(self, hostname=None, port=None, identifier=None, ssl=0, manual=0, get_url=False, test_websocket=False, **kwargs): """ Get the PMS server identifier. @@ -4115,7 +4113,6 @@ class WebInterface(object): server = self.get_server_resources(pms_ip=hostname, pms_port=port, pms_ssl=ssl, - pms_is_remote=remote, pms_url_manual=manual, pms_identifier=identifier) result['url'] = server['pms_url'] From a3af8ed36210e49350c5233487ebf5b832190a39 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Mon, 3 Jun 2024 23:07:11 -0700 Subject: [PATCH 028/141] Fix width of use secure connection checkbox in wizard --- data/interfaces/default/welcome.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/interfaces/default/welcome.html b/data/interfaces/default/welcome.html index e3b4bc56..baf1b57e 100644 --- a/data/interfaces/default/welcome.html +++ b/data/interfaces/default/welcome.html @@ -150,7 +150,7 @@
-
+