06.07.2019

Видео с YouTube на сайт

Иногда встречаются необычные задачи. Одной из таких задач, на моей практике была:

На сайте имеется раздел "Медиа". В него добавляются видео с YouTube про наш продукт. В дальнейшем видео связывается с товарами на сайте.
На данный момент приходится в ручную искать видео, и добавлять на сайт. Это очень не удобно. Так же в ручном режиме можно что то пропустить.

Для решения данное задачи можно использовать YouTube Data API v3.
По ссылке "Get started" есть отличный мануал о том как начать использовать данное api.
В YouTube Data API v3 есть отличный отладчик API

  • Создать Google аккаунт (если у Вас его еще нет)
  • Создать проект в Google Developers Console
  • Получить учетные данные для авторизации. Нам необходим вариант с Api Key
  • После создания проекта убедитесь, что API данных YouTube является одной из служб, для которой ваше приложение зарегистрировано для использования. Для этого перейдите в консоль API и выберите проект, который вы только что зарегистрировали. Посетите страницу Enabled APIs. В списке API убедитесь, что для YouTube Data API v3 включен
  • Выберите клиентскую библиотеку, чтобы упростить реализацию API. В нашем случае это Google APIs Client Library for PHP
  • Остально только написать бизнес логику, используя полученные ключи и клиентскую библиотеку

Под свою задачу я написал следующий php класс

<?php

namespace Gricuk\Youtube;

use Bitrix\Main\Config\Option;
use Bitrix\Main\Error;
use Bitrix\Main\Loader;
use Bitrix\Main\Result;
use Bitrix\Main\Type\DateTime;

class Controller
{
    protected $siteId = NULL;
    protected $API_KEY = NULL;
    protected $iblockId = 0;
    protected $query = false;

    public function __construct($params)
    {
        Loader::includeModule("iblock");

        $this->siteId = $params["SITE_ID"];
        $this->API_KEY = $params["API_KEY"];
        $this->iblockId = $params["IBLOCK_MEDIA"];
        $this->query = $params["QUERY"];

        if (strlen($this->API_KEY) == 0) {
            throw new \Exception("API_KEY не задан");
        }

        if (intval($this->iblockId) == 0) {
            throw new \Exception("IBLOCK_MEDIA не задан");
        }

        if (strlen($this->query) == 0) {
            throw new \Exception("QUERY не задан");
        }
    }


    public function importVideos()
    {
        Loader::includeModule("iblock");
        $result = new Result();
        $resultArray = [];
        $client = new \Google_Client();
        $client->setDeveloperKey($this->API_KEY);

        $youtube = new \Google_Service_YouTube($client);

        $arParams = array("replace_space" => "-", "replace_other" => "-");
        $arSelect = Array("ID", "NAME", "PROPERTY_PUBLISHET_DATE");
        $arFilter = Array(
            "IBLOCK_ID" => $this->iblockId,
        );

        $lastLoadedItem = \CIBlockElement::GetList(array("PROPERTY_PUBLISHET_DATE" => "DESC"), $arFilter, false, ["nTopCount" => 1], $arSelect)->Fetch();


        $nexPageToken = false;

        do {
            $searchParams = array(
                "order" => 'date',
                'type' => 'video',
                'q' => $this->query,
                'maxResults' => 50
            );
            if ($lastLoadedItem) {
                $time = new DateTime($lastLoadedItem["PROPERTY_PUBLISHET_DATE_VALUE"]);
                $searchParams["publishedAfter"] = $time->format(\DateTime::ISO8601);
            }
            if ($nexPageToken) {
                $searchParams["pageToken"] = $nexPageToken;
            }
            $searchResponse = $youtube->search->listSearch('id,snippet', $searchParams);
            $nexPageToken = $searchResponse->nextPageToken;

            $videoResults = array();
            foreach ($searchResponse['items'] as $searchResult) {
                array_push($videoResults, $searchResult['id']['videoId']);
            }

            if (!empty($videoResults)) {
                $arSelect = Array("ID", "NAME", "IBLOCK_ID", "PROPERTY_VIDEO_ID");
                $arFilter = Array(
                    "IBLOCK_ID" => $this->iblockId,
                    "PROPERTY_VIDEO_ID" => $videoResults
                );

                $res = \CIBlockElement::GetList(array("ID" => "ASC"), $arFilter, false, false, $arSelect);
                $iblockItems = [];
                while ($arItem = $res->Fetch()) {
                    $iblockItems[$arItem["PROPERTY_VIDEO_ID_VALUE"]] = $arItem["ID"];
                }

                $videoIds = join(',', $videoResults);

                $videosResponse = $youtube->videos->listVideos('snippet, recordingDetails', array(
                    'id' => $videoIds,
                ));


                foreach ($videosResponse["items"] as $item) {
                    if (isset($iblockItems[$item['id']])) {
                        $resultArray[] = [
                            "youtubeVideoId" => $item['id'],
                            "bitrixId" => $iblockItems[$item['id']],
                            "error" => "Видео уже загружено"
                        ];
                    } else {
                        $clearTitle = trim(preg_replace('/[^\p{L}\s]/u', ' ', $item['snippet']['title']));
                        $arFields = [
                            "IBLOCK_SECTION_ID" => false,
                            "IBLOCK_ID" => \Gricuk\Main\Conf::ID_IBLOCK_MEDIA,
                            "ACTIVE" => "N",
                            "NAME" => $clearTitle,
                            "CODE" => \Cutil::translit($clearTitle, "ru", $arParams),
                            "PROPERTY_VALUES" => [
                                "VIDEO_ID" => $item['id'],
                                "CHANEL_ID" => $item['snippet']['channelId'],
                                "CHANEL_NAME" => $item['snippet']['channelTitle'],
                                "PUBLISHET_DATE" => \Bitrix\Main\Type\DateTime::createFromPhp(new \DateTime($item['snippet']['publishedAt'])),
                            ]
                        ];

                        $el = new \CIBlockElement();
                        $addResult = $el->Add($arFields);

                        if ($addResult) {
                            $resultArray[] = [
                                "youtubeVideoId" => $item['id'],
                                "bitrixId" => $addResult
                            ];
                            $arEventFields = array(
                                "NAME" => "$clearTitle",
                                "VIDEO_ID" => $item['id'],
                                "CHANEL_NAME" => $item['snippet']['channelTitle'],
                            );

                            \CEvent::Send("YOUTUBE_NEW_VIDEO", $this->siteId, $arEventFields);
                        } else {
                            $result->addError(new Error($el->LAST_ERROR));
                            $resultArray[] = [
                                "name" => $clearTitle,
                                "youtubeVideoId" => $item['id'],
                                "bitrixId" => NULL,
                                "error" => $el->LAST_ERROR
                            ];
                        }


                    }
                }
            }
        } while ($nexPageToken);


        $result->setData($resultArray);
        return $result;
    }

    public static function loadYoutubeVideosAgent($siteId)
    {
        try {
            $youtubeController = new Controller([
            	"SITE_ID" => $siteId,
            	"API_KEY" => "XXXXXXXXXXX",
            	"IBLOCK_MEDIA" => 1,
            	"QUERY" => "строка для поиска",
            ]);
            $importResult = $youtubeController->importVideos();
        } catch (\Exception $e) {
        }

        return '\\' . __CLASS__ . "::loadYoutubeVideosAgent('{$siteId}');";
    }
}

Перед использованием необходимо будет создать инфоблок с таким набором свойств
настройка свойств инфоблока

После этого еобходимо подключить клиентскую библиотеку и сам скрипт. Создать агента, и в методе loadYoutubeVideosAgent указать необходимые настройки:

  • API_KEY - Ключ API из Google Console
  • IBLOCK_MEDIA - ID инфоблока в который будут добавляться элементы
  • QUERY - Строка которую будет искать скрипт на youtube