Skip to content

Commit 26afe0f

Browse files
committed
add: top 10 page grouped by work release year
1 parent bd5309c commit 26afe0f

File tree

2 files changed

+113
-4
lines changed

2 files changed

+113
-4
lines changed

app/Http/Livewire/Top10.php

+62-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
use App\Models\Category;
2020
use App\Models\History;
21+
use App\Models\TmdbMovie;
22+
use App\Models\TmdbTv;
2123
use App\Models\Torrent;
2224
use Illuminate\Database\Eloquent\Collection;
2325
use Illuminate\Database\Query\JoinClause;
@@ -42,7 +44,7 @@ class Top10 extends Component
4244
public string $metaType = 'movie_meta';
4345

4446
#[Url(history: true)]
45-
#[Validate('in:day,week,weekly,month,monthly,year,all,custom')]
47+
#[Validate('in:day,week,weekly,month,monthly,year,release_year,all,custom')]
4648
public string $interval = 'day';
4749

4850
#[Url(history: true)]
@@ -207,6 +209,61 @@ final public function monthly(): Collection
207209
);
208210
}
209211

212+
/**
213+
* @return Collection<int|string, Collection<int, Torrent>>
214+
* @phpstan-ignore generics.notSubtype (I can't figure out the correct return type to silence this error)
215+
*/
216+
#[Computed]
217+
final public function releaseYear(): Collection
218+
{
219+
$this->validate();
220+
221+
$metaIdColumn = match ($this->metaType) {
222+
'tv_meta' => 'tmdb_tv_id',
223+
default => 'tmdb_movie_id',
224+
};
225+
226+
return cache()->remember(
227+
'top10-by-release-year:'.$this->metaType,
228+
24 * 3600,
229+
fn () => Torrent::query()
230+
->withoutGlobalScopes()
231+
->with($this->metaType === 'movie_meta' ? 'movie' : 'tv')
232+
->fromSub(
233+
Torrent::query()
234+
->withoutGlobalScopes()
235+
->whereRelation('category', $this->metaType, '=', true)
236+
->leftJoin('tmdb_movies', 'torrents.tmdb_movie_id', '=', 'tmdb_movies.id')
237+
->leftJoin('tmdb_tv', 'torrents.tmdb_tv_id', '=', 'tmdb_tv.id')
238+
->select([
239+
$metaIdColumn,
240+
DB::raw('MIN(category_id) as category_id'),
241+
DB::raw('SUM(times_completed) AS download_count'),
242+
'the_year' => $this->metaType === 'movie_meta'
243+
? TmdbMovie::query()
244+
->selectRaw('EXTRACT(YEAR FROM tmdb_movies.release_date)')
245+
->whereColumn('tmdb_movies.id', '=', 'torrents.tmdb_movie_id')
246+
: TmdbTv::query()
247+
->selectRaw('EXTRACT(YEAR FROM first_air_date)')
248+
->whereColumn('tmdb_tv.id', '=', 'torrents.tmdb_movie_id'),
249+
DB::raw('ROW_NUMBER() OVER (PARTITION BY COALESCE(EXTRACT(YEAR FROM MAX(tmdb_movies.release_date)), EXTRACT(YEAR FROM MAX(tmdb_tv.first_air_date))) ORDER BY SUM(times_completed) DESC) AS place'),
250+
])
251+
->where($metaIdColumn, '!=', 0)
252+
// Small torrents screw the stats since users download them only to farm bon.
253+
->where('torrents.size', '>', 1024 * 1024 * 1024)
254+
->havingNotNull('the_year')
255+
->where(fn ($query) => $query->whereNotNull('tmdb_movies.id')->orWhereNotNull('tmdb_tv.id'))
256+
->groupBy('the_year', $metaIdColumn),
257+
'ranked_groups',
258+
)
259+
->where('place', '<=', 10)
260+
->orderByDesc('the_year')
261+
->orderBy('place')
262+
->get()
263+
->groupBy('the_year')
264+
);
265+
}
266+
210267
/**
211268
* @return array<string, string>
212269
*/
@@ -241,9 +298,10 @@ final public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\C
241298
return view('livewire.top10', [
242299
'user' => auth()->user(),
243300
'works' => match ($this->interval) {
244-
'weekly' => $this->weekly,
245-
'monthly' => $this->monthly,
246-
default => $this->works,
301+
'weekly' => $this->weekly,
302+
'monthly' => $this->monthly,
303+
'release_year' => $this->releaseYear,
304+
default => $this->works,
247305
},
248306
'metaTypes' => $this->metaTypes,
249307
]);

resources/views/livewire/top10.blade.php

+51
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class="form__select"
2424
<option value="all">All-time</option>
2525
<option value="weekly">Weekly</option>
2626
<option value="monthly">Monthly</option>
27+
<option value="release_year">Release year</option>
2728
<option value="custom">Custom</option>
2829
</select>
2930
<label class="form__label form__label--floating" for="interval">Interval</label>
@@ -177,6 +178,56 @@ class="top10-poster__download-count"
177178
</tbody>
178179
</table>
179180
</div>
181+
@elseif ($this->interval === 'release_year')
182+
<div class="data-table-wrapper">
183+
<div wire:loading.delay class="panel__body">Computing...</div>
184+
185+
<table class="data-table">
186+
<thead>
187+
<tr>
188+
<th>Year</th>
189+
<th>Rankings</th>
190+
</tr>
191+
</thead>
192+
<tbody>
193+
@foreach ($works as $releaseYearRankings)
194+
<tr>
195+
<th>{{ $releaseYearRankings->first()?->the_year }}</th>
196+
<td class="panel__body top10-weekly__row">
197+
@foreach ($releaseYearRankings as $ranking)
198+
<figure class="top10-poster">
199+
@switch($this->metaType)
200+
@case('movie_meta')
201+
<x-movie.poster
202+
:movie="$ranking->movie"
203+
:categoryId="$ranking->category_id"
204+
:tmdb="$ranking->tmdb_movie_id"
205+
/>
206+
207+
@break
208+
@case('tv_meta')
209+
<x-tv.poster
210+
:tv="$ranking->tv"
211+
:categoryId="$ranking->category_id"
212+
:tmdb="$ranking->tmdb_tv_id"
213+
/>
214+
215+
@break
216+
@endswitch
217+
<figcaption
218+
class="top10-poster__download-count"
219+
title="{{ __('torrent.completed-times') }}"
220+
>
221+
{{ $ranking->download_count }}
222+
</figcaption>
223+
</figure>
224+
@endforeach
225+
</td>
226+
</tr>
227+
@endforeach
228+
</tbody>
229+
</table>
230+
</div>
180231
@else
181232
<div class="panel__body torrent-search--poster__results">
182233
<div wire:loading.delay>Computing...</div>

0 commit comments

Comments
 (0)