From 4d5031075c2f05b426779d92cb60f6197f5fe2a8 Mon Sep 17 00:00:00 2001 From: Bauke Date: Fri, 5 Jul 2019 23:07:23 +0200 Subject: [PATCH] feat: add RSS/Atom/JSON feeds creation --- gulpfile.js | 80 ++++++++++++++++++++++++++++++++++++-- package.json | 2 + yarn.lock | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 183 insertions(+), 5 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 3e44b9c..446288f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,6 +1,8 @@ // Require dependencies const + cheerio = require('cheerio'), df = require('date-format'), + {Feed} = require('feed'), fs = require('fs-extra'), gitlab = require('gitlab/dist/es5').default, gulp = require('gulp'), @@ -123,7 +125,7 @@ function lintSCSS() { // Start the Browser Sync server and watch individual file types with appropriate build functions function watch() { server.init(opts.sync) - gulp.watch([ paths.html.index, paths.html.posts ], gulp.series(buildHTML, reload)) + gulp.watch([ paths.html.index, paths.html.posts ], gulp.series(buildHTML, createFeeds, reload)) gulp.watch(paths.scss, gulp.series(lintSCSS, buildCSS, reload)) gulp.watch(paths.extra, gulp.series(buildExtra, reload)) } @@ -380,8 +382,80 @@ function createStatistics() { }) } -exports.build = gulp.series(lintSCSS, gulp.parallel(buildHTML, buildCSS, buildExtra)) +function createFeeds() { + const feed = new Feed({ + title: 'Tildes Issue Log', + description: 'Monthly blog highlighting the changes of Tildes.net', + id: 'https://til.bauke.xyz', + link: 'https://til.bauke.xyz', + language: 'en', + image: 'https://til.bauke.xyz/android-chrome-192x192.png', + favicon: 'https://til.bauke.xyz/favicon.ico', + copyright: 'AGPL-3.0-or-later Tildes Issue Log Contributors https://gitlab.com/Bauke/tildes-issue-log', + generator: 'https://github.com/jpmonette/feed', + feedLinks: { + atom: 'https://til.bauke.xyz/feed.atom', + json: 'https://til.bauke.xyz/feed.json', + rss: 'https://til.bauke.xyz/feed.rss', + }, + author: { + name: 'Bauke', + email: 'me@bauke.xyz', + link: 'https://bauke.xyz', + }, + }) + const posts = fs.readdirSync(path.join(paths.out, 'posts')) + // Sort the posts descending year and month + posts.sort((a, b) => { + const yearA = Number(a.replace(/\D/g, '')) + const yearB = Number(b.replace(/\D/g, '')) + if (yearA === yearB) { + const monthA = months.join(',').toLowerCase().split(',').indexOf(a.substring(0, a.indexOf('-'))) + 1 + const monthB = months.join(',').toLowerCase().split(',').indexOf(b.substring(0, b.indexOf('-'))) + 1 + return monthB - monthA + } + + return yearB - yearA + }) + for (const post of posts) { + // Skip the template, that doesn't need to be included + if (post.includes('template')) { + continue + } + + const html = fs.readFileSync(path.join(paths.out, 'posts', post), 'UTF8') + const $ = cheerio.load(html) + const title = $('#wrapper>h1').text() + const id = `https://til.bauke.xyz/posts/${post}` + const date = new Date(Date.UTC( + Number(post.replace(/\D/g, '')), + // Add one to the month since UTC months are 0 based and since we set the + // day as 0 we'll get the Date back as the last day of the previous month + months.join(',').toLowerCase().split(',').indexOf(post.substring(0, post.indexOf('-'))) + 1, + 0, 23, 59, 59 + )) + const content = $('#post') + .html() + .replace(/
.+?<\/article>/g, '') // Remove the TOC + feed.addItem({ + title, + id, + link: id, + date, + published: date, + description: `${title}'s Issue Log`, + content, + image: 'https://til.bauke.xyz/android-chrome-192x192.png', + }) + } + fs.writeFileSync(path.join(paths.out, 'feed.atom'), feed.atom1()) + fs.writeFileSync(path.join(paths.out, 'feed.json'), feed.json1()) + fs.writeFileSync(path.join(paths.out, 'feed.rss'), feed.rss2()) + return Promise.resolve() +} + +exports.build = gulp.series(lintSCSS, gulp.parallel(buildHTML, buildCSS, buildExtra), createFeeds) exports.download = gulp.series(download, gulp.parallel(createIssueTable, createStatistics)) exports.no_download = gulp.parallel(createIssueTable, createStatistics) exports.lint = lintSCSS -exports.watch = gulp.series(lintSCSS, gulp.parallel(buildHTML, buildCSS, buildExtra), watch) +exports.watch = gulp.series(lintSCSS, gulp.parallel(buildHTML, buildCSS, buildExtra), createFeeds, watch) diff --git a/package.json b/package.json index 462687f..f71ad51 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,11 @@ "dependencies": {}, "devDependencies": { "browser-sync": "^2.24.5", + "cheerio": "^1.0.0-rc.3", "date-format": "^2.0.0", "eslint": "^5.1.0", "fancy-log": "^1.3.3", + "feed": "^3.0.0", "fs-extra": "^7.0.1", "gitlab": "^4.3.0", "gulp": "^4.0.0", diff --git a/yarn.lock b/yarn.lock index 1073e4d..c8d9e58 100644 --- a/yarn.lock +++ b/yarn.lock @@ -144,6 +144,11 @@ dependencies: "@types/babel-types" "*" +"@types/node@*": + version "12.0.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.12.tgz#cc791b402360db1eaf7176479072f91ee6c6c7ca" + integrity sha512-Uy0PN4R5vgBUXFoJrKryf5aTk3kJ8Rv3PdlHjl6UaX+Cqp1QE0yPQ68MPXGrZOfG7gZVNDIJZYyot0B9ubXUrQ== + "@types/pug@^2.0.4": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/pug/-/pug-2.0.4.tgz#8772fcd0418e3cd2cc171555d73007415051f4b2" @@ -642,6 +647,11 @@ bluebird@^3.5.0: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -933,6 +943,18 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +cheerio@^1.0.0-rc.3: + version "1.0.0-rc.3" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6" + integrity sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA== + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.1" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash "^4.15.0" + parse5 "^3.0.1" + chokidar@^2.0.0, chokidar@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" @@ -1222,6 +1244,21 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" +css-select@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-what@2.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -1406,12 +1443,20 @@ dom-serializer@0: domelementtype "~1.1.1" entities "~1.1.1" +dom-serializer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" + integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== + dependencies: + domelementtype "^1.3.0" + entities "^1.1.1" + dom-walk@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg= -domelementtype@1, domelementtype@^1.3.0: +domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== @@ -1428,6 +1473,14 @@ domhandler@^2.3.0: dependencies: domelementtype "1" +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + domutils@^1.5.1: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" @@ -1867,6 +1920,13 @@ fast-levenshtein@~2.0.4: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +feed@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/feed/-/feed-3.0.0.tgz#be9cada49c692197e7e14083711597562d14a486" + integrity sha512-2/6RGigcsZkz04LMs8oncuoN08hCOndz7eseLtbSitvIkjDZPkNZY6Y9C2xgTzy1L8u4+TZvCJ/v5zxlmGy2kA== + dependencies: + xml-js "^1.6.11" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -2512,6 +2572,18 @@ htmlclean@~3.0.8: resolved "https://registry.yarnpkg.com/htmlclean/-/htmlclean-3.0.8.tgz#cea451cf5399d4018386a57129489f2d630e62b0" integrity sha1-zqRRz1OZ1AGDhqVxKUifLWMOYrA= +htmlparser2@^3.9.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + htmlparser2@^3.9.2: version "3.10.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.0.tgz#5f5e422dcf6119c0d983ed36260ce9ded0bee464" @@ -3329,7 +3401,7 @@ lodash.mergewith@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927" integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ== -lodash@^4.0.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10: +lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== @@ -3810,6 +3882,13 @@ npm-packlist@^1.1.6: gauge "~2.7.3" set-blocking "~2.0.0" +nth-check@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + num2fraction@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" @@ -4086,6 +4165,13 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= +parse5@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" + integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA== + dependencies: + "@types/node" "*" + parseqs@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" @@ -4642,6 +4728,15 @@ readable-stream@^3.0.6: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@^3.1.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" + integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -6204,6 +6299,13 @@ xhr@^2.5.0: parse-headers "^2.0.0" xtend "^4.0.0" +xml-js@^1.6.11: + version "1.6.11" + resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" + integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== + dependencies: + sax "^1.2.4" + xmlhttprequest-ssl@~1.5.4: version "1.5.5" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"