utils/mpv/mpv-no-libass.patch
$ cat mpv-no-libass.patch
diff --git a/meson.build b/meson.build
index c3cee39..352daaa 100644
--- a/meson.build
+++ b/meson.build
@@ -23,13 +23,13 @@ libavutil = dependency('libavutil', version: '>= 56.70.100')
 libswresample = dependency('libswresample', version: '>= 3.9.100')
 libswscale = dependency('libswscale', version: '>= 5.9.100')
 
-libass = dependency('libass', version: '>= 0.12.2')
+libass = dependency('libass', version: '>= 0.12.2', required: get_option('libass'))
 pthreads = dependency('threads')
 
 # the dependency order of libass -> ffmpeg is necessary due to
 # static linking symbol resolution between fontconfig and MinGW
-dependencies = [libass,
-                libavcodec,
+dependencies = [
+                libavcodec,
                 libavfilter,
                 libavformat,
                 libavutil,
@@ -44,7 +44,7 @@ features = {
     'gpl': get_option('gpl'),
     'jpegxl': libavformat.version().version_compare('>= 59.27.100'),
     'avif_muxer': libavformat.version().version_compare('>= 59.24.100'),
-    'libass': true,
+    'libass': libass.found(),
     'threads': true,
 }
 
@@ -181,75 +181,84 @@ sources = files(
     'stream/stream_slice.c',
 
     ## Subtitles
-    'sub/ass_mp.c',
     'sub/dec_sub.c',
     'sub/draw_bmp.c',
-    'sub/filter_sdh.c',
     'sub/img_convert.c',
-    'sub/lavc_conv.c',
     'sub/osd.c',
-    'sub/osd_libass.c',
-    'sub/sd_ass.c',
-    'sub/sd_lavc.c',
 
     ## Video
     'video/csputils.c',
     'video/decode/vd_lavc.c',
     'video/filter/refqueue.c',
     'video/filter/vf_format.c',
     'video/filter/vf_sub.c',
     'video/fmt-conversion.c',
     'video/hwdec.c',
     'video/image_loader.c',
     'video/image_writer.c',
     'video/img_format.c',
     'video/mp_image.c',
     'video/mp_image_pool.c',
     'video/out/aspect.c',
     'video/out/bitmap_packer.c',
     'video/out/dither.c',
     'video/out/dr_helper.c',
     'video/out/filter_kernels.c',
     'video/out/gpu/context.c',
     'video/out/gpu/error_diffusion.c',
     'video/out/gpu/hwdec.c',
     'video/out/gpu/lcms.c',
     'video/out/gpu/libmpv_gpu.c',
     'video/out/gpu/osd.c',
     'video/out/gpu/ra.c',
     'video/out/gpu/shader_cache.c',
     'video/out/gpu/spirv.c',
     'video/out/gpu/user_shaders.c',
     'video/out/gpu/utils.c',
     'video/out/gpu/video.c',
     'video/out/gpu/video_shaders.c',
     'video/out/libmpv_sw.c',
     'video/out/vo.c',
     'video/out/vo_gpu.c',
     'video/out/vo_image.c',
     'video/out/vo_lavc.c',
     'video/out/vo_libmpv.c',
     'video/out/vo_null.c',
     'video/out/vo_tct.c',
     'video/out/vo_kitty.c',
     'video/out/win_state.c',
     'video/repack.c',
     'video/sws_utils.c',
 
     ## osdep
     'osdep/io.c',
     'osdep/semaphore_osx.c',
     'osdep/subprocess.c',
     'osdep/threads.c',
     'osdep/timer.c',
 
     ## tree_allocator
     'ta/ta.c',
     'ta/ta_talloc.c',
     'ta/ta_utils.c'
 )
 
 
+if features['libass']
+    dependencies = [libass] + dependencies
+    sources += files(
+        'sub/ass_mp.c',
+        'sub/filter_sdh.c',
+        'sub/lavc_conv.c',
+        'sub/osd_libass.c',
+        'sub/sd_ass.c',
+        'sub/sd_lavc.c',
+    )
+else
+    sources += files('sub/osd_dummy.c')
+endif
+
+
 # compiler stuff
 cc = meson.get_compiler('c')
 
diff --git a/meson_options.txt b/meson_options.txt
index 5f2d31d..3420d41 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -15,6 +15,7 @@ option('dvbin', type: 'feature', value: 'disabled', description: 'DVB input modu
 option('dvdnav', type: 'feature', value: 'disabled', description: 'dvdnav support')
 option('iconv', type: 'feature', value: 'auto', description: 'iconv')
 option('javascript', type: 'feature', value: 'auto', description: 'Javascript (MuJS backend)')
+option('libass', type: 'feature', value: 'enabled', description: 'SSA/ASS subtitles and graphical text OSD')
 option('lcms2', type: 'feature', value: 'auto', description: 'LCMS2 support')
 option('libarchive', type: 'feature', value: 'auto', description: 'libarchive wrapper for reading zip files and more')
 option('libavdevice', type: 'feature', value: 'auto', description: 'libavdevice')
diff --git a/player/command.c b/player/command.c
index 0eb13a7..e398bc2 100644
--- a/player/command.c
+++ b/player/command.c
@@ -27,7 +27,11 @@
 #include <pthread.h>
 #include <sys/types.h>
 
+#include "config.h"
+
+#if HAVE_LIBASS
 #include <ass/ass.h>
+#endif
 #include <libavutil/avstring.h>
 #include <libavutil/common.h>
 
@@ -3310,7 +3314,11 @@ static int mp_property_ffmpeg(void *ctx, struct m_property *prop,
 static int mp_property_libass_version(void *ctx, struct m_property *prop,
                                       int action, void *arg)
 {
+#if HAVE_LIBASS
     return m_property_int64_ro(action, arg, ass_library_version());
+#else
+    return M_PROPERTY_UNAVAILABLE;
+#endif
 }
 
 static int mp_property_platform(void *ctx, struct m_property *prop,
diff --git a/sub/dec_sub.c b/sub/dec_sub.c
index 30f5b65..acd5eed 100644
--- a/sub/dec_sub.c
+++ b/sub/dec_sub.c
@@ -22,6 +22,8 @@
 #include <assert.h>
 #include <pthread.h>
 
+#include "config.h"
+
 #include "demux/demux.h"
 #include "sd.h"
 #include "dec_sub.h"
@@ -33,12 +35,16 @@
 #include "misc/dispatch.h"
 #include "osdep/threads.h"
 
+#if HAVE_LIBASS
 extern const struct sd_functions sd_ass;
 extern const struct sd_functions sd_lavc;
+#endif
 
 static const struct sd_functions *const sd_list[] = {
+#if HAVE_LIBASS
     &sd_lavc,
     &sd_ass,
+#endif
     NULL
 };
 
diff --git a/sub/osd_dummy.c b/sub/osd_dummy.c
new file mode 100644
index 0000000..0339e3d
--- /dev/null
+++ b/sub/osd_dummy.c
@@ -0,0 +1,101 @@
+/*
+ * no-op OSD backend for builds without libass
+ */
+
+#include <string.h>
+
+#include "common/msg.h"
+#include "osd.h"
+#include "osd_state.h"
+#include "sd.h"
+
+void osd_init_backend(struct osd_state *osd)
+{
+}
+
+void osd_destroy_backend(struct osd_state *osd)
+{
+}
+
+struct sub_bitmaps *osd_object_get_bitmaps(struct osd_state *osd,
+                                           struct osd_object *obj, int format)
+{
+    return NULL;
+}
+
+void osd_set_external(struct osd_state *osd, struct osd_external_ass *ov)
+{
+}
+
+void osd_set_external_remove_owner(struct osd_state *osd, void *owner)
+{
+}
+
+void osd_get_text_size(struct osd_state *osd, int *out_screen_h, int *out_font_h)
+{
+    *out_screen_h = 0;
+    *out_font_h = 0;
+}
+
+void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function)
+{
+    if (buffer_size)
+        buffer[0] = '\0';
+}
+
+int sd_ass_fmt_offset(const char *event_format)
+{
+    int n = 0;
+    while (event_format && (event_format = strchr(event_format, ','))) {
+        event_format++;
+        n++;
+    }
+    return n - 1;
+}
+
+bstr sd_ass_pkt_text(struct sd_filter *ft, struct demux_packet *pkt, int offset)
+{
+    bstr text = {(char *)pkt->buffer, pkt->len};
+    bstr original = text;
+
+    while (offset-- > 0) {
+        int comma = bstrchr(text, ',');
+        if (comma < 0) {
+            MP_WARN(ft, "Malformed event '%.*s'\n", BSTR_P(original));
+            return (bstr){NULL, 0};
+        }
+        text = bstr_cut(text, comma + 1);
+    }
+    return text;
+}
+
+bstr sd_ass_to_plaintext(char *out, size_t out_size, const char *in)
+{
+    size_t length = 0;
+    bool in_override = false;
+
+    while (*in) {
+        char c = *in++;
+
+        if (c == '{') {
+            in_override = true;
+            continue;
+        }
+        if (in_override) {
+            if (c == '}')
+                in_override = false;
+            continue;
+        }
+        if (c == '\\' && (*in == 'N' || *in == 'n' || *in == 'h')) {
+            c = *in == 'h' ? ' ' : '\n';
+            in++;
+        }
+        if (length < out_size)
+            out[length] = c;
+        length++;
+    }
+
+    if (length < out_size)
+        out[length] = '\0';
+    return (bstr){out, length < out_size ? length : out_size};
+}
diff --git a/version.py b/version.py
index 78db0c5..9118f0e 100755
--- a/version.py
+++ b/version.py
@@ -6,7 +6,7 @@ import time
 
 from datetime import datetime,timezone
 from shutil import which
-from subprocess import check_output, DEVNULL
+from subprocess import check_output, CalledProcessError, DEVNULL
 
 srcdir = os.path.dirname(os.path.abspath(sys.argv[0]))
 git_dir = os.path.join(srcdir, ".git")
@@ -14,10 +14,15 @@ git = which('git')
 
 if git and os.path.exists(git_dir):
     # stdin is set to DEVNULL to workaround waf preforking issues
-    version = check_output([git, "-C", srcdir, "describe", "--always", "--tags",
-                            "--dirty"], stdin=DEVNULL, encoding="UTF-8")
-    version = version[1:].strip()
-else:
+    try:
+        version = check_output([git, "-C", srcdir, "describe", "--always",
+                                "--tags", "--dirty"], stdin=DEVNULL,
+                               stderr=DEVNULL, encoding="UTF-8")
+        version = version[1:].strip()
+    except CalledProcessError:
+        git = None
+
+if not git or not os.path.exists(git_dir):
     version_path = os.path.join(srcdir, "VERSION")
     with open(version_path, "r") as f:
         version = f.readline().strip()
diff --git a/wscript b/wscript
index 82f65b4..29329bc 100644
--- a/wscript
+++ b/wscript
@@ -334,7 +334,7 @@ iconv support use --disable-iconv.",
         'desc' : 'Javascript (MuJS backend)',
         'func': check_pkg_config('mujs', '>= 1.0.0'),
     }, {
-        'name': 'libass',
+        'name': '--libass',
         'desc': 'SSA/ASS support',
         'func': check_pkg_config('libass', '>= 0.12.2'),
         'req': True,
diff --git a/wscript_build.py b/wscript_build.py
index a470808..062e215 100644
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -432,18 +432,19 @@ def build(ctx):
         ( "stream/stream_null.c" ),
 
         ## Subtitles
-        ( "sub/ass_mp.c" ),
+        ( "sub/ass_mp.c",                    "libass" ),
         ( "sub/dec_sub.c" ),
         ( "sub/draw_bmp.c" ),
         ( "sub/filter_regex.c",                  "posix" ),
         ( "sub/filter_jsre.c",                   "javascript" ),
-        ( "sub/filter_sdh.c" ),
+        ( "sub/filter_sdh.c",                "libass" ),
         ( "sub/img_convert.c" ),
-        ( "sub/lavc_conv.c" ),
+        ( "sub/lavc_conv.c",                 "libass" ),
         ( "sub/osd.c" ),
-        ( "sub/osd_libass.c" ),
-        ( "sub/sd_ass.c" ),
-        ( "sub/sd_lavc.c" ),
+        ( "sub/osd_libass.c",                "libass" ),
+        ( "sub/osd_dummy.c",                 "!libass" ),
+        ( "sub/sd_ass.c",                    "libass" ),
+        ( "sub/sd_lavc.c",                   "libass" ),
 
         ## Video
         ( "video/csputils.c" ),