mirror of
https://github.com/Wanxp/obsidian-douban.git
synced 2026-04-04 00:28:43 +08:00
docs: add documents website
This commit is contained in:
parent
dd1648c20a
commit
16b9ff581d
2
.gitignore
vendored
2
.gitignore
vendored
@ -20,3 +20,5 @@ data.json
|
||||
|
||||
# Exclude macOS Finder (System Explorer) View States
|
||||
.DS_Store
|
||||
doc/.vitepress/dist
|
||||
doc/.vitepress/cache
|
||||
|
||||
@ -21,13 +21,13 @@
|
||||
|
||||
Bring your data from [Douban]() to Your [Obsidian](https://obsidian.md/)
|
||||
Including your _Movie, Book, Music, Teleplay, Note, Game_ even your personal State and Comment
|
||||

|
||||

|
||||
|
||||
---
|
||||
If you want some features or have any questions about this plugin, create issues or join the development is welcome or ⭐Star
|
||||
|
||||
- [Bugs, Issues, & Feature Requests](https://github.com/Wanxp/obsidian-douban/issues)
|
||||
- Read Other Languages: English | [简体中文](../README.md)
|
||||
- Read Other Languages: English | [简体中文](README.md)
|
||||
|
||||
## Target
|
||||
- [x] Sync Personal Movie/TV/Book/Music
|
||||
@ -36,23 +36,23 @@ If you want some features or have any questions about this plugin, create issues
|
||||
- [x] Custom Variables
|
||||
|
||||
## 效果
|
||||
1. 结合Timeline插件 __构建个人观影时间线__,请参照[结合timeline插件实现时间线效果](./Obsidian-Douban-TimeLine.md)
|
||||

|
||||
1. 结合Timeline插件 __构建个人观影时间线__,请参照[结合timeline插件实现时间线效果](doc/Obsidian-Douban-TimeLine.md)
|
||||

|
||||
<!--2. 结合DataView插件,__构建个人电子书架(书库数据)__,请参照[结合dateview插件实现个人书架效果](./doc/Obsidian-Douban-DataView.md))-->
|
||||
2. 结合主题 __构建类豆瓣网页效果__,请参照[结合Blue Topaz实现网页效果](./Obsidian-Douban-BlueTopaz.md)
|
||||

|
||||
2. 结合主题 __构建类豆瓣网页效果__,请参照[结合Blue Topaz实现网页效果](doc/Obsidian-Douban-BlueTopaz.md)
|
||||

|
||||
|
||||
## How to use
|
||||
### Sync
|
||||
- Sync Data From Douban
|
||||
Sync data from Douban (to learn how to use the TimeLine plugin to build a reading/movie watching timeline, please refer to [here](Obsidian-Douban-TimeLine.en.md)).
|
||||

|
||||

|
||||
### Search
|
||||
Use the following method: Enter <kbd>Ctrl</kbd> + <kbd>P</kbd>, enter "Douban", select search and use
|
||||
- Search Data And Create Note
|
||||
- Search Data By File Name
|
||||
- Search Movie By Input Text
|
||||

|
||||

|
||||
|
||||
|
||||
## Support Field
|
||||
@ -119,9 +119,7 @@ Use the following method: Enter <kbd>Ctrl</kbd> + <kbd>P</kbd>, enter "Douban",
|
||||
7. Enjoy your develop
|
||||
|
||||
## Community
|
||||
<img src="img/obsidian-douban-qq-qr_code.svg" width="300px">
|
||||
<img src="https://picture-bed-public.wanxuping.com/obsidian-douban/wechat_group.png" width="245px">
|
||||
|
||||
<img src="doc/img/obsidian-douban-qq-qr_code.svg" width="300px"> <img src="doc/img/wechat_group.png" width="245px">
|
||||
|
||||
## Disclaimer
|
||||
1. This program does not crawl any content such as books and videos, and is only for technical research purposes. It does not violate the copyright of authors of books and videos or the official interests of Douban. If there is any infringement, please contact me to delete it.
|
||||
10
README.md
10
README.md
@ -32,7 +32,7 @@
|
||||
如果觉得喜欢或对您有帮助,欢迎一键三连-点亮 ⭐Star
|
||||
|
||||
- [异常, 问题 & 新的想法](https://github.com/Wanxp/obsidian-douban/issues)
|
||||
- 阅读其它语言的介绍请点击 [English](./doc/README.en.md) | 简体中文
|
||||
- 阅读其它语言的介绍请点击 [English](README.en.md) | 简体中文
|
||||
|
||||
## 功能
|
||||
- ☑️ 导入电影、电视剧、书籍、音乐、游戏、日记
|
||||
@ -42,6 +42,7 @@
|
||||
- ⬜ 支持图床自定义
|
||||
- ☑️ 支持自定义参数
|
||||
- ☑️ 支持移动端导入
|
||||
- ⬜ 支持使用AI大模型ChatGPT、Deepseek、Ollama分析导入
|
||||
|
||||
## 效果
|
||||
1. 结合Timeline插件 __构建个人观影时间线__,请参照[结合timeline插件实现时间线效果](./doc/Obsidian-Douban-TimeLine.md)
|
||||
@ -120,7 +121,7 @@
|
||||
3. 在obsidian插件中心开启当前插件功能
|
||||
|
||||
## 如何开发调试
|
||||
|
||||
### 开发
|
||||
1. 进入你的Obsidian测试文档文件夹下的`/.obsidian/plugins/`
|
||||
2. 克隆代码
|
||||
`git clone git@github.com:Wanxp/obsidian-douban.git`
|
||||
@ -134,7 +135,10 @@
|
||||
`npm run dev`
|
||||
7. 进入Obsidian插件中心重新加载当前插件
|
||||
8. 享受开发吧
|
||||
|
||||
#### 文档
|
||||
```shell
|
||||
npm run docs:dev
|
||||
```
|
||||
## 支持开发者
|
||||
如果觉得插件对你有帮助,欢迎请我喝杯咖啡,让我有更多的动力去维护和更新插件
|
||||
|
||||
|
||||
11
ai/other/ACTION_提示词.md
Normal file
11
ai/other/ACTION_提示词.md
Normal file
@ -0,0 +1,11 @@
|
||||
编写github action ,完成以下目标:
|
||||
1. 当文件mainfest.json文件发生变更时才运行
|
||||
2. 提供node18 环境
|
||||
3. 执行npm install
|
||||
4. 执行npm run build
|
||||
5. 提取 package.json中的版本
|
||||
6. 将当前master创建为版本的tag
|
||||
7. 发布到github release 预发布版本,且版本的名称为当前版本
|
||||
8. 发布的信息从commit中提取
|
||||
9. 发布的内容为生成的main.js、mainfest.json、style.css 三个文件
|
||||
10. 输出内容: 发布预发布版本{版本}正常
|
||||
56
doc/.vitepress/config.mts
Normal file
56
doc/.vitepress/config.mts
Normal file
@ -0,0 +1,56 @@
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
title: "Obsidian Douban",
|
||||
description: "Plugin for obsidian to manage your douban data",
|
||||
themeConfig: {
|
||||
lang: 'zh-CN',
|
||||
search: {
|
||||
provider: 'local'
|
||||
},
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
logo: '/obsidian-douban-logo.png',
|
||||
nav: [
|
||||
{ text: '首页', link: '/' },
|
||||
{ text: '效果展示', items: [
|
||||
{ text: '时间线效果', link: '/Obsidian-Douban-TimeLine' },
|
||||
{ text: '类网页效果', link: '/Obsidian-Douban-BlueTopaz' },
|
||||
{ text: '书架效果', link: 'Obsidian-Douban-DataView-Jump' }
|
||||
] },
|
||||
{ text: '作者', link: 'https://wxp.hk' },
|
||||
|
||||
],
|
||||
|
||||
sidebar: [
|
||||
{
|
||||
text: '如何安装', link: '/10_install'
|
||||
},
|
||||
{ text: '使用说明', link: '/20_howtouse_10_detail' },
|
||||
{ text: '登录方式', link: '/20_howtouse_25_setting_login_douban_cookie' },
|
||||
{ text: '图床配置', link: '/20_howtouse_30_picturebed' },
|
||||
{ text: '功能支持', link: '/30_function_10' },
|
||||
{ text: '可用参数', link: '/30_function_20_support_variables' },
|
||||
{ text: '时间线效果', link: '/Obsidian-Douban-TimeLine' },
|
||||
{ text: '类网页效果', link: '/Obsidian-Douban-BlueTopaz' },
|
||||
{ text: '书架效果', link: 'Obsidian-Douban-DataView-Jump' },
|
||||
{ text: '数据影响', link: '/80_others_20_effect' },
|
||||
{ text: '免责声明', link: '/80_others_disclaimer' },
|
||||
{ text: '开发调试', link: '/70_develop' },
|
||||
{ text: '反馈建议', link: '/97_issues' },
|
||||
{ text: '支持作者', link: '/99_support' },
|
||||
|
||||
|
||||
],
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/Wanxp/obsidian-douban' },
|
||||
// { icon: 'blog', link: 'https://github.com/Wanxp/obsidian-douban' }
|
||||
{
|
||||
icon: {
|
||||
png: '/img/wanxp-obsidian-douban-logo.png',
|
||||
},
|
||||
link: 'https://wxp.hk'
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
15
doc/.vitepress/theme/custom.css
Normal file
15
doc/.vitepress/theme/custom.css
Normal file
@ -0,0 +1,15 @@
|
||||
:root {
|
||||
--vp-c-brand-1: #646cff;
|
||||
--vp-c-brand-2: #747bff;
|
||||
--vp-home-hero-name-color: transparent;
|
||||
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #34fe48, #bd34fe);
|
||||
--vp-home-hero-image-background-image: linear-gradient( 135deg, #34fe48 10%, #bd34fe 100%);
|
||||
--vp-home-hero-image-filter: blur(80px);
|
||||
/*--vp-home-hero-image-background-image: linear-gradient(*/
|
||||
/* -45deg,*/
|
||||
/* #34fe48 50%,*/
|
||||
/* #bd34fe 50%*/
|
||||
/*);*/
|
||||
/*--vp-home-hero-image-filter: blur(44px);*/
|
||||
}
|
||||
|
||||
5
doc/.vitepress/theme/index.js
Normal file
5
doc/.vitepress/theme/index.js
Normal file
@ -0,0 +1,5 @@
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import './custom.css'
|
||||
|
||||
|
||||
export default DefaultTheme
|
||||
@ -1,17 +1,15 @@
|
||||
---
|
||||
title: 如何安装
|
||||
layout: default
|
||||
nav_order: 200
|
||||
---
|
||||
|
||||
## 如何安装
|
||||
### 从Obsidian插件中心
|
||||
# 如何安装
|
||||
## 从Obsidian插件中心
|
||||
1. 进入Obsidian插件中心
|
||||
2. 搜索obsidian-douban
|
||||
3. 安装
|
||||
4. 开启插件
|
||||
|
||||
### 手动安装
|
||||
## 手动安装
|
||||
|
||||
1. 从[Github release](https://github.com/Wanxp/obsidian-douban/releases) 页面下载 `main.js`, `manifest.json`, `styles.css`
|
||||
2. 将下载的文件复制到你的Obsidian文档根目录下的`/.obsidian/plugins/obsidian-douban`路径,若不存在则新建文件夹(注意.obsidian文件夹可能是个隐藏为文件夹)
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
---
|
||||
title: 使用说明
|
||||
layout: default
|
||||
nav_order: 300
|
||||
parent: 如何使用
|
||||
---
|
||||
## 如何使用
|
||||
## 搜索
|
||||
# 如何使用
|
||||
# 搜索
|
||||
使用方式: 输入<kbd>Ctrl</kbd> + <kbd>P</kbd>,输入“豆瓣”或“Douban”,选择搜索并使用
|
||||
- 搜索数据并创建笔记
|
||||
- 通过当前文件名搜索
|
||||
@ -13,6 +12,6 @@ parent: 如何使用
|
||||

|
||||
|
||||
|
||||
## 同步
|
||||
# 同步
|
||||
- 同步个人的观影、观剧、阅读、游戏、音乐记录
|
||||

|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
---
|
||||
title: 设置
|
||||
layout: default
|
||||
nav_order: 350
|
||||
parent: 如何使用
|
||||
---
|
||||
|
||||
## 设置
|
||||
# 设置
|
||||
- 设置豆瓣账号(可选,可使用少部分功能)
|
||||
- 设置导入模板(可选,不设置的情况下使用默认模板)
|
||||
- 设置导入路径(可选,不设置的情况下使用默认路径)
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
---
|
||||
title: Cookie登录Douban
|
||||
layout: default
|
||||
nav_order: 350
|
||||
parent: 如何使用
|
||||
---
|
||||
|
||||
# 登录方式
|
||||
Obsidian-Douban插件提供了两种登录方式,扫码登录和Cookie登录。扫码登录是推荐的方式,但如果扫码登录失败,可以使用Cookie登录。
|
||||
## 扫码登录
|
||||
扫码登录是Obsidian-Douban插件的默认登录方式,适用于大多数用户。扫码登录的步骤如下:
|
||||
1. 在Obsidian-Douban插件设置中点击`登录按钮`
|
||||
2. 弹出扫码登录窗口
|
||||
3. 使用手机或其他设备的豆瓣APP 扫描二维码
|
||||
4. 在手机上确认登录
|
||||
5. 登录成功后,Obsidian-Douban插件会自动获取您的豆瓣账号信息
|
||||
## Cookie登录Douban
|
||||
此方式仅在Obsidian-Douban中点击`登录按钮`,弹窗后,扫码登录失败的用户
|
||||
### 操作
|
||||
|
||||
@ -1,22 +1,21 @@
|
||||
---
|
||||
title: 图床
|
||||
layout: default
|
||||
nav_order: 380
|
||||
parent: 如何使用
|
||||
---
|
||||
|
||||
## 图床
|
||||
### PicGo
|
||||
#### 设置步骤
|
||||
# 图床
|
||||
## PicGo
|
||||
### 设置步骤
|
||||
1. 安装并下载PicGo图床软件
|
||||
2. 设置PicGo图床
|
||||
3. (由于Obsidian-Douban是通过剪贴板上传图片的)需要在PicGo设置中开启剪贴板上传
|
||||
4. 需要设置Server,开启并设置 端口36677
|
||||
5. 设置完成之后,可以尝试点击PicGo主界面的`剪贴板上传`按钮,验证是否可以上传图片
|
||||
6. 若在Obsidian-Douban设置中使用PicGo上传图片至图床,则每次导入书影音数据前,需要保证提前打开了PicGo软件
|
||||
#### 注意事项
|
||||
### 注意事项
|
||||
Obsidian-Douban插件使用PicGo上传图片至图床仅在Linux系统下测试通过,其他系统未测试,其它系统有问题欢迎及时反馈
|
||||
##### Linux
|
||||
#### Linux
|
||||
1. x11图形界面下,还需要安装xclip软件,否则无法使用剪贴板上传图片
|
||||
2. wayland图形界面下, 还需要安装wl-clipboard软件,否则无法使用剪贴板上传图片
|
||||
3. 若无法上传图片,可尝试开启PicGo软件设置中的`使用内置剪贴板上传`选项
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
---
|
||||
title: 基础功能
|
||||
layout: default
|
||||
nav_order: 400
|
||||
parent: 功能
|
||||
---
|
||||
## 功能
|
||||
# 功能
|
||||
- ☑️ 导入电影、电视剧、书籍、音乐、游戏、日记
|
||||
- ☑️ 同步个人听过/看过的电影、电视剧、书籍、音乐
|
||||
- ☑️ 同步个人听过/看过的电影、电视剧、书籍、音乐、游戏
|
||||
- ☑️ 导入个人的评论,评论时间,阅读状态,个人评分
|
||||
- ☑️ 支持保存封面至本地
|
||||
- ☑️ 支持保存封面至本地/图床
|
||||
- ⬜ 支持图床自定义
|
||||
- ☑️ 支持自定义参数
|
||||
- ☑️ 支持移动端导入
|
||||
- ⬜ 支持使用AI大模型ChatGPT、Deepseek、Ollama分析导入
|
||||
@ -1,11 +1,10 @@
|
||||
---
|
||||
title: 支持的参数
|
||||
layout: default
|
||||
nav_order: 500
|
||||
parent: 功能
|
||||
---
|
||||
|
||||
## 支持的字段
|
||||
# 支持的字段
|
||||
(若有缺少想导入的字段, 欢迎提issues反馈)
|
||||
|
||||
| 字段 | 电影 | 电视剧 | 书籍 | 音乐 | 日记 | 游戏 | 人物 |
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
---
|
||||
title: 效果介绍
|
||||
layout: default
|
||||
nav_order: 450
|
||||
parent: 特殊效果
|
||||
---
|
||||
|
||||
## 效果
|
||||
# 效果
|
||||
1. 结合Timeline插件 __构建个人观影时间线__,请参照[结合timeline插件实现时间线效果](Obsidian-Douban-TimeLine)
|
||||

|
||||
<!--2. 结合DataView插件,__构建个人电子书架(书库数据)__,请参照[结合dateview插件实现个人书架效果](Obsidian-Douban-DataView.md))-->
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
---
|
||||
title: 开发
|
||||
layout: default
|
||||
nav_order: 700
|
||||
---
|
||||
|
||||
## 如何开发调试
|
||||
# 如何开发调试
|
||||
|
||||
1. 进入你的Obsidian测试文档文件夹下的`/.obsidian/plugins/`
|
||||
2. 克隆代码
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
---
|
||||
title: 数据影响
|
||||
layout: default
|
||||
nav_order: 800
|
||||
parent: 其它
|
||||
---
|
||||
|
||||
## 数据影响
|
||||
# 数据影响
|
||||
注意: 除了在同步书影音数据时勾选 `替换同名文档` 有可能会修改同路径同文档名的笔记外,其余操作均不会修改已有笔记。
|
||||
|
||||
| 操作 | 条件 | 影响 | 举例 |
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
---
|
||||
title: 鸣谢
|
||||
layout: default
|
||||
nav_order: 810
|
||||
parent: 其它
|
||||
---
|
||||
## 鸣谢
|
||||
### IDE支持
|
||||
# 鸣谢
|
||||
## IDE支持
|
||||
[<image src="img/jb_beam.svg"> </image>](https://www.jetbrains.com/?from=obsidian-douban)
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
---
|
||||
title: 免责声明
|
||||
layout: default
|
||||
nav_order: 820
|
||||
parent: 其它
|
||||
---
|
||||
|
||||
## 免责声明
|
||||
# 免责声明
|
||||
1. 建议使用本插件前,一定要至少有一种方式备份你的数据,以防万一。
|
||||
2. 本程序没有爬取任何书影音等内容,只供技术研究使用。没有侵犯书影音作者版权和豆瓣官方利益。如有任何侵权行为,请联系我删除。
|
||||
3. 本程序仅供学习交流使用。
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
---
|
||||
title: 反馈与建议
|
||||
layout: default
|
||||
nav_order: 950
|
||||
---
|
||||
|
||||
## 反馈与建议
|
||||
# 反馈与建议
|
||||
如果你有任何问题或建议,欢迎在提交[Issues](https://github.com/Wanxp/obsidian-douban/issues)
|
||||
|
||||
|
||||
|
||||
@ -1,18 +1,17 @@
|
||||
---
|
||||
title: 支持
|
||||
layout: default
|
||||
nav_order: 1000
|
||||
---
|
||||
|
||||
## 支持
|
||||
# 支持
|
||||
愿世界充满爱与和平!
|
||||
如果觉得喜欢或对您有帮助,欢迎请我喝杯咖啡,让我有更多的动力去维护和更新插件
|
||||
|
||||

|
||||
|
||||
## 交流社群
|
||||
<img src="img/obsidian-douban-qq-qr_code.svg" width="300px">
|
||||
<img src="img/wechat_group.png" width="245px">
|
||||
<img src="/img/obsidian-douban-qq-qr_code.svg" width="300px" style="display: inline-block;"><img src="/img/wechat_group.png" width="245px" style="display: inline-block;">
|
||||
|
||||
|
||||
或者[邮件联系我](mailto:977741432@qq.com)
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem "jekyll", "~> 4.3.3" # installed by `gem jekyll`
|
||||
gem "jekyll" # installed by `gem jekyll`
|
||||
# gem "webrick" # required when using Ruby >= 3 and Jekyll <= 4.2.2
|
||||
|
||||
gem "just-the-docs", "0.8.2" # pinned to the current release
|
||||
gem "just-the-docs" # pinned to the current release
|
||||
# gem "just-the-docs" # always download the latest release
|
||||
|
||||
gem 'json'
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
---
|
||||
title: 类豆瓣网页显示
|
||||
layout: default
|
||||
nav_order: 455
|
||||
parent: 特殊效果
|
||||
render_with_liquid: false
|
||||
|
||||
3
doc/Obsidian-Douban-DataView-Jump.md
Normal file
3
doc/Obsidian-Douban-DataView-Jump.md
Normal file
@ -0,0 +1,3 @@
|
||||
## 书架效果
|
||||
点击以下链接跳转至少数派
|
||||
[使用Obsidian打造个人图书馆!](https://sspai.com/post/85574)
|
||||
@ -1,70 +0,0 @@
|
||||
## 效果如下
|
||||

|
||||
## 适用人群
|
||||
1. 在豆瓣有标记/评论/评分的习惯的人
|
||||
比如看完电影,会在豆瓣进行评分或评论。或者阅读完的书籍,进行评分或评论。支持包含:电影、书籍、电视剧、音乐、游戏
|
||||
## 实现步骤
|
||||
1. 安装[Timeline](https://github.com/Darakah/obsidian-timelines)插件
|
||||
2. 安装[Obsidian-Douban](https://github.com/Wanxp/obsidian-douban)插件(本插件)
|
||||
3. 在Obsidian-Douban插件配置中登录Douban
|
||||
4. 配置同步需要的模板 电影/书籍的模板中的frontmatter,在frontmatter中 **增加** 特定tags(根据自己的需要指定),用于需要过滤成为timeline的笔记,如增加tags:`我看过的电影`
|
||||
```markdown
|
||||
---
|
||||
tags: 我看过的电影
|
||||
---
|
||||
````
|
||||
5. 同时,在电影/书籍... 模板中的 **最后增加** timeline插件需要的html标签如下:
|
||||
```html
|
||||
<span class='ob-timelines' data-date='{{myCollectionDate}}'
|
||||
data-title='{{title}}' data-img='{{image}}'
|
||||
data-class = "custom-my-movie-time-line">{{myComment}} |简介: {{desc}}
|
||||
</span>
|
||||
```
|
||||
6. 选择上述模板导入 电影/书籍...,操作方式是打开obsidian命令窗口,输入豆瓣,找到导入功能,在导入界面配置 选择模板进行导入
|
||||
7. 导入需要一定时间,每条内容导入需要15-30s左右,所有有导入完成后会有导入汇总
|
||||
8. 导入完成后,新建一个笔记,笔记内容加入timeline的代码块,代码块的内容就是你上面指定的tags的内容,如`我看过的电影`,代码块如下:
|
||||
````markdown
|
||||
```timeline
|
||||
我看过的电影
|
||||
```
|
||||
````
|
||||
9. 预览这个笔记就能看出已经出现了时间线
|
||||
## 模板参考
|
||||
### 电影
|
||||
````markdown
|
||||
---
|
||||
doubanId: {{id}}
|
||||
title: {{title}}
|
||||
type: {{type}}
|
||||
score: {{score}}
|
||||
myRate: {{myRate}}
|
||||
originalTitle: {{originalTitle}}
|
||||
genre: {{genre}}
|
||||
datePublished: {{datePublished}}
|
||||
director: {{director}}
|
||||
actor: {{actor}}
|
||||
author: {{author}}
|
||||
tags: {{type}}, 我看过的电影, {{myTags}}
|
||||
state: {{myState}}
|
||||
url: {{url}}
|
||||
createTime: {{currentDate}} {{currentTime}}
|
||||
collectionDate: {{myCollectionDate}}
|
||||
desc: {{desc}}
|
||||
---
|
||||
|
||||

|
||||
|
||||
Comment:
|
||||
---
|
||||
{{myComment}}
|
||||
|
||||
|
||||
<span class='ob-timelines' data-date='{{myCollectionDate}}'
|
||||
data-title='{{title}}' data-img='{{image}}'
|
||||
data-class = "custom-my-movie-time-line">{{myComment}} |简介: {{desc}}
|
||||
</span>
|
||||
````
|
||||
### 书籍、电视剧、音乐、游戏
|
||||
请参照电影模板
|
||||
## 更多
|
||||
参照讨论 [结合timeline插件的妙用](https://github.com/Wanxp/obsidian-douban/issues/19#issuecomment-1428307130)
|
||||
@ -1,6 +1,5 @@
|
||||
---
|
||||
title: 看剧时间线
|
||||
layout: default
|
||||
nav_order: 456
|
||||
parent: 特殊效果
|
||||
render_with_liquid: false
|
||||
|
||||
BIN
doc/img/wanxp-logo.png
Normal file
BIN
doc/img/wanxp-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
79
doc/index.md
79
doc/index.md
@ -1,53 +1,34 @@
|
||||
---
|
||||
title: 简介
|
||||
# https://vitepress.dev/reference/default-theme-home-page
|
||||
layout: home
|
||||
nav_order: 10
|
||||
|
||||
hero:
|
||||
name: "Obsidian Douban"
|
||||
text: "obsidian插件\n同步你的豆瓣书影音"
|
||||
tagline:
|
||||
image:
|
||||
src: /obsidian-douban-logo.png
|
||||
alt: Obsidian Douban Logo
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 开始使用
|
||||
link: /20_howtouse_10_detail
|
||||
- theme: alt
|
||||
text: 安装
|
||||
link: /10_install
|
||||
|
||||
features:
|
||||
- title: 搜索导入影音
|
||||
icon: 📘
|
||||
details: 搜索豆瓣中您喜欢的电影、电视剧、书籍、音乐、游戏等信息结构化并导入到Obsidian中
|
||||
link: /20_howtouse_10_detail
|
||||
- title: 同步个人数据
|
||||
icon: 🙋
|
||||
details: 登录后可同步个人的观影、观剧、阅读、游戏、音乐记录到您的Obsidian中
|
||||
link: /20_howtouse_10_detail
|
||||
- title: 建立个人书架
|
||||
icon: 📚
|
||||
details: 结合DataView生成,整合你的书籍,建立个人书架,统一管理
|
||||
link: /Obsidian-Douban-DataView-Jump
|
||||
---
|
||||
|
||||
|
||||
这是一款[Obsidian](https://obsidian.md/)的插件, 用于导入[豆瓣](https://www.douban.com/)中的 _电影、书籍、音乐、电视剧、日记、游戏
|
||||
甚至是你标记过的书影音, 包含你的评分、观看日期、评论、阅读状态等信息.
|
||||
|
||||

|
||||
|
||||
## 基本功能
|
||||
- ☑️ 导入电影、电视剧、书籍、音乐、游戏、日记
|
||||
- ☑️ 同步个人听过/看过的电影、电视剧、书籍、音乐、游戏
|
||||
- ☑️ 导入个人的评论,评论时间,阅读状态,个人评分
|
||||
- ☑️ 支持保存封面至本地/图床
|
||||
- ⬜ 支持图床自定义
|
||||
- ☑️ 支持自定义参数
|
||||
- ☑️ 支持移动端导入
|
||||
|
||||
## 支持
|
||||
如果觉得喜欢或对您有帮助,欢迎请我喝杯咖啡,让我有更多的动力去维护和更新插件
|
||||
|
||||

|
||||
|
||||
## 交流社群
|
||||
<img src="img/obsidian-douban-qq-qr_code.svg" width="300px">
|
||||
<img src="img/wechat_group.png" width="245px">
|
||||
|
||||
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Wanxp/obsidian-douban/releases/latest">
|
||||
<img src="https://img.shields.io/github/manifest-json/v/Wanxp/obsidian-douban?color=blue">
|
||||
</a>
|
||||
<img src="https://img.shields.io/github/release-date/Wanxp/obsidian-douban">
|
||||
<a href="https://github.com/Wanxp/obsidian-douban/blob/master/License">
|
||||
<img src="https://img.shields.io/github/license/Wanxp/obsidian-douban">
|
||||
</a>
|
||||
<img src="https://img.shields.io/github/downloads/Wanxp/obsidian-douban/total">
|
||||
<a href="https://github.com/Wanxp/obsidian-douban/issues">
|
||||
<img src="https://img.shields.io/github/issues/Wanxp/obsidian-douban">
|
||||
</a>
|
||||
<br>
|
||||
<img src="https://img.shields.io/tokei/lines/github/Wanxp/obsidian-douban">
|
||||
<a href="https://www.codefactor.io/repository/github/wanxp/obsidian-douban">
|
||||
<img src="https://www.codefactor.io/repository/github/wanxp/obsidian-douban/badge" alt="CodeFactor" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
[Just the Docs repo]: https://github.com/Wanxp/obsidian-douban
|
||||
|
||||
BIN
doc/obsidian-douban-logo.png
Normal file
BIN
doc/obsidian-douban-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 780 KiB |
3883
package-lock.json
generated
3883
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@ -7,7 +7,10 @@
|
||||
"dev": "node esbuild.config.mjs",
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json",
|
||||
"test": "jest"
|
||||
"test": "jest",
|
||||
"docs:dev": "vitepress dev doc",
|
||||
"docs:build": "vitepress build doc",
|
||||
"docs:preview": "vitepress preview doc"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
@ -23,7 +26,8 @@
|
||||
"obsidian": "latest",
|
||||
"ts-jest": "^28.0.5",
|
||||
"tslib": "2.3.1",
|
||||
"typescript": "^4.7.2"
|
||||
"typescript": "^4.7.2",
|
||||
"vitepress": "^1.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@notable/html2markdown": "^1.1.3",
|
||||
@ -32,4 +36,4 @@
|
||||
"follow-redirects": "^1.15.6",
|
||||
"schema-dts": "^1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -208,7 +208,7 @@ export const SearchTypeRecords: { [key in SupportType]: string } = {
|
||||
[SupportType.music]: i18nHelper.getMessage('MUSIC'),
|
||||
[SupportType.note]: i18nHelper.getMessage('NOTE'),
|
||||
[SupportType.game]: i18nHelper.getMessage('GAME'),
|
||||
// [SupportType.THEATER]: i18nHelper.getMessage('THEATER'),
|
||||
[SupportType.theater]: i18nHelper.getMessage('THEATER'),
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -44,6 +44,7 @@ export const DEFAULT_SETTINGS: DoubanPluginSetting = {
|
||||
{name: 'myType', value: 'note', field: SupportType.note},
|
||||
{name: 'myType', value: 'game', field: SupportType.game},
|
||||
{name: 'myType', value: 'teleplay', field: SupportType.teleplay},
|
||||
{name: 'myType', value: 'theater', field: SupportType.theater},
|
||||
],
|
||||
loginCookiesContent: '',
|
||||
loginHeadersContent: '',
|
||||
|
||||
@ -78,6 +78,10 @@ desc: {{desc}}
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
Menu:
|
||||
{{menu}}
|
||||
`,
|
||||
noteTemplateFileContent: `---
|
||||
doubanId: {{id}}
|
||||
@ -240,8 +244,12 @@ desc: {{desc}}
|
||||
|
||||

|
||||
|
||||
Comment:
|
||||
---
|
||||
Menu:
|
||||
{{menu}}
|
||||
|
||||
---
|
||||
Comment:
|
||||
{{myComment}}
|
||||
|
||||
`,
|
||||
|
||||
@ -171,7 +171,12 @@ export const DoubanSubjectStateRecords_KEY_WORD_TYPE: Map<string, SupportType> =
|
||||
['我玩过这个游戏', SupportType.game],
|
||||
['我想玩这个游戏', SupportType.game],
|
||||
['我在玩这个游戏', SupportType.game],
|
||||
['我最近在玩这个游戏', SupportType.game],]
|
||||
['我最近在玩这个游戏', SupportType.game],
|
||||
|
||||
['我最近看过这部电影', SupportType.movie],
|
||||
['我看过这部电影', SupportType.movie],
|
||||
['我想看这部电影', SupportType.movie],
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
import {CheerioAPI} from 'cheerio';
|
||||
import DoubanPlugin from "../../../main";
|
||||
import SchemaOrg from "src/org/wanxp/utils/SchemaOrg";
|
||||
import {DataValueType, PropertyName, SupportType} from "../../../constant/Constsant";
|
||||
import {moment} from "obsidian";
|
||||
import {TITLE_ALIASES_SPECIAL_CHAR_REG_G} from "../../../utils/YamlUtil";
|
||||
import {DataField} from "../../../utils/model/DataField";
|
||||
import DoubanAbstractLoadHandler from "../../data/handler/DoubanAbstractLoadHandler";
|
||||
import DoubanTheaterSubject from "../../data/model/DoubanTheaterSubject";
|
||||
import HandleContext from "../../data/model/HandleContext";
|
||||
import DoubanSubject from "../../data/model/DoubanSubject";
|
||||
import {UserStateSubject} from "../../data/model/UserStateSubject";
|
||||
|
||||
export default class DoubanTheaterAiLoadHandler extends DoubanAbstractLoadHandler<DoubanTheaterSubject> {
|
||||
constructor(doubanPlugin: DoubanPlugin) {
|
||||
super(doubanPlugin);
|
||||
}
|
||||
|
||||
getSupportType(): SupportType {
|
||||
return SupportType.theater;
|
||||
}
|
||||
|
||||
getHighQuantityImageUrl(fileName: string): string {
|
||||
return `https://img9.doubanio.com/view/photo/l/public/${fileName}`;
|
||||
}
|
||||
|
||||
getSubjectUrl(id:string):string{
|
||||
return `https://www.douban.com/location/drama/${id}/`;
|
||||
}
|
||||
|
||||
parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: DoubanTheaterSubject, context: HandleContext): void {
|
||||
variableMap.set("director", new DataField(
|
||||
"director",
|
||||
DataValueType.array,
|
||||
extract.director,
|
||||
extract.director.map(SchemaOrg.getPersonName).filter(c => c)
|
||||
));
|
||||
|
||||
variableMap.set("actor", new DataField(
|
||||
"actor",
|
||||
DataValueType.array,
|
||||
extract.actor,
|
||||
extract.actor.map(SchemaOrg.getPersonName).filter(c => c)
|
||||
));
|
||||
|
||||
variableMap.set("author", new DataField(
|
||||
"author",
|
||||
DataValueType.array,
|
||||
extract.author,
|
||||
extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c)
|
||||
));
|
||||
|
||||
variableMap.set("aliases", new DataField(
|
||||
"aliases",
|
||||
DataValueType.array,
|
||||
extract.aliases,
|
||||
extract.aliases.map(a => a.replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_'))
|
||||
));
|
||||
}
|
||||
|
||||
support(extract: DoubanSubject): boolean {
|
||||
return extract && extract.type && (extract.type.contains("舞台剧") || extract.type.contains("舞剧") || extract.type.contains("Theater") || extract.type.contains("theater"));
|
||||
}
|
||||
|
||||
analysisUser(html: CheerioAPI, context: HandleContext): { data: CheerioAPI, userState: UserStateSubject } {
|
||||
const rate = html('input#n_rating').val();
|
||||
const tagsStr = html('div#interest_sect_level > div.a_stars > span.color_gray').text().trim();
|
||||
const tags = tagsStr ? tagsStr.replace('标签:', '').trim().split(' ') : null;
|
||||
const stateWord = html('#interest_sect_level > h2').text().trim();
|
||||
const collectionDateStr = html('div#interest_sect_level > div.a_stars > span.mr10 > span.collection_date').text().trim();
|
||||
const userState1 = DoubanAbstractLoadHandler.getUserState(stateWord);
|
||||
const component = this.getPropertyValue(html, PropertyName.comment);
|
||||
const userState: UserStateSubject = {
|
||||
tags: tags,
|
||||
rate: rate ? Number(rate) : null,
|
||||
state: userState1,
|
||||
collectionDate: collectionDateStr ? moment(collectionDateStr, 'YYYY-MM-DD').toDate() : null,
|
||||
comment: component
|
||||
}
|
||||
return {data: html, userState: userState};
|
||||
}
|
||||
|
||||
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanTheaterSubject {
|
||||
const obj: DoubanTheaterSubject = new DoubanTheaterSubject();
|
||||
obj.id = this.getPropertyValue(html, PropertyName.id);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
@ -54,30 +54,35 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
||||
let frontMatterBefore = '';
|
||||
let frontMatterAfter = '';
|
||||
let result = '';
|
||||
|
||||
const variableMap = this.buildVariableMap(extract, context);
|
||||
this.parseUserInfo(template, variableMap, extract, context);
|
||||
this.parseVariable(template, variableMap, extract, context);
|
||||
|
||||
if (frontMatterStart > -1 && frontMatterEnd > -1) {
|
||||
frontMatterBefore = template.substring(0, frontMatterStart);
|
||||
frontMatter = template.substring(frontMatterStart, frontMatterEnd + 3);
|
||||
frontMatterAfter = template.substring(frontMatterEnd + 3);
|
||||
if (frontMatterBefore.length > 0) {
|
||||
frontMatterBefore = this.parsePartText(frontMatterBefore, extract, context);
|
||||
frontMatterBefore = this.parsePartText(frontMatterBefore, extract, context, variableMap);
|
||||
}
|
||||
if (frontMatterAfter.length > 0) {
|
||||
frontMatterAfter = this.parsePartText(frontMatterAfter, extract, context);
|
||||
frontMatterAfter = this.parsePartText(frontMatterAfter, extract, context, variableMap);
|
||||
}
|
||||
if (frontMatter.length > 0) {
|
||||
frontMatter = this.parsePartText(frontMatter, extract, context, TemplateTextMode.YAML);
|
||||
frontMatter = this.parsePartYml(frontMatter, extract, context, variableMap);
|
||||
}
|
||||
result = frontMatterBefore + frontMatter + frontMatterAfter;
|
||||
} else {
|
||||
result = this.parsePartText(template, extract, context);
|
||||
result = this.parsePartText(template, extract, context, variableMap);
|
||||
}
|
||||
let filePath = '';
|
||||
if (SearchHandleMode.FOR_CREATE == context.mode) {
|
||||
filePath = this.parsePartText(this.getFilePath(context), extract, context);
|
||||
filePath = this.parsePartPath(this.getFilePath(context), extract, context, variableMap);
|
||||
}
|
||||
let fileName = '';
|
||||
if (SearchHandleMode.FOR_CREATE == context.mode) {
|
||||
fileName = this.parsePartText(this.getFileName(context), extract, context);
|
||||
fileName = this.parsePartPath(this.getFileName(context), extract, context, variableMap);
|
||||
}
|
||||
return {content: result,filePath: filePath, fileName: fileName, subject:extract};
|
||||
}
|
||||
@ -106,7 +111,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
||||
|
||||
abstract getSupportType(): SupportType;
|
||||
|
||||
abstract parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: T, context: HandleContext, textMode: TemplateTextMode): void;
|
||||
abstract parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: T, context: HandleContext): void;
|
||||
|
||||
abstract support(extract: DoubanSubject): boolean;
|
||||
|
||||
@ -266,13 +271,25 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
||||
return s;
|
||||
}
|
||||
|
||||
private parsePartText(template: string, extract: T, context: HandleContext, textMode: TemplateTextMode = TemplateTextMode.NORMAL): string {
|
||||
const variableMap:Map<string, DataField> = new Map();
|
||||
private parsePartYml(template: string, extract: T, context: HandleContext, variableMap : Map<string, DataField>): string {
|
||||
return VariableUtil.replaceSubject(variableMap, template, this.getSupportType(), this.doubanPlugin.settingsManager, 'yml_text');
|
||||
}
|
||||
|
||||
private parsePartText(template: string, extract: T, context: HandleContext, variableMap : Map<string, DataField>): string {
|
||||
return VariableUtil.replaceSubject(variableMap, template, this.getSupportType(), this.doubanPlugin.settingsManager, 'text');
|
||||
}
|
||||
|
||||
private parsePartPath(template: string, extract: T, context: HandleContext, variableMap : Map<string, DataField>): string {
|
||||
return VariableUtil.replaceSubject(variableMap, template, this.getSupportType(), this.doubanPlugin.settingsManager, 'path');
|
||||
}
|
||||
|
||||
private buildVariableMap(extract: T, context: HandleContext) {
|
||||
const variableMap: Map<string, DataField> = new Map();
|
||||
for (const [key, value] of Object.entries(extract)) {
|
||||
if (!value) {
|
||||
continue;
|
||||
}
|
||||
const type:DataValueType = VariableUtil.getType(value);
|
||||
const type: DataValueType = VariableUtil.getType(value);
|
||||
if (key == 'score') {
|
||||
variableMap.set(DoubanParameterName.SCORE_STAR, new DataField(
|
||||
DoubanParameterName.SCORE_STAR,
|
||||
@ -320,14 +337,10 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
||||
currentDate,
|
||||
moment(currentDate).format(context.settings.timeFormat)
|
||||
));
|
||||
|
||||
this.parseUserInfo(template, variableMap, extract, context, textMode);
|
||||
this.parseVariable(template, variableMap, extract, context, textMode);
|
||||
return VariableUtil.replaceSubject(variableMap, template, this.getSupportType(), this.doubanPlugin.settingsManager);
|
||||
|
||||
return variableMap;
|
||||
}
|
||||
|
||||
private parseUserInfo(resultContent: string, variableMap:Map<string, DataField>, extract: T, context: HandleContext, textMode: TemplateTextMode) {
|
||||
private parseUserInfo(resultContent: string, variableMap:Map<string, DataField>, extract: T, context: HandleContext) {
|
||||
const userState = extract.userState;
|
||||
if ((resultContent.indexOf(DoubanUserParameter.MY_TAGS) >= 0 ||
|
||||
resultContent.indexOf(DoubanUserParameter.MY_RATING) >= 0 ||
|
||||
|
||||
@ -88,6 +88,9 @@ export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler<Do
|
||||
const idPattern = /(\d){5,10}/g;
|
||||
const id = idPattern.exec(url);
|
||||
|
||||
const trackItems = html('.track-list .track-items li');
|
||||
const tracks = Array.from(trackItems).map(item => html(item).text().trim());
|
||||
|
||||
const result: DoubanMusicSubject = {
|
||||
image: image,
|
||||
imageUrl: image,
|
||||
@ -104,11 +107,10 @@ export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler<Do
|
||||
genre: valueMap.has('genre') ? [valueMap.get('genre')] : [""],
|
||||
albumType: valueMap.has('albumType') ? valueMap.get('albumType') : "",
|
||||
medium: valueMap.has('medium') ? valueMap.get('medium') : "",
|
||||
barcode: valueMap.has('barcode') ? valueMap.get('barcode') : ""
|
||||
barcode: valueMap.has('barcode') ? valueMap.get('barcode') : "",
|
||||
menu: tracks
|
||||
};
|
||||
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -6,4 +6,5 @@ export default class DoubanMusicSubject extends DoubanSubject {
|
||||
medium: string;
|
||||
records: number;
|
||||
barcode: string;
|
||||
menu: string[];
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import DoubanSubject from "./DoubanSubject";
|
||||
|
||||
export default interface HandleResult {
|
||||
content:string
|
||||
filePath?:string
|
||||
fileName?:string
|
||||
subject?:DoubanSubject,
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ export function showFileExample(containerEl: HTMLElement, manager: SettingsManag
|
||||
document.createDiv('file-path-example')
|
||||
.innerHTML = `${i18nHelper.getMessage('121604')}<a href="https://book.douban.com/subject/2253379/">《简爱》</a>: ${VariableUtil.replaceSubject(EXAMPLE_SUBJECT_MAP,
|
||||
FileUtil.join(manager.plugin.settings.dataFilePath, manager.plugin.settings.dataFileNamePath + ".md"), SupportType.book,
|
||||
manager)}`;
|
||||
manager, 'path')}`;
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(i18nHelper.getMessage('120603'))
|
||||
|
||||
@ -301,6 +301,16 @@ ${i18nHelper.getMessage('122004')}
|
||||
<td>${i18nHelper.getMessage('310520')}</th>
|
||||
<td>${i18nHelper.getMessage('310620')}</th>
|
||||
<td>${i18nHelper.getMessage('310720')}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>${i18nHelper.getMessage('320111')}</th>
|
||||
<td>${i18nHelper.getMessage('310122')}</th>
|
||||
<td>${i18nHelper.getMessage('310222')}</th>
|
||||
<td>${i18nHelper.getMessage('310322')}</th>
|
||||
<td>${i18nHelper.getMessage('310422')}</th>
|
||||
<td>${i18nHelper.getMessage('310522')}</th>
|
||||
<td>${i18nHelper.getMessage('310622')}</th>
|
||||
<td>${i18nHelper.getMessage('310722')}</th>
|
||||
</tr>
|
||||
</table>`;
|
||||
|
||||
|
||||
@ -444,6 +444,7 @@ export default {
|
||||
'310118': `producer:出品方`,
|
||||
'310130': `出版年份`,
|
||||
'310121': `封面URL`,
|
||||
'310122': `menu:目录`,
|
||||
|
||||
|
||||
//电影
|
||||
@ -469,6 +470,7 @@ export default {
|
||||
'310220': `-`,
|
||||
'310230': `上映年份`,
|
||||
'310221': `封面URL`,
|
||||
'310222': `-`,
|
||||
|
||||
//电视剧
|
||||
'310301': `豆瓣ID`,
|
||||
@ -493,6 +495,7 @@ export default {
|
||||
'310320': `episode:集数`,
|
||||
'310330': `上映年份`,
|
||||
'310321': `封面URL`,
|
||||
'310322': `-`,
|
||||
|
||||
|
||||
//音乐
|
||||
@ -516,6 +519,7 @@ export default {
|
||||
'310418': `-`,
|
||||
'310430': `发行年份`,
|
||||
'310421': `封面URL`,
|
||||
'310422': `menu:目录`,
|
||||
|
||||
|
||||
//日记
|
||||
@ -539,6 +543,7 @@ export default {
|
||||
'310518': `-`,
|
||||
'310530': `发布年份`,
|
||||
'310521': `封面URL`,
|
||||
'310522': `-`,
|
||||
|
||||
//游戏
|
||||
'310601': `豆瓣ID`,
|
||||
@ -561,6 +566,7 @@ export default {
|
||||
'310618': `-`,
|
||||
'310630': `发行年份`,
|
||||
'310621': `封面URL`,
|
||||
'310622': `-`,
|
||||
|
||||
|
||||
//广播
|
||||
@ -583,7 +589,8 @@ export default {
|
||||
'310717': `-`,
|
||||
'310718': `-`,
|
||||
'310730': `-`,
|
||||
'310721': `封面URL`,
|
||||
'310721': `-`,
|
||||
'310722': `-`,
|
||||
|
||||
'320101': `扩展1`,
|
||||
'320102': `扩展2`,
|
||||
|
||||
@ -58,10 +58,15 @@ export const FileUtil = {
|
||||
/**
|
||||
* replace special characters for filename
|
||||
*/
|
||||
replaceSpecialCharactersForFileName(fileName: string): string {
|
||||
return fileName.replaceAll(/[\\/:*?"<>|]/g, '_');
|
||||
replaceSpecialCharactersForFileName(fileNameInput: string): string {
|
||||
let fileName = fileNameInput.replaceAll(/[\\/:*?"<>|]/g, '_');
|
||||
fileName = fileName.replaceAll(/[\n\r\t]/g, '_');
|
||||
fileName = fileName.replaceAll(/\s+/g, '_');
|
||||
fileName = fileName.replaceAll(/^\.+/g, '_'); // remove leading dots
|
||||
fileName = fileName.replaceAll(/\.+$/g, '_'); // remove trailing dots
|
||||
fileName = fileName.replaceAll(/_+/g, '_'); // remove duplicate underscores
|
||||
return fileName;
|
||||
},
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
@ -117,6 +117,8 @@ export default class StringUtil {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export const EscapeMap:Map< { [Symbol.replace](string: string, replaceValue: string): string; }, string> = new Map([
|
||||
|
||||
@ -8,18 +8,26 @@ import {DataValueType, SupportType} from "../constant/Constsant";
|
||||
import {DataField} from "./model/DataField";
|
||||
import {FieldVariable} from "./model/FieldVariable";
|
||||
import {CustomProperty} from "../douban/setting/model/CustomProperty";
|
||||
import {FileUtil} from "./FileUtil";
|
||||
|
||||
type TargetType = 'text' | 'path' | 'yml_text';
|
||||
|
||||
|
||||
export class VariableUtil {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
*
|
||||
* @param obj
|
||||
* @param content
|
||||
* @param subjectType
|
||||
* @param settingManager
|
||||
* @param targetType
|
||||
*/
|
||||
|
||||
static replaceSubject(obj: any, content: string, subjectType: SupportType, settingManager:SettingsManager): string {
|
||||
static replaceSubject(obj: any, content: string, subjectType: SupportType, settingManager:SettingsManager, targetType: TargetType): string {
|
||||
if (!content || !obj) {
|
||||
return content;
|
||||
}
|
||||
@ -28,12 +36,12 @@ export class VariableUtil {
|
||||
return content;
|
||||
}
|
||||
if (obj instanceof Map) {
|
||||
this.handleCustomVariable(subjectType, obj, settingManager)
|
||||
content = this.replaceMap(obj, allVariables, content, settingManager);
|
||||
this.handleCustomVariable(subjectType, obj, settingManager, 'text')
|
||||
content = this.replaceMap(obj, allVariables, content, settingManager, targetType);
|
||||
}else {
|
||||
const map = this.objToMap(obj);
|
||||
this.handleCustomVariable(subjectType, map, settingManager)
|
||||
content = this.replaceMap(map, allVariables, content, settingManager);
|
||||
this.handleCustomVariable(subjectType, map, settingManager, 'text')
|
||||
content = this.replaceMap(map, allVariables, content, settingManager, targetType);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
@ -44,9 +52,10 @@ export class VariableUtil {
|
||||
* @param obj
|
||||
* @param content
|
||||
* @param settingManager
|
||||
* @param targetType
|
||||
*/
|
||||
|
||||
static replace(obj: any, content: string, settingManager:SettingsManager): string {
|
||||
static replace(obj: any, content: string, settingManager:SettingsManager, targetType : TargetType): string {
|
||||
if (!content || !obj) {
|
||||
return content;
|
||||
}
|
||||
@ -55,10 +64,10 @@ export class VariableUtil {
|
||||
return content;
|
||||
}
|
||||
if (obj instanceof Map) {
|
||||
content = this.replaceMap(obj, allVariables, content, settingManager);
|
||||
content = this.replaceMap(obj, allVariables, content, settingManager, targetType);
|
||||
}else {
|
||||
const map = this.objToMap(obj);
|
||||
content = this.replaceMap(map, allVariables, content, settingManager); }
|
||||
content = this.replaceMap(map, allVariables, content, settingManager, targetType); }
|
||||
|
||||
return content;
|
||||
}
|
||||
@ -75,23 +84,24 @@ export class VariableUtil {
|
||||
* @param value
|
||||
* @param content
|
||||
* @param settingManager
|
||||
* @param targetType
|
||||
*/
|
||||
static replaceVariable(variable: FieldVariable, value: any, content: string, settingManager:SettingsManager): string {
|
||||
static replaceVariable(variable: FieldVariable, value: any, content: string, settingManager:SettingsManager, targetType: TargetType): string {
|
||||
if (!content) {
|
||||
return content;
|
||||
}
|
||||
//根据value的类型,替换对应的变量
|
||||
if (value instanceof Array) {
|
||||
content = this.replaceArray(variable, value, content, settingManager);
|
||||
content = this.replaceArray(variable, value, content, settingManager, targetType);
|
||||
} else if(value instanceof DataField) {
|
||||
content = this.replaceDataField(variable, value, content, settingManager);
|
||||
content = this.replaceDataField(variable, value, content, settingManager, targetType);
|
||||
} else {
|
||||
content = this.replaceString(variable, value, content, settingManager);
|
||||
content = this.replaceString(variable, value, content, settingManager, targetType);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
static replaceArray(variable: FieldVariable, value: any[], content: string, settingManager:SettingsManager): string {
|
||||
static replaceArray(variable: FieldVariable, value: any[], content: string, settingManager:SettingsManager, targetType: TargetType): string {
|
||||
if (!content) {
|
||||
return content;
|
||||
}
|
||||
@ -114,7 +124,7 @@ export class VariableUtil {
|
||||
}
|
||||
})
|
||||
.filter(v => v)
|
||||
.map(v => YamlUtil.handleText(v))
|
||||
.map(v => this.handleText(v, targetType))
|
||||
;
|
||||
const arrayValue = StringUtil.handleArray(strValues, arraySettings);
|
||||
content = content.replaceAll(variableStr, arrayValue);
|
||||
@ -125,19 +135,19 @@ export class VariableUtil {
|
||||
return `{{${key}}}`;
|
||||
}
|
||||
|
||||
static replaceString(variable: FieldVariable, value: any, content: string, settingManager:SettingsManager): string {
|
||||
static replaceString(variable: FieldVariable, value: any, content: string, settingManager:SettingsManager, targetType: TargetType): string {
|
||||
if (!content) {
|
||||
return content;
|
||||
}
|
||||
let strValue = value? value.toString() : "";
|
||||
strValue = YamlUtil.handleText(strValue);
|
||||
return content.replaceAll(variable.variable, strValue);
|
||||
return content.replaceAll(variable.variable, this.handleText(strValue, targetType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从key中提取 arrayName, 然后从settings中获取对应的ArraySetting
|
||||
* @param key
|
||||
* @private
|
||||
* @param content
|
||||
* @param settingManager
|
||||
*/
|
||||
private static getAllVariables(content: string, settingManager:SettingsManager): FieldVariable[] {
|
||||
const reg =/\{\{[a-zA-Z-0-9_.]+([(a-zA-Z-0-9)]+)?}}/g
|
||||
@ -161,6 +171,7 @@ export class VariableUtil {
|
||||
/**
|
||||
* 从key中提取 arrayName, 然后从settings中获取对应的ArraySetting
|
||||
* @param outTypeName
|
||||
* @param settingManager
|
||||
* @private
|
||||
*/
|
||||
private static getArraySetting(outTypeName: string, settingManager:SettingsManager): ArraySetting {
|
||||
@ -172,10 +183,10 @@ export class VariableUtil {
|
||||
}
|
||||
|
||||
|
||||
private static replaceMap(obj: Map<string, any>, allVariables:FieldVariable[], content: string, settingManager: SettingsManager) {
|
||||
private static replaceMap(obj: Map<string, any>, allVariables:FieldVariable[], content: string, settingManager: SettingsManager, targetType: TargetType) {
|
||||
allVariables.forEach(variable => {
|
||||
const value = obj.get(variable.key);
|
||||
content = this.replaceVariable(variable, value,content, settingManager);
|
||||
content = this.replaceVariable(variable, value,content, settingManager, targetType);
|
||||
});
|
||||
return content;
|
||||
}
|
||||
@ -199,7 +210,7 @@ export class VariableUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static replaceDataField(variable: FieldVariable, value: DataField, content: string, settingManager: SettingsManager) {
|
||||
private static replaceDataField(variable: FieldVariable, value: DataField, content: string, settingManager: SettingsManager, targetType: TargetType) {
|
||||
if (!content) {
|
||||
return content;
|
||||
}
|
||||
@ -209,19 +220,19 @@ export class VariableUtil {
|
||||
}
|
||||
switch (value.type) {
|
||||
case DataValueType.string:
|
||||
content = this.replaceString(variable, value.value, content, settingManager);
|
||||
content = this.replaceString(variable, value.value, content, settingManager, targetType);
|
||||
break;
|
||||
case DataValueType.number:
|
||||
content = content.replaceAll(variableStr, value.value.toString());
|
||||
content = content.replaceAll(variableStr, this.handleText(value.value.toString(), targetType));
|
||||
break;
|
||||
case DataValueType.date:
|
||||
content = content.replaceAll(variableStr, value.value);
|
||||
content = content.replaceAll(variableStr, this.handleText(value.value, targetType));
|
||||
break;
|
||||
case DataValueType.array:
|
||||
content = this.replaceArray(variable, value.value, content, settingManager);
|
||||
content = this.replaceArray(variable, value.value, content, settingManager, targetType);
|
||||
break;
|
||||
default:
|
||||
content = content.replaceAll(variableStr, value.value);
|
||||
content = content.replaceAll(variableStr, this.handleText(value.value, targetType));
|
||||
break;
|
||||
|
||||
}
|
||||
@ -231,11 +242,13 @@ export class VariableUtil {
|
||||
|
||||
/**
|
||||
* 处理自定义参数
|
||||
* @param template
|
||||
* @param context
|
||||
* @private
|
||||
* @param subjectType
|
||||
* @param variableMap
|
||||
* @param settingMananger
|
||||
* @param targetType
|
||||
*/
|
||||
static handleCustomVariable(subjectType: SupportType, variableMap:Map<string, DataField>, settingMananger: SettingsManager): void {
|
||||
static handleCustomVariable(subjectType: SupportType, variableMap:Map<string, DataField>, settingMananger: SettingsManager, targetType:TargetType): void {
|
||||
// @ts-ignore
|
||||
const customProperties: CustomProperty[] = settingMananger.getSetting('customProperties');
|
||||
if (!customProperties) {
|
||||
@ -252,7 +265,7 @@ export class VariableUtil {
|
||||
variableMap.set(key,
|
||||
new DataField(
|
||||
key, DataValueType.string, value,
|
||||
VariableUtil.replace(variableMap, value, settingMananger)));
|
||||
VariableUtil.replace(variableMap, value, settingMananger, targetType)));
|
||||
})
|
||||
}
|
||||
|
||||
@ -263,4 +276,16 @@ export class VariableUtil {
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
private static handleText(v: string, targetType: TargetType) {
|
||||
if (targetType === 'yml_text') {
|
||||
return YamlUtil.handleText(v);
|
||||
}
|
||||
if (targetType === 'text') {
|
||||
return v;
|
||||
}
|
||||
if (targetType === 'path') {
|
||||
return FileUtil.replaceSpecialCharactersForFileName(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user