Initial backup 2026-02-17
This commit is contained in:
141
skills/freshrss-reader/scripts/freshrss.sh
Normal file
141
skills/freshrss-reader/scripts/freshrss.sh
Normal file
@@ -0,0 +1,141 @@
|
||||
#!/bin/bash
|
||||
# FreshRSS CLI - Query headlines from a FreshRSS instance
|
||||
# Uses Google Reader compatible API
|
||||
#
|
||||
# Requires environment variables:
|
||||
# FRESHRSS_URL - Your FreshRSS instance URL (e.g., https://freshrss.example.com)
|
||||
# FRESHRSS_USER - Your FreshRSS username
|
||||
# FRESHRSS_API_PASSWORD - Your FreshRSS API password (set in FreshRSS → Settings → Profile → API)
|
||||
#
|
||||
# Usage:
|
||||
# freshrss.sh headlines [--count N] [--hours N] [--category NAME] [--unread]
|
||||
# freshrss.sh categories
|
||||
# freshrss.sh feeds
|
||||
|
||||
set -e
|
||||
|
||||
# --- Config ---
|
||||
CONFIG_FILE="${FRESHRSS_CONFIG:-$HOME/.config/freshrss/config.json}"
|
||||
|
||||
# Load config from file if it exists
|
||||
if [[ -f "$CONFIG_FILE" ]]; then
|
||||
FRESHRSS_URL="${FRESHRSS_URL:-$(jq -r '.url // empty' "$CONFIG_FILE")}"
|
||||
FRESHRSS_USER="${FRESHRSS_USER:-$(jq -r '.user // empty' "$CONFIG_FILE")}"
|
||||
FRESHRSS_API_PASSWORD="${FRESHRSS_API_PASSWORD:-$(jq -r '.password // empty' "$CONFIG_FILE")}"
|
||||
fi
|
||||
|
||||
if [ -z "$FRESHRSS_URL" ] || [ -z "$FRESHRSS_USER" ] || [ -z "$FRESHRSS_API_PASSWORD" ]; then
|
||||
echo "Error: Required environment variables not set." >&2
|
||||
echo "Set FRESHRSS_URL, FRESHRSS_USER, and FRESHRSS_API_PASSWORD" >&2
|
||||
echo "Or configure $CONFIG_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
API_BASE="${FRESHRSS_URL}"
|
||||
|
||||
# --- Auth ---
|
||||
auth_login() {
|
||||
local RESPONSE
|
||||
RESPONSE=$(curl -s "${API_BASE}/accounts/ClientLogin?Email=${FRESHRSS_USER}&Passwd=${FRESHRSS_API_PASSWORD}")
|
||||
AUTH_TOKEN=$(echo "$RESPONSE" | grep "Auth=" | cut -d'=' -f2)
|
||||
if [ -z "$AUTH_TOKEN" ]; then
|
||||
echo "Error: Authentication failed" >&2
|
||||
echo "$RESPONSE" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
api_get() {
|
||||
local ENDPOINT="$1"
|
||||
curl -s -H "Authorization:GoogleLogin auth=${AUTH_TOKEN}" "${API_BASE}/reader/api/0/${ENDPOINT}"
|
||||
}
|
||||
|
||||
# --- Commands ---
|
||||
|
||||
cmd_categories() {
|
||||
auth_login
|
||||
api_get "tag/list?output=json" | jq -r '.tags[] | select(.id | contains("/label/")) | .id | split("/label/")[1]'
|
||||
}
|
||||
|
||||
cmd_feeds() {
|
||||
auth_login
|
||||
api_get "subscription/list?output=json" | jq -r '.subscriptions[] | "\(.title) [\(.categories[0].label // "uncategorized")]"'
|
||||
}
|
||||
|
||||
cmd_headlines() {
|
||||
local COUNT=20
|
||||
local HOURS=""
|
||||
local CATEGORY=""
|
||||
local UNREAD_ONLY=false
|
||||
local STREAM="reading-list"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--count) COUNT="$2"; shift 2 ;;
|
||||
--hours) HOURS="$2"; shift 2 ;;
|
||||
--category) CATEGORY="$2"; shift 2 ;;
|
||||
--unread) UNREAD_ONLY=true; shift ;;
|
||||
*) shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
auth_login
|
||||
|
||||
# Build stream URL
|
||||
local URL="stream/contents"
|
||||
if [ -n "$CATEGORY" ]; then
|
||||
URL="${URL}/user/-/label/${CATEGORY}"
|
||||
else
|
||||
URL="${URL}/user/-/state/com.google/reading-list"
|
||||
fi
|
||||
|
||||
URL="${URL}?output=json&n=${COUNT}"
|
||||
|
||||
# Add time filter
|
||||
if [ -n "$HOURS" ]; then
|
||||
local SINCE
|
||||
SINCE=$(date -v-${HOURS}H +%s 2>/dev/null || date -d "${HOURS} hours ago" +%s 2>/dev/null)
|
||||
if [ -n "$SINCE" ]; then
|
||||
URL="${URL}&ot=${SINCE}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Add unread filter
|
||||
if [ "$UNREAD_ONLY" = true ]; then
|
||||
URL="${URL}&xt=user/-/state/com.google/read"
|
||||
fi
|
||||
|
||||
local RESPONSE
|
||||
RESPONSE=$(api_get "$URL")
|
||||
|
||||
# Format output
|
||||
echo "$RESPONSE" | jq -r '
|
||||
.items[] |
|
||||
{
|
||||
title: .title,
|
||||
source: .origin.title,
|
||||
url: (.canonical[0].href // .alternate[0].href // ""),
|
||||
published: (.published | todate),
|
||||
categories: [.categories[] | select(contains("/label/")) | split("/label/")[1]]
|
||||
} |
|
||||
"[\(.published)] [\(.source)] \(.title)\n \(.url)\n Categories: \(.categories | join(", "))\n"
|
||||
' 2>/dev/null || echo "No articles found or error parsing response" >&2
|
||||
}
|
||||
|
||||
# --- Main ---
|
||||
COMMAND="${1:-headlines}"
|
||||
shift 2>/dev/null || true
|
||||
|
||||
case "$COMMAND" in
|
||||
headlines|news|latest) cmd_headlines "$@" ;;
|
||||
categories|cats) cmd_categories ;;
|
||||
feeds) cmd_feeds ;;
|
||||
*)
|
||||
echo "Usage: $0 {headlines|categories|feeds}" >&2
|
||||
echo "" >&2
|
||||
echo " headlines [--count N] [--hours N] [--category NAME] [--unread]" >&2
|
||||
echo " categories List all categories" >&2
|
||||
echo " feeds List all feeds" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user