first commit
This commit is contained in:
commit
8f201b59e3
38
.gitignore
vendored
Normal file
38
.gitignore
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Node modules
|
||||||
|
node_modules/
|
||||||
|
.wwebjs_auth/
|
||||||
|
.wwebjs_cache/
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
app.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Editor / IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
|
||||||
|
# Build / cache
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.cache/
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
*.bak
|
||||||
|
|
||||||
|
credentials.json
|
||||||
|
token.json
|
||||||
85
README.md
Normal file
85
README.md
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# WhatsApp -> Google Drive batch uploader (Baileys, `mcb` commands)
|
||||||
|
|
||||||
|
Uploads files from WhatsApp chats into structured Google Drive folders using batch commands.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
- User-friendly (case-insensitive): `start`, `done`, `cancel`, `status`, `help`
|
||||||
|
- Also supported fallback: `mcb-*` and legacy `hi mcb` / `bye mcb`
|
||||||
|
- Batch management:
|
||||||
|
- `rename <folder-name>` -> change active batch target folder
|
||||||
|
- `list` -> show queued file names and sizes
|
||||||
|
- `undo` -> remove last queued file
|
||||||
|
- `retry-failed` -> retry previously failed uploads
|
||||||
|
- Project/admin:
|
||||||
|
- `mcb-project <name>` -> set/save a project folder
|
||||||
|
- `admin-stats` -> today + lifetisw
|
||||||
|
me operational stats
|
||||||
|
- `admin-stats 7d` -> rolling summary for last N days (example: `7d`)
|
||||||
|
- `admin-stats YYYY-MM-DD` -> stats for a specific date
|
||||||
|
- `admin-health` -> live ops snapshot (heartbeat, queues, alerts)
|
||||||
|
|
||||||
|
## Local setup (Windows/Linux)
|
||||||
|
1) Install dependencies:
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
2) Create `.env` (example values):
|
||||||
|
```env
|
||||||
|
GOOGLE_CREDENTIALS=./credentials.json
|
||||||
|
GOOGLE_TOKEN=./token.json
|
||||||
|
DEFAULT_ROOT_FOLDER=Whatsapp-Drive
|
||||||
|
WA_CLIENT_ID=MCB-bot
|
||||||
|
BAILEYS_AUTH_DIR=./baileys_auth
|
||||||
|
OWNER_NUMBER=
|
||||||
|
BATCH_TTL_MIN=30
|
||||||
|
IDLE_RESTART_CHECK_MIN=60
|
||||||
|
IDLE_RESTART_MIN=240
|
||||||
|
IDLE_RESTART_MAX_PER_DAY=6
|
||||||
|
DOWNLOAD_TIMEOUT_MS=900000
|
||||||
|
DOWNLOAD_MAX_RETRIES=2
|
||||||
|
DOWNLOAD_RETRY_DELAY_MS=5000
|
||||||
|
MAX_MEDIA_MB=95
|
||||||
|
WA_PROTOCOL_TIMEOUT=9000000
|
||||||
|
WA_INIT_RETRIES=3
|
||||||
|
WA_INIT_RETRY_DELAY_MS=5000
|
||||||
|
WA_HEADLESS=true
|
||||||
|
LOG_DIR=./logs
|
||||||
|
HEARTBEAT_INTERVAL_SEC=60
|
||||||
|
RETRY_MAX_ITEMS=200
|
||||||
|
SMART_SUBFOLDERS=true
|
||||||
|
FAIL_ALERT_WINDOW=10
|
||||||
|
FAIL_ALERT_THRESHOLD_PCT=20
|
||||||
|
FAIL_ALERT_COOLDOWN_MIN=30
|
||||||
|
# Optional on Linux VPS if Chromium is not auto-detected:
|
||||||
|
# WA_EXECUTABLE_PATH=/usr/bin/chromium-browser
|
||||||
|
```
|
||||||
|
|
||||||
|
3) Put Google OAuth client JSON at `credentials.json`.
|
||||||
|
|
||||||
|
4) Generate Drive token:
|
||||||
|
```bash
|
||||||
|
npm run auth
|
||||||
|
```
|
||||||
|
|
||||||
|
5) Start bot:
|
||||||
|
```bash
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
## Linux VPS notes
|
||||||
|
- Install Chromium/Chrome and required libraries for Puppeteer.
|
||||||
|
- If Chromium path is custom, set `WA_EXECUTABLE_PATH`.
|
||||||
|
- Use a process manager (for example PM2/systemd) for auto-restart.
|
||||||
|
|
||||||
|
## Runtime notes
|
||||||
|
- Temporary files are written under your OS temp directory (`MCB-batches`).
|
||||||
|
- Upload target folders are auto-created in Drive.
|
||||||
|
- Uploaded folder gets read-only public link (`anyone` with `reader` role).
|
||||||
|
- Duplicate protection is enabled per batch (same filename + size is skipped).
|
||||||
|
- Failed uploads are moved to retry queue and can be retried with `retry-failed`.
|
||||||
|
- Structured rotating logs are written to `logs/app-YYYY-MM-DD.jsonl`.
|
||||||
|
- Heartbeat logs are emitted periodically for VPS monitoring.
|
||||||
|
- Uploads are auto-organized into Drive subfolders by date + event type (`Invoices`, `Photos`, `Documents`).
|
||||||
|
- Active upload sessions are restored from disk after process restart (within batch TTL).
|
||||||
|
- Owner receives failure alerts when recent upload failures exceed configured threshold.
|
||||||
46
auth.js
Normal file
46
auth.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const readline = require("readline");
|
||||||
|
const { google } = require("googleapis");
|
||||||
|
require("dotenv").config();
|
||||||
|
|
||||||
|
const CREDENTIALS_PATH = process.env.GOOGLE_CREDENTIALS || "./credentials.json";
|
||||||
|
const TOKEN_PATH = process.env.GOOGLE_TOKEN || "./token.json";
|
||||||
|
|
||||||
|
function loadCredentials() {
|
||||||
|
const raw = fs.readFileSync(CREDENTIALS_PATH, "utf8");
|
||||||
|
const json = JSON.parse(raw);
|
||||||
|
const cfg = json.installed || json.web;
|
||||||
|
if (!cfg) throw new Error("Invalid credentials.json. Expected installed/web client.");
|
||||||
|
return {
|
||||||
|
client_id: cfg.client_id,
|
||||||
|
client_secret: cfg.client_secret,
|
||||||
|
redirect_uris: cfg.redirect_uris,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const { client_id, client_secret, redirect_uris } = loadCredentials();
|
||||||
|
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);
|
||||||
|
|
||||||
|
const authUrl = oAuth2Client.generateAuthUrl({
|
||||||
|
access_type: "offline",
|
||||||
|
scope: ["https://www.googleapis.com/auth/drive.file"],
|
||||||
|
prompt: "consent",
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Authorize this app by visiting this url:\n", authUrl, "\n");
|
||||||
|
|
||||||
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
||||||
|
rl.question("Paste the code from the page here: ", async (code) => {
|
||||||
|
rl.close();
|
||||||
|
const { tokens } = await oAuth2Client.getToken(code.trim());
|
||||||
|
fs.writeFileSync(TOKEN_PATH, JSON.stringify(tokens, null, 2));
|
||||||
|
console.log("✅ Token stored at:", path.resolve(TOKEN_PATH));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((e) => {
|
||||||
|
console.error("Auth error:", e);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
2
logs/app-2026-04-18.jsonl
Normal file
2
logs/app-2026-04-18.jsonl
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
{"ts":"2026-04-18T19:38:36.046Z","level":"INFO","message":"QR received. Scan to login."}
|
||||||
|
{"ts":"2026-04-18T19:38:41.454Z","level":"WARN","message":"SIGINT received, cleaning up."}
|
||||||
1997
package-lock.json
generated
Normal file
1997
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
package.json
Normal file
18
package.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "whatsdrive-baileys",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "WhatsApp -> Google Drive batch uploader (Baileys)",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node index.js",
|
||||||
|
"auth": "node auth.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@whiskeysockets/baileys": "^6.7.18",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"googleapis": "^140.0.0",
|
||||||
|
"mime-types": "^2.1.35",
|
||||||
|
"pino": "^9.3.2",
|
||||||
|
"qrcode-terminal": "^0.12.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
50
state copy.json
Normal file
50
state copy.json
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"users": {
|
||||||
|
"15192773600@c.us": {
|
||||||
|
"projectName": null,
|
||||||
|
"folderId": null,
|
||||||
|
"lastBatchFolderName": "2 tier chocolate vegan Star Wars cake",
|
||||||
|
"lastBatchFolderId": "1oJufpdl2yuyZTOEejVv22rKMEf7o6LAV"
|
||||||
|
},
|
||||||
|
"14374329515@c.us": {
|
||||||
|
"projectName": null,
|
||||||
|
"folderId": null,
|
||||||
|
"lastBatchFolderName": "social currency",
|
||||||
|
"lastBatchFolderId": "1iUdfbHOCg3Cambad7DhmDla9wCBPtk_0"
|
||||||
|
},
|
||||||
|
"918220348218@c.us": {
|
||||||
|
"projectName": null,
|
||||||
|
"folderId": null,
|
||||||
|
"lastBatchFolderName": "mohan",
|
||||||
|
"lastBatchFolderId": "1MxGKRFjb60x2pcCySc6DBTC_c2qXzG0L"
|
||||||
|
},
|
||||||
|
"16476796537@c.us": {
|
||||||
|
"projectName": null,
|
||||||
|
"folderId": null,
|
||||||
|
"lastBatchFolderName": "Manesh",
|
||||||
|
"lastBatchFolderId": "1VylDIP7pvKtNa2WV-lAK6f6gNaU9pZ0V"
|
||||||
|
},
|
||||||
|
"919585967575@c.us": {
|
||||||
|
"projectName": null,
|
||||||
|
"folderId": null,
|
||||||
|
"lastBatchFolderName": "Vijay testing",
|
||||||
|
"lastBatchFolderId": "12zRnuoeIhudGLbKckMciYLDxd7zLJpVA"
|
||||||
|
},
|
||||||
|
"16476229848@c.us": {
|
||||||
|
"projectName": null,
|
||||||
|
"folderId": null,
|
||||||
|
"lastBatchFolderName": "Clickstogarlands",
|
||||||
|
"lastBatchFolderId": "1fs-6-2FA6RkioHR2Ybo7Q1xGp6ftCU7B"
|
||||||
|
},
|
||||||
|
"15198976975@c.us": {
|
||||||
|
"projectName": null,
|
||||||
|
"folderId": null,
|
||||||
|
"lastBatchFolderName": "TCA _sportsday",
|
||||||
|
"lastBatchFolderId": "1JVzN_9KHMIm0jDQZL0UthM_jCJDkV8Dz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"restartStats": {
|
||||||
|
"date": "2026-04-17",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
20
state.json
Normal file
20
state.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"users": {},
|
||||||
|
"analytics": {
|
||||||
|
"daily": {},
|
||||||
|
"lifetime": {
|
||||||
|
"batchesStarted": 0,
|
||||||
|
"batchesCompleted": 0,
|
||||||
|
"filesQueued": 0,
|
||||||
|
"filesUploaded": 0,
|
||||||
|
"filesFailed": 0,
|
||||||
|
"uploadBytes": 0,
|
||||||
|
"completedBatchFilesTotal": 0
|
||||||
|
},
|
||||||
|
"uploadOutcomes": [],
|
||||||
|
"alerts": {
|
||||||
|
"lastFailureAlertAt": 0,
|
||||||
|
"lastFailureRate": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user