From c612847048c1ad0ed6b0e37e71d57bcdc881f7a3 Mon Sep 17 00:00:00 2001 From: manetta Date: Sat, 30 Jan 2021 23:15:36 +0100 Subject: [PATCH] added download function for media files + prepared logbot to run on the server --- LogBot/avatar.png | Bin 15643 -> 15754 bytes LogBot/index.html.j2 | 17 ++++--- LogBot/logbot.py | 106 +++++++++++++++++++++++++++++++++--------- LogBot/stylesheet.css | 8 ++++ 4 files changed, 100 insertions(+), 31 deletions(-) diff --git a/LogBot/avatar.png b/LogBot/avatar.png index 5c74215fcd5ff20864b893456f407056f98051d0..1483f5ac28eb57806741ee1826aecc9ece8053a6 100644 GIT binary patch delta 15465 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 CIlWE* delta 15353 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 diff --git a/LogBot/index.html.j2 b/LogBot/index.html.j2 index 22d2812..c77e945 100644 --- a/LogBot/index.html.j2 +++ b/LogBot/index.html.j2 @@ -2,20 +2,19 @@ - *logbot* + {{ title }} - (Generator: LogBot) -

{{ room }}

+

{{ title }}

-{% for num, msg in db.items() %} + {% for num, msg in db.items() %} -
-

({{ num }})

-

{{ msg }}

-
- -{% endfor %} +
+

[{{ num }}]

+

{{ msg }}

+
+ {% endfor %} \ No newline at end of file diff --git a/LogBot/logbot.py b/LogBot/logbot.py index a13ff4c..4e6082e 100644 --- a/LogBot/logbot.py +++ b/LogBot/logbot.py @@ -1,35 +1,78 @@ from xbotlib import Bot -import json import jinja2 -import re -import os -import shutil +import os, re, json, shutil +import urllib.request +from urllib.parse import urlparse -output = './' +local = './' +server = '/var/www/logs/' -def add_to_db(self, message): - keys = [int(x) for x in self.db[message.room].keys()] +# output = local +output = server + +def add_to_db(self, message, media_post=None): + keys = [x for x in self.db[message.room]['messages'].keys()] if not keys: - new_key = '0' + new_key = "0" + else: + new_key = str(int(keys[-1]) + 1) + if media_post: + self.db[message.room]['messages'][new_key] = media_post else: - new_key = str(keys[-1] + 1) - self.db[message.room][new_key] = message.content + self.db[message.room]['messages'][new_key] = message.content.replace('@add','') def del_from_db(self, message, key): - del self.db[message.room][key] + del self.db[message.room]['messages'][key] def write_log(self, message): template_file = 'index.html.j2' # Hmm... how to read the self.template ? print('using the template: ', template_file) template = jinja2.Template(open(template_file).read()) - if not os.path.isdir(message.room): - os.mkdir(message.room) - shutil.copy('stylesheet.css', message.room) with open(f'{ output }/{ message.room }/index.html','w') as out: - html = template.render(room=message.room, db=self.db[message.room]) + html = template.render(title=self.db[message.room]['title'], db=self.db[message.room]['messages']) out.write(html) print('writing to: ', f'{ message.room }/index.html') +def download(message): + # define media_type + if message.url.lower().endswith(('.jpg','jpeg','png','.gif','.bmp','.svg','eps')): + media_type = 'images' + elif message.url.lower().endswith('.pdf'): + media_type = 'pdf' + elif message.url.lower().endswith(('.mp3','.ogg','.oga','.mogg','.wav','.m4a','.webm')): + media_type = 'audio' + elif message.url.lower().endswith(('.mp4','.webm','.flv','.vob','.avi','.mov','.qt','.mpg','.mpeg','.mp4','.m2v','.mpe','.3gp')): + media_type = 'video' + else: + media_type = None + + # download file + data = urllib.request.urlopen(message.url).read() + if data: + print('downloading: ', message.url) + parsed_url = urlparse(message.url) + filename = os.path.basename(parsed_url.path).replace(' ','_').replace('%20','_') # safe url's + print('as the file: ', filename) + if not os.path.isdir(f'{ message.room }/{ media_type }'): + os.mkdir(f'{ message.room }/{ media_type }') + with open(f'{ message.room }/{ media_type }/{ filename }', 'wb') as media_file: + media_file.write(data) + media_file.close() + + # define media_post + media_path = f'{ media_type }/{ filename }' + if message.url.lower().endswith(('.jpg','jpeg','png','.gif','.bmp','.svg','eps')): + media_post = f'' + elif message.url.lower().endswith('.pdf'): + media_post = f'' + elif message.url.lower().endswith(('.mp3','.ogg','.oga','.mogg','.wav','.m4a','.webm')): + media_post = f'' + elif message.url.lower().endswith(('.mp4','.webm','.flv','.vob','.avi','.mov','.qt','.mpg','.mpeg','.mp4','.m2v','.mpe','.3gp')): + media_post = f'' + else: + media_post = None + + return media_post, media_type class logbot(Bot): @@ -45,7 +88,7 @@ logbot @add : Add a message to the log. logbot @delete : Delete posts from the log. For example: @logbot @delete 5 -logbot @title : Set the title of your log. [future-feature] +logbot @title : Set the title of your log. logbot @style : Edit the css of your log. For example: logbot @style body background-color: pink; [future-feature] @@ -56,8 +99,18 @@ logbot @uptime: To check how long @logbot has been around def group(self, message): + # create a folder + database item + # for each of the rooms in which + # logbot is hanging around :) if not message.room in self.db.keys(): self.db[message.room] = {} + self.db[message.room]['messages'] = {} + self.db[message.room]['title'] = message.room + if not os.path.isdir(message.room): + os.mkdir(message.room) + shutil.copy('stylesheet.css', message.room) + else: + print('WARNING! This folder already exists:', message.room) # to debug in the terminal print('------------------') @@ -65,9 +118,15 @@ logbot @uptime: To check how long @logbot has been around print('room: ', message.room) print('sender: ', message.sender) + # image / PDF / audio / video if message.url: - # messages = writedb(f'') - reply = 'Thanks for that image!' + media_post, media_type = download(message) + if media_post: + add_to_db(self, message, media_post=media_post) + media_type = media_type.replace('images', 'image') # linguistic hack! + reply = f'Thanks for that { media_type }!' + else: + reply = 'Sorry, can\'t touch that :(' elif '@add' in message.text: add_to_db(self, message) @@ -77,9 +136,9 @@ logbot @uptime: To check how long @logbot has been around match = re.findall("@delete \d*", message.content)[0] key = str(match.replace('@delete ','')) - if key in self.db[message.room]: - print('To be deleted:', self.db[message.room][key]) - reply = f'This message is deleted: { self.db[message.room][key] }' + if key in self.db[message.room]['messages']: + print('To be deleted:', self.db[message.room]['messages'][key]) + reply = f"This message is deleted: { self.db[message.room]['messages'][key] }" del_from_db(self, message, key) else: reply = 'This message is already gone!' @@ -88,7 +147,10 @@ logbot @uptime: To check how long @logbot has been around print('HELP') elif '@title' in message.text: - reply = 'This is a future-feature ...' + match = re.findall("@title .*", message.content)[0] + title = match.replace('@title','') + self.db[message.room]['title'] = title + reply = f'The title of the log is changed to: { title }' elif '@style' in message.text: reply = 'This is a future-feature ...' diff --git a/LogBot/stylesheet.css b/LogBot/stylesheet.css index bfcadc4..78c9d7e 100644 --- a/LogBot/stylesheet.css +++ b/LogBot/stylesheet.css @@ -1,5 +1,6 @@ body{ margin: 1em; + max-width: 800px; } .post{ margin: 1em 0; @@ -10,4 +11,11 @@ body{ margin: 0 1em 1em; } .post p.message{ +} +img, +iframe, +audio, +video{ + max-width: calc(100% - 100px); + height: auto; } \ No newline at end of file