1
0

Neu: xHamster User Bridge

This commit is contained in:
Akamaru
2025-11-24 15:06:20 +01:00
parent 2b8435e243
commit 36e7909658

138
XHamsterUserBridge.php Normal file
View File

@@ -0,0 +1,138 @@
<?php
declare(strict_types=1);
class XHamsterUserBridge extends BridgeAbstract
{
const NAME = 'xHamster User Videos';
const URI = 'https://xhamster.com';
const DESCRIPTION = 'Returns latest videos from an xHamster user';
const MAINTAINER = 'Akamaru';
const CACHE_TIMEOUT = 3600; // 1 hour
const PARAMETERS = [
[
'username' => [
'name' => 'Username',
'type' => 'text',
'required' => true,
'exampleValue' => 'lolliepopxxx'
],
'limit' => [
'name' => 'Limit',
'type' => 'number',
'defaultValue' => 10,
'required' => false
]
]
];
private $profileName = null;
public function getIcon()
{
return 'https://www.google.com/s2/favicons?domain=xhamster.com&sz=32';
}
public function getName()
{
$username = $this->getInput('username');
if ($username) {
$name = $this->profileName ?? $username;
return $name . ' - xHamster';
}
return self::NAME;
}
public function getURI()
{
$username = $this->getInput('username');
if ($username) {
return self::URI . '/users/' . $username . '/videos';
}
return self::URI;
}
public function collectData()
{
$username = $this->getInput('username');
$limit = $this->getInput('limit') ?: 10;
$url = self::URI . '/users/' . $username . '/videos';
// xHamster requires specific headers to bypass Cloudflare
$headers = [
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language: en-US,en;q=0.5'
];
$html = getSimpleHTMLDOM($url, $headers);
if (!$html) {
returnServerError('Could not fetch page: ' . $url);
}
// Try to get profile name from page title
$titleElement = $html->find('title', 0);
if ($titleElement) {
$pageTitle = html_entity_decode($titleElement->plaintext, ENT_QUOTES | ENT_HTML5, 'UTF-8');
// Extract name from title like "Lolliepopxxx's videos"
if (preg_match('/^(.+?)\'s\s+videos/i', $pageTitle, $matches)) {
$this->profileName = trim($matches[1]);
}
}
$videos = $html->find('.video-thumb');
$count = 0;
foreach ($videos as $video) {
if ($count >= $limit) {
break;
}
$videoId = $video->getAttribute('data-video-id');
if (!$videoId) {
continue;
}
// Get the link element
$linkElement = $video->find('a', 0);
$href = $linkElement ? $linkElement->getAttribute('href') : '';
if (!$href) {
continue;
}
// Get title and thumbnail from img
$imgElement = $video->find('img', 0);
$title = '';
$thumbnail = '';
if ($imgElement) {
$title = $imgElement->getAttribute('alt') ?: '';
$thumbnail = $imgElement->getAttribute('src');
if (!$thumbnail || strpos($thumbnail, 'data:') === 0) {
$thumbnail = $imgElement->getAttribute('data-src') ?: '';
}
}
if (!$title) {
$title = 'Video ' . $videoId;
}
// Build content (just the thumbnail)
$content = '';
if ($thumbnail) {
$content = '<img src="' . htmlspecialchars($thumbnail) . '" />';
}
$item = [
'title' => $title,
'uri' => $href,
'content' => $content,
'author' => $this->profileName ?? $username,
'uid' => 'xhamster-' . $videoId
];
$this->items[] = $item;
$count++;
}
}
}