Add backend support for serving lower quality videos (if available)
This commit is contained in:
parent
ca5969379a
commit
d21c06c465
5 changed files with 60 additions and 7 deletions
48
app/app.go
48
app/app.go
|
@ -178,12 +178,15 @@ func (a *App) indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, fmt.Sprintf("/v/%s?%s", pl[0].ID, r.URL.RawQuery), 302)
|
http.Redirect(w, r, fmt.Sprintf("/v/%s?%s", pl[0].ID, r.URL.RawQuery), 302)
|
||||||
} else {
|
} else {
|
||||||
sort := strings.ToLower(r.URL.Query().Get("sort"))
|
sort := strings.ToLower(r.URL.Query().Get("sort"))
|
||||||
|
quality := strings.ToLower(r.URL.Query().Get("quality"))
|
||||||
ctx := &struct {
|
ctx := &struct {
|
||||||
Sort string
|
Sort string
|
||||||
|
Quality string
|
||||||
Playing *media.Video
|
Playing *media.Video
|
||||||
Playlist media.Playlist
|
Playlist media.Playlist
|
||||||
}{
|
}{
|
||||||
Sort: sort,
|
Sort: sort,
|
||||||
|
Quality: quality,
|
||||||
Playing: &media.Video{ID: ""},
|
Playing: &media.Video{ID: ""},
|
||||||
Playlist: a.Library.Playlist(),
|
Playlist: a.Library.Playlist(),
|
||||||
}
|
}
|
||||||
|
@ -449,10 +452,16 @@ func (a *App) pageHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Printf("/v/%s", id)
|
log.Printf("/v/%s", id)
|
||||||
playing, ok := a.Library.Videos[id]
|
playing, ok := a.Library.Videos[id]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
sort := strings.ToLower(r.URL.Query().Get("sort"))
|
||||||
|
quality := strings.ToLower(r.URL.Query().Get("quality"))
|
||||||
ctx := &struct {
|
ctx := &struct {
|
||||||
|
Sort string
|
||||||
|
Quality string
|
||||||
Playing *media.Video
|
Playing *media.Video
|
||||||
Playlist media.Playlist
|
Playlist media.Playlist
|
||||||
}{
|
}{
|
||||||
|
Sort: sort,
|
||||||
|
Quality: quality,
|
||||||
Playing: &media.Video{ID: ""},
|
Playing: &media.Video{ID: ""},
|
||||||
Playlist: a.Library.Playlist(),
|
Playlist: a.Library.Playlist(),
|
||||||
}
|
}
|
||||||
|
@ -491,13 +500,23 @@ func (a *App) pageHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Warnf("invalid sort critiera: %s", sort)
|
log.Warnf("invalid sort critiera: %s", sort)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quality := strings.ToLower(r.URL.Query().Get("quality"))
|
||||||
|
switch quality {
|
||||||
|
case "", "720p", "480p", "360p", "240p":
|
||||||
|
default:
|
||||||
|
log.WithField("quality", quality).Warn("invalid quality")
|
||||||
|
quality = ""
|
||||||
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
ctx := &struct {
|
ctx := &struct {
|
||||||
Sort string
|
Sort string
|
||||||
|
Quality string
|
||||||
Playing *media.Video
|
Playing *media.Video
|
||||||
Playlist media.Playlist
|
Playlist media.Playlist
|
||||||
}{
|
}{
|
||||||
Sort: sort,
|
Sort: sort,
|
||||||
|
Quality: quality,
|
||||||
Playing: playing,
|
Playing: playing,
|
||||||
Playlist: playlist,
|
Playlist: playlist,
|
||||||
}
|
}
|
||||||
|
@ -508,16 +527,43 @@ func (a *App) pageHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
func (a *App) videoHandler(w http.ResponseWriter, r *http.Request) {
|
func (a *App) videoHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
id := vars["id"]
|
id := vars["id"]
|
||||||
|
|
||||||
prefix, ok := vars["prefix"]
|
prefix, ok := vars["prefix"]
|
||||||
if ok {
|
if ok {
|
||||||
id = path.Join(prefix, id)
|
id = path.Join(prefix, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("/v/%s", id)
|
log.Printf("/v/%s", id)
|
||||||
|
|
||||||
m, ok := a.Library.Videos[id]
|
m, ok := a.Library.Videos[id]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var videoPath string
|
||||||
|
|
||||||
|
quality := strings.ToLower(r.URL.Query().Get("quality"))
|
||||||
|
switch quality {
|
||||||
|
case "720p", "480p", "360p", "240p":
|
||||||
|
videoPath = fmt.Sprintf(
|
||||||
|
"%s#%s.mp4",
|
||||||
|
strings.TrimSuffix(m.Path, filepath.Ext(m.Path)),
|
||||||
|
quality,
|
||||||
|
)
|
||||||
|
if !utils.FileExists(videoPath) {
|
||||||
|
log.
|
||||||
|
WithField("quality", quality).
|
||||||
|
WithField("videoPath", videoPath).
|
||||||
|
Warn("video with specified quality does not exist (defaulting to default quality)")
|
||||||
|
videoPath = m.Path
|
||||||
|
}
|
||||||
|
case "":
|
||||||
|
videoPath = m.Path
|
||||||
|
default:
|
||||||
|
log.WithField("quality", quality).Warn("invalid quality")
|
||||||
|
videoPath = m.Path
|
||||||
|
}
|
||||||
|
|
||||||
if err := a.Store.Migrate(prefix, id); err != nil {
|
if err := a.Store.Migrate(prefix, id); err != nil {
|
||||||
err := fmt.Errorf("error migrating store data: %w", err)
|
err := fmt.Errorf("error migrating store data: %w", err)
|
||||||
log.Warn(err)
|
log.Warn(err)
|
||||||
|
@ -532,7 +578,7 @@ func (a *App) videoHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
disposition := "attachment; filename=\"" + title + ".mp4\""
|
disposition := "attachment; filename=\"" + title + ".mp4\""
|
||||||
w.Header().Set("Content-Disposition", disposition)
|
w.Header().Set("Content-Disposition", disposition)
|
||||||
w.Header().Set("Content-Type", "video/mp4")
|
w.Header().Set("Content-Type", "video/mp4")
|
||||||
http.ServeFile(w, r, m.Path)
|
http.ServeFile(w, r, videoPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP handler for /t/id
|
// HTTP handler for /t/id
|
||||||
|
|
|
@ -23,9 +23,9 @@ func init() {
|
||||||
}
|
}
|
||||||
file4 := &embedded.EmbeddedFile{
|
file4 := &embedded.EmbeddedFile{
|
||||||
Filename: "index.html",
|
Filename: "index.html",
|
||||||
FileModTime: time.Unix(1585371597, 0),
|
FileModTime: time.Unix(1585374250, 0),
|
||||||
|
|
||||||
Content: string("{{ define \"content\" }}\r\n{{ $playing := .Playing }}\r\n<div id=\"player\">\r\n {{ if $playing.ID }}\r\n <video id=\"video\" controls preload=\"metadata\" poster=\"/t/{{ $playing.ID}}\" src=\"/v/{{ $playing.ID }}.mp4\" type=\"video/mp4\"></video>\r\n <h1>{{ $playing.Title }}</h1>\r\n <h2>{{ $playing.Views }} views • {{ $playing.Modified }}<br />{{ $playing.Size | bytes }}</h2>\r\n <p>{{ $playing.Description }}</p>\r\n {{ else }}\r\n <video id=\"video\" controls></video>\r\n {{ end }}\r\n</div>\r\n<div id=\"playlist\">\r\n <div class=\"nav\">\r\n <ul>\r\n <li><a {{ if or (eq $.Sort \"timestamp\") (eq $.Sort \"\") }}class=\"active\"{{ end }} href=\"?sort=timestamp\">Recent</a></li>\r\n <li><a {{ if eq $.Sort \"views\" }}class=\"active\"{{ end }} href=\"?sort=views\">Views</a></li>\r\n </ul>\r\n </div>\r\n {{ range $m := .Playlist }}\r\n {{ if eq $m.ID $playing.ID }}\r\n <a href=\"/v/{{ $m.ID }}\" class=\"playing\">\r\n {{ else }}\r\n <a href=\"/v/{{ $m.ID }}\">\r\n {{ end }}\r\n <img src=\"/t/{{ $m.ID }}\">\r\n <div>\r\n <h1>{{ $m.Title }}</h1>\r\n <h2>{{ $m.Views }} views • {{ $m.Modified }}<br />{{ $m.Size | bytes }}</h2>\r\n </div>\r\n </a>\r\n {{ end }}\r\n</div>\r\n{{end}}\r\n"),
|
Content: string("{{ define \"content\" }}\r\n{{ $playing := .Playing }}\r\n<div id=\"player\">\r\n {{ if $playing.ID }}\r\n <video id=\"video\" controls preload=\"metadata\" poster=\"/t/{{ $playing.ID}}\">\r\n <source src=\"/v/{{ $playing.ID }}.mp4?quality={{ $.Quality }}\" type=\"video/mp4\" />\r\n </video>\r\n <h1>{{ $playing.Title }}</h1>\r\n <h2>{{ $playing.Views }} views • {{ $playing.Modified }}<br />{{ $playing.Size | bytes }}</h2>\r\n <p>{{ $playing.Description }}</p>\r\n {{ else }}\r\n <video id=\"video\" controls></video>\r\n {{ end }}\r\n</div>\r\n<div id=\"playlist\">\r\n <div class=\"nav\">\r\n <ul>\r\n <li><a {{ if or (eq $.Sort \"timestamp\") (eq $.Sort \"\") }}class=\"active\"{{ end }} href=\"?sort=timestamp\">Recent</a></li>\r\n <li><a {{ if eq $.Sort \"views\" }}class=\"active\"{{ end }} href=\"?sort=views\">Views</a></li>\r\n </ul>\r\n </div>\r\n {{ range $m := .Playlist }}\r\n {{ if eq $m.ID $playing.ID }}\r\n <a href=\"/v/{{ $m.ID }}\" class=\"playing\">\r\n {{ else }}\r\n <a href=\"/v/{{ $m.ID }}\">\r\n {{ end }}\r\n <img src=\"/t/{{ $m.ID }}\">\r\n <div>\r\n <h1>{{ $m.Title }}</h1>\r\n <h2>{{ $m.Views }} views • {{ $m.Modified }}<br />{{ $m.Size | bytes }}</h2>\r\n </div>\r\n </a>\r\n {{ end }}\r\n</div>\r\n{{end}}\r\n"),
|
||||||
}
|
}
|
||||||
file5 := &embedded.EmbeddedFile{
|
file5 := &embedded.EmbeddedFile{
|
||||||
Filename: "upload.html",
|
Filename: "upload.html",
|
||||||
|
@ -37,7 +37,7 @@ func init() {
|
||||||
// define dirs
|
// define dirs
|
||||||
dir1 := &embedded.EmbeddedDir{
|
dir1 := &embedded.EmbeddedDir{
|
||||||
Filename: "",
|
Filename: "",
|
||||||
DirModTime: time.Unix(1585371597, 0),
|
DirModTime: time.Unix(1585374250, 0),
|
||||||
ChildFiles: []*embedded.EmbeddedFile{
|
ChildFiles: []*embedded.EmbeddedFile{
|
||||||
file2, // "base.html"
|
file2, // "base.html"
|
||||||
file3, // "import.html"
|
file3, // "import.html"
|
||||||
|
@ -53,7 +53,7 @@ func init() {
|
||||||
// register embeddedBox
|
// register embeddedBox
|
||||||
embedded.RegisterEmbeddedBox(`../templates`, &embedded.EmbeddedBox{
|
embedded.RegisterEmbeddedBox(`../templates`, &embedded.EmbeddedBox{
|
||||||
Name: `../templates`,
|
Name: `../templates`,
|
||||||
Time: time.Unix(1585371597, 0),
|
Time: time.Unix(1585374250, 0),
|
||||||
Dirs: map[string]*embedded.EmbeddedDir{
|
Dirs: map[string]*embedded.EmbeddedDir{
|
||||||
"": dir1,
|
"": dir1,
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,6 +2,7 @@ package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
fs "github.com/fsnotify/fsnotify"
|
fs "github.com/fsnotify/fsnotify"
|
||||||
|
@ -29,7 +30,7 @@ func startWatcher(a *App) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case e := <-a.Watcher.Events:
|
case e := <-a.Watcher.Events:
|
||||||
if filepath.Ext(e.Name) != ".mp4" {
|
if strings.ContainsAny(e.Name, "#") || filepath.Ext(e.Name) != ".mp4" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Debugf("fsnotify event: %s", e)
|
log.Debugf("fsnotify event: %s", e)
|
||||||
|
|
|
@ -50,6 +50,10 @@ func (lib *Library) Import(p *Path) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, info := range files {
|
for _, info := range files {
|
||||||
|
if strings.ContainsAny(info.Name(), "#") {
|
||||||
|
// ignore resized videos e.g: #240p.mp4
|
||||||
|
continue
|
||||||
|
}
|
||||||
err = lib.Add(path.Join(p.Path, info.Name()))
|
err = lib.Add(path.Join(p.Path, info.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Ignore files that can't be parsed
|
// Ignore files that can't be parsed
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
{{ $playing := .Playing }}
|
{{ $playing := .Playing }}
|
||||||
<div id="player">
|
<div id="player">
|
||||||
{{ if $playing.ID }}
|
{{ if $playing.ID }}
|
||||||
<video id="video" controls preload="metadata" poster="/t/{{ $playing.ID}}" src="/v/{{ $playing.ID }}.mp4" type="video/mp4"></video>
|
<video id="video" controls preload="metadata" poster="/t/{{ $playing.ID}}">
|
||||||
|
<source src="/v/{{ $playing.ID }}.mp4?quality={{ $.Quality }}" type="video/mp4" />
|
||||||
|
</video>
|
||||||
<h1>{{ $playing.Title }}</h1>
|
<h1>{{ $playing.Title }}</h1>
|
||||||
<h2>{{ $playing.Views }} views • {{ $playing.Modified }}<br />{{ $playing.Size | bytes }}</h2>
|
<h2>{{ $playing.Views }} views • {{ $playing.Modified }}<br />{{ $playing.Size | bytes }}</h2>
|
||||||
<p>{{ $playing.Description }}</p>
|
<p>{{ $playing.Description }}</p>
|
||||||
|
|
Loading…
Reference in a new issue