From 5612c9c601e83391a0cd3b7f77b5dd02600cc93f Mon Sep 17 00:00:00 2001 From: PawiX25 Date: Sun, 23 Mar 2025 18:52:09 +0100 Subject: [PATCH] Add RSS feed and GitHub Action workflow for automatic updates --- .github/workflows/generate-rss.yml | 36 +++++++++++++ README.md | 9 ++++ generate-rss.js | 86 ++++++++++++++++++++++++++++++ index.html | 5 ++ styles.css | 15 ++++++ 5 files changed, 151 insertions(+) create mode 100644 .github/workflows/generate-rss.yml create mode 100644 generate-rss.js diff --git a/.github/workflows/generate-rss.yml b/.github/workflows/generate-rss.yml new file mode 100644 index 0000000..0b689fd --- /dev/null +++ b/.github/workflows/generate-rss.yml @@ -0,0 +1,36 @@ +name: Generate RSS Feed +on: + push: + paths: + - 'data.yml' + branches: + - main + workflow_dispatch: + +jobs: + generate-rss: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install dependencies + run: npm install js-yaml + + - name: Generate RSS feed + run: node generate-rss.js + + - name: Commit and push if changed + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add feed.xml + git diff --quiet && git diff --staged --quiet || git commit -m "Update RSS feed" + git push diff --git a/README.md b/README.md index 015cab5..a0fc696 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ - **Deadline Indicators:** Visual indicators for program deadlines, highlighting urgent and very urgent statuses to help prioritize participation. - **Real-time Deadline Updates:** Deadlines are updated in real-time to reflect the current status, ensuring information is always up-to-date. - **Responsive Design:** Optimized for various screen sizes and devices, providing a seamless experience on desktops, tablets, and mobile devices. +- **RSS Feed:** Subscribe to get notifications about active YSWS programs in your favorite RSS reader. ## Getting Started @@ -34,6 +35,14 @@ 5. **Toggle Theme:** - Click the 🌙/☀️ button to switch between dark and light modes. +## RSS Feed + +You can subscribe to updates about active YSWS programs using our RSS feed: + +- **Feed URL**: `https://ysws.hackclub.com/feed.xml` + +This feed is automatically updated whenever new programs are added or existing programs' statuses change. You can use this feed with any RSS reader like Feedly, Inoreader, or apps like Glance to get notified about new opportunities. + ## Project Structure - **index.html:** The main HTML file containing the container for program cards and the modal structure. diff --git a/generate-rss.js b/generate-rss.js new file mode 100644 index 0000000..9057829 --- /dev/null +++ b/generate-rss.js @@ -0,0 +1,86 @@ +const fs = require('fs'); +const jsyaml = require('js-yaml'); +const path = require('path'); + +function generateRSS(programs) { + const host = 'https://ysws.hackclub.com'; + const now = new Date().toUTCString(); + + const activePrograms = Object.values(programs) + .flat() + .filter(program => program.status === 'active') + .sort((a, b) => { + if (!a.deadline) return 1; + if (!b.deadline) return -1; + return new Date(a.deadline) - new Date(b.deadline); + }); + + let rss = ` + + + Hack Club YSWS Programs + ${host} + Active "You Ship, We Ship" programs from Hack Club + en-us + ${now} + +`; + + activePrograms.forEach(program => { + const pubDate = program.pubDate ? new Date(program.pubDate).toUTCString() : now; + const deadline = program.deadline ? + `

Deadline: ${new Date(program.deadline).toLocaleDateString('en-US', { + year: 'numeric', month: 'long', day: 'numeric' + })}

` : ''; + + const channelRef = program.slackChannel ? program.slackChannel.replace(/^#+/, '#') : ''; + + rss += ` + + ${escapeXML(program.name)} + ${program.website || host} + ${program.name}-${Date.now()} + ${pubDate} + ${escapeXML(program.description)}

+ ${deadline} + ${program.detailedDescription ? `

${escapeXML(program.detailedDescription)}

` : ''} + ${channelRef ? `

Join the discussion in ${channelRef}

` : ''} + ]]>
+
`; + }); + + rss += ` +
+
`; + + return rss; +} + +function escapeXML(text) { + if (!text) return ''; + return text + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +} + +async function main() { + try { + const dataFile = path.join(__dirname, 'data.yml'); + const fileContent = fs.readFileSync(dataFile, 'utf8'); + const data = jsyaml.load(fileContent); + + const rssFeed = generateRSS(data); + + fs.writeFileSync(path.join(__dirname, 'feed.xml'), rssFeed); + console.log('RSS feed generated successfully!'); + } catch (error) { + console.error('Error generating RSS feed:', error); + process.exit(1); + } +} + +main(); diff --git a/index.html b/index.html index 0ff5ed3..66e08df 100644 --- a/index.html +++ b/index.html @@ -3,6 +3,7 @@ +