diff --git a/src/main/cache.ts b/src/main/cache.ts index 9ec57e4..e09c87e 100644 --- a/src/main/cache.ts +++ b/src/main/cache.ts @@ -14,7 +14,6 @@ export async function setCache(api: string, data: any, query: any) { case 'recommend/resource': case 'likelist': { if (!data) return - console.log(api) db.upsert(Tables.ACCOUNT_DATA, { id: api, json: JSON.stringify(data), @@ -23,7 +22,6 @@ export async function setCache(api: string, data: any, query: any) { break } case 'song/detail': { - console.log('dsdadasdas') if (!data.songs) return const tracks = (data as FetchTracksResponse).songs.map(t => ({ id: t.id, @@ -35,10 +33,10 @@ export async function setCache(api: string, data: any, query: any) { } case 'album': { if (!data.album) return - data.album.songs = (data as FetchTracksResponse).songs + data.album.songs = data.songs db.upsert(Tables.ALBUM, { id: data.album.id, - json: JSON.stringify(data), + json: JSON.stringify(data.album), updatedAt: Date.now(), }) break @@ -63,9 +61,21 @@ export async function setCache(api: string, data: any, query: any) { } case 'artist/album': { if (!data.hotAlbums) return + db.createMany( + Tables.ALBUM, + data.hotAlbums.map((a: Album) => ({ + id: a.id, + json: JSON.stringify(a), + updatedAt: Date.now(), + })) + ) + const modifiedData = { + ...data, + hotAlbums: data.hotAlbums.map((a: Album) => a.id), + } db.upsert(Tables.ARTIST_ALBUMS, { id: data.artist.id, - json: JSON.stringify(data), + json: JSON.stringify(modifiedData), updatedAt: Date.now(), }) break @@ -113,8 +123,13 @@ export function getCache(api: string, query: any): any { case 'album': { if (isNaN(Number(query?.id))) return const data = db.find(Tables.ALBUM, query.id) - console.log(data) - if (data?.json) return JSON.parse(data.json) + if (data?.json) + return { + resourceState: true, + songs: [], + code: 200, + album: JSON.parse(data.json), + } break } case 'playlist/detail': { @@ -131,9 +146,19 @@ export function getCache(api: string, query: any): any { } case 'artist/album': { if (isNaN(Number(query?.id))) return - const data = db.find(Tables.ARTIST_ALBUMS, query.id) - if (data?.json) return JSON.parse(data.json) - break + + const artistAlbumsRaw = db.find(Tables.ARTIST_ALBUMS, query.id) + if (!artistAlbumsRaw?.json) return + const artistAlbums = JSON.parse(artistAlbumsRaw.json) + + const albumsRaw = db.findMany(Tables.ALBUM, artistAlbums.hotAlbums) + if (albumsRaw.length !== artistAlbums.hotAlbums.length) return + const albums = albumsRaw.map(a => JSON.parse(a.json)) + + artistAlbums.hotAlbums = artistAlbums.hotAlbums.map((id: number) => + albums.find(a => a.id === id) + ) + return artistAlbums } } } diff --git a/src/main/database.ts b/src/main/database.ts deleted file mode 100644 index 61b3f9b..0000000 --- a/src/main/database.ts +++ /dev/null @@ -1,125 +0,0 @@ -import Realm from 'realm' -import path from 'path' -import { app, ipcMain } from 'electron' -import fs from 'fs' - -export enum ModelNames { - ACCOUNT_DATA = 'AccountData', - TRACK = 'Track', - ALBUM = 'Album', - ARTIST = 'Artist', - PLAYLIST = 'Playlist', - ARTIST_ALBUMS = 'ArtistAlbums', - USER_PLAYLISTS = 'UserPlaylists', - AUDIO = 'Audio', -} - -export enum AudioSources { - NETEASE = 'netease', - KUWO = 'kuwo', - QQ = 'qq', - KUGOU = 'kugou', - YOUTUBE = 'youtube', - MIGU = 'migu', - JOOX = 'joox', - BILIBILI = 'bilibili', -} - -const RegularSchemas = [ - ModelNames.USER_PLAYLISTS, - ModelNames.ARTIST_ALBUMS, - ModelNames.PLAYLIST, - ModelNames.ALBUM, - ModelNames.TRACK, - ModelNames.ARTIST, -].map(name => ({ - primaryKey: 'id', - name, - properties: { - id: 'int', - json: 'string', - updateAt: 'int', - }, -})) - -export const realm = new Realm({ - path: path.resolve(app.getPath('userData'), './api_cache/db.realm'), - shouldCompactOnLaunch: (totalSize, usedSize) => { - console.log(totalSize, usedSize) - return true - }, - schema: [ - ...RegularSchemas, - { - name: ModelNames.ACCOUNT_DATA, - properties: { - id: 'string', - json: 'string', - updateAt: 'int', - }, - primaryKey: 'id', - }, - { - name: ModelNames.AUDIO, - properties: { - id: 'int', - br: 'int', - type: 'string', - source: 'string', - updateAt: 'int', - }, - primaryKey: 'id', - }, - ], -}) - -export const db = { - get: (model: ModelNames, key: number | string) => { - return realm.objectForPrimaryKey(model, key) - }, - set: (model: ModelNames, key: number | string, value: any) => { - realm.write(() => { - realm.create( - model, - { - id: key, - updateAt: Date.now(), - json: JSON.stringify(value), - }, - 'modified' - ) - }) - }, - batchSet: (model: ModelNames, items: any[]) => { - realm.write(() => { - items.forEach(item => { - realm.create(model, item, 'modified') - }) - }) - }, - delete: (model: ModelNames, key: number) => { - realm.delete(realm.objectForPrimaryKey(model, key)) - }, -} - -ipcMain.on('test', () => { - ;[ - ModelNames.USER_PLAYLISTS, - ModelNames.ARTIST_ALBUMS, - ModelNames.PLAYLIST, - ModelNames.ALBUM, - ModelNames.TRACK, - ModelNames.ARTIST, - ModelNames.AUDIO, - ModelNames.ACCOUNT_DATA, - ].forEach(name => { - const data = realm.objects(name) - - fs.writeFile(`./tmp/${name}.json`, JSON.stringify(data), function (err) { - if (err) { - return console.log(err) - } - console.log('The file was saved!') - }) - }) -}) diff --git a/src/main/db.ts b/src/main/db.ts index ae17991..122642d 100644 --- a/src/main/db.ts +++ b/src/main/db.ts @@ -9,7 +9,6 @@ export enum Tables { ARTIST = 'artist', PLAYLIST = 'playlist', ARTIST_ALBUMS = 'artist_album', - USER_PLAYLISTS = 'user_playlist', // Special tables ACCOUNT_DATA = 'account_data', @@ -19,6 +18,19 @@ export enum Tables { const sqlite = new SQLite3( path.resolve(app.getPath('userData'), './api_cache/db.sqlite') ) +sqlite.pragma('auto_vacuum = FULL') + +// Init tables if not exist +const trackTable = sqlite + .prepare("SELECT * FROM sqlite_master WHERE name='track' and type='table'") + .get() +if (!trackTable) { + const migration = fs.readFileSync( + path.join(process.cwd(), './src/main/migrations/init.sql'), + 'utf8' + ) + sqlite.exec(migration) +} export const db = { find: (table: Tables, key: number | string) => { @@ -33,6 +45,24 @@ export const db = { findAll: (table: Tables) => { return sqlite.prepare(`SELECT * FROM ${table}`).all() }, + create: (table: Tables, data: any, skipWhenExist: boolean = true) => { + if (skipWhenExist && db.find(table, data.id)) return + return sqlite.prepare(`INSERT INTO ${table} VALUES (?)`).run(data) + }, + createMany: (table: Tables, data: any[], skipWhenExist: boolean = true) => { + const valuesQuery = Object.keys(data[0]) + .map(key => `:${key}`) + .join(', ') + const insert = sqlite.prepare( + `INSERT ${ + skipWhenExist ? 'OR IGNORE' : '' + } INTO ${table} VALUES (${valuesQuery})` + ) + const insertMany = sqlite.transaction((rows: any[]) => { + rows.forEach((row: any) => insert.run(row)) + }) + insertMany(data) + }, upsert: (table: Tables, data: any) => { const valuesQuery = Object.keys(data) .map(key => `:${key}`) @@ -63,26 +93,32 @@ export const db = { truncate: (table: Tables) => { return sqlite.prepare(`DELETE FROM ${table}`).run() }, + vacuum: () => { + return sqlite.prepare('VACUUM').run() + }, } -ipcMain.on('db-export-json', () => { - const tables = [ - Tables.ARTIST_ALBUMS, - Tables.PLAYLIST, - Tables.ALBUM, - Tables.TRACK, - Tables.ARTIST, - Tables.AUDIO, - Tables.ACCOUNT_DATA, - ] - tables.forEach(table => { - const data = db.findAll(table) +// 导出tables到json文件,方便查看table大小 +if (process.env.NODE_ENV === 'development') { + ipcMain.on('db-export-json', () => { + const tables = [ + Tables.ARTIST_ALBUMS, + Tables.PLAYLIST, + Tables.ALBUM, + Tables.TRACK, + Tables.ARTIST, + Tables.AUDIO, + Tables.ACCOUNT_DATA, + ] + tables.forEach(table => { + const data = db.findAll(table) - fs.writeFile(`./tmp/${table}.json`, JSON.stringify(data), function (err) { - if (err) { - return console.log(err) - } - console.log('The file was saved!') + fs.writeFile(`./tmp/${table}.json`, JSON.stringify(data), function (err) { + if (err) { + return console.log(err) + } + console.log('The file was saved!') + }) }) }) -}) +} diff --git a/src/main/ipcMain.ts b/src/main/ipcMain.ts new file mode 100644 index 0000000..3299928 --- /dev/null +++ b/src/main/ipcMain.ts @@ -0,0 +1,17 @@ +import { ipcMain } from 'electron' +import { db, Tables } from './db' + +export enum Events { + ClearAPICache = 'clear-api-cache', +} + +ipcMain.on(Events.ClearAPICache, () => { + db.truncate(Tables.TRACK) + db.truncate(Tables.ALBUM) + db.truncate(Tables.ARTIST) + db.truncate(Tables.PLAYLIST) + db.truncate(Tables.ARTIST_ALBUMS) + db.truncate(Tables.ACCOUNT_DATA) + db.truncate(Tables.AUDIO) + db.vacuum() +}) diff --git a/src/main/migrations/init.sql b/src/main/migrations/init.sql new file mode 100644 index 0000000..489f477 --- /dev/null +++ b/src/main/migrations/init.sql @@ -0,0 +1,7 @@ +CREATE TABLE "artist" ("id" integer NOT NULL,"json" text NOT NULL,"updatedAt" int NOT NULL, PRIMARY KEY (id)); +CREATE TABLE "album" ("id" integer NOT NULL,"json" text NOT NULL,"updatedAt" int NOT NULL, PRIMARY KEY (id)); +CREATE TABLE "playlist" ("id" integer NOT NULL,"json" text NOT NULL,"updatedAt" int NOT NULL, PRIMARY KEY (id)); +CREATE TABLE "track" ("id" integer NOT NULL,"json" text NOT NULL,"updatedAt" int NOT NULL, PRIMARY KEY (id)); +CREATE TABLE "artist_album" ("id" integer NOT NULL,"json" text NOT NULL,"updatedAt" int NOT NULL, PRIMARY KEY (id)); +CREATE TABLE "audio" ("id" integer NOT NULL,"br" int NOT NULL,"type" text NOT NULL,"srouce" text NOT NULL,"updateAt" int NOT NULL, PRIMARY KEY (id)); +CREATE TABLE "account_data" ("id" text NOT NULL,"json" text NOT NULL,"updateAt" int NOT NULL, PRIMARY KEY (id)); diff --git a/src/renderer/components/Topbar.tsx b/src/renderer/components/Topbar.tsx index 11c656e..1b8f0f2 100644 --- a/src/renderer/components/Topbar.tsx +++ b/src/renderer/components/Topbar.tsx @@ -56,7 +56,7 @@ const SearchBox = () => {