@ayush24k/telezipper 1.1.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 +110 -0
- package/dist/bin/zipper.js +34 -0
- package/dist/chunking.d.ts +2 -0
- package/dist/chunking.d.ts.map +1 -0
- package/dist/chunking.js +4 -0
- package/dist/chunking.js.map +1 -0
- package/dist/crawler.d.ts +6 -0
- package/dist/crawler.d.ts.map +1 -0
- package/dist/crawler.js +16 -0
- package/dist/crawler.js.map +1 -0
- package/dist/src/chunking.js +26 -0
- package/dist/src/crawler.js +21 -0
- package/dist/src/telegramUploader.js +33 -0
- package/dist/src/zipper.js +47 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# TeleZipper
|
|
2
|
+
|
|
3
|
+
Split folders into multiple 2GB zip files with optional Telegram upload.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install globally using npm link:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cd /path/to/telezipper
|
|
11
|
+
npm install
|
|
12
|
+
npm run build
|
|
13
|
+
npm link
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Now you can use `telezipper` from anywhere on your system!
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Basic Usage (Zip only)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
telezipper <source> -o <output-directory>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
```bash
|
|
28
|
+
telezipper ./my-folder -o ./output
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### With Telegram Upload
|
|
32
|
+
|
|
33
|
+
You can provide Telegram credentials in two ways:
|
|
34
|
+
|
|
35
|
+
#### Option 1: Command-line arguments (Recommended for flexibility)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
telezipper <source> --telegram --bot-token YOUR_BOT_TOKEN --chat-id YOUR_CHAT_ID
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Example:
|
|
42
|
+
```bash
|
|
43
|
+
telezipper ./my-folder --telegram --bot-token 123456:ABC-DEF1234ghIkl --chat-id 987654321
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### Option 2: Environment variables
|
|
47
|
+
|
|
48
|
+
Create a `.env` file in the project directory or set environment variables:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
TELEGRAM_BOT_TOKEN=your_bot_token_here
|
|
52
|
+
TELEGRAM_CHAT_ID=your_chat_id_here
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Then run:
|
|
56
|
+
```bash
|
|
57
|
+
telezipper ./my-folder --telegram
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Options
|
|
61
|
+
|
|
62
|
+
- `<source>` - File or folder to zip (required)
|
|
63
|
+
- `-o, --output <dir>` - Output directory (default: "output")
|
|
64
|
+
- `--telegram` - Upload zip files to Telegram
|
|
65
|
+
- `--bot-token <token>` - Telegram bot token (required if using --telegram without env vars)
|
|
66
|
+
- `--chat-id <id>` - Telegram chat ID (required if using --telegram without env vars)
|
|
67
|
+
- `-h, --help` - Display help
|
|
68
|
+
|
|
69
|
+
## Examples
|
|
70
|
+
|
|
71
|
+
### Zip a folder to the default output directory
|
|
72
|
+
```bash
|
|
73
|
+
telezipper ./my-project
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Zip and specify custom output directory
|
|
77
|
+
```bash
|
|
78
|
+
telezipper ./my-project -o ./backups
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Zip and upload to Telegram with inline credentials
|
|
82
|
+
```bash
|
|
83
|
+
telezipper ./my-project --telegram --bot-token 123456:ABC-DEF --chat-id 987654321
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Zip and upload using environment variables
|
|
87
|
+
```bash
|
|
88
|
+
# Set environment variables first
|
|
89
|
+
export TELEGRAM_BOT_TOKEN=123456:ABC-DEF
|
|
90
|
+
export TELEGRAM_CHAT_ID=987654321
|
|
91
|
+
|
|
92
|
+
# Then run
|
|
93
|
+
telezipper ./my-project --telegram
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## How to Get Telegram Credentials
|
|
97
|
+
|
|
98
|
+
1. **Bot Token**: Create a bot using [@BotFather](https://t.me/botfather) on Telegram
|
|
99
|
+
2. **Chat ID**:
|
|
100
|
+
- Send a message to your bot
|
|
101
|
+
- Visit `https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates`
|
|
102
|
+
- Find your chat ID in the response
|
|
103
|
+
|
|
104
|
+
## Features
|
|
105
|
+
|
|
106
|
+
- ✅ Automatically splits large folders into 2GB chunks
|
|
107
|
+
- ✅ Creates zip files with maximum compression
|
|
108
|
+
- ✅ Optional Telegram upload with progress bars
|
|
109
|
+
- ✅ Works from any directory on your system
|
|
110
|
+
- ✅ Flexible credential management (CLI args or env vars)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
require("dotenv/config");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const commander_1 = require("commander");
|
|
10
|
+
const crawler_1 = require("../src/crawler");
|
|
11
|
+
const chunking_1 = require("../src/chunking");
|
|
12
|
+
const zipper_1 = require("../src/zipper");
|
|
13
|
+
const program = new commander_1.Command();
|
|
14
|
+
program
|
|
15
|
+
.argument("<source>", "File or folder to zip")
|
|
16
|
+
.option("-o, --output <dir>", "Output directory", "output")
|
|
17
|
+
.option("--telegram", "Upload zip files to Telegram")
|
|
18
|
+
.option("--bot-token <token>", "Telegram bot token (required if using --telegram)")
|
|
19
|
+
.option("--chat-id <id>", "Telegram chat ID (required if using --telegram)")
|
|
20
|
+
.parse();
|
|
21
|
+
(async () => {
|
|
22
|
+
const source = path_1.default.resolve(program.args[0]);
|
|
23
|
+
const outputDir = path_1.default.resolve(program.opts().output);
|
|
24
|
+
const useTelegram = program.opts().telegram || false;
|
|
25
|
+
const botToken = program.opts().botToken;
|
|
26
|
+
const chatId = program.opts().chatId;
|
|
27
|
+
console.log(`🕸️ Crawling files in ${source}...`);
|
|
28
|
+
const files = await (0, crawler_1.crawl)(source);
|
|
29
|
+
console.log(`📂 Found ${files.length} files. Chunking...`);
|
|
30
|
+
const chunks = (0, chunking_1.chunkFiles)(files);
|
|
31
|
+
console.log(`📦 Created ${chunks.length} chunks. Zipping...`);
|
|
32
|
+
await (0, zipper_1.zipChunks)(chunks, outputDir, useTelegram, botToken, chatId);
|
|
33
|
+
console.log("🎉 process done!");
|
|
34
|
+
})();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunking.d.ts","sourceRoot":"","sources":["../src/chunking.ts"],"names":[],"mappings":""}
|
package/dist/chunking.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunking.js","sourceRoot":"","sources":["../src/chunking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO;AAElD,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crawler.d.ts","sourceRoot":"","sources":["../src/crawler.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB;AAID,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,SAAS,EAAO,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAezF"}
|
package/dist/crawler.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
// walks folder recursively and returns list of files with their sizes
|
|
4
|
+
export async function crawl(target, files = []) {
|
|
5
|
+
const stats = fs.statSync(target);
|
|
6
|
+
if (stats.isFile()) {
|
|
7
|
+
files.push({ path: target, size: stats.size });
|
|
8
|
+
return files;
|
|
9
|
+
}
|
|
10
|
+
const entries = fs.readdirSync(target);
|
|
11
|
+
for (const entry of entries) {
|
|
12
|
+
await crawl(path.join(target, entry), files);
|
|
13
|
+
}
|
|
14
|
+
return files;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=crawler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crawler.js","sourceRoot":"","sources":["../src/crawler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AASxB,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,MAAc,EAAE,QAAqB,EAAE;IAC/D,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAElC,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAC,CAAC,CAAC;QAC7C,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAEvC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAC,CAAC;QACzB,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.chunkFiles = chunkFiles;
|
|
4
|
+
const CHUNK_SIZE = 2 * 1024 * 1024 * 1024; // 2 GB
|
|
5
|
+
// groups files into chunks where the total size of each chunk does not exceed CHUNK_SIZE
|
|
6
|
+
function chunkFiles(files) {
|
|
7
|
+
const chunks = [];
|
|
8
|
+
let currentChunk = [];
|
|
9
|
+
let currentChunkSize = 0;
|
|
10
|
+
for (const file of files) {
|
|
11
|
+
if (file.size > CHUNK_SIZE) {
|
|
12
|
+
throw new Error(`File ${file.path} exceeds the maximum chunk size of 2GB.`);
|
|
13
|
+
}
|
|
14
|
+
if (currentChunkSize + file.size > CHUNK_SIZE) {
|
|
15
|
+
chunks.push(currentChunk);
|
|
16
|
+
currentChunk = [];
|
|
17
|
+
currentChunkSize = 0;
|
|
18
|
+
}
|
|
19
|
+
currentChunk.push(file);
|
|
20
|
+
currentChunkSize += file.size;
|
|
21
|
+
}
|
|
22
|
+
if (currentChunk.length > 0) {
|
|
23
|
+
chunks.push(currentChunk);
|
|
24
|
+
}
|
|
25
|
+
return chunks;
|
|
26
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.crawl = crawl;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
// walks folder recursively and returns list of files with their sizes
|
|
10
|
+
async function crawl(target, files = []) {
|
|
11
|
+
const stats = fs_1.default.statSync(target);
|
|
12
|
+
if (stats.isFile()) {
|
|
13
|
+
files.push({ path: target, size: stats.size });
|
|
14
|
+
return files;
|
|
15
|
+
}
|
|
16
|
+
const entries = fs_1.default.readdirSync(target);
|
|
17
|
+
for (const entry of entries) {
|
|
18
|
+
await crawl(path_1.default.join(target, entry), files);
|
|
19
|
+
}
|
|
20
|
+
return files;
|
|
21
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.uploadToTelegram = uploadToTelegram;
|
|
7
|
+
const node_telegram_bot_api_1 = __importDefault(require("node-telegram-bot-api"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const cli_progress_1 = __importDefault(require("cli-progress"));
|
|
10
|
+
// upload a zip file to telegram with progress bar
|
|
11
|
+
async function uploadToTelegram(zipPath, botToken, chatId) {
|
|
12
|
+
const bot_token = botToken || process.env.TELEGRAM_BOT_TOKEN || "";
|
|
13
|
+
const chat_id = chatId || process.env.TELEGRAM_CHAT_ID || "";
|
|
14
|
+
if (!bot_token || !chat_id) {
|
|
15
|
+
throw new Error("Telegram credentials are missing. Please provide --bot-token and --chat-id or set TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID environment variables.");
|
|
16
|
+
}
|
|
17
|
+
const bot = new node_telegram_bot_api_1.default(bot_token, { polling: false });
|
|
18
|
+
const totalSize = fs_1.default.statSync(zipPath).size;
|
|
19
|
+
console.log(`📤 Uploading ${zipPath}`);
|
|
20
|
+
const progressBar = new cli_progress_1.default.SingleBar({
|
|
21
|
+
format: "Uploading [{bar}] {percentage}% | {value}/{total} Bytes",
|
|
22
|
+
}, cli_progress_1.default.Presets.shades_classic);
|
|
23
|
+
progressBar.start(totalSize, 0);
|
|
24
|
+
const stream = fs_1.default.createReadStream(zipPath);
|
|
25
|
+
let uploaded = 0;
|
|
26
|
+
stream.on("data", (chunk) => {
|
|
27
|
+
uploaded += chunk.length;
|
|
28
|
+
progressBar.update(uploaded);
|
|
29
|
+
});
|
|
30
|
+
await bot.sendDocument(chat_id, stream);
|
|
31
|
+
progressBar.stop();
|
|
32
|
+
console.log("✅ Upload complete");
|
|
33
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.zipChunks = zipChunks;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const cli_progress_1 = __importDefault(require("cli-progress"));
|
|
10
|
+
const archiver_1 = __importDefault(require("archiver"));
|
|
11
|
+
const telegramUploader_1 = require("./telegramUploader");
|
|
12
|
+
async function zipChunks(chunks, outputDir, useTelegram, botToken, chatId) {
|
|
13
|
+
fs_1.default.mkdirSync(outputDir, { recursive: true });
|
|
14
|
+
const uploadQueue = [];
|
|
15
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
16
|
+
const zipName = `chunk_${i + 1}.zip`;
|
|
17
|
+
const zipPath = path_1.default.join(outputDir, zipName);
|
|
18
|
+
console.log(`📦 Zipping ${zipName}`);
|
|
19
|
+
const progressBar = new cli_progress_1.default.SingleBar({
|
|
20
|
+
format: `Zipping ${zipName} [{bar}] {percentage}% | {value}/{total} files`,
|
|
21
|
+
}, cli_progress_1.default.Presets.shades_classic);
|
|
22
|
+
progressBar.start(chunks[i].length, 0);
|
|
23
|
+
await new Promise((resolve, reject) => {
|
|
24
|
+
const output = fs_1.default.createWriteStream(zipPath);
|
|
25
|
+
const archive = (0, archiver_1.default)("zip", { zlib: { level: 9 } });
|
|
26
|
+
archive.pipe(output);
|
|
27
|
+
output.on("close", () => {
|
|
28
|
+
progressBar.stop();
|
|
29
|
+
if (useTelegram) {
|
|
30
|
+
uploadQueue.push((0, telegramUploader_1.uploadToTelegram)(zipPath, botToken, chatId));
|
|
31
|
+
}
|
|
32
|
+
;
|
|
33
|
+
resolve();
|
|
34
|
+
});
|
|
35
|
+
archive.on("error", reject);
|
|
36
|
+
chunks[i].forEach((file, index) => {
|
|
37
|
+
archive.file(file.path, { name: path_1.default.basename(file.path) });
|
|
38
|
+
progressBar.increment();
|
|
39
|
+
});
|
|
40
|
+
archive.finalize();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
if (useTelegram) {
|
|
44
|
+
console.log("🚀 Uploading all zips to Telegram...");
|
|
45
|
+
await Promise.all(uploadQueue);
|
|
46
|
+
}
|
|
47
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ayush24k/telezipper",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Split folders into multiple 2GB zip files with optional Telegram upload made for personal use.",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"bin": {
|
|
9
|
+
"telezipper": "dist/bin/zipper.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
13
|
+
"build": "tsc"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [],
|
|
16
|
+
"author": "",
|
|
17
|
+
"license": "ISC",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"archiver": "^7.0.1",
|
|
20
|
+
"cli-progress": "^3.12.0",
|
|
21
|
+
"commander": "^14.0.2",
|
|
22
|
+
"dotenv": "^17.2.3",
|
|
23
|
+
"node-telegram-bot-api": "^0.67.0",
|
|
24
|
+
"tough-cookie": "^2.5.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/archiver": "^7.0.0",
|
|
28
|
+
"@types/cli-progress": "^3.11.6",
|
|
29
|
+
"@types/node": "^25.1.0",
|
|
30
|
+
"@types/node-telegram-bot-api": "^0.64.13",
|
|
31
|
+
"typescript": "^5.9.3"
|
|
32
|
+
}
|
|
33
|
+
}
|