@iksdev/shard-cli 0.1.4 → 0.1.5
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/bin/shard.js +94 -0
- package/package.json +1 -1
package/bin/shard.js
CHANGED
|
@@ -20,6 +20,7 @@ Usage:
|
|
|
20
20
|
shard login --username <name> --password <pass> [--server <url>]
|
|
21
21
|
shard whoami [--server <url>]
|
|
22
22
|
shard sync <folder> [--server <url>] [--dry-run] [--force] [--once] [--interval-ms <n>]
|
|
23
|
+
shard share <file> [--server <url>] [--limits <n>] [--temps <jours>]
|
|
23
24
|
shard logout
|
|
24
25
|
shard config show
|
|
25
26
|
shard config set-server <url>
|
|
@@ -29,6 +30,7 @@ Examples:
|
|
|
29
30
|
shard sync ./MonDossier
|
|
30
31
|
shard sync ./MonDossier --once
|
|
31
32
|
shard sync ./MonDossier --dry-run
|
|
33
|
+
shard share ./MonFichier.mp4 --limits 0 --temps 0
|
|
32
34
|
`);
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -288,6 +290,93 @@ async function uploadOneFile(server, token, file) {
|
|
|
288
290
|
});
|
|
289
291
|
}
|
|
290
292
|
|
|
293
|
+
async function findRemoteFileByNameAndSize(server, token, fileName, fileSize) {
|
|
294
|
+
const data = await httpJson(`${server}/api/files?limit=100&offset=0&sort=created_at&order=desc&search=${encodeURIComponent(fileName)}`, {
|
|
295
|
+
method: 'GET',
|
|
296
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
297
|
+
});
|
|
298
|
+
const rows = Array.isArray(data.files) ? data.files : [];
|
|
299
|
+
return rows.find((row) => row.original_name === fileName && Number(row.file_size || 0) === Number(fileSize || 0)) || null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function parseOptionalPositiveInt(raw, flagName) {
|
|
303
|
+
if (raw === undefined || raw === null) return undefined;
|
|
304
|
+
const n = parseInt(String(raw), 10);
|
|
305
|
+
if (Number.isNaN(n) || n < 0) {
|
|
306
|
+
throw new Error(`${flagName} doit etre un entier >= 0`);
|
|
307
|
+
}
|
|
308
|
+
return n;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async function shareFile(positionals, flags) {
|
|
312
|
+
const target = positionals[0];
|
|
313
|
+
if (!target) {
|
|
314
|
+
throw new Error('Usage: shard share <file> [--server <url>] [--limits <n>] [--temps <jours>]');
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const absPath = path.resolve(process.cwd(), target);
|
|
318
|
+
if (!(await pathExists(absPath))) {
|
|
319
|
+
throw new Error(`Fichier introuvable: ${absPath}`);
|
|
320
|
+
}
|
|
321
|
+
const st = await fsp.stat(absPath);
|
|
322
|
+
if (!st.isFile()) {
|
|
323
|
+
throw new Error(`Ce n'est pas un fichier: ${absPath}`);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const limits = parseOptionalPositiveInt(flags.limits, '--limits');
|
|
327
|
+
const temps = parseOptionalPositiveInt(flags.temps, '--temps');
|
|
328
|
+
|
|
329
|
+
const config = await readConfig();
|
|
330
|
+
const server = getServer(flags, config);
|
|
331
|
+
const token = getToken(config);
|
|
332
|
+
if (!token) {
|
|
333
|
+
throw new Error('Non connecte. Lance: shard login --username ... --password ...');
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
await httpJson(`${server}/api/auth/verify`, {
|
|
337
|
+
method: 'POST',
|
|
338
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const fileName = path.basename(absPath);
|
|
342
|
+
let remote = await findRemoteFileByNameAndSize(server, token, fileName, st.size);
|
|
343
|
+
let fileId = remote?.id || null;
|
|
344
|
+
|
|
345
|
+
if (!fileId) {
|
|
346
|
+
console.log(`Upload necessaire: ${fileName} (${formatBytes(st.size)})`);
|
|
347
|
+
const uploaded = await uploadOneFile(server, token, {
|
|
348
|
+
absPath,
|
|
349
|
+
relPath: fileName,
|
|
350
|
+
size: st.size,
|
|
351
|
+
mtimeMs: Math.round(st.mtimeMs)
|
|
352
|
+
});
|
|
353
|
+
fileId = uploaded?.file?.id;
|
|
354
|
+
if (!fileId) {
|
|
355
|
+
throw new Error('Upload reussi mais ID fichier manquant');
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const payload = { fileId };
|
|
360
|
+
if (limits !== undefined && limits > 0) payload.maxDownloads = limits;
|
|
361
|
+
if (temps !== undefined && temps > 0) payload.expiresInDays = temps;
|
|
362
|
+
|
|
363
|
+
const created = await httpJson(`${server}/api/share/create`, {
|
|
364
|
+
method: 'POST',
|
|
365
|
+
headers: {
|
|
366
|
+
Authorization: `Bearer ${token}`,
|
|
367
|
+
'Content-Type': 'application/json'
|
|
368
|
+
},
|
|
369
|
+
body: JSON.stringify(payload)
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
const share = created?.share || {};
|
|
373
|
+
console.log(`Partage cree pour: ${fileName}`);
|
|
374
|
+
if (share.url) console.log(`URL: ${share.url}`);
|
|
375
|
+
if (share.token) console.log(`Token: ${share.token}`);
|
|
376
|
+
console.log(`Limite downloads: ${limits && limits > 0 ? limits : 'illimitee'}`);
|
|
377
|
+
console.log(`Expiration: ${temps && temps > 0 ? `${temps} jour(s)` : 'aucune'}`);
|
|
378
|
+
}
|
|
379
|
+
|
|
291
380
|
function fileListToMap(files) {
|
|
292
381
|
const map = new Map();
|
|
293
382
|
for (const file of files) {
|
|
@@ -675,6 +764,11 @@ async function main() {
|
|
|
675
764
|
return;
|
|
676
765
|
}
|
|
677
766
|
|
|
767
|
+
if (command === 'share') {
|
|
768
|
+
await shareFile(positionals, flags);
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
|
|
678
772
|
if (command === 'config') {
|
|
679
773
|
const sub = positionals[0];
|
|
680
774
|
if (sub === 'show') {
|