searchlink 2.3.86 → 2.3.88
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 +4 -4
- data/bin/searchlink +20 -19
- data/lib/searchlink/config.rb +1 -1
- data/lib/searchlink/curl/html.rb +24 -21
- data/lib/searchlink/curl/json.rb +5 -7
- data/lib/searchlink/help.rb +6 -2
- data/lib/searchlink/output.rb +28 -16
- data/lib/searchlink/parse.rb +425 -405
- data/lib/searchlink/plist/generator.rb +178 -0
- data/lib/searchlink/plist/parser.rb +263 -0
- data/lib/searchlink/plist/version.rb +5 -0
- data/lib/searchlink/plist.rb +12 -202
- data/lib/searchlink/script_plugin.rb +1 -3
- data/lib/searchlink/search.rb +1 -5
- data/lib/searchlink/searches/duckduckgo.rb +2 -1
- data/lib/searchlink/searches/google.rb +4 -2
- data/lib/searchlink/searches/history.rb +5 -5
- data/lib/searchlink/searches/linkding.rb +2 -2
- data/lib/searchlink/searches/popup.rb +14 -15
- data/lib/searchlink/searches/setapp.rb +3 -1
- data/lib/searchlink/searches/shortener.rb +14 -14
- data/lib/searchlink/searches/shorteners/bitly.rb +2 -1
- data/lib/searchlink/searches/shorteners/tinyurl.rb +2 -1
- data/lib/searchlink/searches/social.rb +33 -28
- data/lib/searchlink/searches/twitter.rb +11 -12
- data/lib/searchlink/searches.rb +17 -17
- data/lib/searchlink/string.rb +76 -50
- data/lib/searchlink/url.rb +5 -2
- data/lib/searchlink/util.rb +13 -0
- data/lib/searchlink/version.rb +4 -4
- data/lib/searchlink.rb +3 -3
- metadata +5 -2
@@ -43,7 +43,9 @@ 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.gsub(
|
46
|
+
url = "https://customsearch.googleapis.com/customsearch/v1?cx=338419ee5ac894523&q=#{ERB::Util.url_encode(search_terms.gsub(
|
47
|
+
'%22', '"'
|
48
|
+
))}&num=1&key=#{@api_key}"
|
47
49
|
json = Curl::Json.new(url).json
|
48
50
|
|
49
51
|
if json["error"] && json["error"]["code"].to_i == 429
|
@@ -65,7 +67,7 @@ module SL
|
|
65
67
|
output_title = result["title"]
|
66
68
|
output_title.remove_seo!(output_url) if SL.config["remove_seo"]
|
67
69
|
|
68
|
-
output_url = SL.first_image if search_type =~ /img$/
|
70
|
+
output_url = SL.first_image(output_url) if search_type =~ /img$/
|
69
71
|
|
70
72
|
[output_url, output_title, link_text]
|
71
73
|
rescue StandardError
|
@@ -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 == ""
|
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
|
-
|
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
|
-
|
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")
|
@@ -11,7 +11,7 @@ module SL
|
|
11
11
|
["popa", "Popup Amazon Search"],
|
12
12
|
["popg", "Popup Google Search"],
|
13
13
|
["popw", "Popup Wikipedia Search"]
|
14
|
-
]
|
14
|
+
]
|
15
15
|
}
|
16
16
|
end
|
17
17
|
|
@@ -20,20 +20,19 @@ module SL
|
|
20
20
|
|
21
21
|
term = search_terms.url_encode
|
22
22
|
url = case type
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
34
|
|
35
|
-
|
36
|
-
res = `automator -i "#{url}" "#{path}"`.strip
|
35
|
+
res = `automator -i "#{url}" "#{SL::Util.popup_path}"`.strip
|
37
36
|
|
38
37
|
begin
|
39
38
|
if res.empty?
|
@@ -54,7 +53,7 @@ module SL
|
|
54
53
|
private
|
55
54
|
|
56
55
|
def workflow_exist?
|
57
|
-
unless
|
56
|
+
unless SL::Util.popup_path
|
58
57
|
SL.add_error("Missing Service", "Preview URL Service not installed")
|
59
58
|
return false
|
60
59
|
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,
|
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)
|
@@ -18,22 +18,20 @@ module SL
|
|
18
18
|
# @return [Boolean] True if the user confirms, false otherwise.
|
19
19
|
#
|
20
20
|
def confirm?(url, title: "Confirm URL?")
|
21
|
-
|
22
|
-
|
21
|
+
|
22
|
+
if SL::Util.popup_path
|
23
|
+
cmd = %(osascript -e 'display dialog "#{url}" with title "#{title}" buttons {"Cancel", "Confirm", "Preview"}')
|
23
24
|
|
24
25
|
res = `#{cmd}`.strip
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
return res =~ /Confirm/ unless res =~ /Preview/
|
28
|
+
|
29
|
+
res = `automator -i "#{url}" "#{SL::Util.popup_path}"`.strip
|
29
30
|
|
30
|
-
|
31
|
-
else
|
32
|
-
return res =~ /Confirm/
|
33
|
-
end
|
31
|
+
return res.empty? ? false : res
|
34
32
|
end
|
35
33
|
|
36
|
-
res = system(%(osascript -e
|
34
|
+
res = system(%(osascript -e 'display dialog "#{url}" with title "#{title}" buttons {"Cancel", "Confirm"}'))
|
37
35
|
|
38
36
|
res == 0
|
39
37
|
end
|
@@ -55,12 +53,14 @@ module SL
|
|
55
53
|
known_shorteners = %i[tinyurl bitly isgd]
|
56
54
|
return url unless known_shorteners.include?(shortener)
|
57
55
|
|
58
|
-
|
59
|
-
|
56
|
+
unless NO_CONFIRM
|
57
|
+
# Confirm shortening the URL
|
58
|
+
res = SL::Shortener.confirm?(url, title: "Shorten URL?")
|
60
59
|
|
61
|
-
|
60
|
+
return url unless res
|
62
61
|
|
63
|
-
|
62
|
+
url = res if res.is_a?(String)
|
63
|
+
end
|
64
64
|
|
65
65
|
return url unless SL::URL.url?(url)
|
66
66
|
|
@@ -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,
|
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,
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
data/lib/searchlink/searches.rb
CHANGED
@@ -43,9 +43,9 @@ module SL
|
|
43
43
|
#
|
44
44
|
def available_searches_html
|
45
45
|
searches = plugins[:search]
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
.flat_map { |_, plugin| plugin[:searches] }
|
47
|
+
.reject { |s| s[1].nil? }
|
48
|
+
.sort_by { |s| s[0].is_a?(Array) ? s[0][0] : s[0] }
|
49
49
|
out = ['<table id="searches">',
|
50
50
|
"<thead><td>Shortcut</td><td>Search Type</td></thead>",
|
51
51
|
"<tbody>"]
|
@@ -53,7 +53,7 @@ module SL
|
|
53
53
|
searches.each do |s|
|
54
54
|
out << "<tr>
|
55
55
|
<td>
|
56
|
-
<code>!#{s[0].is_a?(Array) ? "#{s[0][0]} (#{s[0][1..].join(
|
56
|
+
<code>!#{s[0].is_a?(Array) ? "#{s[0][0]} (#{s[0][1..].join(',')})" : s[0]}
|
57
57
|
</code>
|
58
58
|
</td><td>#{s[1]}</td></tr>"
|
59
59
|
end
|
@@ -72,10 +72,10 @@ module SL
|
|
72
72
|
|
73
73
|
searches.each do |s|
|
74
74
|
shortcut = if s[0].is_a?(Array)
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
"#{s[0][0]} (#{s[0][1..].join(',')})"
|
76
|
+
else
|
77
|
+
s[0]
|
78
|
+
end
|
79
79
|
|
80
80
|
out << "!#{shortcut}#{shortcut.spacer}#{s[1]}"
|
81
81
|
end
|
@@ -95,7 +95,7 @@ module SL
|
|
95
95
|
|
96
96
|
def did_you_mean(term)
|
97
97
|
matches = best_search_match(term)
|
98
|
-
matches.empty? ? "" : ", did you mean #{matches.map { |m| "!#{m}" }.join(
|
98
|
+
matches.empty? ? "" : ", did you mean #{matches.map { |m| "!#{m}" }.join(', ')}?"
|
99
99
|
end
|
100
100
|
|
101
101
|
def valid_searches
|
@@ -106,7 +106,7 @@ module SL
|
|
106
106
|
|
107
107
|
def valid_search?(term)
|
108
108
|
valid = false
|
109
|
-
valid = true if term =~ /^(#{valid_searches.join(
|
109
|
+
valid = true if term =~ /^(#{valid_searches.join('|')})$/
|
110
110
|
valid = true if SL.config["custom_site_searches"].keys.include? term
|
111
111
|
# SL.notify("Invalid search#{did_you_mean(term)}", term) unless valid
|
112
112
|
valid
|
@@ -124,7 +124,7 @@ module SL
|
|
124
124
|
trigger: settings.fetch(:trigger, title).normalize_trigger,
|
125
125
|
searches: settings[:searches],
|
126
126
|
config: settings[:config],
|
127
|
-
class: klass
|
127
|
+
class: klass
|
128
128
|
}
|
129
129
|
end
|
130
130
|
|
@@ -155,11 +155,11 @@ module SL
|
|
155
155
|
config = IO.read(file)
|
156
156
|
|
157
157
|
cfg = case ext
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
158
|
+
when /^y/i
|
159
|
+
YAML.safe_load(config)
|
160
|
+
else
|
161
|
+
JSON.parse(config)
|
162
|
+
end
|
163
163
|
cfg["filename"] = File.basename(file)
|
164
164
|
cfg["path"] = file.shorten_path
|
165
165
|
SL::ScriptSearch.new(cfg)
|
@@ -190,7 +190,7 @@ require_relative "searches/itunes"
|
|
190
190
|
# import
|
191
191
|
require_relative "searches/amazon"
|
192
192
|
|
193
|
-
#import
|
193
|
+
# import
|
194
194
|
require_relative "searches/shortener"
|
195
195
|
|
196
196
|
# import
|
data/lib/searchlink/string.rb
CHANGED
@@ -3,6 +3,32 @@
|
|
3
3
|
module SL
|
4
4
|
# String helpers
|
5
5
|
class ::String
|
6
|
+
# Scan a string for links
|
7
|
+
# @return [Hash] Hash of links
|
8
|
+
def scan_links
|
9
|
+
links = {}
|
10
|
+
scan(/\[(.*?)\]:\s+(.*?)\n/).each { |match| links[match[1].strip] = match[0] }
|
11
|
+
links
|
12
|
+
end
|
13
|
+
|
14
|
+
# Count the indent level of a string
|
15
|
+
# @return [Integer] The indent level
|
16
|
+
def indent_level
|
17
|
+
return 0 if empty?
|
18
|
+
|
19
|
+
gsub!(/^ /, "\t") while self =~ /^ /
|
20
|
+
indent = match(/^\t+/)
|
21
|
+
return 0 unless indent
|
22
|
+
|
23
|
+
indent[0].length
|
24
|
+
end
|
25
|
+
|
26
|
+
# Count the links in a string
|
27
|
+
# @return [Integer] The number of links
|
28
|
+
def count_links
|
29
|
+
scan(/\[(.*?)\]\((.*?)\)/).length
|
30
|
+
end
|
31
|
+
|
6
32
|
# Quote a YAML value if needed
|
7
33
|
def yaml_val
|
8
34
|
yaml = YAML.safe_load("key: '#{self}'")
|
@@ -59,15 +85,15 @@ module SL
|
|
59
85
|
|
60
86
|
shortener = split(/_/).last
|
61
87
|
SL.shortener = case shortener
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
88
|
+
when /i/i
|
89
|
+
:isgd
|
90
|
+
when /b/i
|
91
|
+
:bitly
|
92
|
+
when /t/i
|
93
|
+
:tinyurl
|
94
|
+
else
|
95
|
+
:none
|
96
|
+
end
|
71
97
|
|
72
98
|
sub(/_[ibt]$/i, "")
|
73
99
|
end
|
@@ -89,10 +115,10 @@ module SL
|
|
89
115
|
query = SL.query.map { |k, v| "#{k}=#{v}" }.join("&")
|
90
116
|
|
91
117
|
query = if self =~ /\?[^= ]+=\S+/
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
118
|
+
"&#{query}"
|
119
|
+
else
|
120
|
+
"?#{query}"
|
121
|
+
end
|
96
122
|
|
97
123
|
"#{self}#{query}"
|
98
124
|
end
|
@@ -151,23 +177,23 @@ module SL
|
|
151
177
|
output = " "
|
152
178
|
m[2].split("").each do |arg|
|
153
179
|
output += case arg
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
180
|
+
when "c"
|
181
|
+
"--#{bool}confirm"
|
182
|
+
when "d"
|
183
|
+
"--#{bool}debug "
|
184
|
+
when "i"
|
185
|
+
"--#{bool}inline "
|
186
|
+
when "r"
|
187
|
+
"--#{bool}prefix_random "
|
188
|
+
when "t"
|
189
|
+
"--#{bool}include_titles "
|
190
|
+
when "v"
|
191
|
+
"--#{bool}validate_links "
|
192
|
+
when "s"
|
193
|
+
"--#{bool}remove_seo "
|
194
|
+
else
|
195
|
+
""
|
196
|
+
end
|
171
197
|
end
|
172
198
|
|
173
199
|
output
|
@@ -310,7 +336,7 @@ module SL
|
|
310
336
|
"‘" => "’",
|
311
337
|
"[" => "]",
|
312
338
|
"(" => ")",
|
313
|
-
"<" => ">"
|
339
|
+
"<" => ">"
|
314
340
|
}
|
315
341
|
|
316
342
|
left_punct = []
|
@@ -380,7 +406,7 @@ module SL
|
|
380
406
|
# p_re = path.path_elements.map{|seg| seg.downcase.split(//).join('.?') }.join('|')
|
381
407
|
# re_parts.push(p_re) if p_re.length > 0
|
382
408
|
|
383
|
-
site_re = "(#{re_parts.join(
|
409
|
+
site_re = "(#{re_parts.join('|')})"
|
384
410
|
|
385
411
|
dead_switch = 0
|
386
412
|
|
@@ -405,14 +431,14 @@ module SL
|
|
405
431
|
end
|
406
432
|
|
407
433
|
title = if parts.empty?
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
434
|
+
longest
|
435
|
+
elsif parts.length < 2
|
436
|
+
parts.join(sep)
|
437
|
+
elsif parts.length > 2
|
438
|
+
parts.longest_element.strip
|
439
|
+
else
|
440
|
+
parts.join(sep)
|
441
|
+
end
|
416
442
|
end
|
417
443
|
dead_switch += 1
|
418
444
|
end
|
@@ -423,7 +449,7 @@ module SL
|
|
423
449
|
return self
|
424
450
|
end
|
425
451
|
|
426
|
-
seps = Regexp.new(" *[#{seo_title_separators.map { |s| Regexp.escape(s) }.join(
|
452
|
+
seps = Regexp.new(" *[#{seo_title_separators.map { |s| Regexp.escape(s) }.join('')}] +")
|
427
453
|
if title =~ seps
|
428
454
|
seo_parts = title.split(seps)
|
429
455
|
title = seo_parts.longest_element.strip if seo_parts.length.positive?
|
@@ -526,13 +552,13 @@ module SL
|
|
526
552
|
(1..n).each do |j|
|
527
553
|
(1..m).each do |i|
|
528
554
|
d[i][j] = if s[i - 1] == t[j - 1] # adjust index into string
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
].min
|
535
|
-
|
555
|
+
d[i - 1][j - 1] # no operation required
|
556
|
+
else
|
557
|
+
[d[i - 1][j] + 1, # deletion
|
558
|
+
d[i][j - 1] + 1, # insertion
|
559
|
+
d[i - 1][j - 1] + 1 # substitution
|
560
|
+
].min
|
561
|
+
end
|
536
562
|
end
|
537
563
|
end
|
538
564
|
d[m][n]
|
@@ -545,7 +571,7 @@ module SL
|
|
545
571
|
##
|
546
572
|
def matches_exact(string)
|
547
573
|
comp = gsub(/[^a-z0-9 ]/i, "")
|
548
|
-
comp =~ /\b#{string.gsub(/[^a-z0-9 ]/i,
|
574
|
+
comp =~ /\b#{string.gsub(/[^a-z0-9 ]/i, '').split(/ +/).map { |s| Regexp.escape(s) }.join(' +')}/i
|
549
575
|
end
|
550
576
|
|
551
577
|
##
|
@@ -593,7 +619,7 @@ module SL
|
|
593
619
|
def to_rx_array(separator: " ", start_word: true)
|
594
620
|
bound = start_word ? '\b' : ""
|
595
621
|
str = gsub(/(#{separator})+/, separator)
|
596
|
-
str.split(/#{separator}/).map { |arg| /#{bound}#{arg.gsub(/[^a-z0-9]/i,
|
622
|
+
str.split(/#{separator}/).map { |arg| /#{bound}#{arg.gsub(/[^a-z0-9]/i, '.?')}/i }
|
597
623
|
end
|
598
624
|
|
599
625
|
##
|
data/lib/searchlink/url.rb
CHANGED
@@ -66,7 +66,7 @@ module SL
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def only_url?(input)
|
69
|
-
input =~ %r{(?i)^(
|
69
|
+
input =~ %r{(?i)^(https?://)?([\w-]+(\.[\w-]+)+)([\w\-.,@?^=%&:/~+#]*[\w\-@^=%&/~+#])?$}
|
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
|
-
|
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"]
|
data/lib/searchlink/util.rb
CHANGED
@@ -86,6 +86,19 @@ module SL
|
|
86
86
|
FileUtils.mkdir_p(cache_folder) unless File.directory?(cache_folder)
|
87
87
|
File.join(cache_folder, filename.sub(/(\.cache)?$/, ".cache"))
|
88
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
|
89
102
|
end
|
90
103
|
end
|
91
104
|
end
|