Skip to content

Commit

Permalink
Merge pull request #120 from mebtte/beta
Browse files Browse the repository at this point in the history
import music by tags
  • Loading branch information
MEBTTE authored Mar 8, 2024
2 parents 9a4a693 + dc058ca commit 4befcf5
Show file tree
Hide file tree
Showing 62 changed files with 656 additions and 695 deletions.
10 changes: 10 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ extends:
- plugin:react/recommended
- plugin:react-hooks/recommended
- prettier
settings:
react:
version: "detect"
parserOptions:
ecmaVersion: latest
sourceType: module
Expand All @@ -20,5 +23,12 @@ rules:
"@typescript-eslint/no-unsafe-argument": off
"@typescript-eslint/explicit-function-return-type": off
"@typescript-eslint/promise-function-async": off
"@typescript-eslint/strict-boolean-expressions": off
"@typescript-eslint/consistent-type-imports": off
"@typescript-eslint/no-misused-promises": off
"@typescript-eslint/no-non-null-assertion": off
"@typescript-eslint/no-floating-promises": off
"@typescript-eslint/array-type": off
"@typescript-eslint/prefer-nullish-coalescing": off

"react/react-in-jsx-scope": off
5 changes: 1 addition & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"files.exclude": {
"**/design": true
}
"typescript.tsdk": "node_modules/typescript/lib"
}
9 changes: 7 additions & 2 deletions apps/cli/dev_server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'path';
import startServer from './src/commands/start_server';
import exitWithMessage from './src/utils/exit_with_message';
import { Mode } from './src/config';
import { DEFAULT_CONFIG, Mode } from './src/config';

const data = process.env.CICADA_DATA;
if (!data) {
Expand All @@ -12,4 +12,9 @@ if (!data) {
const absoluteData = path.isAbsolute(data!)
? data!
: path.resolve(process.cwd(), data!);
startServer({ mode: Mode.DEVELOPMENT, port: 8000, data: absoluteData });
startServer({
mode: Mode.DEVELOPMENT,
port: 8000,
data: absoluteData,
jwtExpiry: DEFAULT_CONFIG.jwtExpiry,
});
6 changes: 2 additions & 4 deletions apps/cli/src/commands/fix_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,11 @@ export default async ({ data }: { data: string }) => {
let spinner: Spinner;

// eslint-disable-next-line prefer-const
spinner = createSpinner();
spinner.start({ text: "Fixing music's year..." });
spinner = createSpinner().start({ text: "Fixing music's year..." });
await fixMusicYear();
spinner.success({ text: "Music's year has fixed" });

spinner = createSpinner();
spinner.start({ text: 'Fixing DB snapshots...' });
spinner = createSpinner().start({ text: 'Fixing DB snapshots...' });
await fixDBSnapshots();
spinner.success({ text: 'DB snapshots have fixed' });

Expand Down
109 changes: 62 additions & 47 deletions apps/cli/src/commands/import_music.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,13 @@ import {
MusicSingerRelationProperty,
} from '@/constants/db_definition';
import { getAssetDirectory, updateConfig } from '../config';

/**
* 文件格式, singer1,singer2 - name.format
* @author mebtte<[email protected]>
*/
const MATCH_FILENAME = /^((([^,]+)(,?))+)(\s+)-(\s+)(.+)\.(\S+)$/;
import getMusicFileMetadata, {
Metadata,
} from '#/utils/get_music_file_metadata';

let successful = 0;
let ignored = 0;

/**
* 合并多个空格以及移除头尾空格
* @author mebtte<[email protected]>
*/
function handleSpace(s: string) {
return s.replace(/\s+/g, ' ').trim();
}

/**
* 检查音乐是否已存在
* @author mebtte<[email protected]>
Expand All @@ -58,7 +47,7 @@ async function checkMusicExist({
>(
`
SELECT
${MusicProperty.ID},
${MusicProperty.ID},
${MusicProperty.NAME}
FROM ${MUSIC_TABLE_NAME}
WHERE ${MusicProperty.NAME} = ?
Expand Down Expand Up @@ -88,7 +77,7 @@ async function checkMusicExist({
}

async function importFile(
file: string,
filepath: string,
{
skipExistenceCheck,
uid,
Expand All @@ -97,46 +86,38 @@ async function importFile(
uid: string;
},
) {
const spinner = createSpinner(file);
spinner.start();

/**
* 检查文件名
* @author mebtte<[email protected]>
*/
if (!MATCH_FILENAME.test(path.parse(file).base)) {
ignored += 1;
return spinner.warn({
text: `[ ${file} ] isn't a valid filename, ignored`,
});
}
const spinner = createSpinner(filepath).start();

/**
* 检查文件类型
* @author mebtte<[email protected]>
*/
const ft = await fileType.fromFile(file);
const ft = await fileType.fromFile(filepath);
const { acceptTypes } = ASSET_TYPE_MAP[AssetType.MUSIC];
if (ft && acceptTypes.includes(ft.mime)) {
const [singerString, originalName] = path.parse(file).name.split(' - ');
const name = handleSpace(originalName);
const singers = singerString
.split(',')
.map((s) => handleSpace(s))
.filter((s) => s.length > 0);

let musicTag: Metadata;
try {
musicTag = await getMusicFileMetadata(filepath);
} catch (error) {
ignored += 1;
return spinner.warn({
text: `[ ${filepath} ] can not be parsed and been ignored`,
});
}
const name = musicTag.title || 'Unknown';
const singers = musicTag.artist?.split(',') || ['Unknown'];
if (!skipExistenceCheck) {
const exist = await checkMusicExist({ singers, name });
if (exist) {
ignored += 1;
return spinner.warn({
text: `[ ${file} ] has been database already and ignored, using [ --skip-existence-check ] will skip existence check`,
text: `[ ${filepath} ] has been in database already and ignored, using [ --skip-existence-check ] will skip existence check`,
});
}
}

const fileData = await fs.readFile(file);
const assetName = md5(fileData) + path.parse(file).ext;
const fileData = await fs.readFile(filepath);
const assetName = md5(fileData) + path.parse(filepath).ext;
await fs.writeFile(
`${getAssetDirectory(AssetType.MUSIC)}/${assetName}`,
fileData,
Expand Down Expand Up @@ -169,14 +150,46 @@ async function importFile(
);
}

spinner.success({
text: `[ ${file} ] imported`,
});
if (musicTag.year) {
await getDB().run(
`
UPDATE ${MUSIC_TABLE_NAME} SET ${MusicProperty.YEAR} = ?
WHERE ${MusicProperty.ID} = ?
`,
[musicTag.year, id],
);
}

if (musicTag.picture) {
const buffer = Buffer.from(
musicTag.picture.dataURI.split(',')[1],
'base64',
);
const coverFilename = `${md5(buffer)}.${
musicTag.picture.format.split('/')[1]
}`;
await Promise.all([
fs.writeFile(
`${getAssetDirectory(AssetType.MUSIC_COVER)}/${coverFilename}`,
buffer,
),
getDB().run(
`
UPDATE ${MUSIC_TABLE_NAME} SET ${MusicProperty.COVER} = ?
WHERE ${MusicProperty.ID} = ?
`,
[coverFilename, id],
),
]);
}

successful += 1;
spinner.success({
text: `[ ${filepath} ] imported`,
});
} else {
spinner.warn({ text: `[ ${file} ] isn't a valid format, ignored` });
ignored += 1;
spinner.warn({ text: `[ ${filepath} ] isn't a valid format, ignored` });
}
}

Expand Down Expand Up @@ -217,7 +230,7 @@ async function importDirectory(
}
}

export default async ({
async function importMusic({
source,
data,
uid,
Expand All @@ -229,7 +242,7 @@ export default async ({
uid: string;
recursive: boolean;
skipExistenceCheck: boolean;
}) => {
}) {
updateConfig({ data });

/**
Expand All @@ -252,4 +265,6 @@ export default async ({
text: `Successful ${successful}, ignored ${ignored}`,
});
return process.exit();
};
}

export default importMusic;
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default async (ctx: Context) => {
if (
typeof id !== 'string' ||
!id.length ||
// @ts-expect-error
// @ts-expect-error: key is unknown
!Object.values(AllowUpdateKey).includes(key)
) {
return ctx.except(ExceptionCode.WRONG_PARAMETER);
Expand Down
8 changes: 6 additions & 2 deletions apps/cli/src/commands/start_server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,31 @@ import { getFormApp } from './form_app';
import { getPwaApp } from './pwa_app';
import { getBaseApp } from './base_app';
import i18n from './middlewares/i18n';
import ms from 'ms';

function printConfig() {
const config = getConfig();
const printConfigKeys: (keyof Config)[] = ['mode', 'port', 'data'];
const printConfigKeys: Array<keyof Config> = ['mode', 'port', 'data'];
console.log('---');
for (const key of printConfigKeys) {
console.log(`${key}: ${config[key]}`);
}
console.log(`jwtExpiry: ${ms(config.jwtExpiry)}`);
console.log('---');
}

export default async ({
mode,
port,
data,
jwtExpiry,
}: {
mode: Mode;
port: number;
data: string;
jwtExpiry: number;
}) => {
updateConfig({ mode, port, data });
updateConfig({ mode, port, data, jwtExpiry });
printConfig();

await initialize();
Expand Down
29 changes: 12 additions & 17 deletions apps/cli/src/commands/upgrade_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getDB } from '@/db';
import generateRandomString from '#/utils/generate_random_string';

function dropLoginCodeSalt() {
return fs.unlinkSync(`${getConfig().data}/login_code_salt`);
return fsPromises.unlink(`${getConfig().data}/login_code_salt`);
}

function dropLoginCode() {
Expand Down Expand Up @@ -105,15 +105,15 @@ async function addUserPassword() {
}

async function addUserTwoFASecret() {
return getDB().run(
return await getDB().run(
`
ALTER TABLE user ADD twoFASecret TEXT DEFAULT NULL
`,
);
}

async function addUserTokenIdentifier() {
return getDB().run(
return await getDB().run(
`
ALTER TABLE user ADD tokenIdentifier TEXT NOT NULL DEFAULT ''
`,
Expand Down Expand Up @@ -154,38 +154,33 @@ export default async ({ data }: { data: string }) => {

let spinner: Spinner;

spinner = createSpinner();
spinner.start({ text: 'Dropping login code...' });
spinner = createSpinner().start({ text: 'Dropping login code...' });
await dropLoginCode();
spinner.success({ text: 'Login code has dropped' });

spinner = createSpinner();
spinner.start({ text: 'Dropping login code salt...' });
spinner = createSpinner().start({ text: 'Dropping login code salt...' });
await dropLoginCodeSalt();
spinner.success({ text: 'Login code salt has dropped' });

spinner = createSpinner();
spinner.start({ text: 'Renaming user.email to user.username...' });
spinner = createSpinner().start({
text: 'Renaming user.email to user.username...',
});
await renameUserEmailToUsername();
spinner.success({ text: 'user.email has renamed to user.username' });

spinner = createSpinner();
spinner.start({ text: 'Adding user.password...' });
spinner = createSpinner().start({ text: 'Adding user.password...' });
const userList = await addUserPassword();
spinner.success({ text: 'user.password has added' });

spinner = createSpinner();
spinner.start({ text: 'Adding user.twoFASecret...' });
spinner = createSpinner().start({ text: 'Adding user.twoFASecret...' });
await addUserTwoFASecret();
spinner.success({ text: 'user.twoFASecret has added' });

spinner = createSpinner();
spinner.start({ text: 'Adding user.tokenIdentifier...' });
spinner = createSpinner().start({ text: 'Adding user.tokenIdentifier...' });
await addUserTokenIdentifier();
spinner.success({ text: 'user.tokenIdentifier has added' });

spinner = createSpinner();
spinner.start({ text: 'Writting new version of data...' });
spinner = createSpinner().start({ text: 'Writting new version of data...' });
await writeNewVersion();
spinner.success({ text: 'New version of data has wrote' });

Expand Down
3 changes: 3 additions & 0 deletions apps/cli/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ export interface Config {

data: string;
port: number;

jwtExpiry: number;
}

export const DEFAULT_CONFIG: Config = {
mode: Mode.PRODUCTION,

data: `${process.cwd()}/cicada`,
port: 8000,
jwtExpiry: 1000 * 60 * 60 * 24 * 180,
};

let config: Config = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
Expand Down
Loading

0 comments on commit 4befcf5

Please sign in to comment.