/scripts/srcupdatecheck

https://bitbucket.org/kimoto/sushi · #! · 146 lines · 124 code · 22 blank · 0 comment · 0 complexity · 3d6c234a39941a815bd9ecbf05012bac MD5 · raw file

  1. #!/usr/bin/python
  2. # coding=utf8
  3. # srcupdatecheck v13 - part of
  4. # NemRun v1.8.6 - john@pointysoftware.net, 07/25/2012
  5. # Copyright 2012 john@pointysoftware.net
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. import time
  17. import sys
  18. import xml.dom.minidom
  19. import re
  20. gSteamAPI = 'https://api.steampowered.com'
  21. # This supports Python 2.4+ and 3.0+, which requires a few tricks,
  22. # and different libraries
  23. if (sys.hexversion < 0x03000000):
  24. gPy3k = False
  25. import urllib
  26. import urllib2
  27. else:
  28. gPy3k = True
  29. import urllib.request
  30. import urllib.parse
  31. if not len(sys.argv) == 2:
  32. print("Usage: ./srcupdatecheck /path/to/steam.inf")
  33. sys.exit(-1)
  34. #
  35. # Steam API Call
  36. #
  37. def SteamAPICall(path, rawargs = {}):
  38. args = rawargs
  39. args['format'] = 'xml'
  40. if gPy3k:
  41. args = '?%s' % (urllib.parse.urlencode(args))
  42. else:
  43. args = '?%s' % (urllib.urlencode(args))
  44. url = "%s/%s/%s" % (gSteamAPI, path, args)
  45. try:
  46. if gPy3k:
  47. raw = urllib.request.urlopen(url).read().decode()
  48. else:
  49. raw = urllib2.urlopen(url).read()
  50. except Exception:
  51. print("!! API Call failed\n\tURL:\t'%s'" % (url))
  52. return False
  53. try:
  54. dom = xml.dom.minidom.parseString(raw)
  55. except Exception:
  56. print("!! API Call - Failed to parse XML result\n\tURL:\t'%s'\n=== Raw ===\n%s\n===========" % (url, raw))
  57. return False
  58. response = dom.getElementsByTagName('response')
  59. if not len(response):
  60. return False
  61. ret = {}
  62. for c in response[0].childNodes:
  63. if c.nodeType == xml.dom.minidom.Node.ELEMENT_NODE:
  64. if not len(c.childNodes):
  65. ret[c.nodeName] = ""
  66. elif c.childNodes[0].data.lower() == "true":
  67. ret[c.nodeName] = True
  68. elif c.childNodes[0].data.lower() == "false":
  69. ret[c.nodeName] = False
  70. else:
  71. ret[c.nodeName] = c.childNodes[0].data
  72. print("\t -- API Call[%s: %s]\n\t\t%s" % (path, rawargs, ret))
  73. return ret
  74. # 1 Up to date, 0 not, -1 call failed
  75. # Note that the json returns 'version_is_listable', but valve never uses this,
  76. # optional updates don't bump their version # :(
  77. def RunCheck(no, appid, ver):
  78. call = SteamAPICall('ISteamApps/UpToDateCheck/v0001', { 'appid': appid, 'version': ver })
  79. if not call or call['success'] != True:
  80. print("[%u] !! API Call did not succeed\n\tRaw:\t%s" % (no, call))
  81. return -1
  82. if call['up_to_date']:
  83. print("[%u] API returned up to date!" % (no))
  84. return 1
  85. else:
  86. print("[%u] API returned out of date - Version %s vs %s" % (no, ver.replace('.', ''), call['required_version']))
  87. #
  88. # Read PatchVersion from provided steam.inf
  89. #
  90. try:
  91. steaminf = open(sys.argv[1])
  92. except IOError:
  93. print("File \"%s\" does not exist!" % sys.argv[1])
  94. sys.exit(-1)
  95. infblob = steaminf.read()
  96. verre = re.search('PatchVersion=([^\r\n]+)', infblob)
  97. appre = re.search('appID=([^\r\n]+)', infblob)
  98. prodre = re.search('ProductName=([^\r\n]+)', infblob)
  99. if not (verre and appre and prodre):
  100. print("Invalid steam.inf file.")
  101. sys.exit(-1)
  102. ver = verre.group(1)
  103. game = prodre.group(1)
  104. appid = appre.group(1)
  105. print("Found patch version: %s, game: %s, appid: %s" % (ver,game,appid))
  106. # According to Tony, this API call can sometimes return out of date incorrectly (yay!)
  107. # So we'll keep our stupid try-multiple-times logic
  108. lastattempt = -1
  109. attempt = 1
  110. while True:
  111. ret = RunCheck(attempt, appid, ver);
  112. if (ret != -1):
  113. if (ret == lastattempt):
  114. if (ret == 1):
  115. print("Confirmed up to date [%u requests]" % (attempt))
  116. sys.exit(0)
  117. else:
  118. print("Confirmed out of date [%u requests]" % (attempt))
  119. sys.exit(7)
  120. else:
  121. # In the case where we're chain-failing for some reason, don't hammer the API
  122. time.sleep(5)
  123. lastattempt = ret
  124. attempt += 1