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.note]: i18nHelper.getMessage('504105'),
[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 {
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'),
}
// @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 } = {
[ALL]: i18nHelper.getMessage('500004'),
}
@ -129,7 +138,7 @@ export const DoubanSubjectStateRecords_SYNC: { [key in SyncType]: Record<DoubanS
[SyncType.book]:DoubanSubjectStateRecords_BOOK_SYNC,
[SyncType.music]:DoubanSubjectStateRecords_MUSIC_SYNC,
// [SyncType.note]:DoubanSubjectStateRecords_NOTE_SYNC,
// [SyncType.game]:DoubanSubjectStateRecords_GAME_SYNC,
[SyncType.game]:DoubanSubjectStateRecords_GAME_SYNC,
[SyncType.teleplay]:DoubanSubjectStateRecords_TELEPLAY_SYNC,
// [SyncType.theater]:DoubanSubjectStateRecords_THEATER_SYNC,
}

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

@ -82,7 +82,7 @@ export function constructLoginSettingsUI(containerEl: HTMLElement, manager: Sett
'a',
{
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.setAttr('target', '_blank');

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

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

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

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

@ -1,5 +1,13 @@
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 {
getSyncType(): SyncType {
@ -8,6 +16,90 @@ export abstract class DoubanGameListHandler extends DoubanAbstractListHandler {
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";
export default class DoubanGameWishListHandler extends DoubanMovieListHandler{
export default class DoubanGameWishListHandler extends DoubanGameListHandler{
getDoType(): string {
return DoubanSubjectState.wish;
}

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

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