Initial commit: Animexe Laravel platform

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 00:01:48 +03:00
co-authored by Claude Opus 4.8
commit a63515cfc6
366 changed files with 74773 additions and 0 deletions
@@ -0,0 +1,132 @@
<?php
namespace App\Console\Commands;
use App\Models\ImportJob;
use App\Models\Anime;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
/**
* CreateCrossImportJobs
*
* Yayınlanan animeler için çapraz kaynak job'ları oluşturur:
* Anizium import'u olan ama AnimeCix import'u olmayan anime AnimeCix job (watch_id bilgisi Python'dan)
* AnimeCix import'u olan ama Anizium import'u olmayan anime Anizium job (watch_id bilgisi job'lardan)
* Her iki kaynakta da done job'u olan anime bölüm bazlı video_sources yenileme için
* yeni job (done job'u "pending" yaparak botu yeniden çalıştırır)
*
* Kullanım:
* php artisan animexe:cross-import # İki kaynakta da eksik job'ları oluştur
* php artisan animexe:cross-import --force # Var olan done job'larını da yeniden kuyruğa al
* php artisan animexe:cross-import --only=anizium # Sadece Anizium job'larını oluştur
* php artisan animexe:cross-import --only=animecix # Sadece AnimeCix job'larını oluştur
*/
class CreateCrossImportJobs extends Command
{
protected $signature = 'animexe:cross-import
{--force : Mevcut done job\'larını yeniden pending yap}
{--only= : Sadece belirtilen kaynağı oluştur (anizium|animecix)}
{--dry-run : Job oluşturmadan listele}';
protected $description = 'Mevcut animeler için eksik kaynak job\'larını oluşturur (Anizium ↔ AnimeCix çapraz import)';
public function handle(): int
{
$force = $this->option('force');
$only = $this->option('only');
$dryRun = $this->option('dry-run');
$this->info("Animexe Çapraz Import Job Oluşturucu");
$this->info("====================================");
// Tüm yayınlanan animeleri job durumlarıyla al
$animes = Anime::where('is_published', true)
->with('importJobs')
->get();
$this->info("Toplam yayınlanan anime: {$animes->count()}");
$aniziumCreated = 0;
$animecixCreated = 0;
$skipped = 0;
$requeued = 0;
foreach ($animes as $anime) {
$jobs = $anime->importJobs;
$aniziumJobs = $jobs->where('source', 'anizium');
$animecixJobs = $jobs->where('source', 'animecix');
$hasAniziumDone = $aniziumJobs->where('status', 'done')->isNotEmpty();
$hasAnimecixDone = $animecixJobs->where('status', 'done')->isNotEmpty();
$hasAniziumAny = $aniziumJobs->whereIn('status', ['pending','fetching','downloading','uploading','done'])->isNotEmpty();
$hasAnimecixAny = $animecixJobs->whereIn('status', ['pending','fetching','downloading','uploading','done'])->isNotEmpty();
// ── Re-queue: ikisi de done olan animeleri yeniden işlet ──────────
if ($force && $hasAniziumDone && $hasAnimecixDone) {
if (!$dryRun) {
// En son done Anizium job'unu yeniden pending yap
$aj = $aniziumJobs->where('status', 'done')->sortByDesc('id')->first();
if ($aj) {
$aj->update(['status' => 'pending', 'done_episodes' => 0, 'error_log' => null, 'current_step' => 'Çapraz re-import']);
}
// En son done AnimeCix job'unu yeniden pending yap
$cj = $animecixJobs->where('status', 'done')->sortByDesc('id')->first();
if ($cj) {
$cj->update(['status' => 'pending', 'done_episodes' => 0, 'error_log' => null, 'current_step' => 'Çapraz re-import']);
}
$requeued++;
} else {
$this->line("[DRY] Re-queue: {$anime->title} (her iki kaynak mevcut)");
}
continue;
}
// ── Anizium job oluştur ───────────────────────────────────────────
if ((!$only || $only === 'anizium') && !$hasAniziumAny) {
// Anizium watch_id'yi bilmiyoruz — Python reimport_all.py bu görevi üstlenir.
// Buradan sadece anime_id'yi atayarak "ihtiyaç listesi" oluşturabiliriz;
// watch_id olmadan bot job'ı işleyemez. Bu yüzden sadece logluyoruz.
$this->warn("[SKIP-ANİZİUM] {$anime->title} (watch_id bilinmiyor — reimport_all.py kullan)");
$skipped++;
}
// ── AnimeCix job oluştur ──────────────────────────────────────────
if ((!$only || $only === 'animecix') && !$hasAnimecixAny) {
// animecix_title_id'yi bilmiyoruz — daemon.py bunu otomatik keşfeder.
$this->warn("[SKIP-ANİMECİX] {$anime->title} (title_id bilinmiyor — daemon.py kullan)");
$skipped++;
}
// ── Anizium'u olan ama AnimeCix'i olmayan: Anizium job'larından watch_id var ──
// ─ (bu zaten mevcut) ─
// ── AnimeCix'i olan ama Anizium'u olmayan: watch_id bilinmiyorsa skip ──
if ((!$only || $only === 'anizium') && $hasAnimecixDone && !$hasAniziumAny) {
// AnimeCix'te var ama Anizium'da yok — reimport_all.py Anizium katalogunda arayacak
$this->line("[ANİZİUM-GEREKLİ] {$anime->title} (MAL: {$anime->mal_id}) — reimport_all.py işleyecek");
}
// ── Anizium'u olan ama AnimeCix'i olmayan: daemon.py katalog taramasında otomatik bulur ──
if ((!$only || $only === 'animecix') && $hasAniziumDone && !$hasAnimecixAny) {
$this->line("[ANİMECİX-GEREKLİ] {$anime->title} (MAL: {$anime->mal_id}) — daemon.py bulacak");
}
}
// ── Var olan Anizium done job'larını yeniden pending yap (--force) ───
if ($force && !$dryRun) {
$this->info("Re-queue tamamlandı: {$requeued} anime");
}
$this->newLine();
$this->info("Özet:");
$this->info(" Anizium job oluşturuldu : {$aniziumCreated}");
$this->info(" AnimeCix job oluşturuldu: {$animecixCreated}");
$this->info(" Yeniden kuyruğa alındı : {$requeued}");
$this->info(" Atlandı (watch_id yok) : {$skipped}");
$this->newLine();
$this->info("Tüm anime + kaynak eşleştirmesi için: python reimport_all.py");
return 0;
}
}