From 640016267350b338aa01ac5fb9f674fdc690229c Mon Sep 17 00:00:00 2001 From: Justin Donofrio Date: Tue, 24 Dec 2024 05:19:34 -0500 Subject: [PATCH] login to apple music with media-user-token instead of cookie file --- src/onthespot/__init__.py | 1 - src/onthespot/api/apple_music.py | 44 ++++++++++---------------------- src/onthespot/api/generic.py | 1 + src/onthespot/gui/mainui.py | 42 +++++++++--------------------- 4 files changed, 26 insertions(+), 62 deletions(-) diff --git a/src/onthespot/__init__.py b/src/onthespot/__init__.py index d12b969..20e0f76 100644 --- a/src/onthespot/__init__.py +++ b/src/onthespot/__init__.py @@ -64,7 +64,6 @@ def main(): account['service'] = 'youtube_music' config.set_('accounts', cfg_copy) - # Set Application Version version = "v1.0.5" logger.info(f'OnTheSpot Version: {version}') diff --git a/src/onthespot/api/apple_music.py b/src/onthespot/api/apple_music.py index 97aff1d..962f7b9 100644 --- a/src/onthespot/api/apple_music.py +++ b/src/onthespot/api/apple_music.py @@ -1,5 +1,4 @@ import base64 -from http.cookiejar import MozillaCookieJar import json import m3u8 from pathlib import Path @@ -19,46 +18,26 @@ WVN_KEY = base64.b64decode(b'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QrSyZcBqHO0QrdPcU35GBT7S7+IJr2AAXvnjqnb8yrtpPWN2ZW/IWUJN2z4vZ7/HV4aj3OZhkxC1DIMNyvsusUKoQQuf8gwKiEe8cFwbwFSicywlFk9la2IPe8oFShcxAzHLCCn/TIYUAvEL3/4LgaZvqWm80qCPYbgIP5HT8hPYkKWJ4WYknEWK+3InbnkzteFfGrQFCq4CCAESEGnj6Ji7LD+4o7MoHYT4jBQYjtW+kQUijgIwggEKAoIBAQDY9um1ifBRIOmkPtDZTqH+CZUBbb0eK0Cn3NHFf8MFUDzPEz+emK/OTub/hNxCJCao//pP5L8tRNUPFDrrvCBMo7Rn+iUb+mA/2yXiJ6ivqcN9Cu9i5qOU1ygon9SWZRsujFFB8nxVreY5Lzeq0283zn1Cg1stcX4tOHT7utPzFG/ReDFQt0O/GLlzVwB0d1sn3SKMO4XLjhZdncrtF9jljpg7xjMIlnWJUqxDo7TQkTytJmUl0kcM7bndBLerAdJFGaXc6oSY4eNy/IGDluLCQR3KZEQsy/mLeV1ggQ44MFr7XOM+rd+4/314q/deQbjHqjWFuVr8iIaKbq+R63ShAgMBAAEo8CISgAMii2Mw6z+Qs1bvvxGStie9tpcgoO2uAt5Zvv0CDXvrFlwnSbo+qR71Ru2IlZWVSbN5XYSIDwcwBzHjY8rNr3fgsXtSJty425djNQtF5+J2jrAhf3Q2m7EI5aohZGpD2E0cr+dVj9o8x0uJR2NWR8FVoVQSXZpad3M/4QzBLNto/tz+UKyZwa7Sc/eTQc2+ZcDS3ZEO3lGRsH864Kf/cEGvJRBBqcpJXKfG+ItqEW1AAPptjuggzmZEzRq5xTGf6or+bXrKjCpBS9G1SOyvCNF1k5z6lG8KsXhgQxL6ADHMoulxvUIihyPY5MpimdXfUdEQ5HA2EqNiNVNIO4qP007jW51yAeThOry4J22xs8RdkIClOGAauLIl0lLA4flMzW+VfQl5xYxP0E5tuhn0h+844DslU8ZF7U1dU2QprIApffXD9wgAACk26Rggy8e96z8i86/+YYyZQkc9hIdCAERrgEYCEbByzONrdRDs1MrS/ch1moV5pJv63BIKvQHGvLkaFwoMY29tcGFueV9uYW1lEgd1bmtub3duGioKCm1vZGVsX25hbWUSHEFuZHJvaWQgU0RLIGJ1aWx0IGZvciB4ODZfNjQaGwoRYXJjaGl0ZWN0dXJlX25hbWUSBng4Nl82NBodCgtkZXZpY2VfbmFtZRIOZ2VuZXJpY194ODZfNjQaIAoMcHJvZHVjdF9uYW1lEhBzZGtfcGhvbmVfeDg2XzY0GmMKCmJ1aWxkX2luZm8SVUFuZHJvaWQvc2RrX3Bob25lX3g4Nl82NC9nZW5lcmljX3g4Nl82NDo5L1BTUjEuMTgwNzIwLjAxMi80OTIzMjE0OnVzZXJkZWJ1Zy90ZXN0LWtleXMaHgoUd2lkZXZpbmVfY2RtX3ZlcnNpb24SBjE0LjAuMBokCh9vZW1fY3J5cHRvX3NlY3VyaXR5X3BhdGNoX2xldmVsEgEwMg4QASAAKA0wAEAASABQAA==') -def apple_music_add_account(file_path): - with open(file_path, 'r') as file: - first_line = file.readline().strip() - if first_line != '# Netscape HTTP Cookie File': - logger.info("The file is not a valid Netscape cookie file.") - return False - - cookie_lines = file.readlines() - +def apple_music_add_account(media_user_token): cfg_copy = config.get('accounts').copy() - login_dict = {} - - # Process each line to gather cookies - for line in cookie_lines[1:]: # Skip the header line - parts = line.strip().split('\t') - - if len(parts) >= 7: # Ensure there are enough parts - name = parts[5] # Cookie name - value = parts[6] # Cookie value - - # Add each cookie name-value pair to the login dictionary - login_dict[name] = value - new_user = { "uuid": str(uuid.uuid4()), "service": "apple_music", "active": True, - "login": login_dict + "login": { + "media-user-token": media_user_token + } } cfg_copy.append(new_user) config.set_('accounts', cfg_copy) config.update() - return True def apple_music_login_user(account): logger.info('Logging into Apple Music account...') try: session = requests.Session() - session.cookies.update(account['login']) + session.cookies.update({'media-user-token': account['login']['media-user-token']}) session.headers.update( { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0", @@ -78,19 +57,22 @@ def apple_music_login_user(account): ) # Retrieve token from the homepage - home_page = session.get("https://beta.music.apple.com").text + home_page = session.get("https://music.apple.com").text index_js_uri = re.search(r"/(assets/index-legacy-[^/]+\.js)", home_page).group(1) - index_js_page = session.get(f"https://beta.music.apple.com/{index_js_uri}").text + index_js_page = session.get(f"https://music.apple.com/{index_js_uri}").text token = re.search('(?=eyJh)(.*?)(?=")', index_js_page).group(1) session.headers.update({"authorization": f"Bearer {token}"}) session.params = {"l": 'en-US'} + account_data = session.get(f'{BASE_URL}/me/account?meta=subscription&challenge%5BsubscriptionCapabilities%5D=voice%2Cpremium').json() + session.cookies.update({'itua': account_data.get('meta', {}).get('subscription', {}).get('storefront', '')}) + account_pool.append({ "uuid": account['uuid'], - "username": account['login']['pltvcid'], + "username": account['login']['media-user-token'], "service": "apple_music", "status": "active", - "account_type": "premium", + "account_type": "premium" if account_data.get('meta', {}).get('subscription', {}).get('active', '') else 'free', "bitrate": "256k", "login": { "session": session @@ -101,7 +83,7 @@ def apple_music_login_user(account): logger.error(f"Unknown Exception: {str(e)}") account_pool.append({ "uuid": account['uuid'], - "username": account['login']['pltvcid'], + "username": account['login']['media-user-token'], "service": "apple_music", "status": "error", "account_type": "N/A", diff --git a/src/onthespot/api/generic.py b/src/onthespot/api/generic.py index 0ff8f09..69e78af 100644 --- a/src/onthespot/api/generic.py +++ b/src/onthespot/api/generic.py @@ -70,6 +70,7 @@ def generic_get_track_metadata(_, url): return info + def generic_list_extractors(): extractors = extractor.gen_extractors() extractor_list = [] diff --git a/src/onthespot/gui/mainui.py b/src/onthespot/gui/mainui.py index cf20a66..d743668 100644 --- a/src/onthespot/gui/mainui.py +++ b/src/onthespot/gui/mainui.py @@ -252,12 +252,9 @@ def reset_app_config(self): self.__show_popup_dialog("The application setting was cleared successfully !\n Please restart the application.") - def select_dir(self, output, file=False): + def select_dir(self, output): self.setStyleSheet(config.get('theme')) - if file: - path, _ = QFileDialog.getOpenFileName(self, 'OnTheSpot - Select File', os.path.expanduser("~"), "All Files (*)") - else: - path = QFileDialog.getExistingDirectory(self, 'OnTheSpot - Select Directory', os.path.expanduser("~")) + path = QFileDialog.getExistingDirectory(self, 'OnTheSpot - Select Directory', os.path.expanduser("~")) if path.strip() != '': output.setText(QDir.toNativeSeparators(path)) @@ -597,18 +594,22 @@ def set_login_fields(self): # Apple Music if self.inp_login_service.currentIndex() == 0: - self.inp_login_password.setDisabled(True) + self.inp_login_password.setDisabled(False) self.lb_login_username.hide() self.inp_login_username.hide() self.lb_login_password.show() - self.inp_login_password.setPlaceholderText("Enter the path to your cookie file") - self.lb_login_password.setText(self.tr("Cookie File")) + self.inp_login_password.setPlaceholderText("Enter your apple music media-user-token") + self.lb_login_password.setText(self.tr("Media User Token")) self.inp_login_password.show() self.btn_login_add.clicked.disconnect() self.btn_login_add.show() - self.btn_login_add.setText('') - self.btn_login_add.setIcon(self.get_icon('folder')) - self.btn_login_add.clicked.connect(self.add_apple_music_account_worker) + self.btn_login_add.setIcon(QIcon()) + self.btn_login_add.setText(self.tr("Add Account")) + self.btn_login_add.clicked.connect(lambda: + (self.__show_popup_dialog(self.tr("Account added, please restart the app.")) or True) and + apple_music_add_account(self.inp_login_password.text()) and + self.inp_login_password.clear() + ) # Bandcamp elif self.inp_login_service.currentIndex() == 1: @@ -753,25 +754,6 @@ def set_login_fields(self): ) - def add_apple_music_account_worker(self): - session = None - self.lb_login_password.setDisabled(True) - self.btn_login_add.setDisabled(True) - self.select_dir(self.inp_login_password, file=True) - file_path = self.inp_login_password.text() - if file_path: - session = apple_music_add_account(file_path) - - if session: - config.set_('parsing_acc_sn', len(account_pool)) - config.update() - self.__show_popup_dialog(self.tr("Account added, please restart the app.")) - self.btn_login_add.setDisabled(False) - else: - self.__show_popup_dialog(self.tr("Please enter a valid cookie path.")) - self.btn_login_add.setDisabled(False) - - def add_spotify_account(self): logger.info('Add spotify account clicked ') self.btn_login_add.setText(self.tr("Waiting..."))