From 299df65290ef028a997bcfed888b2230ee750f36 Mon Sep 17 00:00:00 2001 From: James Mills Date: Fri, 27 Mar 2020 21:04:10 +1000 Subject: [PATCH] Add optional title and description to video upload --- app/app.go | 9 +++++++-- app/rice-box.go | 20 ++++++++++---------- static/theme.css | 14 +++++++++++++- static/upload.js | 6 +++++- templates/upload.html | 2 ++ 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/app/app.go b/app/app.go index bb13895..bf027e8 100644 --- a/app/app.go +++ b/app/app.go @@ -209,6 +209,9 @@ func (a *App) uploadHandler(w http.ResponseWriter, r *http.Request) { } defer file.Close() + title := r.FormValue("video_title") + description := r.FormValue("video_description") + // TODO: Make collection user selectable from drop-down in Form // XXX: Assume we can put uploaded videos into the first collection (sorted) we find keys := make([]string, 0, len(a.Library.Paths)) @@ -266,6 +269,8 @@ func (a *App) uploadHandler(w http.ResponseWriter, r *http.Request) { "-acodec", "aac", "-strict", "-2", "-loglevel", "quiet", + "-metadata", fmt.Sprintf("title=%s", title), + "-metadata", fmt.Sprintf("comment=%s", description), tf.Name(), ); err != nil { err := fmt.Errorf("error transcoding video: %w", err) @@ -413,8 +418,8 @@ func (a *App) importHandler(w http.ResponseWriter, r *http.Request) { "-acodec", "aac", "-strict", "-2", "-loglevel", "quiet", - "-metadata", fmt.Sprintf("title=\"%s\"", vid.Title), - "-metadata", fmt.Sprintf("description=\"%s\"", vid.Description), + "-metadata", fmt.Sprintf("title=%s", vid.Title), + "-metadata", fmt.Sprintf("comment=%s", vid.Description), tf.Name(), ); err != nil { err := fmt.Errorf("error transcoding video: %w", err) diff --git a/app/rice-box.go b/app/rice-box.go index c0f7c2b..a0846dd 100644 --- a/app/rice-box.go +++ b/app/rice-box.go @@ -29,15 +29,15 @@ func init() { } file5 := &embedded.EmbeddedFile{ Filename: "upload.html", - FileModTime: time.Unix(1585279308, 0), + FileModTime: time.Unix(1585305891, 0), - Content: string("{{define \"content\"}}\n
\n \n

Need to import a video from another source? Click Import

\n
\n{{end}}\n{{define \"scripts\"}}\n \n{{end}}\n"), + Content: string("{{define \"content\"}}\n
\n \n

Need to import a video from another source? Click Import

\n
\n{{end}}\n{{define \"scripts\"}}\n \n{{end}}\n"), } // define dirs dir1 := &embedded.EmbeddedDir{ Filename: "", - DirModTime: time.Unix(1585303730, 0), + DirModTime: time.Unix(1585306797, 0), ChildFiles: []*embedded.EmbeddedFile{ file2, // "base.html" file3, // "import.html" @@ -53,7 +53,7 @@ func init() { // register embeddedBox embedded.RegisterEmbeddedBox(`../templates`, &embedded.EmbeddedBox{ Name: `../templates`, - Time: time.Unix(1585303730, 0), + Time: time.Unix(1585306797, 0), Dirs: map[string]*embedded.EmbeddedDir{ "": dir1, }, @@ -101,9 +101,9 @@ func init() { } filec := &embedded.EmbeddedFile{ Filename: "theme.css", - FileModTime: time.Unix(1585219496, 0), + FileModTime: time.Unix(1585306942, 0), - Content: string(":root {\n --main-title-color: #ae81ff;\n --link-hover-color: #ae81ff;\n}\n\n/* normalize */\n* {\n font-weight: inherit;\n font-size: inherit;\n border: none;\n outline: none;\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\na {\n color: inherit;\n text-decoration: none;\n}\n\nbody {\n font-family: Arial, sans-serif;\n font-size: 16px;\n font-weight: 400;\n color: #c5c8c6;\n background: #1e1e1e;\n padding-bottom: 10px;\n}\n\nnav {\n z-index: 100;\n color: var(--main-title-color);\n text-shadow: -2px 2px 3px rgba(0, 0, 0, 0.7);\n font-weight: 700;\n font-size: 20px;\n text-indent: 20px;\n line-height: 50px;\n width: 100%;\n height: 50px;\n background: #171717;\n border-bottom: 1px solid #272727;\n position: relative;\n overflow: hidden;\n}\n\nnav a.centered {\n float: none;\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n}\n\nmain {\n width: 1156px;\n margin:0 auto;\n margin-top: 15px;\n white-space: nowrap;\n}\n\n#player {\n width: 854px;\n display: inline-block;\n vertical-align: top;\n}\n\n/* 480p */\n#video {\n width: 100%;\n height: 480px;\n background: #000;\n box-shadow: 0 3px 7px 0 rgba(0, 0, 0, 0.2);\n}\n\n#player > h1 {\n margin-top: 10px;\n}\n\n#player > h2 {\n margin-top: 5px;\n color: #676867;\n font-size: 90%;\n}\n\n#player > p {\n margin-top: 10px;\n font-size: 80%;\n width: 100%;\n white-space: normal;\n}\n\n#playlist {\n font-size: 13px;\n display: inline-block;\n margin-left: 10px;\n width: 290px;\n height: 543px;\n background: #282a2e;\n box-shadow: 0 3px 7px 0 rgba(0, 0, 0, 0.2);\n overflow-x: hidden;\n overflow-x: auto;\n}\n\n#playlist > a {\n display: block;\n padding: 10px;\n position: relative;\n min-height: 54px;\n}\n\n#playlist > a:hover {\n color: var(--link-hover-color);\n}\n\n#playlist > a.playing {\n background: #383a3e;\n}\n\n#playlist > a + a {\n border-top: 1px solid #1e1e1e;\n}\n\n#playlist > a > img {\n width: 70px;\n}\n\n#playlist > a > div {\n position: absolute;\n top: 10px;\n right: 10px;\n bottom: 10px;\n left: 90px;\n}\n\n#playlist > a > div > h1 {\n white-space: normal;\n}\n\n#playlist > a > div > h2 {\n margin-top: 5px;\n color: #676867;\n font-size: 90%;\n}\n\n/* 360p */\n@media only screen and (max-width: 1180px) {\n main {\n width: 940px;\n }\n #player {\n width: 640px;\n }\n #video {\n height: 360px;\n }\n}\n\n/* 240p */\n@media only screen and (max-width: 965px) {\n main {\n width: 726px;\n }\n #player {\n width: 426px;\n }\n #video {\n height: 240px;\n }\n}\n\n/* 240p with shifted playlist */\n@media only screen and (max-width: 750px) {\n main {\n width: 426px;\n }\n #player {\n width: 426px;\n }\n #video {\n height: 240px;\n }\n #playlist {\n width: 426px;\n margin-top: 10px;\n margin-left: 0;\n display: block;\n }\n}\n\n/* responsive width with shifted playlist */\n@media only screen and (max-width: 440px) {\n main {\n width: 100%;\n }\n #player {\n width: 100%;\n }\n #video {\n height: auto;\n }\n #playlist {\n width: 100%;\n margin-top: 10px;\n margin-left: 0;\n display: block;\n }\n}\n\n/* Upload */\n.upload_form_cont {\n background: -moz-linear-gradient(#ffffff, #f2f2f2);\n background: -ms-linear-gradient(#ffffff, #f2f2f2);\n background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f2f2f2));\n background: -webkit-linear-gradient(#ffffff, #f2f2f2);\n background: -o-linear-gradient(#ffffff, #f2f2f2);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2');\n -ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2')\";\n background: linear-gradient(#ffffff, #f2f2f2);\n color:#000;\n overflow:hidden;\n}\n#upload_form {\n float:left;\n padding:20px;\n width:700px;\n}\n#upload_form > div {\n margin-bottom:10px;\n}\n#speed,#remaining {\n float:left;\n width:100px;\n}\n#b_transfered {\n float:right;\n text-align:right;\n}\n.clear_both {\n clear:both;\n}\ninput {\n border-radius:10px;\n -moz-border-radius:10px;\n -ms-border-radius:10px;\n -o-border-radius:10px;\n -webkit-border-radius:10px;\n border:1px solid #ccc;\n font-size:14pt;\n padding:5px 10px;\n}\ninput[type=button] {\n background: -moz-linear-gradient(#ffffff, #dfdfdf);\n background: -ms-linear-gradient(#ffffff, #dfdfdf);\n background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #dfdfdf));\n background: -webkit-linear-gradient(#ffffff, #dfdfdf);\n background: -o-linear-gradient(#ffffff, #dfdfdf);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dfdfdf');\n -ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dfdfdf')\";\n background: linear-gradient(#ffffff, #dfdfdf);\n}\n#video_file {\n width:400px;\n}\n#progress_info {\n font-size:10pt;\n}\n#fileinfo,#error,#error2,#abort,#warnsize {\n color:#aaa;\n display:none;\n font-size:10pt;\n font-style:italic;\n margin-top:10px;\n}\n#progress {\n border:1px solid #ccc;\n display:none;\n float:left;\n height:14px;\n border-radius:10px;\n -moz-border-radius:10px;\n -ms-border-radius:10px;\n -o-border-radius:10px;\n -webkit-border-radius:10px;\n background: -moz-linear-gradient(#66cc00, #4b9500);\n background: -ms-linear-gradient(#66cc00, #4b9500);\n background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #66cc00), color-stop(100%, #4b9500));\n background: -webkit-linear-gradient(#66cc00, #4b9500);\n background: -o-linear-gradient(#66cc00, #4b9500);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#66cc00', endColorstr='#4b9500');\n -ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr='#66cc00', endColorstr='#4b9500')\";\n background: linear-gradient(#66cc00, #4b9500);\n}\n#progress_percent {\n float:right;\n}\n#upload_response {\n margin-top: 10px;\n padding: 20px;\n overflow: hidden;\n display: none;\n border: 1px solid #ccc;\n border-radius:10px;\n -moz-border-radius:10px;\n -ms-border-radius:10px;\n -o-border-radius:10px;\n -webkit-border-radius:10px;\n box-shadow: 0 0 5px #ccc;\n background: -moz-linear-gradient(#bbb, #eee);\n background: -ms-linear-gradient(#bbb, #eee);\n background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #bbb), color-stop(100%, #eee));\n background: -webkit-linear-gradient(#bbb, #eee);\n background: -o-linear-gradient(#bbb, #eee);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#bbb', endColorstr='#eee');\n -ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr='#bbb', endColorstr='#eee')\";\n background: linear-gradient(#000000, #1e1e1e);\n}\n\n.fileContainer {\n overflow: hidden;\n position: relative;\n}\n\nlabel.filebutton {\n width:120px;\n height:40px;\n overflow:hidden;\n position:relative;\n background:linear-gradient(#000000, #1e1e1e);\n box-shadow: 0 0 5px #ccc;\n}\n\nlabel span input {\n z-index: 999;\n line-height: 0;\n font-size: 50px;\n position: absolute;\n top: -2px;\n left: -700px;\n opacity: 0;\n filter: alpha(opacity = 0);\n -ms-filter: \"alpha(opacity=0)\";\n cursor: pointer;\n _cursor: hand;\n margin: 0;\n padding:0;\n}\n.lds-ellipsis {\n display: inline-block;\n position: relative;\n width: 80px;\n height: 80px;\n}\n.lds-ellipsis div {\n position: absolute;\n top: 33px;\n width: 13px;\n height: 13px;\n border-radius: 50%;\n background: #fff;\n animation-timing-function: cubic-bezier(0, 1, 1, 0);\n}\n.lds-ellipsis div:nth-child(1) {\n left: 8px;\n animation: lds-ellipsis1 0.6s infinite;\n}\n.lds-ellipsis div:nth-child(2) {\n left: 8px;\n animation: lds-ellipsis2 0.6s infinite;\n}\n.lds-ellipsis div:nth-child(3) {\n left: 32px;\n animation: lds-ellipsis2 0.6s infinite;\n}\n.lds-ellipsis div:nth-child(4) {\n left: 56px;\n animation: lds-ellipsis3 0.6s infinite;\n}\n@keyframes lds-ellipsis1 {\n 0% {\n transform: scale(0);\n }\n 100% {\n transform: scale(1);\n }\n}\n@keyframes lds-ellipsis3 {\n 0% {\n transform: scale(1);\n }\n 100% {\n transform: scale(0);\n }\n}\n@keyframes lds-ellipsis2 {\n 0% {\n transform: translate(0, 0);\n }\n 100% {\n transform: translate(24px, 0);\n }\n}\n\n.nav ul {\n list-style: none;\n background-color: #444;\n text-align: center;\n padding: 0;\n margin: 0;\n}\n.nav li {\n font-family: 'Oswald', sans-serif;\n font-size: 1.2em;\n line-height: 40px;\n height: 40px;\n border-bottom: 1px solid #888;\n}\n\n.nav a {\n text-decoration: none;\n color: #fff;\n display: block;\n transition: .3s background-color;\n}\n\n.nav a:hover {\n background-color: #005f5f;\n}\n\n.nav a.active {\n background-color: #fff;\n color: #444;\n cursor: default;\n}\n\n@media screen and (min-width: 600px) {\n .nav li {\n width: 120px;\n border-bottom: none;\n height: 50px;\n line-height: 50px;\n font-size: 1.4em;\n }\n\n /* Option 1 - Display Inline */\n .nav li {\n display: inline-block;\n margin-right: -4px;\n }\n\n /* Options 2 - Float\n .nav li {\n float: left;\n }\n .nav ul {\n overflow: auto;\n width: 600px;\n margin: 0 auto;\n }\n .nav {\n background-color: #444;\n }\n */\n}\n\nfooter {\n position: fixed;\n left: 0;\n bottom: 0;\n width: 100%;\n background: #1e1e1e;\n color: white;\n text-align: center;\n}\n\nfooter p {\n font-size: 8px;\n}\n\nfooter p a {\n color: #fff;\n}\n\nfooter p a {\n text-decoration: underline;\n color: #fff;\n transition: .3s background-color;\n}\n\nfooter p a:hover {\n background-color: #005f5f;\n}\n"), + Content: string(":root {\n --main-title-color: #ae81ff;\n --link-hover-color: #ae81ff;\n}\n\n/* normalize */\n* {\n font-weight: inherit;\n font-size: inherit;\n border: none;\n outline: none;\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\na {\n color: inherit;\n text-decoration: none;\n}\n\nbody {\n font-family: Arial, sans-serif;\n font-size: 16px;\n font-weight: 400;\n color: #c5c8c6;\n background: #1e1e1e;\n padding-bottom: 10px;\n}\n\nnav {\n z-index: 100;\n color: var(--main-title-color);\n text-shadow: -2px 2px 3px rgba(0, 0, 0, 0.7);\n font-weight: 700;\n font-size: 20px;\n text-indent: 20px;\n line-height: 50px;\n width: 100%;\n height: 50px;\n background: #171717;\n border-bottom: 1px solid #272727;\n position: relative;\n overflow: hidden;\n}\n\nnav a.centered {\n float: none;\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n}\n\nmain {\n width: 1156px;\n margin:0 auto;\n margin-top: 15px;\n white-space: nowrap;\n}\n\n#player {\n width: 854px;\n display: inline-block;\n vertical-align: top;\n}\n\n/* 480p */\n#video {\n width: 100%;\n height: 480px;\n background: #000;\n box-shadow: 0 3px 7px 0 rgba(0, 0, 0, 0.2);\n}\n\n#player > h1 {\n margin-top: 10px;\n}\n\n#player > h2 {\n margin-top: 5px;\n color: #676867;\n font-size: 90%;\n}\n\n#player > p {\n margin-top: 10px;\n font-size: 80%;\n width: 100%;\n white-space: normal;\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n#playlist {\n font-size: 13px;\n display: inline-block;\n margin-left: 10px;\n width: 290px;\n height: 543px;\n background: #282a2e;\n box-shadow: 0 3px 7px 0 rgba(0, 0, 0, 0.2);\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n#playlist > a {\n display: block;\n padding: 10px;\n position: relative;\n min-height: 54px;\n}\n\n#playlist > a:hover {\n color: var(--link-hover-color);\n}\n\n#playlist > a.playing {\n background: #383a3e;\n}\n\n#playlist > a + a {\n border-top: 1px solid #1e1e1e;\n}\n\n#playlist > a > img {\n width: 70px;\n}\n\n#playlist > a > div {\n position: absolute;\n top: 10px;\n right: 10px;\n bottom: 10px;\n left: 90px;\n}\n\n#playlist > a > div > h1 {\n white-space: normal;\n}\n\n#playlist > a > div > h2 {\n margin-top: 5px;\n color: #676867;\n font-size: 90%;\n}\n\n/* 360p */\n@media only screen and (max-width: 1180px) {\n main {\n width: 940px;\n }\n #player {\n width: 640px;\n }\n #video {\n height: 360px;\n }\n}\n\n/* 240p */\n@media only screen and (max-width: 965px) {\n main {\n width: 726px;\n }\n #player {\n width: 426px;\n }\n #video {\n height: 240px;\n }\n}\n\n/* 240p with shifted playlist */\n@media only screen and (max-width: 750px) {\n main {\n width: 426px;\n }\n #player {\n width: 426px;\n }\n #video {\n height: 240px;\n }\n #playlist {\n width: 426px;\n margin-top: 10px;\n margin-left: 0;\n display: block;\n }\n}\n\n/* responsive width with shifted playlist */\n@media only screen and (max-width: 440px) {\n main {\n width: 100%;\n }\n #player {\n width: 100%;\n }\n #video {\n height: auto;\n }\n #playlist {\n width: 100%;\n margin-top: 10px;\n margin-left: 0;\n display: block;\n }\n}\n\n/* Upload */\n.upload_form_cont {\n background: -moz-linear-gradient(#ffffff, #f2f2f2);\n background: -ms-linear-gradient(#ffffff, #f2f2f2);\n background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f2f2f2));\n background: -webkit-linear-gradient(#ffffff, #f2f2f2);\n background: -o-linear-gradient(#ffffff, #f2f2f2);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2');\n -ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2')\";\n background: linear-gradient(#ffffff, #f2f2f2);\n color:#000;\n overflow:hidden;\n}\n#upload_form {\n float:left;\n padding:20px;\n width:700px;\n}\n#upload_form > div {\n margin-bottom:10px;\n}\n#speed,#remaining {\n float:left;\n width:100px;\n}\n#b_transfered {\n float:right;\n text-align:right;\n}\n.clear_both {\n clear:both;\n}\n\ntextarea {\n border-radius:10px;\n -moz-border-radius:10px;\n -ms-border-radius:10px;\n -o-border-radius:10px;\n -webkit-border-radius:10px;\n border:1px solid #ccc;\n font-size:14pt;\n padding:5px 10px;\n}\n\ninput {\n border-radius:10px;\n -moz-border-radius:10px;\n -ms-border-radius:10px;\n -o-border-radius:10px;\n -webkit-border-radius:10px;\n border:1px solid #ccc;\n font-size:14pt;\n padding:5px 10px;\n}\ninput[type=button] {\n background: -moz-linear-gradient(#ffffff, #dfdfdf);\n background: -ms-linear-gradient(#ffffff, #dfdfdf);\n background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #dfdfdf));\n background: -webkit-linear-gradient(#ffffff, #dfdfdf);\n background: -o-linear-gradient(#ffffff, #dfdfdf);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dfdfdf');\n -ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dfdfdf')\";\n background: linear-gradient(#ffffff, #dfdfdf);\n}\n#video_file {\n width:400px;\n}\n#progress_info {\n font-size:10pt;\n}\n#fileinfo,#error,#error2,#abort,#warnsize {\n color:#aaa;\n display:none;\n font-size:10pt;\n font-style:italic;\n margin-top:10px;\n}\n#progress {\n border:1px solid #ccc;\n display:none;\n float:left;\n height:14px;\n border-radius:10px;\n -moz-border-radius:10px;\n -ms-border-radius:10px;\n -o-border-radius:10px;\n -webkit-border-radius:10px;\n background: -moz-linear-gradient(#66cc00, #4b9500);\n background: -ms-linear-gradient(#66cc00, #4b9500);\n background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #66cc00), color-stop(100%, #4b9500));\n background: -webkit-linear-gradient(#66cc00, #4b9500);\n background: -o-linear-gradient(#66cc00, #4b9500);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#66cc00', endColorstr='#4b9500');\n -ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr='#66cc00', endColorstr='#4b9500')\";\n background: linear-gradient(#66cc00, #4b9500);\n}\n#progress_percent {\n float:right;\n}\n#upload_response {\n margin-top: 10px;\n padding: 20px;\n overflow: hidden;\n display: none;\n border: 1px solid #ccc;\n border-radius:10px;\n -moz-border-radius:10px;\n -ms-border-radius:10px;\n -o-border-radius:10px;\n -webkit-border-radius:10px;\n box-shadow: 0 0 5px #ccc;\n background: -moz-linear-gradient(#bbb, #eee);\n background: -ms-linear-gradient(#bbb, #eee);\n background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #bbb), color-stop(100%, #eee));\n background: -webkit-linear-gradient(#bbb, #eee);\n background: -o-linear-gradient(#bbb, #eee);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#bbb', endColorstr='#eee');\n -ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr='#bbb', endColorstr='#eee')\";\n background: linear-gradient(#000000, #1e1e1e);\n}\n\n.fileContainer {\n overflow: hidden;\n position: relative;\n}\n\nlabel.filebutton {\n width:120px;\n height:40px;\n overflow:hidden;\n position:relative;\n background:linear-gradient(#000000, #1e1e1e);\n box-shadow: 0 0 5px #ccc;\n}\n\nlabel span input {\n z-index: 999;\n line-height: 0;\n font-size: 50px;\n position: absolute;\n top: -2px;\n left: -700px;\n opacity: 0;\n filter: alpha(opacity = 0);\n -ms-filter: \"alpha(opacity=0)\";\n cursor: pointer;\n _cursor: hand;\n margin: 0;\n padding:0;\n}\n.lds-ellipsis {\n display: inline-block;\n position: relative;\n width: 80px;\n height: 80px;\n}\n.lds-ellipsis div {\n position: absolute;\n top: 33px;\n width: 13px;\n height: 13px;\n border-radius: 50%;\n background: #fff;\n animation-timing-function: cubic-bezier(0, 1, 1, 0);\n}\n.lds-ellipsis div:nth-child(1) {\n left: 8px;\n animation: lds-ellipsis1 0.6s infinite;\n}\n.lds-ellipsis div:nth-child(2) {\n left: 8px;\n animation: lds-ellipsis2 0.6s infinite;\n}\n.lds-ellipsis div:nth-child(3) {\n left: 32px;\n animation: lds-ellipsis2 0.6s infinite;\n}\n.lds-ellipsis div:nth-child(4) {\n left: 56px;\n animation: lds-ellipsis3 0.6s infinite;\n}\n@keyframes lds-ellipsis1 {\n 0% {\n transform: scale(0);\n }\n 100% {\n transform: scale(1);\n }\n}\n@keyframes lds-ellipsis3 {\n 0% {\n transform: scale(1);\n }\n 100% {\n transform: scale(0);\n }\n}\n@keyframes lds-ellipsis2 {\n 0% {\n transform: translate(0, 0);\n }\n 100% {\n transform: translate(24px, 0);\n }\n}\n\n.nav ul {\n list-style: none;\n background-color: #444;\n text-align: center;\n padding: 0;\n margin: 0;\n}\n.nav li {\n font-family: 'Oswald', sans-serif;\n font-size: 1.2em;\n line-height: 40px;\n height: 40px;\n border-bottom: 1px solid #888;\n}\n\n.nav a {\n text-decoration: none;\n color: #fff;\n display: block;\n transition: .3s background-color;\n}\n\n.nav a:hover {\n background-color: #005f5f;\n}\n\n.nav a.active {\n background-color: #fff;\n color: #444;\n cursor: default;\n}\n\n@media screen and (min-width: 600px) {\n .nav li {\n width: 120px;\n border-bottom: none;\n height: 50px;\n line-height: 50px;\n font-size: 1.4em;\n }\n\n /* Option 1 - Display Inline */\n .nav li {\n display: inline-block;\n margin-right: -4px;\n }\n\n /* Options 2 - Float\n .nav li {\n float: left;\n }\n .nav ul {\n overflow: auto;\n width: 600px;\n margin: 0 auto;\n }\n .nav {\n background-color: #444;\n }\n */\n}\n\nfooter {\n position: fixed;\n left: 0;\n bottom: 0;\n width: 100%;\n background: #1e1e1e;\n color: white;\n text-align: center;\n}\n\nfooter p {\n font-size: 8px;\n}\n\nfooter p a {\n color: #fff;\n}\n\nfooter p a {\n text-decoration: underline;\n color: #fff;\n transition: .3s background-color;\n}\n\nfooter p a:hover {\n background-color: #005f5f;\n}\n"), } filed := &embedded.EmbeddedFile{ Filename: "upload-icon.png", @@ -119,15 +119,15 @@ func init() { } filef := &embedded.EmbeddedFile{ Filename: "upload.js", - FileModTime: time.Unix(1585283060, 0), + FileModTime: time.Unix(1585305638, 0), - Content: string("// common variables\nlet iBytesUploaded = 0\nlet iBytesTotal = 0\nlet iPreviousBytesLoaded = 0\nlet iMaxFilesize = 104857600 // 100MB\nlet timer = 0\nlet uploadInProgress = 'n/a'\nlet isProcessing = false\nlet file = null\n\n/* CACHED ELEMENTS */\n\nconst uploadForm = document.getElementById('upload-form')\nconst videoInput = document.getElementById('video-input')\nconst uploadMessageLabel = document.getElementById('upload-message')\nconst uploadFileContainer = document.getElementById('upload-file')\nconst uploadFilenameLabel = document.getElementById('upload-filename')\nconst uploadButtonWrapper = document.getElementById('upload-button-wrapper')\nconst uploadButton = document.getElementById('upload-button')\nconst uploadProgressContainer = document.getElementById('upload-progress-container')\nconst uploadProgressBar = document.getElementById('upload-progress')\nconst uploadProgressLabel = document.getElementById('upload-progress-label')\nconst uploadStopped = document.getElementById('upload-stopped')\nconst uploadStarted = document.getElementById('upload-started')\n\n/* HELPERS */\n\nconst setProgress = (_progress) => {\n uploadProgressContainer.style.display = _progress > 0 ? 'flex' : 'none'\n uploadProgressBar.style.width = `${_progress}%`\n uploadProgressLabel.innerText = _progress >= 15 ? `${_progress}%` : ''\n}\n\nconst setMessage = (_message, isError) => {\n uploadMessageLabel.style.display = _message ? 'block' : 'none'\n uploadMessageLabel.innerHTML = _message\n if (isError) {\n uploadMessageLabel.classList.add('error')\n } else {\n uploadMessageLabel.classList.remove('error')\n }\n}\n\nconst setUploadState = (_uploadInProgress) => {\n uploadInProgress = _uploadInProgress\n\n uploadStarted.style.display = _uploadInProgress ? 'inline-block' : 'none'\n uploadStopped.style.display = _uploadInProgress ? 'none' : 'block'\n\n if (_uploadInProgress) {\n uploadButton.classList.add('transparent')\n timer = setInterval(doInnerUpdates, 300)\n } else {\n uploadButton.classList.remove('transparent')\n clearInterval(timer)\n }\n}\n\nconst secondsToTime = (secs) => {\n let hr = Math.floor(secs / 3600)\n let min = Math.floor((secs - (hr * 3600)) / 60)\n let sec = Math.floor(secs - (hr * 3600) - (min * 60))\n if (hr < 10) hr = `0${hr}`\n if (min < 10) min = `0${min}`\n if (sec < 10) sec = `0${sec}`\n if (hr) hr = '00'\n return `${hr}:${min}:${sec}`\n}\n\nconst bytesToSize = (bytes) => {\n const sizes = ['Bytes', 'KB', 'MB']\n if (bytes == 0) return 'n/a'\n const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))\n return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]\n}\n\nconst determineDragAndDropCapable = () => {\n const div = document.createElement('div')\n return (('draggable' in div)\n || ('ondragstart' in div && 'ondrop' in div))\n && 'FormData' in window\n && 'FileReader' in window\n}\n\n/* MAIN */\n\ndocument.addEventListener('DOMContentLoaded', () => {\n ['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave']\n .forEach((evt) => {\n uploadForm.addEventListener(evt, (e) => {\n e.preventDefault()\n e.stopPropagation()\n })\n })\n\n uploadForm.addEventListener('drop', (e) => {\n console.log(111)\n e.preventDefault()\n e.stopPropagation()\n\n const _file = e.dataTransfer.files[0]\n if (!_file) return false\n fileSelected(_file)\n\n return false\n })\n}, false)\n\nconst labelClicked = (e) => {\n if (uploadInProgress === true) {\n e.preventDefault()\n return false\n }\n}\n\nconst fileSelected = (_file) => {\n const fileObj = _file || videoInput.files[0]\n if (_file) videoInput.value = ''\n\n if (fileObj) file = fileObj\n if (!file) return\n\n if (file.size > iMaxFilesize) {\n setMessage('Your file is very big. We can\\'t accept it. Please select more small file.', true)\n return\n }\n\n setMessage('')\n setProgress(0)\n \n const filename = file.name.length <= 20 ? file.name : `${file.name.substring(0, 14)}...${file.name.substring(file.name.length - 3)}`\n uploadFilenameLabel.innerText = filename\n uploadFileContainer.style.display = 'flex'\n \n uploadButtonWrapper.style.display = 'block'\n setUploadState(false)\n}\n\nconst removeFile = (e, keepMessage) => {\n if (e) e.preventDefault()\n if (uploadInProgress === true) return\n\n uploadFileContainer.style.display = 'none'\n uploadButtonWrapper.style.display = 'none'\n videoInput.value = ''\n file = null\n if (!keepMessage) setMessage('No file selected')\n\n return false\n}\n\nconst startUploading = () => {\n if (uploadInProgress === true) return\n if (!file) return\n\n isProcessing = false\n iPreviousBytesLoaded = 0\n setMessage('')\n setProgress(0)\n setUploadState(true)\n\n const formData = new FormData()\n formData.append('video_file', file)\n const xhr = new XMLHttpRequest()\n\n xhr.upload.addEventListener('progress', uploadProgress, false)\n xhr.addEventListener('load', uploadFinish, false)\n xhr.addEventListener('error', uploadError, false)\n xhr.addEventListener('abort', uploadAbort, false)\n\n xhr.open('POST', '/upload')\n xhr.send(formData)\n\n timer = setInterval(doInnerUpdates, 300)\n}\n\nconst doInnerUpdates = () => { // we will use this function to display upload speed\n if (isProcessing) {\n clearInterval(timer)\n return\n }\n\n let iDiff = iBytesUploaded - iPreviousBytesLoaded\n // if nothing new loaded - exit\n if (iDiff == 0)\n return\n iPreviousBytesLoaded = iBytesUploaded\n iDiff = iDiff * 2\n const iBytesRem = iBytesTotal - iPreviousBytesLoaded\n const secondsRemaining = iBytesRem / iDiff\n // update speed info\n let iSpeed = iDiff.toString() + 'B/s'\n if (iDiff > 1024 * 1024) {\n iSpeed = (Math.round(iDiff * 100/(1024*1024))/100).toString() + 'MB/s'\n } else if (iDiff > 1024) {\n iSpeed = (Math.round(iDiff * 100/1024)/100).toString() + 'KB/s'\n }\n\n const speedMessage = `${iSpeed} | ${secondsToTime(secondsRemaining)}`\n setMessage(speedMessage)\n}\n\nfunction uploadProgress(e) { // upload process in progress\n if (e.lengthComputable) {\n iBytesUploaded = e.loaded\n iBytesTotal = e.total\n\n const iPercentComplete = Math.round(iBytesUploaded / iBytesTotal * 100)\n setProgress(iPercentComplete)\n if (iPercentComplete === 100) {\n isProcessing = true\n setMessage('Processing video... please wait')\n }\n } else {\n setMessage('Unable to compute progress.')\n }\n}\n\nconst uploadFinish = (e) => { // upload successfully finished\n const message = e.target.responseText\n const isSuccess = e.target.status < 400\n\n setProgress(isSuccess ? 100 : 0)\n setMessage(message, !isSuccess)\n setUploadState(false)\n if (isSuccess) removeFile(null, true)\n}\n\nconst uploadError = () => { // upload error\n setMessage('An error occurred while uploading the file.', true)\n setProgress(0)\n setUploadState(false)\n}\n\nconst uploadAbort = () => { // upload abort\n setMessage('The upload has been canceled by the user or the browser dropped the connection.', true)\n setProgress(0)\n setUploadState(false)\n}"), + Content: string("// common variables\nlet iBytesUploaded = 0\nlet iBytesTotal = 0\nlet iPreviousBytesLoaded = 0\nlet iMaxFilesize = 104857600 // 100MB\nlet timer = 0\nlet uploadInProgress = 'n/a'\nlet isProcessing = false\nlet file = null\n\n/* CACHED ELEMENTS */\n\nconst uploadForm = document.getElementById('upload-form')\nconst videoInput = document.getElementById('video-input')\nconst videoTitle = document.getElementById('video-title')\nconst videoDescription = document.getElementById('video-description')\nconst uploadMessageLabel = document.getElementById('upload-message')\nconst uploadFileContainer = document.getElementById('upload-file')\nconst uploadFilenameLabel = document.getElementById('upload-filename')\nconst uploadButtonWrapper = document.getElementById('upload-button-wrapper')\nconst uploadButton = document.getElementById('upload-button')\nconst uploadProgressContainer = document.getElementById('upload-progress-container')\nconst uploadProgressBar = document.getElementById('upload-progress')\nconst uploadProgressLabel = document.getElementById('upload-progress-label')\nconst uploadStopped = document.getElementById('upload-stopped')\nconst uploadStarted = document.getElementById('upload-started')\n\n/* HELPERS */\n\nconst setProgress = (_progress) => {\n uploadProgressContainer.style.display = _progress > 0 ? 'flex' : 'none'\n uploadProgressBar.style.width = `${_progress}%`\n uploadProgressLabel.innerText = _progress >= 15 ? `${_progress}%` : ''\n}\n\nconst setMessage = (_message, isError) => {\n uploadMessageLabel.style.display = _message ? 'block' : 'none'\n uploadMessageLabel.innerHTML = _message\n if (isError) {\n uploadMessageLabel.classList.add('error')\n } else {\n uploadMessageLabel.classList.remove('error')\n }\n}\n\nconst setUploadState = (_uploadInProgress) => {\n uploadInProgress = _uploadInProgress\n\n uploadStarted.style.display = _uploadInProgress ? 'inline-block' : 'none'\n uploadStopped.style.display = _uploadInProgress ? 'none' : 'block'\n\n if (_uploadInProgress) {\n uploadButton.classList.add('transparent')\n timer = setInterval(doInnerUpdates, 300)\n } else {\n uploadButton.classList.remove('transparent')\n clearInterval(timer)\n }\n}\n\nconst secondsToTime = (secs) => {\n let hr = Math.floor(secs / 3600)\n let min = Math.floor((secs - (hr * 3600)) / 60)\n let sec = Math.floor(secs - (hr * 3600) - (min * 60))\n if (hr < 10) hr = `0${hr}`\n if (min < 10) min = `0${min}`\n if (sec < 10) sec = `0${sec}`\n if (hr) hr = '00'\n return `${hr}:${min}:${sec}`\n}\n\nconst bytesToSize = (bytes) => {\n const sizes = ['Bytes', 'KB', 'MB']\n if (bytes == 0) return 'n/a'\n const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))\n return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]\n}\n\nconst determineDragAndDropCapable = () => {\n const div = document.createElement('div')\n return (('draggable' in div)\n || ('ondragstart' in div && 'ondrop' in div))\n && 'FormData' in window\n && 'FileReader' in window\n}\n\n/* MAIN */\n\ndocument.addEventListener('DOMContentLoaded', () => {\n ['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave']\n .forEach((evt) => {\n uploadForm.addEventListener(evt, (e) => {\n e.preventDefault()\n e.stopPropagation()\n })\n })\n\n uploadForm.addEventListener('drop', (e) => {\n console.log(111)\n e.preventDefault()\n e.stopPropagation()\n\n const _file = e.dataTransfer.files[0]\n if (!_file) return false\n fileSelected(_file)\n\n return false\n })\n}, false)\n\nconst labelClicked = (e) => {\n if (uploadInProgress === true) {\n e.preventDefault()\n return false\n }\n}\n\nconst fileSelected = (_file) => {\n const fileObj = _file || videoInput.files[0]\n if (_file) videoInput.value = ''\n\n if (fileObj) file = fileObj\n if (!file) return\n\n if (file.size > iMaxFilesize) {\n setMessage('Your file is very big. We can\\'t accept it. Please select more small file.', true)\n return\n }\n\n setMessage('')\n setProgress(0)\n \n const filename = file.name.length <= 20 ? file.name : `${file.name.substring(0, 14)}...${file.name.substring(file.name.length - 3)}`\n uploadFilenameLabel.innerText = filename\n uploadFileContainer.style.display = 'flex'\n \n uploadButtonWrapper.style.display = 'block'\n setUploadState(false)\n}\n\nconst removeFile = (e, keepMessage) => {\n if (e) e.preventDefault()\n if (uploadInProgress === true) return\n\n uploadFileContainer.style.display = 'none'\n uploadButtonWrapper.style.display = 'none'\n videoInput.value = ''\n file = null\n if (!keepMessage) setMessage('No file selected')\n\n return false\n}\n\nconst startUploading = () => {\n if (uploadInProgress === true) return\n if (!file) return\n\n isProcessing = false\n iPreviousBytesLoaded = 0\n setMessage('')\n setProgress(0)\n setUploadState(true)\n\n const formData = new FormData()\n formData.append('video_file', file)\n formData.append('video_title', videoTitle.value)\n formData.append('video_description', videoDescription.value)\n const xhr = new XMLHttpRequest()\n\n xhr.upload.addEventListener('progress', uploadProgress, false)\n xhr.addEventListener('load', uploadFinish, false)\n xhr.addEventListener('error', uploadError, false)\n xhr.addEventListener('abort', uploadAbort, false)\n\n xhr.open('POST', '/upload')\n xhr.send(formData)\n\n timer = setInterval(doInnerUpdates, 300)\n}\n\nconst doInnerUpdates = () => { // we will use this function to display upload speed\n if (isProcessing) {\n clearInterval(timer)\n return\n }\n\n let iDiff = iBytesUploaded - iPreviousBytesLoaded\n // if nothing new loaded - exit\n if (iDiff == 0)\n return\n iPreviousBytesLoaded = iBytesUploaded\n iDiff = iDiff * 2\n const iBytesRem = iBytesTotal - iPreviousBytesLoaded\n const secondsRemaining = iBytesRem / iDiff\n // update speed info\n let iSpeed = iDiff.toString() + 'B/s'\n if (iDiff > 1024 * 1024) {\n iSpeed = (Math.round(iDiff * 100/(1024*1024))/100).toString() + 'MB/s'\n } else if (iDiff > 1024) {\n iSpeed = (Math.round(iDiff * 100/1024)/100).toString() + 'KB/s'\n }\n\n const speedMessage = `${iSpeed} | ${secondsToTime(secondsRemaining)}`\n setMessage(speedMessage)\n}\n\nfunction uploadProgress(e) { // upload process in progress\n if (e.lengthComputable) {\n iBytesUploaded = e.loaded\n iBytesTotal = e.total\n\n const iPercentComplete = Math.round(iBytesUploaded / iBytesTotal * 100)\n setProgress(iPercentComplete)\n if (iPercentComplete === 100) {\n isProcessing = true\n setMessage('Processing video... please wait')\n }\n } else {\n setMessage('Unable to compute progress.')\n }\n}\n\nconst uploadFinish = (e) => { // upload successfully finished\n const message = e.target.responseText\n const isSuccess = e.target.status < 400\n\n setProgress(isSuccess ? 100 : 0)\n setMessage(message, !isSuccess)\n setUploadState(false)\n if (isSuccess) removeFile(null, true)\n}\n\nconst uploadError = () => { // upload error\n setMessage('An error occurred while uploading the file.', true)\n setProgress(0)\n setUploadState(false)\n}\n\nconst uploadAbort = () => { // upload abort\n setMessage('The upload has been canceled by the user or the browser dropped the connection.', true)\n setProgress(0)\n setUploadState(false)\n}\n"), } // define dirs dir6 := &embedded.EmbeddedDir{ Filename: "", - DirModTime: time.Unix(1585303730, 0), + DirModTime: time.Unix(1585306942, 0), ChildFiles: []*embedded.EmbeddedFile{ file7, // "close-icon.png" file8, // "defaulticon.jpg" @@ -148,7 +148,7 @@ func init() { // register embeddedBox embedded.RegisterEmbeddedBox(`../static`, &embedded.EmbeddedBox{ Name: `../static`, - Time: time.Unix(1585303730, 0), + Time: time.Unix(1585306942, 0), Dirs: map[string]*embedded.EmbeddedDir{ "": dir6, }, diff --git a/static/theme.css b/static/theme.css index e65094b..13c5e12 100644 --- a/static/theme.css +++ b/static/theme.css @@ -99,7 +99,7 @@ main { background: #282a2e; box-shadow: 0 3px 7px 0 rgba(0, 0, 0, 0.2); overflow-x: hidden; - overflow-x: auto; + overflow-y: auto; } #playlist > a { @@ -239,6 +239,18 @@ main { .clear_both { clear:both; } + +textarea { + border-radius:10px; + -moz-border-radius:10px; + -ms-border-radius:10px; + -o-border-radius:10px; + -webkit-border-radius:10px; + border:1px solid #ccc; + font-size:14pt; + padding:5px 10px; +} + input { border-radius:10px; -moz-border-radius:10px; diff --git a/static/upload.js b/static/upload.js index b65684e..457f01e 100644 --- a/static/upload.js +++ b/static/upload.js @@ -12,6 +12,8 @@ let file = null const uploadForm = document.getElementById('upload-form') const videoInput = document.getElementById('video-input') +const videoTitle = document.getElementById('video-title') +const videoDescription = document.getElementById('video-description') const uploadMessageLabel = document.getElementById('upload-message') const uploadFileContainer = document.getElementById('upload-file') const uploadFilenameLabel = document.getElementById('upload-filename') @@ -161,6 +163,8 @@ const startUploading = () => { const formData = new FormData() formData.append('video_file', file) + formData.append('video_title', videoTitle.value) + formData.append('video_description', videoDescription.value) const xhr = new XMLHttpRequest() xhr.upload.addEventListener('progress', uploadProgress, false) @@ -236,4 +240,4 @@ const uploadAbort = () => { // upload abort setMessage('The upload has been canceled by the user or the browser dropped the connection.', true) setProgress(0) setUploadState(false) -} \ No newline at end of file +} diff --git a/templates/upload.html b/templates/upload.html index 12aea6c..ac5710a 100644 --- a/templates/upload.html +++ b/templates/upload.html @@ -9,6 +9,8 @@ Click to browse or drop file here
+ +