Fixes boolean search

This commit is contained in:
Arhey 2023-02-17 14:51:02 +03:00
parent a5ea157146
commit 1cafbccc9e

View file

@ -9,212 +9,214 @@ export const countries = writable({})
export const filteredChannels = writable([]) export const filteredChannels = writable([])
export function search(_query) { export function search(_query) {
const parts = _query.toLowerCase().match(/(".*?"|[^"\s]+)+(?=\s*|\s*$)/g) || [] const parts = _query.toLowerCase().match(/(".*?"|[^"\s]+)+(?=\s*|\s*$)/g) || []
const filters = [] const filters = []
for (let value of parts) { for (let value of parts) {
let field = '_key' let field = '_key'
if (value.includes(':')) { if (value.includes(':')) {
;[field, value] = value.split(':') ;[field, value] = value.split(':')
} }
value = value.replace(/\"/g, '') value = value.replace(/\"/g, '')
if (field && value) { if (field && value) {
let numerical = ['streams', 'guides'].includes(field) let numerical = ['streams', 'guides'].includes(field)
filters.push({ field, numerical, value }) filters.push({ field, numerical, value })
} }
} }
if (!filters.length) { if (!filters.length) {
hasQuery.set(false) hasQuery.set(false)
filteredChannels.set(get(channels)) filteredChannels.set(get(channels))
return return
} }
const filtered = get(channels).filter(c => { const filtered = get(channels).filter(c => {
let results = [] let results = []
for (let f of filters) { for (let f of filters) {
if (!f.value) return false if (!f.value) return false
if (f.numerical) { if (f.numerical) {
if (f.value.startsWith('<')) { if (f.value.startsWith('<')) {
results.push(c._searchable[f.field] < parseInt(f.value.replace('<', ''))) results.push(c._searchable[f.field] < parseInt(f.value.replace('<', '')))
} else if (f.value.startsWith('>')) { } else if (f.value.startsWith('>')) {
results.push(c._searchable[f.field] > parseInt(f.value.replace('>', ''))) results.push(c._searchable[f.field] > parseInt(f.value.replace('>', '')))
} else { } else {
results.push(c._searchable[f.field] === parseInt(f.value)) results.push(c._searchable[f.field] === parseInt(f.value))
} }
} else { } else {
const regex = new RegExp(f.value.replaceAll(',', '|'), 'i') const regex = new RegExp(f.value.replaceAll(',', '|'), 'i')
results.push(regex.test(c._searchable[f.field])) // console.log(regex, c._searchable[f.field])
} results.push(regex.test(c._searchable[f.field]))
} }
}
return results.every(Boolean) return results.every(Boolean)
}) })
filteredChannels.set(filtered) filteredChannels.set(filtered)
hasQuery.set(true) hasQuery.set(true)
console.log('.') console.log('.')
} }
export async function fetchChannels() { export async function fetchChannels() {
const api = await loadAPI() const api = await loadAPI()
countries.set(api.countries) countries.set(api.countries)
let _channels = api.channels.map(c => { let _channels = api.channels.map(c => {
c._raw = copy(c) c._raw = copy(c)
c._streams = api.streams[c.id] || [] c._streams = api.streams[c.id] || []
c._guides = api.guides[c.id] || [] c._guides = api.guides[c.id] || []
c._country = api.countries[c.country] c._country = api.countries[c.country]
c._subdivision = api.subdivisions[c.subdivision] c._subdivision = api.subdivisions[c.subdivision]
c._languages = c.languages.map(code => api.languages[code]).filter(i => i) c._languages = c.languages.map(code => api.languages[code]).filter(i => i)
c._categories = c.categories.map(id => api.categories[id]).filter(i => i) c._categories = c.categories.map(id => api.categories[id]).filter(i => i)
c._broadcast_area = c.broadcast_area.map(value => { c._broadcast_area = c.broadcast_area.map(value => {
const [type, code] = value.split('/') const [type, code] = value.split('/')
switch (type) { switch (type) {
case 'c': case 'c':
return { type, ...api.countries[code] } return { type, ...api.countries[code] }
case 'r': case 'r':
return { type, ...api.regions[code] } return { type, ...api.regions[code] }
case 's': case 's':
return { type, ...api.subdivisions[code] } return { type, ...api.subdivisions[code] }
} }
}) })
c._searchable = generateSearchable(c) c._searchable = generateSearchable(c)
return c return c
}) })
channels.set(_channels) channels.set(_channels)
filteredChannels.set(_channels) filteredChannels.set(_channels)
} }
function generateSearchable(c) { function generateSearchable(c) {
const searchable = {} const searchable = {}
for (let key in c) { for (let key in c) {
if (key.startsWith('_')) continue if (key.startsWith('_')) continue
if (Array.isArray(c[key])) { if (Array.isArray(c[key])) {
searchable[key] = c[key].map(v => v.toString().toLowerCase()).join(',') searchable[key] = c[key].map(v => v.toString().toLowerCase()).join(',')
} else { } else {
searchable[key] = c[key] ? c[key].toString().toLowerCase() : '' searchable[key] =
} c[key] !== undefined && c[key] !== null ? c[key].toString().toLowerCase() : ''
} }
searchable.streams = c._streams.length }
searchable.guides = c._guides.length searchable.streams = c._streams.length
searchable.is = c.closed || c.replaced_by ? 'closed' : 'active' searchable.guides = c._guides.length
searchable._key = generateKey(c) searchable.is = c.closed || c.replaced_by ? 'closed' : 'active'
searchable._key = generateKey(c)
return searchable return searchable
} }
function generateKey(c) { function generateKey(c) {
const data = Object.values( const data = Object.values(
_.pick(c, [ _.pick(c, [
'id', 'id',
'name', 'name',
'alt_names', 'alt_names',
'network', 'network',
'country', 'country',
'subdivision', 'subdivision',
'city', 'city',
'broadcast_area', 'broadcast_area',
'languages', 'languages',
'categories', 'categories',
'launched', 'launched',
'closed', 'closed',
'replaced_by' 'replaced_by'
]) ])
) )
const translit = c.alt_names ? transliterate(c.alt_names) : null const translit = c.alt_names ? transliterate(c.alt_names) : null
return [...data, translit] return [...data, translit]
.map(v => v || '') .map(v => v || '')
.filter(v => v) .filter(v => v)
.join('|') .join('|')
.toLowerCase() .toLowerCase()
} }
function copy(value) { function copy(value) {
return JSON.parse(JSON.stringify(value)) return JSON.parse(JSON.stringify(value))
} }
export function setSearchParam(key, value) { export function setSearchParam(key, value) {
if (window.history.pushState) { if (window.history.pushState) {
let query = key && value ? `?${key}=${value}` : '' let query = key && value ? `?${key}=${value}` : ''
query = query.replace(/\+/g, '%2B') query = query.replace(/\+/g, '%2B')
const url = `${window.location.protocol}//${window.location.host}${window.location.pathname}${query}` const url = `${window.location.protocol}//${window.location.host}${window.location.pathname}${query}`
const state = {} const state = {}
state[key] = value state[key] = value
window.history.pushState(state, '', url) window.history.pushState(state, '', url)
setPageTitle(value) setPageTitle(value)
} }
} }
export function setPageTitle(value) { export function setPageTitle(value) {
const title = value ? `${value} · iptv-org` : 'iptv-org' const title = value ? `${value} · iptv-org` : 'iptv-org'
document.title = title document.title = title
} }
async function loadAPI() { async function loadAPI() {
const api = {} const api = {}
api.countries = await fetch('https://iptv-org.github.io/api/countries.json') api.countries = await fetch('https://iptv-org.github.io/api/countries.json')
.then(r => r.json()) .then(r => r.json())
.then(data => (data.length ? data : [])) .then(data => (data.length ? data : []))
.then(data => .then(data =>
data.map(i => { data.map(i => {
i.expanded = false i.expanded = false
return i return i
}) })
) )
.then(data => _.keyBy(data, 'code')) .then(data => _.keyBy(data, 'code'))
.catch(console.error) .catch(console.error)
api.regions = await fetch('https://iptv-org.github.io/api/regions.json') api.regions = await fetch('https://iptv-org.github.io/api/regions.json')
.then(r => r.json()) .then(r => r.json())
.then(data => (data.length ? data : [])) .then(data => (data.length ? data : []))
.then(data => _.keyBy(data, 'code')) .then(data => _.keyBy(data, 'code'))
.catch(console.error) .catch(console.error)
api.subdivisions = await fetch('https://iptv-org.github.io/api/subdivisions.json') api.subdivisions = await fetch('https://iptv-org.github.io/api/subdivisions.json')
.then(r => r.json()) .then(r => r.json())
.then(data => (data.length ? data : [])) .then(data => (data.length ? data : []))
.then(data => _.keyBy(data, 'code')) .then(data => _.keyBy(data, 'code'))
.catch(console.error) .catch(console.error)
api.languages = await fetch('https://iptv-org.github.io/api/languages.json') api.languages = await fetch('https://iptv-org.github.io/api/languages.json')
.then(r => r.json()) .then(r => r.json())
.then(data => (data.length ? data : [])) .then(data => (data.length ? data : []))
.then(data => _.keyBy(data, 'code')) .then(data => _.keyBy(data, 'code'))
.catch(console.error) .catch(console.error)
api.categories = await fetch('https://iptv-org.github.io/api/categories.json') api.categories = await fetch('https://iptv-org.github.io/api/categories.json')
.then(r => r.json()) .then(r => r.json())
.then(data => (data.length ? data : [])) .then(data => (data.length ? data : []))
.then(data => _.keyBy(data, 'id')) .then(data => _.keyBy(data, 'id'))
.catch(console.error) .catch(console.error)
api.streams = await fetch('https://iptv-org.github.io/api/streams.json') api.streams = await fetch('https://iptv-org.github.io/api/streams.json')
.then(r => r.json()) .then(r => r.json())
.then(data => (data.length ? data : [])) .then(data => (data.length ? data : []))
.then(data => _.groupBy(data, 'channel')) .then(data => _.groupBy(data, 'channel'))
.catch(console.error) .catch(console.error)
api.guides = await fetch('https://iptv-org.github.io/api/guides.json') api.guides = await fetch('https://iptv-org.github.io/api/guides.json')
.then(r => r.json()) .then(r => r.json())
.then(data => (data.length ? data : [])) .then(data => (data.length ? data : []))
.then(data => _.groupBy(data, 'channel')) .then(data => _.groupBy(data, 'channel'))
.catch(console.error) .catch(console.error)
api.channels = await fetch('https://iptv-org.github.io/api/channels.json') api.channels = await fetch('https://iptv-org.github.io/api/channels.json')
.then(r => r.json()) .then(r => r.json())
.catch(err => { .catch(err => {
console.error(err) console.error(err)
return [] return []
}) })
return api return api
} }