aboutsummaryrefslogtreecommitdiffstats
path: root/home/zaread.nix
blob: 487740a0afd73a87bf05292f170862cf63079884 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
{ 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
    MOBI_CMD="${pkgs.calibre}/bin/ebook-convert"
    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=""
    MOBI_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"
                    ;;
            "application/octet-stream" | \
                    "application/x-mobipocket-ebook")

                    case "$file" in
                    *.mobi)
                            # If the file is a mobi ebook we convert it using $MOBI_CMD.
                            file_converter="$MOBI_CMD"
                            ;;
                    esac
                    ;;
            "text/plain" | \
                    "text/x-c" | \
                    "text/x-objective-c" | \
                    "text/x-script.python" )
                    case "$file" in
                    *.md)
                            # If the file is a markdown we convert it using $MD_CMD.
                            file_converter="$MD_CMD"
                            ;;
                    *.typ)
                            file_converter="$TYPST_CMD"
                            ;;
                    esac
                    ;;
            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"
                            ;;
                    "$MOBI_CMD")
                            eval "$MOBI_CMD" "$MOBI_ARG" \""$directory/$file"\" \""$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"
      "text/csv"
      "application/x-mobipocket-ebook"
      "text/plain"
    ];
  };
}