Skip to content

Commit

Permalink
On Mediaupload, attach video to currently selected playlist #765 (#780)
Browse files Browse the repository at this point in the history
* On Mediaupload attach video to currently selected playlist

* Implement dropdown to choose playlist in mediaupload dialog

* Make sure a course mediaupload isnt added to default playlist

* Make sure only Videos with tokens are available thru the backend

* After mediaupload, visualize that the video is processing and bugfix
  • Loading branch information
ssrahn authored Sep 11, 2023
1 parent d462ded commit 7a5ece2
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 21 deletions.
17 changes: 9 additions & 8 deletions cronjobs/opencast_discover_videos.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,16 @@ public function execute($last_result, $parameters = array())
$video = Videos::findOneBySql("config_id = ? AND episode = ?", [$config['id'], $new_event_id]);
if (!$video) {
$video = new Videos;
$video->setData([
'episode' => $new_event_id,
'config_id' => $config['id'],
'title' => $events[$new_event_id]->title,
'description' => $events[$new_event_id]->description,
'duration' => $events[$new_event_id]->duration
]);
}
$video->setValue('available', true);
$video->setData([
'episode' => $new_event_id,
'config_id' => $config['id'],
'title' => $events[$new_event_id]->title,
'description' => $events[$new_event_id]->description,
'duration' => $events[$new_event_id]->duration,
'state' => 'running',
'available' => true
]);
$video->store();

// create task to update permissions and everything else
Expand Down
29 changes: 20 additions & 9 deletions lib/Models/Videos.php
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ protected static function getFilteredVideos($query, $filters)
}

$where .= " AND trashed = " . $filters->getTrashed();
$where .= " AND oc_video.token IS NOT NULL";

$sql .= $where;

Expand Down Expand Up @@ -789,15 +790,25 @@ public static function addToCoursePlaylist($eventType, $episode, $video)
// get the courses this series belongs to
$series = SeminarSeries::findBySeries_id($episode->is_part_of);
foreach ($series as $s) {
$playlist = Helpers::checkCoursePlaylist($s['seminar_id']);

$pvideo = PlaylistVideos::findOneBySQL('video_id = ? AND playlist_id = ?', [$video->id, $playlist->id]);

if (empty($pvideo)) {
$pvideo = new PlaylistVideos();
$pvideo->video_id = $video->id;
$pvideo->playlist_id = $playlist->id;
$pvideo->store();
// Only add video to default playlist if it is not connected to a any playlist in this course
$stmt = \DBManager::get()->prepare($sql = 'SELECT count(*) FROM oc_playlist_seminar
INNER JOIN oc_playlist_video ON (oc_playlist_video.playlist_id = oc_playlist_seminar.playlist_id)
WHERE oc_playlist_seminar.seminar_id = ?
AND oc_playlist_video.video_id = ?
');
$stmt->execute([$video->id, $s['seminar_id']]);
if ($stmt->fetchColumn() == 0) {
// Add video to default playlist here
$playlist = Helpers::checkCoursePlaylist($s['seminar_id']);

$pvideo = PlaylistVideos::findOneBySQL('video_id = ? AND playlist_id = ?', [$video->id, $playlist->id]);

if (empty($pvideo)) {
$pvideo = new PlaylistVideos();
$pvideo->video_id = $video->id;
$pvideo->playlist_id = $playlist->id;
$pvideo->store();
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/RouteMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public function authenticatedRoutes()
$this->app->put('/videos/{token}', Routes\Video\VideoUpdate::class);
$this->app->put('/videos/{token}/restore', Routes\Video\VideoRestore::class);
$this->app->delete('/videos/{token}', Routes\Video\VideoDelete::class);
$this->app->post('/videos/{episode_id}', Routes\Video\VideoAdd::class);

$this->app->post('/videos/{token}/report', Routes\Video\VideoReport::class);
$this->app->post('/videos/{token}/playlists', Routes\Video\VideoAddToPlaylist::class);
Expand Down
62 changes: 62 additions & 0 deletions lib/Routes/Video/VideoAdd.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace Opencast\Routes\Video;

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Opencast\Errors\AuthorizationFailedException;
use Opencast\Errors\Error;
use Opencast\OpencastTrait;
use Opencast\OpencastController;
use Opencast\Models\Videos;

class VideoAdd extends OpencastController
{
use OpencastTrait;

public function __invoke(Request $request, Response $response, $args)
{
$json = $this->getRequestData($request);
$event = $json['event'];

$episode_id = $args['episode_id'];

$ret = [];

$video = Videos::findByEpisode($episode_id);
if (!empty($video) || !isset($event['config_id'])) {
$message = [
'type' => 'error',
'text' => _('Beim Erstellen des Videos ist ein Fehler aufgetreten.')
];
}
else {
$video = new Videos;
$video->setData([
'episode' => $episode_id,
'config_id' => $event['config_id'],
'title' => $event['title'],
'description' => $event['description'],
'duration' => $event['duration'],
'state' => $event['state'],
'available' => false
]);
if (!$video->token) {
$video->token = bin2hex(random_bytes(8));
}
$video->store();

$ret = $video->toSanitizedArray();

$message = [
'type' => 'success',
'text' => _('Das Video wurde erfolgreich erstellt.')
];
}

return $this->createResponse([
'message' => $message,
'event' => $ret
], $response->withStatus(200));
}
}
2 changes: 1 addition & 1 deletion vueapp/common/upload.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ class UploadService {
const xmlDoc = $.parseXML(mediaPackage);
episode_id = xmlDoc.documentElement.id;
if (episode_id) {
uploadDone(episode_id, workflowId);
uploadDone(episode_id, terms, workflowId);
}
} catch (ex) {
console.log(ex);
Expand Down
2 changes: 1 addition & 1 deletion vueapp/components/Videos/VideoCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
</span>
</span>
</a>
<span v-else-if="!event.available" class="oc--unavailable">
<span v-else-if="!event.available && !event.state" class="oc--unavailable">
{{ $gettext("Video nicht verfügbar") }}
</span>
<a v-else-if="event.state == 'cutting'"
Expand Down
61 changes: 59 additions & 2 deletions vueapp/components/Videos/VideoUpload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@
name="title" id="titleField" v-model="upload.title" required>
</label>

<label>
<span v-translate>
Zu Wiedergabeliste hinzufügen
</span>

<select v-model="upload.playlist_token" required>
<option v-for="playlist in upload_playlists"
v-bind:key="playlist.token"
:value="playlist.token">
{{ playlist.title }}
</option>
</select>
</label>

<label>
<span class="required" v-translate>
Aufnahmezeitpunkt
Expand Down Expand Up @@ -229,6 +243,7 @@ export default {
creator: this.currentUser.username,
contributor: this.currentUser.fullname,
workflow: null,
playlist_token: null,
recordDate: format(new Date(), "yyyy-MM-dd'T'HH:ii", { locale: de}),
subject: this.$gettext('Medienupload, Stud.IP')
},
Expand All @@ -244,9 +259,22 @@ export default {
...mapGetters({
'config' : 'simple_config_list',
'course_config': 'course_config',
'cid' : 'cid'
'cid' : 'cid',
'playlist' : 'playlist',
'playlists' : 'playlists'
}),
upload_playlists() {
let upload_playlists = this.playlists
if (!this.playlist) {
upload_playlists.unshift({
token: null,
title: 'Keine Wiedergabeliste auswählen'
})
}
return upload_playlists;
},
upload_workflows() {
let upload_wfs = [];
Expand Down Expand Up @@ -368,15 +396,40 @@ export default {
progress: parseInt(Math.round((loaded / total) * 100 ))
}
},
uploadDone: (episode_id, workflow_id) => {
uploadDone: (episode_id, uploadData, workflow_id) => {
view.$emit('done');
view.$store.dispatch('createLogEvent', {
event: 'upload',
data: {
episode_id: episode_id,
workflow_id: workflow_id
}
});
// Add event to database
view.$store.dispatch('createVideo', {
'episode': episode_id,
'config_id': view.selectedServer.id,
'title': uploadData.title,
'description': uploadData.description
})
.then(({ data }) => {
this.$store.dispatch('addMessage', data.message);
// If a playlist is selected, connect event with playlist
if (data.event?.token && uploadData.playlist_token) {
let playlist = view.playlists.find(p => p.token === uploadData.playlist_token);
if (playlist) {
this.$store.dispatch('addVideoToPlaylists', {
token: data.event.token,
playlists: [playlist],
})
.then(({data}) => {
this.$store.dispatch('addMessage', data.message);
})
}
}
});
}
});
},
Expand All @@ -401,6 +454,10 @@ export default {
if (this.cid) {
this.$store.dispatch('loadCourseConfig', this.cid);
}
if (this.playlist) {
this.upload.playlist_token = this.playlist.token;
}
}
}
</script>
4 changes: 4 additions & 0 deletions vueapp/store/videos.module.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ const actions = {
return ApiService.put('playlists/' + data.playlist_token + '/positions', data.sortedVideos)
},

async createVideo(context, event) {
return ApiService.post('videos/' + event.episode, {event: event});
},

async deleteVideo(context, token) {
return ApiService.delete('videos/' + token);
},
Expand Down

0 comments on commit 7a5ece2

Please sign in to comment.