PageRenderTime 55ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/mzhelper.py

https://bitbucket.org/skarrok/mzhelper
Python | 419 lines | 395 code | 4 blank | 20 comment | 0 complexity | 57c8e85fca08bf8d71b878465815fa91 MD5 | raw file
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # MediaZona Helper
  5. # Copyright (C) 2008 by skarrok <skarrok.h@gmail.com>
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. #
  20. import httplib, getopt, sys, re
  21. from urlparse import urlparse
  22. from urllib import urlencode
  23. #from os import access, R_OK, F_OK
  24. import os
  25. import stat
  26. import mimetypes
  27. import mimetools
  28. MZHOST = 'www.mediazona.ru'
  29. UPLOADHOST = 'xxx.mediazona.ru'
  30. USERAGENT = 'Opera/9.60 (X11; Linux i686; U; ru) Presto/2.1.1'
  31. CHUNK_SIZE = 65536
  32. class MZ:
  33. def __init__(self, login='', passwd=''):
  34. self.mzhost = 'mediazona.ru'
  35. self.mzuploadhost = 'xxx.mediazona.ru'
  36. self.useragent = 'Opera/9.60 (X11; Linux i686; U; ru) Presto/2.1.1'
  37. self.chunksize = 65536
  38. self.headers = {'User-Agent': self.useragent,
  39. 'Host': self.mzhost,
  40. 'Accept': '*/*',
  41. 'Connection': 'Keep-Alive'}
  42. self.links = []
  43. self.loginpath = '/serv/login/'
  44. self.login = login
  45. self.passwd = passwd
  46. self.phpsessid = ''
  47. self.chiper = ''
  48. self.keypat = re.compile('key="[0-9]{6}"')
  49. self.votedurl = '/change/exchange/serv/voted/?key='
  50. self.voteurl = '/change/exchange/serv/vote/?key='
  51. self.attrpage = ''
  52. def authorize(self):
  53. conn = httplib.HTTPConnection(self.mzhost)
  54. headers = self.headers.copy()
  55. headers.update({'Content-type': 'application/x-www-form-urlencoded; charser=utf-8',
  56. 'X-Requested-With': 'XMLHttpRequest',
  57. 'Referer': 'http://' + self.mzhost})
  58. params = urlencode({'mode': 'login',
  59. 'login': self.login,
  60. 'passwd': self.passwd,
  61. 'remember': 'on'})
  62. conn.request('POST', self.loginpath, params, headers)
  63. resp = conn.getresponse()
  64. respcookie = resp.getheader('Set-Cookie')
  65. self.phpsessid = respcookie.split(' ')[0][:-1]
  66. if self.login and self.passwd:
  67. try:
  68. respread = resp.read()
  69. if respread.split(' ')[3] == '1,':
  70. self.chiper = respcookie.split(' ')[2][:-1]
  71. print >> sys.stderr, 'Authorisation: OK'
  72. else:
  73. print >> sys.stderr, 'Authorisation: failed!'
  74. except LookupError.IndexError:
  75. print 'Authorisation: failed!'
  76. conn.close()
  77. def get_temp_link(self, path):
  78. headers = self.headers.copy()
  79. conn = httplib.HTTPConnection(self.mzhost)
  80. conn.request('GET', path, '', headers)
  81. resp = conn.getresponse()
  82. dwnpage = resp.read()
  83. respheaders = resp.getheader('Set-Cookie')
  84. dwncookie = respheaders.split(' ')[2][:-1]
  85. conn.close()
  86. headers.update({'Cookie': dwncookie,
  87. 'Referer': self.mzhost + path})
  88. conn = httplib.HTTPConnection(self.mzhost)
  89. conn.request('GET', path, '', headers)
  90. resp = conn.getresponse()
  91. conn.close()
  92. headers = {}
  93. return resp.getheader('location')+'\n'
  94. def get_temp_links(self):
  95. return map(self.get_temp_link, self.links)
  96. def set_rating_up(self, path):
  97. headers = self.headers.copy()
  98. headers.update({'X-Requested-With': 'XMLHttpRequest',
  99. 'Cookie': self.phpsessid + '; ' + self.chiper,
  100. 'Referer': 'http://' + self.mzhost + path})
  101. conn = httplib.HTTPConnection(self.mzhost)
  102. conn.request('GET', self.votedurl + path[21:-1], '', headers)
  103. dwnpage = conn.getresponse().read()
  104. conn.close()
  105. res = self.keypat.search(dwnpage)
  106. if not res:
  107. print >> sys.stderr, '\tSet Rating: failed!'
  108. return
  109. key=dwnpage[res.start():res.end()][5:-1]
  110. del dwnpage
  111. if key.isdigit():
  112. conn = httplib.HTTPConnection(self.mzhost)
  113. conn.request('GET', self.voteurl + key + '&vote=1', '', headers)
  114. tmp = conn.getresponse().read().strip()[4:-5].split(',')[0::2]
  115. if tmp[0].split(' ')[1] == '1':
  116. print >> sys.stderr, '\tSet Rating: OK, new', tmp[1]
  117. conn.close()
  118. def check_link(self, path):
  119. conn = httplib.HTTPConnection(self.mzhost)
  120. conn.request('GET', path, '', self.headers)
  121. self.attrpage = conn.getresponse().read()
  122. conn.close()
  123. #if self.attrpage.find('????????????? ???? ?? ??????') != -1:
  124. if '????????????? ???? ?? ??????' in self.attrpage:
  125. print >> sys.stderr, 'File not found:', 'http://mediazona.ru/' + path
  126. self.attrpage = ''
  127. return (False,)
  128. return True, self.get_attr_link()
  129. def check_links(self):
  130. self.links = filter(self.check_link, self.links)
  131. def set_links(self, links):
  132. self.links = map(lambda x: urlparse(x).path, links)
  133. def get_links(self):
  134. return map(lambda x: 'http://' + self.mzhost + x, self.links)
  135. def get_paths(self):
  136. return self.links
  137. def get_attr_link(self):
  138. return parsepage(self.attrpage, '<dt>????????:</dt><dd>', '<'), parsepage(self.attrpage, '<dt>??????:</dt><dd>', '<')
  139. def parsepage(where, what, stopchar):
  140. tmp = where.find(what) + len(what)
  141. i = tmp - 1
  142. for x in where[tmp:]:
  143. i += 1
  144. if x == stopchar:
  145. return where[tmp:i]
  146. # for i in xrange(len(where)):
  147. # if where[i] == '<':
  148. # print >> sys.stderr, 'File:', where[:i]
  149. # break
  150. # for i, c in enumerate(where):
  151. # if c == '<':
  152. # print >> sys.stderr, 'File:', where[:i]
  153. class progressBar:
  154. ''' Creates a text-based progress bar. Call the object with the `print'
  155. command to see the progress bar, which looks something like this:
  156. [=======> 22% ]
  157. You may specify the progress bar's width, min and max values on init.
  158. '''
  159. def __init__(self, minValue = 0, maxValue = 100, totalWidth=80):
  160. self.progBar = '[]'
  161. self.oldprogBar = ''
  162. self.min = minValue
  163. self.max = maxValue
  164. self.span = maxValue - minValue
  165. self.width = totalWidth
  166. self.amount = 0
  167. self.updateAmount(0)
  168. def updateAmount(self, newAmount = 0):
  169. if newAmount < self.min: newAmount = self.min
  170. if newAmount > self.max: newAmount = self.max
  171. self.amount = newAmount
  172. diffFromMin = float(self.amount - self.min)
  173. if self.span == 0:
  174. percentDone = 0
  175. else:
  176. percentDone = (diffFromMin / float(self.span)) * 100.0
  177. percentDone = int(round(percentDone))
  178. allFull = self.width - 2
  179. numHashes = (percentDone / 100.0) * allFull
  180. numHashes = int(round(numHashes))
  181. if numHashes == 0:
  182. self.progBar = '[>%s]' % (' '*(allFull-1))
  183. elif numHashes == allFull:
  184. self.progBar = '[%s]' % ('='*allFull)
  185. else:
  186. self.progBar = '[%s>%s]' % ('='*(numHashes-1),
  187. ' '*(allFull-numHashes))
  188. percentPlace = (len(self.progBar) / 2) - len(str(percentDone))
  189. percentString = str(percentDone) + '%'
  190. self.progBar = ''.join([self.progBar[0:percentPlace], percentString,
  191. self.progBar[percentPlace+len(percentString):]
  192. ])
  193. def __str__(self):
  194. return str(self.progBar)
  195. def __call__(self, value):
  196. #if self.progBar != self.oldprogBar:
  197. #self.oldprogBar = self.progBar
  198. print '\r',
  199. self.updateAmount(value)
  200. sys.stdout.write(str(self))
  201. sys.stdout.flush()
  202. def get_content_type(filename):
  203. return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
  204. def send_data(v_vars, v_files, boundary, sock=None):
  205. l = 0
  206. for (k, v) in v_vars:
  207. buffer=''
  208. buffer += '--%s\r\n' % boundary
  209. buffer += 'Content-Disposition: form-data; name="%s"\r\n' % k
  210. buffer += '\r\n'
  211. buffer += v + '\r\n'
  212. if sock:
  213. sock.send(buffer)
  214. l += len(buffer)
  215. for (k, v) in v_files:
  216. fd = v
  217. file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
  218. nchunks = int(file_size/CHUNK_SIZE)
  219. pbar = progressBar(0, nchunks, 77)
  220. name = fd.name.split('/')[-1]
  221. if isinstance(name, unicode):
  222. name = name.encode('UTF-8')
  223. buffer=''
  224. buffer += '--%s\r\n' % boundary
  225. buffer += 'Content-Disposition: form-data; name="%s"; filename="%s"\r\n' \
  226. % (k, name)
  227. buffer += 'Content-Type: %s\r\n' % get_content_type(name)
  228. buffer += 'Content-Length: %s\r\n' % file_size
  229. buffer += '\r\n'
  230. l += len(buffer)
  231. if sock:
  232. sock.send(buffer)
  233. if hasattr(fd, 'seek'):
  234. fd.seek(0)
  235. i = 0
  236. pbar(i)
  237. while True:
  238. chunk = fd.read(CHUNK_SIZE)
  239. if not chunk: break
  240. sock.send(chunk)
  241. pbar(i)
  242. i += 1
  243. l += file_size
  244. buffer='\r\n'
  245. buffer += '--%s--\r\n' % boundary
  246. buffer += '\r\n'
  247. if sock:
  248. sock.send(buffer)
  249. l += len(buffer)
  250. return l
  251. def uploadfile(file, chiper):
  252. headers = {'User-Agent': USERAGENT,
  253. 'Host': MZHOST,
  254. 'Accept': '*/*',
  255. 'Connection': 'Keep-Alive',
  256. 'Cookie': chiper}
  257. conn = httplib.HTTPConnection(MZHOST)
  258. conn.request('GET', '/change/exchange/upload/', '', headers)
  259. dwnpage = conn.getresponse().read()
  260. conn.close()
  261. tustas_identifier = parsepage(dwnpage, 'TUSTAS_IDENTIFIER" value="', '"')
  262. max_file_size = parsepage(dwnpage, 'MAX_FILE_SIZE" value="', '"')
  263. conn = httplib.HTTPConnection(MZHOST)
  264. conn.request('GET', '/change/exchange/serv/addupload-new/', '', headers)
  265. guid = conn.getresponse().read().split(',')[0][11:-1]
  266. conn.close()
  267. conn = httplib.HTTPConnection(UPLOADHOST)
  268. conn.putrequest('POST', '/uploader/?idsx=' + tustas_identifier, True)
  269. vars = [('TUSTAS_IDENTIFIER', tustas_identifier),
  270. ('MAX_FILE_SIZE', max_file_size),
  271. ('part', '6'),
  272. ('folder', ''),
  273. ('descr', 'tz'),
  274. ('tags', 'mz'),
  275. ('action', 'upload'),
  276. ('guid', guid)]
  277. files = [('filenames[]', open(file))]
  278. boundary = mimetools.choose_boundary()
  279. l = send_data(vars, files, boundary)
  280. conn.putheader('Content-Type', 'multipart/form-data; boundary=' + boundary)
  281. conn.putheader('Content-length', str(l))
  282. conn.putheader('Host', UPLOADHOST)
  283. conn.putheader('Referer', 'mediazona.ru/change/exchange/upload/')
  284. conn.endheaders()
  285. l = send_data(vars, files, boundary, conn)
  286. status = conn.getresponse().read()
  287. status = status.split(',')[0].split(' ')[3][1:-1]
  288. conn.close()
  289. if status == 'OK': return True
  290. return False
  291. def usage():
  292. print sys.argv[0] + ' V0.04 MediaZona Helper'
  293. print 'Usage: ' + sys.argv[0] + ' [OPTIONS]'
  294. print '\tWrite me!'
  295. def main():
  296. try:
  297. opts, args = getopt.getopt(sys.argv[1:], 'hvri:o:l:p:', ['help',
  298. 'verbose',
  299. 'rate',
  300. 'input-file=',
  301. 'output-file=',
  302. 'login=',
  303. 'passwd='])
  304. except getopt.GetoptError, msg:
  305. print >> sys.stderr, 'Getopt Error:', msg
  306. usage()
  307. sys.exit(2)
  308. outputfile = False
  309. inputfile = False
  310. verbose = False
  311. rate = False
  312. login = False
  313. passwd = False
  314. upload = False
  315. for o, a in opts:
  316. if o in ('-v', '--verbose'):
  317. verbose = True
  318. if o in ('-h', '--help'):
  319. usage()
  320. sys.exit()
  321. if o in ('-o', '--output-file'):
  322. outputfile = a
  323. if o in ('-i', '--input-file'):
  324. inputfile = a
  325. if o in ('-r', '--rate'):
  326. rate = True
  327. if o in ('-l', '--login'):
  328. login = a
  329. if o in ('-p', '--passwd'):
  330. passwd = a
  331. try:
  332. if inputfile:
  333. urllist = open(inputfile, 'r')
  334. else:
  335. usage()
  336. sys.exit()
  337. if outputfile:
  338. workfile = open(outputfile, 'w')
  339. else:
  340. workfile = sys.stdout
  341. mz = MZ(login, passwd)
  342. mz.authorize()
  343. links = filter(lambda x: bool(x), [line.strip() for line in urllist.readlines()])
  344. mz.set_links(links)
  345. for path in mz.get_paths():
  346. tmp = mz.check_link(path)
  347. if tmp[0]:
  348. if rate and login and passwd:
  349. print >> sys.stderr, 'File:', tmp[1][0]
  350. print >> sys.stderr, '\tSize:', tmp[1][1]
  351. mz.set_rating_up(path)
  352. elif not rate and login and passwd:
  353. print >> sys.stderr, 'File:', tmp[1][0]
  354. print >> sys.stderr, '\tSize:', tmp[1][1]
  355. mz.set_rating_up(path)
  356. templink = mz.get_temp_link(path)
  357. #os.popen("wget --content-dispositioin -c %s" % templink)
  358. workfile.write(templink)
  359. else:
  360. print >> sys.stderr, 'File:', tmp[1][0]
  361. print >> sys.stderr, '\tSize:', tmp[1][1]
  362. templink = mz.get_temp_link(path)
  363. #os.popen("wget --content-dispositioin -c %s" % templink)
  364. workfile.write(templink)
  365. urllist.close()
  366. workfile.close()
  367. print >> sys.stderr, 'Done!'
  368. except IOError, msg:
  369. print >> sys.stderr, 'IOError', msg
  370. sys.exit(2)
  371. except httplib.HTTPException, msg:
  372. print >> sys.stderr, 'HTTP Error', msg
  373. sys.exit(2)
  374. except KeyboardInterrupt:
  375. print >> sys.stderr, '\nManually stopped!'
  376. sys.exit(2)
  377. if __name__ == '__main__':
  378. main()