Ikon: cari per domain/URL gambar + semua format dikonversi ke PNG
- Dialog ikon: nama aplikasi -> Iconify; domain (mikrotik.com) -> ikon resmi situs (manifest 512, apple-touch-icon, favicon) + layanan favicon; URL gambar -> langsung - Contoh kasus: 'winbox' cuma punya 1 ikon tidak nyambung di Iconify, tapi 'mikrotik.com' memberi ikon resminya (5 pilihan, semuanya PNG) - Decoder ICO: entri BMP 24/32-bit (favicon.ico lama) ikut didukung, bukan cuma PNG - FromURL/Fetch selalu mengembalikan PNG; hasil raster/konversi seragam 512px - Tes: deteksi URL gambar/domain, daftar ikon situs, decode ICO BMP, konversi format
This commit is contained in:
1 parent
cad41caaee
commit
59145910b5
9 files changed
+441
-33
No files matched your search
+61
-5
@@ -161,7 +161,9 @@ func queryVariants(query string) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// FromURL mengunduh ikon dari URL dan menebak ekstensinya dari isi file.
|
||||
// FromURL mengunduh ikon dari URL. Hasilnya selalu PNG: format apa pun
|
||||
// (svg, webp, gif, ico, jpeg) dikonversi dulu supaya desktop environment
|
||||
// tidak perlu mendukung banyak format.
|
||||
func FromURL(rawURL string) ([]byte, string, error) {
|
||||
data, err := get(rawURL)
|
||||
if err != nil {
|
||||
@@ -172,11 +174,65 @@ func FromURL(rawURL string) ([]byte, string, error) {
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
ext := sniffExt(data)
|
||||
if ext == "" {
|
||||
return nil, "", fmt.Errorf("unsupported icon format at %s", rawURL)
|
||||
converted, err := ToPNG(data)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("%s: %w", rawURL, err)
|
||||
}
|
||||
return data, ext, nil
|
||||
return converted, ".png", nil
|
||||
}
|
||||
|
||||
// imageExts adalah ekstensi gambar yang bisa dipakai langsung sebagai ikon.
|
||||
var imageExts = []string{".png", ".svg", ".jpg", ".jpeg", ".webp", ".gif", ".bmp", ".ico", ".xpm"}
|
||||
|
||||
// IsImageURL benar kalau teks yang diketik user berupa URL gambar.
|
||||
func IsImageURL(text string) bool {
|
||||
text = strings.TrimSpace(text)
|
||||
if !strings.Contains(text, "://") {
|
||||
return false
|
||||
}
|
||||
lower := strings.ToLower(text)
|
||||
for _, ext := range imageExts {
|
||||
if strings.HasSuffix(strings.SplitN(lower, "?", 2)[0], ext) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Domain mengembalikan domain kalau user mengetik alamat situs (mis. "mikrotik.com"),
|
||||
// bukan nama aplikasi biasa.
|
||||
func Domain(text string) string {
|
||||
text = strings.TrimSpace(text)
|
||||
if text == "" || strings.ContainsAny(text, " \t") || IsImageURL(text) {
|
||||
return ""
|
||||
}
|
||||
// nama file gambar (mis. "lazyrun.png") bukan domain
|
||||
lower := strings.ToLower(strings.SplitN(text, "?", 2)[0])
|
||||
for _, ext := range imageExts {
|
||||
if strings.HasSuffix(lower, ext) {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
host := text
|
||||
if strings.Contains(text, "://") {
|
||||
if u, err := url.Parse(text); err == nil {
|
||||
host = u.Hostname()
|
||||
}
|
||||
}
|
||||
parts := strings.Split(strings.Trim(host, "."), ".")
|
||||
if len(parts) < 2 {
|
||||
return ""
|
||||
}
|
||||
tld := parts[len(parts)-1]
|
||||
if len(tld) < 2 || len(tld) > 24 {
|
||||
return ""
|
||||
}
|
||||
for _, r := range strings.Join(parts, "") {
|
||||
if !(r == '-' || r == '.' || r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9') {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return host
|
||||
}
|
||||
|
||||
// slug menyamakan nama untuk perbandingan (huruf kecil, tanpa pemisah).
|
||||
|
||||
Reference in new issue
Block a user