Hexoで複数RSSに対応する その2
Hexoで複数RSSに対応する方法のその2。
今は違う方法を使ってる。↓を参照。
フィギュア記事に興味がある人向けに専用のRSSを用意したい❗
ということで、HexoでRSSフィードを複数用意できるようにした。
フィギュア
がついてる記事のRSS: https://tenpamk2-blog.netlify.app/atom_figure.xml
フィギュア
と レビュー
がついてる記事のRSS: https://tenpamk2-blog.netlify.app/atom_figure_review.xml
フィギュア全般用とフィギュアレビュー専用の2つを追加した。 お好みのRSSリーダーに突っ込めば、フィギュア記事だけを追えるぞ❗
例によって、hexoの修正手順などは長くなったので、記事は折りたたみ。
方針としては、既存の hexo-generator-feed のスクリプトを丸パクリして、ちょびっとだけ変更を加える。
解説は記事末尾。
前の記事↓とだいたい一緒。scriptを置いて、設定なりをいじる。
↓のscriptをthemes/***/scripts/add_custom_rss.js
として設置。
scripts
フォルダに置いたjsファイルはhexoのgenerate時に自動で実行される。
// Original code from ↓
//
// - <https://github.com/hexojs/hexo-generator-feed/blob/master/index.js>
// - <https://github.com/hexojs/hexo-generator-feed/blob/master/lib/generator.js>
const feedFn = require("./add_custom_rss_lib/generator");
hexo.config.feed = Object.assign(
{
type: "atom",
limit: 20,
hub: "",
content: true,
content_limit: 140,
content_limit_delim: "",
order_by: "-date",
autodiscovery: true,
template: "",
},
hexo.config.feed,
);
hexo.config.feed = Object.assign(
{
figure_atom_path: "",
figure_review_atom_path: "",
},
hexo.config.add_custom_rss,
);
if (!hexo.config.feed.figure_atom_path) {
// error
return;
}
if (!hexo.config.feed.figure_review_atom_path) {
// error
return;
}
const filterNonFigure = (post) => {
const figRevTag = post.tags.toArray().filter((tag) => {
return tag.name === "フィギュア";
});
return 1 <= figRevTag.length;
};
const filterNonFigureReview = (post) => {
const figRevTag = post.tags.toArray().filter((tag) => {
return tag.name === "フィギュア" || tag.name === "レビュー";
});
return 2 <= figRevTag.length;
};
hexo.extend.generator.register("atom_figure", (locals) => {
return feedFn.call(
hexo,
locals,
"atom",
hexo.config.feed.figure_atom_path,
filterNonFigure,
);
});
hexo.extend.generator.register("atom_figure_review", (locals) => {
return feedFn.call(
hexo,
locals,
"atom",
hexo.config.feed.figure_review_atom_path,
filterNonFigureReview,
);
});
追加で、↓のscriptをthemes/***/scripts/add_custom_rss_lib/generator.js
として設置。
// Original code from ↓
//
// - <https://github.com/hexojs/hexo-generator-feed/blob/master/index.js>
// - <https://github.com/hexojs/hexo-generator-feed/blob/master/lib/generator.js>
"use strict";
const nunjucks = require("nunjucks");
const { join } = require("path");
const { readFileSync } = require("fs");
const { encodeURL, gravatar, full_url_for } = require("hexo-util");
const env = new nunjucks.Environment();
env.addFilter("uriencode", (str) => {
return encodeURL(str);
});
env.addFilter("noControlChars", (str) => {
return str.replace(/[\x00-\x1F\x7F]/g, ""); // eslint-disable-line no-control-regex
});
module.exports = function (locals, type, path, filterFunc) {
const { config } = this;
const { email, feed, url: urlCfg } = config;
const {
icon: iconCfg,
limit,
order_by,
template: templateCfg,
type: typeCfg,
} = feed;
env.addFilter("formatUrl", (str) => {
return full_url_for.call(this, str);
});
let tmplSrc = join(
__dirname,
`../../../../node_modules/hexo-generator-feed/atom.xml`,
);
if (templateCfg) {
if (typeof templateCfg === "string") tmplSrc = templateCfg;
else tmplSrc = templateCfg[typeCfg.indexOf(type)];
}
const template = nunjucks.compile(readFileSync(tmplSrc, "utf8"), env);
let posts = locals.posts.sort(order_by || "-date");
posts = posts.filter((post) => {
return post.draft !== true;
});
// filter by custom-filter
posts = posts.filter(filterFunc);
if (posts.length <= 0) {
feed.autodiscovery = false;
return;
}
if (limit) posts = posts.limit(limit);
let url = urlCfg;
if (url[url.length - 1] !== "/") url += "/";
let icon = "";
if (iconCfg) icon = full_url_for.call(this, iconCfg);
else if (email) icon = gravatar(email);
const feed_url = full_url_for.call(this, path);
const data = template.render({
config,
url,
icon,
posts,
feed_url,
});
return {
path,
data,
};
};
/_config.yml
もいじる。↓の設定を追加。
add_custom_rss:
figure_atom_path: "atom_figure.xml"
figure_review_atom_path: "atom_figure_review.xml"
/themes/landscape/_config.yml
もいじる。
↓を追加。/_config.yml
の記述とズレないように注意。
# Custom RSS
## See `/_config.yml`.
rss_figure: /atom_figure.xml
rss_figure_review: /atom_figure_review.xml
head.ejs
を↓のようにする。
theme.rss
が既存部分。theme.rss_figure
とtheme.rss_figure_review
が追加部分ね。
<% if (theme.rss){ %>
<link rel="alternate" href="<%= url_for(theme.rss) %>" title="<%= config.title %>" type="application/atom+xml">
<% } %>
<% if (theme.rss_figure){ %>
<link rel="alternate" href="<%= url_for(theme.rss_figure) %>" title="<%= config.title + ' tag_figure' %>" type="application/atom+xml">
<% } %>
<% if (theme.rss_figure_review){ %>
<link rel="alternate" href="<%= url_for(theme.rss_figure_review) %>" title="<%= config.title + ' tag_figure-review' %>" type="application/atom+xml">
<% } %>
同じノリでheader.ejs
も↓のようにする。
<% if (theme.rss){ %>
<a id="nav-rss-link" class="nav-icon" href="<%- url_for(theme.rss) %>" title="<%= __('rss_feed') %>"></a>
<% } %>
<% if (theme.rss_figure){ %>
<a id="nav-rss-figure-link" class="nav-icon" href="<%- url_for(theme.rss_figure) %>" title="<%= __('rss_figure_feed') %>"></a>
<% } %>
<% if (theme.rss_figure_review){ %>
<a id="nav-rss-figure-review-link" class="nav-icon" href="<%- url_for(theme.rss_figure_review) %>" title="<%= __('rss_figure_review_feed') %>"></a>
<% } %>
header.styl
を↓のようにする。
#nav-rss-figure-link
&:before
content: "\f143"
#nav-rss-figure-review-link
&:before
content: "\f143"
各言語用のキーワード名定義ファイルもいじる。
ja.yml
に↓を追加する。他の言語用のyml
ファイルはお好みで。
rss_figure_feed: RSSフィード(フィギュア)
rss_figure_review_feed: RSSフィード(フィギュアレビュー)
最後に、clean&generateすればOK。
styl
をいじったので、clean
が必須。注意。
add_custom_rss.js
とgenerator.js
のざっくり設計解説add_custom_rss.js
は本家様と結構変えている
generator.js
で実施generator.js
は本家様とほぼ同じ
atom.xml
はnode_module/hexo-generator-feed/
の直下を直接見るようにheader.styl
のざっくり解説いじる理由は、RSSフィードへのリンクのアイコンを設定するため。
なお、全記事用RSSとフィギュア用RSSとで区別できるようにした。
"_f09e"
が全記事用、"_f143"
がフィギュア用。
アイコンの絵面は
Awesome Fontの公式ページ
で調べられる。
hexo.extend.generator.register("atom_figure" ...
の"atom_figure"
の文字列は好きに決めて良いようだ。
てっきり、特定のキーワードに反応して関数実行するのかと思ったが、違うみたい。