2020-01-28 12:51:21 +01:00
|
|
|
function Viewer(type, viewToken, data) {
|
2020-01-27 16:56:16 +01:00
|
|
|
// Set defaults
|
2021-02-23 16:50:13 +01:00
|
|
|
this.toolbar = null
|
|
|
|
this.listNavigator = null
|
|
|
|
this.detailsWindow = null
|
2020-02-04 19:37:46 +01:00
|
|
|
this.divFilepreview = null
|
2021-02-23 16:50:13 +01:00
|
|
|
this.file = null
|
|
|
|
this.title = "" // Contains either the file name or list title
|
|
|
|
this.listId = ""
|
|
|
|
this.viewToken = viewToken
|
|
|
|
this.isList = false
|
|
|
|
this.isFile = false
|
|
|
|
this.initialized = false
|
|
|
|
this.viewerScript = null
|
2021-03-16 15:52:09 +01:00
|
|
|
this.fullscreen = false
|
2020-02-04 19:37:46 +01:00
|
|
|
|
2021-02-23 16:50:13 +01:00
|
|
|
this.toolbar = new Toolbar(this)
|
2020-02-04 19:37:46 +01:00
|
|
|
this.detailsWindow = new DetailsWindow(this)
|
2021-02-23 16:50:13 +01:00
|
|
|
this.editWindow = new EditWindow()
|
2020-02-04 19:37:46 +01:00
|
|
|
|
|
|
|
this.divFilepreview = document.getElementById("filepreview")
|
2020-01-27 16:56:16 +01:00
|
|
|
|
|
|
|
// On small screens the toolbar takes too much space, so it collapses
|
|
|
|
// automatically
|
2020-11-26 11:13:27 +01:00
|
|
|
if (this.divFilepreview.clientWidth > 600 && !this.toolbar.visible) {
|
2020-02-04 19:37:46 +01:00
|
|
|
this.toolbar.toggle()
|
2020-01-27 16:56:16 +01:00
|
|
|
}
|
2020-01-20 19:55:51 +01:00
|
|
|
|
2021-03-10 20:13:32 +01:00
|
|
|
if (embeddedViewer) {
|
|
|
|
// Remove padding from the headerbar
|
|
|
|
document.getElementById("file_viewer_headerbar").classList += " file_viewer_headerbar_embedded"
|
|
|
|
|
|
|
|
// Hide toolbar by default
|
|
|
|
if (this.toolbar.visible) {
|
|
|
|
this.toolbar.toggle()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Alter home button to open in a new tab
|
|
|
|
document.getElementById("button_home").setAttribute("target", "_blank")
|
|
|
|
|
|
|
|
// Remove sponsor bar if ads are disabled
|
|
|
|
if (!data.show_ads) {
|
|
|
|
document.getElementById("sponsors").remove()
|
|
|
|
}
|
2021-03-16 15:52:09 +01:00
|
|
|
|
|
|
|
// Show fullscreen button if this browser supports it
|
|
|
|
if (document.documentElement.requestFullscreen) {
|
|
|
|
let btnFullscreen = document.getElementById("btn_fullscreen")
|
|
|
|
btnFullscreen.style.display = ""
|
|
|
|
btnFullscreen.addEventListener("click", () => { this.toggleFullscreen() })
|
|
|
|
}
|
2021-03-10 20:13:32 +01:00
|
|
|
}
|
|
|
|
|
2020-01-27 16:56:16 +01:00
|
|
|
if (type === "file") {
|
2020-02-04 19:37:46 +01:00
|
|
|
this.isFile = true
|
|
|
|
this.title = data.name
|
|
|
|
this.setFile(fileFromAPIResp(data))
|
2020-01-27 16:56:16 +01:00
|
|
|
} else if (type === "list") {
|
2020-02-04 19:37:46 +01:00
|
|
|
this.isList = true
|
|
|
|
this.listId = data.id
|
|
|
|
this.title = data.title
|
|
|
|
|
|
|
|
let files = []
|
|
|
|
for (let i in data.files) {
|
|
|
|
files.push(fileFromAPIResp(data.files[i]))
|
|
|
|
}
|
|
|
|
this.listNavigator = new ListNavigator(this, files)
|
|
|
|
} else if (type === "skylink") {
|
|
|
|
this.isFile = true
|
|
|
|
this.title = data.name
|
|
|
|
document.getElementById("btn_details").remove()
|
|
|
|
document.getElementById("stat_views_label").remove()
|
|
|
|
document.getElementById("stat_views").remove()
|
|
|
|
document.getElementById("stat_downloads_label").remove()
|
|
|
|
document.getElementById("stat_downloads").remove()
|
2020-02-04 22:29:48 +01:00
|
|
|
this.setFile(fileFromSkyNet(data))
|
2020-01-27 16:56:16 +01:00
|
|
|
}
|
|
|
|
|
2021-03-16 15:52:09 +01:00
|
|
|
this.embedWindow = new EmbedWindow(this)
|
2021-05-11 16:14:16 +02:00
|
|
|
this.abuseReportWindow = new AbuseReportWindow(this)
|
2021-03-16 15:52:09 +01:00
|
|
|
|
2021-03-16 17:19:03 +01:00
|
|
|
if (userAuthenticated && !this.file.can_edit) {
|
|
|
|
let btnGrab = document.getElementById("btn_grab")
|
|
|
|
btnGrab.style.display = ""
|
|
|
|
btnGrab.addEventListener("click", () => { this.grabFile() })
|
|
|
|
}
|
|
|
|
|
2020-05-24 14:23:03 +02:00
|
|
|
this.renderSponsors()
|
|
|
|
window.addEventListener("resize", e => { this.renderSponsors() })
|
2020-01-20 19:55:51 +01:00
|
|
|
|
2020-01-27 16:56:16 +01:00
|
|
|
// Register keyboard shortcuts
|
2020-02-04 19:37:46 +01:00
|
|
|
document.addEventListener("keydown", e => { this.keyboardEvent(e) })
|
2020-01-20 19:55:51 +01:00
|
|
|
|
2020-02-04 19:37:46 +01:00
|
|
|
this.initialized = true
|
2020-01-27 16:56:16 +01:00
|
|
|
}
|
2020-01-20 19:55:51 +01:00
|
|
|
|
2021-02-23 16:50:13 +01:00
|
|
|
Viewer.prototype.getFile = function () {
|
2020-02-18 14:57:27 +01:00
|
|
|
return this.file
|
|
|
|
}
|
|
|
|
|
2021-02-23 16:50:13 +01:00
|
|
|
Viewer.prototype.setFile = function (file) {
|
2020-02-18 14:57:27 +01:00
|
|
|
this.file = file
|
|
|
|
|
2020-01-28 12:51:21 +01:00
|
|
|
if (this.isList) {
|
2020-02-04 19:37:46 +01:00
|
|
|
document.getElementById("file_viewer_list_title").innerText = this.title
|
|
|
|
document.getElementById("file_viewer_file_title").innerText = file.name
|
|
|
|
document.title = this.title + " ~ " + file.name + " ~ pixeldrain"
|
2020-01-27 16:56:16 +01:00
|
|
|
} else {
|
2020-02-04 19:37:46 +01:00
|
|
|
document.getElementById("file_viewer_file_title").innerText = file.name
|
|
|
|
document.title = file.name + " ~ pixeldrain"
|
2020-01-20 19:55:51 +01:00
|
|
|
}
|
|
|
|
|
2020-02-05 16:52:55 +01:00
|
|
|
// Relay the file change event to all components
|
|
|
|
this.detailsWindow.setFile(file)
|
2020-02-18 14:57:27 +01:00
|
|
|
this.editWindow.setFile(file)
|
2020-02-04 19:37:46 +01:00
|
|
|
this.toolbar.setFile(file)
|
2020-01-27 16:56:16 +01:00
|
|
|
|
|
|
|
// Register a new view. We don't care what this returns becasue we can't
|
|
|
|
// do anything about it anyway
|
2020-02-04 19:37:46 +01:00
|
|
|
if (file.view_href !== "") {
|
|
|
|
fetch(file.view_href, {
|
2021-02-23 16:50:13 +01:00
|
|
|
method: "POST",
|
|
|
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
|
|
body: "token=" + this.viewToken
|
|
|
|
})
|
2020-02-04 19:37:46 +01:00
|
|
|
}
|
2020-01-20 19:55:51 +01:00
|
|
|
|
2020-08-02 17:52:25 +02:00
|
|
|
// Clean up the previous viewer if possible
|
|
|
|
if (this.viewerScript !== null && typeof this.viewerScript.destroy === "function") {
|
|
|
|
this.viewerScript.destroy()
|
|
|
|
}
|
|
|
|
|
2020-01-27 16:56:16 +01:00
|
|
|
// Clear the canvas
|
2020-02-04 19:37:46 +01:00
|
|
|
this.divFilepreview.innerHTML = ""
|
2020-01-27 16:56:16 +01:00
|
|
|
|
2020-08-02 17:52:25 +02:00
|
|
|
// This function can be used by the viewer scripts to navigate to the next
|
|
|
|
// file when a songs has ended for example
|
2020-01-27 16:56:16 +01:00
|
|
|
let nextItem = () => {
|
2020-01-28 12:51:21 +01:00
|
|
|
if (this.listNavigator !== null) {
|
2020-02-04 19:37:46 +01:00
|
|
|
this.listNavigator.nextItem()
|
2020-01-20 19:55:51 +01:00
|
|
|
}
|
2020-02-04 19:37:46 +01:00
|
|
|
}
|
2020-01-27 16:56:16 +01:00
|
|
|
|
2020-08-02 17:52:25 +02:00
|
|
|
if (file.abuse_type !== "") {
|
2021-02-23 16:50:13 +01:00
|
|
|
this.viewerScript = new AbuseViewer(this, file)
|
|
|
|
} else if (file.mime_type.startsWith("image")) {
|
2020-08-02 17:52:25 +02:00
|
|
|
this.viewerScript = new ImageViewer(this, file)
|
2020-01-27 16:56:16 +01:00
|
|
|
} else if (
|
|
|
|
file.mime_type.startsWith("video") ||
|
|
|
|
file.mime_type === "application/matroska" ||
|
|
|
|
file.mime_type === "application/x-matroska"
|
|
|
|
) {
|
2020-08-02 17:52:25 +02:00
|
|
|
this.viewerScript = new VideoViewer(this, file, nextItem)
|
2020-01-27 16:56:16 +01:00
|
|
|
} else if (
|
|
|
|
file.mime_type.startsWith("audio") ||
|
|
|
|
file.mime_type === "application/ogg" ||
|
|
|
|
file.name.endsWith(".mp3")
|
|
|
|
) {
|
2020-08-02 17:52:25 +02:00
|
|
|
this.viewerScript = new AudioViewer(this, file, nextItem)
|
2020-01-27 16:56:16 +01:00
|
|
|
} else if (
|
|
|
|
file.mime_type === "application/pdf" ||
|
|
|
|
file.mime_type === "application/x-pdf"
|
|
|
|
) {
|
2020-08-02 17:52:25 +02:00
|
|
|
this.viewerScript = new PDFViewer(this, file)
|
2020-01-27 16:56:16 +01:00
|
|
|
} else if (
|
|
|
|
file.mime_type.startsWith("text") ||
|
|
|
|
file.id === "demo"
|
|
|
|
) {
|
2020-08-02 17:52:25 +02:00
|
|
|
this.viewerScript = new TextViewer(this, file)
|
2020-01-27 16:56:16 +01:00
|
|
|
} else {
|
2020-08-02 17:52:25 +02:00
|
|
|
this.viewerScript = new FileViewer(this, file)
|
2020-01-20 19:55:51 +01:00
|
|
|
}
|
2020-08-02 17:52:25 +02:00
|
|
|
|
|
|
|
this.viewerScript.render(this.divFilepreview)
|
2020-01-27 16:56:16 +01:00
|
|
|
}
|
2020-01-20 19:55:51 +01:00
|
|
|
|
2021-02-23 16:50:13 +01:00
|
|
|
Viewer.prototype.renderSponsors = function () {
|
2020-06-07 22:39:23 +02:00
|
|
|
// Check if the ad is enabled
|
|
|
|
if (document.querySelector(".sponsors_banner") == null) { return }
|
|
|
|
|
2021-02-23 16:50:13 +01:00
|
|
|
let scaleWidth = 1
|
|
|
|
let scaleHeight = 1
|
2020-05-24 14:23:03 +02:00
|
|
|
let minWindowHeight = 800
|
2021-02-23 16:50:13 +01:00
|
|
|
let bannerWidth = document.querySelector(".sponsors_banner").offsetWidth
|
|
|
|
let bannerHeight = document.querySelector(".sponsors_banner").offsetHeight
|
2020-02-28 14:59:53 +01:00
|
|
|
|
|
|
|
if (window.innerWidth < bannerWidth) {
|
2021-02-23 16:50:13 +01:00
|
|
|
scaleWidth = window.innerWidth / bannerWidth
|
2020-02-21 13:14:21 +01:00
|
|
|
}
|
2020-02-28 14:59:53 +01:00
|
|
|
if (window.innerHeight < minWindowHeight) {
|
2021-02-23 16:50:13 +01:00
|
|
|
scaleHeight = window.innerHeight / minWindowHeight
|
2020-02-21 13:14:21 +01:00
|
|
|
}
|
2020-04-14 16:00:24 +02:00
|
|
|
|
2020-05-24 14:23:03 +02:00
|
|
|
// The smaller scale is the scale we'll use
|
2020-02-28 14:59:53 +01:00
|
|
|
let scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight
|
2020-02-21 13:14:21 +01:00
|
|
|
|
2020-05-24 14:23:03 +02:00
|
|
|
// Because of the scale transformation the automatic margins don't work
|
|
|
|
// anymore. So we have to manually calculate the margin. Here we take the
|
|
|
|
// width of the viewport - the width of the ad to calculate the amount of
|
|
|
|
// pixels around the ad. We multiply the ad size by the scale we calcualted
|
|
|
|
// to account for the smaller size.
|
2021-02-23 16:50:13 +01:00
|
|
|
let offset = (window.innerWidth - (bannerWidth * scale)) / 2
|
2020-05-24 14:23:03 +02:00
|
|
|
|
2021-02-23 16:50:13 +01:00
|
|
|
document.querySelector(".sponsors").style.height = (bannerHeight * scale) + "px"
|
|
|
|
document.querySelector(".sponsors_banner").style.marginLeft = offset + "px"
|
|
|
|
document.querySelector(".sponsors_banner").style.transform = "scale(" + scale + ")"
|
2020-05-24 14:23:03 +02:00
|
|
|
}
|
2020-01-20 19:55:51 +01:00
|
|
|
|
2021-02-23 16:50:13 +01:00
|
|
|
Viewer.prototype.keyboardEvent = function (evt) {
|
2020-04-14 16:00:24 +02:00
|
|
|
if (evt.ctrlKey || evt.altKey || evt.metaKey) {
|
2020-01-27 16:56:16 +01:00
|
|
|
return // prevent custom shortcuts from interfering with system shortcuts
|
2020-01-20 19:55:51 +01:00
|
|
|
}
|
2021-02-23 16:50:13 +01:00
|
|
|
if (document.activeElement.type && document.activeElement.type === "text") {
|
|
|
|
return // Prevent shortcuts from interfering with input fields
|
|
|
|
}
|
2020-01-20 19:55:51 +01:00
|
|
|
|
2021-02-23 16:50:13 +01:00
|
|
|
console.debug("Key pressed: " + evt.keyCode)
|
2020-01-27 16:56:16 +01:00
|
|
|
switch (evt.keyCode) {
|
2021-02-23 16:50:13 +01:00
|
|
|
case 65: // A or left arrow key go to previous file
|
|
|
|
case 37:
|
|
|
|
if (this.listNavigator != null) {
|
|
|
|
this.listNavigator.previousItem()
|
|
|
|
}
|
|
|
|
break
|
|
|
|
case 68: // D or right arrow key go to next file
|
|
|
|
case 39:
|
|
|
|
if (this.listNavigator != null) {
|
|
|
|
this.listNavigator.nextItem()
|
|
|
|
}
|
|
|
|
break
|
|
|
|
case 83:
|
|
|
|
if (evt.shiftKey) {
|
|
|
|
this.listNavigator.downloadList() // SHIFT + S downloads all files in list
|
|
|
|
} else {
|
|
|
|
this.toolbar.download() // S to download the current file
|
|
|
|
}
|
|
|
|
break
|
|
|
|
case 82: // R to toggle list shuffle
|
|
|
|
if (this.listNavigator != null) {
|
|
|
|
this.listNavigator.toggleShuffle()
|
|
|
|
}
|
|
|
|
break
|
|
|
|
case 67: // C to copy to clipboard
|
|
|
|
this.toolbar.copyUrl()
|
|
|
|
break
|
|
|
|
case 73: // I to open the details window
|
|
|
|
this.detailsWindow.toggle()
|
|
|
|
break
|
|
|
|
case 69: // E to open the edit window
|
|
|
|
this.editWindow.toggle()
|
|
|
|
break
|
2021-03-16 15:52:09 +01:00
|
|
|
case 77: // M to open the embed window
|
|
|
|
this.embedWindow.toggle()
|
|
|
|
break
|
2021-03-16 17:19:03 +01:00
|
|
|
case 71: // G to grab this file
|
|
|
|
this.grabFile()
|
|
|
|
break
|
2021-02-23 16:50:13 +01:00
|
|
|
case 81: // Q to close the window
|
|
|
|
window.close()
|
|
|
|
break
|
2020-01-20 19:55:51 +01:00
|
|
|
}
|
2020-01-27 16:56:16 +01:00
|
|
|
}
|
|
|
|
|
2021-03-16 15:52:09 +01:00
|
|
|
Viewer.prototype.toggleFullscreen = function () {
|
|
|
|
if (!this.fullscreen) {
|
|
|
|
document.documentElement.requestFullscreen()
|
|
|
|
document.getElementById("btn_fullscreen_icon").innerText = "fullscreen_exit"
|
|
|
|
this.fullscreen = true
|
|
|
|
} else {
|
|
|
|
document.exitFullscreen()
|
|
|
|
document.getElementById("btn_fullscreen_icon").innerText = "fullscreen"
|
|
|
|
this.fullscreen = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-16 17:19:03 +01:00
|
|
|
Viewer.prototype.grabFile = async function () {
|
|
|
|
if (!userAuthenticated || this.file.can_edit) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
const form = new FormData()
|
|
|
|
form.append("grab_file", this.file.id)
|
|
|
|
console.log(this.file.id)
|
|
|
|
|
|
|
|
try {
|
|
|
|
const resp = await fetch(apiEndpoint + "/file", { method: "POST", body: form });
|
|
|
|
if (resp.status >= 400) {
|
|
|
|
throw (await resp.json()).message
|
|
|
|
}
|
|
|
|
|
|
|
|
window.open(domainURL() + "/u/" + (await resp.json()).id, "_blank")
|
|
|
|
} catch (err) {
|
|
|
|
alert("Failed to grab file: " + err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-20 19:55:51 +01:00
|
|
|
|
|
|
|
// Against XSS attacks
|
|
|
|
function escapeHTML(str) {
|
2021-02-23 16:50:13 +01:00
|
|
|
return String(str)
|
2020-01-20 19:55:51 +01:00
|
|
|
.replace(/&/g, '&')
|
|
|
|
.replace(/</g, '<')
|
|
|
|
.replace(/>/g, '>')
|
|
|
|
.replace(/"/g, '"');
|
|
|
|
}
|
2020-02-04 19:37:46 +01:00
|
|
|
|
|
|
|
function fileFromAPIResp(resp) {
|
2021-02-23 16:50:13 +01:00
|
|
|
resp.date_created = new Date(resp.date_upload)
|
|
|
|
resp.date_last_view = new Date(resp.date_last_view)
|
|
|
|
resp.icon_href = apiEndpoint + "/file/" + resp.id + "/thumbnail"
|
|
|
|
resp.get_href = apiEndpoint + "/file/" + resp.id
|
|
|
|
resp.download_href = apiEndpoint + "/file/" + resp.id + "?download"
|
|
|
|
resp.view_href = apiEndpoint + "/file/" + resp.id + "/view"
|
|
|
|
resp.timeseries_href = apiEndpoint + "/file/" + resp.id + "/timeseries"
|
|
|
|
resp.stats_href = apiEndpoint + "/file/" + resp.id + "/stats"
|
|
|
|
resp.link = domainURL() + "/u/" + resp.id
|
2020-02-18 14:57:27 +01:00
|
|
|
if (resp.description === undefined) {
|
|
|
|
resp.description = ""
|
2020-02-04 19:37:46 +01:00
|
|
|
}
|
2020-02-18 14:57:27 +01:00
|
|
|
|
|
|
|
return resp
|
2020-02-04 19:37:46 +01:00
|
|
|
}
|
|
|
|
function fileFromSkyNet(resp) {
|
|
|
|
let file = fileFromAPIResp(resp)
|
2021-02-23 16:50:13 +01:00
|
|
|
file.icon_href = "/res/img/mime/empty.png"
|
|
|
|
file.get_href = "https://siasky.net/file/" + resp.id
|
|
|
|
file.download_href = "https://siasky.net/file/" + resp.id + "?attachment=1"
|
|
|
|
file.view_href = ""
|
|
|
|
file.timeseries_href = ""
|
|
|
|
file.stats_href = ""
|
|
|
|
file.link = domainURL() + "/s/" + resp.id
|
2020-02-04 19:37:46 +01:00
|
|
|
return file
|
|
|
|
}
|