* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 */ namespace App\Models; use App\Helpers\Bbcode; use App\Helpers\Linkify; use App\Helpers\MediaInfo; use App\Helpers\StringHelper; use App\Models\Scopes\ApprovedScope; use App\Notifications\NewComment; use App\Notifications\NewThank; use App\Traits\Auditable; use App\Traits\GroupedLastScope; use App\Traits\TorrentFilter; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use voku\helper\AntiXSS; /** * @property string $info_hash */ class Torrent extends Model { use Auditable; use GroupedLastScope; use HasFactory; use TorrentFilter; protected $guarded = []; /** * The Attributes That Should Be Mutated To Dates. * * @var array */ protected $casts = [ 'igdb' => 'integer', 'fl_until' => 'datetime', 'du_until' => 'datetime', 'doubleup' => 'boolean', 'refundable' => 'boolean', 'featured' => 'boolean', 'moderated_at' => 'datetime', 'sticky' => 'boolean', ]; /** * The attributes that should not be included in audit log. * * @var string[] */ protected $discarded = [ 'info_hash', ]; final public const PENDING = 0; final public const APPROVED = 1; final public const REJECTED = 2; final public const POSTPONED = 3; protected static function booted(): void { static::addGlobalScope(new ApprovedScope()); } /** * Belongs To A User. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(User::class)->withDefault([ 'username' => 'System', 'id' => '1', ]); } /** * Belongs To A Category. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function category(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Category::class); } /** * Belongs To A Type. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function type(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Type::class); } /** * Belongs To A Resolution. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function resolution(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Resolution::class); } /** * Belongs To A Distributor. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function distributor(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Distributor::class); } /** * Belongs To A Region. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function region(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Region::class); } /** * Belongs To A Movie. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function movie(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Movie::class, 'tmdb'); } /** * Belongs To A Tv. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function tv(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Tv::class, 'tmdb'); } /** * Belongs To A Playlist. * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function playlists(): \Illuminate\Database\Eloquent\Relations\BelongsToMany { return $this->belongsToMany(Playlist::class, 'playlist_torrents')->using(PlaylistTorrent::class)->withPivot('id'); } /** * Torrent Has Been Moderated By. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function moderated(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(User::class, 'moderated_by')->withDefault([ 'username' => 'System', 'id' => '1', ]); } /** * Has Many Keywords. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function keywords(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(Keyword::class); } /** * Has Many History. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function history(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(History::class); } /** * Has Many Tips. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function tips(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(BonTransactions::class, 'torrent_id', 'id')->where('name', '=', 'tip'); } /** * Has Many Thank. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function thanks(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(Thank::class); } /** * Has Many HitRuns. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function hitrun(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(Warning::class, 'torrent'); } /** * Has Many Featured. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function featured(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(FeaturedTorrent::class); } /** * Has Many Files. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function files(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(TorrentFile::class); } /** * @return \Illuminate\Database\Eloquent\Relations\MorphMany */ public function comments(): \Illuminate\Database\Eloquent\Relations\MorphMany { return $this->morphMany(Comment::class, 'commentable'); } /** * Has Many Peers. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function peers(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(Peer::class); } /** * Has Many Subtitles. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function subtitles(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(Subtitle::class); } /** * Relationship To Many Requests. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function requests(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(TorrentRequest::class); } /** * Has many free leech tokens. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function freeleechTokens(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(FreeleechToken::class); } /** * Bookmarks. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function bookmarks(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(Bookmark::class); } /** * Bookmarks. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function resurrections(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(Resurrection::class); } /** * Set The Torrents Description After Its Been Purified. */ public function setDescriptionAttribute(?string $value): void { $this->attributes['description'] = htmlspecialchars((new AntiXSS())->xss_clean($value), ENT_NOQUOTES); } /** * Parse Description And Return Valid HTML. */ public function getDescriptionHtml(): string { $bbcode = new Bbcode(); return (new Linkify())->linky($bbcode->parse($this->description)); } /** * Set The Torrents MediaInfo After Its Been Purified. */ public function setMediaInfoAttribute(?string $value): void { $this->attributes['mediainfo'] = $value; } /** * Returns The Size In Human Format. */ public function getSize(): string { $bytes = $this->size; return StringHelper::formatBytes($bytes, 2); } /** * Notify Uploader When An Action Is Taken. */ public function notifyUploader(string $type, Thank|Comment $payload): bool { $user = User::with('notification')->findOrFail($this->user_id); if ($type == 'thank') { if ($user->acceptsNotification(auth()->user(), $user, 'torrent', 'show_torrent_thank')) { $user->notify(new NewThank('torrent', $payload)); return true; } return true; } if ($user->acceptsNotification(auth()->user(), $user, 'torrent', 'show_torrent_comment')) { $user->notify(new NewComment('torrent', $payload)); return true; } return true; } /** * Torrent Is Freeleech. */ public function isFreeleech(User $user = null): bool { $pfree = $user && ($user->group->is_freeleech || cache()->get('personal_freeleech:'.$user->id)); return $this->free || config('other.freeleech') || $pfree; } }