├── .gitignore ├── .npmignore ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── index.ts ├── lib ├── generate.ts └── types.ts ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.log/ 3 | tmp/ 4 | coverage/ 5 | .idea/ 6 | test/ 7 | .parcel-cache/ 8 | dist/ 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | tmp/ 3 | coverage/ 4 | *.log 5 | .jshintrc 6 | .travis.yml 7 | node_modules/ 8 | .idea/ 9 | 10 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | node 版本: 2 | 3 | hexo 版本: 4 | 5 | hexo-douban 版本: 6 | 7 | douban id : 8 | 9 | 问题描述: 10 | 11 | 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 mythsman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hexo-douban 2 | 3 | 一个在 [Hexo](https://hexo.io) 页面中嵌入豆瓣个人主页的小插件. 4 | 5 | [![package version](https://badge.fury.io/js/hexo-douban.svg)](https://www.npmjs.com/package/hexo-douban) 6 | [![npm](https://img.shields.io/npm/dt/hexo-douban.svg)](https://www.npmjs.com/package/hexo-douban) 7 | [![GitHub license](https://img.shields.io/github/license/mythsman/hexo-douban.svg)](https://github.com/mythsman/hexo-douban/blob/master/LICENSE) 8 | 9 | [![NPM](https://nodei.co/npm/hexo-douban.png)](https://nodei.co/npm/hexo-douban/) 10 | 11 | ## 原理 12 | 13 | hexo-douban 目前升级到了 2.x 版本,将原先由插件客户端自行获取数据的逻辑抽到了一个隐藏的服务端中进行,以统一解决数据获取、数据缓存、风控对抗等问题,提高页面生成的成功率和效率。 14 | 15 | ## 安装 16 | 17 | node 版本要求 >= v18 18 | 19 | ```bash 20 | $ npm install hexo-douban --save 21 | ``` 22 | 23 | ## 配置 24 | 25 | 将下面的配置写入站点的配置文件 `_config.yml` 里(不是主题的配置文件). 26 | 27 | ### 精简配置 28 | 29 | ```yaml 30 | douban: 31 | id: 162448367 32 | book: 33 | title: "This is my book title" 34 | movie: 35 | title: "This is my movie title" 36 | game: 37 | title: "This is my game title" 38 | song: 39 | title: "This is my song title" 40 | ``` 41 | 42 | ### 完整配置 43 | 44 | ```yaml 45 | douban: 46 | id: 162448367 47 | builtin: false 48 | dynamic: false 49 | item_per_page: 10 50 | meta_max_line: 4 51 | customize_layout: page 52 | swup: false 53 | book: 54 | path: books/index.html 55 | title: "This is my book title" 56 | quote: "This is my book quote" 57 | actions: 58 | - do 59 | - wish 60 | - collect 61 | option: 62 | movie: 63 | path: movies/index.html 64 | title: "This is my movie title" 65 | quote: "This is my movie quote" 66 | actions: 67 | - do 68 | - wish 69 | - collect 70 | option: 71 | game: 72 | path: games/index.html 73 | title: "This is my game title" 74 | quote: "This is my game quote" 75 | actions: 76 | - do 77 | - wish 78 | - collect 79 | option: 80 | song: 81 | path: songs/index.html 82 | title: "This is my song title" 83 | quote: "This is my song quote" 84 | actions: 85 | - do 86 | - wish 87 | - collect 88 | option: 89 | ``` 90 | 91 | - **id**: 你的豆瓣 ID(纯数字格式,不是自定义的域名)。获取方法可以参考[怎样获取豆瓣的数字 ID ?](https://www.zhihu.com/question/19634899) 92 | - **builtin**: 是否将`hexo douban`命令默认嵌入进`hexo g`、`hexo s`,使其自动执行`hexo douban` 命令。默认关闭。 93 | - **dynamic**: 豆瓣页面是否在访问时实时请求接口。默认为 false,表示页面信息会在执行 hexo douban 命令时更新,优点是生成的页面不会受到后续接口可用性的影响,缺点是需要手动更新。如果设置为 true ,则会在页面访问时实时调用接口进行渲染,无需执行 hexo douban 命令更新页面,但是代价就是如果接口挂了,页面就会G。 94 | - **item_per_page**: 每页展示的条目数,默认 10 。 95 | - **meta_max_line**: 每个条目展示的详细信息的最大行数,超过该行数则会以 "..." 省略,默认 4 。 96 | - **customize_layout**: 自定义布局文件。默认值为 page 。无特别需要,留空即可。若配置为 `abcd`,则表示指定 `//theme/hexo-theme/layout/abcd.ejs` 文件渲染豆瓣页面。 97 | - **swup**: 是否兼容 [swup](https://swup.js.org/plugins/scripts-plugin/) 。支持 script 热加载,解决一些 single-page 主题的加载问题,默认 false 。 98 | - **path**: 生成页面后的路径,默认生成在 //yourblog/books/index.html 等下面。如需自定义路径,则可以修改这里。 99 | - **title**: 该页面的标题。 100 | - **quote**: 写在页面开头的一段话,支持 html 语法,可以为空。 101 | - **actions**: 一个字符串列表,表示生成的页面中的"已 X","想 X","X 过"的标签配置,默认会自动聚焦在第一个标签。可选项为: 'do','wish','collect'。 102 | - **option**: 该页面额外的 Front-matter 配置,参考[Hexo 文档](https://hexo.io/docs/front-matter.html)。无特别需要,留空即可。 103 | 104 | 如果只想显示某一个页面(比如 movie),那就把其他的配置项注释掉即可。 105 | 106 | ## 使用 107 | 108 | **展示帮助文档** 109 | 110 | ``` 111 | $ hexo douban -h 112 | Usage: hexo douban 113 | 114 | Description: 115 | Generate pages from douban 116 | 117 | Options: 118 | -b, --books Generate douban books only 119 | -g, --games Generate douban games only 120 | -m, --movies Generate douban movies only 121 | -s, --songs Generate douban songs only 122 | ``` 123 | 124 | **主动生成豆瓣页面** 125 | 126 | ``` 127 | $ hexo douban 128 | INFO Start processing 129 | INFO 0 (wish), 0 (do),0 (collect) game loaded in 729 ms 130 | INFO 0 (wish), 0 (do),20 (collect) song loaded in 761 ms 131 | INFO 2 (wish), 0 (do),136 (collect) book loaded in 940 ms 132 | INFO 30 (wish), 0 (do),6105 (collect) movie loaded in 4129 ms 133 | INFO Generated: books/index.html 134 | INFO Generated: movies/index.html 135 | INFO Generated: games/index.html 136 | INFO Generated: songs/index.html 137 | ``` 138 | 139 | 如果不加参数,那么默认参数为`-bgms`。当然,前提是配置文件中均有这些类型的配置。 140 | 141 | **需要注意的是**,通常大家都喜欢用`hexo d`来作为`hexo deploy`命令的简化,但是当安装了`hexo douban`之后,就不能用`hexo d`了,因为`hexo douban`跟`hexo deploy` 的前缀都是`hexo d`。 142 | 143 | 如果 builtin:false 时,执行 hexo g 之后发现将 douban 生成的页面删除了: 144 | 145 | ``` 146 | INFO Start processing 147 | INFO Files loaded in 343 ms 148 | INFO Deleted: games/index.html 149 | INFO Deleted: books/index.html 150 | INFO Deleted: movies/index.html 151 | INFO Deleted: songs/index.html 152 | ``` 153 | 154 | 那么重新执行 hexo clean 一下即可(原因是 db.json 的数据缓存)。 155 | 156 | 第一次使用 hexo douban 时,后台会异步进行数据获取,一般需要等待一段时间(后台访问你的标记页面)才能查到数据。顺利情况下,平均一个页面会花 10s。 157 | 158 | 例如如果你有 150 个想读、150 个已读、150 个在读的图书,每页 15 条,则共需要翻 30 页。那么大约需要等待 30\*10/60=5 分钟。如果长时间没有更新(一天以上),请及时提 issue 反馈。 159 | 160 | 后续如果你的豆瓣数据更新了,hexo douban 同样也会自动进行更新(同样需要等待一段时间才会查到更新数据),不过出于安全考虑,一个用户 id**每半小时至多只会同步一次**。 161 | 162 | 由于豆瓣本身深分页的 RT 过高(上万条目的翻页 RT 会到 15s 到 60s),为了防止系统同步压力过大,每个用户的每一类条目最多只会同步 1w 条。 163 | 164 | 如果 dynamic 设置为 true,则每次访问页面时都会向后端自动发起更新请求,无需手动执行 hexo douban 命令。 165 | 166 | ## 升级 167 | 168 | 我会不定期更新一些功能或者修改一些 Bug,所以如果想使用最新的特性,可以用下面的方法来更新: 169 | 170 | 1. 修改 package.json 内 hexo-douban 的版本号至最新 171 | 2. 重新安装最新版本`npm install hexo-douban --save` 172 | 173 | 或者使用`npm install hexo-douban --update --save`直接更新。 174 | 175 | ## 显示 176 | 177 | 如果上面的配置和操作都没问题,就可以在生成站点之后打开 `//yourblog/books` 和 `//yourblog/movies`, `//yourblog/games`, 来查看结果。 178 | 179 | ## 菜单 180 | 181 | 如果上面的显示没有问题就可以在主题的配置文件 `_config.yml` 里添加如下配置来为这些页面添加菜单链接. 182 | 183 | ```yaml 184 | menu: 185 | Home: / 186 | Archives: /archives 187 | Books: /books #This is your books page 188 | Movies: /movies #This is your movies page 189 | Games: /games #This is your games page 190 | Songs: /songs #This is your songs page 191 | ``` 192 | 193 | ## 通用环境 194 | 195 | 如果有非 hexo 环境的部署需求,则可以考虑以引入静态资源的方式接入 [idouban](https://github.com/mythsman/idouban) 。 196 | 197 | ## 接口 198 | 199 | 如果仅仅想对自己的豆瓣数据进行备份,可以尝试使用下面的接口,复用后端维护的数据提取服务 [mouban](https://github.com/mythsman/mouban) : 200 | 201 | ``` 202 | # 将 {your_douban_id} 改为你的豆瓣数字ID 203 | 204 | # 用户录入/更新 205 | 206 | https://mouban.mythsman.com/guest/check_user?id={your_douban_id} 207 | 208 | # 查询用户的读书评论 209 | 210 | https://mouban.mythsman.com/guest/user_book?id={your_douban_id}&action=wish 211 | 212 | https://mouban.mythsman.com/guest/user_book?id={your_douban_id}&action=do 213 | 214 | https://mouban.mythsman.com/guest/user_book?id={your_douban_id}&action=collect 215 | 216 | # 查询用户的电影评论 217 | 218 | https://mouban.mythsman.com/guest/user_movie?id={your_douban_id}&action=wish 219 | 220 | https://mouban.mythsman.com/guest/user_movie?id={your_douban_id}&action=do 221 | 222 | https://mouban.mythsman.com/guest/user_movie?id={your_douban_id}&action=collect 223 | 224 | # 查询用户的游戏评论 225 | 226 | https://mouban.mythsman.com/guest/user_game?id={your_douban_id}&action=wish 227 | 228 | https://mouban.mythsman.com/guest/user_game?id={your_douban_id}&action=do 229 | 230 | https://mouban.mythsman.com/guest/user_game?id={your_douban_id}&action=collect 231 | 232 | # 查询用户的音乐评论 233 | 234 | https://mouban.mythsman.com/guest/user_song?id={your_douban_id}&action=wish 235 | 236 | https://mouban.mythsman.com/guest/user_song?id={your_douban_id}&action=do 237 | 238 | https://mouban.mythsman.com/guest/user_song?id={your_douban_id}&action=collect 239 | ``` 240 | 241 | ## 他们在用 242 | 243 | 下面列举了在不同 hexo 主题下使用插件后的渲染结果,仅供参考。 244 | 245 | 如果您使用了本插件,也欢迎在 README.md 中提 PR 将您的网站添加进来,供后人参考。 246 | 247 | ### [hexo-theme-butterfly](https://github.com/jerryc127/hexo-theme-butterfly) 248 | 249 | - [七鳄の学习格 - 生在黑暗,行向光明ヾ(@^▽^@)ノ](https://blog.gmcj0816.top/books/) 250 | - [Ofra Serendipity](https://cmwlvip.github.io/movies/) 251 | - [冰糖盒子 - 冰糖的笔记本](https://cvki.cn/movies/) 252 | - [フサエ·キャンベル·木之下 - 天道酬勤功不唐捐](https://zipblog.top/movies/) 253 | - [个人生活感悟记录](https://www.ensoul.club/books/) 254 | - [week.wiki](https://week.wiki/movies/) 255 | - [CodeRain - 越努力,越幸运](https://code7rain.github.io/movies/) 256 | - [hangzl's Blog - 总之岁月漫长 然而值得等待](https://hangzl.xyz/movies/) 257 | - [Lmx0](https://www.lmx0.top/movies/) 258 | - [老胖叔 - JZ](https://laopangshu.top/movies/) 259 | - [来生拓己 オフィシャルサイト](https://kisugitakumi.net/movies/) 260 | - [果实 o 的博客 - 个人网站](https://www.shengshunyan.xyz/movies/) 261 | - [TFC 的个人博客](https://iqdxa.github.io/movies/) 262 | - [吕小布の博客 - MindCons](https://mindcons.cn/booklist/) 263 | - [Darler Space - 极速翱翔](https://blog.darler.cn/movies/) 264 | - [Evergarden](https://evergarden.moe/books/) 265 | - [现实的延续](https://www.intelland.cn/movies/) 266 | - [Gallifrey 的计算机学习日记 - 个人文章归档](https://gallifrey.asia/) 267 | - [Chen's Blog](https://chenxs.site/) 268 | 269 | ### [hexo-theme-matery](https://github.com/blinkfox/hexo-theme-matery) 270 | 271 | - [小法进阶](https://imouyang.com/books/) 272 | - [Peiqi Blog](https://jupeiqi.top/books/) 273 | 274 | ### [hexo-theme-next](https://github.com/theme-next/hexo-theme-next) 275 | 276 | - [Lyz's Blog - Never Give Up](https://blog.home999.cc/books) 277 | - [Sitch's Blog](https://sitchzou.com/movies/) 278 | 279 | ### [hexo-theme-stellar](https://github.com/xaoxuu/hexo-theme-stellar) 280 | 281 | - [是非题](https://www.shifeiti.com/about/movies/) 282 | - [MerryJingle](https://blog.pengfeima.cn/movies/) 283 | - [梅园小径](https://www.auntyang.cf/life/doubanmovies/) 284 | - [苏末了](https://sumorio.com/douban/movie/) 285 | 286 | ### [hexo-theme-volantis](https://github.com/volantis-x/hexo-theme-volantis) 287 | 288 | - [老梁有墨](https://www.laoliang.ink/book/) 289 | 290 | ### [hexo-theme-pure](https://github.com/cofess/hexo-theme-pure) 291 | 292 | - [fyupeng](https://lhx.cool/movies/) 293 | 294 | ### [hexo-theme-icarus](https://github.com/ppoffice/hexo-theme-icarus) 295 | 296 | - [There Hello](https://therehello.top/movies/) 297 | 298 | ### [hexo-theme-fluid](https://github.com/fluid-dev/hexo-theme-fluid) 299 | 300 | - [Loststar's blog](https://blog.loststar.tech/movies) 301 | - [MerickBao の博客](https://merickbao.github.io/movies/) 302 | 303 | ## 免责声明 304 | 305 | 本项目仅供学习交流使用,不得用于任何商业用途。 306 | 307 | 数据来源于互联网公开内容,没有获取任何私有和有权限的信息(个人信息等),由此引发的任何法律纠纷与本人无关。 308 | 309 | ## 反馈 310 | 311 | 系统刚上线,可能还不够完善。如果大家在使用的过程中数据有问题、或者有什么问题和意见,欢迎随时提 issue。 312 | 313 | 如果你觉得这个插件很好用,欢迎右上角点下 star ⭐️,表达对作者的鼓励。 314 | 315 | 如果你想了解数据获的实现方式,可以参考 [mouban](https://github.com/mythsman/mouban) 这个项目。 316 | 317 | ## Star History 318 | 319 | [![Stargazers over time](https://starchart.cc/mythsman/hexo-douban.svg)](https://starchart.cc/mythsman/hexo-douban) 320 | 321 | ## Lisense 322 | 323 | MIT 324 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | import { createWriteStream, mkdirSync } from "hexo-fs"; 3 | import createLogger from "hexo-log"; 4 | import { generate } from "./lib/generate"; 5 | import path from "path"; 6 | 7 | const supported_types = ["book", "movie", "game", "song"]; 8 | 9 | const log = createLogger({ 10 | debug: false, 11 | silent: false, 12 | }); 13 | 14 | // Register `hexo g` and `hexo s` 15 | supported_types.forEach((type) => { 16 | hexo.extend.generator.register(`${type}s`, function (locals) { 17 | if ( 18 | !this.config.douban || 19 | !this.config.douban[type] || 20 | !this.config.douban.builtin 21 | ) { 22 | return; 23 | } 24 | 25 | let path = this.config.douban[type].path; 26 | if (path) { 27 | this.config.douban[type].path = path.replace(/^\//, ""); 28 | } else { 29 | this.config.douban[type].path = `${type}s/index.html`; 30 | } 31 | return generate( 32 | this.config.lang, 33 | this.config.url, 34 | type, 35 | this.config.douban 36 | ) as any; 37 | }); 38 | }); 39 | 40 | const options = { 41 | options: [ 42 | { name: "-b, --books", desc: "Generate douban books only" }, 43 | { name: "-m, --movies", desc: "Generate douban movies only" }, 44 | { name: "-g, --games", desc: "Generate douban games only" }, 45 | { name: "-s, --songs", desc: "Generate douban songs only" }, 46 | ], 47 | }; 48 | 49 | // Register `hexo douban` 50 | hexo.extend.console.register( 51 | "douban", 52 | "Generate pages from douban", 53 | options, 54 | function (args) { 55 | if (!this.config.douban) { 56 | log.info("No douban config specified"); 57 | return; 58 | } 59 | if (!this.config.douban.id) { 60 | log.info("No douban id specified"); 61 | return; 62 | } 63 | 64 | let force_types: string[] = []; 65 | supported_types.forEach((supported_type) => { 66 | if ( 67 | (Object.keys(args).includes(supported_type[0]) || 68 | Object.keys(args).includes(`${supported_type}s`)) && 69 | this.config.douban[supported_type] 70 | ) { 71 | force_types.push(supported_type); 72 | } 73 | }); 74 | 75 | let enabled_types: string[] = []; 76 | 77 | if (force_types.length !== 0) { 78 | enabled_types = force_types; 79 | } else { 80 | supported_types.forEach((type) => { 81 | if (this.config.douban[type]) { 82 | enabled_types.push(type); 83 | } 84 | }); 85 | } 86 | 87 | if (enabled_types.length === 0) { 88 | log.info("No douban type specified"); 89 | return; 90 | } 91 | 92 | // Prepare path 93 | enabled_types.forEach((type) => { 94 | let path = this.config.douban[type].path; 95 | if (path) { 96 | this.config.douban[type].path = path.replace(/^\//, ""); 97 | } else { 98 | this.config.douban[type].path = `${type}s/index.html`; 99 | } 100 | 101 | hexo.extend.generator.register(type, function (locals) { 102 | return generate( 103 | this.config.lang, 104 | this.config.url, 105 | type, 106 | this.config.douban 107 | ) as any; 108 | }); 109 | }); 110 | 111 | const self = this; 112 | 113 | //Generate files 114 | self.load().then(function () { 115 | enabled_types.forEach((type) => { 116 | const publicDir = self.public_dir; 117 | const id = self.config.douban[type].path; 118 | mkdirSync(path.join(publicDir, id.replace("index.html", "")), { 119 | recursive: true, 120 | }); 121 | 122 | let stream = self.route.get(id); 123 | if (stream) { 124 | self.route.get(id).pipe(createWriteStream(path.join(publicDir, id))); 125 | log.info("Generated: %s", id); 126 | } 127 | }); 128 | }); 129 | } 130 | ); 131 | -------------------------------------------------------------------------------- /lib/generate.ts: -------------------------------------------------------------------------------- 1 | import idouban from "idouban"; 2 | import { DoubanConfig, TypeConfig } from "./types"; 3 | import createLogger from "hexo-log"; 4 | import { readFileSync } from "hexo-fs"; 5 | import { createRequire } from "module"; 6 | 7 | const template: string = `
8 | 9 | 11 | 13 | `; 14 | 15 | const log = createLogger({ 16 | debug: false, 17 | silent: false, 18 | }); 19 | 20 | export async function generate( 21 | lang: string, 22 | url: string, 23 | type: string, 24 | config: DoubanConfig 25 | ) { 26 | if (!config.item_per_page) { 27 | config.item_per_page = 10; 28 | } 29 | 30 | if (!config.meta_max_line) { 31 | config.meta_max_line = 4; 32 | } 33 | 34 | if (!config.customize_layout) { 35 | config.customize_layout = "page"; 36 | } 37 | 38 | const available_actions = ["do", "wish", "collect"]; 39 | const type_config = config[type] as TypeConfig; 40 | 41 | if (type_config.actions && type_config.actions.length !== 0) { 42 | type_config.actions = type_config.actions.filter((action) => 43 | available_actions.includes(action) 44 | ); 45 | if (type_config.actions.length === 0) { 46 | type_config.actions = available_actions; 47 | } 48 | } else { 49 | type_config.actions = available_actions; 50 | } 51 | 52 | const script = readFileSync( 53 | createRequire(__dirname).resolve("idouban/dist/index.js") 54 | ) as string; 55 | const style = readFileSync( 56 | createRequire(__dirname).resolve("idouban/dist/index.css") 57 | ) as string; 58 | const swup = config.swup ? "data-swup-reload-script" : ""; 59 | 60 | const init_config = { 61 | selector: "#idouban", 62 | lang: lang, 63 | douban_id: config.id, 64 | type: type, 65 | quote: type_config.quote, 66 | page_size: config.item_per_page, 67 | max_line: config.meta_max_line, 68 | }; 69 | 70 | if (config.dynamic) { 71 | init_config["actions"] = type_config.actions; 72 | } else { 73 | const startTime = new Date().getTime(); 74 | 75 | let data_list = await idouban.fetchData( 76 | config.id, 77 | url, 78 | type, 79 | type_config.actions 80 | ); 81 | init_config["data_list"] = data_list; 82 | const endTime = new Date().getTime(); 83 | 84 | log.info( 85 | `${data_list.map( 86 | (data) => data.action + "(" + data.items.length + ")" 87 | )} ${type} loaded in ${endTime - startTime} ms` 88 | ); 89 | } 90 | 91 | const init = `idouban.init(${JSON.stringify(init_config)})`; 92 | 93 | const dom = template 94 | .replace(/{{style}}/g, Buffer.from(style).toString("base64")) 95 | .replace(/{{script}}/g, Buffer.from(script).toString("base64")) 96 | .replace(/{{init}}/g, Buffer.from(init).toString("base64")) 97 | .replace(/{{swup}}/g, swup); 98 | 99 | return { 100 | path: type_config.path, 101 | data: Object.assign( 102 | { 103 | title: type_config.title, 104 | content: dom, 105 | slug: `${type}s`, 106 | }, 107 | type_config.option 108 | ), 109 | layout: [config.customize_layout, "post"], 110 | }; 111 | } 112 | -------------------------------------------------------------------------------- /lib/types.ts: -------------------------------------------------------------------------------- 1 | export interface TypeConfig { 2 | path: string; 3 | actions: string[]; 4 | title: string; 5 | quote: string; 6 | option: any; 7 | } 8 | 9 | export interface DoubanConfig { 10 | id: string; 11 | builtin: boolean; 12 | dynamic: boolean; 13 | item_per_page: number; 14 | meta_max_line: number; 15 | customize_layout: string; 16 | swup: boolean; 17 | book: TypeConfig; 18 | movie: TypeConfig; 19 | game: TypeConfig; 20 | song: TypeConfig; 21 | } 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hexo-douban", 3 | "version": "2.3.6", 4 | "description": "Generate douban pages of books , movies and games for Hexo.", 5 | "main": "dist/index.js", 6 | "targets": { 7 | "js": { 8 | "source": "index.ts", 9 | "distDir": "dist/", 10 | "optimize": true 11 | } 12 | }, 13 | "scripts": { 14 | "build": "parcel build --no-source-maps" 15 | }, 16 | "dependencies": { 17 | "hexo-fs": "4.1.1", 18 | "hexo-log": "3.2.0", 19 | "idouban": "1.1.3" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/mythsman/hexo-douban.git" 24 | }, 25 | "files": [ 26 | "dist" 27 | ], 28 | "keywords": [ 29 | "hexo-plugin", 30 | "books", 31 | "movies", 32 | "games", 33 | "songs", 34 | "hexo", 35 | "douban", 36 | "idouban" 37 | ], 38 | "author": "mythsman", 39 | "license": "MIT", 40 | "devDependencies": { 41 | "@types/hexo": "^3.8.12", 42 | "@types/hexo-log": "^0.2.6", 43 | "parcel": "^2.12.0" 44 | }, 45 | "bugs": { 46 | "url": "https://github.com/mythsman/hexo-douban/issues" 47 | }, 48 | "engines": { 49 | "node": ">= 18" 50 | }, 51 | "homepage": "https://github.com/mythsman/hexo-douban/" 52 | } 53 | --------------------------------------------------------------------------------