Skip to content

Add api#190

Open
ligeia wants to merge 3 commits intokellnerd:mainfrom
ligeia:add-api
Open

Add api#190
ligeia wants to merge 3 commits intokellnerd:mainfrom
ligeia:add-api

Conversation

@ligeia
Copy link

@ligeia ligeia commented Feb 7, 2026

First PR, hopefully I didn't screw up too badly.

This adds an API to Harmony. I've included an API.md file available in project root for review. The PR consists of a slightly modified server/main.ts and a new server/api.ts. I formatted everything with deno fmt and deno task ok shows no issues.

Copy link
Owner

@kellnerd kellnerd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First off, I really appreciate that you have provided documentation with examples. That makes it a lot easier to understand what you are trying to achieve.

I also like that you have kept the API standalone and independent from the web app, this will make testing and the initial development iterations a lot easier.
Personally I wouldn't integrate the API into the web app until it is ready and the endpoints are reasonably stable.
And if we do that, the API definitely shouldn't start a second web server (on a different port) from the web app's main module, it should be mounted into the existing server of the Fresh app. (Once Harmony's been migrated to Fresh 2.0, composition of middlewares will be a lot easier, similar to Express.js etc.)

I haven't really thought much about how an API for Harmony should look like, so I am open to suggestions by people who would use the API.
Nevertheless I've been confused by two of your decisions:

  1. There are many endpoints which effectively do the same thing (a release lookup), but return different parts of the resulting data. I would have thought one endpoint /api/v1/release/lookup that returns all data (or accepts parameters) should be sufficient?
    Especially /api/v1/match looks oddly-specific with the candidates and best property which always return the same single release.
  2. I don't really see the need for serializeRelease... The existing HarmonyRelease type is already fully JSON-compatible and your serialization deviates only in minor aspects.Most of the differences feel like your personal preferences to me. But if you have well-reasoned improvement suggestions, I would rather change HarmonyRelease and have one consistent format.

We should probably go back to #107 to collect ideas for the initial API endpoints where everyone who is interested has a chance to participate?


P.S. I also wanted to mention that deploying an API is currently not scalable, but that isn't specific to your implementation. There are mainly two concerns, one is inherent to the concept of Harmony, the other is related to the current architecture:

  1. The web app alone is already hitting the limits of the underlying APIs quite frequently nowadays. Hosting an API on the same server would only make this much worse.
  2. All the outgoing API requests are currently cached indefinitely in order to guarantee that the permalinks in edit notes continue to work and provide evidence using the original/historic data that was used to import the release.
    The SnapStorage cache therefore accumulates a lot of (mostly JSON) data (about 57GB in 18 months). While this is acceptable for the Release Lookup page which has a high probability of resulting in a MB import, it is wasteful for Release Actions already and almost pointless for most API requests that I would expect.

So before I feel confident to deploy an API into production, at least the second concern has to be resolved to avoid cluttering the SnapStorage with tons of data. Therefore Harmony needs a second, more traditional caching layer which discards data after a certain time (probably 24 hours). Only Release Lookup (or requests which explicitly need a permalink) should write to the permanent SnapStorage cache.
If the first concern turns out to be an issue, we can always turn off the API to improve the situation while it is hard to impossible to get rid of the useless API snapshots.

Comment on lines +29 to +38
// Primary location: release group MBID (populated by MBID resolver)
if (release.releaseGroup?.mbid) {
return release.releaseGroup.mbid;
}

// Fallback: check if MusicBrainz provider returned data
const mbProvider = release.info.providers.find((p) => p.internalName === 'musicbrainz');
if (mbProvider?.id) {
return mbProvider.id;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong, the first is a release group MBID, the second is a release MBID.

Comment on lines +60 to +66
const trackCounts = release.media.map((m) => m.tracklist.length);
const totalTracks = trackCounts.reduce((sum, c) => sum + c, 0);
return {
mediaCount: release.media.length,
trackCounts,
totalTracks,
};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this is redundant data and should be computed by the client?

Comment on lines +277 to +278
score: 1.0,
evidence: ['harmony-lookup'],
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of these properties (and the "match" endpoint in general)?

```json
{
"ok": true,
"version": "mvp-20",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this? Shouldn't this rather return the Harmony release version?

Comment on lines +401 to +406
function formatDuration(ms: number): string {
const totalSeconds = Math.floor(ms / 1000);
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that the API should format durations, but if it does, there is already an existing utility for that.

Comment on lines +22 to +23
# Standalone
deno task api
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't exist?

Comment on lines +334 to +344
### Supported Providers

- Spotify
- Deezer
- iTunes / Apple Music
- Bandcamp (URL lookup only, no GTIN)
- Beatport
- Tidal
- MusicBrainz
- mora (URL lookup only, no GTIN)
- OTOTOY (URL lookup only, no GTIN)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't API specific and shouldn't be mentioned here. The web app already generates this information for the About page.

@kellnerd kellnerd added feature New feature or request question Further information is requested labels Feb 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request question Further information is requested

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments