# Babashka Scripts
-Miscellaneous [babashka](https://babashka.org "babashka website") scripts I wrote for my own personal use.
+Miscellaneous [babashka](https://babashka.org "babashka website") scripts written for my own personal use.
## Requirements
-babashka (>= 0.2.9)
+babashka (>= 0.4.0)
## Usage
Clone this repository.
``` sh
-cd ~/dev
git clone https://njoseph.me/gitweb/babashka-scripts.git
```
-Add the following lines to your shell configuration file.
+The list of available commands can be found by running `bb tasks` in the directory where the file `bb.edn` is present.
``` sh
-export BABASHKA_PRELOADS='(run! load-file (map #(str (System/getProperty "user.home") "/dev/babashka-scripts/" %) ["lib.clj" "utils.clj"]))'
-export BABASHKA_PRELOADS=$BABASHKA_PRELOADS" (require '[utils :refer :all])"
-export PATH=$PATH:$HOME/dev/babashka-scripts
+The following tasks are available:
+
+gup Do a git pull and rebase branch with master in a given directory.
+gpa Runs `git pull` on all the git repositories in a given directory.
+ebook-to-audiobook A utility to listen to your ebooks using TTS programs. Only tested on macOS with epub files.
+install-deb Install a Debian package given a direct URL to the .deb file.
+install-deb-gh Install a Debian package given a GitHub URL.
+```
+
+Some tasks can also take arguments.
+
+``` sh
+bb ebook-to-audiobook the-great-gatsby.epub
```
-Some useful aliases and functions.
+## Shell aliases
``` sh
-alias gup="bb -e '(git-pull-rebase-branch)'"
-alias bbr="rlwrap bb --repl"
+# bash, zsh
+source /path/to/babashka-scripts/bb-aliases.sh
+alias task = bb --config ~/dev/babashka-scripts/bb.edn
-function bb-wrap {
- expr="($1 \"$2\")"
- bb -e $expr
-}
+# nu
+source /path/to/babashka-scripts/bb-aliases.nu
+alias task = bb --config ~/dev/babashka-scripts/bb.edn
+```
+
+*Example:* To pull all the repositories in a directory, run
-alias install-deb="bb-wrap install-deb"
-alias install-deb-gh="bb-wrap install-deb-from-GitHub"
+``` sh
+task gpa .
```
-## Organization
+There is a utility `bbe` to run tasks in the current working directory in `bb-aliases.sh`.
-`lib.clj` contains functions that the other scripts might use. It must be loaded
-first.
-`utils.clj` contains standalone utilities that can be executed directly. These are
-convenient to use through shell aliases.
+*Example:* To pull all the repositories in a directory, run
-The remaining Clojure files are executable scripts.
+``` sh
+bbe gpa
+```
--- /dev/null
+#!/usr/bin/env nu
+
+def bbe [task] {
+ bb -e $"\(run-task-in-cwd \'($task)\)"
+}
--- /dev/null
+#!/usr/bin/env bash
+
+bbe() {
+ bb -e "(run-task-in-cwd \"$1\")"
+}
--- /dev/null
+{:paths ["scripts"]
+ :tasks
+ {test {:doc "Test whether the 'task' alias is working."
+ :task (println "Yes, it's working!")}
+
+ gup {:requires ([git :refer [git-pull-rebase-branch]])
+ :doc "Do a git pull and rebase branch with master in a given directory."
+ :task (git-pull-rebase-branch (get (into [] *command-line-args*) 0))}
+
+ gpa {:requires ([git :refer [git-pull-all]])
+ :doc "Runs `git pull` on all the git repositories in a given directory."
+ :task (git-pull-all (get (into [] *command-line-args*) 0))}
+
+ ebook-to-audiobook {:requires ([ebooks :refer [convert-ebook-to-audiobook]])
+ :doc "A utility to listen to your ebooks using TTS programs. Only tested on macOS with epub files."
+ :task (convert-ebook-to-audiobook (get (into [] *command-line-args*) 0))}
+
+ install-deb {:requires ([debian :refer [install-deb-from-url]])
+ :doc "Install a Debian package given a direct URL to the .deb file."
+ :task (install-deb-from-url (get (into [] *command-line-args*) 0))}
+
+ install-deb-gh {:requires ([debian :refer [install-deb-from-GitHub]])
+ :doc "Install a Debian package given a GitHub URL."
+ :task (install-deb-from-GitHub (get (into [] *command-line-args*) 0))}}}
+++ /dev/null
-#! /usr/bin/env bb
-
-; Runs `git pull` on all the git repositories in a directory
-
-(require '[babashka.process :as p] '[clojure.java.io :as io])
-
-(def default-root ".")
-
-(defn list-dirs [root] (filter #(.isDirectory %) (.listFiles (io/file root))))
-
-(defn git-pull [dir] (p/process ["git" "-C" dir "pull" "--rebase"]))
-
-(when (= *file* (System/getProperty "babashka.file"))
- (let [root (get (into [] *command-line-args*) 0 default-root)
- dirs (list-dirs root)
- pulls (->> root
- list-dirs
- (map git-pull)
- doall)
- outputs (map #(->> %
- p/check
- :out
- slurp)
- pulls)]
- ;; Print corresponding directory name when pulling
- ;; Skip printing already up to date repos
- (doseq [[dir out] (filter #(not (.contains (second %) "is up to date."))
- (map vector dirs outputs))]
- (println (str dir "\n" out)))))
-(ns utils
+(ns debian
(:require [clojure.string :as str]
[clojure.java.io :as io]
[cheshire.core :as json]
[org.httpkit.client :as http]
[lib :refer [download-binary run-cmd]]))
-(defn git-pull-rebase-branch
- "Do git pull and rebase branch with master"
- []
- (let [current-branch (str/trim (run-cmd ["git" "branch" "--show-current"]))]
- (print (run-cmd ["git" "pull" "--rebase"]))
- (when (not (contains? #{"master" "main"} current-branch))
- (run! print
- (map run-cmd
- '[["git" "checkout" "master"] ["git" "pull" "--rebase"]
- ["git" "checkout" "-"] ["git" "rebase" "master"]])))))
-
-(defn run-seq
- "Run a sequence of shell commands on a sequence of arguments.
-
- Examples:
-
- 1. Play and delete each video from a folder
- ls | bb -i '(run-seq [\"mpv\" \"rm\"] *input*)'
- "
- [commands arguments]
- (doseq [argument arguments
- command commands]
- (println (run-cmd [command argument]))))
-
-(defn install-deb
+(defn install-deb-from-url
"Install a Debian package given a direct URL to the .deb file."
[url]
(println "Downloading deb package...")
assets (get-assets api-url)
deb-url (find-url-to-deb assets)]
;; Download and install Debian package
- (install-deb deb-url))))
+ (install-deb-from-url deb-url))))
-#! /usr/bin/env bb
+(ns ebooks
+ (:require [clojure.java.io :as io]
+ [clojure.string :refer [split]]
+ [lib :refer [run-cmd extract-file-from-zip]]))
-; A utility to listen to your ebooks using TTS programs
-
-(require '[clojure.java.io :as io]
- '[clojure.string :refer [split]]
- '[lib :refer [run-cmd extract-file-from-zip unixify]])
+; Utilities for dealing with ebooks
+;
+; Dependencies:
+; 1. calibre
+; 2. ffmpeg
+; 3. OS-dependent TTS software
;; TODO Check if all required utilities are installed
-;; TODO Allow voice selection
-(println "Selected voice is Samantha")
-
-;; TODO Use festival-tts or say depending on OS
-
-(defn- convert
+;; TODO Use tools.cli to provide more options
+(defn convert-ebook-to-audiobook
+ "A utility to listen to your ebooks using TTS programs. This utility only works on macOS for now."
[book-file]
+ ;; TODO Allow voice selection
+ (let [default-voice (run-cmd ["defaults" "read" "com.apple.speech.voice.prefs" "SelectedVoiceName"])]
+ (println (str "Will read using the default voice " default-voice)))
(let [title (first (split book-file #"\."))
txtz-file (str title ".txtz")
txt-file (str title ".txt")
(run-cmd ["ebook-convert" book-file txtz-file])
(extract-file-from-zip txtz-file "index.txt" txt-file)
(println "Converting text to audio. Don't hold your breath!")
+ ;; TODO Use festival-tts or say depending on OS
(run-cmd ["say" "-f" txt-file "-o" aiff-file])
(println "Creating mp3 file...")
(run-cmd ["ffmpeg" "-i" aiff-file mp3-file])
(println "Cleaning up...")
(run! io/delete-file [txtz-file txt-file aiff-file])
(println (str "Done! Check out " mp3-file))))
-
-(unixify convert)
--- /dev/null
+(ns git
+ (:require [babashka.process :as p]
+ [clojure.java.io :as io]
+ [clojure.string :as str]
+ [lib :refer [run-cmd]]))
+
+; Utilities for git operations
+
+(defn- has-git-repo
+ [dir]
+ (first (filter #(= ".git" %)
+ (map #(.getName %)
+ (filter #(.isDirectory %) (.listFiles (io/file dir)))))))
+
+(defn- list-dirs
+ [root]
+ (filter #(has-git-repo %)
+ (filter #(.isDirectory %) (.listFiles (io/file root)))))
+
+(defn- git-pull
+ "Do a git pull with rebase."
+ [dir]
+ (p/process ["git" "-C" dir "pull" "--rebase"]))
+
+(defn git-pull-all
+ "Runs `git-pull` on all the git repositories in a directory."
+ [root]
+ (let [dirs (list-dirs root)
+ pulls (->> root
+ list-dirs
+ (map git-pull)
+ doall)
+ outputs (map #(->> %
+ p/check
+ :out
+ slurp)
+ pulls)]
+ ;; Print corresponding directory name when pulling
+ ;; Skip printing already up to date repos
+ (doseq [[dir out] (filter #(not (.contains (second %) "is up to date."))
+ (map vector dirs outputs))]
+ (println (str dir "\n" out)))))
+
+
+(defn git-pull-rebase-branch
+ "Do git pull and rebase branch with master."
+ [dir]
+ (git-pull dir)
+ (let [current-branch (str/trim (run-cmd ["git" "branch" "--show-current"]))]
+ (when (not (contains? #{"master" "main"} current-branch))
+ (run! print
+ (map run-cmd
+ [["git" "checkout" "master"] ["git" "pull" "--rebase"]
+ ["git" "checkout" current-branch] ["git" "rebase" "master"]])))))
--- /dev/null
+(ns meta)
+
+; Operations on babashka itself or scripts in this repository.
--- /dev/null
+(ns utils
+ (:require [lib :refer [expand-home run-cmd]]
+ [babashka.process :refer [process]]))
+
+(defn run-seq
+ "Run a sequence of shell commands on a sequence of arguments.
+
+ Examples:
+
+ 1. Play and delete each video from a folder
+ ls | bb -i '(run-seq [\"mpv\" \"rm\"] *input*)'
+ "
+ [commands arguments]
+ (doseq [argument arguments
+ command commands]
+ (println (run-cmd [command argument]))))
+
+(defn run-task-in-cwd
+ "Run a bb task from this repository in the current working directory."
+ [task]
+ (let [current-dir (System/getenv "PWD")
+ babashka-scripts-dir (expand-home "~/dev/babashka-scripts/")]
+ (print (-> (process ["bb" task current-dir] {:dir babashka-scripts-dir})
+ :out
+ slurp))))
#! /usr/bin/env bb
+; -*- mode: clojure -*-
(require '[cheshire.core :as json]
'[org.httpkit.client :as http]