mirror of
https://github.com/Wanxp/obsidian-douban.git
synced 2026-04-05 17:48:42 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 812fc17c5a | |||
|
|
e8a0d8a00c | ||
|
|
318aabb21b | ||
| a8094d7575 | |||
|
|
7ba1a7be0c | ||
|
|
4e8d3f1318 | ||
|
|
c375512903 | ||
|
|
99d4170626 | ||
|
|
297ccd33cf | ||
|
|
a0eccf7370 |
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "obsidian-douban-plugin",
|
"id": "obsidian-douban-plugin",
|
||||||
"name": "Douban",
|
"name": "Douban",
|
||||||
"version": "2.3.1",
|
"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",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "obsidian-douban-plugin",
|
"name": "obsidian-douban-plugin",
|
||||||
"version": "2.3.1",
|
"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": {
|
||||||
|
|||||||
@ -33,24 +33,24 @@ export default class DoubanTheaterAiLoadHandler extends DoubanAbstractLoadHandle
|
|||||||
"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("aliases", DataValueType.array, extract.aliases,
|
||||||
extract.aliases.map(a=>a
|
(extract.aliases || []).map(a=>a
|
||||||
.trim()
|
.trim()
|
||||||
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
||||||
// //replase multiple _ to single _
|
// //replase multiple _ to single _
|
||||||
|
|||||||
@ -169,9 +169,6 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
|
|||||||
const syncButton = new ButtonComponent(controls)
|
const syncButton = new ButtonComponent(controls)
|
||||||
.setButtonText(i18nHelper.getMessage('110007'))
|
.setButtonText(i18nHelper.getMessage('110007'))
|
||||||
.onClick(async () => {
|
.onClick(async () => {
|
||||||
if (!this.plugin.userComponent.isLogin()) {
|
|
||||||
await this.plugin.userComponent.login();
|
|
||||||
}
|
|
||||||
if(!await this.plugin.checkLogin(this.context)) {
|
if(!await this.plugin.checkLogin(this.context)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -142,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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -543,15 +543,20 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
|||||||
}
|
}
|
||||||
fileName = this.parsePartPath(fileName, extract, context, variableMap)
|
fileName = this.parsePartPath(fileName, extract, context, variableMap)
|
||||||
fileName = fileName + fileNameSuffix;
|
fileName = fileName + fileNameSuffix;
|
||||||
// const referHeaders = {'referer': image};
|
const imageReferer = (extract.id ? this.getSubjectUrl(extract.id) : '') || extract.url;
|
||||||
const referHeaders = context.settings.loginHeadersContent ? JSON.parse(context.settings.loginHeadersContent) : {};
|
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);
|
this.initImageVariableMap(extract, context, variableMap);
|
||||||
@ -569,6 +574,14 @@ export default abstract class DoubanAbstractLoadHandler<T extends DoubanSubject>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>) {
|
private initImageVariableMap(extract: T, context: HandleContext, variableMap : Map<string, DataField>) {
|
||||||
variableMap.set(DoubanParameterName.IMAGE_URL, new DataField(
|
variableMap.set(DoubanParameterName.IMAGE_URL, new DataField(
|
||||||
DoubanParameterName.IMAGE_URL,
|
DoubanParameterName.IMAGE_URL,
|
||||||
@ -608,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
|
||||||
|
|||||||
@ -30,9 +30,9 @@ export default class DoubanBookLoadHandler extends DoubanAbstractLoadHandler<Dou
|
|||||||
|
|
||||||
parseVariable(beforeContent: string, variableMap:Map<string, DataField>, extract: DoubanBookSubject, context: HandleContext): 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 {
|
||||||
|
|||||||
@ -31,7 +31,7 @@ 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 {
|
||||||
// super.parseAliases(beforeContent, variableMap, extract, context);
|
// super.parseAliases(beforeContent, variableMap, extract, context);
|
||||||
variableMap.set("aliases", new DataField("aliases", DataValueType.array, extract.aliases,
|
variableMap.set("aliases", new DataField("aliases", DataValueType.array, extract.aliases,
|
||||||
extract.aliases.map(a=>a
|
(extract.aliases || []).map(a=>a
|
||||||
.trim()
|
.trim()
|
||||||
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
||||||
// //replase multiple _ to single _
|
// //replase multiple _ to single _
|
||||||
|
|||||||
@ -35,24 +35,24 @@ 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("aliases", DataValueType.array, extract.aliases,
|
||||||
extract.aliases.map(a=>a
|
(extract.aliases || []).map(a=>a
|
||||||
.trim()
|
.trim()
|
||||||
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
||||||
// //replase multiple _ to single _
|
// //replase multiple _ to single _
|
||||||
@ -98,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 => {
|
||||||
@ -108,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] : '',
|
||||||
@ -119,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: [""],
|
||||||
@ -136,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;
|
||||||
}
|
}
|
||||||
@ -156,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();
|
||||||
@ -164,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,22 +25,22 @@ export class DoubanTeleplayLoadHandler extends DoubanAbstractLoadHandler<DoubanT
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
variableMap.set("aliases", new DataField("aliases", DataValueType.array, extract.aliases,
|
||||||
extract.aliases.map(a=>a
|
(extract.aliases || []).map(a=>a
|
||||||
.trim()
|
.trim()
|
||||||
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
// .replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
||||||
// //replase multiple _ to single _
|
// //replase multiple _ to single _
|
||||||
@ -84,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 => {
|
||||||
@ -104,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: [""],
|
||||||
@ -124,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();
|
||||||
|
|||||||
@ -33,28 +33,28 @@ 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
|
(extract.aliases || []).map(a => a
|
||||||
.trim()
|
.trim()
|
||||||
.replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
.replace(TITLE_ALIASES_SPECIAL_CHAR_REG_G, '_')
|
||||||
//replace multiple _ to single _
|
//replace multiple _ to single _
|
||||||
|
|||||||
@ -3,8 +3,7 @@ import {
|
|||||||
} from "../../../../constant/Constsant";
|
} 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 {
|
||||||
@ -12,22 +11,11 @@ export class AllFirstPageSearchResultPageParser implements SearchResultPageParse
|
|||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ 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 {
|
||||||
@ -10,13 +10,10 @@ export class OtherAllPageSearchResultPageParser implements SearchResultPageParse
|
|||||||
}
|
}
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,8 @@ 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;
|
||||||
|
|||||||
@ -10,17 +10,17 @@ export function constructLoginUI(containerEl: HTMLElement, manager: SettingsMana
|
|||||||
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1210') });
|
// containerEl.createEl('h3', { text: i18nHelper.getMessage('1210') });
|
||||||
|
|
||||||
const userComponent = manager.plugin.userComponent;
|
const userComponent = manager.plugin.userComponent;
|
||||||
if (userComponent.needLogin()) {
|
if (userComponent.isLogin() && !userComponent.isVerified()) {
|
||||||
try {
|
// Assumed login — verify to get user ID/name for settings display
|
||||||
userComponent.login()
|
userComponent.login()
|
||||||
.then(() => {
|
.then(() => constructDoubanLoginSettingsUI(containerEl, manager))
|
||||||
constructDoubanLoginSettingsUI(containerEl, manager);
|
.catch(() => constructDoubanLoginSettingsUI(containerEl, manager));
|
||||||
});
|
} else if (userComponent.needLogin()) {
|
||||||
}catch (e) {
|
// Has credentials but not yet logged in
|
||||||
log.debug(i18nHelper.getMessage('100101'));
|
userComponent.login()
|
||||||
constructDoubanLoginSettingsUI(containerEl, manager);
|
.then(() => constructDoubanLoginSettingsUI(containerEl, manager))
|
||||||
}
|
.catch(() => constructDoubanLoginSettingsUI(containerEl, manager));
|
||||||
}else {
|
} else {
|
||||||
constructDoubanLoginSettingsUI(containerEl, manager);
|
constructDoubanLoginSettingsUI(containerEl, manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {DoubanHttpUtil} from "../../utils/DoubanHttpUtil";
|
|||||||
export default class UserComponent {
|
export default class UserComponent {
|
||||||
private settingsManager: SettingsManager;
|
private settingsManager: SettingsManager;
|
||||||
private user: User;
|
private user: User;
|
||||||
|
private verified: boolean = false;
|
||||||
|
|
||||||
constructor(settingsManager: SettingsManager) {
|
constructor(settingsManager: SettingsManager) {
|
||||||
this.settingsManager = settingsManager;
|
this.settingsManager = settingsManager;
|
||||||
@ -39,11 +40,26 @@ export default class UserComponent {
|
|||||||
this.user.login = false;
|
this.user.login = false;
|
||||||
}
|
}
|
||||||
this.user = null;
|
this.user = null;
|
||||||
|
this.verified = false;
|
||||||
this.settingsManager.updateSetting('loginCookiesContent', '');
|
this.settingsManager.updateSetting('loginCookiesContent', '');
|
||||||
this.settingsManager.updateSetting('loginHeadersContent', '');
|
this.settingsManager.updateSetting('loginHeadersContent', '');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assumeLoggedIn(): void {
|
||||||
|
const headers: any = this.settingsManager.getSetting('loginHeadersContent');
|
||||||
|
const cookies: any = this.settingsManager.getSetting('loginCookiesContent');
|
||||||
|
if (headers || cookies) {
|
||||||
|
this.user = new User();
|
||||||
|
this.user.login = true;
|
||||||
|
this.verified = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isVerified(): boolean {
|
||||||
|
return this.verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
needLogin() {
|
needLogin() {
|
||||||
@ -68,6 +84,7 @@ export default class UserComponent {
|
|||||||
this.settingsManager.debug(`配置界面:loginCookie:豆瓣headers信息正常,${user&&user.id?'获取用户信息成功id:'+ StringUtil.confuse(user.id) + ',用户名:'+ StringUtil.confuse(user.name) :'获取用户信息失败'}`);
|
this.settingsManager.debug(`配置界面:loginCookie:豆瓣headers信息正常,${user&&user.id?'获取用户信息成功id:'+ StringUtil.confuse(user.id) + ',用户名:'+ StringUtil.confuse(user.name) :'获取用户信息失败'}`);
|
||||||
});
|
});
|
||||||
if(this.user) {
|
if(this.user) {
|
||||||
|
this.verified = true;
|
||||||
this.settingsManager.updateSetting('loginHeadersContent', JSON.stringify(headers));
|
this.settingsManager.updateSetting('loginHeadersContent', JSON.stringify(headers));
|
||||||
}
|
}
|
||||||
return this.user;
|
return this.user;
|
||||||
@ -139,6 +156,9 @@ export default class UserComponent {
|
|||||||
this.user = user;
|
this.user = user;
|
||||||
this.settingsManager.debug(`主界面:loginByCookie:豆瓣cookies信息正常,${user&&user.id?'获取用户信息成功id:'+ StringUtil.confuse(user.id) + ',用户名:'+ StringUtil.confuse(user.name) :'获取用户信息失败'}`);
|
this.settingsManager.debug(`主界面:loginByCookie:豆瓣cookies信息正常,${user&&user.id?'获取用户信息成功id:'+ StringUtil.confuse(user.id) + ',用户名:'+ StringUtil.confuse(user.name) :'获取用户信息失败'}`);
|
||||||
});
|
});
|
||||||
|
if (this.user && this.user.id) {
|
||||||
|
this.verified = true;
|
||||||
|
}
|
||||||
return this.user;
|
return this.user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -335,6 +335,8 @@ PS: This file could be delete if you want to.
|
|||||||
'130105': `Can not use Douban this time, Please try again after 12 hour or 24 hour. Or you can reset your connection `,
|
'130105': `Can not use Douban this time, Please try again after 12 hour or 24 hour. Or you can reset your connection `,
|
||||||
'130106': `Can not use Douban this time, Please try Login In Douban Plugin. If not working please again after 12 hour or 24 hour. Or you can reset your connection `,
|
'130106': `Can not use Douban this time, Please try Login In Douban Plugin. If not working please again after 12 hour or 24 hour. Or you can reset your connection `,
|
||||||
'130404': `404 Url Not Found`,
|
'130404': `404 Url Not Found`,
|
||||||
|
'130109': `Downloaded image is empty`,
|
||||||
|
'130110': `Clipboard write failed`,
|
||||||
|
|
||||||
|
|
||||||
'130107': `Can not find array setting for {1} in {0} , Please add it in array settings`,
|
'130107': `Can not find array setting for {1} in {0} , Please add it in array settings`,
|
||||||
|
|||||||
@ -350,6 +350,8 @@ export default {
|
|||||||
'130105': `由于多次频繁请求数据,豆瓣当前暂时不可用. 请于12小时或24小时后再重试,或重置你的网络(如重新拨号或更换网络) `,
|
'130105': `由于多次频繁请求数据,豆瓣当前暂时不可用. 请于12小时或24小时后再重试,或重置你的网络(如重新拨号或更换网络) `,
|
||||||
'130106': `请尝试在Douban插件中登录后操作. 若还是无效果则尝试于12小时或24小时后再重试,或重置你的网络(如重新拨号或更换网络) `,
|
'130106': `请尝试在Douban插件中登录后操作. 若还是无效果则尝试于12小时或24小时后再重试,或重置你的网络(如重新拨号或更换网络) `,
|
||||||
'130107': `参数{0}中指定的数组输出类型{1}不存在,请前往配置进行设置`,
|
'130107': `参数{0}中指定的数组输出类型{1}不存在,请前往配置进行设置`,
|
||||||
|
'130109': `下载图片内容为空`,
|
||||||
|
'130110': `写入剪贴板失败`,
|
||||||
'130120': `同步时发生错误,但同步将会继续。错误项目是 {}。`,
|
'130120': `同步时发生错误,但同步将会继续。错误项目是 {}。`,
|
||||||
'130121': `总数只有{0}, 选择的开始比总数还要大,将不会同步。`,
|
'130121': `总数只有{0}, 选择的开始比总数还要大,将不会同步。`,
|
||||||
|
|
||||||
|
|||||||
@ -286,6 +286,7 @@ export default class DoubanPlugin extends Plugin {
|
|||||||
// this.fetchOnlineData(this.settingsManager);
|
// this.fetchOnlineData(this.settingsManager);
|
||||||
this.userComponent = new UserComponent(this.settingsManager);
|
this.userComponent = new UserComponent(this.settingsManager);
|
||||||
this.netFileHandler = new NetFileHandler(this.fileHandler);
|
this.netFileHandler = new NetFileHandler(this.fileHandler);
|
||||||
|
this.userComponent.assumeLoggedIn();
|
||||||
|
|
||||||
this.settingTab = new DoubanSettingTab(this.app, this);
|
this.settingTab = new DoubanSettingTab(this.app, this);
|
||||||
this.addSettingTab(this.settingTab);
|
this.addSettingTab(this.settingTab);
|
||||||
@ -355,11 +356,16 @@ export default class DoubanPlugin extends Plugin {
|
|||||||
|
|
||||||
async checkLogin(context: HandleContext):Promise<boolean> {
|
async checkLogin(context: HandleContext):Promise<boolean> {
|
||||||
this.settingsManager.debug('主界面:同步时的登录状态检测');
|
this.settingsManager.debug('主界面:同步时的登录状态检测');
|
||||||
if (!context.userComponent.needLogin()) {
|
const uc = context.userComponent;
|
||||||
this.settingsManager.debug('主界面:同步时的登录状态检测完成: 无用户信息, 尝试获取用户信息');
|
// If assumed-logged-in but not verified, verify now (sync needs real user ID)
|
||||||
await context.userComponent.login();
|
if (uc.isLogin() && !uc.isVerified()) {
|
||||||
|
await uc.login();
|
||||||
}
|
}
|
||||||
if (!context.userComponent.isLogin()) {
|
// If has saved credentials but not logged in, try login
|
||||||
|
if (uc.needLogin()) {
|
||||||
|
await uc.login();
|
||||||
|
}
|
||||||
|
if (!uc.isLogin()) {
|
||||||
this.settingsManager.debug('主界面:同步时的登录状态检测完成: 尝试获取用户信息失败');
|
this.settingsManager.debug('主界面:同步时的登录状态检测完成: 尝试获取用户信息失败');
|
||||||
new Notice(i18nHelper.getMessage('140303'));
|
new Notice(i18nHelper.getMessage('140303'));
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -17,16 +17,19 @@ export default class NetFileHandler {
|
|||||||
|
|
||||||
async downloadDBFile(url: string, folder:string, filename: string, context:HandleContext, showError:boolean, headers?:any): Promise<{ success: boolean, error:string, filepath: string }> {
|
async downloadDBFile(url: string, folder:string, filename: string, context:HandleContext, showError:boolean, headers?:any): Promise<{ success: boolean, error:string, filepath: string }> {
|
||||||
const filePath:string = FileUtil.join(folder, filename);
|
const filePath:string = FileUtil.join(folder, filename);
|
||||||
return HttpUtil.httpRequestBuffer(url, headers, context.plugin.settingsManager)
|
return HttpUtil.httpRequestBuffer(url, headers, context.plugin.settingsManager)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status == 404) {
|
if (response.status == 404) {
|
||||||
throw new Error(i18nHelper.getMessage('130404'));
|
throw new Error(i18nHelper.getMessage('130404'));
|
||||||
}
|
}
|
||||||
if (response.status == 403) {
|
if (response.status == 403) {
|
||||||
throw new Error(i18nHelper.getMessage('130106'));
|
throw new Error(i18nHelper.getMessage('130106'));
|
||||||
}
|
}
|
||||||
return response.textArrayBuffer;
|
if (response.status == 418) {
|
||||||
})
|
throw new Error(i18nHelper.getMessage('130105'));
|
||||||
|
}
|
||||||
|
return response.textArrayBuffer;
|
||||||
|
})
|
||||||
.then((buffer) => {
|
.then((buffer) => {
|
||||||
if (!buffer || buffer.byteLength == 0) {
|
if (!buffer || buffer.byteLength == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -56,15 +59,23 @@ export default class NetFileHandler {
|
|||||||
async downloadDBUploadPicGoByClipboard(url: string, filename: string, context:HandleContext, showError:boolean, headers?:any): Promise<{ success: boolean, error:string, filepath: string }> {
|
async downloadDBUploadPicGoByClipboard(url: string, filename: string, context:HandleContext, showError:boolean, headers?:any): Promise<{ success: boolean, error:string, filepath: string }> {
|
||||||
return HttpUtil.httpRequestBuffer(url, headers, context.plugin.settingsManager)
|
return HttpUtil.httpRequestBuffer(url, headers, context.plugin.settingsManager)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
if (response.status == 404) {
|
||||||
|
throw new Error(i18nHelper.getMessage('130404'));
|
||||||
|
}
|
||||||
if (response.status == 403) {
|
if (response.status == 403) {
|
||||||
throw new Error(i18nHelper.getMessage('130106'));
|
throw new Error(i18nHelper.getMessage('130106'));
|
||||||
}
|
}
|
||||||
|
if (response.status == 418) {
|
||||||
|
throw new Error(i18nHelper.getMessage('130105'));
|
||||||
|
}
|
||||||
return response.textArrayBuffer;
|
return response.textArrayBuffer;
|
||||||
})
|
})
|
||||||
.then((buffer) => {
|
.then(async (buffer) => {
|
||||||
ClipboardUtil.writeImage(buffer);
|
if (!buffer || buffer.byteLength == 0) {
|
||||||
}).then(() => {
|
throw new Error(i18nHelper.getMessage('130109'));
|
||||||
return this.uploadClipboardFile(context);
|
}
|
||||||
|
await ClipboardUtil.writeImage(buffer);
|
||||||
|
return await this.uploadClipboardFile(context);
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
return {success: true, error: '', filepath: HttpUtil.extractURLFromString(data.result[0])};
|
return {success: true, error: '', filepath: HttpUtil.extractURLFromString(data.result[0])};
|
||||||
@ -108,4 +119,3 @@ export default class NetFileHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,78 @@
|
|||||||
|
|
||||||
|
|
||||||
export class ClipboardUtil {
|
import {i18nHelper} from "../lang/helper";
|
||||||
|
|
||||||
public static async writeImage(data:ArrayBuffer, options: ClipboardOptions = defaultClipboardOptions) {
|
export class ClipboardUtil {
|
||||||
const { clipboard, nativeImage } = require('electron');
|
|
||||||
|
|
||||||
await clipboard.writeImage(nativeImage.createFromBuffer(data));
|
public static async writeImage(data:ArrayBuffer, options: ClipboardOptions = defaultClipboardOptions) {
|
||||||
console.log(`Copied to clipboard as HTML`);
|
if (!data || data.byteLength == 0) {
|
||||||
|
throw new Error(i18nHelper.getMessage('130110'));
|
||||||
|
}
|
||||||
|
const { clipboard, nativeImage } = require('electron');
|
||||||
|
const isWebp = this.isWebp(data);
|
||||||
|
let image = nativeImage.createFromBuffer(Buffer.from(data));
|
||||||
|
if ((!image || image.isEmpty()) && isWebp) {
|
||||||
|
image = await this.createNativeImageFromWebp(data);
|
||||||
|
}
|
||||||
|
if (!image || image.isEmpty()) {
|
||||||
|
throw new Error(i18nHelper.getMessage('130110'));
|
||||||
|
}
|
||||||
|
clipboard.clear();
|
||||||
|
clipboard.writeImage(image);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
const clipboardImage = clipboard.readImage();
|
||||||
|
if (!clipboardImage || clipboardImage.isEmpty()) {
|
||||||
|
throw new Error(i18nHelper.getMessage('130110'));
|
||||||
|
}
|
||||||
|
console.log(`Copied to clipboard as HTML`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static isWebp(data: ArrayBuffer): boolean {
|
||||||
|
const bytes = new Uint8Array(data);
|
||||||
|
if (bytes.length < 12) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return bytes[0] === 0x52
|
||||||
|
&& bytes[1] === 0x49
|
||||||
|
&& bytes[2] === 0x46
|
||||||
|
&& bytes[3] === 0x46
|
||||||
|
&& bytes[8] === 0x57
|
||||||
|
&& bytes[9] === 0x45
|
||||||
|
&& bytes[10] === 0x42
|
||||||
|
&& bytes[11] === 0x50;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async createNativeImageFromWebp(data: ArrayBuffer) {
|
||||||
|
const { nativeImage } = require('electron');
|
||||||
|
const imageElement = await this.loadImage(URL.createObjectURL(new Blob([data], {type: 'image/webp'})));
|
||||||
|
try {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = imageElement.naturalWidth || imageElement.width;
|
||||||
|
canvas.height = imageElement.naturalHeight || imageElement.height;
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(i18nHelper.getMessage('130110'));
|
||||||
|
}
|
||||||
|
context.drawImage(imageElement, 0, 0);
|
||||||
|
return nativeImage.createFromDataURL(canvas.toDataURL('image/png'));
|
||||||
|
} finally {
|
||||||
|
imageElement.src = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static loadImage(url: string): Promise<HTMLImageElement> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const image = new Image();
|
||||||
|
image.onload = () => {
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
resolve(image);
|
||||||
|
};
|
||||||
|
image.onerror = () => {
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
reject(new Error(i18nHelper.getMessage('130110')));
|
||||||
|
};
|
||||||
|
image.src = url;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -20,4 +86,3 @@ interface ClipboardOptions {
|
|||||||
const defaultClipboardOptions: ClipboardOptions = {
|
const defaultClipboardOptions: ClipboardOptions = {
|
||||||
contentType: 'text/plain',
|
contentType: 'text/plain',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,19 @@ import {HttpResponse} from "./model/HttpResponse";
|
|||||||
|
|
||||||
export default class HttpUtil {
|
export default class HttpUtil {
|
||||||
|
|
||||||
|
private static readonly IMAGE_REQUEST_HEADERS_TO_DROP = new Set([
|
||||||
|
'authority',
|
||||||
|
'content-length',
|
||||||
|
'content-type',
|
||||||
|
'host',
|
||||||
|
'origin',
|
||||||
|
'referer',
|
||||||
|
'sec-fetch-dest',
|
||||||
|
'sec-fetch-mode',
|
||||||
|
'sec-fetch-site',
|
||||||
|
'sec-fetch-user',
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,6 +73,27 @@ export default class HttpUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static buildImageRequestHeaders(headers: Record<string, any> = {}, referer?: string): Record<string, string> {
|
||||||
|
const nextHeaders: Record<string, string> = {};
|
||||||
|
Object.entries(headers || {}).forEach(([key, value]) => {
|
||||||
|
if (value == null || value === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const lowerKey = key.toLowerCase();
|
||||||
|
if (lowerKey === 'referer') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.IMAGE_REQUEST_HEADERS_TO_DROP.has(lowerKey) || lowerKey.startsWith('sec-ch-ua')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nextHeaders[key] = String(value);
|
||||||
|
});
|
||||||
|
if (referer) {
|
||||||
|
nextHeaders.Referer = referer;
|
||||||
|
}
|
||||||
|
return nextHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static parse(url: string): { protocol: string, host: string, port: string, path: string } {
|
public static parse(url: string): { protocol: string, host: string, port: string, path: string } {
|
||||||
const regex = /^(.*?):\/\/([^\/:]+)(?::(\d+))?([^?]*)$/;
|
const regex = /^(.*?):\/\/([^\/:]+)(?::(\d+))?([^?]*)$/;
|
||||||
|
|||||||
@ -61,6 +61,7 @@
|
|||||||
"2.2.3": "0.12.0",
|
"2.2.3": "0.12.0",
|
||||||
"2.2.4": "0.12.0",
|
"2.2.4": "0.12.0",
|
||||||
"2.3.0": "0.12.0",
|
"2.3.0": "0.12.0",
|
||||||
"2.3.1": "0.12.0"
|
"2.3.1": "0.12.0",
|
||||||
|
"2.3.2": "0.12.0"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user