feature: #132 同步游戏

This commit is contained in:
Wanxp 2025-03-10 09:02:54 +08:00
parent 001cb5dc3e
commit 9403fef320
13 changed files with 126 additions and 11 deletions

@ -233,6 +233,7 @@ export const SyncTypeRecords: { [key in SyncType | string]: string } = {
// [SyncType.broadcast]: i18nHelper.getMessage('504104'), // [SyncType.broadcast]: i18nHelper.getMessage('504104'),
// [SyncType.note]: i18nHelper.getMessage('504105'), // [SyncType.note]: i18nHelper.getMessage('504105'),
[SyncType.music]: i18nHelper.getMessage('504106'), [SyncType.music]: i18nHelper.getMessage('504106'),
// [SyncType.game]: i18nHelper.getMessage('504108'),
} }
/** /**

@ -10,3 +10,7 @@ export const doubanHeaders = {
export const doubanSubjectSyncListUrl = function(subjectType:string, userId:string, doType:string, start:number):string { export const doubanSubjectSyncListUrl = function(subjectType:string, userId:string, doType:string, start:number):string {
return `https://${subjectType}.douban.com/people/${userId}/${doType}?start=${start}&sort=time&rating=all&filter=all&mode=list`; return `https://${subjectType}.douban.com/people/${userId}/${doType}?start=${start}&sort=time&rating=all&filter=all&mode=list`;
} }
export const doubanGameSubjectSyncListUrl = function(subjectType:string, userId:string, doType:string, start:number):string {
return `https://douban.com/people/${userId}/games?start=${start}&sort=time&rating=all&filter=all&mode=list${doType != 'all' ? '&action='+doType : ''}`;
}

@ -106,6 +106,15 @@ export const DoubanSubjectStateRecords_BOOK_SYNC: { [key in DoubanSubjectState]:
[DoubanSubjectState.collect]: i18nHelper.getMessage('500304'), [DoubanSubjectState.collect]: i18nHelper.getMessage('500304'),
} }
// @ts-ignore
export const DoubanSubjectStateRecords_GAME_SYNC: { [key in DoubanSubjectState]: string } = {
// @ts-ignore
[ALL]: i18nHelper.getMessage('500004'),
[DoubanSubjectState.wish]: i18nHelper.getMessage('500602'),
[DoubanSubjectState.do]: i18nHelper.getMessage('500603'),
[DoubanSubjectState.collect]: i18nHelper.getMessage('500604'),
}
export const DoubanSubjectStateRecords_BROADCAST_SYNC: { [key :string]: string } = { export const DoubanSubjectStateRecords_BROADCAST_SYNC: { [key :string]: string } = {
[ALL]: i18nHelper.getMessage('500004'), [ALL]: i18nHelper.getMessage('500004'),
} }
@ -129,7 +138,7 @@ export const DoubanSubjectStateRecords_SYNC: { [key in SyncType]: Record<DoubanS
[SyncType.book]:DoubanSubjectStateRecords_BOOK_SYNC, [SyncType.book]:DoubanSubjectStateRecords_BOOK_SYNC,
[SyncType.music]:DoubanSubjectStateRecords_MUSIC_SYNC, [SyncType.music]:DoubanSubjectStateRecords_MUSIC_SYNC,
// [SyncType.note]:DoubanSubjectStateRecords_NOTE_SYNC, // [SyncType.note]:DoubanSubjectStateRecords_NOTE_SYNC,
// [SyncType.game]:DoubanSubjectStateRecords_GAME_SYNC, [SyncType.game]:DoubanSubjectStateRecords_GAME_SYNC,
[SyncType.teleplay]:DoubanSubjectStateRecords_TELEPLAY_SYNC, [SyncType.teleplay]:DoubanSubjectStateRecords_TELEPLAY_SYNC,
// [SyncType.theater]:DoubanSubjectStateRecords_THEATER_SYNC, // [SyncType.theater]:DoubanSubjectStateRecords_THEATER_SYNC,
} }

@ -17,7 +17,7 @@ import {
import { import {
ALL, DoubanSubjectState, DoubanSubjectStateRecords, ALL, DoubanSubjectState, DoubanSubjectStateRecords,
DoubanSubjectStateRecords_BOOK_SYNC, DoubanSubjectStateRecords_BOOK_SYNC,
DoubanSubjectStateRecords_BROADCAST_SYNC, DoubanSubjectStateRecords_BROADCAST_SYNC, DoubanSubjectStateRecords_GAME_SYNC,
DoubanSubjectStateRecords_MOVIE_SYNC, DoubanSubjectStateRecords_MOVIE_SYNC,
DoubanSubjectStateRecords_MUSIC_SYNC, DoubanSubjectStateRecords_MUSIC_SYNC,
DoubanSubjectStateRecords_NOTE_SYNC, DoubanSubjectStateRecords_NOTE_SYNC,
@ -234,14 +234,16 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
case SyncType.teleplay: case SyncType.teleplay:
this.showScopeDropdown(contentEl, DoubanSubjectStateRecords_TELEPLAY_SYNC, config, disable); this.showScopeDropdown(contentEl, DoubanSubjectStateRecords_TELEPLAY_SYNC, config, disable);
break; break;
case SyncType.game:
this.showScopeDropdown(contentEl, DoubanSubjectStateRecords_GAME_SYNC, config, disable);
break;
} }
} }
private showTypeDropdown(containerEl:HTMLElement, config: SyncConfig, disable:boolean) { private showTypeDropdown(containerEl:HTMLElement, config: SyncConfig, disable:boolean) {
const settings = new Setting(containerEl); const settings = new Setting(containerEl);
const scopeSelections = containerEl.createDiv("scope-selection"); const scopeSelections = containerEl.createDiv("scope-selection");
const templateFile:HTMLDivElement = containerEl.createDiv('template-file-path-selection'); // const templateFile:HTMLDivElement = containerEl.createDiv('template-file-path-selection');
settings settings
.setName(i18nHelper.getMessage('110030')) .setName(i18nHelper.getMessage('110030'))
.addDropdown((dropdown) => { .addDropdown((dropdown) => {
@ -251,7 +253,7 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
config.syncType = value; config.syncType = value;
config.templateFile = this.getDefaultTemplatePath(value); config.templateFile = this.getDefaultTemplatePath(value);
this.openScopeDropdown(scopeSelections, config, disable); this.openScopeDropdown(scopeSelections, config, disable);
this.showTemplateFileSelectionSetting(templateFile, config, disable); // this.showTemplateFileSelectionSetting(templateFile, config, disable);
}); });
}).setDisabled(disable); }).setDisabled(disable);
this.openScopeDropdown(scopeSelections, config, disable); this.openScopeDropdown(scopeSelections, config, disable);
@ -274,6 +276,9 @@ ${syncStatus.getHandle() == 0? '...' : i18nHelper.getMessage('110042') + ':' + T
case SyncType.teleplay: case SyncType.teleplay:
result = (settings.teleplayTemplateFile == '' || settings.teleplayTemplateFile == null) ? DEFAULT_SETTINGS.teleplayTemplateFile : settings.teleplayTemplateFile result = (settings.teleplayTemplateFile == '' || settings.teleplayTemplateFile == null) ? DEFAULT_SETTINGS.teleplayTemplateFile : settings.teleplayTemplateFile
break; break;
case SyncType.game:
result = (settings.gameTemplateFile == '' || settings.gameTemplateFile == null) ? DEFAULT_SETTINGS.gameTemplateFile : settings.gameTemplateFile
break;
} }
return result; return result;
} }

@ -82,7 +82,7 @@ export function constructLoginSettingsUI(containerEl: HTMLElement, manager: Sett
'a', 'a',
{ {
text: i18nHelper.getMessage('100139'), text: i18nHelper.getMessage('100139'),
href: 'https://obsidian-douban.wanxuping.com/20_howtouse_25_setting_login_douban_cookie.html', href: 'https://wanxp.github.io/obsidian-douban/20_howtouse_25_setting_login_douban_cookie.html',
}, },
(a) => { (a) => {
a.setAttr('target', '_blank'); a.setAttr('target', '_blank');

@ -10,6 +10,7 @@ import { DoubanBookSyncHandler } from "./DoubanBookSyncHandler";
import {i18nHelper} from "../../../lang/helper"; import {i18nHelper} from "../../../lang/helper";
import {DoubanTeleplaySyncHandler} from "./DoubanTeleplaySyncHandler"; import {DoubanTeleplaySyncHandler} from "./DoubanTeleplaySyncHandler";
import {SyncConditionType} from "../../../constant/Constsant"; import {SyncConditionType} from "../../../constant/Constsant";
import {DoubanGameSyncHandler} from "./DoubanGameSyncHandler";
export default class SyncHandler { export default class SyncHandler {
private app: App; private app: App;
@ -34,6 +35,7 @@ export default class SyncHandler {
// new DoubanNoteSyncHandler(plugin), // new DoubanNoteSyncHandler(plugin),
new DoubanMusicSyncHandler(plugin), new DoubanMusicSyncHandler(plugin),
new DoubanTeleplaySyncHandler(plugin), new DoubanTeleplaySyncHandler(plugin),
new DoubanGameSyncHandler(plugin),
this.defaultSyncHandler this.defaultSyncHandler
]; ];
} }

@ -40,7 +40,7 @@ export default abstract class DoubanAbstractListHandler
async delay(ms: number) {} async delay(ms: number) {}
private getUrl(context: HandleContext, start: number) { protected getUrl(context: HandleContext, start: number) {
return doubanSubjectSyncListUrl( return doubanSubjectSyncListUrl(
this.getSyncTypeDomain(), this.getSyncTypeDomain(),
context.userComponent.getUserId(), context.userComponent.getUserId(),

@ -3,7 +3,7 @@ import { DoubanMovieListHandler } from "./DoubanMovieListHandler";
import {DoubanGameListHandler} from "./DoubanGameListHandler"; import {DoubanGameListHandler} from "./DoubanGameListHandler";
export default class DoubanGameCollectListHandler extends DoubanMovieListHandler{ export default class DoubanGameCollectListHandler extends DoubanGameListHandler{
getDoType(): string { getDoType(): string {
return DoubanSubjectState.collect; return DoubanSubjectState.collect;
} }

@ -3,7 +3,7 @@ import { DoubanMovieListHandler } from "./DoubanMovieListHandler";
import {DoubanGameListHandler} from "./DoubanGameListHandler"; import {DoubanGameListHandler} from "./DoubanGameListHandler";
export default class DoubanGameDoListHandler extends DoubanMovieListHandler{ export default class DoubanGameDoListHandler extends DoubanGameListHandler{
getDoType(): string { getDoType(): string {
return DoubanSubjectState.do; return DoubanSubjectState.do;
} }

@ -1,5 +1,13 @@
import DoubanAbstractListHandler from "./DoubanAbstractListHandler"; import DoubanAbstractListHandler from "./DoubanAbstractListHandler";
import { SyncType} from "../../../../constant/Constsant"; import {PAGE_SIZE, SubjectHandledStatus, SyncType} from "../../../../constant/Constsant";
import {CheerioAPI} from "cheerio";
import HandleContext from "../../../data/model/HandleContext";
import {SearchPageTypeOf} from "../../../data/model/SearchPageTypeOf";
import {SubjectListItem} from "../../../data/model/SubjectListItem";
import {log} from "../../../../utils/Logutil";
import {SearchPage} from "../../../data/model/SearchPage";
import {doubanGameSubjectSyncListUrl, doubanSubjectSyncListUrl} from "../../../../constant/Douban";
import {ALL, DoubanSubjectState} from "../../../../constant/DoubanUserState";
export abstract class DoubanGameListHandler extends DoubanAbstractListHandler { export abstract class DoubanGameListHandler extends DoubanAbstractListHandler {
getSyncType(): SyncType { getSyncType(): SyncType {
@ -8,6 +16,90 @@ export abstract class DoubanGameListHandler extends DoubanAbstractListHandler {
abstract getDoType(): string; abstract getDoType(): string;
protected getUrl(context: HandleContext, start: number) {
return doubanGameSubjectSyncListUrl(
this.getSyncTypeDomain(),
context.userComponent.getUserId(),
this.getDoType(),
start,
);
}
parseSubjectFromHtml(
dataHtml: CheerioAPI,
context: HandleContext,
): SearchPageTypeOf<SubjectListItem> {
const items = dataHtml(".common-item")
.get()
.map((i: any) => {
const item = dataHtml(i);
const linkValue: string = item
.find("div.title > a")
.attr("href");
const titleValue: string = item
.find("div.title > a")
.text()
.trim();
const updateDateStr: string = item.find("div.date").text().trim();
let updateDate = null;
try {
updateDate = new Date(updateDateStr);
}catch (e) {
console.error(e);
log.info("parse date error:" + titleValue);
}
let idPattern = /(\d){5,10}/g;
let ececResult = idPattern.exec(linkValue);
return !ececResult ? null : {id: ececResult[0], url: linkValue, title: titleValue, updateDate: updateDate};
// return linkValue;
});
const total = this.getTotal(dataHtml, context);
return new SearchPage(
total,
Math.floor(context.syncOffset / PAGE_SIZE) + 1,
PAGE_SIZE,
null,
items,
);
}
private getTotal(dataHtml: CheerioAPI,
context: HandleContext):number {
const countDescs = dataHtml("div.tabs > a")
.get()
.map((i: any) => {
const item = dataHtml(i);
return item.text().trim();
});
const {syncConfig} = context;
const {scope} = syncConfig;
const pattern = /(\d+)/g;
const wishCount = this.getCount(countDescs, '想玩', pattern);
const collectCount = this.getCount(countDescs, '玩过', pattern);
const doCount = this.getCount(countDescs, '在玩', pattern);
switch (scope) {
case DoubanSubjectState.wish:
return wishCount;
case DoubanSubjectState.collect:
return collectCount;
case DoubanSubjectState.do:
return doCount;
case ALL:
return wishCount + collectCount + doCount;
}
}
private getCount(countDescs:string[], keyword:string, pattern:RegExp):number {
return countDescs.filter(desc => desc.includes(keyword)).map(desc => {
const result = pattern.exec(desc);
return result ? parseInt(result[0], 10) : 0;
})[0];
}
} }

@ -3,7 +3,7 @@ import { DoubanMovieListHandler } from "./DoubanMovieListHandler";
import {DoubanGameListHandler} from "./DoubanGameListHandler"; import {DoubanGameListHandler} from "./DoubanGameListHandler";
export default class DoubanGameWishListHandler extends DoubanMovieListHandler{ export default class DoubanGameWishListHandler extends DoubanGameListHandler{
getDoType(): string { getDoType(): string {
return DoubanSubjectState.wish; return DoubanSubjectState.wish;
} }

@ -628,6 +628,7 @@ PS: This file could be delete if you want to.
'504104': `My Broadcast`, '504104': `My Broadcast`,
'504105': `My Note`, '504105': `My Note`,
'504106': `My Music`, '504106': `My Music`,
'504108': `My Game`,
'500002': `Sync Status`, '500002': `Sync Status`,

@ -641,6 +641,7 @@ export default {
'504104': `我的广播`, '504104': `我的广播`,
'504105': `我的日记`, '504105': `我的日记`,
'504106': `我的音乐`, '504106': `我的音乐`,
'504108': `我的游戏`,
'ALL': `全部类型`, 'ALL': `全部类型`,