Compare commits

...

3 Commits

Author SHA1 Message Date
xiaomlove
c0eb7b787c Merge pull request #395 from specialpointcentral/php8
feat: expose imdb and douban ids in torrent ratings
2025-11-05 21:23:51 +07:00
Qi HU
450ff5af34 feat: expose imdb and douban ids in torrent ratings
Signed-off-by: Qi HU <github@spcsky.com>
2025-11-05 21:32:03 +08:00
Qi HU
1430ba68dc Switch reCAPTCHA endpoints to recaptcha.net
Signed-off-by: Qi HU <github@spcsky.com>
2025-11-05 21:16:05 +08:00
2 changed files with 144 additions and 18 deletions

View File

@@ -45,7 +45,7 @@ class RecaptchaV2CaptchaDriver implements CaptchaDriverInterface
'<tr><td class="rowhead">%s</td><td align="left"><div %s></div>%s</td></tr>',
htmlspecialchars($label, ENT_QUOTES, 'UTF-8'),
$attributes,
'<script src="https://www.google.com/recaptcha/api.js" async defer></script>'
'<script src="https://www.recaptcha.net/recaptcha/api.js" async defer></script>'
);
}
@@ -74,7 +74,7 @@ class RecaptchaV2CaptchaDriver implements CaptchaDriverInterface
$data['remoteip'] = $remoteIp;
}
$result = $this->sendVerificationRequest('https://www.google.com/recaptcha/api/siteverify', $data);
$result = $this->sendVerificationRequest('https://www.recaptcha.net/recaptcha/api/siteverify', $data);
if (!($result['success'] ?? false)) {
throw new CaptchaValidationException('Captcha verification failed.');

View File

@@ -304,15 +304,15 @@ HTML;
if (!isset($siteIdAndRating[$site])) {
continue;
}
$rating = $siteIdAndRating[$site];
if (empty($rating)) {
[$ratingValue, $externalId] = $this->normalizeRatingInfo($site, $siteIdAndRating[$site]);
if ($ratingValue === '' || $ratingValue === null) {
continue;
}
if ($count > 2) {
//only show the first two
break;
}
$ratingIcons[] = $this->getRatingIcon($site, $rating);
$ratingIcons[] = $this->getRatingIcon($site, $ratingValue, $externalId);
$count++;
}
if (empty($ratingIcons)) {
@@ -323,14 +323,22 @@ HTML;
return $result;
}
public function getRatingIcon($siteId, $rating): string
public function getRatingIcon($siteId, $rating, $externalId = null): string
{
if (is_numeric($rating)) {
$rating = number_format($rating, 1);
}
$spanAttr = '';
if (!empty($externalId)) {
if ($siteId === self::SITE_IMDB) {
$spanAttr = sprintf(' data-imdbid="%s"', htmlspecialchars($externalId, ENT_QUOTES));
} elseif ($siteId === self::SITE_DOUBAN) {
$spanAttr = sprintf(' data-doubanid="%s"', htmlspecialchars($externalId, ENT_QUOTES));
}
}
$result = sprintf(
'<div style="display: flex;align-content: center;justify-content: space-between;padding: 2px 0"><img src="%s" alt="%s" title="%s" style="max-width: 16px;max-height: 16px"/><span>%s</span></div>',
self::$validSites[$siteId]['rating_average_img'], $siteId, $siteId, $rating
'<div style="display: flex;align-content: center;justify-content: space-between;padding: 2px 0"><img src="%s" alt="%s" title="%s" style="max-width: 16px;max-height: 16px"/><span%s>%s</span></div>',
self::$validSites[$siteId]['rating_average_img'], $siteId, $siteId, $spanAttr, $rating
);
return $result;
}
@@ -351,12 +359,17 @@ HTML;
{
$results = [];
$log = "";
$sharedFallbackLinks = [];
if (!empty($ptGenData['__link']) && is_string($ptGenData['__link'])) {
$sharedFallbackLinks[] = $ptGenData['__link'];
}
//First, get from PTGen
foreach (self::$validSites as $site => $info) {
if (!isset($ptGenData[$site]['data'])) {
if (!isset($ptGenData[$site])) {
continue;
}
$data = $ptGenData[$site]['data'];
$siteEntry = $ptGenData[$site];
$data = is_array($siteEntry) && isset($siteEntry['data']) ? $siteEntry['data'] : [];
$log .= ", handling site: $site";
$rating = '';
if (isset($data['__rating'])) {
@@ -376,18 +389,39 @@ HTML;
}
}
}
if (!empty($rating)) {
$results[$site] = $rating;
$log .= ", get rating: $rating";
} else {
$log .= ", can't get rating";
$fallbackLinks = $sharedFallbackLinks;
if ($site === self::SITE_IMDB && !empty($imdbLink)) {
$fallbackLinks[] = $imdbLink;
}
$externalId = $this->extractExternalId($site, $siteEntry, $fallbackLinks);
$allowEmptyRatingWithId = in_array($site, [self::SITE_IMDB, self::SITE_DOUBAN], true);
if (($rating === '' || $rating === null) && !($allowEmptyRatingWithId && $externalId)) {
$log .= ", can't get rating";
continue;
}
if (($rating === '' || $rating === null) && $allowEmptyRatingWithId && $externalId) {
$rating = 'N/A';
$log .= ", missing rating but found id: $externalId";
} else {
$log .= ", get rating: $rating";
}
$results[$site] = [
'rating' => $rating,
'id' => $externalId,
];
}
//Second, imdb can get from imdb api
if (!isset($results[self::SITE_IMDB]) && !empty($imdbLink)) {
$imdb = new Imdb();
$imdbRating = $imdb->getRating($imdbLink);
$results[self::SITE_IMDB] = $imdbRating;
$externalId = $this->extractExternalId(self::SITE_IMDB, $imdbLink);
$results[self::SITE_IMDB] = [
'rating' => $imdbRating,
'id' => $externalId,
];
$log .= ", again 'imdb' from: $imdbLink -> $imdbRating";
}
//Otherwise, get from desc
@@ -403,7 +437,11 @@ HTML;
$log .= ", at last, trying to get '$site' from desc with pattern: $pattern";
if (preg_match($pattern, $desc, $matches)) {
$log .= ", get " . $matches[1];
$results[$site] = $matches[1];
$externalId = $this->extractExternalId($site, $ptGenData[$site] ?? []);
$results[$site] = [
'rating' => $matches[1],
'id' => $externalId,
];
} else {
$log .= ", not match";
}
@@ -413,6 +451,87 @@ HTML;
return $results;
}
private function normalizeRatingInfo(string $siteId, $value): array
{
$rating = '';
$externalId = null;
if (is_array($value)) {
$rating = $value['rating'] ?? '';
$externalId = $value['id'] ?? null;
} else {
$rating = $value;
}
if (($rating === '' || $rating === null) && in_array($siteId, [self::SITE_IMDB, self::SITE_DOUBAN], true) && $externalId) {
$rating = 'N/A';
}
return [$rating, $externalId];
}
private function extractExternalId(string $site, $siteEntry, array $fallbackLinks = []): ?string
{
if (!isset(self::$validSites[$site])) {
return null;
}
$pattern = self::$validSites[$site]['url_pattern'] ?? null;
$candidates = $fallbackLinks;
$candidates = array_merge($candidates, $this->collectStringValues($siteEntry));
foreach ($candidates as $candidate) {
if (!is_string($candidate) || $candidate === '') {
continue;
}
$candidateId = $this->matchExternalId($site, $pattern, $candidate);
if ($candidateId) {
return $candidateId;
}
}
return null;
}
private function collectStringValues($data): array
{
$results = [];
$this->appendStringValues($data, $results);
return $results;
}
private function appendStringValues($value, array &$results): void
{
if (is_string($value)) {
$results[] = $value;
return;
}
if (!is_array($value)) {
return;
}
foreach ($value as $item) {
$this->appendStringValues($item, $results);
}
}
private function matchExternalId(string $site, ?string $pattern, string $candidate): ?string
{
$candidate = trim($candidate);
if ($candidate === '') {
return null;
}
if ($pattern && preg_match($pattern, $candidate, $matches) && !empty($matches[1])) {
return $matches[1];
}
if ($site === self::SITE_IMDB) {
if (preg_match('/^tt\d+$/i', $candidate)) {
return strtolower($candidate);
}
if (preg_match('/^\d+$/', $candidate)) {
return 'tt' . str_pad($candidate, 7, '0', STR_PAD_LEFT);
}
} else {
if (preg_match('/^\d+$/', $candidate)) {
return $candidate;
}
}
return null;
}
public function updateTorrentPtGen(int $id): bool|array
{
$now = Carbon::now();
@@ -457,7 +576,14 @@ HTML;
}
$siteIdAndRating = $this->listRatings($ptGenInfo, $torrent->url, $extra->descr);
foreach ($siteIdAndRating as $key => $value) {
$ptGenInfo[$key]['data']["__rating"] = $value;
if (!isset($ptGenInfo[$key]['data']) || !is_array($ptGenInfo[$key]['data'])) {
continue;
}
$ratingValue = is_array($value) ? ($value['rating'] ?? '') : $value;
$ptGenInfo[$key]['data']["__rating"] = $ratingValue;
if (is_array($value) && isset($value['id']) && $value['id'] !== '') {
$ptGenInfo[$key]['data']["__id"] = $value['id'];
}
}
$ptGenInfo['__link'] = $link;
$ptGenInfo['__updated_at'] = $now->toDateTimeString();