{"id":25049324,"url":"https://github.com/royalgarter/the-newsroom-rss","last_synced_at":"2025-10-09T23:08:26.355Z","repository":{"id":274993633,"uuid":"924730452","full_name":"royalgarter/the-newsroom-rss","owner":"royalgarter","description":"A super simple, fast, personalized RSS Feed Reader using Deno, Alpine.js and TailwindCSS.","archived":false,"fork":false,"pushed_at":"2025-05-06T04:35:20.000Z","size":4040,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-06T05:29:33.274Z","etag":null,"topics":["alpinejs","deno","tailwindcss"],"latest_commit_sha":null,"homepage":"https://rss.phamthanh.me","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/royalgarter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-01-30T14:59:16.000Z","updated_at":"2025-05-06T04:35:23.000Z","dependencies_parsed_at":"2025-03-24T13:22:11.307Z","dependency_job_id":"46a4a29e-60d0-450f-b1c9-4d6ce3f1c09b","html_url":"https://github.com/royalgarter/the-newsroom-rss","commit_stats":null,"previous_names":["royalgarter/rss-render","royalgarter/the-newsroom-rss"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/royalgarter%2Fthe-newsroom-rss","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/royalgarter%2Fthe-newsroom-rss/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/royalgarter%2Fthe-newsroom-rss/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/royalgarter%2Fthe-newsroom-rss/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/royalgarter","download_url":"https://codeload.github.com/royalgarter/the-newsroom-rss/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252782434,"owners_count":21803378,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alpinejs","deno","tailwindcss"],"created_at":"2025-02-06T08:17:43.165Z","updated_at":"2025-10-09T23:08:21.304Z","avatar_url":"https://github.com/royalgarter.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RSS Render Backend\r\n\r\nThis is a backend service built with Deno for fetching, parsing, and serving RSS feeds. It also includes a \"read later\" functionality.\r\n\r\n## Features\r\n\r\n-   **RSS Feed Fetching and Parsing**: Fetches RSS feeds from provided URLs, parses them, and returns structured data.\r\n-   **Caching**: Implements a caching mechanism to reduce redundant fetching and improve response times.\r\n-   **\"Read Later\" Functionality**: Allows users to save articles for later reading.\r\n-   **CORS Support**: Enables Cross-Origin Resource Sharing for wider accessibility.\r\n\r\n## Technologies Used\r\n\r\n-   [Deno](https://deno.land/): A modern runtime for JavaScript and TypeScript.\r\n-   [Deno Standard Modules](https://deno.land/std): For HTTP server, path manipulation, and file system operations.\r\n-   [deno-rss](https://deno.land/x/rss): A Deno module for parsing RSS feeds.\r\n-   [case](https://deno.land/x/case): A Deno module for converting strings to different cases (e.g., title case, upper case).\r\n\r\n## Setup\r\n\r\n### Prerequisites\r\n\r\n-   [Deno](https://deno.land/#installation) installed on your system.\r\n\r\n### Installation\r\n\r\n1.  Clone the repository:\r\n\r\n    ```bash\r\n    git clone \u003crepository-url\u003e\r\n    cd rss-render\r\n    cd backend\r\n    ```\r\n\r\n2.  Set up environment variables:\r\n\r\n    -   `DENO_KV_URL`: URL for Deno KV database. You can use a local or remote KV store.\r\n\r\n    You can set these in your `.env` file or directly in your shell.\r\n\r\n### Running the Service\r\n\r\n```bash\r\ndeno run --allow-net --allow-read --allow-env --allow-write --allow-run server.ts\r\n```\r\n\r\nAlternatively, if you are using a Deno configuration file (e.g., `deno.json` or `deno.jsonc`):\r\n\r\n```bash\r\ndeno run --config deno.json server.ts\r\n```\r\n\r\nThe server will start on port `17385` by default, or the port specified in the `PORT` environment variable.\r\n\r\n## API Endpoints\r\n\r\n### `GET /api/feeds` or `POST /api/feeds`\r\n\r\n-   Fetches and parses RSS feeds.\r\n-   **Method**: `GET` or `POST`\r\n-   **Query Parameters (GET)**:\r\n    -   `u`: Comma-separated list of RSS feed URLs (URL-encoded).\r\n    -   `l`: Limit the number of items returned per feed (optional, default: 12).\r\n    -   `x`: Hash for KV storage (optional).\r\n    -   `v`: Version of the hash (optional).\r\n-   **Request Body (POST)**:\r\n    ```json\r\n    {\r\n      \"keys\": [\r\n        {\"url\": \"rss_feed_url_1\"},\r\n        {\"url\": \"rss_feed_url_2\", \"content\": \"rss_feed_content\"}\r\n      ],\r\n      \"batch\": [\r\n        {\"url\": \"rss_feed_url_1\"},\r\n        {\"url\": \"rss_feed_url_2\", \"content\": \"rss_feed_content\"}\r\n      ],\r\n      \"update\": true\r\n    }\r\n    ```\r\n-   **Response**:\r\n\r\n    ```json\r\n    {\r\n      \"feeds\": [\r\n        {\r\n          \"title\": \"FEED_TITLE \u003e Feed Title\",\r\n          \"link\": \"feed_website_url\",\r\n          \"rss_url\": \"rss_feed_url\",\r\n          \"image\": \"feed_image_url\",\r\n          \"order\": 0,\r\n          \"items\": [\r\n            {\r\n              \"link\": \"article_url\",\r\n              \"title\": \"Article Title\",\r\n              \"author\": \"Author Name\",\r\n              \"description\": \"Article Description\",\r\n              \"published\": 1678886400000,\r\n              \"updated\": 1678886400000,\r\n              \"images\": [\"image_url_1\", \"image_url_2\"],\r\n              \"categories\": [\"Category 1\", \"Category 2\"]\r\n            }\r\n          ]\r\n        }\r\n      ],\r\n      \"hash\": \"unique_hash\"\r\n    }\r\n    ```\r\n\r\n### `GET /api/readlater`\r\n\r\n-   Retrieves saved \"read later\" items.\r\n-   **Method**: `GET`\r\n-   **Query Parameters**:\r\n    -   `x`: Hash to identify the user or context (optional, default: 'default').\r\n-   **Response**:\r\n    ```json\r\n    [\r\n      {\r\n        \"link\": \"article_url\",\r\n        \"title\": \"Article Title\",\r\n        \"description\": \"Article Description\",\r\n        \"image_thumb\": \"thumbnail_url\",\r\n        \"addedAt\": \"timestamp\",\r\n        \"updatedAt\": \"timestamp\"\r\n      }\r\n    ]\r\n    ```\r\n\r\n### `POST /api/readlater`\r\n\r\n-   Adds or updates a \"read later\" item.\r\n-   **Method**: `POST`\r\n-   **Request Body**:\r\n    ```json\r\n    {\r\n      \"x\": \"user_hash\",\r\n      \"item\": {\r\n        \"link\": \"article_url\",\r\n        \"title\": \"Article Title\",\r\n        \"description\": \"Article Description\",\r\n        \"image_thumb\": \"thumbnail_url\"\r\n      }\r\n    }\r\n    ```\r\n-   **Response**:\r\n    ```json\r\n    {\r\n      \"success\": true,\r\n      \"items\": [\r\n        {\r\n          \"link\": \"article_url\",\r\n          \"title\": \"Article Title\",\r\n          \"description\": \"Article Description\",\r\n          \"image_thumb\": \"thumbnail_url\",\r\n          \"addedAt\": \"timestamp\",\r\n          \"updatedAt\": \"timestamp\"\r\n        }\r\n      ],\r\n      \"data\": {\r\n        \"x\": \"user_hash\",\r\n        \"item\": {\r\n          \"link\": \"article_url\",\r\n          \"title\": \"Article Title\",\r\n          \"description\": \"Article Description\",\r\n          \"image_thumb\": \"thumbnail_url\"\r\n        }\r\n      }\r\n    }\r\n    ```\r\n\r\n### `DELETE /api/readlater`\r\n\r\n-   Deletes a \"read later\" item.\r\n-   **Method**: `DELETE`\r\n-   **Request Body**:\r\n    ```json\r\n    {\r\n      \"x\": \"user_hash\",\r\n      \"link\": \"article_url\"\r\n    }\r\n    ```\r\n-   **Response**:\r\n    ```json\r\n    {\r\n      \"success\": true,\r\n      \"items\": [\r\n        {\r\n          \"link\": \"article_url\",\r\n          \"title\": \"Article Title\",\r\n          \"description\": \"Article Description\",\r\n          \"image_thumb\": \"thumbnail_url\",\r\n          \"addedAt\": \"timestamp\",\r\n          \"updatedAt\": \"timestamp\"\r\n        }\r\n      ]\r\n    }\r\n    ```\r\n\r\n### `GET /html`\r\n\r\n-   Fetches the HTML content of a given URL.\r\n-   **Method**: `GET`\r\n-   **Query Parameters**:\r\n    -   `u`: URL to fetch (URL-encoded).\r\n-   **Response**:\r\n    -   Returns the HTML content of the URL.\r\n\r\n## Caching Strategy\r\n\r\nThe service uses a combination of in-memory caching and Deno KV for storing fetched RSS feeds and HTML content.\r\n\r\n-   **In-Memory Cache**: Utilizes a `Map` to store frequently accessed data, with a TTL (time-to-live) of 7 days.\r\n-   **Deno KV**: Used for persistent storage of \"read later\" items and potentially for longer-term caching of RSS feed data.\r\n\r\n## Environment Variables\r\n\r\n-   `DENO_KV_URL`: The URL for the Deno KV database.  If not provided, Deno KV will default to a local database.\r\n-   `PORT`: The port on which the server will listen (default: `17385`).\r\n\r\n## Notes\r\n\r\n-   The service attempts to extract relevant information from RSS feeds, including images, descriptions, and categories.\r\n-   Error handling is implemented to gracefully handle issues such as failed feed fetching or parsing errors.\r\n-   The `handleRequest` function serves as the main request handler, routing requests to the appropriate API endpoints or serving static files from the `frontend` directory.\r\n\r\n## Contributing\r\n\r\nFeel free to contribute to this project by submitting issues or pull requests.\r\n\r\n## License\r\n\r\n[MIT](LICENSE)\r\n\r\n---\r\n\r\n\u003e _\"In the Information Age, ignorance is a choice.\", \"It's not the news, it's how you get the news.\", \"We just decided to try to do it better.\" — Will McAvoy, The Newsroom by Aaron Sorkin_","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froyalgarter%2Fthe-newsroom-rss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froyalgarter%2Fthe-newsroom-rss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froyalgarter%2Fthe-newsroom-rss/lists"}