feat: emojis import

This commit is contained in:
syuilo
2022-01-13 00:47:40 +09:00
parent 1f2dab0a83
commit 7e5e763584
6 changed files with 205 additions and 9 deletions

View File

@ -52,7 +52,7 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi
});
};
await writeMeta(`{"metaVersion":1,"emojis":[`);
await writeMeta(`{"metaVersion":2,"emojis":[`);
const customEmojis = await Emojis.find({
where: {
@ -64,9 +64,9 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi
});
for (const emoji of customEmojis) {
const exportId = ulid().toLowerCase();
const ext = mime.extension(emoji.type);
const emojiPath = path + '/' + exportId + (ext ? '.' + ext : '');
const fileName = emoji.name + (ext ? '.' + ext : '');
const emojiPath = path + '/' + fileName;
fs.writeFileSync(emojiPath, '', 'binary');
let downloaded = false;
@ -77,8 +77,12 @@ export async function exportCustomEmojis(job: Bull.Job, done: () => void): Promi
logger.error(e);
}
if (!downloaded) {
fs.unlinkSync(emojiPath);
}
const content = JSON.stringify({
id: exportId,
fileName: fileName,
downloaded: downloaded,
emoji: emoji,
});

View File

@ -0,0 +1,84 @@
import * as Bull from 'bull';
import * as tmp from 'tmp';
import * as fs from 'fs';
const unzipper = require('unzipper');
import { getConnection } from 'typeorm';
import { queueLogger } from '../../logger';
import { downloadUrl } from '@/misc/download-url';
import { DriveFiles, Emojis } from '@/models/index';
import { DbUserImportJobData } from '@/queue/types';
import addFile from '@/services/drive/add-file';
import { genId } from '@/misc/gen-id';
const logger = queueLogger.createSubLogger('import-custom-emojis');
// TODO: 名前衝突時の動作を選べるようにする
export async function importCustomEmojis(job: Bull.Job<DbUserImportJobData>, done: any): Promise<void> {
logger.info(`Importing custom emojis ...`);
const file = await DriveFiles.findOne({
id: job.data.fileId,
});
if (file == null) {
done();
return;
}
// Create temp dir
const [path, cleanup] = await new Promise<[string, () => void]>((res, rej) => {
tmp.dir((e, path, cleanup) => {
if (e) return rej(e);
res([path, cleanup]);
});
});
logger.info(`Temp dir is ${path}`);
const destPath = path + '/emojis.zip';
try {
fs.writeFileSync(destPath, '', 'binary');
await downloadUrl(file.url, destPath);
} catch (e) { // TODO: 何度か再試行
logger.error(e);
throw e;
}
const outputPath = path + '/emojis';
const unzipStream = fs.createReadStream(destPath);
const extractor = unzipper.Extract({ path: outputPath });
extractor.on('close', async () => {
const metaRaw = fs.readFileSync(outputPath + '/meta.json', 'utf-8');
const meta = JSON.parse(metaRaw);
for (const record of meta.emojis) {
if (!record.downloaded) continue;
const emojiInfo = record.emoji;
const emojiPath = outputPath + '/' + record.fileName;
await Emojis.delete({
name: emojiInfo.name,
});
const driveFile = await addFile(null, emojiPath, record.fileName, null, null, true);
const emoji = await Emojis.insert({
id: genId(),
updatedAt: new Date(),
name: emojiInfo.name,
category: emojiInfo.category,
host: null,
aliases: emojiInfo.aliases,
url: driveFile.url,
type: driveFile.type,
}).then(x => Emojis.findOneOrFail(x.identifiers[0]));
}
await getConnection().queryResultCache!.remove(['meta_emojis']);
cleanup();
logger.succ('Imported');
done();
});
unzipStream.pipe(extractor);
logger.succ(`Unzipping to ${outputPath}`);
}

View File

@ -12,6 +12,7 @@ import { importUserLists } from './import-user-lists';
import { deleteAccount } from './delete-account';
import { importMuting } from './import-muting';
import { importBlocking } from './import-blocking';
import { importCustomEmojis } from './import-custom-emojis';
const jobs = {
deleteDriveFiles,
@ -25,6 +26,7 @@ const jobs = {
importMuting,
importBlocking,
importUserLists,
importCustomEmojis,
deleteAccount,
} as Record<string, Bull.ProcessCallbackFunction<DbJobData> | Bull.ProcessPromiseFunction<DbJobData>>;