<?php
/**
* Downloads videos from [YouTube](https://youtube.com).
*
* @author info@ensostudio.ru
*/
class YouTubeVideo
{
/**
* YouTube video formats and file extensions
*/
public const FORMATS = [
'5' => 'flv',
'6' => 'flv',
'34' => 'flv',
'35' => 'flv',
'18' => 'mp4',
'22' => 'mp4',
'37' => 'mp4',
'38' => 'mp4',
'83' => 'mp4',
'82' => 'mp4',
'85' => 'mp4',
'84' => 'mp4',
'43' => 'webm',
'44' => 'webm',
'45' => 'webm',
'46' => 'webm',
'100' => 'webm',
'101' => 'webm',
'102' => 'webm',
'13' => '3gp',
'17' => '3gp',
'36' => '3gp',
];
/**
* @var string Video ID
*/
protected string $id;
/**
* @var array|false Video data
*/
protected $info;
/**
* @var array|false List of links
*/
protected $links;
/**
* @param string $id the video identifier
* @return void
*/
public function __construct(string $id)
{
$this->id = $id;
}
/**
* Gets information about video.
*
* @return array|false
*/
public function getInfo()
{
if (!isset($this->info)) {
// Loads video data
$curl = curl_init('https://youtube.com/get_video_info?video_id=' . $this->id);
curl_setopt_array(
$curl,
[
CURLOPT_TIMEOUT => 5,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HEADER => false,
]
);
$data = curl_exec($curl);
curl_close($curl);
// Parses data
parse_str($data, $this->info);
if (empty($this->info) || empty($this->info['status']) || $this->info['status'] !== 'ok') {
$this->info = false;
}
}
return $this->info;
}
/**
* Gets direct links to video.
*
* @return array|false
*/
public function getLinks()
{
if (!isset($this->links)) {
$this->links = false;
$info = $this->getInfo();
if ($info !== false) {
$linksMap = explode(',', $info['url_encoded_fmt_stream_map']);
if (!empty($linksMap)) {
$fmtList = explode(',', $info['fmt_list']);
foreach ($linksMap as $key => $link) {
parse_str($link, $parts);
$fmtParts = explode('/', $fmtList[$key], 3);
$ext = static::FORMATS[$parts['itag']];
// Creates array of information about video
$this->links[$ext . '-' . $fmtParts[1]] = [
'ext' => $ext,
'sizes' => $fmtParts[1],
'url' => $parts['url'],
];
}
}
}
}
return $this->links;
}
/**
* Downloads video to local directory.
*
* @param string $format the video format
* @param string $dir the directory to save video
* @param string|null $name the name of video file without extension
* @return void
* @throws InvalidArgumentException
*/
public function load(string $format, string $dir, string $name = null)
{
$links = $this->getLinks();
if ($links === false || !isset($links[$format])) {
throw new InvalidArgumentException("Video in format '$format' not found");
}
// Sets default name of video file
if ($name === null) {
$info = $this->getInfo();
$name = $info === false ? $this->id : $info['title'];
}
$name = preg_replace('/[^-.\w]+/ui', '_', $name);
// Handler of video copy
$file = fopen(realpath($dir) . DIRECTORY_SEPARATOR . $name . '.' . $links[$format]['ext'], 'w');
if ($file) {
$url = $links[$format]['url'] . '&title=' . urlencode($name);
$curl = curl_init($url);
curl_setopt_array(
$curl,
[
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HEADER => false,
CURLOPT_FILE => $file
]
);
curl_exec($curl);
curl_close($curl);
fclose($file);
}
}
}
/**
* Компонент облачного хранилища Яндекс Диск.
*/
class YandexDisk implements CloudInterface
{
/**
* @var string {@see https://oauth.yandex.ru OAuth токен}
*/
private string $oAuthToken;
/**
* @var resource
*/
private $streamContext;
/**
* @param string $oAuthToken OAuth токен
*/
public function __construct(string $oAuthToken)
{
$this->oAuthToken = $oAuthToken;
}
/**
* Возвращает контекст для запроса к API.
*
* @return resource
*/
private function getStreamContext()
{
if (this->streamContext === null) {
$this->streamContext = \stream_context_create([
'http' => [
'header' => ['Accept: application/json', 'Authorization: OAuth ' . $this->oAuthToken],
'timeout' => 5
]
]);
}
return $this->streamContext;
}
/**
* Возвращает результат запроса к API.
*
* @param string $pathSuffix URL path
* @param array $query URL query
* @return array
*/
private function apiRequest(string $pathSuffix, array $query): array
{
$url = 'https://cloud-api.yandex.net/v1/disk/' . $pathSuffix . '?' . \http_build_query($query);
$response = \file_get_contents($url, false, $this->getStreamContext());
return empty($response) ? [] : json_decode($response);
}
/**
* @inheritDoc
*/
public function getFiles(string $dir, int $offset = 0, int $limit = 100): array
{
$query = [
'fields' => 'resource_id,name,path,modified,size,type',
'limit' => $limit,
'offset' => $offset,
'media_type' => 'video'
];
$response = $this->apiRequest('resources/files', $query);
$files = $response['items'] ?? [];
foreach ($files as &$file) {
$file = [
'id' => $file['resource_id'],
'name' => $file['name'],
'path' => $file['path'],
'modified' => $file['modified'],
'size' => $file['size'] ?? 0,
'isDir' => $file['type'] === 'dir'
];
}
unset($file);
return $files;
}
/**
* @inheritDoc
*/
public function getPreview(string $file, $size = null): ?string
{
$query = ['fields' => 'preview', 'preview_crop' => 'false', 'preview_size' => $size ?? 'M', 'path' => $file];
$response = $this->apiRequest('resources', $query);
return $response['preview'] ?? null;
}
/**
* @inheritDoc
*/
public function getTempUrl(string $file): ?string
{
$response = $this->apiRequest('resources/download', ['fields' => 'href', 'path' => $file]);
return $response['href'] ?? null;
}
}
$services = array_merge(ServiceModel::find(...)->indexBy('id')->all(), $сompositeModel->services);
<?= $form->field($model, 'services')->checkboxList(['items' => ServiceModel::find(...)->indexBy('id')->all()]) ?>
Мне 21,в ВУЗ не хочу просто потому что подготовка к ЕГЭ убьёт моё время.
Есть люди кто проходил курсы на Яндекс.Практикуме и стоит ли это своих денег?все зависит от уровня знаний