From e3eec18aa7d9c27fc2c1208028fa6ab7ffb12005 Mon Sep 17 00:00:00 2001 From: Justin Donofrio Date: Sun, 20 Oct 2024 17:19:10 -0400 Subject: [PATCH] chore: clean imports --- src/onthespot/__init__.py | 23 ++----- src/onthespot/accounts.py | 9 +-- src/onthespot/api/soundcloud.py | 18 ++---- src/onthespot/api/spotify.py | 51 ++++------------ src/onthespot/downloader.py | 24 ++------ src/onthespot/gui/dl_progressbtn.py | 5 +- src/onthespot/gui/mainui.py | 33 +++------- src/onthespot/gui/settings.py | 2 +- src/onthespot/parse_item.py | 31 ++++------ src/onthespot/runtimedata.py | 20 +----- src/onthespot/search.py | 15 +++-- src/onthespot/utils.py | 94 +---------------------------- 12 files changed, 63 insertions(+), 262 deletions(-) diff --git a/src/onthespot/__init__.py b/src/onthespot/__init__.py index 15e2c20..d3d4f17 100755 --- a/src/onthespot/__init__.py +++ b/src/onthespot/__init__.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import os import sys +import threading from PyQt6.QtCore import QTranslator from PyQt6.QtWidgets import QApplication from .gui.mainui import MainWindow @@ -8,30 +9,13 @@ from .runtimedata import get_logger from .otsconfig import config from .parse_item import worker -import threading -from .api.spotify import spotify_login_user def main(): logger = get_logger('__init__') logger.info('Starting application in \n3\n2\n1') app = QApplication(sys.argv) - - - - - - - - thread = threading.Thread(target=worker) - thread.daemon = True # Ensure thread exits when main program does - thread.start() - - - - - # Set Application Version version = "v0.7.1" logger.info(f'OnTheSpot Version: {version}') @@ -68,6 +52,11 @@ def main(): translator.load(path) app.installTranslator(translator) + # Start Item Parser + thread = threading.Thread(target=worker) + thread.daemon = True + thread.start() + # Check for start url try: if sys.argv[1] == "-u" or sys.argv[1] == "--url": diff --git a/src/onthespot/accounts.py b/src/onthespot/accounts.py index 8a59bcb..e174de8 100644 --- a/src/onthespot/accounts.py +++ b/src/onthespot/accounts.py @@ -1,12 +1,13 @@ from .runtimedata import get_logger, account_pool from .otsconfig import config -import threading - from PyQt6.QtCore import QThread, pyqtSignal from .api.spotify import spotify_login_user, spotify_get_token from .api.soundcloud import soundcloud_login_user, soundcloud_get_token + +logger = get_logger("spotify.downloader") + class FillAccountPool(QThread): finished = pyqtSignal() progress = pyqtSignal(str, bool) @@ -16,8 +17,8 @@ def __init__(self, gui=False): super().__init__() def run(self): - account_list = config.get('accounts') - for account in account_list: + accounts = config.get('accounts') + for account in accounts: service = account['service'] if not account['active']: continue diff --git a/src/onthespot/api/soundcloud.py b/src/onthespot/api/soundcloud.py index 044fed2..fc0a9c9 100644 --- a/src/onthespot/api/soundcloud.py +++ b/src/onthespot/api/soundcloud.py @@ -1,8 +1,9 @@ import re -import os -import subprocess import requests -import threading +from ..otsconfig import config +from ..runtimedata import get_logger, account_pool, parsing +from ..utils import sanitize_data + SOUNDCLOUD_BASE = "https://api-v2.soundcloud.com" @@ -10,19 +11,8 @@ SOUNDCLOUD_APP_VERSION = "1728640498" SOUNDCLOUD_APP_LOCALE = "en" -from ..otsconfig import config - -import re -import requests -import logging -from ..runtimedata import get_logger, account_pool, parsing - -from ..utils import sanitize_data - logger = get_logger("worker.utility") - - def soundcloud_parse_url(url): headers = {} headers["user-agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36" diff --git a/src/onthespot/api/spotify.py b/src/onthespot/api/spotify.py index 15541c1..f444849 100644 --- a/src/onthespot/api/spotify.py +++ b/src/onthespot/api/spotify.py @@ -1,41 +1,27 @@ -import base64 import os import re -import string -import subprocess -import requests.adapters -from ..otsconfig import config, cache_dir -from ..post_download import conv_list_format -import requests +import time +import uuid import json +from hashlib import md5 +import requests +import requests.adapters +from librespot.audio.decoders import AudioQuality +from librespot.core import Session +from librespot.zeroconf import ZeroconfServer from mutagen import File from mutagen.easyid3 import EasyID3, ID3 from mutagen.flac import Picture, FLAC from mutagen.id3 import APIC, TXXX, USLT, WOAS from mutagen.mp4 import MP4, MP4Cover from mutagen.oggvorbis import OggVorbis -from pathlib import Path -from PIL import Image -from io import BytesIO -from hashlib import md5 -from ..runtimedata import get_logger, session_pool, account_pool -from librespot.audio.decoders import AudioQuality - +from ..otsconfig import config, cache_dir +from ..post_download import conv_list_format +from ..runtimedata import get_logger, account_pool from ..post_download import set_audio_tags - -from librespot.core import Session - from ..utils import sanitize_data - -import os -import pathlib -import sys -import time -import uuid -from librespot.zeroconf import ZeroconfServer from ..otsconfig import cache_dir, config from ..runtimedata import get_logger -import json logger = get_logger("spotify.api") @@ -703,21 +689,6 @@ def spotify_get_show_episodes(session, show_id_str): return episodes - -def get_thumbnail(image_dict, preferred_size=22500): - images = {} - for image in image_dict: - try: - images[image['height'] * image['width']] = image['url'] - except TypeError: - # Some playlist and media item do not have cover images - pass - available_sizes = sorted(images) - for size in available_sizes: - if size >= preferred_size: - return images[size] - return images[available_sizes[-1]] if len(available_sizes) > 0 else "" - def make_call(url, token, params=None, headers=None, skip_cache=False): if params is None: params = {} diff --git a/src/onthespot/downloader.py b/src/onthespot/downloader.py index 9e35a64..05ebc1b 100644 --- a/src/onthespot/downloader.py +++ b/src/onthespot/downloader.py @@ -1,31 +1,17 @@ import os +import traceback +import time +import subprocess +from PyQt6.QtCore import QThread, pyqtSignal from librespot.audio.decoders import AudioQuality, VorbisOnlyAudioQuality from librespot.metadata import TrackId, EpisodeId -#from .spotify.api import get_item_metadata, get_episode_info, get_track_lyrics, check_premium -#from .utils.utils import re_init_session, fetch_account_uuid, sanitize_data -from .runtimedata import get_logger, download_queue, download_queue_gui, downloads_status, downloaded_data, failed_downloads, cancel_list, \ - session_pool, thread_pool +from .runtimedata import get_logger, download_queue from .otsconfig import config from .post_download import convert_audio_format, set_audio_tags, set_music_thumbnail -import traceback -from PyQt6.QtCore import QThread, pyqtSignal from .api.spotify import spotify_get_token, spotify_get_track_metadata, spotify_get_episode_metadata, spotify_format_track_path, spotify_format_episode_path, spotify_get_lyrics from .api.soundcloud import soundcloud_get_token, soundcloud_get_track_metadata, soundcloud_format_track_path -#, soundcloud_download_track -import time -import requests - from .accounts import get_account_token -import re -import os -import subprocess -import requests -import threading - -from .runtimedata import parsing, download_queue, pending, failed, completed, cancelled - - logger = get_logger("spotify.downloader") diff --git a/src/onthespot/gui/dl_progressbtn.py b/src/onthespot/gui/dl_progressbtn.py index 54aeced..29173b0 100644 --- a/src/onthespot/gui/dl_progressbtn.py +++ b/src/onthespot/gui/dl_progressbtn.py @@ -1,15 +1,12 @@ -import platform import os -import subprocess import pyperclip from PyQt6.QtGui import QIcon from PyQt6.QtWidgets import QHBoxLayout, QWidget from ..otsconfig import config -from ..runtimedata import downloaded_data, cancel_list, failed_downloads, downloads_status, download_queue, session_pool, get_logger +from ..runtimedata import download_queue, get_logger from ..utils import open_item from ..api.spotify import check_if_media_in_library, save_media_to_library, remove_media_from_library, queue_media, play_media -from ..runtimedata import download_queue_gui logger = get_logger("worker.utility") diff --git a/src/onthespot/gui/mainui.py b/src/onthespot/gui/mainui.py index 3a1b1a4..f4b8d27 100644 --- a/src/onthespot/gui/mainui.py +++ b/src/onthespot/gui/mainui.py @@ -1,39 +1,24 @@ import os -import queue import time import threading -import uuid -from PyQt6 import uic, QtNetwork, QtGui -from PyQt6.QtCore import QThread, QDir, Qt +from urllib3.exceptions import MaxRetryError, NewConnectionError +from PyQt6 import uic, QtGui +from PyQt6.QtCore import QThread, QDir, Qt, pyqtSignal, QObject, QTimer from PyQt6.QtGui import QIcon from PyQt6.QtWidgets import QApplication, QMainWindow, QHeaderView, QLabel, QPushButton, QProgressBar, QTableWidgetItem, QFileDialog, QRadioButton -from ..api.spotify import get_thumbnail -from ..utils import name_by_from_sdata, remove_user, re_init_session, latest_release, open_item - +from ..utils import re_init_session, latest_release, open_item from .dl_progressbtn import DownloadActionsButtons from .settings import load_config, save_config -from .minidialog import MiniDialog -from ..otsconfig import config_dir, config -from ..parse_item import parse_url -from ..runtimedata import get_logger, downloads_status, downloaded_data, failed_downloads, cancel_list, \ - session_pool, thread_pool +from ..otsconfig import config +from ..runtimedata import get_logger, parsing, pending, download_queue, account_pool from .thumb_listitem import LabelWithThumb -from urllib3.exceptions import MaxRetryError, NewConnectionError - -from ..runtimedata import parsing, pending, failed, completed, cancelled, download_queue, account_pool - -from PyQt6.QtCore import QThread, pyqtSignal, QObject, QTimer - from ..api.spotify import spotify_get_token, spotify_get_track_metadata, spotify_get_episode_metadata, spotify_new_session -from ..post_download import conv_list_format - -from ..accounts import get_account_token - from ..api.soundcloud import soundcloud_get_token, soundcloud_get_track_metadata +from ..post_download import conv_list_format +from ..accounts import get_account_token, FillAccountPool from ..search import get_search_results -import time from ..downloader import DownloadWorker -from ..accounts import FillAccountPool + logger = get_logger('gui.main_ui') diff --git a/src/onthespot/gui/settings.py b/src/onthespot/gui/settings.py index 2aa8c6b..4d86688 100644 --- a/src/onthespot/gui/settings.py +++ b/src/onthespot/gui/settings.py @@ -1,6 +1,6 @@ import os from PyQt6.QtGui import QIcon -from ..otsconfig import config_dir, config +from ..otsconfig import config def load_config(self): diff --git a/src/onthespot/parse_item.py b/src/onthespot/parse_item.py index 87f1b79..64d269b 100755 --- a/src/onthespot/parse_item.py +++ b/src/onthespot/parse_item.py @@ -1,41 +1,34 @@ +import re import time -#from .parse_url import parse_url -import queue from .otsconfig import config - from .api.spotify import spotify_get_token, spotify_get_album_tracks, spotify_get_playlist_data, spotify_get_playlist_items, spotify_get_artist_albums, spotify_get_show_episodes - - from .api.soundcloud import soundcloud_parse_url, soundcloud_get_set_items - - -from .runtimedata import get_logger, download_queue, downloads_status, downloaded_data, failed_downloads, cancel_list, \ - session_pool, thread_pool - -from .runtimedata import parsing, download_queue, pending, failed, completed, cancelled +from .runtimedata import get_logger, parsing, download_queue, pending from .accounts import get_account_token -import re + logger = get_logger('gui.main_ui') SOUNDCLOUD_URL_REGEX = re.compile(r"https://soundcloud.com/[-\w:/]+") -SPOTIFY_URL_REGEX = re.compile(r"^(https?://)?open\.spotify\.com/(?Ptrack|album|artist|playlist|episode|show)/(?P[0-9a-zA-Z]{22})(\?si=.+?)?$") -SPOTIFY_INTERNATIONAL_URL_REGEX = re.compile(r"^(https?://)?open\.spotify\.com/intl-([a-zA-Z]+)/(?Ptrack|album|artist|playlist|episode|show)/(?P[0-9a-zA-Z]{22})(\?si=.+?)?$") +SPOTIFY_URL_REGEX = re.compile(r"^(https?://)?open\.spotify\.com/(intl-([a-zA-Z]+)/|)(?Ptrack|album|artist|playlist|episode|show)/(?P[0-9a-zA-Z]{22})(\?si=.+?)?$") #QOBUZ_INTERPRETER_URL_REGEX = re.compile(r"https?://www\.qobuz\.com/\w\w-\w\w/interpreter/[-\w]+/([-\w]+)") #YOUTUBE_URL_REGEX = re.compile(r"https://www\.youtube\.com/watch\?v=[-\w]") - - - def parse_url(url): - if re.match(SOUNDCLOUD_URL_REGEX, url): + accounts = config.get('accounts') + account_service = accounts[config.get('parsing_acc_sn') - 1]['service'] + print(account_service) + if account_service == 'soundcloud' and re.match(SOUNDCLOUD_URL_REGEX, url): item_type, item_id = soundcloud_parse_url(url) item_service = "soundcloud" - elif re.match(SPOTIFY_URL_REGEX, url) or re.match(SPOTIFY_INTERNATIONAL_URL_REGEX, url): + elif account_service == 'spotify' and re.match(SPOTIFY_URL_REGEX, url): match = re.search(SPOTIFY_URL_REGEX, url) item_id = match.group("ID") item_type = match.group("Type") item_service = "spotify" + else: + logger.info('Invalid Url') + return parsing[item_id] = { 'item_url': url, 'item_service': item_service, diff --git a/src/onthespot/runtimedata.py b/src/onthespot/runtimedata.py index 74a114d..c69a95d 100755 --- a/src/onthespot/runtimedata.py +++ b/src/onthespot/runtimedata.py @@ -1,10 +1,8 @@ -from queue import Empty, Queue -from .otsconfig import config import sys import os import logging from logging.handlers import RotatingFileHandler - +from .otsconfig import config log_formatter = logging.Formatter( '[%(asctime)s :: %(name)s :: %(pathname)s -> %(lineno)s:%(funcName)20s() :: %(levelname)s] -> %(message)s' @@ -18,28 +16,12 @@ stdout_handler = logging.StreamHandler(sys.stdout) log_handler.setFormatter(log_formatter) stdout_handler.setFormatter(log_formatter) -download_queue = Queue() -thread_pool = {} -session_pool = {} parsing = {} pending = {} download_queue = {} account_pool = [] - -download_queue_gui = [] -failed = [] -completed = [] -cancelled = [] - -failed_downloads = {} -cancel_list = {} -downloads_status = {} -playlist_m3u_queue = {} -downloaded_data = {} -unavailable = set() - loglevel = int(os.environ.get("LOG_LEVEL", 20)) diff --git a/src/onthespot/search.py b/src/onthespot/search.py index 837373f..cf1918e 100644 --- a/src/onthespot/search.py +++ b/src/onthespot/search.py @@ -1,17 +1,17 @@ - - -from .api.spotify import spotify_get_search_results -from .api.soundcloud import soundcloud_get_search_results -from .runtimedata import account_pool, get_logger import os +from .runtimedata import account_pool, get_logger from .accounts import get_account_token from .parse_item import parse_url -logger = get_logger("spotify.api") from .otsconfig import config +from .api.spotify import spotify_get_search_results +from .api.soundcloud import soundcloud_get_search_results + +logger = get_logger("spotify.api") def get_search_results(search_term, content_types=None): if len(account_pool) <= 0: - return None + return None + if search_term.startswith('https://'): logger.info(f"Search clicked with value with url {search_term}") parse_url(search_term) @@ -25,7 +25,6 @@ def get_search_results(search_term, content_types=None): parse_url(link) return True - logger.info(f"Search clicked with value term {search_term}") if search_term != "": token = get_account_token() diff --git a/src/onthespot/utils.py b/src/onthespot/utils.py index 4ca0547..34c671d 100644 --- a/src/onthespot/utils.py +++ b/src/onthespot/utils.py @@ -1,21 +1,13 @@ import os import platform import time +import subprocess import requests from librespot.core import Session -import re from .otsconfig import config, config_dir from .runtimedata import get_logger -#from .api.spotify import get_currently_playing_url -import subprocess -import asyncio -import traceback -import json -from hashlib import md5 logger = get_logger("utils") -media_tracker_last_query = '' - def re_init_session(session_pool: dict, session_uuid: str, wait_connectivity: bool = False, connectivity_test_url: str = 'https://spotify.com', timeout=60) -> bool: @@ -46,90 +38,6 @@ def re_init_session(session_pool: dict, session_uuid: str, wait_connectivity: bo return False return True - - - - -def remove_user(username: str, login_data_dir: str, config, session_uuid: str, thread_pool: dict, - session_pool: dict) -> bool: - logger.info(f"Removing user '{username[:4]}*******' from saved entries, uuid {session_uuid}") - # Try to stop the thread using this account - if session_uuid in thread_pool.keys(): - thread_pool[session_uuid][0].stop() - logger.info(f'Waiting for worker bound to account : {session_uuid} to exit !') - while not thread_pool[session_uuid][0].is_stopped(): - time.sleep(0.1) - logger.info(f'Waiting for thread bound to worker bound account : {session_uuid} to exit !') - while thread_pool[session_uuid][1].isRunning(): - thread_pool[session_uuid][1].quit() - logger.info(f'Workers and threads associated with account : {session_uuid} cleaned up !') - thread_pool.pop(session_uuid) - # Remove from session pool - if session_uuid in session_pool: - session_pool.pop(session_uuid) - session_json_path = os.path.join(login_data_dir, f"ots_login_{session_uuid}.json") - if os.path.isfile(session_json_path): - os.remove(session_json_path) - removed = False - accounts_copy = config.get("accounts").copy() - accounts = config.get("accounts") - for i in range(0, len(accounts)): - if accounts[i][3] == session_uuid: - accounts_copy.pop(i) - removed = True - break - if removed: - logger.info(f"Saved Account user '{username[:4]}*******' found and removed, uuid: {session_uuid}") - config.set_("accounts", accounts_copy) - config.update() - return removed - - -def get_now_playing_local(session): - global media_tracker_last_query - if platform.system() == "Linux": - logger.debug("Linux detected ! Use playerctl to get current track information..") - try: - playerctl_out = subprocess.check_output(["playerctl", "-p", "spotify", "metadata", "xesam:url"]) - except subprocess.CalledProcessError: - logger.debug("Spotify not running. Fetching track via api..") - return get_currently_playing_url(session) - spotify_url = playerctl_out.decode() - return spotify_url - else: - logger.debug("Unsupported platform for auto download. Fetching track via api..") - return get_currently_playing_url(session) - - -def name_by_from_sdata(d_key: str, item: dict): - item_name = item_by = None - if d_key == "tracks": - item_name = f"{config.get('explicit_label') if item['explicit'] else ' '} {item['name']}" - item_by = f"{config.get('metadata_seperator').join([artist['name'] for artist in item['artists']])}" - elif d_key == "albums": - rel_year = re.search(r'(\d{4})', item['release_date']).group(1) - item_name = f"[Y:{rel_year}] [T:{item['total_tracks']}] {item['name']}" - item_by = f"{config.get('metadata_seperator').join([artist['name'] for artist in item['artists']])}" - elif d_key == "playlists": - item_name = f"{item['name']}" - item_by = f"{item['owner']['display_name']}" - elif d_key == "artists": - item_name = item['name'] - if f"{'/'.join(item['genres'])}" != "": - item_name = item['name'] + f" | GENERES: {'/'.join(item['genres'])}" - item_by = f"{item['name']}" - elif d_key == "shows": - item_name = f"{config.get('explicit_label') if item['explicit'] else ' '} {item['name']}" - item_by = f"{item['publisher']}" - elif d_key == "episodes": - item_name = f"{config.get('explicit_label') if item['explicit'] else ' '} {item['name']}" - item_by = "" - elif d_key == "audiobooks": - item_name = f"{config.get('explicit_label') if item['explicit'] else ' '} {item['name']}" - item_by = f"{item['publisher']}" - return item_name, item_by - - def latest_release(): url = "https://api.github.com/repos/justin025/onthespot/releases/latest" response = requests.get(url)