-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimage_redirect.go
147 lines (125 loc) · 3.67 KB
/
image_redirect.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package tme
import (
"fmt"
"github.com/dnsge/twitch-mobile-emotes/emotes"
"github.com/dnsge/twitch-mobile-emotes/session"
"log"
"net/http"
"strings"
)
func getSizeFromString(text string) (emotes.ImageSize, error) {
switch text {
case "1.0":
return emotes.ImageSizeSmall, nil
case "2.0":
return emotes.ImageSizeMedium, nil
case "3.0":
return emotes.ImageSizeLarge, nil
default:
return -1, fmt.Errorf("Unknown image size %s\n", text)
}
}
func handleEmoticonRequest(w http.ResponseWriter, r *http.Request, store *emotes.EmoteStore, cache *emotes.ImageFileCache) {
// URL comes in format of "/emoticons/<version>/...
if strings.HasPrefix(r.URL.Path, "/emoticons/v1/") {
// URL is in format of "/emoticons/v1/<id>/<size>"
v1Handler(w, r, store, cache)
} else if strings.HasPrefix(r.URL.Path, "/emoticons/v2/") {
// URL is in format of "/emoticons/v2/<id>/<format>/<theme_mode>/<size>"
v2Handler(w, r, store, cache)
} else {
http.NotFound(w, r)
return
}
}
func v1Handler(w http.ResponseWriter, r *http.Request, store *emotes.EmoteStore, cache *emotes.ImageFileCache) {
// URL is in format of "/emoticons/v1/<id>/<size>"
parts := strings.Split(r.URL.Path, "/")
if len(parts) != 5 { // verify URL
http.NotFound(w, r)
return
}
id := parts[3]
size, err := getSizeFromString(parts[4])
if err != nil {
log.Printf("Error parsing size: %v\n", err)
w.WriteHeader(http.StatusBadRequest)
return
}
commonHandler(w, r, store, cache, id, size, false)
}
func v2Handler(w http.ResponseWriter, r *http.Request, store *emotes.EmoteStore, cache *emotes.ImageFileCache) {
// URL is in format of "/emoticons/v2/<id>/<format>/<theme_mode>/<size>"
parts := strings.Split(r.URL.Path, "/")
if len(parts) != 7 { // verify URL
http.NotFound(w, r)
return
}
id := parts[3]
size, err := getSizeFromString(parts[6])
if err != nil {
log.Printf("Error parsing size: %v\n", err)
w.WriteHeader(http.StatusBadRequest)
return
}
commonHandler(w, r, store, cache, id, size, true)
}
func commonHandler(w http.ResponseWriter, r *http.Request, store *emotes.EmoteStore, cache *emotes.ImageFileCache, id string, size emotes.ImageSize, gifSupport bool) {
if len(id) < 2 {
log.Printf("Got unknown emote code %q\n", r.URL)
http.NotFound(w, r)
return
}
code := id[0]
if code == 'd' { // cache destroyer, discard characters
id = id[session.CacheDestroyerSize+1:]
code = id[0]
}
id = id[1:]
isVirtual := code == 'v'
var half emotes.VirtualHalf = -1
if isVirtual {
// At this point, 'id' is in the form of [l/r][emote_type][emote_id]
if len(id) < 3 {
log.Printf("Got unknown emote code %q\n", r.URL)
http.NotFound(w, r)
return
}
switch id[0] {
case 'l':
half = emotes.LeftHalf
case 'r':
half = emotes.RightHalf
default:
log.Printf("Requested Virtual emote with unknown side %q\n", id[0])
http.NotFound(w, r)
return
}
code = id[1]
id = id[2:]
}
emote, found := store.GetEmote(rune(code), id)
if !found {
log.Printf("Requested emote with code %q id %q but wasn't found\n", rune(code), id)
http.NotFound(w, r)
return
}
if cache == nil || (gifSupport && !isPNG(emote)) || emotes.ShouldNotCache(emote) { // fallback to emote cdn
http.Redirect(w, r, emote.URL(size), http.StatusFound)
} else { // use our own cache
w.Header().Set("Content-Type", "image/png")
var err error
if isVirtual {
err = cache.GetCachedOrDownloadHalf(emote, size, half, w)
} else {
err = cache.GetCachedOrDownload(emote, size, w)
}
if err != nil {
log.Printf("Error downloading emote: %v\n", err)
w.WriteHeader(http.StatusBadRequest)
}
}
}
func isPNG(emote emotes.Emote) bool {
return emote.Type() == "png" || emote.Type() == "image/png"
}