Neu: xHamster User Bridge
This commit is contained in:
138
XHamsterUserBridge.php
Normal file
138
XHamsterUserBridge.php
Normal 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user