diff --git a/tidal_dl_ng/api.py b/tidal_dl_ng/api.py index 0ba5bb8..4da23f1 100644 --- a/tidal_dl_ng/api.py +++ b/tidal_dl_ng/api.py @@ -13,7 +13,7 @@ __KEYS_JSON__ = """ { "version": "1.0.1", "keys": [ - + // Invalid { "platform": "Fire TV", "formats": "Normal/High/HiFi(No Master)", @@ -22,7 +22,7 @@ __KEYS_JSON__ = """ "valid": "False", "from": "Fokka-Engineering (https://github.com/Fokka-Engineering/libopenTIDAL/blob/655528e26e4f3ee2c426c06ea5b8440cf27abc4a/README.md#example)" }, - + // Only max MQA. { "platform": "Fire TV", "formats": "Master-Only(Else Error)", @@ -31,7 +31,7 @@ __KEYS_JSON__ = """ "valid": "True", "from": "Dniel97 (https://github.com/Dniel97/RedSea/blob/4ba02b88cee33aeb735725cb854be6c66ff372d4/config/settings.example.py#L68)" }, - + // Invalid { "platform": "Android TV", "formats": "Normal/High/HiFi(No Master)", @@ -40,7 +40,7 @@ __KEYS_JSON__ = """ "valid": "False", "from": "" }, - + // Invalid { "platform": "TV", "formats": "Normal/High/HiFi/Master", @@ -49,13 +49,13 @@ __KEYS_JSON__ = """ "valid": "False", "from": "morguldir (https://github.com/morguldir/python-tidal/commit/50f1afcd2079efb2b4cf694ef5a7d67fdf619d09)" }, - + // Invalid { "platform": "Android Auto", "formats": "Normal/High/HiFi/Master", "clientId": "zU4XHVVkc2tDPo4t", "clientSecret": "VJKhDFqJPqvsPVNBV6ukXTJmwlvbttP7wlMlrc72se4=", - "valid": "False", + "valid": "True", "from": "1nikolas (https://github.com/yaronzz/Tidal-Media-Downloader/pull/840)" } ] @@ -106,14 +106,14 @@ def getVersion(): # Load from gist -# try: -# respond = requests.get( -# "https://api.github.com/gists/48d01f5a24b4b7b37f19443977c22cd6", timeout=REQUESTS_TIMEOUT_SEC -# ) -# if respond.status_code == 200: -# content = respond.json()["files"]["tidal-api-key.json"]["content"] -# __API_KEYS__ = json.loads(content) -# except Exception as e: +try: + respond = requests.get( + "https://api.github.com/gists/48d01f5a24b4b7b37f19443977c22cd6", timeout=REQUESTS_TIMEOUT_SEC + ) + if respond.status_code == 200: + content = respond.json()["files"]["tidal-api-key.json"]["content"] + __API_KEYS__ = json.loads(content) +except Exception as e: # TODO: Implement proper logging. -# print(e) -# pass + print(e) + pass diff --git a/tidal_dl_ng/cli.py b/tidal_dl_ng/cli.py index ce8dc3d..c2b51fa 100644 --- a/tidal_dl_ng/cli.py +++ b/tidal_dl_ng/cli.py @@ -246,7 +246,7 @@ def _download(ctx: typer.Context, urls: list[str], try_login: bool = True) -> bo fn_logger = LoggerWrapped(progress.print) dl = Download( - session=ctx.obj[CTX_TIDAL].session, + tidal_obj=ctx.obj[CTX_TIDAL], skip_existing=settings.data.skip_existing, path_base=settings.data.download_base_path, fn_logger=fn_logger, diff --git a/tidal_dl_ng/config.py b/tidal_dl_ng/config.py index 7ab9f24..b796b1a 100644 --- a/tidal_dl_ng/config.py +++ b/tidal_dl_ng/config.py @@ -89,6 +89,7 @@ class Settings(BaseConfig, metaclass=SingletonMeta): class Tidal(BaseConfig, metaclass=SingletonMeta): session: tidalapi.Session + atmos_session: tidalapi.Session = None token_from_storage: bool = False settings: Settings is_pkce: bool @@ -96,11 +97,9 @@ class Tidal(BaseConfig, metaclass=SingletonMeta): def __init__(self, settings: Settings = None): self.cls_model = ModelToken tidal_config: tidalapi.Config = tidalapi.Config(item_limit=10000) - if settings and settings.data.api_key_client_id: - tidal_config.client_id = settings.data.api_key_client_id - tidal_config.client_secret = settings.data.api_key_client_secret - self.session = tidalapi.Session(tidal_config) + # self.session.config.client_id = "km8T1xS355y7dd3H" + # self.session.config.client_secret = "vcmeGW1OuZ0fWYMCSZ6vNvSLJlT3XEpW0ambgYt5ZuI=" self.file_path = path_file_token() self.token_from_storage = self.read(self.file_path) @@ -112,8 +111,12 @@ class Tidal(BaseConfig, metaclass=SingletonMeta): if settings: self.settings = settings - self.session.audio_quality = self.settings.data.quality_audio - self.session.video_quality = tidalapi.VideoQuality.high + # Handle standard qualities and our special Dolby Atmos string + if self.settings.data.quality_audio == "DOLBY_ATMOS": + self.session.audio_quality = "DOLBY_ATMOS" + else: + self.session.audio_quality = tidalapi.Quality(self.settings.data.quality_audio) + self.session.video_quality = tidalapi.VideoQuality.high return True @@ -158,6 +161,32 @@ class Tidal(BaseConfig, metaclass=SingletonMeta): self.set_option("expiry_time", self.session.expiry_time) self.save() + def get_atmos_session(self) -> tidalapi.Session: + """ + Returns the Atmos session. If it doesn't exist, it creates it + by logging in with the Fire TV client ID using the main session's token. + """ + if self.atmos_session is None: + # This config uses the Fire TV client ID needed for Dolby Atmos. + # It is handled internally and not exposed to the user. + atmos_config = tidalapi.Config(item_limit=10000) + atmos_config.client_id = "7m7Ap0JC9j1cOM3n" + atmos_config.client_secret = "vRAdA108tlvkJpTsGZS8rGZ7xTlbJ0qaZ2K9saEzsgY=" + + self.atmos_session = tidalapi.Session(atmos_config) + + # Try to log in using the token from the already logged-in main session. + if not self.atmos_session.check_login(): + self.atmos_session.load_oauth_session( + self.data.token_type, + self.data.access_token, + self.data.refresh_token, + self.data.expiry_time, + is_pkce=self.is_pkce, + ) + + return self.atmos_session + def login(self, fn_print: Callable) -> bool: is_token = self.login_token() result = False diff --git a/tidal_dl_ng/download.py b/tidal_dl_ng/download.py index 1735793..a58d48e 100644 --- a/tidal_dl_ng/download.py +++ b/tidal_dl_ng/download.py @@ -30,7 +30,7 @@ from tidalapi import Album, Mix, Playlist, Session, Track, UserPlaylist, Video from tidalapi.exceptions import TooManyRequests from tidalapi.media import AudioExtensions, Codec, Quality, Stream, StreamManifest, VideoExtensions -from tidal_dl_ng.config import Settings +from tidal_dl_ng.config import Settings, Tidal from tidal_dl_ng.constants import ( CHUNK_SIZE, COVER_NAME, @@ -99,6 +99,7 @@ class Download: """Main class for managing downloads, segment merging, file operations, and metadata for TIDAL media.""" settings: Settings + tidal: "Tidal" # Using a forward reference for type hinting session: Session skip_existing: bool = False fn_logger: Callable @@ -110,7 +111,7 @@ class Download: def __init__( self, - session: Session, + tidal_obj: "Tidal", path_base: str, fn_logger: Callable, skip_existing: bool = False, @@ -134,7 +135,8 @@ class Download: event_run (Event | None, optional): Run event. Defaults to None. """ self.settings = Settings() - self.session = session + self.tidal = tidal_obj + self.session = tidal_obj.session self.skip_existing = skip_existing self.fn_logger = fn_logger self.progress_gui = progress_gui @@ -783,8 +785,36 @@ class Download: if isinstance(media, Track): try: - media_stream = media.get_stream() + # Check which quality the user has selected + selected_quality = self.settings.data.quality_audio + + if selected_quality == "DOLBY_ATMOS": + # Dolby Atmos requested: use the special Atmos session. + atmos_session = self.tidal.get_atmos_session() + + # Store the original quality of the atmos_session to restore it later + original_quality = atmos_session.audio_quality + + try: + # Temporarily set the session to request what Tidal considers "High" (320k AAC). + # This is the key to getting the Atmos stream with the Fire TV client ID. + atmos_session.audio_quality = Quality.low_320k + + # Get the track object from the correct session + atmos_track = atmos_session.track(media.id) + + # Call get_stream() WITHOUT arguments. It will use the quality from the session object. + media_stream = atmos_track.get_stream() + finally: + # IMPORTANT: Always restore the original quality on the atmos_session + atmos_session.audio_quality = original_quality + else: + # Standard behavior: get_stream uses the quality already set on the main session + media_stream = media.get_stream() + stream_manifest = media_stream.get_stream_manifest() + + except TooManyRequests: self.fn_logger.exception( f"Too many requests against TIDAL backend. Skipping '{name_builder_item(media)}'. " diff --git a/tidal_dl_ng/gui.py b/tidal_dl_ng/gui.py index f38461b..3086e47 100644 --- a/tidal_dl_ng/gui.py +++ b/tidal_dl_ng/gui.py @@ -52,7 +52,7 @@ from typing import Any from requests.exceptions import HTTPError from tidalapi.session import LinkLogin -from tidal_dl_ng import api as ApiKeys + from tidal_dl_ng import __version__, update_available from tidal_dl_ng.dialog import DialogLogin, DialogPreferences, DialogVersion from tidal_dl_ng.helper.gui import ( @@ -170,7 +170,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): self._init_progressbar() self._populate_quality(self.cb_quality_audio, Quality) self._populate_quality(self.cb_quality_video, QualityVideo) - self._populate_api_keys(self.cb_api_key) self._populate_search_types(self.cb_search_type, SearchTypes) self.apply_settings(self.settings) self._init_signals() @@ -252,7 +251,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): progress: Progress = Progress() handling_app: HandlingApp = HandlingApp() self.dl = Download( - session=self.tidal.session, + tidal_obj=self.tidal, skip_existing=self.tidal.settings.data.skip_existing, path_base=self.settings.data.download_base_path, fn_logger=logger_gui, @@ -306,14 +305,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): self.te_debug.setTextCursor(cursor) self.te_debug.ensureCursorVisible() - - def _populate_api_keys(self, ui_target: QtWidgets.QComboBox) -> None: - """Puebla el ComboBox con los API keys disponibles.""" - ui_target.addItem("Por defecto", None) - for i, key_data in enumerate(ApiKeys.getItems()): - if key_data["valid"] == "True": - platform_name = f"{key_data['platform']} - ({key_data['formats']})" - ui_target.addItem(platform_name, i) def _populate_quality(self, ui_target: QtWidgets.QComboBox, options: Iterable[Any]) -> None: """Populate a combo box with quality options. @@ -324,6 +315,12 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): """ for item in options: ui_target.addItem(item.name, item) + + # Add our custom Dolby Atmos option to the audio quality dropdown + if ui_target == self.cb_quality_audio: + # Check if it already exists to be safe + if ui_target.findText("DOLBY_ATMOS") == -1: + ui_target.addItem("DOLBY_ATMOS", "DOLBY_ATMOS") def _populate_search_types(self, ui_target: QtWidgets.QComboBox, options: Iterable[Any]) -> None: """Populate a combo box with search type options. @@ -525,17 +522,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): item["element"].setCurrentIndex(idx) else: item["element"].setCurrentIndex(item["default_id"]) - if settings.data.api_key_client_id: - for i in range(self.cb_api_key.count()): - key_index = self.cb_api_key.itemData(i) - if key_index is not None: - key_data = ApiKeys.getItem(key_index) - if key_data["clientId"] == settings.data.api_key_client_id: - self.cb_api_key.setCurrentIndex(i) - break - else: - self.cb_api_key.setCurrentIndex(0) # "Por defecto" - def on_spinner_start(self, parent: QtWidgets.QWidget) -> None: """Start a loading spinner on the given parent widget. @@ -905,7 +891,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): Returns: ResultItem: The constructed ResultItem. """ - + final_quality = quality_audio_highest(item) if hasattr(item, "audio_modes") and "DOLBY_ATMOS" in item.audio_modes: final_quality = "Dolby Atmos" @@ -1130,7 +1116,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): ) self.cb_quality_audio.currentIndexChanged.connect(self.on_quality_set_audio) self.cb_quality_video.currentIndexChanged.connect(self.on_quality_set_video) - self.cb_api_key.currentIndexChanged.connect(self.on_api_key_set) self.tr_lists_user.itemClicked.connect(self.on_list_items_show) self.s_spinner_start[QtWidgets.QWidget].connect(self.on_spinner_start) self.s_spinner_stop.connect(self.on_spinner_stop) @@ -1215,7 +1200,14 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): Args: index: The index of the selected quality in the combo box. """ - self.settings.data.quality_audio = Quality(self.cb_quality_audio.itemData(index)) + quality_data = self.cb_quality_audio.itemData(index) + + # Handle our custom string for Dolby Atmos + if isinstance(quality_data, str) and quality_data == "DOLBY_ATMOS": + self.settings.data.quality_audio = "DOLBY_ATMOS" + else: + self.settings.data.quality_audio = Quality(quality_data) + self.settings.save() if self.tidal: @@ -1233,20 +1225,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): if self.tidal: self.tidal.settings_apply() - def on_api_key_set(self, index: int) -> None: - """Guarda el API Key seleccionado en la configuración.""" - key_index = self.cb_api_key.itemData(index) - if key_index is not None: - key_data = ApiKeys.getItem(key_index) - self.settings.data.api_key_client_id = key_data["clientId"] - self.settings.data.api_key_client_secret = key_data["clientSecret"] - else: # Si se selecciona "Por defecto" - self.settings.data.api_key_client_id = "" - self.settings.data.api_key_client_secret = "" - - self.settings.save() - logger_gui.info("API Key cambiado. Reinicia la aplicación para aplicar los cambios.") - def on_list_items_show(self, item: QtWidgets.QTreeWidgetItem) -> None: """Show the items in the selected playlist or mix. diff --git a/tidal_dl_ng/ui/main.py b/tidal_dl_ng/ui/main.py index 221db1e..4b60620 100644 --- a/tidal_dl_ng/ui/main.py +++ b/tidal_dl_ng/ui/main.py @@ -39,9 +39,15 @@ class Ui_MainWindow: self.a_preferences.setEnabled(True) self.a_preferences.setText("Preferences...") self.a_preferences.setIconText("Preferences...") + # if QT_CONFIG(tooltip) self.a_preferences.setToolTip("Preferences...") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.a_preferences.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.a_preferences.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) self.a_version = QAction(MainWindow) self.a_version.setObjectName("a_version") self.a_exit = QAction(MainWindow) @@ -58,11 +64,21 @@ class Ui_MainWindow: sizePolicy.setVerticalStretch(100) sizePolicy.setHeightForWidth(self.w_central.sizePolicy().hasHeightForWidth()) self.w_central.setSizePolicy(sizePolicy) + # if QT_CONFIG(tooltip) self.w_central.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.w_central.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.w_central.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.w_central.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.w_central.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.horizontalLayout = QHBoxLayout(self.w_central) self.horizontalLayout.setObjectName("horizontalLayout") self.lv_list_user = QVBoxLayout() @@ -79,11 +95,21 @@ class Ui_MainWindow: __qtreewidgetitem3 = QTreeWidgetItem(self.tr_lists_user) __qtreewidgetitem3.setFlags(Qt.ItemIsEnabled) self.tr_lists_user.setObjectName("tr_lists_user") + # if QT_CONFIG(tooltip) self.tr_lists_user.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.tr_lists_user.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.tr_lists_user.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.tr_lists_user.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.tr_lists_user.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.tr_lists_user.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) self.tr_lists_user.setProperty("showDropIndicator", False) self.tr_lists_user.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) @@ -93,7 +119,9 @@ class Ui_MainWindow: self.tr_lists_user.header().setCascadingSectionResizes(True) self.tr_lists_user.header().setHighlightSections(True) self.tr_lists_user.header().setProperty("showSortIndicator", True) + self.lv_list_user.addWidget(self.tr_lists_user) + self.lv_list_control = QHBoxLayout() self.lv_list_control.setObjectName("lv_list_control") self.pb_reload_user_lists = QPushButton(self.w_central) @@ -103,54 +131,99 @@ class Ui_MainWindow: sizePolicy1.setVerticalStretch(0) sizePolicy1.setHeightForWidth(self.pb_reload_user_lists.sizePolicy().hasHeightForWidth()) self.pb_reload_user_lists.setSizePolicy(sizePolicy1) + self.lv_list_control.addWidget(self.pb_reload_user_lists) + self.pb_download_list = QPushButton(self.w_central) self.pb_download_list.setObjectName("pb_download_list") sizePolicy1.setHeightForWidth(self.pb_download_list.sizePolicy().hasHeightForWidth()) self.pb_download_list.setSizePolicy(sizePolicy1) + self.lv_list_control.addWidget(self.pb_download_list) + self.lv_list_user.addLayout(self.lv_list_control) + self.horizontalLayout.addLayout(self.lv_list_user) + self.lv_search_result = QVBoxLayout() + # ifndef Q_OS_MAC self.lv_search_result.setSpacing(-1) + # endif self.lv_search_result.setObjectName("lv_search_result") self.lh_search = QHBoxLayout() self.lh_search.setObjectName("lh_search") self.l_search = QLineEdit(self.w_central) self.l_search.setObjectName("l_search") self.l_search.setAcceptDrops(False) + # if QT_CONFIG(tooltip) self.l_search.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.l_search.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.l_search.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.l_search.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.l_search.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.l_search.setLocale(QLocale(QLocale.English, QLocale.UnitedStates)) self.l_search.setText("") self.l_search.setPlaceholderText("Type and press ENTER to search...") self.l_search.setClearButtonEnabled(True) + self.lh_search.addWidget(self.l_search) + self.cb_search_type = QComboBox(self.w_central) self.cb_search_type.setObjectName("cb_search_type") self.cb_search_type.setMinimumSize(QSize(100, 0)) + # if QT_CONFIG(tooltip) self.cb_search_type.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.cb_search_type.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.cb_search_type.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.cb_search_type.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.cb_search_type.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.cb_search_type.setCurrentText("") self.cb_search_type.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContentsOnFirstShow) self.cb_search_type.setPlaceholderText("") + self.lh_search.addWidget(self.cb_search_type) + self.pb_search = QPushButton(self.w_central) self.pb_search.setObjectName("pb_search") + # if QT_CONFIG(statustip) self.pb_search.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.pb_search.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.pb_search.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.pb_search.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.pb_search.setText("Search") + # if QT_CONFIG(shortcut) self.pb_search.setShortcut("") + # endif // QT_CONFIG(shortcut) + self.lh_search.addWidget(self.pb_search) + self.lv_search_result.addLayout(self.lh_search) + self.tr_results = QTreeView(self.w_central) self.tr_results.setObjectName("tr_results") self.tr_results.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) @@ -160,81 +233,138 @@ class Ui_MainWindow: self.tr_results.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) self.tr_results.setIndentation(10) self.tr_results.setSortingEnabled(True) + self.lv_search_result.addWidget(self.tr_results) + self.lh_download = QHBoxLayout() self.lh_download.setObjectName("lh_download") self.l_quality_audio = QLabel(self.w_central) self.l_quality_audio.setObjectName("l_quality_audio") + # if QT_CONFIG(tooltip) self.l_quality_audio.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.l_quality_audio.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.l_quality_audio.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.l_quality_audio.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.l_quality_audio.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.l_quality_audio.setText("Audio") - self.l_quality_audio.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTrailing | Qt.AlignmentFlag.AlignVCenter) + self.l_quality_audio.setAlignment( + Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTrailing | Qt.AlignmentFlag.AlignVCenter + ) + self.lh_download.addWidget(self.l_quality_audio) + self.cb_quality_audio = QComboBox(self.w_central) self.cb_quality_audio.setObjectName("cb_quality_audio") self.cb_quality_audio.setMinimumSize(QSize(140, 0)) + # if QT_CONFIG(tooltip) self.cb_quality_audio.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.cb_quality_audio.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.cb_quality_audio.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.cb_quality_audio.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.cb_quality_audio.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.cb_quality_audio.setCurrentText("") self.cb_quality_audio.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContentsOnFirstShow) self.cb_quality_audio.setPlaceholderText("") self.cb_quality_audio.setFrame(True) + self.lh_download.addWidget(self.cb_quality_audio) + self.l_quality_video = QLabel(self.w_central) self.l_quality_video.setObjectName("l_quality_video") + # if QT_CONFIG(tooltip) self.l_quality_video.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.l_quality_video.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.l_quality_video.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.l_quality_video.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.l_quality_video.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.l_quality_video.setText("Video") - self.l_quality_video.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTrailing | Qt.AlignmentFlag.AlignVCenter) + self.l_quality_video.setAlignment( + Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTrailing | Qt.AlignmentFlag.AlignVCenter + ) + self.lh_download.addWidget(self.l_quality_video) + self.cb_quality_video = QComboBox(self.w_central) self.cb_quality_video.setObjectName("cb_quality_video") self.cb_quality_video.setMinimumSize(QSize(100, 0)) + # if QT_CONFIG(tooltip) self.cb_quality_video.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.cb_quality_video.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.cb_quality_video.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.cb_quality_video.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.cb_quality_video.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.cb_quality_video.setCurrentText("") self.cb_quality_video.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContentsOnFirstShow) self.cb_quality_video.setPlaceholderText("") + self.lh_download.addWidget(self.cb_quality_video) - - # Start of manually added API Key UI - self.l_api_key = QLabel(self.w_central) - self.l_api_key.setObjectName("l_api_key") - self.l_api_key.setText("API Key") - self.l_api_key.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTrailing | Qt.AlignmentFlag.AlignVCenter) - self.lh_download.addWidget(self.l_api_key) - self.cb_api_key = QComboBox(self.w_central) - self.cb_api_key.setObjectName("cb_api_key") - self.cb_api_key.setMinimumSize(QSize(140, 0)) - self.lh_download.addWidget(self.cb_api_key) - # End of manually added API Key UI self.pb_download = QPushButton(self.w_central) self.pb_download.setObjectName("pb_download") + # if QT_CONFIG(tooltip) self.pb_download.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.pb_download.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.pb_download.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.pb_download.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.pb_download.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.pb_download.setText("Download") + # if QT_CONFIG(shortcut) self.pb_download.setShortcut("") + # endif // QT_CONFIG(shortcut) + self.lh_download.addWidget(self.pb_download) + self.lh_download.setStretch(0, 5) self.lh_download.setStretch(2, 5) self.lh_download.setStretch(4, 15) + self.lv_search_result.addLayout(self.lh_download) + self.te_debug = QPlainTextEdit(self.w_central) self.te_debug.setObjectName("te_debug") self.te_debug.setEnabled(True) @@ -245,15 +375,28 @@ class Ui_MainWindow: self.te_debug.setSizePolicy(sizePolicy2) self.te_debug.setMaximumSize(QSize(16777215, 16777215)) self.te_debug.setAcceptDrops(False) + # if QT_CONFIG(tooltip) self.te_debug.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.te_debug.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.te_debug.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.te_debug.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.te_debug.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.te_debug.setUndoRedoEnabled(False) self.te_debug.setReadOnly(True) + self.lv_search_result.addWidget(self.te_debug) + self.horizontalLayout.addLayout(self.lv_search_result) + self.lv_info = QVBoxLayout() self.lv_info.setObjectName("lv_info") self.lv_info_item = QVBoxLayout() @@ -273,9 +416,13 @@ class Ui_MainWindow: self.l_pm_cover.setPixmap(QPixmap("default_album_image.png")) self.l_pm_cover.setScaledContents(True) self.l_pm_cover.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignTop) + self.horizontalLayout_2.addWidget(self.l_pm_cover) + self.lv_info_item.addLayout(self.horizontalLayout_2) + self.lv_info.addLayout(self.lv_info_item) + self.lv_queue_download = QVBoxLayout() self.lv_queue_download.setObjectName("lv_queue_download") self.l_h_queue_download = QLabel(self.w_central) @@ -285,7 +432,9 @@ class Ui_MainWindow: font.setItalic(False) font.setKerning(True) self.l_h_queue_download.setFont(font) + self.lv_queue_download.addWidget(self.l_h_queue_download) + self.tr_queue_download = QTreeWidget(self.w_central) __qtreewidgetitem4 = QTreeWidgetItem() __qtreewidgetitem4.setText(0, "\ud83e\uddd1\u200d\ud83d\udcbb\ufe0f") @@ -303,7 +452,9 @@ class Ui_MainWindow: self.tr_queue_download.setExpandsOnDoubleClick(False) self.tr_queue_download.header().setProperty("showSortIndicator", False) self.tr_queue_download.header().setStretchLastSection(False) + self.lv_queue_download.addWidget(self.tr_queue_download) + self.horizontalLayout_4 = QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.pb_queue_download_remove = QPushButton(self.w_central) @@ -311,52 +462,94 @@ class Ui_MainWindow: self.pb_queue_download_remove.setEnabled(True) icon = QIcon(QIcon.fromTheme(QIcon.ThemeIcon.EditClear)) self.pb_queue_download_remove.setIcon(icon) + self.horizontalLayout_4.addWidget(self.pb_queue_download_remove) + self.pb_queue_download_toggle = QPushButton(self.w_central) self.pb_queue_download_toggle.setObjectName("pb_queue_download_toggle") icon1 = QIcon(QIcon.fromTheme(QIcon.ThemeIcon.MediaPlaybackPause)) self.pb_queue_download_toggle.setIcon(icon1) + self.horizontalLayout_4.addWidget(self.pb_queue_download_toggle) + self.lv_queue_download.addLayout(self.horizontalLayout_4) + self.horizontalLayout_3 = QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.pb_queue_download_clear_finished = QPushButton(self.w_central) self.pb_queue_download_clear_finished.setObjectName("pb_queue_download_clear_finished") + self.horizontalLayout_3.addWidget(self.pb_queue_download_clear_finished) + self.pb_queue_download_clear_all = QPushButton(self.w_central) self.pb_queue_download_clear_all.setObjectName("pb_queue_download_clear_all") + self.horizontalLayout_3.addWidget(self.pb_queue_download_clear_all) + self.lv_queue_download.addLayout(self.horizontalLayout_3) + self.lv_info.addLayout(self.lv_queue_download) + self.horizontalLayout.addLayout(self.lv_info) + self.horizontalLayout.setStretch(1, 50) self.horizontalLayout.setStretch(2, 25) MainWindow.setCentralWidget(self.w_central) self.menubar = QMenuBar(MainWindow) self.menubar.setObjectName("menubar") self.menubar.setGeometry(QRect(0, 0, 1200, 24)) + # if QT_CONFIG(tooltip) self.menubar.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.menubar.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.menubar.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.menubar.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.menubar.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.m_file = QMenu(self.menubar) self.m_file.setObjectName("m_file") + # if QT_CONFIG(tooltip) self.m_file.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.m_file.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.m_file.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.m_file.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.m_file.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.m_help = QMenu(self.menubar) self.m_help.setObjectName("m_help") MainWindow.setMenuBar(self.menubar) self.statusbar = QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") + # if QT_CONFIG(tooltip) self.statusbar.setToolTip("") + # endif // QT_CONFIG(tooltip) + # if QT_CONFIG(statustip) self.statusbar.setStatusTip("") + # endif // QT_CONFIG(statustip) + # if QT_CONFIG(whatsthis) self.statusbar.setWhatsThis("") + # endif // QT_CONFIG(whatsthis) + # if QT_CONFIG(accessibility) self.statusbar.setAccessibleName("") + # endif // QT_CONFIG(accessibility) + # if QT_CONFIG(accessibility) self.statusbar.setAccessibleDescription("") + # endif // QT_CONFIG(accessibility) self.statusbar.setLayoutDirection(Qt.LayoutDirection.LeftToRight) MainWindow.setStatusBar(self.statusbar) @@ -411,4 +604,4 @@ class Ui_MainWindow: self.m_file.setTitle(QCoreApplication.translate("MainWindow", "File", None)) self.m_help.setTitle(QCoreApplication.translate("MainWindow", "Help", None)) - # retranslateUi \ No newline at end of file + # retranslateUi diff --git a/tidal_dl_ng/ui/main.ui b/tidal_dl_ng/ui/main.ui index 55394e1..2b6d9ac 100644 --- a/tidal_dl_ng/ui/main.ui +++ b/tidal_dl_ng/ui/main.ui @@ -1,7 +1,7 @@ - cb_api_key - + MainWindow + 0 @@ -59,13 +59,13 @@ - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers false - QAbstractItemView::NoSelection + QAbstractItemView::SelectionMode::ExtendedSelection 10 @@ -195,9 +195,9 @@ - + - 7 + -1 @@ -262,9 +262,9 @@ - QComboBox::AdjustToContents + QComboBox::SizeAdjustPolicy::AdjustToContentsOnFirstShow - + @@ -296,7 +296,7 @@ - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers false @@ -308,7 +308,7 @@ false - QAbstractItemView::NoSelection + QAbstractItemView::SelectionMode::ExtendedSelection 10 @@ -340,6 +340,9 @@ Audio + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + @@ -369,14 +372,14 @@ - QComboBox::AdjustToContents + QComboBox::SizeAdjustPolicy::AdjustToContentsOnFirstShow + + + true - - - @@ -399,6 +402,9 @@ Video + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + @@ -428,9 +434,9 @@ - QComboBox::AdjustToContents + QComboBox::SizeAdjustPolicy::AdjustToContentsOnFirstShow - + @@ -462,9 +468,6 @@ - - - @@ -540,7 +543,7 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame @@ -551,6 +554,9 @@ true + + Qt::AlignmentFlag::AlignHCenter|Qt::AlignmentFlag::AlignTop + @@ -563,7 +569,6 @@ - 75 false true true @@ -577,7 +582,7 @@ - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers false @@ -589,10 +594,10 @@ false - QAbstractItemView::NoSelection + QAbstractItemView::SelectionMode::ExtendedSelection - QAbstractItemView::SelectItems + QAbstractItemView::SelectionBehavior::SelectRows false @@ -655,8 +660,7 @@ Remove - - .. + @@ -667,8 +671,11 @@ +<<<<<<< HEAD .. +======= +>>>>>>> 13dddc7 (Refactor Dolby Atmos feature to be internal and seamless) @@ -704,7 +711,7 @@ 0 0 1200 - 26 + 24 @@ -772,7 +779,7 @@ - Qt::LeftToRight + Qt::LayoutDirection::LeftToRight