توثيق MakeFav API
أنشئ حزم favicon كاملة من الكود الخاص بك وسكربتات البناء وخطوط CI. طلب واحد يحوّل أي صورة إلى favicon.ico وأيقونات Apple touch وأيقونات Android وPWA وملف manifest وكود HTML جاهز للصق.
في هذه الصفحة
بداية سريعة
MakeFav API هي واجهة REST بسيطة تعتمد على HTTPS وJSON. جميع نقاط النهاية تحت عنوان أساسي واحد:
https://makefav.com/api/v1 - أنشئ حسابًا مجانيًا
سجّل، وأكّد عنوان بريدك الإلكتروني، وأبقِ اشتراكك في نشرة MakeFav البريدية فعّالًا – هذا هو الشرط الوحيد للخطة المجانية. - أنشئ مفتاح API
افتح صفحة مفاتيح API في حسابك وأنشئ مفتاحًا شخصيًا. يبدأ بـ mf_ ويُعرض مرة واحدة فقط، لذا احفظه في مكان آمن. إدارة مفاتيح API - أرسل طلبك الأول
ارفع صورة إلى نقطة نهاية generate واحفظ ملف ZIP المُرجَع:
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip Unzip favicons.zip, upload the files to your website and paste the HTML code from the end of readme-makefav.txt into the <head> of every page.
المصادقة
يجب أن يتضمن كل طلب إلى نقطة نهاية محمية مفتاح API شخصيًا. يمكنك إنشاء المفاتيح وتسميتها وإلغاؤها في أي وقت من صفحة حسابك: مفاتيح API
Send the key as a bearer token in the Authorization header, or – if your HTTP client makes that awkward – in the X-API-Key header. Both are equivalent.
Authorization: Bearer mf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# or, alternatively
X-API-Key: mf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Missing or invalid keys return 401 Unauthorized. The GET /sizes and GET /openapi.json endpoints do not require a key.
حدود الاستخدام
افتراضيًا يمكن لكل مفتاح API إجراء 100 طلب في الساعة. توضح لك كل استجابة موثّقة وضعك الحالي:
| الترويسة | الوصف |
|---|---|
X-RateLimit-Limit | الحد الأقصى لعدد الطلبات المسموح بها في النافذة الحالية. |
X-RateLimit-Remaining | الطلبات المتبقية في النافذة الحالية. |
X-RateLimit-Reset | طابع Unix الزمني (بالثواني، UTC) لوقت إعادة تعيين النافذة. |
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1767225600 When the limit is exceeded the API responds with HTTP 429 and the error code rate_limited. Wait until the time in X-RateLimit-Reset before retrying – do not retry in a tight loop.
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1767225600
{"error": {"code": "rate_limited", "message": "Rate limit exceeded. Try again after the reset time."}} You can check your current quota at any time with GET /me.
نقاط النهاية
| نقطة النهاية | المصادقة | الوصف |
|---|---|---|
POST /generate | مفتاح API | إنشاء حزمة favicon كاملة. |
GET /me | مفتاح API | حسابك وحالة حد الاستخدام الحالية. |
GET /sizes | بدون | قائمة بجميع ملفات الأيقونات وأحجامها التي ينتجها المولّد. |
GET /openapi.json | بدون | مواصفات OpenAPI 3.1 المقروءة آليًا. |
إنشاء حزمة favicon
/generateينشئ حزمة favicon كاملة من صورة مصدر واحدة. أرسل الصورة بإحدى ثلاث طرق:
| نوع المحتوى | حقل الصورة | الوصف |
|---|---|---|
multipart/form-data | image | رفع ملف. موصى به – الخيار الأكثر كفاءة. |
application/json | image_base64 | Base64-encoded image, either raw base64 or a data URL such as data:image/png;base64,iVBOR…. |
application/json | image_url | عنوان URL عام (http أو https) للصورة. يقوم الخادم بتنزيلها (بحد أقصى 10 ميغابايت). |
صيغ الإدخال المدعومة: PNG وJPG وWebP وAVIF وGIF وBMP وSVG وICO. الحد الأقصى لحجم الملف: 10 ميغابايت.
المعاملات
جميع المعاملات اختيارية. أرسلها كحقول نموذج (multipart) أو كخصائص JSON. القيم غير الصالحة تعود إلى القيمة الافتراضية.
| الاسم | النوع / النطاق | الافتراضي | الوصف |
|---|---|---|---|
app_name | نص، بحد أقصى 60 حرفًا | My Website | اسم موقعك أو تطبيقك، يُستخدم في manifest.json وصفحة المثال. |
short_name | نص، بحد أقصى 24 حرفًا | أول 12 حرفًا من app_name | الاسم المختصر الذي يظهر تحت الأيقونة على الشاشات الرئيسية في Android. |
theme_color | #rrggbb | #ffffff | لون واجهة المتصفح (وسم theme-color وmanifest). |
tile_color | #rrggbb | نفس theme_color | لون خلفية بلاطات قائمة ابدأ في Windows. |
background | transparent | #rrggbb | transparent | خلفية أيقونات المتصفح وAndroid وWindows. |
apple_background | #rrggbb | #ffffff | خلفية أيقونات Apple touch والأيقونة القابلة للقناع maskable (لا يدعم iOS الشفافية). يتم تجاهله عندما تكون الخلفية لونًا – ويُستخدم ذلك اللون بدلًا منه. |
padding | عدد صحيح، 0–40 (%) | 0 | مساحة فارغة حول الصورة، كنسبة مئوية من حجم الأيقونة. |
radius | عدد صحيح، 0–50 (%) | 0 | زوايا مستديرة. القيمة 50 تصنع دائرة. لا تُطبَّق على أيقونات Apple، إذ يقوم iOS بتدوير زواياها بنفسه. |
zoom | عدد صحيح، 50–400 (%) | 100 | مقياس الصورة داخل الأيقونة. القيم الأكبر من 100 تقتطع جزءًا من الصورة. |
offset_x, offset_y | رقم، من -1 إلى 1 | 0 | يحرّك الصورة أفقيًا / عموديًا، كنسبة من حجم الأيقونة. |
path | نص | / | المجلد على خادمك الذي ستوضع فيه الأيقونات. يُستخدم في مقتطف HTML وmanifest وbrowserconfig. |
display | standalone | fullscreen | minimal-ui | browser | standalone | وضع عرض PWA المكتوب في manifest. |
pixelated | auto | 1 | 0 | auto | تحجيم حاد بأقرب جار (nearest-neighbour) لفن البكسل. يفعّله الوضع auto للمصادر بحجم 64 بكسل أو أقل. |
maskable | 1 | 0 | 1 | أنشئ أيضًا maskable-icon-512x512.png مع هامش منطقة آمنة لأيقونات Android التكيفية. |
ico_sizes | قائمة مفصولة بفواصل من 16 و24 و32 و48 و64 و128 و256 | 16,32,48 | الأحجام المضمّنة في favicon.ico. |
groups | قائمة مفصولة بفواصل من favicon وapple وandroid وms | favicon,apple,android,ms | مجموعات الأيقونات المراد إنشاؤها: أيقونات favicon للمتصفحات، وأيقونات Apple touch، وأيقونات Android / PWA، وبلاطات Windows. |
format | zip | json | zip | تنسيق الاستجابة – انظر أدناه. |
الاستجابة
format=zip- Binary ZIP archive with
Content-Type: application/zipandContent-Disposition: attachment. Default. format=json- JSON object with the package
id(32 hex characters), thehtmlsnippet for your <head> and afilesarray; each file hasname,mime,size(bytes) andbase64contents.
مثال على طلب – multipart، استجابة ZIP
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip HTTP/1.1 200 OK
Content-Type: application/zip
Content-Disposition: attachment
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1767225600
<binary ZIP data> مثال على طلب – JSON مع رابط صورة، استجابة JSON
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://example.com/logo.png",
"app_name": "My App",
"theme_color": "#2f9e68",
"radius": 20,
"groups": "favicon,apple,android",
"format": "json"
}' {
"id": "9f86d081884c7d659a2feaa0c55ad015",
"html": "<link rel=\"apple-touch-icon\" sizes=\"57x57\" href=\"/apple-icon-57x57.png\">\n…\n<meta name=\"theme-color\" content=\"#2f9e68\">",
"files": [
{"name": "favicon.ico", "mime": "image/x-icon", "size": 15086, "base64": "AAABAAMAEBAAAAEAIABoBAAANgAAACAg…"},
{"name": "favicon-16x16.png", "mime": "image/png", "size": 612, "base64": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQ…"},
{"name": "manifest.json", "mime": "application/json", "size": 1094, "base64": "ewogICAgIm5hbWUiOiAiTXkgQXBwIiwK…"}
]
}
احصل على حسابك
/meتعرض المستخدم الذي يعود إليه مفتاح API وحالة حد الطلبات الحالية. مفيدة للتحقق من المفتاح. تتطلب المصادقة؛ بلا معلمات.
مثال على طلب
curl -sS https://makefav.com/api/v1/me \
-H "Authorization: Bearer $MAKEFAV_API_KEY" مثال على استجابة
{
"id": 1,
"email": "[email protected]",
"name": "Jane Doe",
"rate_limit": {"limit": 100, "remaining": 97, "reset": 1767225600}
}
عرض أحجام الأيقونات
/sizesReturns every icon file the generator can produce, with its pixel size and group. No authentication and no parameters. The group value matches the groups parameter of POST /generate.
مثال على طلب
curl -sS https://makefav.com/api/v1/sizes مثال على استجابة
{
"files": [
{"name": "favicon-16x16.png", "size": 16, "group": "favicon"},
{"name": "favicon-32x32.png", "size": 32, "group": "favicon"},
{"name": "apple-touch-icon.png", "size": 180, "group": "apple"},
{"name": "android-icon-192x192.png", "size": 192, "group": "android"},
{"name": "ms-icon-144x144.png", "size": 144, "group": "ms"}
]
}
مواصفات OpenAPI
/openapi.jsonتعرض وصف OpenAPI 3.1 لواجهة API هذه. بدون مصادقة. استوردها في Postman أو Insomnia أو Swagger UI، أو استخدمها لإنشاء عميل مُنمَّط للغتك.
curl -sS https://makefav.com/api/v1/openapi.json -o makefav-openapi.json الأخطاء
Successful requests return HTTP 200. Every error returns a JSON body with a stable, machine-readable code and a human-readable message. Always branch on the code, not on the message text.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/json
{
"error": {
"code": "invalid_image",
"message": "The uploaded file could not be decoded as an image."
}
} | حالة HTTP | رمز الخطأ | المعنى |
|---|---|---|
| 400 | bad_request | الطلب غير صحيح التكوين، مثلًا لم تُرسل أي صورة أو أن نص JSON غير صالح. |
| 401 | unauthorized | مفتاح API مفقود أو غير صالح. |
| 403 | forbidden | البريد الإلكتروني لمالك المفتاح غير مؤكد، أو أن الاشتراك في النشرة البريدية معطّل، أو أن الحساب محظور. |
| 413 | file_too_large | حجم الصورة أكبر من 10 ميغابايت. |
| 415 | unsupported_type | نوع الملف أو نوع محتوى الطلب غير مدعوم. |
| 422 | invalid_image | تعذّر فك ترميز الملف كصورة، أو تعذّر تنزيل الصورة من الرابط. |
| 429 | rate_limited | طلبات كثيرة جدًا. انتظر حتى X-RateLimit-Reset. |
| 500 | server_error | حدث خطأ من جانبنا. أعد المحاولة لاحقًا، وتواصل مع الدعم إذا استمرت المشكلة. |
ملفات المخرجات
With all groups enabled, a package contains the files below. Files from disabled groups are left out.
| الملف | الحجم | المجموعة |
|---|---|---|
favicon.ico | 16, 32, 48 (قابل للتكوين) | دائمًا |
favicon-16x16.png | 16 × 16 | favicon |
favicon-32x32.png | 32 × 32 | favicon |
favicon-96x96.png | 96 × 96 | favicon |
apple-icon-57x57.png | 57 × 57 | apple |
apple-icon-60x60.png | 60 × 60 | apple |
apple-icon-72x72.png | 72 × 72 | apple |
apple-icon-76x76.png | 76 × 76 | apple |
apple-icon-114x114.png | 114 × 114 | apple |
apple-icon-120x120.png | 120 × 120 | apple |
apple-icon-144x144.png | 144 × 144 | apple |
apple-icon-152x152.png | 152 × 152 | apple |
apple-icon-180x180.png | 180 × 180 | apple |
apple-icon.png | 192 × 192 | apple |
apple-icon-precomposed.png | 192 × 192 | apple |
apple-touch-icon.png | 180 × 180 | apple |
android-icon-36x36.png | 36 × 36 | android |
android-icon-48x48.png | 48 × 48 | android |
android-icon-72x72.png | 72 × 72 | android |
android-icon-96x96.png | 96 × 96 | android |
android-icon-144x144.png | 144 × 144 | android |
android-icon-192x192.png | 192 × 192 | android |
android-icon-512x512.png | 512 × 512 | android |
web-app-manifest-192x192.png | 192 × 192 | android |
web-app-manifest-512x512.png | 512 × 512 | android |
maskable-icon-512x512.png | 512 × 512 | android |
ms-icon-70x70.png | 70 × 70 | ms |
ms-icon-144x144.png | 144 × 144 | ms |
ms-icon-150x150.png | 150 × 150 | ms |
ms-icon-310x310.png | 310 × 310 | ms |
ملفات إضافية
| الملف | مضمّن | الوصف |
|---|---|---|
favicon.svg | فقط لمدخلات SVG بدون قص أو تكبير أو حشو أو زوايا أو خلفية | نسخة منقّاة من ملف SVG للمتصفحات التي تدعم أيقونات favicon المتجهة. |
manifest.json, site.webmanifest | android | ملف manifest لتطبيق الويب لنظام Android وتطبيقات PWA القابلة للتثبيت (نسختان متطابقتان). |
browserconfig.xml | ms | إعدادات بلاطات Windows بلون البلاطة الذي اخترته. |
readme-makefav.txt | دائمًا | تعليمات التثبيت مع شيفرة HTML الخاصة بالعنصر <head> في النهاية. |
أمثلة برمجية
Each example uploads logo.png with a few options and saves favicons.zip, handling API errors. Set the environment variable MAKEFAV_API_KEY to your API key first.
رفع multipart:
# Multipart upload (recommended). --fail-with-body exits non-zero on HTTP errors
# and still saves the JSON error body, so you can inspect it.
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip \
|| { echo "Request failed:"; cat favicons.zip; rm -f favicons.zip; exit 1; } نص JSON مع صورة بترميز base64 (يتطلب jq):
# JSON body with a base64-encoded image (built with jq to avoid argument length limits)
base64 < logo.png | tr -d '\n' > logo.b64
jq -n --rawfile img logo.b64 \
'{image_base64: $img, app_name: "My App", theme_color: "#2f9e68", radius: 20}' \
| curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- \
-o favicons.zip \
|| { echo "Request failed:"; cat favicons.zip; rm -f favicons.zip; exit 1; } <?php
// Requires the curl extension. Run: MAKEFAV_API_KEY=mf_... php favicons.php
$apiKey = getenv('MAKEFAV_API_KEY') ?: exit("Set MAKEFAV_API_KEY first\n");
$ch = curl_init('https://makefav.com/api/v1/generate');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
CURLOPT_POSTFIELDS => [
'image' => new CURLFile('logo.png', 'image/png', 'logo.png'),
'app_name' => 'My App',
'theme_color' => '#2f9e68',
'radius' => '20',
],
]);
$body = curl_exec($ch);
if ($body === false) {
fwrite(STDERR, 'Request failed: ' . curl_error($ch) . PHP_EOL);
exit(1);
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status !== 200) {
$error = json_decode($body, true)['error'] ?? ['code' => 'http_' . $status, 'message' => substr($body, 0, 200)];
fwrite(STDERR, "Error {$status} {$error['code']}: {$error['message']}" . PHP_EOL);
exit(1);
}
file_put_contents('favicons.zip', $body);
echo 'Saved favicons.zip (' . strlen($body) . " bytes)\n"; # pip install requests · Run: MAKEFAV_API_KEY=mf_... python favicons.py
import os
import sys
import requests
API_KEY = os.environ["MAKEFAV_API_KEY"]
try:
with open("logo.png", "rb") as logo:
resp = requests.post(
"https://makefav.com/api/v1/generate",
headers={"Authorization": f"Bearer {API_KEY}"},
files={"image": ("logo.png", logo, "image/png")},
data={"app_name": "My App", "theme_color": "#2f9e68", "radius": 20},
timeout=60,
)
except requests.RequestException as exc:
sys.exit(f"Request failed: {exc}")
if resp.status_code != 200:
try:
err = resp.json()["error"]
sys.exit(f"Error {resp.status_code} {err['code']}: {err['message']}")
except (ValueError, KeyError, TypeError):
sys.exit(f"Error {resp.status_code}: {resp.text[:200]}")
with open("favicons.zip", "wb") as out:
out.write(resp.content)
remaining = resp.headers.get("X-RateLimit-Remaining")
print(f"Saved favicons.zip ({len(resp.content)} bytes), {remaining} requests left this hour") // favicons.mjs — Node.js 18+, no dependencies. Run: MAKEFAV_API_KEY=mf_... node favicons.mjs
import { readFile, writeFile } from 'node:fs/promises';
const form = new FormData();
form.append('image', new Blob([await readFile('logo.png')], { type: 'image/png' }), 'logo.png');
form.append('app_name', 'My App');
form.append('theme_color', '#2f9e68');
form.append('radius', '20');
const res = await fetch('https://makefav.com/api/v1/generate', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.MAKEFAV_API_KEY}` },
body: form,
});
if (!res.ok) {
const body = await res.json().catch(() => null);
console.error(`Error ${res.status} ${body?.error?.code ?? ''}: ${body?.error?.message ?? res.statusText}`);
process.exit(1);
}
await writeFile('favicons.zip', Buffer.from(await res.arrayBuffer()));
console.log(`Saved favicons.zip, ${res.headers.get('x-ratelimit-remaining')} requests left this hour`); <input type="file" id="logo" accept="image/*">
<button type="button" id="go">Generate favicons</button>
<script>
// Never put your API key in browser code. Point ENDPOINT at your own backend route,
// which forwards the multipart body to https://makefav.com/api/v1/generate and adds
// the "Authorization: Bearer mf_..." header on the server.
const ENDPOINT = '/my-backend/favicons';
document.getElementById('go').addEventListener('click', async () => {
const file = document.getElementById('logo').files[0];
if (!file) {
alert('Please choose an image first.');
return;
}
const form = new FormData();
form.append('image', file);
form.append('app_name', 'My App');
form.append('theme_color', '#2f9e68');
form.append('radius', '20');
try {
const res = await fetch(ENDPOINT, { method: 'POST', body: form });
if (!res.ok) {
const body = await res.json().catch(() => null);
throw new Error(body?.error?.message || `HTTP ${res.status}`);
}
const url = URL.createObjectURL(await res.blob());
const a = Object.assign(document.createElement('a'), { href: url, download: 'favicons.zip' });
document.body.append(a);
a.click();
a.remove();
setTimeout(() => URL.revokeObjectURL(url), 1000);
} catch (err) {
alert('Favicon generation failed: ' + err.message);
}
});
</script> // go run favicons.go (MAKEFAV_API_KEY must be set)
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/textproto"
"os"
"time"
)
func main() {
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func run() error {
var body bytes.Buffer
w := multipart.NewWriter(&body)
logo, err := os.ReadFile("logo.png")
if err != nil {
return err
}
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition", `form-data; name="image"; filename="logo.png"`)
h.Set("Content-Type", "image/png")
part, err := w.CreatePart(h)
if err != nil {
return err
}
if _, err := part.Write(logo); err != nil {
return err
}
for k, v := range map[string]string{"app_name": "My App", "theme_color": "#2f9e68", "radius": "20"} {
if err := w.WriteField(k, v); err != nil {
return err
}
}
if err := w.Close(); err != nil {
return err
}
req, err := http.NewRequest(http.MethodPost, "https://makefav.com/api/v1/generate", &body)
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("MAKEFAV_API_KEY"))
req.Header.Set("Content-Type", w.FormDataContentType())
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
var apiErr struct {
Error struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
_ = json.NewDecoder(resp.Body).Decode(&apiErr)
return fmt.Errorf("error %d %s: %s", resp.StatusCode, apiErr.Error.Code, apiErr.Error.Message)
}
zip, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
if err := os.WriteFile("favicons.zip", zip, 0o644); err != nil {
return err
}
fmt.Printf("Saved favicons.zip (%d bytes)\n", len(zip))
return nil
} # ruby favicons.rb (MAKEFAV_API_KEY must be set) — standard library only
require "net/http"
require "json"
require "uri"
uri = URI("https://makefav.com/api/v1/generate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("MAKEFAV_API_KEY")}"
res = File.open("logo.png", "rb") do |logo|
req.set_form(
[
["image", logo, { filename: "logo.png", content_type: "image/png" }],
["app_name", "My App"],
["theme_color", "#2f9e68"],
["radius", "20"]
],
"multipart/form-data"
)
Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: 60) { |http| http.request(req) }
end
unless res.is_a?(Net::HTTPSuccess)
err = (JSON.parse(res.body)["error"] rescue nil) || { "code" => res.code, "message" => res.body.to_s[0, 200] }
abort "Error #{res.code} #{err["code"]}: #{err["message"]}"
end
File.binwrite("favicons.zip", res.body)
puts "Saved favicons.zip (#{res.body.bytesize} bytes)" // .NET 6+ console app (Program.cs, top-level statements, implicit usings enabled)
using System.Net.Http.Headers;
using System.Text.Json;
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(60) };
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("MAKEFAV_API_KEY"));
using var form = new MultipartFormDataContent();
var image = new ByteArrayContent(await File.ReadAllBytesAsync("logo.png"));
image.Headers.ContentType = new MediaTypeHeaderValue("image/png");
form.Add(image, "image", "logo.png");
form.Add(new StringContent("My App"), "app_name");
form.Add(new StringContent("#2f9e68"), "theme_color");
form.Add(new StringContent("20"), "radius");
using var response = await http.PostAsync("https://makefav.com/api/v1/generate", form);
if (!response.IsSuccessStatusCode)
{
var body = await response.Content.ReadAsStringAsync();
string code = "", message = body;
try
{
var error = JsonDocument.Parse(body).RootElement.GetProperty("error");
code = error.GetProperty("code").GetString() ?? "";
message = error.GetProperty("message").GetString() ?? "";
}
catch (Exception e) when (e is JsonException or KeyNotFoundException or InvalidOperationException) { }
Console.Error.WriteLine($"Error {(int)response.StatusCode} {code}: {message}");
return 1;
}
await File.WriteAllBytesAsync("favicons.zip", await response.Content.ReadAsByteArrayAsync());
Console.WriteLine("Saved favicons.zip");
return 0; // Java 11+, no dependencies. Run: MAKEFAV_API_KEY=mf_... java MakeFav.java
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
public class MakeFav {
public static void main(String[] args) throws IOException, InterruptedException {
String boundary = "----MakeFav" + UUID.randomUUID().toString().replace("-", "");
Map<String, String> fields = new LinkedHashMap<>();
fields.put("app_name", "My App");
fields.put("theme_color", "#2f9e68");
fields.put("radius", "20");
// Build the multipart/form-data body by hand
ByteArrayOutputStream body = new ByteArrayOutputStream();
for (Map.Entry<String, String> field : fields.entrySet()) {
body.write(("--" + boundary + "\r\n"
+ "Content-Disposition: form-data; name=\"" + field.getKey() + "\"\r\n\r\n"
+ field.getValue() + "\r\n").getBytes(StandardCharsets.UTF_8));
}
body.write(("--" + boundary + "\r\n"
+ "Content-Disposition: form-data; name=\"image\"; filename=\"logo.png\"\r\n"
+ "Content-Type: image/png\r\n\r\n").getBytes(StandardCharsets.UTF_8));
body.write(Files.readAllBytes(Path.of("logo.png")));
body.write(("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8));
HttpRequest request = HttpRequest.newBuilder(URI.create("https://makefav.com/api/v1/generate"))
.timeout(Duration.ofSeconds(60))
.header("Authorization", "Bearer " + System.getenv("MAKEFAV_API_KEY"))
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.POST(HttpRequest.BodyPublishers.ofByteArray(body.toByteArray()))
.build();
HttpResponse<byte[]> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofByteArray());
if (response.statusCode() != 200) {
// Error body is JSON: {"error":{"code":"...","message":"..."}}
System.err.println("Error " + response.statusCode() + ": "
+ new String(response.body(), StandardCharsets.UTF_8));
System.exit(1);
}
Files.write(Path.of("favicons.zip"), response.body());
System.out.println("Saved favicons.zip (" + response.body().length + " bytes)");
}
} سير عمل GitHub Actions – بتنسيق JSON، مع فك ترميز الملفات باستخدام jq:
# .github/workflows/favicons.yml — regenerate favicons whenever the logo changes.
# Add your key as a repository secret named MAKEFAV_API_KEY.
name: Favicons
on:
push:
paths: ['branding/logo.png']
workflow_dispatch:
jobs:
favicons:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate favicon package (JSON format)
env:
MAKEFAV_API_KEY: ${{ secrets.MAKEFAV_API_KEY }}
run: |
set -euo pipefail
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "image=@branding/logo.png" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-F "path=/icons/" \
-F "format=json" \
-o favicons.json || { cat favicons.json; exit 1; }
mkdir -p public/icons
# Decode every file from the JSON response (jq is preinstalled on GitHub runners)
jq -r '.files[] | "\(.name) \(.base64)"' favicons.json |
while read -r name data; do
printf '%s' "$data" | base64 -d > "public/icons/$(basename "$name")"
done
jq -r '.html' favicons.json > public/icons/head-snippet.html
ls -l public/icons
- uses: actions/upload-artifact@v4
with:
name: favicons
path: public/icons سكربت shell بسيط لأي CI – بتنسيق ZIP:
#!/usr/bin/env bash
# scripts/favicons.sh — simpler variant for any CI or build step: fetch the ZIP and unpack it.
set -euo pipefail
: "${MAKEFAV_API_KEY:?Set MAKEFAV_API_KEY}"
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip || { cat favicons.zip; rm -f favicons.zip; exit 1; }
unzip -o -q favicons.zip -d public/
rm favicons.zip
echo "Favicons written to public/" استخدام HTML
Upload all files to the folder you set with path, then paste the snippet into the <head> of every page. It is included at the end of readme-makefav.txt in the package and, with format=json, returned in the html field. Example for the options used in the code examples above:
<head>
<meta charset="utf-8">
<title>My App</title>
<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#2f9e68">
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
<meta name="msapplication-config" content="/browserconfig.xml">
<meta name="theme-color" content="#2f9e68">
</head> بعد النشر، امسح ذاكرة التخزين المؤقت للمتصفح أو افتح الموقع في نافذة خاصة – فالمتصفحات تخزّن أيقونات favicon مؤقتًا بشكل مكثّف.
سجل التغييرات
v1
- الإصدار العام الأول من واجهة MakeFav REST API.
- Endpoints
POST /generate,GET /me,GET /sizesandGET /openapi.json. - تنسيقا استجابة ZIP وJSON، ودعم multipart وbase64 وإدخال الصور عبر الرابط.
- مفاتيح API شخصية بحد 100 طلب في الساعة.
الإصدار 1 مستقر: نضيف فقط معلمات وحقولًا اختيارية. وستُطرح التغييرات الجذرية كإصدار جديد مع إشعار مسبق.
الدعم
لديك أسئلة أو تقارير أخطاء أو تحتاج إلى حد طلبات أعلى؟ يسعدنا مساعدتك. يُرجى ذكر وقت الطلب ورمز الخطأ في رسالتك – ولا ترسل مفتاح API أبدًا.