searchlink 2.3.83 → 2.3.85

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: 9d9d44b58260a556b6834758e6782fe1b0b0d6ebb43ed79c88b3ecee9d53d124
4
- data.tar.gz: a10d673938b4a58c907b2588fedaf4e71f021d5f85d392cbc17c144dea91c3b8
3
+ metadata.gz: 02b111da9ce13f8646d7357ae5560a1c6b84bb45fd506dca8fafe96e1c844bea
4
+ data.tar.gz: 02fd69545df789fdf1105dea4971b53f02bfc33ac0da20a3f25454c11f9a9ae7
5
5
  SHA512:
6
- metadata.gz: e1a3d23ee5be311f69772b5f46a72a9c18b9684a22d62af561d6c1421ab13343df8b6f233e00ba6811748d5b2cf31c91886d45fae4fff94e797ecca10a285b65
7
- data.tar.gz: 8100ed794563d9747bce2be4b1b2a13e6475331769ee5411a7c4c186089b01bde9536c17002bffdd8c4821db11d185590b9de3d6b8c42b27175540e2cdae945c
6
+ metadata.gz: 7af24cad60ca01ead8ab4a76f82c6d6fa9be6aa30752f088c23cfe387d9a3adf8f076e5e4d1f1dc25d9eeda8879d1ae7e83bbee3bcea250de6914dc67d35cf0c
7
+ data.tar.gz: '089fb329c4c7be4cf30bf929b8c4309374a0b8055f42eb2adeb2c62d29f7a9ef84d9e45527a5c0a13c7e0061345ee814cfd431bc6f33614ad034f8d8c970250a'
@@ -111,7 +111,7 @@ module Curl
111
111
  def extract_tag_contents(tag, source: false)
112
112
  return @body.scan(%r{<#{tag}.*?>(?:.*?</#{tag}>)?}) if source
113
113
 
114
- @body.scan(/<#{tag}.*?>(.*?)</).map { |t| t[0] }
114
+ @body.scan(/<#{tag}.*?>(.*?)</).map { |t| t[1] }
115
115
  end
116
116
 
117
117
  ##
@@ -3,7 +3,8 @@
3
3
  module SL
4
4
  class << self
5
5
  attr_writer :titleize, :clipboard, :output, :footer, :line_num,
6
- :match_column, :match_length, :originput, :errors, :report, :printout
6
+ :match_column, :match_length, :originput, :errors, :report, :printout,
7
+ :shortener
7
8
 
8
9
  # Whether or not to add a title to the output
9
10
  def titleize
@@ -60,6 +61,16 @@ module SL
60
61
  @errors ||= {}
61
62
  end
62
63
 
64
+ # Stores query parameters
65
+ def query
66
+ @query ||= {}
67
+ end
68
+
69
+ # The shortener to use
70
+ def shortener
71
+ @shortener ||= :none
72
+ end
73
+
63
74
  # Posts macOS notifications
64
75
  #
65
76
  # @param title [String] The title of the notification
@@ -102,6 +113,19 @@ module SL
102
113
 
103
114
  title = title.gsub(/[ \t]+/, " ")
104
115
 
116
+ url.add_query_string!
117
+
118
+ url = case SL.shortener
119
+ when :isgd
120
+ SL::IsgdSearch.shorten(url)
121
+ when :tinyurl
122
+ SL::TinyurlSearch.shorten(url)
123
+ when :bitly
124
+ SL::BitlySearch.shorten(url)
125
+ else
126
+ url
127
+ end
128
+
105
129
  case type.to_sym
106
130
  when :ref_title
107
131
  %(\n[#{text}]: #{url}#{title})
@@ -141,7 +165,6 @@ module SL
141
165
  #
142
166
  def print_footer
143
167
  unless SL.footer.empty?
144
-
145
168
  footnotes = []
146
169
  SL.footer.delete_if do |note|
147
170
  note.strip!
@@ -202,6 +225,14 @@ module SL
202
225
  SL.errors[type].push("(#{position}): #{str}")
203
226
  end
204
227
 
228
+ # Add to query string
229
+ # @param hsh [Hash] The queries to add
230
+ # @return [nil]
231
+ def add_query(hsh)
232
+ SL.query ||= {}
233
+ SL.query.merge!(hsh)
234
+ end
235
+
205
236
  # Prints the report.
206
237
  #
207
238
  # @return [String] The report.
@@ -2,194 +2,6 @@
2
2
 
3
3
  module SL
4
4
  class SearchLink
5
- # Parse arguments in the input string
6
- #
7
- # @param string [String] the string to parse
8
- # @param opt [Hash] the options to parse
9
- # @option opt [Boolean] :only_meta (false) whether to skip flags
10
- # @option opt [Boolean] :no_restore (false) whether to restore previous config
11
- # @return [String] the parsed string
12
- #
13
- def parse_arguments(string, opt = {})
14
- input = string.dup
15
- return "" if input.nil?
16
-
17
- skip_flags = opt[:only_meta] || false
18
- no_restore = opt[:no_restore] || false
19
- restore_prev_config unless no_restore
20
-
21
- input.parse_flags! unless skip_flags
22
-
23
- options = %w[debug country_code inline prefix_random include_titles remove_seo validate_links complete_bare]
24
- options.each do |o|
25
- if input =~ /^ *#{o}:\s+(\S+)$/
26
- val = Regexp.last_match(1).strip
27
-
28
- if val.is_a?(String)
29
- value = true if val =~ /true/i
30
- value = false if val =~ /false/i
31
- end
32
- val = value if value
33
- SL.config[o] = val
34
- warn "\r\033[0KGlobal config: #{o} = #{SL.config[o]}\n" unless SILENT
35
- end
36
-
37
- next if skip_flags
38
-
39
- while input =~ /^#{o}:\s+(.*?)$/ || input =~ /--(no-)?#{o}/
40
- next unless input =~ /--(no-)?#{o}/ && !skip_flags
41
-
42
- unless SL.prev_config.key? o
43
- SL.prev_config[o] = SL.config[o]
44
- bool = Regexp.last_match(1).nil? || Regexp.last_match(1) == "" ? true : false
45
- SL.config[o] = bool
46
- $stderr.print "\r\033[0KLine config: #{o} = #{SL.config[o]}\n" unless SILENT
47
- end
48
- input.sub!(/\s?--(no-)?#{o}/, "")
49
- end
50
- end
51
- SL.clipboard ? string : input
52
- end
53
-
54
- # Parse commands from the given input string
55
- #
56
- # @param input [String] the input string
57
- def parse_commands(input)
58
- # Handle commands like help or docs
59
- return unless input.strip =~ /^!?(h(elp)?|wiki|docs?|v(er(s(ion)?)?)?|up(date|grade))$/
60
-
61
- case input.strip
62
- when /^!?help$/i
63
- if SILENT
64
- help_dialog
65
- else
66
- $stdout.puts SL.version_check.to_s
67
- $stdout.puts "See https://github.com/ttscoff/searchlink/wiki for help"
68
- end
69
- print input
70
- when /^!?(wiki|docs)$/i
71
- warn "Opening wiki in browser"
72
- `open https://github.com/ttscoff/searchlink/wiki`
73
- when /^!?v(er(s(ion)?)?)?$/
74
- print "[#{SL.version_check}]"
75
- when /^!?up(date|grade)$/
76
- SL.update_searchlink
77
- print SL.output.join("")
78
- end
79
- Process.exit 0
80
- end
81
-
82
- def create_footnote(mtch)
83
- if mtch[1].nil? || mtch[1] == ""
84
- match
85
- else
86
- note = mtch[1].strip
87
- @footnote_counter += 1
88
- ref = if !@link_text.empty? && @link_text.scan(/\s/).empty?
89
- @link_text
90
- else
91
- format("%<p>sfn%<c>04d", p: @prefix, c: @footnote_counter)
92
- end
93
- SL.add_footer "[^#{ref}]: #{note}"
94
- res = "[^#{ref}]"
95
- @cursor_difference += (SL.match_length - res.length)
96
- SL.match_length = res.length
97
- SL.add_report("#{@match_string} => Footnote #{ref}")
98
- res
99
- end
100
- end
101
-
102
- def add_title(link_info)
103
- @url = link_info
104
- title = SL::URL.title(@url)
105
- @link_text = title
106
-
107
- if @ref_title
108
- unless @links.key? @url
109
- @links[@url] = @link_text
110
- SL.add_footer SL.make_link(:ref_title, @link_text, @url, title: title, force_title: false)
111
- end
112
- @delete_line = true
113
- elsif SL.config["inline"]
114
- res = SL.make_link(:inline, @link_text, @url, title: title, force_title: false)
115
- @cursor_difference += SL.match_length - res.length
116
- SL.match_length = res.length
117
- SL.add_report("#{@match_string} => #{@url}")
118
- res
119
- else
120
- unless @links.key? @url
121
- @highest_marker += 1
122
- @links[@url] = format("%<pre>s%<m>04d", pre: @prefix, m: @highest_marker)
123
- SL.add_footer SL.make_link(:ref_title, @links[@url], @url, title: title, force_title: false)
124
- end
125
-
126
- type = SL.config["inline"] ? :inline : :ref_link
127
- res = SL.make_link(type, @link_text, @links[@url], title: false, force_title: false)
128
- @cursor_difference += SL.match_length - res.length
129
- SL.match_length = res.length
130
- SL.add_report("#{@match_string} => #{@url}")
131
- res
132
- end
133
- end
134
-
135
- def custom_search(search_type, search_terms)
136
- SL.config["custom_site_searches"].each do |k, v|
137
- next unless search_type == k
138
-
139
- @link_text = search_terms if !SL.titleize && @link_text == ""
140
- v = parse_arguments(v, { no_restore: true })
141
- if v =~ %r{^(/|http)}i
142
- search_type = "r"
143
- tokens = v.scan(/\$term\d+[ds]?/).sort.uniq
144
-
145
- if !tokens.empty?
146
- highest_token = 0
147
- tokens.each do |token|
148
- if token =~ /(\d+)[ds]?$/ && Regexp.last_match(1).to_i > highest_token
149
- highest_token = Regexp.last_match(1).to_i
150
- end
151
- end
152
- terms_p = search_terms.split(/ +/)
153
- if terms_p.length > highest_token
154
- remainder = terms_p[highest_token - 1..].join(" ")
155
- terms_p = terms_p[0..highest_token - 2]
156
- terms_p.push(remainder)
157
- end
158
- tokens.each do |t|
159
- next unless t =~ /(\d+)[ds]?$/
160
-
161
- int = Regexp.last_match(1).to_i - 1
162
- replacement = terms_p[int]
163
- case t
164
- when /d$/
165
- replacement.downcase!
166
- re_down = ""
167
- when /s$/
168
- replacement.slugify!
169
- re_down = ""
170
- else
171
- re_down = "(?!d|s)"
172
- end
173
- v.gsub!(/#{Regexp.escape(t) + re_down}/, replacement.url_encode)
174
- end
175
- search_terms = v
176
- else
177
- search_terms = v.gsub(/\$term[ds]?/i) do |mtch|
178
- search_terms.downcase! if mtch =~ /d$/i
179
- search_terms.slugify! if mtch =~ /s$/i
180
- search_terms.url_encode
181
- end
182
- end
183
- else
184
- search_type = SL::GoogleSearch.api_key? ? "gg" : "g"
185
- search_terms = "site:#{v} #{search_terms}"
186
- end
187
-
188
- break
189
- end
190
- [search_type, search_terms]
191
- end
192
-
193
5
  def parse(input)
194
6
  SL.output = []
195
7
  return false if input.empty?
@@ -202,6 +14,7 @@ module SL
202
14
  SL.config["inline"] = true if input.scan(/\]\(/).length == 1 && input.split(/\n/).length == 1
203
15
  SL.errors = {}
204
16
  SL.report = []
17
+ SL.shortener = :none
205
18
 
206
19
  # Check for new version
207
20
  latest_version = SL.new_version?
@@ -274,6 +87,7 @@ module SL
274
87
  end
275
88
  end
276
89
 
90
+ # Handle links in the form of [text](url) or [text](url "title")
277
91
  if input =~ /\[(.*?)\]\((.*?)\)/
278
92
  lines = input.split(/\n/)
279
93
  out = []
@@ -330,6 +144,7 @@ module SL
330
144
 
331
145
  @link_text = this_match[1] || ""
332
146
  link_info = parse_arguments(this_match[2].strip).strip || ""
147
+ query, link_info = link_info.extract_query({})
333
148
 
334
149
  if @link_text.strip == "" && link_info =~ /".*?"/
335
150
  link_info.gsub!(/"(.*?)"/) do
@@ -355,7 +170,7 @@ module SL
355
170
  end
356
171
 
357
172
  if link_info =~ /^!(\S+)/
358
- search_type = Regexp.last_match(1)
173
+ search_type = Regexp.last_match(1).extract_shortener
359
174
  unless SL::Searches.valid_search?(search_type) || search_type =~ /^(\S+\.)+\S+$/
360
175
  SL.add_error("Invalid search#{SL::Searches.did_you_mean(search_type)}", match)
361
176
  invalid_search = true
@@ -391,6 +206,8 @@ module SL
391
206
  m[1]
392
207
  end
393
208
 
209
+ search_type.extract_shortener!
210
+
394
211
  search_terms = m[2].gsub(/(^["']|["']$)/, "")
395
212
  search_terms.strip!
396
213
 
@@ -414,17 +231,22 @@ module SL
414
231
  link_only = true if search_terms =~ /!!\^?$/
415
232
 
416
233
  search_terms = search_terms.sub(/(!!)?\^?(!!)?$/, "")
234
+
235
+ if search_type =~ /^(\S+\.)+\S+$/
236
+ search_type = "g"
237
+ search_terms = "site:#{m[1]} #{search_terms}"
238
+ end
417
239
  elsif link_info =~ /^!/
418
240
  search_word = link_info.match(/^!(\S+)/)
419
-
420
- if search_word && SL::Searches.valid_search?(search_word[1])
421
- search_type = search_word[1] unless search_word.nil?
241
+ st = search_word[1].extract_shortener
242
+ if search_word && SL::Searches.valid_search?(st)
243
+ search_type = st unless search_word.nil?
422
244
  search_terms = @link_text
423
- elsif search_word && search_word[1] =~ /^(\S+\.)+\S+$/
245
+ elsif search_word && st =~ /^(\S+\.)+\S+$/
424
246
  search_type = SL::GoogleSearch.api_key? ? "gg" : "g"
425
247
  search_terms = "site:#{search_word[1]} #{@link_text}"
426
248
  else
427
- SL.add_error("Invalid search#{SL::Searches.did_you_mean(search_word[1])}", match)
249
+ SL.add_error("Invalid search#{SL::Searches.did_you_mean(st)}", match)
428
250
  search_type = false
429
251
  search_terms = false
430
252
  end
@@ -444,6 +266,8 @@ module SL
444
266
  search_type, search_terms = custom_search(search_type, search_terms)
445
267
  end
446
268
 
269
+ SL.add_query(query) if query
270
+
447
271
  if (search_type && search_terms) || @url
448
272
  # warn "Searching #{search_type} for #{search_terms}"
449
273
 
@@ -538,12 +362,13 @@ module SL
538
362
  SL.add_report("Processed: #{total_links} links, #{counter_errors} errors.")
539
363
  SL.print_report
540
364
  SL.print_errors
541
- else
365
+ else # Assume single line input
542
366
  link_only = false
543
367
  SL.clipboard = false
544
368
 
545
369
  res = parse_arguments(input.strip!).strip
546
370
  input = res.nil? ? input.strip : res
371
+ query, input = input.extract_query({})
547
372
 
548
373
  # if the end of input contain "^", copy to clipboard instead of STDOUT
549
374
  SL.clipboard = true if input =~ /\^[!~:\s]*$/
@@ -602,8 +427,9 @@ module SL
602
427
 
603
428
  case input
604
429
  when /^!(\S+)\s+(.*)$/
605
- type = Regexp.last_match(1)
430
+ type = Regexp.last_match(1).extract_shortener
606
431
  link_info = Regexp.last_match(2).strip
432
+
607
433
  @link_text ||= link_info
608
434
  terms = link_info + additional_terms
609
435
  terms.strip!
@@ -611,60 +437,7 @@ module SL
611
437
  if SL::Searches.valid_search?(type) || type =~ /^(\S+\.)+\S+$/
612
438
  if type && terms && !terms.empty?
613
439
  # Iterate through custom searches for a match, perform search if matched
614
- SL.config["custom_site_searches"].each do |k, v|
615
- next unless type == k
616
-
617
- @link_text = terms if @link_text == ""
618
- v = parse_arguments(v, { no_restore: true })
619
- if v =~ %r{^(/|http)}i
620
- type = "r"
621
- tokens = v.scan(/\$term\d+[ds]?/).sort.uniq
622
-
623
- if !tokens.empty?
624
- highest_token = 0
625
- tokens.each do |token|
626
- t = Regexp.last_match(1)
627
- highest_token = t.to_i if token =~ /(\d+)d?$/ && t.to_i > highest_token
628
- end
629
- terms_p = terms.split(/ +/)
630
- if terms_p.length > highest_token
631
- remainder = terms_p[highest_token - 1..].join(" ")
632
- terms_p = terms_p[0..highest_token - 2]
633
- terms_p.push(remainder)
634
- end
635
- tokens.each do |t|
636
- next unless t =~ /(\d+)d?$/
637
-
638
- int = Regexp.last_match(1).to_i - 1
639
- replacement = terms_p[int]
640
-
641
- re_down = case t
642
- when /d$/
643
- replacement.downcase!
644
- ""
645
- when /s$/
646
- replacement.slugify!
647
- ""
648
- else
649
- "(?!d|s)"
650
- end
651
- v.gsub!(/#{Regexp.escape(t) + re_down}/, replacement.url_encode)
652
- end
653
- terms = v
654
- else
655
- terms = v.gsub(/\$term[ds]?/i) do |mtch|
656
- terms.downcase! if mtch =~ /d$/i
657
- terms.slugify! if mtch =~ /s$/i
658
- terms.url_encode
659
- end
660
- end
661
- else
662
- type = SL::GoogleSearch.api_key? ? "gg" : "g"
663
- terms = "site:#{v} #{terms}"
664
- end
665
-
666
- break
667
- end
440
+ type, terms = custom_search(type, terms)
668
441
  end
669
442
 
670
443
  # if contains TLD, use site-specific search
@@ -675,6 +448,7 @@ module SL
675
448
  @search_count ||= 0
676
449
  @search_count += 1
677
450
 
451
+ SL.add_query(query) if query
678
452
  @url, title, @link_text = do_search(type, terms, @link_text, @search_count)
679
453
  else
680
454
  SL.add_error("Invalid search#{SL::Searches.did_you_mean(type)}", input)
@@ -689,9 +463,11 @@ module SL
689
463
  "t"
690
464
  end
691
465
  @link_text = input.sub(/^[tfilm]/, "")
466
+ SL.add_query(query) if query
692
467
  @url, title = SL::SocialSearch.social_handle(type, @link_text)
693
468
  @link_text = title
694
469
  else
470
+ SL.add_query(query) if query
695
471
  @link_text ||= input
696
472
  @url, title, @link_text = SL.ddg(input, @link_text)
697
473
  end
@@ -725,5 +501,199 @@ module SL
725
501
  end
726
502
  end
727
503
  end
504
+
505
+ private
506
+
507
+ def add_title(link_info)
508
+ @url = link_info
509
+ title = SL::URL.title(@url)
510
+ @link_text = title
511
+
512
+ if @ref_title
513
+ unless @links.key? @url
514
+ @links[@url] = @link_text
515
+ SL.add_footer SL.make_link(:ref_title, @link_text, @url, title: title, force_title: false)
516
+ end
517
+ @delete_line = true
518
+ elsif SL.config["inline"]
519
+ res = SL.make_link(:inline, @link_text, @url, title: title, force_title: false)
520
+ @cursor_difference += SL.match_length - res.length
521
+ SL.match_length = res.length
522
+ SL.add_report("#{@match_string} => #{@url}")
523
+ res
524
+ else
525
+ unless @links.key? @url
526
+ @highest_marker += 1
527
+ @links[@url] = format("%<pre>s%<m>04d", pre: @prefix, m: @highest_marker)
528
+ SL.add_footer SL.make_link(:ref_title, @links[@url], @url, title: title, force_title: false)
529
+ end
530
+
531
+ type = SL.config["inline"] ? :inline : :ref_link
532
+ res = SL.make_link(type, @link_text, @links[@url], title: false, force_title: false)
533
+ @cursor_difference += SL.match_length - res.length
534
+ SL.match_length = res.length
535
+ SL.add_report("#{@match_string} => #{@url}")
536
+ res
537
+ end
538
+ end
539
+
540
+ # Parse arguments in the input string
541
+ #
542
+ # @param string [String] the string to parse
543
+ # @param opt [Hash] the options to parse
544
+ # @option opt [Boolean] :only_meta (false) whether to skip flags
545
+ # @option opt [Boolean] :no_restore (false) whether to restore previous config
546
+ # @return [String] the parsed string
547
+ #
548
+ def parse_arguments(string, opt = {})
549
+ input = string.dup
550
+ return "" if input.nil?
551
+
552
+ skip_flags = opt[:only_meta] || false
553
+ no_restore = opt[:no_restore] || false
554
+ restore_prev_config unless no_restore
555
+
556
+ input.parse_flags! unless skip_flags
557
+
558
+ options = %w[debug country_code inline prefix_random include_titles remove_seo validate_links complete_bare]
559
+ options.each do |o|
560
+ if input =~ /^ *#{o}:\s+(\S+)$/
561
+ val = Regexp.last_match(1).strip
562
+
563
+ if val.is_a?(String)
564
+ value = true if val =~ /true/i
565
+ value = false if val =~ /false/i
566
+ end
567
+ val = value if value
568
+ SL.config[o] = val
569
+ warn "\r\033[0KGlobal config: #{o} = #{SL.config[o]}\n" unless SILENT
570
+ end
571
+
572
+ next if skip_flags
573
+
574
+ while input =~ /^#{o}:\s+(.*?)$/ || input =~ /--(no-)?#{o}/
575
+ next unless input =~ /--(no-)?#{o}/ && !skip_flags
576
+
577
+ unless SL.prev_config.key? o
578
+ SL.prev_config[o] = SL.config[o]
579
+ bool = Regexp.last_match(1).nil? || Regexp.last_match(1) == "" ? true : false
580
+ SL.config[o] = bool
581
+ $stderr.print "\r\033[0KLine config: #{o} = #{SL.config[o]}\n" unless SILENT
582
+ end
583
+ input.sub!(/\s?--(no-)?#{o}/, "")
584
+ end
585
+ end
586
+ SL.clipboard ? string : input
587
+ end
588
+
589
+ # Parse commands from the given input string
590
+ #
591
+ # @param input [String] the input string
592
+ def parse_commands(input)
593
+ # Handle commands like help or docs
594
+ return unless input.strip =~ /^!?(h(elp)?|wiki|docs?|v(er(s(ion)?)?)?|up(date|grade))$/
595
+
596
+ case input.strip
597
+ when /^!?help$/i
598
+ if SILENT
599
+ help_dialog
600
+ else
601
+ $stdout.puts SL.version_check.to_s
602
+ $stdout.puts "See https://github.com/ttscoff/searchlink/wiki for help"
603
+ end
604
+ print input
605
+ when /^!?(wiki|docs)$/i
606
+ warn "Opening wiki in browser"
607
+ `open https://github.com/ttscoff/searchlink/wiki`
608
+ when /^!?v(er(s(ion)?)?)?$/
609
+ print "[#{SL.version_check}]"
610
+ when /^!?up(date|grade)$/
611
+ SL.update_searchlink
612
+ print SL.output.join("")
613
+ end
614
+ Process.exit 0
615
+ end
616
+
617
+ def create_footnote(mtch)
618
+ if mtch[1].nil? || mtch[1] == ""
619
+ match
620
+ else
621
+ note = mtch[1].strip
622
+ @footnote_counter += 1
623
+ ref = if !@link_text.empty? && @link_text.scan(/\s/).empty?
624
+ @link_text
625
+ else
626
+ format("%<p>sfn%<c>04d", p: @prefix, c: @footnote_counter)
627
+ end
628
+ SL.add_footer "[^#{ref}]: #{note}"
629
+ res = "[^#{ref}]"
630
+ @cursor_difference += (SL.match_length - res.length)
631
+ SL.match_length = res.length
632
+ SL.add_report("#{@match_string} => Footnote #{ref}")
633
+ res
634
+ end
635
+ end
636
+
637
+ def custom_search(search_type, search_terms)
638
+ SL.config["custom_site_searches"].each do |k, v|
639
+ next unless search_type == k
640
+
641
+ @link_text = search_terms if !SL.titleize && @link_text == ""
642
+ v = parse_arguments(v, { no_restore: true })
643
+ query, v = v.extract_query({})
644
+
645
+ SL.add_query(query)
646
+
647
+ if v =~ %r{^(/|http)}i
648
+ search_type = "r"
649
+ tokens = v.scan(/\$term\d+[ds]?/).sort.uniq
650
+
651
+ if !tokens.empty?
652
+ highest_token = 0
653
+ tokens.each do |token|
654
+ if token =~ /(\d+)[ds]?$/ && Regexp.last_match(1).to_i > highest_token
655
+ highest_token = Regexp.last_match(1).to_i
656
+ end
657
+ end
658
+ terms_p = search_terms.split(/ +/)
659
+ if terms_p.length > highest_token
660
+ remainder = terms_p[highest_token - 1..].join(" ")
661
+ terms_p = terms_p[0..highest_token - 2]
662
+ terms_p.push(remainder)
663
+ end
664
+ tokens.each do |t|
665
+ next unless t =~ /(\d+)[ds]?$/
666
+
667
+ int = Regexp.last_match(1).to_i - 1
668
+ replacement = terms_p[int]
669
+ case t
670
+ when /d$/
671
+ replacement.downcase!
672
+ re_down = ""
673
+ when /s$/
674
+ replacement.slugify!
675
+ re_down = ""
676
+ else
677
+ re_down = "(?!d|s)"
678
+ end
679
+ v.gsub!(/#{Regexp.escape(t) + re_down}/, replacement.url_encode)
680
+ end
681
+ search_terms = v
682
+ else
683
+ search_terms = v.gsub(/\$term[ds]?/i) do |mtch|
684
+ search_terms.downcase! if mtch =~ /d$/i
685
+ search_terms.slugify! if mtch =~ /s$/i
686
+ search_terms.url_encode
687
+ end
688
+ end
689
+ else
690
+ search_type = SL::GoogleSearch.api_key? ? "gg" : "g"
691
+ search_terms = "site:#{v} #{search_terms}"
692
+ end
693
+
694
+ break
695
+ end
696
+ [search_type, search_terms]
697
+ end
728
698
  end
729
699
  end
@@ -14,11 +14,12 @@ module SL
14
14
  config: [
15
15
  {
16
16
  key: "bitly_access_token",
17
- value: "xxxx",
18
- required: false,
17
+ value: "",
18
+ required: true,
19
19
  description: "Generate an access token at https://app.bitly.com/settings/api/"
20
20
  },
21
21
  {
22
+ description: "Bit.ly domain (optional).",
22
23
  key: "bitly_domain",
23
24
  value: "bit.ly",
24
25
  required: false
@@ -31,32 +32,55 @@ module SL
31
32
  if SL::URL.url?(search_terms)
32
33
  link = search_terms
33
34
  else
34
- link, rtitle = SL.ddg(search_terms, link_text)
35
+ link, title, link_text = SL.ddg(search_terms, link_text)
35
36
  end
36
37
 
37
- url, title = bitly_shorten(link, rtitle)
38
- link_text = title || url
39
- [url, title, link_text]
40
- end
38
+ url = shorten(link)
41
39
 
42
- def bitly_shorten(url, title = nil)
43
- unless SL.config.key?("bitly_access_token") && !SL.config["bitly_access_token"].empty?
44
- SL.add_error("Bit.ly not configured", "Missing access token")
45
- return [false, title]
40
+ unless url
41
+ SL.add_error("Result is not a valid URL", "URL error")
42
+ return [false, title, link_text]
46
43
  end
47
44
 
45
+ format_response(url, link, link_text)
46
+ end
47
+
48
+ def shorten(url)
49
+ return false unless bitly_config?
50
+
48
51
  domain = SL.config.key?("bitly_domain") ? SL.config["bitly_domain"] : "bit.ly"
49
- long_url = url.dup
50
- curl = TTY::Which.which("curl")
51
- cmd = [
52
- %(#{curl} -SsL -H 'Authorization: Bearer #{SL.config['bitly_access_token']}'),
53
- %(-H 'Content-Type: application/json'),
54
- "-X POST", %(-d '{ "long_url": "#{url}", "domain": "#{domain}" }'), "https://api-ssl.bitly.com/v4/shorten"
55
- ]
56
- data = JSON.parse(`#{cmd.join(" ")}`.strip)
57
- link = data["link"]
58
- title ||= SL::URL.title(long_url)
59
- [link, title]
52
+
53
+ headers = {
54
+ "Content-Type" => "application/json",
55
+ "Authorization" => "Bearer #{SL.config['bitly_access_token']}"
56
+ }
57
+ data_obj = {
58
+ "long_url" => url,
59
+ "domain" => domain
60
+ }
61
+ data = Curl::Json.new("https://api-ssl.bitly.com/v4/shorten", data: data_obj.to_json, headers: headers, symbolize_names: true)
62
+
63
+ return false unless data.json.key?(:link)
64
+
65
+ link = data.json[:link]
66
+
67
+ return false unless SL::URL.valid_link?(link)
68
+
69
+ link
70
+ end
71
+
72
+ private
73
+
74
+ def bitly_config?
75
+ return true if SL.config["bitly_access_token"] && !SL.config["bitly_access_token"].empty?
76
+
77
+ SL.add_error("Bit.ly not configured", "Missing access token")
78
+ false
79
+ end
80
+
81
+ def format_response(link, original_url, link_text)
82
+ rtitle = SL::URL.title(original_url)
83
+ [link, rtitle, link_text == "" && !SL.titleize ? rtitle : link_text]
60
84
  end
61
85
  end
62
86
 
@@ -25,6 +25,9 @@ module SL
25
25
  end
26
26
 
27
27
  def search(search_type, search_terms, link_text)
28
+ @auth_token = Secrets::GH_AUTH_TOKEN if defined? Secrets::GH_AUTH_TOKEN
29
+ @auth_token = SL.config["github_token"] if SL.config.key?("github_token") && !SL.config["github_token"].empty?
30
+
28
31
  case search_type
29
32
  when /^gist/
30
33
  url, title, link_text = gist(search_terms, search_type, link_text)
@@ -46,7 +49,7 @@ module SL
46
49
  "Accept" => "application/vnd.github+json",
47
50
  "X-GitHub-Api-Version" => "2022-11-28"
48
51
  }
49
- headers["Authorization"] = "Bearer #{Secrets::GH_AUTH_TOKEN}" if defined? Secrets::GH_AUTH_TOKEN
52
+ headers["Authorization"] = "Bearer #{@auth_token}" if defined? @auth_token
50
53
 
51
54
  url = "https://api.github.com/search/#{endpoint}?q=#{query.url_encode}&per_page=1&page=1&order=desc"
52
55
  res = Curl::Json.new(url, headers: headers)
@@ -163,6 +166,8 @@ module SL
163
166
  end
164
167
 
165
168
  def filter_gists(gists, search_terms)
169
+ return false if gists.is_a?(Hash)
170
+
166
171
  score = 0
167
172
  gists.map! do |g|
168
173
  {
@@ -238,7 +243,7 @@ module SL
238
243
  end
239
244
 
240
245
  # Assuming we retrieved a full gist URL
241
- if url =~ %r{https://gist.github.com/(?:(?<user>[^/]+)/)?(?<id>[a-z0-9]+?)(?:[#/](?<file>(?:file-)?.*?))?$}
246
+ if url && url =~ %r{https://gist.github.com/(?:(?<user>[^/]+)/)?(?<id>[a-z0-9]+?)(?:[#/](?<file>(?:file-)?.*?))?$}
242
247
  m = Regexp.last_match
243
248
  user = m["user"]
244
249
  id = m["id"]
@@ -43,7 +43,7 @@ module SL
43
43
  return false
44
44
  end
45
45
 
46
- url = "https://customsearch.googleapis.com/customsearch/v1?cx=338419ee5ac894523&q=#{ERB::Util.url_encode(search_terms)}&num=1&key=#{@api_key}"
46
+ url = "https://customsearch.googleapis.com/customsearch/v1?cx=338419ee5ac894523&q=#{ERB::Util.url_encode(search_terms.gsub(/%22/, '"'))}&num=1&key=#{@api_key}"
47
47
  json = Curl::Json.new(url).json
48
48
 
49
49
  if json["error"] && json["error"]["code"].to_i == 429
@@ -68,8 +68,13 @@ module SL
68
68
  ## @return [Array] [url, title, date]
69
69
  ##
70
70
  def search_safari_bookmarks(terms)
71
- data = `plutil -convert xml1 -o - ~/Library/Safari/Bookmarks.plist`.strip
71
+ data = `plutil -extract Children xml1 -o - ~/Library/Safari/Bookmarks.plist`.strip
72
+
73
+ data.gsub!(%r{<key>Data</key>\s+<data>(.+?)</data>\n}m, "")
74
+ data.gsub!(/\t/, "")
75
+
72
76
  parent = Plist.parse_xml(data)
77
+
73
78
  results = get_safari_bookmarks(parent, terms)
74
79
  return false if results.empty?
75
80
 
@@ -45,12 +45,11 @@ module SL
45
45
  ],
46
46
  config: [
47
47
  {
48
- description:
49
- ["Remove or comment (with #) history searches you don't want",
50
- "performed by `!h`. You can force-enable them per search, e.g.",
51
- "`!hsh` (Safari History only), `!hcb` (Chrome Bookmarks only)",
52
- "etc. Multiple types can be strung together: !hshcb (Safari",
53
- "History and Chrome bookmarks)"].join(" "),
48
+ description: ["Remove or comment (with #) history searches you don't want",
49
+ "performed by `!h`. You can force-enable them per search, e.g.",
50
+ "`!hsh` (Safari History only), `!hcb` (Chrome Bookmarks only)",
51
+ "etc. Multiple types can be strung together: !hshcb (Safari",
52
+ "History and Chrome bookmarks)"].join(" "),
54
53
  required: false,
55
54
  key: "history_types",
56
55
  value: %w[
@@ -17,29 +17,26 @@ module SL
17
17
  if SL::URL.url?(search_terms)
18
18
  link = search_terms
19
19
  else
20
- link, rtitle = SL.ddg(search_terms, link_text)
20
+ link, title, link_text = SL.ddg(search_terms, link_text)
21
21
  end
22
22
 
23
- url, title = isgd_shorten(link, rtitle)
24
- link_text = title || url
23
+ url = shorten(link)
24
+ title = SL::URL.title(link) if title.nil? || title.empty?
25
+ link_text = title if (link_text.nil? || link_text.empty?) && !SL.titleize
25
26
  [url, title, link_text]
26
27
  end
27
28
 
28
- def isgd_shorten(url, title = nil)
29
+ def shorten(url)
29
30
  long_url = url.dup
30
31
 
31
32
  data = Curl::Json.new("https://is.gd/create.php?format=json&url=#{CGI.escape(long_url)}", symbolize_names: true)
32
33
 
33
34
  if data.json.key?("errorcode")
34
35
  SL.add_error("Error creating is.gd url", data.json[:errorcode])
35
- return [false, title, link_text]
36
+ return false
36
37
  end
37
38
 
38
- link = data.json[:shorturl]
39
- rtitle = SL::URL.title(long_url)
40
- title = rtitle
41
- link_text = rtitle if link_text == "" && !SL.titleize
42
- [link, title, link_text]
39
+ data.json[:shorturl]
43
40
  end
44
41
  end
45
42
 
@@ -10,6 +10,20 @@ module SL
10
10
  trigger: "(ld|ding)",
11
11
  searches: [
12
12
  [%w[ld ding], "Linkding Bookmark Search"]
13
+ ],
14
+ config: [
15
+ {
16
+ description: "Linkding server URL.",
17
+ key: "linkding_server",
18
+ value: "''",
19
+ required: true
20
+ },
21
+ {
22
+ description: "Linkding API key.\nYou can find your api key here: https://your_server/settings/integrations",
23
+ key: "linkding_api_key",
24
+ value: "''",
25
+ required: true
26
+ }
13
27
  ]
14
28
  }
15
29
  end
@@ -108,7 +122,7 @@ module SL
108
122
  cache
109
123
  end
110
124
 
111
- # Search pinboard bookmarks
125
+ # Search linkding bookmarks
112
126
  # Begin query with '' to force exact matching (including description text)
113
127
  # Regular matching searches for each word of query and scores the bookmarks
114
128
  # exact matches in title get highest score
@@ -120,13 +134,13 @@ module SL
120
134
  #
121
135
  # Exact matching is case and punctuation insensitive
122
136
  def search(_, search_terms, link_text)
123
- unless SL.config["linkding_server"]
137
+ unless SL.config["linkding_server"] && !SL.config["linkding_server"].empty?
124
138
  SL.add_error("Missing Linkding server",
125
139
  "add it to your configuration (linkding_server: https://YOUR_SERVER)")
126
140
  return false
127
141
  end
128
142
 
129
- unless SL.config["linkding_api_key"]
143
+ unless SL.config["linkding_api_key"] && !SL.config["linkding_api_key"].empty?
130
144
  SL.add_error("Missing Linkding API token",
131
145
  "Find your api key at https://your_server/settings/integrations and add it
132
146
  to your configuration (linkding_api_key: YOURKEY)")
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Setapp Plugin
4
+ # Takes an app name or Setapp URL, adds an affiliate string,
5
+ # and outputs a URL, optionally shortened with is.gd or bit.ly
6
+ #
7
+ # Optional config:
8
+ #
9
+ # ```yaml
10
+ # setapp_affiliate_string: xxxxxxxxx # see below
11
+ # bitly_domain: bit.ly # or custom domain
12
+ # bitly_access_token: xxxxxxxxxxxx # see below
13
+ # ```
14
+ #
15
+ # To get your Setapp affiliate string
16
+ #
17
+ # 1. You must have a Setapp affiliate account through impact.com
18
+ # 2. Generate a campaign url for an app landing page
19
+ # 3. Follow the short link provided
20
+ # 4. The browser URL bar will now show the expanded link
21
+ # 5. Copy everything after the & symbol in the url to
22
+ # the `setapp_affiliate_string` config line
23
+ #
24
+ # Run a search with !set, !seti, or !setb. The input can either be
25
+ # a Setapp app landing page url, or an app name, e.g. `!seti marked`,
26
+ # `[jump desktop](!seti)`, or `!setb https://setapp.com/apps/marked`
27
+ #
28
+ module SL
29
+ # is.gd link shortening
30
+ class SetappSearch
31
+ class << self
32
+ def settings
33
+ {
34
+ trigger: "set[ib]?",
35
+ searches: [
36
+ ["set", "Setapp Link with optional affiliate string"],
37
+ ["seti", "Shorten Setapp Affiliate Link with is.gd"],
38
+ ["setb", "Shorten Setapp Affiliate Link with bit.ly"]
39
+ ],
40
+ config: [
41
+ {
42
+ description: "Setapp affiliate string (optional).\nYou can find your affiliate string here: https://www.impact.com/affiliate/links",
43
+ key: "setapp_affiliate_string",
44
+ value: "''",
45
+ required: false
46
+ }
47
+ ]
48
+ }
49
+ end
50
+
51
+ def search(search_type, search_terms, link_text)
52
+ link = build_link(search_terms)
53
+ link, rtitle, link_text = process_link(link, search_terms, link_text)
54
+ return [false, rtitle, link_text] unless valid_setapp_url?(link)
55
+
56
+ process_search_type(search_type, link, rtitle, link_text)
57
+ end
58
+
59
+ private
60
+
61
+ def build_link(search_terms)
62
+ return search_terms if SL::URL.url?(search_terms)
63
+
64
+ "https://setapp.com/apps/#{CGI.escape(search_terms.gsub(/ \d+$/, '').gsub(/ +/, '-').downcase)}"
65
+ end
66
+
67
+ def process_link(link, search_terms, link_text)
68
+ SL::URL.valid_link?(link, 2) && [link, search_terms, link_text] || SL.ddg("site:setapp.com #{search_terms}", link_text)
69
+ end
70
+
71
+ def process_search_type(search_type, link, title, link_text)
72
+ link_text = link_text.nil? || link_text.empty? ? Curl::Html.new(link).title.sub(/ on Setapp.*/, "") : link_text
73
+ link = build_affiliate_url(link)
74
+ case search_type
75
+ when "set"
76
+ format_response(link, link_text)
77
+ when "seti"
78
+ shorten(:isgd, link, title, link_text)
79
+ when "setb"
80
+ shorten(:bitly, link, title, link_text)
81
+ else
82
+ SL.add_error("Invalid search type", "Search error")
83
+ [false, title, link_text]
84
+ end
85
+ end
86
+
87
+ def shorten(type, url, title = nil, link_text = nil)
88
+ return [false, title, link_text] unless valid_setapp_url?(url)
89
+
90
+ shortened_url = case type
91
+ when :isgd
92
+ SL::IsgdSearch.shorten(url)
93
+ when :bitly
94
+ SL::BitlySearch.shorten(url)
95
+ end
96
+ return [false, title, link_text] unless shortened_url
97
+
98
+ format_response(shortened_url, link_text)
99
+ end
100
+
101
+ def valid_setapp_url?(url)
102
+ return true if SL::URL.valid_link?(url, 2) && url =~ %r{^https://setapp.com}
103
+
104
+ SL.add_error("URL is not a valid Setapp link", "URL error")
105
+ false
106
+ end
107
+
108
+ def valid_affiliate_config?
109
+ return true if SL.config.key?("setapp_affiliate_string") && !SL.config["setapp_affiliate_string"].empty?
110
+
111
+ # SL.add_error("Setapp affiliate string not configured", "Missing affiliate string")
112
+ false
113
+ end
114
+
115
+ def build_affiliate_url(url)
116
+ return url unless valid_affiliate_config?
117
+
118
+ separator = url =~ /\?/ ? "&" : "?"
119
+ "#{url}#{SL.config['setapp_affiliate_string'].sub(/^[?&]?/, separator)}"
120
+ end
121
+
122
+ def format_response(link, link_text)
123
+ title = SL::URL.title(link)
124
+
125
+ [link, title, link_text.nil? || link_text.empty? && !SL.titleize ? title : link_text]
126
+ end
127
+ end
128
+
129
+ SL::Searches.register "setapp", :search, self
130
+ end
131
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SL
4
+ # is.gd link shortening
5
+ class TinyurlSearch
6
+ class << self
7
+ def settings
8
+ {
9
+ trigger: "tiny",
10
+ searches: [
11
+ ["tiny", "TinyURL Shorten"]
12
+ ],
13
+ config: [
14
+ {
15
+ key: "tinyurl_access_token",
16
+ value: "",
17
+ required: true,
18
+ description: "Generate a tinyurl API key at https://tinyurl.ph/developers (login required)"
19
+ }
20
+ ]
21
+ }
22
+ end
23
+
24
+ def search(_, search_terms, link_text)
25
+ if SL::URL.url?(search_terms)
26
+ link = search_terms
27
+ else
28
+ link, title, link_text = SL.ddg(search_terms, link_text)
29
+ end
30
+
31
+ url = shorten(link)
32
+ title = SL::URL.title(link) if title.nil? || title.empty?
33
+ link_text = title if (link_text.nil? || link_text.empty?) && !SL.titleize
34
+ format_response(url, link, link_text)
35
+ end
36
+
37
+ def shorten(url)
38
+ return false unless tinyurl_config?
39
+
40
+ headers = {
41
+ "Content-Type" => "application/json",
42
+ "Authorization" => "Bearer #{SL.config['tinyurl_access_token']}"
43
+ }
44
+ data_obj = {
45
+ "url" => url
46
+ }
47
+ data = Curl::Json.new("https://tinyurl.ph/api/url/add", data: data_obj.to_json, headers: headers, symbolize_names: true)
48
+
49
+ if data.json[:error].positive?
50
+ SL.add_error("Error creating tinyurl", data.json[:error])
51
+ return false
52
+ end
53
+
54
+ data.json[:shorturl]
55
+ end
56
+
57
+ def tinyurl_config?
58
+ return true if SL.config["tinyurl_access_token"] && !SL.config["tinyurl_access_token"].empty?
59
+
60
+ SL.add_error("TinyURL not configured", "Missing access token")
61
+ false
62
+ end
63
+
64
+ def format_response(link, original_url, link_text)
65
+ rtitle = SL::URL.title(original_url)
66
+ [link, rtitle, link_text == "" && !SL.titleize ? rtitle : link_text]
67
+ end
68
+ end
69
+
70
+ SL::Searches.register "tiny", :search, self
71
+ end
72
+ end
@@ -218,6 +218,9 @@ require_relative "searches/lastfm"
218
218
  # import
219
219
  require_relative "searches/pinboard"
220
220
 
221
+ # import
222
+ require_relative "searches/setapp"
223
+
221
224
  # import
222
225
  require_relative "searches/social"
223
226
 
@@ -245,5 +248,8 @@ require_relative "searches/youtube"
245
248
  # import
246
249
  require_relative "searches/stackoverflow"
247
250
 
251
+ # import
252
+ require_relative "searches/tinyurl"
253
+
248
254
  # import
249
255
  require_relative "searches/linkding"
@@ -37,6 +37,73 @@ module SL
37
37
  replace scrub
38
38
  end
39
39
 
40
+ # Extract query string from search string
41
+ def extract_query(known_queries = {})
42
+ string = gsub(/\?((\S+?)=(\S+?)(?=&|$|\s))+/) do |mtch|
43
+ tokens = mtch.sub(/^\?/, "").split("&")
44
+ tokens.each do |token|
45
+ key, value = token.split("=")
46
+
47
+ known_queries[key] = value
48
+ end
49
+
50
+ ""
51
+ end.gsub(/ +/, " ").strip
52
+
53
+ [known_queries, string]
54
+ end
55
+
56
+ # Extract a shortner from a string
57
+ def extract_shortener
58
+ return self unless self =~ /_[ibt]$/i
59
+
60
+ shortener = split(/_/).last
61
+ SL.shortener = case shortener
62
+ when /i/i
63
+ :isgd
64
+ when /b/i
65
+ :bitly
66
+ when /t/i
67
+ :tinyurl
68
+ else
69
+ :none
70
+ end
71
+
72
+ sub(/_[ibt]$/i, "")
73
+ end
74
+
75
+ # Destructive version of #extract_shortener
76
+ # @see #extract_shortener
77
+ # @return [String] The string without the shortener
78
+ def extract_shortener!
79
+ replace extract_shortener
80
+ end
81
+
82
+ # Format and append a query string
83
+ #
84
+ # @return [String] The formatted query string
85
+ #
86
+ def add_query_string
87
+ return self if SL.query.empty?
88
+
89
+ query = SL.query.map { |k, v| "#{k}=#{v}" }.join("&")
90
+
91
+ query = if self =~ /\?[^= ]+=\S+/
92
+ "&#{query}"
93
+ else
94
+ "?#{query}"
95
+ end
96
+
97
+ "#{self}#{query}"
98
+ end
99
+
100
+ # Destructive version of #add_query_string
101
+ # @see #add_query_string
102
+ # @return [String] The formatted query string
103
+ def add_query_string!
104
+ replace add_query_string
105
+ end
106
+
40
107
  # URL Encode string
41
108
  #
42
109
  # @return [String] url encoded string
@@ -157,6 +224,30 @@ module SL
157
224
  input + append
158
225
  end
159
226
 
227
+ ##
228
+ ## Append an affiliate string to a URL
229
+ ##
230
+ ## @param aff_string [String] The affiliate string
231
+ ## @return [String] The URL with the affiliate string
232
+ ##
233
+ ## @see #append_affiliate_string!
234
+ ##
235
+ def append_affiliate_string(aff_string)
236
+ separator = self =~ /\?/ ? "&" : "?"
237
+ "#{self}#{aff_string.sub(/^[?&]?/, separator)}"
238
+ end
239
+
240
+ ## Destructively append an affiliate string to a URL
241
+ ##
242
+ ## @param aff_string [String] The affiliate string
243
+ ## @return [String] The URL with the affiliate string
244
+ ##
245
+ ## @see #append_affiliate_string
246
+ ##
247
+ def append_affiliate_string!(aff_string)
248
+ replace append_affiliate_string(aff_string)
249
+ end
250
+
160
251
  ##
161
252
  ## Remove the protocol from a URL
162
253
  ##
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SL
4
- VERSION = '2.3.83'
4
+ VERSION = "2.3.85"
5
5
  end
6
6
 
7
7
  # Main module
@@ -47,7 +47,7 @@ module SL
47
47
  if defined? Secrets::GH_AUTH_TOKEN
48
48
  headers["Authorization"] = "Bearer #{Secrets::GH_AUTH_TOKEN}"
49
49
  elsif SL.config["github_token"]
50
- headers["Authorization"] = "Bearer #{SL.settings["github_token"]}"
50
+ headers["Authorization"] = "Bearer #{SL.config["github_token"]}"
51
51
  end
52
52
 
53
53
  url = "https://api.github.com/repos/ttscoff/searchlink/releases/latest"
data/lib/tokens.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Secrets
2
- GH_AUTH_TOKEN = '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'
4
+ GH_AUTH_TOKEN = "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"
3
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: searchlink
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.83
4
+ version: 2.3.85
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-26 00:00:00.000000000 Z
10
+ date: 2025-03-30 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: base64
@@ -141,14 +141,14 @@ dependencies:
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: 3.7.1
144
+ version: 3.7.2
145
145
  type: :development
146
146
  prerelease: false
147
147
  version_requirements: !ruby/object:Gem::Requirement
148
148
  requirements:
149
149
  - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: 3.7.1
151
+ version: 3.7.2
152
152
  - !ruby/object:Gem::Dependency
153
153
  name: rake
154
154
  requirement: !ruby/object:Gem::Requirement
@@ -303,11 +303,13 @@ files:
303
303
  - lib/searchlink/searches/linkding.rb
304
304
  - lib/searchlink/searches/lyrics.rb
305
305
  - lib/searchlink/searches/pinboard.rb
306
+ - lib/searchlink/searches/setapp.rb
306
307
  - lib/searchlink/searches/social.rb
307
308
  - lib/searchlink/searches/software.rb
308
309
  - lib/searchlink/searches/spelling.rb
309
310
  - lib/searchlink/searches/spotlight.rb
310
311
  - lib/searchlink/searches/stackoverflow.rb
312
+ - lib/searchlink/searches/tinyurl.rb
311
313
  - lib/searchlink/searches/tmdb.rb
312
314
  - lib/searchlink/searches/twitter.rb
313
315
  - lib/searchlink/searches/wikipedia.rb