mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-08-11 03:09:57 +00:00
rename: slopsmith → feedBack, byron → got-feedBack (#537)
* Update GitHub repo references from feedback* to feedBack* * rename: slopsmith -> feedBack, byron -> got-feedBack Renames across the entire codebase: - slopsmith/Slopsmith/SLOPSMITH/SlopSmith -> feedBack/FeedBack/FEEDBACK/FeedBack - byron/Byron/Byrongamatos -> got-feedBack/got-feedBack/got-feedBack - /home/byron/ -> /opt/got-feedBack/ - byron@ougsoft.com -> hi@got-feedBack.org - github.com/byrongamatos/ -> github.com/got-feedback/ - com.byron. -> com.got-feedback. - SLOPSMITH_ env vars -> FEEDBACK_ with backward-compat fallback - Protocol/storage strings migrated with read-old/write-new pattern - window.slopsmith JS API -> window.feedBack (canonical) + backward-compat alias Refs: #rename-slopsmith * rename: complete regen against current main + fix backward-compat alias Regenerated the slopsmith->feedBack / byron->got-feedBack rename on top of current main (3 commits had landed since the branch: #572/#554/#574), resolving the four content conflicts in favour of main's newer content (autoplay/auto-exit, accuracy-badge, Virtuoso re-home, feedpak badge). Completion fixes on top of the mechanical rename: - Re-apply rename to post-branch content the original rename never saw: window.slopsmith(.Tour) consumers in lessons.js / notifications.js / onboarding-tour.js, and the matching JS + python tests (autoplay_exit, progression_*, test_feedpak_extension FEEDBACK_* env vars). The test env vars now match server.py (which reads FEEDBACK_SYNC_STARTUP / FEEDBACK_SKIP_STARTUP_TASKS), so the sync-startup test exercises the real path again. - Restore the window.slopsmith backward-compat alias dropped during conflict resolution, and move the bus aliases to AFTER the _feedBackExisting merge block so they reference the fully-assembled object (also fixes the loop_api.test.js API-surface regex, which the original PR latently broke). - Drop the stray empty data/web_library.db (runtime DB lives in CONFIG_DIR) and gitignore it. - Fix stale tone-source test: feed[dB]ack -> fee[dB]ack to match shipped source labels. Verified locally (org CI billing-blocked): JS 819/819 pass; pytest 1669 passed / 1683 collected with 0 import errors; zero residual slopsmith/byron except the two intentional window.slopsmith aliases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * rename: implement advertised backward-compat + prune dead community plugins Address gaps where PR #537's "Backward compatibility" section was advertised but not implemented, and clean up the community plugin list. Env vars (FEEDBACK_* canonical, legacy SLOPSMITH_* honoured): - New lib/env_compat.py (getenv_compat / env_flag_compat) + tests. server.py (_env_flag + all FEEDBACK_* reads), diagnostics_hardware, gp2midi and tailwind_rebuild now resolve the legacy alias, so existing SLOPSMITH_UI / SLOPSMITH_PLUGINS_DIR / etc. deployments keep working. - Fix the rename collapsing plugins/__init__.py and minigames/routes.py from `FEEDBACK_PLUGINS_DIR or SLOPSMITH_PLUGINS_DIR` into a redundant `FEEDBACK_ or FEEDBACK_` (the fallback was silently lost). Storage (app.js update-channel): - Read feedBack-update-channel, fall back to legacy slopsmith-update-channel, and clear the legacy key on write — so a user's update-channel preference survives the rename instead of resetting to "stable". Community plugin list (README): the rename rewrote third-party repo URLs we don't own. Probed every one; their owners never renamed, so: - Restore the 13 live community plugins to their real slopsmith-* names. - Prune 6 that are 404 to the public (topkoa splitscreen/stems, OmikronApex tuner, Jafz2001 nam-rig-builder, DeathlySin song-preview, Erikcb91 shuffle). - Fix a pre-existing Guitar Theory clone-command typo (nam-tone -> guitar-theory). Verified: env_compat 7/7, JS 819/819, pytest 1690 collected / 0 import errors, rename-sensitive + startup suites green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: byrongamatos <xasiklas@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
byrongamatos
parent
a8ad02739a
commit
af2949677a
+3
-3
@@ -7,7 +7,7 @@ import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.audio")
|
||||
log = logging.getLogger("feedBack.lib.audio")
|
||||
|
||||
# Maximum length of any single decoder-error fragment that we surface to
|
||||
# the client. ffmpeg can emit multi-kB build-configuration / version
|
||||
@@ -123,7 +123,7 @@ def _scrub_quoted_match(match: re.Match) -> str:
|
||||
|
||||
def _bundled_bin_dir() -> Path | None:
|
||||
"""Resolve the desktop bundle's resources/bin/ directory if we're
|
||||
running inside one. Layout: resources/slopsmith/lib/audio.py →
|
||||
running inside one. Layout: resources/feedBack/lib/audio.py →
|
||||
resources/bin/. Gate on vgmstream-cli's presence so we don't
|
||||
misidentify random parent dirs (e.g. Docker's `/bin`, dev
|
||||
layouts where parents[2] resolves to the repo root) — vgmstream-cli
|
||||
@@ -284,7 +284,7 @@ def _scrub_paths(text: str, *paths: str) -> str:
|
||||
"""Replace absolute filesystem paths in `text` with their basenames.
|
||||
|
||||
Decoder error strings get joined into the RuntimeError that
|
||||
`convert_wem` raises, and slopsmith surfaces that text in the
|
||||
`convert_wem` raises, and feedBack surfaces that text in the
|
||||
browser as `audio_error`. Leaking install / user / DLC paths to the
|
||||
client is a needless info disclosure, so before any decoder error
|
||||
leaves this module we strip absolute paths down to their final
|
||||
|
||||
+24
-24
@@ -130,7 +130,7 @@ ENV_ALLOWLIST = (
|
||||
"LOG_LEVEL",
|
||||
"LOG_FORMAT",
|
||||
"LOG_FILE",
|
||||
"SLOPSMITH_RUNTIME",
|
||||
"FEEDBACK_RUNTIME",
|
||||
"PORT",
|
||||
"HOST",
|
||||
"TZ",
|
||||
@@ -154,13 +154,13 @@ def _safe_json_dumps(obj) -> str:
|
||||
return json.dumps({"error": "unserializable payload"}, indent=2)
|
||||
|
||||
|
||||
def _system_version(slopsmith_version: str, redactor=None) -> dict:
|
||||
def _system_version(feedBack_version: str, redactor=None) -> dict:
|
||||
executable = sys.executable
|
||||
if redactor is not None:
|
||||
executable = redactor.redact_text(executable)
|
||||
return {
|
||||
"schema": "system.version.v1",
|
||||
"slopsmith_version": slopsmith_version,
|
||||
"feedBack_version": feedBack_version,
|
||||
"python": {
|
||||
"version": platform.python_version(),
|
||||
"implementation": platform.python_implementation(),
|
||||
@@ -233,7 +233,7 @@ def _summarize_payload(path: str, parsed) -> dict | None:
|
||||
py = parsed.get("python") or {}
|
||||
os_ = parsed.get("os") or {}
|
||||
return {
|
||||
"slopsmith": parsed.get("slopsmith_version"),
|
||||
"feedBack": parsed.get("feedBack_version"),
|
||||
"python": py.get("version"),
|
||||
"os": os_.get("system"),
|
||||
}
|
||||
@@ -338,7 +338,7 @@ def _git_info(plugin_dir: Path) -> dict | None:
|
||||
"""Return git short SHA + remote URL for a plugin checkout.
|
||||
|
||||
Pure-Python — reads `.git/HEAD` and `.git/config` directly so this
|
||||
works in containers without the `git` binary installed (slopsmith's
|
||||
works in containers without the `git` binary installed (feedBack's
|
||||
runtime image is minimal). Plugins are gitlinks (see CLAUDE.md);
|
||||
the SHA is the most reliable "what build is this" identifier.
|
||||
|
||||
@@ -393,7 +393,7 @@ def _system_plugins(loaded_plugins: list[dict], plugins_root: "Path | list[Path]
|
||||
show up in the bundle.
|
||||
|
||||
*plugins_root* accepts a single Path, a list of Paths (to cover both
|
||||
the built-in ``plugins/`` directory and ``SLOPSMITH_PLUGINS_DIR``), or
|
||||
the built-in ``plugins/`` directory and ``FEEDBACK_PLUGINS_DIR``), or
|
||||
None to skip orphan detection entirely.
|
||||
|
||||
Plugin directories not in ``LOADED_PLUGINS`` appear in ``orphans``.
|
||||
@@ -484,7 +484,7 @@ def _system_plugins(loaded_plugins: list[dict], plugins_root: "Path | list[Path]
|
||||
# plugin failed to load — common when requirements.txt installs
|
||||
# fail in a read-only container). Accepts a single Path, a list of
|
||||
# Paths (to cover both the built-in plugins/ dir and
|
||||
# SLOPSMITH_PLUGINS_DIR), or None.
|
||||
# FEEDBACK_PLUGINS_DIR), or None.
|
||||
orphans: list[dict] = []
|
||||
if plugins_root is not None:
|
||||
roots: list[Path] = plugins_root if isinstance(plugins_root, list) else [plugins_root]
|
||||
@@ -840,11 +840,11 @@ def _redact_value(value: object, redactor: "Redactor") -> object:
|
||||
|
||||
|
||||
README_TEMPLATE = """\
|
||||
Slopsmith Diagnostics Bundle
|
||||
FeedBack Diagnostics Bundle
|
||||
============================
|
||||
|
||||
Generated: {exported_at}
|
||||
Slopsmith: {slopsmith_version}
|
||||
FeedBack: {feedBack_version}
|
||||
Runtime: {runtime_kind}
|
||||
Redacted: {redacted}
|
||||
|
||||
@@ -1005,7 +1005,7 @@ def _build_files_meta(files: dict[str, bytes]) -> list[dict]:
|
||||
|
||||
def _assemble_files_and_notes(
|
||||
*,
|
||||
slopsmith_version: str,
|
||||
feedBack_version: str,
|
||||
config_dir: Path,
|
||||
dlc_dir: Path | None,
|
||||
log_file: Path | None,
|
||||
@@ -1038,7 +1038,7 @@ def _assemble_files_and_notes(
|
||||
if include.get("system", True):
|
||||
# Pass the redactor so python.executable is redacted when paths
|
||||
# should be hidden (it often lives under $HOME or a per-user venv).
|
||||
ver_payload = _safe_json_dumps(_system_version(slopsmith_version, redactor=redactor)).encode("utf-8")
|
||||
ver_payload = _safe_json_dumps(_system_version(feedBack_version, redactor=redactor)).encode("utf-8")
|
||||
files["system/version.json"] = ver_payload
|
||||
env_payload = _safe_json_dumps(_system_env(redactor=redactor)).encode("utf-8")
|
||||
files["system/env.json"] = env_payload
|
||||
@@ -1125,7 +1125,7 @@ def _assemble_files_and_notes(
|
||||
files.update(plugin_files)
|
||||
|
||||
# Per-plugin client-side contributions from
|
||||
# window.slopsmith.diagnostics.contribute(plugin_id, payload).
|
||||
# window.feedBack.diagnostics.contribute(plugin_id, payload).
|
||||
# Gated on the same "plugins" toggle as backend plugin diagnostics.
|
||||
if include.get("plugins", True) and client_contributions and isinstance(client_contributions, dict):
|
||||
# Build the set of actually-loaded plugin IDs so we only accept
|
||||
@@ -1160,7 +1160,7 @@ def _assemble_files_and_notes(
|
||||
|
||||
def _make_manifest(
|
||||
*,
|
||||
slopsmith_version: str,
|
||||
feedBack_version: str,
|
||||
runtime_kind: str,
|
||||
redact: bool,
|
||||
files: dict[str, bytes],
|
||||
@@ -1170,7 +1170,7 @@ def _make_manifest(
|
||||
return {
|
||||
"schema": BUNDLE_SCHEMA,
|
||||
"exported_at": _now_iso(),
|
||||
"slopsmith_version": slopsmith_version,
|
||||
"feedBack_version": feedBack_version,
|
||||
"runtime": runtime_kind,
|
||||
"redacted": redact,
|
||||
"files": _build_files_meta(files),
|
||||
@@ -1181,7 +1181,7 @@ def _make_manifest(
|
||||
|
||||
def build_bundle(
|
||||
*,
|
||||
slopsmith_version: str,
|
||||
feedBack_version: str,
|
||||
config_dir: Path,
|
||||
dlc_dir: Path | None,
|
||||
log_file: Path | None,
|
||||
@@ -1198,7 +1198,7 @@ def build_bundle(
|
||||
) -> tuple[bytes, str, dict]:
|
||||
"""Returns (zip_bytes, filename, manifest_dict)."""
|
||||
files, notes, runtime_kind, redactor = _assemble_files_and_notes(
|
||||
slopsmith_version=slopsmith_version,
|
||||
feedBack_version=feedBack_version,
|
||||
config_dir=config_dir,
|
||||
dlc_dir=dlc_dir,
|
||||
log_file=log_file,
|
||||
@@ -1215,7 +1215,7 @@ def build_bundle(
|
||||
)
|
||||
|
||||
manifest = _make_manifest(
|
||||
slopsmith_version=slopsmith_version,
|
||||
feedBack_version=feedBack_version,
|
||||
runtime_kind=runtime_kind,
|
||||
redact=redact,
|
||||
files=files,
|
||||
@@ -1225,7 +1225,7 @@ def build_bundle(
|
||||
|
||||
readme = README_TEMPLATE.format(
|
||||
exported_at=manifest["exported_at"],
|
||||
slopsmith_version=slopsmith_version,
|
||||
feedBack_version=feedBack_version,
|
||||
runtime_kind=runtime_kind,
|
||||
redacted=redact,
|
||||
)
|
||||
@@ -1259,13 +1259,13 @@ def build_bundle(
|
||||
for path, payload in sorted(files.items()):
|
||||
zf.writestr(path, payload)
|
||||
|
||||
filename = f"slopsmith-diag-{slopsmith_version}-{_now_filename_slug()}.zip"
|
||||
filename = f"feedBack-diag-{feedBack_version}-{_now_filename_slug()}.zip"
|
||||
return buf.getvalue(), filename, manifest
|
||||
|
||||
|
||||
def preview_bundle(
|
||||
*,
|
||||
slopsmith_version: str,
|
||||
feedBack_version: str,
|
||||
config_dir: Path,
|
||||
dlc_dir: Path | None,
|
||||
log_file: Path | None,
|
||||
@@ -1303,7 +1303,7 @@ def preview_bundle(
|
||||
for p in loaded_plugins
|
||||
]
|
||||
files, notes, runtime_kind, redactor = _assemble_files_and_notes(
|
||||
slopsmith_version=slopsmith_version,
|
||||
feedBack_version=feedBack_version,
|
||||
config_dir=config_dir,
|
||||
dlc_dir=dlc_dir,
|
||||
log_file=log_file,
|
||||
@@ -1336,7 +1336,7 @@ def preview_bundle(
|
||||
if key not in files:
|
||||
files[key] = _CALLABLE_PREVIEW_PLACEHOLDER
|
||||
# Frontend plugins (those with a screen or script) may call
|
||||
# window.slopsmith.diagnostics.contribute() and produce a
|
||||
# window.feedBack.diagnostics.contribute() and produce a
|
||||
# plugins/<id>/client.json in the real export. Advertise a
|
||||
# placeholder so the preview file tree is accurate.
|
||||
if p.get("has_screen") or p.get("has_script"):
|
||||
@@ -1377,14 +1377,14 @@ def preview_bundle(
|
||||
}).encode("utf-8")
|
||||
|
||||
manifest = _make_manifest(
|
||||
slopsmith_version=slopsmith_version,
|
||||
feedBack_version=feedBack_version,
|
||||
runtime_kind=runtime_kind,
|
||||
redact=redact,
|
||||
files=files,
|
||||
notes=notes,
|
||||
redactor=redactor,
|
||||
)
|
||||
filename = f"slopsmith-diag-{slopsmith_version}-{_now_filename_slug()}.zip"
|
||||
filename = f"feedBack-diag-{feedBack_version}-{_now_filename_slug()}.zip"
|
||||
return {
|
||||
"filename": filename,
|
||||
"manifest": manifest,
|
||||
|
||||
@@ -16,6 +16,8 @@ import platform
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from env_compat import getenv_compat
|
||||
|
||||
SCHEMA = "system.hardware.v1"
|
||||
|
||||
|
||||
@@ -41,7 +43,7 @@ def detect_runtime() -> dict:
|
||||
nvidia-smi / psutil CPU probes.
|
||||
"""
|
||||
out: dict = {"kind": "bare", "in_docker": False, "in_kubernetes": False}
|
||||
env_runtime = os.environ.get("SLOPSMITH_RUNTIME", "").strip().lower()
|
||||
env_runtime = (getenv_compat("FEEDBACK_RUNTIME", "") or "").strip().lower()
|
||||
if env_runtime in ("electron", "docker", "bare"):
|
||||
out["kind"] = env_runtime
|
||||
if Path("/.dockerenv").exists():
|
||||
@@ -65,7 +67,7 @@ def detect_runtime() -> dict:
|
||||
import psutil # type: ignore
|
||||
|
||||
parent = psutil.Process(os.getppid()).name().lower()
|
||||
if "electron" in parent or "slopsmith" in parent:
|
||||
if "electron" in parent or "feedBack" in parent:
|
||||
out["kind"] = "electron"
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -8,7 +8,7 @@ different salts so tokens cannot be cross-correlated between exports.
|
||||
Stable token grammar (see docs/diagnostics-bundle-spec.md):
|
||||
<DLC_DIR> — DLC root path
|
||||
<HOME> — user's home directory
|
||||
<CONFIG_DIR> — slopsmith config dir
|
||||
<CONFIG_DIR> — feedBack config dir
|
||||
<song:hash8> — song filename / basename (8 hex chars)
|
||||
<ip:hash6> — IPv4 / IPv6 address (6 hex chars)
|
||||
<redacted> — bearer tokens, key=/token= query strings
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
import math
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.drums")
|
||||
log = logging.getLogger("feedBack.lib.drums")
|
||||
|
||||
|
||||
# ── Piece vocabulary ──────────────────────────────────────────────────────────
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
"""Backward-compatible environment lookup for the slopsmith -> feedBack rename.
|
||||
|
||||
Canonical configuration variables are now ``FEEDBACK_*``. Deployments that
|
||||
predate the rename may still set the old ``SLOPSMITH_*`` names (docker-compose
|
||||
overrides, shell profiles, CI), so we honour those as a fallback. New code
|
||||
should always read the canonical ``FEEDBACK_*`` name and let this shim resolve
|
||||
the legacy alias.
|
||||
|
||||
Flat-importable, no import-time IO or global state (constitution P-V).
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
_CANON_PREFIX = "FEEDBACK_"
|
||||
_LEGACY_PREFIX = "SLOPSMITH_"
|
||||
_TRUE_VALUES = {"1", "true", "yes", "on"}
|
||||
|
||||
|
||||
def getenv_compat(name, default=None):
|
||||
"""``os.environ.get`` with a legacy ``SLOPSMITH_*`` fallback.
|
||||
|
||||
For a canonical ``FEEDBACK_<X>`` name, returns the value of ``FEEDBACK_<X>``
|
||||
if set, else ``SLOPSMITH_<X>`` if set, else ``default``. Names that do not
|
||||
start with ``FEEDBACK_`` behave exactly like ``os.environ.get``.
|
||||
"""
|
||||
value = os.environ.get(name)
|
||||
if value is not None:
|
||||
return value
|
||||
if name.startswith(_CANON_PREFIX):
|
||||
legacy = os.environ.get(_LEGACY_PREFIX + name[len(_CANON_PREFIX):])
|
||||
if legacy is not None:
|
||||
return legacy
|
||||
return default
|
||||
|
||||
|
||||
def env_flag_compat(name):
|
||||
"""Parse a conventional boolean env flag, honouring the legacy alias."""
|
||||
return (getenv_compat(name, "") or "").strip().lower() in _TRUE_VALUES
|
||||
+12
-10
@@ -8,7 +8,9 @@ import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.gp2midi")
|
||||
from env_compat import getenv_compat
|
||||
|
||||
log = logging.getLogger("feedBack.lib.gp2midi")
|
||||
|
||||
import guitarpro
|
||||
from midiutil import MIDIFile
|
||||
@@ -152,15 +154,15 @@ def _find_soundfont() -> str | None:
|
||||
"""Locate a .sf2 soundfont for MIDI rendering.
|
||||
|
||||
Precedence:
|
||||
1. ``SLOPSMITH_SOUNDFONT`` env var (user override / desktop-app-supplied)
|
||||
1. ``FEEDBACK_SOUNDFONT`` env var (user override / desktop-app-supplied)
|
||||
2. Bundled ``<RESOURCESPATH>/soundfonts/*.sf2`` (Electron desktop builds)
|
||||
3. Common system locations per OS.
|
||||
"""
|
||||
override = os.environ.get("SLOPSMITH_SOUNDFONT")
|
||||
override = getenv_compat("FEEDBACK_SOUNDFONT")
|
||||
if override:
|
||||
if os.path.isfile(override):
|
||||
return override
|
||||
log.warning("SLOPSMITH_SOUNDFONT is set to %r but that file does not exist; falling back to other sources", override)
|
||||
log.warning("FEEDBACK_SOUNDFONT is set to %r but that file does not exist; falling back to other sources", override)
|
||||
|
||||
resources = os.environ.get("RESOURCESPATH")
|
||||
if resources:
|
||||
@@ -187,10 +189,10 @@ def _find_soundfont() -> str | None:
|
||||
elif sys.platform == "win32":
|
||||
appdata = os.environ.get("APPDATA")
|
||||
if appdata:
|
||||
# "Slopsmith" matches slopsmith-desktop's Electron productName
|
||||
# (app.getPath('userData') resolves to %APPDATA%\Slopsmith on Windows).
|
||||
# "FeedBack" matches feedBack-desktop's Electron productName
|
||||
# (app.getPath('userData') resolves to %APPDATA%\FeedBack on Windows).
|
||||
for pattern in (
|
||||
os.path.join(appdata, "Slopsmith", "soundfonts", "*.sf2"),
|
||||
os.path.join(appdata, "FeedBack", "soundfonts", "*.sf2"),
|
||||
os.path.join(appdata, "SoundFonts", "*.sf2"),
|
||||
):
|
||||
candidates += sorted(glob.glob(pattern))
|
||||
@@ -218,16 +220,16 @@ def _soundfont_install_hint() -> str:
|
||||
"or FluidR3_GM from musical-artifacts.com) and either place the .sf2 "
|
||||
"file in /usr/local/share/sounds/sf2/ (Intel) or "
|
||||
"/opt/homebrew/share/sounds/sf2/ (Apple Silicon), or set the "
|
||||
"SLOPSMITH_SOUNDFONT environment variable to its full path."
|
||||
"FEEDBACK_SOUNDFONT environment variable to its full path."
|
||||
)
|
||||
if sys.platform == "win32":
|
||||
return (
|
||||
"Download a soundfont (e.g. GeneralUser GS from schristiancollins.com or "
|
||||
"FluidR3_GM from musical-artifacts.com) and either place the .sf2 file in "
|
||||
"%APPDATA%\\Slopsmith\\soundfonts\\ or set the SLOPSMITH_SOUNDFONT "
|
||||
"%APPDATA%\\FeedBack\\soundfonts\\ or set the FEEDBACK_SOUNDFONT "
|
||||
"environment variable to its full path."
|
||||
)
|
||||
return "Set SLOPSMITH_SOUNDFONT to the full path of a .sf2 file."
|
||||
return "Set FEEDBACK_SOUNDFONT to the full path of a .sf2 file."
|
||||
|
||||
|
||||
def _fluidsynth_install_hint() -> str:
|
||||
|
||||
+3
-3
@@ -19,8 +19,8 @@ bar-indexed tempo map, per-beat rhythm durations (dots + tuplets; see
|
||||
``_beat_secs`` for the one deliberate double-dot divergence), and
|
||||
``_note_midi`` — so the
|
||||
notation beats line up with the RS-XML notes the highway plays (see
|
||||
slopsmith#618 for the longer-term goal of sharing the note-building walk
|
||||
itself, and slopsmith#261 for the time-signature-denominator pitfalls the
|
||||
feedBack#618 for the longer-term goal of sharing the note-building walk
|
||||
itself, and feedBack#261 for the time-signature-denominator pitfalls the
|
||||
``beat_groups`` emission here exists to avoid re-introducing).
|
||||
|
||||
Where this plugs in: ``gp2rs_gpx.convert_file`` calls
|
||||
@@ -43,7 +43,7 @@ from pathlib import Path
|
||||
|
||||
import notation as notation_mod
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.gp2notation")
|
||||
log = logging.getLogger("feedBack.lib.gp2notation")
|
||||
|
||||
|
||||
# GPX NoteValue string → notation duration denominator (sloppak-spec §5.3:
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ from pathlib import Path
|
||||
|
||||
import guitarpro
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.gp2rs")
|
||||
log = logging.getLogger("feedBack.lib.gp2rs")
|
||||
|
||||
_YEAR_RE = re.compile(r"\b(1[89]\d{2}|20\d{2})\b")
|
||||
|
||||
@@ -1122,7 +1122,7 @@ def _build_xml(
|
||||
|
||||
# Tuning. RS2014 schema names 6 string slots; we always emit those
|
||||
# for compatibility, and emit additional string6+ attributes (up to
|
||||
# `len(tuning)-1`) for 7+ string arrangements. Slopsmith parses
|
||||
# `len(tuning)-1`) for 7+ string arrangements. FeedBack parses
|
||||
# them; the format ignores them.
|
||||
tuning_el = ET.SubElement(root, "tuning")
|
||||
for i in range(max(6, len(tuning))):
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
lib/gp2rs_gpx.py — Guitar Pro 6 (.gpx) support shim for gp2rs.
|
||||
|
||||
Drop this file into slopsmith/lib/ alongside gp2rs.py.
|
||||
Drop this file into feedBack/lib/ alongside gp2rs.py.
|
||||
No third-party dependencies — pure Python stdlib only.
|
||||
|
||||
Public API mirrors the two functions that the editor plugin calls:
|
||||
@@ -20,7 +20,7 @@ from pathlib import Path
|
||||
|
||||
from safepath import safe_join
|
||||
|
||||
_log = logging.getLogger("slopsmith.lib.gp2rs_gpx")
|
||||
_log = logging.getLogger("feedBack.lib.gp2rs_gpx")
|
||||
|
||||
|
||||
def _safe_filename_stem(name: str) -> str:
|
||||
|
||||
@@ -3,7 +3,7 @@ lib/gp8_audio_sync.py — Extract embedded audio and sync data from GP8 (.gp) fi
|
||||
|
||||
Guitar Pro 8 can embed a backing track (OGG audio) into a .gp file alongside
|
||||
sync points that map bar positions to exact audio timestamps. This module
|
||||
extracts both, giving Slopsmith:
|
||||
extracts both, giving FeedBack:
|
||||
|
||||
1. A real backing track audio file (OGG) — no MIDI synthesis needed
|
||||
2. A precise audio_offset (seconds) from the FramePadding value
|
||||
@@ -45,7 +45,7 @@ import io
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
_log = logging.getLogger("slopsmith.lib.gp8_audio_sync")
|
||||
_log = logging.getLogger("feedBack.lib.gp8_audio_sync")
|
||||
|
||||
# GP8 embeds the backing track under Content/Assets/ as OGG *or* one of
|
||||
# several other formats (MP3 is common — e.g. tracks rendered straight
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import zipfile
|
||||
import io
|
||||
from pathlib import Path
|
||||
|
||||
_log = logging.getLogger("slopsmith.lib.gp_autosync")
|
||||
_log = logging.getLogger("feedBack.lib.gp_autosync")
|
||||
|
||||
# ── Dependency check ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
+11
-11
@@ -1,10 +1,10 @@
|
||||
"""Logging configuration for Slopsmith.
|
||||
"""Logging configuration for FeedBack.
|
||||
|
||||
Call ``configure_logging()`` once at server startup, before any slopsmith
|
||||
Call ``configure_logging()`` once at server startup, before any feedBack
|
||||
module imports that might emit log records.
|
||||
|
||||
Environment variables:
|
||||
LOG_LEVEL — severity threshold for the ``slopsmith.*`` logger tree
|
||||
LOG_LEVEL — severity threshold for the ``feedBack.*`` logger tree
|
||||
(default: INFO). Also accepted: DEBUG, WARNING, ERROR.
|
||||
LOG_FORMAT — "json" for structured output (Loki, ELK, Promtail);
|
||||
"text" (default) for human-readable coloured console output.
|
||||
@@ -43,7 +43,7 @@ def _add_correlation_id(
|
||||
|
||||
|
||||
def configure_logging() -> None:
|
||||
"""Wire up the slopsmith logger hierarchy.
|
||||
"""Wire up the feedBack logger hierarchy.
|
||||
|
||||
Safe to call multiple times; always reflects the current LOG_LEVEL,
|
||||
LOG_FORMAT, and LOG_FILE environment variables.
|
||||
@@ -52,7 +52,7 @@ def configure_logging() -> None:
|
||||
level = getattr(logging, raw_level, None)
|
||||
if not isinstance(level, int):
|
||||
sys.stderr.write(
|
||||
f"[slopsmith] WARNING: unrecognised LOG_LEVEL={raw_level!r};"
|
||||
f"[feedBack] WARNING: unrecognised LOG_LEVEL={raw_level!r};"
|
||||
" falling back to INFO.\n"
|
||||
)
|
||||
level = logging.INFO
|
||||
@@ -60,7 +60,7 @@ def configure_logging() -> None:
|
||||
raw_fmt = os.environ.get("LOG_FORMAT", "text").lower()
|
||||
if raw_fmt not in ("json", "text"):
|
||||
sys.stderr.write(
|
||||
f"[slopsmith] WARNING: unrecognised LOG_FORMAT={raw_fmt!r};"
|
||||
f"[feedBack] WARNING: unrecognised LOG_FORMAT={raw_fmt!r};"
|
||||
" falling back to 'text'.\n"
|
||||
)
|
||||
raw_fmt = "text"
|
||||
@@ -137,17 +137,17 @@ def configure_logging() -> None:
|
||||
handlers.append(fh)
|
||||
except OSError as exc:
|
||||
sys.stderr.write(
|
||||
f"[slopsmith] WARNING: could not open LOG_FILE={log_file!r}: {exc}"
|
||||
f"[feedBack] WARNING: could not open LOG_FILE={log_file!r}: {exc}"
|
||||
" — continuing with console-only logging.\n"
|
||||
)
|
||||
|
||||
_uvicorn_names = ("uvicorn", "uvicorn.error", "uvicorn.access")
|
||||
all_loggers = [logging.getLogger("slopsmith")] + [
|
||||
all_loggers = [logging.getLogger("feedBack")] + [
|
||||
logging.getLogger(n) for n in _uvicorn_names
|
||||
]
|
||||
|
||||
# Collect all unique old handlers across every logger *before* any close so
|
||||
# that a shared handler (slopsmith and uvicorn* were intentionally given the
|
||||
# that a shared handler (feedBack and uvicorn* were intentionally given the
|
||||
# same objects) isn't closed while still attached to another logger tree.
|
||||
old_handlers: set[logging.Handler] = set()
|
||||
for lg in all_loggers:
|
||||
@@ -160,8 +160,8 @@ def configure_logging() -> None:
|
||||
for h in old_handlers:
|
||||
h.close()
|
||||
|
||||
# Install fresh handlers on the slopsmith root.
|
||||
root = logging.getLogger("slopsmith")
|
||||
# Install fresh handlers on the feedBack root.
|
||||
root = logging.getLogger("feedBack")
|
||||
for h in handlers:
|
||||
root.addHandler(h)
|
||||
root.setLevel(level)
|
||||
|
||||
@@ -23,14 +23,14 @@ Engine selection
|
||||
Two transcription paths share a common output:
|
||||
|
||||
* `transcribe_vocals_remote(path, server_url, ...)` — POST the vocal
|
||||
stem to the `/align` endpoint on a slopsmith-demucs-server (Byron's
|
||||
stem to the `/align` endpoint on a feedBack-demucs-server (got-feedBack's
|
||||
reference server already hosts WhisperX alongside Demucs at the same
|
||||
URL).
|
||||
|
||||
* `transcribe_vocals_local(path, ...)` — load WhisperX in-process. Heavy
|
||||
(~3 GB of model weights for `large-v2` + the wav2vec2 aligner) and
|
||||
slow on CPU. Deferred imports of `whisperx`, `torch`, and `soundfile`
|
||||
keep the rest of slopsmith free of those dependencies.
|
||||
keep the rest of feedBack free of those dependencies.
|
||||
|
||||
Callers pick between them based on a `whisperx.server_url` config and
|
||||
fall back as appropriate. This module does not read config — both
|
||||
@@ -58,7 +58,7 @@ import logging
|
||||
from pathlib import Path
|
||||
from typing import Callable, Optional
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.lyrics_transcribe")
|
||||
log = logging.getLogger("feedBack.lib.lyrics_transcribe")
|
||||
|
||||
ProgressCB = Optional[Callable[[float, str, str], None]]
|
||||
|
||||
@@ -179,7 +179,7 @@ _MIN_WORD_DURATION = 0.05
|
||||
|
||||
# Semver for the lyric-transcription artifact contract that gets stamped
|
||||
# into the sloppak manifest's `lyric_transcription` block alongside the
|
||||
# engine + model. Bump per the semantics defined in slopsmith#357 (the
|
||||
# engine + model. Bump per the semantics defined in feedBack#357 (the
|
||||
# parent `stem_separation` RFC):
|
||||
# * patch — metadata-only or implementation fixes; no regeneration
|
||||
# * minor — backward-compatible additions
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
import math
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.notation")
|
||||
log = logging.getLogger("feedBack.lib.notation")
|
||||
|
||||
|
||||
# ── Vocabulary ────────────────────────────────────────────────────────────────
|
||||
|
||||
+4
-4
@@ -31,7 +31,7 @@ from tunings import tuning_name
|
||||
import sloppak as sloppak_mod
|
||||
import loosefolder as loosefolder_mod
|
||||
|
||||
log = logging.getLogger("slopsmith.scan_worker")
|
||||
log = logging.getLogger("feedBack.scan_worker")
|
||||
|
||||
|
||||
def _relpath(f: Path, dlc: Path) -> str:
|
||||
@@ -53,7 +53,7 @@ def _extract_meta_sloppak(path: Path) -> dict:
|
||||
meta["tuning_sort_key"] = sum(offsets)
|
||||
meta["tuning_offsets"] = " ".join(str(o) for o in offsets)
|
||||
meta["format"] = "sloppak"
|
||||
# `extract_meta` already populates `stem_ids` (slopsmith#129);
|
||||
# `extract_meta` already populates `stem_ids` (feedBack#129);
|
||||
# default to empty for older callers / mocks.
|
||||
meta.setdefault("stem_ids", [])
|
||||
# Compute smart names for sloppak arrangements using name-based fallback
|
||||
@@ -109,7 +109,7 @@ def _extract_meta_for_file(path: Path, dlc_root=None) -> dict:
|
||||
the root it already resolved; in-process callers can pass the resolver
|
||||
itself (e.g. `_get_dlc_dir`) to keep the lookup lazy.
|
||||
|
||||
Slopsmith reads only its own `.sloppak` format and loose-folder XML
|
||||
FeedBack reads only its own `.sloppak` format and loose-folder XML
|
||||
songs. Encrypted/proprietary archive formats are not supported and are
|
||||
silently ignored (empty metadata) rather than decrypted.
|
||||
"""
|
||||
@@ -121,7 +121,7 @@ def _extract_meta_for_file(path: Path, dlc_root=None) -> dict:
|
||||
if loosefolder_mod.is_loose_song(path):
|
||||
root = dlc_root() if callable(dlc_root) else dlc_root
|
||||
return _extract_meta_loosefolder(path, root)
|
||||
# Unknown/unsupported shape — return empty metadata. Slopsmith never
|
||||
# Unknown/unsupported shape — return empty metadata. FeedBack never
|
||||
# reads encrypted archive formats.
|
||||
return {
|
||||
"title": "", "artist": "", "album": "", "year": "",
|
||||
|
||||
+2
-2
@@ -22,7 +22,7 @@ import zipfile
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.sloppak")
|
||||
log = logging.getLogger("feedBack.lib.sloppak")
|
||||
|
||||
# The feedpak format version this build targets / writes (manifest
|
||||
# `feedpak_version`, a semver string per spec §4). Readers tolerate any version
|
||||
@@ -892,6 +892,6 @@ def extract_meta(path: Path) -> dict:
|
||||
"arrangements": arrangements,
|
||||
"has_lyrics": has_lyrics,
|
||||
"stem_count": stem_count,
|
||||
# slopsmith#129: per-stem filter needs the id list, not just count.
|
||||
# feedBack#129: per-stem filter needs the id list, not just count.
|
||||
"stem_ids": stem_ids,
|
||||
}
|
||||
|
||||
+8
-8
@@ -8,7 +8,7 @@ import logging
|
||||
import math
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.song")
|
||||
log = logging.getLogger("feedBack.lib.song")
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -124,10 +124,10 @@ class PhraseLevel:
|
||||
"""One difficulty tier's worth of note/chord/anchor/hand-shape data for a
|
||||
single phrase iteration. the arrangement XML stores these as `<level
|
||||
difficulty="N">` blocks that repeat for every difficulty tier the chart
|
||||
author wrote; slopsmith used to collapse them to the phrase's
|
||||
author wrote; feedBack used to collapse them to the phrase's
|
||||
maxDifficulty and throw the rest away. Keeping them around lets the
|
||||
highway render a "master difficulty" slider that picks a per-phrase
|
||||
difficulty tier at render time (slopsmith#48)."""
|
||||
difficulty tier at render time (feedBack#48)."""
|
||||
|
||||
difficulty: int
|
||||
notes: list[Note] = field(default_factory=list)
|
||||
@@ -175,7 +175,7 @@ class Arrangement:
|
||||
# `base`/`changes` drive the highway tone-change markers; `definitions`
|
||||
# feed the Tones plugin gear panel.
|
||||
tones: dict | None = None
|
||||
# arrangement XML <arrangementProperties> flags for smart naming (slopsmith feat/arrangement).
|
||||
# arrangement XML <arrangementProperties> flags for smart naming (feedBack feat/arrangement).
|
||||
# Populated from the XML; default False/0 for sloppak / GP-imported sources.
|
||||
path_lead: bool = False
|
||||
path_rhythm: bool = False
|
||||
@@ -622,7 +622,7 @@ def arrangement_string_count(arr: Arrangement) -> int:
|
||||
"""Derive the active arrangement's string count.
|
||||
|
||||
Used by the server to emit ``stringCount`` in the song_info
|
||||
WebSocket payload (slopsmith-plugin-3dhighway#7).
|
||||
WebSocket payload (feedBack-plugin-3dhighway#7).
|
||||
|
||||
The arrangement XML schema always emits 6 ``<tuning>`` slots regardless
|
||||
of instrument (bass charts populate `string0`–`string3` and pad
|
||||
@@ -1276,7 +1276,7 @@ def parse_arrangement(xml_path: str) -> Arrangement:
|
||||
def _collect_from_parsed(parsed, t_start, t_end):
|
||||
"""Append a pre-parsed level's time-clipped slice to the flat
|
||||
arrangement lists. Used for the max-mastery merge that preserves
|
||||
the pre-slopsmith#48 behaviour for existing consumers."""
|
||||
the pre-feedBack#48 behaviour for existing consumers."""
|
||||
lv_notes, lv_chords, lv_anchors, lv_hand_shapes = _extract_level_slice(
|
||||
parsed, t_start, t_end
|
||||
)
|
||||
@@ -1295,7 +1295,7 @@ def parse_arrangement(xml_path: str) -> Arrangement:
|
||||
_collect_from_parsed(best, 0.0, float("inf"))
|
||||
|
||||
# Per-phrase difficulty data for the master-difficulty slider
|
||||
# (slopsmith#48). Only populated when the XML has multiple levels AND
|
||||
# (feedBack#48). Only populated when the XML has multiple levels AND
|
||||
# phrase data — left as None for single-level sources so the frontend
|
||||
# knows to disable the slider.
|
||||
phrases: list[Phrase] | None = None
|
||||
@@ -1445,7 +1445,7 @@ def _convert_sng_to_xml(extracted_dir: str):
|
||||
"""No-op stub.
|
||||
|
||||
Historically this converted proprietary encrypted ``.notechart`` arrangement
|
||||
files to XML via an external tool. That path has been removed: slopsmith
|
||||
files to XML via an external tool. That path has been removed: feedBack
|
||||
reads only its own ``.sloppak`` format and loose-folder/GP/MusicXML-derived
|
||||
arrangement XML, and never decodes or decrypts proprietary archives. Kept
|
||||
as a no-op so ``load_song`` (which loads plain arrangement XML/JSON from a
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ source of truth, so the change survives both incremental and full rescans.
|
||||
only the keys present are overwritten, so an edit of just the title can't blank
|
||||
out the artist.
|
||||
|
||||
Only slopsmith's own ``.sloppak`` format (zip- or directory-form) is writable.
|
||||
Only feedBack's own ``.sloppak`` format (zip- or directory-form) is writable.
|
||||
Unknown / unsupported shapes return False and the caller keeps the DB-only
|
||||
update.
|
||||
"""
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"""Regenerate ``static/tailwind.min.css`` over the full installed-plugin set.
|
||||
|
||||
Core's committed (and image-baked) stylesheet is built scanning only the
|
||||
in-tree plugins. A plugin installed at runtime — into ``SLOPSMITH_PLUGINS_DIR``
|
||||
in-tree plugins. A plugin installed at runtime — into ``FEEDBACK_PLUGINS_DIR``
|
||||
— ships Tailwind classes the sheet never saw, so it renders unstyled. The
|
||||
Play CDN's runtime JIT that used to cover this was removed (slopsmith#411),
|
||||
Play CDN's runtime JIT that used to cover this was removed (feedBack#411),
|
||||
so we rebuild the sheet ourselves with node + the pinned ``tailwindcss``,
|
||||
scanning the baked-in plugins *and* the user plugins dir.
|
||||
|
||||
@@ -24,7 +24,9 @@ import tempfile
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
log = logging.getLogger("slopsmith.tailwind")
|
||||
from env_compat import getenv_compat
|
||||
|
||||
log = logging.getLogger("feedBack.tailwind")
|
||||
|
||||
# Pin matches scripts/build-tailwind.sh and the Dockerfile build stage so every
|
||||
# sheet — committed, image-baked, and runtime-regenerated — comes from the same
|
||||
@@ -45,7 +47,7 @@ APP_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
def _user_plugins_dir() -> Path | None:
|
||||
raw = os.environ.get("SLOPSMITH_PLUGINS_DIR", "").strip()
|
||||
raw = (getenv_compat("FEEDBACK_PLUGINS_DIR", "") or "").strip()
|
||||
if not raw:
|
||||
return None
|
||||
p = Path(raw)
|
||||
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
"""Tone helpers for sloppak playback.
|
||||
|
||||
A slopsmith arrangement may carry a tone block — the initial tone name plus
|
||||
A feedBack arrangement may carry a tone block — the initial tone name plus
|
||||
in-song tone switches — embedded inline in the arrangement JSON (see
|
||||
``lib/song.py`` ``arrangement_to_wire`` / the ``tones`` wire key). This module
|
||||
turns that already-embedded block into the (base, changes) payload the highway
|
||||
WebSocket sends to the client.
|
||||
|
||||
The proprietary-archive tone-extraction path (lifting tone definitions out of
|
||||
an unpacked encrypted archive) has been removed. Slopsmith reads tones only
|
||||
an unpacked encrypted archive) has been removed. FeedBack reads tones only
|
||||
from its own ``.sloppak`` / arrangement JSON; it never reads or decrypts
|
||||
proprietary archive formats.
|
||||
"""
|
||||
@@ -18,7 +18,7 @@ import logging
|
||||
import math
|
||||
import re
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.tones")
|
||||
log = logging.getLogger("feedBack.lib.tones")
|
||||
|
||||
|
||||
def tokens(s: str) -> set[str]:
|
||||
|
||||
+6
-6
@@ -5,7 +5,7 @@ isolated vocals + per-syllable lyric timing (both produced by the
|
||||
WhisperX fallback or shipped in the source archive), the /pitch endpoint
|
||||
runs CREPE over the vocals stem and returns one MIDI note per supplied
|
||||
timing token. The result lands in `<sloppak>/vocal_pitch.json` in the
|
||||
shape the got-feedback/feedback-plugin-lyrics-karaoke renderer
|
||||
shape the got-feedback/feedBack-plugin-lyrics-karaoke renderer
|
||||
already consumes:
|
||||
|
||||
{"version": 1, "notes": [{"t": float, "d": float, "midi": int}, ...]}
|
||||
@@ -23,18 +23,18 @@ runs locally. Adding a local CREPE path here would mean pulling
|
||||
`crepe` + `tensorflow` as plugin deps (~500 MB+ on top of the
|
||||
existing torch/demucs/whisperx). Deferred until users hit the gap.
|
||||
If you need a local fallback today, install
|
||||
`got-feedback/feedback-plugin-lyrics-karaoke` and let its local
|
||||
`got-feedback/feedBack-plugin-lyrics-karaoke` and let its local
|
||||
pYIN run when the server isn't reachable.
|
||||
|
||||
Cache key parity with stem_separation / lyric_transcription
|
||||
───────────────────────────────────────────────────────────
|
||||
A `pitch_extraction` manifest block mirrors the shape introduced by
|
||||
slopsmith#357: `{engine, model, version}`. Today engine is fixed at
|
||||
feedBack#357: `{engine, model, version}`. Today engine is fixed at
|
||||
`"crepe"` (the server's choice) and model at `"v1"` (server doesn't
|
||||
yet expose the CREPE capacity dial it uses internally; this is the
|
||||
requested value, same caveat as `lyric_transcription.model`). The
|
||||
schema version is independent of the upstream CREPE version and bumps
|
||||
per slopsmith's contract:
|
||||
per feedBack's contract:
|
||||
* patch — metadata-only or implementation fixes
|
||||
* minor — backward-compatible additions
|
||||
* major — output shape / semantics changed; existing
|
||||
@@ -50,7 +50,7 @@ import math
|
||||
from pathlib import Path
|
||||
from typing import Callable, Optional
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.vocal_pitch")
|
||||
log = logging.getLogger("feedBack.lib.vocal_pitch")
|
||||
|
||||
ProgressCB = Optional[Callable[[float, str, str], None]]
|
||||
|
||||
@@ -72,7 +72,7 @@ def extract_pitch_remote(
|
||||
) -> list[dict]:
|
||||
"""POST the vocal stem + lyric timings to `{server_url}/pitch`.
|
||||
|
||||
`lyrics` is the same `[{t, d, w}, ...]` list slopsmith writes to
|
||||
`lyrics` is the same `[{t, d, w}, ...]` list feedBack writes to
|
||||
`lyrics.json`. The endpoint only consumes `t` + `d` (it doesn't
|
||||
need the word text), but we pass the full payload through —
|
||||
slimmer to forward what we already have than to project.
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import logging
|
||||
import struct
|
||||
import os
|
||||
|
||||
log = logging.getLogger("slopsmith.lib.wem_decode")
|
||||
log = logging.getLogger("feedBack.lib.wem_decode")
|
||||
|
||||
|
||||
def convert_wem_to_ogg(wem_path: str, output_path: str) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user