├── 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 = "" + method + ">"
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]) + "" + xml_list[0] + ">"
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 |
--------------------------------------------------------------------------------