Avatar downloader
This commit is contained in:
parent
72857972fe
commit
586befcb1a
2
images/avatars/.gitignore
vendored
Normal file
2
images/avatars/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
4
images/elements/no-gravatar.svg
Normal file
4
images/elements/no-gravatar.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="50" height="50">
|
||||||
|
<circle cx="25" cy="19" r="10" fill="rgb(60, 60, 60)" />
|
||||||
|
<circle cx="25" cy="50" r="20" fill="rgb(60, 60, 60)" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 201 B |
122
jobs/avatars/avatars.go
Normal file
122
jobs/avatars/avatars.go
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/animenotifier/arn"
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"github.com/parnurzeal/gorequest"
|
||||||
|
gravatar "github.com/ungerik/go-gravatar"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
users, _ := arn.AllUsers()
|
||||||
|
|
||||||
|
usersQueue := make(chan *arn.User)
|
||||||
|
rateLimiter := time.NewTicker(100 * time.Millisecond)
|
||||||
|
defer rateLimiter.Stop()
|
||||||
|
|
||||||
|
for w := 0; w < runtime.NumCPU(); w++ {
|
||||||
|
go func(workerID int) {
|
||||||
|
for user := range usersQueue {
|
||||||
|
<-rateLimiter.C
|
||||||
|
os.Stdout.WriteString("[" + fmt.Sprint(workerID) + "] ")
|
||||||
|
downloadAvatar(user)
|
||||||
|
makeWebPAvatar(user)
|
||||||
|
}
|
||||||
|
}(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
for user := range users {
|
||||||
|
usersQueue <- user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findAvatar(user *arn.User, dir string) string {
|
||||||
|
testExtensions := []string{"", ".jpg", ".png", ".gif", ".webp"}
|
||||||
|
|
||||||
|
for _, testExt := range testExtensions {
|
||||||
|
if _, err := os.Stat(dir + user.ID + testExt); !os.IsNotExist(err) {
|
||||||
|
return user.ID + testExt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeWebPAvatar(user *arn.User) {
|
||||||
|
baseName := findAvatar(user, "../../images/avatars/original/")
|
||||||
|
|
||||||
|
if baseName == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
original := "../../images/avatars/original/" + baseName
|
||||||
|
outFile := "../../images/avatars/webp/" + user.ID + ".webp"
|
||||||
|
|
||||||
|
err := convertFileToWebP(original, outFile, 80)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
color.Red("[WebP] " + original + " -> " + outFile)
|
||||||
|
} else {
|
||||||
|
color.Green("[WebP] " + original + " -> " + outFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadAvatar(user *arn.User) {
|
||||||
|
if user.Email == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
directory := "../../images/avatars/original/"
|
||||||
|
fileName := directory + user.ID
|
||||||
|
|
||||||
|
// Build URL
|
||||||
|
url := gravatar.Url(user.Email) + "?s=560&d=404&r=pg"
|
||||||
|
|
||||||
|
// Skip existing avatars
|
||||||
|
if findAvatar(user, directory) != "" {
|
||||||
|
color.Yellow(url)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download
|
||||||
|
response, data, err := gorequest.New().Get(url).EndBytes()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
color.Red(url)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType := response.Header.Get("content-type")
|
||||||
|
|
||||||
|
if response.StatusCode != 200 {
|
||||||
|
color.Red(url)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
color.Green(url)
|
||||||
|
|
||||||
|
// Determine file extension
|
||||||
|
extension := ""
|
||||||
|
|
||||||
|
switch contentType {
|
||||||
|
case "image/jpeg":
|
||||||
|
extension = ".jpg"
|
||||||
|
case "image/png":
|
||||||
|
extension = ".png"
|
||||||
|
case "image/gif":
|
||||||
|
extension = ".gif"
|
||||||
|
case "image/webp":
|
||||||
|
extension = ".webp"
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName += extension
|
||||||
|
|
||||||
|
// Write to disk
|
||||||
|
ioutil.WriteFile(fileName, data, 0644)
|
||||||
|
}
|
40
jobs/avatars/webp.go
Normal file
40
jobs/avatars/webp.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
_ "image/gif"
|
||||||
|
_ "image/jpeg"
|
||||||
|
_ "image/png"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/chai2010/webp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func convertFileToWebP(in string, out string, quality float32) error {
|
||||||
|
f, openErr := os.Open(in)
|
||||||
|
|
||||||
|
if openErr != nil {
|
||||||
|
return openErr
|
||||||
|
}
|
||||||
|
|
||||||
|
img, format, decodeErr := image.Decode(f)
|
||||||
|
|
||||||
|
if decodeErr != nil {
|
||||||
|
return decodeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(format, img.Bounds().Dx(), img.Bounds().Dy())
|
||||||
|
|
||||||
|
fileOut, writeErr := os.Create(out)
|
||||||
|
|
||||||
|
if writeErr != nil {
|
||||||
|
return writeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
encodeErr := webp.Encode(fileOut, img, &webp.Options{
|
||||||
|
Quality: quality,
|
||||||
|
})
|
||||||
|
|
||||||
|
return encodeErr
|
||||||
|
}
|
4
main.go
4
main.go
@ -76,6 +76,10 @@ func main() {
|
|||||||
return ctx.File("images/cover/" + ctx.Get("file") + format)
|
return ctx.File("images/cover/" + ctx.Get("file") + format)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.Get("/images/elements/:file", func(ctx *aero.Context) string {
|
||||||
|
return ctx.File("images/elements/" + ctx.Get("file"))
|
||||||
|
})
|
||||||
|
|
||||||
// For benchmarks
|
// For benchmarks
|
||||||
app.Get("/hello", func(ctx *aero.Context) string {
|
app.Get("/hello", func(ctx *aero.Context) string {
|
||||||
return ctx.Text("Hello World")
|
return ctx.Text("Hello World")
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
component ProfileImage(user *arn.User)
|
component ProfileImage(user *arn.User)
|
||||||
if user.Avatar != ""
|
if user.Avatar != ""
|
||||||
img.profile-image(src=user.Avatar + "?s=500&r=x&d=mm", alt="Profile image")
|
img.profile-image(src=user.Avatar + "?s=560&r=x&d=mm", alt="Profile image")
|
||||||
else
|
else
|
||||||
img.profile-image(src="/images/elements/no-gravatar.svg", alt="Profile image")
|
svg.profile-image(width=280, height=280, viewBox="0 0 50 50", alt="Profile image")
|
||||||
|
circle.head(cx="25", cy="19", r="10")
|
||||||
|
circle.body(cx="25", cy="50", r="20")
|
@ -66,8 +66,8 @@ animation cover-animation
|
|||||||
|
|
||||||
.image-container
|
.image-container
|
||||||
flex 1
|
flex 1
|
||||||
max-width 275px
|
max-width 280px
|
||||||
max-height 275px
|
max-height 280px
|
||||||
border-radius 3px
|
border-radius 3px
|
||||||
overflow hidden
|
overflow hidden
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
color.Yellow("Updating user references")
|
color.Yellow("Updating user references")
|
||||||
|
|
||||||
arn.Truncate("NickToUser")
|
arn.DB.DeleteTable("NickToUser")
|
||||||
arn.Truncate("EmailToUser")
|
arn.DB.DeleteTable("EmailToUser")
|
||||||
|
|
||||||
// Get a stream of all anime
|
// Get a stream of all anime
|
||||||
allUsers, err := arn.AllUsers()
|
allUsers, err := arn.AllUsers()
|
||||||
|
5
styles/svg.scarlet
Normal file
5
styles/svg.scarlet
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.head
|
||||||
|
fill text-color
|
||||||
|
|
||||||
|
.body
|
||||||
|
fill text-color
|
Loading…
Reference in New Issue
Block a user