Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

a readline app with replic #1

wants to merge 1 commit into from
Changes from all commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.


Just for now

@@ -0,0 +1,7 @@

$(LISP) --non-interactive \
--load lyrics.asd \
--eval '(ql:quickload :lyrics)' \
--eval '(asdf:make :lyrics)'
@@ -1,6 +1,10 @@
# lyrics

Search song lyrics or, the other way around, search songs from lyrics.

Available as a CL library and as a terminal application.

# Installation

@@ -18,6 +22,16 @@ git clone ~/quicklisp/local-projects/lyri
sudo pacman -S sqlite3

Optionally, build the terminal app:

make build

This produces a `lyrics` binary with the two commands `lyrics` and
`search-song` available.

# Usage

@@ -84,6 +98,10 @@ If the song cannot be found on any of the websites, `lyrics` returns nil. Otherw
`lyrics` returns the song lyrics and saves them in the database from where they
will be fetched on the next call. The `lyrics` function is memoized.

The readline application is built quite automatically with the
[replic]( library.

## Authors
Copyright (c) 2019 [Mihai Olteanu](

@@ -12,7 +12,13 @@
:serial t

:build-operation "program-op"
:build-pathname "lyrics"
:entry-point "lyrics::main"

:components ((:file "package")
(:file "lyrics")))
@@ -1,9 +1,11 @@
;;;; lyrics.lisp
(in-package #:lyrics)

(defparameter *db* nil)

(defun setup-db ()
"Create a sqlite table in ~/ if one does not already exist."
(defparameter *db*
(setf *db*
(connect (merge-pathnames "cl-lyrics.db"
(execute-non-query *db*
@@ -17,10 +19,9 @@


(defstruct website
;; website name, only used for documentation purposes
;; website name, only used for documentation purposes
;; Template used to construct the actual url. It contains the artist-name and
;; song-name string, respectively, which need to be replaced with the user
@@ -160,8 +161,10 @@ name. If the lyrics are not in the db, try and extract them from one of the
supported lyrics websites. If found, save the lyrics the db and return them. If
not found, return nil."
(declare (string artist song))
(unless *db*
(if-let ((lyrics (lyrics-from-db artist song)))
lyrics ;already in db
lyrics ;already in db
(dolist (website
;; Try to minimize the chance of getting banned; try a different
;; order of sites on every request.
@@ -196,3 +199,13 @@ the thread that is started for the request."
;; at a future date; take your time; better to be safe than being banned
;; for making too many requests in a short time.
(sleep (random-elt '(1 2 3)))))))

(defun main ()

(setf replic:*prompt* "lyrics> ")
(replic.completion:functions-to-commands :replic.base)
(replic.completion:functions-to-commands :lyrics)
(replic:autoprint-results-from :lyrics)

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.