mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 17:01:16 +00:00
237 lines
8.3 KiB
PHP
237 lines
8.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Facades\Search;
|
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
|
use Illuminate\Database\Eloquent\Collection;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/**
|
|
* App\Models\Video.
|
|
*
|
|
* @property int $id Show ID to be used in other tables as reference
|
|
* @property bool $type 0 = TV, 1 = Film, 2 = Anime
|
|
* @property string $title Name of the video.
|
|
* @property string $countries_id Two character country code (FK to countries table).
|
|
* @property string $started Date (UTC) of production's first airing.
|
|
* @property int $anidb ID number for anidb site
|
|
* @property string $imdb ID number for IMDB site (without the 'tt' prefix).
|
|
* @property int $tmdb ID number for TMDB site.
|
|
* @property int $trakt ID number for TraktTV site.
|
|
* @property int $tvdb ID number for TVDB site
|
|
* @property int $tvmaze ID number for TVMaze site.
|
|
* @property int $tvrage ID number for TVRage site.
|
|
* @property bool $source Which site did we use for info?
|
|
* @property-read Collection|VideoAlias[] $alias
|
|
* @property-read Collection|TvEpisode[] $episode
|
|
* @property-read Collection|Release[] $release
|
|
*
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereAnidb($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereCountriesId($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereId($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereImdb($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereSource($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereStarted($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereTitle($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereTmdb($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereTrakt($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereTvdb($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereTvmaze($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereTvrage($value)
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video whereType($value)
|
|
*
|
|
* @mixin \Eloquent
|
|
*
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video newModelQuery()
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video newQuery()
|
|
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Video query()
|
|
*/
|
|
class Video extends Model
|
|
{
|
|
protected $dateFormat = false;
|
|
|
|
/**
|
|
* @var array<string>
|
|
*/
|
|
protected $guarded = [];
|
|
|
|
/**
|
|
* @var bool
|
|
*/
|
|
public $timestamps = false;
|
|
|
|
/**
|
|
* @return HasMany<VideoAlias, $this>
|
|
*/
|
|
public function alias(): HasMany
|
|
{
|
|
return $this->hasMany(VideoAlias::class, 'videos_id');
|
|
}
|
|
|
|
/**
|
|
* @return HasMany<Release, $this>
|
|
*/
|
|
public function release(): HasMany
|
|
{
|
|
return $this->hasMany(Release::class, 'videos_id');
|
|
}
|
|
|
|
/**
|
|
* @return HasMany<TvEpisode, $this>
|
|
*/
|
|
public function episode(): HasMany
|
|
{
|
|
return $this->hasMany(TvEpisode::class, 'videos_id');
|
|
}
|
|
|
|
/**
|
|
* @return HasOne<TvInfo, $this>
|
|
*/
|
|
public function tvInfo(): HasOne
|
|
{
|
|
return $this->hasOne(TvInfo::class, 'videos_id');
|
|
}
|
|
|
|
/**
|
|
* Get info from tables for the provided ID.
|
|
*
|
|
*
|
|
* @return Model|null|static
|
|
*/
|
|
public static function getByVideoID(mixed $id)
|
|
{
|
|
return self::query()
|
|
->select(['videos.*', 'tv_info.summary', 'tv_info.publisher', 'tv_info.image'])
|
|
->where('videos.id', $id)
|
|
->join('tv_info', 'videos.id', '=', 'tv_info.videos_id')
|
|
->first();
|
|
}
|
|
|
|
/**
|
|
* Retrieves a range of all shows for the show-edit admin list.
|
|
*/
|
|
public static function getRange(string $showname = ''): LengthAwarePaginator // @phpstan-ignore missingType.generics
|
|
{
|
|
$sql = self::query()
|
|
->select(['videos.*', 'tv_info.summary', 'tv_info.publisher', 'tv_info.image'])
|
|
->join('tv_info', 'videos.id', '=', 'tv_info.videos_id');
|
|
|
|
if ($showname !== '') {
|
|
$sql->where('videos.title', 'like', '%'.$showname.'%');
|
|
}
|
|
|
|
return $sql->paginate(config('nntmux.items_per_page'));
|
|
}
|
|
|
|
/**
|
|
* Returns a count of all shows -- usually used by pager.
|
|
*/
|
|
public static function getCount(string $showname = ''): int
|
|
{
|
|
$res = self::query()->join('tv_info', 'videos.id', '=', 'tv_info.videos_id');
|
|
|
|
if ($showname !== '') {
|
|
$res->where('videos.title', 'like', '%'.$showname.'%');
|
|
}
|
|
|
|
return $res->count('videos.id');
|
|
}
|
|
|
|
/**
|
|
* Retrieves and returns a list of shows with eligible releases.
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
public static function getSeriesList(mixed $uid, string $letter = '', string $showname = ''): array
|
|
{
|
|
$cacheKey = 'video_series_list:'.md5(serialize([(string) $uid, $letter, $showname]));
|
|
|
|
return Cache::remember($cacheKey, now()->addMinutes((int) config('nntmux.cache_expiry_medium', 60)), function () use ($uid, $letter, $showname): array {
|
|
return self::getSeriesListUncached($uid, $letter, $showname);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @internal Used by {@see getSeriesList} with cache wrapper.
|
|
*/
|
|
private static function getSeriesListUncached(mixed $uid, string $letter = '', string $showname = ''): array
|
|
{
|
|
$params = [
|
|
'uid' => $uid,
|
|
'tv_root' => Category::TV_ROOT,
|
|
'tv_other' => Category::TV_OTHER,
|
|
'now' => now()->toDateTimeString(),
|
|
];
|
|
|
|
$letterCondition = '';
|
|
if ($letter !== '') {
|
|
if ($letter === '0-9' || $letter === '[0-9]') {
|
|
$letterCondition = "AND videos.title REGEXP '^[0-9]'";
|
|
} else {
|
|
$letterCondition = 'AND videos.title LIKE :letter';
|
|
$params['letter'] = $letter.'%';
|
|
}
|
|
}
|
|
|
|
$shownameCondition = '';
|
|
if ($showname !== '') {
|
|
if (Search::isAvailable()) {
|
|
$hits = Search::searchTvShows($showname, 800);
|
|
$vids = array_values(array_filter(array_map(static fn ($id): int => (int) $id, $hits['id'] ?? [])));
|
|
if ($vids === []) {
|
|
return [];
|
|
}
|
|
$shownameCondition = 'AND videos.id IN ('.implode(',', $vids).')';
|
|
} else {
|
|
$shownameCondition = 'AND videos.title LIKE :showname';
|
|
$params['showname'] = '%'.$showname.'%';
|
|
}
|
|
}
|
|
|
|
$sql = "
|
|
SELECT
|
|
videos.*,
|
|
tve.firstaired AS prevdate,
|
|
tve.title AS previnfo,
|
|
tvi.publisher,
|
|
us.id AS userseriesid
|
|
FROM videos
|
|
INNER JOIN tv_info AS tvi ON videos.id = tvi.videos_id
|
|
INNER JOIN (
|
|
SELECT videos_id, MAX(firstaired) AS max_firstaired
|
|
FROM tv_episodes
|
|
WHERE firstaired < :now
|
|
GROUP BY videos_id
|
|
) AS latest_ep ON videos.id = latest_ep.videos_id
|
|
INNER JOIN tv_episodes AS tve
|
|
ON videos.id = tve.videos_id
|
|
AND tve.firstaired = latest_ep.max_firstaired
|
|
LEFT JOIN user_series AS us
|
|
ON videos.id = us.videos_id
|
|
AND us.users_id = :uid
|
|
WHERE EXISTS (
|
|
SELECT 1
|
|
FROM releases AS r
|
|
WHERE r.videos_id = videos.id
|
|
AND r.categories_id BETWEEN :tv_root AND :tv_other
|
|
)
|
|
{$letterCondition}
|
|
{$shownameCondition}
|
|
GROUP BY videos.id
|
|
ORDER BY videos.title ASC
|
|
";
|
|
|
|
$results = DB::select($sql, $params);
|
|
|
|
// Convert stdClass objects to arrays for backward compatibility
|
|
return array_map(fn ($row) => (array) $row, $results);
|
|
}
|
|
}
|