rss-bridge/bridges/RutubeBridge.php

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

143 lines
4.7 KiB
PHP
Raw Normal View History

2022-04-15 22:37:38 +03:00
<?php
class RutubeBridge extends BridgeAbstract
{
2022-04-15 22:37:38 +03:00
const NAME = 'Rutube';
const URI = 'https://rutube.ru';
const MAINTAINER = 'em92';
const DESCRIPTION = 'Выводит ленту видео';
const PARAMETERS = [
'По каналу' => [
'c' => [
'name' => 'ИД канала',
'exampleValue' => 1342940, // Мятежник Джек
'type' => 'number',
'required' => true
],
],
'По плейлисту' => [
'p' => [
'name' => 'ИД плейлиста',
'exampleValue' => 83641, // QRUSH
'type' => 'number',
'required' => true
],
],
'По результатам поиска' => [
's' => [
'name' => 'Запрос',
'exampleValue' => 'SUREN',
'required' => true,
]
]
2022-04-15 22:37:38 +03:00
];
protected $title;
public function getURI()
{
if ($this->getInput('c')) {
return self::URI . '/channel/' . strval($this->getInput('c')) . '/videos/';
} elseif ($this->getInput('p')) {
return self::URI . '/plst/' . strval($this->getInput('p')) . '/';
} elseif ($this->getInput('s')) {
return self::URI . '/search/?suggest=1&query=' . strval($this->getInput('s'));
2022-04-15 22:37:38 +03:00
} else {
return parent::getURI();
}
}
public function getIcon()
{
return 'https://static.rutube.ru/static/favicon.ico';
}
public function getName()
{
if (is_null($this->title)) {
return parent::getName();
} else {
return $this->title . ' - ' . parent::getName();
}
}
private function getJSONData($html)
{
$jsonDataRegex = '/window.reduxState = (.*);/';
2022-04-15 22:37:38 +03:00
preg_match($jsonDataRegex, $html, $matches) or returnServerError('Could not find reduxState');
2024-10-16 19:58:18 +03:00
$map = [
'\x26' => '&',
'\x3c' => '<',
'\x3d' => '=',
'\x3e' => '>',
'\x3f' => '?',
];
$jsonString = str_replace(array_keys($map), array_values($map), $matches[1]);
return json_decode($jsonString, false);
2022-04-15 22:37:38 +03:00
}
private function getVideosFromReduxState()
2022-04-15 22:37:38 +03:00
{
$link = $this->getURI();
$html = getContents($link);
$reduxState = $this->getJSONData($html);
$videos = [];
if ($this->getInput('c')) {
2024-10-16 19:58:18 +03:00
$videosMethod = 'videos(' . $this->getInput('c') . ')';
$channelInfoMethod = 'channelInfo({"userChannelId":' . $this->getInput('c') . '})';
$videos = $reduxState->api->queries->$videosMethod->data->results;
$this->title = $reduxState->api->queries->$channelInfoMethod->data->name;
2022-04-15 22:37:38 +03:00
} elseif ($this->getInput('p')) {
$playListVideosMethod = 'getPlaylistVideos(' . $this->getInput('p') . ')';
$videos = $reduxState->api->queries->$playListVideosMethod->data->results;
$playListMethod = 'getPlaylist(' . $this->getInput('p') . ')';
$this->title = $reduxState->api->queries->$playListMethod->data->title;
} elseif ($this->getInput('s')) {
$this->title = 'Поиск ' . $this->getInput('s');
}
return $videos;
}
private function getVideosFromSearchAPI()
{
$contents = getContents(self::URI . '/api/search/video/?suggest=1&client=wdp&query=' . $this->getInput('s'));
$json = json_decode($contents);
return $json->results;
}
public function collectData()
{
if ($this->getInput('c') || $this->getInput('p')) {
$videos = $this->getVideosFromReduxState();
} else {
$videos = $this->getVideosFromSearchAPI();
2022-04-15 22:37:38 +03:00
}
foreach ($videos as $video) {
$item = [];
$item['title'] = $video->title;
$item['uri'] = $video->video_url;
$content = '<a href="' . $video->video_url . '">';
2022-04-15 22:37:38 +03:00
$content .= '<img src="' . $video->thumbnail_url . '" />';
$content .= '</a><br/>';
$content .= nl2br(
// Converting links in plaintext
// Copied from https://stackoverflow.com/a/12590772
preg_replace(
'$(https?://[a-z0-9_./?=&#-]+)(?![^<>]*>)$i',
' <a href="$1" target="_blank">$1</a> ',
$video->description . ' '
)
);
$item['timestamp'] = $video->created_ts;
$item['author'] = $video->author->name;
$item['content'] = $content;
2022-04-15 22:37:38 +03:00
$this->items[] = $item;
}
}
}