Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve plugin settings, standardized captcha errors, hide chapters that no longer exist #1389

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/database/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { createNovelCategoryTableQuery } from './tables/NovelCategoryTable';
import {
createChapterTableQuery,
createChapterNovelIdIndexQuery,
addHiddenColumnQuery,
} from './tables/ChapterTable';
import { dbTxnErrorCallback } from './utils/helpers';
import { noop } from 'lodash-es';
Expand All @@ -32,6 +33,7 @@ export const createTables = () => {

db.transaction(tx => {
tx.executeSql(createRepositoryTableQuery);
tx.executeSql(addHiddenColumnQuery);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Db migration

});
};

Expand Down
20 changes: 18 additions & 2 deletions src/database/queries/ChapterQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ export const insertChapters = async (
if (!chapters?.length) {
return;
}
const existingChapters = await getPageChapters(
novelId,
'',
'',
chapters[0].page || '1',
);
const chaptersToHide = existingChapters.filter(
c => !chapters.some(ch => ch.path === c.path),
);
Comment on lines +31 to +33
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hide chapters if they are known but not in the list given


db.transaction(tx => {
chapters.forEach((chapter, index) => {
tx.executeSql(
Expand All @@ -40,8 +50,8 @@ export const insertChapters = async (
tx.executeSql(
`
UPDATE Chapter SET
page = ?, position = ?
WHERE path = ? AND novelId = ? AND (page != ? OR position != ?)
page = ?, position = ?, hidden = 0
WHERE path = ? AND novelId = ? AND (page != ? OR position != ? OR hidden != 0)
`,
[
chapter.page || '1',
Expand All @@ -56,6 +66,12 @@ export const insertChapters = async (
},
);
});
chaptersToHide.forEach(chapter => {
tx.executeSql(
'UPDATE Chapter SET hidden = 1 WHERE path = ? AND novelId = ?',
[chapter.path, novelId],
);
});
});
};

Expand Down
1 change: 1 addition & 0 deletions src/database/queries/LibraryQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const getLibraryWithCategoryQuery = `
SUM(unread) as chaptersUnread, SUM(isDownloaded) as chaptersDownloaded,
novelId, MAX(readTime) as lastReadAt, MAX(updatedTime) as lastUpdatedAt
FROM Chapter
WHERE hidden = 0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dont show hidden chapters for unread counts

GROUP BY novelId
) as C ON NIL.id = C.novelId
) WHERE 1 = 1
Expand Down
6 changes: 3 additions & 3 deletions src/database/queries/StatsQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@ const getChaptersReadCountQuery = `
FROM Chapter
JOIN Novel
ON Chapter.novelId = Novel.id
WHERE Chapter.unread = 0 AND Novel.inLibrary = 1
WHERE Chapter.unread = 0 AND Novel.inLibrary = 1 AND Chapter.hidden = 0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont show hidden chapters for stats

`;

const getChaptersTotalCountQuery = `
SELECT COUNT(*) as chaptersCount
FROM Chapter
JOIN Novel
ON Chapter.novelId = Novel.id
WHERE Novel.inLibrary = 1
WHERE Novel.inLibrary = 1 AND Chapter.hidden = 0
`;

const getChaptersUnreadCountQuery = `
SELECT COUNT(*) as chaptersUnread
FROM Chapter
JOIN Novel
ON Chapter.novelId = Novel.id
WHERE Chapter.unread = 1 AND Novel.inLibrary = 1
WHERE Chapter.unread = 1 AND Novel.inLibrary = 1 AND Chapter.hidden = 0
`;

const getChaptersDownloadedCountQuery = `
Expand Down
5 changes: 5 additions & 0 deletions src/database/tables/ChapterTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@ export const createChapterTableQuery = `
page TEXT DEFAULT "1",
position INTEGER DEFAULT 0,
progress INTEGER,
hidden INTEGER DEFAULT 0,
UNIQUE(path, novelId),
FOREIGN KEY (novelId) REFERENCES Novel(id) ON DELETE CASCADE
)
`;

export const addHiddenColumnQuery = `
ALTER TABLE Chapter ADD COLUMN hidden INTEGER DEFAULT 0
`;

export const createChapterNovelIdIndexQuery = `
CREATE INDEX
IF NOT EXISTS
Expand Down
1 change: 1 addition & 0 deletions src/hooks/persisted/usePlugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export default function usePlugins() {
name: _plg.name,
version: _plg.version,
hasUpdate: false,
hasSettings: !!_plg.pluginSettings,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update the hasSettings value on plugin update, not only plugin installation

};
if (newPlugin.id === lastUsedPlugin?.id) {
setLastUsedPlugin(newPlugin);
Expand Down
21 changes: 19 additions & 2 deletions src/plugins/helpers/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,25 @@ export const fetchApi = async (
init?: FetchInit,
): Promise<Response> => {
init = makeInit(init);
return await fetch(url, init);
return await fetch(url, init).then(checkCloudflareError);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

standardized cloudflare error handling across all plugins

};

async function checkCloudflareError(res: Response) {
const text = await res.clone().text();
const title = text.match(/<title>(.*?)<\/title>/)?.[1];
if (
title == 'Bot Verification' ||
title == 'You are being redirected...' ||
title == 'Un instant...' ||
title == 'Just a moment...' ||
title == 'Redirecting...'
) {
throw new Error('Captcha error, please open in webview');
}

return res;
}

const FILE_READER_PREFIX_LENGTH = 'data:application/octet-stream;base64,'
.length;

Expand Down Expand Up @@ -79,7 +95,7 @@ export const fetchText = async (
): Promise<string> => {
init = makeInit(init);
try {
const res = await fetch(url, init);
const res = await fetch(url, init).then(checkCloudflareError);
if (!res.ok) {
throw new Error();
}
Expand Down Expand Up @@ -163,6 +179,7 @@ export const fetchProto = async function (
...init,
body: bodyArray,
} as RequestInit)
.then(checkCloudflareError)
.then(r => r.blob())
.then(blob => {
// decode response data
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/pluginManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,17 @@ const getPlugin = (pluginId: string) => {
return plugins[pluginId];
};

const unloadPlugin = (pluginId: string) => {
plugins[pluginId] = undefined;
};
Comment on lines +151 to +153
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

option to unload plugin so you dont need to restart app to apply plugin settings


const LOCAL_PLUGIN_ID = 'local';

export {
getPlugin,
installPlugin,
uninstallPlugin,
unloadPlugin,
updatePlugin,
fetchPlugins,
LOCAL_PLUGIN_ID,
Expand Down
42 changes: 28 additions & 14 deletions src/screens/browse/components/Modals/SourceSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import { Button } from '@components/index';
import { useTheme } from '@hooks/persisted';
import { getString } from '@strings/translations';
import { Storage } from '@plugins/helpers/storage';
import { unloadPlugin } from '@plugins/pluginManager';
import { SwitchItem } from '@components';

interface PluginSetting {
value: string;
label: string;
type?: 'Switch';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add switch setting type

}

interface PluginSettings {
Expand Down Expand Up @@ -75,6 +78,7 @@ const SourceSettingsModal: React.FC<SourceSettingsModal> = ({
Object.entries(formValues).forEach(([key, value]) => {
storage.set(key, value);
});
unloadPlugin(pluginId);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unload plugin on settings change (itll get re-loaded when needed) as this allows re-initialization of plugin settings

onDismiss();
};

Expand Down Expand Up @@ -112,20 +116,30 @@ const SourceSettingsModal: React.FC<SourceSettingsModal> = ({
</Text>
<Text style={[{ color: theme.onSurfaceVariant }]}>{description}</Text>

{Object.entries(pluginSettings).map(([key, setting]) => (
<TextInput
key={key}
mode="outlined"
label={setting.label}
value={formValues[key] || ''}
onChangeText={value => handleChange(key, value)}
placeholder={`Enter ${setting.label}`}
placeholderTextColor={theme.onSurfaceDisabled}
underlineColor={theme.outline}
style={[{ color: theme.onSurface }, styles.textInput]}
theme={{ colors: { ...theme } }}
/>
))}
{Object.entries(pluginSettings).map(([key, setting]) =>
setting?.type === 'Switch' ? (
<SwitchItem
key={key}
label={setting.label}
value={!!formValues[key]}
onPress={() => handleChange(key, formValues[key] ? '' : 'true')}
theme={theme}
/>
) : (
Comment on lines +120 to +128
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

switch setting type

(saves the values as either an empty string or the string "true" as plugin settings are all strings, and by making false falsy it will work just as well)

<TextInput
key={key}
mode="outlined"
label={setting.label}
value={formValues[key] || ''}
onChangeText={value => handleChange(key, value)}
placeholder={`Enter ${setting.label}`}
placeholderTextColor={theme.onSurfaceDisabled}
underlineColor={theme.outline}
style={[{ color: theme.onSurface }, styles.textInput]}
theme={{ colors: { ...theme } }}
/>
),
)}

<View style={styles.customCSSButtons}>
<Button
Expand Down
3 changes: 2 additions & 1 deletion src/screens/novel/NovelScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const Novel = ({ route, navigation }: NovelScreenProps) => {
lastRead,
novelSettings: {
sort = defaultChapterSort,
filter = '',
filter = 'AND hidden=0',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

by default hide hidden chapters

showChapterTitles = false,
},
openPage,
Expand All @@ -89,6 +89,7 @@ const Novel = ({ route, navigation }: NovelScreenProps) => {
refreshChapters,
deleteChapters,
} = useNovel(path, pluginId);

const theme = useTheme();
const { top: topInset, bottom: bottomInset } = useSafeAreaInsets();

Expand Down
6 changes: 5 additions & 1 deletion src/screens/novel/components/Info/NovelInfoHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,11 @@ const NovelInfoHeader = ({
) : null}
<IconButton
icon="filter-variant"
iconColor={filter ? filterColor(theme.isDark) : theme.onSurface}
iconColor={
filter.trim() !== 'AND hidden=0'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cus AND hidden=0 is default check for not eq that

? filterColor(theme.isDark)
: theme.onSurface
}
size={24}
onPress={() => novelBottomSheetRef.current?.present()}
/>
Expand Down
12 changes: 11 additions & 1 deletion src/screens/novel/components/NovelBottomSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ const ChaptersSettingsSheet = ({
: filterChapters(filter + ' AND bookmark=1');
}}
/>
<Checkbox
theme={theme}
label={getString('novelScreen.bottomSheet.filters.dontExist')}
status={!filter.match('AND hidden=0')}
onPress={() => {
filter.match('AND hidden=0')
? filterChapters(filter.replace(/ ?AND hidden=0/, ''))
: filterChapters(filter + ' AND hidden=0');
}}
/>
Comment on lines +95 to +104
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checkbox to remove the AND hidden=0 check (to show hidden chapters)

</View>
);

Expand Down Expand Up @@ -184,7 +194,7 @@ const ChaptersSettingsSheet = ({
);

return (
<BottomSheet snapPoints={[240]} bottomSheetRef={bottomSheetRef}>
<BottomSheet snapPoints={[280]} bottomSheetRef={bottomSheetRef}>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sheet needs to be taller cus new option

<BottomSheetView
style={[
styles.contentContainer,
Expand Down
23 changes: 20 additions & 3 deletions src/services/updates/LibraryUpdateQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { NOVEL_STORAGE } from '@utils/Storages';
import { downloadFile } from '@plugins/helpers/fetch';
import ServiceManager from '@services/ServiceManager';
import { db } from '@database/db';
import { getPageChapters } from '@database/queries/ChapterQueries';

const updateNovelMetadata = (
pluginId: string,
Expand Down Expand Up @@ -73,13 +74,23 @@ const updateNovelTotalPages = (novelId: number, totalPages: number) => {
});
};

const updateNovelChapters = (
const updateNovelChapters = async (
novelName: string,
novelId: number,
chapters: ChapterItem[],
downloadNewChapters?: boolean,
page?: string,
) => {
const existingChapters = await getPageChapters(
novelId,
'',
'',
chapters[0].page || '1',
);
const chaptersToHide = existingChapters.filter(
c => !chapters.some(ch => ch.path === c.path),
);
Comment on lines +90 to +92
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another place where hiding chapters that are in db but not in response


return new Promise((resolve, reject) => {
db.transaction(async tx => {
for (let position = 0; position < chapters.length; position++) {
Expand Down Expand Up @@ -124,8 +135,8 @@ const updateNovelChapters = (
tx.executeSql(
`
UPDATE Chapter SET
name = ?, releaseTime = ?, updatedTime = datetime('now','localtime'), page = ?, position = ?
WHERE path = ? AND novelId = ? AND (name != ? OR releaseTime != ? OR page != ? OR position != ?);
name = ?, releaseTime = ?, updatedTime = datetime('now','localtime'), page = ?, position = ?, hidden = 0
WHERE path = ? AND novelId = ? AND (name != ? OR releaseTime != ? OR page != ? OR position != ? OR hidden != 0);
`,
[
name,
Expand Down Expand Up @@ -153,6 +164,12 @@ const updateNovelChapters = (
},
);
}
chaptersToHide.forEach(chapter => {
tx.executeSql(
'UPDATE Chapter SET hidden = 1 WHERE path = ? AND novelId = ?',
[chapter.path, novelId],
);
});
resolve(null);
});
});
Expand Down
5 changes: 3 additions & 2 deletions strings/languages/en/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
"updatedTo": "Updated to %{version}",
"settings": {
"title": "Plugin Settings",
"description": "Fill in the plugin settings. Restart app to apply the settings."
"description": "Fill in the plugin settings."
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You dont need to restart the app anymore 🔥

}
},
"browseSettings": "Browse Settings",
Expand Down Expand Up @@ -333,7 +333,8 @@
"filters": {
"bookmarked": "Bookmarked",
"downloaded": "Downloaded",
"unread": "Unread"
"unread": "Unread",
"dontExist": "Show chapters that no longer exist"
},
"order": {
"byChapterName": "By chapter name",
Expand Down
1 change: 1 addition & 0 deletions strings/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ export interface StringMap {
'novelScreen.bottomSheet.filters.bookmarked': 'string';
'novelScreen.bottomSheet.filters.downloaded': 'string';
'novelScreen.bottomSheet.filters.unread': 'string';
'novelScreen.bottomSheet.filters.dontExist': 'string';
'novelScreen.bottomSheet.order.byChapterName': 'string';
'novelScreen.bottomSheet.order.bySource': 'string';
'novelScreen.chapterChapnum': 'string';
Expand Down
Loading