Files
emoji-api/api/emoji.php
2025-08-29 23:47:11 +07:00

82 lines
3.5 KiB
PHP

<?php
// api/emoji.php (route: /api/emoji?slug=... or rewrite to /api/emoji/{slug})
require_once __DIR__.'/../helpers/auth.php';
require_once __DIR__.'/../helpers/filters.php';
// ---- Skin tone helpers (Fitzpatrick modifiers) ----
if (!function_exists('dw_supports_skin_tone')) {
function dw_supports_skin_tone(array $emoji): bool {
// Respect explicit flag if present in source data
if (isset($emoji['supports_skin_tone'])) {
return (bool)$emoji['supports_skin_tone'];
}
$cat = strtolower(trim($emoji['category'] ?? ''));
$sub = strtolower(trim($emoji['subcategory'] ?? ''));
$name = strtolower(trim($emoji['name'] ?? ''));
// 1) category must be People & Body
if ($cat !== 'people & body') return false;
// 2) Exclude faces: many face emojis are not tone-modifiable
if (preg_match('~\bface\b~', $name) || preg_match('~\bface\b~', $sub)) return false;
// 3) Allowlist of tone-capable subcategories (based on Unicode charts)
$allowSubs = [
'hand-fingers-open','hand-fingers-partial','hand-fingers-closed','hand-single-finger',
'hands','hand-prop','handshake','body-parts','person','person-gesture','person-activity','person-resting'
];
if (in_array($sub, $allowSubs, true) || str_starts_with($sub, 'hand')) return true;
// Fallback by keywords mentioning body parts / gestures
$keys = [];
foreach (['keywords','keywords_en','keywords_id'] as $k) {
if (!empty($emoji[$k]) && is_array($emoji[$k])) $keys = array_merge($keys, $emoji[$k]);
}
$hay = strtolower(' '.implode(' ', $keys).' ');
return (bool)preg_match('~\b(hand|hands|wave|clap|thumb|finger|palm|point|ear|nose|leg|foot|person|man|woman|boy|girl|salute)\b~', $hay);
}
}
if (!function_exists('dw_skin_tone_modifiers')) {
function dw_skin_tone_modifiers(): array {
return ["\u{1F3FB}", "\u{1F3FC}", "\u{1F3FD}", "\u{1F3FE}", "\u{1F3FF}"]; // light .. dark
}
}
if (!function_exists('dw_strip_tone')) {
function dw_strip_tone(string $emoji): string {
return preg_replace('/\x{1F3FB}|\x{1F3FC}|\x{1F3FD}|\x{1F3FE}|\x{1F3FF}/u', '', $emoji);
}
}
if (!function_exists('dw_build_tone_variants')) {
function dw_build_tone_variants(string $emojiBase): array {
$mods = ["\u{1F3FB}", "\u{1F3FC}", "\u{1F3FD}", "\u{1F3FE}", "\u{1F3FF}"];
return array_map(fn($m) => $emojiBase.$m, $mods);
}
}
header('Content-Type: application/json; charset=utf-8');
$tier = detectTier();
$slug = trim($_GET['slug'] ?? '');
$data = json_decode(file_get_contents(__DIR__.'/../data/emojis.json'), true);
$found = null;
foreach ($data['emojis'] as $e) {
if (($e['slug'] ?? '') === $slug) { $found = $e; break; }
}
if (!$found) { http_response_code(404); echo json_encode(['error'=>'not_found']); exit; }
$out = filterEmoji($found, $tier, false);
// Add tone support & modifiers for single emoji response
$out['supports_skin_tone'] = dw_supports_skin_tone($found) || dw_supports_skin_tone($out);
if (!isset($out['skin_tone_modifiers'])) {
$out['skin_tone_modifiers'] = dw_skin_tone_modifiers();
}
if (!empty($out['supports_skin_tone']) && !empty($out['emoji'])) {
$base = dw_strip_tone($out['emoji']);
if ($base !== '') {
$out['emoji_base'] = $base;
$out['variants'] = dw_build_tone_variants($base);
}
}
$etag = '"'.sha1(json_encode([$slug,$tier,$out])).'"';
header('ETag: '.$etag);
header('Cache-Control: public, max-age=300');
if (($_SERVER['HTTP_IF_NONE_MATCH'] ?? '') === $etag) { http_response_code(304); exit; }
echo json_encode($out, JSON_UNESCAPED_UNICODE);