Merge branch 'master' into translations
[QuestHelper.git] / Development / spider
blobf852e95011b50b440c998ef9fb205ee2c4adf492
1 #!/usr/bin/env lua
3 loadfile("dump.lua")()
4 loadfile("xml.lua")()
5 loadfile("fileutil.lua")()
7 local base_directory = "~/QuestHelper-SpiderData"
9 function searchFile(file, str)
10   local stream = io.popen(string.format("grep %s -ce %s", FileUtil.quoteFile(file), FileUtil.quoteFile(str)))
11   if stream then
12     local number = tonumber(stream:read())
13     io.close(stream)
14     return number or 0
15   end
16   return 0
17 end
19 function fileType(file)
20   local stream = io.popen(string.format("file -bi %s", FileUtil.quoteFile(file)))
21   if stream then
22     local filetype = stream:read()
23     io.close(stream)
24     return filetype or "unknown"
25   end
26   
27   return "unknown"
28 end
30 local WoWData =
31  {
32   quest = {},
33   item = {},
34   npc = {}
35  }
37 local wd_loader = loadfile("External/wowdata.lua")
39 if wd_loader then
40   print("Loading old data.")
41   local env = {}
42   setfenv(wd_loader, env)
43   wd_loader()
44   wd_loader = nil
45   
46   WoWData = env.WoWData or WoWData
47 end
49 local function save()
50   local stream = io.open("External/wowdata.lua", "w")
51   local buffer, prebuf = CreateBuffer(), CreateBuffer()
52   DumpVariable(buffer, prebuf, WoWData, "WoWData")
53   stream:write(DumpingComplete(buffer, prebuf))
54   io.close(stream)
55 end
57 function getQuest(id)
58   local q = WoWData.quest[id]
59   if not q then q = {name={},hash={},faction={}} WoWData.quest[id] = q end
60   return q
61 end
63 function getNPC(id)
64   local n = WoWData.npc[id]
65   if not n then n = {name={}} WoWData.npc[id] = n end
66   return n
67 end
69 function getItem(id)
70   local i = WoWData.item[id]
71   if not i then i = {name={}} WoWData.item[id] = i end
72   return i
73 end
75 function doTag(tag)
76   if tag == "br /" then return "\n" end
77   print("Unknown Tag: "..tag)
78 end
80 function doEntity(entity)
81   if tag == "amp" then return "&" end
82   if tag == "lt" then return "<" end
83   if tag == "gt" then return ">" end
84   print("Unknown Entity: "..tag)
85 end
87 function htmlToText(input)
88   return string.gsub(string.gsub(input, "<(.-)>", doTag), "&(.-);", doEntity)
89 end
91 function preFix(str, pre)
92   if str then
93     while true do
94       local t = select(3, string.find(str, pre))
95       if t then
96         str = t
97       else break end
98     end
99   end
100   return str
103 function hashString(text)
104   -- Computes an Adler-32 checksum.
105   local a, b = 1, 0
106   for i=1,string.len(text) do
107     a = (a+string.byte(text,i))%65521
108     b = (b+a)%65521
109   end
110   return b*65536+a
113 function downloadItems()
114   local index = 1
115   local failures = 0
116   local map = {de ="deDE", en = "enUS", es = "esES", fr = "frFR", ko="koKR", zh="zhCN"}
117   
118   FileUtil.createDirectory(base_directory)
119   FileUtil.createDirectory(base_directory.."/items")
120   
121   while failures < 256 do
122     local failed = true
123     
124     print(index)
125     
126     local destfile = base_directory.."/items/"..index
127     
128     if (FileUtil.fileExists(destfile) or
129         os.execute(string.format("wget %s -q -N -O %s",
130                                  FileUtil.quoteFile("http://www.wowguru.com/db/syndicate/items/id"..index..".xml"),
131                                  FileUtil.quoteFile(destfile))) == 0) and fileType(destfile) == "text/xml" then
132       local xml = XMLtoLUA(destfile)
133       
134       if xml.item and xml.item.translations then
135         local i = getItem(index)
136         if xml.item.translations then
137           local t = xml.item.translations
138           for t, x in pairs(xml.item.translations) do
139             if x.value then
140               print(index, map[t], x.value)
141               i.name[map[t]] = x.value
142             end
143           end
144         end
145         
146         failed = false
147       end
148     end
149     
150     if not failed then
151       failures = 0
152     else
153       failures = failures + 1
154     end
155     
156     index = index + 1
157   end
160 function downloadNPCs()
161   local index = 1
162   local failures = 0
163   local map = {
164                deDE = "http://de.wowguru.com/db/syndicate/mobs/id%d.xml",
165                enUS = "http://www.wowguru.com/db/syndicate/mobs/id%d.xml",
166                frFR = "http://fr.wowguru.com/db/syndicate/mobs/id%d.xml",
167                koKR = "http://ko.wowguru.com/db/syndicate/mobs/id%d.xml",
168                zhCN = "http://zh.wowguru.com/db/syndicate/mobs/id%d.xml",
169                esES = "http://es.wowguru.com/db/syndicate/mobs/id%d.xml"
170               }
171   
172   FileUtil.createDirectory(base_directory)
173   FileUtil.createDirectory(base_directory.."/npcs")
174   for locale in pairs(map) do
175     FileUtil.createDirectory(base_directory.."/npcs/"..locale)
176   end
177   
178   while failures < 256 do
179     local failed = true
180     
181     for locale, url_format in pairs(map) do
182       local destfile = base_directory.."/npcs/"..locale.."/"..index
183       
184       if (FileUtil.fileExists(destfile) or
185           os.execute(string.format("wget %s -q -N -O %s",
186                                    FileUtil.quoteFile(string.format(url_format, index)),
187                                    FileUtil.quoteFile(destfile))) == 0) and fileType(destfile) == "text/xml" then
188         local xml = XMLtoLUA(destfile)
189         
190         if xml.mob and type(xml.mob.name) == "string" then
191           local npc = getNPC(index)
192           
193           print(index, locale, xml.mob.name)
194           
195           npc.name[locale] = xml.mob.name
196           
197           failed = false
198         end
199       end
200     end
201     
202     if not failed then
203       failures = 0
204     else
205       failures = failures + 1
206     end
207     
208     index = index + 1
209   end
212 function downloadQuests()
213   local index = 1
214   local failures = 0
215   local map = {
216                enUS = "http://www.wowguru.com/db/quests/id%d/",
217                frFR = "http://fr.wowguru.com/db/quests/id%d/",
218                esES = "http://es.wowguru.com/db/quests/id%d/",
219                deDE = "http://de.wowguru.com/db/quests/id%d/",
220                zhCN = "http://zh.wowguru.com/db/quests/id%d/",
221                koKR = "http://ko.wowguru.com/db/quests/id%d/"
222               }
223   
224   FileUtil.createDirectory(base_directory)
225   FileUtil.createDirectory(base_directory.."/quests")
226   for locale in pairs(map) do
227     FileUtil.createDirectory(base_directory.."/quests/"..locale)
228   end
229   
230   while failures < 256 do
231     local failed = true
232     
233     for locale, url_format in pairs(map) do
234       local destfile = base_directory.."/quests/"..locale.."/"..index
235       
236       if (FileUtil.fileExists(destfile) or
237           os.execute(string.format("wget %s -q -N -O %s",
238                                    FileUtil.quoteFile(string.format(url_format, index)),
239                                    FileUtil.quoteFile(destfile))) == 0) and searchFile(destfile, "<td id=\"filecontent\">") > 0 then
240         local file = io.open(FileUtil.fileName(destfile), "r")
241         if file then
242           local data = correctText(file:read("*a"))
243           io.close(file)
244           
245           local name, desc, req, faction, level, begin_index, begin_name, ends_index, end_name
246           name, data = select(3, string.find(data, "</h3><h3>%s*([^\n]-)%s*</h3>(.*)"))
247           desc, data = select(3, string.find(data or "", "<h2>.-</h2>%s*<blockquote>%s*(.-)%s*</blockquote>(.*)"))
248           req, data = select(3, string.find(data or "", "<h2>.-</h2>%s*<blockquote>%s*(.-)%s*</blockquote>(.*)"))
249           
250           local obj_table, data2 = select(3, string.find(data or "", "^%s-<table>(.-)</table>(.*)"))
251           data = data2 or data
252           
253           if obj_table then
254             string.gsub(obj_table, "<a href=\"/db/(.-)/.-%-id(%d-)\">%s-(.-)%s-</a>", function (t, index, name)
255               index = tonumber(index)
256               if index and name ~= "" then
257                 if t == "items" then
258                   local i = getItem(index)
259                   i.quest = true
260                   i.name[locale] = i.name[locale] or name
261                   print("QUEST ITEM: "..name)
262                 elseif t == "mobs" then
263                   local n = getNPC(index)
264                   n.quest = true
265                   n.name[locale] = n.name[locale] or name
266                   print("QUEST_MONSTER: "..name)
267                 end
268               end
269             end)
270           end
271           
272           faction = preFix(select(3, string.find(data or "", ">([^\n]-)</div><strong>Faction")), ">(.*)")
273           level = tonumber(preFix(select(3, string.find(data or "", ">([^\n]-)</div><strong>Level")), ">(.*)"))
274           
275           local chunk = preFix(select(3, string.find(data or "", "href=\"(.-)</a></div><strong>Begins")), "href=\"(.*)")
276           begin_id = tonumber(preFix(select(3, string.find(chunk or "", "-id([%d]+)\"")), "-id(.*)"))
277           begin_name = preFix(select(3, string.find(chunk or "", ">([^\n]+)$")), ">(.*)")
278           chunk = preFix(select(3, string.find(data or "", "href=\"(.-)</a></div><strong>Ends")), "href=\"(.*)")
279           end_id = tonumber(preFix(select(3, string.find(chunk or "", "-id([%d]+)\"")), "-id(.*)"))
280           end_name = preFix(select(3, string.find(chunk or "", ">([^\n]+)$")), ">(.*)")
281           
282           chunk = select(3, string.find(data or "", "<ol>(.-)</ol>"))
283           
284           if chunk then
285             local map = {}
286             local pos = 1
287             string.gsub(chunk, "<li(.-)</li>", function (chunk)
288               local id = select(3, string.find(chunk, "%[%d+%].-%-id(%d+)/"))
289               id = tonumber(id)
290               
291               if id then
292                 map[pos] = id
293                 pos = pos + 1
294               end
295             end)
297             
298             for i = 1,#map-1 do
299               local before = getQuest(i)
300               local after = getQuest(i+1)
301               
302               local before_id, after_id = map[i], map[i+1]
303               
304               if before_id and after_id then
305                 before.next = after_id
306                 after.prev = before_id
307               end
308             end
309           end
310           
311           print()
312           
313           print("--- Quest "..locale.."/"..index.." ---")
314           print("NAME:    "..htmlToText(name or "???"))
315           print("DESC:    "..htmlToText(desc or "???"))
316           print("REQ:     "..htmlToText(req or "???"))
317           print("FACTION: "..htmlToText(faction or "???"))
318           print("LEVEL:   "..(level or "???"))
319           print("BEGIN:   "..htmlToText((begin_name or "???").." (#"..(begin_id or "???")..")"))
320           print("END:     "..htmlToText((end_name or "???").." (#"..(end_id or "???")..")"))
321           
322           if name and name ~= "" and level then
323             local q = getQuest(index)
324             q.name[locale] = name
325             q.level = level
326             if req then q.hash[locale] = hashString(req) end
327             
328             if faction == "Alliance" then
329               q.faction[1] = true
330             elseif faction == "Horde" then
331               q.faction[2] = true
332             elseif faction == "N/A" then
333               -- Don't know who the quest is for, factions will be added if we've seen someone do the quest.
334             else
335               print("!!!!!!!!!!!", "UNKNOWN FACTION", faction)
336               assert(false)
337             end
338             
339             if begin_id and begin_name and begin_name ~= "" then
340               local n = getNPC(begin_id)
341               n.quest = true
342               n.name[locale] = begin_name
343               q.begin = begin_id
344             end
345             
346             if end_id and end_name and end_name ~= "" then
347               local n = getNPC(end_id)
348               n.quest = true
349               n.name[locale] = end_name
350               q.finish = end_id
351             end
352             
353             failed = false
354           end
355         end
356       end
357     end
358     
359     if not failed then
360       failures = 0
361     else
362       failures = failures + 1
363     end
364     
365     index = index + 1
366   end
369 --downloadQuests()
370 downloadItems()
371 downloadNPCs()
373 save()