Introduce "sources" util class

This commit is contained in:
schroda
2025-04-21 17:00:13 +02:00
parent 633f58b563
commit 4a9f90b746
11 changed files with 67 additions and 56 deletions

View File

@@ -31,6 +31,8 @@ import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts'; import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
import { Sources } from '@/modules/source/services/Sources.ts';
import { SourceIdInfo } from '@/modules/source/Source.types.ts';
type SourceLoadingState = { isLoading: boolean; hasResults: boolean; emptySearch: boolean }; type SourceLoadingState = { isLoading: boolean; hasResults: boolean; emptySearch: boolean };
type SourceToLoadingStateMap = Map<string, SourceLoadingState>; type SourceToLoadingStateMap = Map<string, SourceLoadingState>;
@@ -62,8 +64,8 @@ const compareSourceByName = (
}; };
const compareSourcesBySearchResult = ( const compareSourcesBySearchResult = (
sourceA: Pick<SourceType, 'id'>, sourceA: SourceIdInfo,
sourceB: Pick<SourceType, 'id'>, sourceB: SourceIdInfo,
sourceToFetchedStateMap: SourceToLoadingStateMap, sourceToFetchedStateMap: SourceToLoadingStateMap,
): -1 | 0 | 1 => { ): -1 | 0 | 1 => {
const isSourceAFetched = !sourceToFetchedStateMap.get(sourceA.id)?.isLoading; const isSourceAFetched = !sourceToFetchedStateMap.get(sourceA.id)?.isLoading;
@@ -101,7 +103,7 @@ const SourceSearchPreview = React.memo(
}: { }: {
source: Pick<SourceType, 'id' | 'displayName' | 'lang'>; source: Pick<SourceType, 'id' | 'displayName' | 'lang'>;
onSearchRequestFinished: ( onSearchRequestFinished: (
source: Pick<SourceType, 'id'>, source: SourceIdInfo,
isLoading: boolean, isLoading: boolean,
hasResults: boolean, hasResults: boolean,
emptySearch: boolean, emptySearch: boolean,
@@ -217,7 +219,7 @@ export const SearchAll: React.FC = () => {
const sourcesSortedByName = useMemo(() => [...sources].sort(compareSourceByName), [sources]); const sourcesSortedByName = useMemo(() => [...sources].sort(compareSourceByName), [sources]);
const sourcesFilteredByLang = useMemo( const sourcesFilteredByLang = useMemo(
() => sourcesSortedByName.filter((source) => shownLangs.includes(source.lang) || Number(source.id) === 0), () => sourcesSortedByName.filter((source) => shownLangs.includes(source.lang) || Sources.isLocalSource(source)),
[sourcesSortedByName, shownLangs], [sourcesSortedByName, shownLangs],
); );
const sourcesFilteredByNsfw = useMemo( const sourcesFilteredByNsfw = useMemo(
@@ -233,7 +235,7 @@ export const SearchAll: React.FC = () => {
); );
const updateSourceLoadingState = useCallback( const updateSourceLoadingState = useCallback(
({ id }: Pick<SourceType, 'id'>, isLoading: boolean, hasResults: boolean, emptySearch: boolean) => { ({ id }: SourceIdInfo, isLoading: boolean, hasResults: boolean, emptySearch: boolean) => {
setSourceToLoadingStateMap((currentMap) => { setSourceToLoadingStateMap((currentMap) => {
const mapCopy = new Map(currentMap); const mapCopy = new Map(currentMap);
mapCopy.set(id, { isLoading, hasResults, emptySearch }); mapCopy.set(id, { isLoading, hasResults, emptySearch });

View File

@@ -153,8 +153,7 @@ function getSourceName(source?: Pick<SourceType, 'id' | 'displayName'> | null):
return translate('global.label.unknown'); return translate('global.label.unknown');
} }
const isLocalSource = Number(source.id) === 0; if (Sources.isLocalSource(source)) {
if (isLocalSource) {
return translate('source.local_source.title'); return translate('source.local_source.title');
} }

View File

@@ -24,9 +24,9 @@ import { extractOriginalKey, getMetadataKey } from '@/modules/metadata/Metadata.
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts'; import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
import { ChapterIdInfo } from '@/modules/chapter/services/Chapters.ts'; import { ChapterIdInfo } from '@/modules/chapter/services/Chapters.ts';
import { CategoryIdInfo } from '@/modules/category/Category.types.ts'; import { CategoryIdInfo } from '@/modules/category/Category.types.ts';
import { SourceType } from '@/lib/graphql/generated/graphql.ts';
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
import { getMetadataDeleteFunction, getMetadataUpdateFunction } from '@/modules/metadata/services/MetadataUpdater.ts'; import { getMetadataDeleteFunction, getMetadataUpdateFunction } from '@/modules/metadata/services/MetadataUpdater.ts';
import { SourceIdInfo } from '@/modules/source/Source.types.ts';
const getAppKeyPrefixForMigration = (migrationId: number): string => { const getAppKeyPrefixForMigration = (migrationId: number): string => {
const appKeyPrefix = METADATA_MIGRATIONS.slice(0, migrationId) const appKeyPrefix = METADATA_MIGRATIONS.slice(0, migrationId)
@@ -269,7 +269,7 @@ const commitMigratedMetadata = (
| (MangaIdInfo & MetadataHolder) | (MangaIdInfo & MetadataHolder)
| (ChapterIdInfo & MetadataHolder) | (ChapterIdInfo & MetadataHolder)
| (CategoryIdInfo & MetadataHolder) | (CategoryIdInfo & MetadataHolder)
| (Pick<SourceType, 'id'> & MetadataHolder) | (SourceIdInfo & MetadataHolder)
| undefined, | undefined,
migratedMetadata: Metadata, migratedMetadata: Metadata,
useEffectFn: typeof useEffect = (fn: () => void) => fn(), useEffectFn: typeof useEffect = (fn: () => void) => fn(),
@@ -334,7 +334,7 @@ export const applyMetadataMigrations = (
| (MangaIdInfo & MetadataHolder) | (MangaIdInfo & MetadataHolder)
| (ChapterIdInfo & MetadataHolder) | (ChapterIdInfo & MetadataHolder)
| (CategoryIdInfo & MetadataHolder) | (CategoryIdInfo & MetadataHolder)
| (Pick<SourceType, 'id'> & MetadataHolder), | (SourceIdInfo & MetadataHolder),
useEffectFn: typeof useEffect = (fn: () => void) => fn(), useEffectFn: typeof useEffect = (fn: () => void) => fn(),
): Metadata | undefined => { ): Metadata | undefined => {
const meta = { ...(metadataHolder?.meta ?? {}) }; const meta = { ...(metadataHolder?.meta ?? {}) };

View File

@@ -19,9 +19,9 @@ import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
import { ChapterIdInfo } from '@/modules/chapter/services/Chapters.ts'; import { ChapterIdInfo } from '@/modules/chapter/services/Chapters.ts';
import { CategoryIdInfo } from '@/modules/category/Category.types.ts'; import { CategoryIdInfo } from '@/modules/category/Category.types.ts';
import { SourceType } from '@/lib/graphql/generated/graphql.ts';
import { doesMetadataKeyExistIn, getMetadataKey } from '@/modules/metadata/Metadata.utils.ts'; import { doesMetadataKeyExistIn, getMetadataKey } from '@/modules/metadata/Metadata.utils.ts';
import { applyMetadataMigrations } from '@/modules/metadata/services/MetadataMigrations.ts'; import { applyMetadataMigrations } from '@/modules/metadata/services/MetadataMigrations.ts';
import { SourceIdInfo } from '@/modules/source/Source.types.ts';
const getMetadataValueFrom = <Key extends AppMetadataKeys, Value extends AllowedMetadataValueTypes>( const getMetadataValueFrom = <Key extends AppMetadataKeys, Value extends AllowedMetadataValueTypes>(
metadata: Metadata | undefined, metadata: Metadata | undefined,
@@ -70,7 +70,7 @@ export function getMetadataFrom<METADATA extends Partial<Metadata<AppMetadataKey
): METADATA; ): METADATA;
export function getMetadataFrom<METADATA extends Partial<Metadata<AppMetadataKeys, AllowedMetadataValueTypes>>>( export function getMetadataFrom<METADATA extends Partial<Metadata<AppMetadataKeys, AllowedMetadataValueTypes>>>(
type: 'source', type: 'source',
metadataHolder: Pick<SourceType, 'id'> & MetadataHolder, metadataHolder: SourceIdInfo & MetadataHolder,
metadataWithDefaultValues: METADATA, metadataWithDefaultValues: METADATA,
prefixes?: string[], prefixes?: string[],
useEffectFn?: typeof useEffect, useEffectFn?: typeof useEffect,
@@ -82,7 +82,7 @@ export function getMetadataFrom<METADATA extends Partial<Metadata<AppMetadataKey
| (MangaIdInfo & MetadataHolder) | (MangaIdInfo & MetadataHolder)
| (ChapterIdInfo & MetadataHolder) | (ChapterIdInfo & MetadataHolder)
| (CategoryIdInfo & MetadataHolder) | (CategoryIdInfo & MetadataHolder)
| (Pick<SourceType, 'id'> & MetadataHolder), | (SourceIdInfo & MetadataHolder),
metadataWithDefaultValues: METADATA, metadataWithDefaultValues: METADATA,
prefixes?: string[], prefixes?: string[],
useEffectFn: typeof useEffect = (fn: () => void) => fn(), useEffectFn: typeof useEffect = (fn: () => void) => fn(),

View File

@@ -7,7 +7,6 @@
*/ */
import { requestManager } from '@/lib/requests/RequestManager.ts'; import { requestManager } from '@/lib/requests/RequestManager.ts';
import { SourceType } from '@/lib/graphql/generated/graphql.ts';
import { ChapterIdInfo } from '@/modules/chapter/services/Chapters.ts'; import { ChapterIdInfo } from '@/modules/chapter/services/Chapters.ts';
import { CategoryIdInfo } from '@/modules/category/Category.types.ts'; import { CategoryIdInfo } from '@/modules/category/Category.types.ts';
import { import {
@@ -21,6 +20,7 @@ import {
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts'; import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
import { getMetadataKey } from '@/modules/metadata/Metadata.utils.ts'; import { getMetadataKey } from '@/modules/metadata/Metadata.utils.ts';
import { convertToGqlMeta } from '@/modules/metadata/services/MetadataConverter.ts'; import { convertToGqlMeta } from '@/modules/metadata/services/MetadataConverter.ts';
import { SourceIdInfo } from '@/modules/source/Source.types.ts';
const requestUpdateMetadataValue = async ( const requestUpdateMetadataValue = async (
metadataHolder: GqlMetaHolder, metadataHolder: GqlMetaHolder,
@@ -46,8 +46,7 @@ const requestUpdateMetadataValue = async (
await requestManager.setMangaMeta((metadataHolder as MangaIdInfo).id, metadataKey, value).response; await requestManager.setMangaMeta((metadataHolder as MangaIdInfo).id, metadataKey, value).response;
break; break;
case 'source': case 'source':
await requestManager.setSourceMeta((metadataHolder as Pick<SourceType, 'id'>).id, metadataKey, value) await requestManager.setSourceMeta((metadataHolder as SourceIdInfo).id, metadataKey, value).response;
.response;
break; break;
default: default:
throw new Error(`requestUpdateMetadataValue: unknown holderType "${holderType}"`); throw new Error(`requestUpdateMetadataValue: unknown holderType "${holderType}"`);
@@ -95,7 +94,7 @@ export const requestUpdateCategoryMetadata = async (
): Promise<void[]> => requestUpdateMetadata(category, 'category', keysToValues, keyPrefixes, isMetadataKey); ): Promise<void[]> => requestUpdateMetadata(category, 'category', keysToValues, keyPrefixes, isMetadataKey);
export const requestUpdateSourceMetadata = async ( export const requestUpdateSourceMetadata = async (
source: Pick<SourceType, 'id'> & GqlMetaHolder, source: SourceIdInfo & GqlMetaHolder,
keysToValue: MetadataKeyValuePair[], keysToValue: MetadataKeyValuePair[],
keyPrefixes?: string[], keyPrefixes?: string[],
isMetadataKey?: boolean, isMetadataKey?: boolean,
@@ -108,7 +107,7 @@ export const getMetadataUpdateFunction = (
| (MangaIdInfo & MetadataHolder) | (MangaIdInfo & MetadataHolder)
| (ChapterIdInfo & MetadataHolder) | (ChapterIdInfo & MetadataHolder)
| (CategoryIdInfo & MetadataHolder) | (CategoryIdInfo & MetadataHolder)
| (Pick<SourceType, 'id'> & MetadataHolder), | (SourceIdInfo & MetadataHolder),
): ((keyValuePair: MetadataKeyValuePair[], keyPrefixes?: string[], isMetadataKey?: boolean) => Promise<void[]>) => { ): ((keyValuePair: MetadataKeyValuePair[], keyPrefixes?: string[], isMetadataKey?: boolean) => Promise<void[]>) => {
switch (type) { switch (type) {
case 'global': case 'global':
@@ -135,7 +134,7 @@ export const getMetadataUpdateFunction = (
return (...args) => return (...args) =>
requestUpdateSourceMetadata( requestUpdateSourceMetadata(
{ {
id: (metadataHolder as Pick<SourceType, 'id'>).id, id: (metadataHolder as SourceIdInfo).id,
meta: convertToGqlMeta(metadataHolder.meta), meta: convertToGqlMeta(metadataHolder.meta),
}, },
...args, ...args,
@@ -168,7 +167,7 @@ export const requestDeleteMetadataValue = async (
await requestManager.deleteMangaMeta((metadataHolder as MangaIdInfo).id, metadataKey).response; await requestManager.deleteMangaMeta((metadataHolder as MangaIdInfo).id, metadataKey).response;
break; break;
case 'source': case 'source':
await requestManager.deleteSourceMeta((metadataHolder as Pick<SourceType, 'id'>).id, metadataKey).response; await requestManager.deleteSourceMeta((metadataHolder as SourceIdInfo).id, metadataKey).response;
break; break;
default: default:
throw new Error(`requestDeleteMetadataValue: unknown holderType "${holderType}"`); throw new Error(`requestDeleteMetadataValue: unknown holderType "${holderType}"`);
@@ -215,7 +214,7 @@ export const requestDeleteCategoryMetadata = async (
): Promise<void[]> => requestDeleteMetadata(category, 'category', keys, keyPrefixes, isMetadataKey); ): Promise<void[]> => requestDeleteMetadata(category, 'category', keys, keyPrefixes, isMetadataKey);
export const requestDeleteSourceMetadata = async ( export const requestDeleteSourceMetadata = async (
source: Pick<SourceType, 'id'> & GqlMetaHolder, source: SourceIdInfo & GqlMetaHolder,
keys: AppMetadataKeys[], keys: AppMetadataKeys[],
keyPrefixes?: string[], keyPrefixes?: string[],
isMetadataKey?: boolean, isMetadataKey?: boolean,
@@ -228,7 +227,7 @@ export const getMetadataDeleteFunction = (
| (MangaIdInfo & MetadataHolder) | (MangaIdInfo & MetadataHolder)
| (ChapterIdInfo & MetadataHolder) | (ChapterIdInfo & MetadataHolder)
| (CategoryIdInfo & MetadataHolder) | (CategoryIdInfo & MetadataHolder)
| (Pick<SourceType, 'id'> & MetadataHolder), | (SourceIdInfo & MetadataHolder),
): ((metadataToDelete: AppMetadataKeys[], keyPrefixes?: string[], isMetadataKey?: boolean) => Promise<void[]>) => { ): ((metadataToDelete: AppMetadataKeys[], keyPrefixes?: string[], isMetadataKey?: boolean) => Promise<void[]>) => {
switch (type) { switch (type) {
case 'global': case 'global':
@@ -255,7 +254,7 @@ export const getMetadataDeleteFunction = (
return (...args) => return (...args) =>
requestDeleteSourceMetadata( requestDeleteSourceMetadata(
{ {
id: (metadataHolder as Pick<SourceType, 'id'>).id, id: (metadataHolder as SourceIdInfo).id,
meta: convertToGqlMeta(metadataHolder.meta), meta: convertToGqlMeta(metadataHolder.meta),
}, },
...args, ...args,

View File

@@ -10,6 +10,7 @@ import {
GetSourceBrowseQuery, GetSourceBrowseQuery,
GetSourceSettingsQuery, GetSourceSettingsQuery,
SourcePreferenceChangeInput, SourcePreferenceChangeInput,
SourceType,
} from '@/lib/graphql/generated/graphql.ts'; } from '@/lib/graphql/generated/graphql.ts';
export interface IPos { export interface IPos {
@@ -57,3 +58,5 @@ export type MultiSelectListPreferenceProps = PreferenceProps &
export type EditTextPreferenceProps = PreferenceProps & export type EditTextPreferenceProps = PreferenceProps &
ExtractByKeyValue<SourcePreferences, '__typename', 'EditTextPreference'>; ExtractByKeyValue<SourcePreferences, '__typename', 'EditTextPreference'>;
export type SourceIdInfo = Pick<SourceType, 'id'>;

View File

@@ -36,8 +36,8 @@ export const SourceCard: React.FC<IProps> = (props: IProps) => {
const isMobileWidth = MediaQuery.useIsMobileWidth(); const isMobileWidth = MediaQuery.useIsMobileWidth();
const { source, showSourceRepo } = props;
const { const {
source: {
id, id,
name, name,
lang, lang,
@@ -45,12 +45,9 @@ export const SourceCard: React.FC<IProps> = (props: IProps) => {
supportsLatest, supportsLatest,
isNsfw, isNsfw,
extension: { repo }, extension: { repo },
}, } = source;
showSourceRepo,
} = props;
const isLocalSource = Number(id) === 0; const sourceName = Sources.isLocalSource(source) ? t('source.local_source.title') : name;
const sourceName = isLocalSource ? t('source.local_source.title') : name;
return ( return (
<Card <Card

View File

@@ -34,7 +34,6 @@ import {
GetSourceBrowseQueryVariables, GetSourceBrowseQueryVariables,
GetSourceMangasFetchMutation, GetSourceMangasFetchMutation,
GetSourceMangasFetchMutationVariables, GetSourceMangasFetchMutationVariables,
SourceType,
} from '@/lib/graphql/generated/graphql.ts'; } from '@/lib/graphql/generated/graphql.ts';
import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts'; import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts';
import { useLocalStorage, useSessionStorage } from '@/modules/core/hooks/useStorage.tsx'; import { useLocalStorage, useSessionStorage } from '@/modules/core/hooks/useStorage.tsx';
@@ -44,7 +43,7 @@ import { createUpdateSourceMetadata, useGetSourceMetadata } from '@/modules/sour
import { makeToast } from '@/modules/core/utils/Toast.ts'; import { makeToast } from '@/modules/core/utils/Toast.ts';
import { GET_SOURCE_BROWSE } from '@/lib/graphql/queries/SourceQuery.ts'; import { GET_SOURCE_BROWSE } from '@/lib/graphql/queries/SourceQuery.ts';
import { TranslationKey } from '@/Base.types.ts'; import { TranslationKey } from '@/Base.types.ts';
import { IPos } from '@/modules/source/Source.types.ts'; import { IPos, SourceIdInfo } from '@/modules/source/Source.types.ts';
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
import { EmptyView } from '@/modules/core/components/placeholder/EmptyView.tsx'; import { EmptyView } from '@/modules/core/components/placeholder/EmptyView.tsx';
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx'; import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx';
@@ -53,8 +52,9 @@ import { GridLayout } from '@/modules/core/Core.types.ts';
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts'; import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
import { Sources } from '@/modules/source/services/Sources.ts';
const DEFAULT_SOURCE: Pick<SourceType, 'id'> = { id: '-1' }; const DEFAULT_SOURCE: SourceIdInfo = { id: '-1' };
const ContentTypeMenu = styled('div')(({ theme }) => ({ const ContentTypeMenu = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',
@@ -332,7 +332,7 @@ export function SourceMangas() {
); );
const message = !isLoading ? t(SOURCE_CONTENT_TYPE_TO_ERROR_MSG_KEY[contentType]) : undefined; const message = !isLoading ? t(SOURCE_CONTENT_TYPE_TO_ERROR_MSG_KEY[contentType]) : undefined;
const isLocalSource = sourceId === '0'; const isLocalSource = sourceId === Sources.LOCAL_SOURCE_ID;
const messageExtra = isLocalSource ? ( const messageExtra = isLocalSource ? (
<> <>
<span>{t('source.local_source.label.checkout')} </span> <span>{t('source.local_source.label.checkout')} </span>

View File

@@ -26,13 +26,13 @@ import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts'; import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
import { Sources as SourceService } from '@/modules/source/services/Sources.ts';
function sourceToLangList(sources: Pick<SourceType, 'id' | 'lang'>[]) { function sourceToLangList(sources: Pick<SourceType, 'id' | 'lang'>[]) {
const result = new Set<string>(); const result = new Set<string>();
sources.forEach((source) => { sources.forEach((source) => {
const isLocalSource = Number(source.id) === 0; const lang = SourceService.isLocalSource(source) ? DefaultLanguage.OTHER : source.lang;
const lang = isLocalSource ? DefaultLanguage.OTHER : source.lang;
result.add(lang); result.add(lang);
}); });
@@ -46,8 +46,7 @@ function groupByLang<Source extends Pick<SourceType, 'id' | 'name' | 'lang'>>(
const result: Record<string, Source[]> = {}; const result: Record<string, Source[]> = {};
sources.forEach((source) => { sources.forEach((source) => {
const isLocalSource = Number(source.id) === 0; const lang = SourceService.isLocalSource(source) ? DefaultLanguage.OTHER : source.lang;
const lang = isLocalSource ? DefaultLanguage.OTHER : source.lang;
result[lang] ??= []; result[lang] ??= [];
result[lang].push(source); result[lang].push(source);
@@ -146,7 +145,7 @@ export function Sources() {
.filter((source) => { .filter((source) => {
const isLangOther = lang === DefaultLanguage.OTHER; const isLangOther = lang === DefaultLanguage.OTHER;
if (isLangOther) { if (isLangOther) {
const isLocalSource = Number(source.id) === 0; const isLocalSource = SourceService.isLocalSource(source);
const isLangShown = shownLangs.includes(lang); const isLangShown = shownLangs.includes(lang);
const isLangOtherSourceShown = isLangShown || isLocalSource; const isLangOtherSourceShown = isLangShown || isLocalSource;

View File

@@ -10,8 +10,7 @@ import { useEffect, useMemo } from 'react';
import { jsonSaveParse } from '@/lib/HelperFunctions.ts'; import { jsonSaveParse } from '@/lib/HelperFunctions.ts';
import { requestUpdateSourceMetadata } from '@/modules/metadata/services/MetadataUpdater.ts'; import { requestUpdateSourceMetadata } from '@/modules/metadata/services/MetadataUpdater.ts';
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
import { SourceType } from '@/lib/graphql/generated/graphql.ts'; import { ISourceMetadata, SourceIdInfo, SourceMetadataKeys } from '@/modules/source/Source.types.ts';
import { ISourceMetadata, SourceMetadataKeys } from '@/modules/source/Source.types.ts';
import { convertFromGqlMeta } from '@/modules/metadata/services/MetadataConverter.ts'; import { convertFromGqlMeta } from '@/modules/metadata/services/MetadataConverter.ts';
import { getMetadataFrom } from '@/modules/metadata/services/MetadataReader.ts'; import { getMetadataFrom } from '@/modules/metadata/services/MetadataReader.ts';
import { import {
@@ -39,10 +38,7 @@ const convertGqlMetadataToAppMetadata = (
savedSearches: jsonSaveParse<ISourceMetadata['savedSearches']>(metadata.savedSearches as string) ?? undefined, savedSearches: jsonSaveParse<ISourceMetadata['savedSearches']>(metadata.savedSearches as string) ?? undefined,
}); });
const getMetadata = ( const getMetadata = (metaHolder: SourceIdInfo & GqlMetaHolder, useEffectFn?: typeof useEffect): ISourceMetadata =>
metaHolder: Pick<SourceType, 'id'> & GqlMetaHolder,
useEffectFn?: typeof useEffect,
): ISourceMetadata =>
convertGqlMetadataToAppMetadata( convertGqlMetadataToAppMetadata(
getMetadataFrom( getMetadataFrom(
'source', 'source',
@@ -53,10 +49,9 @@ const getMetadata = (
), ),
); );
export const getSourceMetadata = (metaHolder: Pick<SourceType, 'id'> & GqlMetaHolder): ISourceMetadata => export const getSourceMetadata = (metaHolder: SourceIdInfo & GqlMetaHolder): ISourceMetadata => getMetadata(metaHolder);
getMetadata(metaHolder);
export const useGetSourceMetadata = (metaHolder: Pick<SourceType, 'id'> & GqlMetaHolder): ISourceMetadata => { export const useGetSourceMetadata = (metaHolder: SourceIdInfo & GqlMetaHolder): ISourceMetadata => {
const metadata = getMetadata(metaHolder, useEffect); const metadata = getMetadata(metaHolder, useEffect);
return useMemo(() => metadata, [metaHolder]); return useMemo(() => metadata, [metaHolder]);
}; };
@@ -65,7 +60,7 @@ export const updateSourceMetadata = async <
MetadataKeys extends SourceMetadataKeys = SourceMetadataKeys, MetadataKeys extends SourceMetadataKeys = SourceMetadataKeys,
MetadataKey extends MetadataKeys = MetadataKeys, MetadataKey extends MetadataKeys = MetadataKeys,
>( >(
source: Pick<SourceType, 'id'> & GqlMetaHolder, source: SourceIdInfo & GqlMetaHolder,
metadataKey: MetadataKey, metadataKey: MetadataKey,
value: ISourceMetadata[MetadataKey], value: ISourceMetadata[MetadataKey],
): Promise<void[]> => ): Promise<void[]> =>
@@ -75,7 +70,7 @@ export const updateSourceMetadata = async <
export const createUpdateSourceMetadata = export const createUpdateSourceMetadata =
<Settings extends SourceMetadataKeys>( <Settings extends SourceMetadataKeys>(
source: Pick<SourceType, 'id'> & GqlMetaHolder, source: SourceIdInfo & GqlMetaHolder,
handleError: (error: any) => void = defaultPromiseErrorHandler('createUpdateSourceMetadata'), handleError: (error: any) => void = defaultPromiseErrorHandler('createUpdateSourceMetadata'),
): ((...args: OmitFirst<Parameters<typeof updateSourceMetadata<Settings>>>) => Promise<void | void[]>) => ): ((...args: OmitFirst<Parameters<typeof updateSourceMetadata<Settings>>>) => Promise<void | void[]>) =>
(metadataKey, value) => (metadataKey, value) =>

View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { SourceIdInfo } from '@/modules/source/Source.types.ts';
export class Sources {
static readonly LOCAL_SOURCE_ID = '0';
static isLocalSource(source: SourceIdInfo): boolean {
return source.id === Sources.LOCAL_SOURCE_ID;
}
}