mirror of
https://github.com/HDInnovations/UNIT3D-Community-Edition.git
synced 2026-04-30 23:42:49 -05:00
@@ -28,13 +28,12 @@ use App\Achievements\UserMadeUpload;
|
||||
use App\Bots\IRCAnnounceBot;
|
||||
use App\Models\AutomaticTorrentFreeleech;
|
||||
use App\Models\Movie;
|
||||
use App\Models\PrivateMessage;
|
||||
use App\Models\Scopes\ApprovedScope;
|
||||
use App\Models\Torrent;
|
||||
use App\Models\Tv;
|
||||
use App\Models\User;
|
||||
use App\Models\Wish;
|
||||
use App\Notifications\NewUpload;
|
||||
use App\Notifications\NewWishListNotice;
|
||||
use App\Services\Unit3dAnnounce;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
@@ -74,20 +73,23 @@ class TorrentHelper
|
||||
|
||||
$uploader = $torrent->user;
|
||||
|
||||
$wishes = Wish::where('tmdb', '=', $torrent->tmdb)->whereNull('source')->get();
|
||||
switch (true) {
|
||||
case $torrent->category->movie_meta:
|
||||
User::query()
|
||||
->whereHas('wishes', fn ($query) => $query->where('movie_id', '=', $torrent->tmdb))
|
||||
->get()
|
||||
->each
|
||||
->notify(new NewWishListNotice($torrent));
|
||||
|
||||
foreach ($wishes as $wish) {
|
||||
$wish->source = sprintf('%s/torrents/%s', $appurl, $torrent->id);
|
||||
$wish->save();
|
||||
break;
|
||||
case $torrent->category->tv_meta:
|
||||
User::query()
|
||||
->whereHas('wishes', fn ($query) => $query->where('tv_id', '=', $torrent->tmdb))
|
||||
->get()
|
||||
->each
|
||||
->notify(new NewWishListNotice($torrent));
|
||||
|
||||
// Send Private Message
|
||||
$pm = new PrivateMessage();
|
||||
$pm->sender_id = User::SYSTEM_USER_ID;
|
||||
$pm->receiver_id = $wish->user_id;
|
||||
$pm->subject = 'Wish List Notice!';
|
||||
$pm->message = sprintf('The following item, %s, from your wishlist has been uploaded to %s! You can view it [url=%s/torrents/', $wish->title, $appname, $appurl).$torrent->id.'] HERE [/url]
|
||||
[color=red][b]THIS IS AN AUTOMATED SYSTEM MESSAGE, PLEASE DO NOT REPLY![/b][/color]';
|
||||
$pm->save();
|
||||
break;
|
||||
}
|
||||
|
||||
if ($torrent->anon == 0) {
|
||||
|
||||
@@ -14,14 +14,12 @@
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Category;
|
||||
use App\Models\Torrent;
|
||||
use App\Http\Requests\StoreWishRequest;
|
||||
use App\Models\User;
|
||||
use App\Models\Wish;
|
||||
use App\Services\Tmdb\Client\Movie;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use App\Services\Tmdb\Client\TV;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use JsonException;
|
||||
|
||||
/**
|
||||
@@ -38,8 +36,11 @@ class WishController extends Controller
|
||||
|
||||
return view('user.wish.index', [
|
||||
'user' => $user,
|
||||
'wishes' => $user->wishes()->latest()->paginate(25),
|
||||
'route' => 'wish',
|
||||
'wishes' => $user->wishes()
|
||||
->withCount(['movieTorrents', 'tvTorrents'])
|
||||
->latest()
|
||||
->paginate(25),
|
||||
'route' => 'wish',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -48,42 +49,47 @@ class WishController extends Controller
|
||||
*
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function store(Request $request, User $user): \Illuminate\Http\RedirectResponse
|
||||
public function store(StoreWishRequest $request, User $user): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
abort_unless($request->user()->is($user), 403);
|
||||
|
||||
$request->validate([
|
||||
'tmdb' => [
|
||||
'required',
|
||||
'integer',
|
||||
'not_in:0',
|
||||
Rule::unique('wishes')->where(fn (Builder $query) => $query->where('user_id', '=', $user->id)),
|
||||
],
|
||||
''
|
||||
]);
|
||||
switch ($request->meta) {
|
||||
case 'movie':
|
||||
$meta = (new Movie($request->movie_id))->data;
|
||||
|
||||
$meta = (new Movie($request->tmdb))->data;
|
||||
if ($meta === null) {
|
||||
return to_route('users.wishes.index', ['user' => $user])
|
||||
->withErrors('TMDB Bad Request!');
|
||||
}
|
||||
|
||||
if ($meta === null) {
|
||||
return to_route('users.wishes.index', ['user' => $user])
|
||||
->withErrors('TMDM Bad Request!');
|
||||
$title = $meta['title'].' ('.$meta['release_date'].')';
|
||||
|
||||
Wish::create([
|
||||
'user_id' => $user->id,
|
||||
'title' => $title,
|
||||
'movie_id' => $request->movie_id,
|
||||
]);
|
||||
|
||||
break;
|
||||
case 'tv':
|
||||
$meta = (new TV($request->tv_id))->data;
|
||||
|
||||
if ($meta === null) {
|
||||
return to_route('users.wishes.index', ['user' => $user])
|
||||
->withErrors('TMDB Bad Request!');
|
||||
}
|
||||
|
||||
$title = $meta['name'].' ('.$meta['first_air_date'].')';
|
||||
|
||||
Wish::create([
|
||||
'user_id' => $user->id,
|
||||
'title' => $title,
|
||||
'tv_id' => $request->tv_id,
|
||||
]);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$torrent = Torrent::query()
|
||||
->where('tmdb', '=', $request->tmdb)
|
||||
->whereIn('category_id', Category::select('id')->where('movie_meta', '=', 1))
|
||||
->where('seeders', '>', 0)
|
||||
->where('status', '=', 1)
|
||||
->first();
|
||||
|
||||
Wish::create([
|
||||
'title' => $meta['title'].' ('.$meta['release_date'].')',
|
||||
'type' => 'Movie',
|
||||
'tmdb' => $request->tmdb,
|
||||
'source' => $torrent === null ? Wish::find($request->integer('tmdb'))?->source : route('torrents.show', $torrent->id),
|
||||
'user_id' => $user->id,
|
||||
]);
|
||||
|
||||
return to_route('users.wishes.index', ['user' => $user])
|
||||
->withSuccess('Wish Successfully Added!');
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author Roardom <roardom@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreWishRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, array<\Illuminate\Validation\Rules\Unique|string>>
|
||||
*/
|
||||
public function rules(Request $request): array
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
return [
|
||||
'movie_id' => [
|
||||
'required_if:meta,movie',
|
||||
'decimal:0',
|
||||
'min:1',
|
||||
Rule::unique('wishes')->where(fn (Builder $query) => $query->where('user_id', '=', $user->id)),
|
||||
],
|
||||
'tv_id' => [
|
||||
'required_if:meta,tv',
|
||||
'decimal:0',
|
||||
'min:1',
|
||||
Rule::unique('wishes')->where(fn (Builder $query) => $query->where('user_id', '=', $user->id)),
|
||||
],
|
||||
'meta' => [
|
||||
'required',
|
||||
'in:movie,tv',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error messages for the defined validation rules.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'movie_id.unique' => 'You are already receiving notifications for this movie.',
|
||||
'tv_id.unique' => 'You are already receiving notifications for this tv.',
|
||||
];
|
||||
}
|
||||
}
|
||||
+25
-7
@@ -23,9 +23,8 @@ use Illuminate\Database\Eloquent\Model;
|
||||
* @property int $id
|
||||
* @property int $user_id
|
||||
* @property string $title
|
||||
* @property string $tmdb
|
||||
* @property string $type
|
||||
* @property string|null $source
|
||||
* @property int $movie_id
|
||||
* @property int $tv_id
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
*/
|
||||
@@ -48,9 +47,28 @@ class Wish extends Model
|
||||
*/
|
||||
public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class)->withDefault([
|
||||
'username' => 'System',
|
||||
'id' => '1',
|
||||
]);
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has many torrents.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany<Torrent>
|
||||
*/
|
||||
public function movieTorrents(): \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
{
|
||||
return $this->hasMany(Torrent::class, 'tmdb', 'movie_id')
|
||||
->whereHas('category', fn ($query) => $query->where('movie_meta', '=', true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Has many torrents.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany<Torrent>
|
||||
*/
|
||||
public function tvTorrents(): \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
{
|
||||
return $this->hasMany(Torrent::class, 'tmdb', 'tv_id')
|
||||
->whereHas('category', fn ($query) => $query->where('tv_meta', '=', true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author Roardom <roardom@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Torrent;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class NewWishListNotice extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* NewWishListNotice constructor.
|
||||
*/
|
||||
public function __construct(public Torrent $torrent)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return ['database'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(object $notifiable): array
|
||||
{
|
||||
return [
|
||||
'title' => 'Wish List Notice!',
|
||||
'body' => $this->torrent->name.' from your wishlist has been uploaded',
|
||||
'url' => '/torrents/'.$this->torrent->id,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ use Illuminate\Support\Str;
|
||||
class TV
|
||||
{
|
||||
/**
|
||||
* @var array{
|
||||
* @var null|array{
|
||||
* adult: ?bool,
|
||||
* backdrop_path: ?string,
|
||||
* created_by: ?array<
|
||||
@@ -290,7 +290,7 @@ class TV
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public array $data;
|
||||
public null|array $data;
|
||||
|
||||
public TMDB $tmdb;
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
DB::table('wishes')->update([
|
||||
'tmdb' => DB::raw("REGEXP_REPLACE(tmdb, 'tt', '')"),
|
||||
]);
|
||||
|
||||
DB::table('wishes')
|
||||
->where('tmdb', 'not regexp', '^[0-9]+$')
|
||||
->delete();
|
||||
|
||||
DB::table('wishes')
|
||||
->whereNull('tmdb')
|
||||
->orWhere('tmdb', '<', 0)
|
||||
->orWhere('tmdb', '>', 2_000_000_000)
|
||||
->delete();
|
||||
|
||||
Schema::table('wishes', function (Blueprint $table): void {
|
||||
$table->dropColumn(['source', 'type']);
|
||||
$table->integer('tmdb')->unsigned()->nullable()->change();
|
||||
$table->integer('tv_id')->unsigned()->nullable()->after('tmdb');
|
||||
$table->renameColumn('tmdb', 'movie_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -61,6 +61,22 @@
|
||||
</a>
|
||||
</li>
|
||||
@if ($meta?->id)
|
||||
<li>
|
||||
<form
|
||||
action="{{ route('users.wishes.store', ['user' => auth()->user()]) }}"
|
||||
method="post"
|
||||
>
|
||||
@csrf
|
||||
<input type="hidden" name="meta" value="movie" />
|
||||
<input type="hidden" name="movie_id" value="{{ $meta->id }}" />
|
||||
<button
|
||||
style="cursor: pointer"
|
||||
title="Receive notifications every time a new torrent is uploaded."
|
||||
>
|
||||
Notify of New Uploads
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
<form
|
||||
action="{{ route('torrents.similar.update', ['category' => $category, 'tmdbId' => $meta->id]) }}"
|
||||
@@ -74,6 +90,7 @@
|
||||
disabled
|
||||
title="This item was recently updated. Try again tomorrow."
|
||||
@endif
|
||||
style="cursor: pointer"
|
||||
>
|
||||
Update Metadata
|
||||
</button>
|
||||
|
||||
@@ -61,6 +61,22 @@
|
||||
</a>
|
||||
</li>
|
||||
@if ($meta?->id)
|
||||
<li>
|
||||
<form
|
||||
action="{{ route('users.wishes.store', ['user' => auth()->user()]) }}"
|
||||
method="post"
|
||||
>
|
||||
@csrf
|
||||
<input type="hidden" name="meta" value="tv" />
|
||||
<input type="hidden" name="movie_id" value="{{ $meta->id }}" />
|
||||
<button
|
||||
style="cursor: pointer"
|
||||
title="Receive notifications every time a new torrent is uploaded."
|
||||
>
|
||||
Notify of New Uploads
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
<form
|
||||
action="{{ route('torrents.similar.update', ['category' => $category, 'tmdbId' => $meta->id]) }}"
|
||||
@@ -73,6 +89,7 @@
|
||||
disabled
|
||||
title="This item was recently updated. Try again tomorrow."
|
||||
@endif
|
||||
style="cursor: pointer"
|
||||
>
|
||||
Update Metadata
|
||||
</button>
|
||||
|
||||
@@ -23,17 +23,45 @@
|
||||
<section class="panelV2">
|
||||
<header class="panel__header">
|
||||
<h2 class="panel__heading">{{ __('user.wishlist') }}</h2>
|
||||
<div class="panel__actions">
|
||||
<div class="panel__actions" x-data="{ meta: 'movie' }">
|
||||
<div class="panel__action">
|
||||
<div class="form__group">
|
||||
<select
|
||||
id="meta"
|
||||
class="form__select"
|
||||
form="wishlistForm"
|
||||
name="meta"
|
||||
x-model="meta"
|
||||
required
|
||||
>
|
||||
<option selected value="movie">{{ __('mediahub.movie') }}</option>
|
||||
<option value="tv">TV</option>
|
||||
</select>
|
||||
<label class="form__label form__label--floating" for="model">
|
||||
{{ __('mediahub.movie') }}/TV
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel__action">
|
||||
<div class="form__group">
|
||||
<input
|
||||
id="tmdb"
|
||||
class="form__text"
|
||||
form="wishlistForm"
|
||||
x-bind:name="meta === 'movie' ? 'movie_id' : 'tv_id'"
|
||||
type="text"
|
||||
required
|
||||
/>
|
||||
<label class="form__label form__label--floating" for="tmdb">TMDB ID</label>
|
||||
</div>
|
||||
</div>
|
||||
<form
|
||||
id="wishlistForm"
|
||||
class="form form--horizontal panel__action"
|
||||
action="{{ route('users.wishes.store', ['user' => $user]) }}"
|
||||
method="POST"
|
||||
>
|
||||
@csrf
|
||||
<div class="form__group">
|
||||
<input id="tmdb" class="form__text" name="tmdb" required type="text" />
|
||||
<label class="form__label form__label--floating" for="tmdb">TMDB ID</label>
|
||||
</div>
|
||||
<button class="form__button form__button--text">
|
||||
{{ __('common.add') }}
|
||||
</button>
|
||||
@@ -45,7 +73,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('torrent.title') }}</th>
|
||||
<th>TMDB</th>
|
||||
<th>{{ __('torrent.torrents') }}</th>
|
||||
<th>{{ __('common.status') }}</th>
|
||||
<th>{{ __('common.actions') }}</th>
|
||||
</tr>
|
||||
@@ -62,21 +90,40 @@
|
||||
</td>
|
||||
<td>
|
||||
<a
|
||||
href="{{ route('torrents.index', ['tmdbId' => $wish->tmdb]) }}"
|
||||
target="_blank"
|
||||
href="{{ route('torrents.index', ['tmdbId' => $wish->movie_id ?? $wish->tv_id, 'view' => 'group']) }}"
|
||||
>
|
||||
Torrents
|
||||
@if ($wish->movie_id !== null)
|
||||
Torrents ({{ $wish->movie_torrents_count }})
|
||||
@elseif ($wish->tv_id !== null)
|
||||
Torrents ({{ $wish->tv_torrents_count }})
|
||||
@endif
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
@if ($wish->source === null)
|
||||
<i
|
||||
class="{{ config('other.font-awesome') }} fa-times text-red"
|
||||
></i>
|
||||
@else
|
||||
<i
|
||||
class="{{ config('other.font-awesome') }} fa-check text-green"
|
||||
></i>
|
||||
@if ($wish->movie_id !== null)
|
||||
@if ($wish->movie_torrents_count === 0)
|
||||
<i
|
||||
class="{{ config('other.font-awesome') }} fa-times text-red"
|
||||
title="Not yet uploaded"
|
||||
></i>
|
||||
@else
|
||||
<i
|
||||
class="{{ config('other.font-awesome') }} fa-check text-green"
|
||||
title="Already uploaded"
|
||||
></i>
|
||||
@endif
|
||||
@elseif ($wish->tv_id !== null)
|
||||
@if ($wish->tv_torrents_count === 0)
|
||||
<i
|
||||
class="{{ config('other.font-awesome') }} fa-times text-red"
|
||||
title="Not yet uploaded"
|
||||
></i>
|
||||
@else
|
||||
<i
|
||||
class="{{ config('other.font-awesome') }} fa-check text-green"
|
||||
title="Already uploaded"
|
||||
></i>
|
||||
@endif
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Reference in New Issue
Block a user