diff --git a/pixelapi/misc.go b/pixelapi/misc.go index 1ca41f4..9a66b5b 100644 --- a/pixelapi/misc.go +++ b/pixelapi/misc.go @@ -8,9 +8,12 @@ type Recaptcha struct { // GetRecaptcha gets the reCaptcha site key from the pixelapi server. If // reCaptcha is disabled the key will be empty func (p *PixelAPI) GetRecaptcha() (resp Recaptcha, err error) { - err = p.jsonRequest("GET", p.apiEndpoint+"/misc/recaptcha", &resp) - if err != nil { - return resp, err - } - return resp, nil + return resp, p.jsonRequest("GET", p.apiEndpoint+"/misc/recaptcha", &resp) +} + +// GetMiscViewToken requests a viewtoken from the server. The viewtoken is valid +// for a limited amount of time and can be used to add views to a file. +// Viewtokens can only be requested from localhost +func (p *PixelAPI) GetMiscViewToken() (resp string, err error) { + return resp, p.jsonRequest("GET", p.apiEndpoint+"/misc/viewtoken", &resp) } diff --git a/res/include/script/file_viewer/ListNavigator.js b/res/include/script/file_viewer/ListNavigator.js index 66aaa16..c64c4d1 100644 --- a/res/include/script/file_viewer/ListNavigator.js +++ b/res/include/script/file_viewer/ListNavigator.js @@ -83,7 +83,7 @@ class ListNavigator { do { rand = Math.round(Math.random() * ln.length); console.log("rand is " + rand); - } while(ln.history.indexOf(index) > -1); + } while(ln.history.indexOf(rand) > -1); ln.setItem(rand); } diff --git a/res/include/script/file_viewer/Viewer.js b/res/include/script/file_viewer/Viewer.js index a0602cd..7a9196a 100644 --- a/res/include/script/file_viewer/Viewer.js +++ b/res/include/script/file_viewer/Viewer.js @@ -9,15 +9,17 @@ class Viewer { currentFile = ""; title = ""; // Contains either the file name or list title listId = ""; + viewToken = ""; isList = false; isFile = false; initialized = false; - constructor(type, data) {let v = this; + constructor(type, viewToken, data) {let v = this; if(v.initialized){ return; } + v.viewToken = viewToken; v.toolbar = new Toolbar(v); v.detailsWindow = new DetailsWindow(v); @@ -72,32 +74,52 @@ class Viewer { // Update the file details v.detailsWindow.setDetails(file); + // Register a new view. We don't care what this returns becasue we can't + // do anything about it anyway + fetch(apiEndpoint+"/file/"+file.id+"/view", + { + method: "POST", + headers: {"Content-Type": "application/x-www-form-urlencoded"}, + body: "token="+v.viewToken + } + ); + // Clear the canvas v.divFilepreview.innerHTML = ""; - if (file.mime_type.startsWith("image")) { + let nextItem = () => { + if (v.listNavigator !== null) { + v.listNavigator.nextItem(); + } + }; + + if ( + file.mime_type.startsWith("image") + ) { new ImageViewer(v, file).render(v.divFilepreview); - } else if (file.mime_type.startsWith("video")) { - new VideoViewer(v, file, () => { - if (v.listNavigator !== null) { - v.listNavigator.nextItem(); - } - }).render(v.divFilepreview); - } else if (file.mime_type.startsWith("audio") || file.mime_type === "application/ogg") { - new AudioViewer(v, file, () => { - if (v.listNavigator !== null) { - v.listNavigator.nextItem(); - } - }).render(v.divFilepreview); + } else if ( + file.mime_type.startsWith("video") || + file.mime_type === "application/matroska" || + file.mime_type === "application/x-matroska" + ) { + new VideoViewer(v, file, nextItem).render(v.divFilepreview); + } else if ( + file.mime_type.startsWith("audio") || + file.mime_type === "application/ogg" + ) { + new AudioViewer(v, file, nextItem).render(v.divFilepreview); + } else if ( + file.mime_type === "application/pdf" || + file.mime_type === "application/x-pdf" + ) { + new PDFViewer(v, file).render(v.divFilepreview); + } else if ( + file.mime_type.startsWith("text") || + file.id === "demo" + ) { + new TextViewer(v, file).render(v.divFilepreview); } else { - fetch("/u/"+file.id+"/preview").then(resp => { - if (!resp.ok) { return Promise.reject(resp.status); } - return resp.text(); - }).then(resp => { - v.divFilepreview.innerHTML = resp; - }).catch(err => { - v.divFilepreview.innerText = "Error loading file: "+err; - }); + new FileViewer(v, file).render(v.divFilepreview); } } diff --git a/res/include/script/file_viewer/viewer_scripts/AudioViewer.js b/res/include/script/file_viewer/viewer_scripts/AudioViewer.js index e2af0fa..9b3d26f 100644 --- a/res/include/script/file_viewer/viewer_scripts/AudioViewer.js +++ b/res/include/script/file_viewer/viewer_scripts/AudioViewer.js @@ -8,37 +8,37 @@ class AudioViewer { element = null; source = null; - constructor(viewer, file, next) {let av = this; - av.viewer = viewer; - av.file = file; - av.next = next; + constructor(viewer, file, next) {let v = this; + v.viewer = viewer; + v.file = file; + v.next = next; - av.container = document.createElement("div"); - av.container.classList = "image-container"; - av.container.appendChild(document.createElement("br")); + v.container = document.createElement("div"); + v.container.classList = "image-container"; + v.container.appendChild(document.createElement("br")); - av.icon = document.createElement("img"); - av.icon.src = "/res/img/mime/audio.png"; - av.container.appendChild(av.icon); + v.icon = document.createElement("img"); + v.icon.src = "/res/img/mime/audio.png"; + v.container.appendChild(v.icon); - av.container.appendChild(document.createElement("br")); - av.container.appendChild(document.createTextNode(file.name)); - av.container.appendChild(document.createElement("br")); - av.container.appendChild(document.createElement("br")); + v.container.appendChild(document.createElement("br")); + v.container.appendChild(document.createTextNode(file.name)); + v.container.appendChild(document.createElement("br")); + v.container.appendChild(document.createElement("br")); - av.element = document.createElement("audio"); - av.element.autoplay = "autoplay"; - av.element.controls = "controls"; - av.element.style.width = "90%"; - av.element.addEventListener("ended", () => { av.next(); }, false); + v.element = document.createElement("audio"); + v.element.autoplay = "autoplay"; + v.element.controls = "controls"; + v.element.style.width = "90%"; + v.element.addEventListener("ended", () => { v.next(); }, false); - av.source = document.createElement("source"); - av.source.src = apiEndpoint+"/file/"+av.file.id; - av.element.appendChild(av.source); - av.container.appendChild(av.element); + v.source = document.createElement("source"); + v.source.src = apiEndpoint+"/file/"+v.file.id; + v.element.appendChild(v.source); + v.container.appendChild(v.element); } - render(parent) {let av = this; - parent.appendChild(av.container); + render(parent) {let v = this; + parent.appendChild(v.container); } } diff --git a/res/include/script/file_viewer/viewer_scripts/FileViewer.js b/res/include/script/file_viewer/viewer_scripts/FileViewer.js new file mode 100644 index 0000000..c4b316a --- /dev/null +++ b/res/include/script/file_viewer/viewer_scripts/FileViewer.js @@ -0,0 +1,35 @@ +class FileViewer { + viewer = null; + file = null; + + container = null; + icon = null; + + constructor(viewer, file, next) {let v = this; + v.viewer = viewer; + v.file = file; + v.next = next; + + v.container = document.createElement("div"); + v.container.classList = "image-container"; + v.container.appendChild(document.createElement("br")); + + v.icon = document.createElement("img"); + v.icon.src = apiEndpoint+"/"+file.thumbnail_href; + v.container.appendChild(v.icon); + + v.container.appendChild(document.createElement("br")); + v.container.appendChild(document.createTextNode(file.name)); + v.container.appendChild(document.createElement("br")); + v.container.appendChild(document.createTextNode("Type: "+file.mime_type)); + v.container.appendChild(document.createElement("br")); + v.container.appendChild(document.createElement("br")); + v.container.appendChild(document.createTextNode( + "Press the 'Download' button in the menu to download this file" + )); + } + + render(parent) {let v = this; + parent.appendChild(v.container); + } +} diff --git a/res/include/script/file_viewer/viewer_scripts/ImageViewer.js b/res/include/script/file_viewer/viewer_scripts/ImageViewer.js index 5bfec0a..6282834 100644 --- a/res/include/script/file_viewer/viewer_scripts/ImageViewer.js +++ b/res/include/script/file_viewer/viewer_scripts/ImageViewer.js @@ -2,54 +2,55 @@ class ImageViewer { viewer = null; file = null; - imgContainer = null; - imgElement = null; + container = null; + element = null; zoomed = false; x = 0; y = 0; dragging = false; - constructor(viewer, file) {let iv = this; - iv.viewer = viewer; - iv.file = file; + constructor(viewer, file) {let v = this; + v.viewer = viewer; + v.file = file; - iv.imgContainer = document.createElement("div"); - iv.imgContainer.classList = "image-container"; + v.container = document.createElement("dv"); + v.container.classList = "image-container"; + // v.container.style.lineHeight = "0"; - iv.imgElement = document.createElement("img"); - iv.imgElement.classList = "pannable drop-shadow"; - iv.imgElement.src = apiEndpoint+"/file/"+iv.file.id; - iv.imgElement.addEventListener("mousedown", (e) => { return iv.mousedown(e); }); - iv.imgElement.addEventListener("dblclick", (e) => { return iv.doubleclick(e); }); - iv.imgElement.addEventListener("doubletap", (e) => { return iv.doubleclick(e); }); - document.addEventListener("mousemove", (e) => { return iv.mousemove(e); }); - document.addEventListener("mouseup", (e) => { return iv.mouseup(e); }); + v.element = document.createElement("img"); + v.element.classList = "pannable center drop-shadow"; + v.element.src = apiEndpoint+"/file/"+v.file.id; + v.element.addEventListener("dblclick", (e) => { return v.doubleclick(e); }); + v.element.addEventListener("doubletap", (e) => { return v.doubleclick(e); }); + v.element.addEventListener("mousedown", (e) => { return v.mousedown(e); }); + document.addEventListener("mousemove", (e) => { return v.mousemove(e); }); + document.addEventListener("mouseup", (e) => { return v.mouseup(e); }); - iv.imgContainer.appendChild(iv.imgElement); + v.container.appendChild(v.element); } - render(parent) {let iv = this; - parent.appendChild(iv.imgContainer); + render(parent) {let v = this; + parent.appendChild(v.container); } - doubleclick(e) {let iv = this; - if (iv.zoomed) { - iv.imgElement.style.maxWidth = "100%"; - iv.imgElement.style.maxHeight = "100%"; - iv.imgElement.style.top = "50%"; - iv.imgElement.style.left = "auto"; - iv.imgElement.style.transform = "translateY(-50%)"; - iv.imgContainer.style.overflow = "hidden"; - iv.zoomed = false; + doubleclick(e) {let v = this; + if (v.zoomed) { + v.element.style.maxWidth = "100%"; + v.element.style.maxHeight = "100%"; + v.element.style.top = "50%"; + v.element.style.left = "auto"; + v.element.style.transform = "translateY(-50%)"; + v.container.style.overflow = "hidden"; + v.zoomed = false; } else { - iv.imgElement.style.maxWidth = "none"; - iv.imgElement.style.maxHeight = "none"; - iv.imgElement.style.top = "0"; - iv.imgElement.style.left = ""; - iv.imgElement.style.transform = "none"; - iv.imgContainer.style.overflow = "scroll"; - iv.zoomed = true; + v.element.style.maxWidth = "none"; + v.element.style.maxHeight = "none"; + v.element.style.top = "0"; + v.element.style.left = ""; + v.element.style.transform = "none"; + v.container.style.overflow = "scroll"; + v.zoomed = true; } e.preventDefault(); @@ -57,11 +58,11 @@ class ImageViewer { return false; } - mousedown(e) {let iv = this; - if (!iv.dragging && e.which === 1 && iv.zoomed) { - iv.x = e.pageX; - iv.y = e.pageY; - iv.dragging = true; + mousedown(e) {let v = this; + if (!v.dragging && e.which === 1 && v.zoomed) { + v.x = e.pageX; + v.y = e.pageY; + v.dragging = true; e.preventDefault(); e.stopPropagation(); @@ -69,13 +70,13 @@ class ImageViewer { } } - mousemove(e) {let iv = this; - if (iv.dragging) { - iv.imgContainer.scrollLeft = iv.imgContainer.scrollLeft - (e.pageX - iv.x); - iv.imgContainer.scrollTop = iv.imgContainer.scrollTop - (e.pageY - iv.y); + mousemove(e) {let v = this; + if (v.dragging) { + v.container.scrollLeft = v.container.scrollLeft - (e.pageX - v.x); + v.container.scrollTop = v.container.scrollTop - (e.pageY - v.y); - iv.x = e.pageX; - iv.y = e.pageY; + v.x = e.pageX; + v.y = e.pageY; e.preventDefault(); e.stopPropagation(); @@ -84,9 +85,9 @@ class ImageViewer { } - mouseup(e) {let iv = this; - if (iv.dragging) { - iv.dragging = false; + mouseup(e) {let v = this; + if (v.dragging) { + v.dragging = false; e.preventDefault(); e.stopPropagation(); @@ -94,63 +95,3 @@ class ImageViewer { } } } - -// var zoomed = false; -// // When a user clicks the image -// $("#displayImg").on("dblclick doubletap", function (event) { -// if (zoomed) { -// $("#displayImg").css("max-width", "100%"); -// $("#displayImg").css("max-height", "100%"); -// $("#displayImg").css("top", "50%"); -// $("#displayImg").css("left", "auto"); -// $("#displayImg").css("transform", "translateY(-50%)"); -// $(".image-container").css("overflow", "hidden"); -// zoomed = false; -// } else { -// $("#displayImg").css("max-width", "none"); -// $("#displayImg").css("max-height", "none"); -// $("#displayImg").css("transform", "none"); -// $(".pannable").css("top", "0"); -// $(".image-container").css("overflow", "scroll"); -// zoomed = true; -// } - - -// return false; -// }); - -// Image dragging around the screen - -// var drag = { -// x: 0, -// y: 0, -// state: false -// }; - -// $(".pannable").on("mousedown", function (e) { -// if (!drag.state && e.which === 1 && zoomed) { -// drag.x = e.pageX; -// drag.y = e.pageY; -// drag.state = true; - -// return false; -// } -// }); - -// var img = $(".image-container"); - -// $(document).on("mousemove", function (e) { -// if (drag.state) { -// img.scrollLeft(img.scrollLeft() - (e.pageX - drag.x)); -// img.scrollTop(img.scrollTop() - (e.pageY - drag.y)); - -// drag.x = e.pageX; -// drag.y = e.pageY; -// } -// }); - -// $(document).on("mouseup", function () { -// if (drag.state) { -// drag.state = false; -// } -// }); diff --git a/res/include/script/file_viewer/viewer_scripts/PDFViewer.js b/res/include/script/file_viewer/viewer_scripts/PDFViewer.js new file mode 100644 index 0000000..84bdf16 --- /dev/null +++ b/res/include/script/file_viewer/viewer_scripts/PDFViewer.js @@ -0,0 +1,19 @@ +class PDFViewer { + viewer = null; + file = null; + container = null; + + constructor(viewer, file) {let v = this; + v.viewer = viewer; + v.file = file; + + v.container = document.createElement("iframe"); + v.container.classList = "image-container"; + v.container.style.border = "none"; + v.container.src = "/res/misc/pdf-viewer/web/viewer.html?file="+apiEndpoint+"/file/"+file.id; + } + + render(parent) {let v = this; + parent.appendChild(v.container); + } +} diff --git a/res/include/script/file_viewer/viewer_scripts/TextViewer.js b/res/include/script/file_viewer/viewer_scripts/TextViewer.js new file mode 100644 index 0000000..c8acb04 --- /dev/null +++ b/res/include/script/file_viewer/viewer_scripts/TextViewer.js @@ -0,0 +1,63 @@ +class TextViewer { + viewer = null; + file = null; + + container = null; + pre = null; + prettyprint = null; + + constructor(viewer, file) {let v = this; + v.viewer = viewer; + v.file = file; + + v.container = document.createElement("div"); + v.container.classList = "text-container"; + + if (file.name.endsWith(".md") || file.name.endsWith(".markdown") || file.id === "demo") { + v.getMarkdown(); + } else { + v.getText(); + } + } + + getText() {let v = this; + v.pre = document.createElement("pre"); + v.pre.classList = "pre-container prettyprint linenums"; + v.pre.innerText = "Loading..."; + v.container.appendChild(v.pre); + + if (v.file.size > 1<<22) { // File larger than 4 MiB + v.pre.innerText = "File is too large to view online.\nPlease download and view it locally."; + return; + } + + fetch(apiEndpoint+"/file/"+v.file.id).then(resp => { + if (!resp.ok) { return Promise.reject(resp.status); } + return resp.text(); + }).then(resp => { + v.pre.innerText = resp; + + // Load prettyprint script + v.prettyprint = document.createElement("script"); + v.prettyprint.src = "https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?skin=desert"; + v.container.appendChild(v.prettyprint); + }).catch(err => { + v.pre.innerText = "Error loading file: "+err; + }); + } + + getMarkdown() {let v = this; + fetch("/u/"+v.file.id+"/preview").then(resp => { + if (!resp.ok) { return Promise.reject(resp.status); } + return resp.text(); + }).then(resp => { + v.container.innerHTML = resp; + }).catch(err => { + v.container.innerText = "Error loading file: "+err; + }); + } + + render(parent) {let v = this; + parent.appendChild(v.container); + } +} diff --git a/res/include/script/file_viewer/viewer_scripts/VideoViewer.js b/res/include/script/file_viewer/viewer_scripts/VideoViewer.js index 6289d1d..5476a83 100644 --- a/res/include/script/file_viewer/viewer_scripts/VideoViewer.js +++ b/res/include/script/file_viewer/viewer_scripts/VideoViewer.js @@ -7,28 +7,28 @@ class VideoViewer { vidElement = null; videoSource = null; - constructor(viewer, file, next) {let vv = this; - vv.viewer = viewer; - vv.file = file; - vv.next = next; + constructor(viewer, file, next) {let v = this; + v.viewer = viewer; + v.file = file; + v.next = next; - vv.vidContainer = document.createElement("div"); - vv.vidContainer.classList = "image-container"; + v.vidContainer = document.createElement("div"); + v.vidContainer.classList = "image-container"; - vv.vidElement = document.createElement("video"); - vv.vidElement.autoplay = "autoplay"; - vv.vidElement.controls = "controls"; - vv.vidElement.classList = "center drop-shadow"; - vv.vidElement.addEventListener("ended", () => { vv.next(); }, false); + v.vidElement = document.createElement("video"); + v.vidElement.autoplay = "autoplay"; + v.vidElement.controls = "controls"; + v.vidElement.classList = "center drop-shadow"; + v.vidElement.addEventListener("ended", () => { v.next(); }, false); - vv.videoSource = document.createElement("source"); - vv.videoSource.src = apiEndpoint+"/file/"+vv.file.id; + v.videoSource = document.createElement("source"); + v.videoSource.src = apiEndpoint+"/file/"+v.file.id; - vv.vidElement.appendChild(vv.videoSource); - vv.vidContainer.appendChild(vv.vidElement); + v.vidElement.appendChild(v.videoSource); + v.vidContainer.appendChild(v.vidElement); } - render(parent) {let vv = this; - parent.appendChild(vv.vidContainer); + render(parent) {let v = this; + parent.appendChild(v.vidContainer); } } diff --git a/res/include/style/viewer.css b/res/include/style/viewer.css index ab42407..791cd43 100644 --- a/res/include/style/viewer.css +++ b/res/include/style/viewer.css @@ -154,20 +154,13 @@ =====================*/ .image-container{ position: relative; + display: block; height: 100%; width: 100%; text-align: center; overflow: hidden; } -.image{ - position: relative; - display: block; - margin: auto; - max-width: 100%; - max-height: 100%; -} - .text-container{ background: #333 none; position: relative; @@ -184,17 +177,6 @@ overflow: hidden; } -.pannable{ - position: relative; - display: inline-block; - margin: auto; - max-width: 100%; - max-height: 100%; - cursor: move; - top: 50%; - transform: translateY(-50%); -} - .center{ position: relative; display: block; @@ -205,9 +187,8 @@ transform: translateY(-50%); } -.drop-shadow{ - box-shadow: var(--shadow_color) 10px 10px 50px; -} +.pannable{ cursor: move; } +.drop-shadow{ box-shadow: var(--shadow_color) 10px 10px 50px; } /* ======================== || TOOLBAR COMPONENTS || diff --git a/res/template/file_viewer.html b/res/template/file_viewer.html index 9a05587..8d9f498 100644 --- a/res/template/file_viewer.html +++ b/res/template/file_viewer.html @@ -92,7 +92,7 @@
-
{{template "spinner.svg" .}}
+
{{template "spinner.svg" .}}
@@ -163,11 +163,14 @@ {{template `ImageViewer.js`}} {{template `VideoViewer.js`}} {{template `AudioViewer.js`}} + {{template `PDFViewer.js`}} + {{template `TextViewer.js`}} + {{template `FileViewer.js`}} // This info gets filled in on the server side to prevent having to make an API call right after the page loads. // Just to slice another few milliseconds from the load time :) window.addEventListener("load", function(){ - new Viewer('{{.Other.Type}}', {{.Other.APIResponse}}); + new Viewer('{{.Other.Type}}', '{{.Other.ViewToken}}', {{.Other.APIResponse}}); }); diff --git a/webcontroller/file_preview.go b/webcontroller/file_preview.go index ab8c09f..f7c159a 100644 --- a/webcontroller/file_preview.go +++ b/webcontroller/file_preview.go @@ -1,13 +1,9 @@ package webcontroller import ( - "fmt" - "html" "io" "io/ioutil" "net/http" - "net/url" - "path/filepath" "strings" "fornaxian.com/pixeldrain-api/util" @@ -16,7 +12,6 @@ import ( "github.com/microcosm-cc/bluemonday" "github.com/julienschmidt/httprouter" - "github.com/timakin/gonvert" "gopkg.in/russross/blackfriday.v2" ) @@ -57,176 +52,34 @@ func (f filePreview) run(inf *pixelapi.FileInfo) string { f.FileURL = f.APIURL + "/file/" + f.FileInfo.ID f.DownloadURL = f.APIURL + "/file/" + f.FileInfo.ID + "?download" - if strings.HasPrefix(f.FileInfo.MimeType, "image") { - return f.image() - } else if strings.HasPrefix(f.FileInfo.MimeType, "video") { - return f.video() - } else if strings.HasPrefix(f.FileInfo.MimeType, "audio") { - return f.audio() - } else if strings.HasPrefix(f.FileInfo.MimeType, "text") { - if strings.HasSuffix(f.FileInfo.Name, ".md") || strings.HasSuffix(f.FileInfo.Name, ".markdown") { - return f.markdown() - } - return f.text() - } - - switch f.FileInfo.MimeType { - case - "application/ogg": - return f.audio() - case - "application/matroska", - "application/x-matroska": - return f.video() - case - "application/pdf", - "application/x-pdf": - return f.pdf() - case - "application/octet-stream": // Fallback for when mime type not recognized - switch filepath.Ext(f.FileInfo.Name) { - case - ".mp3": - return f.audio() - case - ".mp4": - return f.video() - } + if strings.HasPrefix(f.FileInfo.MimeType, "text") && + (strings.HasSuffix(f.FileInfo.Name, ".md") || strings.HasSuffix(f.FileInfo.Name, ".markdown")) { + return f.markdown() } // none of the mime type checks triggered, so we return the default page - return f.def() -} - -func (f filePreview) image() string { - return fmt.Sprintf(`
- -
-`, - f.FileURL) -} - -func (f filePreview) audio() string { - return fmt.Sprintf(`
-
-Audio -
%s
- -
-`, - f.FileInfo.Name, - f.FileURL, - ) -} - -func (f filePreview) video() string { - return fmt.Sprintf(`
- -
-`, - f.FileURL, - ) - -} - -func (f filePreview) pdf() string { - u, _ := url.Parse(f.FileURL) - return f.frame("/res/misc/pdf-viewer/web/viewer.html?file=" + u.String()) -} - -func (f filePreview) text() string { - htmlOut := `
-
%s
-
` - - if f.FileInfo.Size > 1<<22 { // 4 MiB limit to prevent out of memory errors - return fmt.Sprintf(htmlOut, "", - "File is too large to view online.\nPlease download and view it locally.", - ) - } - - body, err := f.PixelAPI.GetFile(f.FileInfo.ID) - if err != nil { - log.Error("Can't download text file for preview: %s", err) - return fmt.Sprintf(htmlOut, "", - "An error occurred while downloading this file.", - ) - } - defer body.Close() - - bodyBytes, err := ioutil.ReadAll(body) - if err != nil { - log.Error("Can't read text file for preview: %s", err) - return fmt.Sprintf(htmlOut, "", - "An error occurred while reading this file.", - ) - } - - converter := gonvert.New(string(bodyBytes), gonvert.UTF8) - result, err := converter.Convert() - if err != nil { - log.Debug("Unable to decode text file: %s", err) - return fmt.Sprintf(htmlOut, "", - "This file is using an unknown character encoding.\nPlease download it and view it locally.", - ) - } - - htmlOut += `` - - return fmt.Sprintf(htmlOut, "prettyprint linenums", html.EscapeString(result)) + return "" } func (f filePreview) markdown() string { - htmlOut := `
%s
` - if f.FileInfo.Size > 1e6 { // Prevent out of memory errors - return fmt.Sprintf(htmlOut, "", - "File is too large to view online.\nPlease download and view it locally.", - ) + return "File is too large to view online.\nPlease download and view it locally." } body, err := f.PixelAPI.GetFile(f.FileInfo.ID) if err != nil { log.Error("Can't download text file for preview: %s", err) - return fmt.Sprintf(htmlOut, "", - "An error occurred while downloading this file.", - ) + return "An error occurred while downloading this file." } defer body.Close() bodyBytes, err := ioutil.ReadAll(body) if err != nil { log.Error("Can't read text file for preview: %s", err) - return fmt.Sprintf(htmlOut, "", - "An error occurred while reading this file.", - ) + return "An error occurred while reading this file." } - md := bluemonday.UGCPolicy().SanitizeBytes(blackfriday.Run(bodyBytes)) - - return fmt.Sprintf(htmlOut, md) -} - -func (f filePreview) frame(url string) string { - return fmt.Sprintf(`