nixers
Share your file-opener script - Printable Version
+- nixers (https://nixers.net)
+-- Forum: Development & Graphics (https://nixers.net/Forum-Development-Graphics)
+--- Forum: Programming On Unix (https://nixers.net/Forum-Programming-On-Unix)
+--- Thread: Share your file-opener script (/Thread-Share-your-file-opener-script)


Share your file-opener script - seninha - 30-05-2020

Most of us have an handy script for opening files and/or links given as arguments. This is, sometimes, one of our most used scripts. Use this thread to share your file-opener or link-opener scripts and steal ideas from others.

Here is mine, I call it xopen.

Code:
#!/bin/sh
# xopen: open file with proper command; use file in $MIMEFILE as rules file
# this file in public domain

usage() {
    echo "usage: xopen [-c mimefile] filename" >&2
    exit 1
}

# get mimetype of a file using the file(1) utility
getfilemime() {
    file -ib "$@" | cut -d';' -f1
}

# get lowercase extension of a file
getextension() {
    echo "${1##*.}" | tr '[:upper:]' '[:lower:]'
}

# get mimetype of a url
geturlmime() {
    protocol=$(printf "%s" "$@" | sed 's/^\([a-zA-Z]\+\):.*/\1/')

    case "$protocol" in
    http|https)
        echo text/html
        ;;
    magnet)
        echo application/x-bittorrent
        ;;
    irc)
        echo x-scheme-handler/irc
        ;;
    esac

    unset protocol
}

# get command to open file or url
getcmd() {
    while read -r line
    do
        line=${line%%#*}                # remove comments
        [ -z "$line" ] && continue      # ignore blank lines

        pattern="$(echo $line | cut -s -d: -f1 | sed -E 's/[     ]*$//; s/\|/ /g')"
        cmd="$(echo $line | cut -s -d: -f2 | sed -E 's/^[     ]*//')"
        cmd="$(eval echo $cmd)"

        # using case for matching patterns to avoid forking
        for i in $pattern
        do
            case $1 in
            $i) echo "$cmd" && return ;;
            esac
        done
    done < "$MIMEFILE"
}

# execute command $1 to open file or url $2
xopen() {
    trap "" 1 15
    echo xopen: opening $search with $1 >&2
    exec $1 "${2}" &
}

while getopts 'c:' c
do
    case "$c" in
    c)
        MIMEFILE="$OPTARG"
        ;;
    *)
        usage
        ;;
    esac
done
shift $((OPTIND -1))

[ "$#" -ne 1 ] && usage

# test whether MIMEFILE is not set
[ -z "$MIMEFILE" ] && echo 'xopen: $MIMEFILE is not set' >&2 && exit 1

# get mimetype and file extension
if [ -e "$@" ];
then            # it's a file
    mime=$(getfilemime "$@")
    extension=$(getextension "$@")
else            # it's a url
    mime=$(geturlmime "$@")
fi
[ -z "$extension$mime" ] && echo "xopen: unknown file or url type" >&2 && exit 1

# get command to open file or url
cmd=$(getcmd "$extension")              # try first to open by file extension
[ -z "$cmd" ] && cmd=$(getcmd "$mime")  # then try to open by mimetype
[ -z "$cmd" ] && echo "xopen: cannot find an command to open $@ ($mime)" >&2 && exit 1

# open file or url with $cmd
xopen "$cmd" "$@"

It gets its configuration from a file specified in the environment variable $MIMEFILE (or after the -c option). Each line in this file is composed by a mimetype or a file extension followed by a colon, followed by the command that opens a file with that mimetype or extension. Here is my $MIMEFILE:

Code:
# web
text/html:  palemoon

# text
text/*:                     $TERMCMD -e $EDITOR
application/x-empty:        $TERMCMD -e $EDITOR
application/x-shellscript:  $TERMCMD -e $EDITOR
inode/x-empty:              $TERMCMD -e $EDITOR
inode/directory:            $TERMCMD -e fm

# Docs
application/pdf:        zathura
application/postscript: zathura
application/epub*:      zathura
image/*djvu:            zathura

# media
application/octet-stream: mpv
video/*:                  mpv
audio/*:                  mpv

# image
image/*:                  sxiv

# Man pages
0|1|2|3|4|5|6|7: $TERMCMD -e man

Now share yours!


RE: Share your file/link-opener script - z3bra - 31-05-2020

Mine is self-contained, though I like your way to use the mailcap entry… I'll look this out later.
I cleaned up mine a bit. The cool stuff about it (I think) is that you can pipe data to it and open it. Not only URIs:

Code:
curl -s 'https://random.tld/image.png' | plumb -s

This would cache the file locally, and open it with the according mime entry.
Here is the full script:

Code:
#!/bin/sh
#
# open things from uri

cachedir=$HOME/.cache/plumber

usage() {
    echo "usage: $(basename $0) [-h] [uri]" >&2
}

peekmime() {
    curl -sSfL "$1" | cut -b-16 | file -ib - | cut -d\; -f1
}

# return a uri to a local file (download if necessary)
localuri() {
    local="$1"
    if [ ! -f "$1" ]; then
        tmp=$(mktemp)
        curl -o $tmp -sSfL "$1"
        local=$(cachefile "$tmp" "${mime##*/}")
        rm $tmp
    fi
    printf '%s\n' "$local"
}

# copy file to cache
cachefile() {
    mkdir -p $cachedir
    hash=$(sha256sum "$1"|cut -d' ' -f1)
    cp "$1" $cachedir/${hash}.$2
    printf '%s/%s.%s\n' "$cachedir" "$hash" "$2"
}

# prompt for a command to open uri
prompt() {
    dmenu_path | dmenu -p "$1" -l 8
}

clip="$(xsel -o 2>/dev/null)"

while getopts "hs" OPT; do
    case $OPT in
    s) slurp=$(mktemp -p $cachedir) ;;
    h) usage; exit 0 ;;
    *) usage; exit 1 ;;
    esac
done
shift $((OPTIND - 1))

# fallback to clipboard when not uri given
uri="${1:-$clip}"

# special arg "-" read uri(s) from stdin
if [ "$uri" = "-" ]; then
    cat | xargs -P$(nproc) -n1 $0
fi

# can read file _content_ from stdin, then process it
if [ -n "$slurp" ]; then
    cat > $slurp
    uri="$slurp"
fi

[ -z "$uri" ] && exit 1

if [ -f "$uri" ]; then
    mime=$(file -ib "$uri" | cut -d\; -f1)
else
    proto="${uri%%:*}"
    case $proto in
    mailto)     mime='application/x-mail' ;;
    magnet)     mime='application/x-bittorrent' ;;
    *)          mime="$(peekmime $uri)" ;;
    esac
fi

if [ -n "$slurp" ]; then
    uri="$(cachefile $slurp ${mime##*/})"
    rm "$slurp"
fi

case "$mime" in
    text/html) exec firefox "$uri" ;;
    video/*)   exec mplayer -cache 512 "$uri" ;;
    image/gif) exec mplayer -loop 0 $(localuri "$uri") ;;
    image/*)   exec meh $(localuri "$uri") ;;
    text/*)    exec st -e less $(localuri "$uri") ;;
    application/x-mail) exec st -e mutt $uri ;;
    application/x-bittorrent) exec st -e rtorrent $uri ;;
    *) exec $(prompt) "$uri" ;;
esac



RE: Share your file/link-opener script - venam - 31-05-2020

I rely on the freedesktop utility xdg-open as it already has full integration with mime types and desktop files. I kind of pointed it a bit in this discussion about default programs.

So what I usually do is xdg-open, and if it doesn't call the program I want then I can switch it using mimeopen -a. In the case where my program isn't listed, I create a desktop file in ~/.local/share/applications, then update-desktop-database. Most of the time, this solves my issues, otherwise I can dive into adding my own mimetype in ~/.local/share/mime/application.


RE: Share your file-opener script - jkl - 10-02-2021

Almost on-topic: In a C++ software of mine (which I really should develop further... some day), I wrote a function to open a text file with the default editor. I would guess that, if one removes the VISUAL/EDITOR checks, it fulfills this thread’s needs as well.

Note that sanitizing the filename needs to be done beforehand. Better don’t make this function publicly callable. :)

Code:
inline bool openWithEditor(const char* filename) {
    // Opens <filename> in your default editor.
#ifdef _WIN32
    // Windows version, using the Windows API.
    return reinterpret_cast<int>(ShellExecuteA(NULL, "open", filename, NULL, NULL, SW_SHOW)) > 32;
#else
    // Other system, other ways...
    string editor = "";

    if (getenv("VISUAL") != NULL) {
        editor = getenv("VISUAL");
    }
    else if (getenv("EDITOR") != NULL) {
        editor = getenv("EDITOR");
    }
    else {
#ifdef __linux__
        editor = "xdg-open";
#else
        // No standard editor found. Sorry!
        return false;
#endif
    }

    return system(string(editor + " \"" + filename + "\"").c_str()) == 0;
#endif
}



RE: Share your file-opener script - neeasade - 13-02-2021

Here is my current "go to what I'm looking at" emacs function: https://github.com/neeasade/emacs.d/blob/001b6d956373a436ad5370dd9f71150548324546/lisp/trees/follow.el#L54-L60

The goal is to handle various fallbacks, through org links, files, urls, and code definitions.


RE: Share your file-opener script - venam - 07-03-2022

There's a discussion on lobsters related to this. An interesting custom solution is this one from vermaden.