Skip to content

Commit

Permalink
feat: add scheduling
Browse files Browse the repository at this point in the history
  • Loading branch information
oae committed Oct 14, 2022
1 parent cc2d6dd commit bce4832
Show file tree
Hide file tree
Showing 26 changed files with 368 additions and 538 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -379,4 +379,6 @@ $RECYCLE.BIN/
# and uncomment the following lines
# .pnp.*

# End of https://www.toptal.com/developers/gitignore/api/linux,windows,macos,node,visualstudiocode,intellij+all,nextjs,yarn
# End of https://www.toptal.com/developers/gitignore/api/linux,windows,macos,node,visualstudiocode,intellij+all,nextjs,yarn

mangas/
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ CREATE TABLE "Manga" (
"cover" TEXT NOT NULL,
"interval" TEXT NOT NULL,
"source" TEXT NOT NULL,
"query" TEXT NOT NULL,
"libraryId" INTEGER,
CONSTRAINT "Manga_libraryId_fkey" FOREIGN KEY ("libraryId") REFERENCES "Library" ("id") ON DELETE SET NULL ON UPDATE CASCADE
"libraryId" INTEGER NOT NULL,
CONSTRAINT "Manga_libraryId_fkey" FOREIGN KEY ("libraryId") REFERENCES "Library" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
5 changes: 2 additions & 3 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ model Manga {
cover String
interval String
source String
query String
Library Library? @relation(fields: [libraryId], references: [id])
libraryId Int?
Library Library @relation(fields: [libraryId], references: [id])
libraryId Int
}
5 changes: 3 additions & 2 deletions src/components/addLibrary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ function Form({ onClose }: { onClose: () => void }) {
<form
onSubmit={form.onSubmit(async (values) => {
setVisible((v) => !v);
let library = null;
try {
await libraryMutation.mutateAsync({
library = await libraryMutation.mutateAsync({
path: values.library.path,
});
} catch (err) {
Expand Down Expand Up @@ -61,7 +62,7 @@ function Form({ onClose }: { onClose: () => void }) {
title: 'Library',
message: (
<Text>
Library is created at <Code color="blue">{values.library.path}</Code>
Library is created at <Code color="blue">{library.path}</Code>
</Text>
),
});
Expand Down
10 changes: 2 additions & 8 deletions src/components/addManga/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ const useStyles = createStyles((theme) => ({
const schema = z.object({
source: z.string().min(1, { message: 'You must select a source' }),
query: z.string().min(1, { message: 'Cannot be empty' }),
mangaOrder: z.number().gte(0, { message: 'Please select a manga' }),
mangaTitle: z.string().min(1, { message: 'Please select a manga' }),
interval: z.string().min(1, { message: 'Please select an interval' }),
});
Expand All @@ -46,7 +45,6 @@ export function AddMangaForm({ onClose }: { onClose: () => void }) {
initialValues: {
source: '',
query: '',
mangaOrder: -1,
mangaTitle: '',
interval: '',
},
Expand All @@ -62,8 +60,7 @@ export function AddMangaForm({ onClose }: { onClose: () => void }) {
}
if (active === 1) {
form.validateField('mangaTitle');
form.validateField('mangaOrder');
if (!form.isValid('mangaOrder') || !form.isValid('mangaTitle')) {
if (!form.isValid('mangaTitle')) {
return;
}
}
Expand All @@ -89,7 +86,6 @@ export function AddMangaForm({ onClose }: { onClose: () => void }) {
}
if (active === 2) {
form.setFieldValue('query', '');
form.setFieldValue('mangaOrder', -1);
form.setFieldValue('mangaTitle', '');
form.setFieldValue('interval', '');
}
Expand All @@ -101,11 +97,9 @@ export function AddMangaForm({ onClose }: { onClose: () => void }) {

const onSubmit = form.onSubmit(async (values) => {
setVisible((v) => !v);
const { mangaOrder, mangaTitle, query, source, interval } = values;
const { mangaTitle, source, interval } = values;
try {
await mutation.mutateAsync({
keyword: query,
order: mangaOrder,
title: mangaTitle,
interval,
source,
Expand Down
1 change: 0 additions & 1 deletion src/components/addManga/mangaSearchResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ ImageCheckbox.defaultProps = {
type IMangaSearchResult = {
status: string;
title: string;
order: number;
cover: string;
};

Expand Down
8 changes: 2 additions & 6 deletions src/components/addManga/steps/downloadStep.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Box, LoadingOverlay, Select, Stack, TextInput } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form';
import { IconFolderPlus } from '@tabler/icons';
import { sanitizer } from '../../../utils/sanitize';
import { trpc } from '../../../utils/trpc';
import type { FormType } from '../form';

Expand All @@ -17,12 +18,7 @@ export function DownloadStep({ form }: { form: UseFormReturnType<FormType> }) {
return <LoadingOverlay visible />;
}

const sanitizeMangaName = form.values.mangaTitle
.replaceAll(/[\\/<>:;"'|?!*{}#%&^+,~\s]/g, '_')
.replaceAll(/__+/g, '_')
.replaceAll(/^[_\-.]+|[_\-.]+$/g, '_');

const downloadPath = `${libraryPath}/${sanitizeMangaName}`;
const downloadPath = `${libraryPath}/${sanitizer(form.values.mangaTitle)}`;

return (
<Box>
Expand Down
5 changes: 2 additions & 3 deletions src/components/addManga/steps/reviewStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ const useStyles = createStyles((_theme) => ({
export function ReviewStep({ form }: { form: UseFormReturnType<FormType> }) {
const query = trpc.manga.detail.useQuery(
{
keyword: form.values.query,
source: form.values.source,
order: form.values.mangaOrder,
title: form.values.mangaTitle,
},
{
staleTime: Infinity,
enabled: !!form.values.query && !!form.values.source && !!form.values.mangaTitle && form.values.mangaOrder > -1,
enabled: !!form.values.source && !!form.values.mangaTitle,
},
);

Expand Down
3 changes: 0 additions & 3 deletions src/components/addManga/steps/searchStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export function SearchStep({ form }: { form: UseFormReturnType<FormType> }) {
if (!form.isValid('query')) {
return;
}
form.setFieldValue('mangaOrder', -1);
form.setFieldValue('mangaTitle', '');
setLoading(true);
const result = await ctx.manga.search.fetch({
Expand Down Expand Up @@ -59,10 +58,8 @@ export function SearchStep({ form }: { form: UseFormReturnType<FormType> }) {
items={searchResult}
onSelect={(selected) => {
if (selected) {
form.setFieldValue('mangaOrder', selected.order);
form.setFieldValue('mangaTitle', selected.title);
} else {
form.setFieldValue('mangaOrder', -1);
form.setFieldValue('mangaTitle', '');
}
}}
Expand Down
48 changes: 43 additions & 5 deletions src/components/mangaCard.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Badge, Button, createStyles, Paper, Title } from '@mantine/core';
import { IconExternalLink } from '@tabler/icons';
import { ActionIcon, Badge, Button, Code, createStyles, Paper, Text, Title } from '@mantine/core';
import { openConfirmModal } from '@mantine/modals';
import { IconExternalLink, IconX } from '@tabler/icons';

const useStyles = createStyles((theme) => ({
const useStyles = createStyles((theme, _params, getRef) => ({
card: {
position: 'relative',
height: 350,
width: 210,
display: 'flex',
Expand All @@ -18,8 +20,17 @@ const useStyles = createStyles((theme) => ({
transform: 'scale(1.01)',
boxShadow: theme.shadows.md,
},
[`&:hover .${getRef('removeButton')}`]: {
display: 'flex',
},
},
removeButton: {
ref: getRef('removeButton'),
position: 'absolute',
right: -5,
top: -5,
display: 'none',
},

title: {
fontFamily: `${theme.fontFamily}`,
fontWeight: 900,
Expand All @@ -37,10 +48,34 @@ interface ArticleCardImageProps {
image: string;
title: string;
category?: string;
onRemove: () => void;
}

export function MangaCard({ image, title, category }: ArticleCardImageProps) {
const createRemoveModal = (title: string, onRemove: () => void) => {
const openDeleteModal = () =>
openConfirmModal({
title: `Delete ${title}?`,
centered: true,
children: (
<Text size="sm">
Are you sure you want to delete
<Code className="text-base font-bold" color="red">
{title}
</Code>
? This action is destructive and all downloaded files will be removed
</Text>
),
labels: { confirm: 'Delete', cancel: 'Cancel' },
confirmProps: { color: 'red' },
onConfirm: onRemove,
});

return openDeleteModal;
};

export function MangaCard({ image, title, category, onRemove }: ArticleCardImageProps) {
const { classes } = useStyles();
const removeModal = createRemoveModal(title, onRemove);

return (
<Paper
Expand All @@ -50,6 +85,9 @@ export function MangaCard({ image, title, category }: ArticleCardImageProps) {
sx={{ backgroundImage: `linear-gradient(rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.5)), url(${image})` }}
className={classes.card}
>
<ActionIcon color="red" variant="filled" radius="xl" className={classes.removeButton} onClick={removeModal}>
<IconX size={16} />
</ActionIcon>
<div>
{category && (
<Badge color="teal" variant="filled" className={classes.category} size="md">
Expand Down
44 changes: 42 additions & 2 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Grid, LoadingOverlay } from '@mantine/core';
import { Code, Grid, LoadingOverlay, Text } from '@mantine/core';
import { showNotification } from '@mantine/notifications';
import { IconCheck, IconX } from '@tabler/icons';
import { AddManga } from '../components/addManga';

import { EmptyPrompt } from '../components/emptyPrompt';
Expand All @@ -7,6 +9,7 @@ import { trpc } from '../utils/trpc';

export default function IndexPage() {
const libraryQuery = trpc.library.query.useQuery();
const mangaDelete = trpc.manga.remove.useMutation();

const libraryId = libraryQuery.data?.id;

Expand Down Expand Up @@ -34,6 +37,38 @@ export default function IndexPage() {
);
}

const handleDelete = async (id: number, title: string) => {
try {
await mangaDelete.mutateAsync({
id,
});
showNotification({
icon: <IconCheck size={18} />,
color: 'teal',
autoClose: true,
title: 'Manga',
message: (
<Text>
<Code color="blue">{title}</Code> is removed from library
</Text>
),
});
} catch (err) {
showNotification({
icon: <IconX size={18} />,
color: 'red',
autoClose: true,
title: 'Manga',
message: (
<Text>
<Code color="red">{`${err}`}</Code>
</Text>
),
});
}
mangaQuery.refetch();
};

return (
<Grid justify="flex-start">
<Grid.Col span="content">
Expand All @@ -47,7 +82,12 @@ export default function IndexPage() {
mangaQuery.data.map((manga) => {
return (
<Grid.Col span="content" key={manga.id}>
<MangaCard category={manga.interval} title={manga.title} image={manga.cover} />
<MangaCard
category={manga.interval}
title={manga.title}
image={manga.cover}
onRemove={() => handleDelete(manga.id, manga.title)}
/>
</Grid.Col>
);
})}
Expand Down
12 changes: 0 additions & 12 deletions src/server/downloader/bullboard.ts

This file was deleted.

Loading

0 comments on commit bce4832

Please sign in to comment.