sfeed_mastodon 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #!/bin/sh
  2. #―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
  3. # Name: sfeed_mastodon
  4. # Desc: Post feed data from sfeed to the fediverse.
  5. # Reqs: curl, xargs
  6. # Date: 2023-11-16
  7. # Lisc: GPLv3
  8. # Auth: @jadedctrl@jam.xwx.moe
  9. #―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
  10. # Print a friendly usage message.
  11. usage() {
  12. echo "usage: $(basename $0) [-h] [-a FEDI_AUTH] SERVER_URL"
  13. echo "Posts sfeed(1) feed data from stdin to Mastodon-compatible servers."
  14. echo ""
  15. echo " -h print this message and exit"
  16. echo " -a the authorization token for your account"
  17. echo " -s the scope for posts, one of: public/unlisted/private/direct"
  18. echo " -t template for post contents"
  19. echo ""
  20. echo "To find your authorization token, you can snoop through request headers in"
  21. echo "your web-browser. In Firefox, this can be done through:"
  22. echo ' Developer Tools (F12) → Network → Headers'
  23. echo 'Look for your $FEDI_AUTH value in the Authorization header like so:'
  24. echo ' Authorization: Bearer $FEDI_AUTH'
  25. echo 'Either place this value in your $FEDI_AUTH environment variable, or pass it'
  26. echo "with -a."
  27. echo ""
  28. echo "The template (-t) is an HTML value for this script’s post format."
  29. echo "Post-related variables go within {{double-braces}}, and the following"
  30. echo "variables are recognized: title, url, desc, desc_short, unix_date."
  31. echo "By default, the template used is:"
  32. echo " <b>{{title}}</b><br>{{url}}<br><br><blockquote>{{desc_short}}</blockquote>"
  33. }
  34. # Deescape a URL-escaped string (percent-encoded), passed over stdin.
  35. url_deescape() {
  36. sed 's@+@ @g;s@%@\\x@g' \
  37. | xargs -0 printf "%b"
  38. }
  39. # Takes a post’s contents and create the corresponding client-API JSON.
  40. post_json() {
  41. local message_text="$1"
  42. printf '{ "content_type": "text/html", "visibility": "%s",' "$FEDI_SCOPE"
  43. printf '"status": "%s" }\n' "$message_text"
  44. }
  45. # Post a status with HTML content to the given Mastodon-compatible server.
  46. post_status() {
  47. local server="$1"
  48. local auth_token="$2"
  49. local message_text="$3"
  50. curl --request POST \
  51. --header "Authorization: Bearer $auth_token" \
  52. --header "Content-Type: application/json" \
  53. --data "$(post_json "$message_text" | tr -d '\n')" \
  54. "${server}/api/v1/statuses"
  55. }
  56. # Print an sfeed post line as per $TEMPLATE, with the following variables:
  57. # {{title}}, {{unix_date}}, {{url}}, {{desc}}, {{desc_short}}
  58. sfeed_post_text() {
  59. local sfeed_line="$1"
  60. local unix_date="$(echo "$line" | awk --field-separator '\t' '{print $1}')"
  61. local title="$(echo "$line" | awk --field-separator '\t' '{print $2}')"
  62. local url="$(echo "$line" | awk --field-separator '\t' '{print $3}' | url_deescape)"
  63. local desc="$(echo "$line" | awk --field-separator '\t' '{print $4}')"
  64. local desc_short="$(echo "$desc" | head -c250)"
  65. # Show that the description was truncated.
  66. if test "$(echo "$desc_short" | wc -c)" -gt 250; then
  67. desc_short="$desc_short […]"
  68. fi
  69. if test -z "$title"; then
  70. title="$url"
  71. fi
  72. # If there is nothing to post, then don’t stdout anything.
  73. if test -z "$url"; then
  74. return
  75. fi
  76. printf "$TEMPLATE" \
  77. | tr -d '|' \
  78. | sed "s|{{title}}|$title|g" \
  79. | sed "s|{{unix_date}}|$unix_date|g" \
  80. | sed "s|{{url}}|$url|g" \
  81. | sed "s|{{desc}}|$desc|g" \
  82. | sed "s|{{desc_short}}|$desc_short|g" \
  83. | sed 's|\\n||g' \
  84. | sed 's|"|\\"|g' \
  85. | tr -d ' \n'
  86. }
  87. # Post an sfeed feed entry, by line, to a Mastodon-compatible fedi server.
  88. post_sfeed_line() {
  89. local server="$1"
  90. local auth="$2"
  91. local line="$3"
  92. local message_text="$(sfeed_post_text "$line")"
  93. if test -n "$line" -a -n "$message_text"; then
  94. post_status "$server" "$auth" "$message_text"
  95. fi
  96. }
  97. TEMPLATE='<b>{{title}}</b><br>{{url}}<br><br><blockquote>{{desc_short}}</blockquote>'
  98. while getopts 'ha:t:' arg; do
  99. case $arg in
  100. h)
  101. usage
  102. exit 0
  103. ;;
  104. s)
  105. FEDI_SCOPE="$OPTARG"
  106. ;;
  107. a)
  108. FEDI_AUTH="$OPTARG"
  109. ;;
  110. t)
  111. TEMPLATE="$OPTARG"
  112. ;;
  113. esac
  114. done
  115. shift $((OPTIND-1))
  116. SERVER_URL="$1"
  117. if test -z "$FEDI_AUTH"; then
  118. 1>&2 echo 'You need to set the environment variable $FEDI_AUTH!'
  119. 1>&2 echo 'You can find your auth key by examining the "Authentication: Bearer" header'
  120. 1>&2 echo "used in requests by your server's web-client."
  121. 1>&2 echo 'In Firefox, F12→Network.'
  122. 1>&2 echo ""
  123. exit 2
  124. fi
  125. if test -z "$SERVER_URL"; then
  126. 1>&2 echo "No server specified!"
  127. 1>&2 echo "Make sure to provide a server base URL (like https://fedi.server) as the last argument."
  128. 1>&2 echo ""
  129. 1>&2 usage
  130. exit 3
  131. fi
  132. if test -z "$FEDI_SCOPE"; then
  133. FEDI_SCOPE="public"
  134. fi
  135. IFS="
  136. "
  137. while read -r line; do
  138. post_sfeed_line "$SERVER_URL" "$FEDI_AUTH" "$line"
  139. done