/*# Open game page in nexusmods.comLets 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 Basseteimport '@johnlindquist/kit'interface Category {category_id: numbername: stringparent_category: boolean | number}interface Game {approved_date: numberauthors: numbercategories: Category[]domain_name: stringdownloads: numberfile_count: numberfile_endorsements: numberfile_views: numberforum_url: stringgenre: stringid: numbermods: numbername: stringnexusmods_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 Basseteimport "@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 Basseteimport "@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 Manganatoimport "@johnlindquist/kit"import { Choice } from "@johnlindquist/kit"import cheerio from 'cheerio'import axios from 'axios'type Manga = {title: stringurl: stringimageUrl: string}type Chapter = {title: stringurl: 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 Basseteimport "@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 notificationsfor ($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 on Youtube// Author: Ricardo Gonçalves Basseteimport "@johnlindquist/kit"const keyword = await arg('Search Youtube...')const searchURL = `https://www.youtube.com/results?search_query=${keyword.toLowerCase().trim().replaceAll(' ', '+')}`open(searchURL)
// Name: Search Game in Steam Charts// Description: Search Game in https://steamcharts.com/// Author: Ricardo Gonçalves Basseteimport "@johnlindquist/kit"import cheerio from 'cheerio'import axios from 'axios'import { Choice } from "@johnlindquist/kit"interface Game {name: stringlink: stringimg: stringcurrentPlayers: stringmonthAvg: stringmonthGain: stringmonthGainPercent: 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: Empty Trash// Author: Ricardo Gonçalves Basseteimport "@johnlindquist/kit"import emptyTrash from 'empty-trash'await emptyTrash()
// Name: Cron Builder// Description: Prompts user for desired intervals, creates a cron schedule based on user input, and describes it// Author: Ricardo Gonçalves Basseteimport "@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: Clear Powershell History// Description: Clear powershell history file on windows// Author: Ricardo Gonçalves Basseteimport "@johnlindquist/kit"const filePath = home('AppData', 'Roaming', 'Microsoft', 'Windows', 'PowerShell', 'PSReadline', 'ConsoleHost_history.txt')writeFile(filePath, '')
// 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 Basseteimport "@johnlindquist/kit"const permissions = ['read', 'write', 'execute']function getValue(permissions: string[]) {const r = permissions.includes('read') ? 4 : 0const w = permissions.includes('write') ? 2 : 0const x = permissions.includes('execute') ? 1 : 0return 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 Basseteimport "@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)})}