Skip to content

Instantly share code, notes, and snippets.

@paul-chambers
Last active April 1, 2025 12:55

Revisions

  1. paul-chambers revised this gist Nov 3, 2023. 2 changed files with 18 additions and 4 deletions.
    16 changes: 12 additions & 4 deletions torrent-complete.sh → torrent-complete
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,11 @@
    # for qBittorrent, enable 'Run external program on torrent completion' under 'Downloads' in the options dialog.
    # in the text field, enter:
    #
    # <path to>/torrent-complete.sh "%K" "%N" "%D"
    # <path to>/torrent-complete.sh "%K" "%N" "%D"
    #
    # %K: Torrent ID
    # %N: Torrent name
    # %D: Save path
    #
    # This provides the same parameters to this script that deluge provides to 'torrent complete' scripts.
    #
    @@ -37,8 +41,10 @@ torrentID=$1
    torrentName=$2
    torrentPath=$3

    srcDir="${HOME}/seeding"
    destDir="${HOME}/downloads"
    baseDir="/home/video"

    srcDir="${baseDir}/downloads"
    destDir="${baseDir}/toUpload"

    # either empty, or has a leading slash
    label="${torrentPath#$srcDir}"
    @@ -48,11 +54,12 @@ label="${torrentPath#$srcDir}"
    srcPath="${torrentPath}/${torrentName}"
    destPath="${destDir}${label}/${torrentName}"

    mkdir -p "~/logs/"
    echo "${torrentID} \"${torrentName}\" \"${torrentPath}\" ${label}" >> ~/logs/torrent-complete.log

    # Non-rar files are always hardlinked to the destination.

    # mkdir -p "${destPath}"
    mkdir -p "${destPath}${label}"
    cp -vrl -t "${destDir}${label}" "${srcPath}"

    # We may be given a file or a directory. If it's a directory, it may contain one or more rar files, in which case
    @@ -85,3 +92,4 @@ fi

    find "${destPath}" -name 'BDMV' -printf "%h\0" | xargs -0 --no-run-if-empty rm -r

    torrent-upload "${destpath}"
    6 changes: 6 additions & 0 deletions torrent-upload
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,6 @@
    #
    # torrent is ready to transfer to its final destination
    #
    # $1 = path to the torrent to transfer (a path to either a folder or file)
    #
    rclone move "$1" destination:
  2. paul-chambers revised this gist Jan 23, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion torrent-complete.sh
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@
    # for qBittorrent, enable 'Run external program on torrent completion' under 'Downloads' in the options dialog.
    # in the text field, enter:
    #
    # <path to>/torrent-complete.sh "%K" "%N" "%F"
    # <path to>/torrent-complete.sh "%K" "%N" "%D"
    #
    # This provides the same parameters to this script that deluge provides to 'torrent complete' scripts.
    #
  3. paul-chambers revised this gist Jan 18, 2023. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions torrent-complete.sh
    Original file line number Diff line number Diff line change
    @@ -63,6 +63,11 @@ then
    # multiple rar files may be found in subdirectories, so handle each one, preserving hierarchy
    find "${destPath}" -name '*.rar' -print0 | while read -d $'\0' rarFile
    do
    # unrar does not delete the rar file(s) after it's finished extracting. But it does tell us
    # on stdout which files it is parsing as it expands the archive. With a little sed magic,
    # we parse out those filenames from stdout and remember them. If unrar completes without
    # error, we then use that list to delete the file(s) that made up the rar archive.

    rarFileList=$(mktemp)
    path="$(dirname "${rarFile}")"
    unrar x -idp -o+ "${rarFile}" "${path}" | \
  4. paul-chambers revised this gist Jan 18, 2023. 1 changed file with 50 additions and 42 deletions.
    92 changes: 50 additions & 42 deletions torrent-complete.sh
    Original file line number Diff line number Diff line change
    @@ -1,74 +1,82 @@
    #!/bin/bash

    # Helper script for the Deluge torrent client
    # Intended to be run at torrent completion, using the 'torrent complete' event in the 'Execute' plugin.
    # Helper script for deluge or qBittorrent bittorrent clients
    # Intended to be run when the torrent download completes
    #
    # The basic idea is to hardlink the files that deluge has just finished downloading to a second directory.
    # This allows you to configure deluge to automatically pause or delete torrents when they reach a given seed ratio,
    # while also keeping a copy around for other reasons. For example, SyncThing could be used to propagate new downloads
    # to a remote machine to be processed further. When processing has finished, and the file is deleted/moved out of the
    # Syncthing folder, the remote Syncthing will propagate a deletion back to the original Synchting (on the machine
    # running deluge).
    # for qBittorrent, enable 'Run external program on torrent completion' under 'Downloads' in the options dialog.
    # in the text field, enter:
    #
    # The end result is that the lifetime of files involved both in deluge's seeding process and the 'forward to somewhere
    # else' process (e.g. via Syncthing) are decoupled, and can safely execute in parallel without needing to be aware of
    # what the other is doing. And yet the net result is that the files will still be cleaned up automagically when both
    # have finished their respective tasks.
    # <path to>/torrent-complete.sh "%K" "%N" "%F"
    #
    # Note: if you use the Label plugin, note that if you change the location where completed torrents should be moved to,
    # remember that each label may also have a location stored in each which will also be need to be updated.
    # This provides the same parameters to this script that deluge provides to 'torrent complete' scripts.
    #
    # Paul Chambers, Copyright (c) 2019.
    # The basic idea is to hardlink the files that the bittorrent client has just finished downloading to a second directory.
    # This allows you to configure qBittorrent to automatically pause or delete torrents when they reach a given seed ratio,
    # while also keeping a copy around for further processing.
    #
    # For example, SyncThing could be used to propagate new downloads to a remote machine to be processed further. When remote
    # processing has finished, and the file is deleted/moved out of the remote downloads folder, the remote Syncthing will
    # propagate a deletion back to the original Synchting (on the machine running this bittorrent client).
    #
    # This approach works equally well for rclone.
    #
    # The end result is that the lifetime of files involved both in the torrent client's seeding process and the 'transfer
    # to somewhere else' process (e.g. via reclone or Syncthing) are decoupled, and can safely execute in parallel without
    # needing to be aware of what the other is doing. And yet the net result is that the files will still be cleaned up
    # automagically when both have finished their respective tasks.
    #
    # Paul Chambers, Copyright (c) 2019-2023.
    #
    # Made available under the Creative Commons 'BY' license
    # https://creativecommons.org/licenses/by/4.0/
    #

    set -x

    torrentId=$1
    torrentID=$1
    torrentName=$2
    torrentPath=$3

    # echo "$torrentId $torrentName $torrentPath" >> /tmp/torrent-complete.log

    srcDir="/home/user/files/seeding"
    destDir="/home/user/files/complete"
    srcDir="${HOME}/seeding"
    destDir="${HOME}/downloads"

    # either empty, or has a leading slash
    label="${torrentPath#$srcDir}"

    # note that srcPath may be a file, not necessarily a
    # directory. Which means the same is true for destPath.
    # directory. In which case, the same is true for destPath.
    srcPath="${torrentPath}/${torrentName}"
    destPath="${destDir}${label}/${torrentName}"

    # We may be given a file or a directory. If it's a directory, it may contain one or more
    # rar files, in which case we unpack each one directly into the destination hierarchy.
    echo "${torrentID} \"${torrentName}\" \"${torrentPath}\" ${label}" >> ~/logs/torrent-complete.log

    # Non-rar files are always hardlinked to the destination.

    if [ -d "${srcPath}" ]
    # mkdir -p "${destPath}"
    cp -vrl -t "${destDir}${label}" "${srcPath}"

    # We may be given a file or a directory. If it's a directory, it may contain one or more rar files, in which case
    # we unpack each one directly into the destination hierarchy.

    if [ -d "${destPath}" ]
    then
    # multiple rar files may be found in subdirectories, so handle each one, preserving hierarchy
    find "${srcPath}" -name '*.rar' -print0 | while read -d $'\0' rarFile
    find "${destPath}" -name '*.rar' -print0 | while read -d $'\0' rarFile
    do
    rarFileList=$(mktemp)
    path="$(dirname "${rarFile}")"
    subDir="${path#$srcDir}"
    mkdir -p "${destDir}/${subDir}"
    unrar e -o+ "${rarFile}" "${destDir}/${subDir}"
    done

    # hardlink everything in the source directory (not rar-related), to the destination directory
    find "${srcPath}" -mindepth 1 ! -regex '.*\.r[a0-9][r0-9]' -print0 | while read -d $'\0' nonRarFile
    do
    path="$(dirname "${nonRarFile}")"
    subDir="${path#$srcDir}"
    mkdir -p "${destDir}/${subDir}"
    ln -v "${nonRarFile}" "${destDir}/${subDir}"
    unrar x -idp -o+ "${rarFile}" "${path}" | \
    sed -n -e "s/^Extracting from \(.*\.r[a0-9][r0-9]\)$/\1/ w ${rarFileList}" \
    && xargs --no-run-if-empty --arg-file="${rarFileList}" rm \
    && rm "${rarFileList}"
    done
    else
    # we were passed a single file, not a directory
    cp -la "${srcPath}" "${destPath}"
    fi

    # could unpack other archives here too, but it's preferable to decompress
    # any already-compressed archives at the remote machine, not here.
    # We could unpack other archives here too (e.g. .zip files), but it's preferable to transfer archives
    # to a remote machine in their compressed form, and decompress them there.

    # remove any files we don't need from {destPath}, to avoid wasting bandwidth transferring them.
    # this is a personal preference - adjust to taste

    find "${destPath}" -name 'BDMV' -printf "%h\0" | xargs -0 --no-run-if-empty rm -r

  5. paul-chambers revised this gist Sep 23, 2020. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions torrent-complete.sh
    Original file line number Diff line number Diff line change
    @@ -15,6 +15,9 @@
    # what the other is doing. And yet the net result is that the files will still be cleaned up automagically when both
    # have finished their respective tasks.
    #
    # Note: if you use the Label plugin, note that if you change the location where completed torrents should be moved to,
    # remember that each label may also have a location stored in each which will also be need to be updated.
    #
    # Paul Chambers, Copyright (c) 2019.
    #
    # Made available under the Creative Commons 'BY' license
  6. paul-chambers revised this gist Jan 18, 2020. 1 changed file with 22 additions and 12 deletions.
    34 changes: 22 additions & 12 deletions torrent-complete.sh
    Original file line number Diff line number Diff line change
    @@ -39,23 +39,33 @@ label="${torrentPath#$srcDir}"
    srcPath="${torrentPath}/${torrentName}"
    destPath="${destDir}${label}/${torrentName}"

    # echo "hardlink ${srcPath} to ${destPath}" >> /tmp/torrent-complete.log

    # We may be given a file or a directory. If it's a directory, it may contain a rar file,
    # in which case we should unpack the rar file (and its suplemental files) directly into
    # the destination. Non-rar files are always hardlinked to the destination.
    # We may be given a file or a directory. If it's a directory, it may contain one or more
    # rar files, in which case we unpack each one directly into the destination hierarchy.
    # Non-rar files are always hardlinked to the destination.

    if [ -d "${srcPath}" ]
    then
    mkdir -p "${destPath}"
    # search for rar files, and unrar any we find into the destination directory
    find "${srcPath}" -name "*.rar" -execdir unrar e -inul -o+ "{}" "${destPath}" ';'
    # hardlink everything in the source directory that's not a rar file to the destination directory
    find "${srcPath}" -mindepth 1 ! -regex '.*\.r[a0-9][r0-9]' -execdir cp -la "{}" "${destPath}" ';'
    # multiple rar files may be found in subdirectories, so handle each one, preserving hierarchy
    find "${srcPath}" -name '*.rar' -print0 | while read -d $'\0' rarFile
    do
    path="$(dirname "${rarFile}")"
    subDir="${path#$srcDir}"
    mkdir -p "${destDir}/${subDir}"
    unrar e -o+ "${rarFile}" "${destDir}/${subDir}"
    done

    # hardlink everything in the source directory (not rar-related), to the destination directory
    find "${srcPath}" -mindepth 1 ! -regex '.*\.r[a0-9][r0-9]' -print0 | while read -d $'\0' nonRarFile
    do
    path="$(dirname "${nonRarFile}")"
    subDir="${path#$srcDir}"
    mkdir -p "${destDir}/${subDir}"
    ln -v "${nonRarFile}" "${destDir}/${subDir}"
    done
    else
    # we were passed a file, not a directory
    # we were passed a single file, not a directory
    cp -la "${srcPath}" "${destPath}"
    fi

    # could unpack other archives here too, but it's preferable to decompress
    # any already-compressed archives at the remote machine, not here.
    # any already-compressed archives at the remote machine, not here.
  7. paul-chambers revised this gist Dec 20, 2019. No changes.
  8. paul-chambers revised this gist Dec 20, 2019. 1 changed file with 14 additions and 24 deletions.
    38 changes: 14 additions & 24 deletions torrent-complete.sh
    Original file line number Diff line number Diff line change
    @@ -21,51 +21,41 @@
    # https://creativecommons.org/licenses/by/4.0/
    #

    # set -x
    set -x

    torrentId=$1
    torrentName=$2
    torrentPath=$3

    # echo "$torrentId $torrentName $torrentPath" >> /tmp/torrent-complete.log

    srcDir="/home/user/files/downloads/seeding"
    destDir="/home/user/files/downloads/complete"
    srcDir="/home/user/files/seeding"
    destDir="/home/user/files/complete"

    label="${torrentPath#$srcDir}"

    # note that srcPath may be a file, not necessarily a directory.
    # Which means the same is true for destPath.
    # note that srcPath may be a file, not necessarily a
    # directory. Which means the same is true for destPath.
    srcPath="${torrentPath}/${torrentName}"
    destPath="${destDir}${label}/${torrentName}"

    # echo "hardlink ${srcPath} to ${destPath}" >> /tmp/torrent-complete.log

    # We may be given a file or a directory. If it's a directory, it may contain a rar file,
    # in which case we should unpack the rar file (and its suplemental files) directly into
    # the destination. Non-rar files are always hardlinked to the destination.

    if [ -d "${srcPath}" ]
    then
    # srcPath is a directory, so make sure destPath exists and is a directory,
    # then recursively link the *contents* of the srcPath directory into destPath
    mkdir -p "${destPath}"
    cp -la "${srcPath}/"* "${destPath}"
    # search for rar files, and unrar any we find into the destination directory
    find "${srcPath}" -name "*.rar" -execdir unrar e -inul -o+ "{}" "${destPath}" ';'
    # hardlink everything in the source directory that's not a rar file to the destination directory
    find "${srcPath}" -mindepth 1 ! -regex '.*\.r[a0-9][r0-9]' -execdir cp -la "{}" "${destPath}" ';'
    else
    # srcPath is a file, so just link it
    # we were passed a file, not a directory
    cp -la "${srcPath}" "${destPath}"
    fi

    #
    # if there are .rar files, unpack them
    # usually there is only one, but nothing prevents more than one..
    #

    for rarFile in `find "${destPath}" -name "*.rar"`
    do
    # echo "unrar ${rarFile}" >> /tmp/torrent-complete.log
    # if the unrar completes without error, unlink the .rar file and its companions.
    # the originals will live on in srcDir and continue to be seeded.
    cd "$(dirname ${rarFile})" \
    && unrar e -inul -o+ "${rarFile}" \
    && find . -type f \( -regex '.*\.r[0-9][0-9]' -o -name '*.rar' \) -delete
    done

    # could unpack other archives here too, but it's preferable to decompress
    # any already-compressed archives at the remote machine, not here.
  9. paul-chambers revised this gist Feb 23, 2019. 1 changed file with 44 additions and 15 deletions.
    59 changes: 44 additions & 15 deletions torrent-complete.sh
    Original file line number Diff line number Diff line change
    @@ -5,38 +5,67 @@
    #
    # The basic idea is to hardlink the files that deluge has just finished downloading to a second directory.
    # This allows you to configure deluge to automatically pause or delete torrents when they reach a given seed ratio,
    # while also keeping a copy around ofr other reasons. Personally I use SyncThing to propagate new downloads to
    # a remote machine, where they are processed and moved out of the Syncthing folder, which in turn propagates their
    # deletion back to the original machine running deluge.
    # while also keeping a copy around for other reasons. For example, SyncThing could be used to propagate new downloads
    # to a remote machine to be processed further. When processing has finished, and the file is deleted/moved out of the
    # Syncthing folder, the remote Syncthing will propagate a deletion back to the original Synchting (on the machine
    # running deluge).
    #
    # The upshot is that both deluge's seeding process and the 'forward to somewhere else' process (via Syncthing) can
    # execute in parallel, not needing to be aware of what the other is doing, yet the net result is that downloads are
    # cleaned up automagically when both have finished their respective tasks.
    # The end result is that the lifetime of files involved both in deluge's seeding process and the 'forward to somewhere
    # else' process (e.g. via Syncthing) are decoupled, and can safely execute in parallel without needing to be aware of
    # what the other is doing. And yet the net result is that the files will still be cleaned up automagically when both
    # have finished their respective tasks.
    #
    # Paul Chambers, Copyright (c) 2019.
    #
    # Made available under the Creative Commons 'BY' license
    # https://creativecommons.org/licenses/by/4.0/
    #

    # set -x

    torrentId=$1
    torrentName=$2
    torrentPath=$3

    # echo "$torrentId $torrentName $torrentPath" >> /tmp/torrent-complete.log

    srcDir="${torrentPath}/${torrentName}"
    destDir="/downloads/completed/${torrentName}"
    srcDir="/home/user/files/downloads/seeding"
    destDir="/home/user/files/downloads/complete"

    label="${torrentPath#$srcDir}"

    # note that srcPath may be a file, not necessarily a directory.
    # Which means the same is true for destPath.
    srcPath="${torrentPath}/${torrentName}"
    destPath="${destDir}${label}/${torrentName}"

    rarFile=`find "${srcDir}" -name "*.rar"`
    # echo "hardlink ${srcPath} to ${destPath}" >> /tmp/torrent-complete.log

    if [ -z "${rarFile}" ]
    if [ -d "${srcPath}" ]
    then
    cp -arl "${srcDir}" "${destDir}"
    # srcPath is a directory, so make sure destPath exists and is a directory,
    # then recursively link the *contents* of the srcPath directory into destPath
    mkdir -p "${destPath}"
    cp -la "${srcPath}/"* "${destPath}"
    else
    mkdir -p "${destDir}" \
    && cd "${destDir}" \
    && unrar e -inul -o+ "${rarFile}" \
    && find "${srcDir}" -type f ! \( -regex '.*\.r[0-9][0-9]' -o -name '*.rar' \) -exec ln "{}" "${destDir}/" ';'
    # srcPath is a file, so just link it
    cp -la "${srcPath}" "${destPath}"
    fi

    #
    # if there are .rar files, unpack them
    # usually there is only one, but nothing prevents more than one..
    #

    for rarFile in `find "${destPath}" -name "*.rar"`
    do
    # echo "unrar ${rarFile}" >> /tmp/torrent-complete.log
    # if the unrar completes without error, unlink the .rar file and its companions.
    # the originals will live on in srcDir and continue to be seeded.
    cd "$(dirname ${rarFile})" \
    && unrar e -inul -o+ "${rarFile}" \
    && find . -type f \( -regex '.*\.r[0-9][0-9]' -o -name '*.rar' \) -delete
    done

    # could unpack other archives here too, but it's preferable to decompress
    # any already-compressed archives at the remote machine, not here.
  10. paul-chambers revised this gist Jan 6, 2019. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions torrent-complete.sh
    Original file line number Diff line number Diff line change
    @@ -12,6 +12,12 @@
    # The upshot is that both deluge's seeding process and the 'forward to somewhere else' process (via Syncthing) can
    # execute in parallel, not needing to be aware of what the other is doing, yet the net result is that downloads are
    # cleaned up automagically when both have finished their respective tasks.
    #
    # Paul Chambers, Copyright (c) 2019.
    #
    # Made available under the Creative Commons 'BY' license
    # https://creativecommons.org/licenses/by/4.0/
    #

    torrentId=$1
    torrentName=$2
  11. paul-chambers created this gist Jan 6, 2019.
    36 changes: 36 additions & 0 deletions torrent-complete.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    #!/bin/bash

    # Helper script for the Deluge torrent client
    # Intended to be run at torrent completion, using the 'torrent complete' event in the 'Execute' plugin.
    #
    # The basic idea is to hardlink the files that deluge has just finished downloading to a second directory.
    # This allows you to configure deluge to automatically pause or delete torrents when they reach a given seed ratio,
    # while also keeping a copy around ofr other reasons. Personally I use SyncThing to propagate new downloads to
    # a remote machine, where they are processed and moved out of the Syncthing folder, which in turn propagates their
    # deletion back to the original machine running deluge.
    #
    # The upshot is that both deluge's seeding process and the 'forward to somewhere else' process (via Syncthing) can
    # execute in parallel, not needing to be aware of what the other is doing, yet the net result is that downloads are
    # cleaned up automagically when both have finished their respective tasks.

    torrentId=$1
    torrentName=$2
    torrentPath=$3

    # echo "$torrentId $torrentName $torrentPath" >> /tmp/torrent-complete.log

    srcDir="${torrentPath}/${torrentName}"
    destDir="/downloads/completed/${torrentName}"


    rarFile=`find "${srcDir}" -name "*.rar"`

    if [ -z "${rarFile}" ]
    then
    cp -arl "${srcDir}" "${destDir}"
    else
    mkdir -p "${destDir}" \
    && cd "${destDir}" \
    && unrar e -inul -o+ "${rarFile}" \
    && find "${srcDir}" -type f ! \( -regex '.*\.r[0-9][0-9]' -o -name '*.rar' \) -exec ln "{}" "${destDir}/" ';'
    fi