Moved version and deezer check from server to app

This commit is contained in:
RemixDev 2020-09-27 19:49:54 +02:00
parent 0be75208fb
commit 4f1d17f7c7
3 changed files with 158 additions and 156 deletions

87
app.py
View file

@ -1,4 +1,7 @@
#!/usr/bin/env python3
import eventlet
requests = eventlet.import_patched('requests')
from deemix.api.deezer import Deezer
from deemix.app.settings import Settings
from deemix.app.queuemanager import QueueManager
@ -10,6 +13,35 @@ from deemix.utils.localpaths import getConfigFolder
import os.path as path
import json
from datetime import datetime
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = path.dirname(path.abspath(path.realpath(__file__)))
return path.join(base_path, relative_path)
class LoginStatus():
"""Login status codes"""
NOT_AVAILABLE = -1
"""Deezer is not Available in your country"""
FAILED = 0
"""Login Failed"""
SUCCESS = 1
"""Login Successfull"""
ALREADY_LOGGED = 2
"""Already logged in"""
FORCED_SUCCESS = 3
"""Forced Login Successfull"""
class deemix:
def __init__(self, portable):
@ -21,6 +53,50 @@ class deemix:
self.chartsList = []
self.homeCache = None
self.currentVersion = None
self.latestVersion = None
self.updateAvailable = False
self.isDeezerAvailable = True
def checkForUpdates(self):
commitFile = resource_path('version.txt')
if path.isfile(commitFile):
print("Checking for updates...")
with open(commitFile, 'r') as f:
self.currentVersion = f.read().strip()
try:
latestVersion = requests.get("https://deemix.app/pyweb/latest")
latestVersion.raise_for_status()
self.latestVersion = latestVersion.text.strip()
except:
self.latestVersion = None
self.updateAvailable = self.compare_versions()
if self.updateAvailable:
print("Update available! Commit: "+self.latestVersion)
else:
print("You're running the latest version")
def compareVersions():
if not self.latestVersion or not self.currentVersion:
return False
(currentDate, currentCommit) = tuple(self.currentVersion.split('-'))
(latestDate, latestCommit) = tuple(self.latestVersion.split('-'))
currentDate = currentDate.split('.')
latestDate = latestDate.split('.')
current = datetime(int(currentDate[0]), int(currentDate[1]), int(currentDate[2]))
latest = datetime(int(latestDate[0]), int(latestDate[1]), int(latestDate[2]))
if latest > current:
return True
elif latest == current:
return latestCommit != currentCommit
else:
return False
def checkDeezerAvailability(self):
body = requests.get("https://www.deezer.com/", headers={'Cookie': 'dz_lang=en; Domain=deezer.com; Path=/; Secure; hostOnly=false;'}).text
title = body[body.find('<title>')+7:body.find('</title>')]
self.isDeezerAvailable = title.strip() != "Deezer will soon be available in your country."
def shutdown(self, interface=None):
if self.set.settings['saveDownloadQueue']:
self.qm.saveQueue(self.configFolder)
@ -43,6 +119,11 @@ class deemix:
f.write(arl)
return arl
def login(self, dz, arl, child):
if not dz.logged_in:
return int(dz.login_via_arl(arl, child))
else:
return LoginStatus.ALREADY_LOGGED
def restoreDownloadQueue(self, dz, interface=None):
self.qm.loadQueue(self.configFolder, self.set.settings, interface)
@ -149,24 +230,22 @@ class deemix:
url = url.split(";")
self.qm.addToQueue(dz, url, self.set.settings, bitrate, interface, ack)
def removeFromQueue(self, uuid, interface=None):
self.qm.removeFromQueue(uuid, interface)
def cancelAllDownloads(self, interface=None):
self.qm.cancelAllDownloads(interface)
def removeFinishedDownloads(self, interface=None):
self.qm.removeFinishedDownloads(interface)
def initDownloadQueue(self):
(queue, queueComplete, queueList, currentItem) = self.qm.getQueue()
return (queue, queueComplete, queueList, currentItem)
def analyzeLink(self, dz, link):
if 'deezer.page.link' in link:
link = requests.get(link).url
type = getTypeFromLink(link)
relID = getIDFromLink(link, type)
if type in ["track", "album"]:

View file

@ -227,7 +227,7 @@ if __name__ == '__main__':
configFolder = portable or getConfigFolder()
x,y,w,h = get_position()
window = MainWindow('deemix', 'http://'+url+':'+str(port), x,y,w,h)
t = Thread(target=run_server, args=(port, url, portable, window))
t = Thread(target=run_server, args=(url, port, portable, window))
else:
t = Thread(target=run_server, args=(port, url, portable))
t.daemon = True

225
server.py
View file

@ -9,16 +9,13 @@ import eventlet
from eventlet import tpool
from eventlet.green import subprocess
requests = eventlet.import_patched('requests')
urlopen = eventlet.import_patched('urllib.request').urlopen
from datetime import datetime
from flask import Flask, render_template, request, session, redirect, copy_current_request_context
from flask_socketio import SocketIO, emit
from werkzeug.middleware.proxy_fix import ProxyFix
from deemix import __version__ as deemixVersion
from app import deemix
from deemix import __version__ as deemix_version
from app import deemix, LoginStatus, resource_path
from deemix.api.deezer import Deezer
from deemix.app.messageinterface import MessageInterface
@ -33,10 +30,21 @@ mimetypes.add_type('text/javascript', '.js')
from engineio.payload import Payload
Payload.max_decode_packets = 500
app = None
gui = None
arl = None
# Disable logging
serverLog = logging.getLogger('werkzeug')
serverLog.disabled = True
logging.getLogger('socketio').setLevel(logging.ERROR)
logging.getLogger('engineio').setLevel(logging.ERROR)
#server.logger.disabled = True
class SocketInterface(MessageInterface):
def send(self, message, value=None):
if value:
socketio.emit(message, value)
else:
socketio.emit(message)
# This allows the frontend to use vue.js
class CustomFlask(Flask):
jinja_options = Flask.jinja_options.copy()
jinja_options.update(dict(
@ -48,99 +56,31 @@ class CustomFlask(Flask):
comment_end_string='#$',
))
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = path.dirname(path.abspath(path.realpath(__file__)))
return path.join(base_path, relative_path)
gui_dir = resource_path(path.join('webui', 'public'))
if not path.exists(gui_dir):
gui_dir = resource_path('webui')
if not path.isfile(path.join(gui_dir, 'index.html')):
# Retrocompatibility with old versions of the app
# Check for public folder and fallback to webui
GUI_DIR = resource_path(path.join('webui', 'public'))
if not path.exists(GUI_DIR):
GUI_DIR = resource_path('webui')
if not path.isfile(path.join(GUI_DIR, 'index.html')):
sys.exit("WebUI not found, please download and add a WebUI")
server = CustomFlask(__name__, static_folder=gui_dir, template_folder=gui_dir, static_url_path="")
server = CustomFlask(__name__, static_folder=GUI_DIR, template_folder=GUI_DIR, static_url_path="")
server.config['SEND_FILE_MAX_AGE_DEFAULT'] = 1 # disable caching
socketio = SocketIO(server)
server.wsgi_app = ProxyFix(server.wsgi_app, x_for=1, x_proto=1)
class SocketInterface(MessageInterface):
def send(self, message, value=None):
if value:
socketio.emit(message, value)
else:
socketio.emit(message)
app = None
gui = None
arl = None
socket_interface = SocketInterface()
loginWindow = False
first_connection = True
serverLog = logging.getLogger('werkzeug')
serverLog.disabled = True
logging.getLogger('socketio').setLevel(logging.ERROR)
logging.getLogger('engineio').setLevel(logging.ERROR)
#server.logger.disabled = True
firstConnection = True
currentVersion = None
latestVersion = None
updateAvailable = False
def compare_versions(currentVersion, latestVersion):
if not latestVersion or not currentVersion:
return False
(currentDate, currentCommit) = tuple(currentVersion.split('-'))
(latestDate, latestCommit) = tuple(latestVersion.split('-'))
currentDate = currentDate.split('.')
latestDate = latestDate.split('.')
current = datetime(int(currentDate[0]), int(currentDate[1]), int(currentDate[2]))
latest = datetime(int(latestDate[0]), int(latestDate[1]), int(latestDate[2]))
if latest > current:
return True
elif latest == current:
return latestCommit != currentCommit
else:
return False
def check_for_updates():
global currentVersion, latestVersion, updateAvailable
commitFile = resource_path('version.txt')
if path.isfile(commitFile):
print("Checking for updates...")
with open(commitFile, 'r') as f:
currentVersion = f.read().strip()
try:
latestVersion = requests.get("https://deemix.app/pyweb/latest")
latestVersion.raise_for_status()
latestVersion = latestVersion.text.strip()
except:
latestVersion = None
if currentVersion and latestVersion:
updateAvailable = compare_versions(currentVersion, latestVersion)
if updateAvailable:
print("Update available! Commit: "+latestVersion)
else:
print("You're running the latest version")
is_deezer_available = True
def check_deezer_availability():
body = requests.get("https://www.deezer.com/", headers={'Cookie': 'dz_lang=en; Domain=deezer.com; Path=/; Secure; hostOnly=false;'}).text
title = body[body.find('<title>')+7:body.find('</title>')]
return title.strip() != "Deezer will soon be available in your country."
def shutdown(interface=None):
def shutdown():
if app is not None:
app.shutdown(interface=interface)
app.shutdown(socket_interface)
socketio.stop()
def shutdown_handler(signalnum, frame):
shutdown()
@server.route('/')
def landing():
return render_template('index.html')
@ -151,27 +91,29 @@ def not_found_handler(e):
@server.route('/shutdown')
def closing():
shutdown(interface=socket_interface)
shutdown()
return 'Server Closed'
serverwide_arl = "--serverwide-arl" in sys.argv
if serverwide_arl:
print("Server-wide ARL enabled.")
@socketio.on('connect')
def on_connect():
session['dz'] = Deezer()
(settings, spotifyCredentials, defaultSettings) = app.getAllSettings()
session['dz'].set_accept_language(settings.get('tagsLanguage'))
emit('init_settings', (settings, spotifyCredentials, defaultSettings))
emit('init_update',
{'currentCommit': currentVersion,
'latestCommit': latestVersion,
'updateAvailable': updateAvailable,
'deemixVersion': deemixVersion}
if first_connection:
app.checkForUpdates()
app.checkDeezerAvailability()
emit('init_update',{
'currentCommit': app.currentVersion,
'latestCommit': app.latestVersion,
'updateAvailable': app.updateAvailable,
'deemixVersion': deemix_version
}
)
if serverwide_arl:
if arl:
login(arl)
else:
emit('init_autologin')
@ -184,9 +126,11 @@ def on_connect():
'queueList': queueList,
'currentItem': currentItem
})
emit('init_home', app.get_home(session['dz']))
emit('init_charts', app.get_charts(session['dz']))
if not is_deezer_available:
if not app.isDeezerAvailable:
emit('deezerNotAvailable')
@socketio.on('get_home_data')
@ -207,49 +151,38 @@ def get_settings_data():
@socketio.on('login')
def login(arl, force=False, child=0):
global firstConnection, is_deezer_available
if not is_deezer_available:
emit('logged_in', {'status': -1, 'arl': arl, 'user': session['dz'].user})
global first_connection
if not app.isDeezerAvailable:
emit('logged_in', {'status': LoginStatus.NOT_AVAILABLE, 'arl': arl, 'user': session['dz'].user})
return
if child == None:
child = 0
if child == None: child = 0
arl = arl.strip()
emit('logging_in')
if not session['dz'].logged_in:
result = session['dz'].login_via_arl(arl, int(child))
else:
if force:
session['dz'] = Deezer()
result = session['dz'].login_via_arl(arl, int(child))
if result == 1:
result = 3
else:
result = 2
if force: session['dz'] = Deezer()
result = app.login(session['dz'], arl, int(child))
if force and result == LoginStatus.SUCCESS: result = LoginStatus.FORCED_SUCCESS
emit('logged_in', {'status': result, 'arl': arl, 'user': session['dz'].user})
if firstConnection and result in [1, 3]:
firstConnection = False
if first_connection and result in [LoginStatus.SUCCESS, LoginStatus.FORCED_SUCCESS]:
first_connection = False
app.restoreDownloadQueue(session['dz'], socket_interface)
if result != 0:
emit('familyAccounts', session['dz'].childs)
emit('init_favorites', app.getUserFavorites(session['dz']))
@socketio.on('changeAccount')
def changeAccount(child):
emit('accountChanged', session['dz'].change_account(int(child)))
emit('init_favorites', app.getUserFavorites(session['dz']))
@socketio.on('logout')
def logout():
status = 0
if session['dz'].logged_in:
session['dz'] = Deezer()
status = 0
else:
status = 1
emit('logged_out', status)
emit('logged_out')
@socketio.on('mainSearch')
def mainSearch(data):
@ -258,7 +191,6 @@ def mainSearch(data):
result['ack'] = data.get('ack')
emit('mainSearch', result)
@socketio.on('search')
def search(data):
if data['term'].strip() != "":
@ -292,29 +224,22 @@ def newReleases(data):
def queueRestored():
app.queueRestored(session['dz'], socket_interface)
@socketio.on('addToQueue')
def addToQueue(data):
result = app.addToQueue(session['dz'], data['url'], data['bitrate'], interface=socket_interface, ack=data.get('ack'))
if result == "Not logged in":
emit('loginNeededToDownload')
@socketio.on('removeFromQueue')
def removeFromQueue(uuid):
app.removeFromQueue(uuid, interface=socket_interface)
@socketio.on('removeFinishedDownloads')
def removeFinishedDownloads():
app.removeFinishedDownloads(interface=socket_interface)
@socketio.on('cancelAllDownloads')
def cancelAllDownloads():
app.cancelAllDownloads(interface=socket_interface)
@socketio.on('saveSettings')
def saveSettings(settings, spotifyCredentials, spotifyUser):
app.saveSettings(settings, session['dz'])
@ -323,7 +248,6 @@ def saveSettings(settings, spotifyCredentials, spotifyUser):
if spotifyUser != False:
emit('updated_userSpotifyPlaylists', app.updateUserSpotifyPlaylists(spotifyUser))
@socketio.on('getTracklist')
def getTracklist(data):
if data['type'] == 'artist':
@ -355,8 +279,6 @@ def getTracklist(data):
@socketio.on('analyzeLink')
def analyzeLink(link):
if 'deezer.page.link' in link:
link = urlopen(link).url
(type, data) = app.analyzeLink(session['dz'], link)
if len(data):
emit('analyze_'+type, data)
@ -411,7 +333,7 @@ def selectDownloadFolder():
emit('downloadFolderSelected', result)
else:
print("Can't open folder selection, you're not running the gui")
def doSelectDowloadFolder():
gui.selectDownloadFolder_trigger.emit()
gui._selectDownloadFolder_semaphore.acquire()
@ -429,41 +351,42 @@ def applogin():
emit('logged_in', {'status': 2, 'user': session['dz'].user})
else:
print("Can't open login page, you're not running the gui")
def dologin():
gui.appLogin_trigger.emit()
gui._appLogin_semaphore.acquire()
return gui.arl
def run_server(port, host="127.0.0.1", portable=None, mainWindow=None):
global app, gui, arl, is_deezer_available
def run_server(host="127.0.0.1", port=6595, portable=None, guiWindow=None, server_arl=False):
global app, gui, arl
app = deemix(portable)
gui = mainWindow
if serverwide_arl:
gui = guiWindow
if server_arl:
print("Server-wide ARL enabled.")
arl = app.getConfigArl()
check_for_updates()
if not check_deezer_availability():
is_deezer_available = False
print("Deezer is not available in your country, you should use a VPN to use this app.")
print("Starting server at http://" + host + ":" + str(port))
socketio.run(server, host=host, port=port)
def shutdown_handler(signalnum, frame):
shutdown()
if __name__ == '__main__':
port = 6595
host = "127.0.0.1"
portable = None
port = 6595
if len(sys.argv) >= 2:
try:
port = int(sys.argv[1])
except ValueError:
pass
portable = None
if '--portable' in sys.argv:
portable = path.join(path.dirname(path.realpath(__file__)), 'config')
if '--host' in sys.argv:
host = str(sys.argv[sys.argv.index("--host")+1])
serverwide_arl = "--serverwide-arl" in sys.argv
signal.signal(signal.SIGINT, shutdown_handler)
signal.signal(signal.SIGTERM, shutdown_handler)
run_server(port, host, portable)
run_server(host, port, portable, server_arl=serverwide_arl)