/** * Use fontconfig or sub-fonts-dir to load the font files in the fonts folder under the playback file path */ 'use strict'; var FONTCONFIG_XML_TEMPLATE = '%s'; var FONTCONFIG_DIR_XML_TEMPLATE = '%s'; var FONTS_SUB_DIRS = ['fonts', 'Fonts', 'FONTS', '字体']; var msg = mp.msg; var commands = require('../script-modules/commands'); var io = require('../script-modules/io'); var p = require('../script-modules/path'); var u = require('../script-modules/utils'); var options = { enable: true, compatible_mode: false, compatible_dir: '~~/.fonts', method: mp.get_property_native('property-list').indexOf('sub-fonts-dir') !== -1 ? 'native' : 'fontconfig', // fontconfig or native }; var state = { compatible_fonts_dir: '', external_fonts_dir: null, fonts_conf: commands.expand_path('~~/.fonts.conf'), /** @type {string|null} */ last_compatible_dir: null, /** @type {string|null} */ last_fonts_dir: null, os: require('../script-modules/DetectOS')(), ready: false, set_fonts_dir: false, }; /** * @returns {boolean} */ function check_ready() { return (options.method === 'fontconfig' && mp.get_property_native('sub-font-provider') === 'fontconfig') || (options.method === 'native' && mp.get_property_native('property-list').indexOf('sub-fonts-dir') !== -1); } function clear_fonts() { if (io.dir_exist(state.compatible_fonts_dir)) { io.remove_dir(state.compatible_fonts_dir); } } /** * @param {string} dir * @returns {boolean} */ function copy_fonts(dir) { return (io.dir_exist(options.compatible_dir) || io.create_dir(options.compatible_dir)) && io.copy_dir(dir, state.compatible_fonts_dir); } /** * @param {string} str * @returns {string} */ function escape_xml(str) { return str .replace(//g, '>') .replace(/&/g, '&') .replace(/'/g, ''') .replace(/"/g, '"'); } /** * @param {string} path * @returns {string} */ function format_path(path) { return state.os === 'windows' ? p.format_windows_path(path) : path; } /** * @param {string} path * @returns {string|null} */ function get_available_fonts_dir(path) { var fonts_dir = null; for (var i = 0; i < FONTS_SUB_DIRS.length; i++) { var dir = p.absolute_path(p.join_path(path, FONTS_SUB_DIRS[i])); if (io.dir_exist(dir)) { fonts_dir = format_path(dir); break; } } return fonts_dir; } /** * @returns {string} */ function get_compatible_fonts_dir() { var base = p.join_path(options.compatible_dir, mp.get_script_name() + '$'); for (var i = 1; ; i++) { var path = base + i; if (!io.dir_exist(path)) { return path; } } } /** * @param {string} dir */ function load_fonts_dir(dir) { if (options.method === 'fontconfig') { write_fonts_conf(dir, false); } if (options.method === 'native') { mp.set_property_native('sub-fonts-dir', dir); } } /** * @param {?string} dir */ function set_fonts_dir(dir) { var fonts_dir = dir; // 如果没有字体目录并且之前设置了字体目录,那么清空配置文件。 if (typeof fonts_dir !== 'string' || fonts_dir.trim() === '') { if (state.set_fonts_dir) { load_fonts_dir(null); state.set_fonts_dir = false; } return; } if (fonts_dir && (!options.enable || !state.ready)) { msg.warn('The fonts directory exists, but the script is not enabled.'); return; } var source_fonts_dir = fonts_dir; if (state.last_fonts_dir === source_fonts_dir) { return; } if (options.compatible_mode) { clear_fonts(); state.compatible_fonts_dir = get_compatible_fonts_dir(); if (copy_fonts(source_fonts_dir)) { fonts_dir = state.compatible_fonts_dir; } else { msg.error(u.string_format("Copy fonts directory failed: '%s' -> '%s'", source_fonts_dir, state.compatible_fonts_dir)); } } state.last_fonts_dir = source_fonts_dir; state.set_fonts_dir = true; load_fonts_dir(fonts_dir); if (fonts_dir === source_fonts_dir) { msg.info(u.string_format('Use %s to set the font directory: %s', options.method, fonts_dir)); } else { msg.info(u.string_format('Use %s to set the font directory (compatible_mode): %s (%s)', options.method, fonts_dir, source_fonts_dir)); } } function unload_fonts_dir() { if (options.method === 'fontconfig') { write_fonts_conf('', true); } if (options.method === 'native') { mp.set_property_native('sub-fonts-dir', ''); } } function update_options() { if (options.compatible_mode && !state.os) { options.compatible_mode = false; msg.warn('Unknown OS detected, compatibility mode disabled.'); } options.compatible_dir = format_path(commands.expand_path(options.compatible_dir)); // 如果兼容目录已更改则清理旧目录 if (state.last_compatible_dir !== options.compatible_dir) { clear_fonts(); } state.last_compatible_dir = options.compatible_dir; state.last_fonts_dir = null; state.ready = check_ready(); } /** * @param {string} fonts_dir * @param {boolean} require_exist */ function write_fonts_conf(fonts_dir, require_exist) { var exist = io.file_exist(state.fonts_conf); // 做一些检查,避免无用的重复写入。 if (require_exist && !exist) { return; } var xml = fonts_dir === '' ? '' : u.string_format(FONTCONFIG_DIR_XML_TEMPLATE, escape_xml(fonts_dir)); var data = u.string_format(FONTCONFIG_XML_TEMPLATE, xml); if (exist & io.read_file(state.fonts_conf) === data) { return; } io.write_file(state.fonts_conf, data); } mp.options.read_options(options, 'auto_load_fonts', function () { if (!options.enable) { state.set_fonts_dir = false; mp.set_property_native('sub-fonts-dir', ''); write_fonts_conf('', true); clear_fonts(); } update_options(); }); update_options(); mp.observe_property('sub-font-provider', 'native', function () { state.ready = check_ready(); }); mp.add_hook('on_load', 50, function () { if (mp.get_property_native('playback-abort')) { return; } var fonts_dir = null; var path = mp.get_property_native('path'); var spaths = p.split_path(path); var current_dir = spaths[0]; var sub_paths = mp.get_property_native('sub-file-paths') || []; sub_paths.unshift(''); for (var i = 0; !fonts_dir && i < sub_paths.length; i++) { fonts_dir = get_available_fonts_dir(p.join_path(current_dir, sub_paths[i])); } if (state.external_fonts_dir) { fonts_dir = state.external_fonts_dir; state.external_fonts_dir = null; } set_fonts_dir(fonts_dir); }); mp.register_event('shutdown', function () { unload_fonts_dir(); clear_fonts(); });