Ricardo Bassete

Ricardo Bassete

/*
# Open game page in nexusmods.com
Lets the user select and open the page of a game in [nexusmods.com](https://www.nexusmods.com/).
*/
// Name: Open game page in nexusmods.com
// Description: Lets the user select and open the page of a game in nexusmods.com.
// Author: Ricardo Gonçalves Bassete
import '@johnlindquist/kit'
interface Category {
category_id: number
name: string
parent_category: boolean | number
}
interface Game {
approved_date: number
authors: number
categories: Category[]
domain_name: string
downloads: number
file_count: number
file_endorsements: number
file_views: number
forum_url: string
genre: string
id: number
mods: number
name: string
nexusmods_url: string
}
const GAMES_API = 'https://api.nexusmods.com/v1/games.json'
const API_KEY = await env('NEXUSMODS_API_KEY', {
panel: md(`## Get a [Nexus Mods Personal API Key](https://next.nexusmods.com/settings/api-keys)`),
ignoreBlur: true,
secret: true,
})
const { data } = await get<Game[]>(GAMES_API, {
headers: {
accept: 'application/json',
apikey: API_KEY,
},
})
const target = await arg({
placeholder: 'Select Game',
choices: data.map(game => {
return {
name: game.name,
description: game.nexusmods_url,
value: game.nexusmods_url,
img: `https://staticdelivery.nexusmods.com/Images/games/4_3/tile_${game.id}.jpg`,
height: 250,
}
}),
})
open(target)
// Name: Download video with yt-dlp
// Description: Download video with yt-dlp
// Author: Ricardo Gonçalves Bassete
import "@johnlindquist/kit"
const outDir = home('Downloads', 'yt-dlp')
const flags = {
mp4: `-f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" -o "%(title)s.mp4"`,
mp3: `-o "%(title)s.mp3" -x --audio-format mp3 --audio-quality 0`,
}
const videoURl = await arg({
placeholder: 'Video URL',
alwaysOnTop: true
})
const format = await arg({
placeholder: 'Select format',
alwaysOnTop: true,
choices: Object.keys(flags),
strict: true
})
await hide()
await ensureDir(outDir)
cd(outDir)
await exec(`yt-dlp ${flags[format]} "${videoURl}"`)
notify({
title: 'Finished downloading video',
message: `Location: ${outDir}`
})
// Name: Trim video with ffmpeg
// Author: Ricardo Gonçalves Bassete
import "@johnlindquist/kit"
import { basename, dirname, extname } from "node:path"
const inputPath = await selectFile('Select your video file')
const start = await arg('Start (hh:mm:ss)')
const end = await arg('End (hh:mm:ss)')
const outputName = await arg('Output name')
const fileDir = dirname(inputPath)
const ext = extname(inputPath)
const flags = [
`-i "${inputPath}"`,
`-ss ${start}`,
`-to ${end}`,
`-c copy "${outputName}.${ext}"`
]
cd(fileDir)
await hide()
await exec(`ffmpeg ${flags.join(' ')}`)
notify({
title: "Trim video with ffmpeg",
message: `Finished trimming ${basename(inputPath)}`
})
// Name: Search Manga in Manganato
import "@johnlindquist/kit"
import { Choice } from "@johnlindquist/kit"
import cheerio from 'cheerio'
import axios from 'axios'
type Manga = {
title: string
url: string
imageUrl: string
}
type Chapter = {
title: string
url: string
}
const baseUrl = 'https://mangakakalot.com'
async function loadCheerio(url: string) {
const { data } = await axios.get(url)
const $ = cheerio.load(data)
return $
}
async function searchManga(searchTerm: string): Promise<Manga[]> {
const searchUrl = `${baseUrl}/search/story/${searchTerm.toLowerCase().replaceAll(' ', '_')}`
const $ = await loadCheerio(searchUrl)
const mangas: Manga[] = $('div.story_item').get().map(el => {
return {
title: $(el).find('h3.story_name').text().replaceAll('\n', ''),
imageUrl: $(el).find('img').attr('src'),
url: $(el).find('h3.story_name > a').attr('href')
}
})
return mangas
}
async function getChapterLinks(mangaUrl: string): Promise<Chapter[]> {
const $ = await loadCheerio(mangaUrl)
const chapterList: Chapter[] = $('ul.row-content-chapter > li > a').get().map(chapter => {
return {
title: $(chapter).text().replaceAll('\n', ''),
url: $(chapter).attr('href')
}
})
return chapterList
}
function buildMangaResult(manga: Manga): Choice {
return {
name: manga.title,
value: manga.url,
img: manga.imageUrl,
height: 250,
preview: buildPreview(manga)
}
}
function buildChapterResult(chapter: Chapter): Choice {
return {
name: chapter.title,
value: chapter.url,
description: chapter.url
}
}
function buildPreview(manga: Manga) {
return `
<div class="p-5 prose prose-sm">
<img class="rounded" src="${manga.imageUrl}"/>
</div>
`
}
const mangaURL = await arg('Manga name', async input => {
const mangas: Manga[] = await searchManga(input)
const results = mangas.map(manga => buildMangaResult(manga))
return results
})
const openChapterOrPage: 'Page' | 'Chapter' = await arg('Open manga page or chapter', ['Page', 'Chapter'])
if(openChapterOrPage == 'Page') {
open(mangaURL)
} else {
const chapters = await getChapterLinks(mangaURL)
const targetChapter = await arg('Select chapter', chapters.map(chapter => buildChapterResult(chapter)))
open(targetChapter)
}
// Name: Clear Windows Notifications
// Author: Ricardo Gonçalves Bassete
import "@johnlindquist/kit"
const command = `
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
# get the list of all registry keys
$notifications = Get-ChildItem HKCU:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Notifications\\Settings | Select-Object Name
# iterate through the keys, extract the name that will be used in the clear function, and clear the notifications
for ($index = 0; $index -lt $notifications.Count; $index++) {
$name = $notifications[$index]
$split = $name -split "\\\\"
$last = $split[$split.Count - 1]
$last = $last.Substring(0, $last.Length - 1)
([Windows.UI.Notifications.ToastNotificationManager]::History).clear($last)
}
`
exec(command, { shell: 'powershell.exe' })
// Name: Search Game in Steam Charts
// Description: Search Game in https://steamcharts.com/
// Author: Ricardo Gonçalves Bassete
import "@johnlindquist/kit"
import cheerio from 'cheerio'
import axios from 'axios'
import { Choice } from "@johnlindquist/kit"
interface Game {
name: string
link: string
img: string
currentPlayers: string
monthAvg: string
monthGain: string
monthGainPercent: string
}
async function searchGames(keyword: string) {
const baseURL = 'https://steamcharts.com'
const searchURL = `${baseURL}/search/?q=${keyword.toLowerCase().replaceAll(' ', '+')}`
const { data } = await axios.get(searchURL)
const $ = cheerio.load(data)
const result: Game[] = $('tr').get().map(el => {
const tr = $(el)
const imgEl = tr.find('td').get()[0]
const nameEl = tr.find('td').get()[1]
const currentPlayersEl = tr.find('td').get()[2]
const monthAvgEl = tr.find('td').get()[3]
const monthGainEl = tr.find('td').get()[4]
const monthGainPercentEl = tr.find('td').get()[5]
return {
img: `${baseURL}${$(imgEl).find('img').attr('src')}`,
name: $(nameEl).text().replaceAll('\t', '').replaceAll('\n', ''),
link: `${baseURL}${$(nameEl).find('a').attr('href')}`,
currentPlayers: $(currentPlayersEl).text(),
monthAvg: $(monthAvgEl).text(),
monthGain: $(monthGainEl).text(),
monthGainPercent: $(monthGainPercentEl).text()
}
})
const games = result.filter(game => game.name !== '')
return games
}
function buildPreview(game: Game) {
const getColor = (text: string) => {
if(text.startsWith('-')) {
return 'text-red-500'
} else if (text.startsWith('+')) {
return 'text-green-500'
} else {
return ''
}
}
return `
<div class="p-5 prose prose-sm">
<img class="w-full rounded" src="${game.img}"/>
<h2>${game.name}</h2>
<div class="w-full h-10 flex flex-row items-center font-bold justify-start uppercase">
Current Players: ${game.currentPlayers}
</div>
<div class="w-full h-10 flex flex-row items-center font-bold justify-start uppercase">
30-Day Avg.: ${game.monthAvg}
</div>
<div class="w-full h-10 flex flex-row items-center font-bold justify-start uppercase ${getColor(game.monthGain)}">
30-Day Gain: ${game.monthGain}
</div>
<div class="w-full h-10 flex flex-row items-center font-bold justify-start uppercase ${getColor(game.monthGainPercent)}">
30-Day % Gain: ${game.monthGainPercent}
</div>
</div>
`
}
function buildResult(game: Game): Choice {
return {
name: game.name,
value: game.link,
img: game.img,
preview: buildPreview(game)
}
}
const keyword = await arg('Keyword')
const games = await searchGames(keyword)
const game = await arg('Select game', games.map(game => buildResult(game)))
open(game)
// Name: Cron Builder
// Description: Prompts user for desired intervals, creates a cron schedule based on user input, and describes it
// Author: Ricardo Gonçalves Bassete
import "@johnlindquist/kit"
import cronstrue from 'cronstrue';
const commonValues = [
'------------------------------',
'* = any value',
', = value list separator',
'- = range of values',
'/ = step values',
]
const minuteValues = [
"Allowed Values = 0 - 59",
...commonValues,
]
const hourValues = [
"Allowed Values = 0 - 23",
...commonValues,
]
const dayMonthValues = [
"Allowed Values = 1 - 31",
...commonValues,
]
const monthValues = [
"Allowed Values = 1 - 12",
...commonValues,
]
const dayWeekValues = [
"Allowed Values = 0 - 6",
'------------------------------',
"0 = Sunday",
"1 = Monday",
"2 = Tuesday",
"3 = Wednesday",
"4 = Thursday",
"5 = Friday",
"6 = Saturday",
...commonValues
]
const minute = await arg({
placeholder: 'Minute interval, default is *',
alwaysOnTop: true,
hint: minuteValues.join('\n')
}).then(input => input === '' ? '*' : input)
const hour = await arg({
placeholder: 'Hour interval, default is *',
alwaysOnTop: true,
hint: hourValues.join('\n')
}).then(input => input === '' ? '*' : input)
const dayMonth = await arg({
placeholder: 'Day of the month interval, default is *',
alwaysOnTop: true,
hint: dayMonthValues.join('\n')
}).then(input => input === '' ? '*' : input)
const month = await arg({
placeholder: 'Month interval, default is *',
alwaysOnTop: true,
hint: monthValues.join('\n')
}).then(input => input === '' ? '*' : input)
const dayWeek = await arg({
placeholder: 'Day of the week interval, default is *',
alwaysOnTop: true,
hint: dayWeekValues.join('\n')
}).then(input => input === '' ? '*' : input)
const result = `${minute} ${hour} ${dayMonth} ${month} ${dayWeek}`
await div({
alwaysOnTop: true,
enter: 'Press Enter to paste result',
html: `
<div class="p-5 prose prose-sm">
<h1>${cronstrue.toString(result)}</h1>
<p>${result}</p>
</div>
`,
onSubmit: () => setSelectedText(result)
})

// Name: Chmod Calculator
// Description: Asks the user what permissions to grant to a file/folder and creates a chmod command with those permissions
// Author: Ricardo Gonçalves Bassete
import "@johnlindquist/kit"
const permissions = ['read', 'write', 'execute']
function getValue(permissions: string[]) {
const r = permissions.includes('read') ? 4 : 0
const w = permissions.includes('write') ? 2 : 0
const x = permissions.includes('execute') ? 1 : 0
return r+w+x
}
const ownerPermissions: string[] = await select({
placeholder: 'Owner permissions',
alwaysOnTop: true,
strict: true,
}, permissions)
const groupPermissions: string[] = await select({
placeholder: 'Group permissions',
alwaysOnTop: true,
strict: true,
}, permissions)
const publicPermissions: string[] = await select({
placeholder: 'Public permissions',
alwaysOnTop: true,
strict: true,
}, permissions)
const command = `chmod ${getValue(ownerPermissions)}${getValue(groupPermissions)}${getValue(publicPermissions)}`
setSelectedText(command)

// Name: Clear Downloads Folder
// Description: Lists files and folders within your downloads folder and asks which items you want to remove
// Author: Ricardo Gonçalves Bassete
import "@johnlindquist/kit"
const downloadsFolder = home('Downloads')
const items = await readdir(downloadsFolder)
const itemsToRemove: string[] = await select({
placeholder: 'Select the items you want to remove',
alwaysOnTop: true,
strict: true,
}, items)
const wishToRemove = await arg({
placeholder: 'This will remove all selected items, do you want to continue?',
choices: [
{ name: 'Yes', value: true },
{ name: 'No', value: false }
],
strict: true
})
if(wishToRemove) {
itemsToRemove.forEach(item => {
const itemPath = path.resolve(downloadsFolder, item)
remove(itemPath)
})
}