Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DOCS/interface-changes/osc-icon-style.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add `osc-icon_style` option
11 changes: 11 additions & 0 deletions DOCS/man/osc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,17 @@ Configurable Options
Use a Unicode minus sign instead of an ASCII hyphen when displaying
the remaining playback time.

``icon_style``
Default: classic

Selects the icon set used for OSC buttons. Both sets are bundled in the
mpv-osd-symbols font.

``classic``
The original mpv icon set.
``fluent``
Icons based on Microsoft's Fluent UI System Icons.

``background_color``
Default: #000000

Expand Down
196 changes: 196 additions & 0 deletions TOOLS/gen-fluent-glyphs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
#!/usr/bin/env python3
"""Import Fluent UI System Icons into mpv-osd-symbols font.

Downloads SVG icons from microsoft/fluentui-system-icons and uses FontForge
to import them into the mpv-osd-symbols font.

Usage:
./TOOLS/gen-fluent-glyphs.py
./TOOLS/gen-osd-font.sh

Requirements: fontforge
"""

import os
import subprocess
import sys
import tempfile
import urllib.parse
import urllib.request

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
SFDIR = os.path.join(SCRIPT_DIR, "mpv-osd-symbols.sfdir")
REPO_SHA = "9a4a2db2df7f0067b4ef43c5ae5bfcae3759a5a0" # v1.1.320
REPO_BASE = ("https://raw.githubusercontent.com/"
f"microsoft/fluentui-system-icons/{REPO_SHA}/assets")
GLYPH_WIDTH = 880

# Mapping: codepoint -> (fluent_icon_name, size, style, transform)
#
# See https://github.com/microsoft/fluentui-system-icons/tree/main/assets
# for available icons.

ICONS = {
0xE200: ("Line Horizontal 3", 20, "filled", None), # menu
0xE201: ("Play", 24, "filled", "flip_x"), # prev / play_backward
0xE202: ("Play", 24, "filled", None), # play / next
0xE203: ("Pause", 24, "filled", None), # pause
0xE204: ("Clock", 24, "regular", None), # clock (buffering)
0xE205: ("Rewind", 24, "filled", None), # skip_backward
0xE206: ("Fast Forward", 24, "filled", None), # skip_forward
0xE207: ("Previous", 24, "filled", None), # chapter_prev
0xE208: ("Next", 24, "filled", None), # chapter_next
0xE209: ("Chat", 24, "regular", None), # audio
0xE20A: ("Closed Caption", 24, "regular", None), # subtitle
0xE20B: ("Speaker Mute", 24, "filled", None), # mute
0xE20C: ("Speaker 0", 24, "filled", None), # volume[1]
0xE20D: ("Speaker 1", 24, "filled", None), # volume[2]
0xE20E: ("Speaker 2", 24, "filled", None), # volume[3]
0xE20F: ("Speaker 2", 24, "filled", "add_alert"),# volume[4] (>100%)
0xE210: ("Full Screen Maximize", 24, "filled", None), # fullscreen
0xE211: ("Full Screen Minimize", 24, "filled", None), # exit_fullscreen
0xE212: ("Dismiss", 24, "filled", None), # close
0xE213: ("Subtract", 24, "filled", None), # minimize
0xE214: ("Maximize", 24, "filled", None), # maximize
0xE215: ("Square Multiple", 24, "filled", None), # unmaximize
}


def icon_url(name, size, style):
snake = name.lower().replace(" ", "_")
filename = f"ic_fluent_{snake}_{size}_{style}.svg"
dir_encoded = urllib.parse.quote(name)
return f"{REPO_BASE}/{dir_encoded}/SVG/{filename}"


def download_icons(dest_dir):
paths = {}
seen: dict[str, str] = {}

for cp, (name, size, style, _transform) in ICONS.items():
url = icon_url(name, size, style)
svg_path = os.path.join(dest_dir, f"uni{cp:04X}.svg")

if url in seen:
# Reuse previously downloaded file.
import shutil
shutil.copy2(seen[url], svg_path)
paths[cp] = svg_path
print(f" U+{cp:04X} {name} (cached)")
continue

print(f" U+{cp:04X} {name} <- {url}")
try:
urllib.request.urlretrieve(url, svg_path)
seen[url] = svg_path
paths[cp] = svg_path
except urllib.error.HTTPError as e:
print(f" ERROR: {e.code} {e.reason} - check icon name/size")

return paths


def import_into_font(svg_paths):
transforms = {}
for cp, (_name, _size, _style, transform) in ICONS.items():
if transform:
transforms[cp] = transform

ff_script = f"""\
import fontforge
import psMat
import os

font = fontforge.open({SFDIR!r})
WIDTH = {GLYPH_WIDTH}

svg_paths = {svg_paths!r}
transforms = {transforms!r}

for cp, svg_path in sorted(svg_paths.items()):
if not os.path.exists(svg_path):
continue

glyph = font.createChar(cp)
glyph.clear()
glyph.importOutlines(svg_path)

# Scale to fit ascent (800 units) with padding
bb = glyph.boundingBox() # (xmin, ymin, xmax, ymax)
bw = bb[2] - bb[0]
bh = bb[3] - bb[1]
if bw == 0 or bh == 0:
print(f" SKIP U+{{cp:04X}} (empty)")
continue

target = 700 # leave some padding within 800-unit ascent
scale = min(target / bh, target / bw)
glyph.transform(psMat.scale(scale))

# Apply transform (e.g. horizontal flip for prev)
if cp in transforms and transforms[cp] == "flip_x":
glyph.transform(psMat.scale(-1, 1))

# Center in glyph
bb = glyph.boundingBox()
x_off = (WIDTH - (bb[2] + bb[0])) / 2
y_off = (800 - (bb[3] + bb[1])) / 2
glyph.transform(psMat.translate(x_off, y_off))

# Add alert indicator
if cp in transforms and transforms[cp] == "add_alert":
bb = glyph.boundingBox()
cx = (bb[0] + bb[2]) / 2
cy = (bb[1] + bb[3]) / 2
# Shrink icon to make room
glyph.transform(psMat.compose(
psMat.translate(-cx, -cy),
psMat.compose(psMat.scale(0.75),
psMat.translate(cx - 80, cy))))
# Draw exclamation mark (centered vertically at y=400)
pen = glyph.glyphPen(replace=False)
pen.moveTo((720, 630))
pen.lineTo((760, 630))
pen.lineTo((760, 300))
pen.lineTo((720, 300))
pen.closePath()
pen.moveTo((720, 240))
pen.lineTo((760, 240))
pen.lineTo((760, 170))
pen.lineTo((720, 170))
pen.closePath()
pen = None

glyph.width = WIDTH
print(f" U+{{cp:04X}} imported")

font.save({SFDIR!r})
print("Saved to", {SFDIR!r})
"""

with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
f.write(ff_script)
script_path = f.name

try:
subprocess.run(["fontforge", "-lang=py", "-script", script_path],check=True)
finally:
os.unlink(script_path)


def main():
print("Downloading Fluent UI System Icons...")
with tempfile.TemporaryDirectory() as tmpdir:
svg_paths = download_icons(tmpdir)
if not svg_paths:
print("No icons downloaded.")
sys.exit(1)

print(f"\nImporting {len(svg_paths)} icons into {SFDIR}...")
import_into_font(svg_paths)

print("\nDone. Run './TOOLS/gen-osd-font.sh' to rebuild the mpv font.")


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion TOOLS/mpv-osd-symbols.sfdir/font.props
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ OS2Version: 3
OS2_WeightWidthSlopeOnly: 0
OS2_UseTypoMetrics: 0
CreationTime: 1408646554
ModificationTime: 1735420479
ModificationTime: 1773309742
PfmFamily: 81
TTFWeight: 400
TTFWidth: 5
Expand Down
2 changes: 1 addition & 1 deletion TOOLS/mpv-osd-symbols.sfdir/uniE102.glyph
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SplineSet
0 640 l 1
0 800 l 1
880 800 l 1
880 640 l 1
880 640 l 1
880 320 m 1
0 320 l 1
0 480 l 1
Expand Down
31 changes: 31 additions & 0 deletions TOOLS/mpv-osd-symbols.sfdir/uniE200.glyph
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
StartChar: uniE200
Encoding: 57856 57856 36
Width: 880
VWidth: 1001
Flags: HW
LayerCount: 2
Fore
SplineSet
90 618.75 m 0
90 636.872070312 104.690429688 651.5625 122.8125 651.5625 c 2
757.1875 651.5625 l 2
775.30859375 651.5625 790 636.872070312 790 618.75 c 0
790 600.627929688 775.30859375 585.9375 757.1875 585.9375 c 2
122.8125 585.9375 l 2
104.690429688 585.9375 90 600.627929688 90 618.75 c 0
90 400 m 0
90 418.122070312 104.690429688 432.8125 122.8125 432.8125 c 2
757.1875 432.8125 l 2
775.30859375 432.8125 790 418.122070312 790 400 c 0
790 381.87890625 775.30859375 367.1875 757.1875 367.1875 c 2
122.8125 367.1875 l 2
104.690429688 367.1875 90 381.87890625 90 400 c 0
122.8125 214.0625 m 2
757.1875 214.0625 l 2
775.30859375 214.0625 790 199.37109375 790 181.25 c 0
790 163.12890625 775.30859375 148.4375 757.1875 148.4375 c 2
122.8125 148.4375 l 2
104.690429688 148.4375 90 163.12890625 90 181.25 c 0
90 199.37109375 104.690429688 214.0625 122.8125 214.0625 c 2
EndSplineSet
EndChar
17 changes: 17 additions & 0 deletions TOOLS/mpv-osd-symbols.sfdir/uniE201.glyph
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
StartChar: uniE201
Encoding: 57857 57857 37
Width: 880
VWidth: 1054
Flags: HW
LayerCount: 2
Fore
SplineSet
768.619140625 662.17578125 m 2
768.619140625 728.706054688 697.439453125 771.008789062 639.000976562 739.2109375 c 2
157.1640625 477.03515625 l 2
96.119140625 443.8203125 96.119140625 356.181640625 157.1640625 322.963867188 c 2
639.000976562 60.7880859375 l 2
697.439453125 28.9921875 768.619140625 71.296875 768.619140625 137.82421875 c 2
768.619140625 662.17578125 l 2
EndSplineSet
EndChar
17 changes: 17 additions & 0 deletions TOOLS/mpv-osd-symbols.sfdir/uniE202.glyph
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
StartChar: uniE202
Encoding: 57858 57858 38
Width: 880
VWidth: 1054
Flags: HW
LayerCount: 2
Fore
SplineSet
111.380859375 662.17578125 m 2
111.380859375 728.706054688 182.560546875 771.008789062 240.999023438 739.2109375 c 2
722.8359375 477.03515625 l 2
783.880859375 443.8203125 783.880859375 356.181640625 722.8359375 322.963867188 c 2
240.999023438 60.7880859375 l 2
182.560546875 28.9921875 111.380859375 71.296875 111.380859375 137.82421875 c 2
111.380859375 662.17578125 l 2
EndSplineSet
EndChar
28 changes: 28 additions & 0 deletions TOOLS/mpv-osd-symbols.sfdir/uniE203.glyph
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
StartChar: uniE203
Encoding: 57859 57859 39
Width: 880
VWidth: 1053
Flags: HW
LayerCount: 2
Fore
SplineSet
196.9453125 750 m 2
333.055664062 750 l 2
370.642578125 750 401.111328125 719.53125 401.111328125 681.944335938 c 2
401.111328125 118.055664062 l 2
401.111328125 80.46875 370.642578125 50 333.055664062 50 c 2
196.9453125 50 l 2
159.359375 50 128.888671875 80.46875 128.888671875 118.055664062 c 2
128.888671875 681.944335938 l 2
128.888671875 719.53125 159.359375 750 196.9453125 750 c 2
546.9453125 750 m 2
683.055664062 750 l 2
720.642578125 750 751.111328125 719.53125 751.111328125 681.944335938 c 2
751.111328125 118.055664062 l 2
751.111328125 80.46875 720.642578125 50 683.055664062 50 c 2
546.9453125 50 l 2
509.359375 50 478.888671875 80.46875 478.888671875 118.055664062 c 2
478.888671875 681.944335938 l 2
478.888671875 719.53125 509.359375 750 546.9453125 750 c 2
EndSplineSet
EndChar
33 changes: 33 additions & 0 deletions TOOLS/mpv-osd-symbols.sfdir/uniE204.glyph
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
StartChar: uniE204
Encoding: 57860 57860 40
Width: 880
VWidth: 987
Flags: HW
LayerCount: 2
Fore
SplineSet
142.5 400 m 0
142.5 235.696289062 275.6953125 102.5 440 102.5 c 0
604.302734375 102.5 737.5 235.696289062 737.5 400 c 0
737.5 564.303710938 604.302734375 697.5 440 697.5 c 0
275.6953125 697.5 142.5 564.303710938 142.5 400 c 0
440 750 m 0
633.296875 750 790 593.299804688 790 400 c 0
790 206.702148438 633.296875 50 440 50 c 0
246.700195312 50 90 206.702148438 90 400 c 0
90 593.299804688 246.700195312 750 440 750 c 0
439.758789062 587.309570312 m 2
440 583.75 l 1
440 400 l 1
553.75 400 l 2
568.240234375 400 580 388.240234375 580 373.75 c 0
580 360.467773438 570.119140625 349.477539062 557.309570312 347.741210938 c 2
553.75 347.5 l 1
413.75 347.5 l 2
400.466796875 347.5 389.477539062 357.380859375 387.741210938 370.190429688 c 2
387.5 373.75 l 1
387.5 583.75 l 2
387.5 598.239257812 399.259765625 610 413.75 610 c 0
427.032226562 610 438.021484375 600.118164062 439.758789062 587.309570312 c 2
EndSplineSet
EndChar
28 changes: 28 additions & 0 deletions TOOLS/mpv-osd-symbols.sfdir/uniE205.glyph
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
StartChar: uniE205
Encoding: 57861 57861 41
Width: 880
VWidth: 1018
Flags: HW
LayerCount: 2
Fore
SplineSet
385.713867188 681.48046875 m 2
421.602539062 712.025390625 476.805664062 686.518554688 476.805664062 639.389648438 c 2
476.805664062 492.393554688 l 1
698.908203125 681.41796875 l 2
734.795898438 711.962890625 790 686.45703125 790 639.328125 c 2
790 160.588867188 l 2
790 128.21875 763.95703125 106.048828125 736.01953125 105.234375 c 2
732.8359375 105.234375 l 2
721.111328125 105.577148438 709.213867188 109.7265625 698.908203125 118.49609375 c 2
476.805664062 307.513671875 l 1
476.805664062 160.647460938 l 2
476.805664062 113.521484375 421.60546875 88.0166015625 385.713867188 118.557617188 c 2
112.690429688 350.908203125 l 2
82.4365234375 376.655273438 82.4365234375 423.369140625 112.689453125 449.118164062 c 2
385.713867188 681.48046875 l 2
112.689453125 449.118164062 m 1
130.600585938 428.075195312 l 1
112.689453125 449.118164062 l 1
EndSplineSet
EndChar
Loading
Loading