Merge pull request #1561 from koodo-reader/dev

update to 2.2.3
This commit is contained in:
troyeguo
2025-12-03 09:53:31 +08:00
committed by GitHub
39 changed files with 385 additions and 302 deletions

View File

@@ -51,6 +51,15 @@ jobs:
run: echo "USE_SYSTEM_FPM=true" >> $GITHUB_ENV
- name: Set environment variable USE_HARD_LINKS
run: echo "USE_HARD_LINKS=false" >> $GITHUB_ENV
- name: Modify package.json for dev branch
if: github.ref == 'refs/heads/dev'
shell: bash
run: |
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
powershell -Command "(Get-Content package.json) -replace '\"productName\": \"Koodo Reader\"', '\"productName\": \"Koodo Reader DEV\"' | Set-Content package.json"
else
sed -i.bak 's/"productName": "Koodo Reader"/"productName": "Koodo Reader DEV"/' package.json
fi
- name: Modify package.json for Linux arm64 build
if: startsWith(matrix.os, 'ubuntu-24.04-arm')
run: |

View File

@@ -669,12 +669,12 @@ const createMainWin = () => {
ipcMain.handle("reload-reader", (event, arg) => {
if (readerWindowList.length > 0) {
readerWindowList.forEach(win => {
if (win && !win.isDestroyed()) {
if (win && !win.isDestroyed() && win.webContents.getURL().indexOf(arg.bookKey) > -1) {
win.reload();
}
})
}
if (readerWindow && !readerWindow.isDestroyed()) {
if (readerWindow && !readerWindow.isDestroyed() && readerWindow.webContents.getURL().indexOf(arg.bookKey) > -1) {
readerWindow.reload();
}
});
@@ -697,7 +697,6 @@ const createMainWin = () => {
hasShadow: true,
transparent: false,
});
console.log(config.url)
chatWindow.loadURL(config.url);
chatWindow.on("close", (event) => {
chatWindow && chatWindow.destroy();
@@ -720,7 +719,6 @@ const createMainWin = () => {
}
});
ipcMain.on('picker-action', (event, config) => {
console.log("Picker finished with data:", config);
//将数据传递给主窗口
if (mainWin && !mainWin.isDestroyed() && config.action === 'picked') {

View File

@@ -1,7 +1,7 @@
{
"name": "koodo-reader",
"main": "main.js",
"version": "2.2.2",
"version": "2.2.3",
"description": "Koodo Reader is a cross-platform ebook reader",
"author": {
"name": "App by Troye",

View File

File diff suppressed because one or more lines are too long

View File

File diff suppressed because one or more lines are too long

View File

File diff suppressed because one or more lines are too long

View File

@@ -208,6 +208,8 @@
"Note": "笔记",
"Page width": "页面宽度",
"Tasks failed after multiple retries, please check the network connection": "多次重试后任务失败,请检查网络连接",
"Tasks failed after multiple retries, please check the network connection or reauthorize the data source in the settings": "多次重试后任务失败,请检查网络连接或在设置中重新授权数据源",
"This data source already contains a library. If you need to merge local and cloud data, please turn off Koodo Sync and resync.": "此数据源已经存在了一个图书库,如果需要将本地和云端的数据合并。请关闭 Koodo Sync 后重新同步。",
"Render PDF from even page": "从偶数页开始渲染 PDF",
"Filter by book": "按图书筛选",
"Server path (Please first create this folder manually)": "服务器路径(请先手动创建此文件夹)",
@@ -337,7 +339,11 @@
"Start Transferring Data": "开始传输数据",
"Download successful": "下载成功",
"Download failed": "下载失败",
"If you have purchased the code directly from our website, please redeem with an account registered in global server region": "如果您是直接从我们的网站购买的兑换码,请使用在全球服务器地区注册的账户进行兑换",
"If you have purchased the code from Tabao store, please redeem with an account registered in Chinese server region": "如果您是从淘宝店铺购买的兑换码,请使用在中国服务器地区注册的账户进行兑换",
"Downloading": "下载中",
"Send email": "发送邮件",
"Email copied to clipboard": "邮箱已复制到剪贴板",
"Back": "返回",
"Almost finished": "即将完成",
"Please select an empty folder": "请选择一个空文件夹",

View File

@@ -2,7 +2,7 @@ import React from "react";
import { Trans } from "react-i18next";
import { AboutDialogProps, AboutDialogState } from "./interface";
import { isElectron } from "react-device-detect";
import { openExternalUrl, WEBSITE_URL } from "../../../utils/common";
import { getWebsiteUrl, openExternalUrl } from "../../../utils/common";
import toast from "react-hot-toast";
import {
exportBooks,
@@ -13,8 +13,7 @@ import {
import "./aboutDialog.css";
import DatabaseService from "../../../utils/storage/databaseService";
import { ConfigService } from "../../../assets/lib/kookit-extra-browser.min";
import ConfigUtil from "../../../utils/file/configUtil";
import copyTextToClipboard from "copy-text-to-clipboard";
declare var window: any;
class AboutDialog extends React.Component<AboutDialogProps, AboutDialogState> {
constructor(props: AboutDialogProps) {
@@ -59,9 +58,9 @@ class AboutDialog extends React.Component<AboutDialogProps, AboutDialogState> {
ConfigService.getReaderConfig("lang") &&
ConfigService.getReaderConfig("lang").startsWith("zh")
) {
this.handleJump(WEBSITE_URL + "/zh/document");
this.handleJump(getWebsiteUrl() + "/zh/document");
} else {
this.handleJump(WEBSITE_URL + "/en/document");
this.handleJump(getWebsiteUrl() + "/en/document");
}
}}
>
@@ -74,9 +73,9 @@ class AboutDialog extends React.Component<AboutDialogProps, AboutDialogState> {
ConfigService.getReaderConfig("lang") &&
ConfigService.getReaderConfig("lang").startsWith("zh")
) {
openExternalUrl(WEBSITE_URL + "/zh/support");
openExternalUrl(getWebsiteUrl() + "/zh/support");
} else {
openExternalUrl(WEBSITE_URL + "/en/support");
openExternalUrl(getWebsiteUrl() + "/en/support");
}
}}
>
@@ -85,11 +84,20 @@ class AboutDialog extends React.Component<AboutDialogProps, AboutDialogState> {
<li
className="sort-by-category-list"
onClick={() => {
this.handleJump(WEBSITE_URL);
this.handleJump(getWebsiteUrl());
}}
>
<Trans>Our website</Trans>
</li>
<li
className="sort-by-category-list"
onClick={() => {
copyTextToClipboard("feedback@koodoreader.com");
toast.success(this.props.t("Email copied to clipboard"));
}}
>
<Trans>Send email</Trans>
</li>
<li
className="sort-by-category-list"
onClick={() => {
@@ -125,7 +133,7 @@ class AboutDialog extends React.Component<AboutDialogProps, AboutDialogState> {
<li
className="sort-by-category-list"
onClick={() => {
this.handleJump(WEBSITE_URL);
this.handleJump(getWebsiteUrl());
}}
style={{ color: "rgb(35, 170, 242)" }}
>

View File

@@ -14,7 +14,7 @@ import {
ConfigService,
TokenService,
} from "../../../assets/lib/kookit-extra-browser.min";
import { generateSyncRecord } from "../../../utils/common";
import { generateSyncRecord, getServerRegion } from "../../../utils/common";
const successOptions = {
loop: false,
autoplay: true,
@@ -157,7 +157,7 @@ class BackupDialog extends React.Component<
{[
{ label: "Local", value: "local", isPro: false },
...driveList.filter((item) => {
if (ConfigService.getItem("serverRegion") === "china") {
if (getServerRegion() === "china") {
return item.isCNAvailable;
}
return true;
@@ -211,7 +211,7 @@ class BackupDialog extends React.Component<
{[
{ label: "Local", value: "local", isPro: false },
...driveList.filter((item) => {
if (ConfigService.getItem("serverRegion") === "china") {
if (getServerRegion() === "china") {
return item.isCNAvailable;
}
return true;

View File

@@ -48,7 +48,7 @@ class ConvertDialog extends React.Component<
item.propName,
this.state[item.propName] ? "no" : "yes"
);
BookUtil.reloadBooks();
BookUtil.reloadBooks(this.props.currentBook);
}}
style={this.state[item.propName] ? {} : { opacity: 0.6 }}
>
@@ -123,7 +123,7 @@ class ConvertDialog extends React.Component<
if (
ConfigService.getReaderConfig("isConvertPDF") === "yes"
) {
BookUtil.reloadBooks();
BookUtil.reloadBooks(this.props.currentBook);
}
}}
>
@@ -182,7 +182,7 @@ class ConvertDialog extends React.Component<
if (
ConfigService.getReaderConfig("isConvertPDF") === "yes"
) {
BookUtil.reloadBooks();
BookUtil.reloadBooks(this.props.currentBook);
}
}}
>
@@ -237,7 +237,7 @@ class ConvertDialog extends React.Component<
ConfigService.getReaderConfig("isConvertPDF") ===
"yes"
) {
BookUtil.reloadBooks();
BookUtil.reloadBooks(this.props.currentBook);
}
}}
>
@@ -298,7 +298,7 @@ class ConvertDialog extends React.Component<
ConfigService.getReaderConfig("isConvertPDF") ===
"yes"
) {
BookUtil.reloadBooks();
BookUtil.reloadBooks(this.props.currentBook);
}
}}
>

View File

@@ -9,6 +9,7 @@ import { isElectron } from "react-device-detect";
import { getCloudConfig } from "../../../utils/file/common";
import SyncService from "../../../utils/storage/syncService";
import {
getServerRegion,
getStorageLocation,
openInBrowser,
showDownloadProgress,
@@ -368,7 +369,7 @@ class ImportDialog extends React.Component<
<>
{driveList
.filter((item) => {
if (ConfigService.getItem("serverRegion") === "china") {
if (getServerRegion() === "china") {
return item.isCNAvailable;
}
return true;
@@ -411,8 +412,7 @@ class ImportDialog extends React.Component<
) {
openInBrowser(
new SyncUtil(settingDrive, {}).getAuthUrl(
ConfigService.getItem("serverRegion") ===
"china" &&
getServerRegion() === "china" &&
(settingDrive === "microsoft" ||
settingDrive === "microsoft_exp" ||
settingDrive === "adrive")

View File

@@ -68,29 +68,17 @@ class SortDialog extends React.Component<SortDialogProps, SortDialogState> {
onMouseEnter={() => {
this.props.handleSortDisplay(true);
}}
style={this.state.isNote ? { height: "132px" } : {}}
style={this.state.isNote ? { height: "102px" } : {}}
>
{this.state.isNote ? (
<ul className="sort-by-category">
{["Book name", "Sort by Date"].map((item, index) => {
return (
<li
className="sort-by-category-list"
onClick={() => {
this.handleSort(index + 1);
}}
style={sortCode.sort === index + 1 ? {} : { opacity: 0.34 }}
>
<Trans>{item}</Trans>
{sortCode.sort === index + 1 && (
<span
className="icon-check"
style={{ fontWeight: "bold" }}
></span>
)}
</li>
);
})}
<li className="sort-by-category-list">
<Trans>{"Sort by Date"}</Trans>
<span
className="icon-check"
style={{ fontWeight: "bold" }}
></span>
</li>
</ul>
) : (
<ul className="sort-by-category">

View File

@@ -6,9 +6,10 @@ import Lottie from "react-lottie";
import supportAnimation from "../../../assets/lotties/support.json";
import exitAnimation from "../../../assets/lotties/exit.json";
import {
getServerRegion,
getWebsiteUrl,
handleContextMenu,
openInBrowser,
WEBSITE_URL,
} from "../../../utils/common";
import {
ConfigService,
@@ -237,6 +238,27 @@ class SupporDialog extends React.Component<
id: "redeem-code",
}
);
if (response.code === 10009) {
if (getServerRegion() === "china") {
toast(
this.props.t(
"If you have purchased the code directly from our website, please redeem with an account registered in global server region"
),
{
duration: 8000,
}
);
} else {
toast(
this.props.t(
"If you have purchased the code from Tabao store, please redeem with an account registered in Chinese server region"
),
{
duration: 8000,
}
);
}
}
}
}}
>
@@ -338,7 +360,7 @@ class SupporDialog extends React.Component<
let deviceUuid =
await TokenService.getFingerprint();
openInBrowser(
WEBSITE_URL +
getWebsiteUrl() +
(ConfigService.getReaderConfig(
"lang"
).startsWith("zh")

View File

@@ -5,7 +5,7 @@ import packageInfo from "../../../../package.json";
import { Trans } from "react-i18next";
import Lottie from "react-lottie";
import animationNew from "../../../assets/lotties/new.json";
import { openExternalUrl, WEBSITE_URL } from "../../../utils/common";
import { getWebsiteUrl, openExternalUrl } from "../../../utils/common";
import { isElectron } from "react-device-detect";
import { sleep } from "../../../utils/common";
import {
@@ -207,7 +207,7 @@ class UpdateInfo extends React.Component<UpdateInfoProps, UpdateInfoState> {
lang = "zh";
}
openExternalUrl(
WEBSITE_URL +
getWebsiteUrl() +
"/" +
lang +
"/download" +
@@ -238,7 +238,7 @@ class UpdateInfo extends React.Component<UpdateInfoProps, UpdateInfoState> {
lang = "zh";
}
openExternalUrl(
WEBSITE_URL +
getWebsiteUrl() +
"/" +
lang +
"/download" +

View File

@@ -6,9 +6,9 @@ import Parser from "html-react-parser";
import DOMPurify from "dompurify";
import { Trans } from "react-i18next";
import {
getWebsiteUrl,
handleContextMenu,
openExternalUrl,
WEBSITE_URL,
} from "../../../utils/common";
import toast from "react-hot-toast";
import DatabaseService from "../../../utils/storage/databaseService";
@@ -348,9 +348,9 @@ class PopupAssist extends React.Component<PopupAssistProps, PopupAssistState> {
ConfigService.getReaderConfig("lang") &&
ConfigService.getReaderConfig("lang").startsWith("zh")
) {
openExternalUrl(WEBSITE_URL + "/zh/plugin");
openExternalUrl(getWebsiteUrl() + "/zh/plugin");
} else {
openExternalUrl(WEBSITE_URL + "/en/plugin");
openExternalUrl(getWebsiteUrl() + "/en/plugin");
}
}}
>

View File

@@ -8,9 +8,9 @@ import axios from "axios";
import DictHistory from "../../../models/DictHistory";
import { Trans } from "react-i18next";
import {
getWebsiteUrl,
handleContextMenu,
openExternalUrl,
WEBSITE_URL,
} from "../../../utils/common";
import toast from "react-hot-toast";
import DatabaseService from "../../../utils/storage/databaseService";
@@ -114,7 +114,7 @@ class PopupDict extends React.Component<PopupDictProps, PopupDictState> {
let moreElement = document.querySelector(".dict-learn-more");
if (moreElement) {
moreElement.addEventListener("click", () => {
openExternalUrl(window.learnMoreUrl || WEBSITE_URL);
openExternalUrl(window.learnMoreUrl || getWebsiteUrl());
});
}
}
@@ -273,9 +273,9 @@ class PopupDict extends React.Component<PopupDictProps, PopupDictState> {
ConfigService.getReaderConfig("lang") &&
ConfigService.getReaderConfig("lang").startsWith("zh")
) {
openExternalUrl(WEBSITE_URL + "/zh/plugin");
openExternalUrl(getWebsiteUrl() + "/zh/plugin");
} else {
openExternalUrl(WEBSITE_URL + "/en/plugin");
openExternalUrl(getWebsiteUrl() + "/en/plugin");
}
}}
>

View File

@@ -7,9 +7,9 @@ import { Trans } from "react-i18next";
import toast from "react-hot-toast";
import {
getDefaultTransTarget,
getWebsiteUrl,
handleContextMenu,
openExternalUrl,
WEBSITE_URL,
} from "../../../utils/common";
import DatabaseService from "../../../utils/storage/databaseService";
import { checkPlugin } from "../../../utils/common";
@@ -214,9 +214,9 @@ class PopupTrans extends React.Component<PopupTransProps, PopupTransState> {
ConfigService.getReaderConfig("lang") &&
ConfigService.getReaderConfig("lang").startsWith("zh")
) {
openExternalUrl(WEBSITE_URL + "/zh/plugin");
openExternalUrl(getWebsiteUrl() + "/zh/plugin");
} else {
openExternalUrl(WEBSITE_URL + "/en/plugin");
openExternalUrl(getWebsiteUrl() + "/en/plugin");
}
}}
>

View File

@@ -6,10 +6,10 @@ import { ConfigService } from "../../assets/lib/kookit-extra-browser.min";
import {
checkPlugin,
getAllVoices,
getWebsiteUrl,
handleContextMenu,
sleep,
splitSentences,
WEBSITE_URL,
} from "../../utils/common";
import { isElectron } from "react-device-detect";
import toast from "react-hot-toast";
@@ -536,9 +536,9 @@ class TextToSpeech extends React.Component<
ConfigService.getReaderConfig("lang") &&
ConfigService.getReaderConfig("lang").startsWith("zh")
) {
openExternalUrl(WEBSITE_URL + "/zh/plugin");
openExternalUrl(getWebsiteUrl() + "/zh/plugin");
} else {
openExternalUrl(WEBSITE_URL + "/en/plugin");
openExternalUrl(getWebsiteUrl() + "/en/plugin");
}
}}
>

View File

@@ -31,21 +31,21 @@ import {
checkMissingBook,
generateSyncRecord,
getChatLocale,
getStorageLocation,
getWebsiteUrl,
removeChatBox,
resetKoodoSync,
showTaskProgress,
WEBSITE_URL,
} from "../../utils/common";
import { driveList } from "../../constants/driveList";
import SupportDialog from "../../components/dialogs/supportDialog";
import SyncService from "../../utils/storage/syncService";
import { LocalFileManager } from "../../utils/file/localFile";
import { updateUserConfig } from "../../utils/request/user";
import packageJson from "../../../package.json";
declare var window: any;
class Header extends React.Component<HeaderProps, HeaderState> {
timer: any;
private isSyncing: boolean = false;
constructor(props: HeaderProps) {
super(props);
@@ -132,8 +132,13 @@ class Header extends React.Component<HeaderProps, HeaderState> {
});
this.props.handleCloudSyncFunc(this.handleCloudSync);
document.addEventListener("visibilitychange", async (event) => {
if (document.visibilityState === "visible") {
if (
document.visibilityState === "visible" &&
!isElectron &&
ConfigService.getReaderConfig("isFinishWebReading") === "yes"
) {
this.handleFinishReading();
ConfigService.setReaderConfig("isFinishWebReading", "no");
}
});
}
@@ -171,27 +176,24 @@ class Header extends React.Component<HeaderProps, HeaderState> {
}
}
handleFinishReading = async () => {
if (!this.props.isLoadMore) {
this.props.handleFetchBooks();
}
this.props.handleFetchBookmarks();
this.props.handleFetchNotes();
if (ConfigService.getItem("isFinshReading") === "yes") {
ConfigService.setItem("isFinshReading", "no");
if (
ConfigService.getReaderConfig("isDisableAutoSync") !== "yes" &&
ConfigService.getItem("defaultSyncOption")
) {
await this.props.handleFetchUserInfo();
this.setState({ isSync: true });
this.handleCloudSync();
}
ConfigService.setItem("isFinshReading", "yes");
if (
ConfigService.getReaderConfig("isDisableAutoSync") !== "yes" &&
ConfigService.getItem("defaultSyncOption") &&
!this.state.isSync
) {
await this.props.handleFetchUserInfo();
this.setState({ isSync: true }, async () => {
await this.handleCloudSync();
ConfigService.setItem("isFinshReading", "no");
});
}
};
handleFinishUpgrade = () => {
setTimeout(() => {
this.props.history.push("/manager/home");
if (this.props.mode === "home") {
this.props.history.push("/manager/home");
}
}, 2000);
};
@@ -247,7 +249,6 @@ class Header extends React.Component<HeaderProps, HeaderState> {
beforeSync = async () => {
if (!ConfigService.getItem("defaultSyncOption")) {
toast.error(this.props.t("Please add data source in the setting"));
this.setState({ isSync: false });
return false;
}
if (
@@ -269,7 +270,6 @@ class Header extends React.Component<HeaderProps, HeaderState> {
duration: 4000,
}
);
this.setState({ isSync: false });
return false;
}
let config = await getCloudConfig(
@@ -277,7 +277,6 @@ class Header extends React.Component<HeaderProps, HeaderState> {
);
if (Object.keys(config).length === 0) {
toast.error(this.props.t("Cannot get sync config"));
this.setState({ isSync: false });
return false;
}
if (
@@ -301,16 +300,7 @@ class Header extends React.Component<HeaderProps, HeaderState> {
this.props.handleFetchDefaultSyncOption();
}
if (ConfigService.getReaderConfig("isEnableKoodoSync") === "yes") {
await updateUserConfig({
is_enable_koodo_sync: "no",
default_sync_option:
ConfigService.getItem("defaultSyncOption") === "google",
});
setTimeout(() => {
updateUserConfig({
is_enable_koodo_sync: "yes",
});
}, 1000);
resetKoodoSync();
}
toast(
this.props.t(
@@ -318,7 +308,6 @@ class Header extends React.Component<HeaderProps, HeaderState> {
),
{ duration: 4000 }
);
this.setState({ isSync: false });
return false;
}
checkMissingBook(this.props.books);
@@ -329,7 +318,6 @@ class Header extends React.Component<HeaderProps, HeaderState> {
"Broken data detected, please click the setting button to reset the sync records"
)
);
this.setState({ isSync: false });
return false;
}
if (ConfigService.getReaderConfig("isEnableKoodoSync") !== "yes") {
@@ -360,12 +348,23 @@ class Header extends React.Component<HeaderProps, HeaderState> {
ConfigUtil
);
};
handleSyncStateChange = (isSyncing: boolean) => {
this.setState({ isSync: isSyncing });
};
handleCloudSync = async (): Promise<false | undefined> => {
this.timer = await showTaskProgress();
if (!this.timer) {
if (this.isSyncing) {
console.info("Sync already in progress, skipping...");
return false;
}
this.isSyncing = true;
try {
this.timer = await showTaskProgress(this.handleSyncStateChange);
if (!this.timer) {
this.setState({ isSync: false });
return false;
}
let res = await this.beforeSync();
if (!res) {
clearInterval(this.timer);
@@ -389,6 +388,8 @@ class Header extends React.Component<HeaderProps, HeaderState> {
clearInterval(this.timer);
this.setState({ isSync: false });
return false;
} finally {
this.isSyncing = false;
}
setTimeout(() => {
toast.dismiss("syncing");
@@ -396,9 +397,10 @@ class Header extends React.Component<HeaderProps, HeaderState> {
return;
};
handleSuccess = async () => {
if (!this.props.isLoadMore) {
if (ConfigService.getItem("isFinshReading") !== "yes" || !isElectron) {
this.props.handleFetchBooks();
}
this.props.handleFetchBookmarks();
this.props.handleFetchNotes();
toast.success(this.props.t("Synchronisation successful"), {
@@ -424,7 +426,9 @@ class Header extends React.Component<HeaderProps, HeaderState> {
}
//when book is empty, need to refresh the book list
setTimeout(() => {
this.props.history.push("/manager/home");
if (this.props.mode === "home") {
this.props.history.push("/manager/home");
}
}, 1000);
};
handleSync = async (compareResult) => {
@@ -498,7 +502,7 @@ class Header extends React.Component<HeaderProps, HeaderState> {
onClick={() => {
window.require("electron").ipcRenderer.invoke("new-chat", {
url:
WEBSITE_URL +
getWebsiteUrl() +
(ConfigService.getReaderConfig("lang").startsWith("zh")
? "/zh/faq"
: "/en/faq") +

View File

@@ -30,6 +30,7 @@ const mapStateToProps = (state: stateType) => {
isCollapsed: state.sidebar.isCollapsed,
isNewWarning: state.manager.isNewWarning,
notes: state.reader.notes,
mode: state.sidebar.mode,
isAuthed: state.manager.isAuthed,
defaultSyncOption: state.backupPage.defaultSyncOption,
userInfo: state.manager.userInfo,

View File

@@ -14,6 +14,7 @@ export interface HeaderProps extends RouteComponentProps<any> {
notes: NoteModel[];
books: BookModel[];
defaultSyncOption: string;
mode: string;
userInfo: any;
bookSortCode: { sort: number; order: number };
handleSortDisplay: (isSortDisplay: boolean) => void;

View File

@@ -3,10 +3,8 @@ import "./cardList.css";
import NoteModel from "../../../models/Note";
import { Trans } from "react-i18next";
import { CardListProps, CardListStates } from "./interface";
import DeleteIcon from "../../../components/deleteIcon";
import { withRouter } from "react-router-dom";
import { Redirect } from "react-router-dom";
import NoteTag from "../../../components/noteTag";
import BookUtil from "../../../utils/file/bookUtil";
import toast from "react-hot-toast";
import BookModel from "../../../models/Book";
@@ -52,13 +50,13 @@ class CardList extends React.Component<CardListProps, CardListStates> {
}
loadInitialCards = () => {
let sortedCards = Object.values(
SortUtil.sortNotes(
this.props.cards,
this.props.noteSortCode,
this.props.books
)
).flat() as NoteModel[];
let sortedCards = [...this.props.cards];
// 按照key排序
sortedCards.sort((a, b) => {
return this.props.noteSortCode.order === 2
? b.key.localeCompare(a.key)
: a.key.localeCompare(b.key);
});
const { itemsPerPage } = this.state;
// 根据屏幕大小动态调整每页显示的卡片数量
@@ -75,13 +73,12 @@ class CardList extends React.Component<CardListProps, CardListStates> {
};
loadMoreCards = () => {
let sortedCards = Object.values(
SortUtil.sortNotes(
this.props.cards,
this.props.noteSortCode,
this.props.books
)
).flat() as NoteModel[];
let sortedCards = [...this.props.cards];
sortedCards.sort((a, b) => {
return this.props.noteSortCode.order === 2
? b.key.localeCompare(a.key)
: a.key.localeCompare(b.key);
});
const { displayedCards, currentPage, itemsPerPage, isLoading } = this.state;
if (isLoading || displayedCards.length >= sortedCards.length) {

View File

@@ -70,7 +70,6 @@ class OperationPanel extends React.Component<
}
async handleExit() {
ConfigService.setReaderConfig("isFullscreen", "no");
ConfigService.setItem("isFinshReading", "yes");
this.props.handleReadingState(false);
this.props.handleSearch(false);
window.speechSynthesis && window.speechSynthesis.cancel();
@@ -86,6 +85,7 @@ class OperationPanel extends React.Component<
window.close();
}
} else {
ConfigService.setReaderConfig("isFinishWebReading", "yes");
window.close();
}
}

View File

@@ -3,16 +3,15 @@ import { SettingInfoProps, SettingInfoState } from "./interface";
import { Trans } from "react-i18next";
import { isElectron } from "react-device-detect";
import _ from "underscore";
import { themeList } from "../../../constants/themeList";
import toast from "react-hot-toast";
import {
formatTimestamp,
getServerRegion,
getWebsiteUrl,
handleContextMenu,
openInBrowser,
reloadManager,
WEBSITE_URL,
} from "../../../utils/common";
import { getStorageLocation } from "../../../utils/common";
import {
CommonTool,
ConfigService,
@@ -46,7 +45,7 @@ class AccountSetting extends React.Component<
redeemCode: "",
isSendingCode: false,
countdown: 0,
serverRegion: ConfigService.getItem("serverRegion") || "global",
serverRegion: getServerRegion(),
};
}
componentDidMount(): void {
@@ -93,8 +92,7 @@ class AccountSetting extends React.Component<
let url = LoginHelper.getAuthUrl(
event.target.value,
"manual",
ConfigService.getItem("serverRegion") === "china" &&
event.target.value === "microsoft"
getServerRegion() === "china" && event.target.value === "microsoft"
? KookitConfig.ThirdpartyConfig.cnCallbackUrl
: KookitConfig.ThirdpartyConfig.callbackUrl
);
@@ -160,7 +158,7 @@ class AccountSetting extends React.Component<
KookitConfig.LoginAuthRequest[this.state.settingLogin].extraParams
.scope,
redirect_uri:
ConfigService.getItem("serverRegion") === "china" &&
getServerRegion() === "china" &&
this.state.settingLogin === "microsoft"
? KookitConfig.ThirdpartyConfig.cnCallbackUrl
: KookitConfig.ThirdpartyConfig.callbackUrl,
@@ -252,7 +250,7 @@ class AccountSetting extends React.Component<
let url = LoginHelper.getAuthUrl(
this.state.settingLogin,
"manual",
ConfigService.getItem("serverRegion") === "china" &&
getServerRegion() === "china" &&
this.state.settingLogin === "microsoft"
? KookitConfig.ThirdpartyConfig.cnCallbackUrl
: KookitConfig.ThirdpartyConfig.callbackUrl
@@ -525,6 +523,27 @@ class AccountSetting extends React.Component<
id: "redeem-code",
}
);
if (response.code === 10009) {
if (getServerRegion() === "china") {
toast(
this.props.t(
"If you have purchased the code directly from our website, please redeem with an account registered in global server region"
),
{
duration: 8000,
}
);
} else {
toast(
this.props.t(
"If you have purchased the code from Tabao store, please redeem with an account registered in Chinese server region"
),
{
duration: 8000,
}
);
}
}
}
}}
>
@@ -544,49 +563,56 @@ class AccountSetting extends React.Component<
</div>
)}
<div className="setting-dialog-new-title">
<Trans>Select server region</Trans>
<select
name=""
className="lang-setting-dropdown"
onChange={(event) => {
if (!event.target.value) {
return;
}
if (event.target.value === "china") {
toast(
this.props.t(
"Some login options and data sources are not available in your selected server region"
)
);
}
ConfigService.setItem("serverRegion", event.target.value);
this.setState({
serverRegion: event.target.value,
});
resetReaderRequest();
resetUserRequest();
resetThirdpartyRequest();
toast.success(this.props.t("Setup successful"));
}}
>
{[
{ value: "", label: "Please select" },
{ value: "global", label: "Global" },
{ value: "china", label: "China" },
].map((item) => (
<option
value={item.value}
key={item.value}
className="lang-setting-option"
selected={
item.value ===
(ConfigService.getItem("serverRegion") || "global")
<Trans>
{this.props.isAuthed ? "Server region" : "Select server region"}
</Trans>
{this.props.isAuthed ? (
<div className="lang-setting-option">
<Trans>
{getServerRegion() === "china" ? "China" : "Global"}
</Trans>
</div>
) : (
<select
name=""
className="lang-setting-dropdown"
onChange={(event) => {
if (!event.target.value) {
return;
}
>
{this.props.t(item.label)}
</option>
))}
</select>
if (event.target.value === "china") {
toast(
this.props.t(
"Some login options and data sources are not available in your selected server region"
)
);
}
ConfigService.setItem("serverRegion", event.target.value);
this.setState({
serverRegion: event.target.value,
});
resetReaderRequest();
resetUserRequest();
resetThirdpartyRequest();
toast.success(this.props.t("Setup successful"));
}}
>
{[
{ value: "", label: "Please select" },
{ value: "global", label: "Global" },
{ value: "china", label: "China" },
].map((item) => (
<option
value={item.value}
key={item.value}
className="lang-setting-option"
selected={item.value === getServerRegion()}
>
{this.props.t(item.label)}
</option>
))}
</select>
)}
</div>
{!this.props.isAuthed && (
<div className="setting-dialog-new-title">
@@ -599,7 +625,7 @@ class AccountSetting extends React.Component<
{[
{ label: "Please select", value: "" },
...loginList.filter((item) => {
if (ConfigService.getItem("serverRegion") === "china") {
if (getServerRegion() === "china") {
return item.isCNAvailable;
}
return true;
@@ -827,7 +853,7 @@ class AccountSetting extends React.Component<
onClick={async () => {
if (!this.props.isAuthed) {
openInBrowser(
WEBSITE_URL +
getWebsiteUrl() +
(ConfigService.getReaderConfig("lang").startsWith("zh")
? "/zh"
: "/en") +
@@ -840,7 +866,7 @@ class AccountSetting extends React.Component<
let tempToken = response.data.access_token;
let deviceUuid = await TokenService.getFingerprint();
openInBrowser(
WEBSITE_URL +
getWebsiteUrl() +
(ConfigService.getReaderConfig("lang").startsWith("zh")
? "/zh"
: "/en") +

View File

@@ -6,9 +6,9 @@ import { themeList } from "../../../constants/themeList";
import toast from "react-hot-toast";
import {
checkPlugin,
getWebsiteUrl,
handleContextMenu,
openExternalUrl,
WEBSITE_URL,
} from "../../../utils/common";
import { getStorageLocation } from "../../../utils/common";
import DatabaseService from "../../../utils/storage/databaseService";
@@ -152,9 +152,9 @@ class SettingDialog extends React.Component<
ConfigService.getReaderConfig("lang") &&
ConfigService.getReaderConfig("lang").startsWith("zh")
) {
openExternalUrl(WEBSITE_URL + "/zh/plugin");
openExternalUrl(getWebsiteUrl() + "/zh/plugin");
} else {
openExternalUrl(WEBSITE_URL + "/en/plugin");
openExternalUrl(getWebsiteUrl() + "/en/plugin");
}
}}
>

View File

@@ -10,13 +10,15 @@ import { themeList } from "../../../constants/themeList";
import toast from "react-hot-toast";
import {
generateSyncRecord,
getServerRegion,
getWebsiteUrl,
handleContextMenu,
openExternalUrl,
openInBrowser,
resetKoodoSync,
showTaskProgress,
testConnection,
testCORS,
WEBSITE_URL,
} from "../../../utils/common";
import { getStorageLocation } from "../../../utils/common";
import { driveInputConfig, driveList } from "../../../constants/driveList";
@@ -35,6 +37,7 @@ import SyncService from "../../../utils/storage/syncService";
import { updateUserConfig } from "../../../utils/request/user";
import BookUtil from "../../../utils/file/bookUtil";
import Book from "../../../models/Book";
import ConfigUtil from "../../../utils/file/configUtil";
declare var window: any;
class SyncSetting extends React.Component<SettingInfoProps, SettingInfoState> {
constructor(props: SettingInfoProps) {
@@ -112,7 +115,7 @@ class SyncSetting extends React.Component<SettingInfoProps, SettingInfoState> {
) {
this.handleJump(
new SyncUtil(settingDrive, {}).getAuthUrl(
ConfigService.getItem("serverRegion") === "china" &&
getServerRegion() === "china" &&
(settingDrive === "microsoft" ||
settingDrive === "microsoft_exp" ||
settingDrive === "adrive")
@@ -149,13 +152,24 @@ class SyncSetting extends React.Component<SettingInfoProps, SettingInfoState> {
return;
}
ConfigService.setItem("defaultSyncOption", event.target.value);
if (ConfigService.getItem("isEnableKoodoSync") === "yes") {
updateUserConfig({
default_sync_option: event.target.value,
});
if (ConfigService.getReaderConfig("isEnableKoodoSync") === "yes") {
resetKoodoSync();
}
this.props.handleFetchDefaultSyncOption();
toast.success(this.props.t("Change successful"));
if (
!(await ConfigUtil.isCloudEmpty()) &&
ConfigService.getReaderConfig("isEnableKoodoSync") === "yes"
) {
toast(
this.props.t(
"This data source already contains a library. If you need to merge local and cloud data, please turn off Koodo Sync and resync."
),
{
duration: 10000,
}
);
}
};
handleCancelDrive = () => {
this.props.handleSettingDrive("");
@@ -238,7 +252,7 @@ class SyncSetting extends React.Component<SettingInfoProps, SettingInfoState> {
ConfigService,
BookUtil
);
let timer = await showTaskProgress();
let timer = await showTaskProgress((_: boolean) => {});
if (!timer) {
return;
}
@@ -452,8 +466,11 @@ class SyncSetting extends React.Component<SettingInfoProps, SettingInfoState> {
}
}
if (
this.props.settingDrive === "docker" ||
this.props.settingDrive === "webdav" ||
this.props.settingDrive === "docker" ||
this.props.settingDrive === "ftp" ||
this.props.settingDrive === "sftp" ||
this.props.settingDrive === "mega" ||
this.props.settingDrive === "s3compatible"
) {
let connectionResult = await testConnection(
@@ -495,7 +512,7 @@ class SyncSetting extends React.Component<SettingInfoProps, SettingInfoState> {
onClick={async () => {
this.handleJump(
new SyncUtil(this.props.settingDrive, {}).getAuthUrl(
ConfigService.getItem("serverRegion") === "china" &&
getServerRegion() === "china" &&
(this.props.settingDrive === "microsoft" ||
this.props.settingDrive === "microsoft_exp" ||
this.props.settingDrive === "adrive")
@@ -545,7 +562,7 @@ class SyncSetting extends React.Component<SettingInfoProps, SettingInfoState> {
className="voice-add-cancel"
style={{ borderWidth: 0, lineHeight: "30px" }}
onClick={() => {
openExternalUrl(WEBSITE_URL + "/zh/add-source");
openExternalUrl(getWebsiteUrl() + "/zh/add-source");
}}
>
{this.props.t("How to fill out")}
@@ -570,7 +587,7 @@ class SyncSetting extends React.Component<SettingInfoProps, SettingInfoState> {
support: ["desktop", "browser", "phone"],
},
...driveList.filter((item) => {
if (ConfigService.getItem("serverRegion") === "china") {
if (getServerRegion() === "china") {
return item.isCNAvailable;
}
return true;
@@ -608,7 +625,7 @@ class SyncSetting extends React.Component<SettingInfoProps, SettingInfoState> {
{[
{ label: "Please select", value: "", isPro: false },
...driveList.filter((item) => {
if (ConfigService.getItem("serverRegion") === "china") {
if (getServerRegion() === "china") {
return item.isCNAvailable;
}
return true;
@@ -672,7 +689,7 @@ class SyncSetting extends React.Component<SettingInfoProps, SettingInfoState> {
{[
{ label: "Please select", value: "", isPro: false },
...driveList.filter((item) => {
if (ConfigService.getItem("serverRegion") === "china") {
if (getServerRegion() === "china") {
return item.isCNAvailable;
}
return true;

View File

@@ -4,7 +4,7 @@ import { sideMenu } from "../../constants/sideMenu";
import { SidebarProps, SidebarState } from "./interface";
import { withRouter } from "react-router-dom";
import { ConfigService } from "../../assets/lib/kookit-extra-browser.min";
import { openInBrowser, WEBSITE_URL } from "../../utils/common";
import { getWebsiteUrl, openInBrowser } from "../../utils/common";
import { Trans } from "react-i18next";
import toast from "react-hot-toast";
class Sidebar extends React.Component<SidebarProps, SidebarState> {
@@ -263,7 +263,7 @@ class Sidebar extends React.Component<SidebarProps, SidebarState> {
}
alt=""
onClick={() => {
this.handleJump(WEBSITE_URL);
this.handleJump(getWebsiteUrl());
}}
style={this.state.isCollapsed ? { display: "none" } : {}}
className="logo"

View File

@@ -16,6 +16,7 @@ import PageWidget from "../pageWidget";
import {
getPageWidth,
getPdfPassword,
getServerRegion,
scrollContents,
showDownloadProgress,
} from "../../utils/common";
@@ -82,9 +83,12 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
)
);
this.props.handleRenderBookFunc(this.handleRenderBook);
window.addEventListener("resize", () => {
BookUtil.reloadBooks();
let resizeTimer: NodeJS.Timeout;
window.addEventListener("resize", (event) => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
BookUtil.reloadBooks(this.props.currentBook);
}, 300); // 300ms 防抖
});
}
async UNSAFE_componentWillReceiveProps(nextProps: ViewerProps) {
@@ -214,20 +218,13 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
if (result) {
toast.success(this.props.t("Download successful"));
} else {
result = await BookUtil.downloadCacheBook(key);
if (result) {
toast.success(this.props.t("Download successful"));
} else {
toast.error(this.props.t("Download failed"));
return;
}
toast.error(this.props.t("Book not exists"));
}
} else {
toast.error(this.props.t("Book not exists"));
return;
}
}
let rendition = BookHelper.getRendition(
result,
{
@@ -258,7 +255,10 @@ class Viewer extends React.Component<ViewerProps, ViewerState> {
(item) => item.lang === ConfigService.getReaderConfig("lang")
)?.value || "chi_sim",
ocrEngine: ConfigService.getReaderConfig("ocrEngine") || "tesseract",
serverRegion: ConfigService.getItem("serverRegion") || "global",
serverRegion:
ConfigService.getItem("serverRegion") === "china"
? "china"
: "global",
paraSpacingValue:
ConfigService.getReaderConfig("paraSpacingValue") || "1.5",
titleSizeValue:

View File

@@ -7,6 +7,7 @@ import toast, { Toaster } from "react-hot-toast";
import { loginList } from "../../constants/loginList";
import {
generateSyncRecord,
getServerRegion,
handleContextMenu,
openInBrowser,
removeSearchParams,
@@ -37,7 +38,7 @@ class Login extends React.Component<LoginProps, LoginState> {
loginConfig: {},
countdown: 0,
isSendingCode: false,
serverRegion: ConfigService.getItem("serverRegion") || "global",
serverRegion: getServerRegion(),
};
}
@@ -366,8 +367,8 @@ class Login extends React.Component<LoginProps, LoginState> {
let url = LoginHelper.getAuthUrl(
item.value,
isElectron ? "desktop" : "browser",
ConfigService.getItem("serverRegion") ===
"china" && item.value === "microsoft"
getServerRegion() === "china" &&
item.value === "microsoft"
? KookitConfig.ThirdpartyConfig.cnCallbackUrl
: KookitConfig.ThirdpartyConfig.callbackUrl
);
@@ -453,7 +454,7 @@ class Login extends React.Component<LoginProps, LoginState> {
<div className="login-sync-container">
{driveList
.filter((item) => {
if (ConfigService.getItem("serverRegion") === "china") {
if (getServerRegion() === "china") {
return item.isCNAvailable;
}
return true;

View File

@@ -11,8 +11,8 @@ import { Tooltip } from "react-tooltip";
import "./index.css";
import Book from "../../models/Book";
import DatabaseService from "../../utils/storage/databaseService";
import BookUtil from "../../utils/file/bookUtil";
import ConvertDialog from "../../components/dialogs/convertDialog";
import { isElectron } from "react-device-detect";
let lock = false; //prevent from clicking too fasts
let throttleTime =
@@ -67,8 +67,11 @@ class Reader extends React.Component<ReaderProps, ReaderState> {
);
}
}, 5000);
window.addEventListener("beforeunload", function (event) {
ConfigService.setItem("isFinshReading", "yes");
if (!isElectron) {
ConfigService.setReaderConfig("isFinishWebReading", "yes");
}
});
window.addEventListener("mousemove", () => {
isMouseMoving = true;

View File

@@ -195,6 +195,9 @@ export function handleFetchAuthed() {
try {
TokenService.getToken("is_authed").then((value) => {
let isAuthed = value === "yes";
if (isAuthed && !ConfigService.getItem("serverRegion")) {
ConfigService.setItem("serverRegion", "global");
}
dispatch(handleAuthed(isAuthed));
});
} catch (error) {

View File

@@ -19,6 +19,7 @@ import { getCloudConfig } from "./file/common";
import SyncService from "./storage/syncService";
import localforage from "localforage";
import { driveList } from "../constants/driveList";
import { updateUserConfig } from "./request/user";
declare var window: any;
export const supportedFormats = [
".epub",
@@ -580,6 +581,21 @@ export const getDefaultTransTarget = (langList) => {
return langMap[langTarget || "English"];
};
export const WEBSITE_URL = "https://koodoreader.com";
export const CN_WEBSITE_URL = "https://koodoreader.cn";
export const getServerRegion = () => {
let isUseCN = false;
if (ConfigService.getItem("serverRegion")) {
isUseCN = ConfigService.getItem("serverRegion") === "china";
} else {
if (navigator.language && navigator.language === "zh-CN") {
isUseCN = true;
}
}
return isUseCN ? "china" : "global";
};
export const getWebsiteUrl = () => {
return getServerRegion() === "china" ? CN_WEBSITE_URL : WEBSITE_URL;
};
export const formatTimestamp = (timestamp) => {
if (!timestamp) return "";
@@ -800,7 +816,9 @@ export const showDownloadProgress = (
}, 500);
return timer;
};
export const showTaskProgress = async () => {
export const showTaskProgress = async (
handleSyncStateChange: (isSync: boolean) => void
) => {
let config = {};
let timer: any;
let service = ConfigService.getItem("defaultSyncOption");
@@ -829,13 +847,14 @@ export const showTaskProgress = async () => {
if (stats.hasFailedTasks) {
toast.error(
i18n.t(
"Tasks failed after multiple retries, please check the network connection"
"Tasks failed after multiple retries, please check the network connection or reauthorize the data source in the settings"
),
{
id: "syncing",
}
);
clearInterval(timer);
handleSyncStateChange(false);
return;
} else {
toast.loading(
@@ -867,13 +886,14 @@ export const showTaskProgress = async () => {
if (stats.hasFailedTasks) {
toast.error(
i18n.t(
"Tasks failed after multiple retries, please check the network connection"
"Tasks failed after multiple retries, please check the network connection or reauthorize the data source in the settings"
),
{
id: "syncing",
}
);
clearInterval(timer);
handleSyncStateChange(false);
return;
} else {
toast.loading(
@@ -925,3 +945,15 @@ export const clearAllData = async () => {
}
await localforage.clear();
};
export const resetKoodoSync = async () => {
await updateUserConfig({
is_enable_koodo_sync: "no",
default_sync_option: ConfigService.getItem("defaultSyncOption"),
});
setTimeout(() => {
updateUserConfig({
is_enable_koodo_sync: "yes",
default_sync_option: ConfigService.getItem("defaultSyncOption"),
});
}, 1000);
};

View File

@@ -200,15 +200,14 @@ class BookUtil {
let result = await this.downloadBook(book.key, book.format);
clearInterval(timer);
toast.dismiss("offline-book");
if (ConfigService.getItem("defaultSyncOption") === "adrive") {
let syncUtil = await SyncService.getSyncUtil();
let covers = await syncUtil.listFiles("cover");
for (let cover of covers) {
if (cover.startsWith(book.key)) {
await CoverUtil.downloadCover(cover);
}
let covers = await CoverUtil.getCloudCoverList();
for (let cover of covers) {
if (cover.startsWith(book.key)) {
await CoverUtil.downloadCover(cover);
}
}
if (result) {
toast.success(i18n.t("Download successful"), {
id: "offline-book",
@@ -276,12 +275,16 @@ class BookUtil {
let ref = book.format.toLowerCase();
return `/${ref}/${book.key}`;
}
static reloadBooks() {
static reloadBooks(currentBook: BookModel) {
if (isElectron) {
if (ConfigService.getReaderConfig("isOpenInMain") === "yes") {
window.require("electron").ipcRenderer.invoke("reload-tab", "ping");
window
.require("electron")
.ipcRenderer.invoke("reload-tab", { bookKey: currentBook.key });
} else {
window.require("electron").ipcRenderer.invoke("reload-reader", "ping");
window.require("electron").ipcRenderer.invoke("reload-reader", {
bookKey: currentBook.key,
});
}
} else {
window.location.reload();

View File

@@ -113,10 +113,9 @@ class ConfigUtil {
}
let thirdpartyRequest = await getThirdpartyRequest();
let response = await thirdpartyRequest.getSyncData();
let response = await thirdpartyRequest.getSyncDataByType({ type });
if (response.code === 200) {
let syncData = response.data;
this.syncData = syncData;
this.syncData[type] = response.data;
return JSON.parse(this.syncData[type] || defaultValue);
} else if (response.code === 401) {
handleExitApp();
@@ -282,5 +281,13 @@ class ConfigUtil {
}
}
}
static async isCloudEmpty() {
let syncDataStr = await this.downloadConfig("sync");
let syncData = JSON.parse(syncDataStr || "{}");
if (!syncData || Object.keys(syncData).length === 0) {
return true;
}
return false;
}
}
export default ConfigUtil;

View File

@@ -132,7 +132,7 @@ export const scrollChapter = async (
}
}
};
let lastScaleTime = 0;
export const bindHtmlEvent = (
rendition: any,
doc: any,
@@ -152,10 +152,16 @@ export const bindHtmlEvent = (
},
{ passive: false }
);
doc.addEventListener(
"wheel",
async (event) => {
if (event.ctrlKey && readerMode !== "double") {
const currentTime = Date.now();
if (currentTime - lastScaleTime < 1500) {
return;
}
lastScaleTime = currentTime;
event.preventDefault();
let scale = parseFloat(ConfigService.getReaderConfig("scale") || "1");
if (event.deltaY < 0) {

View File

@@ -2,18 +2,18 @@ import axios from "axios";
import toast from "react-hot-toast";
import i18n from "../../i18n";
import { TokenService } from "../../assets/lib/kookit-extra-browser.min";
import { reloadManager } from "../common";
import { getServerRegion, reloadManager } from "../common";
const PUBLIC_URL = "https://api.960960.xyz";
const CN_PUBLIC_URL = "https://api.koodoreader.cn";
export const getPublicUrl = () => {
return getServerRegion() === "china" ? CN_PUBLIC_URL : PUBLIC_URL;
};
export const checkDeveloperUpdate = async () => {
let res = await axios.get(
PUBLIC_URL + `/api/update_dev?name=${navigator.language}`
getPublicUrl() + `/api/update_dev?name=${navigator.language}`
);
return res.data.log;
};
export const getUploadUrl = async () => {
let res = await axios.get(PUBLIC_URL + "/api/get_temp_upload_url");
return res.data;
};
export const uploadFile = async (url: string, file: any) => {
return new Promise<boolean>((resolve) => {
axios
@@ -29,7 +29,7 @@ export const uploadFile = async (url: string, file: any) => {
};
export const checkStableUpdate = async () => {
let res = await axios.get(
PUBLIC_URL + `/api/update?name=${navigator.language}`
getPublicUrl() + `/api/update?name=${navigator.language}`
);
return res.data.log;
};

View File

@@ -7,6 +7,7 @@ import {
import i18n from "../../i18n";
import { handleExitApp } from "./common";
import { officialDictList } from "../../constants/settingList";
import { getServerRegion } from "../common";
let readerRequest: ReaderRequest | undefined;
export const getTransStream = async (
text: string,
@@ -81,7 +82,11 @@ export const getReaderRequest = async () => {
if (readerRequest) {
return readerRequest;
}
readerRequest = new ReaderRequest(TokenService, ConfigService);
readerRequest = new ReaderRequest(
TokenService,
ConfigService,
getServerRegion()
);
return readerRequest;
};
export const resetReaderRequest = () => {

View File

@@ -7,12 +7,17 @@ import {
} from "../../assets/lib/kookit-extra-browser.min";
import i18n from "../../i18n";
import { handleExitApp } from "./common";
import { getServerRegion } from "../common";
let thirdpartyRequest: ThirdpartyRequest | undefined;
export const getThirdpartyRequest = async () => {
if (thirdpartyRequest) {
return thirdpartyRequest;
}
thirdpartyRequest = new ThirdpartyRequest(TokenService, ConfigService);
thirdpartyRequest = new ThirdpartyRequest(
TokenService,
ConfigService,
getServerRegion()
);
return thirdpartyRequest;
};
export const resetThirdpartyRequest = () => {
@@ -24,22 +29,7 @@ export const onSyncCallback = async (service: string, authCode: string) => {
let thirdpartyRequest = await getThirdpartyRequest();
let syncUtil = new SyncUtil(service, {}, thirdpartyRequest);
let timer = setTimeout(() => {
if (
ConfigService.getItem("serverRegion") !== "china" &&
navigator.language === "zh-CN"
) {
toast.error(
i18n.t(
"Request timed out, You may change the server region to China to solve the connection issue in mainland China. Go to Settings > Account"
),
{ id: "adding-sync-error", duration: 6000 }
);
return;
}
}, 10000);
let result = await syncUtil.authToken(authCode);
clearTimeout(timer);
if (!result.refresh_token) {
toast.error(i18n.t("Authorization failed"), { id: "adding-sync-id" });
return;
@@ -95,24 +85,9 @@ export const encryptToken = async (service: string, config: any) => {
return { code: 200, msg: "success", data: syncToken };
}
let thirdpartyRequest = await getThirdpartyRequest();
let timer = setTimeout(() => {
if (
ConfigService.getItem("serverRegion") !== "china" &&
navigator.language === "zh-CN"
) {
toast.error(
i18n.t(
"Request timed out, You may change the server region to China to solve the connection issue in mainland China. Go to Settings > Account"
),
{ id: "adding-sync-error", duration: 6000 }
);
return;
}
}, 10000);
let response = await thirdpartyRequest.encryptToken({
token: syncToken,
});
clearTimeout(timer);
if (response.code === 200) {
await TokenService.setToken(
service + "_token",
@@ -143,22 +118,7 @@ export const decryptToken = async (service: string) => {
};
}
let thirdpartyRequest = await getThirdpartyRequest();
let timer = setTimeout(() => {
if (
ConfigService.getItem("serverRegion") !== "china" &&
navigator.language === "zh-CN"
) {
toast.error(
i18n.t(
"Request timed out, You may change the server region to China to solve the connection issue in mainland China. Go to Settings > Account"
),
{ id: "adding-sync-error", duration: 6000 }
);
return;
}
}, 10000);
let encryptedToken = await TokenService.getToken(service + "_token");
clearTimeout(timer);
if (!encryptedToken || encryptedToken === "{}") {
return {};
}

View File

@@ -15,31 +15,17 @@ import packageJson from "../../../package.json";
import toast from "react-hot-toast";
import i18n from "../../i18n";
import { handleExitApp } from "./common";
import { getServerRegion } from "../common";
let userRequest: UserRequest | undefined;
export const loginRegister = async (service: string, code: string) => {
let deviceName = detectBrowser();
let userRequest = await getUserRequest();
let timer = setTimeout(() => {
if (
ConfigService.getItem("serverRegion") !== "china" &&
navigator.language === "zh-CN"
) {
toast.error(
i18n.t(
"Request timed out, You may change the server region to China to solve the connection issue in mainland China. Go to Settings > Account"
),
{ id: "adding-sync-error", duration: 6000 }
);
return;
}
}, 10000);
let response = await userRequest.loginRegister({
code,
provider: service,
scope: KookitConfig.LoginAuthRequest[service].extraParams.scope,
redirect_uri:
ConfigService.getItem("serverRegion") === "china" &&
service === "microsoft"
getServerRegion() === "china" && service === "microsoft"
? KookitConfig.ThirdpartyConfig.cnCallbackUrl
: KookitConfig.ThirdpartyConfig.callbackUrl,
device_name: deviceName,
@@ -50,11 +36,11 @@ export const loginRegister = async (service: string, code: string) => {
device_uuid: await TokenService.getFingerprint(),
app_version: packageJson.version,
});
clearTimeout(timer);
if (response.code === 200) {
await TokenService.setToken("is_authed", "yes");
await TokenService.setToken("access_token", response.data.access_token);
await TokenService.setToken("refresh_token", response.data.refresh_token);
ConfigService.setItem("serverRegion", getServerRegion());
}
return response;
};
@@ -93,7 +79,7 @@ export const getUserRequest = async () => {
if (userRequest) {
return userRequest;
}
userRequest = new UserRequest(TokenService, ConfigService);
userRequest = new UserRequest(TokenService, ConfigService, getServerRegion());
return userRequest;
};
export const resetUserRequest = () => {