-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathretroarch-playlist-helper-lib.ahk
302 lines (242 loc) · 10.2 KB
/
retroarch-playlist-helper-lib.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
;### AUTOHOTKEY FUNCTIONS FOR RETROARCH PLAYLISTS AND THUMBNAILS
;### Based on prior work by libretro forum users roldmort, Tetsuya79, Alexandra, and markwkidd
;### newShrinkArcadeDAT(datfile_source, ByRef shrunk_DAT_array)
;### Parses an XML DAT file for MAME or FB Alpha
;### creates associative 2D array objects in shrunk_DAT_array
BuildArcadeDATArray(datfile_path, ByRef shrunk_DAT_array, display_progress_bar:=False) {
shrunk_DAT_array := Object()
dat_contents := ""
dat_length := 0
is_old_XML_format := False
old_XML_parent_tag := "<game"
new_XML_parent_tag := "<machine"
scanning_pos := 0
needle := ""
if(display_progress_bar) {
Progress, A M T, %datfile_path%,,Parsing arcade DAT
}
FileRead, dat_contents, %datfile_path%
dat_length := StrLen(dat_contents)
needle = PSs)<(?:game|machine) name="(.*?)"(?:\s(.*?))?>(?:\s*?)(.*?)</(?:game|machine)>
scanning_pos := 0
Loop {
scanning_pos += 1
if(display_progress_bar) {
parsing_progress := Round(100 * (scanning_pos / dat_length))
Progress, %parsing_progress%
}
scanning_pos := RegExMatch(dat_contents, needle, dat_match, scanning_pos)
if(!scanning_pos) {
break
}
romset_name := (SubStr(dat_contents, dat_matchPos1, dat_matchLen1) . "")
modifiers := (SubStr(dat_contents, dat_matchPos2, dat_matchLen2) . "")
XML_subentries := (SubStr(dat_contents, dat_matchPos3, dat_matchLen3) . "")
is_BIOS := False
is_device := False
is_mechanical := False
clone_of := False
ROM_of := False
runnable := True
needs_CHD := False
CHD_only := False
title := ""
year := ""
manufacturer := ""
player_count := 0
if(romset_name == "") {
MsgBox Unexpected error processing DAT file.`n`nROM set name:%romset_name% Title:%dat_title%
ExitApp
}
if (InStr(modifiers, "isbios=""yes""")) {
is_BIOS := True
}
if (InStr(modifiers, "isdevice=""yes""")) {
is_device := True
}
if (InStr(modifiers, "ismechanical=""yes""")) {
is_mechanical := True
}
attribute_start_pos := InStr(modifiers, "cloneof")
if(attribute_start_pos) {
attribute_start_pos += 9
clone_of := SubStr(modifiers, attribute_start_pos, (InStr(modifiers, """", false, attribute_start_pos) - attribute_start_pos))
}
attribute_start_pos := InStr(modifiers, "romof")
if(attribute_start_pos) {
attribute_start_pos += 7
ROM_of := SubStr(modifiers, attribute_start_pos, (InStr(modifiers, """", false, attribute_start_pos) - attribute_start_pos))
}
if (InStr(XML_subentries, "status=""preliminary""")) {
runnable := False
}
if (InStr(XML_subentries, "emulation=""preliminary""")) {
runnable := False
}
if (InStr(XML_subentries, "status=""protection""")) {
runnable := False
}
if (InStr(XML_subentries, "protection=""preliminary""")) {
runnable := False
}
if(InStr(XML_subentries, "disk")) {
needs_CHD := True
}
;### TODO: detect CHD-only sets
;### CHD_only := True
attribute_start_pos := InStr(XML_subentries, "<description>")
if(attribute_start_pos) {
attribute_start_pos += 13
title := SubStr(XML_subentries, attribute_start_pos, (InStr(XML_subentries, "</description>") - attribute_start_pos))
}
attribute_start_pos := InStr(XML_subentries, "<year>")
if(attribute_start_pos) {
attribute_start_pos += 6
year := SubStr(XML_subentries, attribute_start_pos, 4)
}
attribute_start_pos := InStr(XML_subentries, "<manufacturer>")
if(attribute_start_pos){
attribute_start_pos += 14
manufacturer := SubStr(XML_subentries, attribute_start_pos, (InStr(XML_subentries, "</manufacturer>") - attribute_start_pos))
}
attribute_start_pos := InStr(XML_subentries, "players=""")
if(attribute_start_pos) {
attribute_start_pos += 9
player_count := SubStr(XML_subentries, attribute_start_pos, 1)
}
if(title != "") {
title := StrReplace(title, "³", "3") ;### Remove HTML encoded characters in the DAT title --
title := StrReplace(title, "'", "'") ;### only handles characters actually spotted in the wild
title := StrReplace(title, "&", "_")
}
shrunk_DAT_array[romset_name] := {romset_name:romset_name
, title:title
, needs_CHD:needs_CHD
, CHD_only:CHD_only
, is_BIOS:is_BIOS
, is_device:is_device
, is_mechanical:is_mechanical
, clone_of:clone_of
, ROM_of:ROM_of
, runnable:runnable
, year:year
, manufacturer:manufacturer
, player_count:player_count}
}
if(display_progress_bar) {
Progress, Off
}
}
;---------------------------------------------------------------------------------------------------------
;### PlaylistGenerator
;###
;### ROM_file_array needs to be an associative array in this format:
;### ROM_file_array[ROM_name_no_file_extension].path == full path to the ROM file
;### ROM_file_array[ROM_name_no_file_extension].title == the title to display on the playlist
PlaylistGenerator(ByRef ROM_file_array, playlist_filename, playlist_name, playlist_ROM_path, path_delimiter, display_progress_bar:=False) {
playlist_file := FileOpen(playlist_filename,"w") ;### erases any existing file and opens a new file with this name
number_of_files := NumGet(&ROM_file_array + 4*A_PtrSize) ;### associative array size. voodoo from the AHK forums
current_ROM_count := 0
if(display_progress_bar) {
Progress, A M T, Generating playlist:`n%playlist_name%,,%app_title%
}
For rom_index, rom_details in ROM_file_array
{
current_ROM_count += 1
current_ROM_path := rom_details.path
SplitPath, current_ROM_path, ROM_filename_with_ext,current_ROM_directory,,
if(display_progress_bar) {
percent_parsed := Round(100 * (current_ROM_count / number_of_files))
Progress, %percent_parsed%
}
playlist_entry_ROM_path := playlist_ROM_path . path_delimiter . playlist_name . path_delimiter . ROM_filename_with_ext
playlist_entry := FormatPlaylistEntry(playlist_entry_ROM_path, (rom_details.title), RA_core_path, playlist_name)
playlist_file.Write(playlist_entry)
}
playlist_file.Close() ;### close and flush the new playlist file
if(display_progress_bar) {
Progress, Off
}
}
;---------------------------------------------------------------------------------------------------------
SanitizeFilename(input_string) { ;### fix chars for multi-platform use per No-Intro standard
input_string := StrReplace(input_string, "&", "_")
input_string := StrReplace(input_string, "\", "_")
input_string := StrReplace(input_string, "/", "_")
input_string := StrReplace(input_string, "?", "_")
input_string := StrReplace(input_string, ":", "_")
input_string := StrReplace(input_string, "``", "_")
input_string := StrReplace(input_string, "<", "_")
input_string := StrReplace(input_string, ">", "_")
input_string := StrReplace(input_string, "*", "_")
input_string := StrReplace(input_string, "|", "_")
return input_string
}
;---------------------------------------------------------------------------------------------------------
StripFinalSlash(ByRef source_path)
{
last_char = SubStr(source_path,0,1)
if ((last_char == "\") or (last_char == "/"))
{
StringTrimRight, source_path, source_path, 1
}
}
;---------------------------------------------------------------------------------------------------------
FormatPlaylistEntry(playlist_entry_rom_path, playlist_title, core_path, playlist_name) {
playlist_entry := playlist_entry_rom_path . "`n"
. playlist_title . "`n"
. core_path . "`n"
. "DETECT" . "`n"
. "DETECT" . "`n"
. playlist_name . ".lpl" . "`n"
return playlist_entry
}
;---------------------------------------------------------------------------------------------------------
;### DownloadFile function by Bruttosozialprodukt with modifications
DownloadFile(UrlToFile, SaveFileAs, Overwrite := True, UseProgressBar := True) {
;### Check if the file already exists and if we must not overwrite it
If (!Overwrite && FileExist(SaveFileAs)) {
Return
}
If (UseProgressBar) {
LastSize =
LastSizeTick =
;### Initialize the WinHttpRequest Object
WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
WebRequest.SetTimeouts("10000", "10000", "10000", "10000")
WebRequest.Open("HEAD", UrlToFile)
WebRequest.Send()
WebRequest.WaitForResponse()
;#### Download the headers
if (WebRequest.Status() == 404) ;### 404 error
return
;### Store the header which holds the file size in a variable:
FinalSize := WebRequest.GetResponseHeader("Content-Length")
;### Create the progressbar and the timer
Progress, , , Downloading..., %UrlToFile%
SetTimer, __UpdateProgressBar, 100
}
;Download the file
UrlDownloadToFile, %UrlToFile%, %SaveFileAs%
;Remove the timer and the progressbar because the download has finished
If (UseProgressBar) {
Progress, Off
SetTimer, __UpdateProgressBar, Off
}
Return
__UpdateProgressBar:
;Get the current filesize and tick
CurrentSize := FileOpen(SaveFileAs, "r").Length ;FileGetSize wouldn't return reliable results
CurrentSizeTick := A_TickCount
;Calculate the downloadspeed
Speed := Round((CurrentSize/1024-LastSize/1024)/((CurrentSizeTick-LastSizeTick)/1000)) . " Kb/s"
;Save the current filesize and tick for the next time
LastSizeTick := CurrentSizeTick
LastSize := FileOpen(SaveFileAs, "r").Length
;Calculate percent done
PercentDone := Round(CurrentSize/FinalSize*100)
;Update the ProgressBar
progress_caption := "Downloading: " . UrlToFile . "`nDestination: " . SaveFileAs
Progress, %PercentDone%, %progress_caption%, %PercentDone%`% (%Speed%), Downloading thumbnails
Return
}