#!/bin/sh # ╔═══════════════════════════════════════════════════════════════════╗ # ║ ⚡ CYBERFEED v0.1 - RSS Aggregator for OpenWrt/SecuBox ⚡ ║ # ║ Cyberpunk Social Feed Analyzer with Emoji Enhancement ║ # ║ Author: CyberMind.FR | License: MIT ║ # ╚═══════════════════════════════════════════════════════════════════╝ . /lib/functions.sh # === CONFIGURATION === CYBERFEED_DIR="/tmp/cyberfeed" CACHE_DIR="${CYBERFEED_DIR}/cache" OUTPUT_DIR="${CYBERFEED_DIR}/output" CONFIG_FILE="/etc/cyberfeed/feeds.conf" TEMPLATE_FILE="/usr/share/cyberfeed/template.html" MAX_ITEMS=20 CACHE_TTL=300 # Load UCI config load_config() { config_load cyberfeed config_get MAX_ITEMS main max_items 20 config_get CACHE_TTL main cache_ttl 300 config_get OUTPUT_DIR main output_dir "/tmp/cyberfeed/output" } # === CYBERPUNK EMOJI MAPPING === cyberpunk_emojify() { local text="$1" # Security/Hacking themes echo "$text" | sed -E ' s/(hack|breach|exploit|vulnerab)/\xf0\x9f\x94\x93\1/gi s/(secur|protect|defense|firewall)/\xf0\x9f\x9b\xa1\xef\xb8\x8f\1/gi s/(cyber|digital|virtual)/\xe2\x9a\xa1\1/gi s/(encrypt|crypto|cipher)/\xf0\x9f\x94\x90\1/gi s/(malware|virus|trojan)/\xe2\x98\xa0\xef\xb8\x8f\1/gi s/(alert|warning|danger)/\xe2\x9a\xa0\xef\xb8\x8f\1/gi s/(attack|threat|risk)/\xf0\x9f\x92\x80\1/gi s/(network|connect|link)/\xf0\x9f\x8c\x90\1/gi s/(server|cloud|data)/\xf0\x9f\x92\xbe\1/gi s/(code|program|script)/\xf0\x9f\x92\xbb\1/gi s/(linux|opensource|github)/\xf0\x9f\x90\xa7\1/gi s/(robot|automat|ai|machine)/\xf0\x9f\xa4\x96\1/gi s/(update|upgrade|patch)/\xf0\x9f\x93\xa1\1/gi s/(launch|deploy|release)/\xf0\x9f\x9a\x80\1/gi s/(new|annonce|breaking)/\xe2\x9c\xa8\1/gi s/(success|win|achieve)/\xf0\x9f\x8f\x86\1/gi s/(fail|error|bug)/\xf0\x9f\x90\x9b\1/gi s/(magic|mystiq|oracle)/\xf0\x9f\x94\xae\1/gi s/(energy|power|force)/\xe2\x9a\xa1\1/gi ' } # === RSS FETCHER === fetch_feed() { local url="$1" local name="$2" local cache_file="${CACHE_DIR}/${name}.xml" # Check cache freshness if [ -f "$cache_file" ]; then local file_time=$(stat -c %Y "$cache_file" 2>/dev/null || echo 0) local now=$(date +%s) local age=$((now - file_time)) if [ "$age" -lt "$CACHE_TTL" ]; then cat "$cache_file" return 0 fi fi # Fetch with wget (OpenWrt standard) wget -q -T 15 -O "$cache_file" "$url" 2>/dev/null if [ -f "$cache_file" ] && [ -s "$cache_file" ]; then cat "$cache_file" else rm -f "$cache_file" return 1 fi } # === RSS PARSER (Pure AWK for OpenWrt) === parse_rss() { local xml="$1" local source="$2" local category="$3" echo "$xml" | awk -v source="$source" -v category="$category" -v max="$MAX_ITEMS" ' BEGIN { RS="|" item_count=0 } { title="" link="" date="" desc="" # Extract title if (match($0, /]*>([^<]+)<\/title>/, arr)) title=arr[1] else if (match($0, /]*><\/title>/, arr)) title=arr[1] # Extract link if (match($0, /]*>([^<]+)<\/link>/, arr)) link=arr[1] else if (match($0, /]*href="([^"]+)"/, arr)) link=arr[1] # Extract date if (match($0, /([^<]+)([^<]+)([^<]+)]*>([^<]+)]*>([^<]+)]*>]+>/, "", desc) desc = substr(desc, 1, 280) printf "{\"title\":\"%s\",\"link\":\"%s\",\"date\":\"%s\",\"desc\":\"%s\",\"source\":\"%s\",\"category\":\"%s\"},", title, link, date, desc, source, category item_count++ } } ' } # === HTML GENERATOR === generate_html() { local json_file="$1" local output_file="${OUTPUT_DIR}/index.html" local timestamp=$(date '+%Y-%m-%d %H:%M:%S') local feed_count=$(grep -c '"title"' "$json_file" 2>/dev/null || echo 0) cat > "$output_file" << 'HTMLEOF' ⚡ CYBERFEED ⚡ Neural RSS Matrix

⚡ CYBERFEED ⚡

NEURAL RSS MATRIX INTERFACE

FEEDS: -- SYNC: --:--:-- STATUS: ONLINE
🔮

Awaiting Neural Feed Connection...

⚡ CYBERFEED v0.1 | Powered by CyberMind.FR | SecuBox Module ⚡

░▒▓ JACK IN TO THE MATRIX ▓▒░

HTMLEOF echo "$output_file" } # === STATUS === get_status() { local enabled=$(uci -q get cyberfeed.main.enabled || echo 0) local feed_count=0 local last_sync="never" local rssbridge_enabled=$(uci -q get cyberfeed.rssbridge.enabled || echo 0) local rssbridge_status="stopped" if [ -f "${OUTPUT_DIR}/feeds.json" ]; then feed_count=$(grep -c '"title"' "${OUTPUT_DIR}/feeds.json" 2>/dev/null || echo 0) last_sync=$(stat -c %Y "${OUTPUT_DIR}/feeds.json" 2>/dev/null || echo 0) fi if [ "$rssbridge_enabled" = "1" ]; then if pgrep -f "rss-bridge" >/dev/null 2>&1; then rssbridge_status="running" fi fi cat << EOF { "enabled": $enabled, "feed_count": $feed_count, "last_sync": $last_sync, "cache_ttl": $CACHE_TTL, "max_items": $MAX_ITEMS, "rssbridge_enabled": $rssbridge_enabled, "rssbridge_status": "$rssbridge_status" } EOF } # === SYNC FEEDS === sync_feeds() { load_config mkdir -p "$CACHE_DIR" "$OUTPUT_DIR" if [ ! -f "$CONFIG_FILE" ]; then echo '[]' > "${OUTPUT_DIR}/feeds.json" generate_html "${OUTPUT_DIR}/feeds.json" return 0 fi local json_items="[" local feed_count=0 while IFS='|' read -r name url type category || [ -n "$name" ]; do # Skip comments and empty lines case "$name" in ''|\#*) continue ;; esac [ -z "$category" ] && category="custom" echo "📡 Fetching: $name" >&2 raw_xml=$(fetch_feed "$url" "$name") if [ -n "$raw_xml" ]; then parsed=$(parse_rss "$raw_xml" "$name" "$category") if [ -n "$parsed" ]; then emojified=$(cyberpunk_emojify "$parsed") json_items="${json_items}${emojified}" feed_count=$((feed_count + 1)) fi fi done < "$CONFIG_FILE" # Remove trailing comma, close array json_items=$(echo "$json_items" | sed 's/,$//') json_items="${json_items}]" echo "$json_items" > "${OUTPUT_DIR}/feeds.json" generate_html "${OUTPUT_DIR}/feeds.json" >/dev/null # Create symlink for web access [ -L /www/cyberfeed/index.html ] || ln -sf "${OUTPUT_DIR}/index.html" /www/cyberfeed/index.html 2>/dev/null [ -L /www/cyberfeed/feeds.json ] || ln -sf "${OUTPUT_DIR}/feeds.json" /www/cyberfeed/feeds.json 2>/dev/null echo "" echo "╔═══════════════════════════════════════════════════════════╗" echo "║ ⚡ CYBERFEED SYNC COMPLETE ⚡ ║" echo "╠═══════════════════════════════════════════════════════════╣" printf "║ 📊 Feeds processed: %-36s ║\n" "$feed_count" echo "║ 📁 Output: /www/cyberfeed/ ║" echo "╚═══════════════════════════════════════════════════════════╝" } # === LIST FEEDS === list_feeds() { if [ ! -f "$CONFIG_FILE" ]; then echo "[]" return fi echo "[" local first=1 while IFS='|' read -r name url type category || [ -n "$name" ]; do case "$name" in ''|\#*) continue ;; esac [ "$first" = "1" ] || echo "," first=0 printf '{"name":"%s","url":"%s","type":"%s","category":"%s"}' \ "$name" "$url" "${type:-rss}" "${category:-custom}" done < "$CONFIG_FILE" echo "]" } # === ADD FEED === add_feed() { local name="$1" local url="$2" local type="${3:-rss}" local category="${4:-custom}" [ -z "$name" ] || [ -z "$url" ] && { echo '{"success":false,"error":"Name and URL required"}' return 1 } # Check if feed already exists if grep -q "^${name}|" "$CONFIG_FILE" 2>/dev/null; then echo '{"success":false,"error":"Feed already exists"}' return 1 fi echo "${name}|${url}|${type}|${category}" >> "$CONFIG_FILE" echo '{"success":true}' } # === DELETE FEED === delete_feed() { local name="$1" [ -z "$name" ] && { echo '{"success":false,"error":"Name required"}' return 1 } if grep -q "^${name}|" "$CONFIG_FILE" 2>/dev/null; then sed -i "/^${name}|/d" "$CONFIG_FILE" rm -f "${CACHE_DIR}/${name}.xml" echo '{"success":true}' else echo '{"success":false,"error":"Feed not found"}' return 1 fi } # === MAIN === case "$1" in sync) sync_feeds ;; status) get_status ;; list) list_feeds ;; add) add_feed "$2" "$3" "$4" "$5" ;; delete) delete_feed "$2" ;; *) echo "Usage: $0 {sync|status|list|add|delete}" echo "" echo "Commands:" echo " sync Fetch and process all feeds" echo " status Show service status (JSON)" echo " list List configured feeds (JSON)" echo " add NAME URL [TYPE] [CATEGORY]" echo " Add a new feed" echo " delete NAME Remove a feed" ;; esac