8000 Plugins · ttscoff/searchlink Wiki · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Plugins

Brett Terpstra edited this page Jan 6, 2025 · 7 revisions

Custom searches in the Configuration are great for adding simple site-specific searches and token replacements, but if you want to do something more complex, you can write a plugin.

You can find more example plugins in github.com/ttscoff/searchlink-plugins.

There are two types of plugin, Script Searches and Ruby Plugins. See each section below to learn more.

Script Plugins

If you want to write a search plugin in a language other than Ruby, you can use the Script Search API to do so.

The Config

Script Search plugins require a configuration file located in ~/.config/searchlink/plugins. This file can be YAML or JSON and requires an extension of .json, .yml, or .yaml. It must contain the keys:

  • name: A name for the plugin, all one word, no spaces allowed
  • trigger: A regex string that will trigger the plugin on a !search
  • searches: An array of arrays defining the searches, used for help output. Each item in the array should be an array containing ["title", "description"].
  • script: The path to your script. This can either be an absolute path, or a path relative to the ~/.config/searchlink/plugins directory

Example JSON config:

{
    "name": "testscript2",
    "trigger": "^scr2$",
    "searches":
    [
        "rubytest",
        "Test Ruby Script Search"
    ],
    "script": "test.rb"
}

Example YAML config:

---
name: test shell script
trigger: ^scr$
searches:
  - [test, "Test Shell Script Search"]
script: test.sh

The Script

The script can be in any language, it just has to be executable (with a hashbang), and output the correct format. The search type, search terms, and link text are passed as arguments to the script, and SearchLink expects a return string on STDOUT containing either JSON or YAML.

The script is called like this:

SCRIPT_PATH "SEARCH_TYPE" "SEARCH_TERMS" "LINK_TEXT"

The script is expected to return either a JSON or YAML array containing the keys url, title, and link_text. Any of these can be nil or false, depending on the type of plugin and expected results. For example, if the plugin is returning an embed, url would be set to 'embed', title would be set to the embed contents, and link_text would be empty. In most cases link text will just return the original link text argument (third argument) passed to the script.

JSON return example:

{ "url": "https://brettterpstra.com", "title": "Script Test", "link_text": "Boogie"  }

YAML return example:

---
url: https://brettterpstra.com
title: BrettTerpstra.com
link_text: "Brett's Website"

It may be possible to bridge some languages to the SearchLink (Ruby) API for access to the SL object, but I haven't played with it much.

Ruby Plugins

Standard Pplugins are Ruby files located in ~/.config/searchlink/plugins (create the directory if it doesn't exist). Plugins need to follow a specific structure. Here's an example with comments:

# Always start with module SL
module SL
  # Give it a unique class name
  class LyricsSearch
    class << self
      # Settings block is required with `trigger` and `searches`
      def settings
        {
          # `trigger` is A regular expression that will trigger this plugin
          # when used with a bang. The one below will trigger on !lyrics or
          # !lyricse.
          trigger: 'lyrics?e?',
          # Every search that the plugin should execute should be individually
          # listed and described in the searches array. This is used for
          # completion and help generation. Do not include the bang (!) in the
          # search keyword.
          searches: [
            ['lyric', 'Song Lyrics Search'],
            ['lyrice', 'Song Lyrics Embed']
          ],
          #
          # # The config block is optional, but can be used to define any
          # # configuration options that the plugin requires. New configuration
          # # options that don't exist in current config will be appended
          # config: [
          #   {
          #     # Description that will appear above the option in config.yaml
          #     description: "Genius API"
          #     # the configuration key
          #     key: "genius_token",
          #     # the default value
          #     value: "''",
          #     # whether the configuration is required. If
          #     # false (meaning optional), it will be added
          #     # with a # in front of the key in the config
          #     # file, making it a comment.
          #     required: false
          #   }
          # ]
        }
      end

      # Every plugin must contain a #search method that takes 3 arguments:
      #
      # - `search_type` will contain the !search trigger that was used (minus the !)
      # - `search_terms` will include everything that came after the !search
      # - `link_text` will contain the text that will be used for the linked
      # text portion of the link. This can usually remain untouched but must
      # be passed back at the end of the function.
      def search(search_type, search_terms, link_text)
      	# You can branch to multiple searches by testing the search_type
        case search_type
        when /e$/
          url, title = SL.ddg("site:genius.com #{search_terms}", link_text)
          if url
            title = get_lyrics(url)
            # To return an embed, set url (first parameter in the return
            # array) to 'embed', and put the embed contents in the second
            # parameter.
            title ? ['embed', title, link_text] : false
          else
          	# Use `SL#add_error(title, text)` to add errors to the HTML
          	# report. The report will only be shown if errors have been added.
            SL.add_error('No lyrics found', "Song lyrics for #{search_terms} not found")
            false
          end
        else
          # You can perform a DuckDuckGo search using SL#ddg, passing the
          # search terms and link_text. It will return url, title, and
          # link_text. SL#ddg will add its own errors, and if it returns false
          # that will automatically be tested for, no additional error
          # handling is required.
          url, title, link_text = SL.ddg("site:genius.com #{search_terms}", link_text)
          # Always return an array containing the resulting URL, the title,
          # and the link_text variable that was passed in, even if it's
          # unmodified.
          [url, title, link_text]
        end
      end

      # Any additional helper methods can be defined after #search
      def get_lyrics(url)
        if SL::URL.valid_link?(url)
          # You can use Ruby's net/http methods for retrieving pages, but
          # `curl -SsL` is faster and easier.
          body = `curl -SsL #{url}`

          matches = body.scan(%r{class="Lyrics__Container-.*?>(.*?)</div><div class="RightSidebar})

          lyrics = matches.join("\n")

          if lyrics
            "```\n#{CGI.unescape(lyrics).gsub(%r{<br/?>}, "  \n").gsub(%r{</?.*?>}, '').gsub(/&#x27;/, "'")}\n```"
          else
            false
          end
        else
          false
        end
      end
    end

    # At the end of the search class, you must register it as a plugin. This
    # method takes a title, a type (:search for a search plugin), and the
    # unique class. When running #register within the search class itself,
    # you can just use `self`.
    SL::Searches.register 'lyrics', :search, self
  end
end

Place this plugin in ~/.config/searchlink/plugins and it will add two new searches to SearchLink. !lyric will search Genius.com for song lyrics, and !lyrice will grab the lyrics and output them as an "embed." This example plugin can be downloaded from the main repository.

Clone this wiki locally
0