mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 01:08:56 +00:00
Update movie cover view query
This commit is contained in:
@@ -47,16 +47,16 @@ class MovieController extends BasePageController
|
||||
}
|
||||
|
||||
$rslt = $this->movieBrowseService->getMovieRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, -1, (array) $this->userdata->categoryexclusions);
|
||||
$results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_cover_page'), $page, $request->url(), $request->query());
|
||||
$totalCount = $rslt->isNotEmpty() ? ($rslt[0]->_totalcount ?? 0) : 0;
|
||||
$results = $this->paginate($rslt ?? [], $totalCount, config('nntmux.items_per_cover_page'), $page, $request->url(), $request->query());
|
||||
|
||||
$movies = $results->map(function ($result) {
|
||||
$result['genre'] = makeFieldLinks($result, 'genre', 'movies');
|
||||
$result['actors'] = makeFieldLinks($result, 'actors', 'movies');
|
||||
$result['director'] = makeFieldLinks($result, 'director', 'movies');
|
||||
$result['languages'] = explode(', ', $result['language']);
|
||||
$result->genre = makeFieldLinks($result, 'genre', 'movies');
|
||||
$result->actors = makeFieldLinks($result, 'actors', 'movies');
|
||||
$result->director = makeFieldLinks($result, 'director', 'movies');
|
||||
|
||||
// Add cover image URL using helper function
|
||||
$result['cover'] = getReleaseCover($result);
|
||||
$result->cover = getReleaseCover($result);
|
||||
|
||||
return $result;
|
||||
});
|
||||
@@ -111,17 +111,6 @@ class MovieController extends BasePageController
|
||||
return redirect()->route('Movies')->with('error', 'Movie not found');
|
||||
}
|
||||
|
||||
// Get all releases for this movie
|
||||
$rslt = $this->movieBrowseService->getMovieRange(1, [], 0, 1000, '', -1, (array) $this->userdata->categoryexclusions);
|
||||
|
||||
// Filter to only this movie's IMDB ID
|
||||
/** @phpstan-ignore argument.templateType */
|
||||
$movieData = collect($rslt)->firstWhere('imdbid', $imdbid);
|
||||
|
||||
if (! $movieData) {
|
||||
return redirect()->route('Movies')->with('error', 'No releases found for this movie');
|
||||
}
|
||||
|
||||
// Convert Eloquent model to array
|
||||
$movieArray = $movieInfo->toArray();
|
||||
|
||||
@@ -147,25 +136,8 @@ class MovieController extends BasePageController
|
||||
// Add cover image URL using helper function
|
||||
$movieArray['cover'] = getReleaseCover($movieArray);
|
||||
|
||||
// Process all releases
|
||||
$releaseNames = isset($movieData->grp_release_name) ? explode('#', $movieData->grp_release_name) : [];
|
||||
$releaseSizes = isset($movieData->grp_release_size) ? explode(',', $movieData->grp_release_size) : [];
|
||||
$releaseGuids = isset($movieData->grp_release_guid) ? explode(',', $movieData->grp_release_guid) : [];
|
||||
$releasePostDates = isset($movieData->grp_release_postdate) ? explode(',', $movieData->grp_release_postdate) : [];
|
||||
$releaseAddDates = isset($movieData->grp_release_adddate) ? explode(',', $movieData->grp_release_adddate) : [];
|
||||
|
||||
$releases = [];
|
||||
foreach ($releaseNames as $index => $releaseName) {
|
||||
if ($releaseName && isset($releaseGuids[$index])) {
|
||||
$releases[] = [
|
||||
'name' => $releaseName,
|
||||
'guid' => $releaseGuids[$index],
|
||||
'size' => $releaseSizes[$index] ?? 0,
|
||||
'postdate' => $releasePostDates[$index] ?? null,
|
||||
'adddate' => $releaseAddDates[$index] ?? null,
|
||||
];
|
||||
}
|
||||
}
|
||||
// Get all releases for this movie directly (no limit)
|
||||
$releases = $this->movieBrowseService->getMovieReleases($imdbid, (array) $this->userdata->categoryexclusions);
|
||||
|
||||
$this->viewData = array_merge($this->viewData, [
|
||||
'movie' => $movieArray,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
/**
|
||||
@@ -71,6 +72,14 @@ class MovieInfo extends Model
|
||||
*/
|
||||
protected $guarded = ['id'];
|
||||
|
||||
/**
|
||||
* Get the releases associated with this movie.
|
||||
*/
|
||||
public function releases(): HasMany // @phpstan-ignore missingType.generics
|
||||
{
|
||||
return $this->hasMany(Release::class, 'imdbid', 'imdbid');
|
||||
}
|
||||
|
||||
public static function getAll(string $search = ''): mixed
|
||||
{
|
||||
$expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Services;
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Models\MovieInfo;
|
||||
use App\Models\Release;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
@@ -23,6 +22,11 @@ class MovieBrowseService
|
||||
/**
|
||||
* Get movie releases with covers for movie browse page.
|
||||
*
|
||||
* Uses three separate queries instead of GROUP_CONCAT:
|
||||
* 1. COUNT query for total results (replaces SQL_CALC_FOUND_ROWS)
|
||||
* 2. Paginated movie list with only needed columns
|
||||
* 3. Top 2 releases per movie using ROW_NUMBER() window function
|
||||
*
|
||||
* @param array<string, mixed> $cat
|
||||
* @param array<string, mixed> $excludedCats
|
||||
*/
|
||||
@@ -30,81 +34,128 @@ class MovieBrowseService
|
||||
{
|
||||
$page = max(1, $page);
|
||||
$start = max(0, $start);
|
||||
|
||||
$catsrch = '';
|
||||
if (count($cat) > 0 && $cat[0] !== -1) { // @phpstan-ignore offsetAccess.notFound
|
||||
$catsrch = Category::getCategorySearch($cat);
|
||||
}
|
||||
|
||||
$order = $this->getMovieOrder($orderBy);
|
||||
$expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
|
||||
|
||||
$whereAge = $maxAge > 0 ? 'AND r.postdate > NOW() - INTERVAL '.$maxAge.' DAY ' : '';
|
||||
$whereExcluded = count($excludedCats) > 0 ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : '';
|
||||
$limitClause = $start === false ? '' : ' LIMIT '.$num.' OFFSET '.$start;
|
||||
$moviesSql = "SELECT SQL_CALC_FOUND_ROWS m.imdbid, GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',' ) AS grp_release_id "
|
||||
."FROM movieinfo m LEFT JOIN releases r USING (imdbid) WHERE m.title != '' AND m.imdbid != '0000000' "
|
||||
."AND r.passwordstatus {$this->showPasswords} "
|
||||
.$this->getBrowseBy().' '
|
||||
.(! empty($catsrch) ? $catsrch.' ' : '')
|
||||
.$whereAge
|
||||
.$whereExcluded.' '
|
||||
."GROUP BY m.imdbid ORDER BY {$order[0]} {$order[1]} {$limitClause}"; // @phpstan-ignore offsetAccess.notFound
|
||||
$movieCache = Cache::get(md5($moviesSql.$page));
|
||||
if ($movieCache !== null) {
|
||||
$movies = $movieCache;
|
||||
} else {
|
||||
$data = MovieInfo::fromQuery($moviesSql);
|
||||
$movies = ['total' => DB::select('SELECT FOUND_ROWS() AS total'), 'result' => $data];
|
||||
Cache::put(md5($moviesSql.$page), $movies, $expiresAt);
|
||||
}
|
||||
$movieIDs = $releaseIDs = [];
|
||||
if (! empty($movies['result'])) {
|
||||
foreach ($movies['result'] as $id) {
|
||||
$movieIDs[] = $id->imdbid;
|
||||
$releaseIDs[] = $id->grp_release_id;
|
||||
}
|
||||
}
|
||||
$inMovieIds = ! empty($movieIDs) ? implode(',', $movieIDs) : -1;
|
||||
$inReleaseIds = ! empty($releaseIDs) ? implode(',', $releaseIDs) : -1;
|
||||
$sql = '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.adddate ORDER BY r.postdate DESC SEPARATOR ',' ) AS grp_release_adddate, "
|
||||
."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(rr.report_count ORDER BY r.postdate DESC SEPARATOR ',' ) AS grp_release_reports, "
|
||||
."GROUP_CONCAT(rr.report_reasons ORDER BY r.postdate DESC SEPARATOR '|' ) AS grp_release_report_reasons, "
|
||||
."GROUP_CONCAT(cp.title, ' > ', c.title ORDER BY r.postdate DESC SEPARATOR ',' ) AS grp_release_catname, "
|
||||
.'m.*, 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 (SELECT releases_id, COUNT(*) AS report_count, GROUP_CONCAT(DISTINCT reason SEPARATOR \', \') AS report_reasons FROM release_reports WHERE status IN (\'pending\', \'reviewed\', \'resolved\') GROUP BY releases_id) rr ON rr.releases_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 movieinfo m ON m.imdbid = r.imdbid '
|
||||
."WHERE m.imdbid IN ($inMovieIds) AND r.id IN ($inReleaseIds) "
|
||||
.(! empty($catsrch) ? $catsrch.' ' : '')
|
||||
."GROUP BY m.imdbid ORDER BY {$order[0]} {$order[1]}"; // @phpstan-ignore offsetAccess.notFound
|
||||
$return = Cache::get(md5($sql.$page));
|
||||
if ($return !== null) {
|
||||
return $return;
|
||||
}
|
||||
$return = Release::fromQuery($sql);
|
||||
if (count($return) > 0) {
|
||||
$return[0]->_totalcount = $movies['total'][0]->total ?? 0;
|
||||
}
|
||||
Cache::put(md5($sql.$page), $return, $expiresAt);
|
||||
$browseBy = $this->getBrowseBy();
|
||||
$catFilter = ! empty($catsrch) ? $catsrch.' ' : '';
|
||||
|
||||
return $return;
|
||||
$baseWhere = "m.title != '' AND m.imdbid != '0000000' "
|
||||
."AND r.passwordstatus {$this->showPasswords} "
|
||||
.$browseBy.' '
|
||||
.$catFilter
|
||||
.$whereAge
|
||||
.$whereExcluded;
|
||||
|
||||
// Build a cache key from all the query parameters
|
||||
$cacheKey = md5('movie_range_'.$baseWhere.$order[0].$order[1].$start.$num.$page); // @phpstan-ignore offsetAccess.notFound
|
||||
|
||||
$cached = Cache::get($cacheKey);
|
||||
if ($cached !== null) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
// Step 1: Count total distinct movies matching filters
|
||||
$countSql = 'SELECT COUNT(DISTINCT m.imdbid) AS total '
|
||||
.'FROM movieinfo m '
|
||||
.'INNER JOIN releases r ON r.imdbid = m.imdbid '
|
||||
.'WHERE '.$baseWhere;
|
||||
|
||||
$totalResult = DB::select($countSql);
|
||||
$totalCount = $totalResult[0]->total ?? 0;
|
||||
|
||||
if ($totalCount === 0) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
// Step 2: Get paginated movie list with only needed columns
|
||||
$moviesSql = 'SELECT m.imdbid, m.tmdbid, m.traktid, m.title, m.year, m.rating, '
|
||||
.'m.plot, m.genre, m.director, m.actors, m.cover, '
|
||||
.'MAX(r.postdate) AS latest_postdate, '
|
||||
.'COUNT(r.id) AS total_releases '
|
||||
.'FROM movieinfo m '
|
||||
.'INNER JOIN releases r ON r.imdbid = m.imdbid '
|
||||
.'WHERE '.$baseWhere.' '
|
||||
.'GROUP BY m.imdbid, m.tmdbid, m.traktid, m.title, m.year, m.rating, '
|
||||
.'m.plot, m.genre, m.director, m.actors, m.cover '
|
||||
."ORDER BY {$order[0]} {$order[1]} " // @phpstan-ignore offsetAccess.notFound
|
||||
."LIMIT {$num} OFFSET {$start}";
|
||||
|
||||
$movies = MovieInfo::fromQuery($moviesSql);
|
||||
|
||||
if ($movies->isEmpty()) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
// Build list of movie IMDB IDs for release query
|
||||
$movieImdbIds = $movies->pluck('imdbid')->toArray();
|
||||
$inMovieIds = implode(',', array_map('intval', $movieImdbIds));
|
||||
|
||||
// Step 3: Get top 2 releases per movie using ROW_NUMBER() window function
|
||||
$releasesSql = 'SELECT ranked.id, ranked.imdbid, ranked.guid, ranked.searchname, '
|
||||
.'ranked.size, ranked.postdate, ranked.adddate, ranked.haspreview '
|
||||
.'FROM ( '
|
||||
.'SELECT r.id, r.imdbid, r.guid, r.searchname, r.size, r.postdate, r.adddate, r.haspreview, '
|
||||
.'ROW_NUMBER() OVER (PARTITION BY r.imdbid ORDER BY r.postdate DESC) AS rn '
|
||||
.'FROM releases r '
|
||||
."WHERE r.imdbid IN ({$inMovieIds}) "
|
||||
."AND r.passwordstatus {$this->showPasswords} "
|
||||
.$catFilter
|
||||
.$whereAge
|
||||
.$whereExcluded
|
||||
.') ranked '
|
||||
.'WHERE ranked.rn <= 2 '
|
||||
.'ORDER BY ranked.imdbid, ranked.postdate DESC';
|
||||
|
||||
$releases = DB::select($releasesSql);
|
||||
|
||||
// Group releases by imdbid for fast lookup
|
||||
$releasesByMovie = [];
|
||||
foreach ($releases as $release) {
|
||||
$releasesByMovie[$release->imdbid][] = $release;
|
||||
}
|
||||
|
||||
// Attach releases to each movie object
|
||||
foreach ($movies as $movie) {
|
||||
$movie->releases = $releasesByMovie[$movie->imdbid] ?? []; // @phpstan-ignore assign.propertyReadOnly
|
||||
}
|
||||
|
||||
// Set total count on first item (matches existing pattern used by controllers)
|
||||
if ($movies->isNotEmpty()) {
|
||||
$movies[0]->_totalcount = $totalCount; // @phpstan-ignore property.notFound
|
||||
}
|
||||
|
||||
Cache::put($cacheKey, $movies, $expiresAt);
|
||||
|
||||
return $movies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all releases for a single movie by IMDB ID.
|
||||
*
|
||||
* @param array<string, mixed> $excludedCats
|
||||
* @return array<int, object>
|
||||
*/
|
||||
public function getMovieReleases(string $imdbid, array $excludedCats = []): array
|
||||
{
|
||||
$whereExcluded = count($excludedCats) > 0 ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : '';
|
||||
|
||||
$sql = 'SELECT r.id, r.guid, r.searchname, r.size, r.postdate, r.adddate, r.haspreview '
|
||||
.'FROM releases r '
|
||||
.'WHERE r.imdbid = '.intval($imdbid).' '
|
||||
."AND r.passwordstatus {$this->showPasswords} "
|
||||
.$whereExcluded.' '
|
||||
.'ORDER BY r.postdate DESC';
|
||||
|
||||
return DB::select($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{{-- Movie Card Partial --}}
|
||||
{{-- Props: $result (movie object), $layout (1 or 2), $site (site configuration) --}}
|
||||
{{-- Props: $result (movie object with ->releases array), $layout (1 or 2), $site (site configuration) --}}
|
||||
|
||||
@props([
|
||||
'result',
|
||||
@@ -8,34 +8,13 @@
|
||||
])
|
||||
|
||||
@php
|
||||
// Get the first GUID from the comma-separated list
|
||||
$guid = isset($result->grp_release_guid) ? explode(',', $result->grp_release_guid)[0] : null;
|
||||
|
||||
// Parse release data
|
||||
$releaseNames = isset($result->grp_release_name) ? explode('#', $result->grp_release_name) : [];
|
||||
$releaseSizes = isset($result->grp_release_size) ? explode(',', $result->grp_release_size) : [];
|
||||
$releaseGuids = isset($result->grp_release_guid) ? explode(',', $result->grp_release_guid) : [];
|
||||
$releaseIds = isset($result->grp_release_id) ? explode(',', $result->grp_release_id) : [];
|
||||
$releasePostDates = isset($result->grp_release_postdate) ? explode(',', $result->grp_release_postdate) : [];
|
||||
$releaseAddDates = isset($result->grp_release_adddate) ? explode(',', $result->grp_release_adddate) : [];
|
||||
$releaseHasPreview = isset($result->grp_haspreview) ? explode(',', $result->grp_haspreview) : [];
|
||||
$releaseJpgStatus = isset($result->grp_jpgstatus) ? explode(',', $result->grp_jpgstatus) : [];
|
||||
$releaseNfoStatus = isset($result->grp_nfostatus) ? explode(',', $result->grp_nfostatus) : [];
|
||||
$releaseFromNames = isset($result->grp_release_fromname) ? explode(',', $result->grp_release_fromname) : [];
|
||||
|
||||
// Limit to maximum 2 releases
|
||||
// Releases are already attached as an array of objects (max 2 from the query)
|
||||
$releases = $result->releases ?? [];
|
||||
$totalReleases = $result->total_releases ?? count($releases);
|
||||
$maxReleases = 2;
|
||||
$totalReleases = count($releaseNames);
|
||||
$releaseNames = array_slice($releaseNames, 0, $maxReleases);
|
||||
$releaseSizes = array_slice($releaseSizes, 0, $maxReleases);
|
||||
$releaseGuids = array_slice($releaseGuids, 0, $maxReleases);
|
||||
$releaseIds = array_slice($releaseIds, 0, $maxReleases);
|
||||
$releasePostDates = array_slice($releasePostDates, 0, $maxReleases);
|
||||
$releaseAddDates = array_slice($releaseAddDates, 0, $maxReleases);
|
||||
$releaseHasPreview = array_slice($releaseHasPreview, 0, $maxReleases);
|
||||
$releaseJpgStatus = array_slice($releaseJpgStatus, 0, $maxReleases);
|
||||
$releaseNfoStatus = array_slice($releaseNfoStatus, 0, $maxReleases);
|
||||
$releaseFromNames = array_slice($releaseFromNames, 0, $maxReleases);
|
||||
|
||||
// Get the first GUID from releases
|
||||
$guid = !empty($releases) ? $releases[0]->guid : null;
|
||||
|
||||
// Image dimensions based on layout
|
||||
$coverClass = $layout == 1 ? 'w-48 h-72' : 'w-32 h-48';
|
||||
@@ -74,7 +53,7 @@
|
||||
|
||||
{{-- Movie Details --}}
|
||||
<div class="flex-1 p-4 min-w-0">
|
||||
{{-- Title and Report Badges --}}
|
||||
{{-- Title --}}
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<div class="flex-1 min-w-0">
|
||||
@if(isset($result->imdbid) && $result->imdbid)
|
||||
@@ -85,40 +64,6 @@
|
||||
<h3 class="text-lg font-bold text-gray-900 dark:text-gray-100 truncate">{{ $result->title }}</h3>
|
||||
@endif
|
||||
|
||||
{{-- Report Badges --}}
|
||||
<div class="flex flex-wrap gap-2 mt-1">
|
||||
@if(!empty($result->grp_release_reports))
|
||||
@php
|
||||
$reportCounts = array_filter(explode(',', $result->grp_release_reports));
|
||||
$totalReports = array_sum($reportCounts);
|
||||
$reportReasonsRaw = !empty($result->grp_release_report_reasons)
|
||||
? implode(',', array_unique(array_filter(preg_split('/[|,]/', $result->grp_release_report_reasons))))
|
||||
: '';
|
||||
$reportReasons = \App\Models\ReleaseReport::reasonKeysToLabels($reportReasonsRaw);
|
||||
@endphp
|
||||
@if($totalReports > 0)
|
||||
<div class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-orange-100 dark:bg-orange-900 text-orange-800 dark:text-orange-200 border border-orange-200 dark:border-orange-800"
|
||||
title="Reported: {{ $reportReasons }}">
|
||||
<i class="fas fa-flag mr-1"></i>
|
||||
<span>{{ $totalReports }} report{{ $totalReports > 1 ? 's' : '' }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if(!empty($result->grp_release_failed))
|
||||
@php
|
||||
$failedCounts = array_filter(explode(',', $result->grp_release_failed));
|
||||
$totalFailed = array_sum($failedCounts);
|
||||
@endphp
|
||||
@if($totalFailed > 0)
|
||||
<div class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200 border border-red-200 dark:border-red-800">
|
||||
<i class="fas fa-exclamation-triangle mr-1"></i>
|
||||
<span>{{ $totalFailed }} failed report{{ $totalFailed > 1 ? 's' : '' }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Year and Rating --}}
|
||||
<div class="flex items-center gap-4 mt-2 text-sm text-gray-600 dark:text-gray-400">
|
||||
@if(isset($result->year) && $result->year)
|
||||
@@ -186,7 +131,7 @@
|
||||
</div>
|
||||
|
||||
{{-- Release Information --}}
|
||||
@if($guid && !empty($releaseNames[0]))
|
||||
@if($guid && !empty($releases))
|
||||
<div class="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<h4 class="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-3">
|
||||
<i class="fas fa-box mr-1"></i> Available Releases
|
||||
@@ -197,18 +142,9 @@
|
||||
@endif
|
||||
</h4>
|
||||
<div class="space-y-3">
|
||||
@foreach($releaseNames as $index => $releaseName)
|
||||
@foreach($releases as $index => $release)
|
||||
@include('movies.partials.release-item', [
|
||||
'releaseName' => $releaseName,
|
||||
'releaseGuid' => $releaseGuids[$index] ?? '',
|
||||
'releaseId' => $releaseIds[$index] ?? null,
|
||||
'releaseSize' => $releaseSizes[$index] ?? 0,
|
||||
'releasePostDate' => $releasePostDates[$index] ?? null,
|
||||
'releaseAddDate' => $releaseAddDates[$index] ?? null,
|
||||
'hasPreview' => $releaseHasPreview[$index] ?? 0,
|
||||
'jpgStatus' => $releaseJpgStatus[$index] ?? 0,
|
||||
'nfoStatus' => $releaseNfoStatus[$index] ?? 0,
|
||||
'fromName' => $releaseFromNames[$index] ?? '',
|
||||
'release' => $release,
|
||||
'layout' => $layout,
|
||||
'index' => $index,
|
||||
])
|
||||
@@ -219,5 +155,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -1,112 +1,76 @@
|
||||
{{-- Release Item Partial --}}
|
||||
{{-- Props: $releaseName, $releaseGuid, $releaseId, $releaseSize, $releasePostDate, $releaseAddDate, $hasPreview, $jpgStatus, $nfoStatus, $fromName, $layout, $index --}}
|
||||
{{-- Props: $release (object with ->id, ->guid, ->searchname, ->size, ->postdate, ->adddate, ->haspreview), $layout, $index --}}
|
||||
|
||||
@props([
|
||||
'releaseName' => '',
|
||||
'releaseGuid' => '',
|
||||
'releaseId' => null,
|
||||
'releaseSize' => 0,
|
||||
'releasePostDate' => null,
|
||||
'releaseAddDate' => null,
|
||||
'hasPreview' => 0,
|
||||
'jpgStatus' => 0,
|
||||
'nfoStatus' => 0,
|
||||
'fromName' => '',
|
||||
'release',
|
||||
'layout' => 2,
|
||||
'index' => 0,
|
||||
])
|
||||
|
||||
@if($releaseName && $releaseGuid)
|
||||
@if(($release->searchname ?? null) && ($release->guid ?? null))
|
||||
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-3 border border-gray-200 dark:border-gray-700">
|
||||
<div class="release-card-container {{ $layout == 1 ? 'flex flex-row items-start justify-between gap-4' : 'flex flex-col space-y-3' }}">
|
||||
<div class="release-info-wrapper {{ $layout == 1 ? 'flex-1 min-w-0' : '' }}">
|
||||
{{-- Release Name --}}
|
||||
<a href="{{ url('/details/' . $releaseGuid) }}"
|
||||
<a href="{{ url('/details/' . $release->guid) }}"
|
||||
class="text-sm text-gray-800 dark:text-gray-200 hover:text-blue-600 dark:hover:text-blue-400 font-medium block break-all"
|
||||
title="{{ $releaseName }}">
|
||||
{{ $releaseName }}
|
||||
title="{{ $release->searchname }}">
|
||||
{{ $release->searchname }}
|
||||
</a>
|
||||
|
||||
{{-- Info Badges --}}
|
||||
<div class="flex flex-wrap items-center gap-2 mt-2">
|
||||
@if($releaseSize)
|
||||
@if($release->size)
|
||||
<span class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-hdd mr-1"></i>{{ number_format($releaseSize / 1073741824, 2) }} GB
|
||||
<i class="fas fa-hdd mr-1"></i>{{ number_format($release->size / 1073741824, 2) }} GB
|
||||
</span>
|
||||
@endif
|
||||
|
||||
@if($releasePostDate)
|
||||
@if($release->postdate)
|
||||
<span class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-calendar-alt mr-1"></i>{{ userDate($releasePostDate, 'M d, Y H:i') }}
|
||||
<i class="fas fa-calendar-alt mr-1"></i>{{ userDate($release->postdate, 'M d, Y H:i') }}
|
||||
</span>
|
||||
@endif
|
||||
|
||||
@if($releaseAddDate)
|
||||
@if($release->adddate)
|
||||
<span class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-plus-circle mr-1"></i>{{ userDateDiffForHumans($releaseAddDate) }}
|
||||
<i class="fas fa-plus-circle mr-1"></i>{{ userDateDiffForHumans($release->adddate) }}
|
||||
</span>
|
||||
@endif
|
||||
|
||||
@if($hasPreview == 1)
|
||||
@if(($release->haspreview ?? 0) == 1)
|
||||
<button type="button"
|
||||
class="preview-badge inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200 hover:bg-purple-200 dark:hover:bg-purple-800 transition cursor-pointer"
|
||||
data-guid="{{ $releaseGuid }}"
|
||||
data-guid="{{ $release->guid }}"
|
||||
title="View preview image">
|
||||
<i class="fas fa-image mr-1"></i> Preview
|
||||
</button>
|
||||
@endif
|
||||
|
||||
@if($jpgStatus == 1)
|
||||
<button type="button"
|
||||
class="sample-badge inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200 hover:bg-green-200 dark:hover:bg-green-800 transition cursor-pointer"
|
||||
data-guid="{{ $releaseGuid }}"
|
||||
title="View sample image">
|
||||
<i class="fas fa-images mr-1"></i> Sample
|
||||
</button>
|
||||
@endif
|
||||
|
||||
@if($nfoStatus == 1)
|
||||
<button type="button"
|
||||
class="nfo-badge inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200 hover:bg-yellow-200 dark:hover:bg-yellow-800 transition cursor-pointer"
|
||||
data-guid="{{ $releaseGuid }}"
|
||||
title="View NFO file">
|
||||
<i class="fas fa-file-alt mr-1"></i> NFO
|
||||
</button>
|
||||
@endif
|
||||
|
||||
@if(!empty($fromName))
|
||||
<span class="inline-flex items-center px-2 py-1 rounded text-xs font-medium bg-indigo-100 dark:bg-indigo-900 text-indigo-800 dark:text-indigo-200"
|
||||
title="Poster/Uploader">
|
||||
<i class="fas fa-user mr-1"></i> {{ $fromName }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Action Buttons --}}
|
||||
<div class="release-actions flex flex-wrap items-center gap-2 {{ $layout == 1 ? 'shrink-0' : 'mt-2' }}">
|
||||
<a href="{{ url('/getnzb/' . $releaseGuid) }}"
|
||||
<a href="{{ url('/getnzb/' . $release->guid) }}"
|
||||
class="inline-flex items-center px-3 py-1 rounded text-xs font-medium bg-green-600 dark:bg-green-700 text-white hover:bg-green-700 dark:hover:bg-green-800 transition">
|
||||
<i class="fas fa-download mr-1"></i> Download
|
||||
</a>
|
||||
|
||||
<button type="button"
|
||||
class="add-to-cart inline-flex items-center px-3 py-1 rounded text-xs font-medium bg-blue-600 dark:bg-blue-700 text-white hover:bg-blue-700 dark:hover:bg-blue-800 transition"
|
||||
data-guid="{{ $releaseGuid }}">
|
||||
data-guid="{{ $release->guid }}">
|
||||
<i class="fas fa-shopping-cart mr-1"></i> Cart
|
||||
</button>
|
||||
|
||||
<a href="{{ url('/details/' . $releaseGuid) }}"
|
||||
<a href="{{ url('/details/' . $release->guid) }}"
|
||||
class="inline-flex items-center px-3 py-1 rounded text-xs font-medium bg-gray-600 dark:bg-gray-700 text-white hover:bg-gray-700 dark:hover:bg-gray-800 transition">
|
||||
<i class="fas fa-info-circle mr-1"></i> Details
|
||||
</a>
|
||||
|
||||
@if($releaseId)
|
||||
<x-report-button :release-id="(int)$releaseId" variant="icon" />
|
||||
@if($release->id)
|
||||
<x-report-button :release-id="(int)$release->id" variant="icon" />
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
|
||||
@@ -191,48 +191,43 @@
|
||||
|
||||
<div class="space-y-3" id="releases-container">
|
||||
@foreach($releases as $release)
|
||||
<div class="release-item bg-gray-50 dark:bg-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700 hover:shadow-md transition" data-release-name="{{ strtolower($release['name']) }}">
|
||||
<div class="release-item bg-gray-50 dark:bg-gray-900 rounded-lg p-4 border border-gray-200 dark:border-gray-700 hover:shadow-md transition" data-release-name="{{ strtolower($release->searchname) }}">
|
||||
<div class="flex flex-col lg:flex-row lg:items-center justify-between gap-3">
|
||||
<div class="flex-1 min-w-0">
|
||||
<a href="{{ url('/details/' . $release['guid']) }}" class="text-base text-gray-800 dark:text-gray-200 hover:text-blue-600 dark:text-blue-400 font-medium block truncate" title="{{ $release['name'] }}">
|
||||
{{ $release['name'] }}
|
||||
<a href="{{ url('/details/' . $release->guid) }}" class="text-base text-gray-800 dark:text-gray-200 hover:text-blue-600 dark:text-blue-400 font-medium block truncate" title="{{ $release->searchname }}">
|
||||
{{ $release->searchname }}
|
||||
</a>
|
||||
<div class="flex flex-wrap items-center gap-4 mt-2 text-sm text-gray-500">
|
||||
<span>
|
||||
<i class="fas fa-hdd mr-1"></i>{{ number_format($release['size'] / 1073741824, 2) }} GB
|
||||
<i class="fas fa-hdd mr-1"></i>{{ number_format($release->size / 1073741824, 2) }} GB
|
||||
</span>
|
||||
@if($release['postdate'])
|
||||
@if($release->postdate)
|
||||
<span>
|
||||
<i class="fas fa-calendar-alt mr-1"></i>Posted: {{ userDate($release['postdate'], 'M d, Y H:i') }}
|
||||
<i class="fas fa-calendar-alt mr-1"></i>Posted: {{ userDate($release->postdate, 'M d, Y H:i') }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 mt-2 text-xs">
|
||||
@if(!empty($release['group_name']))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300">
|
||||
<i class="fas fa-users mr-1"></i> {{ $release['group_name'] }}
|
||||
</span>
|
||||
@endif
|
||||
@if($release['postdate'])
|
||||
@if($release->postdate)
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200">
|
||||
<i class="fas fa-calendar-alt mr-1"></i>Posted: {{ \Carbon\Carbon::parse($release['postdate'])->format('M d, Y H:i') }}
|
||||
<i class="fas fa-calendar-alt mr-1"></i>Posted: {{ \Carbon\Carbon::parse($release->postdate)->format('M d, Y H:i') }}
|
||||
</span>
|
||||
@endif
|
||||
@if(!empty($release['fromname']))
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-indigo-100 dark:bg-indigo-900 text-indigo-800 dark:text-indigo-200 font-mono">
|
||||
<i class="fas fa-user mr-1"></i>{{ $release['fromname'] }}
|
||||
@if($release->adddate)
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200">
|
||||
<i class="fas fa-plus-circle mr-1"></i>Added: {{ userDateDiffForHumans($release->adddate) }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2 flex-shrink-0">
|
||||
<a href="{{ url('/getnzb/' . $release['guid']) }}" class="inline-flex items-center px-4 py-2 bg-green-600 dark:bg-green-700 text-white text-sm font-medium rounded-lg hover:bg-green-700 dark:hover:bg-green-800 transition">
|
||||
<a href="{{ url('/getnzb/' . $release->guid) }}" class="inline-flex items-center px-4 py-2 bg-green-600 dark:bg-green-700 text-white text-sm font-medium rounded-lg hover:bg-green-700 dark:hover:bg-green-800 transition">
|
||||
<i class="fas fa-download mr-2"></i> Download
|
||||
</a>
|
||||
<button class="add-to-cart inline-flex items-center px-4 py-2 bg-blue-600 dark:bg-blue-700 text-white text-sm font-medium rounded-lg hover:bg-blue-700 dark:hover:bg-blue-800 transition" data-guid="{{ $release['guid'] }}">
|
||||
<button class="add-to-cart inline-flex items-center px-4 py-2 bg-blue-600 dark:bg-blue-700 text-white text-sm font-medium rounded-lg hover:bg-blue-700 dark:hover:bg-blue-800 transition" data-guid="{{ $release->guid }}">
|
||||
<i class="fas fa-shopping-cart mr-2"></i> Add to Cart
|
||||
</button>
|
||||
<a href="{{ url('/details/' . $release['guid']) }}" class="inline-flex items-center px-4 py-2 bg-gray-600 text-white text-sm font-medium rounded-lg hover:bg-gray-700 transition">
|
||||
<a href="{{ url('/details/' . $release->guid) }}" class="inline-flex items-center px-4 py-2 bg-gray-600 text-white text-sm font-medium rounded-lg hover:bg-gray-700 transition">
|
||||
<i class="fas fa-info-circle mr-2"></i> Details
|
||||
</a>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user