diff --git a/main.js b/main.js
index cf62a6b2..efe61b5f 100644
--- a/main.js
+++ b/main.js
@@ -18,6 +18,7 @@ app.on("ready", () => {
nodeIntegration: true,
nativeWindowOpen: true,
nodeIntegrationInSubFrames: true,
+ allowRunningInsecureContent: true,
},
show: false,
// transparent: true,
@@ -71,14 +72,165 @@ app.on("ready", () => {
.getFonts()
.then((fonts) => {
event.returnValue = fonts;
-
- const server = require("./server");
})
.catch((err) => {
console.log(err);
});
});
+ let isFirst = true;
+ ipcMain.on("start-server", (event, arg) => {
+ if (isFirst) startExpress();
+ isFirst = false;
+ event.returnValue = "pong";
+ });
});
app.on("window-all-closed", () => {
app.quit();
});
+function startExpress() {
+ const express = require("express");
+ const cors = require("cors");
+ const bodyParser = require("body-parser");
+ const fileUpload = require("express-fileupload");
+ const path = require("path");
+ const fs = require("fs");
+ const Epub = require("epub-gen");
+ const { readFileSync } = require("fs");
+ const iconv = require("iconv-lite");
+ const electron = require("electron");
+ const configDir = (electron.app || electron.remote.app).getPath("userData");
+ var dirPath = path.join(configDir, "uploads");
+ if (!fs.existsSync(dirPath)) {
+ fs.mkdirSync(dirPath);
+ console.log("文件夹创建成功");
+ } else {
+ console.log("文件夹已存在");
+ }
+ const server = express();
+ server.use(
+ fileUpload({
+ createParentPath: true,
+ })
+ );
+ server.use(cors());
+ server.use(bodyParser.json());
+ server.use(bodyParser.urlencoded({ extended: true }));
+ server.post("/ebook_parser", async (req, res) => {
+ let file = req.files.file;
+ file.mv(dirPath + file.name, () => {
+ const data = readFileSync(dirPath + file.name, {
+ encoding: "binary",
+ });
+ const buf = new Buffer(data, "binary");
+ const lines = iconv.decode(buf, "GBK").split("\n");
+ const content = [];
+ for (let i = 0; i < lines.length; i++) {
+ const line = lines[i];
+ // console.log(line, line.startsWith("序章"), "test");
+
+ if (
+ line.startsWith("CHAPTER ") ||
+ line.startsWith("Chapter") ||
+ line.startsWith("第") ||
+ line.startsWith("序章") ||
+ line.startsWith("前言") ||
+ line.startsWith("写在前面的话") ||
+ line.startsWith("后记") ||
+ line.startsWith("楔子") ||
+ line.startsWith("后记") ||
+ line.startsWith("后序")
+ ) {
+ if (content.length) {
+ content[content.length - 1].data = content[
+ content.length - 1
+ ].data.join("\n");
+ }
+ content.push({
+ data: [],
+ });
+ } else if (line.trim() === "" && content.length) {
+ if (content[content.length - 1].data.length > 1) {
+ content[content.length - 1].data.push("
");
+ }
+ content[content.length - 1].data.push("");
+ } else if (content.length) {
+ content[content.length - 1].data.push(line.trim());
+ }
+ if (
+ content[content.length - 1] &&
+ content[content.length - 1].data &&
+ i === lines.length - 1
+ ) {
+ content[content.length - 1].data = content[
+ content.length - 1
+ ].data.join("\n");
+ }
+ }
+ if (!content.length) {
+ content.push({
+ title: "正文",
+ data: lines
+ .map((item) => {
+ return `
${item}
`;
+ })
+ .join("\n"),
+ });
+ }
+ const options = {
+ title: file.name.split(".")[0],
+ author: "Koodo Reader",
+ output: dirPath + `${file.name.split(".")[0]}.epub`,
+ content,
+ };
+ new Epub(options).promise
+ .then(() => {
+ res.sendFile(dirPath + `${file.name.split(".")[0]}.epub`);
+ res.on("finish", function () {
+ try {
+ fs.unlink(dirPath + `${file.name.split(".")[0]}.epub`, (err) => {
+ if (err) throw err;
+ console.log("successfully deleted");
+ });
+ fs.unlink(dirPath + `${file.name}`, (err) => {
+ if (err) throw err;
+ console.log("successfully deleted");
+ });
+ } catch (e) {
+ console.log("error removing ");
+ }
+ });
+ })
+ .catch((err) => console.log("err"));
+ });
+ });
+
+ async function start() {
+ try {
+ const port = 3366;
+ expressServer = await server.listen(port);
+ console.log("started");
+ const address = expressServer.address();
+ serverInfo = {
+ port: address.port,
+ local: "localhost",
+ url: `http://localhost:${address.port}`,
+ };
+ return serverInfo;
+ } catch (e) {
+ return { message: e.message };
+ }
+ }
+
+ async function startServer() {
+ console.log("starting");
+ const { port, local, message } = await start();
+ if (message) {
+ console.log("err");
+ console.error(message);
+ } else {
+ console.info(`启动成功,本地访问 http://${local}:${port}`);
+ }
+ }
+
+ startServer();
+}
diff --git a/src/components/bookCardtem/component.tsx b/src/components/bookCardtem/component.tsx
index b74a9e8e..e341b4a9 100644
--- a/src/components/bookCardtem/component.tsx
+++ b/src/components/bookCardtem/component.tsx
@@ -105,7 +105,11 @@ class BookCardItem extends React.Component {
>
[0]}assets/cover.svg`})
diff --git a/src/components/bookListItem/component.tsx b/src/components/bookListItem/component.tsx
index 13c80988..118f48e9 100644
--- a/src/components/bookListItem/component.tsx
+++ b/src/components/bookListItem/component.tsx
@@ -76,7 +76,11 @@ class BookListItem extends React.Component
{
}}
>
diff --git a/src/components/importLocal/component.tsx b/src/components/importLocal/component.tsx
index bdb1301c..4df24532 100644
--- a/src/components/importLocal/component.tsx
+++ b/src/components/importLocal/component.tsx
@@ -13,11 +13,18 @@ import { config } from "../../constants/readerConfig";
import MobiFile from "../../utils/mobiUtil";
import iconv from "iconv-lite";
import isElectron from "is-electron";
+import { withRouter } from "react-router-dom";
declare var window: any;
var pdfjsLib = window["pdfjs-dist/build/pdf"];
class ImportLocal extends React.Component {
+ componentDidMount() {
+ if (isElectron()) {
+ const { ipcRenderer } = window.require("electron");
+ ipcRenderer.sendSync("start-server", "ping");
+ }
+ }
handleAddBook = (book: BookModel) => {
return new Promise((resolve, reject) => {
let bookArr = this.props.books;
@@ -33,6 +40,7 @@ class ImportLocal extends React.Component {
this.props.handleMessage("Add Successfully");
this.props.handleMessageBox(true);
resolve();
+ this.props.history.push("/manager/home");
})
.catch(() => {
reject();
@@ -349,4 +357,4 @@ class ImportLocal extends React.Component {
}
}
-export default ImportLocal;
+export default withRouter(ImportLocal);
diff --git a/src/components/importLocal/interface.tsx b/src/components/importLocal/interface.tsx
index f0c2d716..dfbd632f 100644
--- a/src/components/importLocal/interface.tsx
+++ b/src/components/importLocal/interface.tsx
@@ -1,6 +1,6 @@
import BookModel from "../../model/Book";
-
-export interface ImportLocalProps {
+import { RouteComponentProps } from "react-router";
+export interface ImportLocalProps extends RouteComponentProps {
books: BookModel[];
handleMessageBox: (isShow: boolean) => void;
handleMessage: (message: string) => void;
diff --git a/src/components/settingDialog/component.tsx b/src/components/settingDialog/component.tsx
index 119bec8a..d4e3c73c 100644
--- a/src/components/settingDialog/component.tsx
+++ b/src/components/settingDialog/component.tsx
@@ -271,7 +271,11 @@ class SettingDialog extends React.Component<
diff --git a/src/components/updataDialog/component.tsx b/src/components/updataDialog/component.tsx
index c918aa42..91a94d04 100644
--- a/src/components/updataDialog/component.tsx
+++ b/src/components/updataDialog/component.tsx
@@ -66,7 +66,11 @@ class UpdateDialog extends React.Component {
koodo.960960.xyz
diff --git a/src/constants/readerConfig.tsx b/src/constants/readerConfig.tsx
index 30324111..d3aed1e6 100644
--- a/src/constants/readerConfig.tsx
+++ b/src/constants/readerConfig.tsx
@@ -79,7 +79,7 @@ export const sideMenu = [
export const config = {
callback_url:
process.env.NODE_ENV === "production"
- ? "https://reader.960960.xyz"
+ ? "https://koodo.960960.xyz"
: "http://localhost:3000",
token_url:
process.env.NODE_ENV === "production"
diff --git a/src/containers/bookList/component.tsx b/src/containers/bookList/component.tsx
index 4abaa11a..b1645421 100644
--- a/src/containers/bookList/component.tsx
+++ b/src/containers/bookList/component.tsx
@@ -14,7 +14,7 @@ import OtherUtil from "../../utils/otherUtil";
import localforage from "localforage";
import DeletePopup from "../../components/deletePopup";
import EmptyPage from "../emptyPage";
-import { Redirect } from "react-router-dom";
+import { Redirect, withRouter } from "react-router-dom";
declare var window: any;
@@ -28,6 +28,9 @@ class BookList extends React.Component {
};
}
componentDidMount() {
+ if (!this.props.books || !this.props.books[0]) {
+ return ;
+ }
this.handleOldVersion();
}
handleOldVersion = async () => {
@@ -146,11 +149,10 @@ class BookList extends React.Component {
SortUtil.sortBooks(this.props.books, this.props.sortCode) || []
)
: this.handleRecent(this.props.books, RecordRecent.getAllRecent());
- console.log(books.length, "books.length");
- if (books.length === 0) {
- console.log("empty");
+ if (this.props.mode === "shelf" && books.length === 0) {
return ;
}
+
return books.map((item: BookModel, index: number) => {
return this.props.isList === "list" ? (
{
this.setState({ isOpenDelete });
};
render() {
- if (this.state.favoriteBooks === 0 && this.props.mode === "favorite") {
+ if (
+ (this.state.favoriteBooks === 0 && this.props.mode === "favorite") ||
+ !this.props.books ||
+ !this.props.books[0]
+ ) {
return ;
}
const deletePopupProps = {
@@ -285,4 +291,4 @@ class BookList extends React.Component {
}
}
-export default BookList;
+export default withRouter(BookList);
diff --git a/src/containers/bookList/interface.tsx b/src/containers/bookList/interface.tsx
index be7a5ad1..f2fffe75 100644
--- a/src/containers/bookList/interface.tsx
+++ b/src/containers/bookList/interface.tsx
@@ -1,6 +1,6 @@
import BookModel from "../../model/Book";
-
-export interface BookListProps {
+import { RouteComponentProps } from "react-router";
+export interface BookListProps extends RouteComponentProps {
books: BookModel[];
mode: string;
shelfIndex: number;
diff --git a/src/containers/deleteDialog/component.tsx b/src/containers/deleteDialog/component.tsx
index 19591196..9310d961 100644
--- a/src/containers/deleteDialog/component.tsx
+++ b/src/containers/deleteDialog/component.tsx
@@ -8,6 +8,7 @@ import RecordLocation from "../../utils/recordLocation";
import AddFavorite from "../../utils/addFavorite";
import { Trans } from "react-i18next";
import { DeleteDialogProps } from "./interface";
+import { withRouter } from "react-router-dom";
class DeleteDialog extends React.Component {
handleCancel = () => {
@@ -74,6 +75,9 @@ class DeleteDialog extends React.Component {
//删除书签,笔记,书摘,高亮
this.handleDeleteOther();
this.props.handleActionDialog(false);
+ if (this.props.books.length === 1) {
+ this.props.history.push("/manager/empty");
+ }
}
this.props.handleMessage("Delete Successfully");
@@ -130,4 +134,4 @@ class DeleteDialog extends React.Component {
}
}
-export default DeleteDialog;
+export default withRouter(DeleteDialog);
diff --git a/src/containers/deleteDialog/interface.tsx b/src/containers/deleteDialog/interface.tsx
index 783a9d5c..7d6d5f88 100644
--- a/src/containers/deleteDialog/interface.tsx
+++ b/src/containers/deleteDialog/interface.tsx
@@ -1,8 +1,9 @@
import BookModel from "../../model/Book";
import NoteModel from "../../model/Note";
import BookmarkModel from "../../model/Bookmark";
+import { RouteComponentProps } from "react-router";
-export interface DeleteDialogProps {
+export interface DeleteDialogProps extends RouteComponentProps {
books: BookModel[];
isOpenDeleteDialog: boolean;
currentBook: BookModel;
diff --git a/src/containers/digestList/component.tsx b/src/containers/digestList/component.tsx
index 94b4bfcb..81d1ccf5 100644
--- a/src/containers/digestList/component.tsx
+++ b/src/containers/digestList/component.tsx
@@ -13,6 +13,9 @@ class DigestList extends React.Component {
tag: [],
};
}
+ componentWillMount() {
+ this.props.handleFetchNotes();
+ }
handleFilter = (items: any, arr: number[]) => {
let itemArr: any[] = [];
arr.forEach((item) => {
diff --git a/src/containers/digestList/index.tsx b/src/containers/digestList/index.tsx
index 2ba97364..6815d148 100644
--- a/src/containers/digestList/index.tsx
+++ b/src/containers/digestList/index.tsx
@@ -3,6 +3,7 @@ import { connect } from "react-redux";
import { stateType } from "../../store";
import { withNamespaces } from "react-i18next";
import DigestList from "./component";
+import { handleFetchNotes } from "../../store/actions/reader";
const mapStateToProps = (state: stateType) => {
return {
@@ -11,7 +12,7 @@ const mapStateToProps = (state: stateType) => {
searchResults: state.manager.searchResults,
};
};
-const actionCreator = {};
+const actionCreator = { handleFetchNotes };
export default connect(
mapStateToProps,
actionCreator
diff --git a/src/containers/digestList/interface.tsx b/src/containers/digestList/interface.tsx
index 022bcb55..de39017c 100644
--- a/src/containers/digestList/interface.tsx
+++ b/src/containers/digestList/interface.tsx
@@ -4,6 +4,7 @@ export interface DigestListProps {
digests: NoteModel[];
isSearch: boolean;
searchResults: number[];
+ handleFetchNotes: () => void;
}
export interface DigestListStates {
tag: string[];
diff --git a/src/containers/emptyPage/component.tsx b/src/containers/emptyPage/component.tsx
index fe2629a3..f66f050e 100644
--- a/src/containers/emptyPage/component.tsx
+++ b/src/containers/emptyPage/component.tsx
@@ -7,7 +7,6 @@ import { EmptyPageProps, EmptyPageState } from "./interface";
class EmptyPage extends React.Component {
render() {
- console.log("empty");
const renderEmptyList = () => {
return emptyList.map((item) => {
return (
@@ -40,7 +39,7 @@ class EmptyPage extends React.Component {
{
}
}
componentDidMount() {
- console.log(window.location.href, "rendered");
let page = document.querySelector("#page-area");
let epub = this.props.currentEpub;
(window as any).rangy.init(); // 初始化
diff --git a/src/containers/header/component.tsx b/src/containers/header/component.tsx
index 12c32fe6..1391aa77 100644
--- a/src/containers/header/component.tsx
+++ b/src/containers/header/component.tsx
@@ -58,11 +58,7 @@ class Header extends React.Component {
>
-
+
{
tag: [],
};
}
+ componentWillMount() {
+ this.props.handleFetchNotes();
+ }
handleTag = (tag: string[]) => {
this.setState({ tag });
};
diff --git a/src/containers/noteList/index.tsx b/src/containers/noteList/index.tsx
index 6a99a780..72ac50be 100644
--- a/src/containers/noteList/index.tsx
+++ b/src/containers/noteList/index.tsx
@@ -3,6 +3,8 @@ import { connect } from "react-redux";
import { stateType } from "../../store";
import { withNamespaces } from "react-i18next";
import NoteList from "./component";
+import { handleFetchNotes } from "../../store/actions/reader";
+
const mapStateToProps = (state: stateType) => {
return {
@@ -11,7 +13,7 @@ const mapStateToProps = (state: stateType) => {
searchResults: state.manager.searchResults,
};
};
-const actionCreator = {};
+const actionCreator = { handleFetchNotes };
export default connect(
mapStateToProps,
actionCreator
diff --git a/src/containers/noteList/interface.tsx b/src/containers/noteList/interface.tsx
index 292d9b6b..147d9930 100644
--- a/src/containers/noteList/interface.tsx
+++ b/src/containers/noteList/interface.tsx
@@ -4,6 +4,7 @@ export interface NoteListProps {
notes: NoteModel[];
isSearch: boolean;
searchResults: number[];
+ handleFetchNotes: () => void;
}
export interface NoteListState {
tag: string[];
diff --git a/src/containers/sidebar/component.tsx b/src/containers/sidebar/component.tsx
index 74ac4509..b2fea482 100644
--- a/src/containers/sidebar/component.tsx
+++ b/src/containers/sidebar/component.tsx
@@ -22,6 +22,7 @@ class Sidebar extends React.Component
{
this.setState({ isCollapse: true });
this.props.history.push(`/manager/${mode}`);
this.props.handleMode(mode);
+ this.props.handleSearch(false);
};
render() {
const renderSideMenu = () => {
@@ -67,7 +68,7 @@ class Sidebar extends React.Component {
{
return { mode: state.sidebar.mode };
};
-const actionCreator = { handleMode };
+const actionCreator = { handleMode, handleSearch };
export default connect(
mapStateToProps,
diff --git a/src/containers/sidebar/interface.tsx b/src/containers/sidebar/interface.tsx
index 795868f8..eb5bab0c 100644
--- a/src/containers/sidebar/interface.tsx
+++ b/src/containers/sidebar/interface.tsx
@@ -3,6 +3,7 @@ import { RouteComponentProps } from "react-router";
export interface SidebarProps extends RouteComponentProps {
mode: string;
handleMode: (mode: string) => void;
+ handleSearch: (isSearch: boolean) => void;
}
export interface SidebarState {
diff --git a/src/pages/manager/component.tsx b/src/pages/manager/component.tsx
index 86d5febe..39e66c34 100644
--- a/src/pages/manager/component.tsx
+++ b/src/pages/manager/component.tsx
@@ -154,7 +154,11 @@ class Manager extends React.Component {
[0]}assets/empty.svg`})
@@ -183,7 +187,7 @@ class Manager extends React.Component
{
) : null}
{this.state.isUpdated ? : null}
{this.props.isSettingOpen ? : null}
- {!books ? (
+ {!books && this.state.totalBooks ? (
) : (
@@ -200,5 +204,4 @@ class Manager extends React.Component {
);
}
}
-
-export default Manager;
+export default Manager;
\ No newline at end of file
diff --git a/src/pages/redirect/component.tsx b/src/pages/redirect/component.tsx
new file mode 100644
index 00000000..bd1cbfd4
--- /dev/null
+++ b/src/pages/redirect/component.tsx
@@ -0,0 +1,85 @@
+import React from "react";
+import "./manager.css";
+import { RedirectProps, RedirectState } from "./interface";
+import { Trans } from "react-i18next";
+import { getParamsFromUrl } from "../../utils/syncUtils/common";
+import copy from "copy-text-to-clipboard";
+import { withRouter } from "react-router-dom";
+class Redirect extends React.Component {
+ timer!: NodeJS.Timeout;
+ constructor(props: RedirectProps) {
+ super(props);
+ this.state = {
+ isAuthed: false,
+ isError: false,
+ isCopied: false,
+ token: "",
+ };
+ }
+
+ componentDidMount() {
+ //判断是否是获取token后的回调页面
+ let url = document.location.href;
+ if (url.indexOf("error") > -1) {
+ this.setState({ isError: true });
+ return false;
+ }
+ if (url.indexOf("code") > -1) {
+ let params: any = getParamsFromUrl();
+ console.log(params, "params");
+ this.setState({ token: params.code });
+ this.setState({ isAuthed: true });
+ return false;
+ }
+ if (url.indexOf("access_token") > -1) {
+ let params: any = getParamsFromUrl();
+ console.log(params, "params");
+ this.setState({ token: params.access_token });
+ this.setState({ isAuthed: true });
+ return false;
+ }
+ }
+
+ render() {
+ if (this.state.isError || this.state.isAuthed) {
+ return (
+
+
+ {this.state.isAuthed ? (
+
+ ) : (
+
+ )}
+
+
+
+ {this.state.isAuthed
+ ? "Authorize Successfully"
+ : "Authorize Failed"}
+
+
+ {this.state.isAuthed ? (
+
{
+ copy(this.state.token);
+ this.setState({ isCopied: true });
+ }}
+ >
+ {this.state.isCopied ? (
+ Copied
+ ) : (
+ Copy Token
+ )}
+
+ ) : null}
+
+
+ );
+ }
+
+ return 你似乎来到了没有知识的荒原
;
+ }
+}
+
+export default withRouter(Redirect);
diff --git a/src/pages/redirect/index.tsx b/src/pages/redirect/index.tsx
new file mode 100644
index 00000000..cacda737
--- /dev/null
+++ b/src/pages/redirect/index.tsx
@@ -0,0 +1,9 @@
+import { connect } from "react-redux";
+import "./manager.css";
+import { stateType } from "../../store";
+import Redirect from "./component";
+const mapStateToProps = (state: stateType) => {
+ return {};
+};
+const actionCreator = {};
+export default connect(mapStateToProps, actionCreator)(Redirect);
diff --git a/src/pages/redirect/interface.tsx b/src/pages/redirect/interface.tsx
new file mode 100644
index 00000000..5c9e8660
--- /dev/null
+++ b/src/pages/redirect/interface.tsx
@@ -0,0 +1,9 @@
+import { RouteComponentProps } from "react-router";
+export interface RedirectProps extends RouteComponentProps {}
+
+export interface RedirectState {
+ isAuthed: boolean;
+ isError: boolean;
+ isCopied: boolean;
+ token: string;
+}
diff --git a/src/pages/redirect/manager.css b/src/pages/redirect/manager.css
new file mode 100644
index 00000000..a1a1bea6
--- /dev/null
+++ b/src/pages/redirect/manager.css
@@ -0,0 +1,22 @@
+.manager {
+ width: 100%;
+ height: 100%;
+}
+.token-dialog-token-text {
+ width: 94px;
+ height: 29px;
+ background: rgba(255, 255, 255, 1);
+ border: 2px solid rgba(45, 111, 200, 1);
+ opacity: 1;
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 29px;
+ color: rgba(45, 111, 200, 1);
+ text-align: center;
+ cursor: pointer;
+}
+.auth-page-close-icon {
+ font-size: 60px !important;
+ float: none !important;
+}
+
diff --git a/src/router/index.tsx b/src/router/index.tsx
index 13b2874a..0100df15 100644
--- a/src/router/index.tsx
+++ b/src/router/index.tsx
@@ -1,24 +1,18 @@
import { hot } from "react-hot-loader/root";
import React from "react";
-import {
- Route,
- Switch,
- Redirect,
- HashRouter,
- BrowserRouter,
-} from "react-router-dom";
+import { Route, Switch, HashRouter } from "react-router-dom";
import Manager from "../pages/manager";
import EpubReader from "../pages/epubReader";
+import _Redirect from "../pages/redirect";
const Router = () => {
return (
-
- {/*
- */}
+
+
);
diff --git a/src/utils/syncUtils/common.tsx b/src/utils/syncUtils/common.tsx
index 410efb77..ecef8c61 100644
--- a/src/utils/syncUtils/common.tsx
+++ b/src/utils/syncUtils/common.tsx
@@ -3,8 +3,8 @@ export function getParamsFromUrl() {
var e,
r = /([^&;=]+)=?([^&;]*)/g,
q =
- window.location.search.substring(1).split("#")[0] ||
- window.location.hash.substring(1);
+ window.location.hash.substring(1) ||
+ window.location.search.substring(1).split("#")[0];
while ((e = r.exec(q))) {
hashParams[e[1]] = decodeURIComponent(e[2]);