Last active
March 21, 2026 09:22
-
-
Save megamit/fe78dfb58214b5b645f3b1a255a31498 to your computer and use it in GitHub Desktop.
Script to check if a torrent contains a file that matches a pattern
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Usage: check-pattern <torrent-file> <pattern> | |
| # The belolw benparse and bp_parse functions are taken exactly from the TorrentParser | |
| # script at https://mywiki.wooledge.org/TorrentParser, which is unlicensed. | |
| # Full credit to the original author, who is not me. I have only copied the code and | |
| # added a small wrapper around it to check for a pattern in the torrent file. | |
| # TORRENT PARSER START | |
| export LC_ALL=C | |
| if [[ $# -ne 2 ]]; then | |
| echo "Usage: $0 <torrent-file> <pattern>" >&2 | |
| echo "Check if any files in the torrent match the given pattern" >&2 | |
| echo "Returns 0 if pattern matches, non-zero if no matches" >&2 | |
| exit 1 | |
| fi | |
| torrent_file="$1" | |
| pattern="$2" | |
| # Global associative array for torrent data | |
| declare -A ben | |
| # Filename ($1) | |
| # Results go into global associative array ben | |
| benparse() { | |
| local data skip p max | |
| [[ -r $1 ]] || { echo "cannot read file '$1'"; return 1; } | |
| IFS= read -rd '' data < <(tr \\0 \\1 <"$1") | |
| max=${#data} | |
| # Begin parsing file at offset 0, namespace "" | |
| bp_parse 0 "" | |
| } | |
| # Starting offset ($1), starting namespace ($2) | |
| # Uses global AA ben, module variable data | |
| # Return parsed data in module var p | |
| # Return total char length of parsed data in module var skip | |
| bp_parse() { | |
| (($1 >= max)) && return | |
| case "${data:$1:1}" in | |
| d) | |
| # Data dictionary, terminated by "e". Get pairs. | |
| local i=$1 j=$(($1 + 1)) key value | |
| while ((j < max)) && [[ ${data:j:1} != e ]]; do | |
| bp_parse $j "$2." | |
| key=$p | |
| ((j+=skip)) | |
| bp_parse $j "$2.$key" | |
| value=$p | |
| ((j+=skip)) | |
| [[ $value ]] && ben["$2.$key"]=$value | |
| done | |
| p="" # We populate the AA ourselves, rather than passing data back | |
| skip=$((j-i+1)) | |
| ;; | |
| i) | |
| # Integer, terminated by "e" | |
| local i=$1 j=$(($1 + 1)) | |
| while [[ ${data:j:1} != e ]]; do | |
| ((j++)) | |
| done | |
| p=${data:i+1:j-i-1} | |
| skip=$((j-i+1)) | |
| ;; | |
| l) | |
| # List, concatenated elements, terminated by "e" | |
| local i=$1 j=$(($1 + 1)) k=0 value | |
| while [[ ${data:j:1} != e ]]; do | |
| bp_parse $j "$2.$k" | |
| [[ $p ]] && ben["$2.$k"]=$p | |
| ((k++, j+=skip)) | |
| done | |
| p="" | |
| skip=$((j-i+1)) | |
| ;; | |
| *) | |
| # String, length-prefixed (integer, colon). Get the length first. | |
| local n n_len | |
| bp_getnum $1 | |
| n_len=${#n} | |
| p=${data:$1+n_len+1:n} | |
| skip=$((n_len+1+n)) | |
| ;; | |
| esac | |
| } | |
| # Find an integer in data, beginning at offset ($1) | |
| # Return value in upstream variable n | |
| bp_getnum() { | |
| local i=$1 j=$1 | |
| while [[ ${data:j:1} = [[:digit:]-] ]]; do | |
| ((j++)) | |
| done | |
| n=${data:i:j-i} | |
| } | |
| # TORRENT PARSER END | |
| # Parse the torrent file | |
| benparse "$torrent_file" | |
| # Check if any file paths match the pattern | |
| found_match=false | |
| # Iterate through all keys in the associative array | |
| for key in "${!ben[@]}"; do | |
| # Look for file path keys (e.g., .info.files.0.path.0) | |
| if [[ $key =~ \.info\.files\.[0-9]+\.path\.[0-9]+$ ]]; then | |
| filename="${ben[$key]}" | |
| # Check if filename matches the pattern (using bash pattern matching) | |
| if [[ $filename == $pattern ]]; then | |
| echo "Match found: $filename" | |
| found_match=true | |
| fi | |
| fi | |
| done | |
| # Handle single-file torrents (where the filename is in .info.name) | |
| if [[ -n "${ben['.info.name']}" ]]; then | |
| filename="${ben['.info.name']}" | |
| if [[ $filename == $pattern ]]; then | |
| echo "Match found: $filename" | |
| found_match=true | |
| fi | |
| fi | |
| # Exit with appropriate code | |
| if [[ $found_match == true ]]; then | |
| exit 1 # Match found | |
| else | |
| exit 0 # No match found | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment