@ -4,54 +4,165 @@ import (
"bytes"
"fmt"
"html/template"
"regexp"
"strings"
)
// ShareOGData contains data for rendering Open Graph HTML page
// ShareOGData contains data for rendering Open Graph HTML page .
type ShareOGData struct {
SiteName string
FileName string
FileSize string
OwnerName string
ShareURL string
ThumbnailURL string
RedirectURL string
SiteName string
SiteDescription string
SiteURL string
ShareURL string
ShareID string
FileName string
FileSize string
FileExt string
FolderName string
OwnerName string
Status string
Title string
Description string
DisplayName string
ThumbnailURL string
RedirectURL string
}
const ogHTMLTemplate = ` < ! DOCTYPE html >
< html >
< head >
< meta charset = "utf-8" >
< meta property = "og:title" content = "{{.FileName}}" >
< meta property = "og:description" content = "{{.FileSize}}{{if .OwnerName}} · {{.OwnerName}}{{end}}" >
< meta property = "og:title" content = "{{. Titl e}}">
< meta property = "og:description" content = "{{. Description }}">
< meta property = "og:image" content = "{{.ThumbnailURL}}" >
< meta property = "og:url" content = "{{.ShareURL}}" >
< meta property = "og:type" content = "website" >
< meta property = "og:site_name" content = "{{.SiteName}}" >
< meta name = "twitter:card" content = "summary" >
< meta name = "twitter:title" content = "{{. FileNam e}}">
< meta name = "twitter:description" content = "{{. FileSize}}{{if .OwnerName}} · {{.OwnerName}}{{end }}">
< meta name = "twitter:title" content = "{{. Titl e}}">
< meta name = "twitter:description" content = "{{. Description }}">
< meta name = "twitter:image" content = "{{.ThumbnailURL}}" >
< title > { { . FileNam e} } - { { . SiteName } } < / title >
< title > { { . Titl e} } - { { . SiteName } } < / title >
< / head >
< body >
< script > window . location . href = "{{.RedirectURL}}" ; < / script >
< noscript >
< p > < a href = "{{.RedirectURL}}" > { { . File Name} } < / a > < / p >
< p > < a href = "{{.RedirectURL}}" > { { . Display Name} } < / a > < / p >
< / noscript >
< / body >
< / html > `
var ogTemplate = template . Must ( template . New ( "og" ) . Parse ( ogHTMLTemplate ) )
var ogMagicVarRe = regexp . MustCompile ( ` \ { [^ { }]+\} ` )
var ogOwnerSeparatorRe = regexp . MustCompile ( ` \s*·\s*·+\s* ` )
const (
ogFileTitleTemplate = "{file_name}"
ogFileDescTemplate = "{file_size} · {owner_name}"
ogFolderTitleTemplate = "{folder_name}"
ogFolderDescTemplate = "Folder · {owner_name}"
ogStatusTitleTemplate = "{site_name}"
ogStatusDescTemplate = "{status}"
)
// RenderOGHTML renders the Open Graph HTML page for file shares.
func RenderOGHTML ( data * ShareOGData , titleTemplate , descTemplate string ) ( string , error ) {
title := replaceOGFileMagicVars ( titleTemplate , data )
description := replaceOGFileMagicVars ( descTemplate , data )
return renderOGHTML ( data , title , description )
}
// RenderFolderOGHTML renders the Open Graph HTML page for folder shares.
func RenderFolderOGHTML ( data * ShareOGData , titleTemplate , descTemplate string ) ( string , error ) {
title := replaceOGFolderMagicVars ( titleTemplate , data )
description := replaceOGFolderMagicVars ( descTemplate , data )
return renderOGHTML ( data , title , description )
}
// RenderStatusOGHTML renders the Open Graph HTML page for share status scenarios.
func RenderStatusOGHTML ( data * ShareOGData , titleTemplate , descTemplate string ) ( string , error ) {
title := replaceOGStatusMagicVars ( titleTemplate , data )
description := replaceOGStatusMagicVars ( descTemplate , data )
return renderOGHTML ( data , title , description )
}
func renderOGHTML ( data * ShareOGData , title , description string ) ( string , error ) {
renderData := * data
renderData . Title = title
renderData . Description = description
// RenderOGHTML renders the Open Graph HTML page
func RenderOGHTML ( data * ShareOGData ) ( string , error ) {
var buf bytes . Buffer
if err := ogTemplate . Execute ( & buf , data ) ; err != nil {
if err := ogTemplate . Execute ( & buf , & renderData ) ; err != nil {
return "" , fmt . Errorf ( "failed to render OG template: %w" , err )
}
return buf . String ( ) , nil
}
func replaceOGFileMagicVars ( tmpl string , data * ShareOGData ) string {
vars := map [ string ] string {
"{site_name}" : data . SiteName ,
"{site_description}" : data . SiteDescription ,
"{site_url}" : data . SiteURL ,
"{file_name}" : data . FileName ,
"{file_size}" : data . FileSize ,
"{file_ext}" : data . FileExt ,
"{owner_name}" : data . OwnerName ,
"{share_url}" : data . ShareURL ,
"{share_id}" : data . ShareID ,
}
return replaceOGMagicVars ( tmpl , vars , data . OwnerName , true )
}
func replaceOGFolderMagicVars ( tmpl string , data * ShareOGData ) string {
vars := map [ string ] string {
"{site_name}" : data . SiteName ,
"{site_description}" : data . SiteDescription ,
"{site_url}" : data . SiteURL ,
"{folder_name}" : data . FolderName ,
"{owner_name}" : data . OwnerName ,
"{share_url}" : data . ShareURL ,
"{share_id}" : data . ShareID ,
}
return replaceOGMagicVars ( tmpl , vars , data . OwnerName , true )
}
func replaceOGStatusMagicVars ( tmpl string , data * ShareOGData ) string {
vars := map [ string ] string {
"{site_name}" : data . SiteName ,
"{site_description}" : data . SiteDescription ,
"{site_url}" : data . SiteURL ,
"{share_url}" : data . ShareURL ,
"{share_id}" : data . ShareID ,
"{status}" : data . Status ,
}
return replaceOGMagicVars ( tmpl , vars , "" , false )
}
func replaceOGMagicVars ( tmpl string , vars map [ string ] string , ownerName string , trimOwner bool ) string {
rendered := ogMagicVarRe . ReplaceAllStringFunc ( tmpl , func ( match string ) string {
if value , ok := vars [ match ] ; ok {
return value
}
return match
} )
if trimOwner {
return trimEmptyOwnerSeparator ( tmpl , rendered , ownerName )
}
return rendered
}
func trimEmptyOwnerSeparator ( tmpl , rendered , ownerName string ) string {
if ownerName != "" || ! strings . Contains ( tmpl , "{owner_name}" ) {
return rendered
}
trimmed := strings . TrimSpace ( rendered )
trimmed = ogOwnerSeparatorRe . ReplaceAllString ( trimmed , " · " )
trimmed = strings . TrimSpace ( trimmed )
trimmed = strings . Trim ( trimmed , "\u00b7" )
return strings . TrimSpace ( trimmed )
}
// FormatFileSize formats file size to human readable format
func FormatFileSize ( size int64 ) string {
const (