@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 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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chunking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunking.d.ts","sourceRoot":"","sources":["../src/chunking.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ import { FileInfro } from "./crawler";
2
+ const CHUNK_SIZE = 2 * 1024 * 1024 * 1024; // 2 GB
3
+ console.log("Using chunk size:", CHUNK_SIZE, "bytes");
4
+ //# sourceMappingURL=chunking.js.map
@@ -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,6 @@
1
+ export interface FileInfro {
2
+ path: string;
3
+ size: number;
4
+ }
5
+ export declare function crawl(target: string, files?: FileInfro[]): Promise<FileInfro[]>;
6
+ //# sourceMappingURL=crawler.d.ts.map
@@ -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"}
@@ -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
+ }