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 +4 -4
- data/.github/workflows/test-and-release.yml +1 -0
- data/README.adoc +48 -3
- data/fontist.gemspec +1 -0
- data/lib/fontist/cli/class_options.rb +28 -0
- data/lib/fontist/cli.rb +4 -16
- data/lib/fontist/collection_file.rb +46 -0
- data/lib/fontist/config.rb +62 -0
- data/lib/fontist/config_cli.rb +40 -0
- data/lib/fontist/errors.rb +2 -0
- data/lib/fontist/exclude.yml +1 -0
- data/lib/fontist/font_file.rb +109 -0
- data/lib/fontist/import/google/new_fonts_fetcher.rb +13 -3
- data/lib/fontist/import/google.rb +2 -0
- data/lib/fontist/import/google_import.rb +7 -2
- data/lib/fontist/import/macos.rb +5 -1
- data/lib/fontist/import_cli.rb +8 -1
- data/lib/fontist/system_font.rb +5 -2
- data/lib/fontist/system_index.rb +33 -54
- data/lib/fontist/utils/cache.rb +1 -1
- data/lib/fontist/utils/downloader.rb +2 -2
- data/lib/fontist/utils/file_magic.rb +35 -0
- data/lib/fontist/version.rb +1 -1
- data/lib/fontist.rb +29 -0
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7df8791fd4754d729546380e67e6c29866f12e4d85bb917b427284c1be610dff
|
4
|
+
data.tar.gz: be7991cacf763d3abc89aeea2841d02b4cc58b7e3a24c99551ee48639b07a3f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ec6f6dfa9169caddd99e3641d05864d49bb1bfa2f59ae4887dd72b703c18c599628711fa5f414cb5863832f14751fddc7536cea549358eebbb926231eaf7651
|
7
|
+
data.tar.gz: a87e924b0741861b59114ae75ea93a09ba86eb43510787501f20980a488ec3a181bba20ea0307e6b7f51f83d989c0edaf7db7ea1c74680534eec3280dc1a8d47
|
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/
|
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/
|
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/
|
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
|
data/lib/fontist/errors.rb
CHANGED
@@ -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
|
-
|
34
|
-
|
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
|
@@ -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
|
22
|
+
Fontist::Import::Google::NewFontsFetcher.new(logging: true,
|
23
|
+
limit: @max_count).call
|
19
24
|
end
|
20
25
|
|
21
26
|
def create_formulas(fonts)
|
data/lib/fontist/import/macos.rb
CHANGED
@@ -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(
|
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
|
data/lib/fontist/import_cli.rb
CHANGED
@@ -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
|
|
data/lib/fontist/system_font.rb
CHANGED
@@ -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 =
|
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
|
data/lib/fontist/system_index.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
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.
|
10
|
+
name.family
|
10
11
|
end
|
11
12
|
|
12
13
|
def type(name)
|
13
|
-
name.
|
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
|
-
|
24
|
-
|
25
|
-
name.preferred_family
|
24
|
+
name.preferred_family || name.family
|
26
25
|
end
|
27
26
|
|
28
27
|
def type(name)
|
29
|
-
|
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
|
-
|
179
|
+
print_recognition_error(Errors::UnknownFontTypeError.new(path), path)
|
176
180
|
end
|
177
|
-
|
181
|
+
end
|
182
|
+
|
183
|
+
def print_recognition_error(exception, path)
|
178
184
|
Fontist.ui.error(<<~MSG.chomp)
|
179
|
-
#{
|
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
|
-
|
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
|
-
|
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
|
-
|
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:
|
210
|
+
full_name: file.full_name,
|
206
211
|
family_name: family_name,
|
207
|
-
type:
|
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 || {}
|
data/lib/fontist/utils/cache.rb
CHANGED
@@ -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:
|
84
|
-
read_timeout:
|
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
|
data/lib/fontist/version.rb
CHANGED
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.
|
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:
|
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
|