feat: 将消息转换为 whatsapp 格式

This commit is contained in:
Clansty 2022-03-08 13:18:34 +08:00
parent ca13bafb96
commit 8890eb2300
No known key found for this signature in database
GPG Key ID: 05F8479BA63A8E92
4 changed files with 143 additions and 1 deletions

View File

@ -5,9 +5,11 @@
"dev": "ts-node src/index.ts",
"build": "tsc",
"start": "prisma db push --accept-data-loss && node build/index.js",
"prisma": "prisma"
"prisma": "prisma",
"convert": "ts-node tools/convert"
},
"devDependencies": {
"@types/date-and-time": "^0.13.0",
"@types/fluent-ffmpeg": "^2",
"@types/node": "^17.0.18",
"prisma": "latest",
@ -18,6 +20,7 @@
"dependencies": {
"@prisma/client": "latest",
"axios": "^0.26.0",
"date-and-time": "^2.2.1",
"eviltransform": "^0.2.2",
"file-type": "^17.1.1",
"fluent-ffmpeg": "^2.1.2",

102
tools/convert/index.ts Normal file
View File

@ -0,0 +1,102 @@
import fsP from 'fs/promises';
import fs from 'fs';
import path from 'path';
import { Message } from './types';
import OicqClient from '../../src/client/OicqClient';
import { Platform } from 'oicq';
import { fetchFile } from '../../src/utils/urls';
import { md5Hex } from '../../src/utils/hashing';
import { format } from 'date-and-time';
import axios from 'axios';
(async () => {
const selfId = Number(process.argv[2]);
const selfName = process.argv[3];
const filePath = process.argv[4];
const outputPath = process.argv[5];
// 可选参数
const account = Number(process.argv[6]);
const password = process.argv[7];
const crvApi = process.argv[8];
const crvKey = process.argv[9];
const oicq = account && await OicqClient.create({
uin: account,
password,
platform: Platform.Android,
onVerifyDevice: () => process.exit(1),
onVerifySlider: () => process.exit(1),
onQrCode: () => process.exit(1),
});
const content = JSON.parse(await fsP.readFile(filePath, 'utf-8')) as Message[];
if (!fs.existsSync(outputPath)) {
await fsP.mkdir(outputPath);
}
const txt = fs.createWriteStream(path.join(outputPath, 'WhatsApp Chat with Cat.txt'), 'utf-8');
content.sort((a, b) => a.time - b.time);
console.log('count:', content.length);
console.log('files:', content.filter(it => it.file?.type?.startsWith('image/')).length);
for (const message of content) {
let sender = message.senderId === selfId ? selfName : message.username;
if (message.system) sender = '系统';
const date = new Date(message.time);
if (message.file) {
if (message.file.type.startsWith('image/')) {
try {
let file: Buffer;
if (message.file.url.startsWith('data:image')) {
const base64Data = message.file.url.replace(/^data:image\/\w+;base64,/, '');
file = Buffer.from(base64Data, 'base64');
}
else {
file = await fetchFile(message.file.url);
}
const md5 = md5Hex(file);
await fsP.writeFile(path.join(outputPath, `IMG-${md5}.jpg`), file);
txt.write(`${format(date, 'DD/MM/YYYY, HH:mm')} - ${sender}: IMG-${md5}.jpg (file attached)\n`);
process.stdout.write('.');
}
catch (e) {
process.stdout.write('x');
txt.write(`${format(date, 'DD/MM/YYYY, HH:mm')} - ${sender}: ${message.file.url}\n`);
}
}
else {
txt.write(`${format(date, 'DD/MM/YYYY, HH:mm')} - ${sender}: 文件: ${message.file.name}\n` +
`${message.file.type}\n${message.file.url}\n`);
}
}
if (message.content) {
const FORWARD_REGEX = /\[Forward: ([A-Za-z0-9\/+=]+)]/;
if (FORWARD_REGEX.test(message.content) && oicq) {
try {
const resId = FORWARD_REGEX.exec(message.content)[1];
const record = await oicq.getForwardMsg(resId);
const hash = md5Hex(resId);
await axios.post(`${crvApi}/add`, {
auth: crvKey,
key: hash,
data: record,
});
txt.write(`${format(date, 'DD/MM/YYYY, HH:mm')} - ${sender}: 转发的消息记录 ${crvApi}/?hash=${hash}\n`);
process.stdout.write('w');
}
catch (e) {
process.stdout.write('v');
}
txt.write(`${format(date, 'DD/MM/YYYY, HH:mm')} - ${sender}: 转发的消息记录\n`);
}
else {
txt.write(`${format(date, 'DD/MM/YYYY, HH:mm')} - ${sender}: ${message.content}\n`);
}
}
}
txt.end();
await oicq.logout(false);
console.log('转换成功');
})();

21
tools/convert/types.d.ts vendored Normal file
View File

@ -0,0 +1,21 @@
export interface Message {
senderId?: number;
username: string;
content: string;
system: boolean;
file?: {
type: string
url: string
size?: number
name?: string
fid?: string
};
files: {
type: string
url: string
size?: number
name?: string
fid?: string
}[];
time: number;
}

View File

@ -125,6 +125,13 @@ __metadata:
languageName: node
linkType: hard
"@types/date-and-time@npm:^0.13.0":
version: 0.13.0
resolution: "@types/date-and-time@npm:0.13.0"
checksum: a430aaaa77479746b026295ee6dab19497cc838f7a575569e3a2304841396e1aeba431bc528a86ffce037c12e371f0f4847085f6c99117f8c5809a97560f2971
languageName: node
linkType: hard
"@types/fluent-ffmpeg@npm:^2":
version: 2.1.20
resolution: "@types/fluent-ffmpeg@npm:2.1.20"
@ -437,6 +444,13 @@ __metadata:
languageName: node
linkType: hard
"date-and-time@npm:^2.2.1":
version: 2.2.1
resolution: "date-and-time@npm:2.2.1"
checksum: 7b789a94b86b551f2777ccefa25a5b9964c1cf0a929044aafbef93316f324002a0454394a2810f1247693c9d8e799adde9e607d4509ff03491e3bdd1321ae636
languageName: node
linkType: hard
"date-format@npm:^4.0.3":
version: 4.0.3
resolution: "date-format@npm:4.0.3"
@ -1607,9 +1621,11 @@ __metadata:
resolution: "q2tg@workspace:."
dependencies:
"@prisma/client": latest
"@types/date-and-time": ^0.13.0
"@types/fluent-ffmpeg": ^2
"@types/node": ^17.0.18
axios: ^0.26.0
date-and-time: ^2.2.1
eviltransform: ^0.2.2
file-type: ^17.1.1
fluent-ffmpeg: ^2.1.2