Skip to content

Instantly share code, notes, and snippets.

@twlz0ne
Last active July 23, 2022 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save twlz0ne/a6334bf0bc4ff6fc07be2a6e9b1f52a1 to your computer and use it in GitHub Desktop.
Save twlz0ne/a6334bf0bc4ff6fc07be2a6e9b1f52a1 to your computer and use it in GitHub Desktop.
Custom Firefox Search Engine #Emacs
(cl-defun custom-firefox-search-engine (&key
name
description
iconurl
searchurl
&allow-other-keys)
"Custom Firefox Search Engin.
NAME Short name of search engine
DESCRIPTION Description of search engine
ICONURL URL of icon file
SEARCHURL Search URL with {searchTerms} in place of query
Usage:
M-x custom-firefox-search-engine
Or:
(custom-firefox-search-engine :name \"汉典\"
:description \"zdic.net\"
:iconurl \"https://www.zdic.net/favicon.ico\"
:searchurl \"https://www.zdic.net/hans/{searchTerms}\")
(custom-firefox-search-engine :name \"京东\"
:description \"jd.com\"
:iconurl \"https://www.jd.com/favicon.ico\"
:searchurl \"https://search.jd.com/Search?enc=utf-8&keyword={searchTerms}\")
Alternate tools:
- https://mycroftproject.com/dlstats.html
A webside provides a collection of Search Engines.
- https://addons.mozilla.org/en-US/firefox/addon/search-engines-helper/
An add-on for exporting, importing and customizing Search Engines.
Inspired by @wsug's works in https://emacs-china.org/t/firefox/18244"
(interactive
(let* ((searchurl
(read-string (concat "Search url (e.g. "
(propertize
"https://example.com/search?keyword={searchTerms}"
'face 'font-lock-keyword-face)
"): ")))
(urlobj (url-generic-parse-url searchurl)))
(list :name (read-string "Name (as short as possible): " (url-host urlobj))
:description (read-string "Description: " (url-host urlobj))
:iconurl (read-string "Icon url: " (concat (url-type urlobj) "://" (url-host urlobj) "/favicon.ico"))
:searchurl searchurl)))
(require 'web-server)
(require 'sgml-mode)
(let (server)
(setq server
(ws-start
`(((lambda (_) t) .
(lambda (request)
(with-slots (process headers) request
(pcase (alist-get :GET headers)
("/"
(message "==> [CUSTOM-ENGINE] /")
(ws-response-header process 200 '("Content-type" . "text/html"))
(process-send-string process
(format-spec
"\
<!DOCTYPE html>
<html>
<head>
<meta charset=\"utf-8\"/><title>%n</title>
<link
rel=\"search\"
type=\"application/opensearchdescription+xml\"
title=\"%n\"
href=\"/opensearch.xml\">
</head>
<body>
<h2>Finish following steps:</h2>
<ol>
<li> Right-click in the address bar, choose【Add \"%n\"】. </li>
<li> Right-click to open <a href=\"about:preferences#search\" target=\"_blank\"> about:preferences#search </a> in new tab to set keyword. </li>
<li> <a href=\"/close\">Close</a> the web server and this page. </li>
</ol>
</body>
</html>"
(list (cons ?n ,name)))))
("/opensearch.xml"
(message "==> [CUSTOM-ENGINE] /opensearch.xml")
(ws-response-header process 200 '("Content-type" . "text/html"))
(process-send-string process
(format-spec
"\
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<OpenSearchDescription xmlns=\"http://a9.com/-/spec/opensearch/1.1/\">
<ShortName>%n</ShortName>
<Description>%d</Description>
<InputEncoding>UTF-8</InputEncoding>
<Image width=\"32\" height=\"32\" type=\"image/x-icon\">%i</Image>
<Url type=\"text/html\" template=\"%s\"></Url>
</OpenSearchDescription>"
(list (cons ?n ,name)
(cons ?d ,description)
(cons ?i ,iconurl)
(cons ?s ,(with-temp-buffer
(insert searchurl)
(sgml-quote (point-min) (point-max))
(buffer-string)))))))
("/close"
(message "==> [CUSTOM-ENGINE] /close")
(ws-response-header process 200 '("Content-type" . "text/html"))
(process-send-string process
"\
<!DOCTYPE html>
<html>
<head>
<script type=\"text/javascript\">
window.close();
</script>
</head>
</html>")
(run-with-timer
0.1 nil
(lambda (server)
(message "==> [CUSTOM-ENGINE] stop server: %s" (process-contact (ws-process server)))
(ws-stop server))
(plist-get (process-plist process) :server)))
(_ (ws-send-404)))))))
t))
(browse-url
(format "http://localhost:%s" (cadr (process-contact (ws-process server)))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment