// Erzeugt das Playtube-Icon-Pack (PNG, 288x288) in zwei Varianten und packt es als Zip. // Aufruf: npm run iconpack import { execFileSync } from 'node:child_process'; import { copyFileSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { Canvas } from './raster.mjs'; import { drawGlyph, GLYPHS } from './glyphs.mjs'; import { drawExtra, EXTRA_GLYPHS } from './glyphs-extra.mjs'; import { drawApp, APP_GLYPHS } from './glyphs-apps.mjs'; import { DARK_BG, WHITE, brandGradient } from './brand.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACK_NAME = 'Playtube-Icons'; const PACK_DIR = path.join(ROOT, 'iconpack', PACK_NAME); const ZIP = path.join(ROOT, 'dist', `${PACK_NAME}.zip`); const SIZE = 288; const GLYPH_RADIUS = SIZE * 0.31; const README = `Playtube Icon Pack ================== Ordner: gradient/ Playtube-Look: Verlauf violett -> pink, weisses Symbol dark/ dunkler Hintergrund, Symbol im Playtube-Verlauf Alle Bilder: PNG, 288 x 288 Pixel (das Geraet nutzt 144 x 144, die doppelte Groesse bleibt beim Verkleinern scharf). Benutzen in der Stream-Dock-Software: Taste anklicken -> das Vorschaubild der Taste (oben links im Einstellungsbereich) anklicken -> "Bild waehlen" / Ordner-Symbol -> eine PNG-Datei aus diesem Pack auswaehlen. `; function render(variant, drawer, name) { const canvas = new Canvas(SIZE); const gradient = brandGradient(SIZE); const background = variant === 'gradient' ? gradient : DARK_BG; canvas.roundRect(0, 0, SIZE, SIZE, 0, background); drawer(canvas, name, SIZE / 2, SIZE / 2, GLYPH_RADIUS, variant === 'gradient' ? WHITE : gradient, background); return canvas.png(); } const SD_PACK_DIR = path.join(ROOT, 'iconpack', 'com.fojadrachi.playtube.sdIconPack'); // Deutsche Suchbegriffe zusaetzlich zu den englischen Symbolnamen. const GERMAN_TAGS = { folder: ['ordner'], file: ['datei'], home: ['start', 'zuhause'], gear: ['einstellungen', 'zahnrad'], plus: ['hinzufuegen'], minus: ['entfernen'], close: ['schliessen'], check: ['haken', 'ok'], star: ['stern', 'favorit'], search: ['suche', 'lupe'], power: ['ein', 'aus'], mic: ['mikrofon'], headphones: ['kopfhoerer'], lock: ['schloss'], bell: ['glocke', 'benachrichtigung'], clock: ['uhr', 'zeit'], calendar: ['kalender'], mail: ['post', 'email'], globe: ['welt', 'internet'], download: ['herunterladen'], upload: ['hochladen'], trash: ['papierkorb', 'loeschen'], eye: ['auge', 'anzeigen'], stop: ['stopp'], refresh: ['aktualisieren', 'neu laden'], wifi: ['wlan'], grid: ['raster'], menu: ['menue'], more: ['mehr'], info: ['information'], warning: ['warnung'], monitor: ['bildschirm'], sun: ['sonne', 'hell'], moon: ['mond', 'dunkel'], play: ['abspielen'], pause: ['pause'], next: ['weiter', 'naechster'], previous: ['zurueck', 'vorheriger'], volup: ['lauter'], voldown: ['leiser'], vol: ['lautstaerke'], mute: ['stumm'], heart: ['herz', 'gefaellt mir'], shuffle: ['zufall'], repeat: ['wiederholen'], playlist: ['liste'], 'eye-off': ['auge', 'ausblenden', 'verstecken'], lightbulb: ['gluehbirne', 'licht', 'lampe'], 'pc-monitor': ['pc', 'computer', 'system', 'monitor', 'leistung'], chrome: ['browser', 'google'], discord: ['chat', 'voice'], steam: ['spiele', 'games'], twitch: ['stream', 'live'], netflix: ['serien', 'filme'], youtube: ['video'], medal: ['clips', 'aufnahme'], nvidia: ['grafikkarte', 'gpu'], steelseries: ['sonar', 'audio'], aniworld: ['anime'], prismlens: ['filter', 'kamera'], }; /** Stream-Dock-Icon-Pack (.sdIconPack): manifest.json, icons.json, icon.png und icons/*.png. */ function buildStreamDockPack(jobs) { rmSync(SD_PACK_DIR, { recursive: true, force: true }); mkdirSync(path.join(SD_PACK_DIR, 'icons'), { recursive: true }); mkdirSync(path.join(SD_PACK_DIR, 'previews'), { recursive: true }); const entries = []; for (const variant of ['gradient', 'dark']) { for (const { name } of jobs) { const file = `${variant}_${name}.png`; copyFileSync(path.join(PACK_DIR, variant, `${name}.png`), path.join(SD_PACK_DIR, 'icons', file)); const base = name.split('-')[0]; entries.push({ path: file, name: `${name.replace(/-/g, ' ')} (${variant})`, tags: ['playtube', variant, ...name.split('-'), ...(GERMAN_TAGS[name] || GERMAN_TAGS[base] || [])], }); } } writeFileSync(path.join(SD_PACK_DIR, 'icons.json'), `${JSON.stringify(entries, null, 2)}\n`); writeFileSync(path.join(SD_PACK_DIR, 'manifest.json'), `${JSON.stringify({ Name: 'Playtube Icons', Version: '1.0.0', Description: 'Icons im Playtube-Look (Verlauf violett/pink): Ordner, Pfeile, Player-Symbole und mehr.', Author: 'Playtube', Icon: 'icon.png', }, null, 2)}\n`); const logo = render('gradient', drawGlyph, 'play'); writeFileSync(path.join(SD_PACK_DIR, 'icon.png'), logo); writeFileSync(path.join(SD_PACK_DIR, 'previews', 'preview1.png'), logo); } function main() { rmSync(PACK_DIR, { recursive: true, force: true }); const jobs = [ ...GLYPHS.map((name) => ({ name, drawer: drawGlyph })), ...EXTRA_GLYPHS.map((name) => ({ name, drawer: drawExtra })), ...APP_GLYPHS.map((name) => ({ name, drawer: drawApp })), ]; for (const variant of ['gradient', 'dark']) { mkdirSync(path.join(PACK_DIR, variant), { recursive: true }); for (const { name, drawer } of jobs) { writeFileSync(path.join(PACK_DIR, variant, `${name}.png`), render(variant, drawer, name)); } } writeFileSync(path.join(PACK_DIR, 'LIESMICH.txt'), README); buildStreamDockPack(jobs); mkdirSync(path.dirname(ZIP), { recursive: true }); rmSync(ZIP, { force: true }); // Unter Windows das mitgelieferte bsdtar (Git-Bash-GNU-tar liest "C:" als Netzwerk-Host). const tar = process.platform === 'win32' ? path.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'tar.exe') : 'tar'; execFileSync(tar, ['-a', '-c', '-f', ZIP, '-C', path.dirname(PACK_DIR), PACK_NAME], { stdio: 'inherit' }); process.stdout.write(`${jobs.length} Symbole x 2 Varianten -> ${PACK_DIR}\nZip: ${ZIP}\n`); } main();