deemix-gui-pyweb/deemix-pyweb.py

260 lines
8.8 KiB
Python

#!/usr/bin/env python3
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QDialog, QVBoxLayout
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage, QWebEngineProfile
from PyQt5.QtCore import QUrl, pyqtSignal
from PyQt5.QtGui import QIcon
import json
import webbrowser
from threading import Thread, Semaphore
import signal
import sys
from pathlib import Path
from os.path import sep as pathSep
from os import makedirs
from time import sleep
from server import run_server
from http.client import HTTPConnection
from deemix.utils.localpaths import getConfigFolder
if sys.platform == "win32":
import ctypes
myappid = 'RemixDev.deemix'
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
class LoginWindow(QDialog):
class CustomPage(QWebEnginePage):
def acceptNavigationRequest(self, url, type, main):
if url.toString() == "https://www.deezer.com/":
url = QUrl('https://www.deezer.com/ajax/gw-light.php?method=user.getArl&input=3&api_version=1.0&api_token=null')
self.setUrl(url)
return False
return super().acceptNavigationRequest(url, type, main)
def __init__(self, parent):
super().__init__(parent)
self.webview = QWebEngineView()
profile = QWebEngineProfile(self.webview)
profile.setPersistentCookiesPolicy(QWebEngineProfile.NoPersistentCookies)
profile.setPersistentStoragePath(str(configFolder / "QtWebEngine" / "Storage" / "OffTheRecord"))
self.page = self.CustomPage(profile, self.webview)
self.page.loadFinished.connect(self.checkURL)
self.webview.setPage(self.page)
self.webview.setUrl(QUrl("https://deezer.com/login"))
layout = QVBoxLayout()
layout.addWidget(self.webview)
self.setLayout(layout)
self.arl = None
self.exec_()
def checkURL(self, ok):
url = self.webview.url().toString()
if 'user.getArl' in url:
sleep(1)
self.webview.page().toPlainText(self.saveARL)
def saveARL(self, body):
if body.startswith("{"):
self.arl = json.loads(body)['results']
self.accept()
class MainWindow(QMainWindow):
selectDownloadFolder_trigger = pyqtSignal()
appLogin_trigger = pyqtSignal()
class MainWebpage(QWebEnginePage):
def __init__(self, profile, parent):
super().__init__(profile, parent)
actions = [
QWebEnginePage.Stop,
QWebEnginePage.Reload,
QWebEnginePage.ReloadAndBypassCache,
QWebEnginePage.PasteAndMatchStyle,
QWebEnginePage.OpenLinkInThisWindow,
QWebEnginePage.OpenLinkInNewWindow,
QWebEnginePage.OpenLinkInNewTab,
QWebEnginePage.OpenLinkInNewBackgroundTab,
QWebEnginePage.DownloadLinkToDisk,
QWebEnginePage.DownloadImageToDisk,
QWebEnginePage.DownloadMediaToDisk,
QWebEnginePage.InspectElement,
QWebEnginePage.RequestClose,
QWebEnginePage.SavePage,
QWebEnginePage.ViewSource
]
for a in actions:
self.action(a).setVisible(False)
class ExternalWebpage(QWebEnginePage):
def __init__(self, parent):
super().__init__(parent)
self.urlChanged.connect(self.open_browser)
def open_browser(self, url):
page = self.sender()
webbrowser.open(url.toString(), 2, True)
page.deleteLater()
def createWindow(self, _type):
page = None
if _type == QWebEnginePage.WebBrowserTab:
page = self.ExternalWebpage(self)
return page
def __init__(self, title, url, x=None, y=None, w=800, h=600):
super().__init__()
startMaximized = False
if w == -1 or h == -1:
self.resize(800, 600)
startMaximized = True
else:
self.resize(w, h)
self.setWindowTitle(title)
self.setWindowIcon(QIcon(str(appDir / 'icon.ico')))
self.setMinimumSize(800, 600)
self.webview = QWebEngineView()
self.profile = QWebEngineProfile("Default", self.webview)
self.profile.setCachePath(str(configFolder / "QtWebEngine" / "Cache" / "Default"))
self.profile.setPersistentStoragePath(str(configFolder / "QtWebEngine" / "Storage" / "Default"))
self.page = self.MainWebpage(self.profile, self.webview)
self.page.loadFinished.connect(self.finishLoading)
self.webview.setPage(self.page)
self.setCentralWidget(self.webview)
self.url = url
if dev:
self.dev_tools = QWebEngineView()
self.webview.page().setDevToolsPage(self.dev_tools.page())
self.dev_tools.show()
self.downloadFolder = None
self.selectDownloadFolder_trigger.connect(self.selectDownloadFolder)
self._selectDownloadFolder_semaphore = Semaphore(0)
self.arl = None
self.appLogin_trigger.connect(self.appLogin)
self._appLogin_semaphore = Semaphore(0)
if x is None or y is None or startMaximized:
center = QApplication.desktop().availableGeometry().center() - self.rect().center()
self.move(center.x(), center.y())
else:
self.move(x, y)
if startMaximized: self.showMaximized()
def showWindow(self):
self.webview.setUrl(QUrl(self.url))
self.show()
def selectDownloadFolder(self):
filename = QFileDialog.getExistingDirectory(self, "Select Download Folder", options=QFileDialog.ShowDirsOnly)
self.downloadFolder = filename.replace('/', pathSep)
self._selectDownloadFolder_semaphore.release()
def appLogin(self):
self.arl = None
loginWindow = LoginWindow(self)
self.arl = loginWindow.arl
self._appLogin_semaphore.release()
loginWindow.page.deleteLater()
loginWindow.webview.deleteLater()
loginWindow.deleteLater()
def closeEvent(self, event):
x = int(self.x())
y = int(self.y())
w = int(self.width())
h = int(self.height())
if x < 0: x = 0
if y < 0: y = 0
if self.isMaximized():
w = -1
h = -1
with open(configFolder / '.UIposition', 'w') as f:
f.write("|".join([str(x),str(y),str(w),str(h)]))
self.page.deleteLater()
event.accept()
def finishLoading(self, ok):
if ok: self.webview.page().runJavaScript("window.dispatchEvent(new Event('pywebviewready'))")
def url_ok(url, port):
try:
conn = HTTPConnection(url, port)
conn.request('GET', '/')
r = conn.getresponse()
return r.status == 200
except:
print("Server not started")
return False
def get_position():
if (configFolder / '.UIposition').is_file():
try:
with open(configFolder / '.UIposition', 'r') as f:
(x,y,w,h) = f.read().strip().split("|")
x = int(x)
y = int(y)
w = int(w)
h = int(h)
if x < 0: x = 0
if y < 0: y = 0
except:
x = None
y = None
w = 800
h = 600
else:
x = None
y = None
w = 800
h = 600
return (x,y,w,h)
url = "127.0.0.1"
port = 6595
def server_shutdown_handler(signalnum, frame):
conn = HTTPConnection(url, port)
conn.request('GET', '/shutdown')
if __name__ == '__main__':
if len(sys.argv) >= 2:
try:
port = int(sys.argv[1])
except ValueError:
pass
portable = None
appDir = Path(__file__).parent
if '--portable' in sys.argv:
portable = appDir / 'config'
server = '--server' in sys.argv or '-s' in sys.argv
dev = '--dev' in sys.argv
if not server:
signal.signal(signal.SIGINT, signal.SIG_DFL)
signal.signal(signal.SIGTERM, signal.SIG_DFL)
app = QApplication([])
configFolder = portable or getConfigFolder()
x,y,w,h = get_position()
makedirs(configFolder / "QtWebEngine", exist_ok=True)
window = MainWindow('deemix', 'http://localhost:'+str(port), x,y,w,h)
t = Thread(target=run_server, args=(url, port, portable, window))
else:
signal.signal(signal.SIGINT, server_shutdown_handler)
signal.signal(signal.SIGTERM, server_shutdown_handler)
t = Thread(target=run_server, args=(url, port, portable))
t.daemon = True
t.start()
if not server:
while not url_ok(url, port):
sleep(1)
window.showWindow()
app.exec_()
conn = HTTPConnection(url, port)
conn.request('GET', '/shutdown')
t.join()