mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
fix(metadata): choose sources by medium and stop overwriting book data
Lead fetches with the primary file, give Book Dock its library's rules and read-along media, default audiobook fields to sources that carry them, and flag providers that never fill a field. Joining a format now fills gaps only and respects locks; a move picks its primary as a scan would.
This commit is contained in:
@@ -99,6 +99,11 @@ export interface BookDockFile {
|
||||
* single file, which is what `fileName` and `fileSize` already describe.
|
||||
*/
|
||||
unitFiles: BookDockUnitFile[];
|
||||
/**
|
||||
* Whether this EPUB carries synced narration. Only a single file's read that asks for it with
|
||||
* `readAlong=true` answers it, since it means opening the file; every other response leaves it out.
|
||||
*/
|
||||
readAlong?: boolean;
|
||||
}
|
||||
|
||||
export interface BookDockFilesPage {
|
||||
|
||||
@@ -166,3 +166,223 @@ export interface ProviderConnectionTestResult {
|
||||
status: ProviderConnectionTestStatus;
|
||||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The field-rule fields each provider can ever fill, read from its mapper on 2026-10-08. The rule
|
||||
* editor uses it to say a provider will never answer a field; nothing fetches by it, so an entry
|
||||
* that drifts costs a wrong hint, never a value. A field filled only on some paths (Goodreads'
|
||||
* publisher, which its fallback search lacks) counts as filled.
|
||||
*
|
||||
* The two cover rules list a provider only where its art can be that slot's shape. Audible's art is
|
||||
* always square, so it is not under `cover`; it still fills an empty ebook slot as a last resort.
|
||||
*/
|
||||
export const METADATA_PROVIDER_SUPPORTED_FIELDS: Record<MetadataProviderKey, readonly MetadataField[]> = {
|
||||
[MetadataProviderKey.GOOGLE]: [
|
||||
"title",
|
||||
"subtitle",
|
||||
"description",
|
||||
"cover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"isbn",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"pageCount",
|
||||
"communityRating",
|
||||
"genres",
|
||||
],
|
||||
[MetadataProviderKey.GOODREADS]: [
|
||||
"title",
|
||||
"subtitle",
|
||||
"description",
|
||||
"cover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"isbn",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"pageCount",
|
||||
"communityRating",
|
||||
"seriesName",
|
||||
"seriesIndex",
|
||||
"genres",
|
||||
],
|
||||
[MetadataProviderKey.AMAZON]: [
|
||||
"title",
|
||||
"subtitle",
|
||||
"description",
|
||||
"cover",
|
||||
"audioCover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"isbn",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"pageCount",
|
||||
"communityRating",
|
||||
"seriesName",
|
||||
"seriesIndex",
|
||||
"genres",
|
||||
],
|
||||
[MetadataProviderKey.HARDCOVER]: [
|
||||
"title",
|
||||
"subtitle",
|
||||
"description",
|
||||
"cover",
|
||||
"audioCover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"isbn",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"pageCount",
|
||||
"communityRating",
|
||||
"seriesName",
|
||||
"seriesIndex",
|
||||
"genres",
|
||||
],
|
||||
[MetadataProviderKey.OPEN_LIBRARY]: [
|
||||
"title",
|
||||
"description",
|
||||
"cover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"isbn",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"pageCount",
|
||||
"communityRating",
|
||||
"genres",
|
||||
],
|
||||
[MetadataProviderKey.ITUNES]: [
|
||||
"title",
|
||||
"description",
|
||||
"cover",
|
||||
"audioCover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"communityRating",
|
||||
"genres",
|
||||
],
|
||||
[MetadataProviderKey.AUDIBLE]: [
|
||||
"title",
|
||||
"subtitle",
|
||||
"description",
|
||||
"audioCover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"communityRating",
|
||||
"seriesName",
|
||||
"seriesIndex",
|
||||
"genres",
|
||||
"narrators",
|
||||
"duration",
|
||||
"abridged",
|
||||
],
|
||||
[MetadataProviderKey.AUDNEXUS]: [
|
||||
"title",
|
||||
"subtitle",
|
||||
"description",
|
||||
"audioCover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"seriesName",
|
||||
"seriesIndex",
|
||||
"narrators",
|
||||
"duration",
|
||||
"abridged",
|
||||
],
|
||||
[MetadataProviderKey.LIBROFM]: [
|
||||
"title",
|
||||
"subtitle",
|
||||
"description",
|
||||
"audioCover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"isbn",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"seriesName",
|
||||
"seriesIndex",
|
||||
"genres",
|
||||
"narrators",
|
||||
"duration",
|
||||
"abridged",
|
||||
],
|
||||
[MetadataProviderKey.COMICVINE]: ["title", "description", "cover", "authors", "publisher", "publishedYear", "seriesName", "seriesIndex"],
|
||||
[MetadataProviderKey.RANOBEDB]: [
|
||||
"title",
|
||||
"subtitle",
|
||||
"description",
|
||||
"cover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"isbn",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"pageCount",
|
||||
"communityRating",
|
||||
"seriesName",
|
||||
"seriesIndex",
|
||||
"genres",
|
||||
],
|
||||
[MetadataProviderKey.KOBO]: [
|
||||
"title",
|
||||
"subtitle",
|
||||
"description",
|
||||
"cover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"isbn",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"pageCount",
|
||||
"seriesName",
|
||||
"seriesIndex",
|
||||
"genres",
|
||||
],
|
||||
[MetadataProviderKey.LUBIMYCZYTAC]: [
|
||||
"title",
|
||||
"description",
|
||||
"cover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"isbn",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"pageCount",
|
||||
"seriesName",
|
||||
"seriesIndex",
|
||||
"genres",
|
||||
],
|
||||
[MetadataProviderKey.ALADIN]: [
|
||||
"title",
|
||||
"description",
|
||||
"cover",
|
||||
"authors",
|
||||
"publisher",
|
||||
"isbn",
|
||||
"publishedYear",
|
||||
"language",
|
||||
"pageCount",
|
||||
"seriesName",
|
||||
"genres",
|
||||
],
|
||||
};
|
||||
|
||||
/** How a provider stands against one field: it can fill it, its cover art is the other shape, or never. */
|
||||
export type ProviderFieldSupport = "supplies" | "otherShape" | "never";
|
||||
|
||||
export function providerFieldSupport(provider: MetadataProviderKey, field: MetadataField): ProviderFieldSupport {
|
||||
const fields = METADATA_PROVIDER_SUPPORTED_FIELDS[provider];
|
||||
// An unknown key is stale data, and a hint about it would be a guess.
|
||||
if (!fields || fields.includes(field)) return "supplies";
|
||||
if (field === "cover" || field === "audioCover") return "otherShape";
|
||||
return "never";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user