Przeglądaj źródła

Added experimental share interface opg support

Toby Chui 3 lat temu
rodzic
commit
b262fb8f80

+ 2 - 1
go.mod

@@ -17,6 +17,7 @@ require (
 	github.com/gabriel-vasile/mimetype v1.4.0
 	github.com/go-git/go-git/v5 v5.4.2
 	github.com/go-ldap/ldap v3.0.3+incompatible
+	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
 	github.com/gopherjs/gopherjs v1.17.2 // indirect
 	github.com/gorilla/sessions v1.2.1
@@ -42,7 +43,7 @@ require (
 	github.com/xanzy/ssh-agent v0.3.1 // indirect
 	gitlab.com/NebulousLabs/go-upnp v0.0.0-20211002182029-11da932010b6
 	golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 // indirect
-	golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 // indirect
+	golang.org/x/image v0.0.0-20220617043117-41969df76e82 // indirect
 	golang.org/x/net v0.0.0-20220513224357-95641704303c // indirect
 	golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
 	golang.org/x/sync v0.0.0-20220513210516-0976fa681c29

+ 4 - 0
go.sum

@@ -166,6 +166,8 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE
 github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -484,6 +486,8 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+o
 golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 h1:LRtI4W37N+KFebI/qV0OFiLUv4GLOWeEW5hn/KEJvxE=
 golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
+golang.org/x/image v0.0.0-20220617043117-41969df76e82 h1:KpZB5pUSBvrHltNEdK/tw0xlPeD13M6M6aGP32gKqiw=
+golang.org/x/image v0.0.0-20220617043117-41969df76e82/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=

+ 147 - 0
mod/share/share.go

@@ -10,8 +10,14 @@ package share
 import (
 	"encoding/json"
 	"errors"
+	"fmt"
+	"image"
+	"image/color"
+	"image/draw"
+	"image/jpeg"
 	"io/ioutil"
 	"log"
+	"math"
 	"net/http"
 	"net/url"
 	"os"
@@ -20,11 +26,14 @@ import (
 	"strings"
 	"time"
 
+	"github.com/golang/freetype"
+	"github.com/nfnt/resize"
 	"github.com/valyala/fasttemplate"
 
 	"imuslab.com/arozos/mod/auth"
 	"imuslab.com/arozos/mod/common"
 	filesystem "imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/filesystem/metadata"
 	"imuslab.com/arozos/mod/share/shareEntry"
 	"imuslab.com/arozos/mod/user"
 )
@@ -49,6 +58,132 @@ func NewShareManager(options Options) *Manager {
 	}
 }
 
+func (s *Manager) HandleOPGServing(w http.ResponseWriter, r *http.Request, shareID string) {
+	shareEntry := s.GetShareObjectFromUUID(shareID)
+	if shareEntry == nil {
+		//This share is not valid
+		http.NotFound(w, r)
+		return
+	}
+
+	//Overlap and generate opg
+	//Load in base template
+	baseTemplate, err := os.Open("./system/share/default_opg.png")
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+
+	base, _, err := image.Decode(baseTemplate)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+
+	//Create base canvas
+	rx := image.Rectangle{image.Point{0, 0}, base.Bounds().Size()}
+	resultopg := image.NewRGBA(rx)
+	draw.Draw(resultopg, base.Bounds(), base, image.Point{0, 0}, draw.Src)
+
+	//Append filename to the image
+	fontBytes, err := ioutil.ReadFile("./system/share/fonts/TaipeiSansTCBeta-Light.ttf")
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+
+	utf8Font, err := freetype.ParseFont(fontBytes)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+
+	fontSize := float64(42)
+	ctx := freetype.NewContext()
+	ctx.SetDPI(72)
+	ctx.SetFont(utf8Font)
+	ctx.SetFontSize(fontSize)
+	ctx.SetClip(resultopg.Bounds())
+	ctx.SetDst(resultopg)
+	ctx.SetSrc(image.NewUniform(color.RGBA{255, 255, 255, 255}))
+
+	//Check if we need to split the filename into two lines
+	filename := filepath.Base(shareEntry.FileRealPath)
+	filenameOnly := strings.TrimSuffix(filename, filepath.Ext(filename))
+
+	fs := filesystem.GetFileSize(shareEntry.FileRealPath)
+	shareMeta := filepath.Ext(shareEntry.FileRealPath) + " / " + filesystem.GetFileDisplaySize(fs, 2)
+
+	if len([]rune(filename)) > 26 {
+		//Split into lines
+		lines := []string{}
+		for i := 0; i < len([]rune(filenameOnly)); i += 20 {
+			endPos := int(math.Min(float64(len([]rune(filenameOnly))), float64(i+20)))
+			lines = append(lines, string([]rune(filenameOnly)[i:endPos]))
+		}
+
+		for j, line := range lines {
+			pt := freetype.Pt(100, (j+1)*60+int(ctx.PointToFixed(fontSize)>>6))
+			_, err = ctx.DrawString(line, pt)
+			if err != nil {
+				fmt.Println(err)
+				return
+			}
+		}
+
+		fontSize = 36
+		ctx.SetFontSize(fontSize)
+		pt := freetype.Pt(100, (len(lines)+1)*60+int(ctx.PointToFixed(fontSize)>>6))
+		_, err = ctx.DrawString(shareMeta, pt)
+		if err != nil {
+			fmt.Println(err)
+			return
+		}
+
+	} else {
+		//One liner
+		pt := freetype.Pt(100, 60+int(ctx.PointToFixed(fontSize)>>6))
+		_, err = ctx.DrawString(filenameOnly, pt)
+		if err != nil {
+			fmt.Println(err)
+			return
+		}
+
+		fontSize = 36
+		ctx.SetFontSize(fontSize)
+		pt = freetype.Pt(100, 120+int(ctx.PointToFixed(fontSize)>>6))
+		_, err = ctx.DrawString(shareMeta, pt)
+		if err != nil {
+			fmt.Println(err)
+			return
+		}
+	}
+
+	//Get thumbnail
+	cacheFileImagePath, err := metadata.GetCacheFilePath(shareEntry.FileRealPath)
+	if err == nil {
+		//We got a thumbnail for this file. Render it as well
+		thumbnailFile, err := os.Open(cacheFileImagePath)
+		if err != nil {
+			fmt.Println(err)
+			return
+		}
+
+		thumb, _, err := image.Decode(thumbnailFile)
+		if err != nil {
+			fmt.Println(err)
+			return
+		}
+
+		resizedThumb := resize.Resize(250, 0, thumb, resize.Lanczos3)
+		draw.Draw(resultopg, resultopg.Bounds(), resizedThumb, image.Point{-(resultopg.Bounds().Dx() - resizedThumb.Bounds().Dx() - 90), -60}, draw.Src)
+	}
+
+	w.Header().Set("Content-Type", "image/jpeg") // <-- set the content-type header
+	jpeg.Encode(w, resultopg, nil)
+
+}
+
 //Main function for handle share. Must be called with http.HandleFunc (No auth)
 func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 	//New download method variables
@@ -98,6 +233,13 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					return
 				}
 			} else if len(subpathElements) >= 4 {
+				if subpathElements[1] == "opg" {
+					//Handle serving opg preview image, usually with
+					// /share/opg/{req.timestamp}/{uuid}
+					s.HandleOPGServing(w, r, subpathElements[3])
+					return
+				}
+
 				//Invalid operation type
 				w.WriteHeader(http.StatusBadRequest)
 				w.Header().Set("Content-Type", "text/plain") // this
@@ -414,6 +556,8 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					"downloadurl":  "../../share/download/" + id,
 					"filename":     filepath.Base(shareOption.FileRealPath),
 					"reqtime":      strconv.Itoa(int(time.Now().Unix())),
+					"requri":       "//" + r.Host + r.URL.Path,
+					"opg_image":    "/share/opg/" + strconv.Itoa(int(time.Now().Unix())) + "/" + id,
 					"treelist":     tl,
 					"downloaduuid": id,
 				})
@@ -487,7 +631,9 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 				t := fasttemplate.New(string(content), "{{", "}}")
 				s := t.ExecuteString(map[string]interface{}{
 					"hostname":    s.options.HostName,
+					"host":        r.Host,
 					"reqid":       id,
+					"requri":      "//" + r.Host + r.URL.Path,
 					"mime":        mime,
 					"ext":         displayExt,
 					"size":        filesystem.GetFileDisplaySize(fsize, 2),
@@ -495,6 +641,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					"downloadurl": "../../share/download/" + id + "/" + filepath.Base(shareOption.FileRealPath),
 					"preview_url": "/share/preview/" + id + "/",
 					"filename":    filepath.Base(shareOption.FileRealPath),
+					"opg_image":   "//" + r.Host + "/share/opg/" + strconv.Itoa(int(time.Now().Unix())) + "/" + id,
 					"reqtime":     strconv.Itoa(int(time.Now().Unix())),
 				})
 

BIN
system/share/default_opg.png


BIN
system/share/default_opg.psd


+ 19 - 0
system/share/downloadPage.html

@@ -4,6 +4,25 @@
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <title>{{hostname}} File Share</title>
+
+    <meta name="description" content="You got a file shared from {{hostname}}">
+
+    <!-- Facebook Meta Tags -->
+    <meta property="og:url" content="{{requri}}">
+    <meta property="og:type" content="website">
+    <meta property="og:title" content="{{hostname}} File Share">
+    <meta property="og:description" content="You got a file shared from {{hostname}}">
+    <meta property="og:image" content="{{opg_image}}">
+  
+    <!-- Twitter Meta Tags -->
+    <meta name="twitter:card" content="summary_large_image">
+    <meta property="twitter:domain" content="{{host}}">
+    <meta property="twitter:url" content="{{requri}}">
+    <meta name="twitter:title" content="{{hostname}} File Share">
+    <meta name="twitter:description" content="You got a file shared from {{hostname}}">
+    <meta name="twitter:image" content="{{opg_image}}">
+
+
     <link rel="stylesheet" href="../../script/skeleton/offline.css">
     <link rel="stylesheet" href="../../script/skeleton/normalize.css">
     <link rel="stylesheet" href="../../script/skeleton/skeleton.css">

BIN
system/share/fonts/TaipeiSansTCBeta-Light.ttf