New Source AO3 (archive of our own) (#1086)
* Add files via upload * 2nd * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * clean up * clean up
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,491 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
import { defaultCover } from '@libs/defaultCover';
|
||||
|
||||
class ArchiveOfOurOwn implements Plugin.PluginBase {
|
||||
id = 'archiveofourown';
|
||||
name = 'Archive Of Our Own';
|
||||
version = '1.0.0';
|
||||
icon = 'src/en/ao3/icon.png';
|
||||
site = 'https://archiveofourown.org/';
|
||||
|
||||
parseNovels(loadedCheerio: CheerioAPI): Plugin.NovelItem[] {
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
|
||||
loadedCheerio('li.work').each((idx, ele) => {
|
||||
const novelName = loadedCheerio(ele)
|
||||
.find('h4.heading > a')
|
||||
.first()
|
||||
.text()
|
||||
.trim();
|
||||
const novelUrl = loadedCheerio(ele)
|
||||
.find('h4.heading > a')
|
||||
.first()
|
||||
.attr('href')
|
||||
?.trim();
|
||||
|
||||
if (!novelUrl) return;
|
||||
|
||||
const novel = {
|
||||
name: novelName,
|
||||
cover: defaultCover, // No cover image
|
||||
path: novelUrl.slice(1),
|
||||
};
|
||||
|
||||
novels.push(novel);
|
||||
});
|
||||
|
||||
return novels;
|
||||
}
|
||||
|
||||
async popularNovels(
|
||||
page: number,
|
||||
{ showLatestNovels, filters }: Plugin.PopularNovelsOptions<Filters>,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
// Base URL and common parameters
|
||||
let link = `${this.site}works/search?page=${page}&work_search%5Blanguage_id%5D=en`;
|
||||
|
||||
// Apply sorting based on showLatestNovels
|
||||
if (showLatestNovels) {
|
||||
link += `&work_search%5Bsort_column%5D=revised_at&work_search%5Bsort_direction%5D=${filters.sortdir.value}`;
|
||||
} else if (filters) {
|
||||
link += `&work_search%5Bsort_column%5D=${filters.sort.value}&work_search%5Bsort_direction%5D=${filters.sortdir.value}`;
|
||||
}
|
||||
|
||||
// Apply additional filters
|
||||
if (filters) {
|
||||
// if (filters.genre.value !== '') link += `&work_search%5Bfandom_names%5D=${filters.genre.value}`;
|
||||
if (filters.completion.value !== '')
|
||||
link += `&work_search%5Bcomplete%5D=${filters.completion.value}`;
|
||||
if (filters.crossover.value !== '')
|
||||
link += `&work_search%5Bcrossover%5D=${filters.crossover.value}`;
|
||||
if (filters.categories.value.length > 0) {
|
||||
filters.categories.value.forEach((category: string) => {
|
||||
link += `&work_search%5Bcategory_ids%5D%5B%5D=${category}`;
|
||||
});
|
||||
}
|
||||
if (filters.warningsFilter.value.length > 0) {
|
||||
filters.warningsFilter.value.forEach((warning: string) => {
|
||||
link += `&work_search%5Barchive_warning_ids%5D%5B%5D=${warning}`;
|
||||
});
|
||||
}
|
||||
if (filters.singlechap.value !== '')
|
||||
link += `&work_search%5Bsingle_chapter%5D=${filters.singlechap.value}`;
|
||||
if (filters.author.value !== '')
|
||||
link += `&work_search%5Bcreators%5D=${filters.author.value}`;
|
||||
if (
|
||||
filters.dateFilter.value !== '' &&
|
||||
filters.dateIncrements.value !== ''
|
||||
) {
|
||||
link += `&work_search%5Brevised_at%5D=${filters.dateFilter.value}+${filters.dateIncrements.value}`;
|
||||
}
|
||||
if (filters.words.value !== '')
|
||||
link += `&work_search%5Bword_count%5D=${filters.words.value}`;
|
||||
if (filters.hits.value !== '')
|
||||
link += `&work_search%5Bhits%5D=${filters.hits.value}`;
|
||||
if (filters.bookmarks.value !== '')
|
||||
link += `&work_search%5Bbookmarks_count%5D=${filters.bookmarks.value}`;
|
||||
if (filters.comments.value !== '')
|
||||
link += `&work_search%5Bcomments_count%5D=${filters.comments.value}`;
|
||||
if (filters.kudos.value !== '')
|
||||
link += `&work_search%5Bkudos_count%5D=${filters.kudos.value}`;
|
||||
}
|
||||
|
||||
const body = await fetchApi(link).then(r => r.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
return this.parseNovels(loadedCheerio);
|
||||
}
|
||||
|
||||
async parseNovel(novelUrl: string): Promise<Plugin.SourceNovel> {
|
||||
const result = await fetchApi(new URL(novelUrl, this.site).toString());
|
||||
const body = await result.text();
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
const novel: Plugin.SourceNovel = {
|
||||
path: novelUrl,
|
||||
name: loadedCheerio('h2.title').text().trim() || 'Untitled',
|
||||
cover: defaultCover, // No cover image available
|
||||
status: loadedCheerio('dt.status').text().includes('Updated')
|
||||
? 'Ongoing'
|
||||
: 'Completed',
|
||||
chapters: [],
|
||||
};
|
||||
|
||||
novel.author = loadedCheerio('a[rel="author"]')
|
||||
.map((i, el) => loadedCheerio(el).text().trim())
|
||||
.get()
|
||||
.join(', ');
|
||||
novel.genres = Array.from(loadedCheerio('dd.freeform.tags li a.tag'))
|
||||
.map(el => loadedCheerio(el).text().trim())
|
||||
.join(',');
|
||||
const summary = loadedCheerio('blockquote.userstuff').text().trim();
|
||||
const fandom = Array.from(loadedCheerio('dd.fandom.tags li a.tag'))
|
||||
.map(el => loadedCheerio(el).text().trim())
|
||||
.join(',');
|
||||
const rating = Array.from(loadedCheerio('dd.rating.tags li a.tag'))
|
||||
.map(el => loadedCheerio(el).text().trim())
|
||||
.join(',');
|
||||
const warning = Array.from(loadedCheerio('dd.warning.tags li a.tag'))
|
||||
.map(el => loadedCheerio(el).text().trim())
|
||||
.join(',');
|
||||
const series = Array.from(loadedCheerio('dd.series li a.tag'))
|
||||
.map(el => loadedCheerio(el).text().trim())
|
||||
.join(',');
|
||||
const relation = Array.from(loadedCheerio('dd.relationship.tags li a.tag'))
|
||||
.map(el => loadedCheerio(el).text().trim())
|
||||
.join(',');
|
||||
const character = Array.from(loadedCheerio('dd.character.tags li a.tag'))
|
||||
.map(el => loadedCheerio(el).text().trim())
|
||||
.join(',');
|
||||
const stats = Array.from(loadedCheerio('dd.stats li a.tag'))
|
||||
.map(el => loadedCheerio(el).text().trim())
|
||||
.join(',');
|
||||
novel.summary = `Fandom:\n${fandom}\n\nRating:\n${rating}\n\nWarning:\n${warning}\n\nSummary:\n${summary}\n\nSeries:\n${series}\n\nRelationships:\n${relation}\n\nCharacters:\n${character}\n\nStats:\n${stats}`;
|
||||
const chapterItems: Plugin.ChapterItem[] = [];
|
||||
loadedCheerio('#chapter_index select').each((i, selectEl) => {
|
||||
loadedCheerio(selectEl)
|
||||
.find('option')
|
||||
.each((i, el) => {
|
||||
const chapterName = loadedCheerio(el).text().trim();
|
||||
const chapterUrlCode = loadedCheerio(el).attr('value')?.trim();
|
||||
const chapterUrl = `${novelUrl}/chapters/${chapterUrlCode}`;
|
||||
|
||||
if (chapterUrl) {
|
||||
chapterItems.push({
|
||||
name: chapterName,
|
||||
path: new URL(chapterUrl, this.site).toString(),
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
novel.chapters = chapterItems;
|
||||
|
||||
return novel;
|
||||
}
|
||||
|
||||
async parseChapter(chapterUrl: string): Promise<string> {
|
||||
const result = await fetchApi(new URL(chapterUrl, this.site).toString());
|
||||
const body = await result.text();
|
||||
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
loadedCheerio('h3.title').each((i, el) => {
|
||||
const $h3 = loadedCheerio(el);
|
||||
const $a = $h3.find('a');
|
||||
$a.removeAttr('href');
|
||||
const aText = $a.text().trim();
|
||||
const nextSiblingText = $h3
|
||||
.contents()
|
||||
.filter((_, node) => node.nodeType === 3)
|
||||
.text()
|
||||
.trim();
|
||||
$h3.html(`${aText}<br>${nextSiblingText}`);
|
||||
});
|
||||
loadedCheerio('h3.landmark.heading#work').remove();
|
||||
|
||||
const chapterText = loadedCheerio('div#chapters > div').html() || '';
|
||||
|
||||
return chapterText;
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
page: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
const searchUrl = `${this.site}works/search?page=${page}&work_search%5Blanguage_id%5D=en&work_search%5Bquery%5D=${searchTerm}`;
|
||||
|
||||
const result = await fetchApi(searchUrl);
|
||||
const body = await result.text();
|
||||
|
||||
const loadedCheerio = parseHTML(body);
|
||||
return this.parseNovels(loadedCheerio);
|
||||
}
|
||||
filters = {
|
||||
sort: {
|
||||
value: 'hits',
|
||||
label: 'Sort by',
|
||||
options: [
|
||||
{ label: 'Best Match', value: '_score' },
|
||||
{ label: 'Hits', value: 'hits' },
|
||||
{ label: 'Kudos', value: 'kudos' },
|
||||
{ label: 'Comments', value: 'comments' },
|
||||
{ label: 'Bookmarks', value: 'bookmarks' },
|
||||
{ label: 'Word Count', value: 'word_count' },
|
||||
{ label: 'Date Updated', value: 'revised_at' },
|
||||
{ label: 'Date Posted', value: 'created_at' },
|
||||
{ label: 'Author', value: 'authors_to_sort_on' },
|
||||
{ label: 'Title', value: 'title_to_sort_on' },
|
||||
],
|
||||
type: FilterTypes.Picker,
|
||||
},
|
||||
sortdir: {
|
||||
value: 'desc',
|
||||
label: 'Sort direction',
|
||||
options: [
|
||||
{ label: 'Descending', value: 'desc' },
|
||||
{ label: 'Ascending', value: 'asc' },
|
||||
],
|
||||
type: FilterTypes.Picker,
|
||||
},
|
||||
ratings: {
|
||||
value: '',
|
||||
label: 'Ratings',
|
||||
options: [
|
||||
{ label: 'Not Rated', value: '9' },
|
||||
{ label: 'General Audiences', value: '10' },
|
||||
{ label: 'Teen And Up Audiences', value: '11' },
|
||||
{ label: 'Mature', value: '12' },
|
||||
{ label: 'Explicit', value: '13' },
|
||||
],
|
||||
type: FilterTypes.Picker,
|
||||
},
|
||||
language: {
|
||||
value: 'en',
|
||||
label: 'Language',
|
||||
options: [
|
||||
{ label: 'None', value: '' },
|
||||
{ label: 'af Soomaali', value: 'so' },
|
||||
{ label: 'Afrikaans', value: 'afr' },
|
||||
{ label: 'Aynu itak | アイヌ イタㇰ', value: 'ain' },
|
||||
{ label: 'العربية', value: 'ar' },
|
||||
{ label: 'አማርኛ', value: 'amh' },
|
||||
{ label: '𓂋𓏺𓈖 𓆎𓅓𓏏𓊖', value: 'egy' },
|
||||
{ label: 'ܐܪܡܝܐ | ארמיא', value: 'arc' },
|
||||
{ label: 'հայերեն', value: 'hy' },
|
||||
{ label: 'American Sign Language', value: 'ase' },
|
||||
{ label: 'asturianu', value: 'ast' },
|
||||
{ label: 'Bahasa Indonesia', value: 'id' },
|
||||
{ label: 'Bahasa Malaysia', value: 'ms' },
|
||||
{ label: 'Български', value: 'bg' },
|
||||
{ label: 'বাংলা', value: 'bn' },
|
||||
{ label: 'Basa Jawa', value: 'jv' },
|
||||
{ label: 'Башҡорт теле', value: 'ba' },
|
||||
{ label: 'беларуская', value: 'be' },
|
||||
{ label: 'Bosanski', value: 'bos' },
|
||||
{ label: 'Brezhoneg', value: 'br' },
|
||||
{ label: 'Català', value: 'ca' },
|
||||
{ label: 'Cebuano', value: 'ceb' },
|
||||
{ label: 'Čeština', value: 'cs' },
|
||||
{ label: 'Chinuk Wawa', value: 'chn' },
|
||||
{ label: 'къырымтатар тили | qırımtatar tili', value: 'crh' },
|
||||
{ label: 'Cymraeg', value: 'cy' },
|
||||
{ label: 'Dansk', value: 'da' },
|
||||
{ label: 'Deutsch', value: 'de' },
|
||||
{ label: 'eesti keel', value: 'et' },
|
||||
{ label: 'Ελληνικά', value: 'el' },
|
||||
{ label: '𒅴𒂠', value: 'sux' },
|
||||
{ label: 'English', value: 'en' },
|
||||
{ label: 'Eald Englisċ', value: 'ang' },
|
||||
{ label: 'Español', value: 'es' },
|
||||
{ label: 'Esperanto', value: 'eo' },
|
||||
{ label: 'Euskara', value: 'eu' },
|
||||
{ label: 'فارسی', value: 'fa' },
|
||||
{ label: 'Filipino', value: 'fil' },
|
||||
{ label: 'Français', value: 'fr' },
|
||||
{ label: 'Friisk', value: 'frr' },
|
||||
{ label: 'Furlan', value: 'fur' },
|
||||
{ label: 'Gaeilge', value: 'ga' },
|
||||
{ label: 'Gàidhlig', value: 'gd' },
|
||||
{ label: 'Galego', value: 'gl' },
|
||||
{ label: '𐌲𐌿𐍄𐌹𐍃𐌺𐌰', value: 'got' },
|
||||
{ label: 'Creolese', value: 'gyn' },
|
||||
{ label: '中文-客家话', value: 'hak' },
|
||||
{ label: '한국어', value: 'ko' },
|
||||
{ label: 'Hausa | هَرْشَن هَوْسَ', value: 'hau' },
|
||||
{ label: 'हिन्दी', value: 'hi' },
|
||||
{ label: 'Hrvatski', value: 'hr' },
|
||||
{ label: 'ʻŌlelo Hawaiʻi', value: 'haw' },
|
||||
{ label: 'Interlingua', value: 'ia' },
|
||||
{ label: 'isiZulu', value: 'zu' },
|
||||
{ label: 'Íslenska', value: 'is' },
|
||||
{ label: 'Italiano', value: 'it' },
|
||||
{ label: 'עברית', value: 'he' },
|
||||
{ label: 'Kalaallisut', value: 'kal' },
|
||||
{ label: 'ಕನ್ನಡ', value: 'kan' },
|
||||
{ label: 'ქართული', value: 'kat' },
|
||||
{ label: 'Kernewek', value: 'cor' },
|
||||
{ label: 'ភាសាខ្មែរ', value: 'khm' },
|
||||
{ label: 'Khuzdul', value: 'qkz' },
|
||||
{ label: 'Kiswahili', value: 'sw' },
|
||||
{ label: 'kreyòl ayisyen', value: 'ht' },
|
||||
{ label: 'Kurdî | کوردی', value: 'ku' },
|
||||
{ label: 'Кыргызча', value: 'kir' },
|
||||
{ label: 'Langue des signes québécoise', value: 'fcs' },
|
||||
{ label: 'Latviešu valoda', value: 'lv' },
|
||||
{ label: 'Lëtzebuergesch', value: 'lb' },
|
||||
{ label: 'Lietuvių kalba', value: 'lt' },
|
||||
{ label: 'Lingua latina', value: 'la' },
|
||||
{ label: 'Magyar', value: 'hu' },
|
||||
{ label: 'македонски', value: 'mk' },
|
||||
{ label: 'മലയാളം', value: 'ml' },
|
||||
{ label: 'Malti', value: 'mt' },
|
||||
{ label: 'ᠮᠠᠨᠵᡠ ᡤᡳᠰᡠᠨ', value: 'mnc' },
|
||||
{ label: "Mando'a", value: 'qmd' },
|
||||
{ label: 'मराठी', value: 'mr' },
|
||||
{ label: 'Mikisúkî', value: 'mik' },
|
||||
{ label: 'ᠮᠣᠩᠭᠣᠯ ᠪᠢᠴᠢᠭ᠌ | Монгол Кирилл үсэг', value: 'mon' },
|
||||
{ label: 'မြန်မာဘာသာ', value: 'my' },
|
||||
{ label: 'Эрзянь кель', value: 'myv' },
|
||||
{ label: 'Nāhuatl', value: 'nah' },
|
||||
{ label: '中文-闽南话 臺語', value: 'nan' },
|
||||
{ label: 'Nawat', value: 'ppl' },
|
||||
{ label: 'Nederlands', value: 'nl' },
|
||||
{ label: '日本語', value: 'ja' },
|
||||
{ label: 'Norsk', value: 'no' },
|
||||
{ label: 'Азәрбајҹан дили | آذربایجان دیلی', value: 'azj' },
|
||||
{ label: 'Нохчийн мотт', value: 'ce' },
|
||||
{ label: '‘O’odham Ñiok', value: 'ood' },
|
||||
{ label: 'لسان عثمانى', value: 'ota' },
|
||||
{ label: 'پښتو', value: 'ps' },
|
||||
{ label: 'Plattdüütsch', value: 'nds' },
|
||||
{ label: 'Polski', value: 'pl' },
|
||||
{ label: 'Português brasileiro', value: 'ptBR' },
|
||||
{ label: 'Português europeu', value: 'ptPT' },
|
||||
{ label: 'ਪੰਜਾਬੀ', value: 'pa' },
|
||||
{ label: 'qazaqşa | қазақша', value: 'kaz' },
|
||||
{ label: 'Uncategorized Constructed Languages', value: 'qlq' },
|
||||
{ label: 'Quenya', value: 'qya' },
|
||||
{ label: 'Română', value: 'ro' },
|
||||
{ label: 'Русский', value: 'ru' },
|
||||
{ label: 'Scots', value: 'sco' },
|
||||
{ label: 'Shqip', value: 'sq' },
|
||||
{ label: 'Sindarin', value: 'sjn' },
|
||||
{ label: 'සිංහල', value: 'si' },
|
||||
{ label: 'Slovenčina', value: 'sk' },
|
||||
{ label: 'Slovenščina', value: 'slv' },
|
||||
{ label: 'Sprēkō Þiudiskō', value: 'gem' },
|
||||
{ label: 'Српски', value: 'sr' },
|
||||
{ label: 'suomi', value: 'fi' },
|
||||
{ label: 'Svenska', value: 'sv' },
|
||||
{ label: 'தமிழ்', value: 'ta' },
|
||||
{ label: 'татар теле', value: 'tat' },
|
||||
{ label: 'te reo Māori', value: 'mri' },
|
||||
{ label: 'తెలుగు', value: 'tel' },
|
||||
{ label: 'ไทย', value: 'th' },
|
||||
{ label: 'Thermian', value: 'tqx' },
|
||||
{ label: 'བོད་སྐད་', value: 'bod' },
|
||||
{ label: 'Tiếng Việt', value: 'vi' },
|
||||
{ label: 'ϯⲙⲉⲧⲣⲉⲙⲛ̀ⲭⲏⲙⲓ', value: 'cop' },
|
||||
{ label: 'tlhIngan-Hol', value: 'tlh' },
|
||||
{ label: 'toki pona', value: 'tok' },
|
||||
{ label: 'Trinidadian Creole', value: 'trf' },
|
||||
{ label: 'τσακώνικα', value: 'tsd' },
|
||||
{ label: 'ᏣᎳᎩ ᎦᏬᏂᎯᏍᏗ', value: 'chr' },
|
||||
{ label: 'Türkçe', value: 'tr' },
|
||||
{ label: 'Українська', value: 'uk' },
|
||||
{ label: 'اُردُو', value: 'urd' },
|
||||
{ label: 'ئۇيغۇر تىلى', value: 'uig' },
|
||||
{ label: 'Volapük', value: 'vol' },
|
||||
{ label: '中文-吴语', value: 'wuu' },
|
||||
{ label: 'יידיש', value: 'yi' },
|
||||
{ label: 'maayaʼ tʼàan', value: 'yua' },
|
||||
{ label: '中文-广东话 粵語', value: 'yue' },
|
||||
{ label: '中文-普通话 國語', value: 'zh' },
|
||||
],
|
||||
type: FilterTypes.Picker,
|
||||
},
|
||||
completion: {
|
||||
value: '',
|
||||
label: 'Completion Status',
|
||||
options: [
|
||||
{ label: 'All works', value: 'checked' },
|
||||
{ label: 'Complete works only', value: 'T' },
|
||||
{ label: 'Works in progress only', value: 'F' },
|
||||
],
|
||||
type: FilterTypes.Picker,
|
||||
},
|
||||
crossover: {
|
||||
value: '',
|
||||
label: 'Crossover Status',
|
||||
options: [
|
||||
{ label: 'Include crossovers', value: 'checked' },
|
||||
{ label: 'Exclude crossovers', value: 'T' },
|
||||
{ label: 'Only crossovers', value: 'F' },
|
||||
],
|
||||
type: FilterTypes.Picker,
|
||||
},
|
||||
categories: {
|
||||
value: [],
|
||||
label: 'Categories',
|
||||
options: [
|
||||
{ label: 'F/F', value: '116' },
|
||||
{ label: 'F/M', value: '22' },
|
||||
{ label: 'Gen', value: '21' },
|
||||
{ label: 'M/M', value: '23' },
|
||||
{ label: 'Multi', value: '2246' },
|
||||
{ label: 'Other', value: '24' },
|
||||
],
|
||||
type: FilterTypes.CheckboxGroup,
|
||||
},
|
||||
warningsFilter: {
|
||||
value: [],
|
||||
label: 'Warnings',
|
||||
options: [
|
||||
{ label: 'Creator Chose Not To Use Archive Warnings', value: '14' },
|
||||
{ label: 'Graphic Depictions Of Violence', value: '17' },
|
||||
{ label: 'Major Character Death', value: '18' },
|
||||
{ label: 'No Archive Warnings Apply', value: '16' },
|
||||
{ label: 'Rape/Non-Con', value: '19' },
|
||||
{ label: 'Underage', value: '20' },
|
||||
],
|
||||
type: FilterTypes.CheckboxGroup,
|
||||
},
|
||||
singlechap: {
|
||||
value: '',
|
||||
label: 'Single Chapter',
|
||||
options: [{ label: 'Days', value: '1' }],
|
||||
type: FilterTypes.Picker,
|
||||
},
|
||||
author: {
|
||||
value: '',
|
||||
label: 'Author/Artist',
|
||||
type: FilterTypes.TextInput,
|
||||
},
|
||||
dateFilter: {
|
||||
value: '',
|
||||
label: 'Enter single Number only Date',
|
||||
type: FilterTypes.TextInput,
|
||||
},
|
||||
dateIncrements: {
|
||||
value: 'days+ago',
|
||||
label: 'Must choose date type',
|
||||
options: [
|
||||
{ label: 'Days', value: 'days+ago' },
|
||||
{ label: 'Weeks', value: 'weeks+ago' },
|
||||
{ label: 'Months', value: 'months+ago' },
|
||||
{ label: 'Years', value: 'years+ago' },
|
||||
],
|
||||
type: FilterTypes.Picker,
|
||||
},
|
||||
words: {
|
||||
value: '',
|
||||
label:
|
||||
'Word Count, exact number eg. 40 or less than eg. <40 or greater than eg. >40 or range eg. 10-100',
|
||||
type: FilterTypes.TextInput,
|
||||
},
|
||||
hits: {
|
||||
value: '',
|
||||
label: 'Hits',
|
||||
type: FilterTypes.TextInput,
|
||||
},
|
||||
bookmarks: {
|
||||
value: '',
|
||||
label: 'Bookmarks',
|
||||
type: FilterTypes.TextInput,
|
||||
},
|
||||
comments: {
|
||||
value: '',
|
||||
label: 'Comments',
|
||||
type: FilterTypes.TextInput,
|
||||
},
|
||||
kudos: {
|
||||
value: '',
|
||||
label: 'Kudos',
|
||||
type: FilterTypes.TextInput,
|
||||
},
|
||||
} satisfies Filters;
|
||||
}
|
||||
|
||||
export default new ArchiveOfOurOwn();
|
||||
Reference in New Issue
Block a user