ani-auto 1.2.2 → 1.2.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +84 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ani-auto",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Automatic anime episode downloader",
5
5
  "bin": {
6
6
  "ani-auto": "./src/cli.js"
package/src/cli.js CHANGED
@@ -68,17 +68,18 @@ program
68
68
  }]);
69
69
  anilistToken = tokenAnswer.anilistToken;
70
70
 
71
+ console.log(chalk.gray(' Tip: select multiple statuses with space, confirm with enter.'));
71
72
  const statusAnswer = await inquirer.prompt([{
72
- type: 'list', name: 'watchStatuses',
73
- message: 'Which AniList status to download?',
73
+ type: 'checkbox',
74
+ name: 'watchStatuses',
75
+ message: 'Which AniList statuses to download?',
74
76
  choices: [
75
- { name: 'CURRENT (Watching)', value: 'CURRENT' },
76
- { name: 'PLANNING (Plan to Watch)', value: 'PLANNING' },
77
- { name: 'PAUSED', value: 'PAUSED' },
78
- { name: 'REPEATING', value: 'REPEATING' },
77
+ { name: 'CURRENT (Watching)', value: 'CURRENT', checked: (current.watchStatuses || ['CURRENT']).includes('CURRENT') },
78
+ { name: 'PLANNING (Plan to Watch)', value: 'PLANNING', checked: (current.watchStatuses || []).includes('PLANNING') },
79
+ { name: 'PAUSED', value: 'PAUSED', checked: (current.watchStatuses || []).includes('PAUSED') },
80
+ { name: 'REPEATING', value: 'REPEATING', checked: (current.watchStatuses || []).includes('REPEATING') },
79
81
  ],
80
- default: (current.watchStatuses || ['CURRENT'])[0],
81
- filter: v => [v],
82
+ validate: v => v.length > 0 ? true : 'Select at least one status',
82
83
  }]);
83
84
  watchStatuses = statusAnswer.watchStatuses;
84
85
  }
@@ -153,7 +154,6 @@ program
153
154
  console.log(chalk.green(` ✔ Saved default quality: ${quality}\n`));
154
155
  }
155
156
 
156
- // Status selection for this run
157
157
  const { pickedStatuses } = await inquirer.prompt([{
158
158
  type: 'checkbox',
159
159
  name: 'pickedStatuses',
@@ -257,8 +257,32 @@ program
257
257
  const config = loadConfig();
258
258
  const manualList = config.manualList || [];
259
259
 
260
- const exists = manualList.find(m => m.title.toLowerCase() === resolvedTitle.toLowerCase());
261
- if (exists) { console.log(chalk.yellow(` ${resolvedTitle} is already in your manual list.`)); return; }
260
+ const existsManual = manualList.find(m => m.title.toLowerCase() === resolvedTitle.toLowerCase());
261
+ if (existsManual) { console.log(chalk.yellow(` "${resolvedTitle}" is already in your manual list.`)); return; }
262
+
263
+ // Check if already in AniList watch list (fuzzy match)
264
+ const normalize = s => s.toLowerCase().replace(/[^a-z0-9]/g, '');
265
+ const { getUserList, pickTitle: pt } = require('./anilist');
266
+ if (config.anilistUsername) {
267
+ try {
268
+ const anilistEntries = await getUserList(
269
+ config.anilistUsername,
270
+ ['CURRENT', 'PLANNING', 'PAUSED', 'REPEATING'],
271
+ config.anilistToken || null
272
+ );
273
+ const normResolved = normalize(resolvedTitle);
274
+ const inAnilist = anilistEntries.find(e => {
275
+ const t = e.titles;
276
+ return [t.english, t.romaji, t.native].some(
277
+ title => title && normalize(title) === normResolved
278
+ );
279
+ });
280
+ if (inAnilist) {
281
+ console.log(chalk.yellow(` "${resolvedTitle}" is already in your AniList list (${inAnilist.status}) — no need to add manually.`));
282
+ return;
283
+ }
284
+ } catch (e) {}
285
+ }
262
286
 
263
287
  const entry = { title: resolvedTitle, anilistId: picked.anilistId, enabled: true, quality: opts.quality || null, language: opts.language || null };
264
288
  manualList.push(entry);
@@ -411,6 +435,55 @@ program
411
435
  console.log('');
412
436
  });
413
437
 
438
+ // ── update ───────────────────────────────────────────────────────────────
439
+
440
+ program
441
+ .command('update')
442
+ .description('Check for updates and install the latest version')
443
+ .action(async () => {
444
+ banner();
445
+ const fetch = require('node-fetch');
446
+ const { execSync } = require('child_process');
447
+
448
+ const spinner = ora('Checking for updates...').start();
449
+ try {
450
+ const res = await fetch('https://registry.npmjs.org/ani-auto/latest');
451
+ const data = await res.json();
452
+ const latest = data.version;
453
+ spinner.stop();
454
+
455
+ if (latest === version) {
456
+ console.log(chalk.green(` ✔ Already on the latest version (v${version}).\n`));
457
+ return;
458
+ }
459
+
460
+ console.log(chalk.cyan(` Current version: ${chalk.bold(version)}`));
461
+ console.log(chalk.cyan(` Latest version: ${chalk.bold(latest)}\n`));
462
+
463
+ const { confirm } = await inquirer.prompt([{
464
+ type: 'confirm',
465
+ name: 'confirm',
466
+ message: `Update to v${latest}?`,
467
+ default: true,
468
+ }]);
469
+
470
+ if (!confirm) return;
471
+
472
+ const installing = ora(`Installing v${latest}...`).start();
473
+ try {
474
+ execSync('npm install -g ani-auto@latest', { stdio: 'pipe' });
475
+ installing.succeed(`Updated to v${latest} — restart your terminal to use the new version.`);
476
+ } catch (e) {
477
+ installing.fail('Update failed. Try manually: npm install -g ani-auto@latest');
478
+ }
479
+ } catch (e) {
480
+ spinner.fail(`Could not check for updates: ${e.message}`);
481
+ }
482
+ console.log('');
483
+ });
484
+
485
+ // ── daemon ────────────────────────────────────────────────────────────────
486
+
414
487
  program
415
488
  .command('daemon')
416
489
  .description('Start the background daemon')