Skip to content

Commit b1d2ca2

Browse files
authored
Mark videos unavailable in discovery instead of removing + Opencast API connectivity check in cronjobs (#1387)
* changes according to discussion: - introducing cronjob utils: oc conecttion trait with OCConfig::checkOpencastAPIConnectivity. - all cronjobs now have a connection checker before processing. - video is marked unavailable when they are no longer found in OC. * changes according to request: - add a global functional config to toggle the listing of unavailable videos * add engage node check for oc connectivity check in cronjobs * make sure the process is terminated when there is no opencast
1 parent ef74ece commit b1d2ca2

10 files changed

+195
-44
lines changed

cronjobs/opencast_clear_recycle_bin.php

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44

55

66
use Opencast\Models\Videos;
7+
use Opencast\Models\REST\ApiEventsClient;
8+
use Opencast\Helpers\CronjobUtils\OpencastConnectionCheckerTrait;
79

810
class OpencastClearRecycleBin extends CronJob
911
{
1012

13+
use OpencastConnectionCheckerTrait;
14+
1115
public static function getName()
1216
{
1317
return _('Opencast - Zum Löschen markierte Videos endgültig löschen');
@@ -28,13 +32,37 @@ public function execute($last_result, $parameters = array())
2832
) AND trashed_timestamp
2933
< NOW() - INTERVAL " . \Config::get()->OPENCAST_CLEAR_RECYCLE_BIN_INTERVAL ." DAY");
3034

35+
// We need to group the videos based on the config_id, in order to check the connection first.
36+
$videos_by_config = [];
3137
foreach ($videos as $video) {
32-
echo "Video #" . $video->id . " (" . $video->title . ") ";
33-
if ($video->removeVideo()) {
34-
echo "removed\n";
38+
$config_id = $video->config_id ?? \Config::get()->OPENCAST_DEFAULT_SERVER;
39+
if (!isset($videos_by_config[$config_id])) {
40+
$videos_by_config[$config_id] = [];
3541
}
36-
else {
37-
echo "remove failed\n";
42+
$videos_by_config[$config_id][] = $video;
43+
}
44+
45+
// Now, we loop through the grouped videos.
46+
foreach ($videos_by_config as $config_id => $videos) {
47+
echo 'Working on config with id #' . $config_id . "\n";
48+
49+
// Checking the connection.
50+
if (!$this->isOpencastReachable($config_id)) {
51+
continue;
52+
}
53+
54+
// To increase performance we instantiate the ApiEndpoint once in here!
55+
$api_event_client = ApiEventsClient::getInstance($config_id);
56+
57+
// Deleting videos.
58+
foreach ($videos as $video) {
59+
echo "Video #" . $video->id . " (" . $video->title . ") ";
60+
if ($video->removeVideo($api_event_client)) {
61+
echo "removed\n";
62+
}
63+
else {
64+
echo "remove failed\n";
65+
}
3866
}
3967
}
4068
}

cronjobs/opencast_discover_videos.php

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,18 @@
44
require_once __DIR__.'/../vendor/autoload.php';
55

66
use Opencast\Models\Config;
7-
use Opencast\Models\REST\Config as OCConfig;
87
use Opencast\Models\Videos;
98
use Opencast\Models\PlaylistVideos;
109
use Opencast\Models\WorkflowConfig;
1110
use Opencast\Models\REST\ApiEventsClient;
11+
use Opencast\Helpers\CronjobUtils\OpencastConnectionCheckerTrait;
1212
use Opencast\Models\Helpers;
1313

1414
class OpencastDiscoverVideos extends CronJob
1515
{
1616

17+
use OpencastConnectionCheckerTrait;
18+
1719
/**
1820
* @var array The required properties of the event object which will be checked before any operation.
1921
*/
@@ -47,17 +49,10 @@ public function execute($last_result, $parameters = array())
4749
$configs = Config::findBySql('active = 1');
4850

4951
foreach ($configs as $config) {
50-
// check, if this opencast instance is accessible
51-
$version = false;
52-
53-
echo 'Working on config with id #'. $config->id ."\n";
54-
$version = OCConfig::getOCBaseVersion($config->id);
52+
echo 'Working on config with id #' . $config->id . "\n";
5553

56-
if (!$version) {
57-
echo 'Cannot connect to opencast, skipping!' ."\n";
54+
if (!$this->isOpencastReachable($config->id)) {
5855
continue;
59-
} else {
60-
echo "Found opencast with version $version, continuing\n";
6156
}
6257

6358
// update endpoints, just to make sure
@@ -206,13 +201,13 @@ public function execute($last_result, $parameters = array())
206201
}
207202
} while (!empty($oc_events));
208203

209-
// Check if local videos are not longer available in OC and remove them from Stud.IP
210-
// If the video should reappear in the future, Stud.IP will readd it again.
204+
// Check if local videos are not longer available in OC and make the video unavailable if it is already there!
211205
foreach (array_diff($local_event_ids, $event_ids) as $event_id) {
212206
$video = Videos::findOneBySql("config_id = ? AND episode = ?", [$config['id'], $event_id]);
213207
// Need null check for archived videos
214208
if ($video) {
215-
$video->delete();
209+
$video->setValue('available', false);
210+
$video->store();
216211
}
217212
}
218213

cronjobs/opencast_refresh_scheduling.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111
use Opencast\Models\Resources;
1212
use Opencast\Models\ScheduleHelper;
1313
use Opencast\Models\REST\SchedulerClient;
14+
use Opencast\Helpers\CronjobUtils\OpencastConnectionCheckerTrait;
1415

1516
class OpencastRefreshScheduling extends CronJob
1617
{
1718

19+
use OpencastConnectionCheckerTrait;
20+
1821
/**
1922
* Return the name of the cronjob.
2023
*/
@@ -42,11 +45,22 @@ public function execute($last_result, $parameters = array())
4245
$config = Config::findBySql(1);
4346
$oc_se_count = 0;
4447

48+
// A flag to check if we should continue!
49+
$should_proceed = false;
50+
4551
// 1. Get Opencast Scheduled Recordings based on each configured server config.
46-
foreach ($config as $conf) {
47-
$config_id = $conf['id'];
52+
foreach ($config as $config) {
53+
$config_id = $config->id;
4854
$scheduled_events = [];
4955

56+
echo 'Working on config with id #' . $config_id . "\n";
57+
58+
if (!$this->isOpencastReachable($config_id)) {
59+
continue;
60+
}
61+
62+
$should_proceed = true;
63+
5064
try {
5165
$events_client = ApiEventsClient::getInstance($config_id);
5266
// Adding config_id to each record for easier use later on!
@@ -65,6 +79,12 @@ public function execute($last_result, $parameters = array())
6579
];
6680
$oc_se_count += count($scheduled_events);
6781
}
82+
83+
if (!$should_proceed) {
84+
echo "No reachable Opencast instance found. Terminating process\n";
85+
return;
86+
}
87+
6888
echo 'In Opencast geplante Events: ' . $oc_se_count . "\n";
6989

7090
// 2. Get all scheduled recordings stored in StudIP.

cronjobs/opencast_sync_acls.php

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
use Opencast\Models\Config;
66
use Opencast\Models\Videos;
77
use Opencast\Models\REST\ApiEventsClient;
8-
use Opencast\Models\REST\Config as OCConfig;
8+
use Opencast\Helpers\CronjobUtils\OpencastConnectionCheckerTrait;
99

1010
class OpencastSyncAcls extends CronJob
1111
{
1212

13+
use OpencastConnectionCheckerTrait;
14+
1315
public static function getName()
1416
{
1517
return _('Opencast - Synchronisiert ACLs für Events');
@@ -37,17 +39,10 @@ public function execute($last_result, $parameters = array())
3739
$configs = Config::findBySql('active = 1');
3840

3941
foreach ($configs as $config) {
40-
// check, if this opencast instance is accessible
41-
$version = false;
42-
43-
echo 'working on config '. $config->id ."\n";
44-
$version = OCConfig::getOCBaseVersion($config->id);
42+
echo 'Working on config with id #' . $config->id . "\n";
4543

46-
if (!$version) {
47-
echo 'cannot connect to opencast, skipping!' ."\n";
44+
if (!$this->isOpencastReachable($config->id)) {
4845
continue;
49-
} else {
50-
echo "found opencast with version $version, continuing\n";
5146
}
5247

5348
// update endpoints, just to make sure
@@ -89,6 +84,8 @@ public function execute($last_result, $parameters = array())
8984
}
9085
}
9186
} while (!empty($oc_events));
87+
88+
echo 'Done working on config with id #' . $config->id . "\n";
9289
}
9390
}
9491

cronjobs/opencast_sync_playlists.php

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
use Opencast\Models\Config;
77
use Opencast\Models\Playlists;
88
use Opencast\Models\REST\ApiPlaylistsClient;
9-
use Opencast\Models\REST\Config as OCConfig;
9+
use Opencast\Helpers\CronjobUtils\OpencastConnectionCheckerTrait;
1010

1111
class OpencastSyncPlaylists extends CronJob
1212
{
13+
use OpencastConnectionCheckerTrait;
14+
1315
public static function getName()
1416
{
1517
return _('Opencast - Wiedergabelisten synchronisieren');
@@ -31,17 +33,10 @@ public function execute($last_result, $parameters = array())
3133
$configs = Config::findBySql('active = 1');
3234

3335
foreach ($configs as $config) {
34-
// check, if this opencast instance is accessible
35-
$version = false;
36-
37-
echo 'working on config ' . $config->id . "\n";
38-
$version = OCConfig::getOCBaseVersion($config->id);
36+
echo 'Working on config with id #' . $config->id . "\n";
3937

40-
if (!$version) {
41-
echo 'cannot connect to opencast, skipping!' . "\n";
38+
if (!$this->isOpencastReachable($config->id)) {
4239
continue;
43-
} else {
44-
echo "found opencast with version $version, continuing\n";
4540
}
4641

4742
// call opencast to get all playlists
@@ -115,4 +110,4 @@ public function execute($last_result, $parameters = array())
115110
}
116111
}
117112
}
118-
}
113+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace Opencast\Helpers\CronjobUtils;
4+
5+
use Opencast\Models\REST\Config as OCConfig;
6+
7+
trait OpencastConnectionCheckerTrait
8+
{
9+
/**
10+
* @var string $not_reachable_message Message to display when Opencast is not reachable.
11+
*/
12+
private $not_reachable_message = 'Opencast is currently unreachable. Process postponed.';
13+
14+
/**
15+
* Checks if the Opencast instance is reachable for the given configuration ID.
16+
*
17+
* This method attempts to connect to the Opencast API using the provided configuration ID.
18+
* If the connection is successful, it returns true. If not, it prints a message and returns false.
19+
* Use this method in cronjob classes before performing any operations that require a working Opencast connection.
20+
*
21+
* @param int $config_id The ID of the Opencast configuration to check.
22+
* @param bool $check_engage_node A flag to determine whether the check should be performed against engage node (e.g play or search endpoint)
23+
* @return bool True if Opencast is reachable, false otherwise.
24+
*/
25+
protected function isOpencastReachable(int $config_id, bool $check_engage_node = false): bool {
26+
$is_opencast_reachable = false;
27+
$message = $this->not_reachable_message;
28+
try {
29+
$is_opencast_reachable = OCConfig::checkOpencastAPIConnectivity($config_id, $check_engage_node);
30+
} catch (\Throwable $th) {
31+
$message .= ': ' . $th->getMessage();
32+
}
33+
if (!$is_opencast_reachable) {
34+
echo $message . "\n";
35+
}
36+
return $is_opencast_reachable;
37+
}
38+
}

lib/Models/REST/Config.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,43 @@ public static function retrieveRESTservices($components, $service_url)
8383

8484
return $services;
8585
}
86+
87+
/**
88+
* Checks if the Opencast API is reachable for the given configuration.
89+
*
90+
* This method performs a basic GET request to the Opencast API base endpoint
91+
* using the provided configuration ID. It returns true if the API responds
92+
* with a 200 HTTP status code, indicating that the Opencast instance is reachable.
93+
*
94+
* @param int $config_id The ID of the Opencast configuration to check.
95+
* @param bool $check_engage_node A flag to determine whether the check should be performed against engage node (e.g play or search endpoint)
96+
* @return bool True if the Opencast API is reachable, false otherwise.
97+
*/
98+
public static function checkOpencastAPIConnectivity(int $config_id, bool $check_engage_node = false): bool
99+
{
100+
$success = false;
101+
$config = null;
102+
if ($check_engage_node) {
103+
$engage_related_service = 'search';
104+
$config = ConfigModel::getConfigForService($engage_related_service, $config_id);
105+
// Since the endpoint url by default has an ending of service label, we make sure it is removed!
106+
if (!empty($config['service_url'])) {
107+
$config['service_url'] = rtrim(str_replace($engage_related_service, '', $config['service_url']), '/');
108+
}
109+
} else {
110+
$config = ConfigModel::getBaseServerConf($config_id);
111+
}
112+
113+
if (empty($config)) {
114+
return false;
115+
}
116+
117+
// populate config_id if calling the RestClient directly
118+
$config['config_id'] = $config['id'];
119+
$oc = new RestClient($config);
120+
121+
$response = $oc->opencastApi->baseApi->get();
122+
123+
return ($response['code'] == 200);
124+
}
86125
}

lib/Models/Videos.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,10 @@ protected static function getFilteredVideos($query, $filters)
442442
$where .= " AND trashed = " . $filters->getTrashed();
443443
$where .= " AND oc_video.token IS NOT NULL";
444444

445+
if (empty(\Config::get()->OPENCAST_LIST_UNAVAILABLE_VIDEOS)) {
446+
$where .= " AND oc_video.available = 1";
447+
}
448+
445449
$sql .= $where;
446450

447451
$sql .= ' GROUP BY oc_video.id';
@@ -812,13 +816,18 @@ public function updateMetadata($event, $check_dirty_state = true)
812816
}
813817

814818
/**
815-
* Removes a video from both opencsat and local sides.
819+
* Removes a video from both opencast and local sides.
816820
*
821+
* @param ApiEventsClient|null $api_event_client Optional API client instance. If not provided, a new one will be created.
822+
817823
* @return boolean the result of deletion process
818824
*/
819-
public function removeVideo()
825+
public function removeVideo(ApiEventsClient $api_event_client = null)
820826
{
821-
$api_event_client = ApiEventsClient::getInstance($this->config_id);
827+
// Make sure $api_event_client gets its instance if not passed.
828+
if ($api_event_client === null) {
829+
$api_event_client = ApiEventsClient::getInstance($this->config_id);
830+
}
822831

823832
// if the video exists in opencast, make sure it is deleted
824833
if ($this->episode && $api_event_client->getEpisode($this->episode)) {

lib/Providers/OpencastConstants.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@
9191
'name' => "OPENCAST_UPLOAD_INFO_TEXT_BODY",
9292
'tag' => 'ui'
9393
],
94+
[
95+
'name' => "OPENCAST_LIST_UNAVAILABLE_VIDEOS",
96+
'tag' => 'functions'
97+
],
9498
],
9599
],
96100
];

0 commit comments

Comments
 (0)