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 {
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)