Skip to content

Instantly share code, notes, and snippets.

@ZicklePop
Last active February 21, 2024 03:23
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save ZicklePop/1662a0771229a5b03571141a9f166152 to your computer and use it in GitHub Desktop.
not updated for the current eshop changes :( -- the fastest way to browse the nintendo switch eshop using scriptable.app
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: red; icon-glyph: gamepad;
const unpkg = (package, file, version) => {
return new Promise((callback) => {
const jsFile = file || package
const pkgVersion = version ? `@${version}` : ''
const fm = FileManager.iCloud()
const modulesPath = fm.joinPath(fm.documentsDirectory(), 'modules/')
const modulePath = fm.joinPath(modulesPath, `${package}${pkgVersion}/`)
const filePath = fm.joinPath(modulePath, `${jsFile.split('/')[jsFile.split('/').length-1]}.js`)
if (!fm.fileExists(modulePath)) {
fm.createDirectory(modulePath, true)
}
if (!fm.fileExists(filePath) ) {
const req = new Request(`https://unpkg.com/${package}${pkgVersion}/${jsFile}.js`)
req.loadString().then(res => {
fm.writeString(filePath, `${res}`).then(() => {
callback(importModule(filePath))
})
})
} else {
fm.downloadFileFromiCloud(filePath).then(() => {
callback(importModule(filePath))
})
}
})
}
const _ = await unpkg('lodash')
const URL_PREFIX = 'https://www.nintendo.com'
const NEW_RELEASES_TITLE = 'New Releases'
const NEW_RELEASES_URL = 'https://www.nintendo.com/games/game-guide/#filter/:q=&dFR[availability][0]=New%20releases&dFR[platform][0]=Nintendo%20Switch&indexName=ncom_game_en_us_release_des'
const COMING_SOON_TITLE = 'Coming Soon'
const COMING_SOON_URL = 'https://www.nintendo.com/games/game-guide/#filter/:q=&dFR[availability][0]=Coming%20soon&dFR[platform][0]=Nintendo%20Switch&indexName=ncom_game_en_us_release_des'
const DEALS_TITLE = 'On Sale'
const DEALS_URL = 'https://www.nintendo.com/games/game-guide/#filter/:q=&dFR[generalFilters][0]=Deals&dFR[platform][0]=Nintendo%20Switch'
const SEARCH_TITLE = 'Results for:'
const SEARCH_URL = 'https://www.nintendo.com/games/game-guide/#filter/:q=QUERY&dFR[platform][0]=Nintendo%20Switch'
const askMode = new Alert()
askMode.title = 'Nintendo Switch eShop'
askMode.addAction('New Releases')
askMode.addAction('Coming Soon')
askMode.addAction('Deals')
askMode.addAction('Search')
askMode.addCancelAction('Cancel')
const mode = await askMode.presentSheet()
let query = ''
if (mode === 3) {
const askQuery = new Alert()
askQuery.title = 'Search'
askQuery.addTextField('Hatsune Miku')
askQuery.addAction('OK')
await askQuery.present()
query = askQuery.textFieldValue(0)
}
if (mode !== -1) {
let modeUrl = NEW_RELEASES_URL
let modeTitle = NEW_RELEASES_TITLE
if (mode === 1) {
modeUrl = COMING_SOON_URL
modeTitle = COMING_SOON_TITLE
} else if (mode === 2) {
modeUrl = DEALS_URL
modeTitle = DEALS_TITLE
} else if (mode === 3) {
modeUrl = SEARCH_URL.replace('QUERY', encodeURIComponent(query))
modeTitle = `${SEARCH_TITLE} ${query}`
}
const wv = new WebView()
await wv.loadURL(modeUrl)
await wv.waitForLoad()
const res = await wv.evaluateJavaScript(`
const MAX_PAGES = 3
let CURRENT_PAGE = 0
let games = []
const getLoadMoreBtn = () => (document.querySelector('#btn-load-more'))
const loadMoreBtnIsVisible = () => (window.getComputedStyle(getLoadMoreBtn()).display !== 'none')
const shouldAttempt = (i) => (loadMoreBtnIsVisible() && i < MAX_PAGES)
const clickLoadMoreBtn = () => {
CURRENT_PAGE = CURRENT_PAGE + 1
getLoadMoreBtn().dispatchEvent(new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window
}))
}
const getHits = () => {
const cache = JSON.parse(window.sessionStorage.getItem('gameguide-lastResults-cache'))
return cache && cache.hits
}
const getGames = () => {
games = games.concat(getHits())
if (shouldAttempt(CURRENT_PAGE)) {
clickLoadMoreBtn()
} else {
completion(games)
observerer.disconnect()
}
}
const observerer = new MutationObserver(getGames)
const gameListDom = document.querySelector('.game-list-results-container')
observerer.observe(gameListDom, { childList: true, subtree: true })
getGames()
`, true)
let games = _.map(res, el => ({
boxart: `${URL_PREFIX}${_.get(el, 'boxart')}`,
description: _.get(el, 'description'),
isOnSale: !_.isNil(_.get(el, 'salePrice')),
msrp: _.get(el, 'msrp'),
price: _.get(el, 'salePrice') || _.get(el, 'msrp'),
releaseDateDisplay: _.get(el, 'releaseDateDisplay'),
salePrice: _.get(el, 'salePrice'),
title: _.get(el, 'title'),
url: `${URL_PREFIX}${_.get(el, 'url')}`
}))
games = _.uniq(games)
if (mode === 1) {
_.reverse(games)
}
let table = new UITable()
let header = new UITableRow()
header.isHeader = true
header.addText(modeTitle)
header.height = 30
table.addRow(header)
const adjustDate = (d) => {
let s = d
if (_.indexOf(s, 'T') >= 0) {
s = _.split(s, 'T')[0]
}
return s
}
_.forEach(games, game => {
let row = new UITableRow()
let price = _.get(game, 'price')
price = `${_.isNil(price) ? '' : '$' + price}${_.get(game, 'isOnSale', false) ? ' (Sale)' : '' }`
let title = _.get(game, 'title')
if (!title) {
return
}
let subtitle = `${_.isEmpty(price) ? '' : price + ' • '}${adjustDate(_.get(game, 'releaseDateDisplay'))}`
let imageCell = row.addImageAtURL(_.get(game, 'boxart'))
let titleCell = row.addText(title, subtitle)
imageCell.widthWeight = 20
titleCell.widthWeight = 80
row.height = 60
row.cellSpacing = 10
row.onSelect = () => {
Safari.open(game.url)
}
table.addRow(row)
})
QuickLook.present(table)
}
@gautamarora
Copy link

Hey @ZicklePop - this is such a cool script! Looks like the Nintendo eShop changed their dom and this has stopped working. Any chance you plan to update it?

Totally cool if not, really appreciate you creating and sharing this for new scriptable devs to see how to do something like this.

@ZicklePop
Copy link
Author

Yeah, I've been suffering through using it and attempting to deconstruct the changes. It's in such an unusable state for browsing right now that the need to make it less painful is there, but I have no immediate plans. Sorry :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment