Skip to content

Commit d307160

Browse files
committed
Merge branch 'pr/52'
2 parents a872f08 + 5e85e14 commit d307160

File tree

5 files changed

+82
-26
lines changed

5 files changed

+82
-26
lines changed

.gitignore

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
.vscode
2-
key.txt
2+
key.txt
3+
__pycache__
4+
Album
5+
venv
6+
virtualenv

README.md

+16-9
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,28 @@
22
Automatically organize and timestamp your Nintendo Switch captures
33
![image](https://user-images.githubusercontent.com/17756301/33006063-0c36d2ce-cdb0-11e7-8875-1044eab6527a.png)
44

5+
# !!! This Project has been deprecated in favor of [Switcheroo](https://github.com/Tyler-A/Switcheroo) / [Switcheroo Lite](https://github.com/dmynerd78/switcheroo-lite) !!!
6+
57
## Requirements
8+
This package requires pycryptodome and BeautifulSoup4.
9+
You can install them by running
10+
``pip install -r requirements.txt``
611

7-
* ``pip install pycryptodome``
12+
(Optional) Key at offset 0x71000704D0 from the capsrv NSO loaded up in IDA as ``key.txt`` on the same folder as nxshot for automatic updating. Hash: ``24e0dc62a15c11d38b622162ea2b4383``
813

9-
* ``pip install BeautifulSoup4``
14+
## Usage
1015

11-
* (Optional) Key at offset 0x71000704D0 from the capsrv NSO loaded up in IDA as ``key.txt`` on the same folder as nxshot for automatic updating. Hash: ``24e0dc62a15c11d38b622162ea2b4383``
16+
``nxshot.py [-h] [-d] FILEPATH``
1217

13-
## Usage
18+
positional arguments:
1419

15-
``nxshot.py FILEPATH``
20+
FILEPATH "Nintendo/Album" folder from your SD card.
1621

17-
Positional arguments:
22+
optional arguments:
1823

19-
>FILEPATH: "Nintendo/Album" folder from your SD card.
24+
-h, --help show this help message and exit
25+
-d, --download-nswdb Download IDs from nswdb.com instead of switchbrew.org
26+
NOTE: Regions may not match SwitchBrew
2027

2128
![image](https://user-images.githubusercontent.com/17756301/33006113-3f204800-cdb0-11e7-99f4-94790c01916d.png)
2229

@@ -28,8 +35,8 @@ If some of your screenshots end up being copied to ``../Nintendo/Album/Organized
2835

2936
To see what games are currently automatically recognized, take a look at the [gameids.json](gameids.json) file.
3037

31-
The list is automatically updated from [SwitchBrew](http://switchbrew.org/index.php?title=Title_list/Games)
32-
38+
The list is automatically updated from [SwitchBrew](http://switchbrew.org/index.php?title=Title_list/Games) by default. [nswdb](http://nswdb.com/) can be used with the ``-d`` flag.
39+
3340
## Help
3441

3542
If you have any questions, feel free to send me a tweet [**@s1cp_**](https://twitter.com/s1cp_).

gameids.json

+1
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@
275275
"1E416003E8D82D42DB8ED6ABCE2CD05C": "Iro Hero (EUR JPN USA)",
276276
"1E777F45D84E62687A707A2E6BFA981B": "Crystal Crisis (EUR USA)",
277277
"1E9175739094EA812C0BB94786A49E66": "SUPERBEAT XONiC EX (EUR)",
278+
"1E95E5926F1CB99A87326D927F27B47E": "System",
278279
"1E986BB24FF2BF4E79161F51B4808BAC": "Cities - Skylines - Nintendo Switch™ Edition (EUR JPN USA)",
279280
"1EB82633F9C7BDC1B178DCD09352DD9B": "Super Mario Odyssey™ Demo for KIOSK (USA)",
280281
"1EF4E2B5E9683EAAB935AE64491CD5FC": "EVE burst error R (イヴ バーストエラー アール) (JPN)",

nxshot.py

+57-16
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
from Crypto.Cipher import AES
99
from Crypto.Util import Padding
1010
import hashlib
11-
from urllib.request import urlopen
11+
from urllib.request import urlopen, urlretrieve
1212
from urllib.error import URLError
1313
from bs4 import BeautifulSoup
14+
import xml.etree.ElementTree as ET
1415

1516
keyhash = "24e0dc62a15c11d38b622162ea2b4383"
1617
updated = 0
@@ -27,6 +28,12 @@
2728
type=Path,
2829
help='"Nintendo/Album" folder from your SD card.')
2930

31+
parser.add_argument('-d',
32+
'--download-nswdb',
33+
action='store_true',
34+
help='Download IDs from nswdb.com instead of switchbrew.org\n \
35+
NOTE: Regions may not match')
36+
3037
# If there are arguments, parse them. If not, exit
3138
args = parser.parse_args()
3239

@@ -45,12 +52,36 @@ def loadKey(filename, keyhash):
4552
except ValueError:
4653
print("Decryption key (key.txt) doesn't match!")
4754

55+
def decryptTitleID(key, titleid):
56+
cipher = AES.new(key, AES.MODE_ECB)
57+
58+
titleidb = bytes.fromhex(titleid)
59+
titleidb = titleidb[7::-1]
60+
conversion = titleidb.hex()
61+
conversion = conversion.ljust(32, '0')
62+
titleidb = bytes.fromhex(conversion)
63+
encrypted = cipher.encrypt(titleidb)
64+
screenshotid = encrypted.hex().upper()
65+
66+
return screenshotid
4867

4968
def updateGameIDs():
5069
key = loadKey('key.txt', keyhash)
5170
if not key:
5271
return -1
5372

73+
if args.download_nswdb:
74+
updateNSWDB(key)
75+
else:
76+
updateSwitchBrew(key)
77+
78+
with open('gameids.json', 'w', encoding='utf-8') as idfile:
79+
json.dump(idname, idfile, ensure_ascii=False, indent=4, sort_keys=True)
80+
print("Successfully updated Game IDs")
81+
82+
return 1
83+
84+
def updateSwitchBrew(key):
5485
wiki = 'http://switchbrew.org/index.php?title=Title_list/Games'
5586
try:
5687
wikipage = urlopen(wiki)
@@ -62,8 +93,6 @@ def updateGameIDs():
6293
gametable = wikisoup.find('table', {"class": "wikitable sortable"})
6394
gametabler = gametable.find_all('tr')
6495

65-
cipher = AES.new(key, AES.MODE_ECB)
66-
6796
for row in gametabler[1:]:
6897
try:
6998
titleid = str(row.contents[1].string)
@@ -80,22 +109,33 @@ def updateGameIDs():
80109

81110
#print('TitleID = {}'.format(titleid))
82111

83-
titleidb = bytes.fromhex(titleid)
84-
titleidb = titleidb[7::-1]
85-
conversion = titleidb.hex()
86-
conversion = conversion.ljust(32, '0')
87-
titleidb = bytes.fromhex(conversion)
88-
encrypted = cipher.encrypt(titleidb)
89-
screenshotid = encrypted.hex().upper()
112+
screenshotid = decryptTitleID(key, titleid)
90113

91114
#print("ScreenshotID = {}".format(encrypted.hex()))
92115
idname[screenshotid] = gamename + ' (' + region + ')'
93116

94-
with open('gameids.json', 'w', encoding='utf-8') as idfile:
95-
json.dump(idname, idfile, ensure_ascii=False, indent=4, sort_keys=True)
96-
print("Successfully updated Game IDs")
97117

98-
return 1
118+
def updateNSWDB(key):
119+
urlretrieve('http://nswdb.com/xml.php', 'db.xml')
120+
tree = ET.parse('db.xml')
121+
root = tree.getroot()
122+
123+
for release in root.findall('release'):
124+
try:
125+
screenshotid = decryptTitleID(key, release.find('titleid').text)
126+
127+
region = release.find('region').text
128+
if region == "WLD":
129+
region = "EUR USA"
130+
131+
name = release.find('name').text
132+
name = name.replace(":", " -")
133+
except ValueError:
134+
continue
135+
136+
idname[screenshotid] = name + ' (' + region + ')'
137+
138+
os.remove("db.xml")
99139

100140

101141
def checkID(gameid, idname):
@@ -149,7 +189,8 @@ def checkFolders(filelist):
149189

150190
current += 1
151191

152-
print('Organized {} of {} files.'.format(current, length))
192+
print('Organized {} of {} files.\r'.format(current, length), end='')
193+
print("")
153194

154195

155196
# Load game ids and their names from external file
@@ -196,4 +237,4 @@ def checkFolders(filelist):
196237
else:
197238
print('\nNo videos found!')
198239

199-
print('Done!')
240+
print('Done!')

requirements.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
beautifulsoup4==4.7.0
2+
pycryptodome==3.7.2
3+
soupsieve==1.6

0 commit comments

Comments
 (0)