brrowser 0.1.4 → 0.1.5

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/bin/brrowser +37 -5
  3. data/lib/brrowser/renderer.rb +33 -14
  4. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3fa096f37a4682bd1edb910013f6a6273acd8f46ee52304eaf140a4963527a5
4
- data.tar.gz: 0b266827e97d189f85cbdc4bd33318419c03a1fc7e684b5b7eb7d0460f5093ce
3
+ metadata.gz: 1502511b56f9175cb771635ca305bad614c6230d342c85b44205f4de29a79cc3
4
+ data.tar.gz: ec1f738931d99d5783b9a0e45f4085b785a3a70c3c6efb11cfd63da3f7b06d5b
5
5
  SHA512:
6
- metadata.gz: 78c2c33f3db1bbbc77230e3a4ba98e691b1434c5566a74c7a97a4d8caa5fe7f55fb779082f1fcf09bdb99e00c7310838169a8a06ac1ca2600f57dd6e16f90d53
7
- data.tar.gz: 4c1d3863f3830fc1e7f43d69810d2ed558922869d5da489322e953b525abec3a608300778530910c473a37991aea8ec7129598ba24e3061fb943721a69e97298
6
+ metadata.gz: 737df9f08305e342142bcefa5e6a80a30dc060998fc91f3f71fbfd623167e17ec3b8f0021d9c24189fd27d7c088fb998d89b474f81b9e6ee0c2a7649b5290466
7
+ data.tar.gz: 24ecf86ab13aaadabd05eacecbfeeeda13dedafd05c77eacf11b5406428918b36d65065e6ecfd3f179c23bb0f134157cbc1f8d060754f03326987fb19821409a
data/bin/brrowser CHANGED
@@ -457,7 +457,7 @@ module Brrowser
457
457
  label = tab.title.to_s.empty? ? "New Tab" : tab.title.to_s
458
458
  label = label[0..20] + "..." if label.length > 23
459
459
  if i == @current_tab
460
- " #{label} ".fg(220).b
460
+ " #{label} ".fg(220).bd
461
461
  else
462
462
  " #{label} ".fg(245)
463
463
  end
@@ -609,6 +609,22 @@ module Brrowser
609
609
  response = @fetcher.fetch(src)
610
610
  next if response[:status] != 200
611
611
  ct = response[:content_type].to_s
612
+ # Handle oEmbed JSON responses (e.g. YouTube playlists)
613
+ if ct.match?(/json/) && src.include?("oembed")
614
+ begin
615
+ data = JSON.parse(response[:body])
616
+ thumb = data["thumbnail_url"]
617
+ next unless thumb
618
+ response = @fetcher.fetch(thumb)
619
+ next if response[:status] != 200
620
+ ct = response[:content_type].to_s
621
+ ext = File.extname(URI.parse(thumb).path)[0..5]
622
+ ext = ".jpg" if ext.empty?
623
+ local = File.join(@img_dir, "#{Digest::MD5.hexdigest(src)}#{ext}")
624
+ rescue
625
+ next
626
+ end
627
+ end
612
628
  next unless ct.match?(/image/) || src.match?(/\.(png|jpe?g|gif|bmp|webp|svg|ico)/i)
613
629
  File.binwrite(local, response[:body])
614
630
  if src.match?(/\.svg/i) || ct.include?("svg")
@@ -816,9 +832,25 @@ module Brrowser
816
832
  lines[@highlighted_line] = lines[@highlighted_line]
817
833
  .gsub("\e[7m", "").gsub("\e[27m", "")
818
834
  end
819
- # Highlight current element line
835
+ # Highlight the specific element (not the whole line)
820
836
  if elem[:line] < lines.length
821
- lines[elem[:line]] = "\e[7m#{lines[elem[:line]]}\e[27m"
837
+ line = lines[elem[:line]]
838
+ highlighted = false
839
+ if elem[:type] == :link
840
+ link_text = Regexp.escape(elem[:data][:text])
841
+ idx = Regexp.escape("[#{elem[:data][:index]}]")
842
+ # Match the ANSI-wrapped link text + label as rendered:
843
+ # text.fg(81).ul => \e[4m\e[38;5;81m...text...\e[39m\e[24m
844
+ # "[N]".fg(39) => \e[38;5;39m[N]\e[39m
845
+ re = /(\e\[4m\e\[38;5;81m#{link_text}\e\[39m\e\[24m\e\[38;5;39m#{idx}\e\[39m)/
846
+ if line.match?(re)
847
+ lines[elem[:line]] = line.sub(re, "\e[7m\\1\e[27m")
848
+ highlighted = true
849
+ end
850
+ end
851
+ unless highlighted
852
+ lines[elem[:line]] = "\e[7m#{line}\e[27m"
853
+ end
822
854
  @highlighted_line = elem[:line]
823
855
  end
824
856
  current_tab.content = lines.join("\n")
@@ -1732,7 +1764,7 @@ module Brrowser
1732
1764
  sel = 0
1733
1765
 
1734
1766
  build = lambda do
1735
- lines = [" brrowser Preferences".b]
1767
+ lines = [" brrowser Preferences".bd]
1736
1768
  lines << " h/l:change H/L:+/-10 Enter:edit ESC:close".fg(245)
1737
1769
  lines << ""
1738
1770
  PREF_SETTINGS.each_with_index do |(label, key, type), i|
@@ -1745,7 +1777,7 @@ module Brrowser
1745
1777
  end
1746
1778
  prefix = i == sel ? " \u25b6 ".fg(220) : " "
1747
1779
  line = "#{prefix}#{label.ljust(18)} \u25c4 #{disp.to_s.ljust(14)} \u25b6"
1748
- line = line.r if i == sel
1780
+ line = line.rv if i == sel
1749
1781
  lines << line
1750
1782
  end
1751
1783
  popup.text = lines.join("\n")
@@ -103,24 +103,24 @@ module Brrowser
103
103
  when "h1"
104
104
  ensure_blank_line
105
105
  text = collect_text(node)
106
- @line << text.b.fg(220)
106
+ @line << text.bd.fg(220)
107
107
  flush_line
108
108
  @line << ("═" * [text.gsub(ANSI_RE, "").length, @width].min).fg(220)
109
109
  flush_line
110
110
  ensure_blank_line
111
111
  when "h2"
112
112
  ensure_blank_line
113
- inline_walk(node, :b, 214)
113
+ inline_walk(node, :bd, 214)
114
114
  flush_line
115
115
  ensure_blank_line
116
116
  when "h3"
117
117
  ensure_blank_line
118
- inline_walk(node, :b, 208)
118
+ inline_walk(node, :bd, 208)
119
119
  flush_line
120
120
  ensure_blank_line
121
121
  when "h4", "h5", "h6"
122
122
  ensure_blank_line
123
- inline_walk(node, :b, 252)
123
+ inline_walk(node, :bd, 252)
124
124
  flush_line
125
125
  ensure_blank_line
126
126
  when "p", "div", "section", "article", "aside", "main",
@@ -187,7 +187,7 @@ module Brrowser
187
187
  ensure_blank_line
188
188
  when "dt"
189
189
  flush_line if @col > 0
190
- inline_walk(node, :b, 252)
190
+ inline_walk(node, :bd, 252)
191
191
  flush_line
192
192
  when "dd"
193
193
  old_indent = @indent
@@ -212,7 +212,7 @@ module Brrowser
212
212
  walk(node)
213
213
  @in_link = nil
214
214
  else
215
- @line << text.fg(81).u
215
+ @line << text.fg(81).ul
216
216
  @col += text.length
217
217
  end
218
218
  label = "[#{link_index}]"
@@ -227,11 +227,11 @@ module Brrowser
227
227
  end
228
228
  end
229
229
  when "strong", "b"
230
- inline_walk(node, :b)
230
+ inline_walk(node, :bd)
231
231
  when "em", "i"
232
- inline_walk(node, :i)
232
+ inline_walk(node, :it)
233
233
  when "u"
234
- inline_walk(node, :u)
234
+ inline_walk(node, :ul)
235
235
  when "s", "strike", "del"
236
236
  text = collect_text(node)
237
237
  @line << text.fg(240)
@@ -253,7 +253,8 @@ module Brrowser
253
253
  src = resolve_url(src) unless src.empty?
254
254
  if src.match?(%r{youtube\.com/embed/|youtube-nocookie\.com/embed/})
255
255
  video_id = src[%r{/embed/([^?&/]+)}, 1]
256
- if video_id
256
+ playlist_id = src[/[?&]list=([^&]+)/, 1]
257
+ if video_id && video_id != "playlist" && video_id != "videoseries"
257
258
  ensure_blank_line
258
259
  # Add YouTube thumbnail as image
259
260
  thumb_url = "https://img.youtube.com/vi/#{video_id}/hqdefault.jpg"
@@ -267,10 +268,28 @@ module Brrowser
267
268
  link_index = @links.length
268
269
  link_line = @output.length
269
270
  @links << { index: link_index, href: video_url, text: "Watch on YouTube", line: link_line }
270
- @line << "\u25b6 Watch on YouTube".fg(196).b + "[#{link_index}]".fg(39)
271
+ @line << "\u25b6 Watch on YouTube".fg(196).bd + "[#{link_index}]".fg(39)
271
272
  @col += 19 + "[#{link_index}]".length
272
273
  flush_line
273
274
  ensure_blank_line
275
+ elsif playlist_id
276
+ ensure_blank_line
277
+ # Playlist embed: use oEmbed to resolve thumbnail
278
+ oembed_url = "https://www.youtube.com/oembed?url=https://www.youtube.com/playlist?list=#{playlist_id}&format=json"
279
+ flush_line if @col > 0
280
+ line_num = @output.length
281
+ @images << { src: oembed_url, alt: "YouTube playlist", line: line_num, height: IMG_RESERVE }
282
+ @output << "[YouTube playlist]".fg(236)
283
+ (IMG_RESERVE - 1).times { @output << "" }
284
+ # Add link to playlist
285
+ playlist_url = "https://www.youtube.com/playlist?list=#{playlist_id}"
286
+ link_index = @links.length
287
+ link_line = @output.length
288
+ @links << { index: link_index, href: playlist_url, text: "YouTube Playlist", line: link_line }
289
+ @line << "\u25b6 YouTube Playlist".fg(196).bd + "[#{link_index}]".fg(39)
290
+ @col += 20 + "[#{link_index}]".length
291
+ flush_line
292
+ ensure_blank_line
274
293
  end
275
294
  elsif !src.empty?
276
295
  ensure_blank_line
@@ -294,7 +313,7 @@ module Brrowser
294
313
  action = resolve_url(action) unless action.empty?
295
314
  method = (node["method"] || "get").downcase
296
315
  @current_form = { action: action, method: method, fields: [], line: @output.length }
297
- @line << "[Form]".fg(208).b
316
+ @line << "[Form]".fg(208).bd
298
317
  flush_line
299
318
  walk(node)
300
319
  # Check if form has password field
@@ -456,7 +475,7 @@ module Brrowser
456
475
  cell.length > w ? cell[0...w] : cell.ljust(w)
457
476
  end
458
477
  line = parts.join(" \u2502 ".fg(240))
459
- line = line.b if ri == 0 && table_node.at_css("th")
478
+ line = line.bd if ri == 0 && table_node.at_css("th")
460
479
  @output << (" " * @indent) + line
461
480
 
462
481
  if ri == 0 && table_node.at_css("th")
@@ -474,7 +493,7 @@ module Brrowser
474
493
  row.each_with_index do |cell, ci|
475
494
  next if cell.strip.empty?
476
495
  label = headers && headers[ci] ? headers[ci] : "Col #{ci + 1}"
477
- @output << (" " * @indent) + "#{label}: ".fg(245).b + cell
496
+ @output << (" " * @indent) + "#{label}: ".fg(245).bd + cell
478
497
  end
479
498
  @output << (" " * @indent) + ("\u2500" * 20).fg(240)
480
499
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brrowser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-28 00:00:00.000000000 Z
11
+ date: 2026-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rcurses
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '6.0'
19
+ version: '7.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '6.0'
26
+ version: '7.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: nokogiri
29
29
  requirement: !ruby/object:Gem::Requirement