mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-13 00:32:58 -07:00
Remove Windows exe auto updater
This commit is contained in:
parent
2cc5bf812f
commit
6e160bb8f8
10 changed files with 14 additions and 280 deletions
5
.github/workflows/publish-installers.yml
vendored
5
.github/workflows/publish-installers.yml
vendored
|
@ -71,11 +71,6 @@ jobs:
|
|||
run: |
|
||||
pyinstaller -y ./package/Tautulli-${{ matrix.os }}.spec
|
||||
|
||||
- name: Move Windows Updater Files
|
||||
if: matrix.os == 'windows'
|
||||
run: |
|
||||
Move-Item dist\updater\* dist\Tautulli\ -Force
|
||||
|
||||
- name: Create Windows Installer
|
||||
uses: joncloud/makensis-action@v3.4
|
||||
if: matrix.os == 'windows'
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
Update your Docker container or <a href="#" id="updateDismiss">Dismiss</a>
|
||||
% elif plexpy.INSTALL_TYPE == 'snap':
|
||||
Update your Snap package or <a href="#" id="updateDismiss">Dismiss</a>
|
||||
% elif plexpy.INSTALL_TYPE == 'macos':
|
||||
% elif plexpy.INSTALL_TYPE in ('windows', 'macos'):
|
||||
<a href="${anon_url('https://github.com/%s/%s/releases/tag/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO, plexpy.LATEST_RELEASE))}" target="_blank" rel="noreferrer">Download</a> and install the latest version or <a href="#" id="updateDismiss">Dismiss</a>
|
||||
% else:
|
||||
<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>
|
||||
|
@ -350,7 +350,7 @@ ${next.modalIncludes()}
|
|||
msg += 'Update your Docker container or <a href="#" id="updateDismiss">Dismiss</a>';
|
||||
} else if (result.install_type === 'snap') {
|
||||
msg += 'Update your Snap package or <a href="#" id="updateDismiss">Dismiss</a>';
|
||||
} else if (result.install_type === 'macos') {
|
||||
} else if (result.install_type === 'windows' || result.install_type === 'macos') {
|
||||
msg += '<a href="' + result.release_url + '" target="_blank" rel="noreferrer">Download</a> and install the latest version or <a href="#" id="updateDismiss">Dismiss</a>'
|
||||
} else {
|
||||
msg += '<a href="update">Update</a> or <a href="#" id="updateDismiss">Dismiss</a>';
|
||||
|
|
|
@ -220,7 +220,7 @@
|
|||
<p class="help-block">Check for Tautulli updates periodically.</p>
|
||||
</div>
|
||||
<div id="git_update_options">
|
||||
% if not plexpy.SNAP and not (plexpy.FROZEN and common.PLATFORM == 'Darwin'):
|
||||
% if not plexpy.SNAP and not plexpy.FROZEN:
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" id="plexpy_auto_update" name="plexpy_auto_update" value="1" ${config['plexpy_auto_update']} ${docker_setting}> Update Automatically ${docker_msg | n}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import sys
|
||||
sys.modules['FixTk'] = None
|
||||
|
||||
excludes = ['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter']
|
||||
block_cipher = None
|
||||
|
||||
analysis = Analysis(
|
||||
|
@ -13,27 +12,13 @@ analysis = Analysis(
|
|||
('..\\data', 'data'),
|
||||
('..\\CHANGELOG.md', '.'),
|
||||
('..\\LICENSE', '.'),
|
||||
('..\\branch.txt', '.'),
|
||||
('..\\version.txt', '.'),
|
||||
('..\\lib\\ipwhois\\data', 'data'),
|
||||
('TautulliUpdateTask.xml', '.')
|
||||
('..\\lib\\ipwhois\\data', 'data')
|
||||
],
|
||||
excludes=excludes,
|
||||
excludes=['FixTk', 'tcl', 'tk', '_tkinter', 'tkinter', 'Tkinter'],
|
||||
hiddenimports=['pkg_resources.py2_warn', 'cheroot.ssl', 'cheroot.ssl.builtin'],
|
||||
cipher=block_cipher
|
||||
)
|
||||
updater_analysis = Analysis(
|
||||
['updater-windows.py'],
|
||||
pathex=['lib'],
|
||||
excludes=excludes,
|
||||
cipher=block_cipher
|
||||
)
|
||||
|
||||
MERGE(
|
||||
(analysis, 'Tautulli', 'Tautulli'),
|
||||
(updater_analysis, 'updater', 'updater')
|
||||
)
|
||||
|
||||
pyz = PYZ(
|
||||
analysis.pure,
|
||||
analysis.zipped_data,
|
||||
|
@ -54,24 +39,3 @@ coll = COLLECT(
|
|||
analysis.datas,
|
||||
name='Tautulli'
|
||||
)
|
||||
|
||||
updater_pyz = PYZ(
|
||||
updater_analysis.pure,
|
||||
updater_analysis.zipped_data,
|
||||
cipher=block_cipher
|
||||
)
|
||||
updater_exe = EXE(
|
||||
updater_pyz,
|
||||
updater_analysis.scripts,
|
||||
exclude_binaries=True,
|
||||
name='updater',
|
||||
console=False,
|
||||
icon='..\\data\\interfaces\\default\\images\\logo-circle.ico'
|
||||
)
|
||||
coll = COLLECT(
|
||||
updater_exe,
|
||||
updater_analysis.binaries,
|
||||
updater_analysis.zipfiles,
|
||||
updater_analysis.datas,
|
||||
name='updater'
|
||||
)
|
||||
|
|
|
@ -77,13 +77,9 @@ InstallDir "$PROGRAMFILES64\${APP_NAME}"
|
|||
|
||||
!include Sections.nsh
|
||||
|
||||
Var /GLOBAL norun
|
||||
Var /GLOBAL nolaunch
|
||||
|
||||
!include "MUI.nsh"
|
||||
!include "FileFunc.nsh"
|
||||
!insertmacro GetParameters
|
||||
!insertmacro GetOptions
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_UNABORTWARNING
|
||||
|
@ -129,10 +125,6 @@ SetOverwrite on
|
|||
SetOutPath "$INSTDIR"
|
||||
File /nonfatal /a /r "..\dist\${APP_NAME}\"
|
||||
|
||||
nsExec::Exec "$INSTDIR\updater.exe --xml"
|
||||
nsExec::Exec '$SYSDIR\SCHTASKS /Create /TN TautulliUpdateTask /XML "$INSTDIR\TautulliUpdateTask.xml" /F'
|
||||
|
||||
StrCmp $norun 1 +3 0
|
||||
IfSilent 0 +2
|
||||
ExecShell "" "$INSTDIR\${MAIN_APP_EXE}" $nolaunch
|
||||
SectionEnd
|
||||
|
@ -218,20 +210,11 @@ RmDir "$SMPROGRAMS\${APP_NAME}"
|
|||
|
||||
DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
|
||||
DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
|
||||
|
||||
nsExec::Exec "$SYSDIR\SCHTASKS /Delete /TN TautulliUpdateTask /F"
|
||||
|
||||
SectionEnd
|
||||
|
||||
######################################################################
|
||||
|
||||
Function .onInit
|
||||
StrCpy $norun 0
|
||||
${GetParameters} $CMDLINE
|
||||
${GetOptions} "$CMDLINE" "/NORUN" $R0
|
||||
IfErrors +2 0
|
||||
StrCpy $norun 1
|
||||
|
||||
IfSilent 0 +2
|
||||
StrCpy $nolaunch "--nolaunch"
|
||||
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,4 @@
|
|||
apscheduler==3.6.3
|
||||
psutil==5.8.0
|
||||
pyinstaller==4.2
|
||||
pyopenssl==20.0.1
|
||||
pycryptodomex==3.9.9
|
||||
|
|
|
@ -1,194 +0,0 @@
|
|||
# -*- 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
|
||||
# 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 logging import handlers
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import psutil
|
||||
import re
|
||||
import requests
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
|
||||
SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
CREATE_NO_WINDOW = 0x08000000
|
||||
REPO_URL = 'https://api.github.com/repos/Tautulli/Tautulli'
|
||||
|
||||
LOGFILE = 'updater.log'
|
||||
LOGPATH = os.path.join(SCRIPT_PATH, LOGFILE)
|
||||
MAX_SIZE = 1000000 # 1MB
|
||||
MAX_FILES = 1
|
||||
|
||||
|
||||
def init_logger():
|
||||
log = logging.getLogger('updater')
|
||||
log.setLevel(logging.DEBUG)
|
||||
file_formatter = logging.Formatter(
|
||||
'%(asctime)s - %(levelname)-7s :: %(threadName)s : Tautulli Updater :: %(message)s',
|
||||
'%Y-%m-%d %H:%M:%S')
|
||||
file_handler = handlers.RotatingFileHandler(
|
||||
LOGPATH, maxBytes=MAX_SIZE, backupCount=MAX_FILES, encoding='utf-8')
|
||||
file_handler.setFormatter(file_formatter)
|
||||
log.addHandler(file_handler)
|
||||
return log
|
||||
|
||||
|
||||
def read_file(file_path):
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
return f.read().strip(' \n\r')
|
||||
except Exception as e:
|
||||
logger.error('Read file error: %s', e)
|
||||
raise Exception(1)
|
||||
|
||||
|
||||
def request_json(url):
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except Exception as e:
|
||||
logger.error('Request error: %s', e)
|
||||
raise Exception(2)
|
||||
|
||||
|
||||
def kill_and_get_processes(process_name):
|
||||
processes = []
|
||||
for process in psutil.process_iter():
|
||||
if process.name() == process_name:
|
||||
processes.append(process.cmdline())
|
||||
logger.info('Sending SIGTERM to %s (PID=%d)', process.name(), process.pid)
|
||||
process.terminate()
|
||||
return processes
|
||||
|
||||
|
||||
def update_tautulli():
|
||||
logger.info('Starting Tautulli update check')
|
||||
|
||||
branch = read_file(os.path.join(SCRIPT_PATH, 'branch.txt'))
|
||||
logger.info('Branch: %s', branch)
|
||||
|
||||
current_version = read_file(os.path.join(SCRIPT_PATH, 'version.txt'))
|
||||
logger.info('Current version: %s', current_version)
|
||||
|
||||
logger.info('Retrieving latest version from GitHub')
|
||||
commits = request_json('{}/commits/{}'.format(REPO_URL, branch))
|
||||
latest_version = commits['sha']
|
||||
logger.info('Latest version: %s', latest_version)
|
||||
|
||||
if current_version == latest_version:
|
||||
logger.info('Tautulli is already up to date')
|
||||
return 0
|
||||
|
||||
logger.info('Comparing version on GitHub')
|
||||
compare = request_json('{}/compare/{}...{}'.format(REPO_URL, latest_version, current_version))
|
||||
commits_behind = compare['behind_by']
|
||||
logger.info('Commits behind: %s', commits_behind)
|
||||
|
||||
if commits_behind <= 0:
|
||||
logger.info('Tautulli is already up to date')
|
||||
return 0
|
||||
|
||||
logger.info('Retrieving releases on GitHub')
|
||||
releases = request_json('{}/releases'.format(REPO_URL))
|
||||
|
||||
if branch == 'master':
|
||||
release = next((r for r in releases if not r['prerelease']), releases[0])
|
||||
else:
|
||||
release = next((r for r in releases), releases[0])
|
||||
|
||||
version = release['tag_name']
|
||||
logger.info('Release: %s', version)
|
||||
|
||||
win_exe = 'application/vnd.microsoft.portable-executable'
|
||||
asset = next((a for a in release['assets'] if a['content_type'] == win_exe), None)
|
||||
download_url = asset['browser_download_url']
|
||||
download_file = asset['name']
|
||||
|
||||
file_path = os.path.join(tempfile.gettempdir(), download_file)
|
||||
logger.info('Downloading installer to temporary directory: %s', file_path)
|
||||
try:
|
||||
with requests.get(download_url, stream=True) as r:
|
||||
with open(file_path, 'wb') as f:
|
||||
shutil.copyfileobj(r.raw, f)
|
||||
except Exception as e:
|
||||
logger.error('Failed to download %s: %s', download_file, e)
|
||||
return 2
|
||||
|
||||
logger.info('Stopping Tautulli processes')
|
||||
try:
|
||||
processes = kill_and_get_processes('Tautulli.exe')
|
||||
except Exception as e:
|
||||
logger.error('Failed to stop Tautulli: %s', e)
|
||||
return 1
|
||||
|
||||
logger.info('Running %s', download_file)
|
||||
try:
|
||||
subprocess.call([file_path, '/S', '/NORUN', '/D=' + SCRIPT_PATH], creationflags=CREATE_NO_WINDOW)
|
||||
status = 0
|
||||
except Exception as e:
|
||||
logger.exception('Failed to install Tautulli: %s', e)
|
||||
status = -1
|
||||
|
||||
if status == 0:
|
||||
logger.info('Tautulli updated to %s', version)
|
||||
|
||||
logger.info('Restarting Tautulli processes')
|
||||
for process in processes:
|
||||
logger.info('Starting process: %s', process)
|
||||
subprocess.Popen(process, creationflags=CREATE_NO_WINDOW)
|
||||
|
||||
return status
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--xml', action='store_true')
|
||||
opts = parser.parse_args()
|
||||
|
||||
if opts.xml:
|
||||
xml_path = os.path.join(SCRIPT_PATH, 'TautulliUpdateTask.xml')
|
||||
tree = ET.parse(xml_path)
|
||||
task = tree.getroot()
|
||||
|
||||
match = re.match(r'{(.*)}', task.tag)
|
||||
namespace = match.group(1)
|
||||
namespaces = {'': namespace}
|
||||
ET.register_namespace('', namespace)
|
||||
|
||||
for elem in task.iterfind('./Actions/Exec/Command', namespaces=namespaces):
|
||||
elem.text = os.path.join(SCRIPT_PATH, 'updater.exe')
|
||||
for elem in task.iterfind('./Actions/Exec/WorkingDirectory', namespaces=namespaces):
|
||||
elem.text = SCRIPT_PATH
|
||||
|
||||
tree.write(xml_path, encoding='UTF-16')
|
||||
|
||||
else:
|
||||
logger = init_logger()
|
||||
|
||||
try:
|
||||
status_code = update_tautulli()
|
||||
except Exception as exc:
|
||||
status_code = exc
|
||||
logger.debug('Update function returned status code %s', status_code)
|
||||
|
||||
sys.exit(status_code)
|
|
@ -2295,12 +2295,7 @@ def upgrade():
|
|||
return
|
||||
|
||||
|
||||
def shutdown(restart=False, update=False, checkout=False, reset=False,
|
||||
_shutdown=True):
|
||||
if FROZEN and common.PLATFORM == 'Windows' and update:
|
||||
restart = False
|
||||
_shutdown = False
|
||||
|
||||
def shutdown(restart=False, update=False, checkout=False, reset=False):
|
||||
webstart.stop()
|
||||
|
||||
# Shutdown the websocket connection
|
||||
|
@ -2373,15 +2368,14 @@ def shutdown(restart=False, update=False, checkout=False, reset=False,
|
|||
else:
|
||||
logger.info("Tautulli is shutting down...")
|
||||
|
||||
if _shutdown:
|
||||
logger.shutdown()
|
||||
logger.shutdown()
|
||||
|
||||
if WIN_SYS_TRAY_ICON:
|
||||
WIN_SYS_TRAY_ICON.shutdown()
|
||||
elif MAC_SYS_TRAY_ICON:
|
||||
MAC_SYS_TRAY_ICON.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)
|
||||
|
||||
|
||||
def generate_uuid():
|
||||
|
|
|
@ -278,8 +278,7 @@ def check_github(scheduler=False, notify=False, use_cache=False):
|
|||
logger.warn('Tautulli is running using Python 2. Unable to run automatic update.')
|
||||
|
||||
elif scheduler and plexpy.CONFIG.PLEXPY_AUTO_UPDATE and \
|
||||
not plexpy.DOCKER and not plexpy.SNAP and \
|
||||
not (plexpy.FROZEN and common.PLATFORM == 'Darwin'):
|
||||
not plexpy.DOCKER and not plexpy.SNAP and not plexpy.FROZEN:
|
||||
logger.info('Running automatic update.')
|
||||
plexpy.shutdown(restart=True, update=True)
|
||||
|
||||
|
@ -297,15 +296,9 @@ def update():
|
|||
if not plexpy.UPDATE_AVAILABLE:
|
||||
return
|
||||
|
||||
if plexpy.INSTALL_TYPE in ('docker', 'snap', 'macos'):
|
||||
if plexpy.INSTALL_TYPE in ('docker', 'snap', 'windows', 'macos'):
|
||||
return
|
||||
|
||||
elif plexpy.INSTALL_TYPE == 'windows':
|
||||
logger.info('Calling Windows scheduled task to update Tautulli')
|
||||
CREATE_NO_WINDOW = 0x08000000
|
||||
subprocess.Popen(['SCHTASKS', '/Run', '/TN', 'TautulliUpdateTask'],
|
||||
creationflags=CREATE_NO_WINDOW)
|
||||
|
||||
elif plexpy.INSTALL_TYPE == 'git':
|
||||
output, err = runGit('pull --ff-only {} {}'.format(plexpy.CONFIG.GIT_REMOTE,
|
||||
plexpy.CONFIG.GIT_BRANCH))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue