MovieController   A
last analyzed

Complexity

Total Complexity 35

Size/Duplication

Total Lines 301
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 35
eloc 166
c 0
b 0
f 0
dl 0
loc 301
rs 9.6

6 Methods

Rating   Name   Duplication   Size   Complexity  
A showTrailer() 0 32 5
A showTrending() 0 60 1
B showMovies() 0 72 8
A updateLayout() 0 15 2
A __construct() 0 5 1
F showMovie() 0 82 18
1
<?php
2
3
namespace App\Http\Controllers;
4
5
use App\Models\Category;
6
use App\Services\MovieBrowseService;
7
use App\Services\MovieService;
8
use Illuminate\Http\Request;
9
10
class MovieController extends BasePageController
11
{
12
    protected MovieBrowseService $movieBrowseService;
13
14
    protected MovieService $movieService;
15
16
    public function __construct(MovieBrowseService $movieBrowseService, MovieService $movieService)
17
    {
18
        parent::__construct();
19
        $this->movieBrowseService = $movieBrowseService;
20
        $this->movieService = $movieService;
21
    }
22
23
    /**
24
     * @throws \Exception
25
     */
26
    public function showMovies(Request $request, string $id = '')
27
    {
28
        $moviecats = Category::getChildren(Category::MOVIE_ROOT)->map(function ($mcat) {
29
            return ['id' => $mcat->id, 'title' => $mcat->title];
30
        });
31
32
        $category = $request->has('imdb') ? -1 : ($request->input('t', Category::MOVIE_ROOT));
33
        if ($id && $moviecats->pluck('title')->contains($id)) {
34
            $cat = Category::where(['title' => $id, 'root_categories_id' => Category::MOVIE_ROOT])->first(['id']);
35
            $category = $cat->id ?? Category::MOVIE_ROOT;
36
        }
37
38
        $catarray = $category !== -1 ? [$category] : [];
39
40
        $page = $request->input('page', 1);
41
        $offset = ($page - 1) * config('nntmux.items_per_cover_page');
42
43
        $orderby = $request->input('ob', '');
44
        $ordering = $this->movieBrowseService->getMovieOrdering();
45
        if (! in_array($orderby, $ordering, false)) {
46
            $orderby = '';
47
        }
48
49
        $rslt = $this->movieBrowseService->getMovieRange($page, $catarray, $offset, config('nntmux.items_per_cover_page'), $orderby, -1, $this->userdata->categoryexclusions);
50
        $results = $this->paginate($rslt ?? [], $rslt[0]->_totalcount ?? 0, config('nntmux.items_per_cover_page'), $page, $request->url(), $request->query());
51
52
        $movies = $results->map(function ($result) {
53
            $result['genre'] = makeFieldLinks($result, 'genre', 'movies');
54
            $result['actors'] = makeFieldLinks($result, 'actors', 'movies');
55
            $result['director'] = makeFieldLinks($result, 'director', 'movies');
56
            $result['languages'] = explode(', ', $result['language']);
57
58
            // Add cover image URL using helper function
59
            $result['cover'] = getReleaseCover($result);
60
61
            return $result;
62
        });
63
64
        $years = range(1903, now()->addYear()->year);
65
        rsort($years);
66
67
        $catname = $category === -1 ? 'All' : Category::find($category) ?? 'All';
68
69
        $this->viewData = array_merge($this->viewData, [
70
            'cpapi' => $this->userdata->cp_api,
71
            'cpurl' => $this->userdata->cp_url,
72
            'catlist' => $moviecats,
73
            'category' => $category,
74
            'categorytitle' => $id,
75
            'title' => stripslashes($request->input('title', '')),
76
            'actors' => stripslashes($request->input('actors', '')),
77
            'director' => stripslashes($request->input('director', '')),
78
            'ratings' => range(1, 9),
79
            'rating' => $request->input('rating', ''),
80
            'genres' => $this->movieBrowseService->getGenres(),
81
            'genre' => $request->input('genre', ''),
82
            'years' => $years,
83
            'year' => $request->input('year', ''),
84
            'catname' => $catname,
85
            'resultsadd' => $movies,
86
            'results' => $results,
87
            'covgroup' => 'movies',
88
            'meta_title' => 'Browse Movies',
89
            'meta_keywords' => 'browse,nzb,description,details',
90
            'meta_description' => 'Browse for Movies',
91
            'movie_layout' => $this->userdata->movie_layout ?? 2,
92
        ]);
93
94
        // Return the appropriate view
95
        $viewName = $request->has('imdb') ? 'movies.viewmoviefull' : 'movies.index';
96
97
        return view($viewName, $this->viewData);
98
    }
99
100
    /**
101
     * Show a single movie with all its releases
102
     *
103
     * @throws \Exception
104
     */
105
    public function showMovie(Request $request, string $imdbid)
106
    {
107
        // Get movie info
108
        $movieInfo = $this->movieService->getMovieInfo($imdbid);
109
110
        if (! $movieInfo) {
111
            return redirect()->route('Movies')->with('error', 'Movie not found');
112
        }
113
114
        // Get all releases for this movie
115
        $rslt = $this->movieBrowseService->getMovieRange(1, [], 0, 1000, '', -1, $this->userdata->categoryexclusions);
116
117
        // Filter to only this movie's IMDB ID
118
        $movieData = collect($rslt)->firstWhere('imdbid', $imdbid);
119
120
        if (! $movieData) {
121
            return redirect()->route('Movies')->with('error', 'No releases found for this movie');
122
        }
123
124
        // Process movie data - ensure we handle both objects and arrays
125
        if (is_object($movieInfo)) {
126
            // If it's an Eloquent model, use toArray()
127
            if (method_exists($movieInfo, 'toArray')) {
128
                $movieArray = $movieInfo->toArray();
129
            } else {
130
                $movieArray = get_object_vars($movieInfo);
131
            }
132
        } else {
133
            $movieArray = $movieInfo;
134
        }
135
136
        // Ensure we have at least the basic fields
137
        if (empty($movieArray['title'])) {
138
            $movieArray['title'] = 'Unknown Title';
139
        }
140
        if (empty($movieArray['imdbid'])) {
141
            $movieArray['imdbid'] = $imdbid;
142
        }
143
144
        // Only process fields if they exist and are not empty
145
        if (! empty($movieArray['genre'])) {
146
            $movieArray['genre'] = makeFieldLinks($movieArray, 'genre', 'movies');
147
        }
148
        if (! empty($movieArray['actors'])) {
149
            $movieArray['actors'] = makeFieldLinks($movieArray, 'actors', 'movies');
150
        }
151
        if (! empty($movieArray['director'])) {
152
            $movieArray['director'] = makeFieldLinks($movieArray, 'director', 'movies');
153
        }
154
155
        // Add cover image URL using helper function
156
        $movieArray['cover'] = getReleaseCover($movieArray);
157
158
        // Process all releases
159
        $releaseNames = isset($movieData->grp_release_name) ? explode('#', $movieData->grp_release_name) : [];
160
        $releaseSizes = isset($movieData->grp_release_size) ? explode(',', $movieData->grp_release_size) : [];
161
        $releaseGuids = isset($movieData->grp_release_guid) ? explode(',', $movieData->grp_release_guid) : [];
162
        $releasePostDates = isset($movieData->grp_release_postdate) ? explode(',', $movieData->grp_release_postdate) : [];
163
        $releaseAddDates = isset($movieData->grp_release_adddate) ? explode(',', $movieData->grp_release_adddate) : [];
164
165
        $releases = [];
166
        foreach ($releaseNames as $index => $releaseName) {
167
            if ($releaseName && isset($releaseGuids[$index])) {
168
                $releases[] = [
169
                    'name' => $releaseName,
170
                    'guid' => $releaseGuids[$index],
171
                    'size' => $releaseSizes[$index] ?? 0,
172
                    'postdate' => $releasePostDates[$index] ?? null,
173
                    'adddate' => $releaseAddDates[$index] ?? null,
174
                ];
175
            }
176
        }
177
178
        $this->viewData = array_merge($this->viewData, [
179
            'movie' => $movieArray,
180
            'releases' => $releases,
181
            'meta_title' => ($movieArray['title'] ?? 'Movie').' - Movie Details',
182
            'meta_keywords' => 'movie,details,releases',
183
            'meta_description' => 'View all releases for '.($movieArray['title'] ?? 'this movie'),
184
        ]);
185
186
        return view('movies.viewmoviefull', $this->viewData);
187
    }
188
189
    /**
190
     * @return \Illuminate\Http\JsonResponse|\Illuminate\View\View
191
     */
192
    public function showTrailer(Request $request)
193
    {
194
        if ($request->has('id') && ctype_digit($request->input('id'))) {
195
            $mov = $this->movieService->getMovieInfo($request->input('id'));
196
197
            if (! $mov) {
198
                return response()->json(['message' => 'There is no trailer for this movie.'], 404);
199
            }
200
201
            $modal = $request->has('modal');
202
203
            $viewData = [
204
                'movie' => $mov,
205
            ];
206
207
            // Return different views for modal vs full page
208
            if ($modal) {
209
                return view('movies.trailer-modal', $viewData);
210
            }
211
212
            $this->viewData = array_merge($this->viewData, [
213
                'movie' => $mov,
214
                'title' => 'Info for '.$mov['title'],
215
                'meta_title' => '',
216
                'meta_keywords' => '',
217
                'meta_description' => '',
218
            ]);
219
220
            return view('movies.viewmovietrailer', $this->viewData);
221
        }
222
223
        return response()->json(['message' => 'Invalid movie ID.'], 400);
224
    }
225
226
    /**
227
     * Show trending movies (top 15 most downloaded in last 48 hours)
228
     *
229
     * @throws \Exception
230
     */
231
    public function showTrending(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

231
    public function showTrending(/** @scrutinizer ignore-unused */ Request $request)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
232
    {
233
234
        // Cache key for trending movies (48 hours)
235
        $cacheKey = 'trending_movies_top_15_48h';
236
237
        // Get trending movies from cache or calculate (refresh every hour)
238
        $trendingMovies = \Illuminate\Support\Facades\Cache::remember($cacheKey, 3600, function () {
239
            // Calculate timestamp for 48 hours ago
240
            $fortyEightHoursAgo = \Illuminate\Support\Carbon::now()->subHours(48);
241
242
            // Get movies with their download counts from last 48 hours
243
            // Join with user_downloads to get actual download timestamps
244
            $query = \Illuminate\Support\Facades\DB::table('movieinfo as m')
245
                ->join('releases as r', 'm.imdbid', '=', 'r.imdbid')
246
                ->leftJoin('user_downloads as ud', 'r.id', '=', 'ud.releases_id')
247
                ->select([
248
                    'm.imdbid',
249
                    'm.title',
250
                    'm.year',
251
                    'm.rating',
252
                    'm.plot',
253
                    'm.genre',
254
                    'm.cover',
255
                    'm.tmdbid',
256
                    'm.traktid',
257
                    \Illuminate\Support\Facades\DB::raw('COUNT(DISTINCT ud.id) as total_downloads'),
258
                    \Illuminate\Support\Facades\DB::raw('COUNT(DISTINCT r.id) as release_count'),
259
                ])
260
                ->where('m.title', '!=', '')
261
                ->where('m.imdbid', '!=', '0000000')
262
                ->where('ud.timestamp', '>=', $fortyEightHoursAgo)
263
                ->groupBy('m.imdbid', 'm.title', 'm.year', 'm.rating', 'm.plot', 'm.genre', 'm.cover', 'm.tmdbid', 'm.traktid')
264
                ->havingRaw('COUNT(DISTINCT ud.id) > 0')
265
                ->orderByDesc('total_downloads')
0 ignored issues
show
Bug introduced by
'total_downloads' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderByDesc(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

265
                ->orderByDesc(/** @scrutinizer ignore-type */ 'total_downloads')
Loading history...
266
                ->limit(15)
267
                ->get();
268
269
            // Process the results
270
            return $query->map(function ($item) {
271
                // Add cover image URL using helper function
272
                $coverArray = [
273
                    'imdbid' => $item->imdbid,
274
                    'tmdbid' => $item->tmdbid,
275
                    'cover' => $item->cover,
276
                ];
277
                $item->cover = getReleaseCover($coverArray);
278
279
                return $item;
280
            });
281
        });
282
283
        $this->viewData = array_merge($this->viewData, [
284
            'trendingMovies' => $trendingMovies,
285
            'meta_title' => 'Trending Movies - Last 48 Hours',
286
            'meta_keywords' => 'trending,movies,popular,downloads,recent',
287
            'meta_description' => 'Browse the most popular and downloaded movies in the last 48 hours',
288
        ]);
289
290
        return view('movies.trending', $this->viewData);
291
    }
292
293
    /**
294
     * Update user's movie layout preference
295
     */
296
    public function updateLayout(Request $request)
297
    {
298
        $request->validate([
299
            'layout' => 'required|integer|in:1,2',
300
        ]);
301
302
        $user = auth()->user();
303
        if ($user) {
304
            $user->movie_layout = (int) $request->input('layout');
305
            $user->save();
306
307
            return response()->json(['success' => true, 'layout' => $user->movie_layout]);
308
        }
309
310
        return response()->json(['success' => false, 'message' => 'User not authenticated'], 401);
311
    }
312
}
313