TO lost in sauce for the day, need to rethink my stragegy

This commit is contained in:
BillyOutlast
2025-08-31 21:23:36 -04:00
parent 6806e38628
commit ea282cb42f
18 changed files with 646 additions and 0 deletions

130
app/Jobs/ProcessPornJob.php Normal file
View File

@@ -0,0 +1,130 @@
<?php
declare(strict_types=1);
namespace App\Jobs;
use App\Models\Torrent;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\Middleware\RateLimited;
use Illuminate\Queue\Middleware\Skip;
use DateTime;
class ProcessPornJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $timeout = 180;
public $failOnTimeout = true;
public function __construct(public int $torrentId) {}
public function middleware(): array
{
return [
Skip::when(cache()->has("porn-meta-job:{$this->torrentId}")),
new WithoutOverlapping((string) $this->torrentId)->dontRelease()->expireAfter(30),
new RateLimited('porn-meta'),
];
}
public function retryUntil(): DateTime
{
return now()->addDay();
}
public function handle(): void
{
$torrent = Torrent::find($this->torrentId);
\Log::debug('ProcessPornJob: Torrent debug data', [
'torrent_id' => $this->torrentId,
'torrent' => $torrent,
]);
if (! $torrent || $torrent->category_id !== 3) {
\Log::error('ProcessPornJob: Torrent not found or not category_id 3', ['torrent_id' => $this->torrentId]);
return;
}
// Example: Gather metadata for each ID
$pornMeta = [
'theporndb_scene_id' => $torrent->theporndb_scene_id,
'theporndb_movie_id' => $torrent->theporndb_movie_id,
'theporndb_jav_id' => $torrent->theporndb_jav_id,
'stashdb_id' => $torrent->stashdb_id,
'fansdb_id' => $torrent->fansdb_id,
];
foreach ($pornMeta as $key => $id) {
if ($id) {
// Example: Call external API for $key/$id and store metadata
\Log::info('ProcessPornJob: Fetching metadata', ['key' => $key, 'id' => $id]);
$metadata = null;
if ($key === 'theporndb_scene_id') {
dispatch(new \App\Jobs\ThePornDBVideoScraper($id, 'scenes', $torrent->id));
// $metadata = fetchThePornDbScene($id); // Your scraper logic
\App\Models\ThePornDbSceneMeta::updateOrCreate([
'theporndb_scene_id' => $id,
'torrent_id' => $torrent->id,
], [
'raw' => $metadata,
]);
} elseif ($key === 'theporndb_movie_id') {
dispatch(new \App\Jobs\ThePornDBVideoScraper($id, 'movies', $torrent->id));
// $metadata = fetchThePornDbMovie($id);
\App\Models\PornMovieMeta::updateOrCreate([
'movie_id' => $id,
'torrent_id' => $torrent->id,
], [
'title' => $metadata['title'] ?? null,
'release_date' => $metadata['release_date'] ?? null,
'studio' => $metadata['studio'] ?? null,
'performers' => $metadata['performers'] ?? null,
'urls' => $metadata['urls'] ?? null,
'details' => $metadata['details'] ?? null,
'director' => $metadata['director'] ?? null,
'raw' => $metadata,
]);
} elseif ($key === 'theporndb_jav_id') {
dispatch(new \App\Jobs\ThePornDBVideoScraper($id, 'jave', $torrent->id));
// $metadata = fetchThePornDbJav($id);
\App\Models\PornJavMeta::updateOrCreate([
'jav_id' => $id,
'torrent_id' => $torrent->id,
], [
'title' => $metadata['title'] ?? null,
'release_date' => $metadata['release_date'] ?? null,
'studio' => $metadata['studio'] ?? null,
'performers' => $metadata['performers'] ?? null,
'urls' => $metadata['urls'] ?? null,
'details' => $metadata['details'] ?? null,
'director' => $metadata['director'] ?? null,
'raw' => $metadata,
]);
} elseif ($key === 'stashdb_id') {
$endpoint = 'https://stashdb.org/graphql';
dispatch(new \App\Jobs\StashBoxSceneScraper($id, $endpoint, $torrent->id));
} elseif ($key === 'fansdb_id') {
$endpoint = 'https://fansdb.cc/graphql';
dispatch(new \App\Jobs\StashBoxSceneScraper($id, $endpoint, $torrent->id));
}
}
}
cache()->put("porn-meta-job:{$this->torrentId}", now(), 8 * 3600);
\Log::info('ProcessPornJob: Completed', ['torrent_id' => $this->torrentId]);
}
public function failed($exception): void
{
\Log::error('ProcessPornJob permanently failed', [
'torrent_id' => $this->torrentId,
'exception' => $exception->getMessage(),
'trace' => $exception->getTraceAsString(),
]);
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Http;
class StashBoxSceneScraper implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $torrentId;
public string $sceneId;
public string $endpoint;
/**
* Create a new job instance.
*/
public function __construct(string $sceneId, string $endpoint, int $torrentId)
{
$this->sceneId = $sceneId;
$this->endpoint = $endpoint;
$this->torrentId = $torrentId;
}
/**
* Execute the job.
*/
public function handle(): void
{
$query = <<<'GRAPHQL'
query MyQuery {
findScene(id: "%s") {
id
title
release_date
studio { id name }
performers { performer { id name disambiguation } }
urls { type url }
details
director
}
}
GRAPHQL;
$graphqlQuery = sprintf($query, $this->sceneId);
$response = Http::post($this->endpoint, [
'query' => $graphqlQuery,
]);
if ($response->successful()) {
$scene = $response->json()['data']['findScene'] ?? [];
if ($this->endpoint === 'https://stashdb.org/graphql') {
\App\Models\StashdbMeta::updateOrCreate([
'stashdb_id' => $this->sceneId,
'torrent_id' => $this->torrentId,
], [
'title' => $scene['title'] ?? null,
'release_date' => $scene['release_date'] ?? null,
'studio' => $scene['studio']['name'] ?? null,
'performers' => $scene['performers'] ?? null,
'urls' => $scene['urls'] ?? null,
'details' => $scene['details'] ?? null,
'director' => $scene['director'] ?? null,
'raw' => $scene,
]);
} elseif ($this->endpoint === 'https://fansdb.cc/graphql') {
\App\Models\FansdbMeta::updateOrCreate([
'fansdb_id' => $this->sceneId,
'torrent_id' => $this->torrentId,
], [
'title' => $scene['title'] ?? null,
'release_date' => $scene['release_date'] ?? null,
'studio' => $scene['studio']['name'] ?? null,
'performers' => $scene['performers'] ?? null,
'urls' => $scene['urls'] ?? null,
'details' => $scene['details'] ?? null,
'director' => $scene['director'] ?? null,
'raw' => $scene,
]);
}
}
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Http;
class ThePornDBVideoScraper implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $torrentId;
public string $id;
public string $type;
/**
* Create a new job instance.
*/
public function __construct(string $id, string $type, int $torrentId)
{
$this->id = $id;
$this->type = $type; // 'scenes', 'movies', or 'jave'
$this->torrentId = $torrentId;
}
/**
* Execute the job.
*/
public function handle(): void
{
$endpoint = sprintf('https://api.theporndb.net/%s/%s?add_to_collection=false', $this->type, $this->id);
$response = Http::get($endpoint);
if ($response->successful()) {
$data = $response->json();
if ($this->type === 'scenes') {
\App\Models\PornSceneMeta::updateOrCreate([
'scene_id' => $this->id,
'torrent_id' => $this->torrentId,
], [
'title' => $data['title'] ?? null,
'release_date' => $data['release_date'] ?? null,
'studio' => $data['studio'] ?? null,
'performers' => $data['performers'] ?? null,
'urls' => $data['urls'] ?? null,
'details' => $data['details'] ?? null,
'director' => $data['director'] ?? null,
'raw' => $data,
]);
} elseif ($this->type === 'movies') {
\App\Models\PornMovieMeta::updateOrCreate([
'movie_id' => $this->id,
'torrent_id' => $this->torrentId,
], [
'title' => $data['title'] ?? null,
'release_date' => $data['release_date'] ?? null,
'studio' => $data['studio'] ?? null,
'performers' => $data['performers'] ?? null,
'urls' => $data['urls'] ?? null,
'details' => $data['details'] ?? null,
'director' => $data['director'] ?? null,
'raw' => $data,
]);
} elseif ($this->type === 'jave') {
\App\Models\PornJavMeta::updateOrCreate([
'jav_id' => $this->id,
'torrent_id' => $this->torrentId,
], [
'title' => $data['title'] ?? null,
'release_date' => $data['release_date'] ?? null,
'studio' => $data['studio'] ?? null,
'performers' => $data['performers'] ?? null,
'urls' => $data['urls'] ?? null,
'details' => $data['details'] ?? null,
'director' => $data['director'] ?? null,
'raw' => $data,
]);
}
} else {
Log::error('ThePornDBVideoScraper failed', ['id' => $this->id, 'type' => $this->type, 'response' => $response->body()]);
}
}
}

15
app/Models/FansdbMeta.php Normal file
View File

@@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class FansdbMeta extends Model
{
protected $guarded = [];
public $timestamps = false;
public function torrent()
{
return $this->belongsTo(Torrent::class);
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class PornJavMeta extends Model
{
protected $guarded = [];
public $timestamps = false;
public function torrent()
{
return $this->belongsTo(Torrent::class);
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class PornMovieMeta extends Model
{
protected $guarded = [];
public $timestamps = false;
public function torrent()
{
return $this->belongsTo(Torrent::class);
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class PornSceneMeta extends Model
{
protected $guarded = [];
public $timestamps = false;
public function torrent()
{
return $this->belongsTo(Torrent::class);
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class StashdbMeta extends Model
{
protected $guarded = [];
public $timestamps = false;
public function torrent()
{
return $this->belongsTo(Torrent::class);
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ThePornDbSceneMeta extends Model
{
protected $table = 'theporndb_scene_metas';
protected $guarded = [];
public $timestamps = true;
public function torrent()
{
return $this->belongsTo(Torrent::class);
}
}

View File

@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('categories', function (Blueprint $table) {
$table->boolean('porn_meta')->default(false)->after('movie_meta');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('categories', function (Blueprint $table) {
$table->dropColumn('porn_meta');
});
}
};

View File

@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('torrents', function (Blueprint $table) {
$table->string('theporndb_scene_id')->nullable()->after('igdb');
$table->string('theporndb_movie_id')->nullable()->after('theporndb_scene_id');
$table->string('theporndb_jav_id')->nullable()->after('theporndb_movie_id');
$table->string('stashdb_id')->nullable()->after('theporndb_jav_id');
$table->string('fansdb_id')->nullable()->after('stashdb_id');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('torrents', function (Blueprint $table) {
$table->dropColumn([
'theporndb_scene_id',
'theporndb_movie_id',
'theporndb_jav_id',
'stashdb_id',
'fansdb_id',
]);
});
}
};

View File

@@ -0,0 +1,27 @@
<?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
{
Schema::create('porn_scene_meta', function (Blueprint $table) {
$table->id();
$table->string('scene_id')->unique();
$table->foreignId('torrent_id')->constrained()->onDelete('cascade');
$table->string('title')->nullable();
$table->date('release_date')->nullable();
$table->string('studio')->nullable();
$table->json('performers')->nullable();
$table->json('urls')->nullable();
$table->text('details')->nullable();
$table->string('director')->nullable();
$table->json('raw')->nullable();
});
}
public function down(): void
{
Schema::dropIfExists('porn_scene_meta');
}
};

View File

@@ -0,0 +1,27 @@
<?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
{
Schema::create('porn_movie_meta', function (Blueprint $table) {
$table->id();
$table->string('movie_id')->unique();
$table->foreignId('torrent_id')->constrained()->onDelete('cascade');
$table->string('title')->nullable();
$table->date('release_date')->nullable();
$table->string('studio')->nullable();
$table->json('performers')->nullable();
$table->json('urls')->nullable();
$table->text('details')->nullable();
$table->string('director')->nullable();
$table->json('raw')->nullable();
});
}
public function down(): void
{
Schema::dropIfExists('porn_movie_meta');
}
};

View File

@@ -0,0 +1,27 @@
<?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
{
Schema::create('porn_jav_meta', function (Blueprint $table) {
$table->id();
$table->string('jav_id')->unique();
$table->foreignId('torrent_id')->constrained()->onDelete('cascade');
$table->string('title')->nullable();
$table->date('release_date')->nullable();
$table->string('studio')->nullable();
$table->json('performers')->nullable();
$table->json('urls')->nullable();
$table->text('details')->nullable();
$table->string('director')->nullable();
$table->json('raw')->nullable();
});
}
public function down(): void
{
Schema::dropIfExists('porn_jav_meta');
}
};

View File

@@ -0,0 +1,27 @@
<?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
{
Schema::create('stashdb_meta', function (Blueprint $table) {
$table->id();
$table->string('stashdb_id')->unique();
$table->foreignId('torrent_id')->constrained()->onDelete('cascade');
$table->string('title')->nullable();
$table->date('release_date')->nullable();
$table->string('studio')->nullable();
$table->json('performers')->nullable();
$table->json('urls')->nullable();
$table->text('details')->nullable();
$table->string('director')->nullable();
$table->json('raw')->nullable();
});
}
public function down(): void
{
Schema::dropIfExists('stashdb_meta');
}
};

View File

@@ -0,0 +1,27 @@
<?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
{
Schema::create('fansdb_meta', function (Blueprint $table) {
$table->id();
$table->string('fansdb_id')->unique();
$table->foreignId('torrent_id')->constrained()->onDelete('cascade');
$table->string('title')->nullable();
$table->date('release_date')->nullable();
$table->string('studio')->nullable();
$table->json('performers')->nullable();
$table->json('urls')->nullable();
$table->text('details')->nullable();
$table->string('director')->nullable();
$table->json('raw')->nullable();
});
}
public function down(): void
{
Schema::dropIfExists('fansdb_meta');
}
};

View File

@@ -0,0 +1,23 @@
<?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
{
Schema::create('theporndb_scene_metas', function (Blueprint $table) {
$table->id();
$table->string('theporndb_scene_id')->index();
$table->unsignedBigInteger('torrent_id');
$table->json('raw')->nullable();
$table->timestamps();
$table->foreign('torrent_id')->references('id')->on('torrents')->onDelete('cascade');
});
}
public function down(): void
{
Schema::dropIfExists('theporndb_scene_metas');
}
};

View File

@@ -0,0 +1,26 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class EnablePornCategorySeeder extends Seeder
{
public function run(): void
{
DB::table('categories')->updateOrInsert(
['name' => 'Porn'],
[
'icon' => 'fa-mars',
'position' => 99,
'porn_meta' => true,
'movie_meta' => false,
'tv_meta' => false,
'game_meta' => false,
'music_meta' => false,
'no_meta' => false,
]
);
}
}