Skip to content

Commit 864762e

Browse files
authored
Download the media files via the browser download mechanism (#1390)
This PR replaces the javascript download function for media files by the integrated browser download mechanism.
1 parent c567da9 commit 864762e

File tree

2 files changed

+23
-116
lines changed

2 files changed

+23
-116
lines changed

app/controllers/redirect.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public function download_action($token, $type, $index)
109109
// Set headers properly.
110110
header('Content-Type: ' . $response->getHeaderLine('Content-Type') ?: 'application/octet-stream');
111111
header('Content-Length: ' . $response->getHeaderLine('Content-Length'));
112-
header('Content-Disposition: attachment; filename*=UTF-8\'\'' . basename($url));
112+
header('Content-Disposition: attachment');
113113
header('Cache-Control: no-cache');
114114
header('Pragma: no-cache');
115115

vueapp/components/Videos/Actions/VideoDownload.vue

Lines changed: 22 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
type="radio"
2121
value="presenter"
2222
v-model="selectedSource"
23-
:disabled="!hasPresenterVideo || downloadInProgress"
23+
:disabled="!hasPresenterVideo"
2424
/>
2525
{{ $gettext('Aufzeichnung der vortragenden Person') }}</label
2626
>
@@ -29,21 +29,21 @@
2929
type="radio"
3030
value="presentation"
3131
v-model="selectedSource"
32-
:disabled="!hasPresentationVideo || downloadInProgress"
32+
:disabled="!hasPresentationVideo"
3333
/>
3434
{{ $gettext('Aufzeichnung des Bildschirms') }}</label
3535
>
3636
<label>
3737
{{ $gettext('Videoqualität') }}
38-
<select v-model="selectedMedia" :disabled="downloadInProgress">
38+
<select v-model="selectedMedia">
3939
<template v-if="selectedSource === 'presenter'">
40-
<option v-for="(media, index) in tuned_presenters" :key="index" :value="media">
40+
<option v-for="(media, index) in presenters" :key="index" :value="media">
4141
{{ getMediaText(media) }}
4242
</option>
4343
</template>
4444
<template v-else>
4545
<option
46-
v-for="(media, index) in tuned_presentations"
46+
v-for="(media, index) in presentations"
4747
:key="index"
4848
:value="media"
4949
>
@@ -53,10 +53,6 @@
5353
</select>
5454
</label>
5555
</form>
56-
<template v-if="downloadInProgress">
57-
<span>{{ $gettext('Video wird heruntergeladen') }}</span>
58-
<ProgressBar :progress="selectedMedia.progress" />
59-
</template>
6056
</div>
6157
<div class="oc--download-messages">
6258
<MessageList :float="true" :dialog="true" />
@@ -72,12 +68,9 @@
7268
>
7369
{{ $gettext('Link kopieren') }}
7470
</button>
75-
<button v-if="!downloadInProgress" class="button" @click="downloadFile()">
71+
<a :href="downloadUrl" :download="selectedFileName" class="button">
7672
{{ $gettext('Herunterladen') }}
77-
</button>
78-
<button v-else class="button" @click="abortDownload()">
79-
{{ $gettext('Herunterladen abbrechen') }}
80-
</button>
73+
</a>
8174
</template>
8275
</StudipDialog>
8376
</div>
@@ -112,26 +105,6 @@ export default {
112105
},
113106
114107
computed: {
115-
tuned_presentations() {
116-
let tuned = this.presentations.map((media) => {
117-
media.loading = false;
118-
media.download_controller = new AbortController();
119-
media.progress = 0;
120-
return media;
121-
});
122-
return tuned;
123-
},
124-
125-
tuned_presenters() {
126-
let tuned = this.presenters.map((media) => {
127-
media.loading = false;
128-
media.download_controller = new AbortController();
129-
media.progress = 0;
130-
return media;
131-
});
132-
return tuned;
133-
},
134-
135108
hasPresenterVideo() {
136109
return this.presenters.length > 0;
137110
},
@@ -140,90 +113,24 @@ export default {
140113
return this.presentations.length > 0;
141114
},
142115
143-
downloadInProgress() {
144-
return this.selectedMedia?.loading;
116+
selectedMediaIndex() {
117+
return this.selectedMedia?.size;
145118
},
146-
},
147119
148-
methods: {
149-
abortDownload() {
150-
if (this.downloadInProgress) {
151-
this.selectedMedia.download_controller.abort();
152-
this.selectedMedia.progress = 0;
153-
this.selectedMedia.loading = false;
154-
}
155-
},
156-
async downloadFile() {
157-
const index = this.selectedMedia?.size;
158-
const type = this.selectedSource;
159-
if (this.selectedMedia?.loading === true) {
160-
return;
161-
}
162-
this.$store.dispatch('clearMessages', true);
163-
let view = this;
164-
165-
let url = window.OpencastPlugin.REDIRECT_URL + '/download/' + this.event.token + '/' + type + '/' + index;
166-
this.selectedMedia.loading = true;
167-
this.selectedMedia.progress = 0;
168-
169-
let dummy_download_link = null;
170-
171-
axios
172-
.get(url, {
173-
responseType: 'blob',
174-
signal: this.selectedMedia.download_controller.signal,
175-
onDownloadProgress: (progressEvent) => {
176-
let percentage = Math.round((progressEvent.loaded * 100) / index);
177-
if (percentage > 100) {
178-
percentage = 100;
179-
}
180-
this.selectedMedia.progress = percentage;
181-
},
182-
})
183-
.then((response) => {
184-
const blob = new Blob([response.data]);
185-
dummy_download_link = document.createElement('a');
186-
dummy_download_link.href = URL.createObjectURL(blob);
187-
dummy_download_link.download = this.getFileName(this.selectedMedia);
188-
dummy_download_link.click();
189-
view.$store.dispatch('addMessage', {
190-
type: 'success',
191-
text: this.$gettext('Herunterladen des Mediums abgeschlossen.'),
192-
dialog: true,
193-
});
194-
})
195-
.catch((err) => {
196-
let message = {
197-
type: 'error',
198-
text: this.$gettext('Herunterladen des Mediums fehlgeschlagen!'),
199-
dialog: true,
200-
};
201-
if (axios.isCancel(err)) {
202-
message.type = 'warning';
203-
message.text = this.$gettext('Herunterladen des Mediums abgebrochen!');
204-
}
205-
view.$store.dispatch('addMessage', message);
206-
})
207-
.finally(() => {
208-
this.resetMediaDownloadProps();
209-
if (dummy_download_link) {
210-
URL.revokeObjectURL(dummy_download_link.href);
211-
dummy_download_link.remove();
212-
dummy_download_link = null;
213-
}
214-
});
120+
downloadUrl() {
121+
return window.OpencastPlugin.REDIRECT_URL + '/download/' + this.event.token + '/' + this.selectedSource + '/' + this.selectedMediaIndex;
215122
},
216123
217-
resetMediaDownloadProps() {
218-
this.selectedMedia.loading = false;
219-
this.selectedMedia.download_controller = new AbortController();
220-
this.selectedMedia.progress = 0;
221-
},
124+
selectedFileName() {
125+
return this.getFileName(this.selectedMedia);
126+
}
127+
},
222128
129+
methods: {
223130
getFileName(media) {
224-
let res = media.info;
131+
let res = media?.info || '';
225132
res = res.replace(' * ', ' x ').replace(/\s+/g, '');
226-
let ext = media.url.split('.').pop();
133+
let ext = media?.url.split('.').pop() || '';
227134
return this.event.title + ' (' + res + ').' + ext;
228135
},
229136
@@ -285,19 +192,19 @@ export default {
285192
this.extractDownloads();
286193
if (this.hasPresenterVideo) {
287194
this.selectedSource = 'presenter';
288-
this.selectedMedia = this.tuned_presenters[0];
195+
this.selectedMedia = this.presenters[0];
289196
} else {
290197
this.selectedSource = 'presentation';
291-
this.selectedMedia = this.tuned_presentations[0];
198+
this.selectedMedia = this.presentations[0];
292199
}
293200
},
294201
watch: {
295202
selectedSource(newSource) {
296203
if (newSource === 'presenter') {
297-
this.selectedMedia = this.tuned_presenters[0];
204+
this.selectedMedia = this.presenters[0];
298205
}
299206
if (newSource === 'presentation') {
300-
this.selectedMedia = this.tuned_presentations[0];
207+
this.selectedMedia = this.presentations[0];
301208
}
302209
}
303210
}

0 commit comments

Comments
 (0)