Neue Bridge für MuchoHentai
This commit is contained in:
219
MuchoHentaiBridge.php
Normal file
219
MuchoHentaiBridge.php
Normal file
@ -0,0 +1,219 @@
|
||||
<?php
|
||||
class MuchoHentaiBridge extends BridgeAbstract {
|
||||
|
||||
const NAME = 'MuchoHentai ENG Subbed Releases';
|
||||
const URI = 'https://muchohentai.com/';
|
||||
const DESCRIPTION = 'Shows new english subbed releases from MuchoHentai';
|
||||
const MAINTAINER = 'Akamaru';
|
||||
const CACHE_TIMEOUT = 3600; // 1 Stunde Cache
|
||||
|
||||
const PARAMETERS = [
|
||||
'' => [
|
||||
'limit' => [
|
||||
'name' => 'Limit',
|
||||
'type' => 'number',
|
||||
'defaultValue' => 15,
|
||||
'title' => 'Maximale Anzahl der Einträge'
|
||||
],
|
||||
'full' => [
|
||||
'name' => 'Vollständige Detailseiten',
|
||||
'type' => 'checkbox',
|
||||
'defaultValue' => false,
|
||||
'title' => 'Besuch der Detailseiten für weitere Informationen (langsamer)'
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
public function getIcon() {
|
||||
return 'https://static1.muchohentai.com/wp-content/uploads/xfavicon.png.pagespeed.ic.MKVCUqwTqw.png';
|
||||
}
|
||||
|
||||
public function collectData() {
|
||||
$limit = $this->getInput('limit');
|
||||
$fullContent = $this->getInput('full');
|
||||
|
||||
// User-Agent für CloudFlare setzen
|
||||
ini_set('user_agent', 'FreshRSS/1.23.1 (Linux; https://freshrss.org)');
|
||||
|
||||
$url = 'https://muchohentai.com/series/%e3%80%90eng-subbed%e3%80%91/?orderby=date';
|
||||
$html = getSimpleHTMLDOM($url);
|
||||
|
||||
if (!$html) {
|
||||
throw new \Exception('Konnte die Webseite nicht laden: ' . $url);
|
||||
}
|
||||
|
||||
// Finde alle Video-Einträge auf der Seite
|
||||
$items = $html->find('div.item.cf.item-video');
|
||||
$count = 0;
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($count >= $limit) {
|
||||
break;
|
||||
}
|
||||
|
||||
$articleItem = [];
|
||||
|
||||
// Titel extrahieren
|
||||
$titleElement = $item->find('h2.entry-title a', 0);
|
||||
if ($titleElement) {
|
||||
$articleItem['title'] = $titleElement->plaintext;
|
||||
} else {
|
||||
continue; // Überspringe Einträge ohne Titel
|
||||
}
|
||||
|
||||
// Link extrahieren
|
||||
if ($titleElement) {
|
||||
$articleItem['uri'] = $titleElement->href;
|
||||
} else {
|
||||
continue; // Überspringe Einträge ohne Link
|
||||
}
|
||||
|
||||
// Thumbnail extrahieren
|
||||
$imageElement = $item->find('span.clip img', 0);
|
||||
if ($imageElement) {
|
||||
$imageUrl = $imageElement->src;
|
||||
$articleItem['enclosures'] = [$imageUrl];
|
||||
}
|
||||
|
||||
// ID extrahieren
|
||||
$idElement = $item->find('a.clip-link', 0);
|
||||
$id = '';
|
||||
if ($idElement) {
|
||||
$id = $idElement->getAttribute('data-id');
|
||||
$articleItem['uid'] = $id;
|
||||
}
|
||||
|
||||
// Extrahiere die Serie und Episode aus dem Titel für bessere Kategorisierung
|
||||
$seriesInfo = $this->extractSeriesInfo($articleItem['title']);
|
||||
if ($seriesInfo) {
|
||||
$articleItem['categories'] = [$seriesInfo['series']];
|
||||
// Füge Episodennummer als Tag hinzu, falls vorhanden
|
||||
if (isset($seriesInfo['episode'])) {
|
||||
$articleItem['tags'] = ['Episode ' . $seriesInfo['episode']];
|
||||
}
|
||||
}
|
||||
|
||||
// Erstelle den Basis-Inhalt
|
||||
$content = '<div>';
|
||||
if (isset($imageUrl)) {
|
||||
$content .= '<img src="' . $imageUrl . '" alt="' . htmlspecialchars($articleItem['title'], ENT_QUOTES) . '" /><br>';
|
||||
}
|
||||
$content .= '<p>' . $articleItem['title'] . '</p>';
|
||||
|
||||
// Wenn vollständiger Inhalt gewünscht ist, besuche die Detailseite
|
||||
if ($fullContent && $articleItem['uri']) {
|
||||
$detailContent = $this->getFullContent($articleItem['uri']);
|
||||
if ($detailContent) {
|
||||
$content .= $detailContent;
|
||||
|
||||
// Versuche ein Datum aus der Detailseite zu extrahieren
|
||||
$date = $this->extractDateFromDetail($detailContent);
|
||||
if ($date) {
|
||||
$articleItem['timestamp'] = $date;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$content .= '</div>';
|
||||
$articleItem['content'] = $content;
|
||||
|
||||
// Wenn kein Datum gefunden wurde, verwenden wir die aktuelle Zeit
|
||||
// Die neuesten Einträge erscheinen immer zuerst auf der Hauptseite
|
||||
if (!isset($articleItem['timestamp'])) {
|
||||
// Setze das Datum basierend auf der Position in der Liste
|
||||
// Neuere Einträge sind oben, daher subtrahieren wir die Position von der aktuellen Zeit
|
||||
$articleItem['timestamp'] = time() - ($count * 3600); // Ungefähre stündliche Abstufung
|
||||
}
|
||||
|
||||
$this->items[] = $articleItem;
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extrahiert Serienname und Episodennummer aus dem Titel
|
||||
*/
|
||||
private function extractSeriesInfo($title) {
|
||||
$result = [];
|
||||
|
||||
// Versuche Serie und Episode zu extrahieren
|
||||
if (preg_match('/^(.*?)\s+Episode\s+(\d+)/i', $title, $matches)) {
|
||||
$result['series'] = trim($matches[1]);
|
||||
$result['episode'] = intval($matches[2]);
|
||||
} elseif (preg_match('/^(.*?)\s+\(Episode\s+(\d+)\)/i', $title, $matches)) {
|
||||
$result['series'] = trim($matches[1]);
|
||||
$result['episode'] = intval($matches[2]);
|
||||
} elseif (preg_match('/^(.*?)\s+[Ee]p\.?\s*(\d+)/i', $title, $matches)) {
|
||||
$result['series'] = trim($matches[1]);
|
||||
$result['episode'] = intval($matches[2]);
|
||||
} else {
|
||||
// Nur Serie ohne Episodennummer
|
||||
$result['series'] = $title;
|
||||
}
|
||||
|
||||
// Entferne "English Subbed" vom Seriennamen
|
||||
$result['series'] = preg_replace('/\s+English\s+Subbed$/i', '', $result['series']);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruft den vollständigen Inhalt von der Detailseite ab
|
||||
*/
|
||||
private function getFullContent($url) {
|
||||
// User-Agent bleibt durch die ini_set in collectData() bestehen
|
||||
$html = getSimpleHTMLDOM($url);
|
||||
|
||||
if (!$html) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$content = '';
|
||||
|
||||
// Versuche, die Beschreibung und andere Details zu extrahieren
|
||||
$descriptionElement = $html->find('div.entry-content', 0);
|
||||
if ($descriptionElement) {
|
||||
$content .= '<h3>Beschreibung</h3>';
|
||||
$content .= $descriptionElement->innertext;
|
||||
}
|
||||
|
||||
// Tags oder Kategorien
|
||||
$tagsElement = $html->find('div.entry-tags', 0);
|
||||
if ($tagsElement) {
|
||||
$content .= '<h3>Tags</h3>';
|
||||
$content .= $tagsElement->innertext;
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Versucht, ein Datum aus der Detailseite zu extrahieren
|
||||
*/
|
||||
private function extractDateFromDetail($content) {
|
||||
// Versuche ein Datumsmuster zu finden
|
||||
if (preg_match('/(\d{4}[-\/]\d{1,2}[-\/]\d{1,2})/', $content, $matches)) {
|
||||
return strtotime($matches[1]);
|
||||
}
|
||||
|
||||
// Versuche nach einem Datum im Format "April 15, 2023" zu suchen
|
||||
$months = implode('|', [
|
||||
'January', 'February', 'March', 'April', 'May', 'June',
|
||||
'July', 'August', 'September', 'October', 'November', 'December'
|
||||
]);
|
||||
|
||||
if (preg_match('/(' . $months . ')\s+(\d{1,2}),\s+(\d{4})/', $content, $matches)) {
|
||||
return strtotime($matches[1] . ' ' . $matches[2] . ' ' . $matches[3]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
public function getURI() {
|
||||
return 'https://muchohentai.com/series/%e3%80%90eng-subbed%e3%80%91/?orderby=date';
|
||||
}
|
||||
}
|
@ -19,6 +19,13 @@ Diese Sammlung enthält verschiedene Bridge-Implementierungen für RSS-Bridge, u
|
||||
### Kemono Friends Music News Bridge
|
||||
- **Beschreibung**: Generiert einen RSS-Feed für Kemono Friends Musik Neuigkeiten
|
||||
|
||||
### MuchoHentai ENG Subbed Releases
|
||||
- **Beschreibung**: Zeigt neue englisch Subbed Folgen von MuchoHentai an
|
||||
- **Parameter**:
|
||||
- **Limit**: Maximale Anzahl der angezeigten Einträge (Standard: 15)
|
||||
- **Vollständige Detailseiten**: Wenn aktiviert, werden zusätzliche Informationen von den Detailseiten abgerufen (langsamer)
|
||||
- **Besonderheiten**: Verwendet den FreshRSS User-Agent zum Umgehen von CloudFlare-Schutz
|
||||
|
||||
## Installation
|
||||
|
||||
1. Kopiere die gewünschten Bridge-Dateien in das `bridges`-Verzeichnis deiner RSS-Bridge-Installation
|
||||
|
Reference in New Issue
Block a user