mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 09:18:54 +00:00
323 lines
9.0 KiB
PHP
Executable File
323 lines
9.0 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Blacklight\processing\post;
|
|
|
|
use Blacklight\NZB;
|
|
use App\Models\Category;
|
|
use App\Models\Settings;
|
|
use Blacklight\ColorCLI;
|
|
use App\Models\AnidbEpisode;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Blacklight\db\populate\AniDB as PaDb;
|
|
|
|
class AniDB
|
|
{
|
|
private const PROC_EXTFAIL = -1; // Release Anime title/episode # could not be extracted from searchname
|
|
private const PROC_NOMATCH = -2; // AniDB ID was not found in anidb table using extracted title/episode #
|
|
|
|
/**
|
|
* @var bool Whether or not to echo messages to CLI
|
|
*/
|
|
public $echooutput;
|
|
|
|
/**
|
|
* @var \Blacklight\db\populate\AniDB
|
|
*/
|
|
public $padb;
|
|
|
|
/**
|
|
* @var \PDO
|
|
*/
|
|
public $pdo;
|
|
|
|
/**
|
|
* @var int number of AniDB releases to process
|
|
*/
|
|
private $aniqty;
|
|
|
|
/**
|
|
* @var int The status of the release being processed
|
|
*/
|
|
private $status;
|
|
|
|
/**
|
|
* @var \Blacklight\ColorCLI
|
|
*/
|
|
protected $colorCli;
|
|
|
|
/**
|
|
* @param array $options Class instances / Echo to cli.
|
|
* @throws \Exception
|
|
*/
|
|
public function __construct(array $options = [])
|
|
{
|
|
$defaults = [
|
|
'Echo' => false,
|
|
'Settings' => null,
|
|
];
|
|
$options += $defaults;
|
|
|
|
$this->echooutput = ($options['Echo'] && config('nntmux.echocli'));
|
|
$this->pdo = DB::connection()->getPdo();
|
|
$this->padb = new PaDb(['Echo' => $options['Echo']]);
|
|
$this->colorCli = new ColorCLI();
|
|
|
|
$qty = (int) Settings::settingValue('..maxanidbprocessed');
|
|
$this->aniqty = $qty ?? 100;
|
|
|
|
$this->status = 'NULL';
|
|
}
|
|
|
|
/**
|
|
* Queues anime releases for processing.
|
|
*
|
|
* @throws \Exception
|
|
*/
|
|
public function processAnimeReleases(): void
|
|
{
|
|
$results = DB::select(
|
|
sprintf(
|
|
'
|
|
SELECT searchname, id
|
|
FROM releases
|
|
WHERE nzbstatus = %d
|
|
AND anidbid IS NULL
|
|
AND categories_id = %d
|
|
ORDER BY postdate DESC
|
|
LIMIT %d',
|
|
NZB::NZB_ADDED,
|
|
Category::TV_ANIME,
|
|
$this->aniqty
|
|
)
|
|
);
|
|
|
|
if (\count($results) > 0) {
|
|
$this->doRandomSleep();
|
|
|
|
foreach ($results as $release) {
|
|
$matched = $this->matchAnimeRelease($release);
|
|
if ($matched === false) {
|
|
DB::update(
|
|
sprintf(
|
|
'
|
|
UPDATE releases
|
|
SET anidbid = %d
|
|
WHERE id = %d',
|
|
$this->status,
|
|
$release->id
|
|
)
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
$this->colorCli->info('No anidb releases to process.');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Selects episode info for a local match.
|
|
*
|
|
* @param $anidbId
|
|
* @param int $episode
|
|
* @return \Illuminate\Database\Eloquent\Model|null|static
|
|
*/
|
|
private function checkAniDBInfo($anidbId, $episode = -1)
|
|
{
|
|
return AnidbEpisode::query()->where(
|
|
[
|
|
'anidbid' => $anidbId,
|
|
'episode_no' => $episode,
|
|
]
|
|
)->first(
|
|
[
|
|
'anidbid',
|
|
'episode_no',
|
|
'airdate',
|
|
'episode_title',
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Sleeps between 10 and 15 seconds for AniDB API cooldown.
|
|
*
|
|
*
|
|
* @throws \Exception
|
|
*/
|
|
private function doRandomSleep(): void
|
|
{
|
|
sleep(random_int(10, 15));
|
|
}
|
|
|
|
/**
|
|
* Extracts anime title and episode info from release searchname.
|
|
*
|
|
* @param string $cleanName
|
|
*
|
|
* @return array $matches
|
|
*/
|
|
private function extractTitleEpisode($cleanName = ''): array
|
|
{
|
|
$cleanName = str_replace('_', ' ', $cleanName);
|
|
|
|
if (preg_match(
|
|
'/(^|.*\")(\[[a-zA-Z\.\!?-]+\][\s_]*)?(\[BD\][\s_]*)?(\[\d{3,4}[ip]\][\s_]*)?(?P<title>[\w\s_.+!?\'\-\(\)]+)(New Edit|(Blu-?ray)?( ?Box)?( ?Set)?)?([ _]\-[ _]|([ ._-]Epi?(sode)?[ ._-]?0?)?[ ._-]?|[ ._-]Vol\.|[ ._-]E)(?P<epno>\d{1,3}|Movie|OVA|Complete Series)(v\d|-\d+)?[\-_. ].*[\[\(\"]/i',
|
|
$cleanName,
|
|
$matches
|
|
)
|
|
) {
|
|
$matches['epno'] = (int) $matches['epno'];
|
|
if (\in_array($matches['epno'], ['Movie', 'OVA'], false)) {
|
|
$matches['epno'] = 1;
|
|
}
|
|
} elseif (preg_match(
|
|
'/^(\[[a-zA-Z\.\-!?]+\][\s_]*)?(\[BD\])?(\[\d{3,4}[ip]\])?(?P<title>[\w\s_.+!?\'\-\(\)]+)(New Edit|(Blu-?ray)?( ?Box)?( ?Set)?)?\s*[\(\[](BD|\d{3,4}[ipx])/i',
|
|
$cleanName,
|
|
$matches
|
|
)
|
|
) {
|
|
$matches['epno'] = 1;
|
|
} elseif (preg_match('#^(\[[a-zA-Z\.\-!?]+\][\s_]*)?(?P<title>[\w -]+)?\s+-\s+(?P<epno>\d+)\s*(\[\d+p\])?$#', $cleanName, $matches)) {
|
|
$matches['epno'] = (int) $matches['epno'];
|
|
} else {
|
|
$this->status = self::PROC_EXTFAIL;
|
|
}
|
|
|
|
if (! empty($matches['title'])) {
|
|
$matches['title'] = trim(str_replace(['_', '.'], ' ', $matches['title']));
|
|
}
|
|
|
|
return $matches;
|
|
}
|
|
|
|
/**
|
|
* Retrieves AniDB Info using a cleaned name.
|
|
*
|
|
*
|
|
* @param string $searchName
|
|
*
|
|
* @return mixed
|
|
*/
|
|
private function getAnidbByName($searchName = '')
|
|
{
|
|
return DB::selectOne(
|
|
sprintf(
|
|
'
|
|
SELECT at.anidbid, at.title
|
|
FROM anidb_titles AS at
|
|
WHERE at.title LIKE %s',
|
|
escapeString('%'.$searchName.'%')
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Matches the anime release to AniDB Info
|
|
* If no info is available locally the AniDB API is invoked.
|
|
*
|
|
*
|
|
* @param $release
|
|
*
|
|
* @return bool
|
|
* @throws \Exception
|
|
*/
|
|
private function matchAnimeRelease($release): bool
|
|
{
|
|
$matched = false;
|
|
$type = 'Local';
|
|
|
|
// clean up the release name to ensure we get a good chance at getting a valid title
|
|
$cleanArr = $this->extractTitleEpisode($release->searchname);
|
|
|
|
if (\is_array($cleanArr) && isset($cleanArr['title']) && is_numeric($cleanArr['epno'])) {
|
|
$this->colorCli->header(PHP_EOL.'Looking Up: ').
|
|
$this->colorCli->primary(' Title: '.$cleanArr['title'].PHP_EOL.
|
|
' Episode: '.$cleanArr['epno']);
|
|
|
|
// get anidb number for the title of the name
|
|
$anidbId = $this->getAnidbByName($cleanArr['title']);
|
|
|
|
if ($anidbId === false) {
|
|
$tmpName = preg_replace('/\s/', '%', $cleanArr['title']);
|
|
$anidbId = $this->getAnidbByName($tmpName);
|
|
}
|
|
|
|
if (! empty($anidbId) && is_numeric($anidbId->anidbid) && $anidbId->anidbid > 0) {
|
|
$updatedAni = $this->checkAniDBInfo($anidbId->anidbid, $cleanArr['epno']);
|
|
|
|
if ($updatedAni === null) {
|
|
if ($this->updateTimeCheck($anidbId->anidbid) !== null) {
|
|
$this->padb->populateTable('info', $anidbId->anidbid);
|
|
$this->doRandomSleep();
|
|
$updatedAni = $this->checkAniDBInfo($anidbId->anidbid);
|
|
$type = 'Remote';
|
|
} else {
|
|
echo PHP_EOL.
|
|
$this->colorCli->info('This AniDB ID was not found to be accurate locally, but has been updated too recently to check AniDB.').
|
|
PHP_EOL;
|
|
}
|
|
}
|
|
|
|
$episodeTitle = $updatedAni['episode_title'] ?? 'Unknown';
|
|
|
|
$this->updateRelease($anidbId->anidbid, $release->id);
|
|
|
|
$this->colorCli->headerOver('Matched '.$type.' AniDB ID: ').
|
|
$this->colorCli->primary($anidbId->anidbid).
|
|
$this->colorCli->alternateOver(' Title: ').
|
|
$this->colorCli->primary($anidbId->title).
|
|
$this->colorCli->alternateOver(' Episode #: ').
|
|
$this->colorCli->primary($cleanArr['epno']).
|
|
$this->colorCli->alternateOver(' Episode Title: ').
|
|
$this->colorCli->primary($episodeTitle);
|
|
|
|
$matched = true;
|
|
} else {
|
|
$this->status = self::PROC_NOMATCH;
|
|
}
|
|
}
|
|
|
|
return $matched;
|
|
}
|
|
|
|
/**
|
|
* @param $anidbId
|
|
* @param $relId
|
|
*/
|
|
private function updateRelease($anidbId, $relId): void
|
|
{
|
|
DB::update(
|
|
sprintf(
|
|
'
|
|
UPDATE releases
|
|
SET anidbid = %d
|
|
WHERE id = %d',
|
|
$anidbId,
|
|
$relId
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Checks a specific Anime title's last update time.
|
|
*
|
|
*
|
|
* @param $anidbId
|
|
*
|
|
* @return mixed
|
|
*/
|
|
private function updateTimeCheck($anidbId)
|
|
{
|
|
return DB::selectOne(
|
|
sprintf(
|
|
'
|
|
SELECT anidbid
|
|
FROM anidb_info ai
|
|
WHERE ai.updated < (NOW() - INTERVAL 7 DAY)
|
|
AND ai.anidbid = %d',
|
|
$anidbId
|
|
)
|
|
);
|
|
}
|
|
}
|