fontist 3.0.2 → 3.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b68f4d4d083a0e2f73df389c0698800b4a4d519428cbf59ddd98f493630a3342
4
- data.tar.gz: 76cc6dd8420deb15d8b5fd872e17550c4b31dc31585834f2290a0e3f36d130ba
3
+ metadata.gz: 5b2847a2098f7dc8ca7652bf08d8e01d5f2a0e826230631bbba3d7cc01831933
4
+ data.tar.gz: 777c69708edc12acfaee0f01d492e9c3eb573822e428da489726fed8a52e4ac7
5
5
  SHA512:
6
- metadata.gz: 72c687e0c3c81823d1e0edf131f9af115564e5d7b60b296d84dad7c297e5ea6e8f5fd6995f18961b6a6d048fb630eeba1e74d7beb942bad0abf97b9922112435
7
- data.tar.gz: 57c8dde9259414c129e83c5fea0b7d50b2970c0062a756ffd9f8dbf91738508c154e0372f7b4a9d30139abb17d650a98954db0cc8764bd8871c7c5611221e4f9
6
+ metadata.gz: da58a8c87b799c5db8241c5e951b26bd17a2e17d8bea327a4c479de1679c40feb6272bdc71a024e0fad6e4dd16743278e57a370c9d6ef021784a07968d6814a6
7
+ data.tar.gz: 22bb4499aa794f0534f850932df74aca65724e7019760fb7f6517233d1290cb2f5c2d3697e6046288acde4d21cb128b787f1d153aaaf50e1791c81a272d60b64
@@ -272,7 +272,7 @@ module Fontist
272
272
  end
273
273
 
274
274
  def font_links
275
- html = URI.parse(ROOT).open.read
275
+ html = URI.parse(ROOT).open("User-Agent" => Fontist::Utils::UserAgent.random_user_agent).read
276
276
  document = Nokogiri::HTML.parse(html)
277
277
  document.css("table.products div.title > a")
278
278
  end
@@ -392,7 +392,7 @@ module Fontist
392
392
  end
393
393
 
394
394
  def find_archive_url_by_page_uri(uri)
395
- response = uri.open
395
+ response = uri.open("User-Agent" => Fontist::Utils::UserAgent.random_user_agent)
396
396
  current_url = response.base_uri
397
397
  html = response.read
398
398
  document = Nokogiri::HTML.parse(html)
@@ -60,6 +60,14 @@ module Fontist
60
60
  self
61
61
  end
62
62
 
63
+ # Disable read-only mode, restoring normal index_changed? checks.
64
+ #
65
+ # @return [self] Returns self for chaining
66
+ def disable_read_only_mode
67
+ collection.disable_read_only_mode
68
+ self
69
+ end
70
+
63
71
  # Returns all fonts in the index
64
72
  #
65
73
  # @return [Array<SystemIndexFont>] All indexed fonts
@@ -55,7 +55,7 @@ module Fontist
55
55
  Fontist.ui.say("Downloading Font#{version} catalog from #{url}...") if Fontist.ui.respond_to?(:say)
56
56
 
57
57
  URI(url).open(
58
- "User-Agent" => "Fontist/#{Fontist::VERSION}",
58
+ "User-Agent" => Fontist::Utils::UserAgent.random_user_agent,
59
59
  ) do |response|
60
60
  File.write(catalog_file, response.read)
61
61
  end
@@ -33,9 +33,15 @@ module Fontist
33
33
  def style_paths(locations: false)
34
34
  ary = Array(styles)
35
35
  (ary.empty? ? [nil] : ary).flat_map do |style|
36
- find_font_with_name(name, style).tap do |x|
37
- raise Errors::MissingFontError.new(name, style) if x.nil? && locations
36
+ paths = find_font_with_name(name, style)
37
+
38
+ if paths.nil? && locations
39
+ try_install_missing_font
40
+ paths = find_font_with_name(name, style)
41
+ raise Errors::MissingFontError.new(name, style) if paths.nil?
38
42
  end
43
+
44
+ paths
39
45
  end.compact
40
46
  end
41
47
 
@@ -96,6 +102,27 @@ module Fontist
96
102
 
97
103
  private
98
104
 
105
+ def try_install_missing_font
106
+ Fontist.ui.debug("self-healing install attempt for #{name.inspect}")
107
+ Fontist::Font.install(
108
+ name,
109
+ force: true,
110
+ confirmation: "no",
111
+ no_progress: true,
112
+ hide_licenses: true,
113
+ format_spec: format_spec,
114
+ )
115
+ rescue Fontist::Errors::FontError,
116
+ Fontist::Errors::LicensingError,
117
+ Fontist::Errors::PlatformMismatchError,
118
+ Fontist::Errors::FormulaIndexNotFoundError => e
119
+ Fontist.ui.debug(
120
+ "self-healing install for #{name.inspect} " \
121
+ "failed: #{e.class}: #{e.message}",
122
+ )
123
+ nil
124
+ end
125
+
99
126
  def validate_location_parameter!(location)
100
127
  return unless location
101
128
  return if location.is_a?(Symbol)
@@ -183,7 +210,11 @@ module Fontist
183
210
 
184
211
  yield
185
212
  ensure
186
- # Always disable caching after the operation
213
+ # Always restore normal mode after the operation so the read-only flag
214
+ # does not leak across calls and turn the singletons effectively stale.
215
+ Fontist::Indexes::FontistIndex.instance.disable_read_only_mode
216
+ Fontist::Indexes::UserIndex.instance.disable_read_only_mode
217
+ Fontist::Indexes::SystemIndex.instance.disable_read_only_mode
187
218
  Fontist::SystemFont.disable_find_styles_cache
188
219
  end
189
220
 
@@ -229,11 +229,12 @@ module Fontist
229
229
  end
230
230
 
231
231
  def index
232
- # Fast path: if read_only mode is set, skip index_changed? check entirely
233
- # But we still need to build if fonts is nil (first time access)
234
- if @read_only_mode && !fonts.nil?
232
+ # Fast path: if read_only mode is set, skip index_changed? check entirely.
233
+ # But we still need to build on first access treat an empty fonts list
234
+ # the same as nil, since Lutaml initializes `instances :fonts` to `[]`
235
+ # rather than nil when the on-disk index file is absent.
236
+ if @read_only_mode && !fonts.nil? && !fonts.empty?
235
237
  return fonts
236
- # Fall through to build the index on first access
237
238
  end
238
239
 
239
240
  return fonts unless index_changed?
@@ -257,6 +258,14 @@ module Fontist
257
258
  self
258
259
  end
259
260
 
261
+ # Disable read-only mode so future `index` calls go through
262
+ # `index_changed?` again. Paired with `read_only_mode` to scope the
263
+ # optimization to a single block (see Manifest.with_performance_optimizations).
264
+ def disable_read_only_mode
265
+ @read_only_mode = false
266
+ self
267
+ end
268
+
260
269
  def index_changed?
261
270
  return true if fonts.nil? || fonts.empty?
262
271
  return false if @index_check_done # Skip if already verified in this session
@@ -1,10 +1,6 @@
1
1
  module Fontist
2
2
  module Utils
3
3
  class Downloader
4
- DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) " \
5
- "AppleWebKit/537.36 (KHTML, like Gecko) " \
6
- "Chrome/131.0.0.0 Safari/537.36".freeze
7
-
8
4
  class << self
9
5
  def download(*args)
10
6
  new(*args).download
@@ -143,7 +139,7 @@ module Fontist
143
139
  obj.headers &&
144
140
  obj.headers.to_h.to_h { |k, v| [k.to_s, v] }) || {} # rubocop:disable Style/HashTransformKeys, Metrics/LineLength
145
141
 
146
- { "User-Agent" => DEFAULT_USER_AGENT }.merge(formula_headers)
142
+ Utils::UserAgent.browser_headers.merge(formula_headers)
147
143
  end
148
144
 
149
145
  def extract_raw_url
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fontist
4
+ module Utils
5
+ module UserAgent
6
+ PROFILES = [
7
+ {
8
+ user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) " \
9
+ "AppleWebKit/537.36 (KHTML, like Gecko) " \
10
+ "Chrome/131.0.0.0 Safari/537.36",
11
+ platform: '"macOS"',
12
+ chrome_version: "131",
13
+ },
14
+ {
15
+ user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " \
16
+ "AppleWebKit/537.36 (KHTML, like Gecko) " \
17
+ "Chrome/130.0.0.0 Safari/537.36",
18
+ platform: '"Windows"',
19
+ chrome_version: "130",
20
+ },
21
+ {
22
+ user_agent: "Mozilla/5.0 (X11; Linux x86_64) " \
23
+ "AppleWebKit/537.36 (KHTML, like Gecko) " \
24
+ "Chrome/132.0.0.0 Safari/537.36",
25
+ platform: '"Linux"',
26
+ chrome_version: "132",
27
+ },
28
+ {
29
+ user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) " \
30
+ "AppleWebKit/537.36 (KHTML, like Gecko) " \
31
+ "Chrome/130.0.0.0 Safari/537.36",
32
+ platform: '"macOS"',
33
+ chrome_version: "130",
34
+ },
35
+ {
36
+ user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " \
37
+ "AppleWebKit/537.36 (KHTML, like Gecko) " \
38
+ "Chrome/132.0.0.0 Safari/537.36",
39
+ platform: '"Windows"',
40
+ chrome_version: "132",
41
+ },
42
+ ].freeze
43
+
44
+ ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9," \
45
+ "image/avif,image/webp,image/apng,*/*;q=0.8," \
46
+ "application/signed-exchange;v=b3;q=0.7"
47
+
48
+ ACCEPT_LANGUAGE = "en-US,en;q=0.9"
49
+
50
+ STATIC_HEADERS = {
51
+ "Accept" => ACCEPT,
52
+ "Accept-Language" => ACCEPT_LANGUAGE,
53
+ "Cache-Control" => "no-cache",
54
+ "Pragma" => "no-cache",
55
+ "Sec-Ch-Ua-Mobile" => "?0",
56
+ "Sec-Fetch-Dest" => "document",
57
+ "Sec-Fetch-Mode" => "navigate",
58
+ "Sec-Fetch-Site" => "cross-site",
59
+ "Sec-Fetch-User" => "?1",
60
+ "Upgrade-Insecure-Requests" => "1",
61
+ }.freeze
62
+
63
+ class << self
64
+ def random_profile
65
+ PROFILES.sample
66
+ end
67
+
68
+ def browser_headers
69
+ profile = random_profile
70
+ build_headers(profile)
71
+ end
72
+
73
+ def random_user_agent
74
+ random_profile[:user_agent]
75
+ end
76
+
77
+ private
78
+
79
+ def build_headers(profile)
80
+ STATIC_HEADERS.merge(
81
+ "User-Agent" => profile[:user_agent],
82
+ "Sec-Ch-Ua" => build_sec_ch_ua(profile[:chrome_version]),
83
+ "Sec-Ch-Ua-Platform" => profile[:platform],
84
+ )
85
+ end
86
+
87
+ def build_sec_ch_ua(chrome_version)
88
+ "\"Google Chrome\";v=\"#{chrome_version}\", " \
89
+ "\"Chromium\";v=\"#{chrome_version}\", " \
90
+ "\"Not_A Brand\";v=\"24\""
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
data/lib/fontist/utils.rb CHANGED
@@ -9,6 +9,7 @@ module Fontist
9
9
  autoload :Locking, "#{__dir__}/utils/locking"
10
10
  autoload :System, "#{__dir__}/utils/system"
11
11
  autoload :UI, "#{__dir__}/utils/ui"
12
+ autoload :UserAgent, "#{__dir__}/utils/user_agent"
12
13
 
13
14
  # Converts a glob pattern to case-insensitive by replacing each
14
15
  # alphabetic character with a character class [aA]
@@ -70,7 +71,7 @@ module Fontist
70
71
 
71
72
  # On case-insensitive filesystems (Windows, macOS), use simple patterns
72
73
  # On case-sensitive filesystems (Linux), use character class patterns
73
- if %i[windows macosx].include?(Fontist::Utils::System.user_os)
74
+ if %i[windows macos].include?(Fontist::Utils::System.user_os)
74
75
  # Case-insensitive filesystem - simple patterns work fine
75
76
  extensions.map { |ext| File.join(prefix, "*.#{ext}") }
76
77
  else
@@ -1,3 +1,3 @@
1
1
  module Fontist
2
- VERSION = "3.0.2".freeze
2
+ VERSION = "3.0.4".freeze
3
3
  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: 3.0.2
4
+ version: 3.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-05-05 00:00:00.000000000 Z
11
+ date: 2026-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: down
@@ -509,6 +509,7 @@ files:
509
509
  - lib/fontist/utils/locking.rb
510
510
  - lib/fontist/utils/system.rb
511
511
  - lib/fontist/utils/ui.rb
512
+ - lib/fontist/utils/user_agent.rb
512
513
  - lib/fontist/validate_cli.rb
513
514
  - lib/fontist/validation.rb
514
515
  - lib/fontist/validator.rb