Skip to content

Core Services

Surface-agnostic business logic from musicseed-core (musicseed.services.*). These services return result models and raise typed exceptions; surfaces (CLI, API handlers) map them.

Library

musicseed.services.library

Library service — surface-agnostic entry points for import, DB, and status operations.

EnrichmentCoverage

Bases: BaseModel

Per-source enrichment coverage counts over the local track library.

LibraryStatus

Bases: BaseModel

Point-in-time statistics for the local library and its configuration.

ImportResult

Bases: BaseModel

Counts of rows written by one Plex import run.

CountCompare

Bases: BaseModel

Plex vs local row counts for one entity type.

missing property

How many Plex rows are not yet imported locally (never negative).

ImportCoverage

Bases: BaseModel

Comparison of Plex library counts against the imported local counts.

complete property

True when every Plex artist, album, and track is imported locally.

setup_incomplete property

True when no import ever succeeded and coverage is not complete.

Surfaces use this to detect an interrupted first-time import that should be resumed.

initialize_database()

Create the SQLite database file and tables. Idempotent.

optimize_database()

Create performance indexes.

Returns:

Type Description
list[IndexResult]

Per-index results describing success or failure for each index.

import_library(plex_db_path=None, library_name=None, full_import=False, progress_callback=None, should_cancel=None)

Import metadata from the Plex database into the local library.

Parameters:

Name Type Description Default
plex_db_path Path | None

path to the Plex SQLite database; defaults to the configured plex.db_path.

None
library_name str | None

Plex library to import; defaults to the configured plex.library.

None
full_import bool

re-import everything instead of an incremental import.

False
progress_callback Callable[[int, int, str], None] | None

optional (current, total, phase) callback invoked as the import progresses.

None
should_cancel Callable[[], bool] | None

optional callable polled by the importer; the import stops early when it returns True.

None

Returns:

Type Description
ImportResult

Counts of imported artists, albums, tracks, and play history rows.

Raises:

Type Description
NotFoundError

if the Plex database file does not exist.

has_succeeded_import()

Return True when any import job has ever reached succeeded.

Returns False (rather than raising) when the database cannot be read.

get_import_coverage()

Compare MusicSeed artist/album/track counts to the configured Plex library.

Returns:

Type Description
ImportCoverage | None

The coverage comparison, or None when the Plex database cannot be

ImportCoverage | None

read. Does not raise.

get_status()

Return library statistics and enrichment coverage.

Returns:

Type Description
LibraryStatus

Entity counts (artists, albums, tracks, plays, tags), per-source

LibraryStatus

enrichment coverage, import coverage against the configured Plex

LibraryStatus

library, and the resolved configuration paths.

Recommend

musicseed.services.recommend

Recommendation service — surface-agnostic entry points for the recommendation flow.

RecommendationResult

Bases: BaseModel

Result of a recommendation request.

PlaylistCreateResult

Bases: BaseModel

Result of a playlist creation request.

get_recommendations(*, seed_texts=None, seed_ids=None, limit=50, weights=None, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None)

Return seed tracks and scored recommendations.

Parameters:

Name Type Description Default
seed_texts list[str] | None

seed tracks as "Artist - Title" (or bare title) strings; at least one text or id seed is required.

None
seed_ids list[int] | None

seed tracks by local database id.

None
limit int

maximum number of recommendations to return.

50
weights Weights | None

signal weights; defaults to Weights() (the "balanced" preset).

None
year_min int | None

only recommend tracks released in this year or later.

None
year_max int | None

only recommend tracks released in this year or earlier.

None
max_tracks_per_artist int

artist diversity cap applied during selection.

3
min_score float | None

drop recommendations with a total score below this value.

None

Returns:

Type Description
RecommendationResult

The resolved seed tracks, the selected recommendations, and the

RecommendationResult

sonic coverage of the candidate pool.

Raises:

Type Description
NotFoundError

if one or more seed tracks cannot be resolved.

create_playlist(name, *, seed_texts=None, seed_ids=None, limit=50, weights=None, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None)

Generate recommendations and create a Plex playlist.

The created playlist contains the resolved seed tracks followed by the recommendations. Accepts the same recommendation arguments as get_recommendations.

Parameters:

Name Type Description Default
name str

title of the Plex playlist to create.

required
seed_texts list[str] | None

seed tracks as "Artist - Title" (or bare title) strings; at least one text or id seed is required.

None
seed_ids list[int] | None

seed tracks by local database id.

None
limit int

maximum number of recommendations to include.

50
weights Weights | None

signal weights; defaults to Weights().

None
year_min int | None

only recommend tracks released in this year or later.

None
year_max int | None

only recommend tracks released in this year or earlier.

None
max_tracks_per_artist int

artist diversity cap applied during selection.

3
min_score float | None

drop recommendations with a total score below this value.

None

Returns:

Type Description
PlaylistCreateResult

The resolved seed tracks, the recommendations, and the created Plex

PlaylistCreateResult

playlist.

Raises:

Type Description
ConfigurationError

if plex.token is not configured.

NotFoundError

if seed tracks cannot be resolved.

PlexAPIError

if the Plex API call fails.

Enrichment

musicseed.services.enrichment

Enrichment service — surface-agnostic entry points for metadata enrichment.

enrich_tracks(source='listenbrainz', batch_size=50, limit=None, artist=None, album=None, resume=False, concurrency=5, progress_callback=None, should_cancel=None)

Enrich tracks with external metadata from Spotify or ListenBrainz.

Runs the async enrichment pipeline via asyncio.run() internally — never call this from inside a running event loop; offload to a thread instead.

Parameters:

Name Type Description Default
source str

enrichment source, "spotify" or "listenbrainz".

'listenbrainz'
batch_size int

tracks processed per batch.

50
limit int | None

maximum number of tracks to enrich (None for all).

None
artist str | None

only enrich tracks whose artist name matches this pattern.

None
album str | None

only enrich tracks whose album title matches this pattern.

None
resume bool

skip tracks that were already attempted.

False
concurrency int

maximum concurrent requests inside the async pipeline.

5
progress_callback Callable[[int, int, str], None] | None

optional (current, total, message) callback.

None
should_cancel Callable[[], bool] | None

optional callable polled by the pipeline; enrichment stops early when it returns True.

None

Returns:

Type Description
EnrichmentStats

Aggregate enrichment statistics (processed, matched, unmatched,

EnrichmentStats

errors).

Raises:

Type Description
ConfigurationError

if Spotify credentials are missing when source='spotify', or the ListenBrainz user token is missing when source='listenbrainz'.

Discovery

musicseed.services.discovery

Local environment discovery: Plex server, databases, and config state.

Surface-agnostic and strictly read-only: probes the filesystem and the Plex HTTP API (GET requests only) but never starts imports, sonic analysis, enrichment, or any Plex mutation. Expected failures are returned as structured data (reason codes) so surfaces can render actionable fixes instead of parsing exceptions. Plex tokens are never included in results.

Reason

Bases: StrEnum

Machine-readable discovery outcome codes.

PathCandidate

Bases: BaseModel

One probed filesystem candidate for a required local file.

FileDiscovery

Bases: BaseModel

Discovery result for a required local file (e.g. a Plex database).

DatabasePathDiscovery

Bases: BaseModel

Discovery result for MusicSeed's own SQLite database location.

PlexServerDiscovery

Bases: BaseModel

Discovery result for the Plex HTTP API.

SpotifyCredentialsCheck

Bases: BaseModel

Presence of Spotify enrichment credentials (values never exposed).

ListenBrainzTokenCheck

Bases: BaseModel

Presence of the ListenBrainz user token (value never exposed).

EnrichmentDiscovery

Bases: BaseModel

Enrichment-provider readiness. Either provider's credentials suffice.

FirstRunStatus

Bases: BaseModel

Derived first-run state and the reasons it is considered a first run.

DiscoveryResult

Bases: BaseModel

Complete, read-only picture of the local MusicSeed environment.

read_plex_token(preferences_path=None, local_admin_token_path=None)

Read a usable Plex token from the local server's data directory.

Prefers the account token (PlexOnlineToken in Preferences.xml), then falls back to .LocalAdminToken (which only works from localhost). When no explicit paths are given, probes macOS and Linux Plex data dirs. Returns None when neither is readable. Read-only — the token value is never logged or returned in discovery results.

Parameters:

Name Type Description Default
preferences_path str | None

explicit path to Preferences.xml; when omitted, the default Plex data dir candidates are probed.

None
local_admin_token_path str | None

explicit path to .LocalAdminToken; same default behavior as preferences_path.

None

Returns:

Type Description
str | None

The token string, or None when no readable token is found.

discover(*, musicseed_db_path=None, plex_db_path=None, plex_url=None, plex_token=None, plex_library=None, check_server=True, timeout=5.0, config=None)

Probe the local MusicSeed/Plex environment (read-only).

Never raises on expected failures — they are reported via reason codes instead.

Overrides apply to this call only and never mutate global configuration.

Parameters:

Name Type Description Default
musicseed_db_path str | None

override for the MusicSeed database path.

None
plex_db_path str | None

override for the Plex library database path.

None
plex_url str | None

override for the Plex server URL.

None
plex_token str | None

override for the Plex token.

None
plex_library str | None

override for the Plex library name.

None
check_server bool

whether to probe the Plex HTTP API (False skips the network call and reports the server check as skipped).

True
timeout float

seconds before the Plex HTTP probe gives up.

5.0
config Config | None

explicit config to probe against; defaults to the global get_config().

None

Returns:

Type Description
DiscoveryResult

The complete discovery result, including per-check reason codes,

DiscoveryResult

enrichment readiness, missing inputs, and the derived first-run

DiscoveryResult

status. The Plex token is never included.

Plex Discovery

musicseed.services.plex_discovery

Plex server discovery — local network (GDM + SSDP) and account (plex.tv).

Two independent, read-only discovery paths feed one result list:

  • Local network — GDM ("Good Day Mate") multicast on 239.0.0.250:32414 with an SSDP fallback on 239.255.255.250:1900. Both use stdlib socket only and find servers on the same subnet (multicast never crosses a router). GDM replies carry the friendly name, port, product, version, and machine identifier.
  • Accountplex.tv/api/resources lists every server linked to the user's Plex account, including servers on other subnets that multicast cannot reach. Requires a Plex token and internet access.

Both paths are strictly read-only and never store or return a token.

This is a deliberately separate, opt-in probe — it is not folded into services.discovery.discover(), which runs on frequent dashboard polls and must stay cheap. The first-run wizard calls it once.

DiscoveredPlexServer

Bases: BaseModel

One Plex server discovered on the local network or the Plex account.

url property

The server's base URL (scheme://host:port).

discover_plex_account_servers(token, timeout=5.0)

Discover servers linked to the Plex account via plex.tv/api/resources.

Requires a Plex token and internet access. Returns an empty list (never raises) when the token is missing or the call fails — e.g. offline, invalid token, or no servers on the account.

Parameters:

Name Type Description Default
token str

Plex account token used to authenticate against plex.tv.

required
timeout float

HTTP timeout in seconds for the plex.tv request.

5.0

Returns:

Type Description
list[DiscoveredPlexServer]

One entry per best-ranked connection of each account server.

discover_plex_servers(timeout=3.0, token=None)

Discover Plex servers — local subnet via GDM/SSDP, plus the account.

With token set, also queries plex.tv/api/resources so servers on other subnets (invisible to multicast) are included. Results are deduplicated by address. Returns an empty list when nothing responds; never raises.

Parameters:

Name Type Description Default
timeout float

seconds to listen for local multicast replies; also the plex.tv request timeout when token is set.

3.0
token str | None

optional Plex account token enabling cross-subnet discovery.

None

Returns:

Type Description
list[DiscoveredPlexServer]

Discovered servers sorted by (host, port, name).

Populate

musicseed.services.populate

Populate service — fill an existing Plex playlist with complementary recommendations.

PopulateResult

Bases: BaseModel

Result of a populate preview request.

PopulateApplyResult

Bases: PopulateResult

Result of a populate request that was written to Plex.

list_plex_playlists()

Return every audio playlist currently on the Plex server.

Returns:

Type Description
list[Playlist]

All audio playlists on the server.

Raises:

Type Description
ConfigurationError

if plex.token is not configured.

PlexAPIError

if the Plex API call fails.

get_populate_recommendations(playlist_id, *, method='average', limit=10, per_seed_limit=30, weights=None, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None)

Preview complementary recommendations for an existing Plex playlist.

Parameters:

Name Type Description Default
playlist_id str

Plex rating key of the playlist to populate.

required
method PopulateMethod

populate strategy (see PopulateMethod).

'average'
limit int

maximum number of recommendations to return.

10
per_seed_limit int

candidates gathered per playlist track ("frequency" method only).

30
weights Weights | None

signal weights; defaults to Weights().

None
year_min int | None

only recommend tracks released in this year or later.

None
year_max int | None

only recommend tracks released in this year or earlier.

None
max_tracks_per_artist int

artist diversity cap applied during selection.

3
min_score float | None

drop recommendations with a total score below this value.

None

Returns:

Type Description
PopulateResult

The playlist identity, how many of its tracks matched the local

PopulateResult

library, and the previewed recommendations. Nothing is written to

PopulateResult

Plex.

Raises:

Type Description
ConfigurationError

if plex.token is not configured.

NotFoundError

if the playlist doesn't exist or none of its tracks are in the local library.

PlexAPIError

if the Plex API call fails.

populate_playlist(playlist_id, *, method='average', limit=10, per_seed_limit=30, weights=None, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None, track_ids=None)

Generate recommendations and add them to an existing Plex playlist.

When track_ids is provided, only those local track ids are added (the recommendation step is skipped). This supports surfaces that let a user prune a preview before confirming.

Parameters:

Name Type Description Default
playlist_id str

Plex rating key of the playlist to populate.

required
method PopulateMethod

populate strategy (see PopulateMethod).

'average'
limit int

maximum number of recommendations to add.

10
per_seed_limit int

candidates gathered per playlist track ("frequency" method only).

30
weights Weights | None

signal weights; defaults to Weights().

None
year_min int | None

only recommend tracks released in this year or later.

None
year_max int | None

only recommend tracks released in this year or earlier.

None
max_tracks_per_artist int

artist diversity cap applied during selection.

3
min_score float | None

drop recommendations with a total score below this value.

None
track_ids list[int] | None

explicit local track ids to add instead of recommending.

None

Returns:

Type Description
PopulateApplyResult

The playlist identity, match counts, the recommendations (empty when

PopulateApplyResult

track_ids was given), and how many tracks were actually added.

Raises:

Type Description
ConfigurationError

if plex.token is not configured.

NotFoundError

if the playlist or its local tracks cannot be resolved.

PlexAPIError

if the Plex API call fails.

Plex Analysis

musicseed.services.plex_analysis

Plex sonic analysis service — inspect and trigger Plex's own sonic analysis.

Keeps the Plex sonic vectors that MusicSeed reads at query time (see musicseed.sonic) up to date:

  1. Which tracks has Plex already analyzed sonically (musicAnalysisVersion)?
  2. Trigger the MusicAnalysis Butler task on demand (POST /butler/…) and watch a date-scoped window of recently added music until it is analyzed.

Note: the Butler task always processes Plex's entire pending backlog; the date window scopes what we target, watch, and report — not what Plex runs.

UnanalyzedAlbum

Bases: BaseModel

An album that has at least one track without Plex sonic analysis.

SonicStatusResult

Bases: BaseModel

Sonic analysis coverage of a Plex music library.

unanalyzed_tracks property

Tracks in the library without Plex sonic analysis.

recent_unanalyzed_tracks property

Recently added tracks still without Plex sonic analysis.

SonicTriggerProbeResult

Bases: BaseModel

Outcome of triggering Plex analysis on one album and re-checking it.

sonic_triggered property

True when the analyzed-track count increased after the trigger.

SonicRefreshResult

Bases: BaseModel

Outcome of a date-scoped sonic analysis refresh.

analyzed_delta property

Tracks that gained sonic analysis during the refresh.

completed property

True when no tracks in the window remain unanalyzed.

get_sonic_status(library_name=None, *, recent_days=7)

Report Plex sonic analysis coverage for a music library.

Fetches every track in the library over the HTTP API, so it can be slow on large libraries. recent_days defines the "recent additions" window (based on Plex's addedAt).

Parameters:

Name Type Description Default
library_name str | None

Plex music library to inspect; defaults to the configured plex.library.

None
recent_days int

size of the "recent additions" window in days.

7

Returns:

Type Description
SonicStatusResult

Coverage counts for the whole library and the recent window, plus the

SonicStatusResult

albums that still have unanalyzed tracks.

Raises:

Type Description
ConfigurationError

if plex.token is not configured.

NotFoundError

if the library name doesn't match a music section.

PlexAPIError

if the Plex API call fails.

refresh_album(album_rating_key)

Ask Plex to refresh one album's metadata (re-reads its files from disk).

This recreates the album's media items, which clears the failed-analysis state that prevents sonic analysis from being queued.

Parameters:

Name Type Description Default
album_rating_key str

Plex rating key of the album to refresh.

required

Raises:

Type Description
ConfigurationError

if plex.token is not configured.

PlexAPIError

if the Plex API call fails.

probe_sonic_trigger(album_rating_key=None, library_name=None, *, wait_seconds=120.0, poll_interval=5.0)

Trigger Plex analysis on one album and check if sonic analysis follows.

If album_rating_key is None, the most recently added album with unanalyzed tracks is picked automatically. Polls the album's tracks until the number of sonically analyzed tracks increases or wait_seconds elapses.

Parameters:

Name Type Description Default
album_rating_key str | None

Plex rating key of the album to analyze and watch; auto-picked when None.

None
library_name str | None

library used for the auto-pick; defaults to the configured plex.library.

None
wait_seconds float

maximum time to watch for analysis.

120.0
poll_interval float

seconds between polls.

5.0

Returns:

Type Description
SonicTriggerProbeResult

The probe outcome, including analyzed counts before/after and the

SonicTriggerProbeResult

Plex activities observed while waiting.

Raises:

Type Description
ConfigurationError

if plex.token is not configured.

NotFoundError

if no unanalyzed album can be found.

PlexAPIError

if the Plex API call fails.

probe_butler_trigger(album_rating_key=None, library_name=None, *, butler_task='MusicAnalysis', wait_seconds=120.0, poll_interval=5.0)

Trigger a Plex Butler task and check if sonic analysis follows.

Unlike per-item analyze, the MusicAnalysis Butler task works through every album pending sonic analysis on the server, which can be CPU-heavy and long-running — it keeps going after this probe returns.

Parameters:

Name Type Description Default
album_rating_key str | None

Plex rating key of the album to watch; auto-picked when None.

None
library_name str | None

library used for the auto-pick; defaults to the configured plex.library.

None
butler_task str

name of the Butler task to run.

'MusicAnalysis'
wait_seconds float

maximum time to watch for analysis.

120.0
poll_interval float

seconds between polls.

5.0

Returns:

Type Description
SonicTriggerProbeResult

The probe outcome for the watched album, including analyzed counts

SonicTriggerProbeResult

before/after and the Plex activities observed while waiting.

Raises:

Type Description
ConfigurationError

if plex.token is not configured.

NotFoundError

if no unanalyzed album can be found.

PlexAPIError

if the Plex API call fails.

refresh_sonic_analysis(library_name=None, *, days=7, wait_seconds=900.0, poll_interval=15.0, stall_after=4, on_poll=None)

Refresh sonic analysis for music added in the last days days.

Triggers the Plex MusicAnalysis Butler task and watches the window's pending track count until it reaches zero, stalls (no progress across stall_after consecutive polls), or wait_seconds elapses. The Butler task keeps running on the server after this function returns.

on_poll(pending_now, pending_before) is called after each poll so a surface can render progress.

Parameters:

Name Type Description Default
library_name str | None

Plex music library to refresh; defaults to the configured plex.library.

None
days int

size of the "recent additions" window in days.

7
wait_seconds float

maximum time to watch the refresh.

900.0
poll_interval float

seconds between polls.

15.0
stall_after int

consecutive polls without progress before giving up.

4
on_poll Callable[[int, int], None] | None

optional (pending_now, pending_before) progress callback.

None

Returns:

Type Description
SonicRefreshResult

The refresh outcome, including pending counts before/after, whether a

SonicRefreshResult

stall was detected, and the albums still pending in the window.

Raises:

Type Description
ConfigurationError

if plex.token is not configured.

NotFoundError

if the library name doesn't match a music section.

PlexAPIError

if the Plex API call fails.

Dashboard

musicseed.services.dashboard

Dashboard aggregation service — combines discovery, library stats, and job status into one surface-agnostic snapshot.

DashboardSnapshot

Bases: BaseModel

Combined dashboard view: discovery, library stats, and job state.

ready_for_recommendations property

True when at least one track has been imported locally.

get_dashboard(check_server=False)

Aggregate a dashboard snapshot.

check_server gates the live Plex HTTP probe inside discovery. It defaults to False so frequent dashboard polls never touch Plex; the caller (a web surface) fetches the full probe separately and less often. When the library status cannot be read (e.g. no database yet), an empty LibraryStatus is used instead of failing the whole snapshot.

Parameters:

Name Type Description Default
check_server bool

whether to probe the Plex server over HTTP as part of the embedded discovery result.

False

Returns:

Type Description
DashboardSnapshot

A snapshot with discovery, library status, active and recent jobs,

DashboardSnapshot

and the last successful import (last_sync, None when no import

DashboardSnapshot

has succeeded yet).

Jobs

musicseed.services.jobs

Persistent, in-process job abstraction for long-running MusicSeed work.

Every operation (create, start, update progress, complete, fail, cancel-request) writes through a dedicated SQLAlchemy session. The JobManager singleton runs workers in daemon threads — no external queue, no Redis, no containers. On first access it reconciles any jobs left in a running state from a prior process into interrupted.

JobKind

Bases: StrEnum

The kinds of long-running work the job system tracks.

JobState

Bases: StrEnum

Lifecycle states of a job row.

JobManager

In-process runner with a bounded concurrency pool.

Workers are daemon threads. Job state lives in the jobs table (shared across processes); the in-memory bookkeeping only tracks this process's threads and concurrency. Cancel is cooperative (should_cancel reads the DB — workers poll it at safe checkpoints).

__init__(max_concurrent=2)

Create a manager that runs at most max_concurrent jobs at once.

Parameters:

Name Type Description Default
max_concurrent int

maximum number of worker threads allowed to be active simultaneously; further submissions are rejected.

2

submit(kind, target, *args, **kwargs)

Create a job and run target for it in a daemon thread.

The target is called as target(job_id, *args, **kwargs) — the job id is always the first positional argument.

Parameters:

Name Type Description Default
kind str

job kind (see JobKind); only one active job per kind is allowed across all processes sharing the database.

required
target Callable[..., None]

blocking callable to run in the worker thread.

required
*args Any

extra positional arguments forwarded to target.

()
**kwargs Any

keyword arguments forwarded to target.

{}

Returns:

Type Description
int

The id of the newly created job row.

Raises:

Type Description
JobConflictError

if a job of the same kind is already active, or the concurrency pool is full.

request_cancel(job_id)

Ask a job to stop (cooperative; see request_cancel).

Parameters:

Name Type Description Default
job_id int

id of the job to cancel.

required

should_cancel(job_id)

Return True when cancellation has been requested for a job.

Workers poll this at safe checkpoints and then wind down on their own.

Parameters:

Name Type Description Default
job_id int

id of the job to check.

required

Returns:

Type Description
bool

True if the job exists and its state is cancel_requested.

shutdown()

Request cancellation of every active job (threads are daemons).

create_job(kind)

Insert a new pending job and return its id.

start_job(job_id)

Mark a job running and stamp its start time.

Parameters:

Name Type Description Default
job_id int

id of the job row to update. Unknown ids are ignored.

required

update_progress(job_id, current, total=0, checkpoint='', phases=None)

Record progress for a running job.

Parameters:

Name Type Description Default
job_id int

id of the job row to update. Unknown ids are ignored.

required
current int

units of work completed so far.

required
total int

total units of work expected (0 when unknown).

0
checkpoint str

human-readable status line; only stored when non-empty.

''
phases dict | None

per-phase {"current", "total"} snapshot for multi-phase jobs; only stored when not None.

None

complete_job(job_id, result_summary='')

Mark a job succeeded and stamp its completion time.

Parameters:

Name Type Description Default
job_id int

id of the job row to update. Unknown ids are ignored.

required
result_summary str

optional JSON-serialized outcome summary; only stored when non-empty.

''

fail_job(job_id, error_summary)

Mark a job failed and stamp its completion time.

Parameters:

Name Type Description Default
job_id int

id of the job row to update. Unknown ids are ignored.

required
error_summary str

failure description, truncated to 500 characters.

required

request_cancel(job_id)

Set a job's state to cancel_requested (cooperative cancellation).

The worker still has to observe the request (via JobManager.should_cancel) and wind itself down; nothing is interrupted forcibly.

Parameters:

Name Type Description Default
job_id int

id of the job row to update. Unknown ids are ignored.

required

cancel_job(job_id)

Mark a job canceled and stamp its completion time.

Parameters:

Name Type Description Default
job_id int

id of the job row to update. Unknown ids are ignored.

required

get_job(job_id)

Return a snapshot of one job, or None when it does not exist.

Parameters:

Name Type Description Default
job_id int

id of the job row to read.

required

Returns:

Type Description
dict | None

The job's fields as a plain dict, or None for an unknown id.

delete_job(job_id)

Delete a job row by id. Returns True if a row was deleted.

list_jobs(limit=20)

Return the most recent jobs, newest first.

Parameters:

Name Type Description Default
limit int

maximum number of jobs to return.

20

Returns:

Type Description
list[dict]

Job snapshots as plain dicts, ordered by creation time descending.

get_latest_job(kind)

Return the most recent job of a given kind, or None.

Parameters:

Name Type Description Default
kind str

job kind to filter on (see JobKind).

required

Returns:

Type Description
dict | None

The newest matching job snapshot as a plain dict, or None when no

dict | None

job of that kind exists.

get_active_jobs()

Return all jobs in a non-terminal state (running or pending).

Returns:

Type Description
list[dict]

Job snapshots as plain dicts.

reconcile_running_jobs()

Mark running jobs from dead processes as interrupted.

A job is only interrupted when its recorded owner pid is no longer alive, so starting one process while another genuinely runs a job leaves that job untouched.

get_manager()

Return the module-level JobManager singleton, creating it lazily.

On first access, jobs left running by dead processes are reconciled to interrupted before the manager is returned.

Returns:

Type Description
JobManager

The shared JobManager instance.

Typeahead

musicseed.services.typeahead

Track typeahead search service — the reusable lookup behind autocomplete.

TypeaheadTrack

Bases: BaseModel

A minimal, JSON-safe view of a track for autocomplete results.

search_tracks(query, exclude_ids=None, limit=10)

Search tracks by title or artist name for autocomplete.

Returns an empty list when the query is shorter than 2 characters. Results exclude exclude_ids, are ordered by title, and capped at limit.

Parameters:

Name Type Description Default
query str

substring matched (case-insensitively) against track titles and artist names.

required
exclude_ids list[int] | None

local track ids to leave out of the results.

None
limit int

maximum number of matches to return.

10

Returns:

Type Description
list[TypeaheadTrack]

Matching tracks as minimal JSON-safe views, ordered by title.