-
Notifications
You must be signed in to change notification settings - Fork 23
Video listing optimization and caching #1389
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
<?php | ||
|
||
namespace Opencast\Caching; | ||
|
||
use Opencast\Models\Videos; | ||
|
||
class VideosCaching | ||
{ | ||
private $cache_factory; | ||
private $cache_name; | ||
const OC_CACHE_KEY_DOMAIN_USERS = 'OpencastV3/videos/users/'; | ||
const OC_CACHE_KEY_DOMAIN_COURSES = 'OpencastV3/videos/courses/'; | ||
const OC_CACHE_KEY_DOMAIN_PLAYLIST = 'OpencastV3/videos/playlist/'; | ||
|
||
public function __construct() { | ||
$this->cache_factory = \StudipCacheFactory::getCache(); | ||
} | ||
|
||
public function userVideos(string $user_id) | ||
{ | ||
$this->cache_name = self::OC_CACHE_KEY_DOMAIN_USERS . $user_id; | ||
return $this; | ||
} | ||
|
||
public function courseVideos(string $course_id) | ||
{ | ||
$this->cache_name = self::OC_CACHE_KEY_DOMAIN_COURSES . $course_id; | ||
return $this; | ||
} | ||
|
||
public function playlistVideos(int $playlist_id) | ||
{ | ||
$this->cache_name = self::OC_CACHE_KEY_DOMAIN_PLAYLIST . $playlist_id; | ||
return $this; | ||
} | ||
|
||
public function readAll() | ||
{ | ||
if (empty($this->cache_name)) { | ||
throw new \Error('Unable to read the cache due to missing cache name!'); | ||
} | ||
|
||
$content = $this->cache_factory->read($this->cache_name); | ||
return $content ? unserialize($content) : []; | ||
} | ||
|
||
public function read(string $unique_query_id) | ||
{ | ||
if (empty($unique_query_id)) { | ||
throw new \Error('Unable to read the cache due to missing cache name!'); | ||
} | ||
|
||
$all = $this->readAll(); | ||
|
||
if (!isset($all[$unique_query_id])) { | ||
return false; | ||
} | ||
|
||
return $all[$unique_query_id]; | ||
} | ||
|
||
public function write($unique_query_id, $content) | ||
{ | ||
if (empty($unique_query_id)) { | ||
throw new \Error('Unable to write the cache data due to missing cache name!'); | ||
} | ||
|
||
$all = $this->readAll(); | ||
|
||
$all[$unique_query_id] = $content; | ||
|
||
$serialized_records = serialize($all); | ||
|
||
return $this->cache_factory->write($this->cache_name, $serialized_records); | ||
} | ||
|
||
public function delete($unique_query_id) | ||
{ | ||
if (empty($unique_query_id)) { | ||
throw new \Error('Unable to expire the cache data due to missing cache name!'); | ||
} | ||
|
||
$all = $this->readAll(); | ||
|
||
if (empty($all)) { | ||
return true; | ||
} | ||
|
||
if (isset($all[$unique_query_id])) { | ||
unset($all[$unique_query_id]); | ||
} | ||
|
||
if (empty($all)) { | ||
$this->expire(); | ||
return true; | ||
} | ||
|
||
return $this->cache_factory->write($this->cache_name, serialize($all)); | ||
} | ||
|
||
public function expire() | ||
{ | ||
$this->cache_factory->expire($this->cache_name); | ||
} | ||
|
||
public static function expireAllVideoCaches(Videos $video) | ||
{ | ||
$cache = \StudipCacheFactory::getCache(); | ||
if (!empty($video->perms)) { | ||
foreach ($video->perms->pluck('user_id') as $user_id) { | ||
$cache->expire(self::OC_CACHE_KEY_DOMAIN_USERS . $user_id); | ||
} | ||
} | ||
|
||
if (!empty($video->playlists)) { | ||
foreach ($video->playlists as $playlist) { | ||
$cache->expire(self::OC_CACHE_KEY_DOMAIN_PLAYLIST . $playlist->id); | ||
|
||
if (!empty($playlist->courses)) { | ||
foreach ($playlist->courses as $course) { | ||
$cache->expire(self::OC_CACHE_KEY_DOMAIN_COURSES . $course->id); | ||
} | ||
} | ||
} | ||
} | ||
|
||
// We need to also look for root accounts! | ||
$stmt = \DBManager::get()->prepare($q = "SELECT `user_id` FROM `auth_user_md5` WHERE `perms` = :perm"); | ||
$stmt->execute([ | ||
':perm' => 'root', | ||
]); | ||
$root_user_ids = $stmt->fetchAll(\PDO::FETCH_COLUMN); | ||
foreach ($root_user_ids as $root_user_id) { | ||
$cache->expire(self::OC_CACHE_KEY_DOMAIN_USERS . $root_user_id); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -106,4 +106,9 @@ public function getTrashed() | |||||||||||
{ | ||||||||||||
return $this->trashed; | ||||||||||||
} | ||||||||||||
|
||||||||||||
public function decodeVars() | ||||||||||||
{ | ||||||||||||
return base64_encode(json_encode(get_object_vars($this))); | ||||||||||||
} | ||||||||||||
Comment on lines
+109
to
+113
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -5,6 +5,7 @@ | |||
use Opencast\Models\REST\ApiPlaylistsClient; | ||||
use Opencast\Helpers\PlaylistMigration; | ||||
use Opencast\Errors\Error; | ||||
use Opencast\Caching\VideosCaching; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
|
||||
class Playlists extends UPMap | ||||
{ | ||||
|
@@ -575,6 +576,8 @@ public function delete() | |||
$playlist_client->deletePlaylist($this->service_playlist_id); | ||||
} | ||||
|
||||
(new VideosCaching())->playlistVideos($this->id)->expire(); | ||||
|
||||
Comment on lines
+579
to
+580
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
return parent::delete(); | ||||
} | ||||
|
||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -10,6 +10,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||
use Opencast\Models\REST\ApiWorkflowsClient; | ||||||||||||||||||||||||||||||||||||||||||||||
use Opencast\Models\Helpers; | ||||||||||||||||||||||||||||||||||||||||||||||
use Opencast\Models\ScheduledRecordings; | ||||||||||||||||||||||||||||||||||||||||||||||
use Opencast\Caching\VideosCaching; | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
class Videos extends UPMap | ||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -297,9 +298,14 @@ protected static function getFilteredVideos($query, $filters) | |||||||||||||||||||||||||||||||||||||||||||||
$course_ids = []; | ||||||||||||||||||||||||||||||||||||||||||||||
$lecturer_ids = []; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
$count_selected_columns = [ | ||||||||||||||||||||||||||||||||||||||||||||||
'id', 'token', 'config_id', 'created' | ||||||||||||||||||||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
foreach ($filters->getFilters() as $filter) { | ||||||||||||||||||||||||||||||||||||||||||||||
switch ($filter['type']) { | ||||||||||||||||||||||||||||||||||||||||||||||
case 'text': | ||||||||||||||||||||||||||||||||||||||||||||||
$count_selected_columns[] = 'title'; | ||||||||||||||||||||||||||||||||||||||||||||||
$pname = ':text' . sizeof($params); | ||||||||||||||||||||||||||||||||||||||||||||||
$where .= " AND (title LIKE $pname OR description LIKE $pname)"; | ||||||||||||||||||||||||||||||||||||||||||||||
$params[$pname] = '%' . $filter['value'] .'%'; | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -450,7 +456,11 @@ protected static function getFilteredVideos($query, $filters) | |||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
$sql .= ' GROUP BY oc_video.id'; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
$stmt = \DBManager::get()->prepare($s = "SELECT COUNT(*) FROM (SELECT oc_video.* FROM oc_video $sql) t"); | ||||||||||||||||||||||||||||||||||||||||||||||
// Preparing count sql, specifically define columns to select in order to increase performance. | ||||||||||||||||||||||||||||||||||||||||||||||
$count_selected_columns = array_map(function($clmn) { return 'oc_video.' . $clmn; }, array_unique($count_selected_columns)); | ||||||||||||||||||||||||||||||||||||||||||||||
$count_select_columns_sql = implode(', ', $count_selected_columns); | ||||||||||||||||||||||||||||||||||||||||||||||
$s = "SELECT COUNT(*) FROM (SELECT $count_select_columns_sql FROM oc_video $sql) t"; | ||||||||||||||||||||||||||||||||||||||||||||||
$stmt = \DBManager::get()->prepare($s); | ||||||||||||||||||||||||||||||||||||||||||||||
$stmt->execute($params); | ||||||||||||||||||||||||||||||||||||||||||||||
$count = $stmt->fetchColumn(); | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -1273,4 +1283,26 @@ public static function addToCoursePlaylist($episode, $video) | |||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* @inheritDoc | ||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||
* Overriding store method, in order to expire caches. | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
public function store() | ||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||
VideosCaching::expireAllVideoCaches($this); | ||||||||||||||||||||||||||||||||||||||||||||||
return parent::store(); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* @inheritDoc | ||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||
* Overriding delete method, in order to expire caches. | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
public function delete() | ||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||
VideosCaching::expireAllVideoCaches($this); | ||||||||||||||||||||||||||||||||||||||||||||||
return parent::delete(); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+1286
to
+1307
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
use Opencast\OpencastController; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The changes in this file need to be reverted |
||
use Opencast\Models\Filter; | ||
use Opencast\Models\Videos; | ||
use Opencast\Caching\VideosCaching; | ||
|
||
class CourseVideoList extends OpencastController | ||
{ | ||
|
@@ -29,22 +30,38 @@ public function __invoke(Request $request, Response $response, $args) | |
throw new \AccessDeniedException(); | ||
} | ||
|
||
// show videos for this course and filter them with optional additional filters | ||
$videos = Videos::getCourseVideos($course_id, new Filter($params)); | ||
$response_result = [ | ||
'videos' => [], | ||
'count' => 0, | ||
]; | ||
|
||
$ret = []; | ||
foreach ($videos['videos'] as $video) { | ||
$video_array = $video->toSanitizedArray($params['cid']); | ||
if (!empty($video_array['perm']) && ($video_array['perm'] == 'owner' || $video_array['perm'] == 'write')) | ||
{ | ||
$video_array['perms'] = $video->perms->toSanitizedArray(); | ||
$filter = new Filter($params); | ||
$video_caching = new VideosCaching(); | ||
$course_videos_cache = $video_caching->courseVideos($course_id); | ||
$unique_query_id = $filter->decodeVars(); | ||
$response_result = $course_videos_cache->read($unique_query_id); | ||
if (empty($response_result)) { | ||
// show videos for this course and filter them with optional additional filters | ||
$videos = Videos::getCourseVideos($course_id, $filter); | ||
|
||
$ret = []; | ||
foreach ($videos['videos'] as $video) { | ||
$video_array = $video->toSanitizedArray($params['cid']); | ||
if (!empty($video_array['perm']) && ($video_array['perm'] == 'owner' || $video_array['perm'] == 'write')) | ||
{ | ||
$video_array['perms'] = $video->perms->toSanitizedArray(); | ||
} | ||
$ret[] = $video_array; | ||
} | ||
$ret[] = $video_array; | ||
|
||
$response_result = [ | ||
'videos' => $ret, | ||
'count' => $videos['count'], | ||
]; | ||
|
||
$course_videos_cache->write($unique_query_id, $response_result); | ||
} | ||
|
||
return $this->createResponse([ | ||
'videos' => $ret, | ||
'count' => $videos['count'], | ||
], $response); | ||
return $this->createResponse($response_result, $response); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
use Opencast\Models\Playlists; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The changes in this file need to be reverted |
||
use Opencast\Models\Videos; | ||
use Opencast\Models\PlaylistSeminarVideos; | ||
use Opencast\Caching\VideosCaching; | ||
|
||
class PlaylistVideoList extends OpencastController | ||
{ | ||
|
@@ -49,22 +50,38 @@ public function __invoke(Request $request, Response $response, $args) | |
} | ||
} | ||
|
||
// show videos for this playlist and filter them with optional additional filters | ||
$videos = Videos::getPlaylistVideos($playlist->id, new Filter($params)); | ||
$response_result = [ | ||
'videos' => [], | ||
'count' => 0, | ||
]; | ||
|
||
$ret = []; | ||
foreach ($videos['videos'] as $video) { | ||
$video_array = $video->toSanitizedArray($course_id, $playlist->id); | ||
if (!empty($video_array['perm']) && ($video_array['perm'] == 'owner' || $video_array['perm'] == 'write')) | ||
{ | ||
$video_array['perms'] = $video->perms->toSanitizedArray(); | ||
$filter = new Filter($params); | ||
$video_caching = new VideosCaching(); | ||
$playlist_videos_cache = $video_caching->playlistVideos($playlist->id); | ||
$unique_query_id = $filter->decodeVars(); | ||
$response_result = $playlist_videos_cache->read($unique_query_id); | ||
if (empty($response_result)) { | ||
// show videos for this playlist and filter them with optional additional filters | ||
$videos = Videos::getPlaylistVideos($playlist->id, $filter); | ||
|
||
$ret = []; | ||
foreach ($videos['videos'] as $video) { | ||
$video_array = $video->toSanitizedArray($course_id, $playlist->id); | ||
if (!empty($video_array['perm']) && ($video_array['perm'] == 'owner' || $video_array['perm'] == 'write')) | ||
{ | ||
$video_array['perms'] = $video->perms->toSanitizedArray(); | ||
} | ||
$ret[] = $video_array; | ||
} | ||
$ret[] = $video_array; | ||
|
||
$response_result = [ | ||
'videos' => $ret, | ||
'count' => $videos['count'], | ||
]; | ||
|
||
$playlist_videos_cache->write($unique_query_id, $response_result); | ||
} | ||
|
||
return $this->createResponse([ | ||
'videos' => $ret, | ||
'count' => $videos['count'] | ||
], $response); | ||
return $this->createResponse($response_result, $response); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file needs to be deleted