google-that
Advanced tools
Comparing version 0.0.1 to 0.0.2
@@ -7,5 +7,5 @@ #!/usr/bin/env node | ||
import enquirer from "enquirer"; | ||
import { ResultTypes } from "google-sr"; | ||
import { ResultTypes as ResultTypes2 } from "google-sr"; | ||
import prettyMilliseconds from "pretty-ms"; | ||
import boxen from "boxen"; | ||
import boxen2 from "boxen"; | ||
import fsPromises from "fs/promises"; | ||
@@ -15,4 +15,7 @@ import path from "path"; | ||
import slugify from "slugify"; | ||
import { stripIndents } from "common-tags"; | ||
import { stripIndents as stripIndents2 } from "common-tags"; | ||
// src/constants.ts | ||
var estimateOffset = 1e3; | ||
// src/query.ts | ||
@@ -24,6 +27,26 @@ import cliProgress from "cli-progress"; | ||
var log = { | ||
info: (...args) => console.log(`${c.blue.bold("[INFO]")} @ ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} ${c.yellow(">")}`, ...args.map((s) => c.blueBright(s))), | ||
success: (...args) => console.log(`${c.green.bold("[SUCCESS]")} @ ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} ${c.yellow(">")}`, ...args.map((s) => c.greenBright(s))), | ||
warn: (...args) => console.log(`${c.yellowBright.bold("[WARN]")} @ ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} ${c.yellow(">")}`, ...args.map((s) => c.yellowBright(s))), | ||
error: (...args) => console.log(`${c.red.bold("[ERROR]")} @ ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} ${c.yellow(">")}`, ...args.map((s) => c.redBright(s))) | ||
info: (...args) => console.log( | ||
`${c.blue.bold("[INFO]")} @ ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} ${c.yellow( | ||
">" | ||
)}`, | ||
...args.map((s) => c.blueBright(s)) | ||
), | ||
success: (...args) => console.log( | ||
`${c.green.bold( | ||
"[SUCCESS]" | ||
)} @ ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} ${c.yellow(">")}`, | ||
...args.map((s) => c.greenBright(s)) | ||
), | ||
warn: (...args) => console.log( | ||
`${c.yellowBright.bold( | ||
"[WARN]" | ||
)} @ ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} ${c.yellow(">")}`, | ||
...args.map((s) => c.yellowBright(s)) | ||
), | ||
error: (...args) => console.log( | ||
`${c.red.bold("[ERROR]")} @ ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} ${c.yellow( | ||
">" | ||
)}`, | ||
...args.map((s) => c.redBright(s)) | ||
) | ||
}; | ||
@@ -67,8 +90,271 @@ var getTimePerEachPage = /* @__PURE__ */ __name((noOfPages) => noOfPages > 10 ? 5e3 : 2e3, "getTimePerEachPage"); | ||
doSearch(page) { | ||
return search({ query: this.query, page: pageToGoogleQueryPage(page) }); | ||
return search({ query: this.query, page: pageToGoogleQueryPage(page), filterResults: this.inputOptions.searchType }); | ||
} | ||
}; | ||
// src/formatters.ts | ||
import boxen from "boxen"; | ||
import { html, stripIndents, stripIndent } from "common-tags"; | ||
import { ResultTypes } from "google-sr"; | ||
function getJSONFormat(results) { | ||
return JSON.stringify(results, null, 4); | ||
} | ||
__name(getJSONFormat, "getJSONFormat"); | ||
function getTXTFormat(results) { | ||
let startTxt = stripIndents(html)` | ||
${results.map( | ||
(page, i) => html` | ||
==============${i + 1}/${results.length}================== | ||
${page.map((data) => { | ||
switch (data.type) { | ||
case ResultTypes.SearchResult: | ||
return boxen( | ||
stripIndents` | ||
๐ ${data.title} | ||
๐ ${data.link} | ||
๐ ${data.description} | ||
`, | ||
{ padding: 1 } | ||
); | ||
case ResultTypes.TranslateResult: | ||
return boxen( | ||
stripIndents` | ||
๐ ${data.source.language} => ๐ ${data.translation.language} | ||
๐ ${data.source.text} => โจ ${data.translation.text} ${data.translation.pronunciation ? `(\u{1F50A} ${data.translation.pronunciation})` : ""} | ||
`, | ||
{ padding: 1 } | ||
); | ||
case ResultTypes.DictionaryResult: | ||
return boxen( | ||
stripIndents(html)` | ||
๐ ${data.word} | ||
๐ ${data.phonetic} | ||
${data.audio ? `\u{1F50A} ${data.audio}` : ""} | ||
${data.definitions.map( | ||
(definition) => stripIndent` | ||
๐ ${definition[0]} | ||
โณ ${definition[1]} | ||
` | ||
)} | ||
`, | ||
{ padding: 1 } | ||
); | ||
case ResultTypes.TimeResult: | ||
return boxen( | ||
stripIndents(html)` | ||
๐ ${data.location} | ||
โฐ ${data.time} | ||
๐ฃ๏ธ ${data.timeInWords} | ||
`, | ||
{ padding: 1 } | ||
); | ||
case ResultTypes.CurrencyResult: | ||
return boxen( | ||
stripIndents(html)` | ||
๐ฐ ${data.from} => ๐ธ ${data.to} | ||
`, | ||
{ padding: 1 } | ||
); | ||
default: | ||
return `Unsupported`; | ||
} | ||
})} | ||
` | ||
)} | ||
`; | ||
return startTxt; | ||
} | ||
__name(getTXTFormat, "getTXTFormat"); | ||
function getHTMLFormat(results, query, total) { | ||
const pages = new Array(results.length).fill(null).map((_m, i) => i + 1); | ||
return html` | ||
<html> | ||
<head> | ||
<!-- Autogenerated by google-that (npm) on ${(/* @__PURE__ */ new Date()).toDateString()} --> | ||
<title>Autogenerated query | ${query}</title> | ||
<style> | ||
body { | ||
height: 100vh; | ||
margin: 3; | ||
background-color: #f0f0f0; | ||
font-family: Arial, sans-serif; | ||
} | ||
input { | ||
width: 100%; | ||
padding: 10px; | ||
border: 1px solid #ccc; | ||
border-radius: 5px; | ||
font-size: 16px; | ||
margin-bottom: 20px; | ||
box-sizing: border-box; | ||
} | ||
li a { | ||
text-decoration: none; | ||
color: #333; | ||
} | ||
.searchResult { | ||
border: 1px solid #ccc; | ||
padding: 10px; | ||
margin: 10px 0; | ||
border-radius: 10px; | ||
background-color: rgb(216, 245, 245); | ||
display: flex; | ||
flex-direction: column; | ||
gap: 2px; | ||
} | ||
.translateResult { | ||
align-items: center; | ||
background-color: rgb(243, 255, 174); | ||
} | ||
.dictionaryResult { | ||
background-color: rgb(189, 174, 255); | ||
} | ||
.currencyResult { | ||
background-color: rgb(241, 174, 255); | ||
} | ||
.timeResult { | ||
background-color: rgb(186, 202, 255); | ||
} | ||
.ulReset { | ||
list-style: none; | ||
padding: 0; | ||
margin: 0; | ||
} | ||
.hero { | ||
display: flex; | ||
gap: 3px; | ||
align-items: center; | ||
justify-content: center; | ||
flex-direction: column; | ||
} | ||
.pagination { | ||
display: flex; | ||
gap: 3px; | ||
align-items: center; | ||
justify-content: center; | ||
font-size: large; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div class="hero"> | ||
<input value="${query}" name="query" readonly /> | ||
<h5>Generated on ${(/* @__PURE__ */ new Date()).toDateString()}</h5> | ||
<h4>${total} results across ${results.length} pages</h4> | ||
<div class="pagination"> | ||
<span><</span> | ||
${pages.map((pageNo) => `<a href="#page${pageNo}">${pageNo}</a>`)} | ||
<span>></span> | ||
</div> | ||
</div> | ||
<hr /> | ||
${results.map( | ||
(page, i) => html(stripIndents)` | ||
<ul id="page-${i + 1}" class="ulReset"> | ||
<h3 id="page${i + 1}">Page ${i + 1} ${results.length > 1 ? `of ${results.length} pages` : ""} | ${page.length} entries for this page</h3> | ||
${page.map((result) => { | ||
switch (result.type) { | ||
case ResultTypes.SearchResult: | ||
return html` | ||
<li class="searchResult"> | ||
<h1>${result.title}</h1> | ||
<a href="${result.link}">${result.link}</a> | ||
<p>${result.description}</p> | ||
</li> | ||
`; | ||
case ResultTypes.TranslateResult: | ||
return html` | ||
<li class="searchResult translateResult"> | ||
<h3> | ||
${result.source.text} | ||
</h3> | ||
โฌ๏ธ | ||
<div> | ||
<h3> | ||
${result.translation.text} | ||
</h3> | ||
${result.translation.pronunciation ? `<h5>\u{1F4E2} ${result.translation.pronunciation}</h5>` : ""} | ||
</div> | ||
</li> | ||
`; | ||
case ResultTypes.DictionaryResult: | ||
return html` | ||
<li class="searchResult dictionaryResult"> | ||
<h1>${result.word}</h1> | ||
<p>${result.phonetic}</p> | ||
<audio controls> | ||
<source src="${result.audio}" type="audio/mp3"> | ||
</audio> | ||
<ul> | ||
${result.definitions.map((definition) => ` | ||
<li> | ||
<h5>${definition[0]}</h5> | ||
<p>${definition[1]}</p> | ||
</li> | ||
`)} | ||
</ul> | ||
</li> | ||
`; | ||
case ResultTypes.CurrencyResult: | ||
return html` | ||
<li class="searchResult currencyResult"> | ||
<h3>${result.formula}</h3> | ||
</li> | ||
`; | ||
case ResultTypes.TimeResult: | ||
return html` | ||
<li class="searchResult timeResult"> | ||
<h3>${result.location}</h3> | ||
<p>${result.time}</p> | ||
<p>${result.timeInWords}</p> | ||
</li> | ||
`; | ||
default: | ||
return "Unsupported"; | ||
} | ||
})} | ||
</ul> | ||
` | ||
)} | ||
<hr /> | ||
<div class="pagination"> | ||
<span><</span> | ||
${pages.map((pageNo) => `<a href="#page${pageNo}">${pageNo}</a>`)} | ||
<span>></span> | ||
</div> | ||
</body> | ||
</html> | ||
`; | ||
} | ||
__name(getHTMLFormat, "getHTMLFormat"); | ||
// src/index.ts | ||
async function main() { | ||
console.clear(); | ||
console.log( | ||
boxen2( | ||
c2.yellow(stripIndents2` | ||
๐จ This CLI tool may sprinkle emojis for a touch of flair. | ||
If your terminal doesn't support emojis, they might appear as question marks. | ||
No worries though! The functionality of the CLI tool remains intact. | ||
If you spot this rocket emoji, you're all set for takeoff! ๐ | ||
`), | ||
{ padding: 1 } | ||
) | ||
); | ||
const queryInput = await enquirer.prompt([ | ||
@@ -99,9 +385,9 @@ { | ||
message: "Organic search", | ||
name: ResultTypes.SearchResult, | ||
name: ResultTypes2.SearchResult, | ||
enabled: true | ||
}, | ||
{ message: "Translate Result", name: ResultTypes.TranslateResult }, | ||
{ message: "Dictionary Result", name: ResultTypes.DictionaryResult }, | ||
{ message: "Current time search", name: ResultTypes.TimeResult }, | ||
{ message: "Currency conversions", name: ResultTypes.CurrencyResult } | ||
{ message: "Translate Result", name: ResultTypes2.TranslateResult }, | ||
{ message: "Dictionary Result", name: ResultTypes2.DictionaryResult }, | ||
{ message: "Current time search", name: ResultTypes2.TimeResult }, | ||
{ message: "Currency conversions", name: ResultTypes2.CurrencyResult } | ||
], | ||
@@ -136,20 +422,30 @@ required: true, | ||
if (!queries.length) | ||
return log.error(`Query/Queries option is required`); | ||
return log.error(`Query option is required`); | ||
if (pages <= 0) | ||
return log.error(`Pages must be greater than 0`); | ||
return log.error(`Amount of pages must be greater than 0`); | ||
if (/[\\/:*?"<>|]/.test(savePath) || savePath.includes(" ")) | ||
return log.error( | ||
`Invalid file name. File names cannot contain spaces or the following characters: \\ / : * ? " < > |` | ||
); | ||
if (pages > 10) | ||
log.warn( | ||
`Fetching more than 10 pages per query, will fetch in delayed chunks to prevent rate limit` | ||
`Fetching more than 10 pages per query. To prevent rate limits, the fetching will be done in delayed chunks.` | ||
); | ||
const perPage = getTimePerEachPage(pages); | ||
const totalTime = perPage * pages * queries.length; | ||
log.info( | ||
`It will take ${prettyMilliseconds(totalTime)} with ${prettyMilliseconds( | ||
perPage | ||
)} for ${pages} pages with ${queries.length} queries / query` | ||
const perQuery = perPage * pages; | ||
const estimatedTime = perQuery * queries.length + estimateOffset; | ||
console.log( | ||
boxen2( | ||
stripIndents2` | ||
โฐ ETA: ${c2.green(prettyMilliseconds(estimatedTime))} | ||
๐ Per page: ${c2.green(prettyMilliseconds(perPage))} | ||
๐ Pages: ${pages} pages | ||
โ ${c2.yellow(String(queries.length))} ${queries.length > 2 ? "queries" : "query"} | ||
๐ญ ${c2.italic.yellowBright(queries.join(","))} | ||
`, | ||
{ padding: 2, margin: 1 } | ||
) | ||
); | ||
log.info( | ||
`Searching for ${queries.length > 1 ? `multiple queries (${queries.length}) [${queries}]` : `query on "${queries[0]}"`}` | ||
); | ||
const downloads = []; | ||
const start = Date.now(); | ||
for (const query of queries) { | ||
@@ -160,31 +456,94 @@ log.info( | ||
const searchQuery = new SearchQuery(query, queryInput, perPage); | ||
const searchStart = Date.now(); | ||
try { | ||
const results = await searchQuery.search(); | ||
log.success(`Retrieved ${results.length} result(s)`); | ||
const saveAt = savePath.replace("%query%", slugify(query, { lower: false })).replace("%format%", resultType.toLowerCase()); | ||
const pathName = path.join(process.cwd(), saveAt); | ||
log.info(`Saving results for query "${query}" to ${pathName}`); | ||
if (!results.length) { | ||
log.warn(`Query "${query}" did not return any results (likely error logs are above), skipping`); | ||
continue; | ||
} | ||
let saveData; | ||
const totalResults = results.reduce((a, b) => a.concat(b)).length; | ||
switch (resultType) { | ||
case "JSON": | ||
await fsPromises.writeFile(pathName, JSON.stringify(results, null, 4)); | ||
saveData = getJSONFormat(results); | ||
break; | ||
case "TXT": | ||
saveData = getTXTFormat(results); | ||
break; | ||
case "HTML": | ||
saveData = getHTMLFormat(results, query, totalResults); | ||
break; | ||
default: | ||
saveData = "Unsupported TYPE"; | ||
} | ||
const totalResults = results.reduce((a, b) => a.concat(b)).length; | ||
await fsPromises.writeFile(pathName, saveData); | ||
const searchEnd = Date.now() - searchStart; | ||
log.info( | ||
`Saved results for query "${query}" to ${pathName} took ${prettyMilliseconds(searchEnd)}` | ||
); | ||
downloads.push({ query, pathName, total: totalResults }); | ||
} catch { | ||
log.error(`Failed to search query`); | ||
log.error(`Failed to search query "${query}"`); | ||
} | ||
} | ||
await delay(2e3); | ||
const end = Date.now() - start; | ||
console.clear(); | ||
console.log(boxen(stripIndents` | ||
โ google-that download finished. | ||
โญ Star us here: ${c2.blue("https://github.com/typicalninja/google-sr")} | ||
๐ฆ Github here: ${c2.blue("https://github.com/typicalninja/google-sr/tree/master/packages/cli")} | ||
${c2.bgCyanBright.underline("Downloads")} | ||
โงโงโงโง | ||
${downloads.map((download) => `\u2192 ${c2.bold.magenta(path.basename(download.pathName))} ("${c2.italic.yellow(download.query)}" [${download.total} results])`).join("\n")} | ||
`)); | ||
if (!downloads.length) { | ||
return console.log( | ||
boxen2( | ||
stripIndents2` | ||
โ ${c2.red("google-that process finished. [FAILED]")} | ||
๐ฐ๏ธ Finished in ${c2.blue( | ||
prettyMilliseconds(end) | ||
)} with a deviation of ${c2.yellow( | ||
prettyMilliseconds(end - estimatedTime) | ||
)} from estimated time (${prettyMilliseconds(estimatedTime)}) | ||
โญ Star us here: ${c2.blue("https://github.com/typicalninja/google-sr")} | ||
๐ฆ Github here: ${c2.blue( | ||
"https://github.com/typicalninja/google-sr/tree/master/packages/cli" | ||
)} | ||
๐ Documentation: ${c2.blue("https://typicalninja.github.io/google-sr/")} | ||
${c2.cyanBright.underline("Downloads")} | ||
โงโงโงโง | ||
${c2.red("Failed")} | ||
`, | ||
{ padding: 1, margin: 1 } | ||
) | ||
); | ||
} else { | ||
console.log( | ||
boxen2( | ||
stripIndents2` | ||
โ ${c2.green("google-that process finished. [SUCCESS]")} | ||
๐ฐ๏ธ Finished in ${c2.blue( | ||
prettyMilliseconds(end) | ||
)} with a deviation of ${c2.yellow( | ||
prettyMilliseconds(end - estimatedTime) | ||
)} from estimated time (${prettyMilliseconds(estimatedTime)}) | ||
โญ Star us here: ${c2.blue("https://github.com/typicalninja/google-sr")} | ||
๐ฆ Github here: ${c2.blue( | ||
"https://github.com/typicalninja/google-sr/tree/master/packages/cli" | ||
)} | ||
๐ Documentation: ${c2.blue("https://typicalninja.github.io/google-sr/")} | ||
${c2.cyanBright.underline("Downloads")} | ||
โงโงโงโง | ||
${downloads.map( | ||
(download) => `\u2192 ${c2.bold.grey( | ||
path.basename(download.pathName) | ||
)} ("${c2.italic.yellow(download.query)}" [${c2.green( | ||
String(download.total) | ||
)} results across ${pages} page${pages > 1 ? "s" : ""}])` | ||
).join("\n")} | ||
`, | ||
{ padding: 1, margin: 1 } | ||
) | ||
); | ||
} | ||
} | ||
@@ -191,0 +550,0 @@ __name(main, "main"); |
{ | ||
"name": "google-that", | ||
"version": "0.0.1", | ||
"description": "CLI tool to scrape google search results without a api key [HOLDING]", | ||
"version": "0.0.2", | ||
"description": "CLI tool to scrape google search results without a api key", | ||
"repository": "typicalninja/google-sr", | ||
"homepage": "https://typicalninja.github.io/google-sr/", | ||
"exports": "./dist/index.js", | ||
@@ -6,0 +8,0 @@ "bin": "./dist/index.js", |
# google-that | ||
CLI tool to scrape google search results without a api key ๐. | ||
CLI tool to scrape google search results without an api key ๐. | ||
# Holding package | ||
## Install ๐ฆ | ||
Until the api is finalized this published package for npm is a name holding package | ||
To get started, you can install **google-that** using your preferred package manager: | ||
> We suggest you install the package as a global module | ||
```bash | ||
# npm | ||
npm install -g google-sr | ||
# pnpm | ||
pnpm add -g google-sr | ||
# yarn | ||
yarn add -g google-sr | ||
``` | ||
# Usage | ||
If installation succeeded you can proceed to this step, run the following command in a **NEW** terminal window without any arguments | ||
```bash | ||
google-that | ||
``` | ||
this should come up with bunch of question answer these to use the tool. | ||
# Related projects | ||
* [google-sr](https://github.com/typicalninja/google-sr) - **google-that** project is a wrapper around google-sr | ||
* [google-sr](https://github.com/typicalninja/google-sr) - This project is a wrapper around google-sr | ||
@@ -14,0 +44,0 @@ # Disclaimer |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
31353
521
1
56
1