@freqhole/api-client 0.3.11 → 0.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freqhole/api-client",
3
- "version": "0.3.11",
3
+ "version": "0.3.13",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -132,6 +132,7 @@ export const routes = {
132
132
  enqueue_bulk_enrichment: { method: 'POST', path: '/api/music/albums/enrichment/bulk', req: s.BulkEnrichmentRequestSchema, resp: s.BulkEnrichmentResponseSchema, auth: { type: 'role', role: 'admin' } as const },
133
133
  enqueue_lastfm_album_detail: { method: 'POST', path: '/api/music/albums/lastfm/enqueue', req: s.EnqueueLastFmAlbumDetailRequestSchema, resp: s.EnqueueLastFmAlbumDetailResponseSchema, auth: { type: 'role', role: 'admin' } as const },
134
134
  enqueue_mb_album_search: { method: 'POST', path: '/api/music/albums/mb-search/enqueue', req: s.EnqueueMbAlbumSearchRequestSchema, resp: s.EnqueueMbAlbumSearchResponseSchema, auth: { type: 'role', role: 'admin' } as const },
135
+ enqueue_repair_library_images: { method: 'POST', path: '/api/music/maintenance/repair-library-images/enqueue', req: s.EnqueueRepairLibraryImagesRequestSchema, resp: s.EnqueueRepairLibraryImagesResponseSchema, auth: { type: 'role', role: 'admin' } as const },
135
136
  entity_taxons_batch: { method: 'POST', path: '/api/music/entities/taxons', req: s.EntityTaxonsBatchRequestSchema, resp: s.EntityTaxonsBatchResponseSchema, auth: { type: 'authenticated' } as const },
136
137
  era_albums: { method: 'POST', path: '/api/music/relations/era-albums', req: s.EraAlbumsRequestSchema, resp: s.EraAlbumsResponseSchema, auth: { type: 'authenticated' } as const },
137
138
  era_bins: { method: 'POST', path: '/api/music/relations/era-bins', req: s.EraBinsRequestSchema, resp: s.EraBinsResponseSchema, auth: { type: 'authenticated' } as const },
@@ -219,9 +220,10 @@ export const routes = {
219
220
  stream_blob: { method: 'GET', path: '/api/blobs/{id}', req: null, resp: null, auth: { type: 'authenticated' } as const },
220
221
  suggestions: { method: 'POST', path: '/api/music/suggestions', req: s.SuggestionsRequestSchema, resp: s.SuggestionsResponseSchema, auth: { type: 'authenticated' } as const },
221
222
  sync_album: { method: 'POST', path: '/api/sync/album', req: s.SyncAlbumRequestSchema, resp: s.SyncAlbumResponseSchema, auth: { type: 'role', role: 'member' } as const },
223
+ sync_job_notify: { method: 'POST', path: '/api/sync/job-notify', req: s.SyncJobNotifySchema, resp: z.boolean(), auth: { type: 'public' } as const },
222
224
  sync_playlist: { method: 'POST', path: '/api/sync/playlist', req: s.SyncPlaylistRequestSchema, resp: s.SyncPlaylistResponseSchema, auth: { type: 'role', role: 'member' } as const },
223
- sync_song_by_blake3: { method: 'POST', path: '/api/sync/song-by-blake3', req: s.SyncSongByBlake3RequestSchema, resp: s.SyncSongByBlake3ResponseSchema, auth: { type: 'role', role: 'member' } as const },
224
- synced_sha256s: { method: 'GET', path: '/api/sync/sha256s', req: null, resp: z.string().array(), auth: { type: 'role', role: 'member' } as const },
225
+ sync_song_by_blake3: { method: 'POST', path: '/api/sync/song-by-blake3', req: s.SyncSongByBlake3RequestSchema, resp: s.SyncJobQueuedResponseSchema, auth: { type: 'role', role: 'member' } as const },
226
+ synced_blake3s: { method: 'GET', path: '/api/sync/blake3s', req: null, resp: z.string().array(), auth: { type: 'role', role: 'member' } as const },
225
227
  top_albums: { method: 'POST', path: '/api/analytics/top-albums', req: s.TopAlbumsRequestSchema, resp: s.TopAlbumSchema.array(), auth: { type: 'authenticated' } as const },
226
228
  top_artists: { method: 'POST', path: '/api/analytics/top-artists', req: s.TopArtistsRequestSchema, resp: s.TopArtistSchema.array(), auth: { type: 'authenticated' } as const },
227
229
  top_songs: { method: 'POST', path: '/api/analytics/top-songs', req: s.TopSongsRequestSchema, resp: s.TopSongSchema.array(), auth: { type: 'authenticated' } as const },
@@ -270,7 +272,7 @@ export const routes = {
270
272
  query_videos: { method: 'POST', path: '/api/video/videos/query', req: s.QueryVideosRequestSchema, resp: s.VideosQueryResultSchema, auth: { type: 'authenticated' } as const },
271
273
  recently_added_videos: { method: 'POST', path: '/api/video/relations/recently-added-videos', req: s.RecentlyAddedVideosRequestSchema, resp: s.RecentlyAddedVideosResponseSchema, auth: { type: 'authenticated' } as const },
272
274
  reprocess_video: { method: 'POST', path: '/api/video/videos/reprocess', req: s.ReprocessVideoRequestSchema, resp: s.ReprocessVideoResultSchema, auth: { type: 'role', role: 'admin' } as const },
273
- sync_video_by_blake3: { method: 'POST', path: '/api/sync/video-by-blake3', req: s.SyncVideoByBlake3RequestSchema, resp: s.SyncVideoByBlake3ResponseSchema, auth: { type: 'role', role: 'member' } as const },
275
+ sync_video_by_blake3: { method: 'POST', path: '/api/sync/video-by-blake3', req: s.SyncVideoByBlake3RequestSchema, resp: s.SyncJobQueuedResponseSchema, auth: { type: 'role', role: 'member' } as const },
274
276
  unassigned_videos: { method: 'POST', path: '/api/video/relations/unassigned-videos', req: s.UnassignedVideosRequestSchema, resp: s.UnassignedVideosResponseSchema, auth: { type: 'authenticated' } as const },
275
277
  update_video_season: { method: 'POST', path: '/api/video/seasons/update', req: s.UpdateVideoSeasonRequestSchema, resp: s.VideoSeasonSchema, auth: { type: 'role', role: 'admin' } as const },
276
278
  update_video_series: { method: 'POST', path: '/api/video/series/update', req: s.UpdateVideoSeriesRequestSchema, resp: s.VideoSeriesSchema, auth: { type: 'role', role: 'admin' } as const },
@@ -1336,7 +1336,6 @@ export type BioSource = z.infer<typeof BioSourceSchema>;
1336
1336
 
1337
1337
  export const BlobMetadataResponseSchema = z.object({
1338
1338
  id: z.string(),
1339
- sha256: z.string(),
1340
1339
  size: z.number().nullish(),
1341
1340
  mime: z.string().nullish(),
1342
1341
  filename: z.string().nullish(),
@@ -1462,7 +1461,7 @@ export const CreateArtistRequestSchema = z.object({
1462
1461
  export type CreateArtistRequest = z.infer<typeof CreateArtistRequestSchema>;
1463
1462
 
1464
1463
  export const CreateJobRequestSchema = z.object({
1465
- job_type: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment')]),
1464
+ job_type: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment'), z.literal('SyncSongByBlake3'), z.literal('SyncVideoByBlake3'), z.literal('RepairLibraryImages')]),
1466
1465
  session_id: z.string().nullish(),
1467
1466
  parameters: z.any(),
1468
1467
  max_retries: z.number().nullish(),
@@ -1716,6 +1715,23 @@ export const EnqueueMbAlbumSearchResponseSchema = z.object({
1716
1715
  });
1717
1716
  export type EnqueueMbAlbumSearchResponse = z.infer<typeof EnqueueMbAlbumSearchResponseSchema>;
1718
1717
 
1718
+ export const EnqueueRepairLibraryImagesRequestSchema = z.object({
1719
+ dry_run: z.boolean(),
1720
+ scan_directory: z.string().nullish(),
1721
+ options: z.object({
1722
+ backfill_waveforms: z.boolean(),
1723
+ backfill_embedded_art: z.boolean(),
1724
+ backfill_directory_art: z.boolean(),
1725
+ remove_overapplied: z.boolean()
1726
+ })
1727
+ });
1728
+ export type EnqueueRepairLibraryImagesRequest = z.infer<typeof EnqueueRepairLibraryImagesRequestSchema>;
1729
+
1730
+ export const EnqueueRepairLibraryImagesResponseSchema = z.object({
1731
+ job_id: z.string()
1732
+ });
1733
+ export type EnqueueRepairLibraryImagesResponse = z.infer<typeof EnqueueRepairLibraryImagesResponseSchema>;
1734
+
1719
1735
  export const EnrichmentLogEntrySchema = z.object({
1720
1736
  at: z.number(),
1721
1737
  step: z.string(),
@@ -1927,7 +1943,7 @@ export const ErrorDetailSchema = z.object({
1927
1943
  export type ErrorDetail = z.infer<typeof ErrorDetailSchema>;
1928
1944
 
1929
1945
  export const EventFilterSchema = z.object({
1930
- kinds: z.array(z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment')])).nullish(),
1946
+ kinds: z.array(z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment'), z.literal('SyncSongByBlake3'), z.literal('SyncVideoByBlake3'), z.literal('RepairLibraryImages')])).nullish(),
1931
1947
  job_ids: z.array(z.string()).nullish(),
1932
1948
  session_ids: z.array(z.string()).nullish(),
1933
1949
  entity_refs: z.array(z.union([z.object({
@@ -2190,7 +2206,6 @@ export const FavoriteItemSchema = z.union([z.intersection(z.object({
2190
2206
  }).nullish(),
2191
2207
  media_blob: z.object({
2192
2208
  id: z.string(),
2193
- sha256: z.string(),
2194
2209
  size: z.number().nullish(),
2195
2210
  mime: z.string().nullish(),
2196
2211
  source_client_id: z.string().nullish(),
@@ -2582,7 +2597,6 @@ export const FavoriteSongResultSchema = z.object({
2582
2597
  }).nullish(),
2583
2598
  media_blob: z.object({
2584
2599
  id: z.string(),
2585
- sha256: z.string(),
2586
2600
  size: z.number().nullish(),
2587
2601
  mime: z.string().nullish(),
2588
2602
  source_client_id: z.string().nullish(),
@@ -3093,16 +3107,13 @@ export const GetVideoSeriesRequestSchema = z.object({
3093
3107
  export type GetVideoSeriesRequest = z.infer<typeof GetVideoSeriesRequestSchema>;
3094
3108
 
3095
3109
  export const HasBlobsRequestSchema = z.object({
3096
- blake3s: z.array(z.string()),
3097
- sha256s: z.array(z.string())
3110
+ blake3s: z.array(z.string())
3098
3111
  });
3099
3112
  export type HasBlobsRequest = z.infer<typeof HasBlobsRequestSchema>;
3100
3113
 
3101
3114
  export const HasBlobsResponseSchema = z.object({
3102
3115
  blake3s_present: z.array(z.string()),
3103
- blake3s_missing: z.array(z.string()),
3104
- sha256s_present: z.array(z.string()),
3105
- sha256s_missing: z.array(z.string())
3116
+ blake3s_missing: z.array(z.string())
3106
3117
  });
3107
3118
  export type HasBlobsResponse = z.infer<typeof HasBlobsResponseSchema>;
3108
3119
 
@@ -3131,7 +3142,7 @@ export type ImageMetadata = z.infer<typeof ImageMetadataSchema>;
3131
3142
  export const ImageUploadResponseSchema = z.object({
3132
3143
  blob_id: z.string(),
3133
3144
  job_id: z.string(),
3134
- sha256: z.string(),
3145
+ blake3: z.string(),
3135
3146
  size: z.number(),
3136
3147
  mime: z.string(),
3137
3148
  existing: z.boolean(),
@@ -3170,7 +3181,7 @@ export type IngestRemoteImageRequest = z.infer<typeof IngestRemoteImageRequestSc
3170
3181
 
3171
3182
  export const IngestRemoteImageResponseSchema = z.object({
3172
3183
  blob_id: z.string(),
3173
- sha256: z.string(),
3184
+ blake3: z.string(),
3174
3185
  size: z.number(),
3175
3186
  mime: z.string(),
3176
3187
  deduped: z.boolean()
@@ -3182,7 +3193,7 @@ export const JobEventSchema = z.union([z.object({
3182
3193
  session_id: z.string(),
3183
3194
  complete: z.number(),
3184
3195
  total: z.number(),
3185
- topic: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment')]),
3196
+ topic: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment'), z.literal('SyncSongByBlake3'), z.literal('SyncVideoByBlake3'), z.literal('RepairLibraryImages')]),
3186
3197
  entity_ref: z.union([z.object({
3187
3198
  kind: z.literal('album'),
3188
3199
  id: z.string()
@@ -3198,7 +3209,7 @@ export const JobEventSchema = z.union([z.object({
3198
3209
  job_id: z.string(),
3199
3210
  from: z.union([z.literal('pending'), z.literal('running'), z.literal('completed'), z.literal('failed'), z.literal('cancelled')]).nullish(),
3200
3211
  to: z.union([z.literal('pending'), z.literal('running'), z.literal('completed'), z.literal('failed'), z.literal('cancelled')]),
3201
- topic: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment')]),
3212
+ topic: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment'), z.literal('SyncSongByBlake3'), z.literal('SyncVideoByBlake3'), z.literal('RepairLibraryImages')]),
3202
3213
  entity_ref: z.union([z.object({
3203
3214
  kind: z.literal('album'),
3204
3215
  id: z.string()
@@ -3213,7 +3224,7 @@ export const JobEventSchema = z.union([z.object({
3213
3224
  job_id: z.string(),
3214
3225
  error_type: z.string(),
3215
3226
  message: z.string(),
3216
- topic: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment')]),
3227
+ topic: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment'), z.literal('SyncSongByBlake3'), z.literal('SyncVideoByBlake3'), z.literal('RepairLibraryImages')]),
3217
3228
  entity_ref: z.union([z.object({
3218
3229
  kind: z.literal('album'),
3219
3230
  id: z.string()
@@ -3228,7 +3239,7 @@ export const JobEventSchema = z.union([z.object({
3228
3239
  job_id: z.string(),
3229
3240
  stage: z.string(),
3230
3241
  message: z.string().nullish(),
3231
- topic: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment')]),
3242
+ topic: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment'), z.literal('SyncSongByBlake3'), z.literal('SyncVideoByBlake3'), z.literal('RepairLibraryImages')]),
3232
3243
  entity_ref: z.union([z.object({
3233
3244
  kind: z.literal('album'),
3234
3245
  id: z.string()
@@ -3236,11 +3247,12 @@ export const JobEventSchema = z.union([z.object({
3236
3247
  kind: z.literal('artist'),
3237
3248
  id: z.string()
3238
3249
  })]).nullish(),
3239
- created_by: z.string().nullish()
3250
+ created_by: z.string().nullish(),
3251
+ details: z.any().nullish()
3240
3252
  }), z.object({
3241
3253
  kind: z.literal('completed'),
3242
3254
  session_id: z.string(),
3243
- topic: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment')]),
3255
+ topic: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment'), z.literal('SyncSongByBlake3'), z.literal('SyncVideoByBlake3'), z.literal('RepairLibraryImages')]),
3244
3256
  entity_ref: z.union([z.object({
3245
3257
  kind: z.literal('album'),
3246
3258
  id: z.string()
@@ -3278,7 +3290,7 @@ export type JobResponse = z.infer<typeof JobResponseSchema>;
3278
3290
  export const JobStateSnapshotSchema = z.object({
3279
3291
  job_id: z.string(),
3280
3292
  session_id: z.string().nullish(),
3281
- job_type: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment')]),
3293
+ job_type: z.union([z.literal('ScanDirectory'), z.literal('RescanDirectories'), z.literal('ProcessFile'), z.literal('ProcessDirectory'), z.literal('FetchMedia'), z.literal('PreCheckFetch'), z.literal('ConvertWebp'), z.literal('ImportMusic'), z.literal('ImportVideo'), z.literal('TranscodeVideo'), z.literal('MbAlbumSearch'), z.literal('MbAlbumDetail'), z.literal('LastFmAlbumDetail'), z.literal('LastFmArtistDetail'), z.literal('AudioDbAlbumDetail'), z.literal('AudioDbArtistDetail'), z.literal('AlbumEnrichmentPipeline'), z.literal('AutoApplyAlbumEnrichment'), z.literal('SyncSongByBlake3'), z.literal('SyncVideoByBlake3'), z.literal('RepairLibraryImages')]),
3282
3294
  status: z.union([z.literal('pending'), z.literal('running'), z.literal('completed'), z.literal('failed'), z.literal('cancelled')]),
3283
3295
  entity_ref: z.union([z.object({
3284
3296
  kind: z.literal('album'),
@@ -3507,7 +3519,6 @@ export const ListFavoritesResponseSchema = z.object({
3507
3519
  }).nullish(),
3508
3520
  media_blob: z.object({
3509
3521
  id: z.string(),
3510
- sha256: z.string(),
3511
3522
  size: z.number().nullish(),
3512
3523
  mime: z.string().nullish(),
3513
3524
  source_client_id: z.string().nullish(),
@@ -4306,7 +4317,6 @@ export type MbUrl = z.infer<typeof MbUrlSchema>;
4306
4317
 
4307
4318
  export const MediaBlobSchema = z.object({
4308
4319
  id: z.string(),
4309
- sha256: z.string(),
4310
4320
  size: z.number().nullish(),
4311
4321
  mime: z.string().nullish(),
4312
4322
  source_client_id: z.string().nullish(),
@@ -4450,7 +4460,7 @@ export type MusicMetadataHints = z.infer<typeof MusicMetadataHintsSchema>;
4450
4460
  export const MusicUploadResponseSchema = z.object({
4451
4461
  blob_id: z.string(),
4452
4462
  job_id: z.string(),
4453
- sha256: z.string(),
4463
+ blake3: z.string(),
4454
4464
  size: z.number(),
4455
4465
  mime: z.string(),
4456
4466
  existing: z.boolean(),
@@ -4893,7 +4903,6 @@ export const PlaylistSongResultSchema = z.object({
4893
4903
  }).nullish(),
4894
4904
  media_blob: z.object({
4895
4905
  id: z.string(),
4896
- sha256: z.string(),
4897
4906
  size: z.number().nullish(),
4898
4907
  mime: z.string().nullish(),
4899
4908
  source_client_id: z.string().nullish(),
@@ -5036,7 +5045,6 @@ export const PlaylistSongsQueryResultSchema = z.object({
5036
5045
  }).nullish(),
5037
5046
  media_blob: z.object({
5038
5047
  id: z.string(),
5039
- sha256: z.string(),
5040
5048
  size: z.number().nullish(),
5041
5049
  mime: z.string().nullish(),
5042
5050
  source_client_id: z.string().nullish(),
@@ -6037,6 +6045,47 @@ export const ReorderPlaylistSongsRequestSchema = z.object({
6037
6045
  });
6038
6046
  export type ReorderPlaylistSongsRequest = z.infer<typeof ReorderPlaylistSongsRequestSchema>;
6039
6047
 
6048
+ export const RepairLibraryImagesJobResultSchema = z.object({
6049
+ totals: z.object({
6050
+ songs_waveforms_backfilled: z.number(),
6051
+ albums_thumbnails_backfilled: z.number(),
6052
+ albums_thumbnails_removed_overapplied: z.number(),
6053
+ albums_left_ambiguous: z.number(),
6054
+ errors: z.array(z.object({
6055
+ error_type: z.string(),
6056
+ title: z.string(),
6057
+ detail: z.string()
6058
+ }))
6059
+ }),
6060
+ done: z.boolean(),
6061
+ next_job_id: z.string().nullish()
6062
+ });
6063
+ export type RepairLibraryImagesJobResult = z.infer<typeof RepairLibraryImagesJobResultSchema>;
6064
+
6065
+ export const RepairLibraryImagesOptionsSchema = z.object({
6066
+ backfill_waveforms: z.boolean(),
6067
+ backfill_embedded_art: z.boolean(),
6068
+ backfill_directory_art: z.boolean(),
6069
+ remove_overapplied: z.boolean()
6070
+ });
6071
+ export type RepairLibraryImagesOptions = z.infer<typeof RepairLibraryImagesOptionsSchema>;
6072
+
6073
+ export const RepairLibraryImagesPhaseSchema = z.union([z.literal('Waveforms'), z.literal('Directories')]);
6074
+ export type RepairLibraryImagesPhase = z.infer<typeof RepairLibraryImagesPhaseSchema>;
6075
+
6076
+ export const RepairLibraryImagesResultSchema = z.object({
6077
+ songs_waveforms_backfilled: z.number(),
6078
+ albums_thumbnails_backfilled: z.number(),
6079
+ albums_thumbnails_removed_overapplied: z.number(),
6080
+ albums_left_ambiguous: z.number(),
6081
+ errors: z.array(z.object({
6082
+ error_type: z.string(),
6083
+ title: z.string(),
6084
+ detail: z.string()
6085
+ }))
6086
+ });
6087
+ export type RepairLibraryImagesResult = z.infer<typeof RepairLibraryImagesResultSchema>;
6088
+
6040
6089
  export const ReplaceAlbumsTagsRequestSchema = z.object({
6041
6090
  album_ids: z.array(z.string()),
6042
6091
  tag_ids: z.array(z.string())
@@ -6079,14 +6128,6 @@ export const RequeryOverrideSchema = z.object({
6079
6128
  });
6080
6129
  export type RequeryOverride = z.infer<typeof RequeryOverrideSchema>;
6081
6130
 
6082
- export const RestartPolicySchema = z.object({
6083
- max_restarts: z.number(),
6084
- window_ms: z.number(),
6085
- initial_backoff_ms: z.number(),
6086
- max_backoff_ms: z.number()
6087
- });
6088
- export type RestartPolicy = z.infer<typeof RestartPolicySchema>;
6089
-
6090
6131
  export const RevokeOwnInviteRequestSchema = z.object({
6091
6132
  code: z.string()
6092
6133
  });
@@ -6704,7 +6745,6 @@ export const SongQueryResultSchema = z.object({
6704
6745
  }).nullish(),
6705
6746
  media_blob: z.object({
6706
6747
  id: z.string(),
6707
- sha256: z.string(),
6708
6748
  size: z.number().nullish(),
6709
6749
  mime: z.string().nullish(),
6710
6750
  source_client_id: z.string().nullish(),
@@ -6874,7 +6914,6 @@ export const SongsQueryResultSchema = z.object({
6874
6914
  }).nullish(),
6875
6915
  media_blob: z.object({
6876
6916
  id: z.string(),
6877
- sha256: z.string(),
6878
6917
  size: z.number().nullish(),
6879
6918
  mime: z.string().nullish(),
6880
6919
  source_client_id: z.string().nullish(),
@@ -7015,9 +7054,8 @@ export const SyncAlbumRequestSchema = z.object({
7015
7054
  mb_release_id: z.string().nullish(),
7016
7055
  mb_release_group_id: z.string().nullish(),
7017
7056
  tags: z.array(z.string()),
7018
- images_base64: z.array(z.object({
7019
- content_sha256: z.string(),
7020
- data_base64: z.string().nullish(),
7057
+ images: z.array(z.object({
7058
+ blake3: z.string(),
7021
7059
  mime_type: z.string(),
7022
7060
  is_primary: z.boolean(),
7023
7061
  blob_type: z.string().nullish()
@@ -7032,28 +7070,52 @@ export const SyncAlbumResponseSchema = z.object({
7032
7070
  artist_id: z.string(),
7033
7071
  existing: z.boolean(),
7034
7072
  images_linked: z.number(),
7035
- missing_image_sha256s: z.array(z.string())
7073
+ missing_image_blake3s: z.array(z.string())
7036
7074
  });
7037
7075
  export type SyncAlbumResponse = z.infer<typeof SyncAlbumResponseSchema>;
7038
7076
 
7039
7077
  export const SyncImageRefSchema = z.object({
7040
- content_sha256: z.string(),
7041
- data_base64: z.string().nullish(),
7078
+ blake3: z.string(),
7042
7079
  mime_type: z.string(),
7043
7080
  is_primary: z.boolean(),
7044
7081
  blob_type: z.string().nullish()
7045
7082
  });
7046
7083
  export type SyncImageRef = z.infer<typeof SyncImageRefSchema>;
7047
7084
 
7085
+ export const SyncJobNotifySchema = z.object({
7086
+ job_id: z.string(),
7087
+ domain: z.string(),
7088
+ blake3: z.string(),
7089
+ title: z.string(),
7090
+ success: z.boolean(),
7091
+ error: z.string().nullish()
7092
+ });
7093
+ export type SyncJobNotify = z.infer<typeof SyncJobNotifySchema>;
7094
+
7095
+ export const SyncJobQueuedResponseSchema = z.object({
7096
+ job_id: z.string(),
7097
+ artist_id: z.string().nullish()
7098
+ });
7099
+ export type SyncJobQueuedResponse = z.infer<typeof SyncJobQueuedResponseSchema>;
7100
+
7101
+ export const SyncPlaylistMemberSchema = z.object({
7102
+ kind: z.string(),
7103
+ blake3: z.string()
7104
+ });
7105
+ export type SyncPlaylistMember = z.infer<typeof SyncPlaylistMemberSchema>;
7106
+
7048
7107
  export const SyncPlaylistRequestSchema = z.object({
7049
7108
  source_remote_id: z.string().nullish(),
7109
+ source_node_id: z.string().nullish(),
7050
7110
  remote_playlist_id: z.string(),
7051
7111
  title: z.string(),
7052
7112
  description: z.string().nullish(),
7053
- song_blake3s: z.array(z.string()),
7113
+ members: z.array(z.object({
7114
+ kind: z.string(),
7115
+ blake3: z.string()
7116
+ })),
7054
7117
  images: z.array(z.object({
7055
- content_sha256: z.string(),
7056
- data_base64: z.string().nullish(),
7118
+ blake3: z.string(),
7057
7119
  mime_type: z.string(),
7058
7120
  is_primary: z.boolean(),
7059
7121
  blob_type: z.string().nullish()
@@ -7064,17 +7126,17 @@ export type SyncPlaylistRequest = z.infer<typeof SyncPlaylistRequestSchema>;
7064
7126
 
7065
7127
  export const SyncPlaylistResponseSchema = z.object({
7066
7128
  playlist_id: z.string(),
7067
- songs_added: z.number(),
7068
- missing_song_blake3s: z.array(z.string()),
7129
+ members_added: z.number(),
7130
+ missing_member_blake3s: z.array(z.string()),
7069
7131
  song_stubs_created: z.number(),
7070
7132
  images_linked: z.number(),
7071
- missing_image_sha256s: z.array(z.string())
7133
+ missing_image_blake3s: z.array(z.string())
7072
7134
  });
7073
7135
  export type SyncPlaylistResponse = z.infer<typeof SyncPlaylistResponseSchema>;
7074
7136
 
7075
7137
  export const SyncSongByBlake3RequestSchema = z.object({
7076
7138
  blake3: z.string(),
7077
- sha256: z.string(),
7139
+ node_id: z.string().nullish(),
7078
7140
  size: z.number().nullish(),
7079
7141
  filename: z.string(),
7080
7142
  source_node_id: z.string(),
@@ -7093,15 +7155,13 @@ export const SyncSongByBlake3RequestSchema = z.object({
7093
7155
  metadata: z.string().nullish(),
7094
7156
  genre_name: z.string().nullish(),
7095
7157
  song_images: z.array(z.object({
7096
- content_sha256: z.string(),
7097
- data_base64: z.string().nullish(),
7158
+ blake3: z.string(),
7098
7159
  mime_type: z.string(),
7099
7160
  is_primary: z.boolean(),
7100
7161
  blob_type: z.string().nullish()
7101
7162
  })),
7102
7163
  album_images: z.array(z.object({
7103
- content_sha256: z.string(),
7104
- data_base64: z.string().nullish(),
7164
+ blake3: z.string(),
7105
7165
  mime_type: z.string(),
7106
7166
  is_primary: z.boolean(),
7107
7167
  blob_type: z.string().nullish()
@@ -7113,18 +7173,18 @@ export type SyncSongByBlake3Request = z.infer<typeof SyncSongByBlake3RequestSche
7113
7173
  export const SyncSongByBlake3ResponseSchema = z.object({
7114
7174
  song_id: z.string(),
7115
7175
  media_blob_id: z.string(),
7176
+ artist_id: z.string(),
7116
7177
  file_path: z.string(),
7117
- sha256: z.string(),
7118
7178
  blake3: z.string(),
7119
7179
  existing: z.boolean(),
7120
7180
  images_linked: z.number(),
7121
- missing_image_sha256s: z.array(z.string())
7181
+ missing_image_blake3s: z.array(z.string())
7122
7182
  });
7123
7183
  export type SyncSongByBlake3Response = z.infer<typeof SyncSongByBlake3ResponseSchema>;
7124
7184
 
7125
7185
  export const SyncVideoByBlake3RequestSchema = z.object({
7126
7186
  blake3: z.string(),
7127
- sha256: z.string().nullish(),
7187
+ node_id: z.string().nullish(),
7128
7188
  size: z.number().nullish(),
7129
7189
  filename: z.string(),
7130
7190
  source_node_id: z.string(),
@@ -7142,22 +7202,19 @@ export const SyncVideoByBlake3RequestSchema = z.object({
7142
7202
  season_title: z.string().nullish(),
7143
7203
  parent_blake3: z.string().nullish(),
7144
7204
  video_images: z.array(z.object({
7145
- content_sha256: z.string(),
7146
- data_base64: z.string().nullish(),
7205
+ blake3: z.string(),
7147
7206
  mime_type: z.string(),
7148
7207
  is_primary: z.boolean(),
7149
7208
  blob_type: z.string().nullish()
7150
7209
  })),
7151
7210
  series_images: z.array(z.object({
7152
- content_sha256: z.string(),
7153
- data_base64: z.string().nullish(),
7211
+ blake3: z.string(),
7154
7212
  mime_type: z.string(),
7155
7213
  is_primary: z.boolean(),
7156
7214
  blob_type: z.string().nullish()
7157
7215
  })),
7158
7216
  season_images: z.array(z.object({
7159
- content_sha256: z.string(),
7160
- data_base64: z.string().nullish(),
7217
+ blake3: z.string(),
7161
7218
  mime_type: z.string(),
7162
7219
  is_primary: z.boolean(),
7163
7220
  blob_type: z.string().nullish()
@@ -7174,7 +7231,7 @@ export const SyncVideoByBlake3ResponseSchema = z.object({
7174
7231
  season_id: z.string().nullish(),
7175
7232
  existing: z.boolean(),
7176
7233
  images_linked: z.number(),
7177
- missing_image_sha256s: z.array(z.string())
7234
+ missing_image_blake3s: z.array(z.string())
7178
7235
  });
7179
7236
  export type SyncVideoByBlake3Response = z.infer<typeof SyncVideoByBlake3ResponseSchema>;
7180
7237
 
@@ -8075,7 +8132,7 @@ export type VideoSeriesSearchResult = z.infer<typeof VideoSeriesSearchResultSche
8075
8132
  export const VideoUploadResponseSchema = z.object({
8076
8133
  blob_id: z.string(),
8077
8134
  job_id: z.string(),
8078
- sha256: z.string(),
8135
+ blake3: z.string(),
8079
8136
  size: z.number(),
8080
8137
  mime: z.string(),
8081
8138
  existing: z.boolean(),
@@ -1460,6 +1460,22 @@ export function createMusicMethods(call: CallFn) {
1460
1460
  );
1461
1461
  },
1462
1462
 
1463
+ // enqueue a whole-library image repair job (admin only): backfills
1464
+ // missing song waveforms / album thumbnails, and cleans up
1465
+ // directory-sourced images that got over-applied across unrelated
1466
+ // albums. returns the job id so the caller can poll status.
1467
+ enqueueRepairLibraryImages: (params: s.EnqueueRepairLibraryImagesRequest) => {
1468
+ return call(
1469
+ "music",
1470
+ "enqueue_repair_library_images",
1471
+ routes.music.enqueue_repair_library_images.resp,
1472
+ routes.music.enqueue_repair_library_images.req,
1473
+ routes.music.enqueue_repair_library_images.method,
1474
+ routes.music.enqueue_repair_library_images.path,
1475
+ params,
1476
+ );
1477
+ },
1478
+
1463
1479
  // download a remote image url and link it to an album or artist
1464
1480
  // (phase 14.6). dedups by sha256.
1465
1481
  ingestRemoteImage: (params: s.IngestRemoteImageRequest) => {
@@ -1779,15 +1795,15 @@ export function createMusicMethods(call: CallFn) {
1779
1795
  );
1780
1796
  },
1781
1797
 
1782
- // get the list of sha256 hashes known to this server for sync checks
1783
- syncedSha256s: () => {
1798
+ // get the list of blake3 hashes known to this server for sync checks
1799
+ syncedBlake3s: () => {
1784
1800
  return call(
1785
1801
  "music",
1786
- "synced_sha256s",
1787
- routes.music.synced_sha256s.resp,
1788
- routes.music.synced_sha256s.req,
1789
- routes.music.synced_sha256s.method,
1790
- routes.music.synced_sha256s.path,
1802
+ "synced_blake3s",
1803
+ routes.music.synced_blake3s.resp,
1804
+ routes.music.synced_blake3s.req,
1805
+ routes.music.synced_blake3s.method,
1806
+ routes.music.synced_blake3s.path,
1791
1807
  undefined,
1792
1808
  );
1793
1809
  },