brightcove.module in Brightcove Video Connect 8
Brightcove module.
File
brightcove.moduleView source
<?php
/**
* @file
* Brightcove module.
*/
use Drupal\brightcove\Entity\BrightcoveSubscription;
use Drupal\brightcove\Entity\BrightcoveVideo;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Database\Database;
use Drupal\Core\Session\AccountInterface;
use Drupal\taxonomy\TermInterface;
use Drupal\taxonomy\VocabularyInterface;
use Drupal\brightcove\BrightcoveUtil;
use Drupal\brightcove\Entity\BrightcoveAPIClient;
use Drupal\brightcove\Entity\BrightcoveCustomField;
use Drupal\brightcove\Entity\BrightcovePlayer;
/**
* Initiates a Brightcove-to-Drupal sync by adding API clients to the queue.
*
* It does nothing if any of the five affected queues is non-empty.
*
* Syncing from Brightcove to Drupal works as follows.
* - This function adds all the API Clients (registered in the Drupal site) to
* the brightcove_client_queue_worker.
* - BrightcoveClientQueueWorker::processItem() counts the videos and the
* playlists on that API Client, then adds pages of them to the
* brightcove_video_page_queue_worker and
* brightcove_playlist_page_queue_worker. All those pages may contain up to
* 100 items.
* - Both BrightcoveVideoPageQueueWorker::processItem() and
* BrightcovePlaylistPageQueueWorker::processItem() cycles through all the
* videos/playlists on that page, and add them to
* brightcove_video_queue_worker or brightcove_playlist_queue_worker,
* respectively.
* - Both BrightcoveVideoQueueWorker::processItem() and
* BrightcovePlaylistQueueWorker::processItem() process one video/playlist at
* a time. However, the latter may throw an exception if it encounters with a
* video which is not yet available on the Drupal side. In this case, the
* playlist is not removed from the queue with the hope that the affected
* video becomes available by the next time this playlist queue item is
* processed.
*
* This process ensures that syncing from Brightcove to Drupal won't eat up all
* the server's resources, and those queues are run from cron, and it's even
* possible to run those queues from batches.
*/
function _brightcove_initiate_sync() {
// Get queues.
$client_queue = \Drupal::queue('brightcove_client_queue_worker');
$player_queue = \Drupal::queue('brightcove_player_queue_worker');
$player_delete_queue = \Drupal::queue('brightcove_player_delete_queue_worker');
$custom_field_queue = \Drupal::queue('brightcove_custom_field_queue_worker');
$custom_field_delete_queue = \Drupal::queue('brightcove_custom_field_delete_queue_worker');
$video_page_queue = \Drupal::queue('brightcove_video_page_queue_worker');
$video_queue = \Drupal::queue('brightcove_video_queue_worker');
$video_delete_queue = \Drupal::queue('brightcove_video_delete_queue_worker');
$text_track_queue = \Drupal::queue('brightcove_text_track_queue_worker');
$text_track_queue_delete = \Drupal::queue('brightcove_text_track_delete_queue_worker');
$playlist_page_queue = \Drupal::queue('brightcove_playlist_page_queue_worker');
$playlist_queue = \Drupal::queue('brightcove_playlist_queue_worker');
$playlist_delete_queue = \Drupal::queue('brightcove_playlist_delete_queue_worker');
$subscriptions_queue = \Drupal::queue('brightcove_subscriptions_queue_worker');
$subscription_delete_queue = \Drupal::queue('brightcove_subscription_delete_queue_worker');
$subscription_queue = \Drupal::queue('brightcove_subscription_queue_worker');
// Check whether the update/create queues are empty or not.
$update_create_queues_empty = $client_queue
->numberOfItems() == 0 && $player_queue
->numberOfItems() == 0 && $custom_field_queue
->numberOfItems() == 0 && $player_delete_queue
->numberOfItems() == 0 && $custom_field_delete_queue
->numberOfItems() == 0 && $video_page_queue
->numberOfItems() == 0 && $video_queue
->numberOfItems() == 0 && $text_track_queue
->numberOfItems() == 0 && $text_track_queue_delete
->numberOfItems() == 0 && $playlist_page_queue
->numberOfItems() == 0 && $playlist_queue
->numberOfItems() == 0;
// Run video deletion queue only if all of the other queues are empty too.
if ($update_create_queues_empty && $video_delete_queue
->numberOfItems() == 0) {
// Collect videos for the queue worker to check whether they are deleted
// from Brightcove or not.
$videos = Database::getConnection()
->select('brightcove_video', 'bv')
->fields('bv', [
'bcvid',
'api_client',
'video_id',
])
->condition('video_id', NULL, 'IS NOT')
->execute();
foreach ($videos as $video) {
$video_delete_queue
->createItem($video);
}
}
// Run playlist deletion queue only if all of the other queues are empty too.
if ($update_create_queues_empty && $playlist_delete_queue
->numberOfItems() == 0) {
// Collect playlists for the queue worker to check whether they are deleted
// from Brightcove or not.
$playlists = Database::getConnection()
->select('brightcove_playlist', 'bv')
->fields('bv', [
'bcplid',
'api_client',
'playlist_id',
])
->condition('playlist_id', NULL, 'IS NOT')
->execute();
foreach ($playlists as $playlist) {
$playlist_delete_queue
->createItem($playlist);
}
}
// Don't start new sync until all of the queues are not emptied.
if ($update_create_queues_empty) {
$brightcove_api_clients = BrightcoveAPIClient::loadMultiple();
/** @var \Drupal\brightcove\Entity\BrightcoveAPIClient $api_client */
foreach ($brightcove_api_clients as $api_client) {
$client_queue
->createItem($api_client
->id());
}
}
// Start Subscription queue workers.
if ($update_create_queues_empty && $subscriptions_queue
->numberOfItems() == 0 && $subscription_queue
->numberOfItems() == 0 && $subscription_delete_queue
->numberOfItems() == 0) {
// Check for new Subscriptions.
/** @var \Drupal\brightcove\Entity\BrightcoveAPIClient[] $brightcove_api_clients */
$brightcove_api_clients = BrightcoveAPIClient::loadMultiple();
foreach ($brightcove_api_clients as $api_client) {
$subscriptions_queue
->createItem($api_client
->id());
}
// Remove non-existing Subscriptions.
$brightcove_subscriptions = BrightcoveSubscription::loadMultiple();
foreach ($brightcove_subscriptions as $brightcove_subscription) {
if (!empty($api_client = $brightcove_subscription
->getApiClient())) {
$subscription_delete_queue
->createItem([
'api_client_id' => $api_client
->id(),
'subscription_id' => $brightcove_subscription
->getBcSid(),
]);
}
}
}
}
/**
* Implements hook_cron().
*/
function brightcove_cron() {
$config = \Drupal::config('brightcove.settings');
if ($config
->get('disable_cron')) {
return;
}
_brightcove_initiate_sync();
}
/**
* Implements hook_entity_extra_field_info().
*/
function brightcove_entity_extra_field_info() {
$extra = [];
$extra['brightcove_video']['brightcove_video']['display']['brightcove_video_player'] = [
'label' => t('Video'),
'description' => t('The video player'),
'weight' => -1000,
'visible' => TRUE,
];
$extra['brightcove_video']['brightcove_video']['display']['brightcove_custom_fields'] = [
'label' => t('Custom fields'),
'description' => t('Video custom fields'),
'weight' => 1000,
'visible' => TRUE,
];
$extra['brightcove_playlist']['brightcove_playlist']['display']['brightcove_playlist_video_player'] = [
'label' => t('Playlist'),
'description' => t('The playlist video player'),
'weight' => -1000,
'visible' => TRUE,
];
return $extra;
}
/**
* Implements hook_ENTITY_TYPE_view().
*/
function brightcove_brightcove_video_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
if ($display
->getComponent('brightcove_video_player')) {
/** @var \Drupal\brightcove\Entity\BrightcoveVideo $video_entity */
$video_entity = $entity;
// Only display the video player if we have all the info needed for it.
if ($video_id = $video_entity
->getVideoId()) {
/** @var \Drupal\brightcove\Entity\BrightcoveApiClient $api_client */
$api_client = BrightcoveAPIClient::load($video_entity
->getApiClient());
/** @var \Drupal\brightcove\Entity\BrightcovePlayer $player */
if ($player = $video_entity
->getPlayer()) {
$player = BrightcovePlayer::load($player);
}
if (!$player) {
$player = BrightcovePlayer::loadByPlayerId($api_client
->getDefaultPlayer());
}
$build['brightcove_video_player'] = [
'#theme' => [
'brightcove_video_player',
],
'#video_id' => $video_id,
'#account' => $api_client
->getAccountId(),
'#player' => BrightcoveUtil::getDefaultPlayer($video_entity),
'#height' => !empty($player) ? $player
->getHeight() : NULL,
'#width' => !empty($player) ? $player
->getWidth() : NULL,
'#data_usage' => 'cms:drupal:' . \DRUPAL::VERSION . ':' . system_get_info('module', 'brightcove')['version'] . ':javascript',
];
}
}
if ($display
->getComponent('brightcove_custom_fields')) {
/** @var \Drupal\brightcove\Entity\BrightcoveVideo $video_entity */
$video_entity = $entity;
$custom_fields = BrightcoveCustomField::loadMultipleByApiClient($video_entity
->getApiClient());
// Show custom fields in the extra field, if it exists and has a value.
$custom_field_values = $video_entity
->getCustomFieldValues();
$build['brightcove_custom_fields'] = [];
foreach ($custom_fields as $custom_field) {
$custom_field_id = $custom_field
->getCustomFieldId();
if (empty($custom_field_values[$custom_field_id])) {
continue;
}
$build['brightcove_custom_fields'][$custom_field_id] = [
'#type' => 'item',
'#title' => $custom_field
->getName(),
'#markup' => $custom_field_values[$custom_field_id],
];
}
}
}
/**
* Implements hook_ENTITY_TYPE_view().
*/
function brightcove_brightcove_playlist_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
if ($display
->getComponent('brightcove_playlist_video_player')) {
/** @var \Drupal\brightcove\Entity\BrightcovePlaylist $playlist_entity */
$playlist_entity = $entity;
// Only display the video player if we have all the info needed for it.
if ($playlist_id = $playlist_entity
->getPlaylistId()) {
/** @var \Drupal\brightcove\Entity\BrightcoveApiClient $api_client */
$api_client = BrightcoveUtil::getApiClient($playlist_entity
->getApiClient());
/** @var \Drupal\brightcove\Entity\BrightcovePlayer $player */
if ($player = $playlist_entity
->getPlayer()) {
$player = BrightcovePlayer::load($player);
}
if (!$player) {
$player = BrightcovePlayer::loadByPlayerId($api_client
->getDefaultPlayer());
}
$build['brightcove_playlist_video_player'] = [
'#theme' => [
'brightcove_playlist_video_player',
],
'#playlist_id' => $playlist_id,
'#account' => $api_client
->getAccountId(),
'#player' => BrightcoveUtil::getDefaultPlayer($playlist_entity),
'#height' => !empty($player) ? $player
->getHeight() : NULL,
'#width' => !empty($player) ? $player
->getWidth() : NULL,
'#data_usage' => 'cms:drupal:' . \DRUPAL::VERSION . ':' . system_get_info('module', 'brightcove')['version'] . ':javascript',
];
}
}
}
/**
* Implements hook_theme().
*/
function brightcove_theme($existing, $type, $theme, $path) {
return [
'brightcove_video' => [
'render element' => 'elements',
],
'brightcove_video_player' => [
'variables' => [
'video_id' => 0,
'account' => 0,
'player' => BrightcoveAPIClient::DEFAULT_PLAYER,
'embed' => 'default',
'height' => NULL,
'width' => NULL,
'data_usage' => NULL,
],
],
'brightcove_playlist_video_player' => [
'variables' => [
'playlist_id' => 0,
'account' => 0,
'player' => BrightcoveAPIClient::DEFAULT_PLAYER,
'embed' => 'default',
'height' => NULL,
'width' => NULL,
'data_usage' => NULL,
],
],
];
}
/**
* Implements hook_theme_suggestions_HOOK_alter().
*/
function brightcove_theme_suggestions_brightcove_video_alter(array &$suggestions, array $variables) {
$suggestions[] = 'brightcove_video__' . strtr($variables['elements']['#view_mode'], '.', '_');
}
/**
* Implements hook_entity_access().
*/
function brightcove_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
// Disable editing/deleting video tags.
if (($entity instanceof TermInterface && $entity
->getVocabularyId() == BrightcoveVideo::TAGS_VID || $entity instanceof VocabularyInterface && $entity
->id() == BrightcoveVideo::TAGS_VID) && ($operation == 'update' || $operation == 'delete')) {
return AccessResult::forbidden();
}
return AccessResult::neutral();
}
/**
* Implements hook_ENTITY_TYPE_delete().
*/
function brightcove_file_delete(EntityInterface $entity) {
/** @var \Drupal\file\FileInterface $entity */
// Condition to check whether the poster or the thumbnail has reference to
// the deleted file.
$condition = new Condition('OR');
$condition
->condition('poster__target_id', $entity
->id())
->condition('thumbnail__target_id', $entity
->id());
// Check file usage on BrightcoveVideo entity.
$database = \Drupal::database();
$results = $database
->select('brightcove_video', 'video')
->fields('video', [
'bcvid',
'poster__target_id',
'thumbnail__target_id',
])
->condition($condition)
->execute()
->fetchAll();
// If we got used files on the BrightcoveVideo entity that were deleted,
// update the entity to remove the reference to the deleted file(s).
foreach ($results as $result) {
$video = BrightcoveVideo::load($result->bcvid);
if (!empty($video)) {
$needs_save = FALSE;
// Unset poster image reference.
if ($result->poster__target_id == $entity
->id()) {
$video
->setPoster(NULL);
$needs_save = TRUE;
}
// Unset thumbnail image reference.
if ($result->thumbnail__target_id == $entity
->id()) {
$video
->setThumbnail(NULL);
$needs_save = TRUE;
}
// Save BrightcoveVideo if needed.
if ($needs_save) {
$video
->save();
}
}
}
}
Functions
Name | Description |
---|---|
brightcove_brightcove_playlist_view | Implements hook_ENTITY_TYPE_view(). |
brightcove_brightcove_video_view | Implements hook_ENTITY_TYPE_view(). |
brightcove_cron | Implements hook_cron(). |
brightcove_entity_access | Implements hook_entity_access(). |
brightcove_entity_extra_field_info | Implements hook_entity_extra_field_info(). |
brightcove_file_delete | Implements hook_ENTITY_TYPE_delete(). |
brightcove_theme | Implements hook_theme(). |
brightcove_theme_suggestions_brightcove_video_alter | Implements hook_theme_suggestions_HOOK_alter(). |
_brightcove_initiate_sync | Initiates a Brightcove-to-Drupal sync by adding API clients to the queue. |