This changelog highlights user-facing improvements across the Tools platform.
/admin/social-media-tools/facebook now defaults to a rolling 40-day range ending today.2026-04-10, default date_from is 2026-03-01 and date_to is 2026-04-10./rss/xpath-lab (permission: rss) for debugging and building XPath rules from pasted HTML snippets.xpath_query) with immediate match previews (node path, tag, text, and snippet).elements rules./rss to the new lab and a helper link in the auto-detect HTML-context section.version_history.articles[*].versions[*] now includes description and conditional content excerpts (when content is present), not title-only rows.My To Do, Whisper, and Whisper Admin shortcuts from the global navbar./services (permission-aware cards)./feed/feed default feeds per page.per_page query parameter is provided./feed?per_page=...) and values remain clamped to safe bounds./feed/entry/{contentId} for noisy posts:
/feed/{urlid} question panels.context_type, analysis_note, period_metadata β scope metadatafeeds β list of matching feeds with id, title, category, urlrecent_entries β period-filtered entries with version count annotationversion_history β period-independent list of all edited articles with every stored version (v1=oldest, vN=newest), title change notes between adjacent versions, and permalinkstop_terms, stats β frequency summary and scope countersversion_history.articles covers ALL recorded time regardless of the selected period (daily/weekly/monthly/yearly), so the AI can answer questions about article edits spanning any date range.version_history.articles to answer questions about edits, content changes, title evolution, and publishing history.buildContextSnapshotFresh() and version-history lookups to reduce latency/timeouts under scoped questions:
content(urlid, pubdate, contentid) for period-window entry samplingcontent(urlid, link, content_hash) for version-count groupingcontent(urlid, link, pubdate, contentid) for version-history row retrievalurls(deleted, is_hidden, category, title, urlid) (or urls(deleted, category, title, urlid) where is_hidden is absent)version_count, title_change_count, first_published, last_published, and a compact sampled versions[] list instead of every stored revision.debug_summary, domains, some sources/terms/feeds/recent entries) and then reduce version_history.articles until the JSON payload fits the configured character budget./whisper (permission:whisper.use)./admin/whisper (permission:whisper.manage) with all-user visibility and run-now trigger./api/whisper/*:
GET /statusGET /jobsPOST /jobsGET /jobs/{jobId}POST /run-now (manager/admin)whisper_transcriptions with stage/progress fields, retry metadata, transcript storage, and owner linkage.whisper:process --limit=1, every minute) plus host config/env support (WHISPER_*) for binary path, timeouts, retries, and SSL behavior./settings/integrations/microsoft-todo./api/microsoft-todo/* for status, sync, list retrieval, task retrieval, and list/task mutations.microsoft-todo:sync) that runs every 15 minutes./admin/social-media-tools/facebook now shows only SocialGPT history rows.source=social_media_extension, SocialGPT tool slug, and feature_slug=gpt) for both list and detail views./admin/social-media-tools/audit/complete.RssController that had caused runtime failures during RSS inbound conversion./api/rss/update crashes caused by missing canQuery() and handleWordPressRestApi() methods./api/rss/feed/* and analytics feed selectors after the accidental method removal.Askingβ¦), the re-rendered answer box labels (Latest answer, Q:, A:), success text, and error messages β instead of always showing English.en, sv, da, no, fi):
ask_error_required β shown when the question field is left empty.ask_error_captcha β shown when the captcha has not been completed.ask_success_answered β shown after a successful answer is received.ask_error_generic β shown on network/server errors.ask_asking phrase in the Norwegian (no) language entry.Daily, Weekly, Monthly, Yearly) and Read more / Show less buttons now respond to the language switcher.site_analytics_title phrase key (site-specific AI analysis summary label) to all languages.Updated TLS configuration in nginx/tools.tornevall.net.conf to remove deprecated TLSv1 and TLSv1.1.
Now only TLSv1.2 and TLSv1.3 are accepted.
Updated cipher suite to modern ECDHE/CHACHA20/AES-GCM set and set ssl_prefer_server_ciphers off (lets clients negotiate the best mutual cipher).
Updated scraper URL selection so always=0 is now agent-aware instead of globally gated by urls.lastscrape.
Each scraper agent (agent_id) now tracks per-URL claim state: when it last saw a URL and when it is next allowed to see it.
Interval checks for always=0 now use the URL's configured readinterval together with that agent-specific seen state.
always=1 now returns all non-deleted/non-noscrape RSS URLs (no interval filtering).
Added backend persistence table rs_agent_url_seen (RSS DB) for per-agent URL scheduling state.
client_event_key or network_activity_id) and all key event fields match exactly.today/day, week, month, year) when no explicit period is selected.user_selection, question_text, or admin_default) for traceability.gpt-4o-mini./feed)/feed page.navigator.languages preference on first visit, then persisted in localStorage.config/feed_phrases.php (editable as code)./rss-admin β π Public feed phrase editor)./feed)localStorage and restored on each visit, so the page opens where you left off.toggleCategory() function is now correctly wired./feed)/feed/user-questions). Free-text, max 500 characters, injected directly into the prompt. Use it to enforce plain prose, suppress bullet lists, or shift the output personality without touching the underlying prompt profile./api/rss/update)handled=1 are now purged as soon as they are unlocked (processlock=0) during update runs.inbound table lighter under sustained feed traffic.processlock=1) are not purged.processlock=1 via RSS admin (/feed-admin, alias /rss-admin) using setting key feed_admin.inbound.processlock_release_minutes.5..720 minutes) and is applied to both handled and unhandled stuck inbound lock recovery./feed)/feed)gpt-5.4.reasoning_effort=medium for reasoning-capable models (gpt-5*, o1*, o3*, o4*)./rss editor now attempts the WordPress REST API (/wp-json/wp/v2/posts?per_page=100) before any other method. If the site serves valid WP-JSON posts the real_url is set to the REST API endpoint with ?per_page=100 (to retrieve more posts than the default RSS feed) and sitetype is set to wp. Falls through to standard RSS discovery if wp-json is disabled or unavailable.<link rel="alternate"> extraction: If WordPress REST API is not available, the editor now fetches the page HTML and parses all <link rel="alternate" type="application/rss+xml|atom+xml"> tags to discover the canonical feed URL declared by the site itself β avoiding guessing.*.blogspot.* are now flagged in the auto-detect response. A warning is shown in the editor status line noting that Blogspot RSS output is minimal and that full-HTML scraping may be added in the future.<link rel="alternate">, no common feed pattern), the editor now calls OpenAI (gpt-4o-mini via the configured OpenAI provider) with a truncated snapshot of the page content and asks it to suggest a feed URL. The result is used as a fallback and clearly flagged with "π€ AI-suggested URL β please verify" in the UI. Silently skipped if OpenAI is not configured./feeds/posts/default) added to the common feed URL probe list.extra_content added to the RSS database (migration 2026_03_28_100000_create_rss_extra_content_table).html_blob) and screenshot file references (filepath).urlid, contentid, link, content_hash, scrape_type, filepath, html_blob, scraped_at./feed)/feed (daily, weekly, monthly, yearly) so each question can choose its own analysis window without changing global admin defaults./api/rss/data)urlid and URL, improving operator visibility during batch runs.POST /api/rss/data response payload (received) so each row now also includes the feed title from urls.title.candidates, converted, and skip counters) to make zero-entry outcomes easier to diagnose.https://www.google.com/url?...) to better preserve destination links during import./users/profile where users can update their own name and email./online admin location visibility so tracked request URIs are matched more reliably against active sessions. Page-visit writes now tolerate missing optional columns during partial deployments, and online matching now falls back more safely for user/session/user-agent combinations./online so authenticated admins/users with users permission now see the detailed location-aware online view on that same URL instead of the simplified public table./rss where legacy Blade flags ($hasProtectedColumn, $hasUseProtectedColumn) could be undefined if deprecated columns are absent./feed when visiting /rss, /feed-admin, or /rss-maintenance-admin, instead of seeing login/403 pages./rss by restoring row cells for protected and useProtected, preventing is_hidden/public_hash values from appearing under the wrong headers.is_hidden on /rss from a free-text input to a checkbox, with AJAX save now posting explicit 1/0 values./admin/jobs RSS Analytics Scheduler is now editable (enabled toggles + run_at per period) and includes a manual "Run Scheduler Check Now" action.rss:generate-analytics: direct cron runs now respect per-period enabled + run_at, skip before slot time, and skip already-completed period keys; manual override remains available via --ignore-scheduler-window./mcu web route to redirect to the controller-backed MCU editor route (mcu.index) instead of rendering the editor Blade without required view data (which caused $perPage/filter variables to be undefined)./keys/mine) β "Google Account" section./auth/google/callback) handles both sign-in and linking flows.GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and GOOGLE_REDIRECT_URI to .env (see .env.example)./admin/visit-stats now exclude RSS scraper/cron paths by default./api/rss/data, /api/rss/urls, /api/rss/update, /api/rss/feed/analytics-*, /api/rss/analytics/run.tools.tornevall.net and "GitHub / Support" link to https://github.com/Tornevall/mcu-timeline-api at the top of the MCU Timeline editor page.dns_zone_cache_records) to support very large AXFR zones with significantly faster paged reads.dns_zone_cache_ip_extras) populated for forward A/AAAA records and decoded reverse-owner entries (DNSBL/OPM style), so future CIDR workflows can use indexed IP metadata.POST /api/dns/records/add|delete|update|bulk) to synchronize cache rows after confirmed successful master DNS updates instead of invalidating full zone caches.dns_zone_settings:
cache_invalidate_enabled (default false)cache_invalidate_interval_seconds (default 259200 = every 3 days when enabled)last_invalidated_atdns:cache:invalidate (hourly scheduler hook) that only invalidates zones where policy is enabled and due./admin/jobs that shows per-period analytics run configuration (enabled, run_at) and latest scheduler state (last_run_at, status, key/reason), so operators can verify timing behavior without opening Feed Admin first.tornevall-tools-cron to run php artisan schedule:run every minute so configured analytics schedule times are actually respected by the scheduler./)/online admin view)user_id consistently and can also store Laravel session_id for more accurate session-to-location matching./feed + /feed/user-questions)/feed so the question form now reuses the shared global Turnstile key when the older feed-specific provider key is missing. The page also now blocks submit until a captcha token is present and shows a clearer temporary-unavailable notice instead of failing silently when captcha keys are not configured correctly./feed, users can now optionally focus the AI's analysis on specific categories or sites using two new multi-select dropdowns:
/feed user questions, selected focus_site_ids[] now override category focus for that question (instead of category-driven broad matching). This keeps context/query scope aligned with the explicitly selected sites and reduces oversized prompts.--force now actually forces overwrite: php artisan rss:generate-analytics now skips unchanged bucket+variant signatures by default and reuses the cached row instead of spending extra AI calls on identical snapshots.--overwrite-current as a clearer alias for --force when operators explicitly want to re-run and overwrite the current bucket row./feed-admin now includes per-period scheduler controls (daily/weekly/monthly/yearly) with enable/disable and run-time fields. A minute-level scheduler command (rss:run-scheduled-analytics) now handles due/catch-up execution from cron.[AUTO] Scheduled analytics) and always overwrite the current automatic bucket variant in place.rss:generate-analytics now prefixes output lines with date/time, making rss-analytics.log easier to audit per generation./ and /services)/ and /services now render the same landing view./menstrual-tracking)birth_date, first_period_started_on) and register cycle starts either as exact dates or month-level entries./, /services, dashboard cards, and navbar./docs/en/menstrual-tracking and /docs/sv/menstrual-tracking.PHP_SUPPRESS_DEPRECATIONS in bootstrap to mute noisy PHP deprecation notices (E_DEPRECATED, E_USER_DEPRECATED) on PHP 8.4+ when running older vendor stacks..env.example documentation for the flag.docs/cron.md for deprecation warnings in cron output./feed mini-card + /feed/user-questions)/feed page now show a truncated preview (280 chars) of each answer. If an answer is longer, a read more / read less toggle button appears, allowing inline expansion without leaving the page./feed/subscriptions) β Stricter Duplicate Filteringcontent_hash that has ever been delivered for each link within a subscription. If a new import row has the same hash as any previously reported version of that link (even if it received a new contentid due to cycling content β AβBβA), it is silently skipped and not re-reported. This prevents notification spam from feeds that repeatedly publish minor or near-identical variations.canQuery) now also checks whether the new entry's content_hash or meaningful_hash already exists in any previous row for that link, not just the most recent row. This closes the AβBβA cycling hole where version A was being reinserted into the content table even though it already existed in older history. Both content_hash and meaningful_hash are checked globally via indexed existence queries, preventing runaway version accumulation from feeds with cycling or near-identical content.projects/scraper/ondisney.php)original_url fallback always populated: Disney sitemap URLs always carry locale prefixes (e.g. en-be, nl-nl). The scraper previously only set original_url on the rare case of a URL without a locale prefix, meaning most items never had original_url set and were silently dropped by the import engine. Now the scraper falls back to a preferred English locale (en-us β en-gb β en-ca β first en-* β first available) and always sets original_url (and original_title if missing) on each item. Existing elements DB JSON for site 8 is unchanged; the fix is in the scraper output.elements format fully documented: Added a complete reference in the internal BAMGRID notes (docs/en/bamgrid-sitemap-extraction-notes.md, docs/sv/bamgrid-sitemap-extraction-notes.md) explaining both supported elements JSON formats:
begin/table): JSON traversal β begin navigates from root to the item array; table maps content columns to source keys (string = direct key, array = nested traversal).elements DB JSON for Disney/BAMGRID site 8 with field-mapping table and explanation of why all locales need to be considered./rss-maintenance-admin)rss_cautious_links table) so future imports of that link automatically run the dedup/purge pass after each new insert β only distinct meaningful versions are kept./rss-maintenance-admin (with non-JS form-submit fallback still intact).POST /rss-maintenance-admin/mark-cautious now handles omitted reason safely (no more Undefined array key "reason" when the field is not provided)./feed/entry/{contentId})permission:rss) now see an Admin actions panel at the bottom of every entry permalink page with:
/feed/subscriptions)channels_json=[] remains "all channels disabled" instead of defaulting back to Email (mail) in UI rendering./feed-admin)/feed page to /feed-admin. All RSS feed configuration for admins is now in one place. The public feed table column layout still reflects saved settings as before.segment anchor -> global anchor -> current date, making historical runs explicit per card./rss)elements visibility: The large elements JSON editor is now shown only for rows where sitetype is xpath, reducing table width pressure for normal RSS/WP rows.elements editor: XPath rules are now edited in an expandable/collapsible per-row panel so the main list remains compact.elements save on blur (AJAX): elements textarea changes are now saved when the field loses focus; other inline fields keep instant AJAX save on change./feed-admin category/site analysis generation now includes an Anchor date picker. Admins can generate daily/weekly/monthly/yearly analytics for earlier periods (for example last week) if a cron run was missed.anchor_date (YYYY-MM-DD) to target historical period buckets when creating/replacing cached analysis variants.app/Console/Kernel.php now schedules rss:generate-analytics --period=daily once per day at 20:00. Weekly/monthly/yearly remain available via manual CLI/API triggers./feed-admin now shows cached daily variants alongside weekly/monthly/yearly, and regenerate/replace actions refresh the page after save so overwritten category/site variants become visible immediately.docs/en/bamgrid-sitemap-extraction-notes.md and docs/sv/bamgrid-sitemap-extraction-notes.md with verified Disney sitemap structure, namespace-safe XPath candidates (url/loc/lastmod/xhtml:link), measured language-coverage impact (en-*-only would drop ~37.1% of unique IDs), and a recommended path toward a dedicated bamgrid import type with canonicalized per-content output./rss now exposes explicit xpath/json site types in Add URL flow, supports editing elements JSON rules inline when the column exists, validates elements payload format server-side, and requires elements when sitetype=xpath./feed now submits inline with JSON responses and shows status/answer directly on the page (no full reload). Non-JS fallback form behavior remains supported.rss.content data for all non-hidden feeds (categories, sources, domains, terms, entry examples). Added OpenAI profile fallback handling so missing prompt-profile config no longer hard-fails with "No prompt profile configured"./feed question context by period, allowed categories, allowed site ids, context entry cap, answer sentence cap, and mini-history size. The /feed card also shows a small recent-question history inline./feed/user-questions now supports practical pagination defaults with configurable rows-per-page to keep large/spammy histories manageable./feed/user-questions via AJAX (DELETE /feed/user-questions/{question}), with non-JS redirect fallback preserved./feed/user-questions and /feed-admin settings blocks), and these settings are applied when OpenAI answers are generated./feed/user-questions now supports filtering by status, user_id (or guest), ip, and deleted scope (active/deleted/all) to moderate noisy histories faster.POST /feed/user-questions/bulk-delete) and choose hard (permanent) or soft delete mode.feed_user_questions now stores moderation metadata for soft-deleted rows (deleted_at, deleted_by_user_id, deleted_reason) while preserving hard-delete for irreversible cleanup./feed/user-questions (POST /feed/user-questions/{question}/restore), including AJAX inline restore actions./feed-admin, the Retranslate action now reads the target language directly from the variant's stored label (e.g., a variant marked EN will always retranslate to English). The "Choose language" dropdown is removed β the labeled language IS the target./feed/subscriptions now saves channel settings inline and also handles Pause/Resume and Remove via AJAX (no full reload). Non-JS fallback submit remains supported./ dashboard and /services admin cards (route: /admin/jobs) so cron management is easier to find./feed/subscriptions now includes Discord OAuth connect flow (/oauth/discord/start -> /oauth/discord/callback), callback URL visibility, and one-click reuse of the latest Discord webhook payload, matching Slack-style onboarding behavior for webhook setup./feed now includes a mini Q&A card for questions about all open feeds. Added /feed/user-questions history page, guest Turnstile enforcement, configurable guest/user daily+weekly quotas, configurable guest concurrent intake guard, admin bypass/unlimited mode, and persistent question/answer audit records (timestamp, IP, actor metadata, status, response meta).SQLSTATE[40001] InnoDB deadlock on /api/rss/update that occurred when multiple concurrent scraper workers triggered the stale-lock cleanup (UPDATE inbound SET processlock=0 β¦) at the same time as the batch lock-acquisition. The stale-reset and old-row DELETE are now wrapped in a retryOnDeadlock() helper (up to 3 attempts with randomised back-off). fetchAndLockInboundBatch() is now fully atomic via DB::transaction() + lockForUpdate() (SELECT β¦ FOR UPDATE), so two workers can never pick up the same batch./api/rss/update no longer purges old handled=0 rows by default. Purge is now opt-in (RSS_PURGE_STALE_UNHANDLED=true) and limited to abandoned locked rows (processlock=1) with deadlock-safe retries, reducing accidental backlog loss if triggers are paused.Call to undefined method App\Services\OpenAI\RequestLogService::excerpt() on POST /api/ai/socialgpt/respond by restoring safe excerpt handling in request audit logging.handled update): setEntryHandled() in RssController now executes through deadlock retry logic and explicitly releases processlock when marking rows handled, reducing SQLSTATE[40001] deadlocks during concurrent /api/rss/update workers./api/rss/feed/{selector} now support analytics-daily, analytics-weekly, analytics-monthly, analytics-yearly, and analytics-bulk (with corresponding *-analytics aliases). Feed rows now link back to related category/site targets when available. Daily period support was also added to analytics generation flows (rss:generate-analytics, POST /api/rss/analytics/run, and scheduler wiring).DB_RSS_*): config/database.php now treats DB_RSS_* as canonical while keeping legacy RSS_* fallback compatibility across host/database/username/password/charset/collation/socket/url fields, and .env/.env.example now include explicit DB_RSS_URL/DB_RSS_PORT/DB_RSS_SOCKET entries.schedule:run), manual artisan execution, and API trigger (POST /api/rss/analytics/run) in EN/SV docs.POST /api/google-home/request, /devices/query, /devices/request-sync) and a new web console at /admin/google-home. Regular users can use it when granted google-home.use permission./api/google-home/push/tokens/register, /push/tokens, /push/test) so mobile clients can register FCM tokens and receive push notifications when Google Home API calls complete.generateText() method, fixing the /feed-admin 500 error (Call to undefined method ... OpenAiEngine::generateText()).projects/nethandle-ui/README.md + CHANGELOG.md, documented script-preserving migration strategy for web-to-terminal network control, and added runtime env/config scaffold (NETHANDLE_EXEC_*, NETHANDLE_RESOLVER_BASE) in .env, .env.example, and config/services.php./feed-admin site-level generation now has a dedicated per-site title input, so site variants no longer depend on the global title field./feed analytics UI: The Feed Analytics (OpenAI cached) category block now renders only when cached analytics exist for that category, reducing empty UI noise.projects/scraper/scrape.php now fetches feed URLs with bounded curl_multi concurrency so a single slow/hanging site does not block the whole scrape batch. Concurrency/timeout can be tuned via CLI args or SCRAPE_CONCURRENCY and SCRAPE_FETCH_TIMEOUT./feed-admin, instead of only appearing after a fresh generation in the current browser session.replace_existing for the selected period/variant id, so weekly/monthly/yearly entries are overwritten intentionally instead of silently creating extra variants.meaningful_hash and tiny-change suppression (isTinyMeaninglessChange) to avoid noisy pseudo-updates (markup jitter, micro text drift) creating endless new versions./rss-maintenance-admin page lists suspicious high-churn links and supports dry-run/live noise purge per link, keeping latest representative rows per meaningful change.content.meaningful_hash with index to support semantic duplicate filtering and maintenance diagnostics.SQL/RSS_QUEUE_DIAGNOSTICS.sql with reusable admin/internal queries for pending inbound rows, stale locks, recently handled rows, payload-shape previews, and recent content insert comparisons when /api/rss/update reports errors or stuck pending items.RssController now writes structured Log::info checkpoints for inbound row start/finish and batch summaries, making it easier to correlate pending/error runs with Laravel logs (and Slack-forwarded Laravel log categories when enabled)./api/rss/update converts new rows into content, the backend now performs an immediate targeted subscription-delivery pass for affected feed ids. The existing rss:notify-subscribers scheduler remains as the fallback safety net every 15 minutes.urls.is_hidden + urls.public_hash. Hidden feeds are omitted from /feed, but can still be reached directly through /feed/key/{public-hash} and /api/rss/feed/{public-hash} without exposing numeric feed ids publicly./rss now exposes protected, useProtected (when present in schema), is_hidden, and public_hash so alert-style feeds such as Google Alerts can stay scraper-visible but public-list-hidden.projects/scraper/ondisney.php no longer depends on TorneLIB\Module\Network\Domain for URL-path parsing. The script now uses native URL parsing, reports sitemap shape samples during the run, and preserves compatibility with the existing JSON import rules by including the expected timestamp field.file_put_contents exception traces in RssController with structured Laravel Log::warning/Log::error events (including incomingidx/urlid context), so parser/import failures are centralized in Laravel logs and can be forwarded via the existing Slack log routing.projects/scraper/ondisney.php no longer assumes only d-sitemap-1..10; it now reads all available shard files from projects/scraper/sitemap-xml when present and otherwise probes remote Disney sitemap shards dynamically, restoring coverage when Disney expands to more XML files.agent_id consistently to /api/rss/data (query + payload), matching the RSS scraper identification contract used by scrape.php/trigger.php and improving backend agent attribution.projects/scraper/sitemap and projects/scraper/sitemap-mini now use dynamic shard discovery with miss-streak stop conditions instead of fixed hardcoded ranges, reducing maintenance when Disney changes shard counts.RssController after the recent cleanup pass. /api/rss/update can now convert queued inbound rows into content again instead of stalling with converted=0/errors>0 while fresh scraper payloads keep arriving.processlock=1 rows older than 30 minutes are unlocked for retry, and row-processing errors now catch all Throwables so aborted conversions stop leaving locked backlog behind.mysql, rss, mcu, gsm, spamassassin, tornis, irclog, firewall)/docsprojects/sc4a-insights and projects/socialgpt-chrome/oauth/slack/callback (a boolean false was being passed as HTTP status, causing The HTTP status code "0" is not valid.)LOG_FORWARD_DEPRECATIONS setting (default false) so noisy PHP deprecation warnings (for example PHP 8.4 dynamic-property notices) can be excluded from Slack warning forwarding/api/* requests now forward success/error events by endpoint group (for example /api/rss, /api/sms, /api/social-media-tools, etc.) so admins can enable only the API groups they care about.app_host (identifies tools.tornevall.com vs tools.tornevall.net), tokens_in, tokens_out (prompt/completion token split), response_language, feature_slug, and used_fallback_model (yes/no). Short fields are shown side-by-side in Slack for readability.context_excerpt (first 200 chars of context) and user_prompt_excerpt (first 200 chars of user prompt) are now included in the Slack audit message.Contact section in sc4a-insights/README.md with the Slack Marketplace entry for Tornevall Networks Tools (https://tornevall.slack.com/marketplace/A0AN2UJ2C4S-tornevall-networks-tools) to make Slack app/webhook setup easier to find.state may be empty on both sides, while still enforcing strict state validation whenever a state value exists. Token exchange now sends redirect_uri only when it was actually present in the authorize step, matching Slack OAuth v2 parity rules./feed now includes an admin-only Translate button next to each category analysis variant (weekly/monthly/yearly). The action is AJAX-driven and reuses the selected language from the variant language selector.sc4a-insights 2.0.0)1.0.0 2025 overlay-only release/api/social-media-tools/soundcloud/ingest/feed/entry/{contentId}), with the original source URL included as secondary fallback./feed/subscriptions now includes direct helper links for webhook setup:
Connect Slack app (get webhook) starts Slack OAuth with incoming-webhook scope and returns to subscriptionsHow to create a Discord webhook links to Discord webhook setup docsincoming_webhook.url, users can now click Use latest Slack OAuth webhook to fill the Slack webhook URL (and channel label when empty) directly in subscription settings./feed/subscriptions now shows whether Slack OAuth is configured on the current host and displays the effective callback URL, making it clearer that TOOLSAPI_SLACK is the global platform webhook while subscription webhooks come from Slack OAuth (incoming_webhook.url).incoming_webhook.url, the Slack webhook URL field is now auto-filled, saved server-side even without manual paste, and shown as readonly in the UI so users do not have to enter it manually./feed/subscriptions, so users can quickly continue sending notifications to the same Slack channel across subscriptions./donate/thankyou, intended for payment-provider completion redirects (for example PayPal return/thank-you URLs)./donate/cancel, intended as the canonical payment-provider cancellation/abort redirect./donate/farewell as a compatibility alias; it now resolves to the same aborted-donation content via the canonical cancel flow./contact, including a styled PayPal donate button and the current donation QR image.config/services.php (services.paypal.donate_url) so public donate entry points reuse the same URL.public/images/index.html with a playful βdirectory listing disabledβ landing page, so direct browsing of the public image folder no longer lands on a blank file./feed/{id}) now show site-level analytics variants (weekly/monthly/yearly)/feed, /rss, and /feed-adminwatch_for)/feed can show different saved analysis variants via title/language selectors/feed analytics sections are collapsed by default and can be expanded per category/feed via AJAX/feed is now sorted by category orderFirst Discovery and Last Discovery are shown for feedsdocs/en and docs/svEarlier releases established the platform basics for:
Maintained by: Tornevall Networks
Last updated: 2026-03-22