Skip to content

Commit

Permalink
Update plugin sanbox (#1014)
Browse files Browse the repository at this point in the history
* add htmlparser2

* fix typo

* flatten plugins
  • Loading branch information
nyagami authored Mar 26, 2024
1 parent e171dfe commit 7ea8eba
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 116 deletions.
66 changes: 61 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"expo-speech": "~11.3.0",
"expo-sqlite": "~11.3.3",
"expo-web-browser": "~12.3.2",
"htmlparser2": "^9.1.0",
"i18n-js": "^3.8.0",
"lodash-es": "^4.17.21",
"protobufjs": "^7.2.6",
Expand Down
84 changes: 37 additions & 47 deletions src/hooks/persisted/usePlugins.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { locale } from 'expo-localization';
import { Language, languagesMapping } from '@utils/constants/languages';
import { languagesMapping } from '@utils/constants/languages';
import { orderBy } from 'lodash-es';
import { useMMKVObject } from 'react-native-mmkv';
import { PluginItem } from '@plugins/types';
Expand All @@ -23,72 +23,65 @@ export const FILTERED_INSTALLED_PLUGINS = 'FILTERED_INSTALLED_PLUGINS';

const defaultLang = languagesMapping[locale.split('-')[0]] || 'English';

export type PluginsMap = Record<Language, PluginItem[] | undefined>;

export default function usePlugins() {
const [lastUsedPlugin, setLastUsedPlugin] =
useMMKVObject<PluginItem>(LAST_USED_PLUGIN);
const [languagesFilter = [defaultLang], setLanguagesFilter] =
useMMKVObject<Language[]>(LANGUAGES_FILTER);
const [
filteredAvailablePlugins = {} as PluginsMap,
setFilteredAvailablePlugins,
] = useMMKVObject<PluginsMap>(FILTERED_AVAILABLE_PLUGINS);
useMMKVObject<string[]>(LANGUAGES_FILTER);
const [filteredAvailablePlugins = [], setFilteredAvailablePlugins] =
useMMKVObject<PluginItem[]>(FILTERED_AVAILABLE_PLUGINS);
const [filteredInstalledPlugins = [], setFilteredInstalledPlugins] =
useMMKVObject<PluginItem[]>(FILTERED_INSTALLED_PLUGINS);
/**
* @param filter
* We cant use the languagesFilter directly because it is updated only after component's lifecycle end.
* And toggleLanguagFilter triggers filterPlugins before lifecycle end.
*/
const filterPlugins = useCallback((filter: Language[]) => {
const filterPlugins = useCallback((filter: string[]) => {
const installedPlugins =
getMMKVObject<PluginItem[]>(INSTALLED_PLUGINS) || [];
const availablePlugins =
getMMKVObject<PluginsMap>(AVAILABLE_PLUGINS) || ({} as PluginsMap);
getMMKVObject<PluginItem[]>(AVAILABLE_PLUGINS) || [];
setFilteredInstalledPlugins(
installedPlugins.filter(plg => filter.includes(plg.lang)),
);
setFilteredAvailablePlugins(
filter.reduce((pre, cur) => {
pre[cur] = orderBy(availablePlugins[cur], 'name');
return pre;
}, {} as PluginsMap),
orderBy(
availablePlugins.filter(plg => filter.includes(plg.lang)),
'name',
),
);
}, []);

const refreshPlugins = useCallback(() => {
const installedPlugins =
getMMKVObject<PluginItem[]>(INSTALLED_PLUGINS) || [];
return fetchPlugins().then(fetchedPluginsMap => {
for (const key in fetchedPluginsMap) {
const lang = key as Language;
fetchedPluginsMap[lang] = fetchedPluginsMap[lang].filter(plg => {
const finded = installedPlugins.find(v => v.id === plg.id);
if (finded) {
if (newer(plg.version, finded.version)) {
finded.hasUpdate = true;
finded.iconUrl = plg.iconUrl;
finded.url = plg.url;
if (finded.id === lastUsedPlugin?.id) {
setLastUsedPlugin(finded);
}
return fetchPlugins().then(fetchedPlugins => {
fetchedPlugins.filter(plg => {
const finded = installedPlugins.find(v => v.id === plg.id);
if (finded) {
if (newer(plg.version, finded.version)) {
finded.hasUpdate = true;
finded.iconUrl = plg.iconUrl;
finded.url = plg.url;
if (finded.id === lastUsedPlugin?.id) {
setLastUsedPlugin(finded);
}
return false;
}
return true;
});
setMMKVObject(INSTALLED_PLUGINS, installedPlugins);
setMMKVObject(AVAILABLE_PLUGINS, fetchedPluginsMap);
filterPlugins(languagesFilter);
}
return false;
}
return true;
});
setMMKVObject(INSTALLED_PLUGINS, installedPlugins);
setMMKVObject(AVAILABLE_PLUGINS, fetchedPlugins);
filterPlugins(languagesFilter);
});
}, [languagesFilter]);

const toggleLanguageFilter = (lang: Language) => {
const toggleLanguageFilter = (lang: string) => {
const newFilter = languagesFilter.includes(lang)
? languagesFilter.filter(l => l !== lang)
: [...languagesFilter, lang];
: [lang, ...languagesFilter];
setLanguagesFilter(newFilter);
filterPlugins(newFilter);
};
Expand All @@ -106,10 +99,7 @@ export default function usePlugins() {
const installedPlugins =
getMMKVObject<PluginItem[]>(INSTALLED_PLUGINS) || [];
const availablePlugins =
getMMKVObject<PluginsMap>(AVAILABLE_PLUGINS) || ({} as PluginsMap);
availablePlugins[plugin.lang] = availablePlugins[plugin.lang]?.filter(
plg => plg.id !== plugin.id,
);
getMMKVObject<PluginItem[]>(AVAILABLE_PLUGINS) || [];

const actualPlugin: PluginItem = {
...plugin,
Expand All @@ -119,7 +109,10 @@ export default function usePlugins() {
if (!installedPlugins.some(plg => plg.id === plugin.id)) {
setMMKVObject(INSTALLED_PLUGINS, [...installedPlugins, actualPlugin]);
}
setMMKVObject(AVAILABLE_PLUGINS, availablePlugins);
setMMKVObject(
AVAILABLE_PLUGINS,
availablePlugins.filter(plg => plg.id !== plugin.id),
);
filterPlugins(languagesFilter);
} else {
throw new Error(
Expand All @@ -136,14 +129,11 @@ export default function usePlugins() {
const installedPlugins =
getMMKVObject<PluginItem[]>(INSTALLED_PLUGINS) || [];
const availablePlugins =
getMMKVObject<PluginsMap>(AVAILABLE_PLUGINS) || ({} as PluginsMap);
getMMKVObject<PluginItem[]>(AVAILABLE_PLUGINS) || [];

// safe
if (!availablePlugins[plugin.lang]?.some(_plg => _plg.id === plugin.id)) {
availablePlugins[plugin.lang] = [
...(availablePlugins[plugin.lang] || []),
plugin,
];
if (!availablePlugins.some(_plg => _plg.id === plugin.id)) {
availablePlugins.push(plugin);
setMMKVObject(AVAILABLE_PLUGINS, availablePlugins);
}
setMMKVObject(
Expand Down
9 changes: 5 additions & 4 deletions src/plugins/pluginManager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import RNFS from 'react-native-fs';
import { PluginDownloadFolder } from '@utils/constants/download';
import { newer } from '@utils/compareVersion';
import { Language } from '@utils/constants/languages';

// packages for plugins
import { load } from 'cheerio';
Expand All @@ -13,11 +12,13 @@ import { isUrlAbsolute } from './helpers/isAbsoluteUrl';
import { fetchApi, fetchFile, fetchProto, fetchText } from './helpers/fetch';
import { defaultCover } from './helpers/constants';
import { encode, decode } from 'urlencode';
import { Parser } from 'htmlparser2';
import TextFile from '@native/TextFile';

const pluginsFilePath = PluginDownloadFolder + '/plugins.json';

const packages: Record<string, any> = {
'htmlparser2': { Parser },
'cheerio': { load },
'dayjs': dayjs,
'qs': qs,
Expand Down Expand Up @@ -125,13 +126,13 @@ const updatePlugin = async (plugin: PluginItem) => {
return installPlugin(plugin.url);
};

const fetchPlugins = (): Promise<Record<Language, Array<PluginItem>>> => {
const fetchPlugins = (): Promise<PluginItem[]> => {
// plugins host
const githubUsername = 'LNReader';
const githubRepository = 'lnreader-sources';

const pluginsTag = 'v2.1.0';
return fetch(
`https://raw.githubusercontent.com/${githubUsername}/${githubRepository}/dist/.dist/plugins.min.json`,
`https://raw.githubusercontent.com/${githubUsername}/${githubRepository}/plugins/${pluginsTag}/.dist/plugins.min.json`,
).then(res => res.json());
};

Expand Down
3 changes: 1 addition & 2 deletions src/plugins/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { FilterToValues, Filters } from './filterTypes';
import { Language } from '@utils/constants/languages';

export interface NovelItem {
name: string;
Expand Down Expand Up @@ -50,7 +49,7 @@ export interface PluginItem {
id: string;
name: string;
site: string;
lang: Language;
lang: string;
version: string;
url: string; // the url of raw code
iconUrl: string;
Expand Down
6 changes: 3 additions & 3 deletions src/screens/browse/BrowseSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Appbar, List, SwitchItem } from '@components';

import { useBrowseSettings, usePlugins, useTheme } from '@hooks/persisted';
import { getString } from '@strings/translations';
import { availableLanguages, languages } from '@utils/constants/languages';
import { languages } from '@utils/constants/languages';
import { BrowseSettingsScreenProp } from '@navigators/types';

const BrowseSettings = ({ navigation }: BrowseSettingsScreenProp) => {
Expand Down Expand Up @@ -61,10 +61,10 @@ const BrowseSettings = ({ navigation }: BrowseSettingsScreenProp) => {
</>
}
keyExtractor={item => item}
data={availableLanguages}
data={languages}
renderItem={({ item }) => (
<SwitchItem
label={languages[item]}
label={item}
value={languagesFilter.includes(item)}
onPress={() => toggleLanguageFilter(item)}
theme={theme}
Expand Down
Loading

0 comments on commit 7ea8eba

Please sign in to comment.