fontist 1.17.0 → 1.18.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1c609003084e7675dfd55c7488c57b9f216a7e9f6412e2dd707e589bdb5f11e
4
- data.tar.gz: ff531fc17364227dc60b47eaa64fe5547bc9c1d30e05c94364109d79d7276b5e
3
+ metadata.gz: 7df8791fd4754d729546380e67e6c29866f12e4d85bb917b427284c1be610dff
4
+ data.tar.gz: be7991cacf763d3abc89aeea2841d02b4cc58b7e3a24c99551ee48639b07a3f8
5
5
  SHA512:
6
- metadata.gz: 2bcb373787926878310fa113e4454ac09e203c82708bd2edb3df796ce1e92f7e038a5c54011aade53f7cbc2ac2f20c311e449d5d5304a0235b93bfb0433750de
7
- data.tar.gz: 6ad5b3863ed427316065477a3c873264ffa6d543bb86be696396e61d8f727533bc8bb50268ce8818b45bb15da387e6913b88f2c1a9abb7ed4a4944e0a8d57691
6
+ metadata.gz: 5ec6f6dfa9169caddd99e3641d05864d49bb1bfa2f59ae4887dd72b703c18c599628711fa5f414cb5863832f14751fddc7536cea549358eebbb926231eaf7651
7
+ data.tar.gz: a87e924b0741861b59114ae75ea93a09ba86eb43510787501f20980a488ec3a181bba20ea0307e6b7f51f83d989c0edaf7db7ea1c74680534eec3280dc1a8d47
@@ -45,6 +45,7 @@ jobs:
45
45
  bundler-cache: true
46
46
 
47
47
  - if: matrix.os == 'macos-latest'
48
+ name: Run tests including dev ones
48
49
  run: |
49
50
  brew install lcdf-typetools
50
51
  bundle exec rspec
data/README.adoc CHANGED
@@ -78,6 +78,9 @@ NOTE: See <<preferred-family-change>> for the differences between
78
78
  `-v, --verbose`:: Set the log level to debug. It prints formulas excluded
79
79
  during installation and information for developers of fontist.
80
80
 
81
+ `-c, --no-cache`:: Prefer direct download even when a file is already cached in
82
+ a system.
83
+
81
84
  === Install fonts: `fontist install`
82
85
 
83
86
  Fontist checks whether this font is already installed, and if not, then installs
@@ -299,6 +302,39 @@ Roboto Mono:
299
302
  - "/Users/user/.fontist/fonts/RobotoMono-VariableFont_wght.ttf"
300
303
  ----
301
304
 
305
+ === Work with fontist config: `fontist config`
306
+
307
+ Fontist supports system-wide settings for the following parameters:
308
+
309
+ `open_timeout`:: Sets timeout for opening a connection during download
310
+ (default: 10)
311
+
312
+ `read_timeout`:: Sets timeout for reading the opened connection during download
313
+ (default: 10)
314
+
315
+ Show current attributes in the config:
316
+
317
+ [source,sh]
318
+ ----
319
+ $ fontist config show
320
+ Current config:
321
+ read_timeout: 5
322
+ ----
323
+
324
+ Assign a value to an attribute:
325
+
326
+ [source,sh]
327
+ ----
328
+ $ fontist config set read_timeout 60
329
+ ----
330
+
331
+ Restore a default value of an attribute:
332
+
333
+ [source,sh]
334
+ ----
335
+ $ fontist config delete read_timeout
336
+ ----
337
+
302
338
  === Work with Fontconfig: `fontist fontconfig`
303
339
 
304
340
  Fontconfig is a software designed to provide fonts to other programs. It is
@@ -621,6 +657,15 @@ Apple Support site:
621
657
  WARNING: Fontist does not allow installing macOS-specific fonts on non-macOS
622
658
  platforms due to font license restrictions of those fonts.
623
659
 
660
+ === Known problematic fonts
661
+
662
+ * NISC18030.ttf (GB18030 Bitmap) - macOS, more info in
663
+ https://github.com/fontist/fontist/issues/344[the NISC18030 issue]
664
+
665
+ The full list of known problematic fonts:
666
+
667
+ * https://github.com/fontist/fontist/blob/main/lib/fontist/exclude.yml[List of fonts excluded from usage]
668
+
624
669
 
625
670
  == Advanced usage
626
671
 
@@ -826,7 +871,7 @@ For file paths, specify the file path as argument:
826
871
 
827
872
  [source,sh]
828
873
  ----
829
- wget https://www.latofonts.com/download/lato2ofl-zip/
874
+ wget https://www.latofonts.com/files/Lato2OFL.zip
830
875
  fontist create-formula lato.zip
831
876
  ----
832
877
 
@@ -834,7 +879,7 @@ For URLs, simply specify the URL as the argument:
834
879
 
835
880
  [source,sh]
836
881
  ----
837
- fontist create-formula https://www.latofonts.com/download/lato2ofl-zip/
882
+ fontist create-formula https://www.latofonts.com/files/Lato2OFL.zip
838
883
  # > file created at lato.yml because the file downloaded is lato.zip
839
884
  ----
840
885
 
@@ -843,7 +888,7 @@ private formula repository location.
843
888
 
844
889
  [source,sh]
845
890
  ----
846
- fontist create-formula https://www.latofonts.com/download/lato2ofl-zip/
891
+ fontist create-formula https://www.latofonts.com/files/Lato2OFL.zip
847
892
  cp lato.yml ~/.fontist/formulas/Formulas/
848
893
  ----
849
894
 
data/fontist.gemspec CHANGED
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
31
31
 
32
32
  spec.add_runtime_dependency "down", "~> 5.0"
33
33
  spec.add_runtime_dependency "extract_ttc", "~> 0.1"
34
+ spec.add_runtime_dependency "json", "~> 2.0"
34
35
  spec.add_runtime_dependency "nokogiri", "~> 1.0"
35
36
  spec.add_runtime_dependency "mime-types", "~> 3.0"
36
37
  spec.add_runtime_dependency "sys-uname", "~> 1.2"
@@ -1,9 +1,37 @@
1
1
  module Fontist
2
2
  class CLI < Thor
3
3
  module ClassOptions
4
+ # rubocop:disable Metrics/MethodLength
5
+ def self.included(base)
6
+ base.class_option :preferred_family,
7
+ type: :boolean,
8
+ desc: "Use Preferred Family when available"
9
+
10
+ base.class_option :quiet,
11
+ aliases: :q,
12
+ type: :boolean,
13
+ desc: "Hide all messages"
14
+
15
+ base.class_option :verbose,
16
+ aliases: :v,
17
+ type: :boolean,
18
+ desc: "Print debug messages"
19
+
20
+ base.class_option :no_cache,
21
+ aliases: :c,
22
+ type: :boolean,
23
+ desc: "Avoid using cache during download"
24
+
25
+ base.class_option :formulas_path,
26
+ type: :string,
27
+ desc: "Path to formulas"
28
+ end
29
+ # rubocop:enable Metrics/MethodLength
30
+
4
31
  def handle_class_options(options)
5
32
  Fontist.preferred_family = options[:preferred_family]
6
33
  Fontist.log_level = log_level(options)
34
+ Fontist.use_cache = !options[:no_cache]
7
35
 
8
36
  if options[:formulas_path]
9
37
  Fontist.formulas_path = Pathname.new(options[:formulas_path])
data/lib/fontist/cli.rb CHANGED
@@ -4,6 +4,7 @@ require "fontist/repo_cli"
4
4
  require "fontist/cache_cli"
5
5
  require "fontist/import_cli"
6
6
  require "fontist/fontconfig_cli"
7
+ require "fontist/config_cli"
7
8
 
8
9
  module Fontist
9
10
  class CLI < Thor
@@ -58,22 +59,6 @@ module Fontist
58
59
  false
59
60
  end
60
61
 
61
- class_option :preferred_family,
62
- type: :boolean,
63
- desc: "Use Preferred Family when available"
64
-
65
- class_option :quiet,
66
- aliases: :q,
67
- type: :boolean,
68
- desc: "Hide all messages"
69
-
70
- class_option :verbose,
71
- aliases: :v,
72
- type: :boolean,
73
- desc: "Print debug messages"
74
-
75
- class_option :formulas_path, type: :string, desc: "Path to formulas"
76
-
77
62
  desc "install FONT", "Install font"
78
63
  option :force, type: :boolean, aliases: :f,
79
64
  desc: "Install even if already installed in system"
@@ -221,6 +206,9 @@ module Fontist
221
206
  desc "fontconfig SUBCOMMAND ...ARGS", "Manage fontconfig"
222
207
  subcommand "fontconfig", Fontist::FontconfigCLI
223
208
 
209
+ desc "config SUBCOMMAND ...ARGS", "Manage fontist config"
210
+ subcommand "config", Fontist::ConfigCLI
211
+
224
212
  desc "cache SUBCOMMAND ...ARGS", "Manage fontist cache"
225
213
  subcommand "cache", Fontist::CacheCLI
226
214
 
@@ -0,0 +1,46 @@
1
+ require "ttfunk"
2
+
3
+ module Fontist
4
+ class CollectionFile
5
+ include Enumerable
6
+
7
+ class << self
8
+ def from_path(path)
9
+ io = ::File.new(path, "rb")
10
+
11
+ yield new(build_collection(io))
12
+ ensure
13
+ io.close
14
+ end
15
+
16
+ private
17
+
18
+ def build_collection(io)
19
+ TTFunk::Collection.new(io)
20
+ rescue StandardError => e
21
+ raise Errors::FontFileError,
22
+ "Font file could not be parsed: #{e.inspect}."
23
+ end
24
+ end
25
+
26
+ def initialize(ttfunk_collection)
27
+ @collection = ttfunk_collection
28
+ end
29
+
30
+ def count
31
+ @collection.count
32
+ end
33
+
34
+ def each
35
+ count.times do |index|
36
+ yield self[index]
37
+ end
38
+
39
+ self
40
+ end
41
+
42
+ def [](index)
43
+ FontFile.from_collection_index(@collection, index)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ module Fontist
2
+ class Config
3
+ include Singleton
4
+
5
+ def initialize
6
+ @custom_values = load_config_file
7
+ end
8
+
9
+ def values
10
+ default_values.merge(@custom_values)
11
+ end
12
+
13
+ def custom_values
14
+ @custom_values
15
+ end
16
+
17
+ def set(key, value)
18
+ v = normalize_value(value)
19
+ @custom_values[key.to_s] = v
20
+
21
+ persist
22
+ end
23
+
24
+ def delete(key)
25
+ @custom_values.delete(key.to_s)
26
+
27
+ persist
28
+ end
29
+
30
+ def default_value(key)
31
+ default_values[key.to_s]
32
+ end
33
+
34
+ def default_values
35
+ { open_timeout: 10,
36
+ read_timeout: 10 }.transform_keys(&:to_s)
37
+ end
38
+
39
+ def persist
40
+ FileUtils.mkdir_p(File.dirname(Fontist.config_path))
41
+ File.write(Fontist.config_path, YAML.dump(@custom_values))
42
+ end
43
+
44
+ def load
45
+ @custom_values = load_config_file
46
+ end
47
+
48
+ private
49
+
50
+ def load_config_file
51
+ return {} unless File.exist?(Fontist.config_path)
52
+
53
+ YAML.load_file(Fontist.config_path)
54
+ end
55
+
56
+ def normalize_value(value)
57
+ return value.to_i if value.to_i.to_s == value # detect integer
58
+
59
+ value
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,40 @@
1
+ module Fontist
2
+ class ConfigCLI < Thor
3
+ include CLI::ClassOptions
4
+
5
+ STATUS_SUCCESS = 0
6
+
7
+ desc "show", "Show values of the current config"
8
+ def show
9
+ handle_class_options(options)
10
+ values = Config.instance.custom_values
11
+ Fontist.ui.success("Current config:")
12
+ Fontist.ui.success(format_hash(values))
13
+ STATUS_SUCCESS
14
+ end
15
+
16
+ desc "set KEY VALUE", "Set the KEY attribute to VALUE in the current config"
17
+ def set(key, value)
18
+ handle_class_options(options)
19
+ Config.instance.set(key, value)
20
+ Fontist.ui.success("'#{key}' set to '#{value}'.")
21
+ STATUS_SUCCESS
22
+ end
23
+
24
+ desc "delete KEY", "Delete the KEY attribute from the current config"
25
+ def delete(key)
26
+ handle_class_options(options)
27
+ Config.instance.delete(key)
28
+ Fontist.ui.success(
29
+ "'#{key}' reset to default ('#{Config.instance.default_value(key)}').",
30
+ )
31
+ STATUS_SUCCESS
32
+ end
33
+
34
+ private
35
+
36
+ def format_hash(hash)
37
+ YAML.dump(hash).gsub(/^---.*$/, "").strip
38
+ end
39
+ end
40
+ end
@@ -18,6 +18,8 @@ module Fontist
18
18
 
19
19
  class FontIndexCorrupted < GeneralError; end
20
20
 
21
+ class FontFileError < GeneralError; end
22
+
21
23
  class FontistVersionError < GeneralError; end
22
24
 
23
25
  class FontNotFoundError < GeneralError; end
@@ -0,0 +1 @@
1
+ - NISC18030.ttf
@@ -0,0 +1,109 @@
1
+ require "ttfunk"
2
+
3
+ module Fontist
4
+ class FontFile
5
+ PLATFORM_MACINTOSH = 1
6
+ PLATFORM_MICROSOFT = 3
7
+
8
+ ENCODING_MAC_ROMAN = 0
9
+ ENCODING_MS_UNICODE_BMP = 1
10
+
11
+ LANGUAGE_MAC_ENGLISH = 0
12
+ LANGUAGE_MS_ENGLISH_AMERICAN = 0x409
13
+
14
+ class << self
15
+ def from_path(path)
16
+ content = File.read(path, mode: "rb")
17
+
18
+ from_content(content)
19
+ end
20
+
21
+ def from_content(content)
22
+ new(build_font(content))
23
+ end
24
+
25
+ def from_collection_index(collection, index)
26
+ new(build_font_from_collection_index(collection, index))
27
+ end
28
+
29
+ private
30
+
31
+ def build_font(content)
32
+ TTFunk::File.new(content)
33
+ rescue StandardError => e
34
+ raise_font_file_error(e)
35
+ end
36
+
37
+ def build_font_from_collection_index(collection, index)
38
+ collection[index]
39
+ rescue StandardError => e
40
+ raise_font_file_error(e)
41
+ end
42
+
43
+ def raise_font_file_error(exception)
44
+ raise Errors::FontFileError,
45
+ "Font file could not be parsed: #{exception.inspect}."
46
+ end
47
+ end
48
+
49
+ def initialize(ttfunk_file)
50
+ @file = ttfunk_file
51
+ end
52
+
53
+ def full_name
54
+ english_name(main_name.font_name)
55
+ end
56
+
57
+ def family
58
+ english_name(main_name.font_family)
59
+ end
60
+
61
+ def subfamily
62
+ english_name(main_name.font_subfamily)
63
+ end
64
+
65
+ def preferred_family
66
+ return if main_name.preferred_family.empty?
67
+
68
+ english_name(main_name.preferred_family)
69
+ end
70
+
71
+ def preferred_subfamily
72
+ return if main_name.preferred_subfamily.empty?
73
+
74
+ english_name(main_name.preferred_subfamily)
75
+ end
76
+
77
+ private
78
+
79
+ def main_name
80
+ @main_name ||= @file.name
81
+ end
82
+
83
+ def english_name(name)
84
+ visible_characters(find_english(name))
85
+ end
86
+
87
+ def find_english(name)
88
+ name.find { |x| microsoft_english?(x) } ||
89
+ name.find { |x| mac_english?(x) } ||
90
+ name.last
91
+ end
92
+
93
+ def microsoft_english?(string)
94
+ string.platform_id == PLATFORM_MICROSOFT &&
95
+ string.encoding_id == ENCODING_MS_UNICODE_BMP &&
96
+ string.language_id == LANGUAGE_MS_ENGLISH_AMERICAN
97
+ end
98
+
99
+ def mac_english?(string)
100
+ string.platform_id == PLATFORM_MACINTOSH &&
101
+ string.encoding_id == ENCODING_MAC_ROMAN &&
102
+ string.language_id == LANGUAGE_MAC_ENGLISH
103
+ end
104
+
105
+ def visible_characters(text)
106
+ text.gsub(/[^[:print:]]/, "").to_s
107
+ end
108
+ end
109
+ end
@@ -9,8 +9,9 @@ module Fontist
9
9
  REPO_URL = "https://github.com/google/fonts.git".freeze
10
10
  SKIPLIST_PATH = File.expand_path("skiplist.yml", __dir__)
11
11
 
12
- def initialize(logging: false)
12
+ def initialize(logging: false, limit: nil)
13
13
  @logging = logging
14
+ @limit = limit
14
15
  end
15
16
 
16
17
  def call
@@ -30,11 +31,20 @@ module Fontist
30
31
  end
31
32
 
32
33
  def fetch_new_paths
33
- fetch_fonts_paths.select do |path|
34
- log_font(path) do
34
+ new_paths = []
35
+
36
+ fetch_fonts_paths.each do |path|
37
+ new = log_font(path) do
35
38
  new?(path)
36
39
  end
40
+
41
+ next unless new
42
+
43
+ new_paths << path
44
+ return new_paths if @limit && new_paths.size >= @limit
37
45
  end
46
+
47
+ new_paths
38
48
  end
39
49
 
40
50
  def fetch_fonts_paths
@@ -1,6 +1,8 @@
1
1
  module Fontist
2
2
  module Import
3
3
  module Google
4
+ DEFAULT_MAX_COUNT = 100
5
+
4
6
  def self.metadata_name(path)
5
7
  metadata_path = File.join(path, "METADATA.pb")
6
8
  return unless File.exist?(metadata_path)
@@ -6,16 +6,21 @@ require_relative "create_formula"
6
6
  module Fontist
7
7
  module Import
8
8
  class GoogleImport
9
+ def initialize(options)
10
+ @max_count = options[:max_count] || Google::DEFAULT_MAX_COUNT
11
+ end
12
+
9
13
  def call
10
14
  fonts = new_fonts
11
15
  create_formulas(fonts)
12
- rebuild_index
16
+ rebuild_index unless fonts.empty?
13
17
  end
14
18
 
15
19
  private
16
20
 
17
21
  def new_fonts
18
- Fontist::Import::Google::NewFontsFetcher.new(logging: true).call
22
+ Fontist::Import::Google::NewFontsFetcher.new(logging: true,
23
+ limit: @max_count).call
19
24
  end
20
25
 
21
26
  def create_formulas(fonts)
@@ -8,6 +8,10 @@ module Fontist
8
8
  FONT_XML = "/System/Library/AssetsV2/com_apple_MobileAsset_Font6/com_apple_MobileAsset_Font6.xml".freeze # rubocop:disable Layout/LineLength
9
9
  HOMEPAGE = "https://support.apple.com/en-om/HT211240#document".freeze
10
10
 
11
+ def initialize(font_xml = FONT_XML)
12
+ @font_xml = font_xml
13
+ end
14
+
11
15
  def call
12
16
  links.each do |link|
13
17
  create_formula(link)
@@ -21,7 +25,7 @@ module Fontist
21
25
  private
22
26
 
23
27
  def links
24
- data = Plist.parse_xml(FONT_XML)
28
+ data = Plist.parse_xml(@font_xml)
25
29
  data["Assets"].map do |x|
26
30
  x.values_at("__BaseURL", "__RelativePath").join
27
31
  end
@@ -1,12 +1,19 @@
1
+ require_relative "import/google"
2
+
1
3
  module Fontist
2
4
  class ImportCLI < Thor
3
5
  include CLI::ClassOptions
4
6
 
5
7
  desc "google", "Import Google fonts"
8
+ option :max_count,
9
+ type: :numeric, aliases: :n,
10
+ desc: "Limit the number of formulas to import " \
11
+ "(default is #{Fontist::Import::Google::DEFAULT_MAX_COUNT})."
12
+
6
13
  def google
7
14
  handle_class_options(options)
8
15
  require "fontist/import/google_import"
9
- Fontist::Import::GoogleImport.new.call
16
+ Fontist::Import::GoogleImport.new(options).call
10
17
  CLI::STATUS_SUCCESS
11
18
  end
12
19
 
@@ -16,9 +16,8 @@ module Fontist
16
16
  end
17
17
 
18
18
  def self.load_system_font_paths
19
- config_path = Fontist.system_file_path
20
19
  os = Fontist::Utils::System.user_os.to_s
21
- templates = YAML.load_file(config_path)["system"][os]["paths"]
20
+ templates = system_config["system"][os]["paths"]
22
21
  patterns = expand_paths(templates)
23
22
 
24
23
  Dir.glob(patterns)
@@ -26,6 +25,10 @@ module Fontist
26
25
  # "Case sensitivity depends on your system"
27
26
  end
28
27
 
28
+ def self.system_config
29
+ YAML.load_file(Fontist.system_file_path)
30
+ end
31
+
29
32
  def self.reset_system_font_paths_cache
30
33
  @system_font_paths = nil
31
34
  end
@@ -1,4 +1,5 @@
1
- require "ttfunk"
1
+ require_relative "font_file"
2
+ require_relative "collection_file"
2
3
 
3
4
  module Fontist
4
5
  class SystemIndex
@@ -6,11 +7,11 @@ module Fontist
6
7
 
7
8
  class DefaultFamily
8
9
  def family_name(name)
9
- name.font_family
10
+ name.family
10
11
  end
11
12
 
12
13
  def type(name)
13
- name.font_subfamily
14
+ name.subfamily
14
15
  end
15
16
 
16
17
  def transform_override_keys(dict)
@@ -20,15 +21,11 @@ module Fontist
20
21
 
21
22
  class PreferredFamily
22
23
  def family_name(name)
23
- return name.font_family if name.preferred_family.empty?
24
-
25
- name.preferred_family
24
+ name.preferred_family || name.family
26
25
  end
27
26
 
28
27
  def type(name)
29
- return name.font_subfamily if name.preferred_subfamily.empty?
30
-
31
- name.preferred_subfamily
28
+ name.preferred_subfamily || name.subfamily
32
29
  end
33
30
 
34
31
  def transform_override_keys(dict)
@@ -37,15 +34,6 @@ module Fontist
37
34
  end
38
35
  end
39
36
 
40
- PLATFORM_MACINTOSH = 1
41
- PLATFORM_MICROSOFT = 3
42
-
43
- ENCODING_MAC_ROMAN = 0
44
- ENCODING_MS_UNICODE_BMP = 1
45
-
46
- LANGUAGE_MAC_ENGLISH = 0
47
- LANGUAGE_MS_ENGLISH_AMERICAN = 0x409
48
-
49
37
  ALLOWED_KEYS = %i[path full_name family_name type].freeze
50
38
 
51
39
  def self.system_index
@@ -78,6 +66,10 @@ module Fontist
78
66
  Fontist.preferred_family? ? PreferredFamily.new : DefaultFamily.new
79
67
  end
80
68
 
69
+ def excluded_fonts
70
+ @excluded_fonts ||= YAML.load_file(Fontist.excluded_fonts_path)
71
+ end
72
+
81
73
  def initialize(index_path, font_paths_fetcher, family)
82
74
  @index_path = index_path
83
75
  @font_paths_fetcher = font_paths_fetcher
@@ -166,30 +158,44 @@ module Fontist
166
158
  end
167
159
 
168
160
  def detect_fonts(path)
161
+ return if excluded?(path)
162
+
163
+ gather_fonts(path)
164
+ rescue Errors::FontFileError => e
165
+ print_recognition_error(e, path)
166
+ end
167
+
168
+ def excluded?(path)
169
+ excluded_fonts.include?(File.basename(path))
170
+ end
171
+
172
+ def gather_fonts(path)
169
173
  case File.extname(path).gsub(/^\./, "").downcase
170
174
  when "ttf", "otf"
171
175
  detect_file_font(path)
172
176
  when "ttc"
173
177
  detect_collection_fonts(path)
174
178
  else
175
- raise Errors::UnknownFontTypeError.new(path)
179
+ print_recognition_error(Errors::UnknownFontTypeError.new(path), path)
176
180
  end
177
- rescue StandardError
181
+ end
182
+
183
+ def print_recognition_error(exception, path)
178
184
  Fontist.ui.error(<<~MSG.chomp)
179
- #{$!.message}
185
+ #{exception.inspect}
180
186
  Warning: File at #{path} not recognized as a font file.
181
187
  MSG
188
+ nil
182
189
  end
183
190
 
184
191
  def detect_file_font(path)
185
- content = File.read(path, mode: "rb")
186
- file = TTFunk::File.new(content)
192
+ file = FontFile.from_path(path)
187
193
 
188
194
  parse_font(file, path)
189
195
  end
190
196
 
191
197
  def detect_collection_fonts(path)
192
- TTFunk::Collection.open(path) do |collection|
198
+ CollectionFile.from_path(path) do |collection|
193
199
  collection.map do |file|
194
200
  parse_font(file, path)
195
201
  end
@@ -197,43 +203,16 @@ module Fontist
197
203
  end
198
204
 
199
205
  def parse_font(file, path)
200
- x = file.name
201
- family_name = english_name(@family.family_name(x))
206
+ family_name = @family.family_name(file)
202
207
 
203
208
  {
204
209
  path: path,
205
- full_name: english_name(x.font_name),
210
+ full_name: file.full_name,
206
211
  family_name: family_name,
207
- type: english_name(@family.type(x)),
212
+ type: @family.type(file),
208
213
  }.merge(override_font_props(path, family_name))
209
214
  end
210
215
 
211
- def english_name(name)
212
- visible_characters(find_english(name))
213
- end
214
-
215
- def find_english(name)
216
- name.find { |x| microsoft_english?(x) } ||
217
- name.find { |x| mac_english?(x) } ||
218
- name.last
219
- end
220
-
221
- def microsoft_english?(string)
222
- string.platform_id == PLATFORM_MICROSOFT &&
223
- string.encoding_id == ENCODING_MS_UNICODE_BMP &&
224
- string.language_id == LANGUAGE_MS_ENGLISH_AMERICAN
225
- end
226
-
227
- def mac_english?(string)
228
- string.platform_id == PLATFORM_MACINTOSH &&
229
- string.encoding_id == ENCODING_MAC_ROMAN &&
230
- string.language_id == LANGUAGE_MAC_ENGLISH
231
- end
232
-
233
- def visible_characters(text)
234
- text.gsub(/[^[:print:]]/, "").to_s
235
- end
236
-
237
216
  def override_font_props(path, font_name)
238
217
  override = Formula.find_by_font_file(path)
239
218
  &.style_override(font_name)&.to_h || {}
@@ -9,7 +9,7 @@ module Fontist
9
9
 
10
10
  def fetch(key)
11
11
  map = load_cache
12
- if cache_exist?(map[key])
12
+ if Fontist.use_cache? && cache_exist?(map[key])
13
13
  print(map[key])
14
14
 
15
15
  return downloaded_file(map[key])
@@ -80,8 +80,8 @@ module Fontist
80
80
  def do_download_file_with_progress_bar(progress_bar)
81
81
  Down.download(
82
82
  url,
83
- open_timeout: 10,
84
- read_timeout: 10,
83
+ open_timeout: Fontist.open_timeout,
84
+ read_timeout: Fontist.read_timeout,
85
85
  max_redirects: 10,
86
86
  headers: headers,
87
87
  content_length_proc: ->(content_length) {
@@ -0,0 +1,35 @@
1
+ module Fontist
2
+ module Utils
3
+ class FileMagic
4
+ MAP_MAGIC_TO_TYPE = {
5
+ "\x00\x01\x00\x00\x00" => :ttf,
6
+ "\x4f\x54\x54\x4f" => :otf,
7
+ "\x74\x74\x63\x66" => :ttc,
8
+ }.freeze
9
+
10
+ def self.detect(path)
11
+ new(path).detect
12
+ end
13
+
14
+ def self.max_magic
15
+ @max_magic ||= MAP_MAGIC_TO_TYPE.keys.map(&:bytesize).max
16
+ end
17
+
18
+ def initialize(path)
19
+ @path = path
20
+ end
21
+
22
+ def detect
23
+ beginning = File.binread(@path, self.class.max_magic)
24
+
25
+ MAP_MAGIC_TO_TYPE.each do |magic, type|
26
+ slice = beginning.byteslice(0, magic.bytesize)
27
+
28
+ return type if slice == magic
29
+ end
30
+
31
+ nil
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,3 +1,3 @@
1
1
  module Fontist
2
- VERSION = "1.17.0".freeze
2
+ VERSION = "1.18.2".freeze
3
3
  end
data/lib/fontist.rb CHANGED
@@ -13,6 +13,7 @@ require "fontist/formula"
13
13
  require "fontist/system_font"
14
14
  require "fontist/manifest"
15
15
  require "fontist/helpers"
16
+ require "fontist/config"
16
17
 
17
18
  module Fontist
18
19
  def self.ui
@@ -75,6 +76,10 @@ module Fontist
75
76
  Fontist.lib_path.join("fontist", "system.yml")
76
77
  end
77
78
 
79
+ def self.excluded_fonts_path
80
+ Fontist.lib_path.join("fontist", "exclude.yml")
81
+ end
82
+
78
83
  def self.system_index_path
79
84
  Fontist.fontist_path.join("system_index.default_family.yml")
80
85
  end
@@ -119,6 +124,30 @@ module Fontist
119
124
  @preferred_family = bool
120
125
  end
121
126
 
127
+ def self.open_timeout
128
+ config[:open_timeout]
129
+ end
130
+
131
+ def self.read_timeout
132
+ config[:read_timeout]
133
+ end
134
+
135
+ def self.config
136
+ Fontist::Config.instance.values
137
+ end
138
+
139
+ def self.config_path
140
+ Fontist.fontist_path.join("config.yml")
141
+ end
142
+
143
+ def self.use_cache?
144
+ instance_variable_defined?("@use_cache") ? @use_cache : true
145
+ end
146
+
147
+ def self.use_cache=(bool)
148
+ @use_cache = bool
149
+ end
150
+
122
151
  def self.log_level=(level)
123
152
  Fontist.ui.level = level
124
153
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fontist
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.0
4
+ version: 1.18.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-05 00:00:00.000000000 Z
11
+ date: 2024-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: down
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: nokogiri
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -305,8 +319,13 @@ files:
305
319
  - lib/fontist/cache_cli.rb
306
320
  - lib/fontist/cli.rb
307
321
  - lib/fontist/cli/class_options.rb
322
+ - lib/fontist/collection_file.rb
323
+ - lib/fontist/config.rb
324
+ - lib/fontist/config_cli.rb
308
325
  - lib/fontist/errors.rb
326
+ - lib/fontist/exclude.yml
309
327
  - lib/fontist/font.rb
328
+ - lib/fontist/font_file.rb
310
329
  - lib/fontist/font_installer.rb
311
330
  - lib/fontist/font_path.rb
312
331
  - lib/fontist/fontconfig.rb
@@ -363,6 +382,7 @@ files:
363
382
  - lib/fontist/utils.rb
364
383
  - lib/fontist/utils/cache.rb
365
384
  - lib/fontist/utils/downloader.rb
385
+ - lib/fontist/utils/file_magic.rb
366
386
  - lib/fontist/utils/locking.rb
367
387
  - lib/fontist/utils/system.rb
368
388
  - lib/fontist/utils/ui.rb