Skip to content

Commit

Permalink
feat(cli): hexo seo-feed ATOM generator
Browse files Browse the repository at this point in the history
  • Loading branch information
dimaslanjaka committed Oct 27, 2024
1 parent d649371 commit 7d9980b
Show file tree
Hide file tree
Showing 15 changed files with 122 additions and 49 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,11 @@ bump: v1.4.3 - fix: bad engine while install
- [ _2024-10-26 16:15:58_ ] [4da807d](https://github.com/dimaslanjaka/safelink/commit/4da807d) drop docs builder
- [ _2024-10-26 16:21:37_ ] [ecc0b8a](https://github.com/dimaslanjaka/safelink/commit/ecc0b8a) feat: build `dist/index.cjs` for CJS calls on ESM
- [ _2024-10-26 16:31:54_ ] [477eb3e](https://github.com/dimaslanjaka/safelink/commit/477eb3e) chore(log): convert to unix path
- [ _2024-10-26 17:21:39_ ] [b8fb3e2](https://github.com/dimaslanjaka/safelink/commit/b8fb3e2) feat: RSS v2.0 generator (https://github.com/dimaslanjaka/hexo-seo/issues/272) (origin/pre-release)
- [ _2024-10-26 17:21:39_ ] [b8fb3e2](https://github.com/dimaslanjaka/safelink/commit/b8fb3e2) feat: RSS v2.0 generator (https://github.com/dimaslanjaka/hexo-seo/issues/272)
- [ _2024-10-26 17:32:29_ ] [ea69e87](https://github.com/dimaslanjaka/safelink/commit/ea69e87) feat: get author email
- [ _2024-10-26 17:57:40_ ] [339cc32](https://github.com/dimaslanjaka/safelink/commit/339cc32) feat(pickPostObjectData): fix missing undefined properties (HEAD -> pre-release)
- [ _2024-10-26 17:57:40_ ] [339cc32](https://github.com/dimaslanjaka/safelink/commit/339cc32) feat(pickPostObjectData): fix missing undefined properties
- [ _2024-10-26 18:53:27_ ] [af52829](https://github.com/dimaslanjaka/safelink/commit/af52829) fix: missing RSS items (https://github.com/dimaslanjaka/hexo-seo/issues/272)
- [ _2024-10-26 18:59:49_ ] [4030d1e](https://github.com/dimaslanjaka/safelink/commit/4030d1e) fix: skip post with empty title to index on RSS
- [ _2024-10-26 19:08:22_ ] [088d219](https://github.com/dimaslanjaka/safelink/commit/088d219) fix: RSS invalid by author email feat: default author email is `[email protected]` fix: skip empty page title (origin/pre-release, origin/integrate-content-search-and-feed, pre-release)
- [ _2024-10-27 08:32:11_ ] [4c69849](https://github.com/dimaslanjaka/safelink/commit/4c69849) use url validator from `sbg-utility`
- [ _2024-10-27 11:14:27_ ] [d649371](https://github.com/dimaslanjaka/safelink/commit/d649371) fix: get author link and email fallback (HEAD -> integrate-content-search-and-feed)
4 changes: 3 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ seo:
feed:
# hexo seo-feed page type to index
type: [page, post]
# site icon for rss (PNG, JPEG, GIF)
icon: 'https://w7.pngwing.com/pngs/745/306/png-transparent-gallery-image-images-photo-picture-pictures-set-app-incredibles-icon-thumbnail.png'
```
## Generate search data
Expand Down Expand Up @@ -231,7 +233,7 @@ author:
email: [email protected]
```

> This parser supported for site config (**_config.yml**) and post markdown and page markdown
> This parser supported for site config (**_config.yml**) and post markdown and page markdown.

# Preview

Expand Down
Binary file modified release/hexo-seo-2.0.0.tgz
Binary file not shown.
Binary file modified release/hexo-seo.tgz
Binary file not shown.
20 changes: 10 additions & 10 deletions release/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
},
"/release/hexo-seo.tgz": {
"integrity": {
"sha1": "bad633765027a85662341f8802295f0ca7c52b75",
"sha256": "hbJ/PTRIjlqUBhFscRjtwVzhsFIjh5kS2ymylOGSdmE=",
"md5": "8170876ac82d448e1d97bd6b877491e9",
"sha512": "dfY63l5XSW8cAGgj6bXgA4ss7OabPAD+Dq2yN1Tlw2WoSANfnneRJgFH1zb8JNuL7MnfYGSh3kbcAoQ6Ee9JqQ=="
"sha1": "ea3b3500d306c929764bf9388db96a84450339c7",
"sha256": "orEORkGXIu+hxfGk3HkDDe033e2i0pBpsSuV0mAJP9Y=",
"md5": "e61e9e9f26562b684d2f92d79fd2a9c2",
"sha512": "71rOIlyslW0WzEVM0ME8z8kxBUKhKuK2yW3h1zeTuzL0fMi/e2rryBUXl2zpCWimQx6bIl8tJvM4ZfYe0sZNbA=="
},
"size": "449.56 KB"
"size": "450.96 KB"
},
"/package-lock.json": {
"integrity": {
Expand Down Expand Up @@ -163,11 +163,11 @@
},
"/release/hexo-seo-2.0.0.tgz": {
"integrity": {
"sha1": "bad633765027a85662341f8802295f0ca7c52b75",
"sha256": "hbJ/PTRIjlqUBhFscRjtwVzhsFIjh5kS2ymylOGSdmE=",
"md5": "8170876ac82d448e1d97bd6b877491e9",
"sha512": "dfY63l5XSW8cAGgj6bXgA4ss7OabPAD+Dq2yN1Tlw2WoSANfnneRJgFH1zb8JNuL7MnfYGSh3kbcAoQ6Ee9JqQ=="
"sha1": "ea3b3500d306c929764bf9388db96a84450339c7",
"sha256": "orEORkGXIu+hxfGk3HkDDe033e2i0pBpsSuV0mAJP9Y=",
"md5": "e61e9e9f26562b684d2f92d79fd2a9c2",
"sha512": "71rOIlyslW0WzEVM0ME8z8kxBUKhKuK2yW3h1zeTuzL0fMi/e2rryBUXl2zpCWimQx6bIl8tJvM4ZfYe0sZNbA=="
},
"size": "449.56 KB"
"size": "450.96 KB"
}
}
6 changes: 3 additions & 3 deletions release/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
| 1.3.0 | https://github.com/dimaslanjaka/hexo-seo/raw/8242ac3/release/hexo-seo-1.3.0.tgz |
| 1.4.0 | https://github.com/dimaslanjaka/hexo-seo/raw/8242ac3/release/hexo-seo-1.4.0.tgz |
| 1.4.3 | https://github.com/dimaslanjaka/hexo-seo/raw/8242ac3/release/hexo-seo-1.4.3.tgz |
| 2.0.0 | https://github.com/dimaslanjaka/hexo-seo/raw/4030d1e/release/hexo-seo-2.0.0.tgz |
| latest | https://github.com/dimaslanjaka/hexo-seo/raw/4030d1e/release/hexo-seo.tgz |
| latest | https://github.com/dimaslanjaka/hexo-seo/raw/pre-release/release/hexo-seo.tgz |
| 2.0.0 | https://github.com/dimaslanjaka/hexo-seo/raw/088d219/release/hexo-seo-2.0.0.tgz |
| latest | https://github.com/dimaslanjaka/hexo-seo/raw/088d219/release/hexo-seo.tgz |
| latest | https://github.com/dimaslanjaka/hexo-seo/raw/integrate-content-search-and-feed/release/hexo-seo.tgz |

use this tarball with `resolutions`:
```json
Expand Down
4 changes: 3 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export interface BaseConfig {
/** hexo seo cli feed options */
feed: {
type: string[];
icon: string;
};
}

Expand Down Expand Up @@ -148,7 +149,8 @@ const getConfig = function (hexo: Hexo, _key = 'config-hexo-seo') {
type: ['post', 'page']
},
feed: {
type: ['post', 'page']
type: ['post', 'page'],
icon: 'https://w7.pngwing.com/pngs/745/306/png-transparent-gallery-image-images-photo-picture-pictures-set-app-incredibles-icon-thumbnail.png'
}
};
const seo: BaseConfig = hexo.config.seo;
Expand Down
66 changes: 48 additions & 18 deletions src/feeds/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Bluebird from 'bluebird';
import fs from 'fs-extra';
import he from 'he';
import Hexo from 'hexo';
import { Args } from 'hexo/dist/hexo/index-d';
import { NodeJSLikeCallback } from 'hexo/dist/types';
import moment, { Moment } from 'moment';
import nunjucks from 'nunjucks';
import path from 'path';
import { writefile } from 'sbg-utility';
Expand All @@ -16,14 +16,14 @@ export async function generateFeeds(this: Hexo, _args: Args, callback?: NodeJSLi
try {
const hexoConfig = this.config;
const config = getConfig(hexo);
const searchConfig = config.feed;
const feedConfig = config.feed;
await hexo.load();
const indexedPages = [];
if (searchConfig.type.includes('post')) {
if (feedConfig.type.includes('post')) {
const posts = hexo.database.model('Post').find({ published: true }).toArray();
indexedPages.push(...posts);
}
if (searchConfig.type.includes('page')) {
if (feedConfig.type.includes('page')) {
const pages = hexo.database.model('Page').toArray(); //.find({ published: true }).toArray();
// .find({
// layout: { $in: pageLayouts }
Expand Down Expand Up @@ -53,7 +53,6 @@ export async function generateFeeds(this: Hexo, _args: Args, callback?: NodeJSLi

storedPost.authorName = getAuthorName(data.author || hexoConfig.author);
storedPost.authorEmail = getAuthorEmail(data.author || hexoConfig.author);
storedPost.pubDate = storedPost.date.utc().format('ddd, DD MMM YYYY HH:mm:ss +0000');
storedPost.link = storedPost.permalink;
storedPost.guid = storedPost.permalink;

Expand All @@ -71,6 +70,9 @@ export async function generateFeeds(this: Hexo, _args: Args, callback?: NodeJSLi

storedPost.title = he.encode(storedPost.title || '');
storedPost.description = he.encode(storedPost.description || storedPost.title);
storedPost.updatedDate = (storedPost.updated as Moment).utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]');
storedPost.pubDate = (storedPost.date as Moment).utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]');
storedPost.createdDate = (storedPost.date as Moment).utc().format('YYYY-MM-DDTHH:mm:ss.SSS[Z]');

// skip empty page title
if (storedPost.title.length === 0) return undefined;
Expand All @@ -83,9 +85,9 @@ export async function generateFeeds(this: Hexo, _args: Args, callback?: NodeJSLi
}
}

if (storedPost.layout === 'post') {
console.log(storedPost);
}
// if (storedPost.layout === 'post') {
// console.log(storedPost);
// }

// {
// title: 'Example Post Title',
Expand All @@ -101,6 +103,13 @@ export async function generateFeeds(this: Hexo, _args: Args, callback?: NodeJSLi
})
.filter((o) => typeof o === 'object');

const latestDate = moment(Math.max(...pageItems.map((o) => o.date).map((date) => date.valueOf()))).format(
'YYYY-MM-DDTHH:mm:ss.SSS[Z]'
);
const latestUpdated = moment(Math.max(...pageItems.map((o) => o.updated).map((date) => date.valueOf()))).format(
'YYYY-MM-DDTHH:mm:ss.SSS[Z]'
);

const templateDir = path.join(__dirname, 'views');
const env = nunjucks.configure(templateDir, {
noCache: true,
Expand All @@ -110,30 +119,51 @@ export async function generateFeeds(this: Hexo, _args: Args, callback?: NodeJSLi
lstripBlocks: false
});

// Use render, ensuring the correct file path is referenced.
const result = env.renderString(fs.readFileSync(path.join(templateDir, 'rss.xml'), 'utf-8'), {
const context = {
config: hexoConfig,
siteTitle: hexoConfig.title,
siteUrl: hexoConfig.url,
feedUrl: `${hexoConfig.url}/rss.xml`,
iconUrl: config.feed.icon,
siteDescription: hexoConfig.description,
language: Array.isArray(hexoConfig.language) ? hexoConfig.language[0] : hexoConfig.language || 'en-us',
lastBuildDate: 'Sat, 26 Oct 2024 10:00:00 +0000',
pubDate: 'Sat, 26 Oct 2024 10:00:00 +0000',
authorName: getAuthorName(hexoConfig.author),
authorEmail: getAuthorEmail(hexoConfig.author),
// lastBuildDate: 'Sat, 26 Oct 2024 10:00:00 +0000',
lastBuildDate: latestUpdated,
updatedDate: latestUpdated,
// pubDate: 'Sat, 26 Oct 2024 10:00:00 +0000',
pubDate: latestDate,
ttl: 1800,
items: pageItems
});
entries: pageItems
};
const RSSContent = env.render('rss.xml', context);

const paths = [path.join(config.source_dir, 'rss.xml'), path.join(config.public_dir, 'rss.xml')];
return Bluebird.all(paths)
const RSS = Bluebird.all([path.join(config.source_dir, 'rss.xml'), path.join(config.public_dir, 'rss.xml')])
.each((file) => {
// Split the file content into lines and filter out empty lines
const cleanedData = result
.split('\n') // Split by new lines
const cleanedData = RSSContent.split('\n') // Split by new lines
.filter((line) => line.trim() !== '') // Remove empty lines
.join('\n'); // Join back into a single string
writefile(file, cleanedData);
hexo.log.info(`[hexo-seo] RSS 2.0 saved to ${file}.`);
})
.catch(callback);

const ATOMContent = env.render('atom.xml', context);

const ATOM = Bluebird.all([path.join(config.source_dir, 'atom.xml'), path.join(config.public_dir, 'atom.xml')])
.each((file) => {
// Split the file content into lines and filter out empty lines
const cleanedData = ATOMContent.split('\n') // Split by new lines
.filter((line) => line.trim() !== '') // Remove empty lines
.join('\n'); // Join back into a single string
writefile(file, cleanedData);
hexo.log.info(`[hexo-seo] ATOM saved to ${file}.`);
})
.catch(callback);

return Bluebird.all([RSS, ATOM]);
} catch (error) {
callback(error);
}
Expand Down
21 changes: 21 additions & 0 deletions src/feeds/views/atom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ siteTitle }}</title>
<link href="{{ siteUrl }}" />
<updated>{{ updatedDate }}</updated>
<author>
<name>{{ authorName }}</name>
<email>{{ authorEmail }}</email>
</author>
<id>{{ siteUrl }}</id>
{% for entry in entries %}
<entry>
<title>{{ entry.title }}</title>
<link href="{{ entry.link }}" />
<id>{{ entry.id if entry.id else entry.link }}</id>
<updated>{{ entry.updatedDate }}</updated>
<summary>{{ entry.description }}</summary>
</entry>
{% endfor %}
</feed>
<!-- XML Atom generated by Dimas Lanjaka -->
17 changes: 15 additions & 2 deletions src/feeds/views/rss.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:atom="http://www.w3.org/2005/Atom">
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>{{ siteTitle }}</title>
<link>{{ siteUrl }}</link>
Expand All @@ -9,7 +10,19 @@
<lastBuildDate>{{ lastBuildDate }}</lastBuildDate>
<pubDate>{{ pubDate }}</pubDate>
<ttl>{{ ttl if ttl else 1800 }}</ttl>
{% for item in items %}

{% if iconUrl %}
<image>
<url>{{ iconUrl }}</url>
<title>{{ siteTitle }}</title>
<link>{{ siteUrl }}</link>
</image>
{% endif %}

{% if feedUrl %}<atom:link href="{{ feedUrl }}" rel="self" type="application/rss+xml"/>{% endif %}
{% if config.feed.hub %}<atom:link href="{{ config.feed.hub }}" rel="hub"/>{% endif %}

{% for item in entries %}
<item>
<title>{{ item.title }}</title>
<link>{{ item.link }}</link>
Expand Down
8 changes: 0 additions & 8 deletions test-server.js

This file was deleted.

2 changes: 1 addition & 1 deletion test/env.js → test/env.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { deepmerge } = require('deepmerge-ts');
const Hexo = require('hexo');
const { fs, path } = require('sbg-utility');

const base = path.resolve(__dirname + '/../site/');
const base = path.resolve(__dirname, '../site/');

// override process.cwd()
process.cwd = () => base;
Expand Down
5 changes: 3 additions & 2 deletions test/single-post.js → test/single-post.cjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const base = __dirname + '/../site/';
const path = require('path');

const base = path.resolve(__dirname, '/../site/');
process.cwd = () => base;

const path = require('path');
const Bluebird = require('bluebird');
const Hexo = require('hexo');
const { fs } = require('sbg-utility');
Expand Down
2 changes: 1 addition & 1 deletion test/sitemap/yoastseo.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { bindProcessExit, fs, path } from 'sbg-utility';
import { baseSite, envHexo } from '../env';
import { baseSite, envHexo } from '../env.cjs';

// test only activate yoastseo sitemap

Expand Down
7 changes: 7 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
"ESNext"
]
},
"include": [
"src",
"test",
"rollup.*",
"gulp*",
"package-*"
],
"exclude": [
"**/node_modules/**",
"**/*.spec.ts",
Expand Down

0 comments on commit 7d9980b

Please sign in to comment.