Skip to content

Commit

Permalink
Release v1.4.0 #157
Browse files Browse the repository at this point in the history
Lyrics Support
  • Loading branch information
cwilvx authored Nov 14, 2023
2 parents be1bb03 + 569f86d commit 52173d4
Show file tree
Hide file tree
Showing 32 changed files with 825 additions and 233 deletions.
25 changes: 19 additions & 6 deletions .github/changelog.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
`v1.3.1` is a patch release to fix issue #149
This version adds a few new features and minor bug fixes.

# Bug fix
`ValueError: Decompressed Data Too Large` error when processing images with large album covers.
# What's new?

---
1. Synced lyrics support #126
2. Lyrics finder plugin (experimental)
3. Context option to search artist or album on streaming platforms

_See [changelog for `v1.3.0`](https://github.com/swing-opensource/swingmusic/releases/tag/v1.3.0) for all main changes since `v1.2.0`._
### Lyrics support

Have fun!
You can now sing along your music with the new lyrics feature. Click the lyrics button in the bottom bar to view lyrics.

### Lyrics finder plugin

This experimental will find synced lyrics for you. Go to `settings > plugins` to start using it. When lyrics are found, they will be saved to a lrc file in the same directory as the playing track.

# Bug fixes
1. Blank page on safari #155
2. Telemetry has been removed #153
3. Seeking before playing will maintain the position when playback starts
4. A forgotten few

_PS: I also attempted to add a cool fullscreen standby view, but I couldn't animate the images when going to the next/prev track, so I ditched it_
5 changes: 3 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ jobs:
run: |
python -m poetry run python manage.py --build
env:
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
LASTFM_API_KEY: ${{ secrets.LASTFM_API_KEY }}
PLUGIN_LYRICS_AUTHORITY: ${{ secrets.PLUGIN_LYRICS_AUTHORITY }}
PLUGIN_LYRICS_ROOT_URL: ${{ secrets.PLUGIN_LYRICS_ROOT_URL }}
- name: Verify Linux build success
if: matrix.os == 'ubuntu-20.04'
run: |
Expand Down Expand Up @@ -102,7 +103,7 @@ jobs:
name: win32
path: dist/swingmusic.exe
retention-days: 1

release:
name: Create New Release
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
</div>
<div align="center" style="font-size: 2rem"><b>Swing Music</b></div>

<div align="center"><b><sub><code>v1.3.1</code></sub></b></div>
<div align="center"><b><sub><code>v1.4.0</code></sub></b></div>

**<div align="center" style="padding-top: 1.25rem">[Download](https://swingmusic.vercel.app/downloads) • <a href="https://swingmusic.vercel.app/support-us.html" target="_blank">Support Development</a> • [Browse Docs](https://swingmusic.vercel.app/guide/introduction.html)[Screenshots](https://swingmusic.vercel.app)</div>**

Expand Down
8 changes: 8 additions & 0 deletions app/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from flask_compress import Compress
from flask_cors import CORS

from .plugins import lyrics as lyrics_plugin
from app.api import (
album,
artist,
Expand All @@ -17,6 +18,8 @@
search,
send_file,
settings,
lyrics,
plugins,
)


Expand All @@ -43,5 +46,10 @@ def create_api():
app.register_blueprint(imgserver.api)
app.register_blueprint(settings.api)
app.register_blueprint(colors.api)
app.register_blueprint(lyrics.api)

# Plugins
app.register_blueprint(plugins.api)
app.register_blueprint(lyrics_plugin.api)

return app
4 changes: 2 additions & 2 deletions app/api/album.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ def get_album_tracks_and_info():
album = AlbumStore.get_album_by_hash(albumhash)

if album is None:
return error_msg, 204
return error_msg, 404

tracks = TrackStore.get_tracks_by_albumhash(albumhash)

if tracks is None:
return error_msg, 404

if len(tracks) == 0:
return error_msg, 204
return error_msg, 404

def get_album_genres(tracks: list[Track]):
genres = set()
Expand Down
17 changes: 1 addition & 16 deletions app/api/artist.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""
Contains all the artist(s) routes.
"""
import random
import math
import random
from datetime import datetime

from flask import Blueprint, request
Expand All @@ -15,29 +15,15 @@
from app.store.albums import AlbumStore
from app.store.artists import ArtistStore
from app.store.tracks import TrackStore
from app.telemetry import Telemetry
from app.utils.threading import background

api = Blueprint("artist", __name__, url_prefix="/")

ARTIST_VISIT_COUNT = 0


@background
def send_event():
global ARTIST_VISIT_COUNT
ARTIST_VISIT_COUNT += 1

if ARTIST_VISIT_COUNT % 5 == 0:
Telemetry.send_artist_visited()


@api.route("/artist/<artisthash>", methods=["GET"])
def get_artist(artisthash: str):
"""
Get artist data.
"""
send_event()
limit = request.args.get("limit")

if limit is None:
Expand Down Expand Up @@ -211,7 +197,6 @@ def get_similar_artists(artisthash: str):
if artist is None:
return {"error": "Artist not found"}, 404

# result = LastFMStore.get_similar_artists_for(artist.artisthash)
result = fmdb.get_similar_artists_for(artist.artisthash)

if result is None:
Expand Down
18 changes: 13 additions & 5 deletions app/api/folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,24 @@ def get_all_drives(is_win: bool = False):
"""
Returns a list of all the drives on a Windows machine.
"""
drives = psutil.disk_partitions()
drives = psutil.disk_partitions(all=True)
drives = [d.mountpoint for d in drives]

if is_win:
drives = [win_replace_slash(d) for d in drives]
else:
remove = ["/boot", "/boot/efi", "/tmp"]
drives = [d for d in drives if d not in remove]
remove = (
"/boot",
"/tmp",
"/snap",
"/var",
"/sys",
"/proc",
"/etc",
"/run",
"/dev",
)
drives = [d for d in drives if not d.startswith(remove)]

return drives

Expand All @@ -94,8 +104,6 @@ def list_folders():
req_dir = "$root"

if req_dir == "$root":
# req_dir = settings.USER_HOME_DIR
# if is_win:
return {
"folders": [{"name": d, "path": d} for d in get_all_drives(is_win=is_win)]
}
Expand Down
59 changes: 59 additions & 0 deletions app/api/lyrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from flask import Blueprint, request

from app.lib.lyrics import (
get_lyrics,
check_lyrics_file,
get_lyrics_from_duplicates,
get_lyrics_from_tags,
)

api = Blueprint("lyrics", __name__, url_prefix="")


@api.route("/lyrics", methods=["POST"])
def send_lyrics():
"""
Returns the lyrics for a track
"""
data = request.get_json()

filepath = data.get("filepath", None)
trackhash = data.get("trackhash", None)

if filepath is None or trackhash is None:
return {"error": "No filepath or trackhash provided"}, 400

is_synced = True
lyrics, copyright = get_lyrics(filepath)

if not lyrics:
lyrics, copyright = get_lyrics_from_duplicates(trackhash, filepath)

if not lyrics:
lyrics, is_synced, copyright = get_lyrics_from_tags(filepath)

if not lyrics:
return {"error": "No lyrics found"}

return {"lyrics": lyrics, "synced": is_synced, "copyright": copyright}, 200


@api.route("/lyrics/check", methods=["POST"])
def check_lyrics():
data = request.get_json()

filepath = data.get("filepath", None)
trackhash = data.get("trackhash", None)

if filepath is None or trackhash is None:
return {"error": "No filepath or trackhash provided"}, 400

exists = check_lyrics_file(filepath, trackhash)

if exists:
return {"exists": exists}, 200

exists = get_lyrics_from_tags(filepath, just_check=True)

return {"exists": exists}, 200

42 changes: 42 additions & 0 deletions app/api/plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from flask import Blueprint, request

from app.db.sqlite.plugins import PluginsMethods


api = Blueprint("plugins", __name__, url_prefix="/plugins")


@api.route("/", methods=["GET"])
def get_all_plugins():
plugins = PluginsMethods.get_all_plugins()

return {"plugins": plugins}


@api.route("/setactive", methods=["GET"])
def activate_deactivate_plugin():
name = request.args.get("plugin", None)
state = request.args.get("state", None)

if not name or not state:
return {"error": "Missing plugin or state"}, 400

PluginsMethods.plugin_set_active(name, int(state))

return {"message": "OK"}, 200


@api.route("/settings", methods=["POST"])
def update_plugin_settings():
data = request.get_json()

plugin = data.get("plugin", None)
settings = data.get("settings", None)

if not plugin or not settings:
return {"error": "Missing plugin or settings"}, 400

PluginsMethods.update_plugin_settings(plugin_name=plugin, settings=settings)
plugin = PluginsMethods.get_plugin_by_name(plugin)

return {"status": "success", "settings": plugin.settings}
47 changes: 47 additions & 0 deletions app/api/plugins/lyrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from flask import Blueprint, request
from app.lib.lyrics import format_synced_lyrics

from app.plugins.lyrics import Lyrics
from app.utils.hashing import create_hash

api = Blueprint("lyricsplugin", __name__, url_prefix="/plugins/lyrics")


@api.route("/search", methods=["POST"])
def search_lyrics():
data = request.get_json()

trackhash = data.get("trackhash", "")
title = data.get("title", "")
artist = data.get("artist", "")
album = data.get("album", "")
filepath = data.get("filepath", None)

finder = Lyrics()

data = finder.search_lyrics_by_title_and_artist(title, artist)

if not data:
return {"trackhash": trackhash, "lyrics": None}

perfect_match = data[0]

for track in data:
i_title = track["title"]
i_album = track["album"]

if create_hash(i_title) == create_hash(title) and create_hash(
i_album
) == create_hash(album):
perfect_match = track

track_id = perfect_match["track_id"]
lrc = finder.download_lyrics(track_id, filepath)

if lrc is not None:
lines = lrc.split("\n")
lyrics = format_synced_lyrics(lines)

return {"trackhash": trackhash, "lyrics": lyrics}, 200

return {"trackhash": trackhash, "lyrics": lrc}, 200
5 changes: 4 additions & 1 deletion app/api/settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from flask import Blueprint, request

from app.db.sqlite.plugins import PluginsMethods as pdb
from app.db.sqlite.settings import SettingsSQLMethods as sdb
from app.lib import populate
from app.lib.watchdogg import Watcher as WatchDog
Expand All @@ -11,7 +12,7 @@
from app.utils.generators import get_random_str
from app.utils.threading import background

api = Blueprint("settings", __name__, url_prefix="/")
api = Blueprint("settings", __name__, url_prefix="")


def get_child_dirs(parent: str, children: list[str]):
Expand Down Expand Up @@ -160,6 +161,7 @@ def get_all_settings():
"""

settings = sdb.get_all_settings()
plugins = pdb.get_all_plugins()

key_list = list(mapp.keys())
s = {}
Expand All @@ -180,6 +182,7 @@ def get_all_settings():

root_dirs = sdb.get_root_dirs()
s["root_dirs"] = root_dirs
s['plugins'] = plugins

return {
"settings": s,
Expand Down
Loading

0 comments on commit 52173d4

Please sign in to comment.