diff --git a/app/config.py b/app/config.py index 683af2f..2d0dc33 100644 --- a/app/config.py +++ b/app/config.py @@ -41,7 +41,6 @@ class Config(object): FADE_STEPS = 20 FADE_TIME = 3000 INFO_TAB_TITLE_LENGTH = 15 - INFO_TAB_URL = "https://www.wikipedia.org/w/index.php?search=%s" LAST_PLAYED_TODAY_STRING = "Today" LOG_LEVEL_STDERR = logging.DEBUG LOG_LEVEL_SYSLOG = logging.DEBUG @@ -51,7 +50,7 @@ class Config(object): MAIL_SERVER = os.environ.get('MAIL_SERVER') or "woodlands.midnighthax.com" MAIL_USERNAME = os.environ.get('MAIL_USERNAME') MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None - MAX_INFO_TABS = 3 + MAX_INFO_TABS = 5 MAX_MISSING_FILES_TO_REPORT = 10 MILLISECOND_SIGFIGS = 0 MYSQL_CONNECT = os.environ.get('MYSQL_CONNECT') or "mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_v2" # noqa E501 @@ -67,7 +66,7 @@ class Config(object): TRACK_TIME_FORMAT = "%H:%M:%S" VOLUME_VLC_DEFAULT = 75 VOLUME_VLC_DROP3db = 65 - WEB_ZOOM_FACTOR = 1.4 + WEB_ZOOM_FACTOR = 1.2 config = Config diff --git a/app/infotabs.py b/app/infotabs.py index 04bbc07..c8b0a9a 100644 --- a/app/infotabs.py +++ b/app/infotabs.py @@ -1,6 +1,7 @@ import urllib.parse from datetime import datetime +from slugify import slugify # type: ignore from typing import Dict, Optional from PyQt5.QtCore import QUrl from PyQt5.QtWebEngineWidgets import QWebEngineView @@ -20,7 +21,23 @@ class InfoTabs(QTabWidget): # re-use the oldest one later) self.last_update: Dict[QWebEngineView, datetime] = {} - def open_tab(self, title: str) -> None: + def open_in_songfacts(self, title): + """Search Songfacts for title""" + + slug = slugify(title, replacements=([["'", ""]])) + url = f"https://www.songfacts.com/search/songs/{slug}" + + self.open_tab(url, title) + + def open_in_wikipedia(self, title): + """Search Wikipedia for title""" + + str = urllib.parse.quote_plus(title) + url = f"https://www.wikipedia.org/w/index.php?search={str}" + + self.open_tab(url, title) + + def open_tab(self, url: str, title: str) -> None: """ Open passed URL. Create new tab if we're below the maximum number otherwise reuse oldest content tab. @@ -36,12 +53,12 @@ class InfoTabs(QTabWidget): else: # Reuse oldest widget - widget = min(self.last_update, key=self.last_update.get) + widget = min( + self.last_update, key=self.last_update.get # type: ignore + ) tab_index = self.indexOf(widget) self.setTabText(tab_index, short_title) - txt = urllib.parse.quote_plus(title) - url = Config.INFO_TAB_URL % txt widget.setUrl(QUrl(url)) self.last_update[widget] = datetime.now() diff --git a/app/musicmuster.py b/app/musicmuster.py index 2dc0b9d..850d330 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -813,8 +813,8 @@ class Window(QMainWindow, Ui_MainWindow): # Update headers self.update_headers() - # Populate 'info' tabs - self.tabInfolist.open_tab(track.title) + # Populate 'info' tabs with Wikipedia info + self.tabInfolist.open_in_wikipedia(track.title) def tick(self) -> None: """ diff --git a/app/playlists.py b/app/playlists.py index 33fffd0..40eb422 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -235,13 +235,15 @@ class PlaylistTab(QTableWidget): if item is not None: row_number = item.row() track_id = self._get_row_track_id(row_number) - if track_id: + track_row = track_id > 0 + header_row = not track_row + if track_row: current = row_number == self._get_current_track_row() next_row = row_number == self._get_next_track_row() else: current = next_row = False - if track_id: + if track_row: # Info act_info = self.menu.addAction('Info') act_info.triggered.connect( @@ -281,26 +283,43 @@ class PlaylistTab(QTableWidget): self.menu.addSeparator() + # Look up in wikipedia + act_wikip = self.menu.addAction("Wikipedia") + act_wikip.triggered.connect( + lambda: self._wikipedia(row_number) + ) + + # Look up in songfacts + act_songfacts = self.menu.addAction("Songfacts") + act_songfacts.triggered.connect( + lambda: self._songfacts(row_number) + ) + + self.menu.addSeparator() + # Remove track act_remove_track = self.menu.addAction('Remove track') act_remove_track.triggered.connect( lambda: self._remove_track(row_number) ) - - else: + if header_row: # Add track to section header (ie, make this a track # row) act_add_track = self.menu.addAction('Add track') act_add_track.triggered.connect(self._add_track) + if not current and not next_row: + # Remove row + act_delete = self.menu.addAction('Remove row') + act_delete.triggered.connect(self._delete_rows) + + self.menu.addSeparator() + if not current and not next_row: act_move = self.menu.addAction('Move to playlist...') act_move.triggered.connect(self.musicmuster.move_selected) self.menu.addSeparator() - # Remove row - act_delete = self.menu.addAction('Remove row') - act_delete.triggered.connect(self._delete_rows) return super(PlaylistTab, self).eventFilter(source, event) @@ -1706,6 +1725,13 @@ class PlaylistTab(QTableWidget): caveat = " (to end of playlist)" return ' [' + duration + caveat + ']' + def _songfacts(self, row_number: int) -> None: + """Look up passed row title in songfacts and display info tab""" + + title = self._get_row_title(row_number) + + self.musicmuster.tabInfolist.open_in_songfacts(title) + def _update_note_text(self, playlist_row: PlaylistRows, additional_text: str) -> None: """Append additional_text to row display""" @@ -1744,3 +1770,10 @@ class PlaylistTab(QTableWidget): item_duration.setText(ms_to_mmss(track.duration)) self.update_display(session) + + def _wikipedia(self, row_number: int) -> None: + """Look up passed row title in Wikipedia and display info tab""" + + title = self._get_row_title(row_number) + + self.musicmuster.tabInfolist.open_in_wikipedia(title) diff --git a/poetry.lock b/poetry.lock index abd3158..3f0e179 100644 --- a/poetry.lock +++ b/poetry.lock @@ -481,6 +481,20 @@ pytest = ">=3.0.0" dev = ["pre-commit", "tox"] doc = ["sphinx", "sphinx-rtd-theme"] +[[package]] +name = "python-slugify" +version = "6.1.2" +description = "A Python slugify application that also handles Unicode" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +text-unidecode = ">=1.3" + +[package.extras] +unidecode = ["Unidecode (>=1.1.1)"] + [[package]] name = "python-vlc" version = "3.0.16120" @@ -557,6 +571,14 @@ pure-eval = "*" [package.extras] tests = ["pytest", "typeguard", "pygments", "littleutils", "cython"] +[[package]] +name = "text-unidecode" +version = "1.3" +description = "The most basic Text::Unidecode port" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "tinytag" version = "1.8.1" @@ -622,7 +644,7 @@ python-versions = "*" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "7754808d801630b110a46869b849a6ce205784f587d3c1d4ed2097553e4368c4" +content-hash = "9b4cf9915bf250afd948596a6ba82794f82abf6a6d4891bc51845409632c15fb" [metadata.files] alembic = [ @@ -964,6 +986,7 @@ pytest-qt = [ {file = "pytest-qt-4.0.2.tar.gz", hash = "sha256:dfc5240dec7eb43b76bcb5f9a87eecae6ef83592af49f3af5f1d5d093acaa93e"}, {file = "pytest_qt-4.0.2-py2.py3-none-any.whl", hash = "sha256:e03847ac02a890ccaac0fde1748855b9dce425aceba62005c6cfced6cf7d5456"}, ] +python-slugify = [] python-vlc = [ {file = "python-vlc-3.0.16120.tar.gz", hash = "sha256:92f98fee088f72bd6d063b3b3312d0bd29b37e7ad65ddeb3a7303320300c2807"}, {file = "python_vlc-3.0.16120-py3-none-any.whl", hash = "sha256:c409afb38fe9f788a663b4302ca583f31289ef0860ab2b1668da96bbe8f14bfc"}, @@ -981,6 +1004,7 @@ stack-data = [ {file = "stack_data-0.2.0-py3-none-any.whl", hash = "sha256:999762f9c3132308789affa03e9271bbbe947bf78311851f4d485d8402ed858e"}, {file = "stack_data-0.2.0.tar.gz", hash = "sha256:45692d41bd633a9503a5195552df22b583caf16f0b27c4e58c98d88c8b648e12"}, ] +text-unidecode = [] tinytag = [ {file = "tinytag-1.8.1.tar.gz", hash = "sha256:363ab3107831a5598b68aaa061aba915fb1c7b4254d770232e65d5db8487636d"}, ] diff --git a/pyproject.toml b/pyproject.toml index a3141bd..0c6b614 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,7 @@ PyQtWebEngine = "^5.15.5" pydub = "^0.25.1" PyQt5-sip = "^12.9.1" types-psutil = "^5.8.22" +python-slugify = "^6.1.2" [tool.poetry.dev-dependencies] ipdb = "^0.13.9"