{ pkgs, lib, ... }: let zareadScript = pkgs.writeShellScriptBin "zaread" '' # zaread cache path ZA_CACHE_DIR="''${XDG_CACHE_HOME:-"$HOME"/.cache}/zaread/" # zaread config path ZA_CONFIG="''${XDG_CONFIG_HOME:-"$HOME"/.config}/zaread/zareadrc" # Default reader, i.e. command, which script uses to open pdf, epub and converted files READER="${pkgs.zathura}/bin/zathura" # Default converters, i.e. commands, which script uses to convert files to pdf OFFICE_CMD="${pkgs.libreoffice-fresh}/bin/soffice" MD_CMD="${pkgs.md2pdf or pkgs.pandoc}/bin/${if pkgs ? md2pdf then "md2pdf" else "pandoc"}" TYPST_CMD="${pkgs.typst}/bin/typst" TYPST_ARG="compile" # Can be changed to "watch" MD_ARG="" OFFICE_ARG="--headless" # If you want to use other commands set these vars in $ZA_CONFIG. Some cli # arguments are hardcoded so some commands won't work. Check that first. # Sources the variables from config file if exists # shellcheck disable=1090 [ -f "$ZA_CONFIG" ] && . "$ZA_CONFIG" # if $ZA_CACHE_DIR doesn't exist, we create it. [ ! -d "$ZA_CACHE_DIR" ] && mkdir -p "$ZA_CACHE_DIR" # Exit if called without arguments if [ "$#" = 0 ]; then echo "No files to open." exit fi if [ "$#" != 1 ]; then echo "More than one filename given. Closing." exit 1 fi path="$1" if [ ! -f "$path" ]; then echo "File doesn't exist." exit 1 fi if ! command -v "$READER" >/dev/null; then echo "$READER is not on the $PATH." echo "Closing." exit 1 fi echo "\$READER='$READER' is in the \$PATH. Starting script..." ## create position and file variables ## # complete file name (path excluded): file="$(basename "$path")" echo "Filename: $file" case "$path" in # complete directory path: # if it has been inserted absolute path ($path starts with '/') /*) directory="$(dirname "$path")" ;; # else (relative path inserted) *) directory="''${PWD}/$(dirname "$path")" # directory="$(echo "$dir" | tr -s '/')" ;; esac echo "Directory: $directory/" echo "Path: $directory/$file" # get file type # if the file is itself a pdf, a djvu or an epub, or we already have a pdf converted version, # then we don't need a converter. But if it's an already converted document, then # file position is different: we must distinguish between original and converted files file_mt="$(file --mime-type "$directory/$file")" file_mt="''${file_mt#*: }" echo "Mime type: $file_mt" cd "$directory" || { echo "Couldn't cd into $directory" exit 1 } # $pdffile is a string composed this way: CRC_BYTECOUNT_$filename.[pdf,epub] # if the converted file exists, then it's named like $pdffile pdffile="$(cksum "$file" | sed -E 's/^([0-9]+) ([0-9]+) (.*)$/\1_\2_\3.pdf/')" echo "Converted pdf filename: $pdffile" file_converter="" # If the converted file exists we can just open it. if [ -f "$ZA_CACHE_DIR/$pdffile" ]; then file_converter="none_converted" else case "$file_mt" in "application/pdf" | "image/vnd.djvu" | "application/epub+zip") # If the file is a pdf, a djvu or an epub we don't need to convert it. file_converter="none_original" ;; "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | \ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | \ "application/vnd.openxmlformats-officedocument.presentationml.presentation" | \ "application/msword" | \ "application/vnd.ms-excel" | \ "application/vnd.ms-powerpoint" | \ "application/vnd.oasis.opendocument.text" | \ "application/vnd.oasis.opendocument.spreadsheet" | \ "application/vnd.oasis.opendocument.presentation" | \ "text/rtf" | \ "text/csv") # If the file is an office file (ooxml or the old format or an # opendocument) we convert it using $OFFICE_CMD. file_converter="$OFFICE_CMD" ;; esac fi case "$file_converter" in "") echo "The file format is unsupported." exit 2 ;; "none_original") echo "The file is already in PDF format. We just open it." eval "$READER" \""$directory/$file"\" ;; "none_converted") echo "We already converted this file. We just open it." eval "$READER" \""$ZA_CACHE_DIR/$pdffile"\" ;; *) # So the file is not a pdf or an epub, and a converted version # doesn't exist, but its format may be convertible if command -v "$file_converter" >/dev/null; then echo "We are starting to convert the file \"$file\" using $file_converter" # If converter tools are changed in $ZA_CONFIG check calling # commands bellow. They may need to be called with different # arguments and format. case "$file_converter" in "$OFFICE_CMD") eval "$OFFICE_CMD" "$OFFICE_ARG" --convert-to pdf \""$directory/$file"\" --outdir \""$ZA_CACHE_DIR"\" # We need to handle cases where file starts with a . and # that's the only one . in filename, i.e. filename hasn't # got extension case "$file" in .*.*) # If it has one more . after the first character # which is a ., we'll consider that as an # extension, so we can use parameter expansion, # and we need this case for the next one to work. tmpfile="''${file%.*}.pdf" ;; .*) # If this case was the first it would also match cases with 2 .'s in the filename. # If the filename starts with a . and it hasn't got an # extension, we just add .pdf to the filename to get # tmpfilename tmpfile="$file.pdf" ;; *) # In the rest of cases we can use parameter expansion tmpfile="''${file%.*}.pdf" ;; esac mv "$ZA_CACHE_DIR/$tmpfile" "$ZA_CACHE_DIR/$pdffile" ;; "$MD_CMD") if [ "$MD_CMD" = "${pkgs.pandoc}/bin/pandoc" ]; then eval "$MD_CMD" "$MD_ARG" \""$directory/$file"\" -o \""$ZA_CACHE_DIR/$pdffile"\" else eval "$MD_CMD" "$MD_ARG" \""$directory/$file"\" -o \""$ZA_CACHE_DIR/$pdffile"\" fi ;; "$TYPST_CMD") eval "$TYPST_CMD" "$TYPST_ARG" \""$directory/$file"\" \""$ZA_CACHE_DIR/$pdffile"\" --open "$READER" exit ;; esac else echo "The command we need to convert '$file_converter' is not in \$PATH." exit 4 fi echo "Now we can open the file $ZA_CACHE_DIR/$pdffile" # ...and after the conversion we open the file eval "$READER" \""$ZA_CACHE_DIR/$pdffile"\" ;; esac ''; in { home.packages = [ zareadScript ]; xdg.desktopEntries.zaread = { name = "zaread"; exec = "${zareadScript}/bin/zaread %f"; icon = "org.pwmt.zathura"; comment = "Lightweight ebook and office document reader"; terminal = false; noDisplay = true; categories = [ "Office" "Viewer" ]; mimeType = [ "application/pdf" "image/vnd.djvu" "application/epub+zip" "application/vnd.openxmlformats-officedocument.wordprocessingml.document" "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" "application/vnd.openxmlformats-officedocument.presentationml.presentation" "application/msword" "application/vnd.ms-excel" "application/vnd.ms-powerpoint" "application/vnd.oasis.opendocument.text" "application/vnd.oasis.opendocument.spreadsheet" "application/vnd.oasis.opendocument.presentation" "text/rtf" "application/x-mobipocket-ebook" ]; }; }