mirror of
https://github.com/Wanxp/obsidian-douban.git
synced 2026-04-05 01:28:46 +08:00
add function: save attachment files
This commit is contained in:
parent
556788ee75
commit
1a98def0d5
35
main.ts
35
main.ts
@ -17,6 +17,7 @@ import { DoubanPluginSetting } from "@App/setting/model/DoubanPluginSetting";
|
||||
import {DEFAULT_SETTINGS} from "./src/constant/DefaultSettings";
|
||||
import UserComponent from "@App/user/UserComponent";
|
||||
import SettingsManager from "@App/setting/SettingsManager";
|
||||
import NetFileHandler from "./src/net/NetFileHandler";
|
||||
|
||||
export default class DoubanPlugin extends Plugin {
|
||||
public settings: DoubanPluginSetting;
|
||||
@ -25,6 +26,7 @@ export default class DoubanPlugin extends Plugin {
|
||||
public fileHandler: FileHandler;
|
||||
public userComponent: UserComponent;
|
||||
public settingsManager: SettingsManager;
|
||||
public netFileHandler: NetFileHandler;
|
||||
|
||||
|
||||
async putToObsidian(context: HandleContext, extract: DoubanSubject) {
|
||||
@ -111,28 +113,39 @@ export default class DoubanPlugin extends Plugin {
|
||||
id: "search-douban-import-and-create-file",
|
||||
name: i18nHelper.getMessage("110101"),
|
||||
callback: () =>
|
||||
this.getDoubanTextForCreateNewNote({mode: SearchHandleMode.FOR_CREATE, settings: this.settings, userComponent: this.userComponent}),
|
||||
this.getDoubanTextForCreateNewNote({mode: SearchHandleMode.FOR_CREATE,
|
||||
settings: this.settings,
|
||||
userComponent: this.userComponent,
|
||||
netFileHandler: this.netFileHandler}),
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "search-douban-and-input-current-file",
|
||||
name: i18nHelper.getMessage("110002"),
|
||||
editorCallback: (editor: Editor) =>
|
||||
this.getDoubanTextForSearchTerm({mode: SearchHandleMode.FOR_REPLACE,
|
||||
settings: this.settings,
|
||||
editor: editor,
|
||||
userComponent: this.userComponent,
|
||||
netFileHandler: this.netFileHandler}),
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "search-douban-by-current-file-name",
|
||||
name: i18nHelper.getMessage("110001"),
|
||||
editorCallback: (editor: Editor) =>
|
||||
this.getDoubanTextForActiveFile({mode: SearchHandleMode.FOR_REPLACE, settings: this.settings, editor: editor, userComponent: this.userComponent}),
|
||||
this.getDoubanTextForActiveFile({mode: SearchHandleMode.FOR_REPLACE,
|
||||
settings: this.settings,
|
||||
editor: editor,
|
||||
userComponent: this.userComponent,
|
||||
netFileHandler: this.netFileHandler}),
|
||||
});
|
||||
|
||||
|
||||
this.addCommand({
|
||||
id: "search-douban-and-input-current-file",
|
||||
name: i18nHelper.getMessage("110002"),
|
||||
editorCallback: (editor: Editor) =>
|
||||
this.getDoubanTextForSearchTerm({mode: SearchHandleMode.FOR_REPLACE, settings: this.settings, editor: editor, userComponent: this.userComponent}),
|
||||
});
|
||||
this.settingsManager = new SettingsManager(app, this);
|
||||
this.userComponent = new UserComponent(this.settingsManager);
|
||||
|
||||
this.netFileHandler = new NetFileHandler(this.fileHandler);
|
||||
if (this.userComponent.needLogin()) {
|
||||
this.userComponent.loginByCookie();
|
||||
await this.userComponent.loginByCookie();
|
||||
}
|
||||
|
||||
this.addSettingTab(new DoubanSettingTab(this.app, this));
|
||||
|
||||
@ -27,4 +27,6 @@ export const DEFAULT_SETTINGS: DoubanPluginSetting = {
|
||||
{name: 'myType', value: 'teleplay', field: SupportType.TELEPLAY},
|
||||
],
|
||||
loginCookiesContent: '',
|
||||
cacheImage: true,
|
||||
attachmentPath: 'assets',
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ export default class DoubanLoginModel {
|
||||
try {
|
||||
await this.modal.loadURL('https://accounts.douban.com/passport/login');
|
||||
} catch (error) {
|
||||
log.error('加载豆瓣登录页面失败')
|
||||
log.error(i18nHelper.getMessage('100101'), error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
||||
|
||||
async parse(extract: T, context: HandleContext): Promise<HandleResult> {
|
||||
let template: string = await this.getTemplate(extract, context);
|
||||
await this.saveImage(extract, context);
|
||||
let frontMatterStart: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, 0);
|
||||
let frontMatterEnd: number = template.indexOf(BasicConst.YAML_FRONT_MATTER_SYMBOL, frontMatterStart + 1);
|
||||
let frontMatter: string = '';
|
||||
@ -388,4 +389,20 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
||||
return v.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
private async saveImage(extract: T, context: HandleContext) {
|
||||
if (!extract.image || !context.settings.cacheImage) {
|
||||
return;
|
||||
}
|
||||
let image = extract.image;
|
||||
const filename = image.split('/').pop();
|
||||
let folder = context.settings.attachmentPath;
|
||||
if (!folder) {
|
||||
folder = DEFAULT_SETTINGS.attachmentPath;
|
||||
}
|
||||
const {success, filepath} = await context.netFileHandler.downloadFile(image, folder, filename);
|
||||
if (success) {
|
||||
extract.image = filepath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,10 +2,12 @@ import {SearchHandleMode} from "../../../constant/Constsant";
|
||||
import {Editor} from "obsidian";
|
||||
import { DoubanPluginSetting } from "@App/setting/model/DoubanPluginSetting";
|
||||
import UserComponent from "@App/user/UserComponent";
|
||||
import NetFileHandler from "src/net/NetFileHandler";
|
||||
|
||||
export default interface HandleContext {
|
||||
mode:SearchHandleMode;
|
||||
settings: DoubanPluginSetting;
|
||||
editor?:Editor;
|
||||
userComponent: UserComponent;
|
||||
netFileHandler: NetFileHandler;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import SettingsManager from "@App/setting/SettingsManager";
|
||||
import DoubanLoginModel from "@App/component/DoubanLoginModel";
|
||||
import DoubanLogoutModel from "@App/component/DoubanLogoutModel";
|
||||
import User from "@App/user/User";
|
||||
import {createFolderSelectionSetting} from "@App/setting/TemplateSettingHelper";
|
||||
|
||||
export function constructBasicUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1210') });
|
||||
@ -94,6 +95,8 @@ export function constructBasicUI(containerEl: HTMLElement, manager: SettingsMana
|
||||
await manager.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
export function constructDoubanTokenSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||
@ -165,10 +168,10 @@ function showMobileLogout(containerEl: HTMLElement, manager: SettingsManager) {
|
||||
const user: User = manager.plugin.userComponent.getUser();
|
||||
let userDom = new DocumentFragment();
|
||||
userDom.createDiv().innerHTML =
|
||||
`已登录<br>
|
||||
豆瓣ID: <a href="https://www.douban.com/people/${user.id}/">${user.id}</a><br>
|
||||
昵称: ${user.name}<br>
|
||||
登录后导入参数可使用你的评分以及阅读状态等,具体可用参数见最后.`;
|
||||
`${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)
|
||||
|
||||
@ -7,8 +7,14 @@ import SettingsManager from "@App/setting/SettingsManager";
|
||||
|
||||
export function constructOutUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||
containerEl.createEl('h3', { text: i18nHelper.getMessage('1220') });
|
||||
|
||||
new Setting(containerEl);
|
||||
let attachmentFileSetting = containerEl.createDiv({ cls: 'settings-item-attachment' });
|
||||
constructAttachmentFileSettingsUI(attachmentFileSetting, manager);
|
||||
|
||||
new Setting(containerEl).then(createFolderSelectionSetting({name: '121501', desc: '121502', placeholder: '121503', key: 'dataFilePath', manager: manager}));
|
||||
let outfolder = containerEl.createDiv({ cls: 'settings-item' });
|
||||
|
||||
constructOutFolderUI(outfolder, manager);
|
||||
|
||||
new Setting(containerEl)
|
||||
@ -76,3 +82,25 @@ export function constructOutFolderUI(containerEl: HTMLElement, manager: Settings
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export function constructAttachmentFileSettingsUI(containerEl: HTMLElement, manager: SettingsManager) {
|
||||
containerEl.empty();
|
||||
new Setting(containerEl)
|
||||
.setName(i18nHelper.getMessage('121430'))
|
||||
.setDesc(i18nHelper.getMessage('121431'))
|
||||
.addToggle((toggleComponent) => {
|
||||
toggleComponent
|
||||
// .setTooltip(i18nHelper.getMessage('121403'))
|
||||
.setValue(manager.plugin.settings.cacheImage)
|
||||
.onChange(async (value) => {
|
||||
manager.plugin.settings.cacheImage = value;
|
||||
await manager.plugin.saveSettings();
|
||||
constructAttachmentFileSettingsUI(containerEl, manager);
|
||||
});
|
||||
});
|
||||
|
||||
if(manager.plugin.settings.cacheImage) {
|
||||
new Setting(containerEl).then(createFolderSelectionSetting({name: '121432', desc: '121433', placeholder: '121434', key: 'attachmentPath', manager: manager}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,6 +269,6 @@ ${i18nHelper.getMessage('160225')}
|
||||
`
|
||||
;
|
||||
new Setting(containerEl)
|
||||
.setName(i18nHelper.getMessage('122002'))
|
||||
.setName(i18nHelper.getMessage('122010'))
|
||||
.setDesc(userInfoVariables);
|
||||
}
|
||||
|
||||
@ -18,5 +18,6 @@ export interface DoubanPluginSetting {
|
||||
statusBar: boolean,
|
||||
customProperties: CustomProperty[],
|
||||
loginCookiesContent: string,
|
||||
|
||||
cacheImage: boolean,
|
||||
attachmentPath: string,
|
||||
}
|
||||
|
||||
@ -68,6 +68,36 @@ export default class FileHandler {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles creating the new note
|
||||
* A new markdown file will be created at the given file path (`input`)
|
||||
* in the specified parent folder (`this.folder`)
|
||||
*/
|
||||
async creatAttachmentWithData(originalFilePath: string, data:ArrayBuffer): Promise<void> {
|
||||
const {vault} = this._app;
|
||||
const {adapter} = vault;
|
||||
const prependDirInput = FileUtil.join("", originalFilePath);
|
||||
const {dir, name} = FileUtil.parse(prependDirInput);
|
||||
const filePath = FileUtil.join(dir, `${name}`);
|
||||
|
||||
try {
|
||||
const fileExists = await adapter.exists(filePath);
|
||||
if (fileExists) {
|
||||
// If the file already exists, respond with error
|
||||
// throw new Error(i18nHelper.getMessage('110201').replace('{0}', filePath??''));
|
||||
return ;
|
||||
}
|
||||
if (dir !== '') {
|
||||
// If `input` includes a directory part, create it
|
||||
await this.createDirectory(dir);
|
||||
}
|
||||
await vault.createBinary(filePath, data);
|
||||
// Create the file and open it in the active leaf
|
||||
} catch (error) {
|
||||
log.error(error.toString(), error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles creating the new note
|
||||
* A new markdown file will be created at the given file path (`input`)
|
||||
|
||||
@ -37,6 +37,7 @@ export default {
|
||||
'100129': `You have not login Douban, please login in computer first! After login, you can use your rating and reading status, see the last for specific variables.`,
|
||||
'100130': `Login`,
|
||||
'100131': `Login Douban`,
|
||||
'100132': `Load Douban Login Page Failed`,
|
||||
|
||||
|
||||
'1210': `Basic Setting`,
|
||||
@ -130,6 +131,13 @@ export default {
|
||||
'121401': `Status Bar`,
|
||||
'121402': `Display status bar when import data ?`,
|
||||
|
||||
'121430': `Save Attachment File`,
|
||||
'121431': `Save attachment file to local disk, such as image ?`,
|
||||
'121432': `Attachment folder`,
|
||||
'121433': `Attachment file created from Obsidian-Douban will be placed in this folder, If blank, they will be placed in the default location for this vault.`,
|
||||
'121434': `assets`,
|
||||
|
||||
|
||||
'121501': `Note folder`,
|
||||
'121502': `Nodes created from Obsidian-Douban will be placed in this folder, If blank, they will be placed in the default location for this vault. `,
|
||||
'121503': `Default Folder`,
|
||||
@ -175,6 +183,7 @@ export default {
|
||||
'122002': `Extra Variables`,
|
||||
'122003': `Basic Variables must has value, Extra Variables can be empty`,
|
||||
'122004': `To use the template variables, you need to wrap them in double curly brackets. For example, {{title}} will be replaced with the title of the note.`,
|
||||
'122010': `My State Variables`,
|
||||
|
||||
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ export default {
|
||||
'100129': `豆瓣未登录,请先在电脑端登录!登录后导入参数可使用你的评分以及阅读状态等,具体可用参数见最后.`,
|
||||
'100130': `登录`,
|
||||
'100131': `登录豆瓣`,
|
||||
|
||||
'100132': `加载豆瓣登录页面失败`,
|
||||
|
||||
|
||||
|
||||
@ -138,8 +138,15 @@ export default {
|
||||
'121401': `状态栏`,
|
||||
'121402': `当在导入数据时, 是否需要在状态栏显示处理状态? `,
|
||||
|
||||
'121430': `保存图片附件`,
|
||||
'121431': `导入数据会同步保存图片附件到本地文件夹, 如电影封面,书籍封面 `,
|
||||
'121432': `附件存放位置`,
|
||||
'121433': `保存的附件将会存放至该文件夹中. 如果为空, 笔记将会存放到默认位置(assets) `,
|
||||
'121434': `assets`,
|
||||
|
||||
|
||||
'121501': `笔记存放位置`,
|
||||
'121502': `创建的笔记将会存放导该文件夹中. 如果为空, 笔记将会存放到Obsidian的默认位置`,
|
||||
'121502': `创建的笔记将会存放至该文件夹中. 如果为空, 笔记将会存放到Obsidian的默认位置`,
|
||||
|
||||
'121601': `笔记名称`,
|
||||
'121602': `创建的笔记将会使用此名称作为模板, 支持所有'通用'的参数作为名称(如:{{type}}/{{title}}), 且支持路径, 比如: 'MyData/{{title}}'. 如果为空, 笔记将会使用默认名称. `,
|
||||
@ -197,7 +204,7 @@ export default {
|
||||
'122002': `扩展参数`,
|
||||
'122003': `通用参数一定有值不为空, 扩展参数可能为空`,
|
||||
'122004': `以下参数使用时请用'{{}}'包裹, 举例: 参数title, 则使用时为{{title}}. `,
|
||||
|
||||
'122010': `我的状态参数`,
|
||||
|
||||
'410101': `其他`,
|
||||
'410102': `未知`,
|
||||
|
||||
37
src/net/NetFileHandler.ts
Normal file
37
src/net/NetFileHandler.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { requestUrl, RequestUrlParam} from "obsidian";
|
||||
import {log} from "../utils/Logutil";
|
||||
import {i18nHelper} from "../lang/helper";
|
||||
import FileHandler from "../file/FileHandler";
|
||||
import {FileUtil} from "../utils/FileUtil";
|
||||
|
||||
export default class NetFileHandler {
|
||||
private fileHandler: FileHandler;
|
||||
|
||||
constructor(fileHandler: FileHandler) {
|
||||
this.fileHandler = fileHandler;
|
||||
}
|
||||
|
||||
async downloadFile(url: string, folder:string, filename: string): Promise<{ success: boolean, error:string, filepath: string }> {
|
||||
const requestUrlParam: RequestUrlParam = {
|
||||
url: url,
|
||||
method: "GET",
|
||||
throw: true,
|
||||
headers: {}
|
||||
};
|
||||
const filePath:string = FileUtil.join(folder, filename);
|
||||
return requestUrl(requestUrlParam)
|
||||
.then((response) => {
|
||||
this.fileHandler.creatAttachmentWithData(filePath, response.arrayBuffer);
|
||||
}).then(() => {
|
||||
return {success: true, error: '', filepath: filePath};
|
||||
})
|
||||
.catch(e => log
|
||||
.error(
|
||||
i18nHelper.getMessage('130101')
|
||||
.replace('{0}', e.toString())
|
||||
, e));
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user