Setting the file. One moment.
Convert · File Conversion · wshobson/agents · Skills Docs
ContentsBack to the top of the page Turborepo Caching
Python
Raw file
scripts/ convert.sh
Shell · 90 lines · 4 KB
12 IN = " ${1 :- } " ; TARGET = " ${2 :- } " ; OUT = " ${3 :- } "
13 if [ -z " $IN " ] || [ -z " $TARGET " ]; then
14 echo "usage: convert.sh <input-file> <target-format> [output-file]" >&2
15 exit 2
16 fi
17 [ -f " $IN " ] || { echo "error: input file not found: $IN " >&2 ; exit 2 ; }
18
19 SIZE = $( wc -c < " $IN " | tr -d ' ' )
20 if [ " $SIZE " -gt 25000000 ]; then
21 echo "error: file is $(( SIZE / 1048576 ))MB — free limit is 25MB. Get a free API key for larger files: https://changethisfile.com/docs/authentication" >&2
22 exit 3
23 fi
24
25 # Only allow plain format tokens (letters/digits), e.g. "pdf", "mp3". Reject
26 # anything else so TARGET can't smuggle path/JSON metacharacters downstream.
27 TARGET = $( printf '%s' " $TARGET " | tr '[:upper:]' '[:lower:]' | sed 's/^\.//' )
28 case " $TARGET " in
29 * [!a-z0-9] *| '' ) echo "error: invalid target format: ' $2 ' (use a plain extension like pdf, mp3, docx)" >&2 ; exit 2 ;;
30 esac
31 BASENAME = $( basename " $IN " )
32 SRC = $( printf '%s' "${ BASENAME ##* .}" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9' )
33 # Reject traversal AND absolute / home-relative paths in a USER-SUPPLIED output
34 # path — OUT is written with `curl -o`, so an unvalidated path could clobber
35 # arbitrary files. Only relative, non-traversing paths are accepted. (The
36 # auto-derived default below safely inherits the input file's own directory.)
37 if [ -n " $OUT " ]; then
38 case " $OUT " in
39 / *| ~ *|* ../ *|* /.. | .. ) echo "error: output path must be relative and must not contain '..': $OUT " >&2 ; exit 2 ;;
40 esac
41 fi
42 [ -z " $OUT " ] && OUT = "${ IN % . * }.${ TARGET }"
43
44 B64_FILE = $( mktemp )
45 REQ_FILE = $( mktemp )
46 RESP_FILE = $( mktemp )
47 trap 'rm -f "$B64_FILE" "$REQ_FILE" "$RESP_FILE"' EXIT
48
49 # Encode to a file (not a shell variable / argv) so multi-MB payloads never hit
50 # the OS per-argument limit. base64 -w0 is GNU; macOS base64 has no -w flag.
51 base64 -w0 < " $IN " > " $B64_FILE " 2> /dev/null || base64 < " $IN " | tr -d '\n' > " $B64_FILE "
52
53 # Build the JSON-RPC payload with jq so the filename (arbitrary user input) is
54 # escaped correctly — newlines, control chars, quotes, backslashes. Falls back
55 # to a strict printable-ASCII sanitization of the filename if jq is unavailable.
56 if command -v jq > /dev/null 2>&1 ; then
57 # --rawfile reads the base64 from a file, avoiding the ~128KB single-argument
58 # limit that `--arg b64 "$B64"` hits on inputs larger than ~96KB.
59 jq -n --rawfile b64 " $B64_FILE " --arg src " $SRC " --arg tgt " $TARGET " --arg fn " $BASENAME " \
60 '{jsonrpc:"2.0",id:1,method:"tools/call",params:{name:"convert_file",arguments:{base64_content:($b64|rtrimstr("\n")),source_format:$src,target_format:$tgt,filename:$fn}}}' \
61 > " $REQ_FILE "
62 else
63 # printf is a shell builtin, so the large payload here is not subject to argv
64 # limits; read it back from the encoded file.
65 B64 = $( cat " $B64_FILE " )
66 SAFE_FN = $( printf '%s' " $BASENAME " | tr -d '"\\' | LC_ALL = C tr -cd '[:print:]' )
67 printf '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"convert_file","arguments":{"base64_content":"%s","source_format":"%s","target_format":"%s","filename":"%s"}}}' \
68 " $B64 " " $SRC " " $TARGET " " $SAFE_FN " > " $REQ_FILE "
69 fi
70
71 HTTP_CODE = $( curl -sS --max-time 300 -o " $RESP_FILE " -w "%{http_code}" \
72 -X POST " $ENDPOINT " -H "Content-Type: application/json" --data-binary "@ $REQ_FILE " )
73
74 if [ " $HTTP_CODE " != "200" ]; then
75 echo "error: conversion service returned HTTP $HTTP_CODE : $( head -c 300 " $RESP_FILE ")" >&2
76 exit 4
77 fi
78
79 DOWNLOAD_URL = $( grep -o 'https://changethisfile.com/v1/jobs/download/[A-Za-z0-9_-]*' " $RESP_FILE " | head -1 || true )
80 if [ -z " $DOWNLOAD_URL " ]; then
81 # Surface the tool's error text (rate limit, unsupported route, etc.)
82 ERR = $( sed 's/\\n/ /g' " $RESP_FILE " | grep -o '"text":"[^"]*"' | head -1 | sed 's/^"text":"//; s/"$//' )
83 echo "error: ${ ERR :- unexpected response : $( head -c 300 " $RESP_FILE ")}" >&2
84 exit 5
85 fi
86
87 curl -sS --max-time 120 -o " $OUT " " $DOWNLOAD_URL "
88 [ -s " $OUT " ] || { echo "error: download produced an empty file" >&2 ; exit 6 ; }
89
90 echo " $OUT "