automatic category fallback in style search (#831)

Even better. Seems way more reliable. Thanks tophf.
This commit is contained in:
tophf 2020-01-28 05:36:43 +03:00 committed by narcolepticinsomniac
parent a3c22325b8
commit 2b985a0a91

View File

@ -20,17 +20,7 @@ window.addEventListener('showStyles:done', function _() {
const API_URL = BASE_URL + '/api/v1/styles/'; const API_URL = BASE_URL + '/api/v1/styles/';
const UPDATE_URL = 'https://update.userstyles.org/%.md5'; const UPDATE_URL = 'https://update.userstyles.org/%.md5';
// normal category is just one word like 'github' or 'google' const STYLUS_CATEGORY = 'chrome-extension';
// but for some sites we need a fallback
// key: category.tld
// value <string>: use as category
// value true: fallback to search_terms
const CATEGORY_FALLBACK = {
'userstyles.org': 'userstyles.org',
'last.fm': true,
'Stylus': true,
};
const RX_CATEGORY = /^(?:.*?)([^.]+)(?:\.com?)?\.(\w+)$/;
const DISPLAY_PER_PAGE = 10; const DISPLAY_PER_PAGE = 10;
// Millisecs to wait before fetching next batch of search results. // Millisecs to wait before fetching next batch of search results.
@ -54,7 +44,7 @@ window.addEventListener('showStyles:done', function _() {
let searchTotalPages; let searchTotalPages;
let searchCurrentPage = 1; let searchCurrentPage = 1;
let searchExhausted = false; let searchExhausted = 0; // 1: once, 2: twice (first host.jp, then host)
// currently active USO requests // currently active USO requests
const xhrSpoofIds = new Set(); const xhrSpoofIds = new Set();
@ -79,7 +69,7 @@ window.addEventListener('showStyles:done', function _() {
const dom = {}; const dom = {};
Object.assign($('#find-styles-link'), { Object.assign($('#find-styles-link'), {
href: getSearchPageURL(tabURL), href: BASE_URL + '/styles/browse/' + getCategory(),
onclick(event) { onclick(event) {
if (!prefs.get('popup.findStylesInline') || dom.container) { if (!prefs.get('popup.findStylesInline') || dom.container) {
handleEvent.openURLandHide.call(this, event); handleEvent.openURLandHide.call(this, event);
@ -222,7 +212,7 @@ window.addEventListener('showStyles:done', function _() {
* Initializes search results container, starts fetching results. * Initializes search results container, starts fetching results.
*/ */
function load() { function load() {
if (searchExhausted) { if (searchExhausted > 1) {
if (!processedResults.length) { if (!processedResults.length) {
error(404); error(404);
} }
@ -233,21 +223,21 @@ window.addEventListener('showStyles:done', function _() {
dom.container.classList.remove('hidden'); dom.container.classList.remove('hidden');
dom.error.classList.add('hidden'); dom.error.classList.add('hidden');
let pass = category ? 1 : 0;
category = category || getCategory(); category = category || getCategory();
search({category}) search({category})
.then(function process(results) { .then(function process(results) {
const data = results.data.filter(sameCategory); const data = results.data.filter(sameCategoryNoDupes);
pass++; if (!data.length && searchExhausted <= 1) {
if (pass === 1 && !data.length) { const old = category;
category = getCategory({keepTLD: true}); const uso = (processedResults[0] || {}).subcategory;
return search({category, restart: true}).then(process); category = uso !== category && uso || getCategory({retry: true});
if (category !== old) return search({category, restart: true}).then(process);
} }
const numIrrelevant = results.data.length - data.length; const numIrrelevant = results.data.length - data.length;
totalResults = results.current_page === 1 ? results.total_entries : totalResults; totalResults += results.current_page === 1 ? results.total_entries : 0;
totalResults = Math.max(0, totalResults - numIrrelevant); totalResults = Math.max(0, totalResults - numIrrelevant);
totalPages = Math.ceil(totalResults / DISPLAY_PER_PAGE); totalPages = Math.ceil(totalResults / DISPLAY_PER_PAGE);
@ -258,7 +248,7 @@ window.addEventListener('showStyles:done', function _() {
processNextResult(); processNextResult();
} else if (numIrrelevant) { } else if (numIrrelevant) {
load(); load();
} else { } else if (!processedResults.length) {
return Promise.reject(404); return Promise.reject(404);
} }
}) })
@ -610,18 +600,10 @@ window.addEventListener('showStyles:done', function _() {
//endregion //endregion
//region USO API wrapper //region USO API wrapper
function getSearchPageURL() {
const category = getCategory();
return BASE_URL +
'/styles/browse/' +
(category in CATEGORY_FALLBACK ? '?search_terms=' : '') +
category;
}
/** /**
* Resolves the Userstyles.org "category" for a given URL. * Resolves the Userstyles.org "category" for a given URL.
*/ */
function getCategory({keepTLD} = {}) { function getCategory({retry} = {}) {
const u = tryCatch(() => new URL(tabURL)); const u = tryCatch(() => new URL(tabURL));
if (!u) { if (!u) {
// Invalid URL // Invalid URL
@ -629,21 +611,28 @@ window.addEventListener('showStyles:done', function _() {
} else if (u.protocol === 'file:') { } else if (u.protocol === 'file:') {
return 'file:'; return 'file:';
} else if (u.protocol === location.protocol) { } else if (u.protocol === location.protocol) {
return 'Stylus'; return STYLUS_CATEGORY;
} else { } else {
// Website address, strip TLD & subdomain const parts = u.hostname.replace(/\.(?:com?|org)(\.\w{2,3})$/, '$1').split('.');
const [, category = u.hostname, tld = ''] = u.hostname.match(RX_CATEGORY) || []; const [tld, main = u.hostname, third, fourth] = parts.reverse();
const categoryWithTLD = category + '.' + tld; const keepTld = !retry && !(
const fallback = CATEGORY_FALLBACK[categoryWithTLD]; tld === 'com' ||
return fallback === true && categoryWithTLD || fallback || category + (keepTLD ? tld : ''); tld === 'org' && main !== 'userstyles'
);
const keepThird = !retry && (
fourth ||
third && third !== 'www' && third !== 'm'
);
return (keepThird && `${third}.` || '') + main + (keepTld ? `.${tld}` : '');
} }
} }
function sameCategory(result) { function sameCategoryNoDupes(result) {
return result.subcategory && ( return (
category === result.subcategory || result.subcategory &&
category === 'Stylus' && /^(chrome|moz)-extension$/.test(result.subcategory) || !processedResults.some(pr => pr.id === result.id) &&
category.replace('.', '').toLowerCase() === result.subcategory.replace('.', '').toLowerCase() (category !== STYLUS_CATEGORY || /\bStylus\b/i.test(result.name + result.description)) &&
category.split('.')[0] === result.subcategory.split('.')[0]
); );
} }
@ -704,10 +693,10 @@ window.addEventListener('showStyles:done', function _() {
.then(json => { .then(json => {
searchCurrentPage = json.current_page + 1; searchCurrentPage = json.current_page + 1;
searchTotalPages = json.total_pages; searchTotalPages = json.total_pages;
searchExhausted = (searchCurrentPage > searchTotalPages); searchExhausted += searchCurrentPage > searchTotalPages;
return json; return json;
}).catch(reason => { }).catch(reason => {
searchExhausted = true; searchExhausted++;
return Promise.reject(reason); return Promise.reject(reason);
}); });
} }