searchlink 2.3.85 → 2.3.87

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.
@@ -41,7 +41,7 @@ module SL
41
41
  ["heh", "Edge History Search"],
42
42
  ["heb", "Edge Bookmark Search"],
43
43
  ["hehb", nil],
44
- ["hebh", nil]
44
+ ["hebh", nil],
45
45
  ],
46
46
  config: [
47
47
  {
@@ -65,9 +65,9 @@ module SL
65
65
  brave_history
66
66
  arc_history
67
67
  arc_bookmarks
68
- ]
69
- }
70
- ]
68
+ ],
69
+ },
70
+ ],
71
71
  }
72
72
  end
73
73
 
@@ -156,7 +156,7 @@ module SL
156
156
  end
157
157
 
158
158
  url, title = search_history(search_terms, types)
159
- link_text = title if link_text == "" || link_text == search_terms
159
+ link_text = title if link_text == ""
160
160
  [url, title, link_text]
161
161
  end
162
162
 
@@ -46,7 +46,7 @@ module SL
46
46
  end
47
47
 
48
48
  def get_linkding_bookmarks
49
- curl = TTY::Which.which("curl")
49
+ TTY::Which.which("curl")
50
50
  call = "/api/bookmarks/?limit=8000&format=json"
51
51
 
52
52
  json = get_json(call)
@@ -101,7 +101,7 @@ module SL
101
101
  cache = linkding_bookmarks
102
102
  save_linkding_cache(cache)
103
103
  end
104
- curl = TTY::Which.which("curl")
104
+ TTY::Which.which("curl")
105
105
  updated = get_json("/api/bookmarks/?limit=1&format=json")["results"][0]
106
106
  last_bookmark = Time.parse(updated["date_modified"])
107
107
  if cache&.key?("update_time")
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SL
4
+ class PopupSearch
5
+ class << self
6
+ def settings
7
+ {
8
+ trigger: "pop(up)?[gaw]?",
9
+ searches: [
10
+ ["pop", "Popup DuckDuckGo Search"],
11
+ ["popa", "Popup Amazon Search"],
12
+ ["popg", "Popup Google Search"],
13
+ ["popw", "Popup Wikipedia Search"]
14
+ ]
15
+ }
16
+ end
17
+
18
+ def search(type, search_terms, link_text)
19
+ return [false, false, link_text] unless workflow_exist?
20
+
21
+ term = search_terms.url_encode
22
+ url = case type
23
+ when /g$/
24
+ "https://www.google.com/search?hl=en&q=#{term}"
25
+ when /a$/
26
+ "https://www.amazon.com/s?k=#{term}"
27
+ when /b$/
28
+ "https://www.bing.com/search?q=#{term}"
29
+ when /w$/
30
+ "https://en.wikipedia.org/w/index.php?search=#{term}&title=Special%3ASearch&ns0=1"
31
+ else
32
+ "https://duckduckgo.com/?q=#{term}&ia=web"
33
+ end
34
+
35
+ res = `automator -i "#{url}" "#{SL::Util.popup_path}"`.strip
36
+
37
+ begin
38
+ if res.empty?
39
+ SL.add_error("Canceled", "Popup Search Cancelled")
40
+ return [false, false, link_text]
41
+ end
42
+
43
+ title = SL::URL.title(res)
44
+
45
+ link_text = title if link_text == "" && !SL.titleize
46
+
47
+ [res, title, link_text]
48
+ rescue StandardError
49
+ false
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def workflow_exist?
56
+ unless SL::Util.popup_path
57
+ SL.add_error("Missing Service", "Preview URL Service not installed")
58
+ return false
59
+ end
60
+
61
+ true
62
+ end
63
+ end
64
+
65
+ SL::Searches.register "popup", :search, self
66
+ end
67
+ end
@@ -65,7 +65,9 @@ module SL
65
65
  end
66
66
 
67
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)
68
+ SL::URL.valid_link?(link,
69
+ 2) && [link, search_terms,
70
+ link_text] || SL.ddg("site:setapp.com #{search_terms}", link_text)
69
71
  end
70
72
 
71
73
  def process_search_type(search_type, link, title, link_text)
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ # import
4
+ require_relative "shorteners/bitly"
5
+
6
+ # import
7
+ require_relative "shorteners/isgd"
8
+
9
+ # import
10
+ require_relative "shorteners/tinyurl"
11
+
12
+ module SL
13
+ class Shortener
14
+ class << self
15
+ # Displays an AppleScript dialog to confirm shortening a URL.
16
+ #
17
+ # @param url [String] The URL to confirm shortening for.
18
+ # @return [Boolean] True if the user confirms, false otherwise.
19
+ #
20
+ def confirm?(url, title: "Confirm URL?")
21
+
22
+ if SL::Util.popup_path
23
+ cmd = %(osascript -e 'display dialog "#{url}" with title "#{title}" buttons {"Cancel", "Confirm", "Preview"}')
24
+
25
+ res = `#{cmd}`.strip
26
+
27
+ return res =~ /Confirm/ unless res =~ /Preview/
28
+
29
+ res = `automator -i "#{url}" "#{SL::Util.popup_path}"`.strip
30
+
31
+ return res.empty? ? false : res
32
+ end
33
+
34
+ res = system(%(osascript -e 'display dialog "#{url}" with title "#{title}" buttons {"Cancel", "Confirm"}'))
35
+
36
+ res == 0
37
+ end
38
+
39
+ # Shortens a URL using the specified shortener.
40
+ #
41
+ # @param url [String] The URL to shorten.
42
+ # @param shortener [Symbol] The shortener to use (:tinyurl, :bitly, :isgd).
43
+ # @return [String] The shortened URL.
44
+ # @raise [ArgumentError] If the shortener is unknown.
45
+ #
46
+ # @example
47
+ # SL::Shortener.shorten('http://example.com', :tinyurl)
48
+ #
49
+ def shorten(url, shortener)
50
+ # Check if the URL is already shortened
51
+ return url unless SL::URL.url?(url)
52
+
53
+ known_shorteners = %i[tinyurl bitly isgd]
54
+ return url unless known_shorteners.include?(shortener)
55
+
56
+ unless NO_CONFIRM
57
+ # Confirm shortening the URL
58
+ res = SL::Shortener.confirm?(url, title: "Shorten URL?")
59
+
60
+ return url unless res
61
+
62
+ url = res if res.is_a?(String)
63
+ end
64
+
65
+ return url unless SL::URL.url?(url)
66
+
67
+ # Use the shortener to shorten the URL
68
+ case shortener
69
+ when :tinyurl
70
+ SL::TinyurlSearch.shorten(url)
71
+ when :bitly
72
+ SL::BitlySearch.shorten(url)
73
+ when :isgd
74
+ SL::IsgdSearch.shorten(url)
75
+ else
76
+ raise ArgumentError, "Unknown shortener"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -58,7 +58,8 @@ module SL
58
58
  "long_url" => url,
59
59
  "domain" => domain
60
60
  }
61
- data = Curl::Json.new("https://api-ssl.bitly.com/v4/shorten", data: data_obj.to_json, headers: headers, symbolize_names: true)
61
+ data = Curl::Json.new("https://api-ssl.bitly.com/v4/shorten", data: data_obj.to_json, headers: headers,
62
+ symbolize_names: true)
62
63
 
63
64
  return false unless data.json.key?(:link)
64
65
 
@@ -44,7 +44,8 @@ module SL
44
44
  data_obj = {
45
45
  "url" => url
46
46
  }
47
- data = Curl::Json.new("https://tinyurl.ph/api/url/add", data: data_obj.to_json, headers: headers, symbolize_names: true)
47
+ data = Curl::Json.new("https://tinyurl.ph/api/url/add", data: data_obj.to_json, headers: headers,
48
+ symbolize_names: true)
48
49
 
49
50
  if data.json[:error].positive?
50
51
  SL.add_error("Error creating tinyurl", data.json[:error])
@@ -11,7 +11,7 @@ module SL
11
11
  ["@f", "Facebook Handle"],
12
12
  ["@i", "Instagram Handle"],
13
13
  ["@l", "LinkedIn Handle"],
14
- ["@m", "Mastodon Handle"],
14
+ ["@m", "Mastodon Handle"]
15
15
  ],
16
16
  config: [
17
17
  description: "Formatting for social links, use %service%, %user%, and %url%
@@ -27,33 +27,38 @@ module SL
27
27
 
28
28
  def search(search_type, search_terms, link_text = "")
29
29
  type = case search_type
30
- when /^@t/ # twitter-ify username
31
- unless search_terms.strip =~ /^@?[0-9a-z_$]+$/i
32
- return [false, "#{search_terms} is not a valid Twitter handle", link_text]
33
- end
34
-
35
- "t"
36
- when /^@fb?/ # fb-ify username
37
- return [false, "#{search_terms} is not a valid Facebook username", link_text] unless search_terms.strip =~ /^@?[0-9a-z_]+$/i
38
-
39
- "f"
40
- when /^@i/ # intagramify username
41
- return [false, "#{search_terms} is not a valid Instagram username", link_text] unless search_terms.strip =~ /^@?[0-9a-z_]+$/i
42
-
43
- "i"
44
- when /^@l/ # linked-inify username
45
- unless search_terms.strip =~ /^@?[0-9a-z_]+$/i
46
- return [false, "#{search_terms} is not a valid LinkedIn username", link_text]
47
- end
48
-
49
- "l"
50
- when /^@m/ # mastodonify username
51
- return [false, "#{search_terms} is not a valid Mastodon username", link_text] unless search_terms.strip =~ /^@?[0-9a-z_]+@[0-9a-z_.]+$/i
52
-
53
- "m"
54
- else
55
- "t"
56
- end
30
+ when /^@t/ # twitter-ify username
31
+ return [false, "#{search_terms} is not a valid Twitter handle", link_text] unless search_terms.strip =~ /^@?[0-9a-z_$]+$/i
32
+
33
+ "t"
34
+ when /^@fb?/ # fb-ify username
35
+ unless search_terms.strip =~ /^@?[0-9a-z_]+$/i
36
+ return [false, "#{search_terms} is not a valid Facebook username",
37
+ link_text]
38
+ end
39
+
40
+ "f"
41
+ when /^@i/ # intagramify username
42
+ unless search_terms.strip =~ /^@?[0-9a-z_]+$/i
43
+ return [false, "#{search_terms} is not a valid Instagram username",
44
+ link_text]
45
+ end
46
+
47
+ "i"
48
+ when /^@l/ # linked-inify username
49
+ return [false, "#{search_terms} is not a valid LinkedIn username", link_text] unless search_terms.strip =~ /^@?[0-9a-z_]+$/i
50
+
51
+ "l"
52
+ when /^@m/ # mastodonify username
53
+ unless search_terms.strip =~ /^@?[0-9a-z_]+@[0-9a-z_.]+$/i
54
+ return [false, "#{search_terms} is not a valid Mastodon username",
55
+ link_text]
56
+ end
57
+
58
+ "m"
59
+ else
60
+ "t"
61
+ end
57
62
 
58
63
  url, title = social_handle(type, search_terms)
59
64
  link_text = title if link_text == ""
@@ -26,19 +26,18 @@ module SL
26
26
 
27
27
  def twitter_embed(tweet)
28
28
  res = `curl -sSL 'https://publish.twitter.com/oembed?url=#{tweet.url_encode}'`.strip
29
- if res
30
- begin
31
- json = JSON.parse(res)
32
- url = "embed"
33
- title = json["html"]
34
- rescue StandardError
35
- SL.add_error("Tweet Error", "Error retrieving tweet")
36
- url = false
37
- title = tweet
38
- end
39
- else
40
- return [false, "Error retrieving tweet"]
29
+ return [false, "Error retrieving tweet"] unless res
30
+
31
+ begin
32
+ json = JSON.parse(res)
33
+ url = "embed"
34
+ title = json["html"]
35
+ rescue StandardError
36
+ SL.add_error("Tweet Error", "Error retrieving tweet")
37
+ url = false
38
+ title = tweet
41
39
  end
40
+
42
41
  [url, title]
43
42
  end
44
43
  end
@@ -169,10 +169,12 @@ module SL
169
169
  def do_search(search_type, search_terms, link_text, timeout: SL.config["timeout"])
170
170
  plugins[:search].each_value do |plugin|
171
171
  trigger = plugin[:trigger].gsub(/(^\^|\$$)/, "")
172
- if search_type =~ /^#{trigger}$/
173
- search = proc { plugin[:class].search(search_type, search_terms, link_text) }
174
- return SL::Util.search_with_timeout(search, timeout)
175
- end
172
+ next unless search_type =~ /^#{trigger}$/
173
+
174
+ search = proc { plugin[:class].search(search_type, search_terms, link_text) }
175
+ SL.config["skip_timeout"] = true if trigger =~ /^pop/
176
+
177
+ return SL::Util.search_with_timeout(search, timeout)
176
178
  end
177
179
  end
178
180
  end
@@ -189,7 +191,7 @@ require_relative "searches/itunes"
189
191
  require_relative "searches/amazon"
190
192
 
191
193
  # import
192
- require_relative "searches/bitly"
194
+ require_relative "searches/shortener"
193
195
 
194
196
  # import
195
197
  require_relative "searches/definition"
@@ -209,15 +211,15 @@ require_relative "searches/history"
209
211
  # import
210
212
  require_relative "searches/hook"
211
213
 
212
- # import
213
- require_relative "searches/isgd"
214
-
215
214
  # import
216
215
  require_relative "searches/lastfm"
217
216
 
218
217
  # import
219
218
  require_relative "searches/pinboard"
220
219
 
220
+ # import
221
+ require_relative "searches/popup"
222
+
221
223
  # import
222
224
  require_relative "searches/setapp"
223
225
 
@@ -248,8 +250,5 @@ require_relative "searches/youtube"
248
250
  # import
249
251
  require_relative "searches/stackoverflow"
250
252
 
251
- # import
252
- require_relative "searches/tinyurl"
253
-
254
253
  # import
255
254
  require_relative "searches/linkding"
@@ -145,12 +145,14 @@ module SL
145
145
 
146
146
  # parse command line flags into long options
147
147
  def parse_flags
148
- gsub(/(\+\+|--)([dirtvs]+)\b/) do
148
+ gsub(/(\+\+|--)([dirtvsc]+)\b/) do
149
149
  m = Regexp.last_match
150
150
  bool = m[1] == "++" ? "" : "no-"
151
151
  output = " "
152
152
  m[2].split("").each do |arg|
153
153
  output += case arg
154
+ when "c"
155
+ "--#{bool}confirm"
154
156
  when "d"
155
157
  "--#{bool}debug "
156
158
  when "i"
@@ -66,7 +66,7 @@ module SL
66
66
  end
67
67
 
68
68
  def only_url?(input)
69
- input =~ %r{(?i)^((http|https)://)?([\w\-_]+(\.[\w\-_]+)+)([\w\-.,@?^=%&amp;:/~+#]*[\w\-@^=%&amp;/~+#])?$}
69
+ input =~ %r{(?i)^(https?://)?([\w-]+(\.[\w-]+)+)([\w\-.,@?^=%&amp;:/~+#]*[\w\-@^=%&amp;/~+#])?$}
70
70
  end
71
71
 
72
72
  def ref_title_for_url(url)
@@ -110,7 +110,10 @@ module SL
110
110
  def amazon_affiliatize(url, amazon_partner)
111
111
  return url if amazon_partner.nil? || amazon_partner.empty?
112
112
 
113
- return [url, ""] unless url =~ %r{https?://(?<subdomain>.*?)amazon.com/(?:(?<title>.*?)/)?(?<type>[dg])p/(?<id>[^?]+)}
113
+ unless url =~ %r{https?://(?<subdomain>.*?)amazon.com/(?:(?<title>.*?)/)?(?<type>[dg])p/(?<id>[^?]+)}
114
+ return [url,
115
+ ""]
116
+ end
114
117
 
115
118
  m = Regexp.last_match
116
119
  sd = m["subdomain"]
@@ -146,6 +149,8 @@ module SL
146
149
  # end
147
150
 
148
151
  begin
152
+ return File.basename(url) if url =~ /\.(gif|jpe?g|png|web[mp]|bmp|svg|tiff?|pdf|avif)$/i
153
+
149
154
  if url =~ %r{https://(amzn.to|(www\.)?amazon\.com)/}
150
155
  final_url = follow_redirects(url)
151
156
  m = final_url.match(%r{https://www.amazon.com/(.*?)/dp/})
@@ -56,9 +56,10 @@ module SL
56
56
  ## @return [Array] url, title, link_text
57
57
  ##
58
58
  def search_with_timeout(search, timeout)
59
- url = nil
60
- title = nil
61
- link_text = nil
59
+ if SL.config["skip_timeout"] || SL.config["confirm"]
60
+ url, title, link_text = search.call
61
+ return [url, title, link_text]
62
+ end
62
63
 
63
64
  begin
64
65
  Timeout.timeout(timeout) do
@@ -85,6 +86,19 @@ module SL
85
86
  FileUtils.mkdir_p(cache_folder) unless File.directory?(cache_folder)
86
87
  File.join(cache_folder, filename.sub(/(\.cache)?$/, ".cache"))
87
88
  end
89
+
90
+ # Checks if the Preview URL.workflow exists, return path if it does.
91
+ def popup_path
92
+ begin
93
+ path = File.expand_path(File.join(__dir__, "../../helpers/Preview URL.workflow"))
94
+ path = File.expand_path("~/Library/Services/Preview URL.workflow") unless File.exist?(path)
95
+ rescue
96
+ path = File.expand_path("~/Library/Services/Preview URL.workflow")
97
+ end
98
+ return false unless File.exist?(path)
99
+
100
+ path
101
+ end
88
102
  end
89
103
  end
90
104
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SL
4
- VERSION = "2.3.85"
4
+ VERSION = "2.3.87"
5
5
  end
6
6
 
7
7
  # Main module
@@ -29,7 +29,7 @@ module SL
29
29
  latest = SemVer.new(latest_tag)
30
30
  current = SemVer.new(SL::VERSION)
31
31
 
32
- File.open(cachefile, "w") { |f| f.puts("#{last_time.strftime("%c")}|#{latest}") }
32
+ File.open(cachefile, "w") { |f| f.puts("#{last_time.strftime('%c')}|#{latest}") }
33
33
 
34
34
  return "SearchLink v#{current}, #{latest} available. Run \"update\" to download." if latest_tag && current.older_than(latest)
35
35
 
@@ -42,12 +42,12 @@ module SL
42
42
  def new_version?
43
43
  headers = {
44
44
  "Accept" => "application/vnd.github+json",
45
- "X-GitHub-Api-Version" => "2022-11-28",
45
+ "X-GitHub-Api-Version" => "2022-11-28"
46
46
  }
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.config["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/searchlink.rb CHANGED
@@ -15,6 +15,9 @@ require "json"
15
15
  require "erb"
16
16
  require "English"
17
17
 
18
+ # import
19
+ require_relative "searchlink/plist"
20
+
18
21
  # import
19
22
  require_relative "tokens" if File.exist?("tokens.rb")
20
23
 
@@ -42,9 +45,6 @@ require_relative "searchlink/array"
42
45
  # import
43
46
  require_relative "searchlink/string"
44
47
 
45
- # import
46
- require_relative "searchlink/plist"
47
-
48
48
  # import
49
49
  require_relative "searchlink/config"
50
50
 
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.85
4
+ version: 2.3.87
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-30 00:00:00.000000000 Z
10
+ date: 2025-04-01 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: base64
@@ -282,12 +282,14 @@ files:
282
282
  - lib/searchlink/output.rb
283
283
  - lib/searchlink/parse.rb
284
284
  - lib/searchlink/plist.rb
285
+ - lib/searchlink/plist/generator.rb
286
+ - lib/searchlink/plist/parser.rb
287
+ - lib/searchlink/plist/version.rb
285
288
  - lib/searchlink/script_plugin.rb
286
289
  - lib/searchlink/search.rb
287
290
  - lib/searchlink/searches.rb
288
291
  - lib/searchlink/searches/amazon.rb
289
292
  - lib/searchlink/searches/applemusic.rb
290
- - lib/searchlink/searches/bitly.rb
291
293
  - lib/searchlink/searches/definition.rb
292
294
  - lib/searchlink/searches/duckduckgo.rb
293
295
  - lib/searchlink/searches/github.rb
@@ -297,19 +299,22 @@ files:
297
299
  - lib/searchlink/searches/helpers/safari.rb
298
300
  - lib/searchlink/searches/history.rb
299
301
  - lib/searchlink/searches/hook.rb
300
- - lib/searchlink/searches/isgd.rb
301
302
  - lib/searchlink/searches/itunes.rb
302
303
  - lib/searchlink/searches/lastfm.rb
303
304
  - lib/searchlink/searches/linkding.rb
304
305
  - lib/searchlink/searches/lyrics.rb
305
306
  - lib/searchlink/searches/pinboard.rb
307
+ - lib/searchlink/searches/popup.rb
306
308
  - lib/searchlink/searches/setapp.rb
309
+ - lib/searchlink/searches/shortener.rb
310
+ - lib/searchlink/searches/shorteners/bitly.rb
311
+ - lib/searchlink/searches/shorteners/isgd.rb
312
+ - lib/searchlink/searches/shorteners/tinyurl.rb
307
313
  - lib/searchlink/searches/social.rb
308
314
  - lib/searchlink/searches/software.rb
309
315
  - lib/searchlink/searches/spelling.rb
310
316
  - lib/searchlink/searches/spotlight.rb
311
317
  - lib/searchlink/searches/stackoverflow.rb
312
- - lib/searchlink/searches/tinyurl.rb
313
318
  - lib/searchlink/searches/tmdb.rb
314
319
  - lib/searchlink/searches/twitter.rb
315
320
  - lib/searchlink/searches/wikipedia.rb