From 64ace9dad6c61843bb8e6bb5258bb24609aad5d9 Mon Sep 17 00:00:00 2001 From: taizan-hokuto <55448286+taizan-hokuto@users.noreply.github.com> Date: Sun, 6 Sep 2020 18:25:16 +0900 Subject: [PATCH 1/2] Update progress bar --- pytchat/cli/__init__.py | 24 ++++++++++++++++------ pytchat/cli/progressbar.py | 31 ++++++++++++++++++++--------- pytchat/processors/html_archiver.py | 31 ++++++++++++++++------------- 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/pytchat/cli/__init__.py b/pytchat/cli/__init__.py index 94601a3..211da9f 100644 --- a/pytchat/cli/__init__.py +++ b/pytchat/cli/__init__.py @@ -62,18 +62,30 @@ def main(): print(f" output path: {path.resolve()}") duration = info.get_duration() - pbar = ProgressBar(duration) - ex = Extractor(video_id, - processor=HTMLArchiver(Arguments().output + video_id + '.html'), + pbar = ProgressBar(total=(duration * 1000) / 0.99, status="Extracting") + ex = Extractor(video_id, callback=pbar._disp, div=10) signal.signal(signal.SIGINT, (lambda a, b: cancel(ex, pbar))) - ex.extract() + data = ex.extract() + if data == []: + return False + pbar.reset("#", "=", total=len(data), status="Rendering ") + processor = HTMLArchiver(Arguments().output + video_id + '.html', callback=pbar._disp) + processor.process( + [{'video_id': None, + 'timeout': 1, + 'chatdata': (action["replayChatItemAction"]["actions"][0] for action in data)}] + ) + processor.finalize() + pbar.reset('#', '#', status='Completed ') pbar.close() + print() if pbar.is_cancelled(): print("\nThe extraction process has been discontinued.\n") - return - print("\nThe extraction process has been completed.\n") + return False + return True + except InvalidVideoIdException: print("Invalid Video ID or URL:", video_id) except TypeError as e: diff --git a/pytchat/cli/progressbar.py b/pytchat/cli/progressbar.py index d49b825..b61d6bc 100644 --- a/pytchat/cli/progressbar.py +++ b/pytchat/cli/progressbar.py @@ -6,33 +6,46 @@ https://gist.github.com/vladignatyev/06860ec2040cb497f0f3 ''' import sys +ROT = ['\u25F4', '\u25F5', '\u25F6', '\u25F7'] + class ProgressBar: - def __init__(self, duration): - self._duration = duration - self._count = 0 + def __init__(self, total, status): self._bar_len = 60 self._cancelled = False + self.reset(total=total, status=status) + self._blinker = 0 + + def reset(self, symbol_done="=", symbol_space=" ", total=100, status=''): + self._symbol_done = symbol_done + self._symbol_space = symbol_space + self._total = total + self._status = status + self._count = 0 def _disp(self, _, fetched): - self._progress(fetched / 1000, self._duration) + self._progress(fetched, self._total) - def _progress(self, fillin, total, status=''): + def _progress(self, fillin, total): if total == 0 or self._cancelled: return self._count += fillin filled_len = int(round(self._bar_len * self._count / float(total))) percents = round(100.0 * self._count / float(total), 1) + if percents > 100: + percents = 100.0 if filled_len > self._bar_len: filled_len = self._bar_len - percents = 100 - bar = '=' * filled_len + ' ' * (self._bar_len - filled_len) - sys.stdout.write(' [%s] %s%s ...%s\r' % (bar, percents, '%', status)) + + bar = self._symbol_done * filled_len + \ + self._symbol_space * (self._bar_len - filled_len) + sys.stdout.write(' [%s] %s%s ...%s %s \r' % (bar, percents, '%', self._status, ROT[self._blinker % 4])) sys.stdout.flush() + self._blinker += 1 def close(self): if not self._cancelled: - self._progress(self._duration, self._duration) + self._progress(self._total, self._total) def cancel(self): self._cancelled = True diff --git a/pytchat/processors/html_archiver.py b/pytchat/processors/html_archiver.py index 5e2e423..3a1b913 100644 --- a/pytchat/processors/html_archiver.py +++ b/pytchat/processors/html_archiver.py @@ -43,20 +43,21 @@ class HTMLArchiver(ChatProcessor): ''' HTMLArchiver saves chat data as HTML table format. ''' - def __init__(self, save_path): + def __init__(self, save_path, callback): super().__init__() self.save_path = self._checkpath(save_path) self.processor = DefaultProcessor() self.emoji_table = {} # tuble for custom emojis. key: emoji_id, value: base64 encoded image binary. self.header = [HEADER_HTML] self.body = ['\n', '\n', self._parse_table_header(fmt_headers)] + self.callback = callback def _checkpath(self, filepath): splitter = os.path.splitext(os.path.basename(filepath)) body = splitter[0] extention = splitter[1] newpath = filepath - counter = 0 + counter = 1 while os.path.exists(newpath): match = re.search(PATTERN, body) if match: @@ -80,17 +81,19 @@ class HTMLArchiver(ChatProcessor): """ if chat_components is None or len(chat_components) == 0: return - self.body.extend( - (self._parse_html_line(( - c.datetime, - c.elapsedTime, - c.author.name, - self._parse_message(c.messageEx), - c.amountString, - c.author.type, - c.author.channelId) - ) for c in self.processor.process(chat_components).items) - ) + for c in self.processor.process(chat_components).items: + self.body.extend( + self._parse_html_line(( + c.datetime, + c.elapsedTime, + c.author.name, + self._parse_message(c.messageEx), + c.amountString, + c.author.type, + c.author.channelId) + ) + ) + self.callback(None, 1) def _parse_html_line(self, raw_line): return ''.join(('', @@ -131,7 +134,7 @@ class HTMLArchiver(ChatProcessor): def finalize(self): self.header.extend([self._create_styles(), '\n']) - self.body.extend(['
\n']) + self.body.extend(['\n\n']) with open(self.save_path, mode='a', encoding='utf-8') as f: f.writelines(self.header) f.writelines(self.body) From 15132a9bb8d5a7d956c807446709468d8e2fdfe7 Mon Sep 17 00:00:00 2001 From: taizan-hokuto <55448286+taizan-hokuto@users.noreply.github.com> Date: Sun, 6 Sep 2020 18:27:08 +0900 Subject: [PATCH 2/2] Increment version --- pytchat/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytchat/__init__.py b/pytchat/__init__.py index 61d1189..38551d5 100644 --- a/pytchat/__init__.py +++ b/pytchat/__init__.py @@ -2,7 +2,7 @@ pytchat is a lightweight python library to browse youtube livechat without Selenium or BeautifulSoup. """ __copyright__ = 'Copyright (C) 2019 taizan-hokuto' -__version__ = '0.1.7' +__version__ = '0.1.8' __license__ = 'MIT' __author__ = 'taizan-hokuto' __author_email__ = '55448286+taizan-hokuto@users.noreply.github.com'