-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support thumbnail image view #980
Changes from 6 commits
bee2ef7
fde88fe
3543eab
07b2302
7b8b91e
223182c
81c412e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,8 +86,15 @@ export default { | |
download () { | ||
return `${baseURL}/api/raw${this.req.path}?auth=${this.jwt}` | ||
}, | ||
thumbnail () { | ||
if (this.req.type === 'image') { | ||
return `${baseURL}/api/preview/big${this.req.path}?auth=${this.jwt}` | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. else is redundant |
||
return `${baseURL}/api/raw${this.req.path}?auth=${this.jwt}` | ||
} | ||
}, | ||
raw () { | ||
return `${this.download}&inline=true` | ||
return `${this.thumbnail}&inline=true` | ||
} | ||
}, | ||
async mounted () { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package http | ||
|
||
import ( | ||
"fmt" | ||
"image" | ||
"net/http" | ||
|
||
"github.com/disintegration/imaging" | ||
"github.com/gorilla/mux" | ||
|
||
"github.com/filebrowser/filebrowser/v2/files" | ||
) | ||
|
||
const ( | ||
sizeThumb = "thumb" | ||
sizeBig = "big" | ||
) | ||
|
||
type imageProcessor func(src image.Image) (image.Image, error) | ||
|
||
var previewHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { | ||
if !d.user.Perm.Download { | ||
return http.StatusAccepted, nil | ||
} | ||
vars := mux.Vars(r) | ||
size := vars["size"] | ||
if size != sizeBig && size != sizeThumb { | ||
o1egl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return http.StatusNotImplemented, nil | ||
} | ||
|
||
file, err := files.NewFileInfo(files.FileOptions{ | ||
Fs: d.user.Fs, | ||
Path: "/" + vars["path"], | ||
Modify: d.user.Perm.Modify, | ||
Expand: true, | ||
Checker: d, | ||
}) | ||
if err != nil { | ||
return errToStatus(err), err | ||
} | ||
|
||
setContentDisposition(w, r, file) | ||
|
||
switch file.Type { | ||
case "image": | ||
return handleImagePreview(w, r, file, size) | ||
default: | ||
return http.StatusNotImplemented, fmt.Errorf("can't create preview for %s type", file.Type) | ||
} | ||
}) | ||
|
||
func handleImagePreview(w http.ResponseWriter, r *http.Request, file *files.FileInfo, size string) (int, error) { | ||
// Unsupported extensions directly return the raw data | ||
if file.Extension == ".ico" || file.Extension == ".svg" { | ||
return rawFileHandler(w, r, file) | ||
} | ||
|
||
var imgProcessor imageProcessor | ||
switch size { | ||
case sizeBig: | ||
imgProcessor = func(img image.Image) (image.Image, error) { | ||
return imaging.Fit(img, 1080, 1080, imaging.Lanczos), nil | ||
} | ||
case sizeThumb: | ||
imgProcessor = func(img image.Image) (image.Image, error) { | ||
return imaging.Thumbnail(img, 128, 128, imaging.Box), nil | ||
} | ||
default: | ||
return http.StatusBadRequest, fmt.Errorf("unsupported preview size %s", size) | ||
} | ||
|
||
fd, err := file.Fs.Open(file.Path) | ||
if err != nil { | ||
return errToStatus(err), err | ||
} | ||
defer fd.Close() | ||
format, err := imaging.FormatFromExtension(file.Extension) | ||
if err != nil { | ||
return http.StatusNotImplemented, err | ||
} | ||
img, err := imaging.Decode(fd, imaging.AutoOrientation(true)) | ||
if err != nil { | ||
return errToStatus(err), err | ||
} | ||
img, err = imgProcessor(img) | ||
if err != nil { | ||
return errToStatus(err), err | ||
} | ||
if imaging.Encode(w, img, format) != nil { | ||
return errToStatus(err), err | ||
} | ||
return 0, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,7 +22,7 @@ func parseQueryFiles(r *http.Request, f *files.FileInfo, _ *users.User) ([]strin | |
fileSlice = append(fileSlice, f.Path) | ||
} else { | ||
for _, name := range names { | ||
name, err := url.QueryUnescape(strings.Replace(name, "+", "%2B", -1)) //nolint:shadow | ||
name, err := url.QueryUnescape(strings.Replace(name, "+", "%2B", -1)) // nolint:shadow | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this change is not correct. there should not be a space in nolint comment |
||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -35,7 +35,7 @@ func parseQueryFiles(r *http.Request, f *files.FileInfo, _ *users.User) ([]strin | |
return fileSlice, nil | ||
} | ||
|
||
//nolint: goconst | ||
// nolint: goconst | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same |
||
func parseQueryAlgorithm(r *http.Request) (string, archiver.Writer, error) { | ||
// TODO: use enum | ||
switch r.URL.Query().Get("algo") { | ||
|
@@ -58,6 +58,15 @@ func parseQueryAlgorithm(r *http.Request) (string, archiver.Writer, error) { | |
} | ||
} | ||
|
||
func setContentDisposition(w http.ResponseWriter, r *http.Request, file *files.FileInfo) { | ||
if r.URL.Query().Get("inline") == "true" { | ||
w.Header().Set("Content-Disposition", "inline") | ||
} else { | ||
// As per RFC6266 section 4.3 | ||
w.Header().Set("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(file.Name)) | ||
} | ||
} | ||
|
||
var rawHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { | ||
if !d.user.Perm.Download { | ||
return http.StatusAccepted, nil | ||
|
@@ -168,12 +177,7 @@ func rawFileHandler(w http.ResponseWriter, r *http.Request, file *files.FileInfo | |
} | ||
defer fd.Close() | ||
|
||
if r.URL.Query().Get("inline") == "true" { | ||
w.Header().Set("Content-Disposition", "inline") | ||
} else { | ||
// As per RFC6266 section 4.3 | ||
w.Header().Set("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(file.Name)) | ||
} | ||
setContentDisposition(w, r, file) | ||
|
||
http.ServeContent(w, r, file.Name, file.ModTime, fd) | ||
return 0, nil | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.