From 4fa16cf091d5787a0a6424addc848cc4dace5267 Mon Sep 17 00:00:00 2001 From: DariusIII Date: Thu, 25 Dec 2025 10:40:05 +0100 Subject: [PATCH] Merge XXX and XXXinfo model --- Blacklight/XXX.php | 408 --------------------- app/Extensions/helper/helpers.php | 4 +- app/Http/Controllers/AdultController.php | 19 +- app/Http/Controllers/DetailsController.php | 13 +- app/Models/XxxInfo.php | 161 ++++++++ app/Services/XxxBrowseService.php | 206 +++++++++++ 6 files changed, 390 insertions(+), 421 deletions(-) delete mode 100755 Blacklight/XXX.php create mode 100644 app/Services/XxxBrowseService.php diff --git a/Blacklight/XXX.php b/Blacklight/XXX.php deleted file mode 100755 index 0bee70772..000000000 --- a/Blacklight/XXX.php +++ /dev/null @@ -1,408 +0,0 @@ -releaseImage = new ReleaseImageService; - $this->colorCli = new ColorCLI; - - $this->movieQty = Settings::settingValue('maxxxxprocessed') ?? 100; - $this->showPasswords = app(\App\Services\Releases\ReleaseBrowseService::class)->showPasswords(); - $this->echoOutput = config('nntmux.echocli'); - $this->imgSavePath = storage_path('covers/xxx/'); - $this->cookie = resource_path('tmp/xxx.cookie'); - } - - /** - * Get info for a xxx id. - * - * @return \Illuminate\Database\Query\Builder|static - */ - public function getXXXInfo($xxxid) - { - return XxxInfo::query()->where('id', $xxxid)->selectRaw(' *, UNCOMPRESS(plot) as plot')->first(); - } - - /** - * Get XXX releases with covers for xxx browse page. - */ - public function getXXXRange($page, $cat, $start, $num, $orderBy, int $maxAge = -1, array $excludedCats = []): array - { - $page = max(1, $page); - $start = max(0, $start); - - $catSrch = ''; - if (\count($cat) > 0 && $cat[0] !== -1) { - $catSrch = Category::getCategorySearch($cat); - } - $order = $this->getXXXOrder($orderBy); - $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium')); - $xxxmoviesSql = - sprintf( - " - SELECT SQL_CALC_FOUND_ROWS - xxx.id, - GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id - FROM xxxinfo xxx - LEFT JOIN releases r ON xxx.id = r.xxxinfo_id - WHERE xxx.title != '' - AND r.passwordstatus %s - %s %s %s %s - GROUP BY xxx.id - ORDER BY %s %s %s", - $this->showPasswords, - $this->getBrowseBy(), - $catSrch, - ( - $maxAge > 0 - ? 'AND r.postdate > NOW() - INTERVAL '.$maxAge.'DAY ' - : '' - ), - (\count($excludedCats) > 0 ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''), - $order[0], - $order[1], - ($start === false ? '' : ' LIMIT '.$num.' OFFSET '.$start) - ); - $xxxmoviesCache = Cache::get(md5($xxxmoviesSql.$page)); - if ($xxxmoviesCache !== null) { - $xxxmovies = $xxxmoviesCache; - } else { - $data = DB::select($xxxmoviesSql); - $xxxmovies = ['total' => DB::select('SELECT FOUND_ROWS() AS total'), 'result' => $data]; - Cache::put(md5($xxxmoviesSql.$page), $xxxmovies, $expiresAt); - } - $xxxIDs = []; - if (\is_array($xxxmovies['result'])) { - foreach ($xxxmovies['result'] as $xxx => $id) { - $xxxIDs[] = $id->id; - } - } - $sql = sprintf( - " - SELECT - GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id, - GROUP_CONCAT(r.rarinnerfilecount ORDER BY r.postdate DESC SEPARATOR ',') AS grp_rarinnerfilecount, - GROUP_CONCAT(r.haspreview ORDER BY r.postdate DESC SEPARATOR ',') AS grp_haspreview, - GROUP_CONCAT(r.passwordstatus ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_password, - GROUP_CONCAT(r.guid ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_guid, - GROUP_CONCAT(rn.releases_id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_nfoid, - GROUP_CONCAT(g.name ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grpname, - GROUP_CONCAT(r.searchname ORDER BY r.postdate DESC SEPARATOR '#') AS grp_release_name, - GROUP_CONCAT(r.postdate ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_postdate, - GROUP_CONCAT(r.size ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_size, - GROUP_CONCAT(r.totalpart ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_totalparts, - GROUP_CONCAT(r.comments ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_comments, - GROUP_CONCAT(r.grabs ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grabs, - GROUP_CONCAT(df.failed ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_failed, - GROUP_CONCAT(cp.title, ' > ', c.title ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_catname, - xxx.*, UNCOMPRESS(xxx.plot) AS plot, - g.name AS group_name, - rn.releases_id AS nfoid - FROM releases r - LEFT OUTER JOIN usenet_groups g ON g.id = r.groups_id - LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id - LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id - LEFT OUTER JOIN categories c ON c.id = r.categories_id - LEFT OUTER JOIN root_categories cp ON cp.id = c.root_categories_id - INNER JOIN xxxinfo xxx ON xxx.id = r.xxxinfo_id - WHERE xxx.id IN (%s) - AND xxx.title != '' - AND r.passwordstatus %s - %s %s %s %s - GROUP BY xxx.id - ORDER BY %s %s", - (! empty($xxxIDs) ? implode(',', $xxxIDs) : -1), - $this->showPasswords, - $this->getBrowseBy(), - $catSrch, - ( - $maxAge > 0 - ? 'AND r.postdate > NOW() - INTERVAL '.$maxAge.'DAY ' - : '' - ), - (\count($excludedCats) > 0 ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''), - $order[0], - $order[1] - ); - $return = Cache::get(md5($sql.$page)); - if ($return !== null) { - return $return; - } - $return = DB::select($sql); - if (\count($return) > 0) { - $return[0]->_totalcount = $xxxmovies['total'][0]->total ?? 0; - } - Cache::put(md5($sql.$page), $return, $expiresAt); - - return $return; - } - - /** - * Get the order type the user requested on the xxx page. - */ - protected function getXXXOrder($orderBy): array - { - $orderArr = explode('_', (($orderBy === '') ? 'r.postdate' : $orderBy)); - $orderField = match ($orderArr[0]) { - 'title' => 'xxx.title', - default => 'r.postdate', - }; - - return [$orderField, isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1]) ? $orderArr[1] : 'desc']; - } - - /** - * Order types for xxx page. - */ - public function getXXXOrdering(): array - { - return ['title_asc', 'title_desc', 'name_asc', 'name_desc', 'size_asc', 'size_desc', 'posted_asc', 'posted_desc', 'cat_asc', 'cat_desc']; - } - - protected function getBrowseBy(): string - { - $browseBy = ' '; - foreach (['title', 'director', 'actors', 'genre', 'id'] as $bb) { - if (! empty($_REQUEST[$bb])) { - $bbv = stripslashes($_REQUEST[$bb]); - if ($bb === 'genre') { - $bbv = $this->getGenreID($bbv); - } - if ($bb === 'id') { - $browseBy .= ' AND xxx.'.$bb.'='.$bbv; - } else { - $browseBy .= ' AND xxx.'.$bb.' '.'LIKE '.escapeString('%'.$bbv.'%'); - } - } - } - - return $browseBy; - } - - /** - * Update XXX Information from getXXXCovers.php in misc/testing/PostProc. - */ - public function update( - string $id = '', - string $title = '', - string $tagLine = '', - string $plot = '', - string $genre = '', - string $director = '', - string $actors = '', - string $extras = '', - string $productInfo = '', - string $trailers = '', - string $directUrl = '', - string $classUsed = '', - string $cover = '', - string $backdrop = '' - ): void { - if (! empty($id)) { - XxxInfo::query()->where('id', $id)->update( - [ - 'title' => $title, - 'tagline' => $tagLine, - 'plot' => "\x1f\x8b\x08\x00".gzcompress($plot), - 'genre' => substr($genre, 0, 64), - 'director' => $director, - 'actors' => $actors, - 'extras' => $extras, - 'productinfo' => $productInfo, - 'trailers' => $trailers, - 'directurl' => $directUrl, - 'classused' => $classUsed, - 'cover' => empty($cover) ? 0 : $cover, - 'backdrop' => empty($backdrop) ? 0 : $backdrop, - ] - ); - } - } - - /** - * Get all genres for search-filter.tpl. - */ - public function getAllGenres(bool $activeOnly = false): array - { - $ret = []; - if ($activeOnly) { - $res = Genre::query()->where(['disabled' => 0, 'type' => Category::XXX_ROOT])->orderBy('title')->get(['title'])->toArray(); - } else { - $res = Genre::query()->where(['type' => Category::XXX_ROOT])->orderBy('title')->get(['title'])->toArray(); - } - - return array_column($res, 'title'); - } - - public function getGenres(bool $activeOnly = false, $gid = null): mixed - { - if ($activeOnly) { - return Genre::query()->where(['disabled' => 0, 'type' => Category::XXX_ROOT])->when($gid !== null, function ($query) use ($gid) { - return $query->where('id', $gid); - })->orderBy('title')->first(['title']); - } - - return Genre::query()->where(['type' => Category::XXX_ROOT])->when($gid !== null, function ($query) use ($gid) { - return $query->where('id', $gid); - })->orderBy('title')->first(['title']); - } - - /** - * Get Genre id's Of the title. - * - * @param $arr - Array or String - * @return string - If array .. 1,2,3,4 if string .. 1 - */ - protected function getGenreID($arr): string - { - $ret = null; - - if (! \is_array($arr)) { - $res = Genre::query()->where('title', $arr)->first(['id']); - if ($res !== null) { - return $res['id']; - } - } - - foreach ($arr as $key => $value) { - $res = Genre::query()->where('title', $value)->first(['id']); - if ($res !== null) { - $ret .= ','.$res['id']; - } else { - $ret .= ','.$this->insertGenre($value); - } - } - - $ret = ltrim($ret, ','); - - return $ret; - } - - /** - * Inserts Genre and returns last affected row (Genre ID). - */ - private function insertGenre($genre): int|string - { - $res = ''; - if ($genre !== null) { - $res = Genre::query()->insert(['title' => $genre, 'type' => Category::XXX_ROOT, 'disabled' => 0]); - } - - return $res; - } - - /** - * Inserts Trailer Code by Class. - */ - public function insertSwf($whichClass, $res): string - { - $ret = ''; - if (($whichClass === 'ade') && ! empty($res)) { - $trailers = unserialize($res, 'ade'); - $ret .= ""; - $ret .= ""; - $ret .= ''; - - return $ret; - } - if (($whichClass === 'pop') && ! empty($res)) { - $trailers = unserialize($res, 'pop'); - $ret .= ""; - - return $ret; - } - - return $ret; - } - - - /** - * Checks xxxinfo to make sure releases exist. - * - * @return \Illuminate\Database\Eloquent\Model|null|static - */ - protected function checkXXXInfoExists($releaseName) - { - return XxxInfo::query()->where('title', 'like', '%'.$releaseName.'%')->first(['id', 'title']); - } - - /** - * Cleans up a searchname to make it easier to scrape. - */ - protected function parseXXXSearchName(string $releaseName): bool - { - $name = ''; - $followingList = '[^\w]((2160|1080|480|720)(p|i)|AC3D|Directors([^\w]CUT)?|DD5\.1|(DVD|BD|BR)(Rip)?|BluRay|divx|HDTV|iNTERNAL|LiMiTED|(Real\.)?Proper|RE(pack|Rip)|Sub\.?(fix|pack)|Unrated|WEB-DL|(x|H)[ ._-]?264|xvid|[Dd][Ii][Ss][Cc](\d+|\s*\d+|\.\d+)|XXX|BTS|DirFix|Trailer|WEBRiP|NFO|(19|20)\d\d)[^\w]'; - - if (preg_match('/([^\w]{2,})?(?P[\w .-]+?)'.$followingList.'/i', $releaseName, $hits)) { - $name = $hits['name']; - } - - // Check if we got something. - if ($name !== '') { - // If we still have any of the words in $followingList, remove them. - $name = preg_replace('/'.$followingList.'/i', ' ', $name); - // Remove periods, underscored, anything between parenthesis. - $name = preg_replace('/\(.*?\)|[._-]/i', ' ', $name); - // Finally remove multiple spaces and trim leading spaces. - $name = trim(preg_replace('/\s{2,}/', ' ', $name)); - // Remove Private Movies {d} from name better matching. - $name = trim(preg_replace('/^Private\s(Specials|Blockbusters|Blockbuster|Sports|Gold|Lesbian|Movies|Classics|Castings|Fetish|Stars|Pictures|XXX|Private|Black\sLabel|Black)\s\d+/i', '', $name)); - // Remove Foreign Words at the end of the name. - $name = trim(preg_replace('/(brazilian|chinese|croatian|danish|deutsch|dutch|estonian|flemish|finnish|french|german|greek|hebrew|icelandic|italian|latin|nordic|norwegian|polish|portuguese|japenese|japanese|russian|serbian|slovenian|spanish|spanisch|swedish|thai|turkish)$/i', '', $name)); - - // Check if the name is long enough and not just numbers and not file (d) of (d) and does not contain Episodes and any dated 00.00.00 which are site rips.. - if (\strlen($name) > 5 && ! preg_match('/^\d+$/', $name) && ! preg_match('/( File \d+ of \d+|\d+.\d+.\d+)/', $name) && ! preg_match('/(E\d+)/', $name) && ! preg_match('/\d\d\.\d\d.\d\d/', $name)) { - $this->currentTitle = $name; - - return true; - } - } - - return false; - } -} diff --git a/app/Extensions/helper/helpers.php b/app/Extensions/helper/helpers.php index 8ee60f996..a76451d82 100644 --- a/app/Extensions/helper/helpers.php +++ b/app/Extensions/helper/helpers.php @@ -2,8 +2,8 @@ use App\Models\Country as CountryModel; use App\Models\Release; +use App\Models\XxxInfo; use Blacklight\NZB; -use Blacklight\XXX; use GuzzleHttp\Client; use GuzzleHttp\Cookie\CookieJar; use GuzzleHttp\Cookie\SetCookie; @@ -122,7 +122,7 @@ if (! function_exists('makeFieldLinks')) { continue; } if ($type === 'xxx' && $field === 'genre') { - $ta = (new XXX)->getGenres(true, $ta); + $ta = XxxInfo::getGenres(true, $ta); $ta = $ta['title'] ?? ''; } if ($i > 7) { diff --git a/app/Http/Controllers/AdultController.php b/app/Http/Controllers/AdultController.php index 45a6c16bf..c219c348e 100644 --- a/app/Http/Controllers/AdultController.php +++ b/app/Http/Controllers/AdultController.php @@ -3,19 +3,26 @@ namespace App\Http\Controllers; use App\Models\Category; -use Blacklight\XXX; +use App\Models\XxxInfo; +use App\Services\XxxBrowseService; use Illuminate\Http\Request; use Illuminate\Support\Arr; class AdultController extends BasePageController { + private XxxBrowseService $xxxBrowseService; + + public function __construct(XxxBrowseService $xxxBrowseService) + { + parent::__construct(); + $this->xxxBrowseService = $xxxBrowseService; + } + /** * @throws \Exception */ public function show(Request $request, string $id = '') { - $adult = new XXX; - $moviecats = Category::getChildren(Category::XXX_ROOT); $mtmp = []; foreach ($moviecats as $mcat) { @@ -36,12 +43,12 @@ class AdultController extends BasePageController $catarray = []; $catarray[] = $category; - $ordering = $adult->getXXXOrdering(); + $ordering = $this->xxxBrowseService->getXXXOrdering(); $orderby = $request->has('ob') && \in_array($request->input('ob'), $ordering, false) ? $request->input('ob') : ''; $page = $request->has('page') && is_numeric($request->input('page')) ? $request->input('page') : 1; $offset = ($page - 1) * config('nntmux.items_per_page'); - $rslt = $adult->getXXXRange($page, $catarray, $offset, config('nntmux.items_per_page'), $orderby, -1, $this->userdata['categoryexclusions']); + $rslt = $this->xxxBrowseService->getXXXRange($page, $catarray, $offset, config('nntmux.items_per_page'), $orderby, -1, $this->userdata['categoryexclusions']); $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_page'), $page, $request->url(), $request->query()); $title = ($request->has('title') && ! empty($request->input('title'))) ? stripslashes($request->input('title')) : ''; @@ -50,7 +57,7 @@ class AdultController extends BasePageController $director = ($request->has('director') && ! empty($request->input('director'))) ? stripslashes($request->input('director')) : ''; - $genres = $adult->getAllGenres(true); + $genres = XxxInfo::getAllGenres(true); $genre = ($request->has('genre') && \in_array($request->input('genre'), $genres, false)) ? $request->input('genre') : ''; $browseby_link = '&title='.$title.'&actors='.$actors.'&director='.$director.'&genre='.$genre; diff --git a/app/Http/Controllers/DetailsController.php b/app/Http/Controllers/DetailsController.php index 6182d41b7..a71124bb2 100644 --- a/app/Http/Controllers/DetailsController.php +++ b/app/Http/Controllers/DetailsController.php @@ -12,15 +12,16 @@ use App\Models\ReleaseRegex; use App\Models\Settings; use App\Models\UserDownload; use App\Models\Video; +use App\Models\XxxInfo; use App\Services\MovieService; use App\Services\Releases\ReleaseSearchService; use App\Services\BookService; use App\Services\AnidbService; +use App\Services\XxxBrowseService; use Blacklight\Console; use Blacklight\Games; use Blacklight\Music; use Blacklight\ReleaseExtra; -use Blacklight\XXX; use Illuminate\Http\Request; class DetailsController extends BasePageController @@ -29,11 +30,14 @@ class DetailsController extends BasePageController private MovieService $movieService; - public function __construct(ReleaseSearchService $releaseSearchService, MovieService $movieService) + private XxxBrowseService $xxxBrowseService; + + public function __construct(ReleaseSearchService $releaseSearchService, MovieService $movieService, XxxBrowseService $xxxBrowseService) { parent::__construct(); $this->releaseSearchService = $releaseSearchService; $this->movieService = $movieService; + $this->xxxBrowseService = $xxxBrowseService; } public function show(Request $request, string $guid) @@ -90,11 +94,10 @@ class DetailsController extends BasePageController $xxx = ''; if ($data['xxxinfo_id'] !== '' && $data['xxxinfo_id'] !== 0) { - $x = new XXX; - $xxx = $x->getXXXInfo($data['xxxinfo_id']); + $xxx = XxxInfo::getXXXInfo($data['xxxinfo_id']); if (isset($xxx['trailers'])) { - $xxx['trailers'] = $x->insertSwf($xxx['classused'], $xxx['trailers']); + $xxx['trailers'] = $this->xxxBrowseService->insertSwf($xxx['classused'], $xxx['trailers']); } if ($xxx && isset($xxx['title'])) { diff --git a/app/Models/XxxInfo.php b/app/Models/XxxInfo.php index 1951f987e..bb2db37c6 100644 --- a/app/Models/XxxInfo.php +++ b/app/Models/XxxInfo.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\HasMany; /** * App\Models\XxxInfo. @@ -63,4 +64,164 @@ class XxxInfo extends Model * @var array */ protected $guarded = []; + + /** + * Get releases associated with this XXX info. + */ + public function releases(): HasMany + { + return $this->hasMany(Release::class, 'xxxinfo_id'); + } + + /** + * Get info for a xxx id with decompressed plot. + */ + public static function getXXXInfo(int $xxxid): ?self + { + return self::query() + ->where('id', $xxxid) + ->selectRaw('*, UNCOMPRESS(plot) as plot') + ->first(); + } + + /** + * Update XXX Information. + */ + public static function updateXxxInfo( + string $id, + string $title = '', + string $tagLine = '', + string $plot = '', + string $genre = '', + string $director = '', + string $actors = '', + string $extras = '', + string $productInfo = '', + string $trailers = '', + string $directUrl = '', + string $classUsed = '', + string $cover = '', + string $backdrop = '' + ): void { + if (! empty($id)) { + self::query()->where('id', $id)->update([ + 'title' => $title, + 'tagline' => $tagLine, + 'plot' => "\x1f\x8b\x08\x00".gzcompress($plot), + 'genre' => substr($genre, 0, 64), + 'director' => $director, + 'actors' => $actors, + 'extras' => $extras, + 'productinfo' => $productInfo, + 'trailers' => $trailers, + 'directurl' => $directUrl, + 'classused' => $classUsed, + 'cover' => empty($cover) ? 0 : $cover, + 'backdrop' => empty($backdrop) ? 0 : $backdrop, + ]); + } + } + + /** + * Get all genres for search-filter.tpl. + */ + public static function getAllGenres(bool $activeOnly = false): array + { + $ret = []; + if ($activeOnly) { + $res = Genre::query() + ->where(['disabled' => 0, 'type' => Category::XXX_ROOT]) + ->orderBy('title') + ->get(['title']) + ->toArray(); + } else { + $res = Genre::query() + ->where(['type' => Category::XXX_ROOT]) + ->orderBy('title') + ->get(['title']) + ->toArray(); + } + + return array_column($res, 'title'); + } + + /** + * Get a specific genre. + */ + public static function getGenres(bool $activeOnly = false, ?int $gid = null): mixed + { + if ($activeOnly) { + return Genre::query() + ->where(['disabled' => 0, 'type' => Category::XXX_ROOT]) + ->when($gid !== null, fn ($query) => $query->where('id', $gid)) + ->orderBy('title') + ->first(['title']); + } + + return Genre::query() + ->where(['type' => Category::XXX_ROOT]) + ->when($gid !== null, fn ($query) => $query->where('id', $gid)) + ->orderBy('title') + ->first(['title']); + } + + /** + * Get Genre id's of the title. + * + * @param array|string $arr - Array or String + * @return string - If array .. 1,2,3,4 if string .. 1 + */ + public static function getGenreID(array|string $arr): string + { + $ret = null; + + if (! \is_array($arr)) { + $res = Genre::query()->where('title', $arr)->first(['id']); + if ($res !== null) { + return (string) $res['id']; + } + + return ''; + } + + foreach ($arr as $key => $value) { + $res = Genre::query()->where('title', $value)->first(['id']); + if ($res !== null) { + $ret .= ','.$res['id']; + } else { + $ret .= ','.self::insertGenre($value); + } + } + + $ret = ltrim($ret, ','); + + return $ret; + } + + /** + * Inserts Genre and returns last affected row (Genre ID). + */ + private static function insertGenre(?string $genre): int|string + { + $res = ''; + if ($genre !== null) { + $res = Genre::query()->insertGetId([ + 'title' => $genre, + 'type' => Category::XXX_ROOT, + 'disabled' => 0, + ]); + } + + return $res; + } + + /** + * Checks xxxinfo to make sure releases exist. + */ + public static function checkXXXInfoExists(string $releaseName): ?self + { + return self::query() + ->where('title', 'like', '%'.$releaseName.'%') + ->first(['id', 'title']); + } } diff --git a/app/Services/XxxBrowseService.php b/app/Services/XxxBrowseService.php new file mode 100644 index 000000000..d20d7b7a4 --- /dev/null +++ b/app/Services/XxxBrowseService.php @@ -0,0 +1,206 @@ +showPasswords = app(ReleaseBrowseService::class)->showPasswords(); + } + + /** + * Get XXX releases with covers for xxx browse page. + */ + public function getXXXRange(int $page, array $cat, int $start, int $num, string $orderBy, int $maxAge = -1, array $excludedCats = []): array + { + $page = max(1, $page); + $start = max(0, $start); + + $catSrch = ''; + if (\count($cat) > 0 && $cat[0] !== -1) { + $catSrch = Category::getCategorySearch($cat); + } + $order = $this->getXXXOrder($orderBy); + $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium')); + $xxxmoviesSql = + sprintf( + " + SELECT SQL_CALC_FOUND_ROWS + xxx.id, + GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id + FROM xxxinfo xxx + LEFT JOIN releases r ON xxx.id = r.xxxinfo_id + WHERE xxx.title != '' + AND r.passwordstatus %s + %s %s %s %s + GROUP BY xxx.id + ORDER BY %s %s %s", + $this->showPasswords, + $this->getBrowseBy(), + $catSrch, + ( + $maxAge > 0 + ? 'AND r.postdate > NOW() - INTERVAL '.$maxAge.'DAY ' + : '' + ), + (\count($excludedCats) > 0 ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''), + $order[0], + $order[1], + ($start === false ? '' : ' LIMIT '.$num.' OFFSET '.$start) + ); + $xxxmoviesCache = Cache::get(md5($xxxmoviesSql.$page)); + if ($xxxmoviesCache !== null) { + $xxxmovies = $xxxmoviesCache; + } else { + $data = DB::select($xxxmoviesSql); + $xxxmovies = ['total' => DB::select('SELECT FOUND_ROWS() AS total'), 'result' => $data]; + Cache::put(md5($xxxmoviesSql.$page), $xxxmovies, $expiresAt); + } + $xxxIDs = []; + if (\is_array($xxxmovies['result'])) { + foreach ($xxxmovies['result'] as $xxx => $id) { + $xxxIDs[] = $id->id; + } + } + $sql = sprintf( + " + SELECT + GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id, + GROUP_CONCAT(r.rarinnerfilecount ORDER BY r.postdate DESC SEPARATOR ',') AS grp_rarinnerfilecount, + GROUP_CONCAT(r.haspreview ORDER BY r.postdate DESC SEPARATOR ',') AS grp_haspreview, + GROUP_CONCAT(r.passwordstatus ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_password, + GROUP_CONCAT(r.guid ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_guid, + GROUP_CONCAT(rn.releases_id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_nfoid, + GROUP_CONCAT(g.name ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grpname, + GROUP_CONCAT(r.searchname ORDER BY r.postdate DESC SEPARATOR '#') AS grp_release_name, + GROUP_CONCAT(r.postdate ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_postdate, + GROUP_CONCAT(r.size ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_size, + GROUP_CONCAT(r.totalpart ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_totalparts, + GROUP_CONCAT(r.comments ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_comments, + GROUP_CONCAT(r.grabs ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grabs, + GROUP_CONCAT(df.failed ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_failed, + GROUP_CONCAT(cp.title, ' > ', c.title ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_catname, + xxx.*, UNCOMPRESS(xxx.plot) AS plot, + g.name AS group_name, + rn.releases_id AS nfoid + FROM releases r + LEFT OUTER JOIN usenet_groups g ON g.id = r.groups_id + LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id + LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id + LEFT OUTER JOIN categories c ON c.id = r.categories_id + LEFT OUTER JOIN root_categories cp ON cp.id = c.root_categories_id + INNER JOIN xxxinfo xxx ON xxx.id = r.xxxinfo_id + WHERE xxx.id IN (%s) + AND xxx.title != '' + AND r.passwordstatus %s + %s %s %s %s + GROUP BY xxx.id + ORDER BY %s %s", + (! empty($xxxIDs) ? implode(',', $xxxIDs) : -1), + $this->showPasswords, + $this->getBrowseBy(), + $catSrch, + ( + $maxAge > 0 + ? 'AND r.postdate > NOW() - INTERVAL '.$maxAge.'DAY ' + : '' + ), + (\count($excludedCats) > 0 ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''), + $order[0], + $order[1] + ); + $return = Cache::get(md5($sql.$page)); + if ($return !== null) { + return $return; + } + $return = DB::select($sql); + if (\count($return) > 0) { + $return[0]->_totalcount = $xxxmovies['total'][0]->total ?? 0; + } + Cache::put(md5($sql.$page), $return, $expiresAt); + + return $return; + } + + /** + * Get the order type the user requested on the xxx page. + */ + protected function getXXXOrder(string $orderBy): array + { + $orderArr = explode('_', (($orderBy === '') ? 'r.postdate' : $orderBy)); + $orderField = match ($orderArr[0]) { + 'title' => 'xxx.title', + default => 'r.postdate', + }; + + return [$orderField, isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1]) ? $orderArr[1] : 'desc']; + } + + /** + * Order types for xxx page. + */ + public function getXXXOrdering(): array + { + return ['title_asc', 'title_desc', 'name_asc', 'name_desc', 'size_asc', 'size_desc', 'posted_asc', 'posted_desc', 'cat_asc', 'cat_desc']; + } + + protected function getBrowseBy(): string + { + $browseBy = ' '; + foreach (['title', 'director', 'actors', 'genre', 'id'] as $bb) { + if (! empty($_REQUEST[$bb])) { + $bbv = stripslashes($_REQUEST[$bb]); + if ($bb === 'genre') { + $bbv = XxxInfo::getGenreID($bbv); + } + if ($bb === 'id') { + $browseBy .= ' AND xxx.'.$bb.'='.$bbv; + } else { + $browseBy .= ' AND xxx.'.$bb.' '.'LIKE '.escapeString('%'.$bbv.'%'); + } + } + } + + return $browseBy; + } + + /** + * Inserts Trailer Code by Class. + */ + public function insertSwf(string $whichClass, ?string $res): string + { + $ret = ''; + if (($whichClass === 'ade') && ! empty($res)) { + $trailers = unserialize($res, ['allowed_classes' => false]); + $ret .= ""; + $ret .= ""; + $ret .= ''; + + return $ret; + } + if (($whichClass === 'pop') && ! empty($res)) { + $trailers = unserialize($res, ['allowed_classes' => false]); + $ret .= ""; + + return $ret; + } + + return $ret; + } +} +