mirror of https://github.com/Nofated095/Q2TG.git
feat: 将消息转换为 whatsapp 格式
This commit is contained in:
parent
ca13bafb96
commit
8890eb2300
|
@ -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",
|
||||
|
|
|
@ -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('转换成功');
|
||||
})();
|
|
@ -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;
|
||||
}
|
16
yarn.lock
16
yarn.lock
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue