Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch 1 #5

Merged
merged 3 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,9 @@ dmypy.json

# Pyre type checker
.pyre/

# pyright
pyrightconfig.json

# typestubs
typings
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# beets-vocadb

Plugin for beets to use VocaDB, UtaiteDB and TouhouDB as an autotagger source.
Plugins for beets to use VocaDB, UtaiteDB and TouhouDB as autotagger sources.

## Installation

```Shell
pip install git+https://github.com/prTopi/beets-vocadb
pip install git+https://github.com/amogus07/beets-vocadb
```

or, if you use [pipx](https://pipx.pypa.io):

```Shell
pipx inject beets git+https://github.com/prTopi/beets-vocadb
pipx inject beets git+https://github.com/amogus07/beets-vocadb
```

This Plugin has 3 components: vocadb, utaitedb and touhoudb.
This repository contains 3 plugins: vocadb, utaitedb and touhoudb.
To enable them, add them to the plugin section of your beets config file:

```yaml
Expand All @@ -24,9 +24,15 @@ plugins:
- touhoudb
```

## Subcommands

Each plugin adds a subcommand to beets that works similarly to the mbsync command.
vocadb adds `vdbsync`, utaitedb adds `udbsync` and touhoudb adds `tdbsync`.
For usage information run `beet [subcommand] -h`.

## Configuration

The plugin uses beets default language list to determine which language to use
The plugins use beets default language list to determine which language to use
for tags.

```yaml
Expand Down
10 changes: 6 additions & 4 deletions beetsplug/touhoudb.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from beetsplug.vocadb import VocaDBPlugin
from beetsplug.vocadb import VocaDBPlugin, VocaDBInstance

class TouhouDBPlugin(VocaDBPlugin):
def __init__(self):
super().__init__()
self.data_source = "TouhouDB"
self.base_url = "https://touhoudb.com/"
self.api_url = "https://touhoudb.com/api/"
self.subcommand = "tdbsync"
self.instance = VocaDBInstance(
base_url = "https://touhoudb.com/",
api_url = "https://touhoudb.com/api/",
subcommand = "tdbsync"
)
10 changes: 6 additions & 4 deletions beetsplug/utaitedb.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from beetsplug.vocadb import VocaDBPlugin
from beetsplug.vocadb import VocaDBPlugin, VocaDBInstance

class UtaiteDBPlugin(VocaDBPlugin):
def __init__(self):
super().__init__()
self.data_source = "UtaiteDB"
self.base_url = "https://utaiteadb.net/"
self.api_url = "https://utaitedb.net/api/"
self.subcommand = "udbsync"
self.instance = VocaDBInstance(
base_url = "https://utaiteadb.net/",
api_url = "https://utaitedb.net/api/",
subcommand = "udbsync"
)
46 changes: 28 additions & 18 deletions beetsplug/vocadb.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from datetime import datetime
from json import load
from re import match, search
from typing import NamedTuple
from urllib.error import HTTPError
from urllib.parse import quote, urljoin
from urllib.request import Request, urlopen
Expand All @@ -10,16 +11,25 @@
from beets.autotag.hooks import AlbumInfo, TrackInfo
from beets.plugins import BeetsPlugin, apply_item_changes, get_distance

USER_AGENT = f"beets/{beets.__version__} +https://beets.io/"
HEADERS = {"accept": "application/json", "User-Agent": USER_AGENT}


class VocaDBInstance(NamedTuple):
base_url: str
api_url: str
subcommand: str


class VocaDBPlugin(BeetsPlugin):
def __init__(self):
super().__init__()
self.data_source = "VocaDB"
self.base_url = "https://vocadb.net/"
self.api_url = "https://vocadb.net/api/"
self.subcommand = "vdbsync"
self.user_agent = f"beets/{beets.__version__} +https://beets.io/"
self.headers = {"accept": "application/json", "User-Agent": self.user_agent}
self.instance = VocaDBInstance(
base_url = "https://vocadb.net/",
api_url = "https://vocadb.net/api/",
subcommand = "vdbsync"
)
self.config.add(
{
"source_weight": 0.5,
Expand All @@ -29,7 +39,7 @@ def __init__(self):
)

def commands(self):
cmd = ui.Subcommand(self.subcommand, help=f"update metadata from {self.data_source}")
cmd = ui.Subcommand(self.instance.subcommand, help=f"update metadata from {self.data_source}")
cmd.parser.add_option(
"-p",
"--pretend",
Expand Down Expand Up @@ -146,14 +156,14 @@ def albums(self, lib, query, move, pretend, write):
track_id,
album_formatted
)

if missing_tracks:
self._log.warning(
"The following track IDs were missing in the VocaDB album info for {0}: {1}",
album_formatted,
', '.join(missing_tracks)
)

self._log.debug("applying changes to {}", album_formatted)
with lib.transaction():
autotag.apply_metadata(album_info, mapping)
Expand Down Expand Up @@ -194,10 +204,10 @@ def album_distance(self, items, album_info, mapping):
def candidates(self, items, artist, album, va_likely, extra_tags=None):
self._log.debug("Searching for album {0}", album)
url = urljoin(
self.api_url,
self.instance.api_url,
f"albums/?query={quote(album)}&maxResults=5&nameMatchMode=Auto",
)
request = Request(url, headers=self.headers)
request = Request(url, headers=HEADERS)
try:
with urlopen(request) as result:
if result:
Expand All @@ -216,13 +226,13 @@ def item_candidates(self, item, artist, title):
self._log.debug("Searching for track {0}", item)
language = self.get_lang(config["import"]["languages"].as_str_seq())
url = urljoin(
self.api_url,
self.instance.api_url,
f"songs/?query={quote(title)}"
+ f"&fields={self.get_song_fields()}"
+ f"&lang={language}"
+ "&maxResults=5&sort=SongType&preferAccurateMatches=true&nameMatchMode=Auto",
)
request = Request(url, headers=self.headers)
request = Request(url, headers=HEADERS)
try:
with urlopen(request) as result:
if result:
Expand All @@ -243,13 +253,13 @@ def album_for_id(self, album_id):
self._log.debug("Searching for album {0}", album_id)
language = self.get_lang(config["import"]["languages"].as_str_seq())
url = urljoin(
self.api_url,
self.instance.api_url,
f"albums/{album_id}"
+ "?fields=Artists,Discs,Tags,Tracks,WebLinks"
+ f"&songFields={self.get_song_fields()}"
+ f"&lang={language}",
)
request = Request(url, headers=self.headers)
request = Request(url, headers=HEADERS)
try:
with urlopen(request) as result:
if result:
Expand All @@ -266,12 +276,12 @@ def track_for_id(self, track_id):
self._log.debug("Searching for track {0}", track_id)
language = self.get_lang(config["import"]["languages"].as_str_seq())
url = urljoin(
self.api_url,
self.instance.api_url,
f"songs/{track_id}"
+ f"?fields={self.get_song_fields()}"
+ f"&lang={language}",
)
request = Request(url, headers=self.headers)
request = Request(url, headers=HEADERS)
try:
with urlopen(request) as result:
if result:
Expand Down Expand Up @@ -360,7 +370,7 @@ def album_info(self, release, search_lang=None):
media = release["discs"][0]["name"]
except IndexError:
media = None
data_url = urljoin(self.base_url, f"Al/{album_id}")
data_url = urljoin(self.instance.base_url, f"Al/{album_id}")
return AlbumInfo(
album=album,
album_id=album_id,
Expand Down Expand Up @@ -417,7 +427,7 @@ def track_info(
composer = ", ".join(artist_categories["composers"])
lyricist = ", ".join(artist_categories["lyricists"])
length = recording.get("lengthSeconds", 0)
data_url = urljoin(self.base_url, f"S/{track_id}")
data_url = urljoin(self.instance.base_url, f"S/{track_id}")
bpm = str(recording.get("maxMilliBpm", 0) // 1000)
genre = self.get_genres(recording)
script, language, lyrics = self.get_lyrics(
Expand Down
Loading