forked from akai/readest
Support reading progress synchronization across platforms (#34)
This commit is contained in:
@@ -26,7 +26,7 @@ export const getBaseFilename = (filename: string) => {
|
||||
return baseName;
|
||||
};
|
||||
export const INIT_BOOK_CONFIG: BookConfig = {
|
||||
lastUpdated: 0,
|
||||
updatedAt: 0,
|
||||
};
|
||||
|
||||
interface LanguageMap {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { BookConfig, BookSearchConfig, ViewSettings } from '@/types/book';
|
||||
|
||||
export const serializeConfig = (
|
||||
config: BookConfig,
|
||||
globalViewSettings: ViewSettings,
|
||||
defaultSearchConfig: BookSearchConfig,
|
||||
): string => {
|
||||
config = JSON.parse(JSON.stringify(config));
|
||||
const viewSettings = config.viewSettings as Partial<ViewSettings>;
|
||||
const searchConfig = config.searchConfig as Partial<BookSearchConfig>;
|
||||
config.viewSettings = Object.entries(viewSettings).reduce(
|
||||
(acc: Partial<Record<keyof ViewSettings, unknown>>, [key, value]) => {
|
||||
if (globalViewSettings[key as keyof ViewSettings] !== value) {
|
||||
acc[key as keyof ViewSettings] = value;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as Partial<Record<keyof ViewSettings, unknown>>,
|
||||
) as Partial<ViewSettings>;
|
||||
config.searchConfig = Object.entries(searchConfig).reduce(
|
||||
(acc: Partial<Record<keyof BookSearchConfig, unknown>>, [key, value]) => {
|
||||
if (defaultSearchConfig[key as keyof BookSearchConfig] !== value) {
|
||||
acc[key as keyof BookSearchConfig] = value;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as Partial<BookSearchConfig>,
|
||||
) as Partial<BookSearchConfig>;
|
||||
|
||||
return JSON.stringify(config);
|
||||
};
|
||||
|
||||
export const deserializeConfig = (
|
||||
str: string,
|
||||
globalViewSettings: ViewSettings,
|
||||
defaultSearchConfig: BookSearchConfig,
|
||||
): BookConfig => {
|
||||
const config = JSON.parse(str) as BookConfig;
|
||||
const { viewSettings, searchConfig } = config;
|
||||
config.viewSettings = { ...globalViewSettings, ...viewSettings };
|
||||
config.searchConfig = { ...defaultSearchConfig, ...searchConfig };
|
||||
config.updatedAt ??= Date.now();
|
||||
return config;
|
||||
};
|
||||
|
||||
export const compressConfig = (
|
||||
config: BookConfig,
|
||||
globalViewSettings: ViewSettings,
|
||||
defaultSearchConfig: BookSearchConfig,
|
||||
): string => {
|
||||
return JSON.parse(serializeConfig(config, globalViewSettings, defaultSearchConfig));
|
||||
};
|
||||
@@ -6,3 +6,15 @@ const supabaseAnonKey =
|
||||
process.env['NEXT_PUBLIC_SUPABASE_ANON_KEY'] || process.env['NEXT_PUBLIC_DEV_SUPABASE_ANON_KEY']!;
|
||||
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
|
||||
|
||||
export const createSupabaseClient = (accessToken?: string) => {
|
||||
return createClient(supabaseUrl, supabaseAnonKey, {
|
||||
global: {
|
||||
headers: accessToken
|
||||
? {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
}
|
||||
: {},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import {
|
||||
Book,
|
||||
BookConfig,
|
||||
BookFormat,
|
||||
BookNote,
|
||||
BookNoteType,
|
||||
HighlightColor,
|
||||
HighlightStyle,
|
||||
} from '@/types/book';
|
||||
import { DBBookConfig, DBBook, DBBookNote } from '@/types/records';
|
||||
|
||||
export const transformBookConfigToDB = (bookConfig: unknown, userId: string): DBBookConfig => {
|
||||
const { bookHash, progress, location, searchConfig, viewSettings, updatedAt } =
|
||||
bookConfig as BookConfig;
|
||||
|
||||
return {
|
||||
user_id: userId,
|
||||
book_hash: bookHash!,
|
||||
location: location,
|
||||
progress: progress && JSON.stringify(progress),
|
||||
search_config: searchConfig && JSON.stringify(searchConfig),
|
||||
view_settings: viewSettings && JSON.stringify(viewSettings),
|
||||
updated_at: new Date(updatedAt).toISOString(),
|
||||
};
|
||||
};
|
||||
|
||||
export const transformBookConfigFromDB = (dbBookConfig: DBBookConfig): BookConfig => {
|
||||
const { book_hash, progress, location, search_config, view_settings, updated_at } = dbBookConfig;
|
||||
return {
|
||||
bookHash: book_hash,
|
||||
location,
|
||||
progress: progress && JSON.parse(progress),
|
||||
searchConfig: search_config && JSON.parse(search_config),
|
||||
viewSettings: view_settings && JSON.parse(view_settings),
|
||||
updatedAt: new Date(updated_at!).getTime(),
|
||||
} as BookConfig;
|
||||
};
|
||||
|
||||
export const transformBookToDB = (book: unknown, userId: string): DBBook => {
|
||||
const { hash, format, title, author, group, tags, createdAt, updatedAt, deletedAt } =
|
||||
book as Book;
|
||||
|
||||
return {
|
||||
user_id: userId,
|
||||
book_hash: hash,
|
||||
format,
|
||||
title,
|
||||
author,
|
||||
group,
|
||||
tags: tags && JSON.stringify(tags),
|
||||
created_at: new Date(createdAt).toISOString(),
|
||||
updated_at: new Date(updatedAt).toISOString(),
|
||||
deleted_at: deletedAt ? new Date(deletedAt).toISOString() : undefined,
|
||||
};
|
||||
};
|
||||
|
||||
export const transformBookFromDB = (dbBook: DBBook): Book => {
|
||||
const { book_hash, format, title, author, group, tags, created_at, updated_at, deleted_at } =
|
||||
dbBook;
|
||||
|
||||
return {
|
||||
hash: book_hash,
|
||||
format: format as BookFormat,
|
||||
title,
|
||||
author,
|
||||
group,
|
||||
tags: tags && JSON.parse(tags),
|
||||
createdAt: new Date(created_at!).getTime(),
|
||||
updatedAt: new Date(updated_at!).getTime(),
|
||||
deletedAt: deleted_at ? new Date(deleted_at!).getTime() : undefined,
|
||||
};
|
||||
};
|
||||
|
||||
export const transformBookNoteToDB = (bookNote: unknown, userId: string): DBBookNote => {
|
||||
const { bookHash, id, type, cfi, text, style, color, note, createdAt, updatedAt, deletedAt } =
|
||||
bookNote as BookNote;
|
||||
|
||||
return {
|
||||
user_id: userId,
|
||||
book_hash: bookHash!,
|
||||
id,
|
||||
type,
|
||||
cfi,
|
||||
text,
|
||||
style,
|
||||
color,
|
||||
note,
|
||||
created_at: new Date(createdAt).toISOString(),
|
||||
updated_at: new Date(updatedAt).toISOString(),
|
||||
deleted_at: deletedAt ? new Date(deletedAt).toISOString() : undefined,
|
||||
};
|
||||
};
|
||||
|
||||
export const transformBookNoteFromDB = (dbBookNote: DBBookNote): BookNote => {
|
||||
const { book_hash, id, type, cfi, text, style, color, note, created_at, updated_at, deleted_at } =
|
||||
dbBookNote;
|
||||
|
||||
return {
|
||||
bookHash: book_hash,
|
||||
id,
|
||||
type: type as BookNoteType,
|
||||
cfi,
|
||||
text,
|
||||
style: style as HighlightStyle,
|
||||
color: color as HighlightColor,
|
||||
note,
|
||||
createdAt: new Date(created_at!).getTime(),
|
||||
updatedAt: new Date(updated_at!).getTime(),
|
||||
deletedAt: deleted_at ? new Date(deleted_at!).getTime() : undefined,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user