Last active
February 21, 2024 03:23
Star
You must be signed in to star a gist
not updated for the current eshop changes :( -- the fastest way to browse the nintendo switch eshop using scriptable.app
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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) | |
} |
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
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.