Merge pull request 'Rename project from karaoke-maker to songtrace' (#3) from songtrace-rename into main
Reviewed-on: branderson/karaoke-maker#3
This commit is contained in:
+2
-2
@@ -11,9 +11,9 @@ COPY pyproject.toml ./
|
||||
COPY src ./src
|
||||
RUN pip install --no-cache-dir .
|
||||
|
||||
ENV KARAOKE_MAKER_CONFIG=/config/config.toml \
|
||||
ENV SONGTRACE_CONFIG=/config/config.toml \
|
||||
TORCH_HOME=/data/models \
|
||||
XDG_CACHE_HOME=/data/models/cache
|
||||
|
||||
EXPOSE 8000
|
||||
CMD ["karaoke-maker", "serve"]
|
||||
CMD ["songtrace", "serve"]
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# karaoke-maker
|
||||
# songtrace
|
||||
|
||||
Turn a song and its lyrics into a playable UltraStar chart.
|
||||
|
||||
A CLI and minimal web UI that turns a song — title, artist, lyrics you supply,
|
||||
and a YouTube URL or local video file — into a playable
|
||||
@@ -35,8 +37,21 @@ editor such as [Yass](http://www.yass-hq.de/) or
|
||||
Config is TOML. Resolution order:
|
||||
|
||||
1. `--config <path>` passed explicitly on the command line
|
||||
2. the `KARAOKE_MAKER_CONFIG` environment variable
|
||||
3. `~/.config/karaoke-maker/config.toml`
|
||||
2. the `SONGTRACE_CONFIG` environment variable
|
||||
3. `~/.config/songtrace/config.toml`
|
||||
|
||||
If you used this project under its former name, move your existing config once:
|
||||
|
||||
```sh
|
||||
pip uninstall karaoke-maker # removes the old console script
|
||||
mv ~/.config/karaoke-maker ~/.config/songtrace
|
||||
```
|
||||
|
||||
The Docker deployment needs no config migration — the image sets
|
||||
`SONGTRACE_CONFIG` itself and the config is bind-mounted to a fixed path.
|
||||
Run `docker compose down` before upgrading (or `docker compose up -d
|
||||
--remove-orphans`) since the service key changed and Compose won't replace
|
||||
the old container in place.
|
||||
|
||||
Copy the example and fill in your Whisper server:
|
||||
|
||||
@@ -73,7 +88,7 @@ container recreation.
|
||||
Run the CLI inside the container instead of the web UI:
|
||||
|
||||
```sh
|
||||
docker compose run --rm karaoke-maker karaoke-maker make \
|
||||
docker compose run --rm songtrace songtrace make \
|
||||
--title "Song Title" --artist "Artist Name" \
|
||||
--lyrics /data/lyrics.txt --youtube https://youtu.be/...
|
||||
```
|
||||
@@ -87,17 +102,17 @@ installed on the host; `docker-compose.yml` requests one GPU via the
|
||||
|
||||
```sh
|
||||
pip install -e .
|
||||
karaoke-maker make --help
|
||||
songtrace make --help
|
||||
```
|
||||
|
||||
```
|
||||
karaoke-maker make --title TITLE --artist ARTIST --lyrics LYRICS_FILE \
|
||||
songtrace make --title TITLE --artist ARTIST --lyrics LYRICS_FILE \
|
||||
(--youtube URL | --video PATH) \
|
||||
[--genre GENRE] [--year YEAR] [--language LANGUAGE] [--cover COVER_IMAGE] \
|
||||
[--bpm BPM] [--force-from STAGE] [--config CONFIG]
|
||||
```
|
||||
|
||||
Run the web UI instead with `karaoke-maker serve [--config CONFIG]`.
|
||||
Run the web UI instead with `songtrace serve [--config CONFIG]`.
|
||||
|
||||
## Re-running a stage
|
||||
|
||||
@@ -108,7 +123,7 @@ stage and everything after it, reusing the cached output of everything
|
||||
before it:
|
||||
|
||||
```sh
|
||||
karaoke-maker make --title "..." --artist "..." --lyrics lyrics.txt \
|
||||
songtrace make --title "..." --artist "..." --lyrics lyrics.txt \
|
||||
--youtube https://youtu.be/... --force-from align
|
||||
```
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
services:
|
||||
karaoke-maker:
|
||||
songtrace:
|
||||
build: .
|
||||
ports:
|
||||
- "8000:8000"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
+3
-3
@@ -1,5 +1,5 @@
|
||||
[project]
|
||||
name = "karaoke-maker"
|
||||
name = "songtrace"
|
||||
version = "0.1.0"
|
||||
description = "Generate UltraStar/Melody Mania karaoke songs from a video and reference lyrics"
|
||||
requires-python = ">=3.11"
|
||||
@@ -26,7 +26,7 @@ dependencies = [
|
||||
dev = ["pytest", "playwright"]
|
||||
|
||||
[project.scripts]
|
||||
karaoke-maker = "karaoke_maker.cli:main"
|
||||
songtrace = "songtrace.cli:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=68"]
|
||||
@@ -36,7 +36,7 @@ build-backend = "setuptools.build_meta"
|
||||
where = ["src"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
karaoke_maker = ["static/*", "static/fonts/*"]
|
||||
songtrace = ["static/*", "static/fonts/*"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
|
||||
@@ -15,9 +15,9 @@ import httpx
|
||||
import uvicorn
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.pipeline import PipelineError, PipelineResult
|
||||
from karaoke_maker.web import create_app
|
||||
from songtrace.config import Config
|
||||
from songtrace.pipeline import PipelineError, PipelineResult
|
||||
from songtrace.web import create_app
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
OUT_IMAGE = REPO_ROOT / "docs" / "images" / "webui.png"
|
||||
|
||||
@@ -16,7 +16,7 @@ def _positive_float(value: str) -> float:
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(prog="karaoke-maker")
|
||||
parser = argparse.ArgumentParser(prog="songtrace")
|
||||
parser.add_argument("--version", action="store_true")
|
||||
sub = parser.add_subparsers(dest="command")
|
||||
|
||||
@@ -72,7 +72,7 @@ def _cmd_make(args) -> int:
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = build_parser().parse_args(argv)
|
||||
if args.version:
|
||||
print(f"karaoke-maker {version('karaoke-maker')}")
|
||||
print(f"songtrace {version('songtrace')}")
|
||||
return 0
|
||||
if args.command == "make":
|
||||
return _cmd_make(args)
|
||||
@@ -12,7 +12,7 @@ class Config:
|
||||
whisper_api: str = "openai"
|
||||
output_dir: Path = Path("output")
|
||||
work_dir: Path = Path("work")
|
||||
creator: str = "karaoke-maker"
|
||||
creator: str = "songtrace"
|
||||
demucs_model: str = "htdemucs_ft"
|
||||
crepe_model: str = "full"
|
||||
device: str = "cuda"
|
||||
@@ -25,8 +25,8 @@ _PATH_FIELDS = {"output_dir", "work_dir"}
|
||||
|
||||
def load_config(path: Path | None = None) -> Config:
|
||||
if path is None:
|
||||
env = os.environ.get("KARAOKE_MAKER_CONFIG")
|
||||
path = Path(env) if env else Path.home() / ".config/karaoke-maker/config.toml"
|
||||
env = os.environ.get("SONGTRACE_CONFIG")
|
||||
path = Path(env) if env else Path.home() / ".config/songtrace/config.toml"
|
||||
data = tomllib.loads(Path(path).read_text())
|
||||
known = {f.name for f in fields(Config)}
|
||||
unknown = set(data) - known
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="color-scheme" content="dark">
|
||||
<title>karaoke-maker</title>
|
||||
<title>songtrace</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: "Chakra Petch";
|
||||
@@ -473,7 +473,7 @@ button { cursor: pointer; }
|
||||
|
||||
<aside id="sidebar">
|
||||
<div class="brand">
|
||||
<h1 class="wordmark"><span>KARAOKE</span> <span class="second">MAKER</span></h1>
|
||||
<h1 class="wordmark"><span>SONG</span> <span class="second">TRACE</span></h1>
|
||||
<div class="kana" aria-hidden="true">カラオケ</div>
|
||||
</div>
|
||||
<div>
|
||||
@@ -1,8 +1,8 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.pipeline import Ctx, SongInput
|
||||
from karaoke_maker.stages import acquire
|
||||
from songtrace.config import Config
|
||||
from songtrace.pipeline import Ctx, SongInput
|
||||
from songtrace.stages import acquire
|
||||
|
||||
def make_ctx(tmp_path, **kw):
|
||||
inp = SongInput(title="T", artist="A", lyrics_text="x", **kw)
|
||||
@@ -46,7 +46,7 @@ def test_outputs_are_meta_and_audio(tmp_path):
|
||||
|
||||
def test_requires_exactly_one_source(tmp_path):
|
||||
import pytest
|
||||
from karaoke_maker.pipeline import PipelineError
|
||||
from songtrace.pipeline import PipelineError
|
||||
ctx = make_ctx(tmp_path)
|
||||
with pytest.raises(PipelineError):
|
||||
acquire.acquire_stage().run(ctx)
|
||||
@@ -73,7 +73,7 @@ def test_classify_no_thumbnail(tmp_path):
|
||||
|
||||
def test_classify_no_video_raises(tmp_path):
|
||||
import pytest
|
||||
from karaoke_maker.pipeline import PipelineError
|
||||
from songtrace.pipeline import PipelineError
|
||||
(tmp_path / "source_video.jpg").write_bytes(b"t")
|
||||
with pytest.raises(PipelineError):
|
||||
acquire._classify_downloads(tmp_path)
|
||||
|
||||
+4
-4
@@ -2,10 +2,10 @@ import json
|
||||
|
||||
import pytest
|
||||
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.lyrics import normalize_lyrics
|
||||
from karaoke_maker.pipeline import Ctx, PipelineError, SongInput
|
||||
from karaoke_maker.stages import align
|
||||
from songtrace.config import Config
|
||||
from songtrace.lyrics import normalize_lyrics
|
||||
from songtrace.pipeline import Ctx, PipelineError, SongInput
|
||||
from songtrace.stages import align
|
||||
|
||||
LYRICS = "it's one two three\nfour five six seven eight"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import numpy as np
|
||||
import soundfile as sf
|
||||
|
||||
from karaoke_maker.audio_io import load_wav
|
||||
from songtrace.audio_io import load_wav
|
||||
|
||||
|
||||
def test_load_wav_mono(tmp_path):
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
from karaoke_maker.cli import main
|
||||
from songtrace.cli import main
|
||||
|
||||
def test_version(capsys):
|
||||
assert main(["--version"]) == 0
|
||||
assert "karaoke-maker" in capsys.readouterr().out
|
||||
assert "songtrace" in capsys.readouterr().out
|
||||
|
||||
@@ -2,9 +2,9 @@ import os
|
||||
|
||||
import pytest
|
||||
|
||||
import karaoke_maker.cli as cli
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.pipeline import PipelineError, PipelineResult
|
||||
import songtrace.cli as cli
|
||||
from songtrace.config import Config
|
||||
from songtrace.pipeline import PipelineError, PipelineResult
|
||||
|
||||
|
||||
def setup_cfg(monkeypatch, tmp_path):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from karaoke_maker.config import Config, load_config
|
||||
from songtrace.config import Config, load_config
|
||||
|
||||
|
||||
def test_load_minimal(tmp_path):
|
||||
@@ -24,7 +24,7 @@ def test_paths_and_overrides(tmp_path):
|
||||
def test_env_var(tmp_path, monkeypatch):
|
||||
cfg_file = tmp_path / "c.toml"
|
||||
cfg_file.write_text('whisper_url = "http://env/v1"\n')
|
||||
monkeypatch.setenv("KARAOKE_MAKER_CONFIG", str(cfg_file))
|
||||
monkeypatch.setenv("SONGTRACE_CONFIG", str(cfg_file))
|
||||
assert load_config().whisper_url == "http://env/v1"
|
||||
|
||||
|
||||
|
||||
+9
-9
@@ -4,27 +4,27 @@ import shutil
|
||||
import pytest
|
||||
|
||||
requires_full = pytest.mark.skipif(
|
||||
not os.environ.get("KARAOKE_E2E"),
|
||||
reason="set KARAOKE_E2E=1 (needs GPU, ffmpeg, whisper server, network)")
|
||||
not os.environ.get("SONGTRACE_E2E"),
|
||||
reason="set SONGTRACE_E2E=1 (needs GPU, ffmpeg, whisper server, network)")
|
||||
|
||||
@requires_full
|
||||
def test_full_pipeline(tmp_path):
|
||||
from karaoke_maker.config import load_config
|
||||
from karaoke_maker.pipeline import SongInput, run_pipeline
|
||||
from songtrace.config import load_config
|
||||
from songtrace.pipeline import SongInput, run_pipeline
|
||||
assert shutil.which("ffmpeg"), "ffmpeg required"
|
||||
cfg = load_config()
|
||||
cfg.output_dir = tmp_path / "out"
|
||||
cfg.work_dir = tmp_path / "work"
|
||||
inp = SongInput(
|
||||
title=os.environ["KARAOKE_E2E_TITLE"],
|
||||
artist=os.environ["KARAOKE_E2E_ARTIST"],
|
||||
lyrics_text=open(os.environ["KARAOKE_E2E_LYRICS"]).read(),
|
||||
youtube_url=os.environ.get("KARAOKE_E2E_URL"),
|
||||
title=os.environ["SONGTRACE_E2E_TITLE"],
|
||||
artist=os.environ["SONGTRACE_E2E_ARTIST"],
|
||||
lyrics_text=open(os.environ["SONGTRACE_E2E_LYRICS"]).read(),
|
||||
youtube_url=os.environ.get("SONGTRACE_E2E_URL"),
|
||||
)
|
||||
result = run_pipeline(inp, cfg)
|
||||
txts = list(result.output_dir.glob("*.txt"))
|
||||
assert len(txts) == 1
|
||||
from karaoke_maker.ultrastar import get_header, parse_ultrastar
|
||||
from songtrace.ultrastar import get_header, parse_ultrastar
|
||||
song = parse_ultrastar(txts[0].read_text(encoding="utf-8"))
|
||||
assert get_header(song, "BPM") and get_header(song, "GAP")
|
||||
assert len(song.body) > 20
|
||||
|
||||
+5
-5
@@ -2,11 +2,11 @@ import json
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.grid import scale_bpm, to_ultrastar
|
||||
from karaoke_maker.pipeline import Ctx, PipelineError, SongInput
|
||||
from karaoke_maker.stages import all_stages, grid as grid_stage_mod
|
||||
from karaoke_maker.ultrastar import (
|
||||
from songtrace.config import Config
|
||||
from songtrace.grid import scale_bpm, to_ultrastar
|
||||
from songtrace.pipeline import Ctx, PipelineError, SongInput
|
||||
from songtrace.stages import all_stages, grid as grid_stage_mod
|
||||
from songtrace.ultrastar import (
|
||||
LineBreak, Note, get_header, parse_ultrastar,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from karaoke_maker.lyrics import normalize_lyrics, alignment_token
|
||||
from songtrace.lyrics import normalize_lyrics, alignment_token
|
||||
|
||||
RAW = """[Verse 1]
|
||||
It's one two three
|
||||
|
||||
+4
-4
@@ -2,13 +2,13 @@ import json
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.notes import (
|
||||
from songtrace.config import Config
|
||||
from songtrace.notes import (
|
||||
MIN_NOTE_SEC, TimedNote, build_notes, hz_to_ultrastar, segment_span,
|
||||
syllabify,
|
||||
)
|
||||
from karaoke_maker.pipeline import Ctx, SongInput
|
||||
from karaoke_maker.stages import all_stages, notes as notes_stage_mod
|
||||
from songtrace.pipeline import Ctx, SongInput
|
||||
from songtrace.stages import all_stages, notes as notes_stage_mod
|
||||
|
||||
|
||||
def flat_pitch(duration=10.0, hz=261.63): # C4
|
||||
|
||||
@@ -4,12 +4,12 @@ from pathlib import Path
|
||||
import pytest
|
||||
from PIL import Image
|
||||
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.pipeline import (
|
||||
from songtrace.config import Config
|
||||
from songtrace.pipeline import (
|
||||
STAGE_ORDER, Ctx, PipelineError, SongInput, run_pipeline, song_slug,
|
||||
)
|
||||
from karaoke_maker.stages import all_stages, package
|
||||
from karaoke_maker.ultrastar import get_header, parse_ultrastar
|
||||
from songtrace.stages import all_stages, package
|
||||
from songtrace.ultrastar import get_header, parse_ultrastar
|
||||
|
||||
SONG_TXT = ("#TITLE:T\n#ARTIST:A\n#MP3:A - T.mp3\n#COVER:A - T.jpg\n"
|
||||
"#VIDEO:A - T.webm\n#BPM:200\n#GAP:0\n: 0 1 0 la\nE\n")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.pipeline import SongInput, Stage, run_pipeline, song_slug
|
||||
from songtrace.config import Config
|
||||
from songtrace.pipeline import SongInput, Stage, run_pipeline, song_slug
|
||||
|
||||
def make_cfg(tmp_path):
|
||||
return Config(whisper_url="http://x/v1", output_dir=tmp_path / "out",
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
import numpy as np
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.pipeline import Ctx, SongInput
|
||||
from karaoke_maker.stages import pitch
|
||||
from songtrace.config import Config
|
||||
from songtrace.pipeline import Ctx, SongInput
|
||||
from songtrace.stages import pitch
|
||||
|
||||
|
||||
def test_pitch_stage_writes_npz(tmp_path, monkeypatch):
|
||||
|
||||
@@ -3,9 +3,9 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.pipeline import STAGE_ORDER, PipelineError, SongInput
|
||||
from karaoke_maker.rebuild import (FIELD_STAGE, changed_fields, plan,
|
||||
from songtrace.config import Config
|
||||
from songtrace.pipeline import STAGE_ORDER, PipelineError, SongInput
|
||||
from songtrace.rebuild import (FIELD_STAGE, changed_fields, plan,
|
||||
relocate_work, superseded_output)
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import numpy as np
|
||||
import soundfile as sf
|
||||
import torch
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.pipeline import Ctx, SongInput
|
||||
from karaoke_maker.stages import separate
|
||||
from songtrace.config import Config
|
||||
from songtrace.pipeline import Ctx, SongInput
|
||||
from songtrace.stages import separate
|
||||
|
||||
|
||||
def test_separate_writes_stems(tmp_path, monkeypatch):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from karaoke_maker.lyrics import normalize_lyrics
|
||||
from karaoke_maker.whisper_client import TranscriptSegment
|
||||
from karaoke_maker.stages.transcribe import lyrics_similarity, vocal_sections
|
||||
from songtrace.lyrics import normalize_lyrics
|
||||
from songtrace.whisper_client import TranscriptSegment
|
||||
from songtrace.stages.transcribe import lyrics_similarity, vocal_sections
|
||||
|
||||
def seg(s, e, t=""):
|
||||
return TranscriptSegment(start=s, end=e, text=t)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from pathlib import Path
|
||||
from karaoke_maker.ultrastar import (
|
||||
from songtrace.ultrastar import (
|
||||
Note, LineBreak, parse_ultrastar, serialize_ultrastar,
|
||||
get_header, format_bpm, parse_bpm,
|
||||
)
|
||||
|
||||
+8
-8
@@ -6,9 +6,9 @@ import time
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.pipeline import STAGE_ORDER, PipelineError, PipelineResult, song_slug
|
||||
from karaoke_maker.web import STAGE_LINE, create_app
|
||||
from songtrace.config import Config
|
||||
from songtrace.pipeline import STAGE_ORDER, PipelineError, PipelineResult, song_slug
|
||||
from songtrace.web import STAGE_LINE, create_app
|
||||
|
||||
|
||||
def make_client(tmp_path, runner):
|
||||
@@ -190,7 +190,7 @@ def test_cover_upload_kept_after_success(tmp_path):
|
||||
|
||||
def test_cleanup_uploads_removes_an_inherited_upload_dir(tmp_path):
|
||||
"""A rebuild's video may live under its parent's id, not its own."""
|
||||
from karaoke_maker.web import _cleanup_uploads
|
||||
from songtrace.web import _cleanup_uploads
|
||||
cfg = Config(whisper_url="u", work_dir=tmp_path / "work",
|
||||
output_dir=tmp_path / "out")
|
||||
parent = cfg.work_dir / "uploads" / "parent"
|
||||
@@ -201,7 +201,7 @@ def test_cleanup_uploads_removes_an_inherited_upload_dir(tmp_path):
|
||||
|
||||
|
||||
def test_cleanup_uploads_ignores_paths_outside_the_upload_root(tmp_path):
|
||||
from karaoke_maker.web import _cleanup_uploads
|
||||
from songtrace.web import _cleanup_uploads
|
||||
cfg = Config(whisper_url="u", work_dir=tmp_path / "work",
|
||||
output_dir=tmp_path / "out")
|
||||
outside = tmp_path / "somewhere" / "keep.mp4"
|
||||
@@ -212,7 +212,7 @@ def test_cleanup_uploads_ignores_paths_outside_the_upload_root(tmp_path):
|
||||
|
||||
|
||||
def test_cleanup_uploads_tolerates_a_missing_file(tmp_path):
|
||||
from karaoke_maker.web import _cleanup_uploads
|
||||
from songtrace.web import _cleanup_uploads
|
||||
cfg = Config(whisper_url="u", work_dir=tmp_path / "work",
|
||||
output_dir=tmp_path / "out")
|
||||
_cleanup_uploads(cfg, "child", cfg.work_dir / "uploads" / "child" / "gone.mp4")
|
||||
@@ -340,13 +340,13 @@ def test_fonts_are_served(tmp_path):
|
||||
|
||||
|
||||
def test_font_licence_is_bundled():
|
||||
from karaoke_maker.web import STATIC
|
||||
from songtrace.web import STATIC
|
||||
licence = (STATIC / "fonts" / "OFL.txt").read_text(encoding="utf-8", errors="replace")
|
||||
assert "SIL OPEN FONT LICENSE" in licence.upper()
|
||||
|
||||
|
||||
def _index_html():
|
||||
from karaoke_maker.web import STATIC
|
||||
from songtrace.web import STATIC
|
||||
return (STATIC / "index.html").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import httpx
|
||||
from pathlib import Path
|
||||
from karaoke_maker.config import Config
|
||||
from karaoke_maker.whisper_client import TranscriptSegment, transcribe
|
||||
from songtrace.config import Config
|
||||
from songtrace.whisper_client import TranscriptSegment, transcribe
|
||||
|
||||
def test_transcribe_parses_segments(tmp_path):
|
||||
audio = tmp_path / "v.wav"
|
||||
|
||||
Reference in New Issue
Block a user