Harden auth, add AI smart-search and post-download organization

Security & correctness hardening:
- Gate /__api/token/auth behind auth and self-scope every handler to the
  caller (was fully unauthenticated — account-takeover hole).
- Escape LDAP filter values (injection) and reject empty-password binds.
- Enforce per-torrent ownership so private torrents aren't exposed via IDOR.
- Assorted cleanup: fix 'use static' typos, drop dead Torrent.migrate + the
  getTorrentData noUpdate flag, Buffer.alloc, __dirname-relative reads,
  res.statusCode in the error handler, const-scope pubsub.

Login-gated proxy + anti-indexing:
- Block all proxying for logged-out users via an auth-token cookie the front
  end mirrors from its token; serve a local login page instead of hitting TPB.
- robots.txt disallow-all + X-Robots-Tag noindex.

Torrent category:
- Store a normalized category (TV/Movie/Music/Adult/App/Game/Other) mapped
  from the TPB category id; captured at add time (migration).

Smart Search (movies/TV):
- New /__api/search: TMDB title confirm -> scrape piratebay.party HTML ->
  Ollama ranks releases against quality prefs (x265/1080p/~1.5GB/subs,
  prefer uncut) returning a recommended pick, optional warned 4K, and other
  editions. Front-end Smart Search box + dialog feeding the existing add flow.

Post-download organization -> Emby (public Movie/TV only):
- Completion watcher files finished torrents: Ollama parses the release name,
  TMDB canonicalizes title/year, files main video (+subs) into the library
  with edition/quality-aware names (movies + TV SxxExx), stops seeding, and
  triggers an Emby library scan. Low-confidence matches are flagged, not
  mis-filed; correctable via "Fix match". Adds organizedAt/metadata columns.

Shared helpers: controller/tmdb.js, controller/ollama.js. Config blocks for
tmdb/ollama/search/emby/library/organize (secrets stay in gitignored secrets.js).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 14:19:13 -04:00
parent b30fe748b2
commit fd5ef14999
21 changed files with 1144 additions and 70 deletions
@@ -0,0 +1,14 @@
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.addColumn('Torrents', 'category', {
type: Sequelize.STRING,
allowNull: false,
defaultValue: 'Other'
});
},
async down(queryInterface, Sequelize) {
await queryInterface.removeColumn('Torrents', 'category');
}
};
@@ -0,0 +1,18 @@
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.addColumn('Torrents', 'organizedAt', {
type: Sequelize.DATE,
allowNull: true,
});
await queryInterface.addColumn('Torrents', 'metadata', {
type: Sequelize.JSON,
allowNull: true,
});
},
async down(queryInterface, Sequelize) {
await queryInterface.removeColumn('Torrents', 'organizedAt');
await queryInterface.removeColumn('Torrents', 'metadata');
}
};