From 9538276aa5164d8ee1405c43cdc294b7161b36f0 Mon Sep 17 00:00:00 2001 From: DariusIII Date: Tue, 6 Nov 2018 14:09:39 +0100 Subject: [PATCH] Add support for tags in browse, APIv2 and on site release searches --- Blacklight/Releases.php | 142 +++++++++++-------- Changelog | 1 + app/Http/Controllers/Api/ApiV2Controller.php | 15 +- app/Http/Controllers/BrowseController.php | 46 ++++++ app/Http/Controllers/SearchController.php | 9 +- resources/views/themes/Gentele/viewnzb.tpl | 5 +- routes/web.php | 1 + 7 files changed, 154 insertions(+), 65 deletions(-) diff --git a/Blacklight/Releases.php b/Blacklight/Releases.php index 9a7d38d2f..d7506695e 100755 --- a/Blacklight/Releases.php +++ b/Blacklight/Releases.php @@ -56,20 +56,23 @@ class Releases * Used for Browse results. * * - * @param $page - * @param $cat - * @param $start - * @param $num - * @param $orderBy - * @param int $maxAge + * @param $page + * @param $cat + * @param $start + * @param $num + * @param $orderBy + * @param int $maxAge * @param array $excludedCats - * @param int $groupName - * @param int $minSize + * @param array $tags + * @param int $groupName + * @param int $minSize + * * @return \Illuminate\Database\Eloquent\Collection|mixed */ - public function getBrowseRange($page, $cat, $start, $num, $orderBy, $maxAge = -1, array $excludedCats = [], $groupName = -1, $minSize = 0) + public function getBrowseRange($page, $cat, $start, $num, $orderBy, $maxAge = -1, array $excludedCats = [], $groupName = -1, $minSize = 0, array $tags = []) { $orderBy = $this->getBrowseOrder($orderBy); + $qry = sprintf( "SELECT r.*, cp.title AS parent_category, c.title AS sub_category, CONCAT(cp.title, ' > ', c.title) AS category_name, @@ -84,9 +87,10 @@ class Releases SELECT r.*, g.name AS group_name FROM releases r LEFT JOIN groups g ON g.id = r.groups_id + %s WHERE r.nzbstatus = %d AND r.passwordstatus %s - %s %s %s %s %s + %s %s %s %s %s %s ORDER BY %s %s %s ) r LEFT JOIN categories c ON c.id = r.categories_id @@ -97,9 +101,11 @@ class Releases LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id GROUP BY r.id - ORDER BY %8\$s %9\$s", + ORDER BY %10\$s %11\$s", + ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '', NZB::NZB_ADDED, $this->showPasswords(), + ! empty($tags) ? " AND tt.tag_name IN ('".implode("','",$tags)."')" : '', Category::getCategorySearch($cat), ($maxAge > 0 ? (' AND postdate > NOW() - INTERVAL '.$maxAge.' DAY ') : ''), (\count($excludedCats) ? (' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')') : ''), @@ -109,13 +115,14 @@ class Releases $orderBy[1], ($start === false ? '' : ' LIMIT '.$num.' OFFSET '.$start) ); + $releases = Cache::get(md5($qry.$page)); if ($releases !== null) { return $releases; } $sql = Release::fromQuery($qry); if (\count($sql) > 0) { - $possibleRows = $this->getBrowseCount($cat, $maxAge, $excludedCats, $groupName); + $possibleRows = $this->getBrowseCount($cat, $maxAge, $excludedCats, $groupName, $tags); $sql[0]->_totalcount = $sql[0]->_totalrows = $possibleRows; } $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium')); @@ -127,26 +134,31 @@ class Releases /** * Used for pager on browse page. * - * @param array $cat - * @param int $maxAge - * @param array $excludedCats + * @param array $cat + * @param int $maxAge + * @param array $excludedCats * @param string|int $groupName * + * @param array $tags + * * @return int */ - public function getBrowseCount($cat, $maxAge = -1, array $excludedCats = [], $groupName = ''): int + public function getBrowseCount($cat, $maxAge = -1, array $excludedCats = [], $groupName = '', array $tags = []): int { $sql = sprintf( 'SELECT COUNT(r.id) AS count FROM releases r - %s + %s %s WHERE r.nzbstatus = %d AND r.passwordstatus %s - %s %s %s %s', + %s + %s %s %s %s ', ($groupName !== -1 ? 'LEFT JOIN groups g ON g.id = r.groups_id' : ''), + ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '', NZB::NZB_ADDED, $this->showPasswords(), ($groupName !== -1 ? sprintf(' AND g.name = %s', escapeString($groupName)) : ''), + ! empty($tags) ? ' AND tt.tag_name IN ('.escapeString(implode(',', $tags)).')' : '', Category::getCategorySearch($cat), ($maxAge > 0 ? (' AND r.postdate > NOW() - INTERVAL '.$maxAge.' DAY ') : ''), (\count($excludedCats) ? (' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')') : '') @@ -562,28 +574,30 @@ class Releases * Function for searching on the site (by subject, searchname or advanced). * * - * @param $searchName - * @param $usenetName - * @param $posterName - * @param $fileName - * @param $groupName - * @param $sizeFrom - * @param $sizeTo - * @param $hasNfo - * @param $hasComments - * @param $daysNew - * @param $daysOld - * @param int $offset - * @param int $limit + * @param $searchName + * @param $usenetName + * @param $posterName + * @param $fileName + * @param $groupName + * @param $sizeFrom + * @param $sizeTo + * @param $hasNfo + * @param $hasComments + * @param $daysNew + * @param $daysOld + * @param int $offset + * @param int $limit * @param string|array $orderBy - * @param int $maxAge - * @param array $excludedCats - * @param string $type - * @param array $cat - * @param int $minSize + * @param int $maxAge + * @param array $excludedCats + * @param string $type + * @param array $cat + * @param int $minSize + * @param array $tags + * * @return \Illuminate\Database\Eloquent\Collection */ - public function search($searchName, $usenetName, $posterName, $fileName, $groupName, $sizeFrom, $sizeTo, $hasNfo, $hasComments, $daysNew, $daysOld, $offset = 0, $limit = 1000, $orderBy = '', $maxAge = -1, array $excludedCats = [], $type = 'basic', array $cat = [-1], $minSize = 0) + public function search($searchName, $usenetName, $posterName, $fileName, $groupName, $sizeFrom, $sizeTo, $hasNfo, $hasComments, $daysNew, $daysOld, $offset = 0, $limit = 1000, $orderBy = '', $maxAge = -1, array $excludedCats = [], $type = 'basic', array $cat = [-1], $minSize = 0, array $tags = []) { $sizeRange = [ 1 => 1, @@ -625,10 +639,11 @@ class Releases $catQuery = sprintf('AND r.categories_id = %d', $cat[0]); } $whereSql = sprintf( - '%s WHERE r.passwordstatus %s AND r.nzbstatus = %d %s %s %s %s %s %s %s %s %s %s %s %s', + '%s WHERE r.passwordstatus %s AND r.nzbstatus = %d %s %s %s %s %s %s %s %s %s %s %s %s %s', $this->releaseSearch->getFullTextJoinString(), $this->showPasswords(), NZB::NZB_ADDED, + ! empty($tags) ? " AND tt.tag_name IN ('".implode("','",$tags)."')" : '', ($maxAge > 0 ? sprintf(' AND r.postdate > (NOW() - INTERVAL %d DAY) ', $maxAge) : ''), ((int) $groupName !== -1 ? sprintf(' AND r.groups_id = %d ', Group::getIDByName($groupName)) : ''), (array_key_exists($sizeFrom, $sizeRange) ? ' AND r.size > '.(string) (104857600 * (int) $sizeRange[$sizeFrom]).' ' : ''), @@ -662,8 +677,9 @@ class Releases LEFT JOIN categories c ON c.id = r.categories_id LEFT JOIN categories cp ON cp.id = c.parentid LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id - %s", + %s %s", $this->getConcatenatedCategoryIDs(), + ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '', $whereSql ); $sql = sprintf( @@ -696,17 +712,19 @@ class Releases * Search function for API. * * - * @param $searchName - * @param $groupName - * @param int $offset - * @param int $limit - * @param int $maxAge + * @param $searchName + * @param $groupName + * @param int $offset + * @param int $limit + * @param int $maxAge * @param array $excludedCats * @param array $cat - * @param int $minSize + * @param int $minSize + * @param array $tags + * * @return \Illuminate\Database\Eloquent\Collection|mixed */ - public function apiSearch($searchName, $groupName, $offset = 0, $limit = 1000, $maxAge = -1, array $excludedCats = [], array $cat = [-1], $minSize = 0) + public function apiSearch($searchName, $groupName, $offset = 0, $limit = 1000, $maxAge = -1, array $excludedCats = [], array $cat = [-1], $minSize = 0, array $tags = []) { $searchOptions = []; if ($searchName !== -1) { @@ -716,10 +734,11 @@ class Releases $catQuery = Category::getCategorySearch($cat); $whereSql = sprintf( - '%s WHERE r.passwordstatus %s AND r.nzbstatus = %d %s %s %s %s %s %s', + '%s WHERE r.passwordstatus %s AND r.nzbstatus = %d %s %s %s %s %s %s %s', $this->releaseSearch->getFullTextJoinString(), $this->showPasswords(), NZB::NZB_ADDED, + ! empty($tags) ? " AND tt.tag_name IN ('".implode("','",$tags)."')" : '', ($maxAge > 0 ? sprintf(' AND r.postdate > (NOW() - INTERVAL %d DAY) ', $maxAge) : ''), ((int) $groupName !== -1 ? sprintf(' AND r.groups_id = %d ', Group::getIDByName($groupName)) : ''), $catQuery, @@ -742,8 +761,9 @@ class Releases LEFT JOIN groups g ON g.id = r.groups_id LEFT JOIN categories c ON c.id = r.categories_id LEFT JOIN categories cp ON cp.id = c.parentid - %s", + %s %s", $this->getConcatenatedCategoryIDs(), + ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '', $whereSql ); $sql = sprintf( @@ -787,7 +807,7 @@ class Releases * @param array $excludedCategories * @return \Illuminate\Database\Eloquent\Collection|mixed */ - public function tvSearch(array $siteIdArr = [], $series = '', $episode = '', $airdate = '', $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1, $minSize = 0, array $excludedCategories = []) + public function tvSearch(array $siteIdArr = [], $series = '', $episode = '', $airdate = '', $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1, $minSize = 0, array $excludedCategories = [], array $tags = []) { $siteSQL = []; $showSql = ''; @@ -850,10 +870,11 @@ class Releases '%s WHERE r.nzbstatus = %d AND r.passwordstatus %s - %s %s %s %s %s %s', + %s %s %s %s %s %s %s', ($name !== '' ? $this->releaseSearch->getFullTextJoinString() : ''), NZB::NZB_ADDED, $this->showPasswords(), + ! empty($tags) ? " AND tt.tag_name IN ('".implode("','",$tags)."')" : '', $showSql, ($name !== '' ? $this->releaseSearch->getSearchSQL(['searchname' => $name]) : ''), Category::getCategorySearch($cat), @@ -881,8 +902,9 @@ class Releases LEFT JOIN groups g ON g.id = r.groups_id LEFT OUTER JOIN video_data re ON re.releases_id = r.id LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id - %s", + %s %s", $this->getConcatenatedCategoryIDs(), + ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '', $whereSql ); $sql = sprintf( @@ -911,7 +933,7 @@ class Releases } /** - * Search TV Shows vua API. + * Search TV Shows via APIv2. * * * @param array $siteIdArr @@ -927,7 +949,7 @@ class Releases * @param array $excludedCategories * @return \Illuminate\Database\Eloquent\Collection|mixed */ - public function apiTvSearch(array $siteIdArr = [], $series = '', $episode = '', $airdate = '', $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1, $minSize = 0, array $excludedCategories = []) + public function apiTvSearch(array $siteIdArr = [], $series = '', $episode = '', $airdate = '', $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1, $minSize = 0, array $excludedCategories = [], array $tags = []) { $siteSQL = []; $showSql = ''; @@ -989,10 +1011,11 @@ class Releases '%s WHERE r.nzbstatus = %d AND r.passwordstatus %s - %s %s %s %s %s %s', + %s %s %s %s %s %s %s', ($name !== '' ? $this->releaseSearch->getFullTextJoinString() : ''), NZB::NZB_ADDED, $this->showPasswords(), + ! empty($tags) ? " AND tt.tag_name IN ('".implode("','",$tags)."')" : '', $showSql, ($name !== '' ? $this->releaseSearch->getSearchSQL(['searchname' => $name]) : ''), Category::getCategorySearch($cat), @@ -1014,8 +1037,9 @@ class Releases LEFT JOIN categories c ON c.id = r.categories_id LEFT JOIN categories cp ON cp.id = c.parentid LEFT JOIN groups g ON g.id = r.groups_id - %s", + %s %s", $this->getConcatenatedCategoryIDs(), + ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '', $whereSql ); $sql = sprintf( @@ -1127,18 +1151,19 @@ class Releases * @param array $excludedCategories * @return \Illuminate\Database\Eloquent\Collection|mixed */ - public function moviesSearch($imDbId = -1, $tmDbId = -1, $traktId = -1, $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1, $minSize = 0, array $excludedCategories = []) + public function moviesSearch($imDbId = -1, $tmDbId = -1, $traktId = -1, $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1, $minSize = 0, array $excludedCategories = [], array $tags = []) { $whereSql = sprintf( '%s WHERE r.categories_id BETWEEN '.Category::MOVIE_ROOT.' AND '.Category::MOVIE_OTHER.' AND r.nzbstatus = %d AND r.passwordstatus %s - %s %s %s %s %s %s %s', + %s %s %s %s %s %s %s %s', $name !== '' ? $this->releaseSearch->getFullTextJoinString() : '', NZB::NZB_ADDED, $this->showPasswords(), $name !== '' ? $this->releaseSearch->getSearchSQL(['searchname' => $name]) : '', + ! empty($tags) ? " AND tt.tag_name IN ('".implode("','",$tags)."')" : '', ($imDbId !== -1 && is_numeric($imDbId)) ? sprintf(' AND m.imdbid = %d ', str_pad($imDbId, 7, '0', STR_PAD_LEFT)) : '', ($tmDbId !== -1 && is_numeric($tmDbId)) ? sprintf(' AND m.tmdbid = %d ', $tmDbId) : '', ($traktId !== -1 && is_numeric($traktId)) ? sprintf(' AND m.traktid = %d ', $traktId) : '', @@ -1159,8 +1184,9 @@ class Releases LEFT JOIN categories c ON c.id = r.categories_id LEFT JOIN categories cp ON cp.id = c.parentid LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id - %s", + %s %s", $this->getConcatenatedCategoryIDs(), + ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '', $whereSql ); $sql = sprintf( diff --git a/Changelog b/Changelog index 0711ec690..b67707379 100755 --- a/Changelog +++ b/Changelog @@ -1,4 +1,5 @@ 2018-11-06 DariusIII + * Chg: Add support for tags in browse, APIv2 and on site release searches * Chg: Add script to misct/run_me_once to tag all the releases 2018-11-05 DariusIII * Chg: Update ApiController data to return arrays for output diff --git a/app/Http/Controllers/Api/ApiV2Controller.php b/app/Http/Controllers/Api/ApiV2Controller.php index 8fee15156..17e68689a 100644 --- a/app/Http/Controllers/Api/ApiV2Controller.php +++ b/app/Http/Controllers/Api/ApiV2Controller.php @@ -75,6 +75,7 @@ class ApiV2Controller extends Controller $imdbId = $request->has('imdbid') && ! empty($request->input('imdbid')) ? $request->input('imdbid') : -1; $tmdbId = $request->has('tmdbid') && ! empty($request->input('tmdbid')) ? $request->input('tmdbid') : -1; $traktId = $request->has('traktid') && ! empty($request->input('traktid')) ? $request->input('traktid') : -1; + $tags = $request->has('tags') && ! empty($request->input('tags')) ? explode(',', $request->input('tags')) : []; $relData = $releases->moviesSearch( $imdbId, @@ -86,7 +87,8 @@ class ApiV2Controller extends Controller $api->categoryID(), $maxAge, $minSize, - $catExclusions + $catExclusions, + $tags ); $response = [ @@ -111,6 +113,7 @@ class ApiV2Controller extends Controller $offset = $api->offset(); $catExclusions = User::getCategoryExclusion($user->id); $minSize = $request->has('minsize') && $request->input('minsize') > 0 ? $request->input('minsize') : 0; + $tags = $request->has('tags') && ! empty($request->input('tags')) ? explode(',', $request->input('tags')) : []; $maxAge = $api->maxAge(); $groupName = $api->group(); UserRequest::addApiRequest($user->id, $request->getRequestUri()); @@ -126,7 +129,8 @@ class ApiV2Controller extends Controller $maxAge, $catExclusions, $categoryID, - $minSize + $minSize, + $tags ); } else { $relData = $releases->getBrowseRange( @@ -138,7 +142,8 @@ class ApiV2Controller extends Controller $maxAge, $catExclusions, $groupName, - $minSize + $minSize, + $tags ); } @@ -163,6 +168,7 @@ class ApiV2Controller extends Controller $releases = new Releases(); $catExclusions = User::getCategoryExclusion($user->id); $minSize = $request->has('minsize') && $request->input('minsize') > 0 ? $request->input('minsize') : 0; + $tags = $request->has('tags') && ! empty($request->input('tags')) ? explode(',', $request->input('tags')) : []; $api->verifyEmptyParameter('id'); $api->verifyEmptyParameter('vid'); $api->verifyEmptyParameter('tvdbid'); @@ -206,7 +212,8 @@ class ApiV2Controller extends Controller $api->categoryID(), $maxAge, $minSize, - $catExclusions + $catExclusions, + $tags ); $response = [ diff --git a/app/Http/Controllers/BrowseController.php b/app/Http/Controllers/BrowseController.php index a079d17a9..3e262d3a6 100644 --- a/app/Http/Controllers/BrowseController.php +++ b/app/Http/Controllers/BrowseController.php @@ -199,4 +199,50 @@ class BrowseController extends BasePageController $this->pagerender(); } } + + /** + * @param \Illuminate\Http\Request $request + * @throws \Exception + */ + public function tags(Request $request) + { + $this->setPrefs(); + $releases = new Releases(); + if ($request->has('tags')) { + $tags = explode(',', $request->input('tags')); + $page = request()->has('page') && is_numeric(request()->input('page')) ? request()->input('page') : 1; + $offset = ($page - 1) * config('nntmux.items_per_page'); + $rslt = $releases->getBrowseRange($page, [-1], $offset, config('nntmux.items_per_page'), '', -1, $this->userdata['categoryexclusions'], -1, 0, $tags); + $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_page'), $page, request()->url(), request()->query()); + + $browse = []; + + foreach ($results as $result) { + $browse[] = $result; + } + + $this->smarty->assign( + [ + 'results' => $results, + 'resultsadd' => $browse, + 'catname' => 'all', + ] + ); + $meta_title = 'Browse Groups'; + $meta_keywords = 'browse,nzb,description,details'; + $meta_description = 'Browse Groups'; + $content = $this->smarty->fetch('browse.tpl'); + + $this->smarty->assign( + [ + 'content' => $content, + 'meta_title' => $meta_title, + 'meta_keywords' => $meta_keywords, + 'meta_description' => $meta_description, + ] + ); + + $this->pagerender(); + } + } } diff --git a/app/Http/Controllers/SearchController.php b/app/Http/Controllers/SearchController.php index 5e0172523..4d3d1d15c 100644 --- a/app/Http/Controllers/SearchController.php +++ b/app/Http/Controllers/SearchController.php @@ -65,6 +65,11 @@ class SearchController extends BasePageController ); } + $tags = []; + if ($request->has('tags')) { + $tags = explode(',', $request->input('tags')); + } + $rslt = $releases->search( $searchString, -1, @@ -83,7 +88,9 @@ class SearchController extends BasePageController -1, $this->userdata['categoryexclusions'], 'basic', - $categoryID + $categoryID, + 0, + $tags ); $results = $this->paginate($rslt ?? [], $rslt[0]->_totalrows ?? 0, config('nntmux.items_per_page'), $page, $request->url(), $request->query()); diff --git a/resources/views/themes/Gentele/viewnzb.tpl b/resources/views/themes/Gentele/viewnzb.tpl index 76fc50984..793b148eb 100755 --- a/resources/views/themes/Gentele/viewnzb.tpl +++ b/resources/views/themes/Gentele/viewnzb.tpl @@ -526,8 +526,9 @@ Category Tags - {foreach $release->tagSlugs() as $tag} - {$tag} + {foreach $release->tagNames() as $tag} + {$tag} {/foreach} diff --git a/routes/web.php b/routes/web.php index 51fb81286..b88e997c7 100644 --- a/routes/web.php +++ b/routes/web.php @@ -35,6 +35,7 @@ Route::group(['middleware' => ['isVerified', 'fw-block-blacklisted']], function Route::get('profile', 'ProfileController@show'); Route::group(['prefix' => 'browse'], function () { + Route::get('tags', 'BrowseController@tags'); Route::get('group', 'BrowseController@group'); Route::get('all', 'BrowseController@index'); Route::get('{parentCategory}/{id?}', 'BrowseController@show')->middleware('clearance');