Skip to content

Commit

Permalink
feat: image tab added
Browse files Browse the repository at this point in the history
  • Loading branch information
Hunam6 committed Apr 13, 2021
1 parent cf98f98 commit 0f14cb5
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 142 deletions.
64 changes: 48 additions & 16 deletions app.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {Application, Router, helpers, send} from 'https://deno.land/x/oak/mod.ts'
import {DOMParser} from 'https://deno.land/x/deno_dom/deno-dom-wasm.ts'
import {existsSync} from 'https://deno.land/std/fs/mod.ts'
import {search} from './src/all.ts'
import {DOMParser} from 'https://deno.land/x/deno_dom/deno-dom-wasm.ts'
import {all} from './src/all.ts'
import {images} from './src/images.ts'

//TODO: maybe switch to .env config
//Default config
let config = {
secure: {
Expand All @@ -13,12 +15,55 @@ let config = {
}
if (existsSync('./goodgle.config.ts')) config = await import('./goodgle.config.ts').then(res => res.config) //TODO: handle just some configs changed, like only the cert

const search = async (params: Record<string, string>) => {
//TODO: handle lang switch (from config or url)
let url = 'https://google.com/search?q=' + params.q
if (params.page != undefined) url += '&start=' + (parseInt(params.page) - 1) + '0' //Handle page

const getDoc = async (url: string) => {
return new DOMParser().parseFromString(
await fetch(url, {
headers: {
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41',
'accept-language': 'en-GB,en;q=0.9'
}
}).then(res => res.text()),
'text/html'
)!
}

//Handle tabs
switch (params.tab) {
case 'images':
url += '&tbm=isch'
return images(await getDoc(url))
case 'videos':
url += '&tbm=vid'
//TODO: videos
break
case 'news':
url += '&tbm=nws'
//TODO: news
break
case 'shopping':
url += '&tbm=shop'
//TODO: shopping
break
case 'books':
url += '&tbm=bks'
//TODO: books
break
default:
return all(await getDoc(url))
}
}

const app = new Application()
const router = new Router()
app.addEventListener('listen', () => console.log('Server started'))
router
.get('/', ctx => {
ctx.response.redirect('/search')
ctx.response.redirect('/search') //TODO: make a home page, probably need a logo for this, a placeholder for now
})
.get('/search', async ctx => {
ctx.response.body = await search(helpers.getQuery(ctx))
Expand All @@ -28,19 +73,6 @@ router
root: './assets'
})
})
.get('/test', async ctx => {
const doc = new DOMParser().parseFromString(
await fetch('https://google.com/search?q=' + helpers.getQuery(ctx).q, {
headers: {
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41',
'accept-language': 'en-GB,en;q=0.9'
}
}).then(res => res.text()),
'text/html'
)!
ctx.response.body = doc.querySelector('html')!.outerHTML
})

app.use(router.routes())
app.use(router.allowedMethods())

Expand Down
35 changes: 11 additions & 24 deletions src/all.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,22 @@
import {DOMParser} from 'https://deno.land/x/deno_dom/deno-dom-wasm.ts'
import {Document} from 'https://deno.land/x/deno_dom/deno-dom-wasm.ts'
import {renderFile} from 'https://deno.land/x/mustache_ts/mustache.ts'

export const search = async (params: Record<string, string>) => {
//TODO: change results per page (& handle for start param)
const doc = new DOMParser().parseFromString(
await fetch('https://google.com/search?q=' + params.q + (params.page != undefined ? '&start='+ (parseInt(params.page)-1) + '0' : ''), {
headers: {
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41',
'accept-language': 'en-GB,en;q=0.9'
}
}).then(res => res.text()),
'text/html'
)!

interface KnwlPanel {
title: string
subtitle: string
desc: string
infos: Record<string, string>[]
}

export const all = async (doc: Document) => {
let data: {
query: string
firstResult: Record<string, string>
firstResults: Record<string, string>[]
results: Record<string, string>[]
hasKnwlPanel: boolean
knwlPanel: KnwlPanel
knwlPanel: {
title: string
subtitle: string
desc: string
infos: Record<string, string>[]
}
relatedSearchs: string[]
} = {
query: params.q,
query: doc.querySelector('title')!.textContent.split(' - ')[0],
firstResult: {},
firstResults: [],
results: [
Expand Down Expand Up @@ -69,5 +56,5 @@ export const search = async (params: Record<string, string>) => {
//TODO: remove unwanted elements from knowledge panel infos (eg: q=toyota)
} else data.hasKnwlPanel = false

return await renderFile('./views/index.hbs', data)
}
return await renderFile('./views/all.hbs', data)
}
124 changes: 22 additions & 102 deletions src/images.ts
Original file line number Diff line number Diff line change
@@ -1,113 +1,33 @@
import {DOMParser} from 'https://deno.land/x/deno_dom/deno-dom-wasm.ts'
import {Document} from 'https://deno.land/x/deno_dom/deno-dom-wasm.ts'
import {renderFile} from 'https://deno.land/x/mustache_ts/mustache.ts'

export const images = async (params: Record<string, string>) => {
//TODO: change results per page (& handle for start param)
const doc = new DOMParser().parseFromString(
await fetch('https://google.com/search?q=' + params.q + (params.page != undefined ? '&start='+ (parseInt(params.page)-1) + '0' : ''), {
headers: {
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41',
'accept-language': 'en-GB,en;q=0.9'
}
}).then(res => res.text()),
'text/html'
)!

interface KnwlPanel {
title: string
subtitle: string
desc: string
infos: Record<string, string>[]
}

let data: {
query: string
firstResult: Record<string, string>
firstResults: Record<string, string>[]
results: Record<string, string>[]
hasKnwlPanel: boolean
knwlPanel: KnwlPanel
relatedSearchs: string[]
} = {
query: params.q,
firstResult: {},
firstResults: [],
results: [
{
title: 'No results',
desc: 'Try searching for something else...'
}
],
hasKnwlPanel: true,
knwlPanel: {
title: '',
subtitle: '',
desc: '',
infos: []
},
relatedSearchs: []
}

doc.querySelectorAll('.LC20lb.DKV0Md').forEach((el, i) => (data.results[i] = {title: el.textContent})) //results title
doc.querySelectorAll('.aCOpRe').forEach((el, i) => (data.results[i].desc = el.textContent)) //results description
let shownLink: string[] = [] //results shown link
doc.querySelectorAll('.iUh30.Zu0yb').forEach(el => shownLink.push(el.textContent))
shownLink = [...new Set(shownLink)]
shownLink.forEach((el, i) => (data.results[i].shownLink = el))
doc.querySelectorAll('.yuRUbf').forEach((el, i) => (data.results[i].link = el.children[0].getAttribute('href')!)) //results link
data.firstResult = data.results.shift()! //first result
doc.querySelectorAll('.l').forEach((el, i) => (data.firstResults[i] = {title: el.textContent})) //first results title
doc.querySelectorAll('.st').forEach((el, i) => (data.firstResults[i].desc = el.textContent)) //first results description
doc.querySelectorAll('.l').forEach((el, i) => (data.firstResults[i].link = el.parentElement!.children[0].getAttribute('href')!)) //first results link
data.firstResults = data.firstResults.slice(0, 4) //Better visibility
if (doc.querySelector('.qrShPb') !== null) {
data.knwlPanel.title = doc.querySelector('.qrShPb')!.textContent //knowledge panel title
data.knwlPanel.subtitle = doc.querySelector('.wwUB2c')!.textContent //knowledge panel subtitle
if (doc.querySelector('.kno-rdesc')! !== null) data.knwlPanel.desc = doc.querySelector('.kno-rdesc')!.children[1].textContent //knowledge panel description
doc.querySelectorAll('.w8qArf').forEach((el, i) => (data.knwlPanel.infos[i] = {title: el.children[0].textContent + ': '})) //knowledge panel infos title
doc.querySelectorAll('.kno-fv').forEach((el, i) => (data.knwlPanel.infos[i].content = el.textContent.replace(' - Disclaimer', '').replace(', MORE', '').replace('%)', '%)\n'))) //knowledge panel infos content
//TODO: remove unwanted elements from knowledge panel infos (eg: q=toyota)
} else data.hasKnwlPanel = false

return await renderFile('./views/index.hbs', data)
}


async function GIS(query: string) {
function fileExt(s: string) {
return ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg'].some(imgExt)
function imgExt(ext: string) {
return s.toLowerCase().includes(ext)
}
}
export const images = async (doc: Document) => {
function imgRefs(content: string) {
const refs = []
const re = /\["(http.+?)",(\d+),(\d+)\]/g
let result
while ((result = re.exec(content)) !== null) {
if (result.length > 3 && !result[1].includes('gstatic.com')) {
refs.push({
url: result[1],
width: +result[3],
height: +result[2]
})
}
}
while ((result = re.exec(content)) !== null) if (result.length > 3 && !/gstatic.com|abc.com/.test(result[1])) refs.push({url: result[1]})
return refs
}
const scriptContents: string[] = []
doc.querySelectorAll('script').forEach(el => (['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg'].some(ext => el.textContent.toLowerCase().includes(ext)) ? scriptContents.push(el.textContent) : null))

let data: {
query: string
imgs: Record<string, string>[]
} = {
query: doc.querySelector('title')!.textContent.split(' - ')[0],
imgs: []
}

const doc = new DOMParser().parseFromString(
await fetch('http://google.com/search?tbm=isch&q=' + query.replace(' ', '+'), {
headers: {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
}
}).then(res => res.text()),
'text/html'
)!
scriptContents.map(imgRefs)[0].forEach((el, i) => (data.imgs[i] = {url: el.url})) //Images url
doc.querySelectorAll('.WGvvNb')!.forEach((el, i) => (data.imgs[i].title = el.textContent.slice(0, -el.children[0].textContent.length))) //Images title
doc.querySelectorAll('.fxgdke')!.forEach((el, i) => (data.imgs[i].subtitle = el.textContent)) //Images subtitle

const scripts = doc.querySelectorAll('script')
const scriptContents: string[] = []
for (let i = 0; i < scripts.length; ++i) if (fileExt(scripts[i].textContent)) scriptContents.push(scripts[i].textContent)
//Fix images link
data.imgs.forEach(el => (el.url.includes('cdn.vox-cdn.com') ? (el.url = 'https://cdn.vox-cdn.com' + el.url.split('cdn.vox-cdn.com')[2]) : null))
data.imgs.forEach(el => (el.url.includes('play-lh.googleusercontent.com') ? (el.url = el.url.split('\\')[0]) : null))
data.imgs.forEach(el => (el.url.includes('\u003d') ? (el.url = el.url.replace('\u003d', '=')) : null)) //TODO: Find why it's not working

return scriptContents.map(imgRefs)
}
return await renderFile('./views/images.hbs', data)
}
1 change: 1 addition & 0 deletions views/index.hbs → views/all.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
content="Goodgle search page." />
<link rel="preconnect"
href="https://fonts.gstatic.com" />
{{!-- TODO: mobile support --}}
<style type="text/css">
* {
outline: 0;
Expand Down
Loading

0 comments on commit 0f14cb5

Please sign in to comment.