├── logs └── .gitkeep ├── downloads └── .gitkeep ├── requirements.txt ├── LICENSE ├── .gitignore ├── README.rst ├── config.py └── downloader.py /logs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /downloads/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | tqdm 3 | volapi==5.17.0 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 kadranel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | .idea 97 | 98 | # Rope project settings 99 | .ropeproject 100 | 101 | # mkdocs documentation 102 | /site 103 | 104 | # mypy 105 | .mypy_cache/ 106 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ===================== 2 | Python Volafile Downloader 3 | ===================== 4 | 5 | Tool for downloading from volafile.org rooms via volapi_. (Currently the downloader is working on volapi 5.17.0) 6 | 7 | .. _volapi: https://github.com/volafiled/python-volapi 8 | This downloader does not use webdrivers and selenium like volafile-downloader_ and instead uses a websocket connection over the API, which makes this implementation a lot more light-weight. 9 | 10 | The downloader allows for blacklists/whitelists for uploaders, filename-search and filetypes. Furthermore you can create your own chat logs. 11 | 12 | .. _volafile-downloader: https://github.com/the-okn3/volafile-downloader 13 | 14 | Installation 15 | ------------ 16 | 17 | 0) What do you need? 18 | a) Python 3.7 19 | b) pip 20 | 1) How to install 21 | a) Download the newest release of the downloader at https://github.com/kadranel/python-volafile-downloader/archive/1.1.5.zip or git clone this repository. 22 | b) Unzip and enter the folder with you favourite shell, then type: 23 | :: 24 | 25 | pip3 install -r requirements.txt 26 | 27 | 2) Edit the config.py to your liking. Check the comments in there for more information on what to change. 28 | 29 | 30 | Start the downloader 31 | ------------ 32 | :: 33 | 34 | python3 downloader.py -r ROOMID -p PASSWORD[OPTIONAL] -d DOWNLOADER[OPTIONAL] -l LOGGER[OPTIONAL] 35 | 36 | a) ROOMID: https://volafile.org/r/ROOMID 37 | b) PASSWORD: The room password if it exists 38 | c) DOWNLOADER: Overwrite for DOWNLOADER in config.py -> True/False 39 | d) LOGGER: Overwrite for LOGGER in config.py -> True/False 40 | 41 | Example: You want to download all files from https://volafile.org/r/n7yc3pgw 42 | :: 43 | 44 | python3 downloader.py -r n7yc3pgw -d True 45 | 46 | Other 47 | ------------ 48 | If you have any issues/questions just post a new issue. Otherwise feel free to share, improve, use and make it your own. 49 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # #### CONFIG VARIABLES 2 | # Does the downloader start -> True/False (can be overwritten in start command) 3 | DOWNLOADER = True 4 | 5 | # Configure a path on your system to put the downloaded files. The files will get sorted by room and uploader. 6 | # Make sure this path exists beforehand 7 | DOWNLOAD_PATH = './downloads/' 8 | 9 | # When starting the script the whole room gets downloaded -> True/False 10 | DOWNLOAD_ALL_ON_ROOM_ENTER = True 11 | 12 | # After entering the room downloader remains running and downloads new files when they get uploaded 13 | # Needed for logging as well -> True/False 14 | CONTINUE_RUNNING = True 15 | 16 | # When this is True files from the same user with the same filename get downloaded with an altered 17 | # filename -> True/False 18 | # Does not apply to the room entering downloads, there no duplicates will be stored 19 | ALLOW_DUPLICATES = True 20 | 21 | # Volafile user for downloading. Useful if you have volafile pro for a higher speed. 22 | VOLAFILE_USER = '' 23 | VOLAFILE_USER_PASSWORD = '' 24 | 25 | # Maximum allowed size to download in MB -> unlimited if -1 26 | MAXIMUM_FILE_SIZE = -1 27 | 28 | # Does the chat logger start -> True/False (can be overwritten in start command) 29 | LOGGER = True 30 | 31 | # Configure a path on your system to put the room chat logs. The files will get sorted by room. 32 | # Make sure this path exists beforehand 33 | LOG_PATH = './logs/' 34 | 35 | # #### FILTERING OPTIONS 36 | # All filters get stored as strings in lists. You can only use either a white- or a blacklist from each filter. 37 | # If you want to specify filters for a certain room put #ROOMNAME behind the filter. (This works for all filters) 38 | # ## USER FILTERING 39 | # Example for this filtertype: USER_WHITELIST = ['zipbot', 'kad#gentoomen'] 40 | # This example allows all files of the user zipbot to be downloaded in all rooms and all files of the user kad to 41 | # to be downloaded only in the room 'gentoomen' (https://volafile.org/r/gentoomen) 42 | USE_USER_WHITELIST = False 43 | USER_WHITELIST = [] 44 | USE_USER_BLACKLIST = False 45 | USER_BLACKLIST = [] 46 | 47 | # ## FILENAME FILTERING 48 | # Example for this filtertype: FILENAME_WHITELIST = ['hello', 'girl#gentoomen'] 49 | # This example will download all files with 'hello' in their filenames in all rooms and all files with girl in 50 | # their filename only in the room 'gentoomen' (https://volafile.org/r/gentoomen) 51 | USE_FILENAME_WHITELIST = False 52 | FILENAME_WHITELIST = [] 53 | USE_FILENAME_BLACKLIST = False 54 | FILENAME_BLACKLIST = [] 55 | 56 | # ## FILETYPE FILTERING 57 | # possible filter options: video, image, other, audio 58 | # Example for this filtertype: FILETYPE_WHITELIST = ['video', 'other#gentoomen'] 59 | # This example will download videos in all rooms and archives/textdocuments/other in the room 'gentoomen' only 60 | USE_FILETYPE_WHITELIST = False 61 | FILETYPE_WHITELIST = [] 62 | USE_FILETYPE_BLACKLIST = False 63 | FILETYPE_BLACKLIST = [] 64 | 65 | # #### REQUESTS CONFIG 66 | # should not be changed unless errors occur when downloading 67 | HEADERS = { 68 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0", 69 | "DNT": "1", 70 | "Upgrade-Insecure-Requests": "1" 71 | } 72 | COOKIES = { 73 | "allow-download": "1" 74 | } 75 | -------------------------------------------------------------------------------- /downloader.py: -------------------------------------------------------------------------------- 1 | from volapi import Room 2 | import argparse 3 | import requests 4 | from tqdm import tqdm 5 | import os 6 | import string 7 | import random 8 | import config 9 | from datetime import datetime, timedelta 10 | import time 11 | 12 | kill = False 13 | 14 | 15 | class VolaDL(object): 16 | def __init__(self, args): 17 | """Initialize Object""" 18 | self.headers = config.HEADERS 19 | self.cookies = config.COOKIES 20 | self.room = args[0] 21 | self.password = args[1] 22 | if args[2] is None: 23 | self.downloader = config.DOWNLOADER 24 | else: 25 | self.downloader = args[2] 26 | if args[3] is None: 27 | self.logger = config.LOGGER 28 | else: 29 | self.logger = args[3] 30 | 31 | self.alive = True 32 | 33 | self.download_all = config.DOWNLOAD_ALL_ON_ROOM_ENTER 34 | self.duplicate = not config.ALLOW_DUPLICATES 35 | self.continue_running = config.CONTINUE_RUNNING 36 | self.max_file_size = config.MAXIMUM_FILE_SIZE 37 | 38 | self.download_path = config.DOWNLOAD_PATH + self.room 39 | self.log_path = config.LOG_PATH + self.room 40 | self.refresh_time = datetime.now() + timedelta(days=1) 41 | self.counter = 1 42 | self.user_whitelist = [] 43 | self.user_blacklist = [] 44 | self.filename_whitelist = [] 45 | self.filename_blacklist = [] 46 | self.filetype_whitelist = [] 47 | self.filetype_blacklist = [] 48 | 49 | if self.config_check(): 50 | self.alive = False 51 | global kill 52 | kill = True 53 | print('### YOU CAN NOT USE A BLACKLIST AND A WHITELIST FOR THE SAME FILTER.') 54 | else: 55 | self.listen = self.create_room() 56 | 57 | def dl(self): 58 | """Main method that gets called at the start""" 59 | 60 | def onfile(f): 61 | """Listener on new files in the room""" 62 | url = f.url 63 | uploader = f.uploader 64 | file_size = '{0:.4f}'.format(f.size / 1048576) 65 | print('### NEW FILE - URL : {} - UPLOADER: {} - FILESIZE: {} MB'.format(url, uploader, file_size)) 66 | if not self.max_file_size == -1 and f.size / 1048576 >= self.max_file_size: 67 | print('File is too big to download.') 68 | elif self.file_check(f): 69 | self.single_file_download(url, uploader) 70 | else: 71 | print('File got filtered out.') 72 | 73 | def ontime(t): 74 | """React to time events emitted by volafile socket connection, used for maintenance""" 75 | if datetime.now() > self.refresh_time: 76 | # if the refresh_time is now -> close the bot 77 | self.close() 78 | return t 79 | # check for connections 80 | if self.listen: 81 | if not self.listen.connected: 82 | self.close() 83 | return t 84 | 85 | def onmessage(m): 86 | """React to and log chat messages""" 87 | self.log_room(m) 88 | 89 | if self.alive: 90 | global kill 91 | 92 | if self.download_all and self.downloader: 93 | print("Downloading room on enter") 94 | duplicate_temp = self.duplicate 95 | self.duplicate = True 96 | self.download_room() 97 | self.duplicate = duplicate_temp 98 | if self.continue_running: 99 | if self.downloader: 100 | self.listen.add_listener("file", onfile) 101 | if self.logger: 102 | self.listen.add_listener("chat", onmessage) 103 | if self.downloader or self.logger: 104 | self.listen.add_listener("time", ontime) 105 | self.listen.listen() 106 | else: 107 | print('### You need to activate either LOGGER or DOWNLOADER for the bot to continue running') 108 | kill = True 109 | else: 110 | kill = True 111 | 112 | def log_room(self, msg): 113 | if msg.nick == 'News' and msg.system: 114 | return False 115 | time_now = datetime.now() 116 | prefix = VolaDL.prefix(msg) 117 | if os.path.exists(self.log_path): 118 | temp_path = self.log_path + '/' 119 | else: 120 | temp_path = VolaDL.create_folder(self.log_path) 121 | file_name = time_now.strftime("[%Y-%m-%d]") + "[" + self.room + "].txt" 122 | path = str(temp_path) + str(file_name) 123 | if not os.path.isfile(path): 124 | fl = open(path, "w+") 125 | else: 126 | fl = open(path, "a") 127 | 128 | log_msg = '[{}][{}][{}][{}]\n'.format(str(time_now.strftime("%Y-%m-%d--%H:%M:%S")), prefix, msg.nick, str(msg)) 129 | print("### Writing to log: " + log_msg[0:-1]) 130 | fl.write(log_msg) 131 | fl.close 132 | 133 | def download_room(self): 134 | """Download the whole room on enter""" 135 | time.sleep(2) 136 | file_list = list(self.listen.files)[:] 137 | for f in file_list: 138 | url = f.url 139 | uploader = f.uploader 140 | file_size = '{0:.4f}'.format(f.size / 1048576) 141 | print('### NEXT FILE:') 142 | print('URL : {} - UPLOADER: {} - FILESIZE: {} MB'.format(url, uploader, file_size)) 143 | if not self.max_file_size == -1 and f.size / 1048576 >= self.max_file_size: 144 | print('File is too big to download.') 145 | elif self.file_check(f): 146 | self.single_file_download(url, uploader) 147 | else: 148 | print('File got filtered out.') 149 | print('### ### ###') 150 | print('Downloading the room has been finished, leave this running to download new files/log or quit.') 151 | print('### ### ###') 152 | 153 | def download_file(self, url, file_name=None): 154 | """ Downloads a file from volafile and shows a progress bar """ 155 | chunk_size = 1024 156 | try: 157 | r = requests.get(url, stream=True, headers=self.headers, cookies=self.cookies) 158 | r.raise_for_status() 159 | if not r: 160 | return False 161 | total_size = int(r.headers.get("content-length", 0)) 162 | with open(file_name + ".part", "wb") as fl: 163 | for data in tqdm(iterable=r.iter_content(chunk_size=chunk_size), total=total_size / chunk_size, 164 | unit="KB", unit_scale=True): 165 | fl.write(data) 166 | os.rename(file_name + ".part", file_name) 167 | return True 168 | except Exception as ex: 169 | print("[-] Error: " + str(ex)) 170 | return False 171 | 172 | def single_file_download(self, url, upl): 173 | """Prepares a single file from vola for download""" 174 | if os.path.exists(self.download_path + '/' + upl): 175 | temp_path = self.download_path + '/' + upl + '/' 176 | else: 177 | temp_path = VolaDL.create_folder(self.download_path + '/' + upl) 178 | 179 | url_split = url.split('/') 180 | file_split = str(url_split[-1]).split('.') 181 | file_split_length = len(file_split[-1]) + 1 182 | download_path = temp_path + str(url_split[-1][0:-file_split_length]) + '.' + str(file_split[-1]) 183 | 184 | if self.duplicate and os.path.isfile(download_path): 185 | print("File exists already!") 186 | return False 187 | elif os.path.isfile(download_path): 188 | download_path = temp_path + str(file_split[0]) + "-" + VolaDL.id_generator() + '.' + str(file_split[-1]) 189 | print('[{}] Downloading to: {}'.format(self.counter, download_path)) 190 | self.counter += 1 191 | return self.download_file(url, download_path) 192 | 193 | def config_check(self): 194 | """Checks filter configs for validity and prepares them for filtering""" 195 | if (config.USE_USER_BLACKLIST and config.USE_USER_WHITELIST) or ( 196 | config.USE_FILENAME_BLACKLIST and config.USE_FILENAME_WHITELIST) or ( 197 | config.USE_FILETYPE_BLACKLIST and config.USE_FILETYPE_WHITELIST): 198 | return (config.USE_USER_BLACKLIST and config.USE_USER_WHITELIST) or ( 199 | config.USE_FILENAME_BLACKLIST and config.USE_FILENAME_WHITELIST) or ( 200 | config.USE_FILETYPE_BLACKLIST and config.USE_FILETYPE_WHITELIST) 201 | else: 202 | if config.USE_USER_BLACKLIST: 203 | self.user_blacklist = config.USER_BLACKLIST 204 | self.config_list_prepare(self.user_blacklist) 205 | if config.USE_USER_WHITELIST: 206 | self.user_whitelist = config.USER_WHITELIST 207 | self.config_list_prepare(self.user_whitelist) 208 | if config.USE_FILETYPE_BLACKLIST: 209 | self.filetype_blacklist = config.FILETYPE_BLACKLIST 210 | self.config_list_prepare(self.filetype_blacklist) 211 | if config.USE_FILETYPE_WHITELIST: 212 | self.filetype_whitelist = config.FILETYPE_WHITELIST 213 | self.config_list_prepare(self.filetype_whitelist) 214 | if config.USE_FILENAME_BLACKLIST: 215 | self.filename_blacklist = config.FILENAME_BLACKLIST 216 | self.config_list_prepare(self.filename_blacklist) 217 | if config.USE_FILENAME_WHITELIST: 218 | self.filename_whitelist = config.FILENAME_WHITELIST 219 | self.config_list_prepare(self.filename_whitelist) 220 | return False 221 | 222 | def config_list_prepare(self, config_list): 223 | """Add #roomname to filters if needed""" 224 | for idx, item in enumerate(config_list): 225 | if '#' not in str(item): 226 | item = item + '#{}'.format(self.room) 227 | config_list[idx] = item 228 | 229 | def file_check(self, file): 230 | """Check file against filters""" 231 | if config.USE_USER_BLACKLIST: 232 | user_bool = True 233 | if str(file.uploader) + '#{}'.format(self.room) in self.user_blacklist: 234 | user_bool = False 235 | elif config.USE_USER_WHITELIST: 236 | user_bool = False 237 | if str(file.uploader) + '#{}'.format(self.room) in self.user_whitelist: 238 | user_bool = True 239 | else: 240 | user_bool = True 241 | 242 | if config.USE_FILENAME_BLACKLIST: 243 | filename_bool = True 244 | for item in self.filename_blacklist: 245 | if item.lower().split('#')[0] in str(file.name).lower() and '#{}'.format(self.room) in item: 246 | filename_bool = False 247 | elif config.USE_FILENAME_WHITELIST: 248 | filename_bool = False 249 | for item in self.filename_whitelist: 250 | if item.lower().split('#')[0] in str(file.name).lower() and '#{}'.format(self.room) in item: 251 | filename_bool = True 252 | else: 253 | filename_bool = True 254 | 255 | if config.USE_FILETYPE_BLACKLIST: 256 | filetype_bool = True 257 | if str(file.filetype) + '#{}'.format(self.room) in self.filetype_blacklist: 258 | filetype_bool = False 259 | elif config.USE_FILETYPE_WHITELIST: 260 | filetype_bool = False 261 | if str(file.filetype) + '#{}'.format(self.room) in self.filetype_whitelist: 262 | filetype_bool = True 263 | else: 264 | filetype_bool = True 265 | 266 | return user_bool and filename_bool and filetype_bool 267 | 268 | def create_room(self): 269 | """return a volapi room""" 270 | if config.VOLAFILE_USER == '': 271 | vola_user = 'downloader' 272 | else: 273 | vola_user = config.VOLAFILE_USER 274 | if self.password == '*': 275 | r = Room(name=self.room, user=vola_user) 276 | elif self.password[0:4] == '#key': 277 | r = Room(name=self.room, user=vola_user, key=self.password[4:]) 278 | else: 279 | r = Room(name=self.room, user=vola_user, password=self.password) 280 | if config.VOLAFILE_USER_PASSWORD == '': 281 | return r 282 | else: 283 | vola_pass = config.VOLAFILE_USER_PASSWORD 284 | time.sleep(1) 285 | try: 286 | r.user.login(vola_pass) 287 | time.sleep(1) 288 | except RuntimeError: 289 | print('### LOGIN FAILED, PLEASE CHECK YOUR CONFIG BEFORE USING THE BOT') 290 | self.alive = False 291 | global kill 292 | kill = True 293 | return r 294 | print('### USER LOGGED IN') 295 | cookie_jar = r.conn.cookies 296 | cookies_dict = {} 297 | for cookie in cookie_jar: 298 | if "volafile" in cookie.domain: 299 | cookies_dict[cookie.name] = cookie.value 300 | self.cookies = {**self.cookies, **cookies_dict} 301 | return r 302 | 303 | def close(self): 304 | """only closes the current session, afterwards the downloader reconnects""" 305 | print("Closing current instance") 306 | self.alive = False 307 | self.listen.close() 308 | del self.listen 309 | return "" 310 | 311 | @staticmethod 312 | def create_folder(new_folder): 313 | """creates a new folder""" 314 | new_path = new_folder 315 | try: 316 | if not os.path.exists(new_path): 317 | os.makedirs(new_path) 318 | print('Created directory: ' + new_path) 319 | return str(new_path + '/') 320 | except OSError: 321 | print('Error: Creating directory. ' + new_path) 322 | return 'Error' 323 | 324 | @staticmethod 325 | def id_generator(size=7, chars=string.ascii_uppercase + string.digits): 326 | """returns an id""" 327 | return ''.join(random.choice(chars) for _ in range(size)) 328 | 329 | @staticmethod 330 | def prefix(msg): 331 | prefix = '' 332 | if msg.purple: 333 | prefix += "@" 334 | if msg.owner: 335 | prefix += "$" 336 | if msg.janitor: 337 | prefix += "~" 338 | if msg.green: 339 | prefix += "+" 340 | if msg.system: 341 | prefix += "%" 342 | return prefix 343 | 344 | 345 | def parse_args(): 346 | """Parses user arguments""" 347 | parser = argparse.ArgumentParser( 348 | description="volafile downloader", 349 | epilog="Pretty meh" 350 | ) 351 | parser.add_argument('--room', '-r', dest='room', type=str, required=True, 352 | help='Room name, as in https://volafile.org/r/ROOMNAME') 353 | parser.add_argument('--passwd', '-p', dest='passwd', type=str, 354 | default="*", 355 | help='Room password to enter the room.') 356 | parser.add_argument('--downloader', '-d', dest='downloader', type=str, 357 | default="None", 358 | help='Do you want to download files -> [True/False]') 359 | parser.add_argument('--logger', '-l', dest='logger', type=str, 360 | default="None", 361 | help='Do you want to log the room -> [True/False]') 362 | return parser.parse_args() 363 | 364 | 365 | def main(): 366 | """Main method""" 367 | global kill 368 | args = parse_args() 369 | if args.downloader == "True": 370 | downloader = True 371 | elif args.downloader == "False": 372 | downloader = False 373 | else: 374 | downloader = None 375 | if args.logger == "True": 376 | logger = True 377 | elif args.logger == "False": 378 | logger = False 379 | else: 380 | logger = None 381 | 382 | lister = [args.room, args.passwd, downloader, logger] 383 | while not kill: 384 | v = VolaDL(lister) 385 | v.dl() 386 | 387 | 388 | def main_callable(room, passwd='*', downloader=None, logger=None): 389 | """Callable main method with arguments""" 390 | global kill 391 | lister = [room, passwd, downloader, logger] 392 | while not kill: 393 | v = VolaDL(lister) 394 | v.dl() 395 | 396 | 397 | if __name__ == "__main__": 398 | main() 399 | --------------------------------------------------------------------------------