Update movie pages

This commit is contained in:
DariusIII
2025-10-03 17:06:35 +02:00
parent 870e629342
commit cb161052d5
5 changed files with 364 additions and 38 deletions
+1
View File
@@ -231,6 +231,7 @@ class Movie
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,
+115
View File
@@ -46,6 +46,19 @@ class MovieController extends BasePageController
$result['director'] = makeFieldLinks($result, 'director', 'movies');
$result['languages'] = explode(', ', $result['language']);
// Add cover image URL
if (! empty($result['imdbid'])) {
$coverId = str_pad($result['imdbid'], 7, '0', STR_PAD_LEFT);
$coverFile = storage_path("covers/movies/{$coverId}-cover.jpg");
if (file_exists($coverFile)) {
$result['cover'] = asset("storage/covers/movies/{$coverId}-cover.jpg");
} else {
$result['cover'] = asset('assets/images/no-cover.png');
}
} else {
$result['cover'] = asset('assets/images/no-cover.png');
}
return $result;
});
@@ -84,6 +97,108 @@ class MovieController extends BasePageController
return view($viewName, $this->viewData);
}
/**
* Show a single movie with all its releases
*
* @throws \Exception
*/
public function showMovie(Request $request, string $imdbid)
{
$this->setPreferences();
$movie = new Movie(['Settings' => $this->settings]);
// Get movie info
$movieInfo = $movie->getMovieInfo($imdbid);
if (! $movieInfo) {
return redirect()->route('Movies')->with('error', 'Movie not found');
}
// Get all releases for this movie
$rslt = $movie->getMovieRange(1, [], 0, 1000, '', -1, $this->userdata->categoryexclusions);
// Filter to only this movie's IMDB ID
$movieData = collect($rslt)->firstWhere('imdbid', $imdbid);
if (! $movieData) {
return redirect()->route('Movies')->with('error', 'No releases found for this movie');
}
// Process movie data - ensure we handle both objects and arrays
if (is_object($movieInfo)) {
// If it's an Eloquent model, use toArray()
if (method_exists($movieInfo, 'toArray')) {
$movieArray = $movieInfo->toArray();
} else {
$movieArray = get_object_vars($movieInfo);
}
} else {
$movieArray = $movieInfo;
}
// Ensure we have at least the basic fields
if (empty($movieArray['title'])) {
$movieArray['title'] = 'Unknown Title';
}
if (empty($movieArray['imdbid'])) {
$movieArray['imdbid'] = $imdbid;
}
// Only process fields if they exist and are not empty
if (! empty($movieArray['genre'])) {
$movieArray['genre'] = makeFieldLinks($movieArray, 'genre', 'movies');
}
if (! empty($movieArray['actors'])) {
$movieArray['actors'] = makeFieldLinks($movieArray, 'actors', 'movies');
}
if (! empty($movieArray['director'])) {
$movieArray['director'] = makeFieldLinks($movieArray, 'director', 'movies');
}
// Add cover image URL
if (! empty($imdbid)) {
$coverId = str_pad($imdbid, 7, '0', STR_PAD_LEFT);
$coverFile = storage_path("covers/movies/{$coverId}-cover.jpg");
if (file_exists($coverFile)) {
$movieArray['cover'] = asset("storage/covers/movies/{$coverId}-cover.jpg");
} else {
$movieArray['cover'] = asset('assets/images/no-cover.png');
}
} else {
$movieArray['cover'] = asset('assets/images/no-cover.png');
}
// 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,
];
}
}
$this->viewData = array_merge($this->viewData, [
'movie' => $movieArray,
'releases' => $releases,
'meta_title' => ($movieArray['title'] ?? 'Movie').' - Movie Details',
'meta_keywords' => 'movie,details,releases',
'meta_description' => 'View all releases for '.($movieArray['title'] ?? 'this movie'),
]);
return view('movies.viewmoviefull', $this->viewData);
}
/**
* @return \Illuminate\Http\JsonResponse|\Illuminate\View\View
*/
+125 -18
View File
@@ -93,23 +93,23 @@
<div class="bg-white border border-gray-200 rounded-lg overflow-hidden hover:shadow-lg transition-shadow">
<div class="flex flex-col md:flex-row">
<!-- Movie Poster -->
<div class="md:w-48 flex-shrink-0">
<div class="flex-shrink-0">
@if($guid)
<a href="{{ url('/details/' . $guid) }}" class="block">
@if(isset($result->cover) && $result->cover)
<img src="{{ $result->cover }}" alt="{{ $result->title }}" class="w-full h-64 md:h-full object-cover">
<img src="{{ $result->cover }}" alt="{{ $result->title }}" class="w-48 h-72 object-cover rounded" style="width: 192px; height: 288px;">
@else
<div class="w-full h-64 md:h-full bg-gray-200 flex items-center justify-center">
<i class="fas fa-film text-gray-400 text-4xl"></i>
<div class="w-48 h-72 bg-gray-200 flex items-center justify-center rounded" style="width: 192px; height: 288px;">
<i class="fas fa-film text-gray-400 text-3xl"></i>
</div>
@endif
</a>
@else
@if(isset($result->cover) && $result->cover)
<img src="{{ $result->cover }}" alt="{{ $result->title }}" class="w-full h-64 md:h-full object-cover">
<img src="{{ $result->cover }}" alt="{{ $result->title }}" class="w-48 h-72 object-cover rounded" style="width: 192px; height: 288px;">
@else
<div class="w-full h-64 md:h-full bg-gray-200 flex items-center justify-center">
<i class="fas fa-film text-gray-400 text-4xl"></i>
<div class="w-48 h-72 bg-gray-200 flex items-center justify-center rounded" style="width: 192px; height: 288px;">
<i class="fas fa-film text-gray-400 text-3xl"></i>
</div>
@endif
@endif
@@ -119,8 +119,8 @@
<div class="flex-1 p-4">
<div class="flex justify-between items-start mb-2">
<div class="flex-1">
@if($guid)
<a href="{{ url('/details/' . $guid) }}" class="hover:text-blue-600">
@if(isset($result->imdbid) && $result->imdbid)
<a href="{{ route('movie.view', ['imdbid' => $result->imdbid]) }}" class="hover:text-blue-600">
<h3 class="text-xl font-bold text-gray-900">{{ $result->title }}</h3>
</a>
@else
@@ -136,17 +136,31 @@
<i class="fas fa-star mr-1"></i> {{ $result->rating }}
</span>
@endif
</div>
<!-- External Links -->
<div class="flex items-center gap-3 mt-2 text-xs">
@if(isset($result->imdbid) && $result->imdbid)
<a href="https://www.imdb.com/title/tt{{ $result->imdbid }}" target="_blank" class="text-blue-600 hover:text-blue-800">
<a href="https://www.imdb.com/title/tt{{ $result->imdbid }}" target="_blank" class="inline-flex items-center px-2 py-1 bg-yellow-100 text-yellow-800 rounded hover:bg-yellow-200 transition">
<i class="fab fa-imdb mr-1"></i> IMDb
</a>
@endif
@if(isset($result->tmdbid) && $result->tmdbid)
<a href="https://www.themoviedb.org/movie/{{ $result->tmdbid }}" target="_blank" class="inline-flex items-center px-2 py-1 bg-blue-100 text-blue-800 rounded hover:bg-blue-200 transition">
<i class="fas fa-film mr-1"></i> TMDb
</a>
@endif
@if(isset($result->traktid) && $result->traktid)
<a href="https://trakt.tv/movies/{{ $result->traktid }}" target="_blank" class="inline-flex items-center px-2 py-1 bg-red-100 text-red-800 rounded hover:bg-red-200 transition">
<i class="fas fa-heart mr-1"></i> Trakt
</a>
@endif
</div>
</div>
</div>
@if(isset($result->plot) && $result->plot)
<p class="text-gray-700 text-sm mt-2 line-clamp-3">{{ $result->plot }}</p>
<p class="text-gray-700 text-sm mt-3 line-clamp-3">{{ $result->plot }}</p>
@endif
<div class="mt-3 flex flex-wrap gap-2 text-xs">
@@ -157,7 +171,7 @@
@endif
</div>
<div class="mt-3 flex flex-wrap gap-2 text-xs">
<div class="mt-2 flex flex-wrap gap-2 text-xs">
@if(isset($result->director) && $result->director)
<div class="text-gray-600">
<strong>Director:</strong> {!! $result->director !!}
@@ -165,7 +179,7 @@
@endif
</div>
<div class="mt-3 flex flex-wrap gap-2 text-xs">
<div class="mt-2 flex flex-wrap gap-2 text-xs">
@if(isset($result->actors) && $result->actors)
<div class="text-gray-600">
<strong>Actors:</strong> {!! $result->actors !!}
@@ -173,12 +187,78 @@
@endif
</div>
<!-- Release Information -->
@if($guid)
<div class="mt-4">
<a href="{{ url('/details/' . $guid) }}" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white text-sm font-medium rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500">
<i class="fas fa-info-circle mr-2"></i> View Details
</a>
</div>
@php
$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) : [];
$releasePostDates = isset($result->grp_release_postdate) ? explode(',', $result->grp_release_postdate) : [];
$releaseAddDates = isset($result->grp_release_adddate) ? explode(',', $result->grp_release_adddate) : [];
// Limit to maximum 2 releases
$maxReleases = 2;
$totalReleases = count($releaseNames);
$releaseNames = array_slice($releaseNames, 0, $maxReleases);
$releaseSizes = array_slice($releaseSizes, 0, $maxReleases);
$releaseGuids = array_slice($releaseGuids, 0, $maxReleases);
$releasePostDates = array_slice($releasePostDates, 0, $maxReleases);
$releaseAddDates = array_slice($releaseAddDates, 0, $maxReleases);
@endphp
@if(!empty($releaseNames[0]))
<div class="mt-4 pt-4 border-t border-gray-200">
<h4 class="text-sm font-semibold text-gray-700 mb-2">
Available Releases
@if($totalReleases > $maxReleases)
<span class="text-xs font-normal text-gray-500">(Showing {{ $maxReleases }} of {{ $totalReleases }})</span>
@endif
</h4>
<div class="space-y-2">
@foreach($releaseNames as $index => $releaseName)
@if($releaseName && isset($releaseGuids[$index]))
<div class="bg-gray-50 rounded-lg p-3 border border-gray-200">
<div class="flex flex-col lg:flex-row lg:items-center justify-between gap-2">
<div class="flex-1 min-w-0">
<a href="{{ url('/details/' . $releaseGuids[$index]) }}" class="text-sm text-gray-800 hover:text-blue-600 font-medium block truncate" title="{{ $releaseName }}">
{{ $releaseName }}
</a>
<div class="flex flex-wrap items-center gap-3 mt-1 text-xs text-gray-500">
@if(isset($releaseSizes[$index]))
<span>
<i class="fas fa-hdd mr-1"></i>{{ number_format($releaseSizes[$index] / 1073741824, 2) }} GB
</span>
@endif
@if(isset($releasePostDates[$index]))
<span>
<i class="fas fa-calendar-alt mr-1"></i>Posted: {{ \Carbon\Carbon::parse($releasePostDates[$index])->format('M d, Y') }}
</span>
@endif
@if(isset($releaseAddDates[$index]))
<span>
<i class="fas fa-plus-circle mr-1"></i>Added: {{ \Carbon\Carbon::parse($releaseAddDates[$index])->diffForHumans() }}
</span>
@endif
</div>
</div>
<div class="flex gap-2 flex-shrink-0">
<a href="{{ url('/getnzb/' . $releaseGuids[$index]) }}" class="inline-flex items-center px-3 py-1 bg-green-600 text-white text-xs font-medium rounded hover:bg-green-700 transition">
<i class="fas fa-download mr-1"></i> Download
</a>
<button onclick="addToCart('{{ $releaseGuids[$index] }}')" class="inline-flex items-center px-3 py-1 bg-blue-600 text-white text-xs font-medium rounded hover:bg-blue-700 transition">
<i class="fas fa-shopping-cart mr-1"></i> Cart
</button>
<a href="{{ url('/details/' . $releaseGuids[$index]) }}" class="inline-flex items-center px-3 py-1 bg-gray-600 text-white text-xs font-medium rounded hover:bg-gray-700 transition">
<i class="fas fa-info-circle mr-1"></i> Details
</a>
</div>
</div>
</div>
@endif
@endforeach
</div>
</div>
@endif
@endif
</div>
</div>
@@ -198,5 +278,32 @@
</div>
@endif
</div>
@push('scripts')
<script>
function addToCart(guid) {
fetch('{{ url("/cart/add") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify({ id: guid })
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('Release added to cart successfully!');
} else {
alert('Failed to add release to cart: ' + (data.message || 'Unknown error'));
}
})
.catch(error => {
console.error('Error:', error);
alert('An error occurred while adding to cart');
});
}
</script>
@endpush
@endsection
+122 -20
View File
@@ -32,20 +32,43 @@
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Movie Poster -->
<div class="lg:col-span-1">
@if(isset($movie['cover']) && $movie['cover'])
<img src="{{ $movie['cover'] }}" alt="{{ $movie['title'] }}" class="w-full rounded-lg shadow-lg">
@if(!empty($movie['cover'] ?? null))
<img src="{{ $movie['cover'] }}" alt="{{ $movie['title'] ?? 'Movie' }}" class="w-full rounded-lg shadow-lg">
@else
<div class="w-full h-96 bg-gray-200 rounded-lg flex items-center justify-center">
<i class="fas fa-film text-gray-400 text-6xl"></i>
</div>
@endif
<!-- External Links -->
<div class="mt-4 space-y-2">
@if(!empty($movie['imdbid'] ?? null))
<a href="https://www.imdb.com/title/tt{{ $movie['imdbid'] }}" target="_blank" class="flex items-center justify-center px-4 py-2 bg-yellow-100 text-yellow-800 rounded-lg hover:bg-yellow-200 transition">
<i class="fab fa-imdb mr-2 text-xl"></i> View on IMDb
</a>
@endif
@if(!empty($movie['tmdbid'] ?? null))
<a href="https://www.themoviedb.org/movie/{{ $movie['tmdbid'] }}" target="_blank" class="flex items-center justify-center px-4 py-2 bg-blue-100 text-blue-800 rounded-lg hover:bg-blue-200 transition">
<i class="fas fa-film mr-2"></i> View on TMDb
</a>
@endif
@if(!empty($movie['traktid'] ?? null))
<a href="https://trakt.tv/movies/{{ $movie['traktid'] }}" target="_blank" class="flex items-center justify-center px-4 py-2 bg-red-100 text-red-800 rounded-lg hover:bg-red-200 transition">
<i class="fas fa-heart mr-2"></i> View on Trakt
</a>
@endif
</div>
</div>
<!-- Movie Details -->
<div class="lg:col-span-2">
<h1 class="text-3xl font-bold text-gray-900 mb-4">{{ $movie['title'] }}</h1>
<h1 class="text-3xl font-bold text-gray-900 mb-4">{{ $movie['title'] ?? 'Unknown Title' }}</h1>
@if(isset($movie['rating']) && $movie['rating'])
@if(!empty($movie['tagline'] ?? null))
<p class="text-lg text-gray-600 italic mb-4">"{{ $movie['tagline'] }}"</p>
@endif
@if(!empty($movie['rating'] ?? null))
<div class="flex items-center mb-4">
<span class="text-yellow-500 text-2xl mr-2">
<i class="fas fa-star"></i>
@@ -56,35 +79,35 @@
@endif
<div class="space-y-3 mb-6">
@if(isset($movie['year']) && $movie['year'])
@if(!empty($movie['year'] ?? null))
<div class="flex">
<span class="font-semibold text-gray-700 w-32">Year:</span>
<span class="text-gray-600">{{ $movie['year'] }}</span>
</div>
@endif
@if(isset($movie['genre']) && $movie['genre'])
@if(!empty($movie['genre'] ?? null))
<div class="flex">
<span class="font-semibold text-gray-700 w-32">Genre:</span>
<span class="text-gray-600">{!! $movie['genre'] !!}</span>
</div>
@endif
@if(isset($movie['director']) && $movie['director'])
@if(!empty($movie['director'] ?? null))
<div class="flex">
<span class="font-semibold text-gray-700 w-32">Director:</span>
<span class="text-gray-600">{!! $movie['director'] !!}</span>
</div>
@endif
@if(isset($movie['actors']) && $movie['actors'])
@if(!empty($movie['actors'] ?? null))
<div class="flex">
<span class="font-semibold text-gray-700 w-32">Actors:</span>
<span class="font-semibold text-gray-700 w-32">Cast:</span>
<span class="text-gray-600">{!! $movie['actors'] !!}</span>
</div>
@endif
@if(isset($movie['language']) && $movie['language'])
@if(!empty($movie['language'] ?? null))
<div class="flex">
<span class="font-semibold text-gray-700 w-32">Language:</span>
<span class="text-gray-600">{{ $movie['language'] }}</span>
@@ -92,29 +115,81 @@
@endif
</div>
@if(isset($movie['plot']) && $movie['plot'])
@if(!empty($movie['plot'] ?? null))
<div class="mb-6">
<h2 class="text-xl font-semibold text-gray-900 mb-2">Plot</h2>
<h2 class="text-xl font-semibold text-gray-900 mb-2">Plot Synopsis</h2>
<p class="text-gray-700 leading-relaxed">{{ $movie['plot'] }}</p>
</div>
@endif
<!-- Trailer -->
@if(isset($movie['trailer']) && $movie['trailer'])
@if(!empty($movie['trailer'] ?? null))
<div class="mb-6">
<h2 class="text-xl font-semibold text-gray-900 mb-2">Trailer</h2>
<div class="aspect-w-16 aspect-h-9">
<iframe src="https://www.youtube.com/embed/{{ $movie['trailer'] }}"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
class="w-full h-96 rounded-lg">
</iframe>
<div class="aspect-video">
{!! $movie['trailer'] !!}
</div>
</div>
@endif
</div>
</div>
<!-- All Available Releases -->
@if(isset($releases) && count($releases) > 0)
<div class="mt-8 pt-8 border-t border-gray-200">
<h2 class="text-2xl font-bold text-gray-900 mb-4">
Available Releases
<span class="text-lg font-normal text-gray-500">({{ count($releases) }} total)</span>
</h2>
<div class="space-y-3">
@foreach($releases as $release)
<div class="bg-gray-50 rounded-lg p-4 border border-gray-200 hover:shadow-md transition">
<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 hover:text-blue-600 font-medium block truncate" title="{{ $release['name'] }}">
{{ $release['name'] }}
</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
</span>
@if($release['postdate'])
<span>
<i class="fas fa-calendar-alt mr-1"></i>Posted: {{ \Carbon\Carbon::parse($release['postdate'])->format('M d, Y') }}
</span>
@endif
@if($release['adddate'])
<span>
<i class="fas fa-plus-circle mr-1"></i>Added: {{ \Carbon\Carbon::parse($release['adddate'])->diffForHumans() }}
</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 text-white text-sm font-medium rounded-lg hover:bg-green-700 transition">
<i class="fas fa-download mr-2"></i> Download
</a>
<button onclick="addToCart('{{ $release['guid'] }}')" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white text-sm font-medium rounded-lg hover:bg-blue-700 transition">
<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">
<i class="fas fa-info-circle mr-2"></i> Details
</a>
</div>
</div>
</div>
@endforeach
</div>
</div>
@else
<div class="mt-8 pt-8 border-t border-gray-200">
<div class="text-center py-8">
<i class="fas fa-inbox text-gray-400 text-5xl mb-4"></i>
<p class="text-gray-600 text-lg">No releases available for this movie.</p>
</div>
</div>
@endif
</div>
@else
<div class="px-6 py-12 text-center">
@@ -123,5 +198,32 @@
</div>
@endif
</div>
@push('scripts')
<script>
function addToCart(guid) {
fetch('{{ url("/cart/add") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify({ id: guid })
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('Release added to cart successfully!');
} else {
alert('Failed to add release to cart: ' + (data.message || 'Unknown error'));
}
})
.catch(error => {
console.error('Error:', error);
alert('An error occurred while adding to cart');
});
}
</script>
@endpush
@endsection
+1
View File
@@ -119,6 +119,7 @@ Route::middleware('isVerified')->group(function () {
Route::middleware('clearance')->group(function () {
Route::match(['GET', 'POST'], 'Games', [GamesController::class, 'show'])->name('Games');
Route::match(['GET', 'POST'], 'movie/{imdbid}', [MovieController::class, 'showMovie'])->name('movie.view');
Route::match(['GET', 'POST'], 'Movies/{id?}', [MovieController::class, 'showMovies'])->name('Movies');
Route::match(['GET', 'POST'], 'movie', [MovieController::class, 'showMovies'])->name('movie');
Route::match(['GET', 'POST'], 'movietrailers', [MovieController::class, 'showTrailer'])->name('movietrailers');