supertelegram 0.1.3 → 0.3.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/README.md +61 -18
- package/package.json +1 -1
- package/src/cli/commands.ts +106 -2
- package/src/cli/prompts.ts +9 -0
- package/src/cli/run.ts +36 -11
- package/src/client/telegram.ts +49 -7
- package/src/config/manager.ts +95 -0
- package/src/session/storage.ts +18 -8
package/README.md
CHANGED
|
@@ -8,41 +8,63 @@ telegram cli for ai to read/write messages using gramjs.
|
|
|
8
8
|
npm install -g supertelegram
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## quick start
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
TELEGRAM_APP_ID="your_app_id"
|
|
16
|
-
TELEGRAM_APP_HASH="your_app_hash"
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
get credentials from https://my.telegram.org/apps
|
|
20
|
-
|
|
21
|
-
## login
|
|
13
|
+
just run login and follow the prompts:
|
|
22
14
|
|
|
23
15
|
```bash
|
|
24
16
|
telegram login
|
|
25
17
|
```
|
|
26
18
|
|
|
27
|
-
|
|
19
|
+
if you don't have API credentials configured, it will:
|
|
20
|
+
1. prompt you to get them from https://my.telegram.org/apps
|
|
21
|
+
2. ask for your app_id and app_hash
|
|
22
|
+
3. save them to `~/.supertelegram/config.json`
|
|
23
|
+
4. continue with telegram phone/code login
|
|
24
|
+
5. save session to `~/.supertelegram/session.txt`
|
|
25
|
+
|
|
26
|
+
that's it! now you're ready to use telegram from the cli.
|
|
28
27
|
|
|
29
28
|
## usage
|
|
30
29
|
|
|
30
|
+
### messages
|
|
31
|
+
|
|
31
32
|
```bash
|
|
32
33
|
# send a message
|
|
33
|
-
telegram send
|
|
34
|
+
telegram send @username "hello there"
|
|
34
35
|
|
|
35
|
-
# read messages
|
|
36
|
-
telegram read
|
|
36
|
+
# read messages (shows [photo], [video], [file] indicators)
|
|
37
|
+
telegram read @username 10
|
|
37
38
|
|
|
38
39
|
# reply to latest message
|
|
39
|
-
telegram reply
|
|
40
|
+
telegram reply "John" "hey back!"
|
|
40
41
|
|
|
41
|
-
# get unread messages (json output)
|
|
42
|
-
telegram unread
|
|
42
|
+
# get unread messages (json output with media info)
|
|
43
|
+
telegram unread 20
|
|
43
44
|
|
|
44
45
|
# list dialogs
|
|
45
|
-
telegram dialogs
|
|
46
|
+
telegram dialogs 10
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### media (images/videos/files)
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# send a file with optional caption
|
|
53
|
+
telegram send-file @username photo.jpg
|
|
54
|
+
telegram send-file @username video.mp4 "check this out!"
|
|
55
|
+
|
|
56
|
+
# download media from a message
|
|
57
|
+
# (use 'read' command to get message IDs)
|
|
58
|
+
telegram download @username 12345 ./downloaded.jpg
|
|
59
|
+
telegram download @username 12346 # auto-named file
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### config
|
|
63
|
+
|
|
64
|
+
manually set API credentials (optional):
|
|
65
|
+
```bash
|
|
66
|
+
telegram config set appId "12345678"
|
|
67
|
+
telegram config set appHash "abc123..."
|
|
46
68
|
```
|
|
47
69
|
|
|
48
70
|
### flags
|
|
@@ -51,6 +73,27 @@ telegram dialogs [limit]
|
|
|
51
73
|
- `--help` - show help
|
|
52
74
|
- `--version` - show version
|
|
53
75
|
|
|
76
|
+
### advanced
|
|
77
|
+
|
|
78
|
+
**multi-account / custom session location:**
|
|
79
|
+
```bash
|
|
80
|
+
# use env var
|
|
81
|
+
TELEGRAM_SESSION=./custom.txt telegram send @friend "hey"
|
|
82
|
+
|
|
83
|
+
# or pass flag (todo)
|
|
84
|
+
telegram send @friend "hey" --session ./custom.txt
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**precedence for API credentials:**
|
|
88
|
+
1. `TELEGRAM_APP_ID` and `TELEGRAM_APP_HASH` env vars
|
|
89
|
+
2. `~/.supertelegram/config.json` (global)
|
|
90
|
+
3. `.env` file in current directory (for dev)
|
|
91
|
+
|
|
92
|
+
**precedence for session file:**
|
|
93
|
+
1. `TELEGRAM_SESSION` env var
|
|
94
|
+
2. `~/.supertelegram/session.txt` (global default)
|
|
95
|
+
3. `./session.txt` (backwards compat)
|
|
96
|
+
|
|
54
97
|
## development
|
|
55
98
|
|
|
56
99
|
clone repo and install:
|
package/package.json
CHANGED
package/src/cli/commands.ts
CHANGED
|
@@ -6,8 +6,12 @@ import {
|
|
|
6
6
|
disconnect,
|
|
7
7
|
getClient,
|
|
8
8
|
login as telegramLogin,
|
|
9
|
+
sendFile as telegramSendFile,
|
|
10
|
+
downloadMedia as telegramDownloadMedia,
|
|
9
11
|
} from "../client/telegram";
|
|
10
|
-
import { askPhoneNumber, askPhoneCode, askPassword } from "./prompts";
|
|
12
|
+
import { askPhoneNumber, askPhoneCode, askPassword, askAppId, askAppHash } from "./prompts";
|
|
13
|
+
import { getApiCredentials, setConfig } from "../config/manager";
|
|
14
|
+
import { Api } from "telegram";
|
|
11
15
|
|
|
12
16
|
export async function send(username: string, message: string) {
|
|
13
17
|
if (!(await isLoggedIn())) {
|
|
@@ -20,6 +24,29 @@ export async function send(username: string, message: string) {
|
|
|
20
24
|
await disconnect();
|
|
21
25
|
}
|
|
22
26
|
|
|
27
|
+
function getMediaInfo(msg: Api.Message): string {
|
|
28
|
+
if (!msg.media) return "";
|
|
29
|
+
|
|
30
|
+
if (msg.media instanceof Api.MessageMediaPhoto) {
|
|
31
|
+
return " [photo]";
|
|
32
|
+
}
|
|
33
|
+
if (msg.media instanceof Api.MessageMediaDocument) {
|
|
34
|
+
const doc = msg.media.document;
|
|
35
|
+
if (doc instanceof Api.Document) {
|
|
36
|
+
const attrs = doc.attributes;
|
|
37
|
+
const filenameAttr = attrs.find((a) => "fileName" in a && a.fileName);
|
|
38
|
+
const filename = filenameAttr && "fileName" in filenameAttr ? filenameAttr.fileName : undefined;
|
|
39
|
+
const isVideo = attrs.some((a) => a instanceof Api.DocumentAttributeVideo);
|
|
40
|
+
const isAudio = attrs.some((a) => a instanceof Api.DocumentAttributeAudio);
|
|
41
|
+
|
|
42
|
+
if (isVideo) return ` [video${filename ? `: ${filename}` : ""}]`;
|
|
43
|
+
if (isAudio) return ` [audio${filename ? `: ${filename}` : ""}]`;
|
|
44
|
+
return ` [file${filename ? `: ${filename}` : ""}]`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return " [media]";
|
|
48
|
+
}
|
|
49
|
+
|
|
23
50
|
export async function read(username: string, limit = 10) {
|
|
24
51
|
if (!(await isLoggedIn())) {
|
|
25
52
|
console.error("not logged in. run: telegram login");
|
|
@@ -30,7 +57,8 @@ export async function read(username: string, limit = 10) {
|
|
|
30
57
|
for (const msg of messages.reverse()) {
|
|
31
58
|
const sender = msg.senderId?.toString() ?? "unknown";
|
|
32
59
|
const date = msg.date ? new Date(msg.date * 1000).toISOString() : "";
|
|
33
|
-
|
|
60
|
+
const mediaInfo = getMediaInfo(msg);
|
|
61
|
+
console.log(`[${date}] [${sender}]: ${msg.message}${mediaInfo}`);
|
|
34
62
|
}
|
|
35
63
|
await disconnect();
|
|
36
64
|
}
|
|
@@ -87,6 +115,7 @@ export async function unread(limit = 20) {
|
|
|
87
115
|
messages: fromOthers.map((m) => ({
|
|
88
116
|
id: m.id,
|
|
89
117
|
text: m.message,
|
|
118
|
+
media: m.media ? getMediaInfo(m).trim() : null,
|
|
90
119
|
date: m.date ? new Date(m.date * 1000).toISOString() : null,
|
|
91
120
|
})),
|
|
92
121
|
});
|
|
@@ -124,6 +153,18 @@ export async function reply(chatName: string, message: string) {
|
|
|
124
153
|
}
|
|
125
154
|
|
|
126
155
|
export async function login() {
|
|
156
|
+
// check if API credentials are configured
|
|
157
|
+
const creds = getApiCredentials();
|
|
158
|
+
if (!creds) {
|
|
159
|
+
console.log("no API credentials found. let's set them up first.");
|
|
160
|
+
const appId = await askAppId();
|
|
161
|
+
const appHash = await askAppHash();
|
|
162
|
+
|
|
163
|
+
setConfig("appId", appId);
|
|
164
|
+
setConfig("appHash", appHash);
|
|
165
|
+
console.log("credentials saved to ~/.supertelegram/config.json\n");
|
|
166
|
+
}
|
|
167
|
+
|
|
127
168
|
const loggedIn = await isLoggedIn();
|
|
128
169
|
if (loggedIn) {
|
|
129
170
|
console.log("already logged in!");
|
|
@@ -141,3 +182,66 @@ export async function login() {
|
|
|
141
182
|
console.log("login complete!");
|
|
142
183
|
await disconnect();
|
|
143
184
|
}
|
|
185
|
+
|
|
186
|
+
export async function config(action?: string, key?: string, value?: string) {
|
|
187
|
+
if (action === "set" && key && value) {
|
|
188
|
+
setConfig(key, value);
|
|
189
|
+
console.log(`set ${key} = ${value}`);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (action === "get" && key) {
|
|
194
|
+
const cfg = getApiCredentials();
|
|
195
|
+
if (key === "appId" && cfg) {
|
|
196
|
+
console.log(cfg.appId);
|
|
197
|
+
} else if (key === "appHash" && cfg) {
|
|
198
|
+
console.log(cfg.appHash);
|
|
199
|
+
} else {
|
|
200
|
+
console.log("not found");
|
|
201
|
+
}
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
console.log("usage:");
|
|
206
|
+
console.log(" telegram config set appId <id>");
|
|
207
|
+
console.log(" telegram config set appHash <hash>");
|
|
208
|
+
console.log(" telegram config get appId");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export async function sendFile(username: string, filePath: string, caption?: string) {
|
|
212
|
+
if (!(await isLoggedIn())) {
|
|
213
|
+
console.error("not logged in. run: telegram login");
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const result = await telegramSendFile(username, filePath, caption);
|
|
218
|
+
console.log(`sent file id: ${result.id}`);
|
|
219
|
+
await disconnect();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export async function downloadMedia(username: string, messageId: number, outputPath?: string) {
|
|
223
|
+
if (!(await isLoggedIn())) {
|
|
224
|
+
console.error("not logged in. run: telegram login");
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const messages = await getMessages(username, 100);
|
|
229
|
+
const msg = messages.find((m) => m.id === messageId);
|
|
230
|
+
|
|
231
|
+
if (!msg) {
|
|
232
|
+
console.error(`message ${messageId} not found`);
|
|
233
|
+
await disconnect();
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (!msg.media) {
|
|
238
|
+
console.error(`message ${messageId} has no media`);
|
|
239
|
+
await disconnect();
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
console.log("downloading media...");
|
|
244
|
+
const path = await telegramDownloadMedia(msg, outputPath);
|
|
245
|
+
console.log(`saved to: ${path || outputPath || "unknown"}`);
|
|
246
|
+
await disconnect();
|
|
247
|
+
}
|
package/src/cli/prompts.ts
CHANGED
|
@@ -23,3 +23,12 @@ export async function askUsername(): Promise<string> {
|
|
|
23
23
|
export async function askCommand(): Promise<string> {
|
|
24
24
|
return input.text("command (send/read/dialogs/quit):");
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
export async function askAppId(): Promise<string> {
|
|
28
|
+
console.log("\nget your API credentials from: https://my.telegram.org/apps\n");
|
|
29
|
+
return input.text("enter TELEGRAM_APP_ID:");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function askAppHash(): Promise<string> {
|
|
33
|
+
return input.text("enter TELEGRAM_APP_HASH:");
|
|
34
|
+
}
|
package/src/cli/run.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { send, read, dialogs, unread, reply, login } from "./commands";
|
|
3
|
-
import { setVerbose } from "../client/telegram";
|
|
2
|
+
import { send, read, dialogs, unread, reply, login, config, sendFile, downloadMedia } from "./commands";
|
|
3
|
+
import { setVerbose, setSessionPath } from "../client/telegram";
|
|
4
4
|
|
|
5
5
|
const VERSION = "0.1.0";
|
|
6
6
|
const NAME = "telegram";
|
|
@@ -12,12 +12,15 @@ usage:
|
|
|
12
12
|
${NAME} <command> [options]
|
|
13
13
|
|
|
14
14
|
commands:
|
|
15
|
-
send <chat> <message>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
send <chat> <message> send a message to a chat
|
|
16
|
+
send-file <chat> <path> send a file/image/video (optional: caption)
|
|
17
|
+
read <chat> [limit] read messages from a chat (default: 10)
|
|
18
|
+
download <chat> <id> [out] download media from message id
|
|
19
|
+
reply <chat> <message> reply to a chat by name (partial match)
|
|
20
|
+
dialogs [limit] list recent dialogs (default: 10)
|
|
21
|
+
unread [limit] show unread messages as json (default: 20)
|
|
22
|
+
login authenticate with telegram
|
|
23
|
+
config set <key> <val> set API credentials (appId, appHash)
|
|
21
24
|
|
|
22
25
|
options:
|
|
23
26
|
-v, --verbose show debug logs
|
|
@@ -26,7 +29,9 @@ options:
|
|
|
26
29
|
|
|
27
30
|
examples:
|
|
28
31
|
${NAME} send @username "hello there"
|
|
32
|
+
${NAME} send-file @username photo.jpg "check this out"
|
|
29
33
|
${NAME} read @username 5
|
|
34
|
+
${NAME} download @username 12345 ./photo.jpg
|
|
30
35
|
${NAME} reply "John" "hey!"
|
|
31
36
|
${NAME} unread
|
|
32
37
|
${NAME} dialogs 20
|
|
@@ -56,7 +61,7 @@ if (verbose) {
|
|
|
56
61
|
async function main() {
|
|
57
62
|
switch (command) {
|
|
58
63
|
case "send":
|
|
59
|
-
if (rest.length < 2) {
|
|
64
|
+
if (rest.length < 2 || !rest[0]) {
|
|
60
65
|
console.error("usage: telegram send <chat> <message>");
|
|
61
66
|
process.exit(1);
|
|
62
67
|
}
|
|
@@ -64,7 +69,7 @@ async function main() {
|
|
|
64
69
|
break;
|
|
65
70
|
|
|
66
71
|
case "read":
|
|
67
|
-
if (rest.length < 1) {
|
|
72
|
+
if (rest.length < 1 || !rest[0]) {
|
|
68
73
|
console.error("usage: telegram read <chat> [limit]");
|
|
69
74
|
process.exit(1);
|
|
70
75
|
}
|
|
@@ -80,17 +85,37 @@ async function main() {
|
|
|
80
85
|
break;
|
|
81
86
|
|
|
82
87
|
case "reply":
|
|
83
|
-
if (rest.length < 2) {
|
|
88
|
+
if (rest.length < 2 || !rest[0]) {
|
|
84
89
|
console.error("usage: telegram reply <chat> <message>");
|
|
85
90
|
process.exit(1);
|
|
86
91
|
}
|
|
87
92
|
await reply(rest[0], rest.slice(1).join(" "));
|
|
88
93
|
break;
|
|
89
94
|
|
|
95
|
+
case "send-file":
|
|
96
|
+
if (rest.length < 2 || !rest[0] || !rest[1]) {
|
|
97
|
+
console.error("usage: telegram send-file <chat> <path> [caption]");
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
await sendFile(rest[0], rest[1], rest.slice(2).join(" ") || undefined);
|
|
101
|
+
break;
|
|
102
|
+
|
|
103
|
+
case "download":
|
|
104
|
+
if (rest.length < 2 || !rest[0] || !rest[1]) {
|
|
105
|
+
console.error("usage: telegram download <chat> <message-id> [output-path]");
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
await downloadMedia(rest[0], Number.parseInt(rest[1]), rest[2]);
|
|
109
|
+
break;
|
|
110
|
+
|
|
90
111
|
case "login":
|
|
91
112
|
await login();
|
|
92
113
|
break;
|
|
93
114
|
|
|
115
|
+
case "config":
|
|
116
|
+
await config(rest[0], rest[1], rest[2]);
|
|
117
|
+
break;
|
|
118
|
+
|
|
94
119
|
case "help":
|
|
95
120
|
console.log(HELP);
|
|
96
121
|
break;
|
package/src/client/telegram.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { StringSession } from "telegram/sessions";
|
|
|
3
3
|
import { Logger } from "telegram/extensions/Logger";
|
|
4
4
|
import type { LogLevel } from "telegram/extensions/Logger";
|
|
5
5
|
import { loadSession, saveSession } from "../session/storage";
|
|
6
|
+
import { getApiCredentials } from "../config/manager";
|
|
6
7
|
|
|
7
8
|
let verbose = false;
|
|
8
9
|
|
|
@@ -11,25 +12,38 @@ export function setVerbose(v: boolean) {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
class SilentLogger extends Logger {
|
|
14
|
-
log(_level: LogLevel, _message: string, _color: string): void {
|
|
15
|
+
override log(_level: LogLevel, _message: string, _color: string): void {
|
|
15
16
|
if (verbose) {
|
|
16
17
|
super.log(_level, _message, _color);
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
const API_ID = Number(process.env.TELEGRAM_APP_ID);
|
|
22
|
-
const API_HASH = process.env.TELEGRAM_APP_HASH ?? "";
|
|
23
|
-
|
|
24
22
|
let client: TelegramClient | null = null;
|
|
23
|
+
let customSessionPath: string | undefined;
|
|
24
|
+
|
|
25
|
+
export function setSessionPath(path: string) {
|
|
26
|
+
customSessionPath = path;
|
|
27
|
+
}
|
|
25
28
|
|
|
26
29
|
export async function getClient(): Promise<TelegramClient> {
|
|
27
30
|
if (client) return client;
|
|
28
31
|
|
|
29
|
-
const
|
|
32
|
+
const creds = getApiCredentials();
|
|
33
|
+
if (!creds) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
"telegram API credentials not found.\n" +
|
|
36
|
+
"get them from: https://my.telegram.org/apps\n" +
|
|
37
|
+
"then run: telegram config set appId <id>\n" +
|
|
38
|
+
" telegram config set appHash <hash>\n" +
|
|
39
|
+
"or set env vars: TELEGRAM_APP_ID, TELEGRAM_APP_HASH"
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const sessionStr = loadSession(customSessionPath);
|
|
30
44
|
const session = new StringSession(sessionStr);
|
|
31
45
|
|
|
32
|
-
client = new TelegramClient(session,
|
|
46
|
+
client = new TelegramClient(session, creds.appId, creds.appHash, {
|
|
33
47
|
connectionRetries: 5,
|
|
34
48
|
baseLogger: new SilentLogger(),
|
|
35
49
|
});
|
|
@@ -58,7 +72,7 @@ export async function login(callbacks: {
|
|
|
58
72
|
});
|
|
59
73
|
|
|
60
74
|
const sessionStr = c.session.save() as unknown as string;
|
|
61
|
-
saveSession(sessionStr);
|
|
75
|
+
saveSession(sessionStr, customSessionPath);
|
|
62
76
|
console.log("session saved!");
|
|
63
77
|
}
|
|
64
78
|
|
|
@@ -70,6 +84,34 @@ export async function sendMessage(
|
|
|
70
84
|
return c.sendMessage(username, { message });
|
|
71
85
|
}
|
|
72
86
|
|
|
87
|
+
export async function sendFile(
|
|
88
|
+
username: string,
|
|
89
|
+
filePath: string,
|
|
90
|
+
caption?: string
|
|
91
|
+
): Promise<Api.Message> {
|
|
92
|
+
const c = await getClient();
|
|
93
|
+
return c.sendFile(username, {
|
|
94
|
+
file: filePath,
|
|
95
|
+
caption: caption,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function downloadMedia(
|
|
100
|
+
message: Api.Message,
|
|
101
|
+
outputPath?: string
|
|
102
|
+
): Promise<string | undefined> {
|
|
103
|
+
const c = await getClient();
|
|
104
|
+
if (!message.media) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const buffer = await c.downloadMedia(message, {
|
|
109
|
+
outputFile: outputPath,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return buffer as string | undefined;
|
|
113
|
+
}
|
|
114
|
+
|
|
73
115
|
export async function getMessages(
|
|
74
116
|
username: string,
|
|
75
117
|
limit = 10
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
const CONFIG_DIR = join(homedir(), ".supertelegram");
|
|
6
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
7
|
+
const SESSION_FILE = join(CONFIG_DIR, "session.txt");
|
|
8
|
+
|
|
9
|
+
export interface Config {
|
|
10
|
+
appId?: string;
|
|
11
|
+
appHash?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function ensureConfigDir() {
|
|
15
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
16
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getConfig(): Config {
|
|
21
|
+
ensureConfigDir();
|
|
22
|
+
|
|
23
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const content = readFileSync(CONFIG_FILE, "utf-8");
|
|
29
|
+
return JSON.parse(content);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
console.error("failed to read config:", err);
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function setConfig(key: string, value: string) {
|
|
37
|
+
ensureConfigDir();
|
|
38
|
+
|
|
39
|
+
const config = getConfig();
|
|
40
|
+
config[key as keyof Config] = value;
|
|
41
|
+
|
|
42
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getSessionPath(customPath?: string): string {
|
|
46
|
+
// precedence:
|
|
47
|
+
// 1. custom path from flag
|
|
48
|
+
// 2. TELEGRAM_SESSION env var
|
|
49
|
+
// 3. global ~/.supertelegram/session.txt
|
|
50
|
+
// 4. local ./session.txt (backwards compat)
|
|
51
|
+
|
|
52
|
+
if (customPath) {
|
|
53
|
+
return customPath;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (process.env.TELEGRAM_SESSION) {
|
|
57
|
+
return process.env.TELEGRAM_SESSION;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// check if local session.txt exists (backwards compat)
|
|
61
|
+
if (existsSync("./session.txt")) {
|
|
62
|
+
return "./session.txt";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return SESSION_FILE;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function getApiCredentials(): { appId: number; appHash: string } | null {
|
|
69
|
+
// precedence:
|
|
70
|
+
// 1. env vars
|
|
71
|
+
// 2. global config
|
|
72
|
+
// 3. local .env (handled by process.env already)
|
|
73
|
+
|
|
74
|
+
const envAppId = process.env.TELEGRAM_APP_ID;
|
|
75
|
+
const envAppHash = process.env.TELEGRAM_APP_HASH;
|
|
76
|
+
|
|
77
|
+
if (envAppId && envAppHash) {
|
|
78
|
+
return {
|
|
79
|
+
appId: Number.parseInt(envAppId),
|
|
80
|
+
appHash: envAppHash,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const config = getConfig();
|
|
85
|
+
if (config.appId && config.appHash) {
|
|
86
|
+
return {
|
|
87
|
+
appId: Number.parseInt(config.appId),
|
|
88
|
+
appHash: config.appHash,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { CONFIG_DIR, CONFIG_FILE, SESSION_FILE };
|
package/src/session/storage.ts
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { getSessionPath } from "../config/manager";
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (existsSync(
|
|
7
|
-
return readFileSync(
|
|
5
|
+
export function loadSession(customPath?: string): string {
|
|
6
|
+
const sessionFile = getSessionPath(customPath);
|
|
7
|
+
|
|
8
|
+
if (existsSync(sessionFile)) {
|
|
9
|
+
return readFileSync(sessionFile, "utf-8").trim();
|
|
8
10
|
}
|
|
9
11
|
return "";
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
export function saveSession(session: string): void {
|
|
13
|
-
|
|
14
|
+
export function saveSession(session: string, customPath?: string): void {
|
|
15
|
+
const sessionFile = getSessionPath(customPath);
|
|
16
|
+
|
|
17
|
+
// ensure directory exists
|
|
18
|
+
const dir = dirname(sessionFile);
|
|
19
|
+
if (!existsSync(dir)) {
|
|
20
|
+
mkdirSync(dir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
writeFileSync(sessionFile, session, "utf-8");
|
|
14
24
|
}
|