mirror of
https://github.com/Wanxp/obsidian-douban.git
synced 2026-04-04 00:28:43 +08:00
add search douban in suggestion
This commit is contained in:
parent
89d363ebcf
commit
c3fb407215
@ -1,2 +1,2 @@
|
||||
npm node_modules
|
||||
npm node_modules
|
||||
build
|
||||
44
.eslintrc
44
.eslintrc
@ -1,23 +1,23 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": { "node": true },
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off"
|
||||
}
|
||||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": { "node": true },
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off"
|
||||
}
|
||||
}
|
||||
146
README.md
146
README.md
@ -1,73 +1,73 @@
|
||||
# Obsidian Sample Plugin
|
||||
|
||||
This is a sample plugin for Obsidian (https://obsidian.md).
|
||||
|
||||
This project uses Typescript to provide type checking and documentation.
|
||||
The repo depends on the latest plugin API (obsidian.d.ts) in Typescript Definition format, which contains TSDoc comments describing what it does.
|
||||
|
||||
**Note:** The Obsidian API is still in early alpha and is subject to change at any time!
|
||||
|
||||
This sample plugin demonstrates some of the basic functionality the plugin API can do.
|
||||
- Changes the default font color to red using `styles.css`.
|
||||
- Adds a ribbon icon, which shows a Notice when clicked.
|
||||
- Adds a command "Open Sample Modal" which opens a Modal.
|
||||
- Adds a plugin setting tab to the settings page.
|
||||
- Registers a global click event and output 'click' to the console.
|
||||
- Registers a global interval which logs 'setInterval' to the console.
|
||||
|
||||
## First time developing plugins?
|
||||
|
||||
Quick starting guide for new plugin devs:
|
||||
|
||||
- Check if [someone already developed a plugin for what you want](https://obsidian.md/plugins)! There might be an existing plugin similar enough that you can partner up with.
|
||||
- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it).
|
||||
- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder.
|
||||
- Install NodeJS, then run `npm i` in the command line under your repo folder.
|
||||
- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`.
|
||||
- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`.
|
||||
- Reload Obsidian to load the new version of your plugin.
|
||||
- Enable plugin in settings window.
|
||||
- For updates to the Obsidian API run `npm update` in the command line under your repo folder.
|
||||
|
||||
## Releasing new releases
|
||||
|
||||
- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release.
|
||||
- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible.
|
||||
- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases
|
||||
- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments. Note: The manifest.json file must be in two places, first the root path of your repository and also in the release.
|
||||
- Publish the release.
|
||||
|
||||
> You can simplify the version bump process by running `npm version patch`, `npm version minor` or `npm version major` after updating `minAppVersion` manually in `manifest.json`.
|
||||
> The command will bump version in `manifest.json` and `package.json`, and add the entry for the new version to `versions.json`
|
||||
|
||||
## Adding your plugin to the community plugin list
|
||||
|
||||
- Check https://github.com/obsidianmd/obsidian-releases/blob/master/plugin-review.md
|
||||
- Publish an initial version.
|
||||
- Make sure you have a `README.md` file in the root of your repo.
|
||||
- Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin.
|
||||
|
||||
## How to use
|
||||
|
||||
- Clone this repo.
|
||||
- `npm i` or `yarn` to install dependencies
|
||||
- `npm run dev` to start compilation in watch mode.
|
||||
|
||||
## Manually installing the plugin
|
||||
|
||||
- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`.
|
||||
|
||||
## Improve code quality with eslint (optional)
|
||||
- [ESLint](https://eslint.org/) is a tool that analyzes your code to quickly find problems. You can run ESLint against your plugin to find common bugs and ways to improve your code.
|
||||
- To use eslint with this project, make sure to install eslint from terminal:
|
||||
- `npm install -g eslint`
|
||||
- To use eslint to analyze this project use this command:
|
||||
- `eslint main.ts`
|
||||
- eslint will then create a report with suggestions for code improvement by file and line number.
|
||||
- If your source code is in a folder, such as `src`, you can use eslint with this command to analyze all files in that folder:
|
||||
- `eslint .\src\`
|
||||
|
||||
|
||||
## API Documentation
|
||||
|
||||
See https://github.com/obsidianmd/obsidian-api
|
||||
# Obsidian Sample Plugin
|
||||
|
||||
This is a sample plugin for Obsidian (https://obsidian.md).
|
||||
|
||||
This project uses Typescript to provide type checking and documentation.
|
||||
The repo depends on the latest plugin API (obsidian.d.ts) in Typescript Definition format, which contains TSDoc comments describing what it does.
|
||||
|
||||
**Note:** The Obsidian API is still in early alpha and is subject to change at any time!
|
||||
|
||||
This sample plugin demonstrates some of the basic functionality the plugin API can do.
|
||||
- Changes the default font color to red using `styles.css`.
|
||||
- Adds a ribbon icon, which shows a Notice when clicked.
|
||||
- Adds a command "Open Sample Modal" which opens a Modal.
|
||||
- Adds a plugin setting tab to the settings page.
|
||||
- Registers a global click event and output 'click' to the console.
|
||||
- Registers a global interval which logs 'setInterval' to the console.
|
||||
|
||||
## First time developing plugins?
|
||||
|
||||
Quick starting guide for new plugin devs:
|
||||
|
||||
- Check if [someone already developed a plugin for what you want](https://obsidian.md/plugins)! There might be an existing plugin similar enough that you can partner up with.
|
||||
- Make a copy of this repo as a template with the "Use this template" button (login to GitHub if you don't see it).
|
||||
- Clone your repo to a local development folder. For convenience, you can place this folder in your `.obsidian/plugins/your-plugin-name` folder.
|
||||
- Install NodeJS, then run `npm i` in the command line under your repo folder.
|
||||
- Run `npm run dev` to compile your plugin from `main.ts` to `main.js`.
|
||||
- Make changes to `main.ts` (or create new `.ts` files). Those changes should be automatically compiled into `main.js`.
|
||||
- Reload Obsidian to load the new version of your plugin.
|
||||
- Enable plugin in settings window.
|
||||
- For updates to the Obsidian API run `npm update` in the command line under your repo folder.
|
||||
|
||||
## Releasing new releases
|
||||
|
||||
- Update your `manifest.json` with your new version number, such as `1.0.1`, and the minimum Obsidian version required for your latest release.
|
||||
- Update your `versions.json` file with `"new-plugin-version": "minimum-obsidian-version"` so older versions of Obsidian can download an older version of your plugin that's compatible.
|
||||
- Create new GitHub release using your new version number as the "Tag version". Use the exact version number, don't include a prefix `v`. See here for an example: https://github.com/obsidianmd/obsidian-sample-plugin/releases
|
||||
- Upload the files `manifest.json`, `main.js`, `styles.css` as binary attachments. Note: The manifest.json file must be in two places, first the root path of your repository and also in the release.
|
||||
- Publish the release.
|
||||
|
||||
> You can simplify the version bump process by running `npm version patch`, `npm version minor` or `npm version major` after updating `minAppVersion` manually in `manifest.json`.
|
||||
> The command will bump version in `manifest.json` and `package.json`, and add the entry for the new version to `versions.json`
|
||||
|
||||
## Adding your plugin to the community plugin list
|
||||
|
||||
- Check https://github.com/obsidianmd/obsidian-releases/blob/master/plugin-review.md
|
||||
- Publish an initial version.
|
||||
- Make sure you have a `README.md` file in the root of your repo.
|
||||
- Make a pull request at https://github.com/obsidianmd/obsidian-releases to add your plugin.
|
||||
|
||||
## How to use
|
||||
|
||||
- Clone this repo.
|
||||
- `npm i` or `yarn` to install dependencies
|
||||
- `npm run dev` to start compilation in watch mode.
|
||||
|
||||
## Manually installing the plugin
|
||||
|
||||
- Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/your-plugin-id/`.
|
||||
|
||||
## Improve code quality with eslint (optional)
|
||||
- [ESLint](https://eslint.org/) is a tool that analyzes your code to quickly find problems. You can run ESLint against your plugin to find common bugs and ways to improve your code.
|
||||
- To use eslint with this project, make sure to install eslint from terminal:
|
||||
- `npm install -g eslint`
|
||||
- To use eslint to analyze this project use this command:
|
||||
- `eslint main.ts`
|
||||
- eslint will then create a report with suggestions for code improvement by file and line number.
|
||||
- If your source code is in a folder, such as `src`, you can use eslint with this command to analyze all files in that folder:
|
||||
- `eslint .\src\`
|
||||
|
||||
|
||||
## API Documentation
|
||||
|
||||
See https://github.com/obsidianmd/obsidian-api
|
||||
|
||||
37
douban/Douban.ts
Normal file
37
douban/Douban.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { type } from "os";
|
||||
|
||||
interface DoubanPluginSettings {
|
||||
template:string,
|
||||
searchUrl:string,
|
||||
searchHeaders?:string
|
||||
}
|
||||
|
||||
export interface DoubanExtract {
|
||||
id: string,
|
||||
type: string;
|
||||
title: string;
|
||||
desc: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
|
||||
export const doubanHeadrs = {
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
||||
"Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
|
||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.61 Safari/537.36",
|
||||
};
|
||||
|
||||
export const DEFAULT_SETTINGS:DoubanPluginSettings = {
|
||||
template:
|
||||
"---\n" +
|
||||
"title: {{title}}" +
|
||||
"cast: {{cast}}" +
|
||||
"score: {{score}}" +
|
||||
"---",
|
||||
searchUrl: 'https://www.douban.com/search?q=',
|
||||
searchHeaders: JSON.stringify(doubanHeadrs)
|
||||
|
||||
}
|
||||
|
||||
|
||||
export type {DoubanPluginSettings}
|
||||
69
douban/DoubanSearchModal.ts
Normal file
69
douban/DoubanSearchModal.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { App, Editor, Modal, TextComponent } from "obsidian";
|
||||
import { log } from "utils/logutil";
|
||||
import DoubanPlugin from "../main";
|
||||
|
||||
export class DoubanSearchModal extends Modal {
|
||||
searchTerm: string;
|
||||
plugin: DoubanPlugin;
|
||||
editor: Editor;
|
||||
|
||||
constructor(app: App, plugin: DoubanPlugin, editor: Editor) {
|
||||
super(app);
|
||||
this.plugin = plugin;
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
let { contentEl } = this;
|
||||
|
||||
contentEl.createEl("h2", { text: "Enter Search Term:" });
|
||||
|
||||
const inputs = contentEl.createDiv("inputs");
|
||||
const searchInput = new TextComponent(inputs).onChange((searchTerm) => {
|
||||
this.searchTerm = searchTerm;
|
||||
});
|
||||
searchInput.inputEl.focus();
|
||||
searchInput.inputEl.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Enter") {
|
||||
this.search();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
const controls = contentEl.createDiv("controls");
|
||||
const searchButton = controls.createEl("button", {
|
||||
text: "Search",
|
||||
cls: "mod-cta",
|
||||
attr: {
|
||||
autofocus: true,
|
||||
},
|
||||
});
|
||||
searchButton.addEventListener("click", this.close.bind(this));
|
||||
const cancelButton = controls.createEl("button", { text: "Cancel" });
|
||||
cancelButton.addEventListener("click", this.close.bind(this));
|
||||
}
|
||||
async search() {
|
||||
log.info("start search :" + this.searchTerm);
|
||||
let { contentEl } = this;
|
||||
contentEl.empty();
|
||||
if (this.searchTerm) {
|
||||
this.close();
|
||||
await this.plugin.search(this.searchTerm);
|
||||
// await this.plugin.pasteIntoEditor(this.editor, null);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
async onClose() {
|
||||
let { contentEl } = this;
|
||||
|
||||
contentEl.empty();
|
||||
if (this.searchTerm) {
|
||||
// await this.plugin.pasteIntoEditor(this.editor, this.searchTerm);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
59
douban/DoubanSettingTab.ts
Normal file
59
douban/DoubanSettingTab.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import DoubanPlugin from "main";
|
||||
import { App, PluginSettingTab, Setting } from "obsidian";
|
||||
|
||||
export class DoubanSettingTab extends PluginSettingTab {
|
||||
plugin: DoubanPlugin;
|
||||
|
||||
constructor(app: App, plugin: DoubanPlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
display(): void {
|
||||
let { containerEl } = this;
|
||||
|
||||
containerEl.empty();
|
||||
|
||||
containerEl.createEl("h2", { text: "Obsidian Wikipedia" });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Douban Search Url")
|
||||
.setDesc(`full search url with https ahead `)
|
||||
.addText((textField) => {
|
||||
textField
|
||||
.setValue(this.plugin.settings.searchUrl)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.searchUrl = value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Douban Request Headers")
|
||||
.setDesc(`full search url with https ahead `)
|
||||
.addText((textField) => {
|
||||
textField
|
||||
.setValue(this.plugin.settings.searchHeaders)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.searchHeaders = value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Content Template")
|
||||
.setDesc(
|
||||
`Set markdown template for extract to be inserted.\n
|
||||
Available template variables are {{id}}, {{type}}, {{title}}, {{score}}, {{cast}}, {{desc}} and {{url}}.
|
||||
`
|
||||
)
|
||||
.addTextArea((textarea) =>
|
||||
textarea
|
||||
.setValue(this.plugin.settings.template)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.template = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
13
douban/ResponseHandle.ts
Normal file
13
douban/ResponseHandle.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Notice } from "obsidian";
|
||||
|
||||
export const ensureStatusCode = (expected:any) => {
|
||||
if (!Array.isArray(expected))
|
||||
expected = [expected];
|
||||
return (res:any) => {
|
||||
const { statusCode } = res;
|
||||
if(!expected.includes(statusCode)) {
|
||||
new Notice(`Request Douban failed, Status code must be "${expected}" but actually "${statusCode}"`)
|
||||
}
|
||||
return res;
|
||||
};
|
||||
};
|
||||
54
douban/movie/Movie.ts
Normal file
54
douban/movie/Movie.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import cheerio from 'cheerio';
|
||||
import { DoubanExtract, doubanHeadrs } from 'douban/Douban';
|
||||
import { get, readStream } from 'tiny-network';
|
||||
import { ensureStatusCode } from 'douban/ResponseHandle';
|
||||
|
||||
|
||||
interface DoubanMovieExtract extends DoubanExtract {
|
||||
|
||||
}
|
||||
|
||||
export const playing = (city:string) => {
|
||||
return Promise
|
||||
.resolve()
|
||||
.then(() => get(`https://movie.douban.com/cinema/nowplaying/${city}/`))
|
||||
.then(ensureStatusCode(200))
|
||||
.then(readStream)
|
||||
.then(cheerio.load)
|
||||
.then(parsePlaying)
|
||||
};
|
||||
|
||||
|
||||
export const parsePlaying = (dataHtml:any) => {
|
||||
return dataHtml('.list-item')
|
||||
.get()
|
||||
.map((i:any) => {
|
||||
const item = dataHtml(i);
|
||||
console.log("version 5");
|
||||
const result = {
|
||||
id: item.attr('id'),
|
||||
title: item.attr('data-title'),
|
||||
score: item.attr('data-score'),
|
||||
duration: item.attr('data-duration'),
|
||||
region: item.attr('data-region'),
|
||||
director: item.attr('data-director'),
|
||||
actors: item.attr('data-actors'),
|
||||
poster: item.find('.poster img').attr('src'),
|
||||
link: `https://movie.douban.com/subject/${item.attr('id')}`,
|
||||
};
|
||||
// console.log("content is " + JSON.stringify(result));
|
||||
|
||||
return result;
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
50
douban/search/DoubanSearchFuzzySuggestModal.ts
Normal file
50
douban/search/DoubanSearchFuzzySuggestModal.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import DoubanPlugin from "main";
|
||||
import { FuzzySuggestModal,App } from "obsidian";
|
||||
import { log } from "utils/logutil";
|
||||
import { DoubanSearchResultExtract } from "./SearchParser";
|
||||
|
||||
|
||||
export {DoubanFuzzySuggester}
|
||||
|
||||
|
||||
class DoubanFuzzySuggester extends FuzzySuggestModal<DoubanSearchResultExtract> {
|
||||
|
||||
public app: App;
|
||||
private plugin: DoubanPlugin;
|
||||
private doubanSearchResultExtract:DoubanSearchResultExtract[]
|
||||
|
||||
constructor(app: App, plugin: DoubanPlugin) {
|
||||
super(app);
|
||||
this.app = app;
|
||||
this.plugin = plugin;
|
||||
this.setPlaceholder("Choose an item...");
|
||||
}
|
||||
|
||||
getItems(): DoubanSearchResultExtract[] {
|
||||
return this.doubanSearchResultExtract;
|
||||
}
|
||||
|
||||
getItemText(item: DoubanSearchResultExtract): string {
|
||||
let text:string = item.type + ":" + item.title + " [score]:" + item.score + ",[cast]:" + item.cast;
|
||||
return text;
|
||||
}
|
||||
|
||||
onChooseItem(item: DoubanSearchResultExtract, evt: MouseEvent | KeyboardEvent): void {
|
||||
log.warn("choose item " + item.title + " id " + item.id);
|
||||
}
|
||||
|
||||
public showSearchList(doubanSearchResultExtractList:DoubanSearchResultExtract[]) {
|
||||
this.doubanSearchResultExtract = doubanSearchResultExtractList;
|
||||
log.info("show search result" );
|
||||
this.start();
|
||||
}
|
||||
|
||||
public start(): void {
|
||||
try {
|
||||
this.open();
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
24
douban/search/Search.ts
Normal file
24
douban/search/Search.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import cheerio from 'cheerio';
|
||||
import { doubanHeadrs, DoubanPluginSettings } from 'douban/Douban';
|
||||
import { get, readStream } from 'tiny-network';
|
||||
import { ensureStatusCode } from 'douban/ResponseHandle';
|
||||
import { DoubanSearchResultExtract, SearchParserHandler } from './SearchParser';
|
||||
import { log } from 'utils/logutil';
|
||||
|
||||
class Searcher {
|
||||
static search(searchItem:string, doubanSettings:DoubanPluginSettings):Promise<DoubanSearchResultExtract[]> {
|
||||
// getData();
|
||||
// getData2();
|
||||
// return Promise.resolve();
|
||||
return Promise
|
||||
.resolve()
|
||||
.then(() => get(doubanSettings.searchUrl + searchItem, JSON.parse(doubanSettings.searchHeaders)))
|
||||
.then(ensureStatusCode(200))
|
||||
.then(readStream)
|
||||
.then(log.info)
|
||||
.then(cheerio.load)
|
||||
.then(SearchParserHandler.parseSearch);
|
||||
};
|
||||
}
|
||||
|
||||
export {Searcher}
|
||||
43
douban/search/SearchParser.ts
Normal file
43
douban/search/SearchParser.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { CheerioAPI } from "cheerio";
|
||||
import { DoubanExtract } from "douban/Douban";
|
||||
import { type } from "os";
|
||||
|
||||
interface DoubanSearchResultExtract extends DoubanExtract{
|
||||
cast: string;
|
||||
score: string;
|
||||
}
|
||||
|
||||
|
||||
class SearchParserHandler {
|
||||
static parseSearch(dataHtml:CheerioAPI):DoubanSearchResultExtract[] {
|
||||
return dataHtml('.result')
|
||||
.get()
|
||||
.map((i:any) => {
|
||||
const item = dataHtml(i);
|
||||
var idPattern = /(\d){5,10}/g;
|
||||
var urlPattern = /(https%3A%2F%2F)\S+(\d){5,10}/g;
|
||||
var linkValue = item.find("div.content > div > h3 > a").text();
|
||||
var ececResult = idPattern.exec(linkValue);
|
||||
var urlResult = urlPattern.exec(linkValue);
|
||||
var cast = item.find(".subject-cast").text();
|
||||
const result:DoubanSearchResultExtract = {
|
||||
id: ececResult?ececResult[0]:'',
|
||||
title: item.find("div.content > div > h3 > a").text(),
|
||||
score: item.find(".rating_nums").text(),
|
||||
// duration: item.attr('data-duration'),
|
||||
// region: item.attr('data-region'),
|
||||
// director: item.attr('data-director'),
|
||||
// actors: item.attr('data-actors'),
|
||||
// poster: item.find('.poster img').attr('src'),
|
||||
cast: cast,
|
||||
type: item.find("div.content > div > h3 > span").text(),
|
||||
desc: item.find("div.content > p").text(),
|
||||
url: urlResult?decodeURIComponent(urlResult[0]):'https://www.douban.com',
|
||||
};
|
||||
return result;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
export {SearchParserHandler}
|
||||
export type {DoubanSearchResultExtract}
|
||||
@ -1,52 +1,52 @@
|
||||
import esbuild from "esbuild";
|
||||
import process from "process";
|
||||
import builtins from 'builtin-modules'
|
||||
|
||||
const banner =
|
||||
`/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
`;
|
||||
|
||||
const prod = (process.argv[2] === 'production');
|
||||
|
||||
esbuild.build({
|
||||
banner: {
|
||||
js: banner,
|
||||
},
|
||||
entryPoints: ['main.ts'],
|
||||
bundle: true,
|
||||
external: [
|
||||
'obsidian',
|
||||
'electron',
|
||||
'@codemirror/autocomplete',
|
||||
'@codemirror/closebrackets',
|
||||
'@codemirror/collab',
|
||||
'@codemirror/commands',
|
||||
'@codemirror/comment',
|
||||
'@codemirror/fold',
|
||||
'@codemirror/gutter',
|
||||
'@codemirror/highlight',
|
||||
'@codemirror/history',
|
||||
'@codemirror/language',
|
||||
'@codemirror/lint',
|
||||
'@codemirror/matchbrackets',
|
||||
'@codemirror/panel',
|
||||
'@codemirror/rangeset',
|
||||
'@codemirror/rectangular-selection',
|
||||
'@codemirror/search',
|
||||
'@codemirror/state',
|
||||
'@codemirror/stream-parser',
|
||||
'@codemirror/text',
|
||||
'@codemirror/tooltip',
|
||||
'@codemirror/view',
|
||||
...builtins],
|
||||
format: 'cjs',
|
||||
watch: !prod,
|
||||
target: 'es2016',
|
||||
logLevel: "info",
|
||||
sourcemap: prod ? false : 'inline',
|
||||
treeShaking: true,
|
||||
outfile: 'main.js',
|
||||
}).catch(() => process.exit(1));
|
||||
import esbuild from "esbuild";
|
||||
import process from "process";
|
||||
import builtins from 'builtin-modules'
|
||||
|
||||
const banner =
|
||||
`/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
`;
|
||||
|
||||
const prod = (process.argv[2] === 'production');
|
||||
|
||||
esbuild.build({
|
||||
banner: {
|
||||
js: banner,
|
||||
},
|
||||
entryPoints: ['main.ts'],
|
||||
bundle: true,
|
||||
external: [
|
||||
'obsidian',
|
||||
'electron',
|
||||
'@codemirror/autocomplete',
|
||||
'@codemirror/closebrackets',
|
||||
'@codemirror/collab',
|
||||
'@codemirror/commands',
|
||||
'@codemirror/comment',
|
||||
'@codemirror/fold',
|
||||
'@codemirror/gutter',
|
||||
'@codemirror/highlight',
|
||||
'@codemirror/history',
|
||||
'@codemirror/language',
|
||||
'@codemirror/lint',
|
||||
'@codemirror/matchbrackets',
|
||||
'@codemirror/panel',
|
||||
'@codemirror/rangeset',
|
||||
'@codemirror/rectangular-selection',
|
||||
'@codemirror/search',
|
||||
'@codemirror/state',
|
||||
'@codemirror/stream-parser',
|
||||
'@codemirror/text',
|
||||
'@codemirror/tooltip',
|
||||
'@codemirror/view',
|
||||
...builtins],
|
||||
format: 'cjs',
|
||||
watch: !prod,
|
||||
target: 'es2016',
|
||||
logLevel: "info",
|
||||
sourcemap: prod ? false : 'inline',
|
||||
treeShaking: true,
|
||||
outfile: 'main.js',
|
||||
}).catch(() => process.exit(1));
|
||||
|
||||
237
main.ts
237
main.ts
@ -1,137 +1,126 @@
|
||||
import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
|
||||
import { DoubanSearchModal } from "douban/DoubanSearchModal";
|
||||
import { DoubanSettingTab } from "douban/DoubanSettingTab";
|
||||
import { DoubanFuzzySuggester } from "douban/search/DoubanSearchFuzzySuggestModal";
|
||||
import { Editor, Notice, Plugin} from "obsidian";
|
||||
import { log } from "utils/logutil";
|
||||
import { DEFAULT_SETTINGS, DoubanExtract, DoubanPluginSettings } from "./douban/Douban";
|
||||
import { Searcher } from "./douban/search/Search";
|
||||
import { DoubanSearchResultExtract } from "./douban/search/SearchParser";
|
||||
|
||||
// Remember to rename these classes and interfaces!
|
||||
export default class DoubanPlugin extends Plugin {
|
||||
public settings: DoubanPluginSettings;
|
||||
public fuzzySuggester: DoubanFuzzySuggester;
|
||||
|
||||
interface MyPluginSettings {
|
||||
mySetting: string;
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: MyPluginSettings = {
|
||||
mySetting: 'default'
|
||||
}
|
||||
formatExtractText(extract: DoubanExtract): string {
|
||||
return this.settings.template ?
|
||||
this.settings.template.replace("{{id}}", extract.id)
|
||||
.replace("{{type}}", extract.type)
|
||||
.replace("{{title}}", extract.title)
|
||||
.replace("{{desc}}", extract.desc)
|
||||
.replace("{{url}}", extract.url) : "";
|
||||
}
|
||||
|
||||
handleNotFound(searchTerm: string) {
|
||||
log.error(`${searchTerm} not found on Wikipedia.`);
|
||||
}
|
||||
|
||||
handleCouldntResolveDisambiguation() {
|
||||
log.error(`Could not automatically resolve disambiguation.`);
|
||||
}
|
||||
|
||||
|
||||
parseSearchList(extract: DoubanSearchResultExtract[]):DoubanSearchResultExtract[] {
|
||||
// return extract.map(result => {
|
||||
// return {
|
||||
// id: result.id,
|
||||
// type: result.type,
|
||||
// title: result.title,
|
||||
// desc: result.desc,
|
||||
// url: result.url,
|
||||
// score: result.score,
|
||||
// cast: result.cast
|
||||
// }
|
||||
// })
|
||||
return extract;
|
||||
}
|
||||
|
||||
async getDoubanSearchList(title: string): Promise<DoubanSearchResultExtract[] | undefined> {
|
||||
return Searcher.search(title, this.settings);
|
||||
}
|
||||
|
||||
export default class MyPlugin extends Plugin {
|
||||
settings: MyPluginSettings;
|
||||
async getDoubanMovieText(title: DoubanSearchResultExtract): Promise<DoubanExtract | undefined> {
|
||||
// const moviesPromise = search(title);
|
||||
// const movies = await moviesPromise;
|
||||
// const extract = this.parseResponse(movies);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
async pasteIntoEditor(editor: Editor, extract: DoubanExtract) {
|
||||
|
||||
if (!extract) {
|
||||
this.handleNotFound("Not Found Subject");
|
||||
return;
|
||||
}
|
||||
editor.replaceSelection(this.formatExtractText(extract));
|
||||
}
|
||||
|
||||
|
||||
async search(searchTerm:string) {
|
||||
log.info("plugin search :" + searchTerm);
|
||||
const resultListPromise = this.getDoubanSearchList(searchTerm);
|
||||
resultListPromise.then(log.info);
|
||||
const resultList = await resultListPromise;
|
||||
const result = this.parseSearchList(resultList);
|
||||
log.info("plugin search result:" + JSON.stringify(result));
|
||||
this.fuzzySuggester.showSearchList(result);
|
||||
}
|
||||
|
||||
async getDoubanMovieTextForActiveFile(editor: Editor) {
|
||||
const activeFile = await this.app.workspace.getActiveFile();
|
||||
if (activeFile) {
|
||||
const searchTerm = activeFile.basename;
|
||||
if (searchTerm) {
|
||||
await this.search(searchTerm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async geDoubanMovieTextForSearchTerm(editor: Editor) {
|
||||
log.info("start open search windows");
|
||||
new DoubanSearchModal(this.app, this, editor).open();
|
||||
}
|
||||
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
await this.loadSettings();
|
||||
|
||||
// This creates an icon in the left ribbon.
|
||||
const ribbonIconEl = this.addRibbonIcon('dice', 'Sample Plugin', (evt: MouseEvent) => {
|
||||
// Called when the user clicks the icon.
|
||||
new Notice('This is a notice!');
|
||||
});
|
||||
// Perform additional things with the ribbon
|
||||
ribbonIconEl.addClass('my-plugin-ribbon-class');
|
||||
|
||||
// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
|
||||
const statusBarItemEl = this.addStatusBarItem();
|
||||
statusBarItemEl.setText('Status Bar Text');
|
||||
|
||||
// This adds a simple command that can be triggered anywhere
|
||||
this.addCommand({
|
||||
id: 'open-sample-modal-simple',
|
||||
name: 'Open sample modal (simple)',
|
||||
callback: () => {
|
||||
new SampleModal(this.app).open();
|
||||
}
|
||||
});
|
||||
// This adds an editor command that can perform some operation on the current editor instance
|
||||
this.addCommand({
|
||||
id: 'sample-editor-command',
|
||||
name: 'Sample editor command',
|
||||
editorCallback: (editor: Editor, view: MarkdownView) => {
|
||||
console.log(editor.getSelection());
|
||||
editor.replaceSelection('Sample Editor Command');
|
||||
}
|
||||
});
|
||||
// This adds a complex command that can check whether the current state of the app allows execution of the command
|
||||
this.addCommand({
|
||||
id: 'open-sample-modal-complex',
|
||||
name: 'Open sample modal (complex)',
|
||||
checkCallback: (checking: boolean) => {
|
||||
// Conditions to check
|
||||
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if (markdownView) {
|
||||
// If checking is true, we're simply "checking" if the command can be run.
|
||||
// If checking is false, then we want to actually perform the operation.
|
||||
if (!checking) {
|
||||
new SampleModal(this.app).open();
|
||||
}
|
||||
|
||||
// This command will only show up in Command Palette when the check function returns true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// This adds a settings tab so the user can configure various aspects of the plugin
|
||||
this.addSettingTab(new SampleSettingTab(this.app, this));
|
||||
|
||||
// If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
|
||||
// Using this function will automatically remove the event listener when this plugin is disabled.
|
||||
this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
|
||||
console.log('click', evt);
|
||||
});
|
||||
|
||||
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
|
||||
this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
|
||||
this.addCommand({
|
||||
id: "douban-movie-for-current-file",
|
||||
name: "get dou ban movie",
|
||||
editorCallback: (editor: Editor) =>
|
||||
this.getDoubanMovieTextForActiveFile(editor),
|
||||
});
|
||||
|
||||
|
||||
this.addCommand({
|
||||
id: "douban-movie-for-search",
|
||||
name: "douban-movie-for-search",
|
||||
editorCallback: (editor: Editor) =>
|
||||
this.geDoubanMovieTextForSearchTerm(editor),
|
||||
});
|
||||
|
||||
this.addSettingTab(new DoubanSettingTab(this.app, this));
|
||||
this.fuzzySuggester = new DoubanFuzzySuggester(this.app, this);
|
||||
}
|
||||
|
||||
onunload() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
|
||||
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SampleModal extends Modal {
|
||||
constructor(app: App) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
const {contentEl} = this;
|
||||
contentEl.setText('Woah!');
|
||||
}
|
||||
|
||||
onClose() {
|
||||
const {contentEl} = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
}
|
||||
|
||||
class SampleSettingTab extends PluginSettingTab {
|
||||
plugin: MyPlugin;
|
||||
|
||||
constructor(app: App, plugin: MyPlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
display(): void {
|
||||
const {containerEl} = this;
|
||||
|
||||
containerEl.empty();
|
||||
|
||||
containerEl.createEl('h2', {text: 'Settings for my awesome plugin.'});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Setting #1')
|
||||
.setDesc('It\'s a secret')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter your secret')
|
||||
.setValue(this.plugin.settings.mySetting)
|
||||
.onChange(async (value) => {
|
||||
console.log('Secret: ' + value);
|
||||
this.plugin.settings.mySetting = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
{
|
||||
"id": "obsidian-sample-plugin",
|
||||
"name": "Sample Plugin",
|
||||
"version": "1.0.1",
|
||||
"minAppVersion": "0.12.0",
|
||||
"description": "This is a sample plugin for Obsidian. This plugin demonstrates some of the capabilities of the Obsidian API.",
|
||||
"author": "Obsidian",
|
||||
"authorUrl": "https://obsidian.md",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
{
|
||||
"id": "obsidian-sample-plugin",
|
||||
"name": "Sample Plugin",
|
||||
"version": "1.0.1",
|
||||
"minAppVersion": "0.12.0",
|
||||
"description": "This is a sample plugin for Obsidian. This plugin demonstrates some of the capabilities of the Obsidian API.",
|
||||
"author": "Obsidian",
|
||||
"authorUrl": "https://obsidian.md",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
|
||||
2130
package-lock.json
generated
Normal file
2130
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
54
package.json
54
package.json
@ -1,24 +1,30 @@
|
||||
{
|
||||
"name": "obsidian-sample-plugin",
|
||||
"version": "1.0.1",
|
||||
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.2.0",
|
||||
"@typescript-eslint/parser": "^5.2.0",
|
||||
"builtin-modules": "^3.2.0",
|
||||
"esbuild": "0.13.12",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.3.1",
|
||||
"typescript": "4.4.4"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "obsidian-sample-plugin",
|
||||
"version": "1.0.1",
|
||||
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.2.0",
|
||||
"@typescript-eslint/parser": "^5.2.0",
|
||||
"builtin-modules": "^3.2.0",
|
||||
"esbuild": "0.13.12",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.3.1",
|
||||
"typescript": "4.4.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.27.2",
|
||||
"cheerio": "^1.0.0-rc.11",
|
||||
"douban-search-crack": "^1.0.6",
|
||||
"tiny-network": "0.0.6"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/* Sets all the text color to red! */
|
||||
body {
|
||||
color: red;
|
||||
}
|
||||
/* Sets all the text color to red! */
|
||||
body {
|
||||
color: red;
|
||||
}
|
||||
|
||||
@ -1,23 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext",
|
||||
"target": "ES6",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES5",
|
||||
"ES6",
|
||||
"ES7"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext",
|
||||
"target": "ES6",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES5",
|
||||
"ES6",
|
||||
"ES7"
|
||||
],
|
||||
"outDir": "dist",
|
||||
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
||||
|
||||
6
typings/tiny-network.d.ts
vendored
Normal file
6
typings/tiny-network.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
declare module 'tiny-network' {
|
||||
export function get(url:string, headers:any): any;
|
||||
export function get(url:string): any;
|
||||
export function readStream(param:any): any;
|
||||
export function ensureStatusCode(code:number): any;
|
||||
}
|
||||
21
utils/logutil.ts
Normal file
21
utils/logutil.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { Notice } from "obsidian";
|
||||
|
||||
class Logger {
|
||||
|
||||
public error(e:any):any {
|
||||
new Notice("Douban Plugin Error: " + e);
|
||||
return e;
|
||||
}
|
||||
|
||||
public warn(e:any):any {
|
||||
new Notice("Douban Plugin Warn: " + e);
|
||||
return e;
|
||||
}
|
||||
|
||||
public info(e:any):any {
|
||||
console.log("Douban Plugin Warn: " + e);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
export const log:Logger = new Logger();
|
||||
@ -1,14 +1,14 @@
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
|
||||
const targetVersion = process.env.npm_package_version;
|
||||
|
||||
// read minAppVersion from manifest.json and bump version to target version
|
||||
let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
|
||||
const { minAppVersion } = manifest;
|
||||
manifest.version = targetVersion;
|
||||
writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
|
||||
|
||||
// update versions.json with target version and minAppVersion from manifest.json
|
||||
let versions = JSON.parse(readFileSync("versions.json", "utf8"));
|
||||
versions[targetVersion] = minAppVersion;
|
||||
writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
|
||||
const targetVersion = process.env.npm_package_version;
|
||||
|
||||
// read minAppVersion from manifest.json and bump version to target version
|
||||
let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
|
||||
const { minAppVersion } = manifest;
|
||||
manifest.version = targetVersion;
|
||||
writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
|
||||
|
||||
// update versions.json with target version and minAppVersion from manifest.json
|
||||
let versions = JSON.parse(readFileSync("versions.json", "utf8"));
|
||||
versions[targetVersion] = minAppVersion;
|
||||
writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{
|
||||
"1.0.0": "0.9.7",
|
||||
"1.0.1": "0.12.0"
|
||||
}
|
||||
{
|
||||
"1.0.0": "0.9.7",
|
||||
"1.0.1": "0.12.0"
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user