Compare commits

..

35 Commits

Author SHA1 Message Date
JonnyWong16
1698622d63 v2.5.3 2020-07-10 17:07:18 -07:00
JonnyWong16
fa27271647 Change shebang on contrib scripts 2020-07-10 17:02:23 -07:00
JonnyWong16
d837811c68 Improve start script 2020-07-09 17:13:16 -07:00
JonnyWong16
ad195f0969 Fix deleteing more than 1000 history entries at the same time 2020-07-08 12:27:20 -07:00
JonnyWong16
4a8748e322 Live TV library not being recreated after server identifier is changed
* Fixes Tautulli/Tautulli-Issues#261
2020-07-07 18:14:00 -07:00
JonnyWong16
0f016c83ea Fix ipwhois data location for macOS package
* Fixes Tautulli/Tautulli-Issues#260
2020-07-07 17:25:46 -07:00
JonnyWong16
061ae44da4 Fix indentation in macOS postinstall script 2020-07-07 17:05:15 -07:00
JonnyWong16
a8b90bf100 Reduce macOS build requirement to pyobjc-framework-Cocoa 2020-07-07 17:05:10 -07:00
JonnyWong16
eb3cd49bc4 Add hidden import pkg_resources.py2_warn to macos.spec
* Fixes build on macOS 10.13 (High Sierra)
2020-07-06 20:57:37 -07:00
JonnyWong16
416d869288 Add python version to Google Analytics 2020-07-06 18:13:33 -07:00
JonnyWong16
a116c26c25 Run python scripts with the same sys.executable as Tautulli 2020-07-06 11:32:16 -07:00
JonnyWong16
cc4ec53dac Full path to python3 interpreter in FreeBSD startup script 2020-07-06 10:08:36 -07:00
JonnyWong16
63164c7ff5 Quote command in systemd script 2020-07-06 09:37:37 -07:00
JonnyWong16
9815c014e8 Add python interpreter to init-scripts 2020-07-06 09:30:35 -07:00
JonnyWong16
41843dc573 Rename some column headers 2020-07-04 12:22:40 -07:00
JonnyWong16
cc6bd528a5 Add architecture to release assets 2020-07-04 11:28:22 -07:00
JonnyWong16
2625ef5fb9 Use Popen to restart on macOS 2020-07-03 19:48:27 -07:00
JonnyWong16
dbd2d28877 Set macOS menu bar icon thread to daemon 2020-07-03 19:47:57 -07:00
JonnyWong16
f70f814c70 Shutdown tray icons last 2020-07-03 19:47:11 -07:00
JonnyWong16
6710e42134 Hide macOS dock icon for pkg install 2020-07-03 19:46:27 -07:00
JonnyWong16
78c5b45e43 Also fix e562ec9 for Python 2 2020-07-03 11:24:47 -07:00
JonnyWong16
e562ec96fa Fix encoding when reading a newsletter file 2020-07-02 20:46:42 -07:00
JonnyWong16
9b5e01c319 Fix logger for email notification exception 2020-07-02 12:45:45 -07:00
JonnyWong16
0097532f4a Fix startup script 2020-07-02 12:33:32 -07:00
JonnyWong16
91935c9018 Add hidden import cheroot.ssl.builtin for pyinstaller 2020-07-02 09:20:58 -07:00
JonnyWong16
83df807f7e Fix typo in eb3db20 2020-07-02 09:15:13 -07:00
JonnyWong16
eb3db20340 Add hidden import chroot.ssl for pyinstaller 2020-07-02 09:11:15 -07:00
JonnyWong16
6dab6194ea Replace which with command -v in startup script 2020-07-01 22:44:05 -07:00
JonnyWong16
356f64cac0 v2.5.2 2020-07-01 19:49:44 -07:00
JonnyWong16
f77f289125 Move GitHub sponsor first 2020-07-01 15:53:08 -07:00
JonnyWong16
280257477a Revert "Change shebang to python3"
This reverts commit cd8a899521.
2020-07-01 14:59:18 -07:00
JonnyWong16
660141cb16 Try various python versions in startup script 2020-07-01 14:43:35 -07:00
JonnyWong16
cd8a899521 Change shebang to python3 2020-07-01 14:43:04 -07:00
JonnyWong16
cb577c51b8 v2.5.2-beta 2020-06-27 15:04:06 -07:00
JonnyWong16
1c395ab10c Patch SameSite support into cookies
* Python 2.7 is missing SameSite cookie attribute
2020-06-27 15:01:16 -07:00
26 changed files with 140 additions and 87 deletions

View File

@@ -53,7 +53,7 @@ jobs:
uses: joncloud/makensis-action@v1.2 uses: joncloud/makensis-action@v1.2
with: with:
script-file: ./package/Tautulli.nsi script-file: ./package/Tautulli.nsi
arguments: /DVERSION=${{ steps.get_version.outputs.VERSION_NSIS }} /DINSTALLER_NAME=..\Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}.exe arguments: /DVERSION=${{ steps.get_version.outputs.VERSION_NSIS }} /DINSTALLER_NAME=..\Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.exe
include-more-plugins: true include-more-plugins: true
include-custom-plugins-path: package/nsis-plugins include-custom-plugins-path: package/nsis-plugins
@@ -61,7 +61,7 @@ jobs:
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: Tautulli-windows-installer name: Tautulli-windows-installer
path: Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}.exe path: Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.exe
- name: Post Status to Discord - name: Post Status to Discord
uses: sarisia/actions-status-discord@v1 uses: sarisia/actions-status-discord@v1
@@ -117,13 +117,13 @@ jobs:
- name: Create Installer - name: Create Installer
run: | run: |
sudo pkgbuild --install-location /Applications --version ${{ steps.get_version.outputs.VERSION }} --component ./dist/Tautulli.app --scripts ./package/macos-scripts Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}.pkg sudo pkgbuild --install-location /Applications --version ${{ steps.get_version.outputs.VERSION }} --component ./dist/Tautulli.app --scripts ./package/macos-scripts Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.pkg
- name: Upload Installer - name: Upload Installer
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: Tautulli-macos-installer name: Tautulli-macos-installer
path: Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}.pkg path: Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.pkg
- name: Post Status to Discord - name: Post Status to Discord
uses: sarisia/actions-status-discord@v1 uses: sarisia/actions-status-discord@v1
@@ -188,8 +188,8 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ steps.create_release.outputs.upload_url }} upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}.exe asset_path: ./Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.exe
asset_name: Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}.exe asset_name: Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.exe
asset_content_type: application/vnd.microsoft.portable-executable asset_content_type: application/vnd.microsoft.portable-executable
- name: Upload MacOS Installer - name: Upload MacOS Installer
@@ -199,6 +199,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ steps.create_release.outputs.upload_url }} upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}.pkg asset_path: ./Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.pkg
asset_name: Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}.pkg asset_name: Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.pkg
asset_content_type: application/vnd.apple.installer+xml asset_content_type: application/vnd.apple.installer+xml

View File

@@ -1,34 +1,46 @@
# Changelog # Changelog
## v2.5.1-beta (2020-06-26) ## v2.5.3 (2020-07-10)
* History:
* Fix: Unable to delete more than 1000 history entries at the same time.
* Notifications:
* Change: Python script notifications to run using the same Python interpreter as Tautulli.
* Newsletters:
* Fix: Unable to view newsletters with special characters.
* Other:
* Fix: Tautulli failing to start after enabling HTTPS when installed using the Windows / macOS installers.
* Fix: Startup script not working on macOS.
* Fix: Unable to hide dock icon on macOS with the pkg install. Refer to the FAQ regarding the Python rocket dock icon.
* Change: Added path to Python interpreter in system startup (daemon) scripts.
* Change: Added Python version to Google analytics.
## v2.5.2 (2020-07-01)
* Announcements:
* Tautulli now supports Python 3!
* Python 2 is still supported for the time being, but it is recommended to upgrade to Python 3.
* Notifications: * Notifications:
* Fix: Error uploading images to Cloudinary on Python 2. * Fix: Error uploading images to Cloudinary on Python 2.
* Fix: Testing browser notifications alert not disappearing. * Fix: Testing browser notifications alert not disappearing.
* Change: Default recently added notification delay set to 300 seconds. * Change: Default recently added notification delay set to 300 seconds.
* UI: * UI:
* Fix: MacOS menu bar icon causing Tautulli to fail to start. * Fix: MacOS menu bar icon causing Tautulli to fail to start.
* New: Added platform icon for LG devices. * Fix: Unable to login to Tautulli on Python 2.
* Mobile App:
* Fix: Improved API security and validation when registering the Android app.
* Other:
* Fix: Error creating self-signed certificates on Python 3.
* Fix: Docker container not respecting the PUID and PGID environment variables.
* Fix: Tautulli login session cookie not set on the HTTP root path.
* Remove: Ability to login to Tautulli using a Plex username and password has been removed. Login using a Plex.tv account is only supported via OAuth.
## v2.5.0-beta (2020-05-31)
* Announcements:
* Tautulli now supports Python 3!
* Python 2 is still supported for the time being, but it is recommended to upgrade to Python 3.
* UI:
* New: Windows and MacOS setting to enable Tautulli to start automatically when you login. * New: Windows and MacOS setting to enable Tautulli to start automatically when you login.
* New: Added menu bar icon for MacOS. * New: Added menu bar icon for MacOS.
* New: Ability to import a Tautulli database in the settings. * New: Ability to import a Tautulli database in the settings.
* New: Added Tautulli news area on the settings page. * New: Added Tautulli news area on the settings page.
* New: Added platform icon for LG devices.
* Remove: Ability to login to Tautulli using a Plex username and password has been removed. Login using a Plex.tv account is only supported via OAuth.
* Mobile App:
* Fix: Improved API security and validation when registering the Android app.
* Docker:
* Fix: Docker container not respecting the PUID and PGID environment variables.
* Other: * Other:
* Fix: Error creating self-signed certificates on Python 3.
* Fix: Tautulli login session cookie not set on the HTTP root path.
* New: Windows and MacOS app installers to install Tautulli without needing Python installed. * New: Windows and MacOS app installers to install Tautulli without needing Python installed.

View File

@@ -265,7 +265,10 @@ def main():
if plexpy.CONFIG.SYS_TRAY_ICON: if plexpy.CONFIG.SYS_TRAY_ICON:
# MacOS menu bar icon must be run on the main thread and is blocking # MacOS menu bar icon must be run on the main thread and is blocking
# Start the rest of Tautulli on a new thread # Start the rest of Tautulli on a new thread
threading.Thread(target=wait).start() thread = threading.Thread(target=wait)
thread.daemon = True
thread.start()
plexpy.MAC_SYS_TRAY_ICON = macos.MacOSSystemTray() plexpy.MAC_SYS_TRAY_ICON = macos.MacOSSystemTray()
plexpy.MAC_SYS_TRAY_ICON.start() plexpy.MAC_SYS_TRAY_ICON.start()
else: else:

View File

@@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# Display information # Display information
echo "This script will remove *.pyc files. These files are generated by Python, but they can cause conflicts after an upgrade. It's safe to remove them, because they will be regenerated." echo "This script will remove *.pyc files. These files are generated by Python, but they can cause conflicts after an upgrade. It's safe to remove them, because they will be regenerated."

View File

@@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# Parameter check # Parameter check
if [ -z "$1" ]; then if [ -z "$1" ]; then

View File

@@ -230,20 +230,12 @@ ${next.modalIncludes()}
</div> </div>
</div> </div>
<ul id="donation_type" class="nav nav-pills" role="tablist" style="display: flex; justify-content: center; margin: 10px 0;"> <ul id="donation_type" class="nav nav-pills" role="tablist" style="display: flex; justify-content: center; margin: 10px 0;">
<li class="active"><a href="#patreon-donation" role="tab" data-toggle="tab">Patreon</a></li> <li class="active"><a href="#github-donation" role="tab" data-toggle="tab">GitHub</a></li>
<li><a href="#github-donation" role="tab" data-toggle="tab">GitHub</a></li> <li><a href="#patreon-donation" role="tab" data-toggle="tab">Patreon</a></li>
<li><a href="#paypal-donation" role="tab" data-toggle="tab">PayPal</a></li> <li><a href="#paypal-donation" role="tab" data-toggle="tab">PayPal</a></li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="patreon-donation" style="text-align: center"> <div role="tabpanel" class="tab-pane active" id="github-donation" style="text-align: center">
<p>
Click the button below to continue to Patreon.
</p>
<a href="${anon_url('https://www.patreon.com/join/tautulli')}" target="_blank">
<img src="images/become_a_patron_button.png" alt="Become a Patron" height="40">
</a>
</div>
<div role="tabpanel" class="tab-pane" id="github-donation" style="text-align: center">
<p> <p>
Click the button below to continue to GitHub. Click the button below to continue to GitHub.
</p> </p>
@@ -251,6 +243,14 @@ ${next.modalIncludes()}
<i class="fa fa-heart fa-sm" style="color: #ea4aaa;"></i>&nbsp; Sponsor <i class="fa fa-heart fa-sm" style="color: #ea4aaa;"></i>&nbsp; Sponsor
</a> </a>
</div> </div>
<div role="tabpanel" class="tab-pane" id="patreon-donation" style="text-align: center">
<p>
Click the button below to continue to Patreon.
</p>
<a href="${anon_url('https://www.patreon.com/join/tautulli')}" target="_blank">
<img src="images/become_a_patron_button.png" alt="Become a Patron" height="40">
</a>
</div>
<div role="tabpanel" class="tab-pane" id="paypal-donation" style="text-align: center"> <div role="tabpanel" class="tab-pane" id="paypal-donation" style="text-align: center">
<p> <p>
Click the button below to continue to PayPal. Click the button below to continue to PayPal.

View File

@@ -38,7 +38,7 @@
<th align="left" id="count">Total Movies / TV Shows / Artists</th> <th align="left" id="count">Total Movies / TV Shows / Artists</th>
<th align="left" id="parent_count">Total Seasons / Albums</th> <th align="left" id="parent_count">Total Seasons / Albums</th>
<th align="left" id="child_count">Total Episodes / Tracks</th> <th align="left" id="child_count">Total Episodes / Tracks</th>
<th align="left" id="last_accessed">Last Accessed</th> <th align="left" id="last_accessed">Last Streamed</th>
<th align="left" id="last_played">Last Played</th> <th align="left" id="last_played">Last Played</th>
<th align="left" id="total_plays">Total Plays</th> <th align="left" id="total_plays">Total Plays</th>
<th align="left" id="total_duration">Total Played Duration</th> <th align="left" id="total_duration">Total Played Duration</th>

View File

@@ -284,7 +284,7 @@ DOCUMENTATION :: END
<table class="display user_ip_table" id="user_ip_table-UID-${data['user_id']}" width="100%"> <table class="display user_ip_table" id="user_ip_table-UID-${data['user_id']}" width="100%">
<thead> <thead>
<tr> <tr>
<th align="left" id="last_seen">Last Seen</th> <th align="left" id="last_seen">Last Streamed</th>
<th align="left" id="ip_address">IP Address</th> <th align="left" id="ip_address">IP Address</th>
<th align="left" id="platform">Last Platform</th> <th align="left" id="platform">Last Platform</th>
<th align="left" id="player">Last Player</th> <th align="left" id="player">Last Player</th>

View File

@@ -34,7 +34,7 @@
<th align="left" id="edit_row">Edit</th> <th align="left" id="edit_row">Edit</th>
<th align="right" id="avatar"></th> <th align="right" id="avatar"></th>
<th align="left" id="friendly_name">User</th> <th align="left" id="friendly_name">User</th>
<th align="left" id="last_seen">Last Seen</th> <th align="left" id="last_seen">Last Streamed</th>
<th align="left" id="last_known_ip">Last Known IP</th> <th align="left" id="last_known_ip">Last Known IP</th>
<th align="left" id="last_platform">Last Platform</th> <th align="left" id="last_platform">Last Platform</th>
<th align="left" id="last_player">Last Player</th> <th align="left" id="last_player">Last Player</th>

View File

@@ -38,6 +38,7 @@ load_rc_config ${name}
status_cmd="${name}_status" status_cmd="${name}_status"
stop_cmd="${name}_stop" stop_cmd="${name}_stop"
command_interpreter="/usr/local/bin/python3"
command="${tautulli_dir}/Tautulli.py" command="${tautulli_dir}/Tautulli.py"
command_args="--daemon --pidfile ${tautulli_pid} --quiet --nolaunch ${tautulli_flags}" command_args="--daemon --pidfile ${tautulli_pid} --quiet --nolaunch ${tautulli_flags}"

View File

@@ -31,11 +31,13 @@
# sudo chown tautulli:tautulli -R /opt/Tautulli # sudo chown tautulli:tautulli -R /opt/Tautulli
# #
# - Adjust ExecStart= to point to: # - Adjust ExecStart= to point to:
# 1. Your Tautulli executable # 1. Your Python interpreter (get the path with "command -v python3")
# - Default: /usr/bin/python3
# 2. Your Tautulli executable
# - Default: /opt/Tautulli/Tautulli.py # - Default: /opt/Tautulli/Tautulli.py
# 2. Your config file (recommended is to put it somewhere in /etc) # 3. Your config file (recommended is to put it somewhere in /etc)
# - Default: --config /opt/Tautulli/config.ini # - Default: --config /opt/Tautulli/config.ini
# 3. Your datadir (recommended is to NOT put it in your Tautulli exec dir) # 4. Your datadir (recommended is to NOT put it in your Tautulli exec dir)
# - Default: --datadir /opt/Tautulli # - Default: --datadir /opt/Tautulli
# #
# - Adjust User= and Group= to the user/group you want Tautulli to run as. # - Adjust User= and Group= to the user/group you want Tautulli to run as.
@@ -50,7 +52,7 @@ Wants=network-online.target
After=network-online.target After=network-online.target
[Service] [Service]
ExecStart=/opt/Tautulli/Tautulli.py --config /opt/Tautulli/config.ini --datadir /opt/Tautulli --quiet --daemon --nolaunch ExecStart=/usr/bin/python3 /opt/Tautulli/Tautulli.py --config /opt/Tautulli/config.ini --datadir /opt/Tautulli --quiet --daemon --nolaunch
GuessMainPID=no GuessMainPID=no
Type=forking Type=forking
User=tautulli User=tautulli

View File

@@ -16,10 +16,10 @@ analysis = Analysis(
('../CHANGELOG.md', '.'), ('../CHANGELOG.md', '.'),
('../LICENSE', '.'), ('../LICENSE', '.'),
('../version.txt', '.'), ('../version.txt', '.'),
('../lib/ipwhois/data', 'data') ('../lib/ipwhois/data', 'ipwhois/data')
], ],
excludes=['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter'], excludes=['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter'],
hiddenimports=['Foundation', 'AppKit'], hiddenimports=['pkg_resources.py2_warn', 'Foundation', 'AppKit', 'cheroot.ssl', 'cheroot.ssl.builtin'],
cipher=block_cipher cipher=block_cipher
) )
pyz = PYZ( pyz = PYZ(
@@ -47,5 +47,9 @@ app = BUNDLE(
name='Tautulli.app', name='Tautulli.app',
icon='../data/interfaces/default/images/logo-circle.icns', icon='../data/interfaces/default/images/logo-circle.icns',
bundle_identifier='com.Tautulli.Tautulli', bundle_identifier='com.Tautulli.Tautulli',
version=VERSION version=VERSION,
info_plist={
'LSBackgroundOnly': True,
'LSUIElement': True
}
) )

View File

@@ -16,6 +16,7 @@ analysis = Analysis(
('..\\lib\\ipwhois\\data', 'data') ('..\\lib\\ipwhois\\data', 'data')
], ],
excludes=['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter'], excludes=['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter'],
hiddenimports=['cheroot.ssl', 'cheroot.ssl.builtin'],
cipher=block_cipher, cipher=block_cipher,
) )
pyz = PYZ( pyz = PYZ(

View File

@@ -1,4 +1,4 @@
pyinstaller pyinstaller
pyopenssl pyopenssl
pycryptodomex pycryptodomex
pyobjc pyobjc-framework-Cocoa

View File

@@ -37,8 +37,7 @@ from apscheduler.triggers.interval import IntervalTrigger
from UniversalAnalytics import Tracker from UniversalAnalytics import Tracker
import pytz import pytz
PYTHON_VERSION = sys.version_info[:3] PYTHON2 = sys.version_info[0] == 2
PYTHON2 = PYTHON_VERSION[0] == 2
if PYTHON2: if PYTHON2:
import activity_handler import activity_handler
@@ -2211,11 +2210,6 @@ def shutdown(restart=False, update=False, checkout=False, reset=False):
logger.info("Removing pidfile %s", PIDFILE) logger.info("Removing pidfile %s", PIDFILE)
os.remove(PIDFILE) os.remove(PIDFILE)
if WIN_SYS_TRAY_ICON:
WIN_SYS_TRAY_ICON.shutdown()
elif MAC_SYS_TRAY_ICON:
MAC_SYS_TRAY_ICON.shutdown()
if restart: if restart:
logger.info("Tautulli is restarting...") logger.info("Tautulli is restarting...")
@@ -2238,7 +2232,7 @@ def shutdown(restart=False, update=False, checkout=False, reset=False):
# https://bugs.python.org/issue19066 # https://bugs.python.org/issue19066
if NOFORK: if NOFORK:
pass pass
elif common.PLATFORM == 'Windows': elif common.PLATFORM in ('Windows', 'Darwin'):
subprocess.Popen(args, cwd=os.getcwd()) subprocess.Popen(args, cwd=os.getcwd())
else: else:
os.execv(exe, args) os.execv(exe, args)
@@ -2248,6 +2242,11 @@ def shutdown(restart=False, update=False, checkout=False, reset=False):
logger.shutdown() logger.shutdown()
if WIN_SYS_TRAY_ICON:
WIN_SYS_TRAY_ICON.shutdown()
elif MAC_SYS_TRAY_ICON:
MAC_SYS_TRAY_ICON.shutdown()
os._exit(0) os._exit(0)
@@ -2264,6 +2263,7 @@ def initialize_tracker():
'appInstallerId': CONFIG.GIT_BRANCH, 'appInstallerId': CONFIG.GIT_BRANCH,
'dimension1': '{} {}'.format(common.PLATFORM, common.PLATFORM_RELEASE), # App Platform 'dimension1': '{} {}'.format(common.PLATFORM, common.PLATFORM_RELEASE), # App Platform
'dimension2': common.PLATFORM_LINUX_DISTRO, # Linux Distro 'dimension2': common.PLATFORM_LINUX_DISTRO, # Linux Distro
'dimension3': common.PYTHON_VERSION,
'userLanguage': SYS_LANGUAGE, 'userLanguage': SYS_LANGUAGE,
'documentEncoding': SYS_ENCODING, 'documentEncoding': SYS_ENCODING,
'noninteractive': True 'noninteractive': True

View File

@@ -35,6 +35,7 @@ PLATFORM_RELEASE = platform.release()
PLATFORM_VERSION = platform.version() PLATFORM_VERSION = platform.version()
PLATFORM_LINUX_DISTRO = ' '.join(x for x in distro.linux_distribution() if x) PLATFORM_LINUX_DISTRO = ' '.join(x for x in distro.linux_distribution() if x)
PLATFORM_DEVICE_NAME = platform.node() PLATFORM_DEVICE_NAME = platform.node()
PYTHON_VERSION = platform.python_version()
BRANCH = version.PLEXPY_BRANCH BRANCH = version.PLEXPY_BRANCH
RELEASE = version.PLEXPY_RELEASE_VERSION RELEASE = version.PLEXPY_RELEASE_VERSION

View File

@@ -75,7 +75,6 @@ _CONFIG_DEFINITIONS = {
'PMS_UPDATE_CHECK_INTERVAL': (int, 'Advanced', 24), 'PMS_UPDATE_CHECK_INTERVAL': (int, 'Advanced', 24),
'PMS_WEB_URL': (str, 'PMS', 'https://app.plex.tv/desktop'), 'PMS_WEB_URL': (str, 'PMS', 'https://app.plex.tv/desktop'),
'TIME_FORMAT': (str, 'General', 'HH:mm'), 'TIME_FORMAT': (str, 'General', 'HH:mm'),
'ADD_LIVE_TV_LIBRARY': (int, 'Advanced', 1),
'ANON_REDIRECT': (str, 'General', 'http://www.nullrefer.com/?'), 'ANON_REDIRECT': (str, 'General', 'http://www.nullrefer.com/?'),
'API_ENABLED': (int, 'General', 1), 'API_ENABLED': (int, 'General', 1),
'API_KEY': (str, 'General', ''), 'API_KEY': (str, 'General', ''),

View File

@@ -27,10 +27,10 @@ import time
import plexpy import plexpy
if plexpy.PYTHON2: if plexpy.PYTHON2:
import logger import logger
from helpers import cast_to_int, bool_true from helpers import cast_to_int, bool_true, chunk
else: else:
from plexpy import logger from plexpy import logger
from plexpy.helpers import cast_to_int, bool_true from plexpy.helpers import cast_to_int, bool_true, chunk
FILENAME = "tautulli.db" FILENAME = "tautulli.db"
@@ -218,12 +218,16 @@ def delete_rows_from_table(table, row_ids):
if row_ids: if row_ids:
logger.info("Tautulli Database :: Deleting row ids %s from %s database table", row_ids, table) logger.info("Tautulli Database :: Deleting row ids %s from %s database table", row_ids, table)
query = "DELETE FROM " + table + " WHERE id IN (%s) " % ','.join(['?'] * len(row_ids))
monitor_db = MonitorDatabase()
# SQlite verions prior to 3.32.0 (2020-05-22) have maximum variable limit of 999
# https://sqlite.org/limits.html
sqlite_max_variable_number = 999
monitor_db = MonitorDatabase()
try: try:
monitor_db.action(query, row_ids) for row_ids_group in chunk(row_ids, sqlite_max_variable_number):
return True query = "DELETE FROM " + table + " WHERE id IN (%s) " % ','.join(['?'] * len(row_ids_group))
monitor_db.action(query, row_ids_group)
except Exception as e: except Exception as e:
logger.error("Tautulli Database :: Failed to delete rows from %s database table: %s" % (table, e)) logger.error("Tautulli Database :: Failed to delete rows from %s database table: %s" % (table, e))
return False return False

View File

@@ -31,7 +31,7 @@ import datetime
from functools import wraps from functools import wraps
import hashlib import hashlib
import imghdr import imghdr
from future.moves.itertools import zip_longest from future.moves.itertools import islice, zip_longest
import ipwhois import ipwhois
import ipwhois.exceptions import ipwhois.exceptions
import ipwhois.utils import ipwhois.utils
@@ -1068,6 +1068,11 @@ def grouper(iterable, n, fillvalue=None):
return zip_longest(fillvalue=fillvalue, *args) return zip_longest(fillvalue=fillvalue, *args)
def chunk(it, size):
it = iter(it)
return iter(lambda: tuple(islice(it, size)), ())
def traverse_map(obj, func): def traverse_map(obj, func):
if isinstance(obj, list): if isinstance(obj, list):
new_obj = [] new_obj = []

View File

@@ -88,6 +88,8 @@ def refresh_libraries():
if result == 'insert': if result == 'insert':
new_keys.append(section['section_id']) new_keys.append(section['section_id'])
add_live_tv_library(refresh=True)
query = 'UPDATE library_sections SET is_active = 0 WHERE server_id != ? OR ' \ query = 'UPDATE library_sections SET is_active = 0 WHERE server_id != ? OR ' \
'section_id NOT IN ({})'.format(', '.join(['?'] * len(section_ids))) 'section_id NOT IN ({})'.format(', '.join(['?'] * len(section_ids)))
monitor_db.action(query=query, args=[plexpy.CONFIG.PMS_IDENTIFIER] + section_ids) monitor_db.action(query=query, args=[plexpy.CONFIG.PMS_IDENTIFIER] + section_ids)
@@ -115,28 +117,28 @@ def refresh_libraries():
return False return False
def add_live_tv_library(): def add_live_tv_library(refresh=False):
if not plexpy.CONFIG.ADD_LIVE_TV_LIBRARY: monitor_db = database.MonitorDatabase()
result = monitor_db.select_single('SELECT * FROM library_sections '
'WHERE section_id = ? and server_id = ?',
[common.LIVE_TV_SECTION_ID, plexpy.CONFIG.PMS_IDENTIFIER])
if result and not refresh or not result and refresh:
return return
logger.info("Tautulli Libraries :: Adding Live TV library to the database.") logger.info("Tautulli Libraries :: Adding Live TV library to the database.")
monitor_db = database.MonitorDatabase()
section_keys = {'server_id': plexpy.CONFIG.PMS_IDENTIFIER, section_keys = {'server_id': plexpy.CONFIG.PMS_IDENTIFIER,
'section_id': common.LIVE_TV_SECTION_ID} 'section_id': common.LIVE_TV_SECTION_ID}
section_values = {'server_id': plexpy.CONFIG.PMS_IDENTIFIER, section_values = {'server_id': plexpy.CONFIG.PMS_IDENTIFIER,
'section_id': common.LIVE_TV_SECTION_ID, 'section_id': common.LIVE_TV_SECTION_ID,
'section_name': common.LIVE_TV_SECTION_NAME, 'section_name': common.LIVE_TV_SECTION_NAME,
'section_type': 'live' 'section_type': 'live',
'is_active': 1
} }
result = monitor_db.upsert('library_sections', key_dict=section_keys, value_dict=section_values) result = monitor_db.upsert('library_sections', key_dict=section_keys, value_dict=section_values)
if result == 'insert':
plexpy.CONFIG.__setattr__('ADD_LIVE_TV_LIBRARY', 0)
plexpy.CONFIG.write()
def has_library_type(section_type): def has_library_type(section_type):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()

View File

@@ -17,6 +17,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from io import open
import os import os
from apscheduler.triggers.cron import CronTrigger from apscheduler.triggers.cron import CronTrigger
@@ -214,7 +215,7 @@ def get_newsletter(newsletter_uuid=None, newsletter_id_name=None):
if newsletter_file in os.listdir(newsletter_folder): if newsletter_file in os.listdir(newsletter_folder):
try: try:
with open(newsletter_file_fp, 'r') as n_file: with open(newsletter_file_fp, 'r', encoding='utf-8') as n_file:
newsletter = n_file.read() newsletter = n_file.read()
return newsletter return newsletter
except OSError as e: except OSError as e:

View File

@@ -1399,8 +1399,7 @@ class EMAIL(Notifier):
success = True success = True
except Exception as e: except Exception as e:
logger.error("Tautulli Notifiers :: {name} notification failed: {e}".format( logger.error("Tautulli Notifiers :: %s notification failed: %s", self.NAME, e)
name=self.NAME, e=str(e).decode('utf-8')))
finally: finally:
if mailserver: if mailserver:
@@ -2970,7 +2969,7 @@ class SCRIPTS(Notifier):
'.php': 'php', '.php': 'php',
'.pl': 'perl', '.pl': 'perl',
'.ps1': 'powershell -executionPolicy bypass -file', '.ps1': 'powershell -executionPolicy bypass -file',
'.py': 'python', '.py': 'python' if plexpy.FROZEN else sys.executable,
'.pyw': 'pythonw', '.pyw': 'pythonw',
'.rb': 'ruby', '.rb': 'ruby',
'.sh': '' '.sh': ''
@@ -3008,7 +3007,7 @@ class SCRIPTS(Notifier):
'TAUTULLI_PUBLIC_URL': plexpy.CONFIG.HTTP_BASE_URL + plexpy.HTTP_ROOT, 'TAUTULLI_PUBLIC_URL': plexpy.CONFIG.HTTP_BASE_URL + plexpy.HTTP_ROOT,
'TAUTULLI_APIKEY': plexpy.CONFIG.API_KEY, 'TAUTULLI_APIKEY': plexpy.CONFIG.API_KEY,
'TAUTULLI_ENCODING': plexpy.SYS_ENCODING, 'TAUTULLI_ENCODING': plexpy.SYS_ENCODING,
'TAUTULLI_PYTHON_VERSION': '.'.join(map(str, plexpy.PYTHON_VERSION)) 'TAUTULLI_PYTHON_VERSION': common.PYTHON_VERSION
} }
if user_id: if user_id:

View File

@@ -17,5 +17,5 @@
from __future__ import unicode_literals from __future__ import unicode_literals
PLEXPY_BRANCH = "beta" PLEXPY_BRANCH = "master"
PLEXPY_RELEASE_VERSION = "v2.5.1-beta" PLEXPY_RELEASE_VERSION = "v2.5.3"

View File

@@ -41,6 +41,13 @@ else:
from plexpy.users import Users, refresh_users from plexpy.users import Users, refresh_users
from plexpy.plextv import PlexTV from plexpy.plextv import PlexTV
# Monkey patch SameSite support into cookies.
# https://stackoverflow.com/a/50813092
try:
from http.cookies import Morsel
except ImportError:
from Cookie import Morsel
Morsel._reserved[str('samesite')] = str('SameSite')
JWT_ALGORITHM = 'HS256' JWT_ALGORITHM = 'HS256'
JWT_COOKIE_NAME = 'tautulli_token_' JWT_COOKIE_NAME = 'tautulli_token_'

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
if [[ "$TAUTULLI_DOCKER" = "True" ]]; then if [[ "$TAUTULLI_DOCKER" == "True" ]]; then
if [[ -v PUID && -v PGID ]]; then if [[ -n $PUID && -n $PGID ]]; then
getent group "$PGID" 2>&1 > /dev/null || groupadd -g "$PGID" tautulli getent group "$PGID" 2>&1 > /dev/null || groupadd -g "$PGID" tautulli
getent passwd "$PUID" 2>&1 > /dev/null || useradd -r -u "$PUID" -g "$PGID" tautulli getent passwd "$PUID" 2>&1 > /dev/null || useradd -r -u "$PUID" -g "$PGID" tautulli
@@ -17,5 +17,17 @@ if [[ "$TAUTULLI_DOCKER" = "True" ]]; then
python Tautulli.py --datadir /config python Tautulli.py --datadir /config
fi fi
else else
python Tautulli.py &> /dev/null & python_versions=("python3" "python3.8" "python3.7" "python3.6" "python" "python2" "python2.7")
for cmd in "${python_versions[@]}"; do
if command -v "$cmd" >/dev/null; then
echo "Starting Tautulli with $cmd."
if [[ "$(uname -s)" == "Darwin" ]]; then
$cmd Tautulli.py &> /dev/null &
else
$cmd Tautulli.py --quiet --daemon
fi
exit
fi
done
echo "Unable to start Tautulli. No Python interpreter was found in the following options:" "${python_versions[@]}"
fi fi