From e8ca48842e81a7e4cd59778bc49df94681ee23a6 Mon Sep 17 00:00:00 2001 From: DariusIII Date: Thu, 14 May 2026 15:43:29 +0200 Subject: [PATCH] Allow nfo file uploads --- app/Http/Controllers/Api/ApiController.php | 43 ++++++++++++++-------- docs/newznab_api_specification.txt | 7 +++- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/app/Http/Controllers/Api/ApiController.php b/app/Http/Controllers/Api/ApiController.php index 0e4629fd1..2ffff0fb8 100644 --- a/app/Http/Controllers/Api/ApiController.php +++ b/app/Http/Controllers/Api/ApiController.php @@ -567,8 +567,9 @@ class ApiController extends BasePageController } break; // - // nzb add request + // nzb / nfo add request // curl -X POST -F "file=@./The.File.nzb" "site_url/api/V1/api?t=nzbadd&apikey=xxx" + // curl -X POST -F "file=@./The.File.nfo" "site_url/api/V1/api?t=nzbadd&apikey=xxx" // case 'nzbAdd': if (! User::canPost($uid)) { @@ -576,14 +577,14 @@ class ApiController extends BasePageController } if ($request->missing('file')) { - return showApiError(200, 'Missing parameter (file is required for adding an NZB)'); + return showApiError(200, 'Missing parameter (file is required for adding an NZB or NFO)'); } if ($request->missing('apikey')) { - return showApiError(200, 'Missing parameter (apikey is required for adding an NZB)'); + return showApiError(200, 'Missing parameter (apikey is required for adding an NZB or NFO)'); } if (! $request->hasFile('file')) { - return showApiError(600, 'Failed to load NZB'); + return showApiError(600, 'Failed to load upload (no file)'); } UserRequest::addApiRequest($uid, $request->getRequestUri()); @@ -592,20 +593,32 @@ class ApiController extends BasePageController // Save the file to the server, get the name without the extension. if ($nzbFile !== null) { - // We need to check if file is an actual nzb file. - if ($nzbFile->getClientOriginalExtension() !== 'nzb') { - return showApiError(600, 'Failed to load NZB (file is not an NZB file)'); + $ext = strtolower((string) $nzbFile->getClientOriginalExtension()); + if (! in_array($ext, ['nzb', 'nfo'], true)) { + return showApiError(600, 'Failed to load NZB (file is not an NZB or NFO file)'); } - // Check if the file is proper xml nzb file. - if (! isValidNewznabNzb($nzbFile->getContent())) { + + $content = $nzbFile->getContent(); + if (! is_string($content)) { + return showApiError(600, 'Failed to load upload'); + } + + if ($ext === 'nzb' && ! isValidNewznabNzb($content)) { return showApiError(600, 'Failed to load NZB (invalid NZB payload)'); } + + // Same max raw size as NfoService::MAX_NFO_SIZE (64KB). + $maxNfoUploadBytes = 65535; + if ($ext === 'nfo' && ($content === '' || strlen($content) > $maxNfoUploadBytes)) { + return showApiError(600, 'Failed to load NFO (empty or too large)'); + } + if (! File::isDirectory(config('nntmux.nzb_upload_folder'))) { @File::makeDirectory(config('nntmux.nzb_upload_folder'), 0775, true); } - if (File::put(config('nntmux.nzb_upload_folder').$nzbFile->getClientOriginalName(), $nzbFile->getContent())) { - Log::channel('nzb_upload')->info('NZB file uploaded by API: '.$nzbFile->getClientOriginalName()); + if (File::put(config('nntmux.nzb_upload_folder').$nzbFile->getClientOriginalName(), $content)) { + Log::channel('nzb_upload')->info('File uploaded by API: '.$nzbFile->getClientOriginalName().' (type: '.$ext.')'); $successXml = sprintf( "\n\n", @@ -616,14 +629,14 @@ class ApiController extends BasePageController return response($successXml, 200)->header('Content-type', 'text/xml'); } - Log::channel('nzb_upload')->warning('NZB file uploaded by API failed: '.$nzbFile->getClientOriginalName()); + Log::channel('nzb_upload')->warning('File upload by API failed to write: '.$nzbFile->getClientOriginalName().' (type: '.$ext.')'); } else { - Log::channel('nzb_upload')->warning('NZB file uploaded by API failed: no file provided'); + Log::channel('nzb_upload')->warning('File upload by API failed: no file provided'); - return showApiError(603, 'NZB failed to write to disk'); + return showApiError(603, 'Failed to write file to disk'); } - return showApiError(603, 'NZB failed to write to disk'); + return showApiError(603, 'Failed to write file to disk'); break; diff --git a/docs/newznab_api_specification.txt b/docs/newznab_api_specification.txt index 74dc5a4dd..8a0de2d8c 100755 --- a/docs/newznab_api_specification.txt +++ b/docs/newznab_api_specification.txt @@ -225,11 +225,16 @@ newznab-tmux https://github.com/NNTmux/newznab-tmux Parameters: t=nzbadd apikey=xxxx - file= + file= Optional: cat, includemeta, dupecheck, nfo, medianfo + Behavior: + Valid .nzb and .nfo uploads are written to the same NZB upload folder + (NZB_UPLOAD_FOLDER). NFO files are not linked to releases at upload time; + a separate import command is expected to process them later. + Error handling: Uses XML error codes from section 6.