mirror of
https://github.com/Wanxp/obsidian-douban.git
synced 2026-04-05 17:48:42 +08:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 812fc17c5a | |||
|
|
e8a0d8a00c | ||
|
|
318aabb21b | ||
| a8094d7575 | |||
|
|
7ba1a7be0c | ||
|
|
4e8d3f1318 | ||
|
|
c375512903 | ||
|
|
99d4170626 | ||
|
|
297ccd33cf | ||
|
|
a0eccf7370 | ||
| 572907719b | |||
| ffc93a4a13 | |||
| 08749116f3 | |||
| 266cfb3901 | |||
| 7e57846f32 | |||
| 16b9ff581d | |||
| dd1648c20a | |||
| df4c4956f1 | |||
| c09f96d3b8 | |||
| a7b81bd189 | |||
| 9403fef320 | |||
| 001cb5dc3e | |||
| 711744e065 | |||
| 836c9c61b3 | |||
| f0b73c7d8b | |||
| 8556de0501 | |||
| 6481c69d81 | |||
| 29322e0869 | |||
| 431c1f2564 | |||
| 89f43432d2 | |||
| 20b6daf10e | |||
| 208e0d2061 | |||
| 449b96cbd1 | |||
| ee514a8c95 | |||
| 161741b4af | |||
| 382e7c87dd | |||
| 671b28f91a | |||
| 0aa0c15cc5 | |||
| 9fe0d1bfc9 | |||
| ea700e481e | |||
| dc225f30f1 | |||
| a120e450e9 | |||
| c866c8be4c | |||
|
|
132e47f2b2 | ||
|
|
eeedf23e7c |
4
.github/workflows/pages.yml
vendored
4
.github/workflows/pages.yml
vendored
@ -55,7 +55,7 @@ jobs:
|
|||||||
JEKYLL_ENV: production
|
JEKYLL_ENV: production
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
# Automatically uploads an artifact from the './_site' directory by default
|
# Automatically uploads an artifact from the './_site' directory by default
|
||||||
uses: actions/upload-pages-artifact@v1
|
uses: actions/upload-pages-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: "doc/_site/"
|
path: "doc/_site/"
|
||||||
# Deployment job
|
# Deployment job
|
||||||
@ -68,4 +68,4 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
id: deployment
|
id: deployment
|
||||||
uses: actions/deploy-pages@v2
|
uses: actions/deploy-pages@v4
|
||||||
|
|||||||
97
.github/workflows/release-draft.yml
vendored
Normal file
97
.github/workflows/release-draft.yml
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
name: Release Draft
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'manifest.json'
|
||||||
|
branches:
|
||||||
|
- "master"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment: node18
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '18'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Build project
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Extract version from package.json
|
||||||
|
id: extract_version
|
||||||
|
run: echo "VERSION=$(jq -r '.version' package.json)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Set Git user
|
||||||
|
run: |
|
||||||
|
git config --global user.name "github-actions[bot]"
|
||||||
|
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
- name: Create tag
|
||||||
|
run: git tag -a "${{ env.VERSION }}" -m "Release version ${{ env.VERSION }}"
|
||||||
|
|
||||||
|
- name: Push tag
|
||||||
|
run: git push origin "${{ env.VERSION }}"
|
||||||
|
|
||||||
|
- name: Create GitHub release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: "${{ env.VERSION }}"
|
||||||
|
release_name: "${{ env.VERSION }}"
|
||||||
|
draft: true
|
||||||
|
prerelease: false
|
||||||
|
generate_release_notes: true
|
||||||
|
|
||||||
|
- name: Upload release assets
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: ./main.js
|
||||||
|
asset_name: main.js
|
||||||
|
asset_content_type: application/javascript
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
VERSION: ${{ env.VERSION }}
|
||||||
|
|
||||||
|
- name: Upload manifest.json
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: ./manifest.json
|
||||||
|
asset_name: manifest.json
|
||||||
|
asset_content_type: application/json
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
VERSION: ${{ env.VERSION }}
|
||||||
|
|
||||||
|
- name: Upload style.css
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: ./styles.css
|
||||||
|
asset_name: styles.css
|
||||||
|
asset_content_type: text/css
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
VERSION: ${{ env.VERSION }}
|
||||||
|
|
||||||
|
- name: Output release message
|
||||||
|
run: echo "发布预发布版本${{ env.VERSION }}正常"
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -20,3 +20,5 @@ data.json
|
|||||||
|
|
||||||
# Exclude macOS Finder (System Explorer) View States
|
# Exclude macOS Finder (System Explorer) View States
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
doc/.vitepress/dist
|
||||||
|
doc/.vitepress/cache
|
||||||
|
|||||||
@ -21,13 +21,13 @@
|
|||||||
|
|
||||||
Bring your data from [Douban]() to Your [Obsidian](https://obsidian.md/)
|
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
|
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
|
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)
|
- [Bugs, Issues, & Feature Requests](https://github.com/Wanxp/obsidian-douban/issues)
|
||||||
- Read Other Languages: English | [简体中文](../README.md)
|
- Read Other Languages: English | [简体中文](README.md)
|
||||||
|
|
||||||
## Target
|
## Target
|
||||||
- [x] Sync Personal Movie/TV/Book/Music
|
- [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
|
- [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. 结合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
|
## How to use
|
||||||
### Sync
|
### Sync
|
||||||
- Sync Data From Douban
|
- 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)).
|
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
|
### Search
|
||||||
Use the following method: Enter <kbd>Ctrl</kbd> + <kbd>P</kbd>, enter "Douban", select search and use
|
Use the following method: Enter <kbd>Ctrl</kbd> + <kbd>P</kbd>, enter "Douban", select search and use
|
||||||
- Search Data And Create Note
|
- Search Data And Create Note
|
||||||
- Search Data By File Name
|
- Search Data By File Name
|
||||||
- Search Movie By Input Text
|
- Search Movie By Input Text
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## Support Field
|
## Support Field
|
||||||
@ -119,9 +119,7 @@ Use the following method: Enter <kbd>Ctrl</kbd> + <kbd>P</kbd>, enter "Douban",
|
|||||||
7. Enjoy your develop
|
7. Enjoy your develop
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
<img src="img/obsidian-douban-qq-qr_code.svg" width="300px">
|
<img src="doc/img/obsidian-douban-qq-qr_code.svg" width="300px"> <img src="doc/img/wechat_group.png" width="245px">
|
||||||
<img src="https://picture-bed-public.wanxuping.com/obsidian-douban/wechat_group.png" width="245px">
|
|
||||||
|
|
||||||
|
|
||||||
## Disclaimer
|
## 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.
|
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.
|
||||||
19
README.md
19
README.md
@ -22,7 +22,7 @@
|
|||||||
这是一款[Obsidian](https://obsidian.md/)插件,支持在Obsidian中导入[豆瓣]()中的 _电影、书籍、音乐、电视剧、日记、游戏_
|
这是一款[Obsidian](https://obsidian.md/)插件,支持在Obsidian中导入[豆瓣]()中的 _电影、书籍、音乐、电视剧、日记、游戏_
|
||||||
甚至是 _你标记过的书影音_ , 包含你的评分、观看日期、评论、阅读状态等信息.
|
甚至是 _你标记过的书影音_ , 包含你的评分、观看日期、评论、阅读状态等信息.
|
||||||
|
|
||||||
访问[Get Started/指导手册](https://wanxp.github.io/obsidian-douban/) 获取更多
|
访问[Get Started/指导手册](https://obsidian-douban.wxp.hk/) 获取更多
|
||||||
|
|
||||||
[//]: # (访问[Get Started/指导手册](https://obsidian-douban.wanxuping.com/) 获取更多 )
|
[//]: # (访问[Get Started/指导手册](https://obsidian-douban.wanxuping.com/) 获取更多 )
|
||||||

|

|
||||||
@ -32,16 +32,17 @@
|
|||||||
如果觉得喜欢或对您有帮助,欢迎一键三连-点亮 ⭐Star
|
如果觉得喜欢或对您有帮助,欢迎一键三连-点亮 ⭐Star
|
||||||
|
|
||||||
- [异常, 问题 & 新的想法](https://github.com/Wanxp/obsidian-douban/issues)
|
- [异常, 问题 & 新的想法](https://github.com/Wanxp/obsidian-douban/issues)
|
||||||
- 阅读其它语言的介绍请点击 [English](./doc/README.en.md) | 简体中文
|
- 阅读其它语言的介绍请点击 [English](README.en.md) | 简体中文
|
||||||
|
|
||||||
## 功能
|
## 功能
|
||||||
- ☑️ 导入电影、电视剧、书籍、音乐、游戏、日记
|
- ☑️ 导入电影、电视剧、书籍、音乐、游戏、日记
|
||||||
- ☑️ 同步个人听过/看过的电影、电视剧、书籍、音乐
|
- ☑️ 同步个人听过/看过的电影、电视剧、书籍、音乐、游戏
|
||||||
- ☑️ 导入个人的评论,评论时间,阅读状态,个人评分
|
- ☑️ 导入个人的评论,评论时间,阅读状态,个人评分
|
||||||
- ☑️ 支持保存封面至本地/图床
|
- ☑️ 支持保存封面至本地/图床
|
||||||
- ⬜ 支持图床自定义
|
- ⬜ 支持图床自定义
|
||||||
- ☑️ 支持自定义参数
|
- ☑️ 支持自定义参数
|
||||||
- ☑️ 支持移动端导入
|
- ☑️ 支持移动端导入
|
||||||
|
- ⬜ 支持使用AI大模型ChatGPT、Deepseek、Ollama分析导入
|
||||||
|
|
||||||
## 效果
|
## 效果
|
||||||
1. 结合Timeline插件 __构建个人观影时间线__,请参照[结合timeline插件实现时间线效果](./doc/Obsidian-Douban-TimeLine.md)
|
1. 结合Timeline插件 __构建个人观影时间线__,请参照[结合timeline插件实现时间线效果](./doc/Obsidian-Douban-TimeLine.md)
|
||||||
@ -120,7 +121,7 @@
|
|||||||
3. 在obsidian插件中心开启当前插件功能
|
3. 在obsidian插件中心开启当前插件功能
|
||||||
|
|
||||||
## 如何开发调试
|
## 如何开发调试
|
||||||
|
### 开发
|
||||||
1. 进入你的Obsidian测试文档文件夹下的`/.obsidian/plugins/`
|
1. 进入你的Obsidian测试文档文件夹下的`/.obsidian/plugins/`
|
||||||
2. 克隆代码
|
2. 克隆代码
|
||||||
`git clone git@github.com:Wanxp/obsidian-douban.git`
|
`git clone git@github.com:Wanxp/obsidian-douban.git`
|
||||||
@ -134,6 +135,14 @@
|
|||||||
`npm run dev`
|
`npm run dev`
|
||||||
7. 进入Obsidian插件中心重新加载当前插件
|
7. 进入Obsidian插件中心重新加载当前插件
|
||||||
8. 享受开发吧
|
8. 享受开发吧
|
||||||
|
#### 文档
|
||||||
|
```shell
|
||||||
|
npm run docs:dev
|
||||||
|
```
|
||||||
|
## 支持开发者
|
||||||
|
如果觉得插件对你有帮助,欢迎请我喝杯咖啡,让我有更多的动力去维护和更新插件
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## 交流社群
|
## 交流社群
|
||||||
<img src="doc/img/obsidian-douban-qq-qr_code.svg" width="300px"> <img src="doc/img/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">
|
||||||
@ -164,7 +173,7 @@
|
|||||||
| 同步书影音数据 | 以上所有 | 以上所有 | 以上所有 |
|
| 同步书影音数据 | 以上所有 | 以上所有 | 以上所有 |
|
||||||
| 同步书影音数据 | `替换同名文档`值为勾选 | 已经存在 **同路径同文档名** ,直接覆盖 | 如已经存在在`data/Movie/蝙蝠侠.md`,配置`笔记名称`值为`/data/{{type}}/{{title}}`, 同步书影音记录时勾选 `替换同名文档`, 则`data/Movie/蝙蝠侠.md`会被替换成最新 |
|
| 同步书影音数据 | `替换同名文档`值为勾选 | 已经存在 **同路径同文档名** ,直接覆盖 | 如已经存在在`data/Movie/蝙蝠侠.md`,配置`笔记名称`值为`/data/{{type}}/{{title}}`, 同步书影音记录时勾选 `替换同名文档`, 则`data/Movie/蝙蝠侠.md`会被替换成最新 |
|
||||||
|
|
||||||
[//]: # (## 鸣谢)
|
|
||||||
|
|
||||||
[//]: # (### IDE支持)
|
[//]: # (### IDE支持)
|
||||||
|
|
||||||
|
|||||||
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' }
|
||||||
|
],
|
||||||
|
lastUpdated: {
|
||||||
|
text: '最后更新于',
|
||||||
|
formatOptions: {
|
||||||
|
dateStyle: 'full',
|
||||||
|
timeStyle: 'medium'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
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: 如何安装
|
title: 如何安装
|
||||||
layout: default
|
|
||||||
nav_order: 200
|
nav_order: 200
|
||||||
---
|
---
|
||||||
|
# 如何安装
|
||||||
## 如何安装
|
## 从Obsidian插件中心
|
||||||
### 从Obsidian插件中心
|
|
||||||
1. 进入Obsidian插件中心
|
1. 进入Obsidian插件中心
|
||||||
2. 搜索obsidian-douban
|
2. 搜索obsidian-douban
|
||||||
3. 安装
|
3. 安装
|
||||||
4. 开启插件
|
4. 开启插件
|
||||||
|
|
||||||
### 手动安装
|
## 手动安装
|
||||||
|
|
||||||
1. 从[Github release](https://github.com/Wanxp/obsidian-douban/releases) 页面下载 `main.js`, `manifest.json`, `styles.css`
|
1. 从[Github release](https://github.com/Wanxp/obsidian-douban/releases) 页面下载 `main.js`, `manifest.json`, `styles.css`
|
||||||
2. 将下载的文件复制到你的Obsidian文档根目录下的`/.obsidian/plugins/obsidian-douban`路径,若不存在则新建文件夹(注意.obsidian文件夹可能是个隐藏为文件夹)
|
2. 将下载的文件复制到你的Obsidian文档根目录下的`/.obsidian/plugins/obsidian-douban`路径,若不存在则新建文件夹(注意.obsidian文件夹可能是个隐藏为文件夹)
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
---
|
---
|
||||||
title: 使用说明
|
title: 使用说明
|
||||||
layout: default
|
|
||||||
nav_order: 300
|
nav_order: 300
|
||||||
parent: 如何使用
|
parent: 如何使用
|
||||||
---
|
---
|
||||||
## 如何使用
|
# 如何使用
|
||||||
## 搜索
|
# 搜索
|
||||||
使用方式: 输入<kbd>Ctrl</kbd> + <kbd>P</kbd>,输入“豆瓣”或“Douban”,选择搜索并使用
|
使用方式: 输入<kbd>Ctrl</kbd> + <kbd>P</kbd>,输入“豆瓣”或“Douban”,选择搜索并使用
|
||||||
- 搜索数据并创建笔记
|
- 搜索数据并创建笔记
|
||||||
- 通过当前文件名搜索
|
- 通过当前文件名搜索
|
||||||
@ -13,6 +12,6 @@ parent: 如何使用
|
|||||||

|

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

|

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

|

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

|
||||||
|
|
||||||
## 交流社群
|
## 交流社群
|
||||||
<img src="img/obsidian-douban-qq-qr_code.svg" width="300px">
|
<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;">
|
||||||
<img src="https://picture-bed-public.wanxuping.com/obsidian-douban/wechat_group.png" width="245px">
|
|
||||||
|
|
||||||
[邮件联系我](mailto:977741432@qq.com)
|
|
||||||
|
或者[邮件联系我](mailto:977741432@qq.com)
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
source 'https://rubygems.org'
|
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 "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 "just-the-docs" # always download the latest release
|
||||||
|
|
||||||
gem 'json'
|
gem 'json'
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 类豆瓣网页显示
|
title: 类豆瓣网页显示
|
||||||
layout: default
|
|
||||||
nav_order: 455
|
nav_order: 455
|
||||||
parent: 特殊效果
|
parent: 特殊效果
|
||||||
render_with_liquid: false
|
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: 看剧时间线
|
title: 看剧时间线
|
||||||
layout: default
|
|
||||||
nav_order: 456
|
nav_order: 456
|
||||||
parent: 特殊效果
|
parent: 特殊效果
|
||||||
render_with_liquid: false
|
render_with_liquid: false
|
||||||
|
|||||||
BIN
doc/img/support_pay_2.png
Normal file
BIN
doc/img/support_pay_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 494 KiB |
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 |
73
doc/index.md
73
doc/index.md
@ -1,47 +1,34 @@
|
|||||||
---
|
---
|
||||||
title: 简介
|
# https://vitepress.dev/reference/default-theme-home-page
|
||||||
layout: home
|
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="https://picture-bed-public.wanxuping.com/obsidian-douban/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 |
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "obsidian-douban-plugin",
|
"id": "obsidian-douban-plugin",
|
||||||
"name": "Douban",
|
"name": "Douban",
|
||||||
"version": "2.1.0",
|
"version": "2.3.2",
|
||||||
"minAppVersion": "0.12.0",
|
"minAppVersion": "0.12.0",
|
||||||
"description": "This is a plugin that can import movies/books/musics/notes/games info data from Douban for Obsidian .",
|
"description": "This is a plugin that can import movies/books/musics/notes/games info data from Douban for Obsidian .",
|
||||||
"author": "Wanxp",
|
"author": "Wanxp",
|
||||||
|
|||||||
9428
package-lock.json
generated
9428
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@ -1,13 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-douban-plugin",
|
"name": "obsidian-douban-plugin",
|
||||||
"version": "2.1.0",
|
"version": "2.3.2",
|
||||||
"description": "This is a plugin for Obsidian (https://obsidian.md) that can import data from Douban (https://www.douban.com/).",
|
"description": "This is a plugin for Obsidian (https://obsidian.md) that can import data from Douban (https://www.douban.com/).",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node esbuild.config.mjs",
|
"dev": "node esbuild.config.mjs",
|
||||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||||
"version": "node version-bump.mjs && git add manifest.json versions.json",
|
"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": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
@ -23,7 +26,8 @@
|
|||||||
"obsidian": "latest",
|
"obsidian": "latest",
|
||||||
"ts-jest": "^28.0.5",
|
"ts-jest": "^28.0.5",
|
||||||
"tslib": "2.3.1",
|
"tslib": "2.3.1",
|
||||||
"typescript": "^4.7.2"
|
"typescript": "^4.7.2",
|
||||||
|
"vitepress": "^1.6.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@notable/html2markdown": "^1.1.3",
|
"@notable/html2markdown": "^1.1.3",
|
||||||
|
|||||||
@ -101,15 +101,34 @@ export enum TemplateKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum SupportType {
|
export enum SupportType {
|
||||||
ALL = "all",
|
all = "all",
|
||||||
MOVIE = 'movie',
|
movie = 'movie',
|
||||||
BOOK = 'book',
|
book = 'book',
|
||||||
MUSIC = 'music',
|
music = 'music',
|
||||||
NOTE = 'note',
|
note = 'note',
|
||||||
GAME = 'game',
|
game = 'game',
|
||||||
TELEPLAY = 'teleplay',
|
teleplay = 'teleplay',
|
||||||
THEATER = 'theater',
|
theater = 'theater',
|
||||||
}
|
}
|
||||||
|
export const SupportTypeMap:object = {
|
||||||
|
"all": SupportType.all,
|
||||||
|
"movie": SupportType.movie,
|
||||||
|
"book": SupportType.book,
|
||||||
|
"music": SupportType.music,
|
||||||
|
"note": SupportType.note,
|
||||||
|
"game": SupportType.game,
|
||||||
|
"teleplay": SupportType.teleplay,
|
||||||
|
"theater": SupportType.theater,
|
||||||
|
"ALL": SupportType.all,
|
||||||
|
"MOVIE": SupportType.movie,
|
||||||
|
"BOOK": SupportType.book,
|
||||||
|
"MUSIC": SupportType.music,
|
||||||
|
"NOTE": SupportType.note,
|
||||||
|
"GAME": SupportType.game,
|
||||||
|
"TELEPLAY": SupportType.teleplay,
|
||||||
|
"THEATER": SupportType.theater,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export enum PropertyName {
|
export enum PropertyName {
|
||||||
//base
|
//base
|
||||||
@ -183,13 +202,13 @@ export enum PropertyName {
|
|||||||
*/
|
*/
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export const SearchTypeRecords: { [key in SupportType]: string } = {
|
export const SearchTypeRecords: { [key in SupportType]: string } = {
|
||||||
[SupportType.ALL]: i18nHelper.getMessage('ALL'),
|
[SupportType.all]: i18nHelper.getMessage('ALL'),
|
||||||
[SupportType.MOVIE]: i18nHelper.getMessage('MOVIE_AND_TELEPLAY'),
|
[SupportType.movie]: i18nHelper.getMessage('MOVIE_AND_TELEPLAY'),
|
||||||
[SupportType.BOOK]: i18nHelper.getMessage('BOOK'),
|
[SupportType.book]: i18nHelper.getMessage('BOOK'),
|
||||||
[SupportType.MUSIC]: i18nHelper.getMessage('MUSIC'),
|
[SupportType.music]: i18nHelper.getMessage('MUSIC'),
|
||||||
[SupportType.NOTE]: i18nHelper.getMessage('NOTE'),
|
[SupportType.note]: i18nHelper.getMessage('NOTE'),
|
||||||
[SupportType.GAME]: i18nHelper.getMessage('GAME'),
|
[SupportType.game]: i18nHelper.getMessage('GAME'),
|
||||||
// [SupportType.THEATER]: i18nHelper.getMessage('THEATER'),
|
[SupportType.theater]: i18nHelper.getMessage('THEATER'),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -204,6 +223,7 @@ export const PersonNameModeRecords: { [key in PersonNameMode]: string } = {
|
|||||||
export enum SyncType {
|
export enum SyncType {
|
||||||
movie = 'movie',
|
movie = 'movie',
|
||||||
book = 'book',
|
book = 'book',
|
||||||
|
game = 'game',
|
||||||
broadcast = 'broadcast',
|
broadcast = 'broadcast',
|
||||||
note = 'note',
|
note = 'note',
|
||||||
music = 'music',
|
music = 'music',
|
||||||
@ -216,20 +236,23 @@ export const SyncTypeUrlDomain: Map<SyncType, string> = new Map([
|
|||||||
[SyncType.broadcast , 'broadcast'],
|
[SyncType.broadcast , 'broadcast'],
|
||||||
[SyncType.note , 'note'],
|
[SyncType.note , 'note'],
|
||||||
[SyncType.music , 'music'],
|
[SyncType.music , 'music'],
|
||||||
[SyncType.teleplay , 'movie']]
|
[SyncType.teleplay , 'movie'],
|
||||||
|
[SyncType.game, 'games'],
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步模式选项
|
* 同步模式选项
|
||||||
*/
|
*/
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export const SyncTypeRecords: { [key in SyncType]: string } = {
|
export const SyncTypeRecords: { [key in SyncType | string]: string } = {
|
||||||
[SyncType.movie]: i18nHelper.getMessage('504103'),
|
[SyncType.movie]: i18nHelper.getMessage('504103'),
|
||||||
[SyncType.teleplay]: i18nHelper.getMessage('504107'),
|
[SyncType.teleplay]: i18nHelper.getMessage('504107'),
|
||||||
[SyncType.book]: i18nHelper.getMessage('504102'),
|
[SyncType.book]: i18nHelper.getMessage('504102'),
|
||||||
// [SyncType.broadcast]: i18nHelper.getMessage('504104'),
|
// [SyncType.broadcast]: i18nHelper.getMessage('504104'),
|
||||||
// [SyncType.note]: i18nHelper.getMessage('504105'),
|
// [SyncType.note]: i18nHelper.getMessage('504105'),
|
||||||
[SyncType.music]: i18nHelper.getMessage('504106'),
|
[SyncType.music]: i18nHelper.getMessage('504106'),
|
||||||
|
[SyncType.game]: i18nHelper.getMessage('504108'),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,6 +280,7 @@ export enum SyncItemStatus {
|
|||||||
replace = 'replace',
|
replace = 'replace',
|
||||||
create = 'create',
|
create = 'create',
|
||||||
fail = 'fail',
|
fail = 'fail',
|
||||||
|
failByDiffType = 'failByDiffType',
|
||||||
unHandle = 'unHandle',
|
unHandle = 'unHandle',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,13 +395,13 @@ sec-ch-ua-platform: "Windows"
|
|||||||
export const ONLINE_SETTING_DEFAULT: DoubanPluginOnlineSettings = {
|
export const ONLINE_SETTING_DEFAULT: DoubanPluginOnlineSettings = {
|
||||||
properties: [
|
properties: [
|
||||||
{
|
{
|
||||||
type: SupportType.BOOK,
|
type: SupportType.book,
|
||||||
name: PropertyName.comment,
|
name: PropertyName.comment,
|
||||||
selectors: ['#interest_sect_level > div > span:nth-child(7)'
|
selectors: ['#interest_sect_level > div > span:nth-child(7)'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: SupportType.MOVIE,
|
type: SupportType.movie,
|
||||||
name: PropertyName.comment,
|
name: PropertyName.comment,
|
||||||
selectors: ['#interest_sect_level > div > span:nth-child(8)',
|
selectors: ['#interest_sect_level > div > span:nth-child(8)',
|
||||||
'#interest_sect_level > div > span:nth-child(7)',
|
'#interest_sect_level > div > span:nth-child(7)',
|
||||||
@ -452,3 +476,75 @@ export const PictureBedSetting_PicGo ={
|
|||||||
export const PictureBedTypeRecords: { [key in PictureBedType]: string } = {
|
export const PictureBedTypeRecords: { [key in PictureBedType]: string } = {
|
||||||
[PictureBedType.PicGo]: PictureBedType.PicGo
|
[PictureBedType.PicGo]: PictureBedType.PicGo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export enum SyncConditionType {
|
||||||
|
/**
|
||||||
|
* 最近新变动
|
||||||
|
*/
|
||||||
|
ALL = "all",
|
||||||
|
// /**
|
||||||
|
// * 最近新变动
|
||||||
|
// */
|
||||||
|
// LAST_UPDATE = "lastUpdate",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最近10条
|
||||||
|
*/
|
||||||
|
LAST_THIRTY = "lastThirty",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义时间
|
||||||
|
*/
|
||||||
|
CUSTOM_TIME = "customTime",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义条数
|
||||||
|
*/
|
||||||
|
CUSTOM_ITEM = "customItem",
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 名称模式选项
|
||||||
|
*/
|
||||||
|
// @ts-ignore
|
||||||
|
export const SyncConditionTypeRecords: { [key in SyncConditionType|string]: string } = {
|
||||||
|
[SyncConditionType.ALL]: i18nHelper.getMessage('110071'),
|
||||||
|
// [SyncConditionType.LAST_UPDATE]: i18nHelper.getMessage('110072'),
|
||||||
|
[SyncConditionType.LAST_THIRTY]: i18nHelper.getMessage('110075'),
|
||||||
|
[SyncConditionType.CUSTOM_ITEM]: i18nHelper.getMessage('110076'),
|
||||||
|
[SyncConditionType.CUSTOM_TIME]: i18nHelper.getMessage('110074'),
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const DoubanSearchResultSubject_EMPTY: DoubanSearchResultSubject = {
|
||||||
|
id: '',
|
||||||
|
title: i18nHelper.getMessage('150107'),
|
||||||
|
score: null,
|
||||||
|
cast: '',
|
||||||
|
type: 'navigate',
|
||||||
|
desc: '-',
|
||||||
|
url: 'https://www.douban.com',
|
||||||
|
image: "",
|
||||||
|
imageUrl: "",
|
||||||
|
publisher: "",
|
||||||
|
datePublished: undefined,
|
||||||
|
genre: []
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DoubanSearchResultSubject_TIP_EMPTY: DoubanSearchResultSubject = {
|
||||||
|
id: '',
|
||||||
|
title: i18nHelper.getMessage('150108'),
|
||||||
|
score: null,
|
||||||
|
cast: '',
|
||||||
|
type: 'navigate',
|
||||||
|
desc: '-',
|
||||||
|
url: 'https://www.douban.com',
|
||||||
|
image: "",
|
||||||
|
imageUrl: "",
|
||||||
|
publisher: "",
|
||||||
|
datePublished: undefined,
|
||||||
|
genre: []
|
||||||
|
};
|
||||||
@ -38,25 +38,29 @@ export const DEFAULT_SETTINGS: DoubanPluginSetting = {
|
|||||||
statusBar: true,
|
statusBar: true,
|
||||||
debugMode: false,
|
debugMode: false,
|
||||||
customProperties: [
|
customProperties: [
|
||||||
{name: 'myType', value: 'movie', field: SupportType.MOVIE},
|
{name: 'myType', value: 'movie', field: SupportType.movie},
|
||||||
{name: 'myType', value: 'book', field: SupportType.BOOK},
|
{name: 'myType', value: 'book', field: SupportType.book},
|
||||||
{name: 'myType', value: 'music', field: SupportType.MUSIC},
|
{name: 'myType', value: 'music', field: SupportType.music},
|
||||||
{name: 'myType', value: 'note', field: SupportType.NOTE},
|
{name: 'myType', value: 'note', field: SupportType.note},
|
||||||
{name: 'myType', value: 'game', field: SupportType.GAME},
|
{name: 'myType', value: 'game', field: SupportType.game},
|
||||||
{name: 'myType', value: 'teleplay', field: SupportType.TELEPLAY},
|
{name: 'myType', value: 'teleplay', field: SupportType.teleplay},
|
||||||
|
{name: 'myType', value: 'theater', field: SupportType.theater},
|
||||||
],
|
],
|
||||||
loginCookiesContent: '',
|
loginCookiesContent: '',
|
||||||
loginHeadersContent: '',
|
loginHeadersContent: '',
|
||||||
cacheImage: true,
|
cacheImage: true,
|
||||||
cacheHighQuantityImage: true,
|
cacheHighQuantityImage: true,
|
||||||
attachmentPath: 'assets',
|
attachmentPath: 'assets',
|
||||||
|
attachmentFileName: "{{title}}",
|
||||||
syncHandledDataArray: [],
|
syncHandledDataArray: [],
|
||||||
|
// syncLastUpdateTime: new Map<string, string>(),
|
||||||
scoreSetting: {
|
scoreSetting: {
|
||||||
starFull: '⭐',
|
starFull: '⭐',
|
||||||
starEmpty: '☆',
|
starEmpty: '☆',
|
||||||
displayStarEmpty: false,
|
displayStarEmpty: false,
|
||||||
maxStar: 5,
|
maxStar: 5,
|
||||||
}
|
},
|
||||||
|
searchDefaultType: SupportType.all,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -78,6 +78,10 @@ desc: {{desc}}
|
|||||||
---
|
---
|
||||||
|
|
||||||

|

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

|

|
||||||
|
|
||||||
Comment:
|
|
||||||
---
|
---
|
||||||
|
Menu:
|
||||||
|
{{menu}}
|
||||||
|
|
||||||
|
---
|
||||||
|
Comment:
|
||||||
{{myComment}}
|
{{myComment}}
|
||||||
|
|
||||||
`,
|
`,
|
||||||
|
|||||||
@ -10,3 +10,7 @@ export const doubanHeaders = {
|
|||||||
export const doubanSubjectSyncListUrl = function(subjectType:string, userId:string, doType:string, start:number):string {
|
export const doubanSubjectSyncListUrl = function(subjectType:string, userId:string, doType:string, start:number):string {
|
||||||
return `https://${subjectType}.douban.com/people/${userId}/${doType}?start=${start}&sort=time&rating=all&filter=all&mode=list`;
|
return `https://${subjectType}.douban.com/people/${userId}/${doType}?start=${start}&sort=time&rating=all&filter=all&mode=list`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const doubanGameSubjectSyncListUrl = function(subjectType:string, userId:string, doType:string, start:number):string {
|
||||||
|
return `https://douban.com/people/${userId}/games?start=${start}&sort=time&rating=all&filter=all&mode=list${doType != 'all' ? '&action='+doType : ''}`;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {i18nHelper} from "../lang/helper";
|
import {i18nHelper} from "../lang/helper";
|
||||||
import {SupportType} from "./Constsant";
|
import {SupportType, SyncType} from "./Constsant";
|
||||||
|
|
||||||
export enum DoubanSubjectState {
|
export enum DoubanSubjectState {
|
||||||
not = 'not',
|
not = 'not',
|
||||||
@ -66,14 +66,14 @@ export const DoubanSubjectStateRecords_THEATER: { [key in DoubanSubjectState]: s
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const DoubanSubjectStateRecords: { [key in SupportType]: Record<DoubanSubjectState, string> } = {
|
export const DoubanSubjectStateRecords: { [key in SupportType]: Record<DoubanSubjectState, string> } = {
|
||||||
[SupportType.ALL]:DoubanSubjectStateRecords_ALL,
|
[SupportType.all]:DoubanSubjectStateRecords_ALL,
|
||||||
[SupportType.MOVIE]:DoubanSubjectStateRecords_MOVIE,
|
[SupportType.movie]:DoubanSubjectStateRecords_MOVIE,
|
||||||
[SupportType.BOOK]:DoubanSubjectStateRecords_BOOK,
|
[SupportType.book]:DoubanSubjectStateRecords_BOOK,
|
||||||
[SupportType.MUSIC]:DoubanSubjectStateRecords_MUSIC,
|
[SupportType.music]:DoubanSubjectStateRecords_MUSIC,
|
||||||
[SupportType.NOTE]:DoubanSubjectStateRecords_NOTE,
|
[SupportType.note]:DoubanSubjectStateRecords_NOTE,
|
||||||
[SupportType.GAME]:DoubanSubjectStateRecords_GAME,
|
[SupportType.game]:DoubanSubjectStateRecords_GAME,
|
||||||
[SupportType.TELEPLAY]:DoubanSubjectStateRecords_TELEPLAY,
|
[SupportType.teleplay]:DoubanSubjectStateRecords_TELEPLAY,
|
||||||
[SupportType.THEATER]:DoubanSubjectStateRecords_THEATER,
|
[SupportType.theater]:DoubanSubjectStateRecords_THEATER,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +106,15 @@ export const DoubanSubjectStateRecords_BOOK_SYNC: { [key in DoubanSubjectState]:
|
|||||||
[DoubanSubjectState.collect]: i18nHelper.getMessage('500304'),
|
[DoubanSubjectState.collect]: i18nHelper.getMessage('500304'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
export const DoubanSubjectStateRecords_GAME_SYNC: { [key in DoubanSubjectState]: string } = {
|
||||||
|
// @ts-ignore
|
||||||
|
// [ALL]: i18nHelper.getMessage('500004'),
|
||||||
|
[DoubanSubjectState.wish]: i18nHelper.getMessage('500602'),
|
||||||
|
[DoubanSubjectState.do]: i18nHelper.getMessage('500603'),
|
||||||
|
[DoubanSubjectState.collect]: i18nHelper.getMessage('500604'),
|
||||||
|
}
|
||||||
|
|
||||||
export const DoubanSubjectStateRecords_BROADCAST_SYNC: { [key :string]: string } = {
|
export const DoubanSubjectStateRecords_BROADCAST_SYNC: { [key :string]: string } = {
|
||||||
[ALL]: i18nHelper.getMessage('500004'),
|
[ALL]: i18nHelper.getMessage('500004'),
|
||||||
}
|
}
|
||||||
@ -123,33 +132,51 @@ export const DoubanSubjectStateRecords_MUSIC_SYNC: { [key in DoubanSubjectState]
|
|||||||
[DoubanSubjectState.collect]: i18nHelper.getMessage('500404'),
|
[DoubanSubjectState.collect]: i18nHelper.getMessage('500404'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
export const DoubanSubjectStateRecords_SYNC: { [key in SyncType]: Record<DoubanSubjectState, string> } = {
|
||||||
|
[SyncType.movie]:DoubanSubjectStateRecords_MOVIE_SYNC,
|
||||||
|
[SyncType.book]:DoubanSubjectStateRecords_BOOK_SYNC,
|
||||||
|
[SyncType.music]:DoubanSubjectStateRecords_MUSIC_SYNC,
|
||||||
|
// [SyncType.note]:DoubanSubjectStateRecords_NOTE_SYNC,
|
||||||
|
[SyncType.game]:DoubanSubjectStateRecords_GAME_SYNC,
|
||||||
|
[SyncType.teleplay]:DoubanSubjectStateRecords_TELEPLAY_SYNC,
|
||||||
|
// [SyncType.theater]:DoubanSubjectStateRecords_THEATER_SYNC,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const DoubanSubjectStateRecords_KEY_WORD_TYPE: Map<string, SupportType> = new Map<string, SupportType> (
|
export const DoubanSubjectStateRecords_KEY_WORD_TYPE: Map<string, SupportType> = new Map<string, SupportType> (
|
||||||
[['我看过这部电视剧', SupportType.TELEPLAY],
|
[['我看过这部电视剧', SupportType.teleplay],
|
||||||
['我最近看过这部电视剧', SupportType.TELEPLAY],
|
['我最近看过这部电视剧', SupportType.teleplay],
|
||||||
['我想看这部电视剧', SupportType.TELEPLAY],
|
['我想看这部电视剧', SupportType.teleplay],
|
||||||
['我在看这部电视剧', SupportType.TELEPLAY],
|
['我在看这部电视剧', SupportType.teleplay],
|
||||||
['我最近在看这部电视剧', SupportType.TELEPLAY],
|
['我最近在看这部电视剧', SupportType.teleplay],
|
||||||
|
|
||||||
['我最近看过这部电影', SupportType.MOVIE],
|
['我最近看过这部电影', SupportType.movie],
|
||||||
['我看过这部电影', SupportType.MOVIE],
|
['我看过这部电影', SupportType.movie],
|
||||||
['我想看这部电影', SupportType.MOVIE],
|
['我想看这部电影', SupportType.movie],
|
||||||
|
|
||||||
['我读过这本书', SupportType.BOOK],
|
['我读过这本书', SupportType.book],
|
||||||
['我想读这本书', SupportType.BOOK],
|
['我想读这本书', SupportType.book],
|
||||||
['我在读这本书', SupportType.BOOK],
|
['我在读这本书', SupportType.book],
|
||||||
['我最近在读这本书', SupportType.BOOK],
|
['我最近在读这本书', SupportType.book],
|
||||||
|
|
||||||
['我最近听过这张唱片', SupportType.MUSIC],
|
['我最近听过这张唱片', SupportType.music],
|
||||||
['我听过这张唱片', SupportType.MUSIC],
|
['我听过这张唱片', SupportType.music],
|
||||||
['我想听这张唱片', SupportType.MUSIC],
|
['我想听这张唱片', SupportType.music],
|
||||||
['我在听这张唱片', SupportType.MUSIC],
|
['我在听这张唱片', SupportType.music],
|
||||||
['我最近在听这张唱片', SupportType.MUSIC],
|
['我最近在听这张唱片', SupportType.music],
|
||||||
|
|
||||||
['我最近玩过这个游戏', SupportType.GAME],
|
['我最近玩过这个游戏', SupportType.game],
|
||||||
['我玩过这个游戏', SupportType.GAME],
|
['我玩过这个游戏', SupportType.game],
|
||||||
['我想玩这个游戏', SupportType.GAME],
|
['我想玩这个游戏', SupportType.game],
|
||||||
['我在玩这个游戏', SupportType.GAME],
|
['我在玩这个游戏', SupportType.game],
|
||||||
['我最近在玩这个游戏', SupportType.GAME],]
|
['我最近在玩这个游戏', SupportType.game],
|
||||||
|
|
||||||
|
['我最近看过这部电影', SupportType.movie],
|
||||||
|
['我看过这部电影', SupportType.movie],
|
||||||
|
['我想看这部电影', SupportType.movie],
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,92 @@
|
|||||||
|
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
|
||||||
|
.trim()
|
||||||
|
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
||||||
|
// //replase multiple _ to single _
|
||||||
|
// .replace(/_+/g, '_')
|
||||||
|
// .replace(/^_/, '')
|
||||||
|
// .replace(/_$/, '')
|
||||||
|
.replace(/:\s+/g, ':')
|
||||||
|
)));
|
||||||
|
// super.parseAliases(beforeContent, variableMap, extract, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,12 +1,18 @@
|
|||||||
import {ButtonComponent, Modal} from "obsidian";
|
import {App, ButtonComponent, Modal} from "obsidian";
|
||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
|
import {create} from "istanbul-reports";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
import {logger} from "bs-logger";
|
||||||
|
import {log} from "../../utils/Logutil";
|
||||||
|
|
||||||
export class ConfirmDialogModal extends Modal {
|
export class ConfirmDialogModal extends Modal {
|
||||||
private promise:Promise<any>;
|
private promise:Promise<any>;
|
||||||
private message:string;
|
private message:string;
|
||||||
|
private doubanPlugin: DoubanPlugin;
|
||||||
|
|
||||||
constructor(app: any, message:string, promise: Promise<any>) {
|
constructor(doubanPlugin: DoubanPlugin, message:string, promise: Promise<any>) {
|
||||||
super(app);
|
super(doubanPlugin.app);
|
||||||
|
this.doubanPlugin = doubanPlugin;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.promise = promise;
|
this.promise = promise;
|
||||||
}
|
}
|
||||||
@ -23,7 +29,12 @@ export class ConfirmDialogModal extends Modal {
|
|||||||
.setButtonText(i18nHelper.getMessage('110152'))
|
.setButtonText(i18nHelper.getMessage('110152'))
|
||||||
.setCta()
|
.setCta()
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
await this.promise;
|
//临时特殊处理导入文件
|
||||||
|
if (this.message == i18nHelper.getMessage('125046')) {
|
||||||
|
createFileSelectModal(this.doubanPlugin);
|
||||||
|
}else {
|
||||||
|
await this.promise;
|
||||||
|
}
|
||||||
this.close();
|
this.close();
|
||||||
}).setClass( "obsidian_douban_search_button");
|
}).setClass( "obsidian_douban_search_button");
|
||||||
new ButtonComponent(controls)
|
new ButtonComponent(controls)
|
||||||
@ -33,3 +44,25 @@ export class ConfirmDialogModal extends Modal {
|
|||||||
}).setClass( "obsidian_douban_cancel_button");
|
}).setClass( "obsidian_douban_cancel_button");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function createFileSelectModal(doubanPlugin: DoubanPlugin) {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.accept = '.json';
|
||||||
|
input.multiple = false;
|
||||||
|
input.onchange = async () => {
|
||||||
|
const file = input.files[0];
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = async () => {
|
||||||
|
const settings:object = JSON.parse(reader.result as string);
|
||||||
|
try {
|
||||||
|
await doubanPlugin.settingsManager.loadAndSaveSettings(settings);
|
||||||
|
}catch (e) {
|
||||||
|
log.error(i18nHelper.getMessage('125043'), e);
|
||||||
|
}
|
||||||
|
log.notice(i18nHelper.getMessage('125044'))
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
};
|
||||||
|
input.click();}
|
||||||
18
src/org/wanxp/douban/component/DatePickComponent.ts
Normal file
18
src/org/wanxp/douban/component/DatePickComponent.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* 日期选择组件
|
||||||
|
* 继承自 TextComponent
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {TextComponent} from 'obsidian';
|
||||||
|
|
||||||
|
export class DatePickComponent extends TextComponent {
|
||||||
|
constructor(container: HTMLElement, date: Date = new Date()) {
|
||||||
|
super(container);
|
||||||
|
this.inputEl.type = 'date';
|
||||||
|
this.inputEl.value = date.toISOString().substring(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(): string {
|
||||||
|
return this.inputEl.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,7 +3,7 @@ import { log } from 'src/org/wanxp/utils/Logutil';
|
|||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
||||||
import SettingsManager from "../setting/SettingsManager";
|
import SettingsManager from "../setting/SettingsManager";
|
||||||
import {constructDoubanTokenSettingsUI} from "../setting/BasicSettingsHelper";
|
import {constructDoubanTokenSettingsUI} from "../setting/LoginSettingsHelper";
|
||||||
|
|
||||||
// Credits go to zhaohongxuan's Weread Plugin : https://github.com/zhaohongxuan/obsidian-weread-plugin
|
// Credits go to zhaohongxuan's Weread Plugin : https://github.com/zhaohongxuan/obsidian-weread-plugin
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { log } from 'src/org/wanxp/utils/Logutil';
|
|||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
||||||
import SettingsManager from "../setting/SettingsManager";
|
import SettingsManager from "../setting/SettingsManager";
|
||||||
import {constructDoubanTokenSettingsUI} from "../setting/BasicSettingsHelper";
|
import {constructDoubanTokenSettingsUI} from "../setting/LoginSettingsHelper";
|
||||||
import StringUtil from "../../utils/StringUtil";
|
import StringUtil from "../../utils/StringUtil";
|
||||||
import {Integer} from "schema-dts";
|
import {Integer} from "schema-dts";
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
import {DoubanSettingTab} from "../setting/DoubanSettingTab";
|
||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import SettingsManager from "../setting/SettingsManager";
|
import SettingsManager from "../setting/SettingsManager";
|
||||||
import {constructDoubanTokenSettingsUI, constructLoginSettingsUI} from "../setting/BasicSettingsHelper";
|
import {constructDoubanTokenSettingsUI, constructLoginSettingsUI} from "../setting/LoginSettingsHelper";
|
||||||
import {log} from "../../utils/Logutil";
|
import {log} from "../../utils/Logutil";
|
||||||
|
|
||||||
// Credits go to zhaohongxuan's Weread Plugin : https://github.com/zhaohongxuan/obsidian-weread-plugin
|
// Credits go to zhaohongxuan's Weread Plugin : https://github.com/zhaohongxuan/obsidian-weread-plugin
|
||||||
|
|||||||
@ -1,17 +1,23 @@
|
|||||||
import {
|
import {
|
||||||
App,
|
App,
|
||||||
ButtonComponent,
|
ButtonComponent, DropdownComponent,
|
||||||
Modal, SearchComponent, Setting,
|
Modal, SearchComponent, Setting, TextComponent, ValueComponent,
|
||||||
} from "obsidian";
|
} from "obsidian";
|
||||||
|
|
||||||
import DoubanPlugin from "../../main";
|
import DoubanPlugin from "../../main";
|
||||||
import {i18nHelper} from "src/org/wanxp/lang/helper";
|
import {i18nHelper} from "src/org/wanxp/lang/helper";
|
||||||
import HandleContext from "../data/model/HandleContext";
|
import HandleContext from "../data/model/HandleContext";
|
||||||
import {SyncType, SyncTypeRecords} from "../../constant/Constsant";
|
|
||||||
import {
|
import {
|
||||||
ALL,
|
DEFAULT_SETTINGS_ARRAY_INPUT_SIZE,
|
||||||
|
SupportType, SyncConditionType,
|
||||||
|
SyncConditionTypeRecords,
|
||||||
|
SyncType,
|
||||||
|
SyncTypeRecords
|
||||||
|
} from "../../constant/Constsant";
|
||||||
|
import {
|
||||||
|
ALL, DoubanSubjectState, DoubanSubjectStateRecords,
|
||||||
DoubanSubjectStateRecords_BOOK_SYNC,
|
DoubanSubjectStateRecords_BOOK_SYNC,
|
||||||
DoubanSubjectStateRecords_BROADCAST_SYNC,
|
DoubanSubjectStateRecords_BROADCAST_SYNC, DoubanSubjectStateRecords_GAME_SYNC,
|
||||||
DoubanSubjectStateRecords_MOVIE_SYNC,
|
DoubanSubjectStateRecords_MOVIE_SYNC,
|
||||||
DoubanSubjectStateRecords_MUSIC_SYNC,
|
DoubanSubjectStateRecords_MUSIC_SYNC,
|
||||||
DoubanSubjectStateRecords_NOTE_SYNC,
|
DoubanSubjectStateRecords_NOTE_SYNC,
|
||||||
@ -25,6 +31,12 @@ import {createFileSelectionSetting} from "../setting/TemplateSettingHelper";
|
|||||||
import {FileSuggest} from "../setting/model/FileSuggest";
|
import {FileSuggest} from "../setting/model/FileSuggest";
|
||||||
import {getDefaultTemplateContent} from "../../constant/DefaultTemplateContent";
|
import {getDefaultTemplateContent} from "../../constant/DefaultTemplateContent";
|
||||||
import TimeUtil from "../../utils/TimeUtil";
|
import TimeUtil from "../../utils/TimeUtil";
|
||||||
|
import SettingsManager from "../setting/SettingsManager";
|
||||||
|
import {ArraySetting, DEFAULT_SETTINGS_ARRAY_NAME} from "../setting/model/ArraySetting";
|
||||||
|
import {arraySettingDisplay} from "../setting/ArrayDisplayTypeSettingsHelper";
|
||||||
|
import {DatePickComponent} from "./DatePickComponent";
|
||||||
|
import {NumberComponent} from "./NumberComponent";
|
||||||
|
import {log} from "../../utils/Logutil";
|
||||||
|
|
||||||
export class DoubanSyncModal extends Modal {
|
export class DoubanSyncModal extends Modal {
|
||||||
plugin: DoubanPlugin;
|
plugin: DoubanPlugin;
|
||||||
@ -96,7 +108,16 @@ export class DoubanSyncModal extends Modal {
|
|||||||
progress.innerHTML = `<p>
|
progress.innerHTML = `<p>
|
||||||
<label for="file">${i18nHelper.getMessage('110033')}</label>
|
<label for="file">${i18nHelper.getMessage('110033')}</label>
|
||||||
<progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal() == 0 ? 1:syncStatus.getTotal()}" value="${syncStatus.getHasHandle()}"> </progress> <span> ${syncStatus.getHasHandle()}/${syncStatus.getTotal()}:${i18nHelper.getMessage('110036')} </span>
|
<progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal() == 0 ? 1:syncStatus.getTotal()}" value="${syncStatus.getHasHandle()}"> </progress> <span> ${syncStatus.getHasHandle()}/${syncStatus.getTotal()}:${i18nHelper.getMessage('110036')} </span>
|
||||||
</p>`
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="file">${i18nHelper.getMessage('110092')}</label>
|
||||||
|
<span>${i18nHelper.getMessage('110090', syncStatus.getTypeName(), syncStatus.getScopeName(), syncStatus.getAllTotal(), syncStatus.getTotal())}</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="file">${i18nHelper.getMessage('110091')}</label>
|
||||||
|
<span>${syncStatus.getMessage()}</span>
|
||||||
|
</p>
|
||||||
|
`
|
||||||
backgroundButton.setDisabled(true);
|
backgroundButton.setDisabled(true);
|
||||||
stopButton.setButtonText(i18nHelper.getMessage('110036'))
|
stopButton.setButtonText(i18nHelper.getMessage('110036'))
|
||||||
return;
|
return;
|
||||||
@ -105,7 +126,16 @@ export class DoubanSyncModal extends Modal {
|
|||||||
<label for="file">${i18nHelper.getMessage('110033')}</label>
|
<label for="file">${i18nHelper.getMessage('110033')}</label>
|
||||||
<progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal() == 0 ? 1:syncStatus.getTotal()}" value="${syncStatus.getHasHandle()}"> </progress> <span> ${syncStatus.getTotal() == 0 ? i18nHelper.getMessage('110043') : syncStatus.getHasHandle() + '/' + syncStatus.getTotal()}
|
<progress class="obsidian_douban_sync_slider" max="${syncStatus.getTotal() == 0 ? 1:syncStatus.getTotal()}" value="${syncStatus.getHasHandle()}"> </progress> <span> ${syncStatus.getTotal() == 0 ? i18nHelper.getMessage('110043') : syncStatus.getHasHandle() + '/' + syncStatus.getTotal()}
|
||||||
${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + TimeUtil.estimateTimeMsg(syncStatus.getNeedHandled()-syncStatus.getHandle(), syncStatus.getOverSize())} </span>
|
${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + TimeUtil.estimateTimeMsg(syncStatus.getNeedHandled()-syncStatus.getHandle(), syncStatus.getOverSize())} </span>
|
||||||
</p>`}
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="file">${i18nHelper.getMessage('110092')}</label>
|
||||||
|
<span>${i18nHelper.getMessage('110090', syncStatus.getTypeName(), syncStatus.getScopeName(), syncStatus.getAllTotal(), syncStatus.getTotal())}</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="file">${i18nHelper.getMessage('110091')}</label>
|
||||||
|
<span>${syncStatus.getMessage()}</span>
|
||||||
|
</p>
|
||||||
|
`}
|
||||||
|
|
||||||
private showSyncConfig(contentEl: HTMLElement) {
|
private showSyncConfig(contentEl: HTMLElement) {
|
||||||
if (this.timer != null) {
|
if (this.timer != null) {
|
||||||
@ -120,8 +150,14 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
cacheImage: ( settings.cacheImage == null) ? DEFAULT_SETTINGS.cacheImage : settings.cacheImage,
|
cacheImage: ( settings.cacheImage == null) ? DEFAULT_SETTINGS.cacheImage : settings.cacheImage,
|
||||||
cacheHighQuantityImage: ( settings.cacheHighQuantityImage == null) ? DEFAULT_SETTINGS.cacheHighQuantityImage : settings.cacheHighQuantityImage,
|
cacheHighQuantityImage: ( settings.cacheHighQuantityImage == null) ? DEFAULT_SETTINGS.cacheHighQuantityImage : settings.cacheHighQuantityImage,
|
||||||
attachmentPath: (settings.attachmentPath == '' || settings.attachmentPath == null) ? DEFAULT_SETTINGS.attachmentPath : settings.attachmentPath,
|
attachmentPath: (settings.attachmentPath == '' || settings.attachmentPath == null) ? DEFAULT_SETTINGS.attachmentPath : settings.attachmentPath,
|
||||||
|
attachmentFileName: (settings.attachmentFileName == '' || settings.attachmentFileName == null) ? DEFAULT_SETTINGS.attachmentFileName : settings.attachmentFileName,
|
||||||
templateFile: (settings.movieTemplateFile == '' || settings.movieTemplateFile == null) ? DEFAULT_SETTINGS.movieTemplateFile : settings.movieTemplateFile,
|
templateFile: (settings.movieTemplateFile == '' || settings.movieTemplateFile == null) ? DEFAULT_SETTINGS.movieTemplateFile : settings.movieTemplateFile,
|
||||||
incrementalUpdate: true,
|
incrementalUpdate: true,
|
||||||
|
syncConditionType: SyncConditionType.ALL,
|
||||||
|
syncConditionDateFromValue: TimeUtil.getLastMonth(),
|
||||||
|
syncConditionDateToValue: new Date(),
|
||||||
|
syncConditionCountFromValue: 1,
|
||||||
|
syncConditionCountToValue: 30
|
||||||
};
|
};
|
||||||
this.showConfigPan(contentEl.createDiv('config'), syncConfig, false);
|
this.showConfigPan(contentEl.createDiv('config'), syncConfig, false);
|
||||||
const controls = contentEl.createDiv("controls");
|
const controls = contentEl.createDiv("controls");
|
||||||
@ -160,10 +196,10 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
private showConfigPan(contentEl: HTMLElement, config:SyncConfig, disable:boolean) {
|
private showConfigPan(contentEl: HTMLElement, config:SyncConfig, disable:boolean) {
|
||||||
new Setting(contentEl);
|
new Setting(contentEl);
|
||||||
this.showTypeDropdown(contentEl, config, disable);
|
this.showTypeDropdown(contentEl, config, disable);
|
||||||
|
this.showCondition(contentEl, config, disable);
|
||||||
this.showOutputFolderSelections(contentEl, config, disable);
|
// this.showOutputFolderSelections(contentEl, config, disable);
|
||||||
this.showOutiFleName(contentEl, config, disable);
|
// this.showOutiFleName(contentEl, config, disable);
|
||||||
this.showAttachmentsFileConfig(contentEl, config, disable);
|
// this.showAttachmentsFileConfig(contentEl, config, disable);
|
||||||
this.showUpdateAllConfig(contentEl, config, disable);
|
this.showUpdateAllConfig(contentEl, config, disable);
|
||||||
this.showForceUpdateConfig(contentEl, config, disable);
|
this.showForceUpdateConfig(contentEl, config, disable);
|
||||||
}
|
}
|
||||||
@ -196,14 +232,17 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
case SyncType.teleplay:
|
case SyncType.teleplay:
|
||||||
this.showScopeDropdown(contentEl, DoubanSubjectStateRecords_TELEPLAY_SYNC, config, disable);
|
this.showScopeDropdown(contentEl, DoubanSubjectStateRecords_TELEPLAY_SYNC, config, disable);
|
||||||
break;
|
break;
|
||||||
|
case SyncType.game:
|
||||||
|
config.scope = DoubanSubjectState.collect;
|
||||||
|
this.showScopeDropdown(contentEl, DoubanSubjectStateRecords_GAME_SYNC, config, disable);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private showTypeDropdown(containerEl:HTMLElement, config: SyncConfig, disable:boolean) {
|
private showTypeDropdown(containerEl:HTMLElement, config: SyncConfig, disable:boolean) {
|
||||||
const settings = new Setting(containerEl);
|
const settings = new Setting(containerEl);
|
||||||
const scopeSelections = containerEl.createDiv("scope-selection");
|
const scopeSelections = containerEl.createDiv("scope-selection");
|
||||||
const templateFile:HTMLDivElement = containerEl.createDiv('template-file-path-selection');
|
// const templateFile:HTMLDivElement = containerEl.createDiv('template-file-path-selection');
|
||||||
settings
|
settings
|
||||||
.setName(i18nHelper.getMessage('110030'))
|
.setName(i18nHelper.getMessage('110030'))
|
||||||
.addDropdown((dropdown) => {
|
.addDropdown((dropdown) => {
|
||||||
@ -213,11 +252,11 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
config.syncType = value;
|
config.syncType = value;
|
||||||
config.templateFile = this.getDefaultTemplatePath(value);
|
config.templateFile = this.getDefaultTemplatePath(value);
|
||||||
this.openScopeDropdown(scopeSelections, config, disable);
|
this.openScopeDropdown(scopeSelections, config, disable);
|
||||||
this.showTemplateFileSelectionSetting(templateFile, config, disable);
|
// this.showTemplateFileSelectionSetting(templateFile, config, disable);
|
||||||
});
|
});
|
||||||
}).setDisabled(disable);
|
}).setDisabled(disable);
|
||||||
this.openScopeDropdown(scopeSelections, config, disable);
|
this.openScopeDropdown(scopeSelections, config, disable);
|
||||||
this.showTemplateFileSelectionSetting(templateFile, config, disable);
|
// this.showTemplateFileSelectionSetting(templateFile, config, disable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDefaultTemplatePath(value: string) {
|
private getDefaultTemplatePath(value: string) {
|
||||||
@ -236,6 +275,9 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
case SyncType.teleplay:
|
case SyncType.teleplay:
|
||||||
result = (settings.teleplayTemplateFile == '' || settings.teleplayTemplateFile == null) ? DEFAULT_SETTINGS.teleplayTemplateFile : settings.teleplayTemplateFile
|
result = (settings.teleplayTemplateFile == '' || settings.teleplayTemplateFile == null) ? DEFAULT_SETTINGS.teleplayTemplateFile : settings.teleplayTemplateFile
|
||||||
break;
|
break;
|
||||||
|
case SyncType.game:
|
||||||
|
result = (settings.gameTemplateFile == '' || settings.gameTemplateFile == null) ? DEFAULT_SETTINGS.gameTemplateFile : settings.gameTemplateFile
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -383,6 +425,20 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.setDisabled(disable);
|
.setDisabled(disable);
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName( i18nHelper.getMessage('121452'))
|
||||||
|
.setDesc( i18nHelper.getMessage('121453'))
|
||||||
|
.addSearch(async (search: SearchComponent) => {
|
||||||
|
new FolderSuggest(this.plugin.app, search.inputEl);
|
||||||
|
// @ts-ignore
|
||||||
|
search.setValue(config.attachmentFileName)
|
||||||
|
// @ts-ignore
|
||||||
|
.setPlaceholder(i18nHelper.getMessage('121454'))
|
||||||
|
.onChange(async (value: string) => {
|
||||||
|
config.attachmentFileName = value;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.setDisabled(disable);
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(i18nHelper.getMessage('121435'))
|
.setName(i18nHelper.getMessage('121435'))
|
||||||
@ -412,4 +468,128 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
.setDisabled(disable);
|
.setDisabled(disable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private showCondition(contentEl: HTMLElement, config: SyncConfig, disable: boolean) {
|
||||||
|
showConditionItem(contentEl.createDiv("sync-douban-condition"), this.plugin.settingsManager, config, disable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showConditionItem(containerEl: HTMLElement, manager: SettingsManager, config: SyncConfig, disable: boolean) {
|
||||||
|
containerEl.empty();
|
||||||
|
const condition = new Setting(containerEl).setName(i18nHelper.getMessage('110070'))
|
||||||
|
|
||||||
|
const conditionDesc = condition.descEl.createDiv('sync-douban-condition-desc');
|
||||||
|
new DropdownComponent(conditionDesc).addOptions(SyncConditionTypeRecords)
|
||||||
|
.setValue(config.syncConditionType)
|
||||||
|
.onChange((value) => {
|
||||||
|
config.syncConditionType = value;
|
||||||
|
showConditionItem(containerEl, manager, config, disable);
|
||||||
|
}).setDisabled(disable);
|
||||||
|
showConditionItemInput(conditionDesc, config, disable);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showConditionItemInput(containerEl: HTMLElement, config: SyncConfig, disable: boolean) {
|
||||||
|
if (config.syncConditionType == SyncConditionType.CUSTOM_ITEM) {
|
||||||
|
showCustomInputCount(containerEl, config, disable);
|
||||||
|
}else if (config.syncConditionType == SyncConditionType.CUSTOM_TIME) {
|
||||||
|
showCustomInputTime(containerEl, config, disable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showCustomInputCount(containerEl: HTMLElement, config: SyncConfig, disable: boolean) {
|
||||||
|
containerEl.createEl('span', { text: ' ' })
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110077') })
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110078') })
|
||||||
|
const fromField = new TextComponent(containerEl);
|
||||||
|
fromField.setPlaceholder(i18nHelper.getMessage('110080'))
|
||||||
|
.setValue(config.syncConditionCountFromValue + '')
|
||||||
|
.onChange(async (value) => {
|
||||||
|
if (!value) {
|
||||||
|
config.syncConditionCountFromValue = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
config.syncConditionCountFromValue = parseInt(value);
|
||||||
|
}catch (e) {
|
||||||
|
log.notice(i18nHelper.getMessage('112080'))
|
||||||
|
}
|
||||||
|
}).setDisabled(disable);
|
||||||
|
let fromEl = fromField.inputEl;
|
||||||
|
fromEl.addClass('obsidian_douban_settings_input')
|
||||||
|
fromEl.style.width ='20%';
|
||||||
|
containerEl.appendChild(fromEl);
|
||||||
|
const lang = window.localStorage.getItem('language');
|
||||||
|
if (lang == 'zh') {
|
||||||
|
containerEl.createEl('span', {text: i18nHelper.getMessage('110073')})
|
||||||
|
}
|
||||||
|
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110079') })
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110078') })
|
||||||
|
const toField = new TextComponent(containerEl);
|
||||||
|
toField.setPlaceholder(i18nHelper.getMessage('110080'))
|
||||||
|
.setValue(config.syncConditionCountToValue + '')
|
||||||
|
.onChange(async (value) => {
|
||||||
|
if (!value) {
|
||||||
|
config.syncConditionCountToValue = 30;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
config.syncConditionCountToValue = parseInt(value);
|
||||||
|
}catch (e) {
|
||||||
|
log.notice(i18nHelper.getMessage('112080'))
|
||||||
|
}
|
||||||
|
}).setDisabled(disable);
|
||||||
|
let toEl = toField.inputEl;
|
||||||
|
toEl.addClass('obsidian_douban_settings_input')
|
||||||
|
toEl.style.width ='20%';
|
||||||
|
containerEl.appendChild(toEl);
|
||||||
|
if (lang == 'zh') {
|
||||||
|
containerEl.createEl('span', {text: i18nHelper.getMessage('110073')})
|
||||||
|
}
|
||||||
|
containerEl.createEl('span', {text: ' '})
|
||||||
|
const buttopn = new ButtonComponent(containerEl).setIcon('help').setTooltip(i18nHelper.getMessage('110095'))
|
||||||
|
containerEl.appendChild(buttopn.buttonEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showCustomInputTime(containerEl: HTMLElement, config: SyncConfig, disable: boolean) {
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110077') })
|
||||||
|
const fromDateField = new TextComponent(containerEl);
|
||||||
|
const fromDateEl = fromDateField.inputEl;
|
||||||
|
fromDateEl.type = 'date';
|
||||||
|
fromDateEl.value = config.syncConditionDateFromValue ? config.syncConditionDateFromValue.toISOString().substring(0, 10) : TimeUtil.getLastMonth().toISOString().substring(0, 10);
|
||||||
|
fromDateField.setPlaceholder(i18nHelper.getMessage('110075'))
|
||||||
|
.setValue(config.syncConditionDateFromValue ? config.syncConditionDateFromValue.toISOString().substring(0, 10) : TimeUtil.getLastMonth().toISOString().substring(0, 10))
|
||||||
|
.onChange(async (value) => {
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
config.syncConditionDateFromValue = new Date(value);
|
||||||
|
}catch (e) {
|
||||||
|
log.notice(i18nHelper.getMessage('110082'))
|
||||||
|
}
|
||||||
|
}).setDisabled(disable);
|
||||||
|
fromDateEl.addClass('obsidian_douban_settings_input')
|
||||||
|
containerEl.appendChild(fromDateEl);
|
||||||
|
|
||||||
|
containerEl.createEl('span', { text: i18nHelper.getMessage('110079') })
|
||||||
|
const toDateField = new TextComponent(containerEl);
|
||||||
|
let toDateEl = toDateField.inputEl;
|
||||||
|
toDateEl.type = 'date';
|
||||||
|
toDateEl.value = config.syncConditionDateToValue ? config.syncConditionDateToValue.toISOString().substring(0, 10) : new Date().toISOString().substring(0, 10);
|
||||||
|
toDateField.setPlaceholder(i18nHelper.getMessage('110075'))
|
||||||
|
.setValue(config.syncConditionDateToValue ? config.syncConditionDateToValue.toISOString().substring(0, 10) : new Date().toISOString().substring(0, 10))
|
||||||
|
.onChange(async (value) => {
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
config.syncConditionDateToValue = new Date(value);
|
||||||
|
}catch (e) {
|
||||||
|
log.notice(i18nHelper.getMessage('110082'))
|
||||||
|
}
|
||||||
|
}).setDisabled(disable);
|
||||||
|
toDateEl.addClass('obsidian_douban_settings_input')
|
||||||
|
containerEl.appendChild(toDateEl);
|
||||||
|
new ButtonComponent(containerEl).setIcon('help').setTooltip(i18nHelper.getMessage('110095'))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/org/wanxp/douban/component/NumberComponent.ts
Normal file
26
src/org/wanxp/douban/component/NumberComponent.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* 日期选择组件
|
||||||
|
* 继承自 TextComponent
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {TextComponent} from 'obsidian';
|
||||||
|
|
||||||
|
export class NumberComponent extends TextComponent {
|
||||||
|
constructor(container: HTMLElement, value: number = 0) {
|
||||||
|
super(container);
|
||||||
|
this.inputEl.type = 'date';
|
||||||
|
this.inputEl.value = value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(): string {
|
||||||
|
return this.inputEl.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//当输入框输入的内容不是数字时,则回退到之前的值
|
||||||
|
// onChanged() {
|
||||||
|
// if (isNaN(Number(this.inputEl.value))) {
|
||||||
|
// this.inputEl.value = this.inputEl.value.slice(0, -1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
@ -5,7 +5,7 @@ import {moment, Platform, TFile} from "obsidian";
|
|||||||
import {i18nHelper} from 'src/org/wanxp/lang/helper';
|
import {i18nHelper} from 'src/org/wanxp/lang/helper';
|
||||||
import {log} from "src/org/wanxp/utils/Logutil";
|
import {log} from "src/org/wanxp/utils/Logutil";
|
||||||
import {CheerioAPI, load} from "cheerio";
|
import {CheerioAPI, load} from "cheerio";
|
||||||
import YamlUtil from "../../../utils/YamlUtil";
|
import YamlUtil, {TITLE_ALIASES_SPECIAL_CHAR_REG_G} from "../../../utils/YamlUtil";
|
||||||
import {
|
import {
|
||||||
BasicConst,
|
BasicConst,
|
||||||
DataValueType,
|
DataValueType,
|
||||||
@ -47,36 +47,44 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
|||||||
|
|
||||||
async parse(extract: T, context: HandleContext): Promise<HandleResult> {
|
async parse(extract: T, context: HandleContext): Promise<HandleResult> {
|
||||||
const template: string = await this.getTemplate(extract, context);
|
const template: string = await this.getTemplate(extract, context);
|
||||||
await this.saveImage(extract, context);
|
const variableMap = this.buildVariableMap(extract, context);
|
||||||
|
this.parseUserInfo(template, variableMap, extract, context);
|
||||||
|
this.parseVariable(template, variableMap, extract, context);
|
||||||
|
await this.saveImage(extract, context, variableMap);
|
||||||
|
|
||||||
const frontMatterStart: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, 0);
|
const frontMatterStart: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, 0);
|
||||||
const frontMatterEnd: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, frontMatterStart + 1);
|
const frontMatterEnd: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, frontMatterStart + 1);
|
||||||
let frontMatter = '';
|
let frontMatter = '';
|
||||||
let frontMatterBefore = '';
|
let frontMatterBefore = '';
|
||||||
let frontMatterAfter = '';
|
let frontMatterAfter = '';
|
||||||
let result = '';
|
let result = '';
|
||||||
|
|
||||||
if (frontMatterStart > -1 && frontMatterEnd > -1) {
|
if (frontMatterStart > -1 && frontMatterEnd > -1) {
|
||||||
frontMatterBefore = template.substring(0, frontMatterStart);
|
frontMatterBefore = template.substring(0, frontMatterStart);
|
||||||
frontMatter = template.substring(frontMatterStart, frontMatterEnd + 3);
|
frontMatter = template.substring(frontMatterStart, frontMatterEnd + 3);
|
||||||
frontMatterAfter = template.substring(frontMatterEnd + 3);
|
frontMatterAfter = template.substring(frontMatterEnd + 3);
|
||||||
if (frontMatterBefore.length > 0) {
|
if (frontMatterBefore.length > 0) {
|
||||||
frontMatterBefore = this.parsePartText(frontMatterBefore, extract, context);
|
frontMatterBefore = this.parsePartText(frontMatterBefore, extract, context, variableMap);
|
||||||
}
|
}
|
||||||
if (frontMatterAfter.length > 0) {
|
if (frontMatterAfter.length > 0) {
|
||||||
frontMatterAfter = this.parsePartText(frontMatterAfter, extract, context);
|
frontMatterAfter = this.parsePartText(frontMatterAfter, extract, context, variableMap);
|
||||||
}
|
}
|
||||||
if (frontMatter.length > 0) {
|
if (frontMatter.length > 0) {
|
||||||
frontMatter = this.parsePartText(frontMatter, extract, context, TemplateTextMode.YAML);
|
frontMatter = this.parsePartYml(frontMatter, extract, context, variableMap);
|
||||||
}
|
}
|
||||||
result = frontMatterBefore + frontMatter + frontMatterAfter;
|
result = frontMatterBefore + frontMatter + frontMatterAfter;
|
||||||
} else {
|
} else {
|
||||||
result = this.parsePartText(template, extract, context);
|
result = this.parsePartText(template, extract, context, variableMap);
|
||||||
|
}
|
||||||
|
let filePath = '';
|
||||||
|
if (SearchHandleMode.FOR_CREATE == context.mode) {
|
||||||
|
filePath = this.parsePartPath(this.getFilePath(context), extract, context, variableMap);
|
||||||
}
|
}
|
||||||
let fileName = '';
|
let fileName = '';
|
||||||
if (SearchHandleMode.FOR_CREATE == context.mode) {
|
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};
|
||||||
return {content: result, fileName: fileName, subject:extract};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFileName(context: HandleContext): string {
|
private getFileName(context: HandleContext): string {
|
||||||
@ -88,13 +96,22 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
|||||||
return dataFileNamePath ? dataFileNamePath : DEFAULT_SETTINGS.dataFileNamePath;
|
return dataFileNamePath ? dataFileNamePath : DEFAULT_SETTINGS.dataFileNamePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getFilePath(context: HandleContext): string {
|
||||||
|
const {syncConfig} = context;
|
||||||
|
if (syncConfig) {
|
||||||
|
return syncConfig.dataFilePath;
|
||||||
|
}
|
||||||
|
const {dataFilePath} = context.settings;
|
||||||
|
return dataFilePath ? dataFilePath : DEFAULT_SETTINGS.dataFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
abstract getSupportType(): SupportType;
|
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;
|
abstract support(extract: DoubanSubject): boolean;
|
||||||
|
|
||||||
@ -125,7 +142,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
|||||||
}else {
|
}else {
|
||||||
context.syncStatusHolder?context.syncStatusHolder.syncStatus.handled(1):null;
|
context.syncStatusHolder?context.syncStatusHolder.syncStatus.handled(1):null;
|
||||||
}
|
}
|
||||||
return e;
|
return undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -207,7 +224,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
|||||||
default:
|
default:
|
||||||
resultName = name;
|
resultName = name;
|
||||||
}
|
}
|
||||||
return resultName;
|
return resultName.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
getTitleNameByMode(name: string, personNameMode: string, context: HandleContext): string {
|
getTitleNameByMode(name: string, personNameMode: string, context: HandleContext): string {
|
||||||
@ -254,13 +271,25 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private parsePartText(template: string, extract: T, context: HandleContext, textMode: TemplateTextMode = TemplateTextMode.NORMAL): string {
|
private parsePartYml(template: string, extract: T, context: HandleContext, variableMap : Map<string, DataField>): string {
|
||||||
const variableMap:Map<string, DataField> = new Map();
|
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)) {
|
for (const [key, value] of Object.entries(extract)) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const type:DataValueType = VariableUtil.getType(value);
|
const type: DataValueType = VariableUtil.getType(value);
|
||||||
if (key == 'score') {
|
if (key == 'score') {
|
||||||
variableMap.set(DoubanParameterName.SCORE_STAR, new DataField(
|
variableMap.set(DoubanParameterName.SCORE_STAR, new DataField(
|
||||||
DoubanParameterName.SCORE_STAR,
|
DoubanParameterName.SCORE_STAR,
|
||||||
@ -308,14 +337,10 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
|||||||
currentDate,
|
currentDate,
|
||||||
moment(currentDate).format(context.settings.timeFormat)
|
moment(currentDate).format(context.settings.timeFormat)
|
||||||
));
|
));
|
||||||
|
return variableMap;
|
||||||
this.parseUserInfo(template, variableMap, extract, context, textMode);
|
|
||||||
this.parseVariable(template, variableMap, extract, context, textMode);
|
|
||||||
return VariableUtil.replaceSubject(variableMap, template, this.getSupportType(), this.doubanPlugin.settingsManager);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
const userState = extract.userState;
|
||||||
if ((resultContent.indexOf(DoubanUserParameter.MY_TAGS) >= 0 ||
|
if ((resultContent.indexOf(DoubanUserParameter.MY_TAGS) >= 0 ||
|
||||||
resultContent.indexOf(DoubanUserParameter.MY_RATING) >= 0 ||
|
resultContent.indexOf(DoubanUserParameter.MY_RATING) >= 0 ||
|
||||||
@ -389,22 +414,22 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
|||||||
private getTemplateKey():TemplateKey {
|
private getTemplateKey():TemplateKey {
|
||||||
let templateKey: TemplateKey;
|
let templateKey: TemplateKey;
|
||||||
switch (this.getSupportType()) {
|
switch (this.getSupportType()) {
|
||||||
case SupportType.MOVIE:
|
case SupportType.movie:
|
||||||
templateKey = TemplateKey.movieTemplateFile;
|
templateKey = TemplateKey.movieTemplateFile;
|
||||||
break;
|
break;
|
||||||
case SupportType.BOOK:
|
case SupportType.book:
|
||||||
templateKey = TemplateKey.bookTemplateFile;
|
templateKey = TemplateKey.bookTemplateFile;
|
||||||
break;
|
break;
|
||||||
case SupportType.MUSIC:
|
case SupportType.music:
|
||||||
templateKey = TemplateKey.musicTemplateFile;
|
templateKey = TemplateKey.musicTemplateFile;
|
||||||
break;
|
break;
|
||||||
case SupportType.TELEPLAY:
|
case SupportType.teleplay:
|
||||||
templateKey = TemplateKey.teleplayTemplateFile;
|
templateKey = TemplateKey.teleplayTemplateFile;
|
||||||
break;
|
break;
|
||||||
case SupportType.GAME:
|
case SupportType.game:
|
||||||
templateKey = TemplateKey.gameTemplateFile;
|
templateKey = TemplateKey.gameTemplateFile;
|
||||||
break;
|
break;
|
||||||
case SupportType.NOTE:
|
case SupportType.note:
|
||||||
templateKey = TemplateKey.noteTemplateFile;
|
templateKey = TemplateKey.noteTemplateFile;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -497,43 +522,82 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async saveImage(extract: T, context: HandleContext) {
|
private async saveImage(extract: T, context: HandleContext, variableMap : Map<string, DataField>) {
|
||||||
const {syncConfig} = context;
|
const {syncConfig} = context;
|
||||||
if (!extract.image || (syncConfig && !syncConfig.cacheImage) || !context.settings.cacheImage) {
|
if (!extract.image || (syncConfig && !syncConfig.cacheImage) || !context.settings.cacheImage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const image = extract.image;
|
const image = extract.image;
|
||||||
const filename = image.split('/').pop();
|
|
||||||
let folder = syncConfig? syncConfig.attachmentPath : context.settings.attachmentPath;
|
let folder = syncConfig? syncConfig.attachmentPath : context.settings.attachmentPath;
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
folder = DEFAULT_SETTINGS.attachmentPath;
|
folder = DEFAULT_SETTINGS.attachmentPath;
|
||||||
}
|
}
|
||||||
folder = this.parsePartText(folder, extract, context)
|
folder = this.parsePartPath(folder, extract, context, variableMap)
|
||||||
|
let fileName = syncConfig? syncConfig.attachmentFileName : context.settings.attachmentFileName;
|
||||||
const referHeaders = {'referer': image};
|
if (!fileName) {
|
||||||
|
fileName = DEFAULT_SETTINGS.attachmentFileName;
|
||||||
|
}
|
||||||
|
let fileNameSuffix = image ? image.substring(image.lastIndexOf('.')) : '.jpg';
|
||||||
|
if (fileNameSuffix && fileNameSuffix.length > 10) {
|
||||||
|
fileNameSuffix = '.jpg';
|
||||||
|
}
|
||||||
|
fileName = this.parsePartPath(fileName, extract, context, variableMap)
|
||||||
|
fileName = fileName + fileNameSuffix;
|
||||||
|
const imageReferer = (extract.id ? this.getSubjectUrl(extract.id) : '') || extract.url;
|
||||||
|
const referHeaders = HttpUtil.buildImageRequestHeaders(
|
||||||
|
context.plugin.settingsManager.getHeaders() as Record<string, any>,
|
||||||
|
imageReferer
|
||||||
|
);
|
||||||
if ((syncConfig ? syncConfig.cacheHighQuantityImage : context.settings.cacheHighQuantityImage) && context.userComponent.isLogin()) {
|
if ((syncConfig ? syncConfig.cacheHighQuantityImage : context.settings.cacheHighQuantityImage) && context.userComponent.isLogin()) {
|
||||||
try {
|
try {
|
||||||
const fileNameSpilt = filename.split('.');
|
const highImageFilename = this.getImageFilename(image);
|
||||||
const highFilename = fileNameSpilt.first() + '.jpg';
|
const highImage = this.getHighQuantityImageUrl(highImageFilename);
|
||||||
|
const highImageHeaders = HttpUtil.buildImageRequestHeaders(
|
||||||
const highImage = this.getHighQuantityImageUrl(highFilename);
|
context.plugin.settingsManager.getHeaders() as Record<string, any>,
|
||||||
const resultValue = await this.handleImage(highImage, folder, highFilename, context, false, referHeaders);
|
imageReferer
|
||||||
|
);
|
||||||
|
const resultValue = await this.handleImage(highImage, folder, fileName, context, false, highImageHeaders);
|
||||||
if (resultValue && resultValue.success) {
|
if (resultValue && resultValue.success) {
|
||||||
extract.image = resultValue.filepath;
|
extract.image = resultValue.filepath;
|
||||||
|
this.initImageVariableMap(extract, context, variableMap);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}catch (e) {
|
}catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
console.error('下载高清封面失败,将会使用普通封面')
|
console.error('下载高清封面失败,将会使用普通封面')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const resultValue = await this.handleImage(image, folder, filename, context, true, referHeaders);
|
const resultValue = await this.handleImage(image, folder, fileName, context, true, referHeaders);
|
||||||
if (resultValue && resultValue.success) {
|
if (resultValue && resultValue.success) {
|
||||||
extract.image = resultValue.filepath;
|
extract.image = resultValue.filepath;
|
||||||
|
this.initImageVariableMap(extract, context, variableMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getImageFilename(image: string): string {
|
||||||
|
if (!image) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const imageUrl = image.split('?').first() || image;
|
||||||
|
return imageUrl.substring(imageUrl.lastIndexOf('/') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private initImageVariableMap(extract: T, context: HandleContext, variableMap : Map<string, DataField>) {
|
||||||
|
variableMap.set(DoubanParameterName.IMAGE_URL, new DataField(
|
||||||
|
DoubanParameterName.IMAGE_URL,
|
||||||
|
DataValueType.url,
|
||||||
|
extract.imageUrl,
|
||||||
|
extract.imageUrl
|
||||||
|
));
|
||||||
|
variableMap.set(DoubanParameterName.IMAGE, new DataField(
|
||||||
|
DoubanParameterName.IMAGE,
|
||||||
|
DataValueType.path,
|
||||||
|
extract.image,
|
||||||
|
extract.image
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private async handleImage(image: string, folder: string, filename: string, context: HandleContext, showError: boolean, headers?: any) {
|
private async handleImage(image: string, folder: string, filename: string, context: HandleContext, showError: boolean, headers?: any) {
|
||||||
//只有在桌面版且开启了图片上传才会使用PicGo,并且开启图床功能
|
//只有在桌面版且开启了图片上传才会使用PicGo,并且开启图床功能
|
||||||
if (context.settings.pictureBedFlag && Platform.isDesktopApp) {
|
if (context.settings.pictureBedFlag && Platform.isDesktopApp) {
|
||||||
@ -557,12 +621,20 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
|||||||
|
|
||||||
handlePersonNameByMeta(html: CheerioAPI, movie: DoubanSubject, context: HandleContext,
|
handlePersonNameByMeta(html: CheerioAPI, movie: DoubanSubject, context: HandleContext,
|
||||||
metaProperty:string, objectProperty:string) {
|
metaProperty:string, objectProperty:string) {
|
||||||
|
if (!movie) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const metaProperties: string[] = html(`head > meta[property='${metaProperty}']`).get()
|
const metaProperties: string[] = html(`head > meta[property='${metaProperty}']`).get()
|
||||||
.map((e) => {
|
.map((e) => {
|
||||||
return html(e).attr('content');
|
return html(e).attr('content');
|
||||||
});
|
});
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
movie[objectProperty]
|
const currentArray = movie[objectProperty];
|
||||||
|
if (!Array.isArray(currentArray)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
currentArray
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
.filter((p:Person) => p.name)
|
.filter((p:Person) => p.name)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<Dou
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSupportType(): SupportType {
|
getSupportType(): SupportType {
|
||||||
return SupportType.BOOK;
|
return SupportType.book;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHighQuantityImageUrl(fileName:string):string{
|
getHighQuantityImageUrl(fileName:string):string{
|
||||||
@ -28,11 +28,11 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<Dou
|
|||||||
return `https://book.douban.com/subject/${id}/`;
|
return `https://book.douban.com/subject/${id}/`;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: DoubanBookSubject, context: HandleContext, textMode: TemplateTextMode): void {
|
parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: DoubanBookSubject, context: HandleContext): void {
|
||||||
variableMap.set(DoubanBookParameter.author, new DataField(DoubanBookParameter.author,
|
variableMap.set(DoubanBookParameter.author, new DataField(DoubanBookParameter.author,
|
||||||
DataValueType.array, extract.author, extract.author.map(this.handleSpecialAuthorName)));
|
DataValueType.array, extract.author, (extract.author || []).map(this.handleSpecialAuthorName)));
|
||||||
variableMap.set(DoubanBookParameter.translator, new DataField(DoubanBookParameter.translator,
|
variableMap.set(DoubanBookParameter.translator, new DataField(DoubanBookParameter.translator,
|
||||||
DataValueType.array, extract.translator, extract.translator.map(this.handleSpecialAuthorName)));
|
DataValueType.array, extract.translator, (extract.translator || []).map(this.handleSpecialAuthorName)));
|
||||||
}
|
}
|
||||||
|
|
||||||
support(extract: DoubanSubject): boolean {
|
support(extract: DoubanSubject): boolean {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {UserStateSubject} from "../model/UserStateSubject";
|
|||||||
import {moment} from "obsidian";
|
import {moment} from "obsidian";
|
||||||
import {TITLE_ALIASES_SPECIAL_CHAR_REG_G} from "../../../utils/YamlUtil";
|
import {TITLE_ALIASES_SPECIAL_CHAR_REG_G} from "../../../utils/YamlUtil";
|
||||||
import {DataField} from "../../../utils/model/DataField";
|
import {DataField} from "../../../utils/model/DataField";
|
||||||
|
import {b} from "@shikijs/engine-javascript/dist/shared/engine-javascript.BnuFKbIS";
|
||||||
|
|
||||||
export default class DoubanGameLoadHandler extends DoubanAbstractLoadHandler<DoubanGameSubject> {
|
export default class DoubanGameLoadHandler extends DoubanAbstractLoadHandler<DoubanGameSubject> {
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ export default class DoubanGameLoadHandler extends DoubanAbstractLoadHandler<Dou
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSupportType(): SupportType {
|
getSupportType(): SupportType {
|
||||||
return SupportType.GAME;
|
return SupportType.game;
|
||||||
}
|
}
|
||||||
getHighQuantityImageUrl(fileName:string):string{
|
getHighQuantityImageUrl(fileName:string):string{
|
||||||
return `https://img9.doubanio.com/lpic/${fileName}`;
|
return `https://img9.doubanio.com/lpic/${fileName}`;
|
||||||
@ -28,7 +29,18 @@ export default class DoubanGameLoadHandler extends DoubanAbstractLoadHandler<Dou
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: DoubanGameSubject, context: HandleContext): void {
|
parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: DoubanGameSubject, context: HandleContext): void {
|
||||||
variableMap.set("aliases", new DataField("aliases", DataValueType.array, extract.aliases, extract.aliases.map(a=>a.replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_'))));
|
// super.parseAliases(beforeContent, variableMap, extract, context);
|
||||||
|
variableMap.set("aliases", new DataField("aliases", DataValueType.array, extract.aliases,
|
||||||
|
(extract.aliases || []).map(a=>a
|
||||||
|
.trim()
|
||||||
|
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
||||||
|
// //replase multiple _ to single _
|
||||||
|
// .replace(/_+/g, '_')
|
||||||
|
// .replace(/^_/, '')
|
||||||
|
// .replace(/_$/, '')
|
||||||
|
.replace(/:\s+/g, ':')
|
||||||
|
)));
|
||||||
|
// super.parseAliases(beforeContent, variableMap, extract, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
support(extract: DoubanSubject): boolean {
|
support(extract: DoubanSubject): boolean {
|
||||||
|
|||||||
@ -19,7 +19,7 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSupportType(): SupportType {
|
getSupportType(): SupportType {
|
||||||
return SupportType.MOVIE;
|
return SupportType.movie;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHighQuantityImageUrl(fileName:string):string{
|
getHighQuantityImageUrl(fileName:string):string{
|
||||||
@ -35,30 +35,34 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
|
|||||||
"director",
|
"director",
|
||||||
DataValueType.array,
|
DataValueType.array,
|
||||||
extract.director,
|
extract.director,
|
||||||
extract.director.map(SchemaOrg.getPersonName).filter(c => c)
|
(extract.director || []).map(SchemaOrg.getPersonName).filter(c => c)
|
||||||
));
|
));
|
||||||
|
|
||||||
variableMap.set("actor", new DataField(
|
variableMap.set("actor", new DataField(
|
||||||
"actor",
|
"actor",
|
||||||
DataValueType.array,
|
DataValueType.array,
|
||||||
extract.actor,
|
extract.actor,
|
||||||
extract.actor.map(SchemaOrg.getPersonName).filter(c => c)
|
(extract.actor || []).map(SchemaOrg.getPersonName).filter(c => c)
|
||||||
));
|
));
|
||||||
|
|
||||||
variableMap.set("author", new DataField(
|
variableMap.set("author", new DataField(
|
||||||
"author",
|
"author",
|
||||||
DataValueType.array,
|
DataValueType.array,
|
||||||
extract.author,
|
extract.author,
|
||||||
extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c)
|
(extract.author || []).map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c)
|
||||||
));
|
));
|
||||||
|
variableMap.set("aliases", new DataField("aliases", DataValueType.array, extract.aliases,
|
||||||
variableMap.set("aliases", new DataField(
|
(extract.aliases || []).map(a=>a
|
||||||
"aliases",
|
.trim()
|
||||||
DataValueType.array,
|
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
||||||
extract.aliases,
|
// //replase multiple _ to single _
|
||||||
extract.aliases.map(a => a.replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_'))
|
// .replace(/_+/g, '_')
|
||||||
));
|
// .replace(/^_/, '')
|
||||||
}
|
// .replace(/_$/, '')
|
||||||
|
.replace(/:\s+/g, ':')
|
||||||
|
)));
|
||||||
|
// super.parseAliases(beforeContent, variableMap, extract, context);
|
||||||
|
}
|
||||||
|
|
||||||
support(extract: DoubanSubject): boolean {
|
support(extract: DoubanSubject): boolean {
|
||||||
return extract && extract.type && (extract.type.contains("电影") || extract.type.contains("Movie") || extract.type.contains("movie"));
|
return extract && extract.type && (extract.type.contains("电影") || extract.type.contains("Movie") || extract.type.contains("movie"));
|
||||||
@ -94,7 +98,7 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanMovieSubject {
|
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanMovieSubject {
|
||||||
const movie:DoubanMovieSubject = html('script')
|
let movie: DoubanMovieSubject | undefined = html('script')
|
||||||
.get()
|
.get()
|
||||||
.filter(scd => "application/ld+json" == html(scd).attr("type"))
|
.filter(scd => "application/ld+json" == html(scd).attr("type"))
|
||||||
.map(i => {
|
.map(i => {
|
||||||
@ -104,8 +108,8 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
|
|||||||
const idPattern = /(\d){5,10}/g;
|
const idPattern = /(\d){5,10}/g;
|
||||||
const id = idPattern.exec(obj.url);
|
const id = idPattern.exec(obj.url);
|
||||||
const name = obj.name;
|
const name = obj.name;
|
||||||
const title = super.getTitleNameByMode(name, PersonNameMode.CH_NAME, context)??name;
|
const title = super.getTitleNameByMode(name, PersonNameMode.CH_NAME, context) ?? name;
|
||||||
const originalTitle = super.getTitleNameByMode(name, PersonNameMode.EN_NAME, context) ?? name;
|
const originalTitle = super.getTitleNameByMode(name, PersonNameMode.EN_NAME, context) ?? name;
|
||||||
|
|
||||||
const result: DoubanMovieSubject = {
|
const result: DoubanMovieSubject = {
|
||||||
id: id ? id[0] : '',
|
id: id ? id[0] : '',
|
||||||
@ -115,14 +119,14 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
|
|||||||
originalTitle: originalTitle,
|
originalTitle: originalTitle,
|
||||||
desc: obj.description,
|
desc: obj.description,
|
||||||
url: "https://movie.douban.com" + obj.url,
|
url: "https://movie.douban.com" + obj.url,
|
||||||
director: obj.director,
|
director: obj.director || [],
|
||||||
author: obj.author,
|
author: obj.author || [],
|
||||||
actor: obj.actor,
|
actor: obj.actor || [],
|
||||||
aggregateRating: obj.aggregateRating,
|
aggregateRating: obj.aggregateRating,
|
||||||
datePublished: obj.datePublished ? new Date(obj.datePublished) : undefined,
|
datePublished: obj.datePublished ? new Date(obj.datePublished) : undefined,
|
||||||
image: obj.image,
|
image: obj.image,
|
||||||
imageUrl: obj.image,
|
imageUrl: obj.image,
|
||||||
genre: obj.genre,
|
genre: obj.genre || [],
|
||||||
publisher: '',
|
publisher: '',
|
||||||
aliases: [""],
|
aliases: [""],
|
||||||
language: [""],
|
language: [""],
|
||||||
@ -132,10 +136,52 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
})[0];
|
})[0];
|
||||||
this.handlePersonNameByMeta(html, movie, context, 'video:actor', 'actor');
|
|
||||||
this.handlePersonNameByMeta(html, movie, context, 'video:director', 'director');
|
|
||||||
|
|
||||||
const desc:string = html("span[property='v:summary']").text();
|
// Fallback: if JSON-LD parsing failed (e.g., anti-bot page), extract from meta tags
|
||||||
|
if (!movie) {
|
||||||
|
const title = html(html("head > meta[property='og:title']").get(0)).attr("content") || '';
|
||||||
|
const image = html(html("head > meta[property='og:image']").get(0)).attr("content") || '';
|
||||||
|
const urlMeta = html(html("head > meta[property='og:url']").get(0)).attr("content") || '';
|
||||||
|
const desc = html(html("head > meta[property='og:description']").get(0)).attr("content") || '';
|
||||||
|
|
||||||
|
// Extract ID from URL
|
||||||
|
const idPattern = /(\d){5,10}/g;
|
||||||
|
const idMatch = idPattern.exec(urlMeta);
|
||||||
|
const id = idMatch ? idMatch[0] : '';
|
||||||
|
|
||||||
|
// Extract score from HTML
|
||||||
|
const scoreText = html("#interest_sectl strong[property='v:average']").text();
|
||||||
|
const score = scoreText ? parseFloat(scoreText) : undefined;
|
||||||
|
|
||||||
|
movie = {
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
type: this.getSupportType(),
|
||||||
|
score,
|
||||||
|
originalTitle: title,
|
||||||
|
desc,
|
||||||
|
url: urlMeta || (id ? `https://movie.douban.com/subject/${id}/` : ''),
|
||||||
|
director: [],
|
||||||
|
author: [],
|
||||||
|
actor: [],
|
||||||
|
aggregateRating: undefined,
|
||||||
|
datePublished: undefined,
|
||||||
|
image,
|
||||||
|
imageUrl: image,
|
||||||
|
genre: [],
|
||||||
|
publisher: '',
|
||||||
|
aliases: [],
|
||||||
|
language: [],
|
||||||
|
country: [],
|
||||||
|
time: null,
|
||||||
|
IMDb: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handlePersonNameByMeta(html, movie, context, 'video:actor', 'actor');
|
||||||
|
this.handlePersonNameByMeta(html, movie, context, 'video:director', 'director');
|
||||||
|
|
||||||
|
const desc: string = html("span[property='v:summary']").text();
|
||||||
if (desc) {
|
if (desc) {
|
||||||
movie.desc = desc;
|
movie.desc = desc;
|
||||||
}
|
}
|
||||||
@ -152,7 +198,7 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
|
|||||||
// value = html(info.next.next).text().trim();
|
// value = html(info.next.next).text().trim();
|
||||||
const vas = html(info.next).text().trim();
|
const vas = html(info.next).text().trim();
|
||||||
value = vas.split("/").map((v) => v.trim());
|
value = vas.split("/").map((v) => v.trim());
|
||||||
} else if(key.indexOf('片长') >= 0) {
|
} else if (key.indexOf('片长') >= 0) {
|
||||||
value = html(info.next.next).text().trim()
|
value = html(info.next.next).text().trim()
|
||||||
} else {
|
} else {
|
||||||
value = html(info.next).text().trim();
|
value = html(info.next).text().trim();
|
||||||
@ -160,11 +206,11 @@ export default class DoubanMovieLoadHandler extends DoubanAbstractLoadHandler<Do
|
|||||||
valueMap.set(MovieKeyValueMap.get(key), value);
|
valueMap.set(MovieKeyValueMap.get(key), value);
|
||||||
})
|
})
|
||||||
|
|
||||||
movie.country = valueMap.has('country') ? valueMap.get('country') : [];
|
movie.country = valueMap.has('country') ? valueMap.get('country') : [];
|
||||||
movie.language = valueMap.has('language') ? valueMap.get('language') : [];
|
movie.language = valueMap.has('language') ? valueMap.get('language') : [];
|
||||||
movie.time = valueMap.has('time') ? valueMap.get('time') : "";
|
movie.time = valueMap.has('time') ? valueMap.get('time') : "";
|
||||||
movie.aliases = valueMap.has('aliases') ? valueMap.get('aliases') : [];
|
movie.aliases = valueMap.has('aliases') ? valueMap.get('aliases') : [];
|
||||||
movie.IMDb = valueMap.has('IMDb') ? valueMap.get('IMDb') : "";
|
movie.IMDb = valueMap.has('IMDb') ? valueMap.get('IMDb') : "";
|
||||||
return movie;
|
return movie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler<Do
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSupportType(): SupportType {
|
getSupportType(): SupportType {
|
||||||
return SupportType.MUSIC;
|
return SupportType.music;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHighQuantityImageUrl(fileName:string):string{
|
getHighQuantityImageUrl(fileName:string):string{
|
||||||
@ -88,6 +88,9 @@ export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler<Do
|
|||||||
const idPattern = /(\d){5,10}/g;
|
const idPattern = /(\d){5,10}/g;
|
||||||
const id = idPattern.exec(url);
|
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 = {
|
const result: DoubanMusicSubject = {
|
||||||
image: image,
|
image: image,
|
||||||
imageUrl: image,
|
imageUrl: image,
|
||||||
@ -104,11 +107,10 @@ export default class DoubanMusicLoadHandler extends DoubanAbstractLoadHandler<Do
|
|||||||
genre: valueMap.has('genre') ? [valueMap.get('genre')] : [""],
|
genre: valueMap.has('genre') ? [valueMap.get('genre')] : [""],
|
||||||
albumType: valueMap.has('albumType') ? valueMap.get('albumType') : "",
|
albumType: valueMap.has('albumType') ? valueMap.get('albumType') : "",
|
||||||
medium: valueMap.has('medium') ? valueMap.get('medium') : "",
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export default class DoubanNoteLoadHandler extends DoubanAbstractLoadHandler<Dou
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSupportType(): SupportType {
|
getSupportType(): SupportType {
|
||||||
return SupportType.NOTE;
|
return SupportType.note;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHighQuantityImageUrl(fileName:string):string{
|
getHighQuantityImageUrl(fileName:string):string{
|
||||||
|
|||||||
@ -12,8 +12,8 @@ import {DataField} from "../../../utils/model/DataField";
|
|||||||
* 默认的处理器
|
* 默认的处理器
|
||||||
*/
|
*/
|
||||||
export default class DoubanOtherLoadHandler extends DoubanAbstractLoadHandler<DoubanSubject> {
|
export default class DoubanOtherLoadHandler extends DoubanAbstractLoadHandler<DoubanSubject> {
|
||||||
getSupportType(): SupportType.ALL {
|
getSupportType(): SupportType.all {
|
||||||
return SupportType.ALL;
|
return SupportType.all;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: DoubanSubject, context: HandleContext): void {
|
parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: DoubanSubject, context: HandleContext): void {
|
||||||
|
|||||||
@ -21,31 +21,35 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler<DoubanT
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSupportType(): SupportType {
|
getSupportType(): SupportType {
|
||||||
return SupportType.TELEPLAY;
|
return SupportType.teleplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: DoubanTeleplaySubject, context: HandleContext): void {
|
parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: DoubanTeleplaySubject, context: HandleContext): void {
|
||||||
variableMap.set("director", new DataField("director", DataValueType.array, extract.director,extract.director.map(SchemaOrg.getPersonName).filter(c => c)));
|
variableMap.set("director", new DataField("director", DataValueType.array, extract.director,(extract.director || []).map(SchemaOrg.getPersonName).filter(c => c)));
|
||||||
variableMap.set("actor", new DataField(
|
variableMap.set("actor", new DataField(
|
||||||
"actor",
|
"actor",
|
||||||
DataValueType.array,
|
DataValueType.array,
|
||||||
extract.actor,
|
extract.actor,
|
||||||
extract.actor.map(SchemaOrg.getPersonName).filter(c => c)
|
(extract.actor || []).map(SchemaOrg.getPersonName).filter(c => c)
|
||||||
));
|
));
|
||||||
|
|
||||||
variableMap.set("author", new DataField(
|
variableMap.set("author", new DataField(
|
||||||
"author",
|
"author",
|
||||||
DataValueType.array,
|
DataValueType.array,
|
||||||
extract.author,
|
extract.author,
|
||||||
extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c)
|
(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, '_'))
|
|
||||||
));
|
));
|
||||||
|
variableMap.set("aliases", new DataField("aliases", DataValueType.array, extract.aliases,
|
||||||
|
(extract.aliases || []).map(a=>a
|
||||||
|
.trim()
|
||||||
|
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
||||||
|
// //replase multiple _ to single _
|
||||||
|
// .replace(/_+/g, '_')
|
||||||
|
// .replace(/^_/, '')
|
||||||
|
// .replace(/_$/, '')
|
||||||
|
.replace(/:\s+/g, ':')
|
||||||
|
)));
|
||||||
|
// super.parseAliases(beforeContent, variableMap, extract, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
support(extract: DoubanSubject): boolean {
|
support(extract: DoubanSubject): boolean {
|
||||||
@ -80,7 +84,7 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler<DoubanT
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanTeleplaySubject {
|
parseSubjectFromHtml(html: CheerioAPI, context: HandleContext): DoubanTeleplaySubject {
|
||||||
const teleplay:DoubanTeleplaySubject = html('script')
|
let teleplay: DoubanTeleplaySubject | undefined = html('script')
|
||||||
.get()
|
.get()
|
||||||
.filter(scd => "application/ld+json" == html(scd).attr("type"))
|
.filter(scd => "application/ld+json" == html(scd).attr("type"))
|
||||||
.map(i => {
|
.map(i => {
|
||||||
@ -100,14 +104,14 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler<DoubanT
|
|||||||
originalTitle: originalTitle,
|
originalTitle: originalTitle,
|
||||||
desc: obj.description,
|
desc: obj.description,
|
||||||
url: "https://movie.douban.com" + obj.url,
|
url: "https://movie.douban.com" + obj.url,
|
||||||
director: obj.director,
|
director: obj.director || [],
|
||||||
author: obj.author,
|
author: obj.author || [],
|
||||||
actor: obj.actor,
|
actor: obj.actor || [],
|
||||||
aggregateRating: obj.aggregateRating,
|
aggregateRating: obj.aggregateRating,
|
||||||
datePublished: obj.datePublished ? new Date(obj.datePublished) : undefined,
|
datePublished: obj.datePublished ? new Date(obj.datePublished) : undefined,
|
||||||
image: obj.image,
|
image: obj.image,
|
||||||
imageUrl: obj.image,
|
imageUrl: obj.image,
|
||||||
genre: obj.genre,
|
genre: obj.genre || [],
|
||||||
score: obj.aggregateRating ? obj.aggregateRating.ratingValue : undefined,
|
score: obj.aggregateRating ? obj.aggregateRating.ratingValue : undefined,
|
||||||
publisher: "",
|
publisher: "",
|
||||||
aliases: [""],
|
aliases: [""],
|
||||||
@ -120,6 +124,46 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler<DoubanT
|
|||||||
return result;
|
return result;
|
||||||
})[0];
|
})[0];
|
||||||
|
|
||||||
|
// Fallback: if JSON-LD parsing failed, extract from meta tags
|
||||||
|
if (!teleplay) {
|
||||||
|
const title = html(html("head > meta[property='og:title']").get(0)).attr("content") || '';
|
||||||
|
const image = html(html("head > meta[property='og:image']").get(0)).attr("content") || '';
|
||||||
|
const urlMeta = html(html("head > meta[property='og:url']").get(0)).attr("content") || '';
|
||||||
|
const desc = html(html("head > meta[property='og:description']").get(0)).attr("content") || '';
|
||||||
|
|
||||||
|
const idPattern = /(\d){5,10}/g;
|
||||||
|
const idMatch = idPattern.exec(urlMeta);
|
||||||
|
const id = idMatch ? idMatch[0] : '';
|
||||||
|
|
||||||
|
const scoreText = html("#interest_sectl strong[property='v:average']").text();
|
||||||
|
const score = scoreText ? parseFloat(scoreText) : undefined;
|
||||||
|
|
||||||
|
teleplay = {
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
type: this.getSupportType(),
|
||||||
|
score,
|
||||||
|
originalTitle: title,
|
||||||
|
desc,
|
||||||
|
url: urlMeta || (id ? `https://movie.douban.com/subject/${id}/` : ''),
|
||||||
|
director: [],
|
||||||
|
author: [],
|
||||||
|
actor: [],
|
||||||
|
aggregateRating: undefined,
|
||||||
|
datePublished: undefined,
|
||||||
|
image,
|
||||||
|
imageUrl: image,
|
||||||
|
genre: [],
|
||||||
|
publisher: '',
|
||||||
|
aliases: [],
|
||||||
|
language: [],
|
||||||
|
country: [],
|
||||||
|
episode: null,
|
||||||
|
time: null,
|
||||||
|
IMDb: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
this.handlePersonNameByMeta(html, teleplay, context, 'video:actor', 'actor');
|
this.handlePersonNameByMeta(html, teleplay, context, 'video:actor', 'actor');
|
||||||
this.handlePersonNameByMeta(html, teleplay, context, 'video:director', 'director');
|
this.handlePersonNameByMeta(html, teleplay, context, 'video:director', 'director');
|
||||||
const desc:string = html("span[property='v:summary']").text();
|
const desc:string = html("span[property='v:summary']").text();
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export default class DoubanTheaterLoadHandler extends DoubanAbstractLoadHandler<
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSupportType(): SupportType {
|
getSupportType(): SupportType {
|
||||||
return SupportType.THEATER;
|
return SupportType.theater;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHighQuantityImageUrl(fileName: string): string {
|
getHighQuantityImageUrl(fileName: string): string {
|
||||||
@ -33,28 +33,36 @@ export default class DoubanTheaterLoadHandler extends DoubanAbstractLoadHandler<
|
|||||||
"director",
|
"director",
|
||||||
DataValueType.array,
|
DataValueType.array,
|
||||||
extract.director,
|
extract.director,
|
||||||
extract.director.map(SchemaOrg.getPersonName).filter(c => c)
|
(extract.director || []).map(SchemaOrg.getPersonName).filter(c => c)
|
||||||
));
|
));
|
||||||
|
|
||||||
variableMap.set("actor", new DataField(
|
variableMap.set("actor", new DataField(
|
||||||
"actor",
|
"actor",
|
||||||
DataValueType.array,
|
DataValueType.array,
|
||||||
extract.actor,
|
extract.actor,
|
||||||
extract.actor.map(SchemaOrg.getPersonName).filter(c => c)
|
(extract.actor || []).map(SchemaOrg.getPersonName).filter(c => c)
|
||||||
));
|
));
|
||||||
|
|
||||||
variableMap.set("author", new DataField(
|
variableMap.set("author", new DataField(
|
||||||
"author",
|
"author",
|
||||||
DataValueType.array,
|
DataValueType.array,
|
||||||
extract.author,
|
extract.author,
|
||||||
extract.author.map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c)
|
(extract.author || []).map(SchemaOrg.getPersonName).map(name => super.getPersonName(name, context)).filter(c => c)
|
||||||
));
|
));
|
||||||
|
|
||||||
variableMap.set("aliases", new DataField(
|
variableMap.set("aliases", new DataField(
|
||||||
"aliases",
|
"aliases",
|
||||||
DataValueType.array,
|
DataValueType.array,
|
||||||
extract.aliases,
|
extract.aliases,
|
||||||
extract.aliases.map(a => a.replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_'))
|
(extract.aliases || []).map(a => a
|
||||||
|
.trim()
|
||||||
|
.replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
||||||
|
//replace multiple _ to single _
|
||||||
|
.replace(/_+/g, '_')
|
||||||
|
.replace(/^_/, '')
|
||||||
|
.replace(/_$/, '')
|
||||||
|
|
||||||
|
)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,4 +6,5 @@ export default class DoubanMusicSubject extends DoubanSubject {
|
|||||||
medium: string;
|
medium: string;
|
||||||
records: number;
|
records: number;
|
||||||
barcode: string;
|
barcode: string;
|
||||||
|
menu: string[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,5 +26,6 @@ export default interface HandleContext {
|
|||||||
syncActive?:boolean;
|
syncActive?:boolean;
|
||||||
|
|
||||||
searchPage?:SearchPageInfo;
|
searchPage?:SearchPageInfo;
|
||||||
|
syncOffset?:number;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import DoubanSubject from "./DoubanSubject";
|
|||||||
|
|
||||||
export default interface HandleResult {
|
export default interface HandleResult {
|
||||||
content:string
|
content:string
|
||||||
|
filePath?:string
|
||||||
fileName?:string
|
fileName?:string
|
||||||
subject?:DoubanSubject,
|
subject?:DoubanSubject,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,14 @@
|
|||||||
import {SearchPageInfo} from "./SearchPageInfo";
|
import { SearchPageInfo } from "./SearchPageInfo";
|
||||||
import {SupportType} from "../../../constant/Constsant";
|
import { SupportType } from "../../../constant/Constsant";
|
||||||
|
import {SearchPageTypeOf} from "./SearchPageTypeOf";
|
||||||
|
|
||||||
export class SearchPage extends SearchPageInfo{
|
export class SearchPage extends SearchPageTypeOf<any> {
|
||||||
|
|
||||||
private _list:any[];
|
public static empty(type: SupportType): SearchPage {
|
||||||
|
return new SearchPage(0, 1, 0, type, []);
|
||||||
|
|
||||||
constructor(total: number, pageNum: number, pageSize: number, type:SupportType, list: any[]) {
|
|
||||||
super(total, pageNum, pageSize, type);
|
|
||||||
this._list = list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get list() {
|
static emptyWithNoType() {
|
||||||
return this._list;
|
return new SearchPage(0, 1, 0, null, []);
|
||||||
}
|
|
||||||
|
|
||||||
public static empty(type:SupportType):SearchPage {
|
|
||||||
return new SearchPage(0, 0, 0, type, []);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,6 +56,10 @@ export class SearchPageInfo {
|
|||||||
return this._total;
|
return this._total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public set total(total: number) {
|
||||||
|
this._total = total;
|
||||||
|
}
|
||||||
|
|
||||||
get pageSize(): number {
|
get pageSize(): number {
|
||||||
return this._pageSize;
|
return this._pageSize;
|
||||||
}
|
}
|
||||||
@ -73,7 +77,7 @@ export class SearchPageInfo {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return new SearchPageInfo(this.total, this._pageNum - 1,
|
return new SearchPageInfo(this.total, this._pageNum - 1,
|
||||||
this._pageSize, SupportType.ALL);
|
this._pageSize, SupportType.all);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
29
src/org/wanxp/douban/data/model/SearchPageTypeOf.ts
Normal file
29
src/org/wanxp/douban/data/model/SearchPageTypeOf.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { SearchPageInfo } from "./SearchPageInfo";
|
||||||
|
import { SupportType } from "../../../constant/Constsant";
|
||||||
|
|
||||||
|
export class SearchPageTypeOf<T> extends SearchPageInfo {
|
||||||
|
private _list: T[];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
total: number,
|
||||||
|
pageNum: number,
|
||||||
|
pageSize: number,
|
||||||
|
type: SupportType,
|
||||||
|
list: T[],
|
||||||
|
) {
|
||||||
|
super(total, pageNum, pageSize, type);
|
||||||
|
this._list = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get list() {
|
||||||
|
return this._list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static empty(type: SupportType): SearchPageTypeOf<any> {
|
||||||
|
return new SearchPageTypeOf(0, 1, 0, type, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
static emptyWithNoType() {
|
||||||
|
return new SearchPageTypeOf(0, 1, 0, null, []);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,4 +2,5 @@ export interface SubjectListItem {
|
|||||||
id:string;
|
id:string;
|
||||||
url:string;
|
url:string;
|
||||||
title:string;
|
title:string;
|
||||||
|
updateDate: Date | null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
DoubanSearchGroupPublishResultSubjectNextPage, DoubanSearchGroupPublishResultSubjectPreviousPage,
|
DoubanSearchGroupPublishResultSubjectNextPage,
|
||||||
|
DoubanSearchGroupPublishResultSubjectPreviousPage,
|
||||||
|
DoubanSearchResultSubject_EMPTY, DoubanSearchResultSubject_TIP_EMPTY,
|
||||||
DoubanSearchResultSubjectNextPage,
|
DoubanSearchResultSubjectNextPage,
|
||||||
DoubanSearchResultSubjectNextPageNeedLogin,
|
DoubanSearchResultSubjectNextPageNeedLogin,
|
||||||
DoubanSearchResultSubjectPreviousPage,
|
DoubanSearchResultSubjectPreviousPage,
|
||||||
NavigateType, SEARCH_ITEM_PAGE_SIZE, SupportType
|
NavigateType,
|
||||||
|
SEARCH_ITEM_PAGE_SIZE,
|
||||||
|
SupportType
|
||||||
} from "../../../constant/Constsant";
|
} from "../../../constant/Constsant";
|
||||||
import {FuzzySuggestModal, RequestUrlParam, request} from "obsidian";
|
import {FuzzySuggestModal, RequestUrlParam, request} from "obsidian";
|
||||||
|
|
||||||
@ -27,7 +31,7 @@ class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject>
|
|||||||
private searchItem:string;
|
private searchItem:string;
|
||||||
|
|
||||||
constructor(plugin: DoubanPlugin, context: HandleContext, searchItem:string) {
|
constructor(plugin: DoubanPlugin, context: HandleContext, searchItem:string) {
|
||||||
super(app);
|
super(plugin.app);
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.searchItem = searchItem;
|
this.searchItem = searchItem;
|
||||||
@ -106,9 +110,18 @@ class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject>
|
|||||||
|
|
||||||
private initItems(searchPage: SearchPage) {
|
private initItems(searchPage: SearchPage) {
|
||||||
const doubanList: DoubanSearchResultSubject[] = searchPage.list;
|
const doubanList: DoubanSearchResultSubject[] = searchPage.list;
|
||||||
|
|
||||||
|
if (searchPage.type == SupportType.all && searchPage.pageNum == 1) {
|
||||||
|
if (doubanList.length == 0) {
|
||||||
|
// if (searchPage.list.length > 0) {
|
||||||
|
doubanList.push(DoubanSearchResultSubject_EMPTY);
|
||||||
|
}else if (searchPage.list.length < SEARCH_ITEM_PAGE_SIZE) {
|
||||||
|
doubanList.push(DoubanSearchResultSubject_TIP_EMPTY);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (searchPage.hasNext) {
|
if (searchPage.hasNext) {
|
||||||
if (this.plugin.userComponent.isLogin()) {
|
if (this.plugin.userComponent.isLogin()) {
|
||||||
if (searchPage.type == SupportType.ALL && searchPage.pageNum == 1) {
|
if (searchPage.type == SupportType.all && searchPage.pageNum == 1) {
|
||||||
doubanList.push(DoubanSearchGroupPublishResultSubjectNextPage)
|
doubanList.push(DoubanSearchGroupPublishResultSubjectNextPage)
|
||||||
}else {
|
}else {
|
||||||
doubanList.push(DoubanSearchResultSubjectNextPage)
|
doubanList.push(DoubanSearchResultSubjectNextPage)
|
||||||
@ -118,7 +131,7 @@ class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultSubject>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (searchPage.hasPrevious) {
|
if (searchPage.hasPrevious) {
|
||||||
if (searchPage.type == SupportType.ALL && searchPage.pageNum == 2) {
|
if (searchPage.type == SupportType.all && searchPage.pageNum == 2) {
|
||||||
doubanList.unshift(DoubanSearchGroupPublishResultSubjectPreviousPage)
|
doubanList.unshift(DoubanSearchGroupPublishResultSubjectPreviousPage)
|
||||||
}else {
|
}else {
|
||||||
doubanList.unshift(DoubanSearchResultSubjectPreviousPage);
|
doubanList.unshift(DoubanSearchResultSubjectPreviousPage);
|
||||||
|
|||||||
@ -8,16 +8,19 @@ import {sleep} from "../../../utils/TimeUtil";
|
|||||||
|
|
||||||
export class DoubanSearchModal extends Modal {
|
export class DoubanSearchModal extends Modal {
|
||||||
searchTerm: string;
|
searchTerm: string;
|
||||||
searchType: SupportType = SupportType.ALL;
|
searchType: SupportType = SupportType.all;
|
||||||
plugin: DoubanPlugin;
|
plugin: DoubanPlugin;
|
||||||
context: HandleContext
|
context: HandleContext
|
||||||
|
|
||||||
constructor(app: App, plugin: DoubanPlugin, context: HandleContext) {
|
constructor(app: App, plugin: DoubanPlugin, context: HandleContext, type: SupportType) {
|
||||||
super(app);
|
super(app);
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.searchType = type??SupportType.all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
onOpen() {
|
onOpen() {
|
||||||
let {contentEl} = this;
|
let {contentEl} = this;
|
||||||
|
|
||||||
@ -42,7 +45,7 @@ export class DoubanSearchModal extends Modal {
|
|||||||
const typeSelect = content.createDiv("type-select");
|
const typeSelect = content.createDiv("type-select");
|
||||||
const typeSelectInput = new DropdownComponent(typeSelect)
|
const typeSelectInput = new DropdownComponent(typeSelect)
|
||||||
.addOptions(SearchTypeRecords)
|
.addOptions(SearchTypeRecords)
|
||||||
.setValue(SupportType.ALL)
|
.setValue(this.searchType)
|
||||||
.onChange((value:SupportType) => {
|
.onChange((value:SupportType) => {
|
||||||
this.searchType = value;
|
this.searchType = value;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,31 +1,21 @@
|
|||||||
import {SupportType} from "../../../../constant/Constsant";
|
import {
|
||||||
|
SupportType
|
||||||
|
} from "../../../../constant/Constsant";
|
||||||
import {SearchResultPageParserInterface} from "./SearchResultPageParserInterface";
|
import {SearchResultPageParserInterface} from "./SearchResultPageParserInterface";
|
||||||
import {SearchPage} from "../../model/SearchPage";
|
import {SearchPage} from "../../model/SearchPage";
|
||||||
import SearchParserHandlerV2 from "../SearchParserV2";
|
import SearchParserHandler from "../SearchParser";
|
||||||
import StringUtil from "../../../../utils/StringUtil";
|
|
||||||
import {log} from "../../../../utils/Logutil";
|
import {log} from "../../../../utils/Logutil";
|
||||||
|
|
||||||
export class AllFirstPageSearchResultPageParser implements SearchResultPageParserInterface {
|
export class AllFirstPageSearchResultPageParser implements SearchResultPageParserInterface {
|
||||||
support(type:SupportType, pageNum:number):boolean {
|
support(type:SupportType, pageNum:number):boolean {
|
||||||
return pageNum == 1 && type == SupportType.ALL;
|
return pageNum == 1 && type == SupportType.all;
|
||||||
}
|
}
|
||||||
parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage {
|
parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage {
|
||||||
if (!source || StringUtil.notJsonString(source)) {
|
log.debug("解析给多页面结果");
|
||||||
//TODO 国际化
|
if (!source) {
|
||||||
log.notice("Obsidian-Douban:查询结果为空,无匹配结果,请尝试登录获取获取更多数据(已登录则忽略)");
|
return new SearchPage(0, 0, 0, type, []);
|
||||||
return SearchPage.empty(type);
|
|
||||||
}
|
}
|
||||||
|
return SearchParserHandler.parseSearchJson(source, type, pageNum);
|
||||||
const {subjects} = JSON.parse(source);
|
|
||||||
if (!subjects) {
|
|
||||||
return SearchPage.empty(type);
|
|
||||||
}
|
|
||||||
const {items} = subjects;
|
|
||||||
if (!items ||items.length == 0) {
|
|
||||||
return SearchPage.empty(type);
|
|
||||||
}
|
|
||||||
const doubanSearchResultSubjects = SearchParserHandlerV2.itemMapToSearchResult(items);
|
|
||||||
return new SearchPage(2000, pageNum, pageSize, type, doubanSearchResultSubjects);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import SearchParserHandler from "../SearchParser";
|
|||||||
|
|
||||||
export class NotAllPageSearchResultPageParser implements SearchResultPageParserInterface {
|
export class NotAllPageSearchResultPageParser implements SearchResultPageParserInterface {
|
||||||
support(type:SupportType, pageNum:number):boolean {
|
support(type:SupportType, pageNum:number):boolean {
|
||||||
return type != SupportType.ALL && !(pageNum ==1 && type == SupportType.NOTE);
|
return type != SupportType.all && !(pageNum ==1 && type == SupportType.note);
|
||||||
}
|
}
|
||||||
parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage {
|
parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage {
|
||||||
log.debug("解析给多页面结果");
|
log.debug("解析给多页面结果");
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import DoubanSearchResultSubject from "../../model/DoubanSearchResultSubject";
|
|||||||
|
|
||||||
export class NoteFirstPageSearchResultPageParser implements SearchResultPageParserInterface {
|
export class NoteFirstPageSearchResultPageParser implements SearchResultPageParserInterface {
|
||||||
support(type:SupportType, pageNum:number):boolean {
|
support(type:SupportType, pageNum:number):boolean {
|
||||||
return pageNum == 1 && type == SupportType.NOTE;
|
return pageNum == 1 && type == SupportType.note;
|
||||||
}
|
}
|
||||||
parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage {
|
parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage {
|
||||||
const pageData = load(source);
|
const pageData = load(source);
|
||||||
|
|||||||
@ -2,21 +2,18 @@ import {SupportType} from "../../../../constant/Constsant";
|
|||||||
import {SearchResultPageParserInterface} from "./SearchResultPageParserInterface";
|
import {SearchResultPageParserInterface} from "./SearchResultPageParserInterface";
|
||||||
import {log} from "../../../../utils/Logutil";
|
import {log} from "../../../../utils/Logutil";
|
||||||
import {SearchPage} from "../../model/SearchPage";
|
import {SearchPage} from "../../model/SearchPage";
|
||||||
import SearchParserHandlerV2 from "../SearchParserV2";
|
import SearchParserHandler from "../SearchParser";
|
||||||
|
|
||||||
export class OtherAllPageSearchResultPageParser implements SearchResultPageParserInterface {
|
export class OtherAllPageSearchResultPageParser implements SearchResultPageParserInterface {
|
||||||
support(type:SupportType, pageNum:number):boolean {
|
support(type:SupportType, pageNum:number):boolean {
|
||||||
return pageNum > 1 && type == SupportType.ALL;
|
return pageNum > 1 && type == SupportType.all;
|
||||||
}
|
}
|
||||||
parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage {
|
parse(source:string, type:SupportType, pageNum:number, pageSize:number):SearchPage {
|
||||||
log.debug("解析给多页面结果");
|
log.debug("解析给多页面结果");
|
||||||
const {contents} = JSON.parse(source);
|
if (!source) {
|
||||||
if (!contents) {
|
|
||||||
return new SearchPage(0, 0, 0, type, []);
|
return new SearchPage(0, 0, 0, type, []);
|
||||||
}
|
}
|
||||||
const data:{total:number, start:number, count:number, items:any[]} = contents;
|
return SearchParserHandler.parseSearchJson(source, type, pageNum);
|
||||||
const doubanSearchResultSubjects = SearchParserHandlerV2.itemMapToSearchResult(data.items);
|
|
||||||
return new SearchPage(data.total, pageNum, pageSize, type, doubanSearchResultSubjects);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,8 +17,9 @@ export abstract class AbstractSearchPageFetcher implements SearchPageFetcherInte
|
|||||||
|
|
||||||
support(type: SupportType, pageNum?:number): boolean {
|
support(type: SupportType, pageNum?:number): boolean {
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
fetch(keyword: string, pageNum: number, pageSize: number): Promise<string> {
|
|
||||||
|
fetch(keyword: string, pageNum: number, pageSize: number): Promise<string> {
|
||||||
const start:number = Math.floor((pageNum - 1) * pageSize);
|
const start:number = Math.floor((pageNum - 1) * pageSize);
|
||||||
const url:string = this.getSearchUrl(keyword, start, pageSize);
|
const url:string = this.getSearchUrl(keyword, start, pageSize);
|
||||||
if (!url) {
|
if (!url) {
|
||||||
@ -27,7 +28,8 @@ export abstract class AbstractSearchPageFetcher implements SearchPageFetcherInte
|
|||||||
return DoubanHttpUtil.httpRequestGet(url, this.settingsManager.getHeaders(), this.settingsManager)
|
return DoubanHttpUtil.httpRequestGet(url, this.settingsManager.getHeaders(), this.settingsManager)
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
throw log.error(i18nHelper.getMessage('130101').replace('{0}', e.toString()), e);
|
throw log.error(i18nHelper.getMessage('130101').replace('{0}', e.toString()), e);
|
||||||
}); }
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getSearchUrl(keyword: string, start: number, pageSize: number):string {
|
getSearchUrl(keyword: string, start: number, pageSize: number):string {
|
||||||
keyword = keyword.trim();
|
keyword = keyword.trim();
|
||||||
|
|||||||
@ -2,11 +2,11 @@ import {AbstractSearchPageFetcher} from "./AbstractSearchPageFetcher";
|
|||||||
import { SupportType } from "src/org/wanxp/constant/Constsant";
|
import { SupportType } from "src/org/wanxp/constant/Constsant";
|
||||||
|
|
||||||
export class AllPageSearchPageFetcher extends AbstractSearchPageFetcher {
|
export class AllPageSearchPageFetcher extends AbstractSearchPageFetcher {
|
||||||
getUrl(keyword: string, pageNum: number, pageSize: number): string {
|
getUrl(keyword: string, start: number, pageSize: number): string {
|
||||||
return `https://m.douban.com/rexxar/api/v2/search?q=${keyword}&start=${pageNum}&count=${pageSize}`;
|
return `https://www.douban.com/j/search?q=${keyword}&start=${start}`;
|
||||||
}
|
}
|
||||||
support(type: SupportType): boolean {
|
support(type: SupportType): boolean {
|
||||||
return type == SupportType.ALL;
|
return type == SupportType.all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export class BookPageSearchPageFetcher extends AbstractSearchPageFetcher {
|
|||||||
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=1001`;
|
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=1001`;
|
||||||
}
|
}
|
||||||
support(type: SupportType): boolean {
|
support(type: SupportType): boolean {
|
||||||
return type == SupportType.BOOK;
|
return type == SupportType.book;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export class GamePageSearchPageFetcher extends AbstractSearchPageFetcher {
|
|||||||
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=3114`;
|
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=3114`;
|
||||||
}
|
}
|
||||||
support(type: SupportType): boolean {
|
support(type: SupportType): boolean {
|
||||||
return type == SupportType.GAME;
|
return type == SupportType.game;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export class MoviePageSearchPageFetcher extends AbstractSearchPageFetcher {
|
|||||||
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=1002`;
|
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=1002`;
|
||||||
}
|
}
|
||||||
support(type: SupportType): boolean {
|
support(type: SupportType): boolean {
|
||||||
return type == SupportType.MOVIE;
|
return type == SupportType.movie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export class MusicPageSearchPageFetcher extends AbstractSearchPageFetcher {
|
|||||||
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=1003`;
|
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=1003`;
|
||||||
}
|
}
|
||||||
support(type: SupportType): boolean {
|
support(type: SupportType): boolean {
|
||||||
return type == SupportType.MUSIC;
|
return type == SupportType.music;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export class NoteFirstPageSearchPageFetcher extends AbstractSearchPageFetcher {
|
|||||||
return `https://www.douban.com/search?cat=1015&q=${keyword}`;
|
return `https://www.douban.com/search?cat=1015&q=${keyword}`;
|
||||||
}
|
}
|
||||||
support(type: SupportType, pageNum:number): boolean {
|
support(type: SupportType, pageNum:number): boolean {
|
||||||
return type == SupportType.NOTE && pageNum == 1;
|
return type == SupportType.note && pageNum == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export class NotePageSearchPageFetcher extends AbstractSearchPageFetcher {
|
|||||||
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=1015`;
|
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=1015`;
|
||||||
}
|
}
|
||||||
support(type: SupportType, pageNum:number): boolean {
|
support(type: SupportType, pageNum:number): boolean {
|
||||||
return type == SupportType.NOTE && pageNum > 1;
|
return type == SupportType.note && pageNum > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export class TheaterPageSearchPageFetcher extends AbstractSearchPageFetcher {
|
|||||||
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=3069`;
|
return `https://www.douban.com/j/search?q=${keyword}&start=${start}&cat=3069`;
|
||||||
}
|
}
|
||||||
support(type: SupportType): boolean {
|
support(type: SupportType): boolean {
|
||||||
return type == SupportType.THEATER;
|
return type == SupportType.theater;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,31 +8,74 @@ import User from "../user/User";
|
|||||||
import {createFolderSelectionSetting} from "./TemplateSettingHelper";
|
import {createFolderSelectionSetting} from "./TemplateSettingHelper";
|
||||||
import { log } from "../../utils/Logutil";
|
import { log } from "../../utils/Logutil";
|
||||||
import {ConfirmDialogModal} from "../component/ConfirmDialogModal";
|
import {ConfirmDialogModal} from "../component/ConfirmDialogModal";
|
||||||
|
import {DoubanSearchModal} from "../data/search/DoubanSearchModal";
|
||||||
|
import {DoubanPluginSetting} from "./model/DoubanPluginSetting";
|
||||||
|
import TimeUtil from "../../utils/TimeUtil";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function constructAdvancedUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructAdvancedUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1250') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1250') });
|
||||||
containerEl.createEl('p', { text: i18nHelper.getMessage('1252') });
|
containerEl.createEl('p', { text: i18nHelper.getMessage('1252') });
|
||||||
const settings:Setting = new Setting(containerEl);
|
|
||||||
const advancedSettings = containerEl.createDiv('advanced-settings');
|
|
||||||
settings.setDesc(i18nHelper.getMessage('1251')).addExtraButton((extraButton) => {
|
|
||||||
extraButton
|
|
||||||
.setIcon('reset')
|
|
||||||
.setTooltip(i18nHelper.getMessage('121905'))
|
|
||||||
.onClick(async () => {
|
|
||||||
resetAdvanced(manager);
|
|
||||||
await manager.plugin.saveSettings();
|
|
||||||
showAdvancedSettings(advancedSettings, manager)
|
|
||||||
});
|
|
||||||
})
|
|
||||||
showAdvancedSettings(advancedSettings, manager);
|
|
||||||
|
|
||||||
|
// const settings:Setting = new Setting(containerEl);
|
||||||
|
const advancedSettings = containerEl.createDiv('advanced-settings');
|
||||||
|
// settings.setDesc(i18nHelper.getMessage('1251')).addExtraButton((extraButton) => {
|
||||||
|
// extraButton
|
||||||
|
// .setIcon('reset')
|
||||||
|
// .setTooltip(i18nHelper.getMessage('121905'))
|
||||||
|
// .onClick(async () => {
|
||||||
|
// resetAdvanced(manager);
|
||||||
|
// await manager.plugin.saveSettings();
|
||||||
|
// showAdvancedSettings(advancedSettings, manager)
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
showAdvancedSettings(advancedSettings, manager);
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAdvancedSettings(containerEl: HTMLElement, manager: SettingsManager) {
|
function showAdvancedSettings(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.empty();
|
containerEl.empty();
|
||||||
const promise:Promise<any> = new Promise<any>((resolve, reject) => {resolve(null)});
|
const promise:Promise<any> = new Promise<any>((resolve, reject) => {resolve(null)});
|
||||||
|
|
||||||
|
|
||||||
|
//导出
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName(i18nHelper.getMessage('125034'))
|
||||||
|
.setDesc(i18nHelper.getMessage('125035'))
|
||||||
|
.addButton((buttonComponent) => {
|
||||||
|
buttonComponent
|
||||||
|
.setIcon('folder')
|
||||||
|
.setButtonText(i18nHelper.getMessage('125047'))
|
||||||
|
.onClick(async (value) => {
|
||||||
|
const settings = manager.getSettings()
|
||||||
|
const settingsString = JSON.stringify(settings, null, 2);
|
||||||
|
const blob = new Blob([settingsString], { type: 'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = `obsidian_douban_plugin_settings_${TimeUtil.formatDate(new Date(), 'yyyy-MM-dd_HH-mm-ss')}.json`;
|
||||||
|
a.click();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
//导入
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName(i18nHelper.getMessage('125036'))
|
||||||
|
.setDesc(i18nHelper.getMessage('125037'))
|
||||||
|
.addButton((buttonComponent) => {
|
||||||
|
buttonComponent
|
||||||
|
.setIcon('document')
|
||||||
|
.setButtonText(i18nHelper.getMessage('125039'))
|
||||||
|
.onClick(async (value) => {
|
||||||
|
showConfirmDialog(i18nHelper.getMessage('125046'), promise.then(() => {
|
||||||
|
}), manager);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(i18nHelper.getMessage('125001'))
|
.setName(i18nHelper.getMessage('125001'))
|
||||||
.setDesc(i18nHelper.getMessage('125002'))
|
.setDesc(i18nHelper.getMessage('125002'))
|
||||||
@ -79,6 +122,7 @@ function showAdvancedSettings(containerEl: HTMLElement, manager: SettingsManager
|
|||||||
}), manager)
|
}), manager)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(i18nHelper.getMessage('125031'))
|
.setName(i18nHelper.getMessage('125031'))
|
||||||
.setDesc(i18nHelper.getMessage('125032'))
|
.setDesc(i18nHelper.getMessage('125032'))
|
||||||
@ -92,6 +136,7 @@ function showAdvancedSettings(containerEl: HTMLElement, manager: SettingsManager
|
|||||||
}), manager);
|
}), manager);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetAdvanced( manager: SettingsManager) {
|
function resetAdvanced( manager: SettingsManager) {
|
||||||
@ -100,7 +145,7 @@ function resetAdvanced( manager: SettingsManager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showConfirmDialog(message:string, promise:Promise<any>, manager: SettingsManager) {
|
function showConfirmDialog(message:string, promise:Promise<any>, manager: SettingsManager) {
|
||||||
new ConfirmDialogModal(manager.plugin.app, message, promise
|
new ConfirmDialogModal(manager.plugin, message, promise
|
||||||
.then( () => {
|
.then( () => {
|
||||||
manager.plugin.saveSettings();
|
manager.plugin.saveSettings();
|
||||||
})
|
})
|
||||||
|
|||||||
@ -4,14 +4,15 @@ import {Setting, TextComponent} from "obsidian";
|
|||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import {DEFAULT_SETTINGS} from "../../constant/DefaultSettings";
|
import {DEFAULT_SETTINGS} from "../../constant/DefaultSettings";
|
||||||
import {DEFAULT_SETTINGS_ARRAY_INPUT_SIZE} from "../../constant/Constsant";
|
import {DEFAULT_SETTINGS_ARRAY_INPUT_SIZE} from "../../constant/Constsant";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
|
||||||
|
|
||||||
export function arraySettingDisplayUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function arraySettingDisplayUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', {text: i18nHelper.getMessage('120601')});
|
// containerEl.createEl('h3', {text: i18nHelper.getMessage('120601')});
|
||||||
arraySettingDisplay(containerEl.createDiv('array-settings'), manager, false);
|
arraySettingDisplay(containerEl.createDiv('array-settings'), manager, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function arraySettingDisplay(containerEl: HTMLElement, manager: SettingsManager, displayExtraListTypeFlag: boolean = false) {
|
export function arraySettingDisplay(containerEl: HTMLElement, manager: SettingsManager, displayExtraListTypeFlag: boolean = true) {
|
||||||
containerEl.empty();
|
containerEl.empty();
|
||||||
const arraySet = new Setting(containerEl)
|
const arraySet = new Setting(containerEl)
|
||||||
.setName(i18nHelper.getMessage('120601'))
|
.setName(i18nHelper.getMessage('120601'))
|
||||||
@ -25,27 +26,28 @@ export function arraySettingDisplay(containerEl: HTMLElement, manager: SettingsM
|
|||||||
arraySettingDisplay(containerEl, manager, true);
|
arraySettingDisplay(containerEl, manager, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (displayExtraListTypeFlag) {
|
// if (displayExtraListTypeFlag) {
|
||||||
arraySettingDisplayItem(containerEl, manager, manager.getArraySetting(DEFAULT_SETTINGS_ARRAY_NAME));
|
new Setting(containerEl)
|
||||||
displayExtraListType(manager, containerEl);
|
arraySettingDisplayItem(containerEl, manager, manager.getArraySetting(DEFAULT_SETTINGS_ARRAY_NAME));
|
||||||
arraySet.addButton((button) => {
|
displayExtraListType(manager, containerEl);
|
||||||
button
|
// arraySet.addButton((button) => {
|
||||||
.setIcon('down-chevron-glyph')
|
// button
|
||||||
.setTooltip(i18nHelper.getMessage('120608'))
|
// .setIcon('down-chevron-glyph')
|
||||||
.onClick(async () => {
|
// .setTooltip(i18nHelper.getMessage('120608'))
|
||||||
arraySettingDisplay(containerEl, manager, false);
|
// .onClick(async () => {
|
||||||
});
|
// arraySettingDisplay(containerEl, manager, false);
|
||||||
});
|
// });
|
||||||
}else {
|
// });
|
||||||
arraySet.addButton((button) => {
|
// }else {
|
||||||
button
|
// arraySet.addButton((button) => {
|
||||||
.setIcon('right-chevron-glyph')
|
// button
|
||||||
.setTooltip(i18nHelper.getMessage('120608'))
|
// .setIcon('right-chevron-glyph')
|
||||||
.onClick(async () => {
|
// .setTooltip(i18nHelper.getMessage('120608'))
|
||||||
arraySettingDisplay(containerEl, manager, true);
|
// .onClick(async () => {
|
||||||
});
|
// arraySettingDisplay(containerEl, manager, true);
|
||||||
});
|
// });
|
||||||
}
|
// });
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
function arraySettingDisplayItem(containerEl: HTMLElement, manager: SettingsManager, arraySetting:ArraySetting) {
|
function arraySettingDisplayItem(containerEl: HTMLElement, manager: SettingsManager, arraySetting:ArraySetting) {
|
||||||
|
|||||||
@ -8,12 +8,12 @@ import User from "../user/User";
|
|||||||
import {createFolderSelectionSetting} from "./TemplateSettingHelper";
|
import {createFolderSelectionSetting} from "./TemplateSettingHelper";
|
||||||
import StringUtil from "../../utils/StringUtil";
|
import StringUtil from "../../utils/StringUtil";
|
||||||
import {log} from "../../utils/Logutil";
|
import {log} from "../../utils/Logutil";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
import {SearchTypeRecords, SupportType, SupportTypeMap} from "../../constant/Constsant";
|
||||||
|
|
||||||
export function constructBasicUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructBasicUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1210') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1210') });
|
||||||
containerEl.createDiv('login-setting', async (loginSettingEl) => {
|
|
||||||
constructDoubanTokenSettingsUI(loginSettingEl, manager);
|
|
||||||
});
|
|
||||||
|
|
||||||
new Setting(containerEl).setName(i18nHelper.getMessage('120501')).then((setting) => {
|
new Setting(containerEl).setName(i18nHelper.getMessage('120501')).then((setting) => {
|
||||||
setting.addMomentFormat((mf) => {
|
setting.addMomentFormat((mf) => {
|
||||||
@ -98,166 +98,19 @@ export function constructBasicUI(containerEl: HTMLElement, manager: SettingsMana
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
new Setting(containerEl)
|
||||||
}
|
.setName(i18nHelper.getMessage('121410'))
|
||||||
|
.setDesc(i18nHelper.getMessage('121411'))
|
||||||
export function constructDoubanTokenSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
.addDropdown((dropdown) => {
|
||||||
containerEl.empty();
|
dropdown
|
||||||
let login = manager.plugin.userComponent.isLogin();
|
.addOptions(SearchTypeRecords)
|
||||||
manager.debug(`配置界面:展示豆瓣状态:${login?'已登录':'未登录'}`)
|
.setValue(manager.plugin.settings.searchDefaultType)
|
||||||
if (Platform.isDesktopApp) {
|
.onChange(async (value) => {
|
||||||
if(login) {
|
// @ts-ignore
|
||||||
constructHasLoginSettingsUI(containerEl, manager);
|
manager.plugin.settings.searchDefaultType = SupportTypeMap[value];
|
||||||
}else {
|
await manager.plugin.saveSettings();
|
||||||
constructLoginSettingsUI(containerEl, manager);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(login) {
|
|
||||||
showMobileLogout(containerEl, manager);
|
|
||||||
}else {
|
|
||||||
showMobileLogin(containerEl, manager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function constructLoginSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
|
||||||
manager.debug(`配置界面:未登录-展示登录按钮`)
|
|
||||||
let loginSetting = containerEl.createDiv("login-button");
|
|
||||||
let loginCookie = containerEl.createDiv("login-button-cookie");
|
|
||||||
|
|
||||||
new Setting(loginSetting).setName(i18nHelper.getMessage('100131')).addButton((button) => {
|
|
||||||
return button
|
|
||||||
.setButtonText(i18nHelper.getMessage('100130'))
|
|
||||||
.onClick(async () => {
|
|
||||||
button.setDisabled(true);
|
|
||||||
manager.debug(`配置界面:点击登录按钮`)
|
|
||||||
const loginModel = new DoubanLoginModel(containerEl, manager);
|
|
||||||
await loginModel.doLogin();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const loginCookieSetting:Setting = new Setting(loginSetting).setName(i18nHelper.getMessage('100133'));
|
|
||||||
// .setDesc(i18nHelper.getMessage('100134'))
|
|
||||||
loginCookieSetting.addButton((button) => {
|
|
||||||
loginCookieSetting.descEl.appendChild(
|
|
||||||
createFragment((frag) => {
|
|
||||||
frag.appendText(
|
|
||||||
i18nHelper.getMessage('100134')
|
|
||||||
);
|
|
||||||
frag.createEl(
|
|
||||||
'a',
|
|
||||||
{
|
|
||||||
text: i18nHelper.getMessage('100139'),
|
|
||||||
href: 'https://obsidian-douban.wanxuping.com/20_howtouse_25_setting_login_douban_cookie.html',
|
|
||||||
},
|
|
||||||
(a) => {
|
|
||||||
a.setAttr('target', '_blank');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
frag.appendText(i18nHelper.getMessage('100138'));
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
return button
|
|
||||||
.setButtonText(i18nHelper.getMessage('100135'))
|
|
||||||
.onClick(async () => {
|
|
||||||
button.setDisabled(true);
|
|
||||||
manager.debug(`配置界面:点击登录异常处理按钮`)
|
|
||||||
constructLoginCookieSettingsUI(loginCookie, containerEl, manager);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function constructLoginCookieSettingsUI(containerEl: HTMLElement, parentContainerEl: HTMLElement, manager: SettingsManager) {
|
|
||||||
manager.debug(`配置界面:登录异常处理按钮-展示Cookie输入框`)
|
|
||||||
new Setting(containerEl).setName(i18nHelper.getMessage('100136'))
|
|
||||||
.setClass("obsidian_douban_settings_cookie_login").addTextArea((text) => {
|
|
||||||
text.onChange(value => manager.updateCookieTemp(value));
|
|
||||||
return text;
|
|
||||||
}).addExtraButton((button) => {
|
|
||||||
return button
|
|
||||||
.setIcon('check')
|
|
||||||
.onClick(async () => {
|
|
||||||
manager.debug(`配置界面:确认输入Cookie`);
|
|
||||||
const user:User = await manager.plugin.userComponent.loginCookie(manager.getCookieTemp())
|
|
||||||
if (!user || !user.id) {
|
|
||||||
log.notice(i18nHelper.getMessage('100137'))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
constructDoubanTokenSettingsUI(parentContainerEl, manager);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.addExtraButton((button) => {
|
|
||||||
return button
|
|
||||||
.setIcon('x')
|
|
||||||
.onClick(async () => {
|
|
||||||
button.setDisabled(true);
|
|
||||||
manager.debug(`配置界面:取消输入Cookie`);
|
|
||||||
constructDoubanTokenSettingsUI(parentContainerEl, manager);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function constructHasLoginSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
|
||||||
const user: User = manager.plugin.userComponent.getUser();
|
|
||||||
let userDom = new DocumentFragment();
|
|
||||||
userDom.createDiv().innerHTML =
|
|
||||||
`${i18nHelper.getMessage('100120')}<br>
|
|
||||||
${i18nHelper.getMessage('100123')}: <a href="https://www.douban.com/people/${user.id}/">${user.id}</a><br>
|
|
||||||
${i18nHelper.getMessage('100124')}: ${user.name}<br>
|
|
||||||
${i18nHelper.getMessage('100125')}`;
|
|
||||||
manager.debug(`配置界面:展示豆瓣登录信息:id:${StringUtil.confuse(user.id)}, 用户名:${StringUtil.confuse(user.name)}`)
|
|
||||||
new Setting(containerEl)
|
|
||||||
.setName(i18nHelper.getMessage('100126'))
|
|
||||||
.setDesc(userDom)
|
|
||||||
.addButton((button) => {
|
|
||||||
return button
|
|
||||||
.setButtonText(i18nHelper.getMessage('100128'))
|
|
||||||
.setCta()
|
|
||||||
.onClick(async () => {
|
|
||||||
button.setDisabled(true);
|
|
||||||
manager.debug(`配置界面:点击退出登录按钮,准备退出登录`)
|
|
||||||
// manager.debug(`配置界面:登出界面退出登录请求检测成功,准备退出登录`)
|
|
||||||
manager.plugin.userComponent.logout();
|
|
||||||
manager.debug(`配置界面:退出登录成功`);
|
|
||||||
constructDoubanTokenSettingsUI(containerEl, manager);
|
|
||||||
|
|
||||||
// const loginModel = new DoubanLogoutModel(containerEl, manager);
|
|
||||||
// await loginModel.doLogout();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function showMobileLogin(containerEl: HTMLElement, manager: SettingsManager) {
|
|
||||||
new Setting(containerEl)
|
|
||||||
.setName(i18nHelper.getMessage('100126'))
|
|
||||||
.setDesc(i18nHelper.getMessage('100129'))
|
|
||||||
}
|
|
||||||
|
|
||||||
function showMobileLogout(containerEl: HTMLElement, manager: SettingsManager) {
|
|
||||||
const user: User = manager.plugin.userComponent.getUser();
|
|
||||||
let userDom = new DocumentFragment();
|
|
||||||
userDom.createDiv().innerHTML =
|
|
||||||
`${i18nHelper.getMessage('100120')}<br>
|
|
||||||
${i18nHelper.getMessage('100123')}: <a href="https://www.douban.com/people/${user.id}/">${user.id}</a><br>
|
|
||||||
${i18nHelper.getMessage('100124')}: ${user.name}<br>
|
|
||||||
${i18nHelper.getMessage('100125')}`;
|
|
||||||
new Setting(containerEl)
|
|
||||||
.setName(i18nHelper.getMessage('100126'))
|
|
||||||
.setDesc(userDom)
|
|
||||||
.addButton((button) => {
|
|
||||||
return button
|
|
||||||
.setButtonText(i18nHelper.getMessage('100128'))
|
|
||||||
.setCta()
|
|
||||||
.onClick(async () => {
|
|
||||||
button.setDisabled(true);
|
|
||||||
manager.updateSetting('loginCookiesContent', '');
|
|
||||||
manager.updateSetting('loginHeadersContent', '');
|
|
||||||
constructDoubanTokenSettingsUI(containerEl, manager);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,10 +2,11 @@ import {i18nHelper} from "../../lang/helper";
|
|||||||
import SettingsManager from "./SettingsManager";
|
import SettingsManager from "./SettingsManager";
|
||||||
import {CustomProperty} from "./model/CustomProperty";
|
import {CustomProperty} from "./model/CustomProperty";
|
||||||
import {ButtonComponent, DropdownComponent, ExtraButtonComponent, Setting, TextComponent} from "obsidian";
|
import {ButtonComponent, DropdownComponent, ExtraButtonComponent, Setting, TextComponent} from "obsidian";
|
||||||
import {SupportType} from "../../constant/Constsant";
|
import {SupportType, SupportTypeMap} from "../../constant/Constsant";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
|
||||||
export function constructCustomPropertySettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructCustomPropertySettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1240') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1240') });
|
||||||
containerEl.createEl('p', { text: i18nHelper.getMessage('1242') });
|
containerEl.createEl('p', { text: i18nHelper.getMessage('1242') });
|
||||||
const customProperties = manager.plugin.settings.customProperties;
|
const customProperties = manager.plugin.settings.customProperties;
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
@ -15,7 +16,7 @@ export function constructCustomPropertySettingsUI(containerEl: HTMLElement, mana
|
|||||||
button.setTooltip(i18nHelper.getMessage('124101'));
|
button.setTooltip(i18nHelper.getMessage('124101'));
|
||||||
button.setIcon('plus');
|
button.setIcon('plus');
|
||||||
button.onClick(async () => {
|
button.onClick(async () => {
|
||||||
customProperties.push({name: '', value: '', field: SupportType.ALL});
|
customProperties.push({name: '', value: '', field: SupportType.all});
|
||||||
constructCustomPropertyUI(list, customProperties, manager);
|
constructCustomPropertyUI(list, customProperties, manager);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -67,11 +68,15 @@ function addFilterInput(data: CustomProperty, el: HTMLElement, customProperties:
|
|||||||
|
|
||||||
const fieldsDropdown = new DropdownComponent(el);
|
const fieldsDropdown = new DropdownComponent(el);
|
||||||
for (const fieldSelect in SupportType) {
|
for (const fieldSelect in SupportType) {
|
||||||
// @ts-ignore
|
|
||||||
fieldsDropdown.addOption(fieldSelect, i18nHelper.getMessage(fieldSelect));
|
fieldsDropdown.addOption(fieldSelect, i18nHelper.getMessage(fieldSelect));
|
||||||
}
|
}
|
||||||
item.createEl('span', { text: i18nHelper.getMessage('124106') });
|
item.createEl('span', { text: i18nHelper.getMessage('124106') });
|
||||||
fieldsDropdown.setValue(data.field)
|
let dataFieldValue = data.field;
|
||||||
|
if(typeof dataFieldValue === 'string') {
|
||||||
|
// @ts-ignore
|
||||||
|
dataFieldValue = SupportTypeMap[dataFieldValue];
|
||||||
|
}
|
||||||
|
fieldsDropdown.setValue(dataFieldValue)
|
||||||
.onChange(async (value: SupportType) => {
|
.onChange(async (value: SupportType) => {
|
||||||
customProperties[idx].field = value;
|
customProperties[idx].field = value;
|
||||||
await manager.plugin.saveSettings();
|
await manager.plugin.saveSettings();
|
||||||
|
|||||||
@ -9,11 +9,15 @@ import { constructTemplateVariablesUI } from "./TemplateVariableSettingsHelper";
|
|||||||
import {constructCustomPropertySettingsUI } from "./CustomPropertySettingsHelper";
|
import {constructCustomPropertySettingsUI } from "./CustomPropertySettingsHelper";
|
||||||
import { constructAdvancedUI } from "./AdvancedSettingsHelper";
|
import { constructAdvancedUI } from "./AdvancedSettingsHelper";
|
||||||
import {arraySettingDisplay, arraySettingDisplayUI} from "./ArrayDisplayTypeSettingsHelper";
|
import {arraySettingDisplay, arraySettingDisplayUI} from "./ArrayDisplayTypeSettingsHelper";
|
||||||
|
import {i18nHelper} from "../../lang/helper";
|
||||||
|
import {constructLoginUI} from "./LoginSettingsHelper";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部分逻辑参考以下项目
|
* 部分逻辑参考以下项目
|
||||||
* obsidian-kanban
|
* obsidian-kanban
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
export class DoubanSettingTab extends PluginSettingTab {
|
export class DoubanSettingTab extends PluginSettingTab {
|
||||||
plugin: DoubanPlugin;
|
plugin: DoubanPlugin;
|
||||||
settingsManager: SettingsManager;
|
settingsManager: SettingsManager;
|
||||||
@ -25,18 +29,51 @@ export class DoubanSettingTab extends PluginSettingTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
display(): void {
|
display(): void {
|
||||||
const {containerEl} = this;
|
const {containerEl} = this;
|
||||||
containerEl.empty();
|
containerEl.empty();
|
||||||
containerEl.createEl("h2", {text: 'Obsidian Douban'});
|
containerEl.createEl("h2", {text: 'Obsidian Douban'});
|
||||||
new Setting(containerEl);
|
|
||||||
constructBasicUI(containerEl, this.settingsManager);
|
|
||||||
constructTemplateUI(containerEl, this.settingsManager);
|
|
||||||
constructOutUI(containerEl, this.settingsManager);
|
|
||||||
arraySettingDisplayUI(containerEl, this.settingsManager);
|
|
||||||
constructCustomPropertySettingsUI(containerEl, this.settingsManager);
|
|
||||||
constructTemplateVariablesUI(containerEl, this.settingsManager);
|
|
||||||
constructAdvancedUI(containerEl, this.settingsManager);
|
|
||||||
|
|
||||||
|
// Create tab container
|
||||||
|
const tabContainer = containerEl.createEl("div", {cls: "obsidian_douban_settings_tab_container"});
|
||||||
|
const tabHeaders = containerEl.createEl("div", {cls: "obsidian_douban_settings_tab_headers"});
|
||||||
|
const tabContents = containerEl.createEl("div", {cls: "obsidian_douban_settings_tab_contents"});
|
||||||
|
|
||||||
|
// Create tabs
|
||||||
|
const tabs = [
|
||||||
|
{name: i18nHelper.getMessage('1210'), construct: constructBasicUI},
|
||||||
|
{name: i18nHelper.getMessage('1203'), construct: constructTemplateUI},
|
||||||
|
{name: i18nHelper.getMessage('1260'), construct: constructLoginUI},
|
||||||
|
{name: i18nHelper.getMessage('1220'), construct: constructOutUI},
|
||||||
|
{name: i18nHelper.getMessage('120601'), construct: arraySettingDisplayUI},
|
||||||
|
{name: i18nHelper.getMessage('1240'), construct: constructCustomPropertySettingsUI},
|
||||||
|
{name: i18nHelper.getMessage('1230'), construct: constructTemplateVariablesUI},
|
||||||
|
{name: i18nHelper.getMessage('1250'), construct: constructAdvancedUI}
|
||||||
|
];
|
||||||
|
|
||||||
|
tabs.forEach((tab, index) => {
|
||||||
|
const tabHeader = tabHeaders.createEl("div", {cls: "obsidian_douban_settings_tab_header", text: tab.name});
|
||||||
|
const tabContent = tabContents.createEl("div", {cls: "obsidian_douban_settings_tab_content"});
|
||||||
|
tab.construct(tabContent, this.settingsManager);
|
||||||
|
|
||||||
|
// Show the first tab by default
|
||||||
|
if (index === 0) {
|
||||||
|
tabHeader.addClass("active");
|
||||||
|
tabContent.addClass("active");
|
||||||
|
}
|
||||||
|
|
||||||
|
tabHeader.addEventListener("click", () => {
|
||||||
|
// Remove active class from all headers and contents
|
||||||
|
tabHeaders.querySelectorAll(".obsidian_douban_settings_tab_header").forEach(header => header.removeClass("active"));
|
||||||
|
tabContents.querySelectorAll(".obsidian_douban_settings_tab_content").forEach(content => content.removeClass("active"));
|
||||||
|
|
||||||
|
// Add active class to the clicked header and corresponding content
|
||||||
|
tabHeader.addClass("active");
|
||||||
|
tabContent.addClass("active");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tabContainer.appendChild(tabHeaders);
|
||||||
|
tabContainer.appendChild(tabContents);
|
||||||
}
|
}
|
||||||
|
|
||||||
hide(): void {
|
hide(): void {
|
||||||
|
|||||||
192
src/org/wanxp/douban/setting/LoginSettingsHelper.ts
Normal file
192
src/org/wanxp/douban/setting/LoginSettingsHelper.ts
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import I18nHelper, {i18nHelper} from "../../lang/helper";
|
||||||
|
import {Platform, Setting} from "obsidian";
|
||||||
|
import SettingsManager from "./SettingsManager";
|
||||||
|
import DoubanLoginModel from "../component/DoubanLoginModel";
|
||||||
|
import User from "../user/User";
|
||||||
|
import StringUtil from "../../utils/StringUtil";
|
||||||
|
import {log} from "../../utils/Logutil";
|
||||||
|
|
||||||
|
export function constructLoginUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1210') });
|
||||||
|
|
||||||
|
const userComponent = manager.plugin.userComponent;
|
||||||
|
if (userComponent.isLogin() && !userComponent.isVerified()) {
|
||||||
|
// Assumed login — verify to get user ID/name for settings display
|
||||||
|
userComponent.login()
|
||||||
|
.then(() => constructDoubanLoginSettingsUI(containerEl, manager))
|
||||||
|
.catch(() => constructDoubanLoginSettingsUI(containerEl, manager));
|
||||||
|
} else if (userComponent.needLogin()) {
|
||||||
|
// Has credentials but not yet logged in
|
||||||
|
userComponent.login()
|
||||||
|
.then(() => constructDoubanLoginSettingsUI(containerEl, manager))
|
||||||
|
.catch(() => constructDoubanLoginSettingsUI(containerEl, manager));
|
||||||
|
} else {
|
||||||
|
constructDoubanLoginSettingsUI(containerEl, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function constructDoubanLoginSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
containerEl.createDiv('login-setting', async (loginSettingEl) => {
|
||||||
|
constructDoubanTokenSettingsUI(loginSettingEl, manager);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function constructDoubanTokenSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
containerEl.empty();
|
||||||
|
let login = manager.plugin.userComponent.isLogin();
|
||||||
|
manager.debug(`配置界面:展示豆瓣状态:${login?'已登录':'未登录'}`)
|
||||||
|
if (Platform.isDesktopApp) {
|
||||||
|
if(login) {
|
||||||
|
constructHasLoginSettingsUI(containerEl, manager);
|
||||||
|
}else {
|
||||||
|
constructLoginSettingsUI(containerEl, manager);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(login) {
|
||||||
|
showMobileLogout(containerEl, manager);
|
||||||
|
}else {
|
||||||
|
showMobileLogin(containerEl, manager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function constructLoginSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
manager.debug(`配置界面:未登录-展示登录按钮`)
|
||||||
|
let loginSetting = containerEl.createDiv("login-button");
|
||||||
|
let loginCookie = containerEl.createDiv("login-button-cookie");
|
||||||
|
|
||||||
|
new Setting(loginSetting).setName(i18nHelper.getMessage('100131')).addButton((button) => {
|
||||||
|
return button
|
||||||
|
.setButtonText(i18nHelper.getMessage('100130'))
|
||||||
|
.onClick(async () => {
|
||||||
|
button.setDisabled(true);
|
||||||
|
manager.debug(`配置界面:点击登录按钮`)
|
||||||
|
const loginModel = new DoubanLoginModel(containerEl, manager);
|
||||||
|
await loginModel.doLogin();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const loginCookieSetting:Setting = new Setting(loginSetting).setName(i18nHelper.getMessage('100133'));
|
||||||
|
// .setDesc(i18nHelper.getMessage('100134'))
|
||||||
|
loginCookieSetting.addButton((button) => {
|
||||||
|
loginCookieSetting.descEl.appendChild(
|
||||||
|
createFragment((frag) => {
|
||||||
|
frag.appendText(
|
||||||
|
i18nHelper.getMessage('100134')
|
||||||
|
);
|
||||||
|
frag.createEl(
|
||||||
|
'a',
|
||||||
|
{
|
||||||
|
text: i18nHelper.getMessage('100139'),
|
||||||
|
href: 'https://wanxp.github.io/obsidian-douban/20_howtouse_25_setting_login_douban_cookie.html',
|
||||||
|
},
|
||||||
|
(a) => {
|
||||||
|
a.setAttr('target', '_blank');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
frag.appendText(i18nHelper.getMessage('100138'));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return button
|
||||||
|
.setButtonText(i18nHelper.getMessage('100135'))
|
||||||
|
.onClick(async () => {
|
||||||
|
button.setDisabled(true);
|
||||||
|
manager.debug(`配置界面:点击登录异常处理按钮`)
|
||||||
|
constructLoginCookieSettingsUI(loginCookie, containerEl, manager);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function constructLoginCookieSettingsUI(containerEl: HTMLElement, parentContainerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
manager.debug(`配置界面:登录异常处理按钮-展示Cookie输入框`)
|
||||||
|
new Setting(containerEl).setName(i18nHelper.getMessage('100136'))
|
||||||
|
.setClass("obsidian_douban_settings_cookie_login").addTextArea((text) => {
|
||||||
|
text.onChange(value => manager.updateCookieTemp(value));
|
||||||
|
return text;
|
||||||
|
}).addExtraButton((button) => {
|
||||||
|
return button
|
||||||
|
.setIcon('check')
|
||||||
|
.onClick(async () => {
|
||||||
|
manager.debug(`配置界面:确认输入Cookie`);
|
||||||
|
const user:User = await manager.plugin.userComponent.loginCookie(manager.getCookieTemp())
|
||||||
|
if (!user || !user.id) {
|
||||||
|
log.notice(i18nHelper.getMessage('100137'))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
constructDoubanTokenSettingsUI(parentContainerEl, manager);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.addExtraButton((button) => {
|
||||||
|
return button
|
||||||
|
.setIcon('x')
|
||||||
|
.onClick(async () => {
|
||||||
|
button.setDisabled(true);
|
||||||
|
manager.debug(`配置界面:取消输入Cookie`);
|
||||||
|
constructDoubanTokenSettingsUI(parentContainerEl, manager);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function constructHasLoginSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
const user: User = manager.plugin.userComponent.getUser();
|
||||||
|
let userDom = new DocumentFragment();
|
||||||
|
userDom.createDiv().innerHTML =
|
||||||
|
`${i18nHelper.getMessage('100120')}<br>
|
||||||
|
${i18nHelper.getMessage('100123')}: <a href="https://www.douban.com/people/${user.id}/">${user.id}</a><br>
|
||||||
|
${i18nHelper.getMessage('100124')}: ${user.name}<br>
|
||||||
|
${i18nHelper.getMessage('100125')}`;
|
||||||
|
manager.debug(`配置界面:展示豆瓣登录信息:id:${StringUtil.confuse(user.id)}, 用户名:${StringUtil.confuse(user.name)}`)
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName(i18nHelper.getMessage('100126'))
|
||||||
|
.setDesc(userDom)
|
||||||
|
.addButton((button) => {
|
||||||
|
return button
|
||||||
|
.setButtonText(i18nHelper.getMessage('100128'))
|
||||||
|
.setCta()
|
||||||
|
.onClick(async () => {
|
||||||
|
button.setDisabled(true);
|
||||||
|
manager.debug(`配置界面:点击退出登录按钮,准备退出登录`)
|
||||||
|
// manager.debug(`配置界面:登出界面退出登录请求检测成功,准备退出登录`)
|
||||||
|
manager.plugin.userComponent.logout();
|
||||||
|
manager.debug(`配置界面:退出登录成功`);
|
||||||
|
constructDoubanTokenSettingsUI(containerEl, manager);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMobileLogin(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName(i18nHelper.getMessage('100126'))
|
||||||
|
.setDesc(i18nHelper.getMessage('100129'))
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMobileLogout(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
|
const user: User = manager.plugin.userComponent.getUser();
|
||||||
|
let userDom = new DocumentFragment();
|
||||||
|
userDom.createDiv().innerHTML =
|
||||||
|
`${i18nHelper.getMessage('100120')}<br>
|
||||||
|
${i18nHelper.getMessage('100123')}: <a href="https://www.douban.com/people/${user.id}/">${user.id}</a><br>
|
||||||
|
${i18nHelper.getMessage('100124')}: ${user.name}<br>
|
||||||
|
${i18nHelper.getMessage('100125')}`;
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName(i18nHelper.getMessage('100126'))
|
||||||
|
.setDesc(userDom)
|
||||||
|
.addButton((button) => {
|
||||||
|
return button
|
||||||
|
.setButtonText(i18nHelper.getMessage('100128'))
|
||||||
|
.setCta()
|
||||||
|
.onClick(async () => {
|
||||||
|
button.setDisabled(true);
|
||||||
|
manager.updateSetting('loginCookiesContent', '');
|
||||||
|
manager.updateSetting('loginHeadersContent', '');
|
||||||
|
constructDoubanTokenSettingsUI(containerEl, manager);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import {Setting, TextComponent, ToggleComponent} from "obsidian";
|
import {Setting, TextComponent, ToggleComponent} from "obsidian";
|
||||||
import {createFolderSelectionSetting} from "./TemplateSettingHelper";
|
import {createFolderSelectionSetting, createFolderSelectionSettingInput} from "./TemplateSettingHelper";
|
||||||
import {DEFAULT_SETTINGS} from "../../constant/DefaultSettings";
|
import {DEFAULT_SETTINGS} from "../../constant/DefaultSettings";
|
||||||
import {
|
import {
|
||||||
DEFAULT_SETTINGS_ARRAY_INPUT_SIZE, EXAMPLE_RATE, EXAMPLE_RATE_MAX,
|
DEFAULT_SETTINGS_ARRAY_INPUT_SIZE, EXAMPLE_RATE, EXAMPLE_RATE_MAX,
|
||||||
@ -14,6 +14,7 @@ import NumberUtil from "../../utils/NumberUtil";
|
|||||||
import {VariableUtil} from "../../utils/VariableUtil";
|
import {VariableUtil} from "../../utils/VariableUtil";
|
||||||
import {FileUtil} from "../../utils/FileUtil";
|
import {FileUtil} from "../../utils/FileUtil";
|
||||||
import {ScoreSetting} from "./model/ScoreSetting";
|
import {ScoreSetting} from "./model/ScoreSetting";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
|
||||||
|
|
||||||
function showStarExample(containerEl: HTMLElement, manager: SettingsManager) {
|
function showStarExample(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
@ -32,8 +33,8 @@ export function showFileExample(containerEl: HTMLElement, manager: SettingsManag
|
|||||||
const document = new DocumentFragment();
|
const document = new DocumentFragment();
|
||||||
document.createDiv('file-path-example')
|
document.createDiv('file-path-example')
|
||||||
.innerHTML = `${i18nHelper.getMessage('121604')}<a href="https://book.douban.com/subject/2253379/">《简爱》</a>: ${VariableUtil.replaceSubject(EXAMPLE_SUBJECT_MAP,
|
.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,
|
FileUtil.join(manager.plugin.settings.dataFilePath, manager.plugin.settings.dataFileNamePath + ".md"), SupportType.book,
|
||||||
manager)}`;
|
manager, 'path')}`;
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(i18nHelper.getMessage('120603'))
|
.setName(i18nHelper.getMessage('120603'))
|
||||||
@ -111,16 +112,21 @@ function scoreSettingDisplay(containerEl: HTMLElement, manager: SettingsManager)
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function constructOutUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructOutUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1220') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1220') });
|
||||||
|
|
||||||
new Setting(containerEl);
|
new Setting(containerEl);
|
||||||
const attachmentFileSetting = containerEl.createDiv({ cls: 'settings-item-attachment' });
|
const attachmentFileSetting = containerEl.createDiv({ cls: 'settings-item-attachment' });
|
||||||
constructAttachmentFileSettingsUI(attachmentFileSetting, manager);
|
constructAttachmentFileSettingsUI(attachmentFileSetting, manager);
|
||||||
|
|
||||||
const folder = new Setting(containerEl);
|
const folder = new Setting(containerEl);
|
||||||
|
const folderInput = new Setting(containerEl);
|
||||||
|
|
||||||
const outFolder = containerEl.createDiv({ cls: 'settings-item' });
|
const outFolder = containerEl.createDiv({ cls: 'settings-item' });
|
||||||
const filePathDisplayExample = containerEl.createDiv('filePath-display-example');
|
const filePathDisplayExample = containerEl.createDiv('filePath-display-example');
|
||||||
folder.then(createFolderSelectionSetting({name: '121501', desc: '121502', placeholder: '121503', key: 'dataFilePath', manager: manager}, filePathDisplayExample));
|
|
||||||
|
folder.then(createFolderSelectionSetting({containerEl: containerEl, name: '121501', desc: '121502', placeholder: null, key: null, manager: manager}, filePathDisplayExample));
|
||||||
|
folderInput.then(createFolderSelectionSettingInput({containerEl: containerEl, name: null, desc: null, placeholder: '121503', key: 'dataFilePath', manager: manager}, filePathDisplayExample));
|
||||||
|
|
||||||
constructOutputFileNameUI(outFolder, filePathDisplayExample, manager);
|
constructOutputFileNameUI(outFolder, filePathDisplayExample, manager);
|
||||||
|
|
||||||
|
|
||||||
@ -215,7 +221,11 @@ export function constructAttachmentFileSettingsUI(containerEl: HTMLElement, mana
|
|||||||
if (manager.plugin.settings.pictureBedFlag) {
|
if (manager.plugin.settings.pictureBedFlag) {
|
||||||
constructAttachmentFilePictureBedSettingsUI(containerEl, manager);
|
constructAttachmentFilePictureBedSettingsUI(containerEl, manager);
|
||||||
}else {
|
}else {
|
||||||
new Setting(containerEl).then(createFolderSelectionSetting({name: '121432', desc: '121433', placeholder: '121434', key: 'attachmentPath', manager: manager}));
|
new Setting(containerEl).then(createFolderSelectionSetting({containerEl: containerEl, name: '121432', desc: '121433', placeholder: null, key: null, manager: manager}));
|
||||||
|
new Setting(containerEl).then(createFolderSelectionSettingInput({containerEl: containerEl, name: null, desc: null, placeholder: '121434', key: 'attachmentPath', manager: manager}));
|
||||||
|
new Setting(containerEl).then(createFolderSelectionSetting({containerEl: containerEl, name: '121452', desc: '121453', placeholder: null, key: null, manager: manager}));
|
||||||
|
new Setting(containerEl).then(createFolderSelectionSettingInput({containerEl: containerEl, name: null, desc: null, placeholder: '121454', key: 'attachmentFileName', manager: manager}));
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
|
|||||||
@ -17,6 +17,8 @@ import {
|
|||||||
ArraySettingFieldName,
|
ArraySettingFieldName,
|
||||||
DEFAULT_SETTINGS_ARRAY_NAME
|
DEFAULT_SETTINGS_ARRAY_NAME
|
||||||
} from "./model/ArraySetting";
|
} from "./model/ArraySetting";
|
||||||
|
import {logger} from "bs-logger";
|
||||||
|
import {i18nHelper} from "../../lang/helper";
|
||||||
|
|
||||||
export default class SettingsManager {
|
export default class SettingsManager {
|
||||||
app: App;
|
app: App;
|
||||||
@ -228,4 +230,21 @@ export default class SettingsManager {
|
|||||||
clearSyncCache() {
|
clearSyncCache() {
|
||||||
this.settings.syncHandledDataArray = [];
|
this.settings.syncHandledDataArray = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async loadAndSaveSettings(config: object) {
|
||||||
|
this.validateSettings(config);
|
||||||
|
// @ts-ignore
|
||||||
|
this.settings = Object.assign({}, config);
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private validateSettings(config: object) {
|
||||||
|
if (!config) {
|
||||||
|
this.innerLogger.warn(i18nHelper.getMessage('125040'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettings() {
|
||||||
|
return this.settings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,43 +7,50 @@ import {getDefaultTemplateContent} from "../../constant/DefaultTemplateContent";
|
|||||||
import {FolderSuggest} from "./model/FolderSuggest";
|
import {FolderSuggest} from "./model/FolderSuggest";
|
||||||
import SettingsManager from "./SettingsManager";
|
import SettingsManager from "./SettingsManager";
|
||||||
import {showFileExample} from "./OutputSettingsHelper";
|
import {showFileExample} from "./OutputSettingsHelper";
|
||||||
|
import {FileTreeSelectSuggest} from "./model/FileTreeSelectSuggest";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
import {FolderTreeSelectSuggest} from "./model/FolderTreeSelectSuggest";
|
||||||
|
|
||||||
|
|
||||||
export function constructTemplateUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructTemplateUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1203') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1203') });
|
||||||
containerEl.createEl('p', { text: i18nHelper.getMessage('1204') });
|
containerEl.createEl('p', { text: i18nHelper.getMessage('1204') });
|
||||||
new Setting(containerEl).setDesc(i18nHelper.getMessage('1205'))
|
new Setting(containerEl).setDesc(i18nHelper.getMessage('1205'))
|
||||||
|
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '120101', desc: '120102', placeholder: '121701', key: 'movieTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '120101', desc: '120102', placeholder: '121701', key: 'movieTemplateFile', manager: manager}));
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '120201', desc: '120202', placeholder: '121701', key: 'bookTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '120201', desc: '120202', placeholder: '121701', key: 'bookTemplateFile', manager: manager}));
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '120301', desc: '120302', placeholder: '121701', key: 'musicTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '120301', desc: '120302', placeholder: '121701', key: 'musicTemplateFile', manager: manager}));
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '120401', desc: '120402', placeholder: '121701', key: 'noteTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '120401', desc: '120402', placeholder: '121701', key: 'noteTemplateFile', manager: manager}));
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '121301', desc: '121302', placeholder: '121701', key: 'gameTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '121301', desc: '121302', placeholder: '121701', key: 'gameTemplateFile', manager: manager}));
|
||||||
new Setting(containerEl).then(createFileSelectionSetting({name: '121801', desc: '121802', placeholder: '121701', key: 'teleplayTemplateFile', manager: manager}));
|
new Setting(containerEl).then(createFileSelectionSetting({containerEl: containerEl, name: '121801', desc: '121802', placeholder: '121701', key: 'teleplayTemplateFile', manager: manager}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createFileSelectionSetting({name, desc, placeholder, key, manager
|
export function createFileSelectionSetting({containerEl, name, desc, placeholder, key, manager
|
||||||
}: CreateTemplateSelectParams) {
|
}: CreateTemplateSelectParams) {
|
||||||
return (setting: Setting) => {
|
return (setting: Setting) => {
|
||||||
|
setting.controlEl.addClass('obsidian_douban_template_file_select');
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
setting.setName(i18nHelper.getMessage(name));
|
setting.setName(i18nHelper.getMessage(name));
|
||||||
// @ts-ignore
|
// settingDesc.setDesc(i18nHelper.getMessage(desc));
|
||||||
setting.setDesc(i18nHelper.getMessage(desc));
|
|
||||||
setting.addSearch(async (search: SearchComponent) => {
|
setting.addSearch(async (search: SearchComponent) => {
|
||||||
const [oldValue, defaultVal] = manager.getSettingWithDefault(key);
|
const [oldValue, defaultVal] = manager.getSettingWithDefault(key);
|
||||||
let v = defaultVal;
|
let v = defaultVal;
|
||||||
if (oldValue) {
|
if (oldValue) {
|
||||||
v = oldValue;
|
v = oldValue;
|
||||||
}
|
}
|
||||||
new FileSuggest(manager.app, search.inputEl);
|
const fileTreeSelectSuggest = new FileTreeSelectSuggest(manager.app, search.inputEl, manager, key);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
search.setValue(v);
|
search.setValue(v);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
search.setPlaceholder(i18nHelper.getMessage(placeholder));
|
search.setPlaceholder(i18nHelper.getMessage(placeholder));
|
||||||
search.onChange(async (value: string) => {
|
search.inputEl.addClass('obsidian_douban_template_file_select_input');
|
||||||
|
search.inputEl.style.width = '100%';
|
||||||
|
search.onChange(async (value: string) => {
|
||||||
manager.updateSetting(key, value);
|
manager.updateSetting(key, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setting.addExtraButton((button) => {
|
setting.addExtraButton((button) => {
|
||||||
button
|
button
|
||||||
.setIcon('copy')
|
.setIcon('copy')
|
||||||
@ -74,13 +81,25 @@ export function createFolderSelectionSetting({
|
|||||||
setting.setName( i18nHelper.getMessage(name));
|
setting.setName( i18nHelper.getMessage(name));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
setting.setDesc( i18nHelper.getMessage(desc));
|
setting.setDesc( i18nHelper.getMessage(desc));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function createFolderSelectionSettingInput({
|
||||||
|
name, desc, placeholder, key, manager,
|
||||||
|
}: CreateTemplateSelectParams, filePathDisplayExample?:HTMLDivElement) {
|
||||||
|
return (setting: Setting) => {
|
||||||
|
setting.controlEl.addClass('obsidian_douban_template_file_select');
|
||||||
setting.addSearch(async (search: SearchComponent) => {
|
setting.addSearch(async (search: SearchComponent) => {
|
||||||
const [oldValue, defaultVal] = manager.getSettingWithDefault(key);
|
const [oldValue, defaultVal] = manager.getSettingWithDefault(key);
|
||||||
let v = defaultVal;
|
let v = defaultVal;
|
||||||
if (oldValue) {
|
if (oldValue) {
|
||||||
v = oldValue;
|
v = oldValue;
|
||||||
}
|
}
|
||||||
new FolderSuggest(manager.app, search.inputEl);
|
new FolderTreeSelectSuggest(manager.app, search.inputEl);
|
||||||
|
search.inputEl.addClass('obsidian_douban_template_file_select_input');
|
||||||
|
search.inputEl.style.width = '100%';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
search.setValue(v)
|
search.setValue(v)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -95,5 +114,3 @@ export function createFolderSelectionSetting({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import SettingsManager from "./SettingsManager";
|
import SettingsManager from "./SettingsManager";
|
||||||
import {i18nHelper} from "../../lang/helper";
|
import {i18nHelper} from "../../lang/helper";
|
||||||
import {Setting} from "obsidian";
|
import {Setting} from "obsidian";
|
||||||
|
import DoubanPlugin from "../../main";
|
||||||
|
|
||||||
export function constructTemplateVariablesUI(containerEl: HTMLElement, manager: SettingsManager) {
|
export function constructTemplateVariablesUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1230') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1230') });
|
||||||
containerEl.createEl('p', { text: i18nHelper.getMessage('122003') });
|
containerEl.createEl('p', { text: i18nHelper.getMessage('122003') });
|
||||||
|
|
||||||
const basicVariablesTable = new DocumentFragment();
|
const basicVariablesTable = new DocumentFragment();
|
||||||
@ -300,6 +301,16 @@ ${i18nHelper.getMessage('122004')}
|
|||||||
<td>${i18nHelper.getMessage('310520')}</th>
|
<td>${i18nHelper.getMessage('310520')}</th>
|
||||||
<td>${i18nHelper.getMessage('310620')}</th>
|
<td>${i18nHelper.getMessage('310620')}</th>
|
||||||
<td>${i18nHelper.getMessage('310720')}</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>
|
</tr>
|
||||||
</table>`;
|
</table>`;
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { DoubanPluginSetting } from "./DoubanPluginSetting";
|
|||||||
|
|
||||||
export interface CreateTemplateSelectParams {
|
export interface CreateTemplateSelectParams {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
containerEl: HTMLElement,
|
||||||
name:string,
|
name:string,
|
||||||
desc:string,
|
desc:string,
|
||||||
placeholder:string,
|
placeholder:string,
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import {SyncHandledData} from "./SyncHandledData";
|
|||||||
import {ArraySetting} from "./ArraySetting";
|
import {ArraySetting} from "./ArraySetting";
|
||||||
import {ScoreSetting} from "./ScoreSetting";
|
import {ScoreSetting} from "./ScoreSetting";
|
||||||
import PictureBedSetting from "./PictureBedSetting";
|
import PictureBedSetting from "./PictureBedSetting";
|
||||||
|
import {SupportType} from "../../../constant/Constsant";
|
||||||
|
|
||||||
export interface DoubanPluginSetting {
|
export interface DoubanPluginSetting {
|
||||||
onlineSettingsFileName: string;
|
onlineSettingsFileName: string;
|
||||||
@ -32,10 +33,13 @@ export interface DoubanPluginSetting {
|
|||||||
cacheImage: boolean,
|
cacheImage: boolean,
|
||||||
cacheHighQuantityImage: boolean,
|
cacheHighQuantityImage: boolean,
|
||||||
attachmentPath: string,
|
attachmentPath: string,
|
||||||
|
attachmentFileName: string,
|
||||||
pictureBedFlag: boolean
|
pictureBedFlag: boolean
|
||||||
pictureBedType: string;
|
pictureBedType: string;
|
||||||
pictureBedSetting: PictureBedSetting;
|
pictureBedSetting: PictureBedSetting;
|
||||||
syncHandledDataArray: SyncHandledData[],
|
syncHandledDataArray: SyncHandledData[],
|
||||||
|
// syncLastUpdateTime: Map<string, string>,
|
||||||
arraySettings: ArraySetting[],
|
arraySettings: ArraySetting[],
|
||||||
scoreSetting: ScoreSetting,
|
scoreSetting: ScoreSetting,
|
||||||
|
searchDefaultType: SupportType,
|
||||||
}
|
}
|
||||||
|
|||||||
90
src/org/wanxp/douban/setting/model/FileTreeSelectSuggest.ts
Normal file
90
src/org/wanxp/douban/setting/model/FileTreeSelectSuggest.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import {App, TAbstractFile, TFile, TFolder} from "obsidian";
|
||||||
|
import {TextInputSuggest} from "./TextInputSuggest";
|
||||||
|
import SettingsManager from "../SettingsManager";
|
||||||
|
|
||||||
|
export class FileTreeSelectSuggest extends TextInputSuggest<TAbstractFile> {
|
||||||
|
parentPath: string = "/";
|
||||||
|
settingKey: string = "";
|
||||||
|
manager: SettingsManager;
|
||||||
|
|
||||||
|
constructor(app: App, inputEl: HTMLInputElement, manager: SettingsManager, settingKey:string) {
|
||||||
|
super(app, inputEl);
|
||||||
|
this.manager = manager;
|
||||||
|
this.settingKey = settingKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSuggestions(inputStr: string): TAbstractFile[] {
|
||||||
|
const files: TAbstractFile[] = [];
|
||||||
|
|
||||||
|
if (inputStr.length == 0 || inputStr.trim().length == 0 || inputStr.trim() == '/') {
|
||||||
|
this.searchFiles(this.app.vault.getRoot(), "", files);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
let parentSearchPath:string = null;
|
||||||
|
let currentName:string = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const testFile = this.app.vault.getAbstractFileByPath(inputStr.trim())
|
||||||
|
if (testFile) {
|
||||||
|
if (testFile instanceof TFile && testFile.name.endsWith(".md")) {
|
||||||
|
files.push(testFile);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
if (testFile instanceof TFolder) {
|
||||||
|
parentSearchPath = inputStr.trim();
|
||||||
|
currentName = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
if (parentSearchPath == null) {
|
||||||
|
parentSearchPath = inputStr.lastIndexOf("/") > 0 ? inputStr.substring(0, inputStr.lastIndexOf("/")) : "/";
|
||||||
|
currentName = inputStr.lastIndexOf("/") > 0 ? inputStr.substring(inputStr.lastIndexOf("/") + 1) : inputStr;
|
||||||
|
currentName = currentName.trim();
|
||||||
|
}
|
||||||
|
if (currentName == null) {
|
||||||
|
currentName = "";
|
||||||
|
}
|
||||||
|
const root = this.app.vault.getAbstractFileByPath(parentSearchPath) as TFolder;
|
||||||
|
if (!root) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const name = currentName.toLowerCase();
|
||||||
|
if (root) {
|
||||||
|
this.searchFiles(root, name, files);
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchFiles(folder: TFolder, name: string, files: TAbstractFile[]): void {
|
||||||
|
folder.children.forEach((file: TAbstractFile) => {
|
||||||
|
if (file.name.toLowerCase().contains(name)) {
|
||||||
|
files.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSuggestion(file: TAbstractFile, el: HTMLElement): void {
|
||||||
|
el.setText(file.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectSuggestion(file: TAbstractFile): void {
|
||||||
|
this.inputEl.value = file.path;
|
||||||
|
this.parentPath = file.path;
|
||||||
|
// this.inputEl.addEventListener("change", () => {
|
||||||
|
// this.onInputChanged()
|
||||||
|
// })
|
||||||
|
if (file instanceof TFolder) {
|
||||||
|
this.inputEl.value += "/";
|
||||||
|
this.inputEl.trigger("input");
|
||||||
|
}else {
|
||||||
|
//@ts-ignore
|
||||||
|
this.manager.updateSetting(this.settingKey, file.path);
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
import {TAbstractFile, TFile, TFolder} from "obsidian";
|
||||||
|
import {TextInputSuggest} from "./TextInputSuggest";
|
||||||
|
|
||||||
|
export class FolderTreeSelectSuggest extends TextInputSuggest<TAbstractFile> {
|
||||||
|
parentPath: string = "/";
|
||||||
|
|
||||||
|
getSuggestions(inputStr: string): TAbstractFile[] {
|
||||||
|
const files: TAbstractFile[] = [];
|
||||||
|
|
||||||
|
if (inputStr.length == 0 || inputStr.trim().length == 0 || inputStr.trim() == '/') {
|
||||||
|
this.searchFiles(this.app.vault.getRoot(), "", files);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
let parentSearchPath:string = null;
|
||||||
|
let currentName:string = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const testFile = this.app.vault.getAbstractFileByPath(inputStr.trim())
|
||||||
|
if (testFile) {
|
||||||
|
if (testFile instanceof TFile) {
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
if (testFile instanceof TFolder) {
|
||||||
|
parentSearchPath = inputStr.trim();
|
||||||
|
currentName = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
if (parentSearchPath == null) {
|
||||||
|
parentSearchPath = inputStr.lastIndexOf("/") > 0 ? inputStr.substring(0, inputStr.lastIndexOf("/")) : "/";
|
||||||
|
currentName = inputStr.lastIndexOf("/") > 0 ? inputStr.substring(inputStr.lastIndexOf("/") + 1) : inputStr;
|
||||||
|
currentName = currentName.trim();
|
||||||
|
}
|
||||||
|
if (currentName == null) {
|
||||||
|
currentName = "";
|
||||||
|
}
|
||||||
|
const root = this.app.vault.getAbstractFileByPath(parentSearchPath) as TFolder;
|
||||||
|
if (!root) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const name = currentName.toLowerCase();
|
||||||
|
if (root) {
|
||||||
|
this.searchFiles(root, name, files);
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchFiles(folder: TFolder, name: string, files: TAbstractFile[]): void {
|
||||||
|
folder.children.filter(f => f instanceof TFolder).forEach((file: TAbstractFile) => {
|
||||||
|
if (file.name.toLowerCase().contains(name)) {
|
||||||
|
files.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSuggestion(file: TAbstractFile, el: HTMLElement): void {
|
||||||
|
el.setText(file.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectSuggestion(file: TAbstractFile): void {
|
||||||
|
this.inputEl.value = file.path;
|
||||||
|
this.parentPath = file.path;
|
||||||
|
// this.inputEl.addEventListener("change", () => {
|
||||||
|
// this.onInputChanged()
|
||||||
|
// })
|
||||||
|
if (file instanceof TFolder) {
|
||||||
|
this.inputEl.value += "/";
|
||||||
|
this.inputEl.trigger("input");
|
||||||
|
}else {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,25 +1,67 @@
|
|||||||
import DoubanPlugin from "../../../main";
|
import DoubanPlugin from "../../../main";
|
||||||
import {BasicConst, SubjectHandledStatus, SyncType} from "../../../constant/Constsant";
|
import {
|
||||||
import {DoubanSyncHandler} from "./DoubanSyncHandler";
|
BasicConst,
|
||||||
import {SyncConfig} from "../model/SyncConfig";
|
PAGE_SIZE,
|
||||||
|
SyncConditionType,
|
||||||
|
SyncType,
|
||||||
|
} from "../../../constant/Constsant";
|
||||||
|
import { DoubanSyncHandler } from "./DoubanSyncHandler";
|
||||||
|
import { SyncConfig } from "../model/SyncConfig";
|
||||||
import HandleContext from "../../data/model/HandleContext";
|
import HandleContext from "../../data/model/HandleContext";
|
||||||
import {SubjectListItem} from "../../data/model/SubjectListItem";
|
import { SubjectListItem } from "../../data/model/SubjectListItem";
|
||||||
import {sleepRange} from "../../../utils/TimeUtil";
|
import { sleepRange } from "../../../utils/TimeUtil";
|
||||||
import DoubanSubjectLoadHandler from "../../data/handler/DoubanSubjectLoadHandler";
|
import DoubanSubjectLoadHandler from "../../data/handler/DoubanSubjectLoadHandler";
|
||||||
import {DoubanListHandler} from "./list/DoubanListHandler";
|
import { DoubanListHandler } from "./list/DoubanListHandler";
|
||||||
import DoubanSubject from "../../data/model/DoubanSubject";
|
import DoubanSubject from "../../data/model/DoubanSubject";
|
||||||
import {log} from "../../../utils/Logutil";
|
import { log } from "../../../utils/Logutil";
|
||||||
import {i18nHelper} from "../../../lang/helper";
|
import { i18nHelper } from "../../../lang/helper";
|
||||||
|
import { SearchPage } from "../../data/model/SearchPage";
|
||||||
|
import {SearchPageTypeOf} from "../../data/model/SearchPageTypeOf";
|
||||||
|
|
||||||
export abstract class DoubanAbstractSyncHandler<T extends DoubanSubject> implements DoubanSyncHandler{
|
function toDateList(dataList: SubjectListItem[]): Date[] {
|
||||||
|
const dateList = dataList
|
||||||
|
.map((item) => item.updateDate)
|
||||||
|
.sort((a, b) => {
|
||||||
|
try {
|
||||||
|
return a.getTime() - b.getTime();
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
return dateList;
|
||||||
|
}
|
||||||
|
|
||||||
|
function testTouchEndCondition(searchPage: SearchPage, context: HandleContext) {
|
||||||
|
const { syncConfig } = context;
|
||||||
|
if (!syncConfig) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (syncConfig.syncConditionType) {
|
||||||
|
case SyncConditionType.ALL:
|
||||||
|
return false;
|
||||||
|
case SyncConditionType.LAST_THIRTY:
|
||||||
|
return searchPage.pageNum >= 0;
|
||||||
|
case SyncConditionType.CUSTOM_ITEM:
|
||||||
|
const syncConditionCountToValue = syncConfig.syncConditionCountToValue? syncConfig.syncConditionCountToValue : searchPage.total;
|
||||||
|
return searchPage.start + PAGE_SIZE - 1 >= syncConditionCountToValue;
|
||||||
|
case SyncConditionType.CUSTOM_TIME:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class DoubanAbstractSyncHandler<T extends DoubanSubject>
|
||||||
|
implements DoubanSyncHandler
|
||||||
|
{
|
||||||
private plugin: DoubanPlugin;
|
private plugin: DoubanPlugin;
|
||||||
private doubanSubjectLoadHandler:DoubanSubjectLoadHandler<T>;
|
private doubanSubjectLoadHandler: DoubanSubjectLoadHandler<T>;
|
||||||
private doubanListHandlers:DoubanListHandler[];
|
private doubanListHandlers: DoubanListHandler[];
|
||||||
|
|
||||||
constructor(plugin: DoubanPlugin,
|
constructor(
|
||||||
doubanSubjectLoadHandler:DoubanSubjectLoadHandler<T>,
|
plugin: DoubanPlugin,
|
||||||
doubanListHandlers:DoubanListHandler[]) {
|
doubanSubjectLoadHandler: DoubanSubjectLoadHandler<T>,
|
||||||
|
doubanListHandlers: DoubanListHandler[],
|
||||||
|
) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.doubanSubjectLoadHandler = doubanSubjectLoadHandler;
|
this.doubanSubjectLoadHandler = doubanSubjectLoadHandler;
|
||||||
this.doubanListHandlers = doubanListHandlers;
|
this.doubanListHandlers = doubanListHandlers;
|
||||||
@ -31,61 +73,387 @@ export abstract class DoubanAbstractSyncHandler<T extends DoubanSubject> implem
|
|||||||
|
|
||||||
abstract getSyncType(): SyncType;
|
abstract getSyncType(): SyncType;
|
||||||
|
|
||||||
async sync(syncConfig: SyncConfig, context: HandleContext): Promise<void>{
|
async sync(syncConfig: SyncConfig, context: HandleContext): Promise<void> {
|
||||||
return Promise.resolve()
|
if (syncConfig.syncConditionType == SyncConditionType.CUSTOM_TIME) {
|
||||||
.then(() => this.getItems(syncConfig, context))
|
await this.syncByTimeLimit(syncConfig, context);
|
||||||
.then(items => this.removeExists(items , syncConfig, context))
|
} else if (syncConfig.syncConditionType == SyncConditionType.CUSTOM_ITEM) {
|
||||||
.then(items => this.handleItems(items, context));
|
await this.syncByCountLimit(syncConfig, context);
|
||||||
|
}else if (syncConfig.syncConditionType == SyncConditionType.ALL) {
|
||||||
|
await this.syncAll(syncConfig, context);
|
||||||
|
}else if (syncConfig.syncConditionType == SyncConditionType.LAST_THIRTY) {
|
||||||
|
await this.syncLastThirty(syncConfig, context);
|
||||||
|
}else {
|
||||||
|
log.warn(i18nHelper.getMessage("110083"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getByTimeLimit(syncConfig: SyncConfig, context: HandleContext): Promise<SubjectListItem[]> {
|
||||||
|
let startDate = syncConfig.syncConditionDateFromValue
|
||||||
|
? new Date(syncConfig.syncConditionDateFromValue)
|
||||||
|
: null;
|
||||||
|
let endDate = syncConfig.syncConditionDateToValue
|
||||||
|
? new Date(syncConfig.syncConditionDateToValue)
|
||||||
|
: null;
|
||||||
|
if (!startDate && !endDate) {
|
||||||
|
log.warn(i18nHelper.getMessage("110081"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cacheList = new Map<number, SearchPageTypeOf<SubjectListItem>>();
|
||||||
|
let searchPage = await this.getItems(syncConfig, context);
|
||||||
|
if (!searchPage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const total = searchPage.total;
|
||||||
|
const lastPage = total / PAGE_SIZE + 1;
|
||||||
|
if (lastPage == 1) {
|
||||||
|
return searchPage.list;
|
||||||
|
}
|
||||||
|
let leftPage = 1;
|
||||||
|
let startPage = 1;
|
||||||
|
let rightPage = lastPage;
|
||||||
|
let endPage = lastPage;
|
||||||
|
let currentPage = 1;
|
||||||
|
cacheList.set(currentPage, searchPage);
|
||||||
|
if (startDate != null) {
|
||||||
|
do {
|
||||||
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let page = cacheList.get(currentPage);
|
||||||
|
if (!page) {
|
||||||
|
page = await this.getItems(syncConfig, context);
|
||||||
|
if (!page) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cacheList.set(currentPage, page);
|
||||||
|
}
|
||||||
|
const pageItems = page.list;
|
||||||
|
const pageDateList = toDateList(pageItems);
|
||||||
|
if (pageDateList[pageDateList.length - 1] >= startDate) {
|
||||||
|
leftPage = currentPage;
|
||||||
|
endPage = currentPage;
|
||||||
|
currentPage = Math.ceil((leftPage + rightPage) / 2);
|
||||||
|
}else {
|
||||||
|
rightPage = currentPage;
|
||||||
|
endPage = currentPage;
|
||||||
|
currentPage = Math.floor((leftPage + rightPage) / 2);
|
||||||
|
}
|
||||||
|
if (currentPage == leftPage || currentPage == rightPage) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (currentPage < lastPage);
|
||||||
|
}
|
||||||
|
leftPage = 1;
|
||||||
|
rightPage = lastPage;
|
||||||
|
currentPage = 1;
|
||||||
|
if (endDate != null) {
|
||||||
|
do {
|
||||||
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let page = cacheList.get(currentPage);
|
||||||
|
if (!page) {
|
||||||
|
page = await this.getItems(syncConfig, context);
|
||||||
|
if (!page) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cacheList.set(currentPage, page);
|
||||||
|
}
|
||||||
|
const pageItems = page.list;
|
||||||
|
const pageDateList = toDateList(pageItems);
|
||||||
|
if (pageDateList[0] <= endDate) {
|
||||||
|
rightPage = currentPage;
|
||||||
|
startPage = currentPage;
|
||||||
|
currentPage = Math.ceil((leftPage + rightPage) / 2);
|
||||||
|
}else {
|
||||||
|
leftPage = currentPage;
|
||||||
|
startPage = currentPage;
|
||||||
|
currentPage = Math.floor((leftPage + rightPage) / 2);
|
||||||
|
}
|
||||||
|
if (currentPage == leftPage || currentPage == rightPage) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (currentPage < lastPage);
|
||||||
|
}
|
||||||
|
let needHandleItems:SubjectListItem[] = [];
|
||||||
|
for (let pageNum = startPage; pageNum <= endPage; pageNum++) {
|
||||||
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let page = cacheList.get(pageNum);
|
||||||
|
if (!page) {
|
||||||
|
page = await this.getItems(syncConfig, context);
|
||||||
|
if (!page) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cacheList.set(pageNum, page);
|
||||||
|
}
|
||||||
|
const pageItems = page.list;
|
||||||
|
needHandleItems = needHandleItems.concat(pageItems
|
||||||
|
.filter((item) => {
|
||||||
|
const itemDate = item.updateDate;
|
||||||
|
return (!startDate || itemDate >= startDate) && (!endDate || itemDate <= endDate);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return needHandleItems;
|
||||||
|
|
||||||
|
}
|
||||||
|
async syncByTimeLimit(syncConfig: SyncConfig, context: HandleContext) {
|
||||||
|
const items = await this.getByTimeLimit(syncConfig, context);
|
||||||
|
if (!items || items.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let subjectListItems = await this.removeExists(
|
||||||
|
items,
|
||||||
|
syncConfig,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
|
||||||
|
const searchPage = new SearchPageTypeOf<SubjectListItem>(subjectListItems.length,
|
||||||
|
1,
|
||||||
|
subjectListItems.length,
|
||||||
|
null,subjectListItems);
|
||||||
|
await this.handleItems(searchPage, subjectListItems, context);
|
||||||
|
|
||||||
private async getItems(syncConfig:SyncConfig, context:HandleContext):Promise<SubjectListItem[]> {
|
|
||||||
const supportHandlers:DoubanListHandler[] = this.doubanListHandlers.filter((h) => h.support(syncConfig));
|
|
||||||
let items:SubjectListItem[] = [];
|
|
||||||
for(const handler of supportHandlers) {
|
|
||||||
if (!context.plugin.statusHolder.syncing()) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const item = await handler.getAllPageList(context);
|
|
||||||
if (item) {
|
|
||||||
items = items.concat(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async removeExists(items:SubjectListItem[], syncConfig: SyncConfig, context: HandleContext):Promise<SubjectListItem[]> {
|
private async getItems(
|
||||||
|
syncConfig: SyncConfig,
|
||||||
|
context: HandleContext,
|
||||||
|
): Promise<SearchPageTypeOf<SubjectListItem>> {
|
||||||
|
const supportHandlers: DoubanListHandler[] =
|
||||||
|
this.doubanListHandlers.filter((h) => h.support(syncConfig));
|
||||||
|
const handler = supportHandlers[0];
|
||||||
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
|
return SearchPage.emptyWithNoType();
|
||||||
|
}
|
||||||
|
const item = await handler.getPageData(context);
|
||||||
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
|
return SearchPage.emptyWithNoType();
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async removeExists(
|
||||||
|
items: SubjectListItem[],
|
||||||
|
syncConfig: SyncConfig,
|
||||||
|
context: HandleContext,
|
||||||
|
): Promise<SubjectListItem[]> {
|
||||||
if (!context.plugin.statusHolder.syncing()) {
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleItems(items:SubjectListItem[], context:HandleContext):Promise<void> {
|
private async handleItems(
|
||||||
|
searchPage: SearchPage,
|
||||||
|
items: SubjectListItem[],
|
||||||
|
context: HandleContext,
|
||||||
|
): Promise<void> {
|
||||||
if (!items || items.length == 0) {
|
if (!items || items.length == 0) {
|
||||||
return ;
|
return;
|
||||||
}
|
}
|
||||||
const {syncStatus} = context.syncStatusHolder;
|
const { syncStatus } = context.syncStatusHolder;
|
||||||
syncStatus.totalNum(items.length);
|
syncStatus.totalNum(searchPage.total);
|
||||||
const needHandled:number = items.filter(item => syncStatus.shouldSync(item.id)).length;
|
const needHandled: number =
|
||||||
|
syncStatus.getTotal() - syncStatus.getHasHandle();
|
||||||
syncStatus.setNeedHandled(needHandled);
|
syncStatus.setNeedHandled(needHandled);
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
if (!context.plugin.statusHolder.syncing()) {
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if(syncStatus.shouldSync(item.id)) {
|
if (syncStatus.shouldSync(item.id)) {
|
||||||
let subject: DoubanSubject = await this.doubanSubjectLoadHandler.handle(item.id, context);
|
let subject: DoubanSubject =
|
||||||
await sleepRange(BasicConst.CALL_DOUBAN_DELAY, BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE);
|
await this.doubanSubjectLoadHandler.handle(
|
||||||
}else {
|
item.id,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
|
||||||
|
await sleepRange(
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY,
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY +
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY_RANGE,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
syncStatus.unHandle(item.id, item.title);
|
syncStatus.unHandle(item.id, item.title);
|
||||||
}
|
}
|
||||||
}catch (e) {
|
} catch (e) {
|
||||||
log.notice(i18nHelper.getMessage('130120'))
|
log.notice(i18nHelper.getMessage("130120"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async syncByCountLimit(syncConfig: SyncConfig, context: HandleContext) {
|
||||||
|
const {syncConditionCountFromValue, syncConditionCountToValue} = syncConfig;
|
||||||
|
const startOffset = Math.floor((syncConditionCountFromValue - 1)/ PAGE_SIZE) * PAGE_SIZE;
|
||||||
|
context.syncOffset = startOffset;
|
||||||
|
//结束点是第几条
|
||||||
|
let endOffsetNumberForCustom = 0;
|
||||||
|
let needHandleTotalCustomItem = 0;
|
||||||
|
let isFirstStep = true;
|
||||||
|
let handleCount = 0;
|
||||||
|
do {
|
||||||
|
let searchPage = await this.getItems(syncConfig, context);
|
||||||
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const {list, total} = searchPage;
|
||||||
|
if (
|
||||||
|
!searchPage ||
|
||||||
|
!list ||
|
||||||
|
list.length == 0
|
||||||
|
) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (syncConditionCountFromValue > total) {
|
||||||
|
context.syncStatusHolder.syncStatus.setMessage(i18nHelper.getMessage("130121", total));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (endOffsetNumberForCustom == 0) {
|
||||||
|
endOffsetNumberForCustom = Math.min(syncConditionCountToValue?syncConditionCountToValue:searchPage.total, searchPage.total);
|
||||||
|
needHandleTotalCustomItem = endOffsetNumberForCustom - syncConditionCountFromValue + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
let subjectListItems = [];
|
||||||
|
|
||||||
|
//在开始和结束同一页
|
||||||
|
if (Math.floor((syncConditionCountFromValue - 1) / PAGE_SIZE) == Math.floor((endOffsetNumberForCustom - 1) / PAGE_SIZE)) {
|
||||||
|
const startIndex = Math.floor((syncConditionCountFromValue - 1) % PAGE_SIZE);
|
||||||
|
const endIndex = Math.floor((endOffsetNumberForCustom - 1) % PAGE_SIZE);
|
||||||
|
subjectListItems = await this.removeExists(
|
||||||
|
list.slice(startIndex, endIndex + 1),
|
||||||
|
syncConfig,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
handleCount += (endIndex - startIndex + 1);
|
||||||
|
//第一页
|
||||||
|
} else if (isFirstStep) {
|
||||||
|
const startIndex = (syncConditionCountFromValue - 1) % PAGE_SIZE;
|
||||||
|
handleCount += (list.length - startIndex);
|
||||||
|
subjectListItems = await this.removeExists(
|
||||||
|
list.slice(startIndex),
|
||||||
|
syncConfig,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
isFirstStep = false;
|
||||||
|
}
|
||||||
|
//最后一页
|
||||||
|
else if (needHandleTotalCustomItem - handleCount <= PAGE_SIZE) {
|
||||||
|
const endIndex = needHandleTotalCustomItem - handleCount;
|
||||||
|
subjectListItems = await this.removeExists(
|
||||||
|
list.slice(0, endIndex),
|
||||||
|
syncConfig,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
handleCount += endIndex;
|
||||||
|
//中间页
|
||||||
|
} else {
|
||||||
|
subjectListItems = await this.removeExists(
|
||||||
|
list,
|
||||||
|
syncConfig,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
handleCount += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!subjectListItems || subjectListItems.length == 0) {
|
||||||
|
await sleepRange(
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY,
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY +
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY_RANGE,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchPage.total = needHandleTotalCustomItem;
|
||||||
|
//处理
|
||||||
|
await this.handleItems(searchPage, subjectListItems, context);
|
||||||
|
|
||||||
|
context.syncOffset = context.syncOffset + PAGE_SIZE;
|
||||||
|
await sleepRange(
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY,
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY +
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY_RANGE,
|
||||||
|
);
|
||||||
|
} while (handleCount < needHandleTotalCustomItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async syncAll(syncConfig: SyncConfig, context: HandleContext) {
|
||||||
|
//最多100000条
|
||||||
|
context.syncOffset = 0;
|
||||||
|
let handleCount = 0;
|
||||||
|
let totalForHandle = 0;
|
||||||
|
let isFirstStep = true;
|
||||||
|
do {
|
||||||
|
let searchPage = await this.getItems(syncConfig, context);
|
||||||
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {list, total} = searchPage;
|
||||||
|
if (
|
||||||
|
!searchPage ||
|
||||||
|
!list ||
|
||||||
|
list.length == 0
|
||||||
|
) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (isFirstStep) {
|
||||||
|
totalForHandle = total;
|
||||||
|
isFirstStep = false;
|
||||||
|
}
|
||||||
|
handleCount += list.length;
|
||||||
|
let subjectListItems = await this.removeExists(
|
||||||
|
list,
|
||||||
|
syncConfig,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
if (!subjectListItems || subjectListItems.length == 0) {
|
||||||
|
await sleepRange(
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY,
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY +
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY_RANGE,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
await this.handleItems(searchPage, subjectListItems, context);
|
||||||
|
context.syncOffset = context.syncOffset + PAGE_SIZE;
|
||||||
|
await sleepRange(
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY,
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY +
|
||||||
|
BasicConst.CALL_DOUBAN_DELAY_RANGE,
|
||||||
|
);
|
||||||
|
} while (handleCount <= totalForHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async syncLastThirty(syncConfig: SyncConfig, context: HandleContext) {
|
||||||
|
context.syncOffset = 0;
|
||||||
|
let searchPage = await this.getItems(syncConfig, context);
|
||||||
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {list, total} = searchPage;
|
||||||
|
if (
|
||||||
|
!searchPage ||
|
||||||
|
!list ||
|
||||||
|
list.length == 0
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let subjectListItems = await this.removeExists(
|
||||||
|
list,
|
||||||
|
syncConfig,
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
if (!subjectListItems || subjectListItems.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
searchPage.total = Math.min(list.length, total);
|
||||||
|
await this.handleItems(searchPage, subjectListItems, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
40
src/org/wanxp/douban/sync/handler/DoubanGameSyncHandler.ts
Normal file
40
src/org/wanxp/douban/sync/handler/DoubanGameSyncHandler.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import {DoubanAbstractSyncHandler} from "./DoubanAbstractSyncHandler";
|
||||||
|
import {BasicConst, SyncType} from "../../../constant/Constsant";
|
||||||
|
import {SyncConfig} from "../model/SyncConfig";
|
||||||
|
import HandleContext from "../../data/model/HandleContext";
|
||||||
|
import DoubanSubjectLoadHandler from "../../data/handler/DoubanSubjectLoadHandler";
|
||||||
|
import DoubanMovieLoadHandler from "../../data/handler/DoubanMovieLoadHandler";
|
||||||
|
import DoubanMovieSubject from "../../data/model/DoubanMovieSubject";
|
||||||
|
import DoubanPlugin from "../../../main";
|
||||||
|
import {SubjectListItem} from "../../data/model/SubjectListItem";
|
||||||
|
import DoubanMovieCollectListHandler from "./list/DoubanMovieCollectListHandler";
|
||||||
|
import {DoubanListHandler} from "./list/DoubanListHandler";
|
||||||
|
import DoubanMovieWishListHandler from "./list/DoubanMovieWishListHandler";
|
||||||
|
import DoubanMovieDoListHandler from "./list/DoubanMovieDoListHandler";
|
||||||
|
import TimeUtil, {sleepRange} from "../../../utils/TimeUtil";
|
||||||
|
import {log} from "../../../utils/Logutil";
|
||||||
|
import DoubanGameLoadHandler from "../../data/handler/DoubanGameLoadHandler";
|
||||||
|
import DoubanGameCollectListHandler from "./list/DoubanGameCollectListHandler";
|
||||||
|
import DoubanGameWishListHandler from "./list/DoubanGameWishListHandler";
|
||||||
|
import DoubanGameDoListHandler from "./list/DoubanGameDoListHandler";
|
||||||
|
import DoubanGameSubject from "../../data/model/DoubanGameSubject";
|
||||||
|
|
||||||
|
//TODO will support in future version
|
||||||
|
export class DoubanGameSyncHandler extends DoubanAbstractSyncHandler<DoubanGameSubject>{
|
||||||
|
|
||||||
|
constructor(plugin:DoubanPlugin) {
|
||||||
|
super(plugin, new DoubanGameLoadHandler(plugin),[
|
||||||
|
new DoubanGameCollectListHandler(),
|
||||||
|
new DoubanGameWishListHandler(),
|
||||||
|
new DoubanGameDoListHandler()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
getSyncType(): SyncType {
|
||||||
|
return SyncType.game;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -9,6 +9,11 @@ import { DoubanMusicSyncHandler } from "./DoubanMusicSyncHandler";
|
|||||||
import { DoubanBookSyncHandler } from "./DoubanBookSyncHandler";
|
import { DoubanBookSyncHandler } from "./DoubanBookSyncHandler";
|
||||||
import {i18nHelper} from "../../../lang/helper";
|
import {i18nHelper} from "../../../lang/helper";
|
||||||
import {DoubanTeleplaySyncHandler} from "./DoubanTeleplaySyncHandler";
|
import {DoubanTeleplaySyncHandler} from "./DoubanTeleplaySyncHandler";
|
||||||
|
import {SyncConditionType} from "../../../constant/Constsant";
|
||||||
|
import {DoubanGameSyncHandler} from "./DoubanGameSyncHandler";
|
||||||
|
import {DataField} from "../../../utils/model/DataField";
|
||||||
|
import {VariableUtil} from "../../../utils/VariableUtil";
|
||||||
|
import {FileUtil} from "../../../utils/FileUtil";
|
||||||
|
|
||||||
export default class SyncHandler {
|
export default class SyncHandler {
|
||||||
private app: App;
|
private app: App;
|
||||||
@ -18,6 +23,7 @@ export default class SyncHandler {
|
|||||||
private syncHandlers: DoubanSyncHandler[];
|
private syncHandlers: DoubanSyncHandler[];
|
||||||
private defaultSyncHandler: DoubanSyncHandler;
|
private defaultSyncHandler: DoubanSyncHandler;
|
||||||
|
|
||||||
|
|
||||||
constructor(app: App, plugin: DoubanPlugin, syncConfig: SyncConfig, context: HandleContext) {
|
constructor(app: App, plugin: DoubanPlugin, syncConfig: SyncConfig, context: HandleContext) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
@ -32,12 +38,17 @@ export default class SyncHandler {
|
|||||||
// new DoubanNoteSyncHandler(plugin),
|
// new DoubanNoteSyncHandler(plugin),
|
||||||
new DoubanMusicSyncHandler(plugin),
|
new DoubanMusicSyncHandler(plugin),
|
||||||
new DoubanTeleplaySyncHandler(plugin),
|
new DoubanTeleplaySyncHandler(plugin),
|
||||||
|
new DoubanGameSyncHandler(plugin),
|
||||||
this.defaultSyncHandler
|
this.defaultSyncHandler
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
async sync() {
|
async sync() {
|
||||||
if (this.syncConfig && this.syncConfig.syncType && this.syncConfig.scope) {
|
if (this.syncConfig && this.syncConfig.syncType && this.syncConfig.scope) {
|
||||||
|
if(this.checkSyncConfig()) {
|
||||||
|
this.context.syncStatusHolder.syncStatus.setMessage(this.checkSyncConfig());
|
||||||
|
return;
|
||||||
|
}
|
||||||
let syncHandler = this.syncHandlers.find(handler => handler.support(this.syncConfig.syncType));
|
let syncHandler = this.syncHandlers.find(handler => handler.support(this.syncConfig.syncType));
|
||||||
if (syncHandler) {
|
if (syncHandler) {
|
||||||
await syncHandler.sync(this.syncConfig, this.context);
|
await syncHandler.sync(this.syncConfig, this.context);
|
||||||
@ -53,6 +64,25 @@ export default class SyncHandler {
|
|||||||
const {syncStatus} = syncStatusHolder;
|
const {syncStatus} = syncStatusHolder;
|
||||||
const {statusHandleMap} = syncStatus;
|
const {statusHandleMap} = syncStatus;
|
||||||
const {syncResultMap} = syncStatus;
|
const {syncResultMap} = syncStatus;
|
||||||
|
const {syncConfig} = this;
|
||||||
|
|
||||||
|
let extendCondition = '';
|
||||||
|
if (syncConfig.syncConditionType == SyncConditionType.CUSTOM_ITEM) {
|
||||||
|
extendCondition = `${syncConfig.syncConditionCountFromValue} - ${syncConfig.syncConditionCountToValue}`;
|
||||||
|
} else if (syncConfig.syncConditionType == SyncConditionType.CUSTOM_TIME) {
|
||||||
|
extendCondition = `${syncConfig.syncConditionDateFromValue.toISOString().substring(0, 10)} - ${syncConfig.syncConditionDateToValue.toISOString().substring(0, 10)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const condition = `
|
||||||
|
1. ${i18nHelper.getMessage('110030')} \`${syncStatus.getTypeName()}\`
|
||||||
|
2. ${i18nHelper.getMessage('110032')} \`${syncStatus.getScopeName()}\`
|
||||||
|
3. ${i18nHelper.getMessage('110070')} \`${syncStatus.getSyncConditionName()}\`${extendCondition? (' => ' + extendCondition) : ''}
|
||||||
|
4. ${i18nHelper.getMessage('110039')} \`${syncConfig.incrementalUpdate?i18nHelper.getMessage('110055'):i18nHelper.getMessage('110056')}\`
|
||||||
|
5. ${i18nHelper.getMessage('110031')} \`${syncConfig.force?i18nHelper.getMessage('110055'):i18nHelper.getMessage('110056')}\`
|
||||||
|
`
|
||||||
|
|
||||||
|
|
||||||
let summary:string
|
let summary:string
|
||||||
= `${i18nHelper.getMessage('110053', i18nHelper.getMessage('110050'), i18nHelper.getMessage('110051'), i18nHelper.getMessage('110052'))}
|
= `${i18nHelper.getMessage('110053', i18nHelper.getMessage('110050'), i18nHelper.getMessage('110051'), i18nHelper.getMessage('110052'))}
|
||||||
|-----|----|----------------------------------|
|
|-----|----|----------------------------------|
|
||||||
@ -74,13 +104,33 @@ export default class SyncHandler {
|
|||||||
`;
|
`;
|
||||||
}else {
|
}else {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
details+= `${value.id}-[[${value.title}]]: ${i18nHelper.getMessage(value.status)}
|
details+= `${value.id}-[[${FileUtil.replaceSpecialCharactersForFileName(value.title)}]]: ${i18nHelper.getMessage(value.status)}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
const result : string = i18nHelper.getMessage('110037', summary, details);
|
const result : string = i18nHelper.getMessage('110037', condition, summary, details);
|
||||||
const resultFileName = `${i18nHelper.getMessage('110038')}_${moment(new Date()).format('YYYYMMDDHHmmss')}`
|
const resultFileName = `${i18nHelper.getMessage('110038')}_${moment(new Date()).format('YYYYMMDDHHmmss')}`
|
||||||
await this.plugin.fileHandler.createNewNoteWithData(`${this.syncConfig.dataFilePath}/${resultFileName}`, result, true);
|
await this.plugin.fileHandler.createNewNoteWithData(`${this.syncConfig.dataFilePath}/${resultFileName}`, result, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private checkSyncConfig() {
|
||||||
|
const {syncConfig} = this;
|
||||||
|
switch (syncConfig.syncConditionType) {
|
||||||
|
case SyncConditionType.CUSTOM_ITEM:
|
||||||
|
if (syncConfig.syncConditionCountFromValue && syncConfig.syncConditionCountToValue) {
|
||||||
|
if (syncConfig.syncConditionCountFromValue > syncConfig.syncConditionCountToValue) {
|
||||||
|
return i18nHelper.getMessage('110044');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SyncConditionType.CUSTOM_TIME:
|
||||||
|
if (syncConfig.syncConditionDateToValue && syncConfig.syncConditionDateFromValue) {
|
||||||
|
if (syncConfig.syncConditionDateFromValue > syncConfig.syncConditionDateToValue) {
|
||||||
|
return i18nHelper.getMessage('110045');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,88 +1,124 @@
|
|||||||
import { request, RequestUrlParam} from "obsidian";
|
import { request, RequestUrlParam } from "obsidian";
|
||||||
import {i18nHelper} from 'src/org/wanxp/lang/helper';
|
import { i18nHelper } from "src/org/wanxp/lang/helper";
|
||||||
import {log} from "src/org/wanxp/utils/Logutil";
|
import { log } from "src/org/wanxp/utils/Logutil";
|
||||||
import {CheerioAPI, load} from "cheerio";
|
import { CheerioAPI, load } from "cheerio";
|
||||||
import HandleContext from "../../../data/model/HandleContext";
|
import HandleContext from "../../../data/model/HandleContext";
|
||||||
import {doubanSubjectSyncListUrl} from "../../../../constant/Douban";
|
import { doubanSubjectSyncListUrl } from "../../../../constant/Douban";
|
||||||
import {BasicConst, PAGE_SIZE, SyncType, SyncTypeUrlDomain} from "../../../../constant/Constsant";
|
import {
|
||||||
import {SubjectListItem} from "../../../data/model/SubjectListItem";
|
BasicConst,
|
||||||
import {DoubanListHandler} from "./DoubanListHandler";
|
PAGE_SIZE,
|
||||||
import {SyncConfig} from "../../model/SyncConfig";
|
SyncType,
|
||||||
import { sleepRange} from "../../../../utils/TimeUtil";
|
SyncTypeUrlDomain,
|
||||||
import {ALL} from "../../../../constant/DoubanUserState";
|
} from "../../../../constant/Constsant";
|
||||||
|
import { SubjectListItem } from "../../../data/model/SubjectListItem";
|
||||||
|
import { DoubanListHandler } from "./DoubanListHandler";
|
||||||
|
import { SyncConfig } from "../../model/SyncConfig";
|
||||||
|
import { sleepRange } from "../../../../utils/TimeUtil";
|
||||||
|
import { ALL } from "../../../../constant/DoubanUserState";
|
||||||
import HttpUtil from "../../../../utils/HttpUtil";
|
import HttpUtil from "../../../../utils/HttpUtil";
|
||||||
import {DoubanHttpUtil} from "../../../../utils/DoubanHttpUtil";
|
import { DoubanHttpUtil } from "../../../../utils/DoubanHttpUtil";
|
||||||
|
import { SearchPage } from "../../../data/model/SearchPage";
|
||||||
|
import {SearchPageTypeOf} from "../../../data/model/SearchPageTypeOf";
|
||||||
|
|
||||||
export default abstract class DoubanAbstractListHandler implements DoubanListHandler{
|
export default abstract class DoubanAbstractListHandler
|
||||||
|
implements DoubanListHandler
|
||||||
|
{
|
||||||
|
async getPageData(context: HandleContext): Promise<SearchPage> {
|
||||||
|
let all: SubjectListItem[] = [];
|
||||||
|
let pages: SearchPage = SearchPage.emptyWithNoType();
|
||||||
|
|
||||||
async getAllPageList(context: HandleContext):Promise<SubjectListItem[]>{
|
const url: string = this.getUrl(context, context.syncOffset);
|
||||||
let all:SubjectListItem[] = [];
|
if (!context.plugin.statusHolder.syncing()) {
|
||||||
let pages:SubjectListItem[] = [];
|
return SearchPage.emptyWithNoType();
|
||||||
let start = 0;
|
}
|
||||||
do {
|
let subjectListItemSearchPageTypeOf = await this.getPageList(url, context);
|
||||||
await sleepRange(BasicConst.CALL_DOUBAN_DELAY,
|
if (subjectListItemSearchPageTypeOf) {
|
||||||
BasicConst.CALL_DOUBAN_DELAY + BasicConst.CALL_DOUBAN_DELAY_RANGE);
|
context.plugin.statusHolder.syncStatus.setAllTotal(subjectListItemSearchPageTypeOf.total)
|
||||||
const url:string = this.getUrl(context, start);
|
}
|
||||||
if (!context.plugin.statusHolder.syncing()) {
|
return subjectListItemSearchPageTypeOf;
|
||||||
return [];
|
|
||||||
}
|
|
||||||
pages = await this.getPageList(url, context);
|
|
||||||
if (pages) {
|
|
||||||
all = all.concat(pages);
|
|
||||||
}
|
|
||||||
start = start + PAGE_SIZE;
|
|
||||||
} while (pages && pages.length > 0)
|
|
||||||
return all;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async delay(ms: number) {
|
async delay(ms: number) {}
|
||||||
|
|
||||||
|
protected getUrl(context: HandleContext, start: number) {
|
||||||
|
return doubanSubjectSyncListUrl(
|
||||||
|
this.getSyncTypeDomain(),
|
||||||
|
context.userComponent.getUserId(),
|
||||||
|
this.getDoType(),
|
||||||
|
start,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getUrl(context: HandleContext, start:number) {
|
abstract getDoType(): string;
|
||||||
return doubanSubjectSyncListUrl(this.getSyncTypeDomain(), context.userComponent.getUserId(), this.getDoType(), start);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract getDoType():string;
|
abstract getSyncType(): SyncType;
|
||||||
|
|
||||||
abstract getSyncType():SyncType;
|
getSyncTypeDomain(): string {
|
||||||
|
|
||||||
getSyncTypeDomain():string {
|
|
||||||
return SyncTypeUrlDomain.get(this.getSyncType());
|
return SyncTypeUrlDomain.get(this.getSyncType());
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPageList(url: string, context: HandleContext):Promise<SubjectListItem[]> {
|
async getPageList(
|
||||||
return DoubanHttpUtil.httpRequestGet(url, context.plugin.settingsManager.getHeaders(), context.plugin.settingsManager)
|
url: string,
|
||||||
|
context: HandleContext,
|
||||||
|
): Promise<SearchPageTypeOf<SubjectListItem>> {
|
||||||
|
return DoubanHttpUtil.httpRequestGet(
|
||||||
|
url,
|
||||||
|
context.plugin.settingsManager.getHeaders(),
|
||||||
|
context.plugin.settingsManager,
|
||||||
|
)
|
||||||
.then(load)
|
.then(load)
|
||||||
.then(data => this.parseSubjectFromHtml(data, context))
|
.then((data) => this.parseSubjectFromHtml(data, context))
|
||||||
.catch(e => log
|
.catch((e) =>
|
||||||
.error(
|
log.error(
|
||||||
i18nHelper.getMessage('130101')
|
i18nHelper
|
||||||
.replace('{0}', e.toString())
|
.getMessage("130101")
|
||||||
, e));
|
.replace("{0}", e.toString()),
|
||||||
;
|
e,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parseSubjectFromHtml(
|
||||||
|
dataHtml: CheerioAPI,
|
||||||
|
context: HandleContext,
|
||||||
|
): SearchPageTypeOf<SubjectListItem> {
|
||||||
parseSubjectFromHtml(dataHtml: CheerioAPI, context: HandleContext):SubjectListItem[] {
|
const items = dataHtml(".item-show")
|
||||||
return dataHtml('.item-show')
|
|
||||||
.get()
|
.get()
|
||||||
.map((i: any) => {
|
.map((i: any) => {
|
||||||
const item = dataHtml(i);
|
const item = dataHtml(i);
|
||||||
const linkValue:string = item.find('div.title > a').attr('href');
|
const linkValue: string = item
|
||||||
const titleValue:string = item.find('div.title > a').text().trim();
|
.find("div.title > a")
|
||||||
|
.attr("href");
|
||||||
|
const titleValue: string = item
|
||||||
|
.find("div.title > a")
|
||||||
|
.text()
|
||||||
|
.trim();
|
||||||
|
const updateDateStr: string = item.find("div.date").text().trim();
|
||||||
|
let updateDate = null;
|
||||||
|
try {
|
||||||
|
updateDate = new Date(updateDateStr);
|
||||||
|
}catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
log.info("parse date error:" + titleValue);
|
||||||
|
}
|
||||||
let idPattern = /(\d){5,10}/g;
|
let idPattern = /(\d){5,10}/g;
|
||||||
let ececResult = idPattern.exec(linkValue);
|
let ececResult = idPattern.exec(linkValue);
|
||||||
return ececResult?{id: ececResult[0], url: linkValue, title: titleValue}:null;
|
return !ececResult ? null : {id: ececResult[0], url: linkValue, title: titleValue, updateDate: updateDate};
|
||||||
// return linkValue;
|
// return linkValue;
|
||||||
})
|
});
|
||||||
|
const subjectNumText = dataHtml(".subject-num").text().trim();
|
||||||
|
const totalNumMatch = subjectNumText.match(/\/\s*(\d+)/);
|
||||||
|
const totalNum = totalNumMatch ? parseInt(totalNumMatch[1], 10) : 0;
|
||||||
|
return new SearchPage(
|
||||||
|
totalNum,
|
||||||
|
Math.floor(context.syncOffset / PAGE_SIZE) + 1,
|
||||||
|
PAGE_SIZE,
|
||||||
|
null,
|
||||||
|
items,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
support(config: SyncConfig): boolean {
|
support(config: SyncConfig): boolean {
|
||||||
return this.getDoType() == config.scope || ALL == config.scope;
|
return this.getDoType() == config.scope || ALL == config.scope;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { DoubanSubjectState} from "src/org/wanxp/constant/DoubanUserState";
|
||||||
|
import { DoubanMovieListHandler } from "./DoubanMovieListHandler";
|
||||||
|
import {DoubanGameListHandler} from "./DoubanGameListHandler";
|
||||||
|
|
||||||
|
|
||||||
|
export default class DoubanGameCollectListHandler extends DoubanGameListHandler{
|
||||||
|
getDoType(): string {
|
||||||
|
return DoubanSubjectState.collect;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { DoubanSubjectState} from "src/org/wanxp/constant/DoubanUserState";
|
||||||
|
import { DoubanMovieListHandler } from "./DoubanMovieListHandler";
|
||||||
|
import {DoubanGameListHandler} from "./DoubanGameListHandler";
|
||||||
|
|
||||||
|
|
||||||
|
export default class DoubanGameDoListHandler extends DoubanGameListHandler{
|
||||||
|
getDoType(): string {
|
||||||
|
return DoubanSubjectState.do;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
105
src/org/wanxp/douban/sync/handler/list/DoubanGameListHandler.ts
Normal file
105
src/org/wanxp/douban/sync/handler/list/DoubanGameListHandler.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import DoubanAbstractListHandler from "./DoubanAbstractListHandler";
|
||||||
|
import {PAGE_SIZE, SubjectHandledStatus, SyncType} from "../../../../constant/Constsant";
|
||||||
|
import {CheerioAPI} from "cheerio";
|
||||||
|
import HandleContext from "../../../data/model/HandleContext";
|
||||||
|
import {SearchPageTypeOf} from "../../../data/model/SearchPageTypeOf";
|
||||||
|
import {SubjectListItem} from "../../../data/model/SubjectListItem";
|
||||||
|
import {log} from "../../../../utils/Logutil";
|
||||||
|
import {SearchPage} from "../../../data/model/SearchPage";
|
||||||
|
import {doubanGameSubjectSyncListUrl, doubanSubjectSyncListUrl} from "../../../../constant/Douban";
|
||||||
|
import {ALL, DoubanSubjectState} from "../../../../constant/DoubanUserState";
|
||||||
|
|
||||||
|
export abstract class DoubanGameListHandler extends DoubanAbstractListHandler {
|
||||||
|
getSyncType(): SyncType {
|
||||||
|
return SyncType.game;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract getDoType(): string;
|
||||||
|
|
||||||
|
protected getUrl(context: HandleContext, start: number) {
|
||||||
|
return doubanGameSubjectSyncListUrl(
|
||||||
|
this.getSyncTypeDomain(),
|
||||||
|
context.userComponent.getUserId(),
|
||||||
|
this.getDoType(),
|
||||||
|
start,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseSubjectFromHtml(
|
||||||
|
dataHtml: CheerioAPI,
|
||||||
|
context: HandleContext,
|
||||||
|
): SearchPageTypeOf<SubjectListItem> {
|
||||||
|
const items = dataHtml(".common-item")
|
||||||
|
.get()
|
||||||
|
.map((i: any) => {
|
||||||
|
const item = dataHtml(i);
|
||||||
|
const linkValue: string = item
|
||||||
|
.find("div.title > a")
|
||||||
|
.attr("href");
|
||||||
|
const titleValue: string = item
|
||||||
|
.find("div.title > a")
|
||||||
|
.text()
|
||||||
|
.trim();
|
||||||
|
const updateDateStr: string = item.find("span.date").text().trim();
|
||||||
|
let updateDate = null;
|
||||||
|
try {
|
||||||
|
updateDate = new Date(updateDateStr);
|
||||||
|
}catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
log.info("parse date error:" + titleValue);
|
||||||
|
}
|
||||||
|
let idPattern = /(\d){5,10}/g;
|
||||||
|
let ececResult = idPattern.exec(linkValue);
|
||||||
|
return !ececResult ? null : {id: ececResult[0], url: linkValue, title: titleValue, updateDate: updateDate};
|
||||||
|
// return linkValue;
|
||||||
|
});
|
||||||
|
const total = this.getTotal(dataHtml, context);
|
||||||
|
return new SearchPage(
|
||||||
|
total,
|
||||||
|
Math.floor(context.syncOffset / PAGE_SIZE) + 1,
|
||||||
|
PAGE_SIZE,
|
||||||
|
null,
|
||||||
|
items,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTotal(dataHtml: CheerioAPI,
|
||||||
|
context: HandleContext):number {
|
||||||
|
const countDescs = dataHtml("div.tabs > a")
|
||||||
|
.get()
|
||||||
|
.map((i: any) => {
|
||||||
|
const item = dataHtml(i);
|
||||||
|
return item.text().trim();
|
||||||
|
});
|
||||||
|
const {syncConfig} = context;
|
||||||
|
const {scope} = syncConfig;
|
||||||
|
|
||||||
|
const wishCount = this.getCount(countDescs, '想玩');
|
||||||
|
const collectCount = this.getCount(countDescs, '玩过');
|
||||||
|
const doCount = this.getCount(countDescs, '在玩');
|
||||||
|
|
||||||
|
|
||||||
|
switch (scope) {
|
||||||
|
case DoubanSubjectState.wish:
|
||||||
|
return wishCount;
|
||||||
|
case DoubanSubjectState.collect:
|
||||||
|
return collectCount;
|
||||||
|
case DoubanSubjectState.do:
|
||||||
|
return doCount;
|
||||||
|
case ALL:
|
||||||
|
return wishCount + collectCount + doCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCount(countDescs:string[], keyword:string):number {
|
||||||
|
return countDescs.filter(desc => desc.includes(keyword)).map(desc => {
|
||||||
|
const pattern = /(\d+)/g;
|
||||||
|
const result = pattern.exec(desc);
|
||||||
|
return result ? parseInt(result[0], 10) : 0;
|
||||||
|
})[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user