From b29a172bf87a5937de46fb6c7dfc54d172b8d5c0 Mon Sep 17 00:00:00 2001 From: BarsTiger Date: Tue, 27 Dec 2022 14:18:22 +0200 Subject: [PATCH] Added collab --- gui/gui.py | 236 ++++++++- gui/gui.ui | 604 +++++++++++++++++++++++- gui/modules/collab/__init__.py | 1 + gui/modules/collab/connect.py | 43 ++ gui/modules/collab/create.py | 34 ++ gui/modules/collab/handlers.py | 50 ++ gui/modules/collab/host.py | 45 ++ gui/modules/download/downloader.py | 45 +- gui/modules/handlers/register.py | 2 + gui/modules/initialize/fill_settings.py | 6 + gui/modules/settings/handlers.py | 14 + modules/anonfiles/__init__.py | 0 modules/anonfiles/anonfiles.py | 35 ++ modules/config/model.py | 9 + modules/config/pusher.py | 45 ++ modules/player/convert.py | 10 +- requirements.txt | 5 +- 17 files changed, 1150 insertions(+), 34 deletions(-) create mode 100644 gui/modules/collab/__init__.py create mode 100644 gui/modules/collab/connect.py create mode 100644 gui/modules/collab/create.py create mode 100644 gui/modules/collab/handlers.py create mode 100644 gui/modules/collab/host.py create mode 100644 modules/anonfiles/__init__.py create mode 100644 modules/anonfiles/anonfiles.py create mode 100644 modules/config/pusher.py diff --git a/gui/gui.py b/gui/gui.py index 6e9ace5..5404f8e 100644 --- a/gui/gui.py +++ b/gui/gui.py @@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(815, 484) + MainWindow.resize(815, 497) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap(":/img/img/kotopad.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off) MainWindow.setWindowIcon(icon) @@ -324,6 +324,153 @@ class Ui_MainWindow(object): self.content.addWidget(self.stream_page) self.collab_page = QtWidgets.QWidget() self.collab_page.setObjectName("collab_page") + self.collab_page_lay = QtWidgets.QVBoxLayout(self.collab_page) + self.collab_page_lay.setContentsMargins(0, 0, 0, 0) + self.collab_page_lay.setObjectName("collab_page_lay") + self.collab_tab_widget = QtWidgets.QTabWidget(self.collab_page) + self.collab_tab_widget.setObjectName("collab_tab_widget") + self.collab_connect_tab = QtWidgets.QWidget() + self.collab_connect_tab.setObjectName("collab_connect_tab") + self.collab_connect_tab_2 = QtWidgets.QVBoxLayout(self.collab_connect_tab) + self.collab_connect_tab_2.setContentsMargins(0, 0, 0, 0) + self.collab_connect_tab_2.setObjectName("collab_connect_tab_2") + self.connect_session_widget = QtWidgets.QWidget(self.collab_connect_tab) + self.connect_session_widget.setObjectName("connect_session_widget") + self.connect_session_widget_lay = QtWidgets.QHBoxLayout(self.connect_session_widget) + self.connect_session_widget_lay.setContentsMargins(0, 0, 0, 0) + self.connect_session_widget_lay.setObjectName("connect_session_widget_lay") + self.collab_session_key_box = QtWidgets.QLineEdit(self.connect_session_widget) + self.collab_session_key_box.setMinimumSize(QtCore.QSize(0, 35)) + self.collab_session_key_box.setObjectName("collab_session_key_box") + self.connect_session_widget_lay.addWidget(self.collab_session_key_box) + self.connect_to_session_button = QtWidgets.QPushButton(self.connect_session_widget) + self.connect_to_session_button.setMinimumSize(QtCore.QSize(70, 35)) + self.connect_to_session_button.setObjectName("connect_to_session_button") + self.connect_session_widget_lay.addWidget(self.connect_to_session_button) + self.collab_connect_tab_2.addWidget(self.connect_session_widget) + self.collab_connect_logs = QtWidgets.QTextBrowser(self.collab_connect_tab) + self.collab_connect_logs.setObjectName("collab_connect_logs") + self.collab_connect_tab_2.addWidget(self.collab_connect_logs) + self.collab_disconnect_button = QtWidgets.QPushButton(self.collab_connect_tab) + self.collab_disconnect_button.setMinimumSize(QtCore.QSize(0, 35)) + self.collab_disconnect_button.setObjectName("collab_disconnect_button") + self.collab_connect_tab_2.addWidget(self.collab_disconnect_button) + self.collab_tab_widget.addTab(self.collab_connect_tab, "") + self.collab_host_tab = QtWidgets.QWidget() + self.collab_host_tab.setObjectName("collab_host_tab") + self.collab_host_tab_lay = QtWidgets.QVBoxLayout(self.collab_host_tab) + self.collab_host_tab_lay.setContentsMargins(0, 0, 0, 0) + self.collab_host_tab_lay.setObjectName("collab_host_tab_lay") + self.collab_host_tabs = QtWidgets.QTabWidget(self.collab_host_tab) + self.collab_host_tabs.setObjectName("collab_host_tabs") + self.collab_host_create_tab = QtWidgets.QWidget() + self.collab_host_create_tab.setObjectName("collab_host_create_tab") + self.collab_host_create_tab_lay = QtWidgets.QVBoxLayout(self.collab_host_create_tab) + self.collab_host_create_tab_lay.setContentsMargins(0, 0, 0, 0) + self.collab_host_create_tab_lay.setObjectName("collab_host_create_tab_lay") + self.create_session_widget = QtWidgets.QWidget(self.collab_host_create_tab) + self.create_session_widget.setObjectName("create_session_widget") + self.create_session_widget_lay = QtWidgets.QHBoxLayout(self.create_session_widget) + self.create_session_widget_lay.setContentsMargins(0, 0, 0, 0) + self.create_session_widget_lay.setObjectName("create_session_widget_lay") + self.create_session_name_box = QtWidgets.QLineEdit(self.create_session_widget) + self.create_session_name_box.setMinimumSize(QtCore.QSize(0, 35)) + self.create_session_name_box.setMaxLength(25) + self.create_session_name_box.setObjectName("create_session_name_box") + self.create_session_widget_lay.addWidget(self.create_session_name_box) + self.create_session_button = QtWidgets.QPushButton(self.create_session_widget) + self.create_session_button.setMinimumSize(QtCore.QSize(70, 35)) + self.create_session_button.setObjectName("create_session_button") + self.create_session_widget_lay.addWidget(self.create_session_button) + self.collab_host_create_tab_lay.addWidget(self.create_session_widget, 0, QtCore.Qt.AlignTop) + self.connection_key_label = QtWidgets.QLabel(self.collab_host_create_tab) + self.connection_key_label.setObjectName("connection_key_label") + self.collab_host_create_tab_lay.addWidget(self.connection_key_label, 0, QtCore.Qt.AlignTop) + self.new_connection_key_copy_box = QtWidgets.QLineEdit(self.collab_host_create_tab) + self.new_connection_key_copy_box.setMinimumSize(QtCore.QSize(0, 35)) + self.new_connection_key_copy_box.setReadOnly(True) + self.new_connection_key_copy_box.setObjectName("new_connection_key_copy_box") + self.collab_host_create_tab_lay.addWidget(self.new_connection_key_copy_box) + self.admin_key_label = QtWidgets.QLabel(self.collab_host_create_tab) + self.admin_key_label.setObjectName("admin_key_label") + self.collab_host_create_tab_lay.addWidget(self.admin_key_label) + self.new_connection_admin_key_copy_box = QtWidgets.QLineEdit(self.collab_host_create_tab) + self.new_connection_admin_key_copy_box.setMinimumSize(QtCore.QSize(0, 35)) + self.new_connection_admin_key_copy_box.setReadOnly(True) + self.new_connection_admin_key_copy_box.setObjectName("new_connection_admin_key_copy_box") + self.collab_host_create_tab_lay.addWidget(self.new_connection_admin_key_copy_box) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.collab_host_create_tab_lay.addItem(spacerItem1) + self.collab_host_tabs.addTab(self.collab_host_create_tab, "") + self.collab_host_control_tab = QtWidgets.QWidget() + self.collab_host_control_tab.setObjectName("collab_host_control_tab") + self.collab_host_control_tab_lay = QtWidgets.QVBoxLayout(self.collab_host_control_tab) + self.collab_host_control_tab_lay.setContentsMargins(0, 0, 0, 0) + self.collab_host_control_tab_lay.setObjectName("collab_host_control_tab_lay") + self.connect_admin_session_widget = QtWidgets.QWidget(self.collab_host_control_tab) + self.connect_admin_session_widget.setObjectName("connect_admin_session_widget") + self.connect_session_widget_lay_2 = QtWidgets.QHBoxLayout(self.connect_admin_session_widget) + self.connect_session_widget_lay_2.setContentsMargins(0, 0, 0, 0) + self.connect_session_widget_lay_2.setObjectName("connect_session_widget_lay_2") + self.collab_session_admin_key_box = QtWidgets.QLineEdit(self.connect_admin_session_widget) + self.collab_session_admin_key_box.setMinimumSize(QtCore.QSize(0, 35)) + self.collab_session_admin_key_box.setObjectName("collab_session_admin_key_box") + self.connect_session_widget_lay_2.addWidget(self.collab_session_admin_key_box) + self.connect_to_admin_session_button = QtWidgets.QPushButton(self.connect_admin_session_widget) + self.connect_to_admin_session_button.setMinimumSize(QtCore.QSize(70, 35)) + self.connect_to_admin_session_button.setObjectName("connect_to_admin_session_button") + self.connect_session_widget_lay_2.addWidget(self.connect_to_admin_session_button) + self.collab_host_control_tab_lay.addWidget(self.connect_admin_session_widget, 0, QtCore.Qt.AlignTop) + self.url_to_send_admin_box = QtWidgets.QLineEdit(self.collab_host_control_tab) + self.url_to_send_admin_box.setMinimumSize(QtCore.QSize(0, 35)) + self.url_to_send_admin_box.setObjectName("url_to_send_admin_box") + self.collab_host_control_tab_lay.addWidget(self.url_to_send_admin_box, 0, QtCore.Qt.AlignTop) + self.send_to_users_admin_button = QtWidgets.QPushButton(self.collab_host_control_tab) + self.send_to_users_admin_button.setMinimumSize(QtCore.QSize(0, 35)) + self.send_to_users_admin_button.setObjectName("send_to_users_admin_button") + self.collab_host_control_tab_lay.addWidget(self.send_to_users_admin_button) + self.stop_all_button_admin = QtWidgets.QPushButton(self.collab_host_control_tab) + self.stop_all_button_admin.setMinimumSize(QtCore.QSize(0, 35)) + self.stop_all_button_admin.setObjectName("stop_all_button_admin") + self.collab_host_control_tab_lay.addWidget(self.stop_all_button_admin) + self.control_admin_logs = QtWidgets.QTextBrowser(self.collab_host_control_tab) + self.control_admin_logs.setObjectName("control_admin_logs") + self.collab_host_control_tab_lay.addWidget(self.control_admin_logs) + self.collab_host_tabs.addTab(self.collab_host_control_tab, "") + self.collab_host_upload_tab = QtWidgets.QWidget() + self.collab_host_upload_tab.setObjectName("collab_host_upload_tab") + self.collab_host_upload_tab_lay = QtWidgets.QVBoxLayout(self.collab_host_upload_tab) + self.collab_host_upload_tab_lay.setContentsMargins(0, 0, 0, 0) + self.collab_host_upload_tab_lay.setObjectName("collab_host_upload_tab_lay") + self.upload_sound_widget = QtWidgets.QWidget(self.collab_host_upload_tab) + self.upload_sound_widget.setObjectName("upload_sound_widget") + self.create_session_widget_lay_2 = QtWidgets.QHBoxLayout(self.upload_sound_widget) + self.create_session_widget_lay_2.setContentsMargins(0, 0, 0, 0) + self.create_session_widget_lay_2.setObjectName("create_session_widget_lay_2") + self.filename_to_upload_box = QtWidgets.QLineEdit(self.upload_sound_widget) + self.filename_to_upload_box.setMinimumSize(QtCore.QSize(0, 35)) + self.filename_to_upload_box.setObjectName("filename_to_upload_box") + self.create_session_widget_lay_2.addWidget(self.filename_to_upload_box) + self.choose_upload_sound_button = QtWidgets.QPushButton(self.upload_sound_widget) + self.choose_upload_sound_button.setMinimumSize(QtCore.QSize(70, 35)) + self.choose_upload_sound_button.setObjectName("choose_upload_sound_button") + self.create_session_widget_lay_2.addWidget(self.choose_upload_sound_button) + self.collab_host_upload_tab_lay.addWidget(self.upload_sound_widget) + self.upload_sound_button = QtWidgets.QPushButton(self.collab_host_upload_tab) + self.upload_sound_button.setMinimumSize(QtCore.QSize(0, 35)) + self.upload_sound_button.setObjectName("upload_sound_button") + self.collab_host_upload_tab_lay.addWidget(self.upload_sound_button) + self.anonfiles_uploaded_url_box = QtWidgets.QLineEdit(self.collab_host_upload_tab) + self.anonfiles_uploaded_url_box.setMinimumSize(QtCore.QSize(0, 35)) + self.anonfiles_uploaded_url_box.setReadOnly(True) + self.anonfiles_uploaded_url_box.setObjectName("anonfiles_uploaded_url_box") + self.collab_host_upload_tab_lay.addWidget(self.anonfiles_uploaded_url_box) + spacerItem2 = QtWidgets.QSpacerItem(20, 261, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.collab_host_upload_tab_lay.addItem(spacerItem2) + self.collab_host_tabs.addTab(self.collab_host_upload_tab, "") + self.collab_host_tab_lay.addWidget(self.collab_host_tabs) + self.collab_tab_widget.addTab(self.collab_host_tab, "") + self.collab_page_lay.addWidget(self.collab_tab_widget) self.content.addWidget(self.collab_page) self.download_page = QtWidgets.QWidget() self.download_page.setObjectName("download_page") @@ -445,8 +592,8 @@ class Ui_MainWindow(object): self.use_original_streaming_method_desc.setWordWrap(True) self.use_original_streaming_method_desc.setObjectName("use_original_streaming_method_desc") self.audio_devices_settings_tab_lay.addWidget(self.use_original_streaming_method_desc, 0, QtCore.Qt.AlignTop) - spacerItem1 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.audio_devices_settings_tab_lay.addItem(spacerItem1) + spacerItem3 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.audio_devices_settings_tab_lay.addItem(spacerItem3) self.settings_tabs_widget.addTab(self.audio_devices_settings_tab, "") self.general_settings_tab = QtWidgets.QWidget() self.general_settings_tab.setObjectName("general_settings_tab") @@ -493,13 +640,58 @@ class Ui_MainWindow(object): self.spotify_client_secret_box.setMinimumSize(QtCore.QSize(0, 30)) self.spotify_client_secret_box.setObjectName("spotify_client_secret_box") self.spotify_api_settings_tab_lay.addWidget(self.spotify_client_secret_box) + spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.spotify_api_settings_tab_lay.addItem(spacerItem4) self.api_keys_settings_tabs_widget.addTab(self.spotify_api_settings_tab, "") self.pusher_settings_tab = QtWidgets.QWidget() self.pusher_settings_tab.setObjectName("pusher_settings_tab") + self.pusher_settings_tab_lay = QtWidgets.QVBoxLayout(self.pusher_settings_tab) + self.pusher_settings_tab_lay.setContentsMargins(0, 0, 0, 0) + self.pusher_settings_tab_lay.setObjectName("pusher_settings_tab_lay") + self.pusher_app_id_label = QtWidgets.QLabel(self.pusher_settings_tab) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pusher_app_id_label.sizePolicy().hasHeightForWidth()) + self.pusher_app_id_label.setSizePolicy(sizePolicy) + self.pusher_app_id_label.setMaximumSize(QtCore.QSize(16777215, 50)) + self.pusher_app_id_label.setObjectName("pusher_app_id_label") + self.pusher_settings_tab_lay.addWidget(self.pusher_app_id_label) + self.pusher_app_id_box = QtWidgets.QLineEdit(self.pusher_settings_tab) + self.pusher_app_id_box.setMinimumSize(QtCore.QSize(0, 30)) + self.pusher_app_id_box.setObjectName("pusher_app_id_box") + self.pusher_settings_tab_lay.addWidget(self.pusher_app_id_box) + self.pusher_key_label = QtWidgets.QLabel(self.pusher_settings_tab) + self.pusher_key_label.setObjectName("pusher_key_label") + self.pusher_settings_tab_lay.addWidget(self.pusher_key_label) + self.pusher_key_box = QtWidgets.QLineEdit(self.pusher_settings_tab) + self.pusher_key_box.setMinimumSize(QtCore.QSize(0, 30)) + self.pusher_key_box.setObjectName("pusher_key_box") + self.pusher_settings_tab_lay.addWidget(self.pusher_key_box) + self.pusher_secret_label = QtWidgets.QLabel(self.pusher_settings_tab) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.pusher_secret_label.sizePolicy().hasHeightForWidth()) + self.pusher_secret_label.setSizePolicy(sizePolicy) + self.pusher_secret_label.setMaximumSize(QtCore.QSize(16777215, 50)) + self.pusher_secret_label.setObjectName("pusher_secret_label") + self.pusher_settings_tab_lay.addWidget(self.pusher_secret_label) + self.pusher_secret_box = QtWidgets.QLineEdit(self.pusher_settings_tab) + self.pusher_secret_box.setMinimumSize(QtCore.QSize(0, 30)) + self.pusher_secret_box.setObjectName("pusher_secret_box") + self.pusher_settings_tab_lay.addWidget(self.pusher_secret_box) + self.pusher_cluster_label = QtWidgets.QLabel(self.pusher_settings_tab) + self.pusher_cluster_label.setObjectName("pusher_cluster_label") + self.pusher_settings_tab_lay.addWidget(self.pusher_cluster_label) + self.pusher_cluster_box = QtWidgets.QLineEdit(self.pusher_settings_tab) + self.pusher_cluster_box.setMinimumSize(QtCore.QSize(0, 30)) + self.pusher_cluster_box.setObjectName("pusher_cluster_box") + self.pusher_settings_tab_lay.addWidget(self.pusher_cluster_box) self.api_keys_settings_tabs_widget.addTab(self.pusher_settings_tab, "") self.general_settings_tab_lay.addWidget(self.api_keys_settings_tabs_widget, 0, QtCore.Qt.AlignTop) - spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.general_settings_tab_lay.addItem(spacerItem2) + spacerItem5 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.general_settings_tab_lay.addItem(spacerItem5) self.clear_temp_button = QtWidgets.QPushButton(self.general_settings_tab) self.clear_temp_button.setMinimumSize(QtCore.QSize(0, 40)) self.clear_temp_button.setObjectName("clear_temp_button") @@ -566,7 +758,10 @@ class Ui_MainWindow(object): self.pads_content.setCurrentIndex(0) self.browser_page_tabs.setCurrentIndex(0) self.collections_page_tabs.setCurrentIndex(0) + self.collab_tab_widget.setCurrentIndex(0) + self.collab_host_tabs.setCurrentIndex(0) self.settings_tabs_widget.setCurrentIndex(0) + self.api_keys_settings_tabs_widget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): @@ -611,6 +806,29 @@ class Ui_MainWindow(object): self.collections_page_tabs.setTabText(self.collections_page_tabs.indexOf(self.edit_collections_tabs), _translate("MainWindow", "Edit collections")) self.to_stream_url_box.setPlaceholderText(_translate("MainWindow", "URL (direct web file, YouTube or spotify link) or path to file")) self.play_stream_button.setText(_translate("MainWindow", "Play")) + self.collab_session_key_box.setPlaceholderText(_translate("MainWindow", "Collab session key")) + self.connect_to_session_button.setText(_translate("MainWindow", "Connect")) + self.collab_disconnect_button.setText(_translate("MainWindow", "Disconnect")) + self.collab_tab_widget.setTabText(self.collab_tab_widget.indexOf(self.collab_connect_tab), _translate("MainWindow", "Connect")) + self.create_session_name_box.setPlaceholderText(_translate("MainWindow", "Collab session room name")) + self.create_session_button.setText(_translate("MainWindow", "Create")) + self.connection_key_label.setText(_translate("MainWindow", "Connection key. With this key, everyone can connect to the room")) + self.new_connection_key_copy_box.setPlaceholderText(_translate("MainWindow", "Create session first")) + self.admin_key_label.setText(_translate("MainWindow", "Control key, contains current pusher credentials. Do not share it")) + self.new_connection_admin_key_copy_box.setPlaceholderText(_translate("MainWindow", "Create session first")) + self.collab_host_tabs.setTabText(self.collab_host_tabs.indexOf(self.collab_host_create_tab), _translate("MainWindow", "Create")) + self.collab_session_admin_key_box.setPlaceholderText(_translate("MainWindow", "Admin session key")) + self.connect_to_admin_session_button.setText(_translate("MainWindow", "Connect")) + self.url_to_send_admin_box.setPlaceholderText(_translate("MainWindow", "Direct, Anonfiles, YouTube or Spotify URL")) + self.send_to_users_admin_button.setText(_translate("MainWindow", "Send URL")) + self.stop_all_button_admin.setText(_translate("MainWindow", "Stop playing")) + self.collab_host_tabs.setTabText(self.collab_host_tabs.indexOf(self.collab_host_control_tab), _translate("MainWindow", "Control")) + self.filename_to_upload_box.setPlaceholderText(_translate("MainWindow", "Path to file")) + self.choose_upload_sound_button.setText(_translate("MainWindow", "Pick file")) + self.upload_sound_button.setText(_translate("MainWindow", "Upload")) + self.anonfiles_uploaded_url_box.setPlaceholderText(_translate("MainWindow", "Upload file first")) + self.collab_host_tabs.setTabText(self.collab_host_tabs.indexOf(self.collab_host_upload_tab), _translate("MainWindow", "Upload sound")) + self.collab_tab_widget.setTabText(self.collab_tab_widget.indexOf(self.collab_host_tab), _translate("MainWindow", "Host")) self.download_url_box.setPlaceholderText(_translate("MainWindow", "URL (direct web file, YouTube or spotify link) or path to file")) self.download_to_path_box.setPlaceholderText(_translate("MainWindow", "File download folder")) self.choose_download_path_button.setText(_translate("MainWindow", "Choose path")) @@ -635,6 +853,14 @@ class Ui_MainWindow(object): self.spotify_client_secret_label.setText(_translate("MainWindow", "Client secret")) self.spotify_client_secret_box.setPlaceholderText(_translate("MainWindow", "212476d9b0f3472eaa762d90b19b0ba8")) self.api_keys_settings_tabs_widget.setTabText(self.api_keys_settings_tabs_widget.indexOf(self.spotify_api_settings_tab), _translate("MainWindow", "Spotify")) + self.pusher_app_id_label.setText(_translate("MainWindow", "app_id")) + self.pusher_app_id_box.setPlaceholderText(_translate("MainWindow", "1699645")) + self.pusher_key_label.setText(_translate("MainWindow", "key")) + self.pusher_key_box.setPlaceholderText(_translate("MainWindow", "0c39944565451ae335d1")) + self.pusher_secret_label.setText(_translate("MainWindow", "secret")) + self.pusher_secret_box.setPlaceholderText(_translate("MainWindow", "5011da8cb2725b4b2298")) + self.pusher_cluster_label.setText(_translate("MainWindow", "cluster")) + self.pusher_cluster_box.setPlaceholderText(_translate("MainWindow", "us")) self.api_keys_settings_tabs_widget.setTabText(self.api_keys_settings_tabs_widget.indexOf(self.pusher_settings_tab), _translate("MainWindow", "Pusher")) self.clear_temp_button.setText(_translate("MainWindow", "Clear KotoPad temporary files (use if sound doesn\'t play correctly)")) self.settings_tabs_widget.setTabText(self.settings_tabs_widget.indexOf(self.general_settings_tab), _translate("MainWindow", "General")) diff --git a/gui/gui.ui b/gui/gui.ui index e7d874f..5be809a 100644 --- a/gui/gui.ui +++ b/gui/gui.ui @@ -7,7 +7,7 @@ 0 0 815 - 484 + 497 @@ -1072,7 +1072,469 @@ QListWidget:item:selected { - + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + Connect + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 35 + + + + Collab session key + + + + + + + + 70 + 35 + + + + Connect + + + + + + + + + + + + + + 0 + 35 + + + + Disconnect + + + + + + + + Host + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + Create + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 35 + + + + 25 + + + Collab session room name + + + + + + + + 70 + 35 + + + + Create + + + + + + + + + + Connection key. With this key, everyone can connect to the room + + + + + + + + 0 + 35 + + + + true + + + Create session first + + + + + + + Control key, contains current pusher credentials. Do not share it + + + + + + + + 0 + 35 + + + + true + + + Create session first + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Control + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 35 + + + + Admin session key + + + + + + + + 70 + 35 + + + + Connect + + + + + + + + + + + 0 + 35 + + + + Direct, Anonfiles, YouTube or Spotify URL + + + + + + + + 0 + 35 + + + + Send URL + + + + + + + + 0 + 35 + + + + Stop playing + + + + + + + + + + + Upload sound + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 35 + + + + Path to file + + + + + + + + 70 + 35 + + + + Pick file + + + + + + + + + + + 0 + 35 + + + + Upload + + + + + + + + 0 + 35 + + + + true + + + Upload file first + + + + + + + Qt::Vertical + + + + 20 + 261 + + + + + + + + + + + + + + @@ -1358,7 +1820,7 @@ QListWidget:item:selected { - + Qt::Vertical @@ -1430,6 +1892,9 @@ QListWidget:item:selected { + + 0 + Spotify @@ -1499,12 +1964,143 @@ QListWidget:item:selected { + + + + Qt::Vertical + + + + 20 + 40 + + + + Pusher + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 16777215 + 50 + + + + app_id + + + + + + + + 0 + 30 + + + + 1699645 + + + + + + + key + + + + + + + + 0 + 30 + + + + 0c39944565451ae335d1 + + + + + + + + 0 + 0 + + + + + 16777215 + 50 + + + + secret + + + + + + + + 0 + 30 + + + + 5011da8cb2725b4b2298 + + + + + + + cluster + + + + + + + + 0 + 30 + + + + us + + + + @@ -1516,7 +2112,7 @@ QListWidget:item:selected { 20 - 40 + 0 diff --git a/gui/modules/collab/__init__.py b/gui/modules/collab/__init__.py new file mode 100644 index 0000000..d7ed779 --- /dev/null +++ b/gui/modules/collab/__init__.py @@ -0,0 +1 @@ +from .handlers import * diff --git a/gui/modules/collab/connect.py b/gui/modules/collab/connect.py new file mode 100644 index 0000000..e7cfc44 --- /dev/null +++ b/gui/modules/collab/connect.py @@ -0,0 +1,43 @@ +from gui.gui import Ui_MainWindow +import json +import pysher +from gui.modules.core.popup import popup +import base64 +from modules.player.player import Player + + +def on_url_music(url: str, p: Player, ui: Ui_MainWindow): + ui.collab_connect_logs.append(f"Received {url}") + p.set_media(url) + p.play(ui) + + +def handle_connection_to_server(ui: Ui_MainWindow, p: Player): + ui.collab_connect_logs.append(f'Connected to {ui.receiver_creds["name"]}') + channel = ui.receiver.subscribe(ui.collab_session_key_box.text()) + channel.bind('sound', lambda _: on_url_music(_, p, ui)) + channel.bind('stop', lambda _: (p.mediaplayer_preview.stop(), + p.mediaplayer_out.stop())) + + +def on_connect_clicked(ui: Ui_MainWindow, p: Player): + try: + creds = dict(json.loads( + base64.decodebytes(bytes(ui.collab_session_key_box.text().replace('-', '\n'), encoding='utf-8') + ).decode('utf-8').replace("'", '"') + )) + ui.collab_connect_logs.append(f'Loaded {creds["name"]}') + except Exception as e: + print(e) + popup("Error", 'Invalid connection key') + return + + ui.receiver_creds = creds + + ui.receiver = pysher.Pusher( + key=creds["key"], + cluster=creds["cluster"] + ) + ui.receiver.connection.bind('pusher:connection_established', lambda _: handle_connection_to_server(ui, p)) + ui.receiver.connect() + ui.collab_disconnect_button.setEnabled(True) diff --git a/gui/modules/collab/create.py b/gui/modules/collab/create.py new file mode 100644 index 0000000..1c9f4bc --- /dev/null +++ b/gui/modules/collab/create.py @@ -0,0 +1,34 @@ +from gui.gui import Ui_MainWindow +from modules.config.pusher import PusherConfig +from gui.modules.core.popup import popup +import base64 +from gui.modules.collab.host import connect_to_host_admin + + +def on_create_session_clicked(ui: Ui_MainWindow): + if ui.create_session_name_box.text() == "": + popup("Error", "Specify room name") + return + + connection_key = base64.encodebytes( + bytes(str( + { + "name": ui.create_session_name_box.text(), + "key": PusherConfig.get().key, + "cluster": PusherConfig.get().cluster + } + ), encoding='utf-8')).decode('utf-8').strip().replace('\n', '-') + + ui.new_connection_key_copy_box.setText(connection_key) + + admin_key = base64.encodebytes( + bytes(str( + { + "connection_key": connection_key, + "app_id": PusherConfig.get().app_id, + "secret": PusherConfig.get().secret + } + ), encoding='utf-8')).decode('utf-8').strip().replace('\n', '-') + ui.new_connection_admin_key_copy_box.setText(admin_key) + ui.collab_session_admin_key_box.setText(admin_key) + connect_to_host_admin(ui) diff --git a/gui/modules/collab/handlers.py b/gui/modules/collab/handlers.py new file mode 100644 index 0000000..bb2dd2a --- /dev/null +++ b/gui/modules/collab/handlers.py @@ -0,0 +1,50 @@ +from gui.gui import Ui_MainWindow +from PyQt5.QtWidgets import QFileDialog +from modules.player.player import Player +from modules.anonfiles.anonfiles import Anonfiles +from ezzthread import threaded +from gui.modules.core.qt_updater import call +from gui.modules.collab import create, host, connect + + +def register_handlers(ui: Ui_MainWindow, p: Player): + ui.send_to_users_admin_button.setEnabled(False) + ui.collab_disconnect_button.setEnabled(False) + ui.stop_all_button_admin.setEnabled(False) + + ui.create_session_button.clicked.connect( + lambda: create.on_create_session_clicked(ui) + ) + + + ui.connect_to_admin_session_button.clicked.connect( + lambda: host.connect_to_host_admin(ui) + ) + ui.send_to_users_admin_button.clicked.connect( + lambda: host.on_send_sound_button(ui) + ) + ui.stop_all_button_admin.clicked.connect( + lambda: host.on_stop_sound_button(ui) + ) + + + ui.connect_to_session_button.clicked.connect( + lambda: connect.on_connect_clicked(ui, p) + ) + ui.collab_disconnect_button.clicked.connect( + lambda: (ui.receiver.disconnect(), + ui.collab_disconnect_button.setEnabled(False), + ui.collab_connect_logs.append('Disconnected')) + ) + + + ui.choose_upload_sound_button.clicked.connect( + lambda: ui.filename_to_upload_box.setText( + QFileDialog.getOpenFileName(caption='Choose file to upload')[0] + ) + ) + ui.upload_sound_button.clicked.connect( + lambda: threaded( + call(ui.anonfiles_uploaded_url_box.setText, Anonfiles.upload(ui.filename_to_upload_box.text()).url) + ) + ) diff --git a/gui/modules/collab/host.py b/gui/modules/collab/host.py new file mode 100644 index 0000000..a57ce5b --- /dev/null +++ b/gui/modules/collab/host.py @@ -0,0 +1,45 @@ +from gui.gui import Ui_MainWindow +import pusher +import base64 +import json +from gui.modules.core.popup import popup + + +def connect_to_host_admin(ui: Ui_MainWindow): + try: + creds = dict(json.loads( + base64.decodebytes(bytes(ui.collab_session_admin_key_box.text().replace('-', '\n'), encoding='utf-8') + ).decode('utf-8').replace("'", '"') + )) + creds_from_connection = dict(json.loads( + base64.decodebytes(bytes(creds['connection_key'].replace('-', '\n'), encoding='utf-8') + ).decode('utf-8').replace("'", '"') + )) + creds |= creds_from_connection + ui.control_admin_logs.append(f'Loaded {creds["name"]}') + except Exception as e: + print(e) + popup("Error", 'Invalid admin key') + return + + ui.sender_creds = creds + + ui.sender = pusher.Pusher( + app_id=creds["app_id"], + key=creds["key"], + secret=creds["secret"], + cluster=creds["cluster"] + ) + ui.send_to_users_admin_button.setEnabled(True) + ui.stop_all_button_admin.setEnabled(True) + + +def on_send_sound_button(ui: Ui_MainWindow): + ui.sender.trigger(ui.sender_creds["connection_key"], 'sound', + ui.url_to_send_admin_box.text()) + ui.control_admin_logs.append(f'Sent {ui.url_to_send_admin_box.text()}') + + +def on_stop_sound_button(ui: Ui_MainWindow): + ui.sender.trigger(ui.sender_creds["connection_key"], 'stop', None) + ui.control_admin_logs.append(f'Stopped sounds') diff --git a/gui/modules/download/downloader.py b/gui/modules/download/downloader.py index a819769..bf7c709 100644 --- a/gui/modules/download/downloader.py +++ b/gui/modules/download/downloader.py @@ -13,30 +13,35 @@ import os @threaded def download_track(ui: Ui_MainWindow): - url = ui.download_url_box.text() + try: + url = ui.download_url_box.text() - if not validators.url(url): - call(ui.download_track_logs.append, f"{url} is not valid URL, skipping") - return + if not validators.url(url): + call(ui.download_track_logs.append, f"{url} is not valid URL, skipping") + return - call(ui.download_track_logs.append, f"Downloading {url}") + call(ui.download_track_logs.append, f"Downloading {url}") - name = (lambda song: song.artist + " - " + song.name + ".mp3")(Spotify().get_song(url)) \ - if "spotify" in url or "youtu" in url else url.split('/')[-1] + name = (lambda song: song.artist + " - " + song.name + ".mp3")(Spotify().get_song(url)) \ + if "spotify" in url or "youtu" in url else url.split('/')[-1] - url = convert.get_raw_link(url) + url = convert.get_raw_link(url) - call(ui.download_track_button.setEnabled, False) + call(ui.download_track_button.setEnabled, False) - response = urlopen(url) - call(ui.download_track_progress.setValue, 0) - size = int(response.info()["Content-length"]) - downloaded = 0 - with open(os.path.join(ui.download_to_path_box.text(), name), "wb") as dest_file: - for data in iter(partial(response.read, 4096), b""): - downloaded += len(data) - dest_file.write(data) - call(ui.download_track_progress.setValue, int(downloaded / size * 100)) + response = urlopen(url) + call(ui.download_track_progress.setValue, 0) + size = int(response.info()["Content-length"]) + downloaded = 0 + with open(os.path.join(ui.download_to_path_box.text(), name), "wb") as dest_file: + for data in iter(partial(response.read, 4096), b""): + downloaded += len(data) + dest_file.write(data) + call(ui.download_track_progress.setValue, int(downloaded / size * 100)) - call(ui.download_track_button.setEnabled, True) - call(ui.download_track_logs.append, f"Downloaded to {os.path.join(ui.download_to_path_box.text(), name)}") + call(ui.download_track_button.setEnabled, True) + call(ui.download_track_logs.append, f"Downloaded to {os.path.join(ui.download_to_path_box.text(), name)}") + except Exception as e: + print(e) + call(ui.download_track_button.setEnabled, True) + call(ui.download_track_logs.append, f"Failed") diff --git a/gui/modules/handlers/register.py b/gui/modules/handlers/register.py index 39bf4a9..73507a2 100644 --- a/gui/modules/handlers/register.py +++ b/gui/modules/handlers/register.py @@ -9,6 +9,7 @@ from gui.modules import explorer from gui.modules import collections from gui.modules import stream from gui.modules import download +from gui.modules import collab from modules.player.player import Player from modules.restream.restream import Restreamer @@ -23,3 +24,4 @@ def register_handlers(ui: Ui_MainWindow, MainWindow: QMainWindow, p: Player, rs: collections.register_handlers(ui, p) stream.register_handlers(ui, p) download.register_handlers(ui) + collab.register_handlers(ui, p) diff --git a/gui/modules/initialize/fill_settings.py b/gui/modules/initialize/fill_settings.py index 719242c..ceb0117 100644 --- a/gui/modules/initialize/fill_settings.py +++ b/gui/modules/initialize/fill_settings.py @@ -1,5 +1,6 @@ from gui.gui import Ui_MainWindow from modules.config import Config +from modules.config.pusher import PusherConfig from modules.spotify.config import SpotifyConfig from modules.restream import get_streaming_devices from modules.player.player import get_devices, get_instance, get_player @@ -41,4 +42,9 @@ def fill_settings(ui: Ui_MainWindow): ui.spotify_client_id_box.setText(SpotifyConfig.get().client_id) ui.spotify_client_secret_box.setText(SpotifyConfig.get().client_secret) + ui.pusher_app_id_box.setText(PusherConfig.get().app_id) + ui.pusher_key_box.setText(PusherConfig.get().key) + ui.pusher_secret_box.setText(PusherConfig.get().secret) + ui.pusher_cluster_box.setText(PusherConfig.get().cluster) + ui.use_original_streaming_method_check.setChecked(Config.get().direct_stream) diff --git a/gui/modules/settings/handlers.py b/gui/modules/settings/handlers.py index 840d5a9..bf6d011 100644 --- a/gui/modules/settings/handlers.py +++ b/gui/modules/settings/handlers.py @@ -1,5 +1,6 @@ from gui.gui import Ui_MainWindow from modules.config import Config +from modules.config.pusher import PusherConfig from modules.spotify.config import SpotifyConfig import shutil @@ -30,6 +31,19 @@ def register_handlers(ui: Ui_MainWindow): lambda: SpotifyConfig.update("client_secret", ui.spotify_client_secret_box.text()) ) + ui.pusher_app_id_box.textChanged.connect( + lambda: PusherConfig.update("app_id", ui.pusher_app_id_box.text()) + ) + ui.pusher_key_box.textChanged.connect( + lambda: PusherConfig.update("key", ui.pusher_key_box.text()) + ) + ui.pusher_secret_box.textChanged.connect( + lambda: PusherConfig.update("secret", ui.pusher_secret_box.text()) + ) + ui.pusher_cluster_box.textChanged.connect( + lambda: PusherConfig.update("cluster", ui.pusher_cluster_box.text()) + ) + ui.use_original_streaming_method_check.stateChanged.connect( lambda: Config.update("direct_stream", ui.use_original_streaming_method_check.isChecked()) ) diff --git a/modules/anonfiles/__init__.py b/modules/anonfiles/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/anonfiles/anonfiles.py b/modules/anonfiles/anonfiles.py new file mode 100644 index 0000000..2ecb9a2 --- /dev/null +++ b/modules/anonfiles/anonfiles.py @@ -0,0 +1,35 @@ +import requests +from dataclasses import dataclass +from Direct_Download import Direct + + +@dataclass +class File: + url: str | None + id: str | None + name: str | None + + +class Anonfiles: + @staticmethod + def upload(path: str) -> File | None: + try: + r = requests.post("https://api.anonfiles.com/upload", files={'file': open(path, 'rb')}).json() + if not r["status"]: + return + + return File(url=r["data"]["file"]["url"]["full"], + id=r["data"]["file"]["metadata"]["id"], + name=r["data"]["file"]["metadata"]["name"]) + + except Exception as e: + print(e) + return File(None, None, None) + + @staticmethod + def get_direct(url: str) -> str | None: + try: + return Direct().anonfiles(url)['directDownload'] + + except Exception as e: + print(e) diff --git a/modules/config/model.py b/modules/config/model.py index b585141..8074e72 100644 --- a/modules/config/model.py +++ b/modules/config/model.py @@ -22,3 +22,12 @@ class PathsModel: first_browser_path: str second_browser_path: str collections_list: List[str] + + +@dataclass_json +@dataclass(frozen=True) +class PusherModel: + app_id: str + key: str + secret: str + cluster: str diff --git a/modules/config/pusher.py b/modules/config/pusher.py new file mode 100644 index 0000000..b6a4541 --- /dev/null +++ b/modules/config/pusher.py @@ -0,0 +1,45 @@ +from modules.config.model import PusherModel +import json +import os + + +class PusherConfig: + @staticmethod + def default(): + return { + "app_id": str(), + "key": str(), + "secret": str(), + "cluster": str() + } + + @staticmethod + def fix() -> None: + try: + with open("data/config.pusher", "w") as file: + json.dump(PusherConfig.default(), file) + except FileNotFoundError: + if not os.path.exists('data'): + os.mkdir('data') + PusherConfig.fix() + + @staticmethod + def get() -> PusherModel: + try: + with open("data/config.pusher", "r") as file: + return PusherModel.from_dict(json.load(file)) + except: + PusherConfig.fix() + return PusherConfig.get() + + @staticmethod + def update(key: str, value: str | list | None) -> dict: + with open("data/config.pusher", "r") as file: + settings = json.load(file) + + settings[key] = value + + with open("data/config.pusher", "w") as file: + json.dump(settings, file) + + return settings diff --git a/modules/player/convert.py b/modules/player/convert.py index a030816..5f4a1fc 100644 --- a/modules/player/convert.py +++ b/modules/player/convert.py @@ -6,17 +6,19 @@ import pafy import hashlib import os from modules.spotify.spotify_dl import Spotify +from modules.anonfiles.anonfiles import Anonfiles import requests +import urllib.parse def get_raw_link(url): if validators.url(url): - if 'spotify' in url: + if 'spotify' in url.lower(): url = Spotify().get_youtube_url(url) - print(url) - if 'youtu' in url: + if 'youtu' in url.lower(): url = pafy.new(url).getbestaudio().url - print(url) + if 'anonfiles' in url.lower(): + url = urllib.parse.quote(Anonfiles.get_direct(url), safe=':/') return url diff --git a/requirements.txt b/requirements.txt index 0ca280f..e7dd2d7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,4 +12,7 @@ pydub pafy youtube-dl==2020.12.2 ezzthread -qt-thread-updater \ No newline at end of file +qt-thread-updater +Direct-Download +pusher +pysher \ No newline at end of file