Skip to content

Commit 6ce17a6

Browse files
author
Ron Lucke
authored
Merge pull request elan-ev#1349 from ferishili/issue-1325
New Download Process
2 parents 2b4ecc8 + de7c290 commit 6ce17a6

File tree

7 files changed

+514
-158
lines changed

7 files changed

+514
-158
lines changed

app/controllers/redirect.php

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use Opencast\Models\VideosShares;
55
use Opencast\Models\LTI\LtiHelper;
66
use Opencast\Models\REST\ApiEventsClient;
7+
use Opencast\Errors\Error;
78

89
class RedirectController extends Opencast\Controller
910
{
@@ -87,15 +88,46 @@ public function download_action($token, $type, $index)
8788

8889
$publication = $video->publication? json_decode($video->publication, true) : null;
8990
if (!empty($publication) && isset($publication['downloads'][$type][$index]['url'])) {
90-
$url = $publication['downloads'][$type][$index]['url'];
9191

92-
$api_events = ApiEventsClient::getInstance($video->config_id);
93-
$response = $api_events->fileRequest($url);
92+
// Make sure the server configs are overwritten, in order to allow large file downloads.
93+
ignore_user_abort(true);
94+
set_time_limit(0);
95+
ini_set('memory_limit', '512M');
9496

95-
header('Content-Type: '. $response['mimetype']);
96-
97-
echo $response['body'];
98-
die;
97+
// Clean all output buffers.
98+
while (ob_get_level()) {
99+
ob_end_clean();
100+
}
101+
try {
102+
$url = $publication['downloads'][$type][$index]['url'];
103+
104+
$api_events = ApiEventsClient::getInstance($video->config_id);
105+
// Since we are using stream, we need to perform the get directly here! Doing it in another file and pass the body as a parameter won't work!
106+
$response = $api_events->ocRestClient->get($url, $api_events->getStreamDownloadConfig());
107+
$stream = $response->getBody();
108+
109+
// Set headers properly.
110+
header('Content-Type: ' . $response->getHeaderLine('Content-Type') ?: 'application/octet-stream');
111+
header('Content-Length: ' . $response->getHeaderLine('Content-Length'));
112+
header('Content-Disposition: attachment; filename*=UTF-8\'\'' . basename($url));
113+
header('Cache-Control: no-cache');
114+
header('Pragma: no-cache');
115+
116+
// Stream in chunks
117+
while (!$stream->eof()) {
118+
// A double check to make sure the connection is still open.
119+
if(connection_status() != CONNECTION_NORMAL){
120+
// If not leave the loop!
121+
break;
122+
}
123+
// 1MB per chunk.
124+
echo $stream->read(1024 * 1024);
125+
flush();
126+
}
127+
die;
128+
} catch (\Throwable $th) {
129+
throw new Error(_('Fehler beim Herunterladen der Datei').': ' . $th->getMessage(), 500);
130+
}
99131
}
100132
}
101133

assets/css/opencast.scss

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,13 @@ h2.oc--loadingbar, .oc--loadingbar-title {
723723
}
724724
}
725725

726+
&.oc--minimal-progress {
727+
height: 3px !important;
728+
.oc--progress-bar {
729+
height: 3px !important;
730+
}
731+
}
732+
726733
margin: 5px 0;
727734
}
728735

@@ -911,6 +918,134 @@ div.oc--dialog-possibilities {
911918
display: block;
912919
}
913920

921+
/* * * * * * * * * * * */
922+
/* DOWNLOAD VIDEOS */
923+
/* * * * * * * * * * * */
924+
925+
.oc--download-list-container {
926+
display: flex;
927+
flex-direction: column;
928+
height: 100%;
929+
.oc--download-list {
930+
flex-grow: 1;
931+
}
932+
.oc--download-messages {
933+
flex-shrink: 0;
934+
}
935+
936+
.oc--download-item {
937+
position: relative;
938+
display: flex;
939+
flex-direction: column;
940+
justify-content: start;
941+
align-items: stretch;
942+
padding: 5px 0px;
943+
944+
button.button {
945+
margin: 0px !important;
946+
}
947+
948+
.oc--download-item-control-row {
949+
display: flex;
950+
flex-direction: row;
951+
justify-content: space-between;
952+
align-items: center;
953+
width: 100%;
954+
gap: 5px;
955+
956+
.oc--tooltip--copy {
957+
width: 40px;
958+
flex-shrink: 0;
959+
display: flex;
960+
justify-content: center;
961+
align-items: center;
962+
963+
.oc--tooltip--copy-success {
964+
top: 0;
965+
}
966+
}
967+
}
968+
969+
.oc--download-btn-container {
970+
position: relative;
971+
display: flex;
972+
flex-direction: row;
973+
justify-content: space-between;
974+
align-items: center;
975+
width: 100%;
976+
977+
.oc--download-btn {
978+
flex-grow: 1;
979+
position: relative;
980+
}
981+
982+
.oc--download-cancel {
983+
margin-left: 5px;
984+
flex-shrink: 0;
985+
display: flex;
986+
justify-content: center;
987+
align-items: center;
988+
989+
&.active {
990+
cursor: pointer;
991+
}
992+
993+
&.inactive {
994+
cursor: default;
995+
}
996+
}
997+
}
998+
999+
.oc--download-info-container {
1000+
display: flex;
1001+
flex-direction: row;
1002+
justify-content: start;
1003+
align-items: center;
1004+
.oc--download-info-status {
1005+
flex: 1;
1006+
margin-left: 5px;
1007+
font-size: 0.8em;
1008+
}
1009+
}
1010+
1011+
.oc--download-spinner-container {
1012+
z-index: 999;
1013+
position: absolute;
1014+
top: 50%;
1015+
translate: 0 -50%;
1016+
left: 2px;
1017+
margin-right: 5px;
1018+
flex-shrink: 0;
1019+
display: flex;
1020+
justify-content: center;
1021+
align-items: center;
1022+
width: 24px;
1023+
height: 24px;
1024+
1025+
.oc--spinner {
1026+
transform: scale(0.5);
1027+
}
1028+
.oc--spinner:after {
1029+
content: " ";
1030+
display: block;
1031+
width: 24px;
1032+
height: 24px;
1033+
border-radius: 50%;
1034+
border: 6px solid;
1035+
border-color: #28497c transparent #28497c transparent;
1036+
animation: oc-spinner 1.2s linear infinite;
1037+
}
1038+
@keyframes oc-spinner {
1039+
0% {
1040+
transform: rotate(0deg);
1041+
}
1042+
100% {
1043+
transform: rotate(360deg);
1044+
}
1045+
}
1046+
}
1047+
}
1048+
}
9141049

9151050
/* * * * * * * * * * * * * * * * * * */
9161051
/* U P L O A D E L E M E N T S */

lib/Models/REST/RestClient.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,20 @@ public function __construct($config)
8282
$this->ocRestClient = new OcRestClient($oc_config);
8383
}
8484

85+
/**
86+
* Get the Guzzle client options suitable for stream downloading files.
87+
*
88+
* @return array
89+
*/
90+
public function getStreamDownloadConfig() {
91+
return [
92+
'auth' => [$this->username, $this->password],
93+
'timeout' => 0,
94+
'connect_timeout' => 0,
95+
'stream' => true,
96+
];
97+
}
98+
8599
public function fileRequest($file_url)
86100
{
87101
$response = $this->ocRestClient->get($file_url, [

vueapp/app.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ window.addEventListener("DOMContentLoaded", function() {
4545
}, function (error) {
4646
store.dispatch('axiosStop');
4747

48+
// This makes it possible to cancel requests, but we at the moment we don't want to handle it here.
49+
if (axios.isCancel(error)) {
50+
return Promise.reject(error);
51+
}
52+
4853
if (error.response.data !== undefined) {
4954
store.dispatch('addMessage', error.response);
5055
}

vueapp/components/ProgressBar.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
2-
<div class="oc--progress">
2+
<div class="oc--progress" :class="{'oc--minimal-progress': minimal === true}">
33
<div class="oc--progress-bar" :style="`width: ` + progress + `%`">
4-
<span>
4+
<span v-if="minimal !== true">
55
{{ progress }}%
66
</span>
77
</div>
@@ -12,6 +12,6 @@
1212
export default {
1313
name: 'ProgressBar',
1414
15-
props: ['progress']
15+
props: ['progress', 'minimal']
1616
}
1717
</script>

0 commit comments

Comments
 (0)