Skip to content

Commit

Permalink
TTK-26792 add Youtube Downloader videos
Browse files Browse the repository at this point in the history
  • Loading branch information
Yurujai committed Jan 23, 2024
1 parent b3cbf07 commit 5b2d493
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 1 deletion.
186 changes: 186 additions & 0 deletions Command/ImportDownloadVideosFromYoutubeChannel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<?php

declare(strict_types=1);

namespace Pumukit\YoutubeBundle\Command;

use Doctrine\ODM\MongoDB\DocumentManager;
use Pumukit\SchemaBundle\Document\Tag;
use Pumukit\YoutubeBundle\Services\GoogleAccountService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use YouTube\DownloadOptions;
use YouTube\Models\StreamFormat;
use YouTube\Utils\Utils;
use YouTube\YouTubeDownloader;
use YouTube\Exception\YouTubeException;

final class ImportDownloadVideosFromYoutubeChannel extends Command
{
public const BASE_URL_YOUTUBE_VIDEO = 'https://www.youtube.com/watch?v=';

private DocumentManager $documentManager;
private GoogleAccountService $googleAccountService;
private string $tempDir;
private array $qualities;

public function __construct(DocumentManager $documentManager, GoogleAccountService $googleAccountService, string $tempDir)
{
$this->documentManager = $documentManager;
$this->googleAccountService = $googleAccountService;
$this->tempDir = $tempDir;
$this->qualities = [];
parent::__construct();
}

protected function configure(): void
{
$this
->setName('pumukit:youtube:import:videos:from:channel')
->addOption(
'account',
null,
InputOption::VALUE_REQUIRED,
'Account'
)
->addOption(
'channel',
null,
InputOption::VALUE_REQUIRED,
'Channel ID'
)
->addOption(
'limit',
null,
InputOption::VALUE_OPTIONAL,
'limit'
)
->setDescription('Import all videos from Youtube channel')
->setHelp(
<<<'EOT'
Import all videos from Youtube channel
Limit is optional to test the command. If you don't set it, all videos will be downloaded.
Usage: php bin/console pumukit:youtube:import:videos:from:channel --account={ACCOUNT} --channel={CHANNEL_ID} --limit={LIMIT}

EOT
)
;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$channel = $input->getOption('channel');
$youtubeAccount = $this->documentManager->getRepository(Tag::class)->findOneBy([
'properties.login' => $input->getOption('account'),
]);

if(!$youtubeAccount) {
throw new \Exception('Account not found');
}

$service = $this->googleAccountService->googleServiceFromAccount($youtubeAccount);
$queryParams = [
'id' => $channel
];

$channels = $service->channels->listChannels('snippet', $queryParams);
$channelId = $channels->getItems()[0]->getId();

$nextPageToken = null;
$count = 0;
do {
$queryParams = [
'channelId' => $channelId,
'maxResults' => 50,
'order' => 'date',
'type' => 'video'
];

if($input->getOption('limit') !== null && $count >= $input->getOption('limit')) {
break;
}

if($nextPageToken !== null) {
$queryParams['pageToken'] = $nextPageToken;
}

$response = $service->search->listSearch('snippet', $queryParams);
$nextPageToken = $response->getNextPageToken();
foreach($response->getItems() as $item) {

if($input->getOption('limit') !== null && $count >= $input->getOption('limit')) {
break;
}
$count++;
$videoId = $item->getId()->getVideoId();
$youtubeDownloader = new YouTubeDownloader();
try {
$youtubeURL = self::BASE_URL_YOUTUBE_VIDEO.$videoId;
$downloadOptions = $youtubeDownloader->getDownloadLinks($youtubeURL);

if (empty($downloadOptions->getAllFormats())) {
$output->writeln('URL: '. $youtubeURL . ' no formats found.');
continue;
}

$url = $this->selectBestStreamFormat($downloadOptions);
try {
$this->moveFileToStorage($item, $url, $downloadOptions, $channelId);
} catch (\Exception $exception) {
$output->writeln('Error moving file to storage: ' . $exception->getMessage());
}

} catch (YouTubeException $e) {
echo 'Something went wrong: ' . $e->getMessage();
}
}
} while(null !== $nextPageToken);

return 0;
}

private function selectBestStreamFormat(DownloadOptions $downloadOptions): ?StreamFormat
{
$quality720p = Utils::arrayFilterReset($downloadOptions->getAllFormats(), function ($format) {
return str_starts_with($format->mimeType, 'video') && !empty($format->audioQuality) && $format->qualityLabel === '720p';
});

$quality360p = Utils::arrayFilterReset($downloadOptions->getAllFormats(), function ($format) {
return str_starts_with($format->mimeType, 'video') && !empty($format->audioQuality) && $format->qualityLabel === '360p';
});

$quality240p = Utils::arrayFilterReset($downloadOptions->getAllFormats(), function ($format) {
return str_starts_with($format->mimeType, 'video') && !empty($format->audioQuality) && $format->qualityLabel === '240p';
});

return $quality720p[0] ?? $quality360p[0] ?? $quality240p[0] ?? null;
}

private function moveFileToStorage($item, $url, DownloadOptions $downloadOptions, string $channelId): void
{
$videoId = $item->getId()->getVideoId();
$mimeType = explode('video/', $this->selectBestStreamFormat($downloadOptions)->getCleanMimeType())[1];
$this->createChannelDir($channelId);
$file = $this->tempDir.'/'.$channelId.'/'.$videoId.'.'.$mimeType;

if(file_exists($file)) {
return;
}

$content = file_get_contents($url->url);

file_put_contents($file, $content);
}

private function createChannelDir(string $channelId): void
{
if (!is_dir($this->tempDir.'/'.$channelId)) {
mkdir($this->tempDir.'/'.$channelId, 0775, true);
}
}

}
1 change: 1 addition & 0 deletions Resources/config/pumukit_youtube.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ services:
public: true
bind:
$pumukitLocales: "%pumukit.locales%"
$tempDir: "%pumukit.tmp%"

Pumukit\YoutubeBundle\Controller\:
resource: '../../Controller'
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"require": {
"php": "^7.4 || ^8.2",
"pumukit/pumukit": ">4.0",
"google/apiclient" : "^2.0"
"google/apiclient" : "^2.0",
"athlon1600/youtube-downloader": "^4.0"
},
"autoload": {
"psr-4": {
Expand Down

0 comments on commit 5b2d493

Please sign in to comment.