SkillAgentSearch skills...

Tinshop

Tinshop is your own personal shop compatible with tinfoil

Install / Use

/learn @DblK/Tinshop
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<div align="center"> <img alt="TinShop" src="./logo.png" width="50%"><br><br> Your own personal shop right into tinfoil!<br><br>

golangci-lint test GitHub go.mod Go version of a Go module GoDoc reference example GoReportCard GitHub release License: AGPL v3

</div>

⚠️ Disclaimer

This program DOES NOT encourage piracy at all!
It was designed to reduce the time to download/install a game from the Nintendo eShop.
In case you have a ADSL connection, to install latest Zelda (14.4Gb) it can take ages!

On top of that, if you have bought a game on eShop like Jump Force, once it is not anymore on the shop how can you install it again?
Using your personal NSP dump, with tinfoil and tinshop everything should be fine and fast!

🎮 Use

To proper use this software, here is the checklist:

  • [ ] Optional: A proper configured config.yaml
    • [ ] Copy/Paste config.example.yaml to config.yaml
    • [ ] Comment/Uncomment parts in the config according to your needs
  • [ ] Games should have in their name [ID][v0] to be recognized
  • [ ] Games extension should be nsp or nsz
  • [ ] Retrieve binary from latest release or container (See Docker section below) or build from source (See Dev section below)

Now simply run it and add a shop inside tinfoil with the address setup in config (or http://localIp:3000 if not specified).

🎉 Features

Here is the list of all main features so far:

  • [X] Automatically download titles.US.en.json if missing at startup
  • [X] Basic protection from forged queries (should allow only tinfoil to use the shop)
  • [X] Serve from several mounted directories
  • [X] Serve from several network directories (Using NFS)
  • [X] Display a webpage for forbidden devices
  • [X] Auto-refresh configuration on file change
  • [X] Add the possibility to whitelist or blacklist a switch
  • [X] Add the possibility to ban theme
  • [X] You can specify custom titledb to be merged with official one
  • [X] Auto-watch for mounted directories
  • [X] Add filters path for shop
  • [X] Simple ticket check in NSP/NSZ (based on titledb file)
  • [X] Collect basic statistics
  • [X] An API to query information about your shop
  • [X] Handle Basic Auth from Tinfoil through Forward Auth Endpoint

🏳️ Filtering

When you setup your shop inside tinfoil you can now add the following path:

  • multi : Filter only multiplayer games
  • fr, en, ... : Filter by languages
  • world : All games without any filter (equivalent without path)

🧱 Dev or build from source

I suggest to use a tiny executable gow to help you during the process (hot reload, etc..).
For example I use the following command to develop gow -c run ..

If you want to build TinShop from source, please run go build.

And then, simply run ./tinshop.

🐋 Docker

To run with Docker, you can use this as a starting cli example:

docker run -d --restart=always -e TINSHOP_SOURCES_DIRECTORIES=/games -e TINSHOP_WELCOMEMESSAGE="Welcome to my Tinshop!" -v /local/game/backups:/games -p 3000:3000 ghcr.io/dblk/tinshop:latest

This will run Tinshop on http://localhost:3000 and persist across reboots!

If docker compose is your thing, then start with this example:

version: '3.9'
services:
  tinshop:
    container_name: tinshop
    image: ghcr.io/dblk/tinshop:latest
    restart: always
    ports:
      - 3000:3000
    environment:
      - TINSHOP_SOURCES_DIRECTORIES=/games
      - TINSHOP_WELCOMEMESSAGE=Welcome to my Tinshop!
    volumes:
      - /media/switch:/games

All of the settings in the config.yaml file are valid Environment Variables. They must be UPPERCASE and prefixed by TINSHOP_. Nested properties should be prefixed by _. Here are a few examples:

| ENV_VAR | config.yaml entry | Default Value | Example Value | |------------------------------|---------------------|--------------------------------|-----------------------------------| | TINSHOP_HOST | host | <empty> | tinshop.example.com | | TINSHOP_PROTOCOL | protocol | http | https | | TINSHOP_NAME | name | TinShop | MyShop | | TINSHOP_REVERSEPROXY | reverseProxy | false | true | | TINSHOP_WELCOMEMESSAGE | welcomeMessage | Welcome to your own TinShop! | Welcome to my shop! | | TINSHOP_NOWELCOMEMESSAGE | noWelcomeMessage | false | true | | TINSHOP_DEBUG_NFS | debug.nfs | false | true | | TINSHOP_DEBUG_NOSECURITY | debug.nosecurity | false | true | | TINSHOP_DEBUG_TICKET | debug.ticket | false | true | | TINSHOP_NSP_CHECKVERIFIED | nsp.checkVerified | false | true | | TINSHOP_SOURCES_DIRECTORIES | sources.directories | ./games | /games /path/two /path/three | | TINSHOP_SOURCES_NSF | sources.nfs | null | 192.168.1.100:/path/to/games | | TINSHOP_SECURITY_BANNEDTHEME | sources.bannedTheme | null | THEME1 THEME2 THEME3 | | TINSHOP_SECURITY_WHITELIST | sources.whitelist | null | NSWID1 NSWID2 NSWID3 | | TINSHOP_SECURITY_BLACKLIST | sources.blacklist | null | NSWID4 NSWID5 NSWID6 | | TINSHOP_SECURITY_FORWARDAUTH | sources.forwardAuth | null | https://auth.tinshop.com/switch |

🥍 Want to do cross-build generation?

Wanting to generate all possible os binaries (macOS, linux, windows) with all architectures (arm, amd64)?
Here is the command goreleaser release --snapshot --skip-publish --rm-dist.

Dead simple, thanks to Golang!

🏛️ Changing the structure of an interface?

If you change an interface (or add a new one), do not forget to execute ./update_mocks.sh to generate up-to-date mocks for tests.

Do not forget to install mockgen first:

go install github.com/golang/mock/mockgen@v1.6.0

🧪 What to launch tests?

You can run ginkgo -r for one shot or ginkgo watch -r during development.
Note: you can add -cover to have an idea of the code coverage.

🎯 Roadmap

You can see the roadmap here.

If you have any suggestions, do not hesitate to participate!

👂🏻 Q & A

Why use this instead of X (NUT or others software)?

<details> <summary>Answer</summary>

It's dead simple, and no dependencies! It's just a single small executable.
Easier to install games without connecting switch or by updating SD card (Nightmare if you are on macOS).

The upcoming features will also be a huge advantage against others software.

</details>

Where do I put my games?

<details> <summary>Answer</summary>

By default, TinShop will look into the games directory relative to tinshop executable.

However in the config.yaml file, you can change this.
In the sources section, you can have the following:

  • directories: List of directories where you put your games
  • nfs: List of NFS shares that contains your games
</details>

Can I set up a https endpoint?

<details> <summary>Answer</summary>

Yes, you can!
Use a reverse proxy (like traefik, caddy, nginx...) to do tls termination and forward to your instance on port 3000.

Example for caddy

To work with caddy, you need to put in your Caddyfile something similar to this:

tinshop.example.com:80 {
    reverse_proxy 192.168.1.2:3000
}

and your config.yaml as follow:

host: tinshop.example.com
protocol: http
port: 3000
reverseProxy: true

If you want to have HTTPS, ensure caddy handle it (it will with Let's Encrypt) and change https in the config and remove :80 in the Caddyfile example.

Example for traefik

To work with traefik, you need to put in your Dynamic Configuration something similar to this:

http:
  routers:
    service: tinshop
    rule: Host(`tinshop.exa
View on GitHub
GitHub Stars53
CategoryDevelopment
Updated23d ago
Forks3

Languages

Go

Security Score

100/100

Audited on Mar 2, 2026

No findings