mirror of
https://github.com/tachiyomiorg/tachiyomi-extensions-inspector.git
synced 2024-12-25 00:01:49 +01:00
single source search done
This commit is contained in:
parent
6401b946b6
commit
7d1c63e181
@ -119,10 +119,11 @@ class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// single source search
|
// single source search
|
||||||
app.get("/api/v1/source/:sourceId/search/:searchTerm") { ctx ->
|
app.get("/api/v1/source/:sourceId/search/:searchTerm/:pageNum") { ctx ->
|
||||||
val sourceId = ctx.pathParam("sourceId").toLong()
|
val sourceId = ctx.pathParam("sourceId").toLong()
|
||||||
val searchTerm = ctx.pathParam("searchTerm")
|
val searchTerm = ctx.pathParam("searchTerm")
|
||||||
ctx.json(sourceSearch(sourceId, searchTerm))
|
val pageNum = ctx.pathParam("pageNum").toInt()
|
||||||
|
ctx.json(sourceSearch(sourceId, searchTerm, pageNum))
|
||||||
}
|
}
|
||||||
|
|
||||||
// source filter list
|
// source filter list
|
||||||
|
@ -8,7 +8,7 @@ data class MangaDataClass(
|
|||||||
|
|
||||||
val url: String,
|
val url: String,
|
||||||
val title: String,
|
val title: String,
|
||||||
val thumbnail_url: String? = null,
|
val thumbnailUrl: String? = null,
|
||||||
|
|
||||||
val initialized: Boolean = false,
|
val initialized: Boolean = false,
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ir.armor.tachidesk.util
|
package ir.armor.tachidesk.util
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import ir.armor.tachidesk.database.dataclass.MangaDataClass
|
import ir.armor.tachidesk.database.dataclass.MangaDataClass
|
||||||
import ir.armor.tachidesk.database.table.MangaStatus
|
import ir.armor.tachidesk.database.table.MangaStatus
|
||||||
import ir.armor.tachidesk.database.table.MangaTable
|
import ir.armor.tachidesk.database.table.MangaTable
|
||||||
@ -17,6 +18,11 @@ fun getMangaList(sourceId: Long, pageNum: Int = 1, popular: Boolean): List<Manga
|
|||||||
else
|
else
|
||||||
throw Exception("Source $source doesn't support latest")
|
throw Exception("Source $source doesn't support latest")
|
||||||
}
|
}
|
||||||
|
return mangasPage.processEntries(sourceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun MangasPage.processEntries(sourceId: Long): List<MangaDataClass> {
|
||||||
|
val mangasPage = this
|
||||||
return transaction {
|
return transaction {
|
||||||
return@transaction mangasPage.mangas.map { manga ->
|
return@transaction mangasPage.mangas.map { manga ->
|
||||||
var mangaEntry = MangaTable.select { MangaTable.url eq manga.url }.firstOrNull()
|
var mangaEntry = MangaTable.select { MangaTable.url eq manga.url }.firstOrNull()
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package ir.armor.tachidesk.util
|
package ir.armor.tachidesk.util
|
||||||
|
|
||||||
|
import ir.armor.tachidesk.database.dataclass.MangaDataClass
|
||||||
|
|
||||||
fun sourceFilters(sourceId: Long) {
|
fun sourceFilters(sourceId: Long) {
|
||||||
val source = getHttpSource(sourceId)
|
val source = getHttpSource(sourceId)
|
||||||
// source.getFilterList().toItems()
|
// source.getFilterList().toItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sourceSearch(sourceId: Long, searchTerm: String) {
|
fun sourceSearch(sourceId: Long, searchTerm: String, pageNum: Int): List<MangaDataClass> {
|
||||||
val source = getHttpSource(sourceId)
|
val source = getHttpSource(sourceId)
|
||||||
// source.fetchSearchManga()
|
val searchManga = source.fetchSearchManga(pageNum, searchTerm, source.getFilterList()).toBlocking().first()
|
||||||
|
return searchManga.processEntries(sourceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sourceGlobalSearch(searchTerm: String) {
|
fun sourceGlobalSearch(searchTerm: String) {
|
||||||
@ -18,7 +21,7 @@ data class FilterWrapper(
|
|||||||
val filter: Any
|
val filter: Any
|
||||||
)
|
)
|
||||||
|
|
||||||
// private fun FilterList.toItems(): List<FilterWrapper> {
|
// private fun FilterList.toFilterWrapper(): List<FilterWrapper> {
|
||||||
// return mapNotNull { filter ->
|
// return mapNotNull { filter ->
|
||||||
// when (filter) {
|
// when (filter) {
|
||||||
// is Filter.Header -> FilterWrapper("Header",filter)
|
// is Filter.Header -> FilterWrapper("Header",filter)
|
||||||
|
@ -9,7 +9,7 @@ import Extensions from './screens/Extensions';
|
|||||||
import MangaList from './screens/MangaList';
|
import MangaList from './screens/MangaList';
|
||||||
import Manga from './screens/Manga';
|
import Manga from './screens/Manga';
|
||||||
import Reader from './screens/Reader';
|
import Reader from './screens/Reader';
|
||||||
import Search from './screens/Search';
|
import Search from './screens/SearchSingle';
|
||||||
import NavBarTitle from './context/NavbarTitle';
|
import NavBarTitle from './context/NavbarTitle';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
@ -22,7 +22,7 @@ export default function App() {
|
|||||||
<NavBar />
|
<NavBar />
|
||||||
|
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/search">
|
<Route path="/sources/:sourceId/search/">
|
||||||
<Search />
|
<Search />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/extensions">
|
<Route path="/extensions">
|
||||||
|
@ -65,8 +65,9 @@ export default function SourceCard(props: IProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
{supportsLatest && <Button variant="outlined" style={{ marginLeft: 20 }} onClick={() => { window.location.href = `sources/${id}/latest/`; }}>Latest</Button>}
|
<Button variant="outlined" style={{ marginLeft: 20 }} onClick={() => { window.location.href = `/sources/${id}/search/`; }}>Search</Button>
|
||||||
<Button variant="outlined" style={{ marginLeft: 20 }} onClick={() => { window.location.href = `sources/${id}/popular/`; }}>Browse</Button>
|
{supportsLatest && <Button variant="outlined" style={{ marginLeft: 20 }} onClick={() => { window.location.href = `/sources/${id}/latest/`; }}>Latest</Button>}
|
||||||
|
<Button variant="outlined" style={{ marginLeft: 20 }} onClick={() => { window.location.href = `/sources/${id}/popular/`; }}>Browse</Button>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -48,14 +48,14 @@ export default function TemporaryDrawer({ drawerOpen, setDrawerOpen }: IProps) {
|
|||||||
<ListItemText primary="Sources" />
|
<ListItemText primary="Sources" />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="/search" style={{ color: 'inherit', textDecoration: 'none' }}>
|
{/* <Link to="/search" style={{ color: 'inherit', textDecoration: 'none' }}>
|
||||||
<ListItem button key="Search">
|
<ListItem button key="Search">
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<InboxIcon />
|
<InboxIcon />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary="Global Search" />
|
<ListItemText primary="Global Search" />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</Link>
|
</Link> */}
|
||||||
</List>
|
</List>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -19,8 +19,8 @@ export default function MangaList(props: { popular: boolean }) {
|
|||||||
const sourceType = props.popular ? 'popular' : 'latest';
|
const sourceType = props.popular ? 'popular' : 'latest';
|
||||||
fetch(`http://127.0.0.1:4567/api/v1/source/${sourceId}/${sourceType}/${lastPageNum}`)
|
fetch(`http://127.0.0.1:4567/api/v1/source/${sourceId}/${sourceType}/${lastPageNum}`)
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data: { title: string, thumbnail_url: string, id:number }[]) => setMangas(
|
.then((data: IManga[]) => setMangas(
|
||||||
data.map((it) => ({ title: it.title, thumbnailUrl: it.thumbnail_url, id: it.id })),
|
data.map((it) => ({ title: it.title, thumbnailUrl: it.thumbnailUrl, id: it.id })),
|
||||||
));
|
));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
import React, { useContext, useState } from 'react';
|
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
|
||||||
import TextField from '@material-ui/core/TextField';
|
|
||||||
import Button from '@material-ui/core/Button';
|
|
||||||
import MangaGrid from '../components/MangaGrid';
|
|
||||||
import NavBarTitle from '../context/NavbarTitle';
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
|
||||||
root: {
|
|
||||||
TextField: {
|
|
||||||
margin: theme.spacing(1),
|
|
||||||
width: '25ch',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default function Search() {
|
|
||||||
const { setTitle } = useContext(NavBarTitle);
|
|
||||||
setTitle('Search');
|
|
||||||
const classes = useStyles();
|
|
||||||
const [error, setError] = useState<boolean>(false);
|
|
||||||
const [mangas, setMangas] = useState<IManga[]>([]);
|
|
||||||
const [message, setMessage] = useState<string>('');
|
|
||||||
|
|
||||||
const textInput = React.createRef<HTMLInputElement>();
|
|
||||||
|
|
||||||
function doSearch() {
|
|
||||||
if (textInput.current) {
|
|
||||||
const { value } = textInput.current;
|
|
||||||
if (value === '') { setError(true); } else {
|
|
||||||
setError(false);
|
|
||||||
setMangas([]);
|
|
||||||
setMessage('button pressed');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mangaGrid = <MangaGrid mangas={mangas} message={message} />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<form className={classes.root} noValidate autoComplete="off">
|
|
||||||
<TextField inputRef={textInput} error={error} id="standard-basic" label="Search text.." />
|
|
||||||
<Button variant="contained" color="primary" onClick={() => doSearch()}>
|
|
||||||
Primary
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
{mangaGrid}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
81
webUI/react/src/screens/SearchSingle.tsx
Normal file
81
webUI/react/src/screens/SearchSingle.tsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
|
import TextField from '@material-ui/core/TextField';
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import MangaGrid from '../components/MangaGrid';
|
||||||
|
import NavBarTitle from '../context/NavbarTitle';
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
root: {
|
||||||
|
TextField: {
|
||||||
|
margin: theme.spacing(1),
|
||||||
|
width: '25ch',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function SearchSingle() {
|
||||||
|
const { setTitle } = useContext(NavBarTitle);
|
||||||
|
const { sourceId } = useParams<{sourceId: string}>();
|
||||||
|
const classes = useStyles();
|
||||||
|
const [error, setError] = useState<boolean>(false);
|
||||||
|
const [mangas, setMangas] = useState<IManga[]>([]);
|
||||||
|
const [message, setMessage] = useState<string>('');
|
||||||
|
const [lastPageNum] = useState<number>(1);
|
||||||
|
const [searchTerm, setSearchTerm] = useState<string>('');
|
||||||
|
|
||||||
|
const textInput = React.createRef<HTMLInputElement>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(`http://127.0.0.1:4567/api/v1/source/${sourceId}`)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data: { name: string }) => setTitle(`Search: ${data.name}`));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
function processInput() {
|
||||||
|
if (textInput.current) {
|
||||||
|
const { value } = textInput.current;
|
||||||
|
if (value === '') {
|
||||||
|
setError(true);
|
||||||
|
setMessage('Type something to search');
|
||||||
|
} else {
|
||||||
|
setError(false);
|
||||||
|
setSearchTerm(value);
|
||||||
|
setMessage('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (searchTerm.length > 0) {
|
||||||
|
fetch(`http://127.0.0.1:4567/api/v1/source/${sourceId}/search/${searchTerm}/${lastPageNum}`)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data: IManga[]) => {
|
||||||
|
if (data.length > 0) {
|
||||||
|
setMangas(
|
||||||
|
data.map((it) => (
|
||||||
|
{ title: it.title, thumbnailUrl: it.thumbnailUrl, id: it.id }
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setMessage('search qeury returned nothing.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [searchTerm]);
|
||||||
|
|
||||||
|
const mangaGrid = <MangaGrid mangas={mangas} message={message} />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<form className={classes.root} noValidate autoComplete="off">
|
||||||
|
<TextField inputRef={textInput} error={error} id="standard-basic" label="Search text.." />
|
||||||
|
<Button variant="contained" color="primary" onClick={() => processInput()}>
|
||||||
|
Primary
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
{mangaGrid}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user