add library

This commit is contained in:
Aria Moradi 2021-02-13 21:12:18 +03:30
parent eb90db7ce6
commit 09d624a4e2
13 changed files with 165 additions and 23 deletions

View File

@ -6,11 +6,13 @@ package ir.armor.tachidesk
import eu.kanade.tachiyomi.App
import io.javalin.Javalin
import ir.armor.tachidesk.util.addMangaToLibrary
import ir.armor.tachidesk.util.applicationSetup
import ir.armor.tachidesk.util.getChapter
import ir.armor.tachidesk.util.getChapterList
import ir.armor.tachidesk.util.getExtensionIcon
import ir.armor.tachidesk.util.getExtensionList
import ir.armor.tachidesk.util.getLibraryMangas
import ir.armor.tachidesk.util.getManga
import ir.armor.tachidesk.util.getMangaList
import ir.armor.tachidesk.util.getPageImage
@ -20,6 +22,7 @@ import ir.armor.tachidesk.util.getThumbnail
import ir.armor.tachidesk.util.installAPK
import ir.armor.tachidesk.util.openInBrowser
import ir.armor.tachidesk.util.removeExtension
import ir.armor.tachidesk.util.removeMangaFromLibrary
import ir.armor.tachidesk.util.sourceFilters
import ir.armor.tachidesk.util.sourceGlobalSearch
import ir.armor.tachidesk.util.sourceSearch
@ -73,15 +76,16 @@ class Main {
println("Warning: react build files are missing.")
hasWebUiBundled = false
}
config.enableCorsForAllOrigins()
}.start(4567)
if (hasWebUiBundled) {
openInBrowser()
}
app.before() { ctx ->
// allow the client which is running on another port
ctx.header("Access-Control-Allow-Origin", "*")
}
// app.before() { ctx ->
// // allow the client which is running on another port
// ctx.header("Access-Control-Allow-Origin", "*")
// }
app.get("/api/v1/extension/list") { ctx ->
ctx.json(getExtensionList())
@ -146,12 +150,17 @@ class Main {
// adds the manga to library
app.get("api/v1/manga/:mangaId/library") { ctx ->
// TODO
val mangaId = ctx.pathParam("mangaId").toInt()
addMangaToLibrary(mangaId)
ctx.status(200)
}
// removes the manga from the library
app.delete("api/v1/manga/:mangaId/library") { ctx ->
// TODO
val mangaId = ctx.pathParam("mangaId").toInt()
println("fuck")
removeMangaFromLibrary(mangaId)
ctx.status(200)
}
// adds the manga to category
@ -207,7 +216,7 @@ class Main {
// lists all manga in the library, suitable if no categories are defined
app.get("/api/v1/library/") { ctx ->
// TODO
ctx.json(getLibraryMangas())
}
// category list

View File

@ -20,7 +20,8 @@ data class MangaDataClass(
val author: String? = null,
val description: String? = null,
val genre: String? = null,
val status: String = MangaStatus.UNKNOWN.name
val status: String = MangaStatus.UNKNOWN.name,
val inLibrary: Boolean = false
)
data class PagedMangaListDataClass(

View File

@ -5,7 +5,10 @@ package ir.armor.tachidesk.database.table
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import eu.kanade.tachiyomi.source.model.SManga
import ir.armor.tachidesk.database.dataclass.MangaDataClass
import ir.armor.tachidesk.util.proxyThumbnailUrl
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ResultRow
object MangaTable : IntIdTable() {
val url = varchar("url", 2048)
@ -27,6 +30,25 @@ object MangaTable : IntIdTable() {
val sourceReference = reference("source", SourceTable)
}
fun MangaTable.toDataClass(mangaEntry: ResultRow) =
MangaDataClass(
mangaEntry[MangaTable.id].value,
mangaEntry[sourceReference].value,
mangaEntry[MangaTable.url],
mangaEntry[MangaTable.title],
proxyThumbnailUrl(mangaEntry[MangaTable.id].value),
mangaEntry[MangaTable.initialized],
mangaEntry[MangaTable.artist],
mangaEntry[MangaTable.author],
mangaEntry[MangaTable.description],
mangaEntry[MangaTable.genre],
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
mangaEntry[MangaTable.inLibrary]
)
enum class MangaStatus(val status: Int) {
UNKNOWN(0),
ONGOING(1),

View File

@ -0,0 +1,42 @@
package ir.armor.tachidesk.util
import ir.armor.tachidesk.database.dataclass.MangaDataClass
import ir.armor.tachidesk.database.table.MangaTable
import ir.armor.tachidesk.database.table.toDataClass
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
fun addMangaToLibrary(mangaId: Int) {
val manga = getManga(mangaId)
if (!manga.inLibrary) {
transaction {
MangaTable.update({ MangaTable.id eq manga.id }) {
it[inLibrary] = true
}
}
}
}
fun removeMangaFromLibrary(mangaId: Int) {
val manga = getManga(mangaId)
if (!manga.inLibrary) {
transaction {
MangaTable.update({ MangaTable.id eq manga.id }) {
it[inLibrary] = false
}
}
}
}
fun getLibraryMangas(): List<MangaDataClass> {
return transaction {
MangaTable.select { MangaTable.inLibrary eq true }.map {
MangaTable.toDataClass(it)
}
}
}

View File

@ -34,6 +34,7 @@ fun getManga(mangaId: Int, proxyThumbnail: Boolean = true): MangaDataClass {
mangaEntry[MangaTable.description],
mangaEntry[MangaTable.genre],
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
mangaEntry[MangaTable.inLibrary]
)
} else { // initialize manga
val source = getHttpSource(mangaEntry[MangaTable.sourceReference].value)
@ -77,6 +78,7 @@ fun getManga(mangaId: Int, proxyThumbnail: Boolean = true): MangaDataClass {
fetchedManga.description,
fetchedManga.genre,
MangaStatus.valueOf(fetchedManga.status).name,
false
)
}
}

View File

@ -64,7 +64,7 @@ fun MangasPage.processEntries(sourceId: Long): PagedMangaListDataClass {
manga.author,
manga.description,
manga.genre,
MangaStatus.valueOf(manga.status).name,
MangaStatus.valueOf(manga.status).name
)
} else {
val mangaId = mangaEntry[MangaTable.id].value
@ -83,6 +83,7 @@ fun MangasPage.processEntries(sourceId: Long): PagedMangaListDataClass {
mangaEntry[MangaTable.description],
mangaEntry[MangaTable.genre],
MangaStatus.valueOf(mangaEntry[MangaTable.status]).name,
mangaEntry[MangaTable.inLibrary]
)
}
}

10
webUI/node_modules/.yarn-integrity generated vendored
View File

@ -1,10 +0,0 @@
{
"systemParams": "linux-x64-88",
"modulesFolders": [],
"flags": [],
"linkedModules": [],
"topLevelPatterns": [],
"lockfileEntries": {},
"files": [],
"artifacts": {}
}

View File

@ -20,6 +20,7 @@ import Reader from './screens/Reader';
import Search from './screens/SearchSingle';
import NavBarTitle from './context/NavbarTitle';
import DarkTheme from './context/DarkTheme';
import Library from './screens/Library';
export default function App() {
const [title, setTitle] = useState<string>('Tachidesk');
@ -53,7 +54,6 @@ export default function App() {
return (
<Router>
<ThemeProvider theme={theme}>
<NavBarTitle.Provider value={navTitleContext}>
<CssBaseline />
@ -83,6 +83,9 @@ export default function App() {
<Route path="/manga/:id">
<Manga />
</Route>
<Route path="/library">
<Library />
</Route>
<Route path="/">
<Home />
</Route>

View File

@ -2,20 +2,49 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import React from 'react';
import { Button } from '@material-ui/core';
import React, { useState } from 'react';
interface IProps{
manga: IManga | undefined
manga: IManga
}
export default function MangaDetails(props: IProps) {
const { manga } = props;
const [inLibrary, setInLibrary] = useState<string>(
manga.inLibrary ? 'In Library' : 'Not In Library',
);
function addToLibrary() {
setInLibrary('adding');
fetch(`http://127.0.0.1:4567/api/v1/manga/${manga.id}/library/`).then(() => {
setInLibrary('In Library');
});
}
function removeFromLibrary() {
setInLibrary('removing');
fetch(`http://127.0.0.1:4567/api/v1/manga/${manga.id}/library/`, { method: 'DELETE', mode: 'cors' }).then(() => {
setInLibrary('Not In Library');
});
}
function handleButtonClick() {
if (inLibrary === 'Not In Library') {
addToLibrary();
} else {
removeFromLibrary();
}
}
return (
<>
<h1>
{manga && manga.title}
</h1>
<div style={{ display: 'flex', flexDirection: 'row-reverse' }}>
<Button variant="outlined" onClick={() => handleButtonClick()}>{inLibrary}</Button>
</div>
</>
);
}

View File

@ -36,6 +36,14 @@ export default function TemporaryDrawer({ drawerOpen, setDrawerOpen }: IProps) {
onKeyDown={() => setDrawerOpen(false)}
>
<List>
<Link to="/library" style={{ color: 'inherit', textDecoration: 'none' }}>
<ListItem button key="Library">
<ListItemIcon>
<InboxIcon />
</ListItemIcon>
<ListItemText primary="Library" />
</ListItem>
</Link>
<Link to="/extensions" style={{ color: 'inherit', textDecoration: 'none' }}>
<ListItem button key="Extensions">
<ListItemIcon>

View File

@ -0,0 +1,34 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import React, { useContext, useEffect, useState } from 'react';
import MangaGrid from '../components/MangaGrid';
import NavBarTitle from '../context/NavbarTitle';
export default function MangaList() {
const { setTitle } = useContext(NavBarTitle);
const [mangas, setMangas] = useState<IManga[]>([]);
const [lastPageNum, setLastPageNum] = useState<number>(1);
useEffect(() => {
setTitle('Library');
}, []);
useEffect(() => {
fetch('http://127.0.0.1:4567/api/v1/library')
.then((response) => response.json())
.then((data: IManga[]) => {
setMangas(data);
});
}, [lastPageNum]);
return (
<MangaGrid
mangas={mangas}
hasNextPage={false}
lastPageNum={lastPageNum}
setLastPageNum={setLastPageNum}
/>
);
}

View File

@ -38,7 +38,7 @@ export default function Manga() {
return (
<>
<MangaDetails manga={manga} />
{manga && <MangaDetails manga={manga} />}
{chapterCards}
</>
);

View File

@ -25,6 +25,7 @@ interface IManga {
id: number
title: string
thumbnailUrl: string
inLibrary?: boolean
}
interface IChapter {