searchlink 2.3.74 → 2.3.76

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/searchlink/config.rb +23 -23
  3. data/lib/searchlink/curl/html.rb +38 -38
  4. data/lib/searchlink/curl/json.rb +19 -17
  5. data/lib/searchlink/curl.rb +2 -2
  6. data/lib/searchlink/exceptions.rb +2 -2
  7. data/lib/searchlink/help.rb +13 -13
  8. data/lib/searchlink/output.rb +21 -21
  9. data/lib/searchlink/parse.rb +113 -108
  10. data/lib/searchlink/plist.rb +11 -11
  11. data/lib/searchlink/script_plugin.rb +10 -10
  12. data/lib/searchlink/search.rb +6 -6
  13. data/lib/searchlink/searches/amazon.rb +4 -4
  14. data/lib/searchlink/searches/applemusic.rb +28 -28
  15. data/lib/searchlink/searches/bitly.rb +11 -11
  16. data/lib/searchlink/searches/definition.rb +7 -7
  17. data/lib/searchlink/searches/duckduckgo.rb +31 -27
  18. data/lib/searchlink/searches/github.rb +48 -48
  19. data/lib/searchlink/searches/google.rb +16 -16
  20. data/lib/searchlink/searches/helpers/chromium.rb +46 -46
  21. data/lib/searchlink/searches/helpers/firefox.rb +20 -20
  22. data/lib/searchlink/searches/helpers/safari.rb +14 -14
  23. data/lib/searchlink/searches/history.rb +78 -78
  24. data/lib/searchlink/searches/hook.rb +5 -5
  25. data/lib/searchlink/searches/itunes.rb +37 -37
  26. data/lib/searchlink/searches/lastfm.rb +13 -13
  27. data/lib/searchlink/searches/linkding.rb +14 -14
  28. data/lib/searchlink/searches/lyrics.rb +11 -11
  29. data/lib/searchlink/searches/pinboard.rb +35 -35
  30. data/lib/searchlink/searches/social.rb +45 -56
  31. data/lib/searchlink/searches/software.rb +4 -4
  32. data/lib/searchlink/searches/spelling.rb +10 -10
  33. data/lib/searchlink/searches/spotlight.rb +4 -4
  34. data/lib/searchlink/searches/stackoverflow.rb +5 -5
  35. data/lib/searchlink/searches/tmdb.rb +17 -17
  36. data/lib/searchlink/searches/twitter.rb +8 -8
  37. data/lib/searchlink/searches/wikipedia.rb +4 -4
  38. data/lib/searchlink/searches/youtube.rb +7 -7
  39. data/lib/searchlink/searches.rb +16 -16
  40. data/lib/searchlink/semver.rb +4 -4
  41. data/lib/searchlink/string.rb +55 -55
  42. data/lib/searchlink/url.rb +30 -32
  43. data/lib/searchlink/util.rb +3 -3
  44. data/lib/searchlink/version.rb +19 -21
  45. data/lib/searchlink/which.rb +5 -5
  46. data/lib/searchlink.rb +31 -31
  47. metadata +31 -18
  48. data/lib/tokens.rb +0 -3
@@ -6,17 +6,17 @@ module SL
6
6
  # Script Search
7
7
  class ScriptSearch
8
8
  def initialize(config)
9
- @filename = config['filename']
10
- @path = config['path']
9
+ @filename = config["filename"]
10
+ @path = config["path"]
11
11
 
12
12
  %w[trigger searches name script].each do |key|
13
13
  raise PluginError.new(%(configuration missing key "#{key}"), plugin: @filename) unless config.key?(key)
14
14
  end
15
15
 
16
- @trigger = config['trigger']
17
- @searches = config['searches']
18
- @name = config['name']
19
- @script = find_script(config['script'])
16
+ @trigger = config["trigger"]
17
+ @searches = config["searches"]
18
+ @name = config["name"]
19
+ @script = find_script(config["script"])
20
20
 
21
21
  unless File.executable?(@script)
22
22
  raise PluginError.new(%(script "#{File.basename(@script)}" not executable\nrun `chmod a+x #{@script.shorten_path}` to correct),
@@ -36,7 +36,7 @@ module SL
36
36
  terms = Shellwords.escape(search_terms)
37
37
  text = Shellwords.escape(link_text)
38
38
 
39
- stdout = `#{[@script, type, terms, text].join(' ')} 2>&1`
39
+ stdout = `#{[@script, type, terms, text].join(" ")} 2>&1`
40
40
 
41
41
  unless $CHILD_STATUS.success?
42
42
  raise PluginError.new(%("#{File.basename(@script)}" returned error #{$CHILD_STATUS.exitstatus}\n#{stdout}),
@@ -60,7 +60,7 @@ module SL
60
60
  end
61
61
  end
62
62
 
63
- [res['url'], res['title'], res['link_text']]
63
+ [res["url"], res["title"], res["link_text"]]
64
64
  end
65
65
  end
66
66
 
@@ -70,11 +70,11 @@ module SL
70
70
  def find_script(script)
71
71
  return File.expand_path(script) if File.exist?(File.expand_path(script))
72
72
 
73
- base = File.expand_path('~/.config/searchlink/plugins')
73
+ base = File.expand_path("~/.config/searchlink/plugins")
74
74
  first = File.join(base, script)
75
75
  return first if File.exist?(first)
76
76
 
77
- base = File.expand_path('~/.config/searchlink')
77
+ base = File.expand_path("~/.config/searchlink")
78
78
  second = File.join(base, script)
79
79
  return second if File.exist?(second)
80
80
 
@@ -21,9 +21,9 @@ module SL
21
21
  #
22
22
  # @return [Array] [Url, link, text]
23
23
  #
24
- def do_search(search_type, search_terms, link_text = '', search_count = 0)
24
+ def do_search(search_type, search_terms, link_text = "", search_count = 0)
25
25
  if (search_count % 5).zero?
26
- SL.notify('Throttling for 5s')
26
+ SL.notify("Throttling for 5s")
27
27
  sleep 5
28
28
  end
29
29
 
@@ -37,13 +37,13 @@ module SL
37
37
  else
38
38
  case search_type
39
39
  when /^r$/ # simple replacement
40
- if SL.config['validate_links'] && !SL::URL.valid_link?(search_terms)
40
+ if SL.config["validate_links"] && !SL::URL.valid_link?(search_terms)
41
41
  return [false, "Link not valid: #{search_terms}", link_text]
42
42
  end
43
43
 
44
44
  title = SL::URL.title(search_terms) || search_terms
45
45
 
46
- link_text = title if link_text == ''
46
+ link_text = title if link_text == ""
47
47
  return [search_terms, title, link_text]
48
48
  else
49
49
  if search_terms
@@ -56,11 +56,11 @@ module SL
56
56
  end
57
57
  end
58
58
 
59
- if link_text == ''
59
+ if link_text == ""
60
60
  link_text = SL.titleize ? title : search_terms
61
61
  end
62
62
 
63
- if url && SL.config['validate_links'] && !SL::URL.valid_link?(url) && search_type !~ /^sp(ell)?/
63
+ if url && SL.config["validate_links"] && !SL::URL.valid_link?(url) && search_type !~ /^sp(ell)?/
64
64
  [false, "Not found: #{url}", link_text]
65
65
  elsif !url
66
66
  [false, "No results: #{url}", link_text]
@@ -6,22 +6,22 @@ module SL
6
6
  class << self
7
7
  def settings
8
8
  {
9
- trigger: 'a',
9
+ trigger: "a",
10
10
  searches: [
11
- ['a', 'Amazon Search']
11
+ ["a", "Amazon Search"]
12
12
  ]
13
13
  }
14
14
  end
15
15
 
16
16
  def search(_, search_terms, link_text)
17
17
  az_url, = SL.ddg("site:amazon.com #{search_terms}", link_text)
18
- url, title = SL::URL.amazon_affiliatize(az_url, SL.config['amazon_partner'])
18
+ url, title = SL::URL.amazon_affiliatize(az_url, SL.config["amazon_partner"])
19
19
  title ||= search_terms
20
20
 
21
21
  [url, title, link_text]
22
22
  end
23
23
  end
24
24
 
25
- SL::Searches.register 'amazon', :search, self
25
+ SL::Searches.register "amazon", :search, self
26
26
  end
27
27
  end
@@ -8,35 +8,35 @@ module SL
8
8
  class << self
9
9
  def settings
10
10
  {
11
- trigger: 'am(pod|art|alb|song)?e?',
11
+ trigger: "am(pod|art|alb|song)?e?",
12
12
  searches: [
13
- ['am', 'Apple Music'],
14
- ['ampod', 'Apple Music Podcast'],
15
- ['amart', 'Apple Music Artist'],
16
- ['amalb', 'Apple Music Album'],
17
- ['amsong', 'Apple Music Song'],
18
- ['amalbe', 'Apple Music Album Embed'],
19
- ['amsong', 'Apple Music Song Embed']
13
+ ["am", "Apple Music"],
14
+ ["ampod", "Apple Music Podcast"],
15
+ ["amart", "Apple Music Artist"],
16
+ ["amalb", "Apple Music Album"],
17
+ ["amsong", "Apple Music Song"],
18
+ ["amalbe", "Apple Music Album Embed"],
19
+ ["amsong", "Apple Music Song Embed"]
20
20
  ]
21
21
  }
22
22
  end
23
23
 
24
24
  def search(search_type, search_terms, link_text)
25
- stype = search_type.downcase.sub(/^am/, '')
25
+ stype = search_type.downcase.sub(/^am/, "")
26
26
  otype = :link
27
27
  if stype =~ /e$/
28
28
  otype = :embed
29
- stype.sub!(/e$/, '')
29
+ stype.sub!(/e$/, "")
30
30
  end
31
31
  result = case stype
32
32
  when /^pod$/
33
- applemusic(search_terms, 'podcast')
33
+ applemusic(search_terms, "podcast")
34
34
  when /^art$/
35
- applemusic(search_terms, 'music', 'musicArtist')
35
+ applemusic(search_terms, "music", "musicArtist")
36
36
  when /^alb$/
37
- applemusic(search_terms, 'music', 'album')
37
+ applemusic(search_terms, "music", "album")
38
38
  when /^song$/
39
- applemusic(search_terms, 'music', 'musicTrack')
39
+ applemusic(search_terms, "music", "musicTrack")
40
40
  else
41
41
  applemusic(search_terms)
42
42
  end
@@ -45,7 +45,7 @@ module SL
45
45
 
46
46
  # {:type=>,:id=>,:url=>,:title=>}
47
47
  if otype == :embed && result[:type] =~ /(album|song)/
48
- url = 'embed'
48
+ url = "embed"
49
49
  if result[:type] =~ /song/
50
50
  link = %(https://embed.music.apple.com/#{SL.config['country_code'].downcase}/album/#{result[:album]}?i=#{result[:id]}&app=music#{SL.config['itunes_affiliate']})
51
51
  height = 150
@@ -60,7 +60,7 @@ module SL
60
60
  %(style="width:100%;max-width:660px;overflow:hidden;background:transparent;"),
61
61
  %(sandbox="allow-forms allow-popups allow-same-origin),
62
62
  %(allow-scripts allow-top-navigation-by-user-activation"></iframe>)
63
- ].join(' ')
63
+ ].join(" ")
64
64
  else
65
65
  url = result[:url]
66
66
  title = result[:title]
@@ -73,8 +73,8 @@ module SL
73
73
  # media => music, podcast
74
74
  # entity => optional: artist, song, album, podcast
75
75
  # returns {:type=>,:id=>,:url=>,:title}
76
- def applemusic(terms, media = 'music', entity = '')
77
- url = "http://itunes.apple.com/search?term=#{terms.url_encode}&country=#{SL.config['country_code']}&media=#{media}&entity=#{entity}"
76
+ def applemusic(terms, media = "music", entity = "")
77
+ url = "https://itunes.apple.com/search?term=#{terms.url_encode}&country=#{SL.config['country_code']}&media=#{media}&entity=#{entity}"
78
78
  page = Curl::Json.new(url, compressed: true, symbolize_names: true)
79
79
  json = page.json
80
80
  return false unless json[:resultCount]&.positive?
@@ -88,29 +88,29 @@ module SL
88
88
 
89
89
  def process_result(result)
90
90
  output = {}
91
- aff = SL.config['itunes_affiliate']
91
+ aff = SL.config["itunes_affiliate"]
92
92
 
93
93
  case result[:wrapperType]
94
- when 'track'
95
- if result[:kind] == 'podcast'
96
- output[:type] = 'podcast'
94
+ when "track"
95
+ if result[:kind] == "podcast"
96
+ output[:type] = "podcast"
97
97
  output[:id] = result[:collectionId]
98
98
  output[:url] = result[:collectionViewUrl].to_am + aff
99
99
  output[:title] = result[:collectionName]
100
100
  else
101
- output[:type] = 'song'
101
+ output[:type] = "song"
102
102
  output[:album] = result[:collectionId]
103
103
  output[:id] = result[:trackId]
104
104
  output[:url] = result[:trackViewUrl].to_am + aff
105
105
  output[:title] = "#{result[:trackName]} by #{result[:artistName]}"
106
106
  end
107
- when 'collection'
108
- output[:type] = 'album'
107
+ when "collection"
108
+ output[:type] = "album"
109
109
  output[:id] = result[:collectionId]
110
110
  output[:url] = result[:collectionViewUrl].to_am + aff
111
111
  output[:title] = "#{result[:collectionName]} by #{result[:artistName]}"
112
- when 'artist'
113
- output[:type] = 'artist'
112
+ when "artist"
113
+ output[:type] = "artist"
114
114
  output[:id] = result[:artistId]
115
115
  output[:url] = result[:artistLinkUrl].to_am + aff
116
116
  output[:title] = result[:artistName]
@@ -120,6 +120,6 @@ module SL
120
120
  end
121
121
  end
122
122
 
123
- SL::Searches.register 'applemusic', :search, self
123
+ SL::Searches.register "applemusic", :search, self
124
124
  end
125
125
  end
@@ -6,10 +6,10 @@ module SL
6
6
  class << self
7
7
  def settings
8
8
  {
9
- trigger: 'b(l|itly)',
9
+ trigger: "b(l|itly)",
10
10
  searches: [
11
- ['bl', 'bit.ly Shorten'],
12
- ['bitly', 'bit.ly shorten']
11
+ ["bl", "bit.ly Shorten"],
12
+ ["bitly", "bit.ly shorten"]
13
13
  ]
14
14
  }
15
15
  end
@@ -27,26 +27,26 @@ module SL
27
27
  end
28
28
 
29
29
  def bitly_shorten(url, title = nil)
30
- unless SL.config.key?('bitly_access_token') && !SL.config['bitly_access_token'].empty?
31
- SL.add_error('Bit.ly not configured', 'Missing access token')
30
+ unless SL.config.key?("bitly_access_token") && !SL.config["bitly_access_token"].empty?
31
+ SL.add_error("Bit.ly not configured", "Missing access token")
32
32
  return [false, title]
33
33
  end
34
34
 
35
- domain = SL.config.key?('bitly_domain') ? SL.config['bitly_domain'] : 'bit.ly'
35
+ domain = SL.config.key?("bitly_domain") ? SL.config["bitly_domain"] : "bit.ly"
36
36
  long_url = url.dup
37
- curl = TTY::Which.which('curl')
37
+ curl = TTY::Which.which("curl")
38
38
  cmd = [
39
39
  %(#{curl} -SsL -H 'Authorization: Bearer #{SL.config['bitly_access_token']}'),
40
40
  %(-H 'Content-Type: application/json'),
41
- '-X POST', %(-d '{ "long_url": "#{url}", "domain": "#{domain}" }'), 'https://api-ssl.bitly.com/v4/shorten'
41
+ "-X POST", %(-d '{ "long_url": "#{url}", "domain": "#{domain}" }'), "https://api-ssl.bitly.com/v4/shorten"
42
42
  ]
43
- data = JSON.parse(`#{cmd.join(' ')}`.strip)
44
- link = data['link']
43
+ data = JSON.parse(`#{cmd.join(" ")}`.strip)
44
+ link = data["link"]
45
45
  title ||= SL::URL.title(long_url)
46
46
  [link, title]
47
47
  end
48
48
  end
49
49
 
50
- SL::Searches.register 'bitly', :search, self
50
+ SL::Searches.register "bitly", :search, self
51
51
  end
52
52
  end
@@ -10,10 +10,10 @@ module SL
10
10
  #
11
11
  def settings
12
12
  {
13
- trigger: 'def(?:ine)?',
13
+ trigger: "def(?:ine)?",
14
14
  searches: [
15
- ['def', 'Dictionary Definition'],
16
- ['define', nil]
15
+ ["def", "Dictionary Definition"],
16
+ ["define", nil]
17
17
  ]
18
18
  }
19
19
  end
@@ -32,7 +32,7 @@ module SL
32
32
  fix = SL.spell(search_terms)
33
33
 
34
34
  if fix && search_terms.downcase != fix.downcase
35
- SL.add_error('Spelling', "Spelling altered for '#{search_terms}' to '#{fix}'")
35
+ SL.add_error("Spelling", "Spelling altered for '#{search_terms}' to '#{fix}'")
36
36
  search_terms = fix
37
37
  link_text = fix
38
38
  end
@@ -49,12 +49,12 @@ module SL
49
49
  #
50
50
  def define(terms)
51
51
  def_url = "https://www.wordnik.com/words/#{terms.url_encode}"
52
- curl = TTY::Which.which('curl')
52
+ curl = TTY::Which.which("curl")
53
53
  body = `#{curl} -sSL '#{def_url}'`
54
54
  if body =~ /id="define"/
55
55
  first_definition = body.match(%r{(?mi)(?:id="define"[\s\S]*?<li>)([\s\S]*?)</li>})[1]
56
56
  parts = first_definition.match(%r{<abbr title="partOfSpeech">(.*?)</abbr> (.*?)$})
57
- return [def_url, "(#{parts[1]}) #{parts[2]}".gsub(%r{</?.*?>}, '').strip]
57
+ return [def_url, "(#{parts[1]}) #{parts[2]}".gsub(%r{</?.*?>}, "").strip]
58
58
  end
59
59
 
60
60
  false
@@ -64,6 +64,6 @@ module SL
64
64
  end
65
65
 
66
66
  # Registers the search with the SL::Searches module
67
- SL::Searches.register 'definition', :search, self
67
+ SL::Searches.register "definition", :search, self
68
68
  end
69
69
  end
@@ -12,12 +12,12 @@ module SL
12
12
  #
13
13
  def settings
14
14
  {
15
- trigger: '(?:g|ddg|z|ddgimg)',
15
+ trigger: "(?:g|ddg|z|ddgimg)",
16
16
  searches: [
17
- ['g', 'Google/DuckDuckGo Search'],
18
- ['ddg', 'DuckDuckGo Search'],
19
- ['z', 'DDG Zero Click Search'],
20
- ['ddgimg', 'Return the first image from the destination page']
17
+ ["g", "Google/DuckDuckGo Search"],
18
+ ["ddg", "DuckDuckGo Search"],
19
+ ["z", "DDG Zero Click Search"],
20
+ ["ddgimg", "Return the first image from the destination page"]
21
21
  ]
22
22
  }
23
23
  end
@@ -41,13 +41,13 @@ module SL
41
41
  terms = "%5C#{search_terms.url_encode}"
42
42
  page = Curl::Html.new("https://duckduckgo.com/?q=#{terms}", compressed: true)
43
43
 
44
- locs = page.meta['refresh'].match(%r{/l/\?uddg=(.*?)$})
44
+ locs = page.meta["refresh"].match(%r{/l/\?uddg=(.*?)$})
45
45
  locs = page.body.match(%r{/l/\?uddg=(.*?)'}) if locs.nil?
46
46
  locs = page.body.match(/url=(.*?)'/) if locs.nil?
47
47
 
48
48
  return false if locs.nil?
49
49
 
50
- url = locs[1].url_decode.sub(/&rut=\w+/, '')
50
+ url = locs[1].url_decode.sub(/&rut=\w+/, "")
51
51
 
52
52
  result = url.strip.url_decode || false
53
53
  return false unless result
@@ -57,10 +57,10 @@ module SL
57
57
  # output_url = CGI.unescape(result)
58
58
  output_url = result
59
59
 
60
- output_title = if SL.config['include_titles'] || SL.titleize
61
- SL::URL.title(output_url) || ''
60
+ output_title = if SL.config["include_titles"] || SL.titleize
61
+ SL::URL.title(output_url) || ""
62
62
  else
63
- ''
63
+ ""
64
64
  end
65
65
 
66
66
  output_url = SL.first_image(output_url) if search_type =~ /img$/
@@ -83,11 +83,15 @@ module SL
83
83
  #
84
84
  def zero_click(search_terms, link_text, disambiguate: false)
85
85
  search_terms.gsub!(/%22/, '"')
86
- d = disambiguate ? '0' : '1'
87
- url = "http://api.duckduckgo.com/?q=#{search_terms.url_encode}&format=json&no_redirect=1&no_html=1&skip_disambig=#{d}"
88
- result = Curl::Json.new(url, symbolize_names: true).json
89
- return SL.ddg(terms, link_text) unless result
90
-
86
+ d = disambiguate ? "0" : "1"
87
+ url = "https://api.duckduckgo.com/?q=#{search_terms.url_encode}&format=json&no_redirect=1&no_html=1&skip_disambig=#{d}"
88
+ begin
89
+ result = Curl::Json.new(url, symbolize_names: true).json
90
+ return SL.ddg(terms, link_text) unless result
91
+ rescue StandardError => e
92
+ SL.add_error("Invalid response", "Search for #{terms}: (#{e})")
93
+ return false
94
+ end
91
95
  wiki_link = result[:AbstractURL] || result[:Redirect]
92
96
  title = result[:Heading] || false
93
97
 
@@ -107,7 +111,7 @@ module SL
107
111
  # @param type [Symbol] the type of search to
108
112
  # perform
109
113
  # @param klass [Class] the class to register
110
- SL::Searches.register 'duckduckgo', :search, self
114
+ SL::Searches.register "duckduckgo", :search, self
111
115
  end
112
116
  end
113
117
 
@@ -121,13 +125,13 @@ module SL
121
125
  # @param link_text [String] The link text
122
126
  # @param timeout [Integer] The timeout
123
127
  #
124
- def google(search_terms, link_text = nil, timeout: SL.config['timeout'], image: false)
128
+ def google(search_terms, link_text = nil, timeout: SL.config["timeout"], image: false)
125
129
  if SL::GoogleSearch.api_key?
126
- s_class = 'google'
127
- s_type = image ? 'img' : 'gg'
130
+ s_class = "google"
131
+ s_type = image ? "img" : "gg"
128
132
  else
129
- s_class = 'duckduckgo'
130
- s_type = image ? 'ddgimg' : 'g'
133
+ s_class = "duckduckgo"
134
+ s_type = image ? "ddgimg" : "g"
131
135
  end
132
136
  search = proc { SL::Searches.plugins[:search][s_class][:class].search(s_type, search_terms, link_text) }
133
137
  SL::Util.search_with_timeout(search, timeout)
@@ -144,13 +148,13 @@ module SL
144
148
  # @param image [Boolean] Image search
145
149
  # @return [SL::Searches::Result] The search result
146
150
  #
147
- def ddg(search_terms, link_text = nil, timeout: SL.config['timeout'], google: true, image: false)
151
+ def ddg(search_terms, link_text = nil, timeout: SL.config["timeout"], google: true, image: false)
148
152
  if google && SL::GoogleSearch.api_key?
149
- s_class = 'google'
150
- s_type = image ? 'img' : 'gg'
153
+ s_class = "google"
154
+ s_type = image ? "img" : "gg"
151
155
  else
152
- s_class = 'duckduckgo'
153
- s_type = image ? 'ddgimg' : 'g'
156
+ s_class = "duckduckgo"
157
+ s_type = image ? "ddgimg" : "g"
154
158
  end
155
159
 
156
160
  search = proc { SL::Searches.plugins[:search][s_class][:class].search(s_type, search_terms, link_text) }
@@ -170,7 +174,7 @@ module SL
170
174
 
171
175
  def first_image(url)
172
176
  images = Curl::Html.new(url).images
173
- images.filter { |img| img[:type] == 'img' }.first[:src]
177
+ images.filter { |img| img[:type] == "img" }.first[:src]
174
178
  end
175
179
  end
176
180
  end