tphim 2.1.0 → 2.2.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 CHANGED
@@ -5,6 +5,7 @@
5
5
  ## 🚀 Tính năng vượt trội
6
6
  - **Batch Pipeline:** Xử lý hàng loạt phim chỉ với 1 dòng lệnh.
7
7
  - **AI Subtitles:** Tự động tạo phụ đề Tiếng Việt/Tiếng Anh bằng công cụ AI (Whisper) chạy offline. Hỗ trợ bỏ qua phụ đề để tăng tốc độ.
8
+ - **Resume Upload:** Tự động lưu tiến trình upload, tiếp tục từ điểm dừng nếu bị gián đoạn.
8
9
  - **Cloud Ready:** Upload trực tiếp lên Tebi.io hoặc bất kỳ S3-compatible storage nào.
9
10
  - **Interactive CLI:** Giao diện terminal đẹp mắt với neon theme.
10
11
 
@@ -172,6 +173,7 @@ TEBI_PUBLIC_URL=https://your-bucket.tebi.io
172
173
  - Tự động fetch metadata từ video
173
174
  - Chọn ngôn ngữ phụ đề (VI/EN/Both/Skip)
174
175
  - Batch processing với progress bar
176
+ - **Resume Upload**: Tự động tiếp tục upload nếu bị gián đoạn
175
177
 
176
178
  **Help System:**
177
179
  ```bash
@@ -180,7 +182,31 @@ ntxa --help # Tương tự
180
182
  ntxa -h # Tương tự
181
183
  ```
182
184
 
185
+ ## 🔄 Resume Upload Feature
186
+
187
+ **Tự động lưu và khôi phục tiến trình upload:**
188
+
189
+ - **Progress Tracking**: Tạo file `.upload-progress.json` trong thư mục HLS
190
+ - **Smart Resume**: Chỉ upload những file chưa có trên cloud
191
+ - **Crash Recovery**: Nếu mất kết nối, chạy lại là tiếp tục từ điểm dừng
192
+ - **Auto Cleanup**: Xóa progress file khi upload hoàn tất
193
+
194
+ **Cách hoạt động:**
195
+ ```bash
196
+ # Lần đầu chạy
197
+ ☁️ Uploading 1227 files to Tebi.io... (0 already uploaded)
198
+ ↳ 107/1227 files...
199
+
200
+ # Nếu bị gián đoạn và chạy lại
201
+ 🔄 Found progress file. Resuming from 106 uploaded files...
202
+ ☁️ Uploading 1121 files to Tebi.io... (106 already uploaded)
203
+ ↳ 113/1227 files...
204
+
205
+ # Bỏ qua file đã tồn tại
206
+ ⏭ Skipping hls/test-phim-2024/1080p/index.m3u8 (already exists on cloud)
207
+ ```
208
+
183
209
  ---
184
210
 
185
- *Phát triển bởi TXA - Ultimate Video Pipeline 2030 v2.1.0* 🍿🎬
211
+ *Phát triển bởi TXA - Ultimate Video Pipeline 2030 v2.2.0* 🍿🎬
186
212
  *Last Update: February 2026*
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tphim",
3
- "version": "2.1.0",
4
- "description": "TPHIM - Ultimate Video Pipeline: Download, Transcode HLS, AI Subtitles (with skip option), and Cloud Upload.",
3
+ "version": "2.2.0",
4
+ "description": "TPHIM - Ultimate Video Pipeline: Download, Transcode HLS, AI Subtitles (with skip option), Resume Upload, and Cloud Upload.",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
7
  "bin": {
package/pro-terminal.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * NROTXA ULTIMATE CLI 2030 EDITION
4
- * High-performance, Neon-infused Video Pipeline
3
+ * NROTXA ULTIMATE CLI 2030 EDITION v2.2.0
4
+ * High-performance, Neon-infused Video Pipeline with Resume Upload
5
5
  */
6
6
 
7
7
  import * as p from '@clack/prompts';
@@ -111,7 +111,7 @@ function showHelp() {
111
111
  )
112
112
  );
113
113
 
114
- console.log(chalk.gray(' ⚡ TPHIM ULTIMATE VIDEO CORE v2.1.0 | STATUS: READY ⚡\n'));
114
+ console.log(chalk.gray(' ⚡ TPHIM ULTIMATE VIDEO CORE v2.2.0 | STATUS: READY ⚡\n'));
115
115
 
116
116
  console.log(`${neonPurple('📖 CÁCH SỬ DỤNG:')}`);
117
117
  console.log(chalk.cyan(' ntxa help - Hiển thị help này'));
@@ -131,6 +131,8 @@ function showHelp() {
131
131
  console.log(chalk.cyan(' • Download video từ multiple sources'));
132
132
  console.log(chalk.cyan(' • Transcode HLS 4-6 qualities'));
133
133
  console.log(chalk.cyan(' • AI Subtitle generation (Whisper)'));
134
+ console.log(chalk.cyan(' • Skip subtitle option (fast mode)'));
135
+ console.log(chalk.cyan(' • Resume upload (crash recovery)'));
134
136
  console.log(chalk.cyan(' • Upload cloud storage (Tebi.io)'));
135
137
  console.log(chalk.cyan(' • Batch processing support'));
136
138
  console.log(chalk.cyan(' • Proxy rotation tự động'));
@@ -168,7 +170,7 @@ async function main() {
168
170
  )
169
171
  );
170
172
 
171
- console.log(chalk.gray(' ⚡ NEON-INFUSED VIDEO CORE v2.1.0 | STATUS: READY ⚡\n'));
173
+ console.log(chalk.gray(' ⚡ NEON-INFUSED VIDEO CORE v2.2.0 | STATUS: READY ⚡\n'));
172
174
 
173
175
  p.intro(`${neonPurple('▣ SYSTEM INITIALIZED - BATCH MODE ENABLED')}`);
174
176
 
@@ -1,7 +1,7 @@
1
1
  // scripts/upload-tebi.mjs
2
2
  // Tebi.io S3-compatible — dùng @aws-sdk/client-s3 bình thường
3
- import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
4
- import { readdirSync, readFileSync } from 'fs';
3
+ import { S3Client, PutObjectCommand, HeadObjectCommand } from '@aws-sdk/client-s3';
4
+ import { readdirSync, readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs';
5
5
  import { join, extname, relative } from 'path';
6
6
  import { lookup } from 'mime-types';
7
7
  import 'dotenv/config';
@@ -19,14 +19,44 @@ const s3 = new S3Client({
19
19
  export async function uploadHLSFolder(slug) {
20
20
  const localDir = join('hls', slug);
21
21
  const files = getAllFiles(localDir);
22
+ const progressFile = join('hls', slug, '.upload-progress.json');
23
+
24
+ // Load existing progress
25
+ let uploadedFiles = [];
26
+ if (existsSync(progressFile)) {
27
+ try {
28
+ const progressData = JSON.parse(readFileSync(progressFile, 'utf-8'));
29
+ uploadedFiles = progressData.uploadedFiles || [];
30
+ console.log(`\n🔄 Found progress file. Resuming from ${uploadedFiles.length} uploaded files...`);
31
+ } catch (e) {
32
+ console.log('\n⚠ Progress file corrupted, starting fresh...');
33
+ }
34
+ }
22
35
 
23
- console.log(`\n☁️ Uploading ${files.length} files to Tebi.io...`);
24
- let uploaded = 0;
36
+ // Filter files that haven't been uploaded yet
37
+ const filesToUpload = files.filter(file => !uploadedFiles.includes(relative('.', file).replace(/\\/g, '/')));
38
+
39
+ console.log(`\n☁️ Uploading ${filesToUpload.length} files to Tebi.io... (${files.length - filesToUpload.length} already uploaded)`);
40
+ let uploaded = uploadedFiles.length;
25
41
 
26
- for (const filePath of files) {
42
+ for (const filePath of filesToUpload) {
27
43
  const s3Key = relative('.', filePath).replace(/\\/g, '/');
28
44
  const ext = extname(filePath).toLowerCase();
29
45
 
46
+ // Check if file already exists on cloud
47
+ try {
48
+ await s3.send(new HeadObjectCommand({
49
+ Bucket: process.env.TEBI_BUCKET,
50
+ Key: s3Key
51
+ }));
52
+ console.log(`\n ⏭ Skipping ${s3Key} (already exists on cloud)`);
53
+ uploaded++;
54
+ uploadedFiles.push(s3Key);
55
+ continue;
56
+ } catch (e) {
57
+ // File doesn't exist, proceed with upload
58
+ }
59
+
30
60
  const cacheMap = {
31
61
  '.ts': 'public, max-age=31536000',
32
62
  '.m3u8': 'public, max-age=300',
@@ -44,9 +74,30 @@ export async function uploadHLSFolder(slug) {
44
74
  }));
45
75
 
46
76
  uploaded++;
77
+ uploadedFiles.push(s3Key);
78
+
79
+ // Save progress after each successful upload
80
+ writeFileSync(progressFile, JSON.stringify({
81
+ uploadedFiles,
82
+ totalFiles: files.length,
83
+ lastUpdate: new Date().toISOString()
84
+ }));
85
+
47
86
  process.stdout.write(`\r ↳ ${uploaded}/${files.length} files...`);
48
87
  }
49
88
 
89
+ // Clean up progress file when complete
90
+ if (uploaded === files.length) {
91
+ try {
92
+ if (existsSync(progressFile)) {
93
+ unlinkSync(progressFile);
94
+ console.log('\n 🧹 Cleaned up progress file');
95
+ }
96
+ } catch (e) {
97
+ // Ignore cleanup error
98
+ }
99
+ }
100
+
50
101
  const base = process.env.TEBI_PUBLIC_URL;
51
102
  const masterName = `txa-${slug}.m3u8`;
52
103
  const finalMasterUrl = `${base}/hls/${slug}/${masterName}`;