Compare commits
45 Commits
Author | SHA1 | Date | |
---|---|---|---|
ead54fce3f | |||
ae93efb17a | |||
d95dfb18fd | |||
4e3c397ce5 | |||
4e6126405f | |||
8cdec543e1 | |||
4810cbe138 | |||
8ec7fbb49e | |||
7d52ed8802 | |||
9d44d063eb | |||
d5eb9ed478 | |||
40afb6cdc2 | |||
74234476ab | |||
82c71a3bd8 | |||
5161e1c045 | |||
40052dbf3f | |||
e73d92754e | |||
6df1b80941 | |||
a9e5963b74 | |||
95671966cd | |||
a8ce7216e1 | |||
5c6829165b | |||
91eebfd895 | |||
72cc04342f | |||
75267294f9 | |||
f81d302c9a | |||
c3ab0406e4 | |||
fdcaf4e596 | |||
ca7b3eff29 | |||
f1eb640564 | |||
194ca2d380 | |||
976e90f0a0 | |||
2c836f473d | |||
f834b6046e | |||
e6087f3818 | |||
20c3df6be2 | |||
b914e4b548 | |||
f336489609 | |||
4ce2e88568 | |||
a917a6a9cd | |||
a01eabea91 | |||
605f0da751 | |||
6bd0c10ef2 | |||
a9032602bf | |||
8c03601bd2 |
@@ -21,6 +21,27 @@ test_py3:
|
|||||||
- '%PYTHON3% -m coverage report --omit="test*"'
|
- '%PYTHON3% -m coverage report --omit="test*"'
|
||||||
coverage: '/TOTAL.+ ([0-9]{1,3}%)/'
|
coverage: '/TOTAL.+ ([0-9]{1,3}%)/'
|
||||||
|
|
||||||
|
documentation:
|
||||||
|
type: deploy
|
||||||
|
tags:
|
||||||
|
- windows10
|
||||||
|
before_script:
|
||||||
|
- '%PYTHON3% -v'
|
||||||
|
script:
|
||||||
|
- copy changelog.md doc\changelog.md
|
||||||
|
- cd doc
|
||||||
|
- '%PYTHON2% documentation_importer.py'
|
||||||
|
- cd ..\src
|
||||||
|
- '%PYTHON2% ..\doc\generator.py'
|
||||||
|
- 'move documentation ..\'
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- documentation
|
||||||
|
name: socializer_documentation
|
||||||
|
expire_in: 1 day
|
||||||
|
|
||||||
alpha_python3:
|
alpha_python3:
|
||||||
type: deploy
|
type: deploy
|
||||||
tags:
|
tags:
|
||||||
|
28
changelog.md
28
changelog.md
@@ -4,6 +4,34 @@
|
|||||||
|
|
||||||
### New additions
|
### New additions
|
||||||
|
|
||||||
|
* Added "post in groups" feature. In order to do so, you need to load the posts for the group where you want to send something. Once loaded, go to the post button in the group's wall and select whether you want to post in the group's behalf or as yourself.
|
||||||
|
* In all audio buffers, it is possible to select individual tracks to be played together. In order to do so, you need to press space to start the selection of items. When selected, the item will emit a sound to indicate the change. Press space in all items you want to select/unselect. When you're focusing an already selected item it will play a sound to indicate that it is already selected. Once you're done with your selection, pressing enter in the list of tracks will start the playback of the list of items you have selected. This is a very experimental feature. More actions can be supported based in this selection method if it proves to be useful.
|
||||||
|
* In conversation buffers, it is possible to display and open wall posts sent as attachments in messages.
|
||||||
|
* In people buffers, it is possible to create a new timeline by using the context menu while focusing an user. This method will create the buffer for the selected user, as opposed to creating the buffer from the menu bar, where you have to type the username or find it in a list.
|
||||||
|
|
||||||
|
### bugfixes
|
||||||
|
|
||||||
|
* Fixed an error with two factor authentication in the recent socializer version. Now it works reliably again.
|
||||||
|
* Fixed an error when trying to attach a photo to a wall post. The error was fixed in the [vk_api](https://github.com/python273/vk_api) module and the fix was sent to the developer of the library, so he will be able to merge it in the next version. In the meantime, socializer already includes the fix for this method, so you can upload photos to wall posts normally.
|
||||||
|
* Fixed an error retrieving some group information for the current session.
|
||||||
|
* When posting in a topic, links will be posted properly.
|
||||||
|
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
* the audio player module has received some improvements:
|
||||||
|
- When there is something being played, the label of the "play" button, located in all audio buffers, will change automatically to "pause". When pressed, it will pause the song instead of starting the playback again since the beginning.
|
||||||
|
- The last change will work also in the dialog for displaying audio information. Now it's possible to play and pause an audio from such dialog.
|
||||||
|
- When playing a voice message, if a song is playing already socializer will decrease the volume so you can hear the voice message well enough. Some seconds after the message has finished, the song's volume will be restored.
|
||||||
|
* In audio buffers, you will play the focused audio when pressing enter in the item, instead of opening the audio information dialog.
|
||||||
|
* Removed some old keystrokes in socializer buffers due to better alternatives. The reason for this change is that currently you don't need to be focusing an item in a buffer for being able to use the alternative keystrokes, which makes those a better implementation.
|
||||||
|
- Control+Enter and control+Shift+Enter: superseeded by Control+P for playing (and pausing) the currently focused audio.
|
||||||
|
- F5 and F6: superseeded by Alt+down and up arrows for modifying volume.
|
||||||
|
|
||||||
|
## changes in version 0.20 (25.04.2019)
|
||||||
|
|
||||||
|
### New additions
|
||||||
|
|
||||||
* For users with multiple soundcards, there is a new tab in the preferences dialogue of Socializer, called sound. From there, you can define which soundcard will be used for input and output. [#25,](https://code.manuelcortez.net/manuelcortez/socializer/issues/25)
|
* For users with multiple soundcards, there is a new tab in the preferences dialogue of Socializer, called sound. From there, you can define which soundcard will be used for input and output. [#25,](https://code.manuelcortez.net/manuelcortez/socializer/issues/25)
|
||||||
* the audio player can seek positions in the currently playing track. You can use the menu items (located in the main menu) or use the new available keystrokes dedicated to the actions. Seeking will be made in 5 second intervals.
|
* the audio player can seek positions in the currently playing track. You can use the menu items (located in the main menu) or use the new available keystrokes dedicated to the actions. Seeking will be made in 5 second intervals.
|
||||||
* Alt+Shift+Left arrow: Seek 5 seconds backwards.
|
* Alt+Shift+Left arrow: Seek 5 seconds backwards.
|
||||||
|
@@ -3,7 +3,10 @@ wxpython==4.0.3
|
|||||||
pywin32
|
pywin32
|
||||||
pyenchant
|
pyenchant
|
||||||
markdown
|
markdown
|
||||||
vk_api
|
# For the moment we will use the modified vk_api version that does not try to include enum34 and
|
||||||
|
# already fixed the caption for wall uploaded photos.
|
||||||
|
# Hopefully I can uncomment this in the near future when my changes will get merged upstream.
|
||||||
|
#vk_api
|
||||||
bs4
|
bs4
|
||||||
configobj
|
configobj
|
||||||
pypubsub
|
pypubsub
|
||||||
@@ -19,3 +22,5 @@ git+https://code.manuelcortez.net/manuelcortez/libloader
|
|||||||
git+https://code.manuelcortez.net/manuelcortez/platform_utils
|
git+https://code.manuelcortez.net/manuelcortez/platform_utils
|
||||||
git+https://github.com/chrisnorman7/sound_lib
|
git+https://github.com/chrisnorman7/sound_lib
|
||||||
git+https://code.manuelcortez.net/manuelcortez/accessible_output2
|
git+https://code.manuelcortez.net/manuelcortez/accessible_output2
|
||||||
|
# Modified vk_api.
|
||||||
|
git+https://github.com/manuelcortez/vk_api
|
@@ -55,11 +55,12 @@ def get_non_refreshed(login, password, scope=scope):
|
|||||||
url = "https://oauth.vk.com/token"
|
url = "https://oauth.vk.com/token"
|
||||||
params = dict(grant_type="password",
|
params = dict(grant_type="password",
|
||||||
client_id=client_id, client_secret=client_secret, username=login,
|
client_id=client_id, client_secret=client_secret, username=login,
|
||||||
password=password, v=api_ver, scope=scope, lang="en", device_id=device_id)
|
password=password, v=api_ver, scope=scope, lang="en", device_id=device_id, force_sms=1)
|
||||||
# Add two factor auth later due to python's syntax.
|
# Add two factor auth later due to python's syntax.
|
||||||
params["2fa_supported"] = 1
|
params["2fa_supported"] = 1
|
||||||
headers = {'User-Agent': user_agent}
|
headers = {'User-Agent': user_agent}
|
||||||
r = requests.get(url, params=params, headers=headers)
|
r = requests.get(url, params=params, headers=headers)
|
||||||
|
log.exception(r.json())
|
||||||
# If a 401 error is raised, we need to use 2FA here.
|
# If a 401 error is raised, we need to use 2FA here.
|
||||||
# see https://vk.com/dev/auth_direct (switch lang to russian, english docs are very incomplete in the matter)
|
# see https://vk.com/dev/auth_direct (switch lang to russian, english docs are very incomplete in the matter)
|
||||||
# ToDo: this needs testing after implemented official VK tokens.
|
# ToDo: this needs testing after implemented official VK tokens.
|
||||||
|
@@ -4,24 +4,14 @@ import time
|
|||||||
import wx
|
import wx
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
|
|
||||||
code = None
|
|
||||||
remember = True
|
|
||||||
|
|
||||||
def two_factor_auth():
|
def two_factor_auth():
|
||||||
global code, remember
|
code = None
|
||||||
wx.CallAfter(get_code)
|
|
||||||
while code == None:
|
|
||||||
time.sleep(0.5)
|
|
||||||
return (code, remember)
|
|
||||||
|
|
||||||
def get_code():
|
|
||||||
global code, remember
|
|
||||||
dlg = wx.TextEntryDialog(None, _("Please provide the authentication code you have received from VK."), _("Two factor authentication code"))
|
dlg = wx.TextEntryDialog(None, _("Please provide the authentication code you have received from VK."), _("Two factor authentication code"))
|
||||||
response = dlg.ShowModal()
|
response = dlg.ShowModal()
|
||||||
if response == widgetUtils.OK:
|
if response == widgetUtils.OK:
|
||||||
code = dlg.GetValue()
|
code = dlg.GetValue()
|
||||||
dlg.Destroy()
|
dlg.Destroy()
|
||||||
dlg.Destroy()
|
return (code, True)
|
||||||
|
|
||||||
def bad_password():
|
def bad_password():
|
||||||
return wx.MessageDialog(None, _("Your password or email address are incorrect. Please fix the mistakes and try it again."), _("Wrong data"), wx.ICON_ERROR).ShowModal()
|
return wx.MessageDialog(None, _("Your password or email address are incorrect. Please fix the mistakes and try it again."), _("Wrong data"), wx.ICON_ERROR).ShowModal()
|
@@ -19,6 +19,7 @@ from requests.exceptions import ReadTimeout, ConnectionError
|
|||||||
from mutagen.id3 import ID3
|
from mutagen.id3 import ID3
|
||||||
from presenters import player
|
from presenters import player
|
||||||
from wxUI.tabs import home
|
from wxUI.tabs import home
|
||||||
|
from wxUI.dialogs import timeline
|
||||||
from sessionmanager import session, renderers, utils
|
from sessionmanager import session, renderers, utils
|
||||||
from mysc.thread_utils import call_threaded
|
from mysc.thread_utils import call_threaded
|
||||||
from wxUI import commonMessages, menus
|
from wxUI import commonMessages, menus
|
||||||
@@ -79,7 +80,7 @@ class baseBuffer(object):
|
|||||||
def insert(self, item, reversed=False):
|
def insert(self, item, reversed=False):
|
||||||
""" Add a new item to the list. Uses renderers.composefunc for parsing the dictionary and create a valid result for putting it in the list."""
|
""" Add a new item to the list. Uses renderers.composefunc for parsing the dictionary and create a valid result for putting it in the list."""
|
||||||
item_ = getattr(renderers, self.compose_function)(item, self.session)
|
item_ = getattr(renderers, self.compose_function)(item, self.session)
|
||||||
self.tab.list.insert_item(reversed, *item_)
|
wx.CallAfter(self.tab.list.insert_item, reversed, *item_)
|
||||||
|
|
||||||
def get_items(self, show_nextpage=False):
|
def get_items(self, show_nextpage=False):
|
||||||
""" Retrieve items from the VK API. This function is called repeatedly by the main controller and users could call it implicitly as well with the update buffer option.
|
""" Retrieve items from the VK API. This function is called repeatedly by the main controller and users could call it implicitly as well with the update buffer option.
|
||||||
@@ -304,11 +305,7 @@ class baseBuffer(object):
|
|||||||
|
|
||||||
def get_event(self, ev):
|
def get_event(self, ev):
|
||||||
""" Parses keyboard input in the ListCtrl and executes the event associated with user keypresses."""
|
""" Parses keyboard input in the ListCtrl and executes the event associated with user keypresses."""
|
||||||
if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown() and ev.ShiftDown(): event = "pause_audio"
|
if ev.GetKeyCode() == wx.WXK_RETURN: event = "open_post"
|
||||||
elif ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "play_audio"
|
|
||||||
elif ev.GetKeyCode() == wx.WXK_RETURN: event = "open_post"
|
|
||||||
elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down"
|
|
||||||
elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up"
|
|
||||||
else:
|
else:
|
||||||
event = None
|
event = None
|
||||||
ev.Skip()
|
ev.Skip()
|
||||||
@@ -377,7 +374,7 @@ class baseBuffer(object):
|
|||||||
else:
|
else:
|
||||||
return [post["source_id"]]
|
return [post["source_id"]]
|
||||||
|
|
||||||
def onFocus(self, *args,**kwargs):
|
def onFocus(self, event, *args,**kwargs):
|
||||||
""" Function executed when the item in a list is selected.
|
""" Function executed when the item in a list is selected.
|
||||||
For this buffer it updates the date of posts in the list."""
|
For this buffer it updates the date of posts in the list."""
|
||||||
post = self.get_post()
|
post = self.get_post()
|
||||||
@@ -386,6 +383,7 @@ class baseBuffer(object):
|
|||||||
original_date = arrow.get(post["date"])
|
original_date = arrow.get(post["date"])
|
||||||
created_at = original_date.humanize(locale=languageHandler.curLang[:2])
|
created_at = original_date.humanize(locale=languageHandler.curLang[:2])
|
||||||
self.tab.list.list.SetItem(self.tab.list.get_selected(), 2, created_at)
|
self.tab.list.list.SetItem(self.tab.list.get_selected(), 2, created_at)
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
def open_in_browser(self, *args, **kwargs):
|
def open_in_browser(self, *args, **kwargs):
|
||||||
post = self.get_post()
|
post = self.get_post()
|
||||||
@@ -478,11 +476,14 @@ class feedBuffer(baseBuffer):
|
|||||||
|
|
||||||
class communityBuffer(feedBuffer):
|
class communityBuffer(feedBuffer):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(communityBuffer, self).__init__(*args, **kwargs)
|
||||||
|
self.group_id = self.kwargs["owner_id"]
|
||||||
|
|
||||||
def create_tab(self, parent):
|
def create_tab(self, parent):
|
||||||
self.tab = home.communityTab(parent)
|
self.tab = home.communityTab(parent)
|
||||||
self.connect_events()
|
self.connect_events()
|
||||||
self.tab.name = self.name
|
self.tab.name = self.name
|
||||||
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
|
|
||||||
self.tab.post.Enable(False)
|
self.tab.post.Enable(False)
|
||||||
|
|
||||||
def connect_events(self):
|
def connect_events(self):
|
||||||
@@ -499,21 +500,41 @@ class communityBuffer(feedBuffer):
|
|||||||
""" This method retrieves community information, useful to show different parts of the community itself."""
|
""" This method retrieves community information, useful to show different parts of the community itself."""
|
||||||
if self.can_get_items:
|
if self.can_get_items:
|
||||||
# Strangely, groups.get does not return counters so we need those to show options for loading specific posts for communities.
|
# Strangely, groups.get does not return counters so we need those to show options for loading specific posts for communities.
|
||||||
self.group_info = self.session.vk.client.groups.getById(group_ids=-1*self.kwargs["owner_id"], fields="counters")[0]
|
group_info = self.session.vk.client.groups.getById(group_ids=-1*self.kwargs["owner_id"], fields="counters")[0]
|
||||||
# print(self.group_info["counters"])
|
self.session.db["group_info"][self.group_id].update(group_info)
|
||||||
|
if "can_post" in self.session.db["group_info"][self.group_id] and self.session.db["group_info"][self.group_id]["can_post"] == True:
|
||||||
|
self.tab.post.Enable(True)
|
||||||
super(communityBuffer, self).get_items(*args, **kwargs)
|
super(communityBuffer, self).get_items(*args, **kwargs)
|
||||||
|
|
||||||
|
def post(self, *args, **kwargs):
|
||||||
|
menu = wx.Menu()
|
||||||
|
user1 = self.session.get_user(self.session.user_id)
|
||||||
|
user2 = self.session.get_user(self.kwargs["owner_id"])
|
||||||
|
user = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user1))
|
||||||
|
group = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user2))
|
||||||
|
menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 1), group)
|
||||||
|
menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 0), user)
|
||||||
|
self.tab.post.PopupMenu(menu, self.tab.post.GetPosition())
|
||||||
|
|
||||||
|
def _post(self, event, from_group):
|
||||||
|
owner_id = self.kwargs["owner_id"]
|
||||||
|
user = self.session.get_user(owner_id, key="user1")
|
||||||
|
title = _("Post to {user1_nom}'s wall").format(**user)
|
||||||
|
p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createPostDialog(title=title, message="", text=""))
|
||||||
|
if hasattr(p, "text") or hasattr(p, "privacy"):
|
||||||
|
call_threaded(self.do_last, p=p, owner_id=owner_id, from_group=from_group)
|
||||||
|
|
||||||
class topicBuffer(feedBuffer):
|
class topicBuffer(feedBuffer):
|
||||||
|
|
||||||
def create_tab(self, parent):
|
def create_tab(self, parent):
|
||||||
self.tab = home.topicTab(parent)
|
self.tab = home.topicTab(parent)
|
||||||
self.connect_events()
|
self.connect_events()
|
||||||
self.tab.name = self.name
|
self.tab.name = self.name
|
||||||
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
|
if "can_create_topic" not in self.session.db["group_info"][self.kwargs["group_id"]*-1] or ("can_create_topic" in self.session.db["group_info"][self.kwargs["group_id"]*-1] and self.session.db["group_info"][self.kwargs["group_id"]*-1]["can_create_topic"] != True):
|
||||||
self.tab.post.Enable(False)
|
self.tab.post.Enable(False)
|
||||||
|
|
||||||
def onFocus(self, *args, **kwargs):
|
def onFocus(self, event, *args, **kwargs):
|
||||||
pass
|
event.Skip()
|
||||||
|
|
||||||
def open_post(self, *args, **kwargs):
|
def open_post(self, *args, **kwargs):
|
||||||
""" Opens the currently focused post."""
|
""" Opens the currently focused post."""
|
||||||
@@ -524,7 +545,6 @@ class topicBuffer(feedBuffer):
|
|||||||
|
|
||||||
def open_in_browser(self, *args, **kwargs):
|
def open_in_browser(self, *args, **kwargs):
|
||||||
post = self.get_post()
|
post = self.get_post()
|
||||||
print(post)
|
|
||||||
if post == None:
|
if post == None:
|
||||||
return
|
return
|
||||||
# In order to load the selected topic we firstly have to catch the group_id, which is present in self.kwargs
|
# In order to load the selected topic we firstly have to catch the group_id, which is present in self.kwargs
|
||||||
@@ -533,6 +553,43 @@ class topicBuffer(feedBuffer):
|
|||||||
url = "https://vk.com/topic{group_id}_{topic_id}".format(group_id=group_id, topic_id=post["id"])
|
url = "https://vk.com/topic{group_id}_{topic_id}".format(group_id=group_id, topic_id=post["id"])
|
||||||
webbrowser.open_new_tab(url)
|
webbrowser.open_new_tab(url)
|
||||||
|
|
||||||
|
def post(self, *args, **kwargs):
|
||||||
|
menu = wx.Menu()
|
||||||
|
user1 = self.session.get_user(self.session.user_id)
|
||||||
|
user2 = self.session.get_user(-1*self.kwargs["group_id"])
|
||||||
|
user = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user1))
|
||||||
|
group = menu.Append(wx.NewId(), _("Post as {user1_nom}").format(**user2))
|
||||||
|
menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 1), group)
|
||||||
|
menu.Bind(widgetUtils.MENU, lambda evt: self._post(evt, 0), user)
|
||||||
|
self.tab.post.PopupMenu(menu, self.tab.post.GetPosition())
|
||||||
|
|
||||||
|
def _post(self, event, from_group):
|
||||||
|
owner_id = self.kwargs["group_id"]
|
||||||
|
user = self.session.get_user(-1*owner_id, key="user1")
|
||||||
|
title = _("Create topic in {user1_nom}").format(**user)
|
||||||
|
p = presenters.createPostPresenter(session=self.session, interactor=interactors.createPostInteractor(), view=views.createTopicDialog(title=title, message="", text=""))
|
||||||
|
if hasattr(p, "text") or hasattr(p, "privacy"):
|
||||||
|
call_threaded(self.do_last, p=p, group_id=owner_id, from_group=from_group)
|
||||||
|
|
||||||
|
def do_last(self, p, *args, **kwargs):
|
||||||
|
title = p.view.title
|
||||||
|
msg = p.text
|
||||||
|
attachments = ""
|
||||||
|
if hasattr(p, "attachments"):
|
||||||
|
attachments = self.upload_attachments(p.attachments)
|
||||||
|
urls = utils.find_urls_in_text(msg)
|
||||||
|
if len(urls) != 0:
|
||||||
|
if len(attachments) == 0: attachments = urls[0]
|
||||||
|
else: attachments += urls[0]
|
||||||
|
msg = msg.replace(urls[0], "")
|
||||||
|
if msg != "":
|
||||||
|
kwargs.update(text=msg, title=title.GetValue())
|
||||||
|
if attachments != "":
|
||||||
|
kwargs.update(attachments=attachments)
|
||||||
|
# Determines the correct functions to call here.
|
||||||
|
post = self.session.vk.client.board.addTopic(**kwargs)
|
||||||
|
pub.sendMessage("posted", buffer=self.name)
|
||||||
|
|
||||||
class documentBuffer(feedBuffer):
|
class documentBuffer(feedBuffer):
|
||||||
can_get_items = False
|
can_get_items = False
|
||||||
|
|
||||||
@@ -543,13 +600,14 @@ class documentBuffer(feedBuffer):
|
|||||||
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
|
if hasattr(self, "can_post") and self.can_post == False and hasattr(self.tab, "post"):
|
||||||
self.tab.post.Enable(False)
|
self.tab.post.Enable(False)
|
||||||
|
|
||||||
def onFocus(self, *args,**kwargs):
|
def onFocus(self, event, *args,**kwargs):
|
||||||
post = self.get_post()
|
post = self.get_post()
|
||||||
if post == None:
|
if post == None:
|
||||||
return
|
return
|
||||||
original_date = arrow.get(post["date"])
|
original_date = arrow.get(post["date"])
|
||||||
created_at = original_date.humanize(locale=languageHandler.curLang[:2])
|
created_at = original_date.humanize(locale=languageHandler.curLang[:2])
|
||||||
self.tab.list.list.SetItem(self.tab.list.get_selected(), 4, created_at)
|
self.tab.list.list.SetItem(self.tab.list.get_selected(), 4, created_at)
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
def connect_events(self):
|
def connect_events(self):
|
||||||
super(documentBuffer, self).connect_events()
|
super(documentBuffer, self).connect_events()
|
||||||
@@ -619,9 +677,6 @@ class documentCommunityBuffer(documentBuffer):
|
|||||||
self.tab.post.Enable(False)
|
self.tab.post.Enable(False)
|
||||||
|
|
||||||
class audioBuffer(feedBuffer):
|
class audioBuffer(feedBuffer):
|
||||||
""" this buffer was supposed to be used with audio elements
|
|
||||||
but is deprecated as VK removed its audio support for third party apps."""
|
|
||||||
|
|
||||||
def create_tab(self, parent):
|
def create_tab(self, parent):
|
||||||
self.tab = home.audioTab(parent)
|
self.tab = home.audioTab(parent)
|
||||||
self.tab.name = self.name
|
self.tab.name = self.name
|
||||||
@@ -629,16 +684,38 @@ class audioBuffer(feedBuffer):
|
|||||||
if self.name == "me_audio":
|
if self.name == "me_audio":
|
||||||
self.tab.post.Enable(True)
|
self.tab.post.Enable(True)
|
||||||
|
|
||||||
|
def get_event(self, ev):
|
||||||
|
if ev.GetKeyCode() == wx.WXK_RETURN:
|
||||||
|
if len(self.tab.list.get_multiple_selection()) < 2:
|
||||||
|
event = "play_all"
|
||||||
|
else:
|
||||||
|
event = "play_audio"
|
||||||
|
else:
|
||||||
|
event = None
|
||||||
|
ev.Skip()
|
||||||
|
if event != None:
|
||||||
|
try:
|
||||||
|
getattr(self, event)(skip_pause=True)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
def connect_events(self):
|
def connect_events(self):
|
||||||
widgetUtils.connect_event(self.tab.play, widgetUtils.BUTTON_PRESSED, self.play_audio)
|
widgetUtils.connect_event(self.tab.play, widgetUtils.BUTTON_PRESSED, self.play_audio)
|
||||||
widgetUtils.connect_event(self.tab.play_all, widgetUtils.BUTTON_PRESSED, self.play_all)
|
widgetUtils.connect_event(self.tab.play_all, widgetUtils.BUTTON_PRESSED, self.play_all)
|
||||||
|
pub.subscribe(self.change_label, "playback-changed")
|
||||||
super(audioBuffer, self).connect_events()
|
super(audioBuffer, self).connect_events()
|
||||||
|
|
||||||
def play_audio(self, *args, **kwargs):
|
def play_audio(self, *args, **kwargs):
|
||||||
selected = self.tab.list.get_selected()
|
if player.player.check_is_playing() and not "skip_pause" in kwargs:
|
||||||
if selected == -1:
|
return pub.sendMessage("pause")
|
||||||
selected = 0
|
selected = self.tab.list.get_multiple_selection()
|
||||||
pub.sendMessage("play", object=self.session.db[self.name]["items"][selected])
|
if len(selected) == 0:
|
||||||
|
return
|
||||||
|
elif len(selected) == 1:
|
||||||
|
pub.sendMessage("play", object=self.session.db[self.name]["items"][selected[0]])
|
||||||
|
else:
|
||||||
|
selected_audios = [self.session.db[self.name]["items"][item] for item in selected]
|
||||||
|
pub.sendMessage("play-all", list_of_songs=selected_audios)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def play_next(self, *args, **kwargs):
|
def play_next(self, *args, **kwargs):
|
||||||
@@ -696,8 +773,8 @@ class audioBuffer(feedBuffer):
|
|||||||
# Translators: Some buffers can't use the get previous item feature due to API limitations.
|
# Translators: Some buffers can't use the get previous item feature due to API limitations.
|
||||||
output.speak(_("This buffer doesn't support getting more items."))
|
output.speak(_("This buffer doesn't support getting more items."))
|
||||||
|
|
||||||
def onFocus(self, *args, **kwargs):
|
def onFocus(self, event, *args, **kwargs):
|
||||||
pass
|
event.Skip()
|
||||||
|
|
||||||
def add_to_library(self, *args, **kwargs):
|
def add_to_library(self, *args, **kwargs):
|
||||||
post = self.get_post()
|
post = self.get_post()
|
||||||
@@ -778,6 +855,16 @@ class audioBuffer(feedBuffer):
|
|||||||
url = "https://vk.com/audio{user_id}_{post_id}".format(user_id=post["owner_id"], post_id=post["id"])
|
url = "https://vk.com/audio{user_id}_{post_id}".format(user_id=post["owner_id"], post_id=post["id"])
|
||||||
webbrowser.open_new_tab(url)
|
webbrowser.open_new_tab(url)
|
||||||
|
|
||||||
|
def change_label(self, stopped):
|
||||||
|
if hasattr(self.tab, "play"):
|
||||||
|
if stopped == False:
|
||||||
|
self.tab.play.SetLabel(_("P&ause"))
|
||||||
|
else:
|
||||||
|
self.tab.play.SetLabel(_("P&lay"))
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
pub.unsubscribe(self.change_label, "playback-changed")
|
||||||
|
|
||||||
class audioAlbum(audioBuffer):
|
class audioAlbum(audioBuffer):
|
||||||
""" this buffer was supposed to be used with audio albums
|
""" this buffer was supposed to be used with audio albums
|
||||||
but is deprecated as VK removed its audio support for third party apps."""
|
but is deprecated as VK removed its audio support for third party apps."""
|
||||||
@@ -852,8 +939,8 @@ class videoBuffer(feedBuffer):
|
|||||||
# Translators: Some buffers can't use the get previous item feature due to API limitations.
|
# Translators: Some buffers can't use the get previous item feature due to API limitations.
|
||||||
output.speak(_("This buffer doesn't support getting more items."))
|
output.speak(_("This buffer doesn't support getting more items."))
|
||||||
|
|
||||||
def onFocus(self, *args, **kwargs):
|
def onFocus(self, event, *args, **kwargs):
|
||||||
pass
|
event.Skip()
|
||||||
|
|
||||||
def add_to_library(self, *args, **kwargs):
|
def add_to_library(self, *args, **kwargs):
|
||||||
post = self.get_post()
|
post = self.get_post()
|
||||||
@@ -1056,9 +1143,9 @@ class chatBuffer(baseBuffer):
|
|||||||
if show_nextpage == False:
|
if show_nextpage == False:
|
||||||
if self.tab.history.GetValue() != "" and num > 0:
|
if self.tab.history.GetValue() != "" and num > 0:
|
||||||
v = [i for i in self.session.db[self.name]["items"][:num]]
|
v = [i for i in self.session.db[self.name]["items"][:num]]
|
||||||
[self.insert(i, False) for i in v]
|
[wx.CallAfter(self.insert, i, False) for i in v]
|
||||||
else:
|
else:
|
||||||
[self.insert(i) for i in self.session.db[self.name]["items"][:num]]
|
[wx.CallAfter(self.insert, i) for i in self.session.db[self.name]["items"][:num]]
|
||||||
else:
|
else:
|
||||||
if num > 0:
|
if num > 0:
|
||||||
# At this point we save more CPU and mathematical work if we just delete everything in the chat history and readd all messages.
|
# At this point we save more CPU and mathematical work if we just delete everything in the chat history and readd all messages.
|
||||||
@@ -1068,7 +1155,7 @@ class chatBuffer(baseBuffer):
|
|||||||
self.chats = dict()
|
self.chats = dict()
|
||||||
self.tab.history.SetValue("")
|
self.tab.history.SetValue("")
|
||||||
v = [i for i in self.session.db[self.name]["items"]]
|
v = [i for i in self.session.db[self.name]["items"]]
|
||||||
[self.insert(i) for i in v]
|
[wx.CallAfter(self.insert, i) for i in v]
|
||||||
# Now it's time to set back the focus in the post.
|
# Now it's time to set back the focus in the post.
|
||||||
for i in self.chats.keys():
|
for i in self.chats.keys():
|
||||||
if self.chats[i] == focused_post["id"]:
|
if self.chats[i] == focused_post["id"]:
|
||||||
@@ -1186,8 +1273,7 @@ class chatBuffer(baseBuffer):
|
|||||||
a = presenters.displayAudioPresenter(session=self.session, postObject=[attachment["audio"]], interactor=interactors.displayAudioInteractor(), view=views.displayAudio())
|
a = presenters.displayAudioPresenter(session=self.session, postObject=[attachment["audio"]], interactor=interactors.displayAudioInteractor(), view=views.displayAudio())
|
||||||
elif attachment["type"] == "audio_message":
|
elif attachment["type"] == "audio_message":
|
||||||
link = attachment["audio_message"]["link_mp3"]
|
link = attachment["audio_message"]["link_mp3"]
|
||||||
output.speak(_("Playing..."))
|
pub.sendMessage("play-message", message_url=link)
|
||||||
pub.sendMessage("play", object=dict(url=link), set_info=False)
|
|
||||||
elif attachment["type"] == "link":
|
elif attachment["type"] == "link":
|
||||||
output.speak(_("Opening URL..."), True)
|
output.speak(_("Opening URL..."), True)
|
||||||
webbrowser.open_new_tab(attachment["link"]["url"])
|
webbrowser.open_new_tab(attachment["link"]["url"])
|
||||||
@@ -1217,6 +1303,8 @@ class chatBuffer(baseBuffer):
|
|||||||
break
|
break
|
||||||
if url != "":
|
if url != "":
|
||||||
webbrowser.open_new_tab(url)
|
webbrowser.open_new_tab(url)
|
||||||
|
if attachment["type"] == "wall":
|
||||||
|
pub.sendMessage("open-post", post_object=attachment["wall"], controller_="displayPost")
|
||||||
else:
|
else:
|
||||||
log.debug("Unhandled attachment: %r" % (attachment,))
|
log.debug("Unhandled attachment: %r" % (attachment,))
|
||||||
|
|
||||||
@@ -1279,7 +1367,14 @@ class peopleBuffer(feedBuffer):
|
|||||||
self.tab.list.list.SetItem(self.tab.list.get_selected(), 1, online_status)
|
self.tab.list.list.SetItem(self.tab.list.get_selected(), 1, online_status)
|
||||||
|
|
||||||
def open_timeline(self, *args, **kwargs):
|
def open_timeline(self, *args, **kwargs):
|
||||||
pass
|
user = self.get_post()
|
||||||
|
if user == None:
|
||||||
|
return
|
||||||
|
a = timeline.timelineDialog([self.session.get_user(user["id"])["user1_gen"]], show_selector=False)
|
||||||
|
if a.get_response() == widgetUtils.OK:
|
||||||
|
buffer_type = a.get_buffer_type()
|
||||||
|
user_id = user["id"]
|
||||||
|
pub.sendMessage("create-timeline", user_id=user_id, buffer_type=buffer_type)
|
||||||
|
|
||||||
def get_menu(self, *args, **kwargs):
|
def get_menu(self, *args, **kwargs):
|
||||||
""" display menu for people buffers (friends and requests)"""
|
""" display menu for people buffers (friends and requests)"""
|
||||||
|
@@ -200,13 +200,14 @@ class Controller(object):
|
|||||||
if self.session.settings["load_at_startup"]["communities"] == False and force_action == False:
|
if self.session.settings["load_at_startup"]["communities"] == False and force_action == False:
|
||||||
return
|
return
|
||||||
log.debug("Create community buffers...")
|
log.debug("Create community buffers...")
|
||||||
groups= self.session.vk.client.groups.get(user_id=user_id, extended=1, count=1000)
|
groups= self.session.vk.client.groups.get(user_id=user_id, extended=1, count=1000, fields="can_post,can_create_topic")
|
||||||
self.session.groups=groups["items"]
|
self.session.groups=groups["items"]
|
||||||
# Let's feed the local database cache with new groups coming from here.
|
# Let's feed the local database cache with new groups coming from here.
|
||||||
data= dict(profiles=[], groups=self.session.groups)
|
data= dict(profiles=[], groups=self.session.groups)
|
||||||
self.session.process_usernames(data)
|
self.session.process_usernames(data)
|
||||||
if create_buffers:
|
if create_buffers:
|
||||||
for i in self.session.groups:
|
for i in self.session.groups:
|
||||||
|
self.session.db["group_info"][i["id"]*-1] = i
|
||||||
wx.CallAfter(pub.sendMessage, "create_buffer", buffer_type="communityBuffer", buffer_title=i["name"], parent_tab="communities", loadable=True, get_items=True, kwargs=dict(parent=self.window.tb, name="{0}_community".format(i["id"],), composefunc="render_status", session=self.session, endpoint="get", parent_endpoint="wall", extended=1, count=self.session.settings["buffers"]["count_for_wall_buffers"], owner_id=-1*i["id"]))
|
wx.CallAfter(pub.sendMessage, "create_buffer", buffer_type="communityBuffer", buffer_title=i["name"], parent_tab="communities", loadable=True, get_items=True, kwargs=dict(parent=self.window.tb, name="{0}_community".format(i["id"],), composefunc="render_status", session=self.session, endpoint="get", parent_endpoint="wall", extended=1, count=self.session.settings["buffers"]["count_for_wall_buffers"], owner_id=-1*i["id"]))
|
||||||
time.sleep(0.15)
|
time.sleep(0.15)
|
||||||
|
|
||||||
@@ -296,6 +297,7 @@ class Controller(object):
|
|||||||
pub.subscribe(self.create_buffer, "create_buffer")
|
pub.subscribe(self.create_buffer, "create_buffer")
|
||||||
pub.subscribe(self.user_typing, "user-typing")
|
pub.subscribe(self.user_typing, "user-typing")
|
||||||
pub.subscribe(self.get_chat, "order-sent-message")
|
pub.subscribe(self.get_chat, "order-sent-message")
|
||||||
|
pub.subscribe(self.create_timeline, "create-timeline")
|
||||||
|
|
||||||
def disconnect_events(self):
|
def disconnect_events(self):
|
||||||
log.debug("Disconnecting some events...")
|
log.debug("Disconnecting some events...")
|
||||||
@@ -307,6 +309,7 @@ class Controller(object):
|
|||||||
pub.unsubscribe(self.user_online, "user-online")
|
pub.unsubscribe(self.user_online, "user-online")
|
||||||
pub.unsubscribe(self.user_offline, "user-offline")
|
pub.unsubscribe(self.user_offline, "user-offline")
|
||||||
pub.unsubscribe(self.notify, "notify")
|
pub.unsubscribe(self.notify, "notify")
|
||||||
|
pub.subscribe(self.create_timeline, "create-timeline")
|
||||||
|
|
||||||
def in_post(self, buffer):
|
def in_post(self, buffer):
|
||||||
""" This event is triggered whenever an user requires an update in their buffers. For example after sending a post successfully.
|
""" This event is triggered whenever an user requires an update in their buffers. For example after sending a post successfully.
|
||||||
@@ -408,7 +411,7 @@ class Controller(object):
|
|||||||
if user == None:
|
if user == None:
|
||||||
log.exception("Getting user manually...")
|
log.exception("Getting user manually...")
|
||||||
user = self.session.vk.client.users.get(user_ids=event.user_id, fields="last_seen")[0]
|
user = self.session.vk.client.users.get(user_ids=event.user_id, fields="last_seen")[0]
|
||||||
online_buffer.add_person(user)
|
wx.CallAfter(online_buffer.add_person, user)
|
||||||
|
|
||||||
def user_offline(self, event):
|
def user_offline(self, event):
|
||||||
""" Sends a notification of an user logging off in VK.
|
""" Sends a notification of an user logging off in VK.
|
||||||
@@ -421,7 +424,7 @@ class Controller(object):
|
|||||||
sound = "friend_offline.ogg"
|
sound = "friend_offline.ogg"
|
||||||
self.notify(msg, sound, self.session.settings["chat"]["notifications"])
|
self.notify(msg, sound, self.session.settings["chat"]["notifications"])
|
||||||
online_friends = self.search("online_friends")
|
online_friends = self.search("online_friends")
|
||||||
online_friends.remove_person(event.user_id)
|
wx.CallAfter(online_friends.remove_person, event.user_id)
|
||||||
|
|
||||||
def notify(self, message="", sound="", type="native"):
|
def notify(self, message="", sound="", type="native"):
|
||||||
""" display a notification in Socializer.
|
""" display a notification in Socializer.
|
||||||
@@ -509,7 +512,7 @@ class Controller(object):
|
|||||||
# Let's add this to the buffer.
|
# Let's add this to the buffer.
|
||||||
# ToDo: Clean this code and test how is the database working with this set to True.
|
# ToDo: Clean this code and test how is the database working with this set to True.
|
||||||
buffer.session.db[buffer.name]["items"].append(message)
|
buffer.session.db[buffer.name]["items"].append(message)
|
||||||
buffer.insert(self.session.db[buffer.name]["items"][-1], False)
|
wx.CallAfter(buffer.insert, self.session.db[buffer.name]["items"][-1], False)
|
||||||
self.session.soundplayer.play("message_received.ogg")
|
self.session.soundplayer.play("message_received.ogg")
|
||||||
wx.CallAfter(self.reorder_buffer, buffer)
|
wx.CallAfter(self.reorder_buffer, buffer)
|
||||||
# Check if we have to read the message aloud
|
# Check if we have to read the message aloud
|
||||||
@@ -517,13 +520,34 @@ class Controller(object):
|
|||||||
rendered_message = renderers.render_message(message, self.session)
|
rendered_message = renderers.render_message(message, self.session)
|
||||||
output.speak(rendered_message[0])
|
output.speak(rendered_message[0])
|
||||||
|
|
||||||
|
def create_timeline(self, user_id, buffer_type, user=""):
|
||||||
|
if user_id == "":
|
||||||
|
user_data = self.session.vk.client.utils.resolveScreenName(screen_name=user)
|
||||||
|
if type(user_data) == list:
|
||||||
|
commonMessages.no_user_exist()
|
||||||
|
return
|
||||||
|
user_id = user_data["object_id"]
|
||||||
|
if buffer_type == "audio":
|
||||||
|
buffer = buffers.audioBuffer(parent=self.window.tb, name="{0}_audio".format(user_id,), composefunc="render_audio", session=self.session, create_tab=False, endpoint="get", parent_endpoint="audio", owner_id=user_id)
|
||||||
|
user = self.session.get_user(user_id, key="user1")
|
||||||
|
name_ = _("{user1_nom}'s audios").format(**user)
|
||||||
|
elif buffer_type == "wall":
|
||||||
|
buffer = buffers.feedBuffer(parent=self.window.tb, name="{0}_feed".format(user_id,), composefunc="render_status", session=self.session, create_tab=False, endpoint="get", parent_endpoint="wall", extended=1, count=self.session.settings["buffers"]["count_for_wall_buffers"], owner_id=user_id)
|
||||||
|
user = self.session.get_user(user_id, key="user1")
|
||||||
|
name_ = _("{user1_nom}'s posts").format(**user)
|
||||||
|
elif buffer_type == "friends":
|
||||||
|
buffer = buffers.peopleBuffer(parent=self.window.tb, name="friends_{0}".format(user_id,), composefunc="render_person", session=self.session, create_tab=False, endpoint="get", parent_endpoint="friends", count=5000, fields="uid, first_name, last_name, last_seen", user_id=user_id)
|
||||||
|
user = self.session.get_user(user_id, key="user1")
|
||||||
|
name_ = _("{user1_nom}'s friends").format(**user)
|
||||||
|
wx.CallAfter(self.complete_buffer_creation, buffer=buffer, name_=name_, position=self.window.search("timelines"))
|
||||||
|
|
||||||
### GUI events
|
### GUI events
|
||||||
# These functions are connected to GUI elements such as menus, buttons and so on.
|
# These functions are connected to GUI elements such as menus, buttons and so on.
|
||||||
def connect_gui_events(self):
|
def connect_gui_events(self):
|
||||||
widgetUtils.connect_event(self.window, widgetUtils.CLOSE_EVENT, self.exit)
|
widgetUtils.connect_event(self.window, widgetUtils.CLOSE_EVENT, self.exit)
|
||||||
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.update_buffer, menuitem=self.window.update_buffer)
|
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.update_buffer, menuitem=self.window.update_buffer)
|
||||||
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.check_for_updates, menuitem=self.window.check_for_updates)
|
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.check_for_updates, menuitem=self.window.check_for_updates)
|
||||||
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.window.about_dialog, menuitem=self.window.about)
|
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.on_about, menuitem=self.window.about)
|
||||||
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.search_audios, menuitem=self.window.search_audios)
|
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.search_audios, menuitem=self.window.search_audios)
|
||||||
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.search_videos, menuitem=self.window.search_videos)
|
widgetUtils.connect_event(self.window, widgetUtils.MENU, self.search_videos, menuitem=self.window.search_videos)
|
||||||
widgetUtils.connect_event(self.window, widgetUtils.MENU,self.remove_buffer, menuitem=self.window.remove_buffer_)
|
widgetUtils.connect_event(self.window, widgetUtils.MENU,self.remove_buffer, menuitem=self.window.remove_buffer_)
|
||||||
@@ -574,6 +598,10 @@ class Controller(object):
|
|||||||
if update == False:
|
if update == False:
|
||||||
commonMessages.no_update_available()
|
commonMessages.no_update_available()
|
||||||
|
|
||||||
|
def on_about(self, *args, **kwargs):
|
||||||
|
channel = self.session.settings["general"]["update_channel"]
|
||||||
|
self.window.about_dialog(channel)
|
||||||
|
|
||||||
def search_audios(self, *args, **kwargs):
|
def search_audios(self, *args, **kwargs):
|
||||||
dlg = searchDialogs.searchAudioDialog()
|
dlg = searchDialogs.searchAudioDialog()
|
||||||
if dlg.get_response() == widgetUtils.OK:
|
if dlg.get_response() == widgetUtils.OK:
|
||||||
@@ -656,25 +684,7 @@ class Controller(object):
|
|||||||
for i in d:
|
for i in d:
|
||||||
if i[1] == user:
|
if i[1] == user:
|
||||||
user_id = i[0]
|
user_id = i[0]
|
||||||
if user_id == "":
|
pub.sendMessage("create-timeline", user_id=user_id, buffer_type=buffertype)
|
||||||
user_data = self.session.vk.client.utils.resolveScreenName(screen_name=user)
|
|
||||||
if type(user_data) == list:
|
|
||||||
commonMessages.no_user_exist()
|
|
||||||
return
|
|
||||||
user_id = user_data["object_id"]
|
|
||||||
if buffertype == "audio":
|
|
||||||
buffer = buffers.audioBuffer(parent=self.window.tb, name="{0}_audio".format(user_id,), composefunc="render_audio", session=self.session, create_tab=False, endpoint="get", parent_endpoint="audio", owner_id=user_id)
|
|
||||||
user = self.session.get_user(user_id, key="user1")
|
|
||||||
name_ = _("{user1_nom}'s audios").format(**user)
|
|
||||||
elif buffertype == "wall":
|
|
||||||
buffer = buffers.feedBuffer(parent=self.window.tb, name="{0}_feed".format(user_id,), composefunc="render_status", session=self.session, create_tab=False, endpoint="get", parent_endpoint="wall", extended=1, count=self.session.settings["buffers"]["count_for_wall_buffers"], owner_id=user_id)
|
|
||||||
user = self.session.get_user(user_id, key="user1")
|
|
||||||
name_ = _("{user1_nom}'s posts").format(**user)
|
|
||||||
elif buffertype == "friends":
|
|
||||||
buffer = buffers.peopleBuffer(parent=self.window.tb, name="friends_{0}".format(user_id,), composefunc="render_person", session=self.session, create_tab=False, endpoint="get", parent_endpoint="friends", count=5000, fields="uid, first_name, last_name, last_seen", user_id=user_id)
|
|
||||||
user = self.session.get_user(user_id, key="user1")
|
|
||||||
name_ = _("{user1_nom}'s friends").format(**user)
|
|
||||||
wx.CallAfter(self.complete_buffer_creation, buffer=buffer, name_=name_, position=self.window.search("timelines"))
|
|
||||||
|
|
||||||
def create_audio_album(self, *args, **kwargs):
|
def create_audio_album(self, *args, **kwargs):
|
||||||
d = creation.audio_album()
|
d = creation.audio_album()
|
||||||
@@ -821,19 +831,19 @@ class Controller(object):
|
|||||||
# 2. If the group_info does not have counters for such items, which would indicate there are no items posted yet.
|
# 2. If the group_info does not have counters for such items, which would indicate there are no items posted yet.
|
||||||
if self.search(current_buffer.name+"_audios") != False:
|
if self.search(current_buffer.name+"_audios") != False:
|
||||||
menu.load_audios.Enable(False)
|
menu.load_audios.Enable(False)
|
||||||
elif hasattr(current_buffer, "group_info") and "audios" not in current_buffer.group_info["counters"]:
|
elif "counters" in self.session.db["group_info"][current_buffer.group_id] and "audios" not in self.session.db["group_info"][current_buffer.group_id]["counters"]:
|
||||||
menu.load_audios.Enable(False)
|
menu.load_audios.Enable(False)
|
||||||
if self.search(current_buffer.name+"_videos") != False:
|
if self.search(current_buffer.name+"_videos") != False:
|
||||||
menu.load_videos.Enable(False)
|
menu.load_videos.Enable(False)
|
||||||
elif hasattr(current_buffer, "group_info") and "videos" not in current_buffer.group_info["counters"]:
|
elif "counters" in self.session.db["group_info"][current_buffer.group_id] and "videos" not in self.session.db["group_info"][current_buffer.group_id]["counters"]:
|
||||||
menu.load_videos.Enable(False)
|
menu.load_videos.Enable(False)
|
||||||
if self.search(current_buffer.name+"_topics") != False:
|
if self.search(current_buffer.name+"_topics") != False:
|
||||||
menu.load_topics.Enable(False)
|
menu.load_topics.Enable(False)
|
||||||
elif hasattr(current_buffer, "group_info") and "topics" not in current_buffer.group_info["counters"]:
|
elif "counters" in self.session.db["group_info"][current_buffer.group_id] and "topics" not in self.session.db["group_info"][current_buffer.group_id]["counters"]:
|
||||||
menu.load_topics.Enable(False)
|
menu.load_topics.Enable(False)
|
||||||
if self.search(current_buffer.name+"_documents") != False:
|
if self.search(current_buffer.name+"_documents") != False:
|
||||||
menu.load_documents.Enable(False)
|
menu.load_documents.Enable(False)
|
||||||
elif hasattr(current_buffer, "group_info") and "docs" not in current_buffer.group_info["counters"]:
|
elif "counters" in self.session.db["group_info"][current_buffer.group_id] and "docs" not in self.session.db["group_info"][current_buffer.group_id]["counters"]:
|
||||||
menu.load_documents.Enable(False)
|
menu.load_documents.Enable(False)
|
||||||
# Connect the rest of the functions.
|
# Connect the rest of the functions.
|
||||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.load_community_posts, menuitem=menu.load_posts)
|
widgetUtils.connect_event(menu, widgetUtils.MENU, self.load_community_posts, menuitem=menu.load_posts)
|
||||||
@@ -888,10 +898,10 @@ class Controller(object):
|
|||||||
""" Load community audios if they are not loaded already."""
|
""" Load community audios if they are not loaded already."""
|
||||||
current_buffer = self.get_current_buffer()
|
current_buffer = self.get_current_buffer()
|
||||||
# Get group_info if the community buffer does not have it already, so future menus will be able to use it.
|
# Get group_info if the community buffer does not have it already, so future menus will be able to use it.
|
||||||
if not hasattr(current_buffer, "group_info"):
|
if current_buffer.group_id not in self.session.db["group_info"] or "counters" not in self.session.db["group_info"][current_buffer.group_id]:
|
||||||
group_info = self.session.vk.client.groups.getById(group_ids=-1*current_buffer.kwargs["owner_id"], fields="counters")[0]
|
group_info = self.session.vk.client.groups.getById(group_ids=-1*current_buffer.kwargs["owner_id"], fields="counters,can_create_topics,can_post")[0]
|
||||||
current_buffer.group_info = group_info
|
self.session.db["group_info"][current_buffer.kwargs["owner_id"]].update(group_info)
|
||||||
if "audios" not in current_buffer.group_info["counters"]:
|
if "audios" not in self.session.db["group_info"][current_buffer.group_id]["counters"]:
|
||||||
commonMessages.community_no_items()
|
commonMessages.community_no_items()
|
||||||
return
|
return
|
||||||
new_name = current_buffer.name+"_audios"
|
new_name = current_buffer.name+"_audios"
|
||||||
@@ -901,10 +911,10 @@ class Controller(object):
|
|||||||
""" Load community videos if they are not loaded already."""
|
""" Load community videos if they are not loaded already."""
|
||||||
current_buffer = self.get_current_buffer()
|
current_buffer = self.get_current_buffer()
|
||||||
# Get group_info if the community buffer does not have it already, so future menus will be able to use it.
|
# Get group_info if the community buffer does not have it already, so future menus will be able to use it.
|
||||||
if not hasattr(current_buffer, "group_info"):
|
if current_buffer.group_id not in self.session.db["group_info"] or "counters" not in self.session.db["group_info"][current_buffer.group_id]:
|
||||||
group_info = self.session.vk.client.groups.getById(group_ids=-1*current_buffer.kwargs["owner_id"], fields="counters")[0]
|
group_info = self.session.vk.client.groups.getById(group_ids=-1*current_buffer.kwargs["owner_id"], fields="counters,can_create_topics,can_post")[0]
|
||||||
current_buffer.group_info = group_info
|
self.session.db["group_info"][current_buffer.kwargs["owner_id"]].update(group_info)
|
||||||
if "videos" not in current_buffer.group_info["counters"]:
|
if "videos" not in self.session.db["group_info"][current_buffer.group_id]["counters"]:
|
||||||
commonMessages.community_no_items()
|
commonMessages.community_no_items()
|
||||||
return
|
return
|
||||||
new_name = current_buffer.name+"_videos"
|
new_name = current_buffer.name+"_videos"
|
||||||
@@ -914,10 +924,10 @@ class Controller(object):
|
|||||||
""" Load community topics."""
|
""" Load community topics."""
|
||||||
current_buffer = self.get_current_buffer()
|
current_buffer = self.get_current_buffer()
|
||||||
# Get group_info if the community buffer does not have it already, so future menus will be able to use it.
|
# Get group_info if the community buffer does not have it already, so future menus will be able to use it.
|
||||||
if not hasattr(current_buffer, "group_info"):
|
if current_buffer.group_id not in self.session.db["group_info"] or "counters" not in self.session.db["group_info"][current_buffer.group_id]:
|
||||||
group_info = self.session.vk.client.groups.getById(group_ids=-1*current_buffer.kwargs["owner_id"], fields="counters")[0]
|
group_info = self.session.vk.client.groups.getById(group_ids=-1*current_buffer.kwargs["owner_id"], fields="counters,can_create_topic,can_post")[0]
|
||||||
current_buffer.group_info = group_info
|
self.session.db["group_info"][current_buffer.kwargs["owner_id"]].update(group_info)
|
||||||
if "topics" not in current_buffer.group_info["counters"]:
|
if "topics" not in self.session.db["group_info"][current_buffer.group_id]["counters"]:
|
||||||
commonMessages.community_no_items()
|
commonMessages.community_no_items()
|
||||||
return
|
return
|
||||||
new_name = current_buffer.name+"_topics"
|
new_name = current_buffer.name+"_topics"
|
||||||
@@ -926,10 +936,10 @@ class Controller(object):
|
|||||||
def load_community_documents(self, *args, **kwargs):
|
def load_community_documents(self, *args, **kwargs):
|
||||||
current_buffer = self.get_current_buffer()
|
current_buffer = self.get_current_buffer()
|
||||||
# Get group_info if the community buffer does not have it already, so future menus will be able to use it.
|
# Get group_info if the community buffer does not have it already, so future menus will be able to use it.
|
||||||
if not hasattr(current_buffer, "group_info"):
|
if current_buffer.group_id not in self.session.db["group_info"] or "counters" not in self.session.db["group_info"][current_buffer.group_id]:
|
||||||
group_info = self.session.vk.client.groups.getById(group_ids=-1*current_buffer.kwargs["owner_id"], fields="counters")[0]
|
group_info = self.session.vk.client.groups.getById(group_ids=-1*current_buffer.kwargs["owner_id"], fields="counters,can_create_topics,can_post")[0]
|
||||||
current_buffer.group_info = group_info
|
self.session.db["group_info"][current_buffer.kwargs["owner_id"]].update(group_info)
|
||||||
if "docs" not in current_buffer.group_info["counters"]:
|
if "docs" not in self.session.db["group_info"][current_buffer.group_id]["counters"]:
|
||||||
commonMessages.community_no_items()
|
commonMessages.community_no_items()
|
||||||
return
|
return
|
||||||
new_name = current_buffer.name+"_documents"
|
new_name = current_buffer.name+"_documents"
|
||||||
|
@@ -59,8 +59,6 @@ class configurationInteractor(base.baseInteractor):
|
|||||||
self.presenter.update_setting(section="general", setting="update_channel", value=update_channel)
|
self.presenter.update_setting(section="general", setting="update_channel", value=update_channel)
|
||||||
self.presenter.update_setting(section="chat", setting="notify_online", value=self.view.get_value("chat", "notify_online"))
|
self.presenter.update_setting(section="chat", setting="notify_online", value=self.view.get_value("chat", "notify_online"))
|
||||||
self.presenter.update_setting(section="chat", setting="notify_offline", value=self.view.get_value("chat", "notify_offline"))
|
self.presenter.update_setting(section="chat", setting="notify_offline", value=self.view.get_value("chat", "notify_offline"))
|
||||||
self.presenter.update_setting(section="chat", setting="open_unread_conversations", value=self.view.get_value("chat", "open_unread_conversations"))
|
|
||||||
self.presenter.update_setting(section="chat", setting="automove_to_conversations", value=self.view.get_value("chat", "automove_to_conversations"))
|
|
||||||
self.presenter.update_setting(section="chat", setting="notifications", value=self.presenter.get_notification_type(self.view.get_value("chat", "notifications")))
|
self.presenter.update_setting(section="chat", setting="notifications", value=self.presenter.get_notification_type(self.view.get_value("chat", "notifications")))
|
||||||
self.presenter.update_setting(section="load_at_startup", setting="audio_albums", value=self.view.get_value("startup", "audio_albums"))
|
self.presenter.update_setting(section="load_at_startup", setting="audio_albums", value=self.view.get_value("startup", "audio_albums"))
|
||||||
self.presenter.update_setting(section="load_at_startup", setting="video_albums", value=self.view.get_value("startup", "video_albums"))
|
self.presenter.update_setting(section="load_at_startup", setting="video_albums", value=self.view.get_value("startup", "video_albums"))
|
||||||
|
@@ -171,6 +171,13 @@ class displayAudioInteractor(base.baseInteractor):
|
|||||||
getattr(self.view, control).Append(i)
|
getattr(self.view, control).Append(i)
|
||||||
getattr(self.view, control).SetSelection(0)
|
getattr(self.view, control).SetSelection(0)
|
||||||
|
|
||||||
|
def change_label(self, stopped):
|
||||||
|
|
||||||
|
if stopped == False:
|
||||||
|
self.view.play.SetLabel(_("P&ause"))
|
||||||
|
else:
|
||||||
|
self.view.play.SetLabel(_("P&lay"))
|
||||||
|
|
||||||
def install(self, *args, **kwargs):
|
def install(self, *args, **kwargs):
|
||||||
super(displayAudioInteractor, self).install(*args, **kwargs)
|
super(displayAudioInteractor, self).install(*args, **kwargs)
|
||||||
widgetUtils.connect_event(self.view.list, widgetUtils.LISTBOX_CHANGED, self.on_change)
|
widgetUtils.connect_event(self.view.list, widgetUtils.LISTBOX_CHANGED, self.on_change)
|
||||||
@@ -180,11 +187,13 @@ class displayAudioInteractor(base.baseInteractor):
|
|||||||
widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.on_remove_from_library)
|
widgetUtils.connect_event(self.view.remove, widgetUtils.BUTTON_PRESSED, self.on_remove_from_library)
|
||||||
pub.subscribe(self.set, self.modulename+"_set")
|
pub.subscribe(self.set, self.modulename+"_set")
|
||||||
pub.subscribe(self.add_items, self.modulename+"_add_items")
|
pub.subscribe(self.add_items, self.modulename+"_add_items")
|
||||||
|
pub.subscribe(self.change_label, "playback-changed")
|
||||||
|
|
||||||
def uninstall(self):
|
def uninstall(self):
|
||||||
super(displayAudioInteractor, self).uninstall()
|
super(displayAudioInteractor, self).uninstall()
|
||||||
pub.unsubscribe(self.set, self.modulename+"_set")
|
pub.unsubscribe(self.set, self.modulename+"_set")
|
||||||
pub.unsubscribe(self.add_items, self.modulename+"_add_items")
|
pub.unsubscribe(self.add_items, self.modulename+"_add_items")
|
||||||
|
pub.unsubscribe(self.change_label, "playback-changed")
|
||||||
|
|
||||||
def on_change(self, *args, **kwargs):
|
def on_change(self, *args, **kwargs):
|
||||||
post = self.view.get_audio()
|
post = self.view.get_audio()
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -59,8 +59,6 @@ class configurationPresenter(base.basePresenter):
|
|||||||
self.send_message("create_tab", tab="chat")
|
self.send_message("create_tab", tab="chat")
|
||||||
self.send_message("set", tab="chat", setting="notify_online", value=self.session.settings["chat"]["notify_online"])
|
self.send_message("set", tab="chat", setting="notify_online", value=self.session.settings["chat"]["notify_online"])
|
||||||
self.send_message("set", tab="chat", setting="notify_offline", value=self.session.settings["chat"]["notify_offline"])
|
self.send_message("set", tab="chat", setting="notify_offline", value=self.session.settings["chat"]["notify_offline"])
|
||||||
self.send_message("set", tab="chat", setting="open_unread_conversations", value=self.session.settings["chat"]["open_unread_conversations"])
|
|
||||||
self.send_message("set", tab="chat", setting="automove_to_conversations", value=self.session.settings["chat"]["automove_to_conversations"])
|
|
||||||
self.send_message("set", tab="chat", setting="notifications", value=self.get_notification_label(self.session.settings["chat"]["notifications"]))
|
self.send_message("set", tab="chat", setting="notifications", value=self.get_notification_label(self.session.settings["chat"]["notifications"]))
|
||||||
self.send_message("create_tab", tab="startup_options")
|
self.send_message("create_tab", tab="startup_options")
|
||||||
self.send_message("set", tab="startup", setting="audio_albums", value=self.session.settings["load_at_startup"]["audio_albums"])
|
self.send_message("set", tab="startup", setting="audio_albums", value=self.session.settings["load_at_startup"]["audio_albums"])
|
||||||
|
@@ -3,7 +3,7 @@ import logging
|
|||||||
from sessionmanager import utils
|
from sessionmanager import utils
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
from mysc.thread_utils import call_threaded
|
from mysc.thread_utils import call_threaded
|
||||||
from presenters import base
|
from presenters import base, player
|
||||||
|
|
||||||
log = logging.getLogger(__file__)
|
log = logging.getLogger(__file__)
|
||||||
|
|
||||||
@@ -82,6 +82,8 @@ class displayAudioPresenter(base.basePresenter):
|
|||||||
|
|
||||||
def play(self, audio_index):
|
def play(self, audio_index):
|
||||||
post = self.post[audio_index]
|
post = self.post[audio_index]
|
||||||
|
if player.player.check_is_playing() == True:
|
||||||
|
return pub.sendMessage("stop")
|
||||||
pub.sendMessage("play", object=post)
|
pub.sendMessage("play", object=post)
|
||||||
|
|
||||||
def load_audios(self):
|
def load_audios(self):
|
||||||
|
@@ -115,11 +115,6 @@ class displayTopicPresenter(basePost.displayPostPresenter):
|
|||||||
attachments = ""
|
attachments = ""
|
||||||
if hasattr(comment, "attachments"):
|
if hasattr(comment, "attachments"):
|
||||||
attachments = self.upload_attachments(comment.attachments)
|
attachments = self.upload_attachments(comment.attachments)
|
||||||
urls = utils.find_urls_in_text(msg)
|
|
||||||
if len(urls) != 0:
|
|
||||||
if len(attachments) == 0: attachments = urls[0]
|
|
||||||
else: attachments += urls[0]
|
|
||||||
msg = msg.replace(urls[0], "")
|
|
||||||
if msg != "":
|
if msg != "":
|
||||||
kwargs.update(message=msg)
|
kwargs.update(message=msg)
|
||||||
if attachments != "":
|
if attachments != "":
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
As this player does not have (still) an associated GUI, I have decided to place here the code for the interactor, which connects a bunch of pubsub events, and the presenter itself.
|
As this player does not have (still) an associated GUI, I have decided to place here the code for the interactor, which connects a bunch of pubsub events, and the presenter itself.
|
||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
import random
|
import random
|
||||||
import logging
|
import logging
|
||||||
import sound_lib
|
import sound_lib
|
||||||
@@ -19,7 +20,6 @@ from sessionmanager import utils
|
|||||||
player = None
|
player = None
|
||||||
log = logging.getLogger("player")
|
log = logging.getLogger("player")
|
||||||
|
|
||||||
# This function will be deprecated when the player works with pubsub events, as will no longer be needed to instantiate and import the player directly.
|
|
||||||
def setup():
|
def setup():
|
||||||
global player
|
global player
|
||||||
if player == None:
|
if player == None:
|
||||||
@@ -34,6 +34,7 @@ class audioPlayer(object):
|
|||||||
self.is_playing = False
|
self.is_playing = False
|
||||||
# This will be the URLStream handler
|
# This will be the URLStream handler
|
||||||
self.stream = None
|
self.stream = None
|
||||||
|
self.message = None
|
||||||
self.vol = config.app["sound"]["volume"]
|
self.vol = config.app["sound"]["volume"]
|
||||||
# this variable is set to true when the URLPlayer is decoding something, thus it will block other calls to the play method.
|
# this variable is set to true when the URLPlayer is decoding something, thus it will block other calls to the play method.
|
||||||
self.is_working = False
|
self.is_working = False
|
||||||
@@ -41,13 +42,18 @@ class audioPlayer(object):
|
|||||||
self.queue = []
|
self.queue = []
|
||||||
# Index of the currently playing track.
|
# Index of the currently playing track.
|
||||||
self.playing_track = 0
|
self.playing_track = 0
|
||||||
|
self.playing_all = False
|
||||||
|
self.worker = RepeatingTimer(5, self.player_function)
|
||||||
|
self.worker.start()
|
||||||
# Status of the player.
|
# Status of the player.
|
||||||
self.stopped = True
|
self.stopped = True
|
||||||
# Modify some default settings present in Bass so it will increase timeout connection, thus causing less "connection timed out" errors when playing.
|
# Modify some default settings present in Bass so it will increase timeout connection, thus causing less "connection timed out" errors when playing.
|
||||||
bassconfig = BassConfig()
|
bassconfig = BassConfig()
|
||||||
# Set timeout connection to 30 seconds.
|
# Set timeout connection to 30 seconds.
|
||||||
bassconfig["net_timeout"] = 30000
|
bassconfig["net_timeout"] = 30000
|
||||||
|
# subscribe all pubsub events.
|
||||||
pub.subscribe(self.play, "play")
|
pub.subscribe(self.play, "play")
|
||||||
|
pub.subscribe(self.play_message, "play-message")
|
||||||
pub.subscribe(self.play_all, "play-all")
|
pub.subscribe(self.play_all, "play-all")
|
||||||
pub.subscribe(self.pause, "pause")
|
pub.subscribe(self.pause, "pause")
|
||||||
pub.subscribe(self.stop, "stop")
|
pub.subscribe(self.stop, "stop")
|
||||||
@@ -55,6 +61,18 @@ class audioPlayer(object):
|
|||||||
pub.subscribe(self.play_previous, "play-previous")
|
pub.subscribe(self.play_previous, "play-previous")
|
||||||
pub.subscribe(self.seek, "seek")
|
pub.subscribe(self.seek, "seek")
|
||||||
|
|
||||||
|
# Stopped has a special function here, hence the decorator
|
||||||
|
# when stopped will be set to True, it will send a pubsub event to inform other parts of the application about the status change.
|
||||||
|
# this is useful for changing labels between play and pause, and so on, in buttons.
|
||||||
|
@property
|
||||||
|
def stopped(self):
|
||||||
|
return self._stopped
|
||||||
|
|
||||||
|
@stopped.setter
|
||||||
|
def stopped(self, value):
|
||||||
|
self._stopped = value
|
||||||
|
pub.sendMessage("playback-changed", stopped=value)
|
||||||
|
|
||||||
def play(self, object, set_info=True, fresh=False):
|
def play(self, object, set_info=True, fresh=False):
|
||||||
""" Play an URl Stream.
|
""" Play an URl Stream.
|
||||||
@object dict: typically an audio object as returned by VK, with a "url" component which must be a valid URL to a media file.
|
@object dict: typically an audio object as returned by VK, with a "url" component which must be a valid URL to a media file.
|
||||||
@@ -70,9 +88,7 @@ class audioPlayer(object):
|
|||||||
log.exception("error when stopping the file")
|
log.exception("error when stopping the file")
|
||||||
self.stream = None
|
self.stream = None
|
||||||
self.stopped = True
|
self.stopped = True
|
||||||
if fresh == True and hasattr(self, "worker") and self.worker != None:
|
if fresh == True:
|
||||||
self.worker.cancel()
|
|
||||||
self.worker = None
|
|
||||||
self.queue = []
|
self.queue = []
|
||||||
# Make sure that there are no other sounds trying to be played.
|
# Make sure that there are no other sounds trying to be played.
|
||||||
if self.is_working == False:
|
if self.is_working == False:
|
||||||
@@ -94,16 +110,41 @@ class audioPlayer(object):
|
|||||||
self.stopped = False
|
self.stopped = False
|
||||||
self.is_working = False
|
self.is_working = False
|
||||||
|
|
||||||
|
def play_message(self, message_url):
|
||||||
|
if self.message != None and (self.message.is_playing == True or self.message.is_stalled == True):
|
||||||
|
return self.stop_message()
|
||||||
|
output.speak(_("Playing..."))
|
||||||
|
url_ = utils.transform_audio_url(message_url)
|
||||||
|
url_ = bytes(url_, "utf-8")
|
||||||
|
try:
|
||||||
|
self.message = URLStream(url=url_)
|
||||||
|
except:
|
||||||
|
log.error("Unable to play URL %s" % (url_))
|
||||||
|
return
|
||||||
|
self.message.volume = self.vol/100.0
|
||||||
|
self.message.play()
|
||||||
|
volume_percent = self.volume*0.25
|
||||||
|
volume_step = self.volume*0.15
|
||||||
|
while self.stream.volume*100 > volume_percent:
|
||||||
|
self.stream.volume = self.stream.volume-(volume_step/100)
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
""" Stop audio playback. """
|
""" Stop audio playback. """
|
||||||
if self.stream != None and self.stream.is_playing == True:
|
if self.stream != None and self.stream.is_playing == True:
|
||||||
self.stream.stop()
|
self.stream.stop()
|
||||||
self.stopped = True
|
self.stopped = True
|
||||||
if hasattr(self, "worker") and self.worker != None:
|
|
||||||
self.worker.cancel()
|
|
||||||
self.worker = None
|
|
||||||
self.queue = []
|
self.queue = []
|
||||||
|
|
||||||
|
def stop_message(self):
|
||||||
|
if hasattr(self, "message") and self.message != None and self.message.is_playing == True:
|
||||||
|
self.message.stop()
|
||||||
|
volume_step = self.volume*0.15
|
||||||
|
while self.stream.volume*100 < self.volume:
|
||||||
|
self.stream.volume = self.stream.volume+(volume_step/100)
|
||||||
|
time.sleep(0.1)
|
||||||
|
self.message = None
|
||||||
|
|
||||||
def pause(self):
|
def pause(self):
|
||||||
""" pause the current playback, without destroying the queue or the current stream. If the stream is already paused this function will resume the playback. """
|
""" pause the current playback, without destroying the queue or the current stream. If the stream is already paused this function will resume the playback. """
|
||||||
if self.stream != None:
|
if self.stream != None:
|
||||||
@@ -116,6 +157,8 @@ class audioPlayer(object):
|
|||||||
self.stopped = False
|
self.stopped = False
|
||||||
except BassError:
|
except BassError:
|
||||||
pass
|
pass
|
||||||
|
if self.playing_all == False and len(self.queue) > 0:
|
||||||
|
self.playing_all = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def volume(self):
|
def volume(self):
|
||||||
@@ -130,6 +173,10 @@ class audioPlayer(object):
|
|||||||
elif vol > 100:
|
elif vol > 100:
|
||||||
self.vol = 100
|
self.vol = 100
|
||||||
if self.stream != None:
|
if self.stream != None:
|
||||||
|
if self.message != None and self.message.is_playing:
|
||||||
|
self.stream.volume = (self.vol*0.25)/100.0
|
||||||
|
self.message.volume = self.vol/100.0
|
||||||
|
else:
|
||||||
self.stream.volume = self.vol/100.0
|
self.stream.volume = self.vol/100.0
|
||||||
|
|
||||||
def play_all(self, list_of_songs, shuffle=False):
|
def play_all(self, list_of_songs, shuffle=False):
|
||||||
@@ -145,16 +192,24 @@ class audioPlayer(object):
|
|||||||
if shuffle:
|
if shuffle:
|
||||||
random.shuffle(self.queue)
|
random.shuffle(self.queue)
|
||||||
call_threaded(self.play, self.queue[self.playing_track])
|
call_threaded(self.play, self.queue[self.playing_track])
|
||||||
self.worker = RepeatingTimer(5, self.player_function)
|
self.playing_all = True
|
||||||
self.worker.start()
|
|
||||||
|
|
||||||
def player_function(self):
|
def player_function(self):
|
||||||
""" Check if the stream has reached the end of the file so it will play the next song. """
|
""" Check if the stream has reached the end of the file so it will play the next song. """
|
||||||
|
if self.message != None and self.message.is_playing == False and len(self.message) == self.message.position:
|
||||||
|
volume_step = self.volume*0.15
|
||||||
|
while self.stream.volume*100 < self.volume:
|
||||||
|
self.stream.volume = self.stream.volume+(volume_step/100)
|
||||||
|
time.sleep(0.1)
|
||||||
if self.stream != None and self.stream.is_playing == False and self.stopped == False and len(self.stream) == self.stream.position:
|
if self.stream != None and self.stream.is_playing == False and self.stopped == False and len(self.stream) == self.stream.position:
|
||||||
if len(self.queue) == 0 or self.playing_track >= len(self.queue):
|
if self.playing_track >= len(self.queue):
|
||||||
self.worker.cancel()
|
self.stopped = True
|
||||||
|
self.playing_all = False
|
||||||
return
|
return
|
||||||
if self.playing_track < len(self.queue):
|
elif self.playing_all == False:
|
||||||
|
self.stopped = True
|
||||||
|
return
|
||||||
|
elif self.playing_track < len(self.queue):
|
||||||
self.playing_track += 1
|
self.playing_track += 1
|
||||||
self.play(self.queue[self.playing_track])
|
self.play(self.queue[self.playing_track])
|
||||||
|
|
||||||
|
@@ -20,8 +20,6 @@ count_for_audio_buffers = integer(default=1000)
|
|||||||
[chat]
|
[chat]
|
||||||
notify_online = boolean(default=True)
|
notify_online = boolean(default=True)
|
||||||
notify_offline = boolean(default=True)
|
notify_offline = boolean(default=True)
|
||||||
open_unread_conversations = boolean(default=True)
|
|
||||||
automove_to_conversations = boolean(default=False)
|
|
||||||
notifications = string(default="custom")
|
notifications = string(default="custom")
|
||||||
|
|
||||||
[load_at_startup]
|
[load_at_startup]
|
||||||
|
@@ -75,6 +75,14 @@ def add_attachment(attachment):
|
|||||||
elif attachment["type"] == "poll":
|
elif attachment["type"] == "poll":
|
||||||
tpe = _("Poll")
|
tpe = _("Poll")
|
||||||
msg = attachment["poll"]["question"]
|
msg = attachment["poll"]["question"]
|
||||||
|
elif attachment["type"] == "wall":
|
||||||
|
tpe = _("Post")
|
||||||
|
user = attachment["wall"]["from"]["name"]
|
||||||
|
if len(attachment["wall"]["text"]) > 140:
|
||||||
|
text = attachment["wall"]["text"][:145]+"..."
|
||||||
|
else:
|
||||||
|
text = attachment["wall"]["text"]
|
||||||
|
msg = _("{user}: {post}").format(user=user, post=text)
|
||||||
else:
|
else:
|
||||||
print(attachment)
|
print(attachment)
|
||||||
return [tpe, msg]
|
return [tpe, msg]
|
||||||
|
@@ -40,7 +40,8 @@ def find_item(list, item):
|
|||||||
break
|
break
|
||||||
if identifier == None:
|
if identifier == None:
|
||||||
# if there are objects that can't be processed by lack of identifier, let's print keys for finding one.
|
# if there are objects that can't be processed by lack of identifier, let's print keys for finding one.
|
||||||
log.exception("Can't find an identifier for the following object: %r" % (list(item.keys()),))
|
log.exception("Can't find an identifier for the following object: %r" % (item.keys(),))
|
||||||
|
return False
|
||||||
for i in list:
|
for i in list:
|
||||||
if identifier in i and i[identifier] == item[identifier]:
|
if identifier in i and i[identifier] == item[identifier]:
|
||||||
return True
|
return True
|
||||||
@@ -53,7 +54,7 @@ class vkSession(object):
|
|||||||
""" Put new items on the local cache database.
|
""" Put new items on the local cache database.
|
||||||
@name str: The name for the buffer stored in the dictionary.
|
@name str: The name for the buffer stored in the dictionary.
|
||||||
@data list: A list with items and some information about cursors.
|
@data list: A list with items and some information about cursors.
|
||||||
returns the number of items that has been added in this execution"""
|
returns the number of items that have been added in this execution"""
|
||||||
global post_types
|
global post_types
|
||||||
# When this method is called by friends.getOnlyne, it gives only friend IDS so we need to retrieve full objects from VK.
|
# When this method is called by friends.getOnlyne, it gives only friend IDS so we need to retrieve full objects from VK.
|
||||||
# ToDo: It would be nice to investigate whether reusing some existing objects would be a good idea, whenever possible.
|
# ToDo: It would be nice to investigate whether reusing some existing objects would be a good idea, whenever possible.
|
||||||
@@ -101,6 +102,7 @@ class vkSession(object):
|
|||||||
self.db = {}
|
self.db = {}
|
||||||
self.db["users"] = {}
|
self.db["users"] = {}
|
||||||
self.db["groups"] = {}
|
self.db["groups"] = {}
|
||||||
|
self.db["group_info"] = {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_logged(self):
|
def is_logged(self):
|
||||||
@@ -115,9 +117,13 @@ class vkSession(object):
|
|||||||
log.debug("Creating config file %s" % (file_,))
|
log.debug("Creating config file %s" % (file_,))
|
||||||
self.settings = Configuration(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), "session.defaults"))
|
self.settings = Configuration(os.path.join(paths.config_path(), file_), os.path.join(paths.app_path(), "session.defaults"))
|
||||||
self.soundplayer = sound.soundSystem(config.app["sound"])
|
self.soundplayer = sound.soundSystem(config.app["sound"])
|
||||||
|
pub.subscribe(self.play_sound, "play-sound")
|
||||||
# except:
|
# except:
|
||||||
# log.exception("The session configuration has failed.")
|
# log.exception("The session configuration has failed.")
|
||||||
|
|
||||||
|
def play_sound(self, sound):
|
||||||
|
self.soundplayer.play(sound)
|
||||||
|
|
||||||
def login(self):
|
def login(self):
|
||||||
""" Logging in VK.com. This is basically the first method interacting with VK. """
|
""" Logging in VK.com. This is basically the first method interacting with VK. """
|
||||||
# If user is already logged in, we should skip this method.
|
# If user is already logged in, we should skip this method.
|
||||||
@@ -258,6 +264,10 @@ class vkSession(object):
|
|||||||
k = "{key}_{case}".format(key=key, case=i)
|
k = "{key}_{case}".format(key=key, case=i)
|
||||||
v = self.db["groups"][abs(user_id)][i]
|
v = self.db["groups"][abs(user_id)][i]
|
||||||
user_data[k] = v
|
user_data[k] = v
|
||||||
|
else:
|
||||||
|
group = self.vk.client.groups.getById(group_ids=-1*user_id)[0]
|
||||||
|
self.process_usernames(data=dict(profiles=[], groups=[group]))
|
||||||
|
return self.get_user(user_id=user_id, key=key)
|
||||||
return user_data
|
return user_data
|
||||||
|
|
||||||
def process_usernames(self, data):
|
def process_usernames(self, data):
|
||||||
|
@@ -78,19 +78,16 @@ def transform_audio_url(url):
|
|||||||
""" Transforms the URL offered by VK to the unencrypted stream so we can still play it.
|
""" Transforms the URL offered by VK to the unencrypted stream so we can still play it.
|
||||||
This function will be updated every time VK decides to change something in their Audio API'S.
|
This function will be updated every time VK decides to change something in their Audio API'S.
|
||||||
Changelog:
|
Changelog:
|
||||||
16/04/2019: Implemented this function. For now it replaces /index.m3u8 by .mp3, also removes the path component before "/audios" if the URL contains the word /audios, or the last path component before the filename if doesn't.
|
30/04/2019: Re-enabled old methods as VK changed everything as how it was working on 16.04.2019.
|
||||||
17/04/2019: Updated function. Now it is not required to strip anything, just replacing /index.m3u8 with .mp3 should be enough.
|
17.04.2019: Updated function. Now it is not required to strip anything, just replacing /index.m3u8 with .mp3 should be enough.
|
||||||
|
16.04.2019: Implemented this function. For now it replaces /index.m3u8 by .mp3, also removes the path component before "/audios" if the URL contains the word /audios, or the last path component before the filename if doesn't.
|
||||||
"""
|
"""
|
||||||
if "vkuseraudio.net" not in url and "index.m3u8" not in url:
|
if "vkuseraudio.net" not in url and "index.m3u8" not in url:
|
||||||
return url
|
return url
|
||||||
url = url.replace("/index.m3u8", ".mp3")
|
url = url.replace("/index.m3u8", ".mp3")
|
||||||
|
parts = url.split("/")
|
||||||
|
if "/audios" not in url:
|
||||||
|
url = url.replace("/"+parts[-2], "")
|
||||||
|
else:
|
||||||
|
url = url.replace("/"+parts[-3], "")
|
||||||
return url
|
return url
|
||||||
### The following code was useful for VK audio methods prior to 17/04/2019.
|
|
||||||
# I just left this here because they may enable such change any time soon.
|
|
||||||
### basically this method was requiring us to strip a part of the full URL.
|
|
||||||
# parts = url.split("/")
|
|
||||||
# if "/audio" not in url:
|
|
||||||
# url = url.replace("/"+parts[-2], "")
|
|
||||||
# else:
|
|
||||||
# url = url.replace("/"+parts[-3], "")
|
|
||||||
# return url
|
|
BIN
src/sounds/default/checked.ogg
Normal file
BIN
src/sounds/default/checked.ogg
Normal file
Binary file not shown.
BIN
src/sounds/default/selected.ogg
Normal file
BIN
src/sounds/default/selected.ogg
Normal file
Binary file not shown.
BIN
src/sounds/default/unchecked.ogg
Normal file
BIN
src/sounds/default/unchecked.ogg
Normal file
Binary file not shown.
@@ -46,10 +46,6 @@ class chat(wx.Panel, widgetUtils.BaseDialog):
|
|||||||
sizer.Add(self.notify_online, 0, wx.ALL, 5)
|
sizer.Add(self.notify_online, 0, wx.ALL, 5)
|
||||||
self.notify_offline = wx.CheckBox(self, wx.NewId(), _("Show notifications when users are offline"))
|
self.notify_offline = wx.CheckBox(self, wx.NewId(), _("Show notifications when users are offline"))
|
||||||
sizer.Add(self.notify_offline, 0, wx.ALL, 5)
|
sizer.Add(self.notify_offline, 0, wx.ALL, 5)
|
||||||
self.open_unread_conversations = wx.CheckBox(self, wx.NewId(), _("Open unread conversations at startup"))
|
|
||||||
sizer.Add(self.open_unread_conversations, 0, wx.ALL, 5)
|
|
||||||
self.automove_to_conversations = wx.CheckBox(self, wx.NewId(), _("Move focus to new conversations"))
|
|
||||||
sizer.Add(self.automove_to_conversations, 0, wx.ALL, 5)
|
|
||||||
lbl = wx.StaticText(self, wx.NewId(), _("Notification type"))
|
lbl = wx.StaticText(self, wx.NewId(), _("Notification type"))
|
||||||
self.notifications = wx.ComboBox(self, wx.NewId(), choices=[_("Native"), _("Custom"),], value=_("Native"), style=wx.CB_READONLY)
|
self.notifications = wx.ComboBox(self, wx.NewId(), choices=[_("Native"), _("Custom"),], value=_("Native"), style=wx.CB_READONLY)
|
||||||
nbox = wx.BoxSizer(wx.HORIZONTAL)
|
nbox = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
@@ -121,3 +121,51 @@ class createCommentDialog(createTextMessage):
|
|||||||
super(createCommentDialog, self).__init__()
|
super(createCommentDialog, self).__init__()
|
||||||
self.createControls(message, title, text)
|
self.createControls(message, title, text)
|
||||||
self.SetClientSize(self.mainBox.CalcMin())
|
self.SetClientSize(self.mainBox.CalcMin())
|
||||||
|
self.SetTitle(title)
|
||||||
|
|
||||||
|
class createTopicDialog(createCommentDialog):
|
||||||
|
def createTextArea(self, message="", text=""):
|
||||||
|
self.panel = wx.Panel(self)
|
||||||
|
label = wx.StaticText(self.panel, -1, _("Title"))
|
||||||
|
self.title = wx.TextCtrl(self.panel, wx.NewId())
|
||||||
|
label2 = wx.StaticText(self.panel, -1, _("Message"))
|
||||||
|
self.text = wx.TextCtrl(self.panel, -1, text, size=(439, -1), style=wx.TE_MULTILINE)
|
||||||
|
self.title.SetFocus()
|
||||||
|
self.textBox = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
titleb = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
titleb.Add(label, 0, wx.ALL, 5)
|
||||||
|
titleb.Add(self.title, 0, wx.ALL, 5)
|
||||||
|
self.textBox.Add(titleb, 0, wx.ALL, 5)
|
||||||
|
textb = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
textb.Add(label2, 0, wx.ALL, 5)
|
||||||
|
textb.Add(self.text, 0, wx.ALL, 5)
|
||||||
|
self.textBox.Add(textb, 0, wx.ALL, 5)
|
||||||
|
|
||||||
|
def createControls(self, title, message, text):
|
||||||
|
self.mainBox = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
self.createTextArea(message, text)
|
||||||
|
self.mainBox.Add(self.textBox, 0, wx.ALL, 5)
|
||||||
|
self.attach = wx.Button(self.panel, -1, _("Attach"), size=wx.DefaultSize)
|
||||||
|
self.mention = wx.Button(self.panel, wx.NewId(), _("Tag a friend"))
|
||||||
|
self.spellcheck = wx.Button(self.panel, -1, _("Spelling &correction"), size=wx.DefaultSize)
|
||||||
|
self.translateButton = wx.Button(self.panel, -1, _("&Translate message"), size=wx.DefaultSize)
|
||||||
|
self.okButton = wx.Button(self.panel, wx.ID_OK, _("Send"), size=wx.DefaultSize)
|
||||||
|
self.okButton.SetDefault()
|
||||||
|
cancelButton = wx.Button(self.panel, wx.ID_CANCEL, _("Close"), size=wx.DefaultSize)
|
||||||
|
self.buttonsBox1 = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
self.buttonsBox1.Add(self.attach, 0, wx.ALL, 10)
|
||||||
|
self.buttonsBox1.Add(self.mention, 0, wx.ALL, 10)
|
||||||
|
self.buttonsBox1.Add(self.spellcheck, 0, wx.ALL, 10)
|
||||||
|
self.buttonsBox1.Add(self.translateButton, 0, wx.ALL, 10)
|
||||||
|
self.mainBox.Add(self.buttonsBox1, 0, wx.ALL, 10)
|
||||||
|
self.ok_cancelSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
self.ok_cancelSizer.Add(self.okButton, 0, wx.ALL, 10)
|
||||||
|
self.ok_cancelSizer.Add(cancelButton, 0, wx.ALL, 10)
|
||||||
|
self.mainBox.Add(self.ok_cancelSizer)
|
||||||
|
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)
|
||||||
|
self.panel.SetSizer(self.mainBox)
|
||||||
|
|
||||||
|
@@ -4,7 +4,9 @@ from __future__ import unicode_literals
|
|||||||
import languageHandler
|
import languageHandler
|
||||||
import paths
|
import paths
|
||||||
import wx
|
import wx
|
||||||
|
import wx.lib.mixins.listctrl as listmix
|
||||||
from builtins import range
|
from builtins import range
|
||||||
|
from pubsub import pub
|
||||||
|
|
||||||
toolkit = "wx"
|
toolkit = "wx"
|
||||||
|
|
||||||
@@ -134,6 +136,30 @@ class mainLoopObject(wx.App):
|
|||||||
def run(self):
|
def run(self):
|
||||||
self.app.MainLoop()
|
self.app.MainLoop()
|
||||||
|
|
||||||
|
class multiselectionBaseList(wx.ListCtrl, listmix.CheckListCtrlMixin):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
wx.ListCtrl.__init__(self, *args, **kwargs)
|
||||||
|
listmix.CheckListCtrlMixin.__init__(self)
|
||||||
|
self.Bind(wx.EVT_CHAR_HOOK, self.on_keydown)
|
||||||
|
self.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.on_focus)
|
||||||
|
|
||||||
|
def on_focus(self, event):
|
||||||
|
currentItem = self.GetFocusedItem()
|
||||||
|
if self.IsChecked(currentItem):
|
||||||
|
pub.sendMessage("play-sound", sound="selected.ogg")
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
|
def OnCheckItem(self, index, flag):
|
||||||
|
if flag == True:
|
||||||
|
pub.sendMessage("play-sound", sound="checked.ogg")
|
||||||
|
else:
|
||||||
|
pub.sendMessage("play-sound", sound="unchecked.ogg")
|
||||||
|
|
||||||
|
def on_keydown(self, event):
|
||||||
|
if event.GetKeyCode() == wx.WXK_SPACE:
|
||||||
|
self.ToggleItem(self.GetFocusedItem())
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
class list(object):
|
class list(object):
|
||||||
def __init__(self, parent, *columns, **listArguments):
|
def __init__(self, parent, *columns, **listArguments):
|
||||||
self.columns = columns
|
self.columns = columns
|
||||||
@@ -182,3 +208,19 @@ class list(object):
|
|||||||
|
|
||||||
def Enable(self, value):
|
def Enable(self, value):
|
||||||
return self.list.Enable(value)
|
return self.list.Enable(value)
|
||||||
|
|
||||||
|
class multiselectionList(list):
|
||||||
|
|
||||||
|
def create_list(self, parent):
|
||||||
|
self.list = multiselectionBaseList(parent, -1, **self.listArguments)
|
||||||
|
for i in range(0, len(self.columns)):
|
||||||
|
self.list.InsertColumn(i, "%s" % (self.columns[i]))
|
||||||
|
|
||||||
|
def get_multiple_selection(self):
|
||||||
|
selected = []
|
||||||
|
for item in range(0, self.list.GetItemCount()):
|
||||||
|
if self.list.IsChecked(item):
|
||||||
|
selected.append(item)
|
||||||
|
if len(selected) == 0 and self.list.GetFocusedItem() != -1:
|
||||||
|
selected.append(self.list.GetFocusedItem())
|
||||||
|
return selected
|
@@ -5,16 +5,18 @@ import widgetUtils
|
|||||||
|
|
||||||
class timelineDialog(widgetUtils.BaseDialog):
|
class timelineDialog(widgetUtils.BaseDialog):
|
||||||
|
|
||||||
def __init__(self, users=[]):
|
def __init__(self, users=[], show_selector=True):
|
||||||
super(timelineDialog, self).__init__(parent=None, title=_("New timeline for {0}").format(users[0],))
|
super(timelineDialog, self).__init__(parent=None, title=_("New timeline for {0}").format(users[0],))
|
||||||
panel = wx.Panel(self)
|
panel = wx.Panel(self)
|
||||||
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||||
|
if show_selector:
|
||||||
userLabel = wx.StaticText(panel, -1, _("User"))
|
userLabel = wx.StaticText(panel, -1, _("User"))
|
||||||
self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0])
|
self.cb = wx.ComboBox(panel, -1, choices=users, value=users[0])
|
||||||
self.cb.SetFocus()
|
self.cb.SetFocus()
|
||||||
userSizer = wx.BoxSizer()
|
userSizer = wx.BoxSizer()
|
||||||
userSizer.Add(userLabel, 0, wx.ALL, 5)
|
userSizer.Add(userLabel, 0, wx.ALL, 5)
|
||||||
userSizer.Add(self.cb, 0, wx.ALL, 5)
|
userSizer.Add(self.cb, 0, wx.ALL, 5)
|
||||||
|
sizer.Add(userSizer, 0, wx.ALL, 5)
|
||||||
actionsSizer = wx.StaticBoxSizer(parent=panel, orient=wx.VERTICAL, label=_("Buffer type"))
|
actionsSizer = wx.StaticBoxSizer(parent=panel, orient=wx.VERTICAL, label=_("Buffer type"))
|
||||||
self.wall = wx.RadioButton(actionsSizer.GetStaticBox(), wx.NewId(), _("&Wall posts"), style=wx.RB_GROUP)
|
self.wall = wx.RadioButton(actionsSizer.GetStaticBox(), wx.NewId(), _("&Wall posts"), style=wx.RB_GROUP)
|
||||||
self.audio = wx.RadioButton(actionsSizer.GetStaticBox(), wx.NewId(), _("Audio"))
|
self.audio = wx.RadioButton(actionsSizer.GetStaticBox(), wx.NewId(), _("Audio"))
|
||||||
|
@@ -133,10 +133,14 @@ class mainWindow(wx.Frame):
|
|||||||
def advance_selection(self, forward):
|
def advance_selection(self, forward):
|
||||||
self.tb.AdvanceSelection(forward)
|
self.tb.AdvanceSelection(forward)
|
||||||
|
|
||||||
def about_dialog(self, *args, **kwargs):
|
def about_dialog(self, channel="stable", *args, **kwargs):
|
||||||
|
if channel == "stable":
|
||||||
|
version = _("{version} (stable)").format(version=application.version)
|
||||||
|
else:
|
||||||
|
version = _("{version} (alpha)").format(version=application.update_next_version)
|
||||||
info = wx.adv.AboutDialogInfo()
|
info = wx.adv.AboutDialogInfo()
|
||||||
info.SetName(application.name)
|
info.SetName(application.name)
|
||||||
info.SetVersion(application.version)
|
info.SetVersion(version)
|
||||||
info.SetDescription(application.description)
|
info.SetDescription(application.description)
|
||||||
info.SetCopyright(application.copyright)
|
info.SetCopyright(application.copyright)
|
||||||
info.SetTranslators(application.translators)
|
info.SetTranslators(application.translators)
|
||||||
|
@@ -57,14 +57,14 @@ class communityTab(feedTab):
|
|||||||
def create_post_buttons(self):
|
def create_post_buttons(self):
|
||||||
self.postBox = wx.StaticBoxSizer(parent=self, orient=wx.HORIZONTAL, label=_("Actions"))
|
self.postBox = wx.StaticBoxSizer(parent=self, orient=wx.HORIZONTAL, label=_("Actions"))
|
||||||
self.load = wx.Button(self.postBox.GetStaticBox(), wx.NewId(), _("Load buffer"))
|
self.load = wx.Button(self.postBox.GetStaticBox(), wx.NewId(), _("Load buffer"))
|
||||||
self.post = wx.Button(self.postBox.GetStaticBox(), -1, _("&Post"))
|
self.post = wx.Button(self.postBox.GetStaticBox(), -1, _("&Post in group"))
|
||||||
self.postBox.Add(self.load, 0, wx.ALL, 5)
|
self.postBox.Add(self.load, 0, wx.ALL, 5)
|
||||||
self.postBox.Add(self.post, 0, wx.ALL, 5)
|
self.postBox.Add(self.post, 0, wx.ALL, 5)
|
||||||
|
|
||||||
class audioTab(homeTab):
|
class audioTab(homeTab):
|
||||||
def create_list(self):
|
def create_list(self):
|
||||||
self.lbl = wx.StaticText(self, wx.NewId(), _("Mu&sic"))
|
self.lbl = wx.StaticText(self, wx.NewId(), _("Mu&sic"))
|
||||||
self.list = widgetUtils.list(self, *[_("Title"), _("Artist"), _("Duration")], style=wx.LC_REPORT)
|
self.list = widgetUtils.multiselectionList(self, *[_("Title"), _("Artist"), _("Duration")], style=wx.LC_REPORT)
|
||||||
self.list.set_windows_size(0, 160)
|
self.list.set_windows_size(0, 160)
|
||||||
self.list.set_windows_size(1, 380)
|
self.list.set_windows_size(1, 380)
|
||||||
self.list.set_windows_size(2, 80)
|
self.list.set_windows_size(2, 80)
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
{"current_version": "0.19",
|
{"current_version": "0.20",
|
||||||
"description": ".",
|
"description": ".",
|
||||||
"downloads":
|
"downloads":
|
||||||
{"Windows32": "https://code.manuelcortez.net/manuelcortez/socializer/-/jobs/artifacts/v0.19/raw/socializer.zip?job=stable"}}
|
{"Windows32": "https://code.manuelcortez.net/manuelcortez/socializer/-/jobs/artifacts/v0.20/raw/socializer.zip?job=stable"}}
|
Reference in New Issue
Block a user