├── src └── main │ ├── resources │ ├── static │ │ ├── img │ │ │ ├── blank.gif │ │ │ ├── danbo.png │ │ │ ├── donateqr.png │ │ │ ├── fadegif.gif │ │ │ ├── osclogo.png │ │ │ ├── discord_qr.png │ │ │ ├── badges │ │ │ │ ├── nunchuk.gif │ │ │ │ ├── wii_remote.gif │ │ │ │ ├── wii_zapper.gif │ │ │ │ ├── usb_keyboard.gif │ │ │ │ ├── classic_controller.gif │ │ │ │ ├── gamecube_controller.gif │ │ │ │ └── wiimote.svg │ │ │ ├── link-hover.svg │ │ │ ├── osclogoanimated.gif │ │ │ ├── link-pressed.svg │ │ │ ├── title_placeholder.png │ │ │ ├── screenshot_placeholder.png │ │ │ ├── buttons │ │ │ │ ├── option.svg │ │ │ │ ├── option-hover.svg │ │ │ │ ├── button-hl.svg │ │ │ │ ├── button.svg │ │ │ │ ├── button-hl-hover.svg │ │ │ │ ├── button-hover.svg │ │ │ │ ├── button-dl.svg │ │ │ │ └── button-dl-hover.svg │ │ │ ├── icons │ │ │ │ ├── right-arrow.svg │ │ │ │ ├── top.svg │ │ │ │ ├── left-arrow.svg │ │ │ │ ├── help.svg │ │ │ │ ├── controller.svg │ │ │ │ ├── utilities.svg │ │ │ │ ├── media.svg │ │ │ │ └── channels.svg │ │ │ ├── update.svg │ │ │ ├── 1px-blue-rounded-border.svg │ │ │ └── confirmation-card.svg │ │ ├── js │ │ │ ├── buttons.js │ │ │ ├── download.js │ │ │ ├── ec.js │ │ │ ├── ec-watchdog.js │ │ │ ├── common.js │ │ │ └── skeleton.js │ │ └── css │ │ │ └── common.css │ ├── application.yml │ ├── data │ │ └── recommended.json │ └── templates │ │ ├── error │ │ ├── 404.ftl │ │ ├── ecerror.ftl │ │ └── 500.ftl │ │ ├── includes │ │ ├── macros.ftl │ │ ├── base-layout.ftl │ │ └── header.ftl │ │ ├── initial.ftl │ │ ├── debug.ftl │ │ ├── title │ │ ├── controllers.ftl │ │ ├── details.ftl │ │ ├── download.ftl │ │ ├── title.ftl │ │ └── prepare-download.ftl │ │ ├── home.ftl │ │ ├── publishers.ftl │ │ ├── browse.ftl │ │ ├── catalog.ftl │ │ └── landing.ftl │ └── java │ └── org │ └── oscwii │ └── shop │ ├── config │ ├── ContentConfig.java │ ├── ShopServerConfig.java │ ├── SchedulerConfig.java │ ├── AppConfig.java │ └── WebConfig.java │ ├── model │ └── RTitlesPage.java │ ├── utils │ ├── AssetUtil.java │ ├── Paginator.java │ ├── DownloadUtil.java │ └── FormatUtil.java │ ├── controllers │ ├── BaseController.java │ ├── StatController.java │ ├── TitleController.java │ └── PageController.java │ ├── ShopServer.java │ └── services │ ├── CatalogService.java │ ├── DownloadService.java │ └── RTitlesService.java ├── translations ├── de │ └── LC_MESSAGES │ │ ├── messages.mo │ │ └── messages.po ├── es │ └── LC_MESSAGES │ │ ├── messages.mo │ │ └── messages.po ├── fr │ └── LC_MESSAGES │ │ ├── messages.mo │ │ └── messages.po ├── it │ └── LC_MESSAGES │ │ ├── messages.mo │ │ └── messages.po ├── ja │ └── LC_MESSAGES │ │ ├── messages.mo │ │ └── messages.po ├── nl │ └── LC_MESSAGES │ │ ├── messages.mo │ │ └── messages.po └── readme.md ├── .editorconfig ├── crowdin.yml ├── data ├── motd.txt ├── messages.txt └── errors.json ├── .gitignore ├── README.md ├── messages.pot └── pom.xml /src/main/resources/static/img/blank.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/blank.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/danbo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/danbo.png -------------------------------------------------------------------------------- /translations/de/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/translations/de/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /translations/es/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/translations/es/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /translations/fr/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/translations/fr/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /translations/it/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/translations/it/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /translations/ja/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/translations/ja/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /translations/nl/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/translations/nl/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_size = 4 5 | indent_style = space 6 | 7 | [*.{js,css,html,svg,ftl}] 8 | indent_style = tab -------------------------------------------------------------------------------- /src/main/resources/static/img/donateqr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/donateqr.png -------------------------------------------------------------------------------- /src/main/resources/static/img/fadegif.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/fadegif.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/osclogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/osclogo.png -------------------------------------------------------------------------------- /src/main/resources/static/img/discord_qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/discord_qr.png -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | bundles: 2 | - 2 3 | files: 4 | - source: messages.pot 5 | translation: /translations/%two_letters_code%/LC_MESSAGES/messages.po 6 | -------------------------------------------------------------------------------- /src/main/resources/static/img/badges/nunchuk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/badges/nunchuk.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/link-hover.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/static/img/osclogoanimated.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/osclogoanimated.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/badges/wii_remote.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/badges/wii_remote.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/badges/wii_zapper.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/badges/wii_zapper.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/link-pressed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/static/img/title_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/title_placeholder.png -------------------------------------------------------------------------------- /src/main/resources/static/img/badges/usb_keyboard.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/badges/usb_keyboard.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/screenshot_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/screenshot_placeholder.png -------------------------------------------------------------------------------- /src/main/resources/static/img/badges/classic_controller.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/badges/classic_controller.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/buttons/option.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/static/img/badges/gamecube_controller.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenShopChannel/WSC-Web/HEAD/src/main/resources/static/img/badges/gamecube_controller.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/buttons/option-hover.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/motd.txt: -------------------------------------------------------------------------------- 1 | Open the shop, or so we said. 2 | Have you, in fact, got any cheese here at all? 3 | There's a spill in the utilities aisle. 4 | If the shop is closed, try the back entrance. 5 | Curbside delivery not available. -------------------------------------------------------------------------------- /src/main/resources/static/img/icons/right-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/main/resources/static/img/icons/top.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/org/oscwii/shop/config/ContentConfig.java: -------------------------------------------------------------------------------- 1 | package org.oscwii.shop.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | import java.nio.file.Path; 6 | 7 | @ConfigurationProperties(prefix = "shop-server.contents") 8 | public record ContentConfig(Path nandLoaderPath, Path appInstallerPath) 9 | { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/resources/static/img/icons/left-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/org/oscwii/shop/model/RTitlesPage.java: -------------------------------------------------------------------------------- 1 | package org.oscwii.shop.model; 2 | 3 | public record RTitlesPage(String id, String title, String subtitle, boolean dynamic, String[] apps) 4 | { 5 | public RTitlesPage(RTitlesPage oldPage, String[] apps) 6 | { 7 | this(oldPage.id(), oldPage.title(), oldPage.subtitle(), oldPage.dynamic(), apps); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/resources/static/img/update.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/static/img/1px-blue-rounded-border.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /translations/readme.md: -------------------------------------------------------------------------------- 1 | How to use these translations? Glad you asked. 2 | 3 | ### Compile Translations 4 | `pybabel compile -d translations` 5 | 6 | ### Extract new strings 7 | `pybabel extract -F babel.cfg -o messages.pot .` 8 | 9 | ### Initialize a new translation for a language 10 | `pybabel init -i messages.pot -d translations -l de` 11 | 12 | ### Update existing translation files with new strings 13 | `pybabel update -i messages.pot -d translations` 14 | -------------------------------------------------------------------------------- /src/main/java/org/oscwii/shop/utils/AssetUtil.java: -------------------------------------------------------------------------------- 1 | package org.oscwii.shop.utils; 2 | 3 | import org.oscwii.api.Package; 4 | import org.oscwii.api.Package.Asset; 5 | 6 | @SuppressWarnings("unused") 7 | public class AssetUtil 8 | { 9 | public static String getWSCIconUrl(Package app) 10 | { 11 | // WSC won't load content over HTTPS for other (sub)domains 12 | return app.assets().get(Asset.Type.ICON).url().replace("https", "http"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/oscwii/shop/config/ShopServerConfig.java: -------------------------------------------------------------------------------- 1 | package org.oscwii.shop.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 5 | 6 | @ConfigurationProperties(prefix = "shop-server") 7 | public record ShopServerConfig(String apiHost, @NestedConfigurationProperty ContentConfig contentConfig, 8 | boolean development, boolean handleEc, String repoManAccessToken) 9 | { 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # idea 26 | *.iml 27 | .idea/ 28 | 29 | application.yml 30 | application-staging.yml 31 | application-dev*.yml 32 | contents/ 33 | /data/ 34 | target/ -------------------------------------------------------------------------------- /src/main/resources/static/img/icons/help.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | sentry: 5 | dsn: "" 6 | environment: "production" 7 | # It is recommended to lower this value from the default of 1.0 on production 8 | traces-sample-rate: 1.0 9 | 10 | spring: 11 | application: 12 | name: "WSC-Web" 13 | 14 | shop-server: 15 | api-host: "https://hbb1.oscwii.org" 16 | contents: 17 | nandloader-path: "contents/00000001" 18 | appinstaller-path: "contents/00000002" 19 | development: true 20 | handle-ec: true 21 | repoman-access-token: "ChangeMe" 22 | 23 | logging: 24 | level: 25 | root: INFO 26 | org.springframework: INFO 27 | # org.springframework.beans: TRACE -------------------------------------------------------------------------------- /src/main/resources/static/js/buttons.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Setup and listen to specific events on buttons, as to play the hover and selection sounds. 3 | */ 4 | function setupButtons() { 5 | $(".btn").each(function(i) { 6 | $(this).mouseenter(function(e) { 7 | // too bad optional chaining is too new 8 | if (sound) 9 | sound.playSE(SoundType.HOVER); 10 | 11 | // ditto 12 | if (isWiiShop) 13 | redrawElement(e.currentTarget, 100); 14 | }); 15 | 16 | $(this).mousedown(function(e) { 17 | if (sound) { 18 | if ($(this).hasClass("btn-cancel")) 19 | sound.playSE(SoundType.CANCEL); 20 | else 21 | sound.playSE(SoundType.SELECT); 22 | } 23 | }); 24 | }); 25 | } -------------------------------------------------------------------------------- /src/main/java/org/oscwii/shop/config/SchedulerConfig.java: -------------------------------------------------------------------------------- 1 | package org.oscwii.shop.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.scheduling.TaskScheduler; 6 | import org.springframework.scheduling.annotation.EnableScheduling; 7 | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 8 | 9 | @Configuration 10 | @EnableScheduling 11 | public class SchedulerConfig 12 | { 13 | @Bean 14 | public TaskScheduler taskScheduler() 15 | { 16 | var scheduler = new ThreadPoolTaskScheduler(); 17 | scheduler.setPoolSize(3); 18 | scheduler.setThreadNamePrefix("Shopkeeper"); 19 | return scheduler; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/resources/static/img/confirmation-card.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/main/resources/data/recommended.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "recommendedTitles-1", 4 | "title": "Recommended Titles", 5 | "subtitle": "", 6 | "apps": [ 7 | "danbo", "danbo2", "danbo3", "danbo4" 8 | ] 9 | }, 10 | { 11 | "id": "recommendedTitles-2", 12 | "title": "Recommended Titles 2", 13 | "subtitle": "", 14 | "apps": [ 15 | "danbo5", "danbo6", "danbo7", "danbo8" 16 | ] 17 | }, 18 | { 19 | "id": "recommendedTitles-3", 20 | "title": "Highlights", 21 | "subtitle": "", 22 | "dynamic": true, 23 | "apps": [ 24 | "osc:featuredapp", "osc:latest", "osc:latest:games", "osc:latest:utilities" 25 | ] 26 | } 27 | ] -------------------------------------------------------------------------------- /src/main/resources/static/img/badges/wiimote.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/org/oscwii/shop/controllers/BaseController.java: -------------------------------------------------------------------------------- 1 | package org.oscwii.shop.controllers; 2 | 3 | import org.oscwii.shop.config.ShopServerConfig; 4 | import org.oscwii.shop.services.CatalogService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.ModelAttribute; 7 | 8 | public abstract class BaseController 9 | { 10 | @Autowired 11 | protected ShopServerConfig config; 12 | @Autowired 13 | protected CatalogService catalog; 14 | 15 | @ModelAttribute("isDevelopment") 16 | protected boolean isDevelopment() 17 | { 18 | return config.development(); 19 | } 20 | 21 | @ModelAttribute("handleEc") 22 | protected boolean handleEc() 23 | { 24 | return config.handleEc(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/templates/error/404.ftl: -------------------------------------------------------------------------------- 1 | <#import "../includes/base-layout.ftl" as layout> 2 | <@layout.header.header "404 - Not Found"> 3 | 8 | @layout.header.header> 9 | 10 | <@layout.navigation/> 11 | 12 | <@layout.page> 13 | <#-- "200" will be our prefix for Shop HTTP errors--> 14 |
Error Code: 200404
15 |Not Found
16 |The resource you were looking for is not here.
18 |Error Code: 219${code}
15 | <#-- TODO error desc --> 16 |ERROR_DESC
17 |A critical error has occurred.
19 | Please try again later, if this continues please contact the Open Shop Channel.
20 |
Error Code: 200500
15 |Internal Server Error
16 |A critical server-side error has occurred.
18 | Please try again later, if this continues please contact the Open Shop Channel.
19 |
Connecting. Please wait...
46 | @layout.page> 47 | 48 | <@layout.footer/> -------------------------------------------------------------------------------- /src/main/java/org/oscwii/shop/controllers/StatController.java: -------------------------------------------------------------------------------- 1 | package org.oscwii.shop.controllers; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import org.oscwii.shop.services.DownloadService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.PostMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestParam; 12 | 13 | @Controller 14 | @RequestMapping("/stat") 15 | public class StatController 16 | { 17 | private final DownloadService downloadService; 18 | 19 | @Autowired 20 | public StatController(DownloadService downloadService) 21 | { 22 | this.downloadService = downloadService; 23 | } 24 | 25 | @PostMapping("/download/{slug}") 26 | public ResponseEntity> notifyDownload(@PathVariable String slug, @RequestParam String token, HttpServletRequest request) 27 | { 28 | if(token == null || token.isBlank()) 29 | return ResponseEntity.badRequest().body("No token provided"); 30 | if(!downloadService.isValidToken(token)) 31 | return ResponseEntity.badRequest().body("Invalid token"); 32 | 33 | downloadService.notifyDownload(slug, request); 34 | return ResponseEntity.noContent().build(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/resources/templates/debug.ftl: -------------------------------------------------------------------------------- 1 | <#import "includes/base-layout.ftl" as layout> 2 | <@layout.header.header "Debug"> 3 | 16 | 17 | 32 | @layout.header.header> 33 | 34 | <@layout.navigation dots=true showTitle=false/> 35 | 36 | <@layout.page> 37 | Go back 38 | 39 |Current language: ${lang}
40 |Force language:
41 | 49 | 50 | 51 | 52 | @layout.page> 53 |