├── src ├── __init__.py ├── main.py ├── downloader.py ├── soap.py ├── model.py ├── view.py └── chomikbox.py ├── MANIFEST ├── chomik_downloader ├── .project ├── .pydevproject ├── README └── setup.py /src/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | README 2 | chomik_downloader 3 | setup.py 4 | src/__init__.py 5 | src/main.py 6 | src/downloader.py 7 | src/chomikbox.py 8 | src/view.py 9 | src/model.py 10 | src/soap.py 11 | -------------------------------------------------------------------------------- /chomik_downloader: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | try: 6 | import chomikdownloader.main 7 | chomikdownloader.main.start() 8 | #raise ImportError 9 | except ImportError, e: 10 | import src.main 11 | src.main.start() 12 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | chomik_downloader 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | /chomik_downloader/src 7 | 8 | python 2.7 9 | Default 10 | 11 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Program do pobierania plikow z wlasnego konta na chomikuj.pl 2 | 3 | INSTALACJA: 4 | Potrzebny jest python2.* (najlepiej 2.6 lub 2.7) oraz system Linux 5 | Aby zainstalowac skrypt odpalamy polecenie (z uprawnieniami administratora): 6 | python setup.py install 7 | Jesli nie mozemy zdobyc praw administratora mozemy uzywac programu bez instalacji. Wtedy uruchamiamy plik main.py z katalogu src. 8 | 9 | PRZYKŁAD UŻYCIA: 10 | Wypisanie "helpa": 11 | chomik_downloader -h 12 | 13 | Pobranie zawartoscie katalogu "/Prywatne/katalog1" na chomikuj.pl do "/tmp" 14 | chomik_downloader "/Prywatne/katalog1" "/tmp" 15 | 16 | 5 watkow pobierania 17 | chomik_downloader -t 5 "/Prywatne/katalog1" "/tmp" 18 | 19 | Podanie login 20 | chomik_downloader -l login_na_chomikuj.pl -t 5 "/Prywatne/katalog1" "/tmp" 21 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | import sys 3 | import os 4 | 5 | if sys.platform.startswith('win'): 6 | import py2exe 7 | 8 | setup(name='chomikDownloader', 9 | version='0.1.2', 10 | author='adam_gr', 11 | author_email='adam_gr [at] gazeta.pl', 12 | description='Downloads files from your account chomikuj.pl', 13 | package_dir = {'chomikdownloader' : 'src'}, 14 | packages = ['chomikdownloader'], 15 | options = {"py2exe" : { 16 | "compressed" : True, 17 | "ignores" : ["email.Iterators", "email.Generator"], 18 | "bundle_files" : 1 19 | }, 20 | "sdist" : { 21 | 'formats': 'zip' 22 | } 23 | }, 24 | scripts = ['chomik_downloader'], 25 | console = ['chomik_downloader'], 26 | zipfile = None 27 | ) 28 | 29 | -------------------------------------------------------------------------------- /src/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | ''' 4 | Created on 25-08-2012 5 | 6 | @author: adam 7 | ''' 8 | import downloader 9 | import sys 10 | import getopt 11 | 12 | def usage(): 13 | print 'Użycie programu:' 14 | print 'python', sys.argv[0], '[-h|--help] [-t|--threads] [-l|--login nazwa_chomika] [-p|--password haslo chomika] "katalog_na_chomikuj" "katalog_lokalny"\n' 15 | print '-h,--help\t\t pokazuje pomoc programu' 16 | print '-l,--login\t\t login/nazwa_uzytkownika do chomika' 17 | print '-p,--password\t\t haslo do chomika. Przyklad:', 18 | print 'python', sys.argv[0], '-l nazwa_chomika -p haslo "/katalog1/katalog2/katalog3" "/home/nick/Dokumenty/"' 19 | print '-t, --threads\t\t liczba watkow (ile plikow jest jednoczescnie wysylanych). Przyklad: ', 20 | print 'python', sys.argv[0], '-t 5 "/katalog1/katalog2/katalog3" "/home/nick/Dokumenty"' 21 | 22 | 23 | def start(): 24 | try: 25 | opts, args = getopt.getopt(sys.argv[1:], 'hl:p:t:d', ['help','login', 'password','threads', 'debug']) 26 | except Exception, e: 27 | print 'Przekazano niepoprawny parametr' 28 | print e 29 | usage() 30 | sys.exit(2) 31 | 32 | if len(args) != 2: 33 | usage() 34 | sys.exit() 35 | 36 | login = None 37 | password = None 38 | threads = 1 39 | debug = False 40 | for opt, arg in opts: 41 | if opt in ('-h', '--help'): 42 | usage() 43 | sys.exit() 44 | elif opt in ('-l', '--login'): 45 | login = arg 46 | elif opt in ('-p', '--password'): 47 | password = arg 48 | elif opt in ('-t', '--threads'): 49 | threads = int(arg) 50 | elif opt in ('-d', '--debug'): 51 | debug = True 52 | d = downloader.Downloader(login, password, debug = debug, threads = threads) 53 | d.download_folder(args[0], args[1]) 54 | 55 | if __name__ == '__main__': 56 | start() 57 | -------------------------------------------------------------------------------- /src/downloader.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on 15-08-2012 3 | 4 | @author: adam 5 | ''' 6 | import view 7 | import model 8 | from chomikbox import Chomik 9 | import getpass 10 | import re 11 | import traceback 12 | import sys 13 | import os 14 | import threading 15 | import urllib 16 | import urllib2 17 | import time 18 | 19 | class ReportHook(object): 20 | def __init__(self, rate_refresh, name, view): 21 | self.initiatlized = False 22 | self.rate_refresh = rate_refresh 23 | self.name = name 24 | self.view = view 25 | 26 | def update(self, count, block_size, total): 27 | if not self.initiatlized: 28 | self.initiatlized = True 29 | self.pb = view.ProgressBar(total=total, rate_refresh = self.rate_refresh, count = 0, name = self.name) 30 | self.view.add_progress_bar(self.pb) 31 | else: 32 | self.pb.update(block_size) 33 | self.view.update_progress_bars() 34 | 35 | def remove_pb(self): 36 | if self.initiatlized: 37 | self.view.update_progress_bars() 38 | self.view.delete_progress_bar(self.pb) 39 | 40 | 41 | 42 | class DownloaderThread(threading.Thread): 43 | def __init__(self, pool_sema, filepath, chomik_file_path, url, view_, model_): 44 | threading.Thread.__init__(self) 45 | self.pool_sema = pool_sema 46 | self.filepath = filepath 47 | self.chomik_file_path = chomik_file_path 48 | self.view = view_ 49 | self.model = model_ 50 | self.url = url 51 | self.daemon = True 52 | 53 | def run(self): 54 | self.model.add_notuploaded_normal(self.chomik_file_path) 55 | self.view.print_("Pobieranie:", self.filepath, '\r\n') 56 | pb = ReportHook(0.5, self.filepath, self.view) 57 | try: 58 | opener = urllib.FancyURLopener({}) 59 | opener.retrieve(self.url, self.filepath, pb.update ) 60 | except Exception, e: 61 | self.view.print_("Blad:", e) 62 | self.view.print_(self.filepath) 63 | pb.remove_pb() 64 | self.pool_sema.release() 65 | else: 66 | self.model.remove_notuploaded(self.chomik_file_path) 67 | self.model.add_uploaded(self.chomik_file_path) 68 | pb.remove_pb() 69 | self.view.print_("Pobrano:", self.filepath, '\r\n') 70 | self.pool_sema.release() 71 | 72 | 73 | 74 | 75 | class Downloader(object): 76 | def __init__(self, user = None, password = None, view_ = None, model_ = None, debug = False, threads = 1): 77 | if view_ == None: 78 | self.view = view.View() 79 | else: 80 | self.view = view_ 81 | if model_ == None: 82 | self.model = model.Model() 83 | else: 84 | self.model = model_ 85 | self.debug = debug 86 | self.user = user 87 | self.password = password 88 | maxthreads = threads 89 | self.pool_sema = threading.BoundedSemaphore(value=maxthreads) 90 | self.chomik = Chomik(self.view, self.model) 91 | if self.user == None: 92 | self.user = raw_input('Podaj nazwe uzytkownika:\n') 93 | if self.password == None: 94 | self.password = getpass.getpass('Podaj haslo:\r\n') 95 | self.view.print_('Logowanie') 96 | if not self.chomik.login(self.user, self.password): 97 | self.view.print_( 'Bledny login lub haslo' ) 98 | sys.exit(1) 99 | 100 | def download_folder(self, chomik_folder_path, disc_folder_path): 101 | folder_dom = self.chomik.chdirs(chomik_folder_path) 102 | if folder_dom == None: 103 | return 104 | chomik_folder_path = [self.user] + [i for i in chomik_folder_path.split("/") if i != ""] 105 | chomik_folder_path = "/" + "/".join(chomik_folder_path[:-1]) + "/" 106 | for folder_id, chomik_folder in self.chomik.get_next_folder(folders_dom=folder_dom): 107 | folder_path = os.path.join(disc_folder_path, chomik_folder[1:255]) 108 | chomik_path = chomik_folder_path + chomik_folder 109 | chomik_path = chomik_path.replace("//","/") 110 | if not os.path.exists( folder_path ): 111 | os.makedirs( folder_path ) 112 | self.__download_files_in_folder(folder_id, folder_path, chomik_path) 113 | while threading.active_count() > 1: 114 | time.sleep(1.) 115 | 116 | def __download_files_in_folder(self, folder_id, folder_path, chomik_path): 117 | for name, url in self.chomik.get_files_list(folder_id): 118 | filepath = os.path.join(folder_path, name) 119 | chomik_file_path = os.path.join(chomik_path, name) 120 | if self.model.in_uploaded(chomik_file_path): 121 | continue 122 | self.pool_sema.acquire() 123 | t = DownloaderThread(self.pool_sema, filepath, chomik_file_path, url, self.view, self.model) 124 | t.start() 125 | #t.run() 126 | 127 | 128 | if __name__ == "__main__": 129 | d = Downloader() 130 | d.download_folder("", "/tmp") 131 | -------------------------------------------------------------------------------- /src/soap.py: -------------------------------------------------------------------------------- 1 | from itertools import groupby 2 | from xml.dom.minidom import Document 3 | import xml.parsers.expat 4 | import copy 5 | 6 | 7 | class SOAP(object): 8 | def __init__(self): 9 | pass 10 | 11 | def soap_xml_to_dict(self, xml): 12 | return parse(xml) 13 | 14 | def soap_dict_to_xml(self, soap_dict, method): 15 | ''' 16 | method = i.e Auth 17 | ''' 18 | xml = dict2xml(soap_dict) 19 | text = xml.replace("", "") 20 | text = text.replace("", "") 21 | prefix = """""" 22 | prefix += "<" + method + ' xmlns="http://chomikuj.pl/"' + '>' 23 | suffix = "" 24 | suffix += """""" 25 | return prefix + text + suffix 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ################################################################### 35 | 36 | def dict2xml(xml_list): 37 | if type(xml_list) == list: 38 | return "".join([dict2xml(i) for i in xml_list]) 39 | elif type(xml_list) == tuple: 40 | return "<" + xml_list[0] + ">" + dict2xml(xml_list[1]) + "" 41 | else: 42 | return str(xml_list) 43 | 44 | 45 | ################################################################## 46 | 47 | __author__ = 'Martin Blech' 48 | __version__ = '0.1.dev' 49 | __license__ = 'MIT' 50 | 51 | class ParsingInterrupted(Exception): pass 52 | 53 | class DictSAXHandler: 54 | def __init__(self, 55 | item_depth=0, 56 | xml_attribs=True, 57 | item_callback=lambda *args: True, 58 | attr_prefix='@', 59 | cdata_key='#text', 60 | force_cdata=False): 61 | self.path = [] 62 | self.stack = [] 63 | self.data = None 64 | self.item = None 65 | self.item_depth = item_depth 66 | self.xml_attribs = xml_attribs 67 | self.item_callback = item_callback 68 | self.attr_prefix = attr_prefix; 69 | self.cdata_key = cdata_key 70 | self.force_cdata = force_cdata 71 | 72 | def startElement(self, name, attrs): 73 | self.path.append((name, attrs or None)) 74 | if len(self.path) > self.item_depth: 75 | self.stack.append((self.item, self.data)) 76 | attrs = dict((self.attr_prefix+key, value) 77 | for (key, value) in attrs.items()) 78 | self.item = self.xml_attribs and attrs or None 79 | self.data = None 80 | 81 | def endElement(self, name): 82 | if len(self.path) == self.item_depth: 83 | item = self.item 84 | if item is None: 85 | item = self.data 86 | should_continue = self.item_callback(self.path, item) 87 | if not should_continue: 88 | raise ParsingInterrupted() 89 | if len(self.stack): 90 | item, data = self.item, self.data 91 | self.item, self.data = self.stack.pop() 92 | if self.force_cdata and item is None: 93 | item = {} 94 | if item is not None: 95 | if data: 96 | item[self.cdata_key] = data 97 | self.push_data(name, item) 98 | else: 99 | self.push_data(name, data) 100 | else: 101 | self.item = self.data = None 102 | self.path.pop() 103 | 104 | def characters(self, data): 105 | if data.strip(): 106 | if not self.data: 107 | self.data = data 108 | else: 109 | self.data += data 110 | 111 | def push_data(self, key, data): 112 | if self.item is None: 113 | self.item = {} 114 | try: 115 | value = self.item[key] 116 | if isinstance(value, list): 117 | value.append(data) 118 | else: 119 | self.item[key] = [value, data] 120 | except KeyError: 121 | self.item[key] = data 122 | 123 | def parse(xml_input, *args, **kwargs): 124 | """Parse the given XML input and convert it into a dictionary. 125 | 126 | `xml_input` can either be a `string` or a file-like object. 127 | 128 | If `xml_attribs` is `True`, element attributes are put in the dictionary 129 | among regular child elements, using `@` as a prefix to avoid collisions. If 130 | set to `False`, they are just ignored. 131 | 132 | Simple example:: 133 | 134 | >>> doc = xmltodict.parse(\"\"\" 135 | ... 136 | ... 1 137 | ... 2 138 | ... 139 | ... \"\"\") 140 | >>> doc['a']['@prop'] 141 | u'x' 142 | >>> doc['a']['b'] 143 | [u'1', u'2'] 144 | 145 | If `item_depth` is `0`, the function returns a dictionary for the root 146 | element (default behavior). Otherwise, it calls `item_callback` every time 147 | an item at the specified depth is found and returns `None` in the end 148 | (streaming mode). 149 | 150 | The callback function receives two parameters: the `path` from the document 151 | root to the item (name-attribs pairs), and the `item` (dict). If the 152 | callback's return value is false-ish, parsing will be stopped with the 153 | :class:`ParsingInterrupted` exception. 154 | 155 | Streaming example:: 156 | 157 | >>> def handle(path, item): 158 | ... print 'path:%s item:%s' % (path, item) 159 | ... return True 160 | ... 161 | >>> xmltodict.parse(\"\"\" 162 | ... 163 | ... 1 164 | ... 2 165 | ... \"\"\", item_depth=2, item_callback=handle) 166 | path:[(u'a', {u'prop': u'x'}), (u'b', None)] item:1 167 | path:[(u'a', {u'prop': u'x'}), (u'b', None)] item:2 168 | 169 | """ 170 | handler = DictSAXHandler(*args, **kwargs) 171 | parser = xml.parsers.expat.ParserCreate() 172 | parser.StartElementHandler = handler.startElement 173 | parser.EndElementHandler = handler.endElement 174 | parser.CharacterDataHandler = handler.characters 175 | if hasattr(xml_input, 'read'): 176 | parser.ParseFile(xml_input) 177 | else: 178 | parser.Parse(xml_input, True) 179 | return handler.item 180 | 181 | if __name__ == '__main__': 182 | s = SOAP() 183 | print parse("""Ok5762328tmp_chomik1092fb999-6494-48b5-b6fd-859c1595f7ab""") 184 | print parse("""Ok5762328tmp_chomik1092fb999-6494-48b5-b6fd-859c1595f7ab""") 185 | print s.soap_xml_to_dict("""Ok5762328tmp_chomik1092fb999-6494-48b5-b6fd-859c1595f7ab""") 186 | Y = {'Body': {'client': [{'version': '2.0.4.3<', 'name': 'chomikbox'} ], 'ver': '4', 'name': 'tmp_chomik1', 'passHash': 'ba2e57cbd8546cffd7db6bfd4077758b'}} 187 | X = """""" 188 | user = "a" 189 | password = "b" 190 | example = {'ROOT':{'client':{'version':'2.0.4.3','name':'chomikbox' }, 'ver' : '4', 'name' : user, 'passHash': password}} 191 | example = [('ROOT',[('name' , user), ('passHash', password), ('ver' , '4'), ('client',[('name','chomikbox'),('version','2.0.4.3') ]) ])] 192 | #example = [('ROOT', [('client', 'w')])] 193 | #example = {'ROOT':{'client':{'version':'2.0.4.3','name':'chomikbox' }, 'ver' : '4', 'name' : 'tmp_chomik1', 'passHash': 'ba2e57cbd8546cffd7db6bfd4077758b'}} 194 | print dict2xml(example) 195 | print dict2xml(example) 196 | 197 | print s.soap_dict_to_xml(example, "Auth") 198 | -------------------------------------------------------------------------------- /src/model.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Author: Adam Grycner (adam_gr [at] gazeta.pl) 4 | # 5 | # Written: 12/11/2011 6 | # 7 | # Released under: GNU GENERAL PUBLIC LICENSE 8 | # 9 | # Ver: 0.4 10 | import os 11 | import threading 12 | import re 13 | import view 14 | import sys 15 | 16 | 17 | def change_coding(text): 18 | try: 19 | if type(text) == unicode: 20 | text = text.encode('utf-8') 21 | elif sys.platform.startswith('win'): 22 | text = text.decode('cp1250').encode('utf-8') 23 | except Exception, e: 24 | print e 25 | return text 26 | 27 | def singleton(cls): 28 | instances = {} 29 | def getinstance(): 30 | if cls not in instances: 31 | instances[cls] = cls() 32 | return instances[cls] 33 | return getinstance 34 | 35 | 36 | #@singleton 37 | class Model(object): 38 | 39 | def __init__(self): 40 | """ 41 | Wczytywanie danych z plikow uploaded.txt i notuploaded.txt 42 | """ 43 | self.view = view.View() 44 | self.lock = threading.Lock() 45 | ##synchronizacja zmiany katalogow w chomiku 46 | self.chdirs_lock = threading.Lock() 47 | self.notuploaded_file_name = 'notdownloaded.txt' 48 | self.uploaded_file_name = 'downloaded.txt' 49 | self.uploaded = [] 50 | self.notuploaded = [] 51 | 52 | if not os.path.exists(self.uploaded_file_name): 53 | open(self.uploaded_file_name, 'w').close() 54 | f = open(self.uploaded_file_name, 'r') 55 | self.uploaded = f.read().split('\n') 56 | self.uploaded = set([i.strip() for i in self.uploaded]) 57 | f.close() 58 | #TODO: tu stanowczo jakis test zrobic 59 | if not os.path.exists(self.notuploaded_file_name): 60 | open(self.notuploaded_file_name,"w").close() 61 | f = open(self.notuploaded_file_name,"r") 62 | files = [ i.strip() for i in f.readlines()] 63 | f.close() 64 | self.notuploaded_resume = [] 65 | self.notuploaded_normal = [] 66 | self.pending = [] 67 | 68 | for f in files: 69 | try: 70 | filepath, filename, folder_id, chomik_id, token, host, port, stamp = re.findall("([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)", f)[0] 71 | self.notuploaded_resume.append( (filepath, filename, folder_id, chomik_id, token, host, port, stamp) ) 72 | except IndexError, e: 73 | self.notuploaded_normal.append( f.strip() ) 74 | 75 | 76 | def _aux_remove_notuploaded_resume(self, filepath): 77 | filepath = change_coding(filepath) 78 | it = 0 79 | while it < len(self.notuploaded_resume): 80 | i = self.notuploaded_resume[it] 81 | if i[0] == filepath: 82 | self.notuploaded_resume.remove(i) 83 | it += 1 84 | 85 | def _aux_remove_notuploaded_normal(self, filepath): 86 | filepath = change_coding(filepath) 87 | it = 0 88 | while it < len(self.notuploaded_normal): 89 | i = self.notuploaded_normal[it] 90 | if i == filepath: 91 | self.notuploaded_normal.remove(i) 92 | it += 1 93 | 94 | def _aux_remove_pending(self, filepath): 95 | filepath = change_coding(filepath) 96 | it = 0 97 | while it < len(self.pending): 98 | i = self.pending[it] 99 | if i == filepath: 100 | self.pending.remove(i) 101 | it += 1 102 | 103 | def add_notuploaded_normal(self, filepath): 104 | """ 105 | Dodawanie informacji o filepath na liscie notuploaded i w pliku notuploaded.txt 106 | """ 107 | self.lock.acquire() 108 | filepath = change_coding(filepath) 109 | try: 110 | if not filepath in self.notuploaded_normal: 111 | self.notuploaded_normal.append(filepath) 112 | f = open(self.notuploaded_file_name,'a') 113 | f.write( filepath ) 114 | f.write('\r\n') 115 | f.close() 116 | finally: 117 | self.lock.release() 118 | 119 | def add_notuploaded_resume(self, filepath, filename, folder_id, chomik_id, token, host, port, stamp): 120 | """ 121 | Dodawanie informacji o filepath i danych do wznawiania na liscie notuploaded i w pliku notuploaded.txt 122 | """ 123 | self.lock.acquire() 124 | filepath = change_coding(filepath) 125 | try: 126 | #FIXME:danger 127 | self._aux_remove_notuploaded_resume(filepath) 128 | self._aux_remove_notuploaded_normal(filepath) 129 | self._save_notuploaded() 130 | self.notuploaded_resume.append( (filepath, filename, folder_id, chomik_id, token, host, port, stamp) ) 131 | f = open(self.notuploaded_file_name,'a') 132 | f.write(change_coding(filepath) + '\t') 133 | f.write(change_coding(filename) + '\t') 134 | f.write(str(folder_id) + '\t') 135 | f.write(str(chomik_id) + '\t') 136 | f.write(str(token) + '\t') 137 | f.write(str(host) + '\t') 138 | f.write(str(port) + '\t') 139 | f.write(str(stamp)) 140 | f.write('\r\n') 141 | f.close() 142 | finally: 143 | self.lock.release() 144 | 145 | def remove_notuploaded(self, filepath): 146 | """ 147 | Usuwanie filepath z listy notuploaded i z pliku notuploaded.txt 148 | """ 149 | self.lock.acquire() 150 | filepath = change_coding(filepath) 151 | try: 152 | #FIXME:danger 153 | self._aux_remove_notuploaded_resume(filepath) 154 | self._aux_remove_notuploaded_normal(filepath) 155 | self._save_notuploaded() 156 | finally: 157 | self.lock.release() 158 | 159 | def _save_notuploaded(self): 160 | """ 161 | Zapisanie do pliku nieudanych wyslan 162 | """ 163 | f = open(self.notuploaded_file_name,'w') 164 | for nu in self.notuploaded_resume: 165 | l = [ str(i) for i in list(nu)] 166 | f.write( change_coding('\t'.join(l)) ) 167 | f.write( '\r\n' ) 168 | for nu in self.notuploaded_normal: 169 | f.write( change_coding(nu) ) 170 | f.write( '\r\n' ) 171 | f.close() 172 | 173 | 174 | def get_notuploaded_resume(self): 175 | """ 176 | Zwraca liste plikow, ktore mozna wznowic 177 | """ 178 | return self.notuploaded_resume 179 | 180 | 181 | def add_uploaded(self, filepath): 182 | """ 183 | Dodanie filepath do listy plikow poprawnie wyslanych 184 | """ 185 | self.lock.acquire() 186 | filepath = change_coding(filepath) 187 | try: 188 | self.uploaded.add(filepath) 189 | f = open(self.uploaded_file_name,'a') 190 | f.write(filepath + '\r\n') 191 | f.close() 192 | finally: 193 | self.lock.release() 194 | 195 | 196 | def in_uploaded(self, filepath): 197 | """ 198 | Sprawdzanie, czy plik znajduje sie na liscie plikow wyslanych 199 | """ 200 | self.lock.acquire() 201 | filepath = change_coding(filepath) 202 | try: 203 | result = filepath in self.uploaded 204 | finally: 205 | self.lock.release() 206 | return result 207 | 208 | def add_to_pending(self, filepath): 209 | pass 210 | 211 | def remove_from_pending(self, filepath): 212 | self.lock.acquire() 213 | try: 214 | #FIXME:danger 215 | self._aux_remove_pending(filepath) 216 | #self.pending = [i for i in self.pending if i != filepath] 217 | finally: 218 | self.lock.release() 219 | 220 | def is_uploaded_or_pended_and_add(self, filepath): 221 | """ 222 | Sprawdza, cyz plik byl juz wyslany lub, czy jest przetwarzany. 223 | Jesli nie, to dodaje go do listy przetwarzanych 224 | """ 225 | self.lock.acquire() 226 | try: 227 | result1 = filepath in self.uploaded 228 | result2 = filepath in self.pending 229 | result = (result1 or result2) 230 | if (not result1) and (not result2): 231 | self.pending.append(filepath) 232 | finally: 233 | self.lock.release() 234 | return result 235 | 236 | def return_chdirlock(self): 237 | return self.chdirs_lock 238 | 239 | if __name__ == '__main__': 240 | m = Model() 241 | print m.add_uploaded('./tmp.txt') 242 | print m.is_uploaded_or_pended_and_add('./tmp.txt') 243 | print m.is_uploaded_or_pended_and_add('./tmp.txt') 244 | -------------------------------------------------------------------------------- /src/view.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Author: Adam (adam_gr [at] gazeta.pl) 4 | # 5 | # Written: 12/11/2011 6 | # 7 | # Released under: GNU GENERAL PUBLIC LICENSE 8 | # 9 | # Ver: 0.4 10 | 11 | import ctypes 12 | import sys 13 | import threading 14 | import time, math 15 | 16 | 17 | 18 | 19 | 20 | ############################################################################################################### 21 | if sys.platform.startswith('win'): 22 | SHORT = ctypes.c_short 23 | WORD = ctypes.c_ushort 24 | STD_OUTPUT_HANDLE = -11 25 | 26 | class COORD(ctypes.Structure): 27 | _fields_ = [('X', SHORT),('Y', SHORT)] 28 | 29 | class SMALL_RECT(ctypes.Structure): 30 | _fields_ = [("Left", ctypes.c_short), ("Top",ctypes.c_short), ("Right", ctypes.c_short), ("Bottom", ctypes.c_short)] 31 | 32 | class CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure): 33 | _fields_ = [("Size", COORD), ("CursorPosition", COORD), ("Attributes", ctypes.c_short), ("Window", SMALL_RECT), ("MaximumWindowSize", COORD)] 34 | 35 | class CONSOLE_CURSOR_INFO(ctypes.Structure): 36 | _fields_ = [('dwSize',ctypes.c_ulong), ('bVisible', ctypes.c_int)] 37 | 38 | hconsole = ctypes.windll.kernel32.GetStdHandle(-11) 39 | sbinfo = CONSOLE_SCREEN_BUFFER_INFO() 40 | csinfo = CONSOLE_CURSOR_INFO() 41 | to_int = lambda number, default: number and int(number) or default 42 | 43 | 44 | 45 | class ConsoleWin(object): 46 | def __init__(self): 47 | self.hconsole = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE) 48 | self.orig_sbinfo = CONSOLE_SCREEN_BUFFER_INFO() 49 | self.orig_csinfo = CONSOLE_CURSOR_INFO() 50 | ctypes.windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, ctypes.byref(self.orig_sbinfo)) 51 | ctypes.windll.kernel32.GetConsoleCursorInfo(hconsole, ctypes.byref(self.orig_csinfo)) 52 | 53 | def screen_buffer_info(self): 54 | sbinfo = CONSOLE_SCREEN_BUFFER_INFO() 55 | ctypes.windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, ctypes.byref(sbinfo)) 56 | return sbinfo 57 | 58 | def clear_line(self, param = 2): 59 | #clearing line 60 | #param == 1: Clear from begining of line to cursor position 61 | #param == 2: Clear entire line 62 | #else: Clear from cursor position to end of line 63 | mode = param and int(param) or 0 64 | sbinfo = self.screen_buffer_info() 65 | if mode == 1: # Clear from begining of line to cursor position 66 | line_start = COORD(0, sbinfo.CursorPosition.Y) 67 | line_length = sbinfo.Size.X 68 | elif mode == 2: # Clear entire line 69 | line_start = COORD(sbinfo.CursorPosition.X, sbinfo.CursorPosition.Y) 70 | line_length = sbinfo.Size.X - sbinfo.CursorPosition.X 71 | else: # Clear from cursor position to end of line 72 | line_start = sbinfo.CursorPosition 73 | line_length = sbinfo.Size.X - sbinfo.CursorPosition.X 74 | chars_written = ctypes.c_int() 75 | ctypes.windll.kernel32.FillConsoleOutputCharacterA(self.hconsole, ctypes.c_char(' '), line_length, line_start, ctypes.byref(chars_written)) 76 | ctypes.windll.kernel32.FillConsoleOutputAttribute(self.hconsole, sbinfo.Attributes, line_length, line_start, ctypes.byref(chars_written)) 77 | 78 | def move_cursor(self, x_offset=0, y_offset=0): 79 | #moving cursor to specific part of screen 80 | sbinfo = self.screen_buffer_info() 81 | new_pos = COORD( 82 | min(max(0, sbinfo.CursorPosition.X + x_offset), sbinfo.Size.X), 83 | min(max(0, sbinfo.CursorPosition.Y + y_offset), sbinfo.Size.Y) 84 | ) 85 | ctypes.windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos) 86 | 87 | def move_up(self, param): 88 | #moving up certain (param) number of lines 89 | self.move_cursor(y_offset = -to_int(param, 1)) 90 | 91 | def move_down(self, param): 92 | #moving down certain (param) number of lines 93 | self.move_cursor(y_offset = to_int(param, 1)) 94 | 95 | def prev_line(self): 96 | #moving to previous line on screen 97 | sbinfo = self.screen_buffer_info() 98 | new_pos = COORD( 99 | min(0, sbinfo.Size.X), 100 | min(max(0, sbinfo.CursorPosition.Y -1), sbinfo.Size.Y) 101 | ) 102 | ctypes.windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos) 103 | 104 | def next_line(self): 105 | #moving to next line on screen 106 | sbinfo = self.screen_buffer_info() 107 | new_pos = COORD( 108 | min(0, sbinfo.Size.X), 109 | min(max(0, sbinfo.CursorPosition.Y +1), sbinfo.Size.Y) 110 | ) 111 | ctypes.windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos) 112 | ############################################################################################################### 113 | else: 114 | #TODO: tutaj moznaby jakas nadklase tych konsol stworzyc 115 | class ConsoleUnix(object): 116 | def __init__(self): 117 | self.ESC = chr(27) 118 | 119 | def clear_line(self, param = 2): 120 | #clearing line 121 | #param == 1: Clear from begining of line to cursor position 122 | #param == 2: Clear entire line 123 | #else: Clear from cursor position to end of line 124 | mode = param and int(param) or 0 125 | if mode == 1: # Clear from begining of line to cursor position 126 | sys.stdout.write(self.ESC + '[1K') 127 | elif mode == 2: # Clear entire line 128 | sys.stdout.write(self.ESC + '[2K') 129 | else: # Clear from cursor position to end of line 130 | sys.stdout.write(self.ESC + '[0K') 131 | 132 | def move_cursor(self, x_offset=0, y_offset=0): 133 | #moving cursor to specific part of screen 134 | if x_offset >= 0: 135 | sys.stdout.write(self.ESC + '[%dC' % (x_offset) ) 136 | else: 137 | sys.stdout.write(self.ESC + '[%dD' % (-x_offset) ) 138 | if y_offset >= 0: 139 | sys.stdout.write(self.ESC + '[%dB' % (y_offset) ) 140 | else: 141 | sys.stdout.write(self.ESC + '[%dA' % (-y_offset) ) 142 | 143 | def move_up(self, param): 144 | #moving up certain (param) number of lines 145 | sys.stdout.write(self.ESC + '[%dA' % (param) ) 146 | 147 | def move_down(self, param): 148 | #moving down certain (param) number of lines 149 | sys.stdout.write(self.ESC + '[%dB' % (param) ) 150 | 151 | def prev_line(self): 152 | #moving to previous line on screen 153 | sys.stdout.write(self.ESC + '[1A' ) 154 | sys.stdout.write('\r' ) 155 | 156 | def next_line(self): 157 | #moving to next line on screen 158 | sys.stdout.write(self.ESC + '[1B' ) 159 | sys.stdout.write('\r' ) 160 | ############################################################################################################### 161 | def change_unit_bytes(value): 162 | if value < 1024: 163 | return (value, 'B') 164 | elif value < 1048576: 165 | return (value/1024., 'kB') 166 | elif value < 1024**3: 167 | return (value/1048576., 'MB') 168 | else: 169 | return (value/(1024.**3), 'GB') 170 | 171 | def change_unit_time(value): 172 | if value < 60: 173 | return (value, 's.') 174 | elif value < 60*60: 175 | return (value/60., 'min') 176 | else: 177 | return (value/3600., 'h.') 178 | 179 | class ProgressBar(object): 180 | def __init__(self, total = 100, rate_refresh = 0.5, count = 0, name = ""): 181 | """count - starting value""" 182 | self.name = name 183 | # Number of units to process 184 | self.total = total 185 | # Refresh rate in seconds 186 | self.rate_refresh = rate_refresh 187 | 188 | # dane progress bara 189 | self.meter_ticks = 20 190 | self.meter_division = float(self.total) / self.meter_ticks 191 | ############################## 192 | self.count = count 193 | #count, ktore bedzie wyswietlane na ekranie 194 | self.count_total = count 195 | #predkosc 196 | self.rate_current = 0.0 197 | self.rate_current_total = 0.0 198 | self.meter_value = int(self.count / self.meter_division) 199 | self.meter_value_total = int(self.count / self.meter_division) 200 | ############################# 201 | #time 202 | self.last_update = None 203 | #liczba jednostek od ostatniego odswiezenia predkosci 204 | self.rate_count = 0 205 | #ostatnie odswiezenie 206 | self.last_refresh = 0 207 | self.history_len = 10 208 | self.history = [None]*self.history_len 209 | self.history_index = 0 210 | self.lock = threading.Lock() 211 | 212 | 213 | def update(self, count): 214 | """ 215 | Update data of progress bar 216 | """ 217 | #rate_current 218 | #self.count 219 | # 220 | 221 | now = time.time() 222 | # Caclulate rate of progress 223 | rate = 0.0 224 | # Add count to Total 225 | self.count += count 226 | self.count = min(self.count, self.total) 227 | if self.last_update == None: 228 | self.last_update = now 229 | 230 | # Device Total by meter division 231 | value = int(self.count / self.meter_division) 232 | if value > self.meter_value: 233 | self.meter_value = value 234 | 235 | self.rate_count += count 236 | if now - self.last_update > 0.5: #FIXME 237 | self.history[self.history_index] = self.rate_count / float(now - self.last_update) 238 | self.history_index = (self.history_index + 1) % self.history_len 239 | hist = [i for i in self.history if i != None] 240 | self.rate_current = sum(hist)/float(len(hist)) 241 | self.rate_count = 0 242 | self.last_update = now 243 | ###MUTEXES 244 | self.update_to_display() 245 | 246 | 247 | def update_to_display(self): 248 | """ 249 | Actualize data to display 250 | """ 251 | #self.lock.acquire() 252 | #try: 253 | self.meter_value_total = self.meter_value 254 | self.count_total = self.count 255 | self.rate_current_total = self.rate_current 256 | #finally: 257 | # self.lock.release() 258 | 259 | def get_meter(self, **kw): 260 | """ 261 | Creating progress bar string 262 | """ 263 | #self.lock.acquire() 264 | #try: 265 | bar = '-' * self.meter_value_total 266 | pad = ' ' * (self.meter_ticks - self.meter_value_total) 267 | perc = (float(self.count_total) / self.total) * 100 268 | rate_current, unit = change_unit_bytes(self.rate_current_total) 269 | downloaded, unit_d = change_unit_bytes(self.count_total) 270 | total, unit_t = change_unit_bytes(self.total) 271 | if self.rate_current_total == 0: 272 | rest_time = float("inf") 273 | unit_time = '' 274 | else: 275 | rest_time, unit_time = change_unit_time( (self.total - self.count_total)/float(self.rate_current_total) ) 276 | 277 | #finally: 278 | # self.lock.release() 279 | return '[%s>%s] %d%% %.1f%s/sec %.1f%s/%.1f%s %.1f%s' % (bar, pad, perc, rate_current, unit, downloaded, unit_d, total, unit_t, rest_time, unit_time) 280 | 281 | ############################################################################################################### 282 | def create_console(): 283 | """Creating console object depending on operating system""" 284 | if sys.platform.startswith('win'): 285 | return ConsoleWin() 286 | else: 287 | return ConsoleUnix() 288 | 289 | def change_print_coding(text): 290 | if sys.platform.startswith('win'): 291 | try: 292 | text = text.decode('utf-8') 293 | except Exception: 294 | try: 295 | text = text.decode('cp1250') 296 | except Exception, e: 297 | pass 298 | return text 299 | 300 | def singleton(cls): 301 | instances = {} 302 | def getinstance(): 303 | if cls not in instances: 304 | instances[cls] = cls() 305 | return instances[cls] 306 | return getinstance 307 | 308 | 309 | #@singleton 310 | class View(object): 311 | """ 312 | View object (displaying informations) 313 | """ 314 | def __init__(self): 315 | self.lock = threading.Lock() 316 | self.progress_bars = [] 317 | self.console = create_console() 318 | self.last_update = time.time() 319 | 320 | def print_(self, *args): 321 | """ 322 | Print something on screen 323 | """ 324 | self.lock.acquire() 325 | try: 326 | self.last_update = time.time() 327 | self._wipe_progress_bars() 328 | for i in args: print change_print_coding(i), 329 | print 330 | self._show_progress_bars() 331 | sys.stdout.flush() 332 | finally: 333 | self.lock.release() 334 | 335 | def _wipe_progress_bars(self): 336 | """ 337 | Remove progress bar objects from screen 338 | """ 339 | for progress_bar in self.progress_bars: 340 | #TODO: kodowanie 341 | self.console.prev_line() 342 | self.console.clear_line(2) 343 | self.console.prev_line() 344 | self.console.clear_line(2) 345 | sys.stdout.flush() 346 | 347 | 348 | def _show_progress_bars(self): 349 | """ 350 | Show progress bar objects on screen 351 | """ 352 | for progress_bar in self.progress_bars: 353 | #TODO: kodowanie 354 | #sys.stdout.write( change_print_coding(progress_bar.name) ) 355 | print change_print_coding(progress_bar.name[-80:]), 356 | sys.stdout.write('\r\n') 357 | sys.stdout.write(progress_bar.get_meter()) 358 | sys.stdout.write('\r\n') 359 | sys.stdout.flush() 360 | 361 | 362 | def update_progress_bars(self): 363 | """ 364 | Redisplay progress bar objects 365 | """ 366 | #sprawdzic kiedy ostatnio byl aktualizowany ekran 367 | self.lock.acquire() 368 | try: 369 | now = time.time() 370 | if now - self.last_update > 0.5: 371 | self._wipe_progress_bars() 372 | self._show_progress_bars() 373 | sys.stdout.flush() 374 | self.last_update = time.time() 375 | finally: 376 | self.lock.release() 377 | 378 | 379 | def add_progress_bar(self, progress_bar_object): 380 | """ 381 | Add progress bar object on list 382 | """ 383 | self.lock.acquire() 384 | try: 385 | #sys.stdout.write( change_print_coding(progress_bar_object.name) ) 386 | print change_print_coding(progress_bar_object.name), 387 | sys.stdout.write('\r\n') 388 | sys.stdout.write(progress_bar_object.get_meter()) 389 | sys.stdout.write('\r\n') 390 | self.progress_bars.append(progress_bar_object) 391 | finally: 392 | self.lock.release() 393 | 394 | 395 | def delete_progress_bar(self, progress_bar_object): 396 | """ 397 | Delete progress bar object from list 398 | """ 399 | self.lock.acquire() 400 | try: 401 | #sys.stdout.write( change_print_coding(progress_bar_object.name) ) 402 | self._wipe_progress_bars() 403 | print change_print_coding(progress_bar_object.name), 404 | sys.stdout.write('\r\n') 405 | progress_bar_object.update_to_display() 406 | sys.stdout.write(progress_bar_object.get_meter()) 407 | sys.stdout.write('\r\n') 408 | self.progress_bars.remove(progress_bar_object) 409 | self._show_progress_bars() 410 | finally: 411 | self.lock.release() 412 | 413 | 414 | if __name__ == '__main__': 415 | v = View() 416 | pr = [ ProgressBar(total = 100, name = "probś" + str(i) ) for i in range(1,5) ] 417 | for p in pr: 418 | v.add_progress_bar(p) 419 | for i in range(100): 420 | for p in pr: 421 | p.update(1) 422 | v.update_progress_bars() 423 | time.sleep(0.1) 424 | if i % 2 == 0: 425 | v.print_("Infośćł", i) 426 | if i == 25: 427 | p = ProgressBar(total = 100, name = "tmp1" ) 428 | v.add_progress_bar( p ) 429 | pr.append(p) 430 | if i == 50: 431 | v.delete_progress_bar( pr[0] ) 432 | if i == 75: 433 | p = ProgressBar(total = 100, name = "tmp2" ) 434 | v.add_progress_bar( p ) 435 | pr.append( p ) 436 | -------------------------------------------------------------------------------- /src/chomikbox.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Author: Adam (adam_gr [at] gazeta.pl) 4 | # 5 | # Written: 05/08/2012 6 | # 7 | # Released under: GNU GENERAL PUBLIC LICENSE 8 | # 9 | 10 | import socket 11 | import urllib2 12 | import urllib 13 | import hashlib 14 | import re 15 | import sys 16 | import time 17 | import os 18 | import zlib 19 | #import progress 20 | import view 21 | import traceback 22 | import model 23 | ################## 24 | from soap import SOAP 25 | from cookielib import CookieJar 26 | 27 | ############################# 28 | glob_timeout = 240 29 | #KONFIGURACJA 30 | #login_ip = "208.43.223.12" 31 | #login_ip = "main.box.chomikuj.pl" 32 | login_ip = "box.chomikuj.pl" 33 | #login_port = 8083 34 | login_port = 80 35 | version = "2.0.8.1" 36 | client = "ChomikBox-" + version 37 | 38 | def print_dict_in_dict(d, root = ""): 39 | if u"name" in d: 40 | print d 41 | print root + "/" + d["name"], d["id"], 42 | if d["passwd"] == "true": 43 | print d["password"] 44 | else: 45 | print 46 | root += "/" + d["name"] 47 | for k,v in d.iteritems(): 48 | if type(v) == type({}): 49 | print_dict_in_dict(v, root) 50 | elif type(v) == type([]): 51 | for inner_dict in v: 52 | print_dict_in_dict(inner_dict, root) 53 | 54 | 55 | def change_coding(text): 56 | try: 57 | if sys.platform.startswith('win'): 58 | text = text.decode('cp1250').encode('utf-8') 59 | except Exception, e: 60 | print e 61 | return text 62 | 63 | def to_unicode(text): 64 | try: 65 | if sys.platform.startswith('win'): 66 | text = text.decode('cp1250') 67 | else: 68 | text = text.decode('utf8') 69 | except Exception, e: 70 | print e 71 | return text 72 | 73 | def unescape_name(text): 74 | text = text.replace(""", '"') 75 | text = text.replace("'", "'") 76 | text = text.replace("<", "<") 77 | text = text.replace(">", ">") 78 | text = text.replace("&", "&") 79 | return text 80 | 81 | ##################################################################################################### 82 | class ChomikException(Exception): 83 | def __init__(self, filepath, filename, folder_id, chomik_id, token, server, port, stamp, excpt = None): 84 | Exception.__init__(self) 85 | self.filepath = filepath 86 | self.filename = filename 87 | self.folder_id = folder_id 88 | self.chomik_id = chomik_id 89 | self.token = token 90 | self.server = server 91 | self.port = port 92 | self.stamp = stamp 93 | self.excpt = excpt 94 | 95 | def __str__(self): 96 | return str(self.excpt) 97 | 98 | def get_excpt(self): 99 | return self.excpt 100 | 101 | def args(self): 102 | return (self.filepath, self.filename, self.folder_id, self.chomik_id, self.token, self.server, self.port, self.stamp) 103 | 104 | ##################################################################################################### 105 | #TODO: zmienic cos z kodowaniem 106 | class Chomik(object): 107 | def __init__(self, view_ = None, model_ = None, debug = False): 108 | if view_ == None: 109 | self.view = view.View() 110 | else: 111 | self.view = view_ 112 | if model_ == None: 113 | self.model = model.Model() 114 | else: 115 | self.model = model_ 116 | self.debug = debug 117 | self.soap = SOAP() 118 | ######## 119 | #root folder 120 | self.folders_dom = {} 121 | self.ses_id = '' 122 | self.chomik_id = '0' 123 | self.folder_id = '0' 124 | self.cur_fold = [] 125 | self.user = '' 126 | self.password = '' 127 | self.last_login = 0 128 | self.cookie = '' 129 | self.chomikbox_url = '' 130 | self.opener = None 131 | 132 | 133 | def send(self, content, l_ip = "box.chomikuj.pl", l_port = 80): 134 | if l_ip != None: 135 | login_ip = l_ip 136 | if l_port != None: 137 | login_port = l_port 138 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 139 | sock.settimeout(glob_timeout) 140 | sock.connect( (login_ip, login_port) ) 141 | sock.send(content) 142 | resp = "" 143 | kRespSize = 2056 144 | while True: 145 | tmp = sock.recv(kRespSize) 146 | resp += tmp 147 | if tmp == '' or tmp.endswith("\r\n\r\n"): 148 | break 149 | sock.close() 150 | if "Set-Cookie: __cfduid=" in resp: 151 | self.cookie = re.findall("Set-Cookie: __cfduid=([^;]*)", resp)[0] 152 | resp = resp.partition("\r\n\r\n")[2] 153 | resp = re.sub("\r\n\w{1,10}\r\n", "", resp) 154 | _, _, resp = resp.partition("<") 155 | resp = "<" + resp 156 | resp,_,_ = resp.rpartition(">") 157 | resp = resp + ">" 158 | return resp 159 | 160 | 161 | def login(self, user, password): 162 | """ 163 | Logowanie sie do chomika 164 | Zwraca True przy pomyslnym zalogowani, a False wpp 165 | """ 166 | self.user = user 167 | self.password = password 168 | if self.relogin() == True: 169 | self.get_dir_list() 170 | return True 171 | else: 172 | return False 173 | 174 | def relogin(self): 175 | if self.last_login + 360 > time.time(): 176 | return True 177 | self.last_login = time.time() 178 | password = hashlib.md5(self.password).hexdigest() 179 | xml_dict = [('ROOT',[('name' , self.user), ('passHash', password), ('ver' , '4'), ('client',[('name','chomikbox'),('version',version) ]) ])] 180 | xml_content = self.soap.soap_dict_to_xml(xml_dict, "Auth").strip() 181 | xml_len = len(xml_content) 182 | header = """POST /services/ChomikBoxService.svc HTTP/1.1\r\n""" 183 | header += """SOAPAction: http://chomikuj.pl/IChomikBoxService/Auth\r\n""" 184 | #header += """Content-Encoding: identity\r\n""" 185 | header += """Content-Type: text/xml;charset=utf-8\r\n""" 186 | header += """Content-Length: %d\r\n""" % xml_len 187 | header += """Connection: Keep-Alive\r\n""" 188 | header += """Accept-Encoding: identity\r\n""" 189 | header += """Accept-Language: pl-PL,en,*\r\n""" 190 | header += """User-Agent: Mozilla/5.0\r\n""" 191 | header += """Host: box.chomikuj.pl\r\n\r\n""" 192 | header += xml_content 193 | resp = self.send(header) 194 | resp_dict = self.soap.soap_xml_to_dict(resp) 195 | status = resp_dict['s:Envelope']['s:Body']['AuthResponse']['AuthResult']['a:status'] 196 | if status != 'Ok': 197 | self.view.print_( "Blad(relogin):" ) 198 | self.view.print_( status ) 199 | return False 200 | try: 201 | chomik_id = resp_dict['s:Envelope']['s:Body']['AuthResponse']['AuthResult']['a:hamsterId'] 202 | ses_id = resp_dict['s:Envelope']['s:Body']['AuthResponse']['AuthResult']['a:token'] 203 | self.ses_id = ses_id 204 | self.chomik_id = chomik_id 205 | if self.ses_id == "-1" or self.chomik_id == "-1": 206 | return False 207 | except IndexError, e: 208 | self.view.print_( "Blad(relogin):" ) 209 | self.view.print_( e ) 210 | self.view.print_( resp ) 211 | return False 212 | else: 213 | #self.get_dir_list() 214 | self.check_events() 215 | self.log_www() 216 | return True 217 | 218 | def log_www(self): 219 | if self.opener == None: 220 | cj = CookieJar() 221 | self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) 222 | self.opener.addheaders.append(('User-Agent','Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)')) 223 | self.opener.addheaders.append(('X-Requested-With', 'XMLHttpRequest')) 224 | self.opener.addheaders.append(('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')) 225 | resp = self.opener.open("http://chomikuj.pl/chomik/chomikbox/LoginFromBox?t=" + self.ses_id + "&returnUrl=/ChomikBox") 226 | cont = resp.read() 227 | resp.close() 228 | req_token = re.findall("""input name="__RequestVerificationToken".*?value="([^"]*)" """, cont)[0] 229 | ################# 230 | values = { "ReturnUrl" : "", "Login": self.user, "rememberLogin" : "true" , "Password" : self.password , "__RequestVerificationToken" : req_token } 231 | data = urllib.urlencode(values) 232 | resp = self.opener.open("http://chomikuj.pl/action/Login/TopBarLogin", data) 233 | cont = resp.read() 234 | resp.close() 235 | ######## 236 | values = { "chomikName" : self.user, "folderId": 0, "__RequestVerificationToken" : req_token } 237 | data = urllib.urlencode(values) 238 | resp = self.opener.open("http://chomikuj.pl/action/chomikbox/DownloadFolderChomikBox", data) 239 | cont = resp.read() 240 | resp.close() 241 | self.chomikbox_url = re.findall("""chomik://files/:(\d*)/""", cont)[0] 242 | 243 | 244 | def get_dir_list(self): 245 | """ 246 | Pobiera liste folderow chomika. 247 | """ 248 | self.relogin() 249 | xml_dict = [('ROOT',[('token' , self.ses_id), ('hamsterId', self.chomik_id), ('folderId' , '0'), ('depth' , 0) ])] 250 | xml_content = self.soap.soap_dict_to_xml(xml_dict, "Folders").strip() 251 | xml_len = len(xml_content) 252 | header = """POST /services/ChomikBoxService.svc HTTP/1.1\r\n""" 253 | header += """SOAPAction: http://chomikuj.pl/IChomikBoxService/Folders\r\n""" 254 | header += """Content-Type: text/xml;charset=utf-8\r\n""" 255 | if self.cookie != '': 256 | header += """Cookie: __cfduid={0}\r\n""".format(self.cookie) 257 | header += """Content-Length: %d\r\n""" % xml_len 258 | header += """Connection: Keep-Alive\r\n""" 259 | header += """Accept-Language: pl-PL,en,*\r\n""" 260 | header += """User-Agent: Mozilla/5.0\r\n""" 261 | header += """Host: box.chomikuj.pl\r\n\r\n""" 262 | header += xml_content 263 | resp = self.send(header) 264 | resp_dict = self.soap.soap_xml_to_dict(resp) 265 | status = resp_dict['s:Envelope']['s:Body']['FoldersResponse']['FoldersResult']['a:status'] 266 | if status != 'Ok': 267 | self.view.print_( "Blad(pobieranie listy folderow):" ) 268 | self.view.print_( status ) 269 | return False 270 | self.folders_dom = resp_dict['s:Envelope']['s:Body']['FoldersResponse']['FoldersResult']['a:folder'] 271 | return True 272 | 273 | 274 | def check_events(self): 275 | """ 276 | Sprawdza ostatni stan aplikacji chomikbox 277 | """ 278 | self.relogin() 279 | xml_dict = [('ROOT',[('token' , self.ses_id), ('stats', [("isUploading", '0'), ("isDownloading", '0'), ("panelSelectedTab", '0'), ("animation", '2') ]) ])] 280 | xml_content = self.soap.soap_dict_to_xml(xml_dict, "CheckEvents").strip() 281 | xml_len = len(xml_content) 282 | header = """POST /services/ChomikBoxService.svc HTTP/1.1\r\n""" 283 | header += """SOAPAction: http://chomikuj.pl/IChomikBoxService/CheckEvents\r\n""" 284 | header += """Content-Type: text/xml;charset=utf-8\r\n""" 285 | if self.cookie != '': 286 | header += """Cookie: __cfduid={0}\r\n""".format(self.cookie) 287 | header += """Content-Length: %d\r\n""" % xml_len 288 | header += """Connection: Keep-Alive\r\n""" 289 | header += """Accept-Language: pl-PL,en,*\r\n""" 290 | header += """User-Agent: Mozilla/5.0\r\n""" 291 | header += """Host: box.chomikuj.pl\r\n\r\n""" 292 | header += xml_content 293 | resp = self.send(header) 294 | resp_dict = self.soap.soap_xml_to_dict(resp) 295 | status = resp_dict['s:Envelope']['s:Body']['CheckEventsResponse']['CheckEventsResult']['status']['#text'] 296 | if status != 'Ok': 297 | self.view.print_( "Blad(sprawdzanie stanu chomikboxa):" ) 298 | self.view.print_( status ) 299 | return False 300 | return True 301 | 302 | 303 | def cur_adr(self, atr = None): 304 | """ 305 | Zwracanie lub ustawianie obecnego polozenia w katalogach 306 | """ 307 | if atr == None: 308 | return self.cur_fold, self.folder_id 309 | else: 310 | self.cur_fold, self.folder_id = atr 311 | 312 | 313 | def get_next_folder(self, folders_dom = None, root = ""): 314 | if folders_dom == None: 315 | folders_dom = self.folders_dom 316 | if u"name" in folders_dom: 317 | yield (folders_dom["id"], root + "/" + folders_dom["name"]) 318 | root += "/" + folders_dom["name"] 319 | for k,v in folders_dom.iteritems(): 320 | if type(v) == type({}): 321 | for i in self.get_next_folder(v, root): 322 | yield i 323 | elif type(v) == type([]): 324 | for inner_dict in v: 325 | for i in self.get_next_folder(inner_dict, root): 326 | yield i 327 | 328 | def chdirs(self, directories): 329 | folders = [i.replace("/","") for i in directories.split('/') if i != ''] 330 | result = self.__access_node(folders, self.folders_dom) 331 | if result == None: 332 | self.view.print_("Bledna sciezka", directories) 333 | return result 334 | 335 | def __access_node(self, directories, folders_dom): 336 | if len(directories) == 0: 337 | return folders_dom 338 | folders_dom = folders_dom[u'folders'][u'FolderInfo'] 339 | #TODO - utf 340 | if u"name" in folders_dom and folders_dom[u'name'] == unescape_name(to_unicode(directories[0])): 341 | return self.__access_node(directories[1:], folders_dom) 342 | if type(folders_dom) == type([]): 343 | for inner_dict in folders_dom: 344 | if u"name" in inner_dict and inner_dict[u'name'] == unescape_name(to_unicode(directories[0])): 345 | return self.__access_node(directories[1:], inner_dict) 346 | return None 347 | 348 | 349 | 350 | 351 | 352 | def get_files_list(self, folder_id): 353 | #TODO: nie wiem jaki ma byc stamp 354 | stamp = 0 355 | #reqid = str(self.chomik_id) + "/" + str(folder_id) 356 | reqid = str(self.chomikbox_url) + "/" + str(folder_id) 357 | #reqid? 358 | xml_dict = [('ROOT', [('token', self.ses_id), ( 'sequence', [('stamp', stamp), ('part', 0), ('count', 1), ]), ('disposition', 'download'), ('list', [('DownloadReqEntry', [('id', reqid), ('agreementInfo', [('AgreementInfo',[('name', 'own')])])] )]) ] ) ] 359 | #xml_dict = [('ROOT', [('token', self.ses_id), ( 'sequence', [('stamp', stamp), ('part', 0), ('count', 1), ]), ('disposition', 'download'), ('list', [('DownloadReqEntry', [('id', reqid)] )]) ] ) ] 360 | xml_content = self.soap.soap_dict_to_xml(xml_dict, "Download").strip() 361 | xml_len = len(xml_content) 362 | header = """POST /services/ChomikBoxService.svc HTTP/1.1\r\n""" 363 | header += """SOAPAction: http://chomikuj.pl/IChomikBoxService/Download\r\n""" 364 | header += """Content-Type: text/xml;charset=utf-8\r\n""" 365 | if self.cookie != '': 366 | header += """Cookie: __cfduid={0}\r\n""".format(self.cookie) 367 | header += """Content-Length: %d\r\n""" % xml_len 368 | header += """Connection: Keep-Alive\r\n""" 369 | header += """Accept-Encoding: identity\r\n""" 370 | header += """Accept-Language: pl-PL,en,*\r\n""" 371 | header += """User-Agent: Mozilla/5.0\r\n""" 372 | header += """Host: box.chomikuj.pl\r\n\r\n""" 373 | header += xml_content 374 | resp = self.send(header) 375 | resp_dict = self.soap.soap_xml_to_dict(resp) 376 | status = resp_dict['s:Envelope']['s:Body']['DownloadResponse']['DownloadResult']['a:status'] 377 | if status != 'Ok': 378 | self.view.print_( "Blad(pobieranie listy plikow z folderu %s):" % str(folder_id) ) 379 | self.view.print_( status ) 380 | return False 381 | file_list = resp_dict['s:Envelope']['s:Body']['DownloadResponse']['DownloadResult']['a:list']['DownloadFolder']['files'] 382 | result = [i for i in self.__get_files_list_aux(file_list)] 383 | return result 384 | 385 | 386 | def __get_files_list_aux(self, files_dict): 387 | if files_dict == None or files_dict == "None": 388 | pass 389 | else: 390 | files_list = files_dict["FileEntry"] 391 | if type(files_list) == type({}) and type(files_list["url"]) != type({}): 392 | yield (files_list["name"], files_list["url"]) 393 | elif type(files_list) == type([]): 394 | for inner_dict in files_list : 395 | if type(inner_dict["url"]) != type({}): 396 | yield (inner_dict["name"], inner_dict["url"]) 397 | 398 | 399 | def download_token(self): 400 | reqid = 353442452 401 | stamp = 2 402 | xml_dict = [('ROOT', [('token', self.ses_id), ( 'sequence', [('stamp', stamp), ('part', 0), ('count', 1), ]), ('disposition', 'download'), ('list', [('DownloadReqEntry', [('id', reqid), ('agreementInfo', [('AgreementInfo',[('name', 'own')])])] )]) ] ) ] 403 | xml_dict = [('ROOT', [('token', self.ses_id), ( 'sequence', [('stamp', stamp), ('part', 0), ('count', 1), ]), ('disposition', 'player.audio'), ('list', [('DownloadReqEntry', [('id', reqid), ('agreementInfo', [('AgreementInfo',[('name', 'access')])])] )]) ] ) ] 404 | #reqid = "20188/1616" 405 | #xml_dict = [('ROOT', [('token', self.ses_id), ( 'sequence', [('stamp', stamp), ('part', 0), ('count', 1), ]), ('disposition', 'download'), ('list', [('DownloadReqEntry', [('id', reqid)] )]) ] ) ] 406 | xml_content = self.soap.soap_dict_to_xml(xml_dict, "Download").strip() 407 | xml_len = len(xml_content) 408 | header = """POST /services/ChomikBoxService.svc HTTP/1.1\r\n""" 409 | header += """SOAPAction: http://chomikuj.pl/IChomikBoxService/Download\r\n""" 410 | header += """Content-Type: text/xml;charset=utf-8\r\n""" 411 | header += """Content-Length: %d\r\n""" % xml_len 412 | header += """Connection: Keep-Alive\r\n""" 413 | header += """Accept-Language: pl-PL,en,*\r\n""" 414 | header += """User-Agent: Mozilla/5.0\r\n""" 415 | header += """Host: box.chomikuj.pl\r\n\r\n""" 416 | header += xml_content 417 | resp = self.send(header) 418 | #print resp 419 | resp_dict = self.soap.soap_xml_to_dict(resp) 420 | #print resp_dict 421 | 422 | 423 | 424 | 425 | if __name__ == "__main__": 426 | pass 427 | --------------------------------------------------------------------------------