preserve-video-filename (#49)
This should fix issue #40 I have not made the `allowed_characters` configurable yet nor the `replacement_character`. Mostly because I couldn't decide if I should define those "globally" on a server basis, or on the library nodes. Feel free to modify, extend, rip apart. 😁 Reviewed-on: https://git.mills.io/prologic/tube/pulls/49 Co-authored-by: Heinrich 'Henrik' Langos <gumbo2000@noreply@mills.io> Co-committed-by: Heinrich 'Henrik' Langos <gumbo2000@noreply@mills.io>
This commit is contained in:
parent
9952cc533a
commit
19a1141af3
7 changed files with 111 additions and 26 deletions
35
README.md
35
README.md
|
@ -96,14 +96,37 @@ Here are some documentation on key configuration items:
|
|||
"library": [
|
||||
{
|
||||
"path": "videos",
|
||||
"prefix": ""
|
||||
"prefix": "",
|
||||
"preserve_upload_filename": false
|
||||
}
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
Set `path` to the value of the path where you want to store videos and where
|
||||
`tube` will look for new videos.
|
||||
- Set `path` to the value of the path where you want to store videos
|
||||
and where `tube` will watch for new video files to show up.
|
||||
- Set `prefix` to add a directory component in the video URL.
|
||||
- Set the (optional) `preserve_upload_filename` parameter to `true`,
|
||||
to to preserve the name of files that are uploaded to this location.
|
||||
|
||||
You can add more than one location for video files.
|
||||
```#!json
|
||||
{
|
||||
"library": [
|
||||
{
|
||||
"path": "/path/to/cat/videos",
|
||||
"prefix": "cats",
|
||||
"preserve_upload_filename": true
|
||||
},
|
||||
{
|
||||
"path": "relative/dog/directory/",
|
||||
"prefix": "dogs"
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
The path will be visible on the upload page and clients can select a
|
||||
destination for their uploads. Both `prefix` and `path` need to be unique.
|
||||
|
||||
### Server Options / Upload Path and Max Upload Size
|
||||
|
||||
|
@ -114,6 +137,7 @@ Set `path` to the value of the path where you want to store videos and where
|
|||
"port": 8000,
|
||||
"store_path": "tube.db",
|
||||
"upload_path": "uploads",
|
||||
"preserve_upload_filename": false,
|
||||
"max_upload_size": 104857600
|
||||
}
|
||||
}
|
||||
|
@ -129,6 +153,11 @@ Set `path` to the value of the path where you want to store videos and where
|
|||
- Set `upload_path` to a directory that you wish to use as a temporary working
|
||||
space for `tube` to store uploaded videos and process them. This can be a
|
||||
tmpfs file system for example for faster I/O.
|
||||
- Set `preserve_upload_filename` parameter to `true` and tube will try to
|
||||
preserve the filename that was transmitted by the client. The default is
|
||||
to give random filenames to uploaded files.
|
||||
If you set it to `true` in the "server" node, it will be active for all
|
||||
library locations.
|
||||
- Set `max_upload_size` to the maximum number of bytes you wish to impose on
|
||||
uploaded and imported videos. Upload(s)/Import(s) that exceed this size will
|
||||
by denied by the server. This is a saftey measure so as to not DoS the
|
||||
|
|
48
app/app.go
48
app/app.go
|
@ -21,6 +21,7 @@ import (
|
|||
"git.mills.io/prologic/tube/templates"
|
||||
"git.mills.io/prologic/tube/utils"
|
||||
|
||||
"github.com/cyphar/filepath-securejoin"
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/gorilla/handlers"
|
||||
|
@ -150,6 +151,7 @@ func (a *App) Run() error {
|
|||
p := &media.Path{
|
||||
Path: pc.Path,
|
||||
Prefix: pc.Prefix,
|
||||
PreserveUploadFilename: pc.PreserveUploadFilename,
|
||||
}
|
||||
err := a.Library.AddPath(p)
|
||||
if err != nil {
|
||||
|
@ -215,6 +217,11 @@ func (a *App) indexHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func filenameWithoutExtension(path string) (stem string) {
|
||||
var basename string = filepath.Base(path)
|
||||
return basename[0:len(basename)-len(filepath.Ext(basename))]
|
||||
}
|
||||
|
||||
// HTTP handler for /upload
|
||||
func (a *App) uploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "GET" {
|
||||
|
@ -278,10 +285,49 @@ func (a *App) uploadHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
vf := filepath.Join(
|
||||
// Here we set the final filename for the video file after transcoding.
|
||||
var vf string
|
||||
if a.Config.Server.PreserveUploadFilename ||
|
||||
a.Library.Paths[targetLibraryPath].PreserveUploadFilename {
|
||||
vf, err = securejoin.SecureJoin(
|
||||
a.Library.Paths[targetLibraryPath].Path,
|
||||
fmt.Sprintf("%s.mp4", filenameWithoutExtension(handler.Filename)),
|
||||
)
|
||||
} else {
|
||||
vf, err = securejoin.SecureJoin(
|
||||
a.Library.Paths[targetLibraryPath].Path,
|
||||
fmt.Sprintf("%s.mp4", shortuuid.New()),
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error creating file name in target library: %w", err)
|
||||
log.Error(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// If the (sanitized) original filename collides with an existing file,
|
||||
// we try to add a shortuuid() to it until we find one that doesn't exist.
|
||||
for _, err := os.Stat(vf) ; ! os.IsNotExist(err) ; _, err = os.Stat(vf) {
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Warn("File '"+ vf + "' already exists.");
|
||||
vf, err = securejoin.SecureJoin(
|
||||
a.Library.Paths[targetLibraryPath].Path,
|
||||
fmt.Sprintf("%s_%s.mp4", filenameWithoutExtension(vf), shortuuid.New()),
|
||||
)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error creating file name in target library: %w", err)
|
||||
log.Error(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Warn("Using filename '" + vf + "' instead.");
|
||||
}
|
||||
|
||||
|
||||
thumbFn1 := fmt.Sprintf("%s.jpg", strings.TrimSuffix(tf.Name(), filepath.Ext(tf.Name())))
|
||||
thumbFn2 := fmt.Sprintf("%s.jpg", strings.TrimSuffix(vf, filepath.Ext(vf)))
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ type Config struct {
|
|||
type PathConfig struct {
|
||||
Path string `json:"path"`
|
||||
Prefix string `json:"prefix"`
|
||||
PreserveUploadFilename bool `json:"preserve_upload_filename,omitempty"`
|
||||
}
|
||||
|
||||
// ServerConfig settings for App Server.
|
||||
|
@ -27,6 +28,7 @@ type ServerConfig struct {
|
|||
Port int `json:"port"`
|
||||
StorePath string `json:"store_path"`
|
||||
UploadPath string `json:"upload_path"`
|
||||
PreserveUploadFilename bool `json:"preserve_upload_filename,omitempty"`
|
||||
MaxUploadSize int64 `json:"max_upload_size"`
|
||||
}
|
||||
|
||||
|
@ -70,6 +72,7 @@ func DefaultConfig() *Config {
|
|||
&PathConfig{
|
||||
Path: "videos",
|
||||
Prefix: "",
|
||||
PreserveUploadFilename: false,
|
||||
},
|
||||
},
|
||||
Server: &ServerConfig{
|
||||
|
@ -77,6 +80,7 @@ func DefaultConfig() *Config {
|
|||
Port: 8000,
|
||||
StorePath: "tube.db",
|
||||
UploadPath: "uploads",
|
||||
PreserveUploadFilename: false,
|
||||
MaxUploadSize: 104857600,
|
||||
},
|
||||
Thumbnailer: &ThumbnailerConfig{
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
"library": [
|
||||
{
|
||||
"path": "videos",
|
||||
"prefix": ""
|
||||
"prefix": "",
|
||||
"preserve_upload_filename": false
|
||||
}
|
||||
],
|
||||
"server": {
|
||||
|
@ -10,6 +11,7 @@
|
|||
"port": 8000,
|
||||
"store_path": "tube.db",
|
||||
"upload_path": "uploads",
|
||||
"preserve_upload_filename": false,
|
||||
"max_upload_size": 104857600
|
||||
},
|
||||
"thumbnailer": {
|
||||
|
|
1
go.mod
1
go.mod
|
@ -22,6 +22,7 @@ require (
|
|||
github.com/abcum/lcp v0.0.0-20201209214815-7a3f3840be81 // indirect
|
||||
github.com/antchfx/jsonquery v1.3.0 // indirect
|
||||
github.com/antchfx/xpath v1.2.1 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -85,6 +85,8 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
|
|||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
|
|
@ -4,4 +4,5 @@ package media
|
|||
type Path struct {
|
||||
Path string
|
||||
Prefix string
|
||||
PreserveUploadFilename bool
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue