diff options
author | Joey Hess <joeyh@joeyh.name> | 2014-12-11 18:09:44 -0400 |
---|---|---|
committer | Joey Hess <joeyh@joeyh.name> | 2014-12-11 18:09:44 -0400 |
commit | 0a26abf0ea0f19deb2e318e574bcbdc2f2f4d79d (patch) | |
tree | 531fcbf789b3d67fd43a372f851c0c76db7388ed /doc/special_remotes | |
parent | 7efc177f1a75cfdccb08cc195cbca3f880de59ad (diff) |
add working external special remote for torrents
Not IMHO good enough quality to be more than an example, but it does work!
Diffstat (limited to 'doc/special_remotes')
-rw-r--r-- | doc/special_remotes/external.mdwn | 8 | ||||
-rwxr-xr-x | doc/special_remotes/external/git-annex-remote-torrent | 191 |
2 files changed, 197 insertions, 2 deletions
diff --git a/doc/special_remotes/external.mdwn b/doc/special_remotes/external.mdwn index d96999693..010f2a17b 100644 --- a/doc/special_remotes/external.mdwn +++ b/doc/special_remotes/external.mdwn @@ -14,14 +14,18 @@ It's not hard! * Install it in PATH. * When the user runs `git annex initremote foo type=external externaltype=$bar`, it will use your program. +* See [[design/external_special_remote_protocol]] for what the program + needs to do. There's an example at the end of this page. * If things don't seem to work, pass `--debug` and you'll see, amoung other things, a transcript of git-annex's communication with your program. * If you build a new special remote, please add it to the list of [[special_remotes]]. +Here's an example of using an external special remote to add torrent +support to git-annex: [[external/git-annex-remote-torrent]] + Here's a simple shell script example, which can easily be adapted to run whatever commands you need. Or better, re-written in some better -language of your choice. See [[design/external_special_remote_protocol]] -for the details. +language of your choice. [[!inline pages="special_remotes/external/example.sh" feeds=no]] diff --git a/doc/special_remotes/external/git-annex-remote-torrent b/doc/special_remotes/external/git-annex-remote-torrent new file mode 100755 index 000000000..4f5e62a90 --- /dev/null +++ b/doc/special_remotes/external/git-annex-remote-torrent @@ -0,0 +1,191 @@ +#!/bin/sh +# This is a demo git-annex external special remote program, +# which adds basic torrent download support to git-annex. +# +# Uses aria2c. Also needs the original bittorrent (or bittornado) for the +# btshowmetainfo command. +# +# Install in PATH as git-annex-remote-torrent +# +# Enable remote by running: +# git annex initremote torrent type=external encryption=none externaltype=torrent +# git annex untrust torrent +# +# Copyright 2014 Joey Hess; licenced under the GNU GPL version 3 or higher. + +set -e + +# This program speaks a line-based protocol on stdin and stdout. +# When running any commands, their stdout should be redirected to stderr +# (or /dev/null) to avoid messing up the protocol. +runcmd () { + "$@" >&2 +} + +# Gets a VALUE response and stores it in $RET +getvalue () { + read resp + # Tricky POSIX shell code to split first word of the resp, + # preserving all other whitespace + case "${resp%% *}" in + VALUE) + RET="$(echo "$resp" | sed 's/^VALUE \?//')" + ;; + *) + RET="" + ;; + esac +} + +# Get a list of all known torrent urls for a key, +# storing it in a temp file. +geturls () { + key="$1" + tmp="$2" + + echo GETURLS "$key" + getvalue + while [ -n "$RET" ]; do + if istorrent "$RET"; then + echo "$RET" >> "$tmp" + fi + getvalue + done +} + +# Does the url end in .torrent? +# Note that we use #N on the url to indicate which file +# from a multi-file torrent is wanted. +istorrent () { + echo "$1" | egrep -q "\.torrent(#.*)?$" +} + +# Download a single file from a torrent. +# +# Note: Does not support resuming interrupted transfers. +# Note: Does not feed progress info back to git-annex, and since +# the destination file is only populated at the end, git-annex will fail +# to display a progress bar for this download. +downloadtorrent () { + torrent="$1" + n="$2" + dest="$3" + + tmpdir="$(mktemp -d)" + if ! runcmd aria2c --select-file="$n" "$torrent" -d "$tmpdir"; then + false + fi + + # aria2c will create part of the directory structure + # contained in the torrent. It may download parts of other files + # in addition to the one we asked for. So, we need to find + # out the filename we want, and look for it. + wantdir="$(btshowmetainfo "$torrent" | grep "^directory name: " | sed "s/^directory name: //")" + wantfile="$(btshowmetainfo "$tmp" | grep '^ ' | sed 's/^ //' | head -n "$n" | tail -n 1 | sed 's/ ([0-9]*)$//')" + if [ -e "$tmpdir/$wantdir/$wantfile" ]; then + mv "$tmpdir/$wantdir/$wantfile" "$dest" + rm -rf "$tmpdir" + else + rm -rf "$tmpdir" + false + fi +} + +# This has to come first, to get the protocol started. +echo VERSION 1 + +while read line; do + set -- $line + case "$1" in + INITREMOTE) + echo INITREMOTE-SUCCESS + ;; + PREPARE) + echo PREPARE-SUCCESS + ;; + CLAIMURL) + url="$2" + if istorrent "$url"; then + echo CLAIMURL-SUCCESS + else + echo CLAIMURL-FAILURE + fi + ;; + CHECKURL) + url="$2" + # List contents of torrent. + tmp=$(mktemp) + if ! runcmd curl -o "$tmp" "$url"; then + echo CHECKURL-FAILURE + else + oldIFS="$IFS" + IFS=" +" + printf "CHECKURL-MULTI" + n=0 + for l in $(btshowmetainfo "$tmp" | grep '^ ' | sed 's/^ //'); do + # Note that the file cannot contain spaces. + file="$(echo "$l" | sed 's/ ([0-9]*)$//' | sed 's/ /_/g')" + size="$(echo "$l" | sed 's/.* (\([0-9]*\))$/\1/')" + n=$(expr $n + 1) + printf " $url#$n $size $file" + done + printf "\n" + IFS="$oldIFS" + fi + rm -f "$tmp" + ;; + TRANSFER) + key="$3" + file="$4" + case "$2" in + STORE) + runcmd echo "upload not supported" + echo TRANSFER-FAILURE STORE "$key" + ;; + RETRIEVE) + urltmp=$(mktemp) + geturls "$key" "$urltmp" + url="$(head "$urltmp")" || true + rm -f "$urltmp" + if [ -z "$url" ]; then + echo TRANSFER-FAILURE RETRIEVE "$key" "no known torrent urls for this key" + else + tmp=$(mktemp) + if ! runcmd curl -o "$tmp" "$url"; then + echo TRANSFER-FAILURE RETRIEVE "$key" "failed downloading torrent file from $url" + else + filenum="$(echo "$url" | sed 's/.*#\(\d*\)/\1/')" + if downloadtorrent "$tmp" "$filenum" "$file"; then + echo TRANSFER-SUCCESS RETRIEVE "$key" + else + echo TRANSFER-FAILURE RETRIEVE "$key" "failed to download torrent contents from $url" + fi + fi + rm -f "$tmp" + fi + ;; + esac + ;; + CHECKPRESENT) + key="$2" + # Let's just assume that torrents are always present + # for simplicity. + echo CHECKPRESENT-SUCCESS "$key" + ;; + REMOVE) + key="$2" + # Remove all torrent urls for the key. + tmp=$(mktemp) + geturls "$key" "$tmp" + for url in $(cat "$tmp"); do + echo SETURLMISSING "$key" "$url" + done + rm -f "$tmp" + echo REMOVE-SUCCESS "$key" + ;; + *) + echo UNSUPPORTED-REQUEST + ;; + esac +done |