diff --git a/go/twitterchiver/viewer/templates/tweets.html b/go/twitterchiver/viewer/templates/tweets.html index 17d051737d..a7d767ff6a 100644 --- a/go/twitterchiver/viewer/templates/tweets.html +++ b/go/twitterchiver/viewer/templates/tweets.html @@ -105,6 +105,9 @@ a:hover { width: 100%; object-fit: cover; } +.media-video { + width: 100%; +}

Twitterchiver: {{.TwitterUsername}}

{{if .Query}} @@ -141,9 +144,19 @@ a:hover {
{{range $entity := .Object.extended_entities.media}}
- - - + {{if eq $entity.type "video"}} + + {{else}} + + + + {{end}}
{{end}}
diff --git a/go/twitterchiver/viewer/viewer.go b/go/twitterchiver/viewer/viewer.go index a8bdb7669f..8be3a35e23 100644 --- a/go/twitterchiver/viewer/viewer.go +++ b/go/twitterchiver/viewer/viewer.go @@ -10,6 +10,8 @@ import ( "fmt" "log" "net/http" + "net/url" + "path" "sort" "strconv" "strings" @@ -28,9 +30,14 @@ var ( databaseURL = flag.String("database_url", "", "Database URL") userMapping = userMap{} localDisableAuth = flag.String("local_auth_override_user", "", "Disable authn/authz - used for dev - set to username") + mediaDirectory = flag.String("media_dir", "/media", "Archived media directory") - indexTmpl = template.Must(template.ParseFiles("templates/index.html")) - tweetsTmpl = template.Must(template.ParseFiles("templates/tweets.html")) + funcMap = template.FuncMap{ + "rewriteURL": rewriteURL, + "bestVariant": bestVariant, + } + indexTmpl = template.Must(template.New("index.html").Funcs(funcMap).ParseFiles("templates/index.html")) + tweetsTmpl = template.Must(template.New("tweets.html").Funcs(funcMap).ParseFiles("templates/tweets.html")) ) func init() { @@ -65,6 +72,34 @@ func (um userMap) Set(v string) error { return nil } +func rewriteURL(u string) string { + p, err := url.Parse(u) + if err != nil { + return "" + } + ps := strings.TrimLeft(p.Path, "/") + + return path.Join("/media", p.Host, ps) +} + +func bestVariant(vs []interface{}) interface{} { + var bestBitrate float64 = -1 + var bestVariant interface{} + for _, v := range vs { + v := v.(map[string]interface{}) + if v["content_type"].(string) == "application/x-mpegURL" { + // m3u8 isn't very interesting since we'd have to parse it to get a playlist. + continue + } + br := v["bitrate"].(float64) + if br > bestBitrate { + bestBitrate = br + bestVariant = v + } + } + return bestVariant +} + func main() { flag.Parse() ctx := context.Background() @@ -105,6 +140,7 @@ func main() { fmt.Fprintf(rw, "

%s

", wrap) } + authR.Handle("/media/{path}", http.StripPrefix("/media/", http.FileServer(http.Dir(*mediaDirectory)))) authR.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() user := userFromContext(ctx)