Added reading article support from Socializer wall posts
This commit is contained in:
@@ -218,6 +218,21 @@ class displayAudioInteractor(base.baseInteractor):
|
||||
post = self.view.get_audio()
|
||||
self.presenter.remove_from_library(post)
|
||||
|
||||
class displayArticleInteractor(base.baseInteractor):
|
||||
|
||||
def set(self, control, value):
|
||||
if not hasattr(self.view, control):
|
||||
raise AttributeError("The control is not present in the view.")
|
||||
getattr(self.view, control).SetValue(value)
|
||||
|
||||
def install(self, *args, **kwargs):
|
||||
super(displayArticleInteractor, self).install(*args, **kwargs)
|
||||
pub.subscribe(self.set, self.modulename+"_set")
|
||||
|
||||
def uninstall(self):
|
||||
super(displayArticleInteractor, self).uninstall()
|
||||
pub.unsubscribe(self.set, self.modulename+"_set")
|
||||
|
||||
class displayPollInteractor(base.baseInteractor):
|
||||
|
||||
def set(self, control, value):
|
||||
|
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .basePost import *
|
||||
from .audio import *
|
||||
from .article import *
|
||||
from .comment import *
|
||||
from .peopleList import *
|
||||
from .poll import *
|
||||
|
47
src/presenters/displayPosts/article.py
Normal file
47
src/presenters/displayPosts/article.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Presenter to render an article from the VK mobile website.
|
||||
this is an helper class to display an article within socializer, as opposed to opening a web browser and asking the user to get there.
|
||||
"""
|
||||
import logging
|
||||
import re
|
||||
from bs4 import BeautifulSoup
|
||||
from presenters import base
|
||||
|
||||
log = logging.getLogger(__file__)
|
||||
|
||||
class displayArticlePresenter(base.basePresenter):
|
||||
def __init__(self, session, postObject, view, interactor):
|
||||
super(displayArticlePresenter, self).__init__(view=view, interactor=interactor, modulename="display_article")
|
||||
self.session = session
|
||||
self.post = postObject
|
||||
self.load_article()
|
||||
self.run()
|
||||
|
||||
def load_article(self):
|
||||
""" Loads the article in the interactor.
|
||||
This function retrieves, by using the params defined in the VK API, the web version of the article and extracts some info from it.
|
||||
this is needed because there are no public API for articles so far.
|
||||
"""
|
||||
article = self.post[0]
|
||||
# By using the vk_api's session, proxy settings are applied, thus might work in blocked countries.
|
||||
article_body = self.session.vk.session_object.http.get(article["view_url"])
|
||||
# Parse and extract text from all paragraphs.
|
||||
# ToDo: Extract all links and set those as attachments.
|
||||
soup = BeautifulSoup(article_body.text, "lxml")
|
||||
# ToDo: Article extraction require testing to see if you can add more tags beside paragraphs.
|
||||
msg = [p.get_text() for p in soup.find_all("p")]
|
||||
msg = "\n\n".join(msg)
|
||||
self.send_message("set", control="article_view", value=msg)
|
||||
self.send_message("set_title", value=article["title"])
|
||||
# Retrieve views count
|
||||
views = soup.find("div", class_="articleView__views_info")
|
||||
# This might return None if VK changes anything, so let's avoid errors.
|
||||
if views == None:
|
||||
views = str(-1)
|
||||
else:
|
||||
views = views.text
|
||||
# Find the integer and remove the words from the string.
|
||||
numbers = re.findall(r'\d+', views)
|
||||
if len(numbers) != 0:
|
||||
views = numbers[0]
|
||||
self.send_message("set", control="views", value=views)
|
@@ -15,7 +15,7 @@ from extra import SpellChecker, translator
|
||||
from mysc.thread_utils import call_threaded
|
||||
from presenters import base
|
||||
from presenters.createPosts.basePost import createPostPresenter
|
||||
from . import audio, poll
|
||||
from . import audio, poll, article
|
||||
|
||||
log = logging.getLogger(__file__)
|
||||
|
||||
@@ -351,10 +351,9 @@ class displayPostPresenter(base.basePresenter):
|
||||
elif attachment["type"] == "poll":
|
||||
a = poll.displayPollPresenter(session=self.session, poll=attachment, interactor=interactors.displayPollInteractor(), view=views.displayPoll())
|
||||
elif attachment["type"] == "article":
|
||||
output.speak(_("Opening Article in web browser..."), True)
|
||||
webbrowser.open_new_tab(attachment["article"]["url"])
|
||||
a = article.displayArticlePresenter(session=self.session, postObject=[attachment["article"]], interactor=interactors.displayArticleInteractor(), view=views.displayArticle())
|
||||
else:
|
||||
log.debug("Unhandled attachment: %r" % (attachment,))
|
||||
log.error("Unhandled attachment: %r" % (attachment,))
|
||||
|
||||
def __del__(self):
|
||||
if hasattr(self, "worker"):
|
||||
|
@@ -1,6 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Session object for Socializer. A session is the only object to call VK API methods, save settings and access to the cache database and sound playback mechanisms. """
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
import logging
|
||||
import warnings
|
||||
|
@@ -1,5 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import wx
|
||||
import widgetUtils
|
||||
|
||||
@@ -283,6 +282,76 @@ class displayAudio(widgetUtils.BaseDialog):
|
||||
def get_audio(self):
|
||||
return self.list.GetSelection()
|
||||
|
||||
class displayArticle(widgetUtils.BaseDialog):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(displayArticle, self).__init__(parent=None, *args, **kwargs)
|
||||
self.panel = wx.Panel(self, -1)
|
||||
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
article_view_box = self.create_article_view()
|
||||
self.sizer.Add(article_view_box, 0, wx.ALL, 5)
|
||||
views_box = self.create_views_control()
|
||||
self.sizer.Add(views_box, 0, wx.ALL, 5)
|
||||
attachments_box = self.create_attachments()
|
||||
self.sizer.Add(attachments_box, 0, wx.ALL, 5)
|
||||
self.attachments.list.Enable(False)
|
||||
self.create_tools_button()
|
||||
self.sizer.Add(self.tools, 0, wx.ALL, 5)
|
||||
self.sizer.Add(self.create_dialog_buttons())
|
||||
self.done()
|
||||
|
||||
def done(self):
|
||||
self.panel.SetSizer(self.sizer)
|
||||
self.SetClientSize(self.sizer.CalcMin())
|
||||
|
||||
def create_article_view(self, label=_("Article")):
|
||||
lbl = wx.StaticText(self.panel, -1, label)
|
||||
self.article_view = wx.TextCtrl(self.panel, -1, size=(730, -1), style=wx.TE_READONLY|wx.TE_MULTILINE|wx.BORDER_SIMPLE)
|
||||
selectId = wx.NewId()
|
||||
self.Bind(wx.EVT_MENU, self.onSelect, id=selectId)
|
||||
self.accel_tbl = wx.AcceleratorTable([
|
||||
(wx.ACCEL_CTRL, ord('A'), selectId),])
|
||||
self.SetAcceleratorTable(self.accel_tbl)
|
||||
box = wx.BoxSizer(wx.HORIZONTAL)
|
||||
box.Add(lbl, 0, wx.ALL, 5)
|
||||
box.Add(self.article_view, 0, wx.ALL, 5)
|
||||
return box
|
||||
|
||||
def onSelect(self, event):
|
||||
self.article_view.SelectAll()
|
||||
|
||||
def create_views_control(self):
|
||||
lbl = wx.StaticText(self.panel, -1, _("Views"))
|
||||
self.views = wx.TextCtrl(self.panel, -1, style=wx.TE_READONLY|wx.TE_MULTILINE)
|
||||
box = wx.BoxSizer(wx.HORIZONTAL)
|
||||
box.Add(lbl, 0, wx.ALL, 5)
|
||||
box.Add(self.views, 0, wx.ALL, 5)
|
||||
return box
|
||||
|
||||
def create_tools_button(self):
|
||||
self.tools = wx.Button(self.panel, -1, _("Actions"))
|
||||
|
||||
def create_dialog_buttons(self):
|
||||
self.close = wx.Button(self.panel, wx.ID_CANCEL, _("Close"))
|
||||
return self.close
|
||||
|
||||
def create_attachments(self):
|
||||
lbl = wx.StaticText(self.panel, -1, _("Attachments"))
|
||||
self.attachments = widgetUtils.list(self.panel, _("Type"), _("Title"), style=wx.LC_REPORT)
|
||||
box = wx.BoxSizer(wx.HORIZONTAL)
|
||||
box.Add(lbl, 0, wx.ALL, 5)
|
||||
box.Add(self.attachments.list, 0, wx.ALL, 5)
|
||||
return box
|
||||
|
||||
def set_article(self, text):
|
||||
if hasattr(self, "article_view"):
|
||||
self.article_view.ChangeValue(text)
|
||||
else:
|
||||
return False
|
||||
|
||||
def insert_attachments(self, attachments):
|
||||
for i in attachments:
|
||||
self.attachments.insert_item(False, *i)
|
||||
|
||||
class displayFriendship(widgetUtils.BaseDialog):
|
||||
def __init__(self):
|
||||
super(displayFriendship, self).__init__(parent=None)
|
||||
|
Reference in New Issue
Block a user