diff --git a/core/__pycache__/about_dialog.cpython-39.pyc b/core/__pycache__/about_dialog.cpython-39.pyc
new file mode 100644
index 0000000..85d0e96
Binary files /dev/null and b/core/__pycache__/about_dialog.cpython-39.pyc differ
diff --git a/core/__pycache__/alert_dialog.cpython-39.pyc b/core/__pycache__/alert_dialog.cpython-39.pyc
new file mode 100644
index 0000000..85684aa
Binary files /dev/null and b/core/__pycache__/alert_dialog.cpython-39.pyc differ
diff --git a/core/__pycache__/confirm_dialog.cpython-39.pyc b/core/__pycache__/confirm_dialog.cpython-39.pyc
new file mode 100644
index 0000000..d7d9671
Binary files /dev/null and b/core/__pycache__/confirm_dialog.cpython-39.pyc differ
diff --git a/core/__pycache__/download_manager.cpython-39.pyc b/core/__pycache__/download_manager.cpython-39.pyc
new file mode 100644
index 0000000..bb96444
Binary files /dev/null and b/core/__pycache__/download_manager.cpython-39.pyc differ
diff --git a/core/__pycache__/input_dialog.cpython-39.pyc b/core/__pycache__/input_dialog.cpython-39.pyc
new file mode 100644
index 0000000..39388eb
Binary files /dev/null and b/core/__pycache__/input_dialog.cpython-39.pyc differ
diff --git a/core/__pycache__/main_window.cpython-39.pyc b/core/__pycache__/main_window.cpython-39.pyc
new file mode 100644
index 0000000..bfdcf70
Binary files /dev/null and b/core/__pycache__/main_window.cpython-39.pyc differ
diff --git a/core/__pycache__/mini_player_dialog.cpython-39.pyc b/core/__pycache__/mini_player_dialog.cpython-39.pyc
new file mode 100644
index 0000000..79dae64
Binary files /dev/null and b/core/__pycache__/mini_player_dialog.cpython-39.pyc differ
diff --git a/core/__pycache__/options_dialog.cpython-39.pyc b/core/__pycache__/options_dialog.cpython-39.pyc
new file mode 100644
index 0000000..018ac32
Binary files /dev/null and b/core/__pycache__/options_dialog.cpython-39.pyc differ
diff --git a/core/__pycache__/tray_icon.cpython-39.pyc b/core/__pycache__/tray_icon.cpython-39.pyc
new file mode 100644
index 0000000..bb119f9
Binary files /dev/null and b/core/__pycache__/tray_icon.cpython-39.pyc differ
diff --git a/core/__pycache__/web_engine_page.cpython-39.pyc b/core/__pycache__/web_engine_page.cpython-39.pyc
new file mode 100644
index 0000000..748cfaf
Binary files /dev/null and b/core/__pycache__/web_engine_page.cpython-39.pyc differ
diff --git a/core/__pycache__/web_engine_view.cpython-39.pyc b/core/__pycache__/web_engine_view.cpython-39.pyc
new file mode 100644
index 0000000..8fa140c
Binary files /dev/null and b/core/__pycache__/web_engine_view.cpython-39.pyc differ
diff --git a/core/about_dialog.py b/core/about_dialog.py
index d54f2b5..08d68d1 100644
--- a/core/about_dialog.py
+++ b/core/about_dialog.py
@@ -1,4 +1,3 @@
-#about_dialog.py
from PyQt5.QtWidgets import QDialog
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
@@ -31,7 +30,7 @@ def __init__(
self._init_connect()
def _init_content(self):
- pass
+ self.BodyLabel_2.setText(self.version)
def _init_connect(self):
self.PushButton.clicked.connect(self.close)
diff --git a/core/alert_dialog.py b/core/alert_dialog.py
index 9f8fce2..868738e 100644
--- a/core/alert_dialog.py
+++ b/core/alert_dialog.py
@@ -1,4 +1,3 @@
-#alert_dialog.py
from PyQt5.QtWidgets import QDialog, QSizePolicy
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QIcon
diff --git a/core/confirm_dialog.py b/core/confirm_dialog.py
index cb3c6c6..ac0014f 100644
--- a/core/confirm_dialog.py
+++ b/core/confirm_dialog.py
@@ -1,4 +1,3 @@
-#confirm_dialog.py
from PyQt5.QtWidgets import QDialog
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
diff --git a/core/css/main.css b/core/css/main.css
index 8c6a7ee..e75a81d 100644
--- a/core/css/main.css
+++ b/core/css/main.css
@@ -3,13 +3,13 @@ QMenuBar{
color: white;
}
QMenuBar::item:selected{
- background-color: rgb(65,65,65);
+ background-color: rgb(60,60,60);
}
QMenu {
background-color: rgb(43,43,43);
color: white;
- border: 1px solid rgb(160,160,160);
+ border: 1px solid rgb(46,46,46);
padding: 2px 2px;
}
QMenu::icon {
@@ -22,7 +22,7 @@ QMenu::item {
margin: 0px;
}
QMenu::item:selected {
- background-color: rgb(65,65,65);
+ background-color: rgb(60,60,60);
}
QMenu::item:disabled:selected {
background-color: rgb(53,53,53);
@@ -33,13 +33,13 @@ QMenu::item:disabled {
}
QMenu::separator {
height: 1px;
- background-color: rgb(128,128,128);
+ background-color: rgb(64,64,64);
margin: 3px 3px;
}
QToolTip {
- background-color: rgb(17,18,20);
+ background-color: rgb(44,44,44);
color: white;
- border: 1px solid rgb(63,65,71);
+ border: 1px solid rgb(55,60,67);
padding: 3px 4px;
}
\ No newline at end of file
diff --git a/core/download_manager.py b/core/download_manager.py
new file mode 100644
index 0000000..05e36a8
--- /dev/null
+++ b/core/download_manager.py
@@ -0,0 +1,26 @@
+from PyQt5.QtCore import pyqtSignal, QObject
+from subprocess import Popen, PIPE
+
+class DownloadManager(QObject):
+ downloadFinished = pyqtSignal(str)
+ downloadError = pyqtSignal(str)
+
+ def __init__(self, current_dir, settings):
+ super().__init__()
+ self.current_dir = current_dir
+ self.settings = settings
+
+ def download_external_process(self, url, download_path, download_type):
+ script_dir = self.settings.value("current_dir")
+ process = Popen(
+ [f'{self.current_dir}/core/download_script.exe',
+ url, download_path, download_type, script_dir],
+ stdout=PIPE,
+ stderr=PIPE
+ )
+ output, error = process.communicate()
+
+ if process.returncode == 0:
+ self.downloadFinished.emit(download_path)
+ else:
+ self.downloadError.emit(str(error))
\ No newline at end of file
diff --git a/core/download_script.exe b/core/download_script.exe
index 3e6068b..519ecd8 100644
Binary files a/core/download_script.exe and b/core/download_script.exe differ
diff --git a/core/input_dialog.py b/core/input_dialog.py
index a0b209a..c0120dd 100644
--- a/core/input_dialog.py
+++ b/core/input_dialog.py
@@ -1,4 +1,3 @@
-#input_dialog.py
from PyQt5.QtWidgets import QDialog
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
diff --git a/core/js/get_play_pause_state.js b/core/js/get_play_pause_state.js
new file mode 100644
index 0000000..6e1e81b
--- /dev/null
+++ b/core/js/get_play_pause_state.js
@@ -0,0 +1 @@
+var video = document.getElementsByTagName('video')[0]; video.paused;
\ No newline at end of file
diff --git a/core/js/get_track_image.js b/core/js/get_track_image.js
new file mode 100644
index 0000000..a5963e3
--- /dev/null
+++ b/core/js/get_track_image.js
@@ -0,0 +1 @@
+document.querySelector(".image.style-scope.ytmusic-player-bar").getAttribute("src")
\ No newline at end of file
diff --git a/core/js/next_track.js b/core/js/next_track.js
new file mode 100644
index 0000000..18ca2ed
--- /dev/null
+++ b/core/js/next_track.js
@@ -0,0 +1 @@
+document.querySelector(".next-button").click();
\ No newline at end of file
diff --git a/core/js/play_pause_track.js b/core/js/play_pause_track.js
new file mode 100644
index 0000000..ab8488b
--- /dev/null
+++ b/core/js/play_pause_track.js
@@ -0,0 +1,2 @@
+var video = document.getElementsByTagName('video')[0];
+if (video.paused) video.play(); else video.pause();
\ No newline at end of file
diff --git a/core/js/previous_track.js b/core/js/previous_track.js
new file mode 100644
index 0000000..b2ee3dc
--- /dev/null
+++ b/core/js/previous_track.js
@@ -0,0 +1 @@
+document.querySelector(".previous-button").click();
\ No newline at end of file
diff --git a/core/main_window.py b/core/main_window.py
index e874d76..f77f13a 100644
--- a/core/main_window.py
+++ b/core/main_window.py
@@ -1,24 +1,16 @@
-#main_window.py
from PyQt5.QtWidgets import (
QMainWindow, QApplication, QFileDialog, QShortcut
)
-from PyQt5.QtGui import (
- QIcon, QKeySequence
-)
-from PyQt5.QtCore import (
- QSize, Qt, QUrl, pyqtSignal, QObject
-)
-from PyQt5.QtWebEngineWidgets import (
- QWebEngineView, QWebEnginePage, QWebEngineSettings
-)
+from PyQt5.QtGui import QIcon, QKeySequence
+from PyQt5.QtCore import QSize, Qt, QUrl
from PyQt5.QtWinExtras import (
QWinThumbnailToolBar, QWinThumbnailToolButton
)
+from PyQt5.QtWebEngineWidgets import QWebEngineSettings
from PyQt5 import uic
from qfluentwidgets import (
- InfoBar, InfoBarPosition, RoundMenu, Action,
- MenuAnimationType, IndeterminateProgressRing,
+ InfoBar, InfoBarPosition, IndeterminateProgressRing,
setTheme, setThemeColor, Theme, SplashScreen,
PushButton, ToolTipFilter, ToolTipPosition
)
@@ -27,196 +19,15 @@
import sys
import requests
import webbrowser
-import subprocess
from threading import Thread
-from pytube import YouTube
+from core.web_engine_page import WebEnginePage
+from core.web_engine_view import WebEngineView
+from core.download_manager import DownloadManager
from core.options_dialog import OptionsDlg
from core.about_dialog import AboutDlg
from core.mini_player_dialog import MiniPlayerDlg
from core.tray_icon import TrayIcon
-from core.alert_dialog import AlertDlg
-from core.confirm_dialog import ConfirmDlg
-from core.input_dialog import InputDlg
-
-class WebEnginePage(QWebEnginePage):
- def acceptNavigationRequest(self, url, _type, isMainFrame):
- if "music.youtube.com" not in url.toString() and "google.com" not in url.toString() and "googlesyndication.com" not in url.toString():
- webbrowser.open_new_tab(url.toString())
- return False
-
- return QWebEnginePage.acceptNavigationRequest(self, url, _type, isMainFrame)
-
- def javaScriptAlert(self, qurl, text):
- dialog = AlertDlg(
- self.parent().name,
- self.parent().current_dir,
- self.view()
- )
- dialog.setText(text)
- reply = dialog.exec_()
-
- def javaScriptConfirm(self, qurl, text):
- dialog = ConfirmDlg(
- self.parent().name,
- self.parent().current_dir,
- self.view()
- )
- dialog.setText(text)
- reply = dialog.exec_()
- return reply == True
-
- def javaScriptPrompt(self, qurl, text, text_value):
- dialog = InputDlg(
- self.parent().name,
- self.parent().current_dir,
- self.view()
- )
- dialog.setText(text)
- dialog.setTextValue(text_value)
- if dialog.exec_():
- return (True, dialog.textValue())
- else:
- return (False, "")
-
-class WebEngineView(QWebEngineView):
- def contextMenuEvent(self, event):
- url = self.window().webview.url().toString()
- menu = RoundMenu(parent=self.window())
-
- go_back_action = Action("Back", shortcut="Left")
- go_back_action.setIcon(
- QIcon(f"{self.window().current_dir}/resources/icons/arrow_back_white_24dp.svg")
- )
- go_back_action.triggered.connect(
- self.window().go_back
- )
- menu.addAction(go_back_action)
-
- go_forward_action = Action("Forward", shortcut="Right")
- go_forward_action.setIcon(
- QIcon(f"{self.window().current_dir}/resources/icons/arrow_forward_white_24dp.svg")
- )
- go_forward_action.triggered.connect(
- self.window().go_forward
- )
- menu.addAction(go_forward_action)
-
- go_home_action = Action("Home", shortcut="Ctrl+H")
- go_home_action.setIcon(
- QIcon(f"{self.window().current_dir}/resources/icons/home_white_24dp.svg")
- )
- go_home_action.triggered.connect(
- self.window().go_home
- )
- menu.addAction(go_home_action)
-
- go_reload_action = Action("Reload", shortcut="Ctrl+R")
- go_reload_action.setIcon(
- QIcon(f"{self.window().current_dir}/resources/icons/refresh_white_24dp.svg")
- )
- go_reload_action.triggered.connect(
- self.window().go_reload
- )
- menu.addAction(go_reload_action)
-
- menu.addSeparator()
-
- download_menu = RoundMenu("Download...", self)
- download_menu.setIcon(
- QIcon(f"{self.window().current_dir}/resources/icons/file_download_white_24dp.svg")
- )
- menu.addMenu(download_menu)
-
- download_track_action = Action('track', shortcut="Ctrl+D")
- download_track_action.triggered.connect(
- lambda: self.window().go_download('track')
- )
- download_menu.addAction(download_track_action)
-
- download_playlist_action = Action('playlist', shortcut="Ctrl+P")
- download_playlist_action.triggered.connect(
- lambda: self.window().go_download('playlist')
- )
- download_menu.addAction(download_playlist_action)
-
- open_mini_player_action = Action("Mini-Player", shortcut="Ctrl+M")
- open_mini_player_action.setIcon(
- QIcon(f"{self.window().current_dir}/resources/icons/picture_in_picture_white_24dp.svg")
- )
- open_mini_player_action.triggered.connect(
- self.window().open_mini_player
- )
- menu.addAction(open_mini_player_action)
-
- menu.addSeparator()
-
- open_settings_action = Action("Settings", shortcut="Ctrl+S")
- open_settings_action.setIcon(
- QIcon(f"{self.window().current_dir}/resources/icons/settings_white_24dp.svg")
- )
- open_settings_action.triggered.connect(
- self.window().open_settings_dialog
- )
- menu.addAction(open_settings_action)
-
- menu.addSeparator()
-
- bug_report_action = Action("Bug Report")
- bug_report_action.setIcon(
- QIcon(f"{self.window().current_dir}/resources/icons/bug_report_white_24dp.svg")
- )
- bug_report_action.triggered.connect(lambda:
- webbrowser.open_new_tab(
- "https://github.com/deeffest/Youtube-Music-Desktop-Player/issues/new/choose"
- )
- )
- menu.addAction(bug_report_action)
-
- open_about_action = Action("About...")
- open_about_action.setIcon(
- QIcon(f"{self.window().current_dir}/resources/icons/info_white_24dp.svg")
- )
- open_about_action.triggered.connect(
- self.window().open_about_dialog
- )
- menu.addAction(open_about_action)
-
- if not "watch" in url:
- download_track_action.setEnabled(False)
- open_mini_player_action.setEnabled(False)
- if not "playlist" in url:
- download_playlist_action.setEnabled(False)
-
- if not self.page().history().canGoForward():
- go_forward_action.setEnabled(False)
- if not self.page().history().canGoBack():
- go_back_action.setEnabled(False)
-
- menu.exec(event.globalPos(), aniType=MenuAnimationType.DROP_DOWN)
-
-class DownloadManager(QObject):
- downloadFinished = pyqtSignal(str)
- downloadError = pyqtSignal(str)
-
- def __init__(self, current_dir, settings):
- super().__init__()
- self.current_dir = current_dir
- self.settings = settings
-
- def download_external_process(self, url, download_path, download_type):
- script_dir = self.settings.value("current_dir")
- process = subprocess.Popen(
- [f'{self.current_dir}/core/download_script.exe', url, download_path, download_type, script_dir],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE
- )
- output, error = process.communicate()
-
- if process.returncode == 0:
- self.downloadFinished.emit(download_path)
- else:
- self.downloadError.emit(error.decode('utf-8'))
class Window(QMainWindow):
def __init__(
@@ -487,6 +298,8 @@ def on_load_progress(self, progress):
with open(f"{self.current_dir}/core/js/add_styles.js", "r") as js_file:
self.webview.page().runJavaScript(js_file.read())
+
+ self.update_play_pause_icon()
else:
self.ProgressBar.setValue(progress)
if self.ProgressBar.isHidden():
@@ -537,43 +350,49 @@ def create_win_toolbar_buttons(self):
self.win_toolbar.addButton(self.tool_btn_next)
def previous_track(self):
- self.webview.page().runJavaScript(
- 'document.querySelector(".previous-button").click();'
- )
+ with open(f"{self.current_dir}/core/js/previous_track.js", "r") as js_file:
+ self.webview.page().runJavaScript(js_file.read())
def next_track(self):
- self.webview.page().runJavaScript(
- 'document.querySelector(".next-button").click();'
- )
+ with open(f"{self.current_dir}/core/js/next_track.js", "r") as js_file:
+ self.webview.page().runJavaScript(js_file.read())
def play_pause_track(self):
- script = "var video = document.getElementsByTagName('video')[0];" \
- "if (video.paused) video.play(); else video.pause();"
- self.webview.page().runJavaScript(script)
-
+ with open(f"{self.current_dir}/core/js/play_pause_track.js", "r") as js_file:
+ self.webview.page().runJavaScript(js_file.read())
self.update_play_pause_icon()
def update_play_pause_icon(self):
- self.webview.page().runJavaScript(
- "var video = document.getElementsByTagName('video')[0]; video.paused;",
- self.set_play_pause_icon
- )
-
+ with open(f"{self.current_dir}/core/js/get_play_pause_state.js", "r") as js_file:
+ self.webview.page().runJavaScript(js_file.read(), self.set_play_pause_icon)
+
def set_play_pause_icon(self, is_paused):
- if is_paused:
- self.tool_btn_play_pause.setIcon(QIcon(
- f"{self.current_dir}/resources/icons/win_toolbar_icons/play_arrow_white_24dp.svg"
- ))
- self.tray_icon.play_pause_action.setIcon(QIcon(
- f"{self.current_dir}/resources/icons/play_arrow_white_24dp.svg"
- ))
+ if is_paused:
+ if "watch" in self.webview.url().toString():
+ self.tool_btn_play_pause.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/win_toolbar_icons/play_arrow_white_24dp.svg"
+ ))
+ self.tray_icon.play_pause_action.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/play_arrow_white_24dp.svg"
+ ))
+ else:
+ self.tool_btn_play_pause.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/disabled_win_toolbar_icons/play_arrow_white_24dp.svg"
+ ))
+ self.tray_icon.play_pause_action.setEnabled(False)
else:
- self.tool_btn_play_pause.setIcon(QIcon(
- f"{self.current_dir}/resources/icons/win_toolbar_icons/pause_white_24dp.svg"
- ))
- self.tray_icon.play_pause_action.setIcon(QIcon(
- f"{self.current_dir}/resources/icons/pause_white_24dp.svg"
- ))
+ if "watch" in self.webview.url().toString():
+ self.tool_btn_play_pause.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/win_toolbar_icons/pause_white_24dp.svg"
+ ))
+ self.tray_icon.play_pause_action.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/pause_white_24dp.svg"
+ ))
+ else:
+ self.tool_btn_play_pause.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/disabled_win_toolbar_icons/pause_white_24dp.svg"
+ ))
+ self.tray_icon.play_pause_action.setEnabled(False)
def _init_window(self):
self.setWindowTitle(self.name)
@@ -614,13 +433,41 @@ def update_url(self, url):
if "watch" in url.toString():
self.tool_btn_previous.setEnabled(True)
- self.tool_btn_next.setEnabled(True)
+ self.tool_btn_previous.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/win_toolbar_icons/skip_previous_white_24dp.svg"
+ ))
+ self.tray_icon.previous_track_action.setEnabled(True)
+
self.tool_btn_play_pause.setEnabled(True)
+ self.tool_btn_play_pause.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/win_toolbar_icons/pause_white_24dp.svg"
+ ))
+ self.tray_icon.play_pause_action.setEnabled(True)
+
+ self.tool_btn_next.setEnabled(True)
+ self.tool_btn_next.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/win_toolbar_icons/skip_next_white_24dp.svg"
+ ))
+ self.tray_icon.next_track_action.setEnabled(True)
else:
self.tool_btn_previous.setEnabled(False)
- self.tool_btn_next.setEnabled(False)
+ self.tool_btn_previous.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/disabled_win_toolbar_icons/skip_previous_white_24dp.svg"
+ ))
+ self.tray_icon.previous_track_action.setEnabled(False)
+
self.tool_btn_play_pause.setEnabled(False)
-
+ self.tool_btn_play_pause.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/disabled_win_toolbar_icons/pause_white_24dp.svg"
+ ))
+ self.tray_icon.play_pause_action.setEnabled(False)
+
+ self.tool_btn_next.setEnabled(False)
+ self.tool_btn_next.setIcon(QIcon(
+ f"{self.current_dir}/resources/icons/disabled_win_toolbar_icons/skip_next_white_24dp.svg"
+ ))
+ self.tray_icon.next_track_action.setEnabled(False)
+
def check_for_updates(self, startup=None):
response = requests.get(
"https://api.github.com/repos/deeffest/Youtube-Music-Desktop-Player/releases/latest"
@@ -684,7 +531,7 @@ def resizeEvent(self, event):
self.settings.setValue("last_window_size", event.size())
self.label.setMaximumWidth(self.width() * 0.8)
- def closeInTray(self):
+ def close_in_tray(self):
sys.exit(0)
def closeEvent(self, event):
diff --git a/core/mini_player_dialog.py b/core/mini_player_dialog.py
index a4b59fb..fd24508 100644
--- a/core/mini_player_dialog.py
+++ b/core/mini_player_dialog.py
@@ -42,6 +42,7 @@ def __init__(
)
self._init_window()
+ self._init_attributes()
self._init_content()
self._init_connect()
@@ -49,6 +50,7 @@ def __init__(
def _init_content(self):
self.change_info(self.window.webview.url())
+ self.update_play_pause_icon()
self.ToolButton.setIcon(
QIcon(f"{self.current_dir}/resources/icons/close_white_24dp.svg")
@@ -70,27 +72,25 @@ def _init_connect(self):
self.ToolButton.clicked.connect(self.close)
self.ToolButton_2.clicked.connect(lambda: self.showMinimized())
self.TransparentToolButton_2.clicked.connect(self.play_pause_track)
- self.TransparentToolButton.clicked.connect(self.previous_track)
- self.TransparentToolButton_3.clicked.connect(self.next_track)
- self.window.webview.urlChanged.connect(self.update_info)
- self.window.webview.titleChanged.connect(self.change_title)
+ self.TransparentToolButton.clicked.connect(self.window.previous_track)
+ self.TransparentToolButton_3.clicked.connect(self.window.next_track)
+ self.window.webview.titleChanged.connect(self.title_changed)
self.PillToolButton.clicked.connect(self.toggle_on_top_hint)
- self.tool_btn_previous.clicked.connect(self.previous_track)
- self.tool_btn_next.clicked.connect(self.next_track)
+ self.tool_btn_previous.clicked.connect(self.window.previous_track)
+ self.tool_btn_next.clicked.connect(self.window.next_track)
self.tool_btn_play_pause.clicked.connect(self.play_pause_track)
- def play_pause_track(self):
- script = "var video = document.getElementsByTagName('video')[0];" \
- "if (video.paused) video.play(); else video.pause();"
- self.window.webview.page().runJavaScript(script)
+ def _init_attributes(self):
+ self.previous_url = self.window.webview.url()
+ def play_pause_track(self):
+ with open(f"{self.current_dir}/core/js/play_pause_track.js", "r") as js_file:
+ self.window.webview.page().runJavaScript(js_file.read())
self.update_play_pause_icon()
def update_play_pause_icon(self):
- self.window.webview.page().runJavaScript(
- "var video = document.getElementsByTagName('video')[0]; video.paused;",
- self.set_play_pause_icon
- )
+ with open(f"{self.current_dir}/core/js/get_play_pause_state.js", "r") as js_file:
+ self.window.webview.page().runJavaScript(js_file.read(), self.set_play_pause_icon)
def set_play_pause_icon(self, is_paused):
if is_paused:
@@ -109,10 +109,8 @@ def set_play_pause_icon(self, is_paused):
))
def set_track_image(self):
- self.window.webview.page().runJavaScript(
- 'document.querySelector(".image.style-scope.ytmusic-player-bar").getAttribute("src")',
- self.displayImage
- )
+ with open(f"{self.current_dir}/core/js/get_track_image.js", "r") as js_file:
+ self.window.webview.page().runJavaScript(js_file.read(), self.displayImage)
def displayImage(self, url: str) -> None:
if url:
@@ -126,16 +124,6 @@ def displayImage(self, url: str) -> None:
except Exception as e:
print(e)
- def previous_track(self):
- self.window.webview.page().runJavaScript(
- 'document.querySelector(".previous-button").click();'
- )
-
- def next_track(self):
- self.window.webview.page().runJavaScript(
- 'document.querySelector(".next-button").click();'
- )
-
def mouseMoveEvent(self, event: QMouseEvent):
if event.buttons() == Qt.LeftButton and self.drag_position:
if not self.isDragging:
@@ -196,11 +184,13 @@ def update_info(self, url):
def change_info(self, url):
self.set_track_image()
- self.update_play_pause_icon()
self.update_info(url)
- def change_title(self, title):
- self.set_track_image()
+ def title_changed(self, title):
+ if self.window.webview.url() != self.previous_url:
+ self.change_info(self.window.webview.url())
+ self.previous_url = self.window.webview.url()
+
self.update_play_pause_icon()
self.setWindowTitle(title)
diff --git a/core/options_dialog.py b/core/options_dialog.py
index d26063f..99dc3b0 100644
--- a/core/options_dialog.py
+++ b/core/options_dialog.py
@@ -1,4 +1,3 @@
-#options_dialog.py
from PyQt5.QtWidgets import QDialog
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
diff --git a/core/tray_icon.py b/core/tray_icon.py
index 442595b..50f55fe 100644
--- a/core/tray_icon.py
+++ b/core/tray_icon.py
@@ -58,7 +58,7 @@ def _init_content(self):
menu.addSeparator()
- self.exit_action = Action('Exit', triggered=self.window.closeInTray)
+ self.exit_action = Action('Exit', triggered=self.window.close_in_tray)
self.exit_action.setIcon(QIcon(
f"{self.current_dir}/resources/icons/close_white_24dp.svg"))
menu.addAction(self.exit_action)
diff --git a/core/ui/about_dialog.ui b/core/ui/about_dialog.ui
index ecfb435..db7f850 100644
--- a/core/ui/about_dialog.ui
+++ b/core/ui/about_dialog.ui
@@ -6,8 +6,8 @@
0
0
- 480
- 296
+ 431
+ 306
@@ -81,11 +81,55 @@
-
-
-
- <html><head/><body><p><span style=" font-size:18pt;">Youtube Music Desktop Player </span><span style=" font-size:14pt; color:#d3d3d3;">v1.1.1</span></p></body></html>
+
+
+ 0
-
+
-
+
+
+ <html><head/><body><p><span style=" font-size:18pt;">Youtube Music Desktop Player</span></p></body></html>
+
+
+
+ -
+
+
+ 6
+
+
-
+
+
+ Current app version:
+
+
+
+ -
+
+
+
+
+
+ 1.1.2
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
@@ -102,13 +146,13 @@
0
- 100
+ 110
16777215
- 100
+ 110
@@ -120,6 +164,9 @@
<html><head/><body><p><span style=" color:#d3d3d3;">Displays Youtube Music site using QWebEngine to make your music listening experience even more convenient.</span></p><p><span style=" font-size:11pt; color:#d3d3d3;">Created with </span><a href="https://www.riverbankcomputing.com/software/pyqt/intro"><span style=" text-decoration: underline; color:#d3d3d3;">PyQt5</span></a><span style=" font-size:11pt; color:#d3d3d3;"> + </span><a href="https://github.com/zhiyiYo/PyQt-Fluent-Widgets"><span style=" text-decoration: underline; color:#d3d3d3;">PyQt-Fluent-Widgets</span></a><span style=" font-size:11pt; color:#d3d3d3;"> and distributed under the </span><a href="https://www.gnu.org/licenses/gpl-3.0.html"><span style=" text-decoration: underline; color:#d3d3d3;">GNU GPL v3</span></a><span style=" font-size:11pt; color:#d3d3d3;"> license, source code is available on </span><a href="https://github.com/deeffest/Youtube-Music-Desktop-Player"><span style=" text-decoration: underline; color:#d3d3d3;">GitHub</span></a><span style=" font-size:11pt; color:#d3d3d3;">. </span></p></body></html>
+
+ false
+
true
diff --git a/core/web_engine_page.py b/core/web_engine_page.py
new file mode 100644
index 0000000..879db74
--- /dev/null
+++ b/core/web_engine_page.py
@@ -0,0 +1,50 @@
+from PyQt5.QtCore import Qt
+from PyQt5.QtWebEngineWidgets import (
+ QWebEnginePage
+)
+
+from core.alert_dialog import AlertDlg
+from core.confirm_dialog import ConfirmDlg
+from core.input_dialog import InputDlg
+
+class WebEnginePage(QWebEnginePage):
+ def acceptNavigationRequest(self, url, _type, isMainFrame):
+ if ("music.youtube.com" not in url.toString() and
+ "google.com" not in url.toString() and
+ "googlesyndication.com" not in url.toString()):
+ webbrowser.open_new_tab(url.toString())
+ return False
+
+ return QWebEnginePage.acceptNavigationRequest(self, url, _type, isMainFrame)
+
+ def javaScriptAlert(self, qurl, text):
+ dialog = AlertDlg(
+ self.parent().name,
+ self.parent().current_dir,
+ self.view()
+ )
+ dialog.setText(text)
+ reply = dialog.exec_()
+
+ def javaScriptConfirm(self, qurl, text):
+ dialog = ConfirmDlg(
+ self.parent().name,
+ self.parent().current_dir,
+ self.view()
+ )
+ dialog.setText(text)
+ reply = dialog.exec_()
+ return reply == True
+
+ def javaScriptPrompt(self, qurl, text, text_value):
+ dialog = InputDlg(
+ self.parent().name,
+ self.parent().current_dir,
+ self.view()
+ )
+ dialog.setText(text)
+ dialog.setTextValue(text_value)
+ if dialog.exec_():
+ return (True, dialog.textValue())
+ else:
+ return (False, "")
\ No newline at end of file
diff --git a/core/web_engine_view.py b/core/web_engine_view.py
new file mode 100644
index 0000000..45f6fc4
--- /dev/null
+++ b/core/web_engine_view.py
@@ -0,0 +1,131 @@
+from PyQt5.QtCore import Qt
+from PyQt5.QtGui import QIcon
+from PyQt5.QtWebEngineWidgets import QWebEngineView
+
+from qfluentwidgets import (
+ RoundMenu, Action, MenuAnimationType
+)
+
+import webbrowser
+
+class WebEngineView(QWebEngineView):
+ def contextMenuEvent(self, event):
+ url = self.window().webview.url().toString()
+ menu = RoundMenu(parent=self.window())
+
+ go_back_action = Action("Back", shortcut="Left")
+ go_back_action.setIcon(
+ QIcon(f"{self.window().current_dir}/resources/icons/arrow_back_white_24dp.svg")
+ )
+ go_back_action.triggered.connect(
+ self.window().go_back
+ )
+ menu.addAction(go_back_action)
+
+ go_forward_action = Action("Forward", shortcut="Right")
+ go_forward_action.setIcon(
+ QIcon(f"{self.window().current_dir}/resources/icons/arrow_forward_white_24dp.svg")
+ )
+ go_forward_action.triggered.connect(
+ self.window().go_forward
+ )
+ menu.addAction(go_forward_action)
+
+ go_home_action = Action("Home", shortcut="Ctrl+H")
+ go_home_action.setIcon(
+ QIcon(f"{self.window().current_dir}/resources/icons/home_white_24dp.svg")
+ )
+ go_home_action.triggered.connect(
+ self.window().go_home
+ )
+ menu.addAction(go_home_action)
+
+ go_reload_action = Action("Reload", shortcut="Ctrl+R")
+ go_reload_action.setIcon(
+ QIcon(f"{self.window().current_dir}/resources/icons/refresh_white_24dp.svg")
+ )
+ go_reload_action.triggered.connect(
+ self.window().go_reload
+ )
+ menu.addAction(go_reload_action)
+
+ menu.addSeparator()
+
+ download_menu = RoundMenu("Download...", self)
+ download_menu.setIcon(
+ QIcon(f"{self.window().current_dir}/resources/icons/file_download_white_24dp.svg")
+ )
+ menu.addMenu(download_menu)
+
+ download_track_action = Action('Track', shortcut="Ctrl+D")
+ download_track_action.triggered.connect(
+ lambda: self.window().go_download('track')
+ )
+ download_track_action.setIcon(
+ QIcon(f"{self.window().current_dir}/resources/icons/audiotrack_white_24dp.svg")
+ )
+ download_menu.addAction(download_track_action)
+
+ download_playlist_action = Action('Playlist', shortcut="Ctrl+P")
+ download_playlist_action.triggered.connect(
+ lambda: self.window().go_download('playlist')
+ )
+ download_playlist_action.setIcon(
+ QIcon(f"{self.window().current_dir}/resources/icons/playlist_play_white_24dp.svg")
+ )
+ download_menu.addAction(download_playlist_action)
+
+ open_mini_player_action = Action("Mini-Player", shortcut="Ctrl+M")
+ open_mini_player_action.setIcon(
+ QIcon(f"{self.window().current_dir}/resources/icons/picture_in_picture_white_24dp.svg")
+ )
+ open_mini_player_action.triggered.connect(
+ self.window().open_mini_player
+ )
+ menu.addAction(open_mini_player_action)
+
+ menu.addSeparator()
+
+ open_settings_action = Action("Settings", shortcut="Ctrl+S")
+ open_settings_action.setIcon(
+ QIcon(f"{self.window().current_dir}/resources/icons/settings_white_24dp.svg")
+ )
+ open_settings_action.triggered.connect(
+ self.window().open_settings_dialog
+ )
+ menu.addAction(open_settings_action)
+
+ menu.addSeparator()
+
+ bug_report_action = Action("Bug Report")
+ bug_report_action.setIcon(
+ QIcon(f"{self.window().current_dir}/resources/icons/bug_report_white_24dp.svg")
+ )
+ bug_report_action.triggered.connect(lambda:
+ webbrowser.open_new_tab(
+ "https://github.com/deeffest/Youtube-Music-Desktop-Player/issues/new/choose"
+ )
+ )
+ menu.addAction(bug_report_action)
+
+ open_about_action = Action("About...")
+ open_about_action.setIcon(
+ QIcon(f"{self.window().current_dir}/resources/icons/info_white_24dp.svg")
+ )
+ open_about_action.triggered.connect(
+ self.window().open_about_dialog
+ )
+ menu.addAction(open_about_action)
+
+ if not "watch" in url:
+ download_track_action.setEnabled(False)
+ open_mini_player_action.setEnabled(False)
+ if not "playlist" in url:
+ download_playlist_action.setEnabled(False)
+
+ if not self.page().history().canGoForward():
+ go_forward_action.setEnabled(False)
+ if not self.page().history().canGoBack():
+ go_back_action.setEnabled(False)
+
+ menu.exec(event.globalPos(), aniType=MenuAnimationType.DROP_DOWN)
\ No newline at end of file
diff --git a/main.py b/main.py
index 2a719c2..249c202 100644
--- a/main.py
+++ b/main.py
@@ -9,7 +9,7 @@
from core.main_window import Window
name = "Youtube Music Desktop Player"
-version = "1.1.1"
+version = "1.1.2"
current_dir = os.path.dirname(os.path.abspath(__file__))
username = getpass.getuser()
diff --git a/notes.txt b/notes.txt
index e3f41b6..0ae9ca1 100644
--- a/notes.txt
+++ b/notes.txt
@@ -1,4 +1,4 @@
-1.1.1 Update!
+1.1.2 Update!
-- Fixed a bug where the loading indicator would not disappear when loading existing music.
+- Fixed installer size too large.
- Other changes and improvements.
\ No newline at end of file
diff --git a/requierements.txt b/requierements.txt
new file mode 100644
index 0000000..5b076fa
--- /dev/null
+++ b/requierements.txt
@@ -0,0 +1,99 @@
+aiohttp==3.9.3
+aiosignal==1.3.1
+altair==5.2.0
+altgraph==0.17.4
+async-timeout==4.0.3
+attrs==23.2.0
+auto-py-to-exe==2.37.0
+beautifulsoup4==4.12.3
+blinker==1.7.0
+bottle==0.12.25
+bottle-websocket==0.2.9
+Brotli==1.1.0
+cachetools==5.3.2
+certifi==2024.2.2
+cffi==1.16.0
+charset-normalizer==3.3.2
+click==8.1.7
+colorama==0.4.6
+colorthief==0.2.1
+darkdetect==0.8.0
+discord==2.3.2
+discord.py==2.3.2
+Eel==0.16.0
+ffmpeg-python==0.2.0
+Flask==3.0.2
+frozenlist==1.4.1
+future==1.0.0
+gevent==24.2.1
+gevent-websocket==0.10.1
+gitdb==4.0.11
+GitPython==3.1.42
+greenlet==3.0.3
+idna==3.6
+importlib-metadata==7.0.1
+itsdangerous==2.1.2
+Jinja2==3.1.3
+jsonschema==4.21.1
+jsonschema-specifications==2023.12.1
+markdown-it-py==3.0.0
+MarkupSafe==2.1.5
+mdurl==0.1.2
+multidict==6.0.5
+mutagen==1.47.0
+numpy==1.26.4
+packaging==23.2
+pandas==2.2.1
+pefile==2023.2.7
+pillow==10.2.0
+protobuf==4.25.3
+psutil==5.9.8
+py-cpuinfo==9.0.0
+pyarrow==15.0.0
+pycparser==2.21
+pycryptodomex==3.20.0
+pydeck==0.8.1b0
+pygame==2.5.2
+Pygments==2.17.2
+pyinstaller==5.13.2
+pyinstaller-hooks-contrib==2024.1
+pyparsing==3.1.1
+PyQt-Fluent-Widgets==1.5.1
+PyQt5==5.15.10
+PyQt5-Frameless-Window==0.3.8
+PyQt5-Qt5==5.15.2
+PyQt5-sip==12.13.0
+PyQtWebEngine==5.15.6
+PyQtWebEngine-Qt5==5.15.2
+python-dateutil==2.8.2
+pytube==15.0.0
+pytz==2024.1
+pywin32==306
+pywin32-ctypes==0.2.2
+referencing==0.33.0
+requests==2.31.0
+rich==13.7.0
+rpds-py==0.18.0
+scipy==1.12.0
+six==1.16.0
+smmap==5.0.1
+soupsieve==2.5
+tenacity==8.2.3
+tk==0.1.0
+toml==0.10.2
+toolz==0.12.1
+tornado==6.4
+typing_extensions==4.10.0
+tzdata==2024.1
+tzlocal==5.2
+urllib3==2.2.1
+validators==0.22.0
+watchdog==4.0.0
+websockets==12.0
+Werkzeug==3.0.1
+whichcraft==0.6.1
+yarl==1.9.4
+yt-dlp==2023.12.30
+zipp==3.17.0
+zope.event==5.0
+zope.interface==6.2
\ No newline at end of file
diff --git a/resources/icons/audiotrack_white_24dp.svg b/resources/icons/audiotrack_white_24dp.svg
new file mode 100644
index 0000000..466585c
--- /dev/null
+++ b/resources/icons/audiotrack_white_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/disabled_win_toolbar_icons/pause_white_24dp.svg b/resources/icons/disabled_win_toolbar_icons/pause_white_24dp.svg
new file mode 100644
index 0000000..3ff8cb9
--- /dev/null
+++ b/resources/icons/disabled_win_toolbar_icons/pause_white_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/disabled_win_toolbar_icons/play_arrow_white_24dp.svg b/resources/icons/disabled_win_toolbar_icons/play_arrow_white_24dp.svg
new file mode 100644
index 0000000..7a76990
--- /dev/null
+++ b/resources/icons/disabled_win_toolbar_icons/play_arrow_white_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/disabled_win_toolbar_icons/skip_next_white_24dp.svg b/resources/icons/disabled_win_toolbar_icons/skip_next_white_24dp.svg
new file mode 100644
index 0000000..0449319
--- /dev/null
+++ b/resources/icons/disabled_win_toolbar_icons/skip_next_white_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/disabled_win_toolbar_icons/skip_previous_white_24dp.svg b/resources/icons/disabled_win_toolbar_icons/skip_previous_white_24dp.svg
new file mode 100644
index 0000000..20f32a7
--- /dev/null
+++ b/resources/icons/disabled_win_toolbar_icons/skip_previous_white_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/playlist_play_white_24dp.svg b/resources/icons/playlist_play_white_24dp.svg
new file mode 100644
index 0000000..8d51382
--- /dev/null
+++ b/resources/icons/playlist_play_white_24dp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file