|
|
@@ -5,6 +5,8 @@ import { WebDavAccount } from '../viewmodel/WebDavAccount';
|
|
|
import { ImagePickerUtil } from '../common/util/ImagePickerUtil';
|
|
|
import Logger from '../common/util/Logger';
|
|
|
import { ConfigurationConstant, Context } from '@kit.AbilityKit';
|
|
|
+import { BaiduConstants } from '../common/constants/BaiduConstants';
|
|
|
+import { BaiduTokenError, BaiduTokenResponse, pollAccessToken, requestDeviceCode } from '../common/network/BaiduPanClient';
|
|
|
|
|
|
interface ParsedConnectionParts {
|
|
|
protocol: string;
|
|
|
@@ -42,13 +44,21 @@ export struct RemoteDriveAccountDialog {
|
|
|
@State username: string = '';
|
|
|
@State password: string = '';
|
|
|
@State enableHttps: boolean = false;
|
|
|
- @Prop driveType: RemoteDriveType = RemoteDriveType.WebDav;
|
|
|
+ @Prop initialDriveType: RemoteDriveType = RemoteDriveType.WebDav;
|
|
|
+ @State driveType: RemoteDriveType = RemoteDriveType.WebDav;
|
|
|
@State shareName: string = '';
|
|
|
@State domain: string = '';
|
|
|
@State navidromeBasePath: string = '/rest';
|
|
|
@State coverPath: string = '';
|
|
|
@State isDarkMode: boolean = false;
|
|
|
@State ftpEncoding: string = 'utf-8';
|
|
|
+ @State baiduUserCode: string = '';
|
|
|
+ @State baiduQrUrl: string = '';
|
|
|
+ @State baiduVerificationUrl: string = '';
|
|
|
+ @State baiduAuthStatus: string = '';
|
|
|
+ @State baiduAccessToken: string = '';
|
|
|
+ @State baiduRefreshToken: string = '';
|
|
|
+ @State baiduTokenExpiresAt: number = 0;
|
|
|
@StorageProp('themeColor') themeColor: string = CommonConstants.DEFAULT_THEME_COLOR;
|
|
|
@StorageProp('currentColorMode') @Watch('onColorModeChange') currentMode: number =
|
|
|
ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
|
|
|
@@ -57,16 +67,18 @@ export struct RemoteDriveAccountDialog {
|
|
|
private nameCustomized: boolean = false;
|
|
|
private portCustomized: boolean = false;
|
|
|
private navBasePathCustomized: boolean = false;
|
|
|
+ private baiduDeviceCode?: string;
|
|
|
+ private baiduDeviceCodeExpireAt: number = 0;
|
|
|
+ private baiduPollingTimer?: number;
|
|
|
|
|
|
onColorModeChange() {
|
|
|
this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK
|
|
|
}
|
|
|
|
|
|
aboutToAppear(): void {
|
|
|
- console.info('heanup driveType = ' +this.driveType)
|
|
|
- // 初始化深色模式状态
|
|
|
- this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK
|
|
|
- if(this.isEditMode){
|
|
|
+ console.info('heanup driveType = ' + this.driveType);
|
|
|
+ this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
|
|
|
+ if (this.isEditMode) {
|
|
|
this.accountName = this.account.name;
|
|
|
this.host = this.account.host;
|
|
|
this.updatePortState(this.account.port, true);
|
|
|
@@ -79,6 +91,9 @@ export struct RemoteDriveAccountDialog {
|
|
|
this.domain = this.account.smbDomain ?? '';
|
|
|
this.coverPath = this.account.coverPath || '';
|
|
|
this.ftpEncoding = this.account.ftpEncoding ?? 'utf-8';
|
|
|
+ this.baiduAccessToken = this.account.baiduAccessToken ?? '';
|
|
|
+ this.baiduRefreshToken = this.account.baiduRefreshToken ?? '';
|
|
|
+ this.baiduTokenExpiresAt = this.account.baiduTokenExpiresAt ?? 0;
|
|
|
this.nameCustomized = true;
|
|
|
if (this.driveType === RemoteDriveType.Navidrome) {
|
|
|
this.navidromeBasePath = this.normalizeNavidromeBasePath(this.account.navidromeBasePath ?? '/rest');
|
|
|
@@ -89,11 +104,18 @@ export struct RemoteDriveAccountDialog {
|
|
|
Logger.info('heanup RemoteDriveAccountDialog', `封面文件是否存在: ${ImagePickerUtil.imageExists(this.coverPath)}`);
|
|
|
}
|
|
|
} else {
|
|
|
- // this.applyTypeDefaults(this.driveType);
|
|
|
+ this.driveType = this.initialDriveType ?? RemoteDriveType.WebDav;
|
|
|
+ this.baiduAccessToken = '';
|
|
|
+ this.baiduRefreshToken = '';
|
|
|
+ this.baiduTokenExpiresAt = 0;
|
|
|
this.handleDriveTypeChange(this.driveType, true);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ aboutToDisappear(): void {
|
|
|
+ this.stopBaiduPolling();
|
|
|
+ }
|
|
|
+
|
|
|
build() {
|
|
|
Scroll(){
|
|
|
this.contentBuilder()
|
|
|
@@ -201,6 +223,9 @@ export struct RemoteDriveAccountDialog {
|
|
|
.width('100%')
|
|
|
.alignItems(VerticalAlign.Center);
|
|
|
|
|
|
+ if (this.driveType === RemoteDriveType.Baidu) {
|
|
|
+ this.buildBaiduAuthSection();
|
|
|
+ } else {
|
|
|
// 服务器地址
|
|
|
Row({ space: 8 }) {
|
|
|
Text(this.getServerLabel())
|
|
|
@@ -311,6 +336,7 @@ export struct RemoteDriveAccountDialog {
|
|
|
.alignItems(VerticalAlign.Center);
|
|
|
this.buildHelperText('Navidrome/Subsonic REST 前缀,默认 /rest,可填 /navidrome/rest 等路径')
|
|
|
}
|
|
|
+ } // end non-baidu block
|
|
|
|
|
|
// 文件目录
|
|
|
Row({ space: 8 }) {
|
|
|
@@ -327,52 +353,51 @@ export struct RemoteDriveAccountDialog {
|
|
|
.alignItems(VerticalAlign.Center);
|
|
|
// this.buildHelperText('从共享根开始的路径,例如 /music 或 /音乐/歌单1')
|
|
|
|
|
|
- // 用户名
|
|
|
- Row({ space: 8 }) {
|
|
|
- Text('用户名')
|
|
|
- .fontSize(14)
|
|
|
- .fontColor($r('app.color.index_tab_font_color'));
|
|
|
- TextInput({ placeholder: '请输入用户名', text: this.username })
|
|
|
- .layoutWeight(1)
|
|
|
- .maxLines(1)
|
|
|
- .onChange((value: string) => {
|
|
|
- this.username = value;
|
|
|
- });
|
|
|
- }
|
|
|
- .alignItems(VerticalAlign.Center);
|
|
|
-
|
|
|
- // 密码
|
|
|
- Row({ space: 8 }) {
|
|
|
- Text('密码')
|
|
|
- .fontSize(14)
|
|
|
- .fontColor($r('app.color.index_tab_font_color'));
|
|
|
- TextInput({ placeholder: '请输入密码', text: this.password })
|
|
|
- .type(InputType.Password)
|
|
|
- .layoutWeight(1)
|
|
|
- .maxLines(2)
|
|
|
- .onChange((value: string) => {
|
|
|
- this.password = value;
|
|
|
- });
|
|
|
- }
|
|
|
- .alignItems(VerticalAlign.Center);
|
|
|
+ if (this.driveType !== RemoteDriveType.Baidu) {
|
|
|
+ Row({ space: 8 }) {
|
|
|
+ Text('用户名')
|
|
|
+ .fontSize(14)
|
|
|
+ .fontColor($r('app.color.index_tab_font_color'));
|
|
|
+ TextInput({ placeholder: '请输入用户名', text: this.username })
|
|
|
+ .layoutWeight(1)
|
|
|
+ .maxLines(1)
|
|
|
+ .onChange((value: string) => {
|
|
|
+ this.username = value;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ .alignItems(VerticalAlign.Center);
|
|
|
|
|
|
- // HTTPS开关
|
|
|
- if (this.driveType === RemoteDriveType.WebDav) {
|
|
|
- Row() {
|
|
|
- Text('启用HTTPS')
|
|
|
+ Row({ space: 8 }) {
|
|
|
+ Text('密码')
|
|
|
.fontSize(14)
|
|
|
.fontColor($r('app.color.index_tab_font_color'));
|
|
|
- Blank();
|
|
|
- Toggle({ type: ToggleType.Switch, isOn: this.enableHttps })
|
|
|
- .selectedColor(this.themeColor)
|
|
|
- .onChange((isOn: boolean) => {
|
|
|
- this.enableHttps = isOn;
|
|
|
- if (!this.portCustomized && this.driveType === RemoteDriveType.WebDav) {
|
|
|
- this.updatePortState(this.getDefaultPort(), false);
|
|
|
- }
|
|
|
+ TextInput({ placeholder: '请输入密码', text: this.password })
|
|
|
+ .type(InputType.Password)
|
|
|
+ .layoutWeight(1)
|
|
|
+ .maxLines(2)
|
|
|
+ .onChange((value: string) => {
|
|
|
+ this.password = value;
|
|
|
});
|
|
|
}
|
|
|
- .width('100%');
|
|
|
+ .alignItems(VerticalAlign.Center);
|
|
|
+
|
|
|
+ if (this.driveType === RemoteDriveType.WebDav) {
|
|
|
+ Row() {
|
|
|
+ Text('启用HTTPS')
|
|
|
+ .fontSize(14)
|
|
|
+ .fontColor($r('app.color.index_tab_font_color'));
|
|
|
+ Blank();
|
|
|
+ Toggle({ type: ToggleType.Switch, isOn: this.enableHttps })
|
|
|
+ .selectedColor(this.themeColor)
|
|
|
+ .onChange((isOn: boolean) => {
|
|
|
+ this.enableHttps = isOn;
|
|
|
+ if (!this.portCustomized && this.driveType === RemoteDriveType.WebDav) {
|
|
|
+ this.updatePortState(this.getDefaultPort(), false);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ .width('100%');
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 按钮
|
|
|
@@ -389,21 +414,26 @@ export struct RemoteDriveAccountDialog {
|
|
|
.backgroundColor(this.themeColor)
|
|
|
.layoutWeight(1)
|
|
|
.onClick(() => {
|
|
|
- if (!this.accountName || !this.host) {
|
|
|
+ const needHost = this.driveType !== RemoteDriveType.Baidu;
|
|
|
+ if (!this.accountName || (needHost && !this.host)) {
|
|
|
ToastUtil.showToast('请填写账户名称和服务器地址');
|
|
|
return;
|
|
|
}
|
|
|
+ if (this.driveType === RemoteDriveType.Baidu && !this.baiduAccessToken) {
|
|
|
+ ToastUtil.showToast('请先完成百度网盘授权');
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
const updatedAccount = new WebDavAccount();
|
|
|
if (this.isEditMode) {
|
|
|
updatedAccount.id = this.account.id;
|
|
|
}
|
|
|
updatedAccount.name = this.accountName;
|
|
|
- updatedAccount.host = this.host;
|
|
|
- updatedAccount.port = this.port;
|
|
|
+ updatedAccount.host = this.driveType === RemoteDriveType.Baidu ? 'pan.baidu.com' : this.host;
|
|
|
+ updatedAccount.port = this.driveType === RemoteDriveType.Baidu ? 443 : this.port;
|
|
|
updatedAccount.filepath = this.filepath;
|
|
|
- updatedAccount.account = this.username;
|
|
|
- updatedAccount.password = this.password;
|
|
|
+ updatedAccount.account = this.driveType === RemoteDriveType.Baidu ? '' : this.username;
|
|
|
+ updatedAccount.password = this.driveType === RemoteDriveType.Baidu ? '' : this.password;
|
|
|
updatedAccount.enableHttps = this.enableHttps;
|
|
|
updatedAccount.coverPath = this.coverPath;
|
|
|
updatedAccount.isActivate = true;
|
|
|
@@ -417,6 +447,9 @@ export struct RemoteDriveAccountDialog {
|
|
|
updatedAccount.smbDomain = this.domain;
|
|
|
updatedAccount.navidromeBasePath = this.normalizeNavidromeBasePath(this.navidromeBasePath);
|
|
|
updatedAccount.ftpEncoding = this.ftpEncoding && this.ftpEncoding.length > 0 ? this.ftpEncoding : 'utf-8';
|
|
|
+ updatedAccount.baiduAccessToken = this.baiduAccessToken;
|
|
|
+ updatedAccount.baiduRefreshToken = this.baiduRefreshToken;
|
|
|
+ updatedAccount.baiduTokenExpiresAt = this.baiduTokenExpiresAt;
|
|
|
this.onConfirm?.(updatedAccount);
|
|
|
|
|
|
});
|
|
|
@@ -442,6 +475,7 @@ export struct RemoteDriveAccountDialog {
|
|
|
this.buildTypeButton('SMB', RemoteDriveType.Smb);
|
|
|
this.buildTypeButton('Navidrome', RemoteDriveType.Navidrome);
|
|
|
this.buildTypeButton('FTP', RemoteDriveType.Ftp);
|
|
|
+ this.buildTypeButton('百度网盘', RemoteDriveType.Baidu);
|
|
|
}
|
|
|
.width('100%');
|
|
|
}
|
|
|
@@ -461,15 +495,17 @@ export struct RemoteDriveAccountDialog {
|
|
|
|
|
|
private handleDriveTypeChange(type: RemoteDriveType, forceApply: boolean = false) {
|
|
|
const changed = this.driveType !== type;
|
|
|
- if (changed) {
|
|
|
- this.driveType = type;
|
|
|
- if (type === RemoteDriveType.Smb || type === RemoteDriveType.Ftp) {
|
|
|
- this.enableHttps = false;
|
|
|
- }
|
|
|
+ if (!changed && !forceApply) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (this.driveType === RemoteDriveType.Baidu && type !== RemoteDriveType.Baidu) {
|
|
|
+ this.stopBaiduPolling();
|
|
|
}
|
|
|
- if (changed || forceApply) {
|
|
|
- this.applyTypeDefaults(type, true);
|
|
|
+ this.driveType = type;
|
|
|
+ if (type === RemoteDriveType.Smb || type === RemoteDriveType.Ftp) {
|
|
|
+ this.enableHttps = false;
|
|
|
}
|
|
|
+ this.applyTypeDefaults(type, true);
|
|
|
}
|
|
|
|
|
|
private applyTypeDefaults(type: RemoteDriveType, forcePort: boolean = false) {
|
|
|
@@ -482,6 +518,17 @@ export struct RemoteDriveAccountDialog {
|
|
|
if (type === RemoteDriveType.Ftp && (!this.ftpEncoding || this.ftpEncoding.length === 0)) {
|
|
|
this.ftpEncoding = 'utf-8';
|
|
|
}
|
|
|
+ if (type === RemoteDriveType.Baidu) {
|
|
|
+ this.enableHttps = true;
|
|
|
+ this.host = 'pan.baidu.com';
|
|
|
+ this.username = '';
|
|
|
+ this.password = '';
|
|
|
+ this.shareName = '';
|
|
|
+ this.domain = '';
|
|
|
+ if (!this.filepath || this.filepath.length === 0) {
|
|
|
+ this.filepath = '/';
|
|
|
+ }
|
|
|
+ }
|
|
|
this.updatePortForType(type, forcePort);
|
|
|
}
|
|
|
|
|
|
@@ -500,6 +547,8 @@ export struct RemoteDriveAccountDialog {
|
|
|
return '新建Navidrome';
|
|
|
case RemoteDriveType.Ftp:
|
|
|
return '新建FTP';
|
|
|
+ case RemoteDriveType.Baidu:
|
|
|
+ return '百度网盘';
|
|
|
default:
|
|
|
return '新建WebDAV';
|
|
|
}
|
|
|
@@ -517,6 +566,8 @@ export struct RemoteDriveAccountDialog {
|
|
|
return '可粘贴 Navidrome/Subsonic 连接(如 https://user:pass@host:4533/rest),自动填充参数';
|
|
|
case RemoteDriveType.Ftp:
|
|
|
return '支持 ftp://user:pass@host:21/path 输入,自动填充账户和目录';
|
|
|
+ case RemoteDriveType.Baidu:
|
|
|
+ return '百度网盘无需服务器地址,请使用下方按钮完成授权';
|
|
|
default:
|
|
|
return '支持 https://user:pass@host:port/path WebDAV 连接串,自动填充账户、端口和目录';
|
|
|
}
|
|
|
@@ -536,6 +587,9 @@ export struct RemoteDriveAccountDialog {
|
|
|
if (this.driveType === RemoteDriveType.Ftp) {
|
|
|
return 21;
|
|
|
}
|
|
|
+ if (this.driveType === RemoteDriveType.Baidu) {
|
|
|
+ return 443;
|
|
|
+ }
|
|
|
return this.enableHttps ? 443 : 5005;
|
|
|
}
|
|
|
|
|
|
@@ -558,6 +612,22 @@ export struct RemoteDriveAccountDialog {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @Builder
|
|
|
+ private buildFileDirectoryRow() {
|
|
|
+ Row({ space: 8 }) {
|
|
|
+ Text('文件目录')
|
|
|
+ .fontSize(14)
|
|
|
+ .fontColor($r('app.color.index_tab_font_color'));
|
|
|
+ TextInput({ placeholder: '远程目录', text: this.filepath })
|
|
|
+ .layoutWeight(1)
|
|
|
+ .maxLines(1)
|
|
|
+ .onChange((value: string) => {
|
|
|
+ this.filepath = value;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ .alignItems(VerticalAlign.Center);
|
|
|
+ }
|
|
|
+
|
|
|
private tryParseConnectionString(input: string): boolean {
|
|
|
const parsed = this.parseConnectionString(input);
|
|
|
if (!parsed) {
|
|
|
@@ -718,6 +788,155 @@ export struct RemoteDriveAccountDialog {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @Builder
|
|
|
+ private buildBaiduAuthSection() {
|
|
|
+ Column({ space: 12 }) {
|
|
|
+ Text('百度账号授权')
|
|
|
+ .fontSize(14)
|
|
|
+ .fontWeight(FontWeight.Medium)
|
|
|
+ .fontColor($r('app.color.index_tab_font_color'))
|
|
|
+ .alignSelf(ItemAlign.Start);
|
|
|
+
|
|
|
+ Row({ space: 8 }) {
|
|
|
+ Button(this.baiduDeviceCode ? '刷新二维码' : '生成授权二维码')
|
|
|
+ .type(ButtonType.Capsule)
|
|
|
+ .backgroundColor(this.themeColor)
|
|
|
+ .fontColor(Color.White)
|
|
|
+ .onClick(() => {
|
|
|
+ this.handleBaiduDeviceCodeRequest();
|
|
|
+ });
|
|
|
+ if (this.baiduAccessToken) {
|
|
|
+ Button('清除授权')
|
|
|
+ .type(ButtonType.Capsule)
|
|
|
+ .backgroundColor(this.isDarkMode ? '#2C2C2E' : $r('app.color.input_background'))
|
|
|
+ .fontColor($r('app.color.index_tab_font_color'))
|
|
|
+ .onClick(() => {
|
|
|
+ this.baiduAccessToken = '';
|
|
|
+ this.baiduRefreshToken = '';
|
|
|
+ this.baiduTokenExpiresAt = 0;
|
|
|
+ this.baiduAuthStatus = '已清除授权信息';
|
|
|
+ this.stopBaiduPolling();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.baiduQrUrl) {
|
|
|
+ Image(this.baiduQrUrl)
|
|
|
+ .width(180)
|
|
|
+ .height(180)
|
|
|
+ .objectFit(ImageFit.Contain)
|
|
|
+ .backgroundColor(this.isDarkMode ? '#1C1C1E' : '#F2F2F7')
|
|
|
+ .borderRadius(12);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.baiduUserCode) {
|
|
|
+ Text(`用户码: ${this.baiduUserCode}`)
|
|
|
+ .fontSize(18)
|
|
|
+ .fontWeight(FontWeight.Bold)
|
|
|
+ .fontColor(this.themeColor);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.baiduVerificationUrl) {
|
|
|
+ Text(`也可访问 ${this.baiduVerificationUrl} 输入用户码完成授权`)
|
|
|
+ .fontSize(13)
|
|
|
+ .fontColor($r('app.color.index_tab_font_color'))
|
|
|
+ .maxLines(2);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.baiduAuthStatus) {
|
|
|
+ Text(this.baiduAuthStatus)
|
|
|
+ .fontSize(13)
|
|
|
+ .fontColor(this.isDarkMode ? '#EBEBF5' : '#666666')
|
|
|
+ .maxLines(2);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.baiduAccessToken) {
|
|
|
+ Text(`已获取 Access Token,${this.baiduTokenExpiresAt > 0 ? `将在 ${this.getBaiduExpireText()} 过期` : '有效期未知'}`)
|
|
|
+ .fontSize(13)
|
|
|
+ .fontColor(this.isDarkMode ? '#EBEBF5' : '#666666');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .width('100%');
|
|
|
+ }
|
|
|
+
|
|
|
+ private getBaiduExpireText(): string {
|
|
|
+ if (!this.baiduTokenExpiresAt) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ const remain = Math.max(0, this.baiduTokenExpiresAt - Date.now());
|
|
|
+ const hours = Math.floor(remain / 3600000);
|
|
|
+ const minutes = Math.floor((remain % 3600000) / 60000);
|
|
|
+ return hours > 0 ? `${hours}小时${minutes}分后` : `${minutes}分钟后`;
|
|
|
+ }
|
|
|
+
|
|
|
+ private async handleBaiduDeviceCodeRequest(): Promise<void> {
|
|
|
+ try {
|
|
|
+ this.baiduAuthStatus = '正在获取设备码...';
|
|
|
+ const response = await requestDeviceCode();
|
|
|
+ this.baiduDeviceCode = response.device_code;
|
|
|
+ this.baiduUserCode = response.user_code;
|
|
|
+ this.baiduVerificationUrl = response.verification_url;
|
|
|
+ this.baiduQrUrl = response.qrcode_url;
|
|
|
+ this.baiduDeviceCodeExpireAt = Date.now() + response.expires_in * 1000;
|
|
|
+ this.baiduAuthStatus = '请使用百度网盘或百度APP扫码授权';
|
|
|
+ this.startBaiduPolling(response.device_code, response.interval);
|
|
|
+ } catch (error) {
|
|
|
+ this.baiduAuthStatus = `获取设备码失败: ${(error as Error).message}`;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private startBaiduPolling(deviceCode: string, intervalSeconds: number): void {
|
|
|
+ this.stopBaiduPolling();
|
|
|
+ const interval = Math.max(intervalSeconds || BaiduConstants.DEFAULT_POLL_INTERVAL, BaiduConstants.DEFAULT_POLL_INTERVAL) * 1000;
|
|
|
+ const timerId = setInterval(() => {
|
|
|
+ this.pollBaiduAuthorization(deviceCode).catch((err: Error) => {
|
|
|
+ Logger.error('RemoteDriveAccountDialog', `poll baidu auth failed: ${err.message}`);
|
|
|
+ });
|
|
|
+ }, interval);
|
|
|
+ this.baiduPollingTimer = timerId as number;
|
|
|
+ }
|
|
|
+
|
|
|
+ private stopBaiduPolling(): void {
|
|
|
+ if (this.baiduPollingTimer !== undefined) {
|
|
|
+ clearInterval(this.baiduPollingTimer);
|
|
|
+ this.baiduPollingTimer = undefined;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private async pollBaiduAuthorization(deviceCode: string): Promise<void> {
|
|
|
+ if (!this.baiduDeviceCode || Date.now() > this.baiduDeviceCodeExpireAt) {
|
|
|
+ this.stopBaiduPolling();
|
|
|
+ this.baiduAuthStatus = '二维码已过期,请重新获取';
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const result = await pollAccessToken(deviceCode);
|
|
|
+ if ((result as BaiduTokenError).error) {
|
|
|
+ const errorResult = result as BaiduTokenError;
|
|
|
+ switch (errorResult.error) {
|
|
|
+ case 'authorization_pending':
|
|
|
+ this.baiduAuthStatus = '等待用户确认授权...';
|
|
|
+ return;
|
|
|
+ case 'slow_down':
|
|
|
+ this.baiduAuthStatus = '授权中,请稍候...';
|
|
|
+ return;
|
|
|
+ case 'expired_token':
|
|
|
+ this.stopBaiduPolling();
|
|
|
+ this.baiduAuthStatus = '设备码已过期,请重新获取';
|
|
|
+ return;
|
|
|
+ default:
|
|
|
+ this.stopBaiduPolling();
|
|
|
+ this.baiduAuthStatus = `授权失败: ${errorResult.error}`;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const token = result as BaiduTokenResponse;
|
|
|
+ this.baiduAccessToken = token.access_token;
|
|
|
+ this.baiduRefreshToken = token.refresh_token ?? this.baiduRefreshToken;
|
|
|
+ this.baiduTokenExpiresAt = token.expires_in ? Date.now() + token.expires_in * 1000 : 0;
|
|
|
+ this.baiduAuthStatus = '授权成功,可保存账户';
|
|
|
+ this.stopBaiduPolling();
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 处理选择封面
|
|
|
*/
|