diff --git a/pytchat/processors/default/renderer/base.py b/pytchat/processors/default/renderer/base.py index 1e42619..64fbecc 100644 --- a/pytchat/processors/default/renderer/base.py +++ b/pytchat/processors/default/renderer/base.py @@ -52,8 +52,11 @@ class BaseRenderer: if r: if r.get('emoji'): message += r['emoji'].get('shortcuts', [''])[0] - message_ex.append( - r['emoji']['image']['thumbnails'][1].get('url')) + message_ex.append({ + 'id': r['emoji'].get('emojiId').split('/')[-1], + 'txt': r['emoji'].get('shortcuts', [''])[0], + 'url': r['emoji']['image']['thumbnails'][0].get('url') + }) else: message += r.get('text', '') message_ex.append(r.get('text', '')) diff --git a/pytchat/processors/html_archiver.py b/pytchat/processors/html_archiver.py index 397d31e..dba8d22 100644 --- a/pytchat/processors/html_archiver.py +++ b/pytchat/processors/html_archiver.py @@ -1,31 +1,56 @@ import os import re +import requests +from base64 import standard_b64encode from .chat_processor import ChatProcessor from .default.processor import DefaultProcessor + PATTERN = re.compile(r"(.*)\(([0-9]+)\)$") + fmt_headers = ['datetime', 'elapsed', 'authorName', 'message', 'superchat', 'type', 'authorChannel'] HEADER_HTML = ''' - + + +''' + +TABLE_CSS = ''' +table.css { + border-collapse: collapse; +} + +table.css thead{ + border-collapse: collapse; + border: 1px solid #000 +} + +table.css tr td{ + padding: 0.3em; + border: 1px solid #000 +} + +table.css th{ + padding: 0.3em; + border: 1px solid #000 +} ''' class HTMLArchiver(ChatProcessor): ''' - HtmlArchiver saves chat data as HTML table format. + HTMLArchiver saves chat data as HTML table format. ''' def __init__(self, save_path): super().__init__() self.save_path = self._checkpath(save_path) - with open(self.save_path, mode='a', encoding='utf-8') as f: - f.write(HEADER_HTML) - f.write('') - f.writelines(self._parse_html_header(fmt_headers)) self.processor = DefaultProcessor() + self.emoji_table = {} + self.header = [HEADER_HTML] + self.body = ['\n', '
\n', self._parse_table_header(fmt_headers)] def _checkpath(self, filepath): splitter = os.path.splitext(os.path.basename(filepath)) @@ -56,42 +81,59 @@ class HTMLArchiver(ChatProcessor): """ if chat_components is None or len(chat_components) == 0: return - - with open(self.save_path, mode='a', encoding='utf-8') as f: - chats = self.processor.process(chat_components).items - for c in chats: - f.writelines( - self._parse_html_line([ - c.datetime, - c.elapsedTime, - c.author.name, - c.message, - c.amountString, - c.author.type, - c.author.channelId] - ) - ) - ''' - #Palliative treatment# - Comment out below line to prevent the table - display from collapsing. - ''' - # f.write('
') + # chats = 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) + ) for c in self.processor.process(chat_components).items) + ) def _parse_html_line(self, raw_line): - html = '' - html += ' ' - for cell in raw_line: - html += '' + cell + '' - html += '\n' - return html + return ''.join(('', + ''.join(''.join(('', cell, '')) for cell in raw_line), + '\n')) - def _parse_html_header(self, raw_line): - html = '' - html += '\n' - html += ' ' - for cell in raw_line: - html += '' + cell + '' - html += '\n' - html += '\n' - return html + def _parse_table_header(self, raw_line): + return ''.join(('', + ''.join(''.join(('', cell, '')) for cell in raw_line), + '\n')) + + def _parse_message(self, message_items: list) -> str: + return ''.join(''.join(('')) + if type(item) is dict else item + for item in message_items) + + def _encode_img(self, url): + resp = requests.get(url) + return standard_b64encode(resp.content).decode() + + def _set_emoji_table(self, item: dict): + emoji_id = item['id'] + if emoji_id not in self.emoji_table: + self.emoji_table.setdefault(emoji_id, self._encode_img(item['url'])) + return emoji_id + + def _stylecode(self, name, code, width, height): + return ''.join((".", name, " { display: inline-block; background-image: url(data:image/png;base64,", + code, "); background-repeat: no-repeat; width: ", + str(width), "; height: ", str(height), ";}")) + + def _create_styles(self): + return '\n'.join(('\n')) + + def finalize(self): + self.header.extend([self._create_styles(), '\n']) + self.body.extend(['\n']) + with open(self.save_path, mode='a', encoding='utf-8') as f: + f.writelines(self.header) + f.writelines(self.body) diff --git a/pytchat/tool/extract/extractor.py b/pytchat/tool/extract/extractor.py index 1110e14..2b421af 100644 --- a/pytchat/tool/extract/extractor.py +++ b/pytchat/tool/extract/extractor.py @@ -83,11 +83,13 @@ class Extractor: data = self._execute_extract_operations() if self.processor is None: return data - return self.processor.process( + ret = self.processor.process( [{'video_id': None, 'timeout': 1, 'chatdata': (action["replayChatItemAction"]["actions"][0] for action in data)}] ) + self.processor.finalize() + return ret def cancel(self): asyncdl.cancel()