rubjs 2.7.6 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -7
- package/rubjs/client.d.ts +2 -2
- package/rubjs/client.js +0 -8
- package/rubjs/index.d.ts +2 -2
- package/rubjs/index.js +2 -1
- package/rubjs/methods/chats/sendLive.js +1 -1
- package/rubjs/methods/messages/sendMessage.js +6 -2
- package/rubjs/methods/utilities/start.js +15 -1
- package/rubjs/methods/utilities/thumbnail.js +14 -43
- package/rubjs/network/index.js +23 -1
- package/rubjs/session/index.d.ts +9 -9
- package/rubjs/session/index.js +152 -45
- package/rubjs/types/decorators.d.ts +1 -0
- package/rubjs/utils/VoiceChatClient.d.ts +2 -2
- package/rubjs/utils/VoiceChatClient.js +14 -10
- package/rubjs/utils/index.d.ts +2 -1
- package/rubjs/utils/index.js +3 -1
- package/rubjs/utils/sendLiveClient.d.ts +25 -0
- package/rubjs/utils/sendLiveClient.js +146 -0
package/package.json
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
{
|
2
2
|
"name": "rubjs",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.8.0",
|
4
4
|
"main": "rubjs/index.js",
|
5
5
|
"types": "rubjs/index.d.ts",
|
6
6
|
"keywords": [
|
7
7
|
"javascript",
|
8
8
|
"Rubika",
|
9
|
-
"library"
|
9
|
+
"library",
|
10
|
+
"rubjs"
|
10
11
|
],
|
11
12
|
"module": "rubjs/index.js",
|
12
13
|
"exports": {
|
@@ -24,13 +25,9 @@
|
|
24
25
|
},
|
25
26
|
"dependencies": {
|
26
27
|
"axios": "^1.7.9",
|
27
|
-
"better-sqlite3": "^11.8.1",
|
28
|
-
"fluent-ffmpeg": "^2.1.3",
|
29
28
|
"input": "^1.0.1",
|
30
|
-
"music-metadata": "^10.9.0",
|
31
29
|
"node-rsa": "^1.1.1",
|
32
|
-
"
|
33
|
-
"wrtc": "^0.4.7",
|
30
|
+
"optional-require": "^1.1.8",
|
34
31
|
"ws": "^8.18.0"
|
35
32
|
},
|
36
33
|
"devDependencies": {
|
package/rubjs/client.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import Methods from "./methods";
|
2
2
|
import Network from "./network";
|
3
|
-
import
|
3
|
+
import SessionManager from "./session";
|
4
4
|
import { VoiceChatClient } from "./utils";
|
5
5
|
interface Platform {
|
6
6
|
app_name: string;
|
@@ -24,7 +24,7 @@ declare class Client extends Methods {
|
|
24
24
|
sessionFile: string;
|
25
25
|
platform: PlatformType;
|
26
26
|
userGuid: string | null;
|
27
|
-
sessionDb:
|
27
|
+
sessionDb: SessionManager;
|
28
28
|
initialize: boolean;
|
29
29
|
eventHandlers: {
|
30
30
|
callback: Function;
|
package/rubjs/client.js
CHANGED
@@ -34,14 +34,6 @@ class Client extends methods_1.default {
|
|
34
34
|
this.privateKey = null;
|
35
35
|
this.eventHandlers = [];
|
36
36
|
this.initialize = false;
|
37
|
-
const DBInformation = this.sessionDb.getSession();
|
38
|
-
if (DBInformation) {
|
39
|
-
this.auth = DBInformation.auth;
|
40
|
-
this.userGuid = DBInformation.guid;
|
41
|
-
this.privateKey = DBInformation.private_key;
|
42
|
-
if (typeof DBInformation.agent === "string")
|
43
|
-
this.userAgent = DBInformation.agent || this.userAgent;
|
44
|
-
}
|
45
37
|
this.start();
|
46
38
|
}
|
47
39
|
}
|
package/rubjs/index.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import Client from "./client";
|
2
2
|
import Crypto from "./crypto";
|
3
3
|
import * as Types from "./types";
|
4
|
-
import { Filters, Utils, VoiceChatClient } from "./utils";
|
4
|
+
import { Filters, Utils, VoiceChatClient, SendLiveClient } from "./utils";
|
5
5
|
export default Client;
|
6
|
-
export { Client, Crypto, Utils, VoiceChatClient, Filters, Types };
|
6
|
+
export { Client, Crypto, Utils, VoiceChatClient, Filters, Types, SendLiveClient, };
|
package/rubjs/index.js
CHANGED
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
37
37
|
};
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
39
|
-
exports.Types = exports.Filters = exports.VoiceChatClient = exports.Utils = exports.Crypto = exports.Client = void 0;
|
39
|
+
exports.SendLiveClient = exports.Types = exports.Filters = exports.VoiceChatClient = exports.Utils = exports.Crypto = exports.Client = void 0;
|
40
40
|
const client_1 = __importDefault(require("./client"));
|
41
41
|
exports.Client = client_1.default;
|
42
42
|
const crypto_1 = __importDefault(require("./crypto"));
|
@@ -47,4 +47,5 @@ const utils_1 = require("./utils");
|
|
47
47
|
Object.defineProperty(exports, "Filters", { enumerable: true, get: function () { return utils_1.Filters; } });
|
48
48
|
Object.defineProperty(exports, "Utils", { enumerable: true, get: function () { return utils_1.Utils; } });
|
49
49
|
Object.defineProperty(exports, "VoiceChatClient", { enumerable: true, get: function () { return utils_1.VoiceChatClient; } });
|
50
|
+
Object.defineProperty(exports, "SendLiveClient", { enumerable: true, get: function () { return utils_1.SendLiveClient; } });
|
50
51
|
exports.default = client_1.default;
|
@@ -15,7 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
const thumbnail_1 = __importDefault(require("../utilities/thumbnail"));
|
16
16
|
function sendLive(title_1, object_guid_1, image_1) {
|
17
17
|
return __awaiter(this, arguments, void 0, function* (title, object_guid, image, device_type = "Software") {
|
18
|
-
const thumb_inline = yield thumbnail_1.default.
|
18
|
+
const thumb_inline = yield thumbnail_1.default.fromVideo(image);
|
19
19
|
return yield this.builder("sendLive", {
|
20
20
|
thumb_inline,
|
21
21
|
device_type,
|
@@ -46,9 +46,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
46
46
|
};
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
48
48
|
const fs = __importStar(require("fs"));
|
49
|
-
const
|
49
|
+
const optional_require_1 = require("optional-require");
|
50
50
|
const utilities_1 = require("../utilities");
|
51
51
|
const parser_1 = __importDefault(require("../../parser"));
|
52
|
+
const optionalMusicMetadata = (0, optional_require_1.optionalRequire)("music-metadata");
|
52
53
|
function sendMessage(object_guid_1) {
|
53
54
|
return __awaiter(this, arguments, void 0, function* (object_guid, text = null, reply_to_message_id = null, file_inline = null, type = "File", is_spoil = false, thumb = true, audio_info = false, auto_delete) {
|
54
55
|
if (["me", "cloud", "self"].includes(object_guid.toLowerCase())) {
|
@@ -91,7 +92,10 @@ function sendMessage(object_guid_1) {
|
|
91
92
|
if (["Music", "Voice"].includes(type)) {
|
92
93
|
thumb = false;
|
93
94
|
if (audio_info) {
|
94
|
-
|
95
|
+
if (!optionalMusicMetadata) {
|
96
|
+
throw new Error("music-metadata module is not installed. Some features may be disabled.");
|
97
|
+
}
|
98
|
+
audio_data = yield optionalMusicMetadata.parseBuffer(file_inline);
|
95
99
|
duration = audio_data.format.duration || 5000;
|
96
100
|
}
|
97
101
|
}
|
@@ -16,6 +16,14 @@ const crypto_1 = __importDefault(require("../../crypto"));
|
|
16
16
|
const input_1 = __importDefault(require("input"));
|
17
17
|
function start() {
|
18
18
|
return __awaiter(this, void 0, void 0, function* () {
|
19
|
+
const DBInformation = this.sessionDb.getSession();
|
20
|
+
if (DBInformation) {
|
21
|
+
this.auth = DBInformation.auth;
|
22
|
+
this.userGuid = DBInformation.guid;
|
23
|
+
this.privateKey = DBInformation.private_key;
|
24
|
+
if (typeof DBInformation.agent === "string")
|
25
|
+
this.userAgent = DBInformation.agent || this.userAgent;
|
26
|
+
}
|
19
27
|
try {
|
20
28
|
this.key = Buffer.from(crypto_1.default.passphrase(this.auth), "utf8");
|
21
29
|
this.decode_auth = crypto_1.default.decode_auth(this.auth);
|
@@ -56,7 +64,13 @@ function start() {
|
|
56
64
|
this.key = Buffer.from(crypto_1.default.passphrase(response.auth), "utf8");
|
57
65
|
this.auth = response.auth;
|
58
66
|
this.decode_auth = crypto_1.default.decode_auth(this.auth);
|
59
|
-
this.sessionDb.saveSession(
|
67
|
+
this.sessionDb.saveSession({
|
68
|
+
phone: response.user.phone,
|
69
|
+
auth: this.auth,
|
70
|
+
guid: response.user.user_guid,
|
71
|
+
agent: this.userAgent,
|
72
|
+
private_key: this.privateKey
|
73
|
+
});
|
60
74
|
yield this.registerDevice();
|
61
75
|
break;
|
62
76
|
}
|
@@ -1,37 +1,4 @@
|
|
1
1
|
"use strict";
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
-
if (k2 === undefined) k2 = k;
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
-
}
|
8
|
-
Object.defineProperty(o, k2, desc);
|
9
|
-
}) : (function(o, m, k, k2) {
|
10
|
-
if (k2 === undefined) k2 = k;
|
11
|
-
o[k2] = m[k];
|
12
|
-
}));
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
-
}) : function(o, v) {
|
16
|
-
o["default"] = v;
|
17
|
-
});
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
19
|
-
var ownKeys = function(o) {
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
21
|
-
var ar = [];
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
23
|
-
return ar;
|
24
|
-
};
|
25
|
-
return ownKeys(o);
|
26
|
-
};
|
27
|
-
return function (mod) {
|
28
|
-
if (mod && mod.__esModule) return mod;
|
29
|
-
var result = {};
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
31
|
-
__setModuleDefault(result, mod);
|
32
|
-
return result;
|
33
|
-
};
|
34
|
-
})();
|
35
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
36
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
37
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
@@ -45,22 +12,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
46
13
|
};
|
47
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
48
|
-
const fluent_ffmpeg_1 = __importDefault(require("fluent-ffmpeg"));
|
49
15
|
const promises_1 = __importDefault(require("fs/promises"));
|
50
16
|
const path_1 = __importDefault(require("path"));
|
51
17
|
const os_1 = __importDefault(require("os"));
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
}
|
56
|
-
catch (err) {
|
57
|
-
console.log("⚠️ Sharp module could not be loaded:", err.message);
|
58
|
-
}
|
18
|
+
const optional_require_1 = require("optional-require");
|
19
|
+
const sharp = (0, optional_require_1.optionalRequire)("sharp", { default: true });
|
20
|
+
const ffmpeg = (0, optional_require_1.optionalRequire)("fluent-ffmpeg", { default: true });
|
59
21
|
class ThumbnailGenerator {
|
60
22
|
static getTime(videoPath) {
|
61
23
|
return __awaiter(this, void 0, void 0, function* () {
|
24
|
+
if (!ffmpeg) {
|
25
|
+
throw new Error("fluent-ffmpeg module is not installed. Some features may be disabled.");
|
26
|
+
}
|
62
27
|
return new Promise((resolve, reject) => {
|
63
|
-
|
28
|
+
ffmpeg.ffprobe(videoPath, (err, metadata) => {
|
64
29
|
if (err) {
|
65
30
|
console.error("Error fetching metadata:", err);
|
66
31
|
reject(err);
|
@@ -73,10 +38,13 @@ class ThumbnailGenerator {
|
|
73
38
|
}
|
74
39
|
static fromVideo(videoPath) {
|
75
40
|
return __awaiter(this, void 0, void 0, function* () {
|
41
|
+
if (!ffmpeg) {
|
42
|
+
throw new Error("fluent-ffmpeg module is not installed. Some features may be disabled.");
|
43
|
+
}
|
76
44
|
const tempImagePath = path_1.default.join(os_1.default.tmpdir(), `thumbnail_${Date.now()}.png`);
|
77
45
|
try {
|
78
46
|
yield new Promise((resolve, reject) => {
|
79
|
-
(
|
47
|
+
ffmpeg(videoPath)
|
80
48
|
.on("end", () => resolve(undefined))
|
81
49
|
.on("error", reject)
|
82
50
|
.screenshots({
|
@@ -100,6 +68,9 @@ class ThumbnailGenerator {
|
|
100
68
|
}
|
101
69
|
static fromImage(imagePath_1) {
|
102
70
|
return __awaiter(this, arguments, void 0, function* (imagePath, width = 320) {
|
71
|
+
if (!sharp) {
|
72
|
+
throw new Error("sharp module is not installed. Some features may be disabled.");
|
73
|
+
}
|
103
74
|
try {
|
104
75
|
const buffer = yield sharp(imagePath).resize(width).toBuffer();
|
105
76
|
return buffer.toString("base64");
|
package/rubjs/network/index.js
CHANGED
@@ -200,8 +200,28 @@ class Network {
|
|
200
200
|
return;
|
201
201
|
const update = JSON.parse(crypto_1.default.decrypt(data_enc, this.client.key));
|
202
202
|
this.client.eventHandlers.forEach((_a) => __awaiter(this, [_a], void 0, function* ({ callback, filters = [], updateType }) {
|
203
|
-
var _b;
|
203
|
+
var _b, _c, _d, _e, _f, _g, _h, _j;
|
204
204
|
if (((_b = update[updateType]) === null || _b === void 0 ? void 0 : _b.length) > 0) {
|
205
|
+
let username = null;
|
206
|
+
const isMUp = updateType === "message_updates";
|
207
|
+
if (isMUp) {
|
208
|
+
if (((_c = update === null || update === void 0 ? void 0 : update.show_notifications) === null || _c === void 0 ? void 0 : _c.length) > 0) {
|
209
|
+
const notification = (_d = update === null || update === void 0 ? void 0 : update.show_notifications) === null || _d === void 0 ? void 0 : _d[0];
|
210
|
+
const obg = (_e = notification === null || notification === void 0 ? void 0 : notification.message_data) === null || _e === void 0 ? void 0 : _e.object_guid;
|
211
|
+
if (obg === null || obg === void 0 ? void 0 : obg.startsWith("u0")) {
|
212
|
+
username = notification.title;
|
213
|
+
}
|
214
|
+
else if (obg === null || obg === void 0 ? void 0 : obg.startsWith("g0")) {
|
215
|
+
username = (_f = notification.text) === null || _f === void 0 ? void 0 : _f.split(":")[0];
|
216
|
+
}
|
217
|
+
}
|
218
|
+
else {
|
219
|
+
const chat_updates = (_g = update === null || update === void 0 ? void 0 : update.chat_updates) === null || _g === void 0 ? void 0 : _g[0];
|
220
|
+
username =
|
221
|
+
((_j = (_h = chat_updates === null || chat_updates === void 0 ? void 0 : chat_updates.chat) === null || _h === void 0 ? void 0 : _h.last_message) === null || _j === void 0 ? void 0 : _j.author_title) ||
|
222
|
+
"Unknown User";
|
223
|
+
}
|
224
|
+
}
|
205
225
|
for (let messageData of update[updateType]) {
|
206
226
|
if (!messageData)
|
207
227
|
return;
|
@@ -216,6 +236,8 @@ class Network {
|
|
216
236
|
}
|
217
237
|
return false;
|
218
238
|
});
|
239
|
+
if (isMUp)
|
240
|
+
messageData.message.author_title = username;
|
219
241
|
if (isValid)
|
220
242
|
yield callback(new types_1.Message(this.client, messageData));
|
221
243
|
}
|
package/rubjs/session/index.d.ts
CHANGED
@@ -5,14 +5,14 @@ interface SessionData {
|
|
5
5
|
agent: string;
|
6
6
|
private_key: string;
|
7
7
|
}
|
8
|
-
declare class
|
9
|
-
private
|
10
|
-
private
|
11
|
-
|
12
|
-
|
13
|
-
private
|
8
|
+
declare class SessionManager {
|
9
|
+
private secretKey;
|
10
|
+
private filename;
|
11
|
+
private iv;
|
12
|
+
constructor(filename: string);
|
13
|
+
private encrypt;
|
14
|
+
private decrypt;
|
15
|
+
saveSession(sessionData: SessionData): void;
|
14
16
|
getSession(): SessionData | null;
|
15
|
-
saveSession(phone: string, auth: string, guid: string, agent: string, privateKey: string): void;
|
16
|
-
closeDB(): void;
|
17
17
|
}
|
18
|
-
export default
|
18
|
+
export default SessionManager;
|
package/rubjs/session/index.js
CHANGED
@@ -1,57 +1,164 @@
|
|
1
1
|
"use strict";
|
2
|
+
// import sqlite3 from "sqlite3";
|
2
3
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
5
|
};
|
5
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
// interface SessionData {
|
8
|
+
// phone: string;
|
9
|
+
// auth: string;
|
10
|
+
// guid: string;
|
11
|
+
// agent: string;
|
12
|
+
// private_key: string;
|
13
|
+
// }
|
14
|
+
// class SQLiteSession {
|
15
|
+
// private dbFile: string;
|
16
|
+
// private db: sqlite3.Database;
|
17
|
+
// constructor(sessionName: string) {
|
18
|
+
// this.dbFile = sessionName.endsWith(".rp") ? sessionName : `${sessionName}.rp`;
|
19
|
+
// this.db = new sqlite3.Database(this.dbFile, (err) => {
|
20
|
+
// if (err) {
|
21
|
+
// console.error("Error opening database:", err);
|
22
|
+
// } else {
|
23
|
+
// this.initializeDB();
|
24
|
+
// }
|
25
|
+
// });
|
26
|
+
// }
|
27
|
+
// private handleError<T>(operation: string, callback: () => T): T | null {
|
28
|
+
// try {
|
29
|
+
// return callback();
|
30
|
+
// } catch (error) {
|
31
|
+
// console.error(`Error in ${operation}:`, error);
|
32
|
+
// console.warn(`Failed to execute ${operation}`);
|
33
|
+
// return null;
|
34
|
+
// }
|
35
|
+
// }
|
36
|
+
// private initializeDB(): void {
|
37
|
+
// this.handleError("initializeDB", () => {
|
38
|
+
// this.db.exec("PRAGMA journal_mode = DELETE");
|
39
|
+
// this.db.get(
|
40
|
+
// "SELECT name FROM sqlite_master WHERE type=? AND name=?",
|
41
|
+
// ["table", "session"],
|
42
|
+
// (err, row) => {
|
43
|
+
// if (!row) {
|
44
|
+
// this.db.run(
|
45
|
+
// `CREATE TABLE session (
|
46
|
+
// phone TEXT PRIMARY KEY,
|
47
|
+
// auth TEXT,
|
48
|
+
// guid TEXT,
|
49
|
+
// agent TEXT,
|
50
|
+
// private_key TEXT
|
51
|
+
// )`
|
52
|
+
// );
|
53
|
+
// }
|
54
|
+
// }
|
55
|
+
// );
|
56
|
+
// });
|
57
|
+
// }
|
58
|
+
// getSession(): SessionData | null {
|
59
|
+
// return this.handleError("getSession", () => {
|
60
|
+
// return new Promise<SessionData | null>((resolve) => {
|
61
|
+
// this.db.get("SELECT * FROM session", (err, row) => {
|
62
|
+
// if (err) {
|
63
|
+
// console.error("Error fetching session:", err);
|
64
|
+
// resolve(null);
|
65
|
+
// } else {
|
66
|
+
// resolve(row as SessionData || null);
|
67
|
+
// }
|
68
|
+
// });
|
69
|
+
// }) as unknown as SessionData | null;
|
70
|
+
// }) as SessionData | null;
|
71
|
+
// }
|
72
|
+
// saveSession(
|
73
|
+
// phone: string,
|
74
|
+
// auth: string,
|
75
|
+
// guid: string,
|
76
|
+
// agent: string,
|
77
|
+
// privateKey: string
|
78
|
+
// ): void {
|
79
|
+
// this.handleError("saveSession", () => {
|
80
|
+
// this.db.run(
|
81
|
+
// `INSERT OR REPLACE INTO session (phone, auth, guid, agent, private_key)
|
82
|
+
// VALUES (?, ?, ?, ?, ?)`,
|
83
|
+
// [phone, auth, guid, agent, privateKey]
|
84
|
+
// );
|
85
|
+
// });
|
86
|
+
// }
|
87
|
+
// closeDB(): void {
|
88
|
+
// this.handleError("closeDB", () => {
|
89
|
+
// this.db.close((err) => {
|
90
|
+
// if (err) {
|
91
|
+
// console.error("Error closing database:", err);
|
92
|
+
// }
|
93
|
+
// });
|
94
|
+
// });
|
95
|
+
// }
|
96
|
+
// }
|
97
|
+
// export default SQLiteSession;
|
98
|
+
const fs_1 = __importDefault(require("fs"));
|
99
|
+
const crypto_1 = __importDefault(require("crypto"));
|
100
|
+
class SessionManager {
|
101
|
+
constructor(filename) {
|
102
|
+
this.secretKey = "12345678901234567890123456789012";
|
103
|
+
this.iv = crypto_1.default.randomBytes(16);
|
104
|
+
this.filename = filename + ".json";
|
12
105
|
}
|
13
|
-
|
106
|
+
encrypt(sessionData) {
|
107
|
+
const cipher = crypto_1.default.createCipheriv("aes-256-cbc", Buffer.from(this.secretKey), this.iv);
|
108
|
+
let encrypted = cipher.update(JSON.stringify(sessionData), "utf8", "hex");
|
109
|
+
encrypted += cipher.final("hex");
|
110
|
+
return encrypted;
|
111
|
+
}
|
112
|
+
decrypt(encryptedData, iv) {
|
113
|
+
const decipher = crypto_1.default.createDecipheriv("aes-256-cbc", Buffer.from(this.secretKey), iv);
|
114
|
+
let decrypted = decipher.update(encryptedData, "hex", "utf8");
|
115
|
+
decrypted += decipher.final("utf8");
|
116
|
+
return JSON.parse(decrypted);
|
117
|
+
}
|
118
|
+
saveSession(sessionData) {
|
119
|
+
const encryptedData = this.encrypt(sessionData);
|
120
|
+
const dataToWrite = {
|
121
|
+
iv: this.iv.toString("hex"),
|
122
|
+
encryptedData: encryptedData,
|
123
|
+
};
|
124
|
+
fs_1.default.writeFileSync(this.filename, JSON.stringify(dataToWrite, null, 2));
|
125
|
+
}
|
126
|
+
getSession() {
|
14
127
|
try {
|
15
|
-
|
128
|
+
if (!fs_1.default.existsSync(this.filename)) {
|
129
|
+
const defaultSessionData = {
|
130
|
+
phone: "",
|
131
|
+
auth: "",
|
132
|
+
guid: "",
|
133
|
+
agent: "",
|
134
|
+
private_key: "",
|
135
|
+
};
|
136
|
+
this.saveSession(defaultSessionData);
|
137
|
+
return defaultSessionData;
|
138
|
+
}
|
139
|
+
const rawData = fs_1.default.readFileSync(this.filename, "utf8");
|
140
|
+
const parsedData = JSON.parse(rawData);
|
141
|
+
return this.decrypt(parsedData.encryptedData, Buffer.from(parsedData.iv, "hex"));
|
16
142
|
}
|
17
143
|
catch (error) {
|
18
|
-
console.error(
|
19
|
-
|
144
|
+
console.error("Error reading or decrypting session data:", error);
|
145
|
+
return null;
|
20
146
|
}
|
21
147
|
}
|
22
|
-
initializeDB() {
|
23
|
-
this.handleError("initializeDB", () => {
|
24
|
-
this.db.pragma("journal_mode = DELETE");
|
25
|
-
const sessionTable = this.db
|
26
|
-
.prepare("SELECT name FROM sqlite_master WHERE type=? AND name=?")
|
27
|
-
.get("table", "session");
|
28
|
-
if (!sessionTable) {
|
29
|
-
this.db.prepare(`CREATE TABLE session (
|
30
|
-
phone TEXT PRIMARY KEY,
|
31
|
-
auth TEXT,
|
32
|
-
guid TEXT,
|
33
|
-
agent TEXT,
|
34
|
-
private_key TEXT
|
35
|
-
)`).run();
|
36
|
-
}
|
37
|
-
});
|
38
|
-
}
|
39
|
-
getSession() {
|
40
|
-
return this.handleError("getSession", () => {
|
41
|
-
const result = this.db.prepare("SELECT * FROM session").get();
|
42
|
-
return result ? result : null;
|
43
|
-
});
|
44
|
-
}
|
45
|
-
saveSession(phone, auth, guid, agent, privateKey) {
|
46
|
-
this.handleError("saveSession", () => {
|
47
|
-
this.db.prepare(`INSERT OR REPLACE INTO session (phone, auth, guid, agent, private_key)
|
48
|
-
VALUES (?, ?, ?, ?, ?)`).run(phone, auth, guid, agent, privateKey);
|
49
|
-
});
|
50
|
-
}
|
51
|
-
closeDB() {
|
52
|
-
this.handleError("closeDB", () => {
|
53
|
-
this.db.close();
|
54
|
-
});
|
55
|
-
}
|
56
148
|
}
|
57
|
-
exports.default =
|
149
|
+
exports.default = SessionManager;
|
150
|
+
// // مثال استفاده از کلاس
|
151
|
+
// const secretKey = '12345678901234567890123456789012'; // کلید رمزنگاری 32 بایتی
|
152
|
+
// const sessionManager = new SessionManager(secretKey, 'session.json');
|
153
|
+
// const sessionData: SessionData = {
|
154
|
+
// phone: '1234567890',
|
155
|
+
// auth: 'auth-token',
|
156
|
+
// guid: 'unique-guid',
|
157
|
+
// agent: 'user-agent',
|
158
|
+
// private_key: 'private-key-example'
|
159
|
+
// };
|
160
|
+
// // ذخیره دادهها در فایل
|
161
|
+
// sessionManager.saveSession(sessionData);
|
162
|
+
// // خواندن دادهها از فایل
|
163
|
+
// const sessionFromFile = sessionManager.getSession();
|
164
|
+
// console.log('Decrypted session data:', sessionFromFile);
|
@@ -15,8 +15,8 @@ declare class VoiceChatClient {
|
|
15
15
|
private lastPosition;
|
16
16
|
private intervalId?;
|
17
17
|
private isManualSkip;
|
18
|
-
private
|
19
|
-
constructor(
|
18
|
+
private getMusicUrl;
|
19
|
+
constructor(getMusicUrl?: () => Promise<string>);
|
20
20
|
play(filePath?: string): Promise<void>;
|
21
21
|
stop(): void;
|
22
22
|
resume(): void;
|
@@ -10,9 +10,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
10
10
|
};
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
12
12
|
const child_process_1 = require("child_process");
|
13
|
-
const
|
13
|
+
const optional_require_1 = require("optional-require");
|
14
|
+
const optionalWrtc = (0, optional_require_1.optionalRequire)("wrtc");
|
14
15
|
class VoiceChatClient {
|
15
|
-
constructor(
|
16
|
+
constructor(getMusicUrl) {
|
16
17
|
this.buffer = Buffer.alloc(0);
|
17
18
|
this.frameSize = 960;
|
18
19
|
this.playlist = [];
|
@@ -20,11 +21,14 @@ class VoiceChatClient {
|
|
20
21
|
this.isPaused = false;
|
21
22
|
this.lastPosition = 0;
|
22
23
|
this.isManualSkip = false;
|
23
|
-
|
24
|
-
|
24
|
+
if (!optionalWrtc) {
|
25
|
+
throw new Error("wrtc module is not installed. Some features may be disabled.");
|
26
|
+
}
|
27
|
+
this.pc = new optionalWrtc.RTCPeerConnection();
|
28
|
+
this.source = new optionalWrtc.nonstandard.RTCAudioSource();
|
25
29
|
this.track = this.source.createTrack();
|
26
30
|
this.pc.addTrack(this.track);
|
27
|
-
this.
|
31
|
+
this.getMusicUrl = getMusicUrl;
|
28
32
|
}
|
29
33
|
play(filePath) {
|
30
34
|
return __awaiter(this, void 0, void 0, function* () {
|
@@ -32,8 +36,8 @@ class VoiceChatClient {
|
|
32
36
|
this.stop();
|
33
37
|
if (!filePath) {
|
34
38
|
if (this.playlist.length === 0) {
|
35
|
-
if (this.
|
36
|
-
this.playlist = [yield this.
|
39
|
+
if (this.getMusicUrl) {
|
40
|
+
this.playlist = [yield this.getMusicUrl()];
|
37
41
|
}
|
38
42
|
else
|
39
43
|
return;
|
@@ -127,8 +131,8 @@ class VoiceChatClient {
|
|
127
131
|
this.play(this.playlist[this.currentIndex]);
|
128
132
|
}
|
129
133
|
else {
|
130
|
-
if (this.
|
131
|
-
this.playlist = [...this.playlist, yield this.
|
134
|
+
if (this.getMusicUrl) {
|
135
|
+
this.playlist = [...this.playlist, yield this.getMusicUrl()];
|
132
136
|
yield this.next();
|
133
137
|
}
|
134
138
|
}
|
@@ -165,7 +169,7 @@ class VoiceChatClient {
|
|
165
169
|
yield this.pc.setLocalDescription(offer);
|
166
170
|
const connect = yield client.joinGroupVoiceChat(chatGuid, voiceChatId, offer.sdp, client.userGuid);
|
167
171
|
const sdpAnswer = connect.sdp_answer_data;
|
168
|
-
yield this.pc.setRemoteDescription(new
|
172
|
+
yield this.pc.setRemoteDescription(new optionalWrtc.RTCSessionDescription({ type: "answer", sdp: sdpAnswer }));
|
169
173
|
yield client.setVoiceChatState(chatGuid, voiceChatId);
|
170
174
|
});
|
171
175
|
}
|
package/rubjs/utils/index.d.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import Filters from "./filters";
|
2
2
|
import Utils from "./utils";
|
3
3
|
import VoiceChatClient from "./VoiceChatClient";
|
4
|
-
|
4
|
+
import SendLiveClient from "./sendLiveClient";
|
5
|
+
export { Filters, Utils, VoiceChatClient, SendLiveClient };
|
package/rubjs/utils/index.js
CHANGED
@@ -3,10 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.VoiceChatClient = exports.Utils = exports.Filters = void 0;
|
6
|
+
exports.SendLiveClient = exports.VoiceChatClient = exports.Utils = exports.Filters = void 0;
|
7
7
|
const filters_1 = __importDefault(require("./filters"));
|
8
8
|
exports.Filters = filters_1.default;
|
9
9
|
const utils_1 = __importDefault(require("./utils"));
|
10
10
|
exports.Utils = utils_1.default;
|
11
11
|
const VoiceChatClient_1 = __importDefault(require("./VoiceChatClient"));
|
12
12
|
exports.VoiceChatClient = VoiceChatClient_1.default;
|
13
|
+
const sendLiveClient_1 = __importDefault(require("./sendLiveClient"));
|
14
|
+
exports.SendLiveClient = sendLiveClient_1.default;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import Client from "..";
|
2
|
+
declare class SendLiveClient {
|
3
|
+
private client;
|
4
|
+
private title;
|
5
|
+
private object_guid;
|
6
|
+
private streamUrlRegex;
|
7
|
+
private streamKeyRegex;
|
8
|
+
private playlist;
|
9
|
+
private currentIndex;
|
10
|
+
private getVideoUrl;
|
11
|
+
private ffmpeg?;
|
12
|
+
private isPaused;
|
13
|
+
private lastPosition;
|
14
|
+
constructor(client: Client, title: string, object_guid: string, getVideoUrl?: () => Promise<string>);
|
15
|
+
detectOrientation(filePath: string): Promise<boolean>;
|
16
|
+
createLive(filePath?: string, startTime?: number): Promise<void>;
|
17
|
+
stop(): void;
|
18
|
+
getCurrentTime(): Promise<void>;
|
19
|
+
resume(): void;
|
20
|
+
next(): Promise<void>;
|
21
|
+
previous(): void;
|
22
|
+
addToPlaylist(filePath: string): void;
|
23
|
+
removeFromPlaylist(filePath: string): void;
|
24
|
+
}
|
25
|
+
export default SendLiveClient;
|
@@ -0,0 +1,146 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9
|
+
});
|
10
|
+
};
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
12
|
+
const child_process_1 = require("child_process");
|
13
|
+
class SendLiveClient {
|
14
|
+
constructor(client, title, object_guid, getVideoUrl) {
|
15
|
+
this.streamUrlRegex = /Stream url:\s*(rtmp:\/\/[^\n]+)/;
|
16
|
+
this.streamKeyRegex = /Stream key:\s*([^\n]+)/;
|
17
|
+
this.playlist = [];
|
18
|
+
this.currentIndex = 0;
|
19
|
+
this.isPaused = false;
|
20
|
+
this.lastPosition = 0;
|
21
|
+
this.client = client;
|
22
|
+
this.getVideoUrl = getVideoUrl;
|
23
|
+
this.title = title;
|
24
|
+
this.object_guid = object_guid;
|
25
|
+
}
|
26
|
+
detectOrientation(filePath) {
|
27
|
+
return __awaiter(this, void 0, void 0, function* () {
|
28
|
+
return new Promise((resolve) => {
|
29
|
+
const ffprobe = (0, child_process_1.spawn)("ffprobe", [
|
30
|
+
"-v", "error",
|
31
|
+
"-select_streams", "v:0",
|
32
|
+
"-show_entries", "stream=width,height",
|
33
|
+
"-of", "csv=p=0",
|
34
|
+
filePath,
|
35
|
+
]);
|
36
|
+
let output = "";
|
37
|
+
ffprobe.stdout.on("data", (data) => {
|
38
|
+
output += data.toString();
|
39
|
+
});
|
40
|
+
ffprobe.on("close", () => {
|
41
|
+
const [width, height] = output.trim().split(",").map(Number);
|
42
|
+
resolve(width > height);
|
43
|
+
});
|
44
|
+
});
|
45
|
+
});
|
46
|
+
}
|
47
|
+
createLive(filePath_1) {
|
48
|
+
return __awaiter(this, arguments, void 0, function* (filePath, startTime = 0) {
|
49
|
+
var _a;
|
50
|
+
if (!filePath) {
|
51
|
+
if (!this.playlist.length && this.getVideoUrl) {
|
52
|
+
this.playlist = [yield this.getVideoUrl()];
|
53
|
+
}
|
54
|
+
filePath = (_a = this.playlist[this.currentIndex]) !== null && _a !== void 0 ? _a : "";
|
55
|
+
}
|
56
|
+
if (!filePath)
|
57
|
+
return;
|
58
|
+
let isLandscape = yield this.detectOrientation(filePath);
|
59
|
+
let res = yield this.client.sendLive(this.title, this.object_guid, filePath);
|
60
|
+
const streamUrl = res.publish_text.match(this.streamUrlRegex)[1];
|
61
|
+
const streamKey = res.publish_text.match(this.streamKeyRegex)[1];
|
62
|
+
const streamSendUrl = streamUrl + streamKey;
|
63
|
+
const resolution = !isLandscape ? "1920:1080" : "1080:1920";
|
64
|
+
const rotateFilter = !isLandscape ? "" : "transpose=1,";
|
65
|
+
const seekArgs = startTime > 0 ? ["-ss", startTime.toFixed(2)] : [];
|
66
|
+
this.ffmpeg = (0, child_process_1.spawn)("ffmpeg", [
|
67
|
+
"-re",
|
68
|
+
...seekArgs,
|
69
|
+
"-i", filePath,
|
70
|
+
"-c:v", "libx264",
|
71
|
+
"-preset", "ultrafast",
|
72
|
+
"-b:v", "1200k",
|
73
|
+
"-c:a", "aac",
|
74
|
+
"-b:a", "128k",
|
75
|
+
"-vf", `${rotateFilter}scale=${resolution}`,
|
76
|
+
"-rtbufsize", "100M",
|
77
|
+
"-f", "flv",
|
78
|
+
streamSendUrl,
|
79
|
+
]);
|
80
|
+
this.ffmpeg.on("close", (code) => {
|
81
|
+
console.log(`FFmpeg process exited with code ${code}`);
|
82
|
+
});
|
83
|
+
});
|
84
|
+
}
|
85
|
+
stop() {
|
86
|
+
if (this.ffmpeg) {
|
87
|
+
this.ffmpeg.kill();
|
88
|
+
this.ffmpeg = undefined;
|
89
|
+
this.isPaused = true;
|
90
|
+
this.getCurrentTime();
|
91
|
+
}
|
92
|
+
}
|
93
|
+
getCurrentTime() {
|
94
|
+
return __awaiter(this, void 0, void 0, function* () {
|
95
|
+
if (!this.ffmpeg)
|
96
|
+
return;
|
97
|
+
const ffprobe = (0, child_process_1.spawn)("ffprobe", ["-i", this.playlist[this.currentIndex], "-show_entries", "format=start_time", "-of", "default=noprint_wrappers=1:nokey=1"]);
|
98
|
+
let output = "";
|
99
|
+
ffprobe.stdout.on("data", (data) => {
|
100
|
+
output += data.toString();
|
101
|
+
});
|
102
|
+
ffprobe.on("close", () => {
|
103
|
+
this.lastPosition = parseFloat(output.trim()) || 0;
|
104
|
+
});
|
105
|
+
});
|
106
|
+
}
|
107
|
+
resume() {
|
108
|
+
if (this.isPaused) {
|
109
|
+
this.createLive(this.playlist[this.currentIndex], this.lastPosition);
|
110
|
+
this.isPaused = false;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
next() {
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
115
|
+
if (this.playlist.length > this.currentIndex + 1) {
|
116
|
+
this.stop();
|
117
|
+
this.currentIndex += 1;
|
118
|
+
this.lastPosition = 0;
|
119
|
+
this.isPaused = true;
|
120
|
+
this.createLive(this.playlist[this.currentIndex]);
|
121
|
+
}
|
122
|
+
});
|
123
|
+
}
|
124
|
+
previous() {
|
125
|
+
if (this.currentIndex > 0) {
|
126
|
+
this.stop();
|
127
|
+
this.currentIndex--;
|
128
|
+
this.lastPosition = 0;
|
129
|
+
this.isPaused = true;
|
130
|
+
this.createLive();
|
131
|
+
}
|
132
|
+
}
|
133
|
+
addToPlaylist(filePath) {
|
134
|
+
this.playlist.push(filePath);
|
135
|
+
}
|
136
|
+
removeFromPlaylist(filePath) {
|
137
|
+
const index = this.playlist.indexOf(filePath);
|
138
|
+
if (index !== -1) {
|
139
|
+
this.playlist.splice(index, 1);
|
140
|
+
if (index <= this.currentIndex && this.currentIndex > 0) {
|
141
|
+
this.currentIndex--;
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
145
|
+
}
|
146
|
+
exports.default = SendLiveClient;
|