filebrowser/frontend/src/views/files/Preview.vue

335 lines
8.4 KiB
Vue
Raw Normal View History

2018-02-01 12:17:04 +00:00
<template>
2021-03-21 11:51:58 +00:00
<div
id="previewer"
@mousemove="toggleNavigation"
@touchstart="toggleNavigation"
>
2021-02-25 18:37:07 +00:00
<header-bar>
<action icon="close" :label="$t('buttons.close')" @action="close()" />
<title>{{ name }}</title>
2021-03-21 11:51:58 +00:00
<action
:disabled="loading"
v-if="isResizeEnabled && req.type === 'image'"
:icon="fullSize ? 'photo_size_select_large' : 'hd'"
@action="toggleSize"
/>
2018-02-01 12:17:04 +00:00
2021-02-25 18:37:07 +00:00
<template #actions>
2021-03-21 11:51:58 +00:00
<action
:disabled="loading"
v-if="user.perm.rename"
2021-03-21 11:51:58 +00:00
icon="mode_edit"
:label="$t('buttons.rename')"
show="rename"
/>
<action
:disabled="loading"
v-if="user.perm.delete"
2021-03-21 11:51:58 +00:00
icon="delete"
:label="$t('buttons.delete')"
@action="deleteFile"
id="delete-button"
/>
<action
:disabled="loading"
v-if="user.perm.download"
2021-03-21 11:51:58 +00:00
icon="file_download"
:label="$t('buttons.download')"
@action="download"
/>
<action
:disabled="loading"
icon="info"
:label="$t('buttons.info')"
show="info"
/>
2021-02-25 18:37:07 +00:00
</template>
</header-bar>
<div class="loading delayed" v-if="loading">
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
2018-02-01 12:17:04 +00:00
</div>
<template v-else>
2020-07-14 01:18:53 +00:00
<div class="preview">
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
2021-03-26 17:31:27 +00:00
<audio
v-else-if="req.type == 'audio'"
ref="player"
:src="raw"
controls
:autoplay="autoPlay"
@play="autoPlay = true"
></audio>
<video
v-else-if="req.type == 'video'"
ref="player"
:src="raw"
controls
:autoplay="autoPlay"
@play="autoPlay = true"
>
2020-07-14 01:18:53 +00:00
<track
kind="captions"
v-for="(sub, index) in subtitles"
:key="index"
:src="sub"
2021-03-21 11:51:58 +00:00
:label="'Subtitle ' + index"
:default="index === 0"
/>
Sorry, your browser doesn't support embedded videos, but don't worry,
you can <a :href="downloadUrl">download it</a>
2020-07-14 01:18:53 +00:00
and watch it with your favorite video player!
</video>
2021-03-21 11:51:58 +00:00
<object
v-else-if="req.extension.toLowerCase() == '.pdf'"
class="pdf"
:data="raw"
></object>
<a v-else-if="req.type == 'blob'" :href="downloadUrl">
2021-03-21 11:51:58 +00:00
<h2 class="message">
{{ $t("buttons.download") }}
<i class="material-icons">file_download</i>
</h2>
2020-07-14 01:18:53 +00:00
</a>
</div>
</template>
2020-08-18 12:47:23 +00:00
2021-03-21 11:51:58 +00:00
<button
@click="prev"
@mouseover="hoverNav = true"
@mouseleave="hoverNav = false"
:class="{ hidden: !hasPrevious || !showNav }"
:aria-label="$t('buttons.previous')"
:title="$t('buttons.previous')"
>
2021-02-22 16:01:13 +00:00
<i class="material-icons">chevron_left</i>
</button>
2021-03-21 11:51:58 +00:00
<button
@click="next"
@mouseover="hoverNav = true"
@mouseleave="hoverNav = false"
:class="{ hidden: !hasNext || !showNav }"
:aria-label="$t('buttons.next')"
:title="$t('buttons.next')"
>
2021-02-22 16:01:13 +00:00
<i class="material-icons">chevron_right</i>
</button>
2018-02-01 12:17:04 +00:00
</div>
</template>
<script>
2021-03-21 11:51:58 +00:00
import { mapState } from "vuex";
import { files as api } from "@/api";
import { baseURL, resizePreview } from "@/utils/constants";
import url from "@/utils/url";
import throttle from "lodash.throttle";
import HeaderBar from "@/components/header/HeaderBar";
import Action from "@/components/header/Action";
import ExtendedImage from "@/components/files/ExtendedImage";
const mediaTypes = ["image", "video", "audio", "blob"];
2018-02-01 12:17:04 +00:00
export default {
2021-03-21 11:51:58 +00:00
name: "preview",
2018-02-01 12:17:04 +00:00
components: {
2021-02-25 18:37:07 +00:00
HeaderBar,
Action,
2021-03-21 11:51:58 +00:00
ExtendedImage,
2018-02-01 12:17:04 +00:00
},
data: function () {
return {
2021-03-21 11:51:58 +00:00
previousLink: "",
nextLink: "",
listing: null,
2021-03-21 11:51:58 +00:00
name: "",
2020-08-18 13:08:58 +00:00
subtitles: [],
2021-02-22 16:01:13 +00:00
fullSize: false,
showNav: true,
navTimeout: null,
2021-03-21 11:51:58 +00:00
hoverNav: false,
2021-03-26 17:31:27 +00:00
autoPlay: false,
2021-03-21 11:51:58 +00:00
};
2018-02-01 12:17:04 +00:00
},
computed: {
2021-03-21 11:51:58 +00:00
...mapState(["req", "user", "oldReq", "jwt", "loading", "show"]),
hasPrevious() {
return this.previousLink !== "";
2018-02-01 12:17:04 +00:00
},
2021-03-21 11:51:58 +00:00
hasNext() {
return this.nextLink !== "";
},
2021-03-21 11:51:58 +00:00
downloadUrl() {
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${
this.jwt
}`;
},
2021-03-21 11:51:58 +00:00
previewUrl() {
2021-03-10 15:14:01 +00:00
// reload the image when the file is replaced
2021-03-21 11:51:58 +00:00
const key = Date.parse(this.req.modified);
2021-03-10 15:14:01 +00:00
2021-03-21 11:51:58 +00:00
if (this.req.type === "image" && !this.fullSize) {
return `${baseURL}/api/preview/big${url.encodePath(
this.req.path
)}?auth=${this.jwt}&k=${key}`;
}
2021-03-21 11:51:58 +00:00
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${
this.jwt
}&k=${key}`;
},
2021-03-21 11:51:58 +00:00
raw() {
return `${this.previewUrl}&inline=true`;
2020-08-18 12:47:23 +00:00
},
2021-03-21 11:51:58 +00:00
showMore() {
return this.$store.state.show === "more";
},
isResizeEnabled() {
return resizePreview;
2020-08-18 13:08:58 +00:00
},
2018-02-01 12:17:04 +00:00
},
2020-07-14 01:18:53 +00:00
watch: {
$route: function () {
2021-03-21 11:51:58 +00:00
this.updatePreview();
this.toggleNavigation();
},
2020-07-14 01:18:53 +00:00
},
2021-03-21 11:51:58 +00:00
async mounted() {
window.addEventListener("keydown", this.key);
this.listing = this.oldReq.items;
this.updatePreview();
2018-02-01 12:17:04 +00:00
},
2021-03-21 11:51:58 +00:00
beforeDestroy() {
window.removeEventListener("keydown", this.key);
2018-02-01 12:17:04 +00:00
},
methods: {
2021-03-21 11:51:58 +00:00
deleteFile() {
this.$store.commit("showHover", {
prompt: "delete",
2021-03-04 14:40:18 +00:00
confirm: () => {
2021-03-21 11:51:58 +00:00
this.listing = this.listing.filter((item) => item.name !== this.name);
2021-03-04 14:40:18 +00:00
if (this.hasNext) {
2021-03-21 11:51:58 +00:00
this.next();
2021-03-04 14:40:18 +00:00
} else if (!this.hasPrevious && !this.hasNext) {
2021-03-21 11:51:58 +00:00
this.close();
2021-03-04 14:40:18 +00:00
} else {
2021-03-21 11:51:58 +00:00
this.prev();
2021-03-04 14:40:18 +00:00
}
2021-03-21 11:51:58 +00:00
},
});
},
2021-03-21 11:51:58 +00:00
prev() {
this.hoverNav = false;
this.$router.push({ path: this.previousLink });
2018-02-01 12:17:04 +00:00
},
2021-03-21 11:51:58 +00:00
next() {
this.hoverNav = false;
this.$router.push({ path: this.nextLink });
2018-02-01 12:17:04 +00:00
},
2021-03-21 11:51:58 +00:00
key(event) {
2020-09-29 14:04:55 +00:00
if (this.show !== null) {
2021-03-21 11:51:58 +00:00
return;
2020-09-29 14:04:55 +00:00
}
2021-03-21 11:51:58 +00:00
if (event.which === 13 || event.which === 39) {
// right arrow
if (this.hasNext) this.next();
} else if (event.which === 37) {
// left arrow
if (this.hasPrevious) this.prev();
} else if (event.which === 27) {
// esc
this.close();
2018-02-01 12:17:04 +00:00
}
},
2021-03-21 11:51:58 +00:00
async updatePreview() {
2021-03-26 17:31:27 +00:00
if (
this.$refs.player &&
this.$refs.player.paused &&
!this.$refs.player.ended
) {
this.autoPlay = false;
}
2020-07-14 01:18:53 +00:00
if (this.req.subtitles) {
2021-03-21 11:51:58 +00:00
this.subtitles = this.req.subtitles.map(
(sub) => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`
);
2020-07-14 01:18:53 +00:00
}
2021-03-21 11:51:58 +00:00
let dirs = this.$route.fullPath.split("/");
this.name = decodeURIComponent(dirs[dirs.length - 1]);
2020-07-14 01:18:53 +00:00
if (!this.listing) {
try {
2021-03-21 11:51:58 +00:00
const path = url.removeLastDir(this.$route.path);
const res = await api.fetch(path);
this.listing = res.items;
2020-07-14 01:18:53 +00:00
} catch (e) {
2021-03-21 11:51:58 +00:00
this.$showError(e);
2020-07-14 01:18:53 +00:00
}
}
2021-03-21 11:51:58 +00:00
this.previousLink = "";
this.nextLink = "";
2020-07-14 01:18:53 +00:00
for (let i = 0; i < this.listing.length; i++) {
if (this.listing[i].name !== this.name) {
2021-03-21 11:51:58 +00:00
continue;
2018-02-01 12:17:04 +00:00
}
for (let j = i - 1; j >= 0; j--) {
2020-07-14 01:18:53 +00:00
if (mediaTypes.includes(this.listing[j].type)) {
2021-03-21 11:51:58 +00:00
this.previousLink = this.listing[j].url;
break;
}
}
2018-02-01 12:17:04 +00:00
2020-07-14 01:18:53 +00:00
for (let j = i + 1; j < this.listing.length; j++) {
if (mediaTypes.includes(this.listing[j].type)) {
2021-03-21 11:51:58 +00:00
this.nextLink = this.listing[j].url;
break;
}
}
2018-02-01 12:17:04 +00:00
2021-03-21 11:51:58 +00:00
return;
2018-02-01 12:17:04 +00:00
}
2020-08-18 12:47:23 +00:00
},
2021-03-21 11:51:58 +00:00
openMore() {
this.$store.commit("showHover", "more");
2020-08-18 12:47:23 +00:00
},
2021-03-21 11:51:58 +00:00
resetPrompts() {
this.$store.commit("closeHovers");
2020-08-18 13:08:58 +00:00
},
2021-03-21 11:51:58 +00:00
toggleSize() {
this.fullSize = !this.fullSize;
2021-02-22 16:01:13 +00:00
},
2021-03-21 11:51:58 +00:00
toggleNavigation: throttle(function () {
this.showNav = true;
2021-02-22 16:01:13 +00:00
if (this.navTimeout) {
2021-03-21 11:51:58 +00:00
clearTimeout(this.navTimeout);
2021-02-22 16:01:13 +00:00
}
this.navTimeout = setTimeout(() => {
2021-03-21 11:51:58 +00:00
this.showNav = false || this.hoverNav;
this.navTimeout = null;
2021-02-22 16:01:13 +00:00
}, 1500);
2021-02-25 18:37:07 +00:00
}, 500),
2021-03-21 11:51:58 +00:00
close() {
this.$store.commit("updateRequest", {});
2021-03-01 16:12:17 +00:00
2021-03-21 11:51:58 +00:00
let uri = url.removeLastDir(this.$route.path) + "/";
this.$router.push({ path: uri });
},
download() {
2021-03-21 11:51:58 +00:00
api.download(null, this.$route.path);
},
},
};
2018-02-01 12:17:04 +00:00
</script>