mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2025-08-25 17:39:23 +00:00
Compare commits
90 Commits
v0.94
...
snapshot11
Author | SHA1 | Date | |
---|---|---|---|
4c1cad7f61 | |||
fffd98e09e | |||
a1a084bfda | |||
85e575386e | |||
2c64805eec | |||
6f2e439ddc | |||
7e42a096a5 | |||
9d2cf05a41 | |||
d7c095173d | |||
36ba6eca92 | |||
b6fa131999 | |||
c85c478595 | |||
![]() |
74e020c090 | ||
40105f37ed | |||
ca3f8779b8 | |||
a6a651d6f7 | |||
7748b4bb5d | |||
01a6c65c82 | |||
211d43aa30 | |||
c716f4aa96 | |||
9fd9d2a120 | |||
5c75be20d3 | |||
1ccb898f78 | |||
d734a30a18 | |||
3d310c0ee4 | |||
79512af350 | |||
7a2ad3797d | |||
f87312fc53 | |||
682f1e8bd4 | |||
cbc2e978c9 | |||
72fd93eaf6 | |||
8bac4b8ec6 | |||
6c29a4a18f | |||
3ae581a19f | |||
a9378988cb | |||
00f96bb7af | |||
ecd2984a61 | |||
3be69cb6a2 | |||
099bc49761 | |||
ec61f4b431 | |||
b16a6c5ddb | |||
9a94b92018 | |||
fe8a3b1565 | |||
a3d1052193 | |||
fbbd3cf00e | |||
8a6f73fdc2 | |||
c806f17484 | |||
db231e07f8 | |||
eaf13a4453 | |||
d4a73fb3bb | |||
8459135002 | |||
4aef2595b2 | |||
ccdcc7676e | |||
967cc8da71 | |||
071bcf55ef | |||
cf735211c9 | |||
bd56eb953b | |||
940ace664c | |||
![]() |
8619deb6ee | ||
![]() |
9fcc5d36e5 | ||
![]() |
c374cdefe9 | ||
7b925b5909 | |||
013a80a1f2 | |||
ec860aa6fc | |||
12e06eb52d | |||
464fce07b0 | |||
ad484a1f35 | |||
7296d2a939 | |||
cd596a6ad6 | |||
![]() |
ed3b9c9538 | ||
df9d99edcd | |||
![]() |
f5f4074409 | ||
6439eac76c | |||
5c794aaeff | |||
8cdd1b52d1 | |||
6928ac4b99 | |||
ae42a53b41 | |||
be7df1714d | |||
8cf7ca5ef2 | |||
0cfa89b389 | |||
f63ed6d0a7 | |||
00440e9050 | |||
76db14360a | |||
0966739296 | |||
1e27056902 | |||
3b41e18573 | |||
2668e47a6f | |||
b44e30ed28 | |||
bfad5b82f0 | |||
41d4c97067 |
@@ -1,6 +1,8 @@
|
||||
TWBlue -
|
||||
======
|
||||
|
||||
[](https://ci.appveyor.com/project/manuelcortez/twblue)
|
||||
|
||||
TW Blue is an app designed to use Twitter simply and efficiently while using minimal system resources.
|
||||
With this app you’ll have access to twitter features such as:
|
||||
|
||||
@@ -31,7 +33,6 @@ Although most dependencies can be found in the windows-dependencies directory, w
|
||||
|
||||
* [Python,](http://python.org) version 2.7.15
|
||||
If you want to build both x86 and x64 binaries, you can install python x86 to C:\python27 and python x64 to C:\python27x64, for example.
|
||||
* [Python windows extensions (pywin32)](http://www.sourceforge.net/projects/pywin32/) for python 2.7, build 223
|
||||
* [PyEnchant,](http://pythonhosted.org/pyenchant/) version 1.6.6.
|
||||
x64 version has been built by TWBlue developers, so you only will find it in windows-dependencies folder
|
||||
|
||||
|
83
appveyor.yml
Normal file
83
appveyor.yml
Normal file
@@ -0,0 +1,83 @@
|
||||
pull_requests:
|
||||
# Avoid building after pull requests. Shall we disable this option?
|
||||
do_not_increment_build_number: true
|
||||
|
||||
# Only build whenever we add tags to the repo.
|
||||
skip_non_tags: true
|
||||
|
||||
environment:
|
||||
|
||||
matrix:
|
||||
|
||||
# List of python versions we want to work with.
|
||||
- PYTHON: "C:\\Python27"
|
||||
PYTHON_VERSION: "2.7.x" # currently 2.7.9
|
||||
PYTHON_ARCH: "32"
|
||||
|
||||
# perhaps we may enable this one in future?
|
||||
# - PYTHON: "C:\\Python27-x64"
|
||||
# PYTHON_VERSION: "2.7.x" # currently 2.7.9
|
||||
# PYTHON_ARCH: "64"
|
||||
|
||||
# This is important so we will retrieve everything in submodules as opposed to default method.
|
||||
clone_script:
|
||||
- cmd: >-
|
||||
git clone -q --branch=%APPVEYOR_REPO_BRANCH% https://github.com/%APPVEYOR_REPO_NAME%.git %APPVEYOR_BUILD_FOLDER%
|
||||
&& cd %APPVEYOR_BUILD_FOLDER%
|
||||
&& git checkout -qf %APPVEYOR_REPO_COMMIT%
|
||||
&& git submodule update --init --recursive
|
||||
|
||||
install:
|
||||
# If there is a newer build queued for the same PR, cancel this one.
|
||||
# The AppVeyor 'rollout builds' option is supposed to serve the same
|
||||
# purpose but it is problematic because it tends to cancel builds pushed
|
||||
# directly to master instead of just PR builds (or the converse).
|
||||
# credits: JuliaLang developers.
|
||||
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
|
||||
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
|
||||
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
|
||||
throw "There are newer queued builds for this pull request, failing early." }
|
||||
- ECHO "Filesystem root:"
|
||||
- ps: "ls \"C:/\""
|
||||
|
||||
# Check that we have the expected version and architecture for Python
|
||||
- "python --version"
|
||||
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
|
||||
|
||||
# Upgrade to the latest version of pip to avoid it displaying warnings
|
||||
# about it being out of date.
|
||||
- "python -m pip install --upgrade pip setuptools"
|
||||
|
||||
# Install the build dependencies of the project. If some dependencies contain
|
||||
# compiled extensions and are not provided as pre-built wheel packages,
|
||||
# pip will build them from source using the MSVC compiler matching the
|
||||
# target Python version and architecture
|
||||
- "%CMD_IN_ENV% pip install -r requirements.txt"
|
||||
- "%CMD_IN_ENV% pip install pyenchant py2exe_py2"
|
||||
|
||||
build_script:
|
||||
# Build documentation at first, so setup.py won't fail when copying everything.
|
||||
- "cd doc"
|
||||
# Import documentation before building, so strings.py will be created.
|
||||
- "%CMD_IN_ENV% python documentation_importer.py"
|
||||
# build doc from src folder so it will generate result files right there.
|
||||
- "cd ..\\src"
|
||||
- "%CMD_IN_ENV% python ..\\doc\\generator.py"
|
||||
# Build distributable files.
|
||||
- "%CMD_IN_ENV% python setup.py py2exe"
|
||||
- "cd dist"
|
||||
# Zip it all.
|
||||
- cmd: 7z a ..\..\snapshot.zip *
|
||||
|
||||
artifacts:
|
||||
- path: snapshot.zip
|
||||
|
||||
deploy:
|
||||
- provider: FTP
|
||||
host: twblue.es
|
||||
protocol: ftp
|
||||
beta: true
|
||||
username: twblue
|
||||
password:
|
||||
secure: ml/xB8YEoZ7DmjzDr+KSNw==
|
||||
# folder: '//pubs'
|
@@ -2,20 +2,41 @@
|
||||
|
||||
## changes in this version
|
||||
|
||||
* When adding or removing an user from a list, it is possible to press enter in the focused list instead of having to search for the "add" or "delete" button.
|
||||
* Quoted and long tweets are displayed properly in the sent tweets buffer after being send. ([#253](https://github.com/manuelcortez/TWBlue/issues/253))
|
||||
* Fixed an issue that was making the list manager keystroke unable to be shown in the keystroke editor. Now the keystroke is listed properly. ([#260](https://github.com/manuelcortez/TWBlue/issues/260))
|
||||
* The volume slider, located in the account settings of TWBlue, now should decrease and increase value properly when up and down arrows are pressed. Before it was doing it in inverted order. ([#261](https://github.com/manuelcortez/TWBlue/issues/261))
|
||||
* autoreading has been redesigned to work in a similar way for almost all buffers. Needs testing. ([#221](https://github.com/manuelcortez/TWBlue/issues/221))
|
||||
* When displaying tweets or direct messages, a new field has been added to show the date when the item has been posted to Twitter.
|
||||
* Added support for deleting direct messages by using the new Twitter API methods.
|
||||
* When quoting a retweet, the quote will be made to the original tweet instead of the retweet.
|
||||
* If the sent direct messages buffer is hidden, TWBlue should keep loading everything as expected. ([#246](https://github.com/manuelcortez/TWBlue/issues/246))
|
||||
* There is a new soundpack, called FreakyBlue (Thanks to [Andre Louis](https://twitter.com/FreakyFwoof)) as a new option in TWBlue. This pack can be the default in the next stable, so users can take a look and share their opinion in snapshot versions. ([#247](https://github.com/manuelcortez/TWBlue/issues/247))
|
||||
* There is a new option in the help menu that allows you to visit the soundpacks section in the TWBlue website. ([#247](https://github.com/manuelcortez/TWBlue/issues/247))
|
||||
* When reading location of a geotagged tweet, it will be translated for users of other languages. ([#251](https://github.com/manuelcortez/TWBlue/pull/251))
|
||||
* In the Windows 10 Keymap, the action to read location of a tweet has been remapped to Ctrl+Win+G. ([#177](https://github.com/manuelcortez/TWBlue/pull/177))
|
||||
* When there are no more items to retrieve in direct messages and people buffers, a message will announce it.
|
||||
* Fixed an issue reported by some users that was making them unable to load more items in their direct messages.
|
||||
* It is possible to add a tweet to the likes buffer from the menu bar again.
|
||||
* Tweets, replies and retweets will be added to sent tweets right after being posted in Twitter.
|
||||
* Extended Tweets should be displayed properly in list buffers.
|
||||
|
||||
## Changes in version 0.94
|
||||
|
||||
* Added an option in the global settings dialog to disable the Streaming features of TWBlue. TWBlue will remove all Streaming features after August 16, so this option will give people an idea about how it will be. ([#219](https://github.com/manuelcortez/TWBlue/issues/219))
|
||||
* Due to Twitter API changes, Switched authorisation method to Pin-code based authorisation. When you add new accounts to TWBlue, you will be required to paste a code displayed in the Twitter website in order to grant access to TWBlue. ([#216](https://github.com/manuelcortez/TWBlue/issues/216))
|
||||
* In order to comply with latest Twitter changes, TWBlue has switched to the new method used to send and receive direct messages, according to issue [#215.](https://github.com/manuelcortez/twblue/issues/215)
|
||||
* The new method does not allow direct messages to be processed in real time. Direct messages will be updated periodically.
|
||||
* After august 16 or when streaming is disabled, the events buffer will no longer be created in TWBlue.
|
||||
* You can configure frequency for buffer updates in TWBlue. By default, TWBlue will update all buffers every 2 minutes, but you can change this setting in the global settings dialog. ([#223](https://github.com/manuelcortez/TWBlue/issues/223))
|
||||
* Added a new tab called feedback, in the account settings dialog. This tab allows you to control wether automatic speech or Braille feedbak in certain events (mentions and direct messages received) is enabled. Take into account that this option will take preference over automatic reading of buffers and any kind of automatic output. ([#203](https://github.com/manuelcortez/TWBlue/issues/203))
|
||||
* Added a new tab called feedback, in the account settings dialog. This tab allows you to control whether automatic speech or Braille feedbak in certain events (mentions and direct messages received) is enabled. Take into account that this option will take preference over automatic reading of buffers and any kind of automatic output. ([#203](https://github.com/manuelcortez/TWBlue/issues/203))
|
||||
* The spell checking dialog now has access keys defined for the most important actions. ([#211](https://github.com/manuelcortez/TWBlue/issues/211))
|
||||
* TWBlue now Uses WXPython 4.0.1. This will allow us to migrate all important components to Python 3 in the future. ([#207](https://github.com/manuelcortez/TWBlue/issues/207))
|
||||
* When you quote a Tweet, if the original tweet was posted with Twishort, TWBlue should display properly the quoted tweet. Before it was displaying the original tweet only. ([#206](https://github.com/manuelcortez/TWBlue/issues/206))
|
||||
* It is possible to filter by retweets, quotes and replies when creating a new filter.
|
||||
* Added support for playing youtube Links directly from the client. ([#94](https://github.com/manuelcortez/TWBlue/issues/94))
|
||||
* Replaced Bass with libVLC for playing URL streams.
|
||||
* the checkbox for indicating wether TWBlue will include everyone in a reply or not, will be unchecked by default.
|
||||
* the checkbox for indicating whether TWBlue will include everyone in a reply or not, will be unchecked by default.
|
||||
* You can request TWBlue to save the state for two checkboxes: Long tweet and mention all, from the global settings dialogue.
|
||||
* For windows 10 users, some keystrokes in the invisible user interface have been changed or merged:
|
||||
* control+Windows+alt+F will be used for toggling between adding and removing a tweet to user's likes. This function will execute the needed action based in the current status for the focused tweet.
|
||||
|
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import markdown
|
||||
import os
|
||||
import shutil
|
||||
from codecs import open as _open
|
||||
import languageHandler
|
||||
languageHandler.setLanguage("en")
|
||||
@@ -38,14 +39,18 @@ def generate_document(language, document_type="documentation"):
|
||||
""" % (language, title, title)
|
||||
first_html_block = first_html_block+ markdown_file
|
||||
first_html_block = first_html_block + "\n</body>\n</html>"
|
||||
if not os.path.exists(language):
|
||||
os.mkdir(language)
|
||||
mdfile = _open("%s/%s" % (language, filename), "w", encoding="utf-8")
|
||||
if not os.path.exists(os.path.join("documentation", language)):
|
||||
os.mkdir(os.path.join("documentation", language))
|
||||
mdfile = _open(os.path.join("documentation", language, filename), "w", encoding="utf-8")
|
||||
mdfile.write(first_html_block)
|
||||
mdfile.close()
|
||||
|
||||
def create_documentation():
|
||||
print("Creating documentation in the supported languages...\n")
|
||||
if not os.path.exists("documentation"):
|
||||
os.mkdir("documentation")
|
||||
if os.path.exists(os.path.join("documentation", "license.txt")) == False:
|
||||
shutil.copy(os.path.join("..", "license.txt"), os.path.join("documentation", "license.txt"))
|
||||
for i in languages:
|
||||
print("Creating documentation for: %s" % (i,))
|
||||
generate_document(i)
|
||||
|
@@ -20,4 +20,7 @@ idna
|
||||
chardet
|
||||
urllib3
|
||||
youtube-dl
|
||||
python-vlc
|
||||
python-vlc
|
||||
pywin32
|
||||
certifi
|
||||
backports.functools_lru_cache
|
||||
|
@@ -2,13 +2,13 @@
|
||||
import datetime
|
||||
|
||||
name = 'TWBlue'
|
||||
snapshot = False
|
||||
snapshot = True
|
||||
if snapshot == False:
|
||||
version = "0.94"
|
||||
update_url = 'https://twblue.es/updates/stable.php'
|
||||
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json'
|
||||
else:
|
||||
version = "8"
|
||||
version = "11"
|
||||
update_url = 'https://twblue.es/updates/snapshot.php'
|
||||
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json'
|
||||
authors = [u"Manuel Cortéz", u"José Manuel Delicado"]
|
||||
@@ -18,18 +18,4 @@ description = unicode(name+" is an app designed to use Twitter simply and effici
|
||||
translators = [u"Manuel Cortéz (English)", u"Mohammed Al Shara, Hatoun Felemban (Arabic)", u"Francisco Torres (Catalan)", u"Manuel cortéz (Spanish)", u"Sukil Etxenike Arizaleta (Basque)", u"Jani Kinnunen (finnish)", u"Rémy Ruiz (French)", u"Juan Buño (Galician)", u"Steffen Schultz (German)", u"Zvonimir Stanečić (Croatian)", u"Robert Osztolykan (Hungarian)", u"Christian Leo Mameli (Italian)", u"Riku (Japanese)", u"Paweł Masarczyk (Polish)", u"Odenilton Júnior Santos (Portuguese)", u"Florian Ionașcu, Nicușor Untilă (Romanian)", u"Natalia Hedlund, Valeria Kuznetsova (Russian)", u"Aleksandar Đurić (Serbian)", u"Burak Yüksek (Turkish)"]
|
||||
url = u"https://twblue.es"
|
||||
report_bugs_url = "https://github.com/manuelcortez/twblue/issues"
|
||||
supported_languages = []
|
||||
|
||||
def streaming_lives():
|
||||
""" Check if we are in August 16.
|
||||
ToDo: This method should be removed after deadline==True"""
|
||||
# Let's import config here so we will avoid breaking things when setup.py is going to be used.
|
||||
# Check if user has disabled the streaming API things from settings.
|
||||
import config
|
||||
if config.app != None:
|
||||
no_streaming = config.app["app-settings"]["no_streaming"]
|
||||
if no_streaming == True:
|
||||
return False
|
||||
deadline = datetime.date(2018, 8, 16)
|
||||
now = datetime.datetime.now().date()
|
||||
return deadline>now
|
||||
supported_languages = []
|
7
src/controller/buffers/__init__.py
Normal file
7
src/controller/buffers/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" this package contains logic related to buffers. A buffer is a virtual representation of a group of items retrieved through the Social network API'S.
|
||||
Ideally, new social networks added to TWBlue will have its own "buffers", and these buffers should be defined within this package, following the Twitter example.
|
||||
Currently, the package contains the following modules:
|
||||
* baseBuffers: Define a set of functions and structure to be expected in all buffers. New buffers should inherit its classes from one of the classes present here.
|
||||
* twitterBuffers: All other code, specific to Twitter.
|
||||
"""
|
201
src/controller/buffers/baseBuffers.py
Normal file
201
src/controller/buffers/baseBuffers.py
Normal file
@@ -0,0 +1,201 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Common logic to all buffers in TWBlue."""
|
||||
import logging
|
||||
import wx
|
||||
import output
|
||||
import config
|
||||
import sound
|
||||
import widgetUtils
|
||||
from pubsub import pub
|
||||
from wxUI import buffers
|
||||
|
||||
log = logging.getLogger("controller.buffers.baseBuffers")
|
||||
|
||||
def _items_exist(function):
|
||||
""" A decorator to execute a function only if the selected buffer contains at least one item."""
|
||||
def function_(self, *args, **kwargs):
|
||||
if self.buffer.list.get_count() > 0:
|
||||
function(self, *args, **kwargs)
|
||||
return function_
|
||||
|
||||
class buffer(object):
|
||||
""" A basic buffer object. This should be the base class for all other derived buffers."""
|
||||
|
||||
def __init__(self, parent=None, function=None, session=None, *args, **kwargs):
|
||||
"""Inits the main controller for this buffer:
|
||||
@ parent wx.Treebook object: Container where we will put this buffer.
|
||||
@ function str or None: function to be called periodically and update items on this buffer.
|
||||
@ session sessionmanager.session object or None: Session handler for settings, database and data access.
|
||||
"""
|
||||
super(buffer, self).__init__()
|
||||
self.function = function
|
||||
# Compose_function will be used to render an object on this buffer. Normally, signature is as follows:
|
||||
# compose_function(item, db, relative_times, show_screen_names=False, session=None)
|
||||
# Read more about compose functions in twitter/compose.py.
|
||||
self.compose_function = None
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
# This will be used as a reference to the wx.Panel object wich stores the buffer GUI.
|
||||
self.buffer = None
|
||||
# This should countains the account associated to this buffer.
|
||||
self.account = ""
|
||||
# This controls whether the start_stream function should be called when starting the program.
|
||||
self.needs_init = True
|
||||
# if this is set to False, the buffer will be ignored on the invisible interface.
|
||||
self.invisible = False
|
||||
# Control variable, used to track time of execution for calls to start_stream.
|
||||
self.execution_time = 0
|
||||
|
||||
def clear_list(self):
|
||||
pass
|
||||
|
||||
def get_event(self, ev):
|
||||
""" Catch key presses in the WX interface and generate the corresponding event names."""
|
||||
if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "audio"
|
||||
elif ev.GetKeyCode() == wx.WXK_RETURN: event = "url"
|
||||
elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down"
|
||||
elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up"
|
||||
elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list"
|
||||
elif ev.GetKeyCode() == wx.WXK_DELETE: event = "destroy_status"
|
||||
else:
|
||||
event = None
|
||||
ev.Skip()
|
||||
if event != None:
|
||||
try:
|
||||
getattr(self, event)()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def volume_down(self):
|
||||
""" Decreases volume by 5%"""
|
||||
if self.session.settings["sound"]["volume"] > 0.0:
|
||||
if self.session.settings["sound"]["volume"] <= 0.05:
|
||||
self.session.settings["sound"]["volume"] = 0.0
|
||||
else:
|
||||
self.session.settings["sound"]["volume"] -=0.05
|
||||
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100.0))
|
||||
self.session.sound.play("volume_changed.ogg")
|
||||
self.session.settings.write()
|
||||
|
||||
def volume_up(self):
|
||||
""" Increases volume by 5%."""
|
||||
if self.session.settings["sound"]["volume"] < 1.0:
|
||||
if self.session.settings["sound"]["volume"] >= 0.95:
|
||||
self.session.settings["sound"]["volume"] = 1.0
|
||||
else:
|
||||
self.session.settings["sound"]["volume"] +=0.05
|
||||
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100))
|
||||
self.session.sound.play("volume_changed.ogg")
|
||||
self.session.settings.write()
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True):
|
||||
pass
|
||||
|
||||
def get_more_items(self):
|
||||
output.speak(_(u"This action is not supported for this buffer"), True)
|
||||
|
||||
def put_items_on_list(self, items):
|
||||
pass
|
||||
|
||||
def remove_buffer(self):
|
||||
return False
|
||||
|
||||
def remove_item(self, item):
|
||||
f = self.buffer.list.get_selected()
|
||||
self.buffer.list.remove_item(item)
|
||||
self.buffer.list.select_item(f)
|
||||
|
||||
def bind_events(self):
|
||||
pass
|
||||
|
||||
def get_object(self):
|
||||
return self.buffer
|
||||
|
||||
def get_message(self):
|
||||
pass
|
||||
|
||||
def set_list_position(self, reversed=False):
|
||||
if reversed == False:
|
||||
self.buffer.list.select_item(-1)
|
||||
else:
|
||||
self.buffer.list.select_item(0)
|
||||
|
||||
def reply(self):
|
||||
pass
|
||||
|
||||
def send_message(self):
|
||||
pass
|
||||
|
||||
def share_item(self):
|
||||
pass
|
||||
|
||||
def destroy_status(self):
|
||||
pass
|
||||
|
||||
def post_status(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def save_positions(self):
|
||||
try:
|
||||
self.session.db[self.name+"_pos"]=self.buffer.list.get_selected()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
class accountPanel(buffer):
|
||||
def __init__(self, parent, name, account, account_id):
|
||||
super(accountPanel, self).__init__(parent, None, name)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
self.buffer = buffers.accountPanel(parent, name)
|
||||
self.type = self.buffer.type
|
||||
self.compose_function = None
|
||||
self.session = None
|
||||
self.needs_init = False
|
||||
self.account = account
|
||||
self.buffer.account = account
|
||||
self.name = name
|
||||
self.account_id = account_id
|
||||
|
||||
def setup_account(self):
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.CHECKBOX, self.autostart, menuitem=self.buffer.autostart_account)
|
||||
if self.account_id in config.app["sessions"]["ignored_sessions"]:
|
||||
self.buffer.change_autostart(False)
|
||||
else:
|
||||
self.buffer.change_autostart(True)
|
||||
if not hasattr(self, "logged"):
|
||||
self.buffer.change_login(login=False)
|
||||
widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.logout)
|
||||
else:
|
||||
self.buffer.change_login(login=True)
|
||||
widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.login)
|
||||
|
||||
def login(self, *args, **kwargs):
|
||||
del self.logged
|
||||
self.setup_account()
|
||||
pub.sendMessage("login", session_id=self.account_id)
|
||||
|
||||
def logout(self, *args, **kwargs):
|
||||
self.logged = False
|
||||
self.setup_account()
|
||||
pub.sendMessage("logout", session_id=self.account_id)
|
||||
|
||||
def autostart(self, *args, **kwargs):
|
||||
if self.account_id in config.app["sessions"]["ignored_sessions"]:
|
||||
self.buffer.change_autostart(True)
|
||||
config.app["sessions"]["ignored_sessions"].remove(self.account_id)
|
||||
else:
|
||||
self.buffer.change_autostart(False)
|
||||
config.app["sessions"]["ignored_sessions"].append(self.account_id)
|
||||
config.app.write()
|
||||
|
||||
class emptyPanel(buffer):
|
||||
def __init__(self, parent, name, account):
|
||||
super(emptyPanel, self).__init__(parent=parent)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
self.buffer = buffers.emptyPanel(parent, name)
|
||||
self.type = self.buffer.type
|
||||
self.compose_function = None
|
||||
self.account = account
|
||||
self.buffer.account = account
|
||||
self.name = name
|
||||
self.session = None
|
||||
self.needs_init = True
|
@@ -4,11 +4,11 @@ import platform
|
||||
if platform.system() == "Windows":
|
||||
import wx
|
||||
from wxUI import buffers, dialogs, commonMessageDialogs, menus
|
||||
import user
|
||||
from controller import user
|
||||
elif platform.system() == "Linux":
|
||||
from gi.repository import Gtk
|
||||
from gtkUI import buffers, dialogs, commonMessageDialogs
|
||||
import messages
|
||||
from controller import messages
|
||||
import widgetUtils
|
||||
import arrow
|
||||
import webbrowser
|
||||
@@ -18,11 +18,12 @@ import sound
|
||||
import languageHandler
|
||||
import logging
|
||||
import youtube_utils
|
||||
from twitter import compose, utils
|
||||
from controller.buffers import baseBuffers
|
||||
from sessions.twitter import compose, utils
|
||||
from mysc.thread_utils import call_threaded
|
||||
from twython import TwythonError
|
||||
from pubsub import pub
|
||||
from long_tweets import twishort, tweets
|
||||
from sessions.twitter.long_tweets import twishort, tweets
|
||||
|
||||
log = logging.getLogger("controller.buffers")
|
||||
|
||||
@@ -33,216 +34,7 @@ def _tweets_exist(function):
|
||||
function(self, *args, **kwargs)
|
||||
return function_
|
||||
|
||||
class bufferController(object):
|
||||
""" A basic buffer object. This should be the base class for all other derived buffers."""
|
||||
|
||||
def __init__(self, parent=None, function=None, session=None, *args, **kwargs):
|
||||
"""Inits the main controller for this buffer:
|
||||
@ parent wx.Treebook object: Container where we will put this buffer.
|
||||
@ function str or None: function to be called periodically and update items on this buffer.
|
||||
@ session sessionmanager.session object or None: Session handler for settings, database and Twitter access.
|
||||
"""
|
||||
super(bufferController, self).__init__()
|
||||
self.function = function
|
||||
# Compose_function will be used to render an object on this buffer. Normally, signature is as follows:
|
||||
# compose_function(item, db, relative_times, show_screen_names=False, session=None)
|
||||
# Compose functions will be defined in every buffer if items are different than tweets.
|
||||
# Read more about compose functions in twitter/compose.py.
|
||||
self.compose_function = None
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
# This will be used as a reference to the wx.Panel object wich stores the buffer GUI.
|
||||
self.buffer = None
|
||||
# This should countains the account associated to this buffer.
|
||||
self.account = ""
|
||||
# This controls wether the start_stream function should be called when starting the program.
|
||||
self.needs_init = True
|
||||
# if this is set to False, the buffer will be ignored on the invisible interface.
|
||||
self.invisible = False
|
||||
# Control variable, used to track time of execution for calls to start_stream.
|
||||
self.execution_time = 0
|
||||
|
||||
def clear_list(self): pass
|
||||
|
||||
def get_event(self, ev):
|
||||
""" Catches key presses in the WX interface and generate the corresponding event names."""
|
||||
if ev.GetKeyCode() == wx.WXK_RETURN and ev.ControlDown(): event = "audio"
|
||||
elif ev.GetKeyCode() == wx.WXK_RETURN: event = "url"
|
||||
elif ev.GetKeyCode() == wx.WXK_F5: event = "volume_down"
|
||||
elif ev.GetKeyCode() == wx.WXK_F6: event = "volume_up"
|
||||
elif ev.GetKeyCode() == wx.WXK_DELETE and ev.ShiftDown(): event = "clear_list"
|
||||
elif ev.GetKeyCode() == wx.WXK_DELETE: event = "destroy_status"
|
||||
else:
|
||||
event = None
|
||||
ev.Skip()
|
||||
if event != None:
|
||||
try:
|
||||
getattr(self, event)()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def volume_down(self):
|
||||
if self.session.settings["sound"]["volume"] > 0.0:
|
||||
if self.session.settings["sound"]["volume"] <= 0.05:
|
||||
self.session.settings["sound"]["volume"] = 0.0
|
||||
else:
|
||||
self.session.settings["sound"]["volume"] -=0.05
|
||||
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100.0))
|
||||
self.session.sound.play("volume_changed.ogg")
|
||||
self.session.settings.write()
|
||||
|
||||
def volume_up(self):
|
||||
if self.session.settings["sound"]["volume"] < 1.0:
|
||||
if self.session.settings["sound"]["volume"] >= 0.95:
|
||||
self.session.settings["sound"]["volume"] = 1.0
|
||||
else:
|
||||
self.session.settings["sound"]["volume"] +=0.05
|
||||
sound.URLPlayer.player.audio_set_volume(int(self.session.settings["sound"]["volume"]*100))
|
||||
self.session.sound.play("volume_changed.ogg")
|
||||
self.session.settings.write()
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True):
|
||||
# if mandatory == True:
|
||||
# output.speak(_(u"Unable to update this buffer."))
|
||||
pass
|
||||
|
||||
def get_more_items(self):
|
||||
output.speak(_(u"This action is not supported for this buffer"), True)
|
||||
|
||||
def put_items_on_list(self, items):
|
||||
pass
|
||||
|
||||
def remove_buffer(self):
|
||||
return False
|
||||
|
||||
def remove_item(self, item):
|
||||
f = self.buffer.list.get_selected()
|
||||
self.buffer.list.remove_item(item)
|
||||
self.buffer.list.select_item(f)
|
||||
|
||||
def bind_events(self):
|
||||
pass
|
||||
|
||||
def get_object(self):
|
||||
return self.buffer
|
||||
|
||||
def get_message(self):
|
||||
pass
|
||||
|
||||
def set_list_position(self, reversed=False):
|
||||
if reversed == False:
|
||||
self.buffer.list.select_item(-1)
|
||||
else:
|
||||
self.buffer.list.select_item(0)
|
||||
|
||||
def reply(self):
|
||||
pass
|
||||
|
||||
def direct_message(self):
|
||||
pass
|
||||
|
||||
def retweet(self):
|
||||
pass
|
||||
|
||||
def destroy_status(self):
|
||||
pass
|
||||
|
||||
def post_tweet(self, *args, **kwargs):
|
||||
title = _(u"Tweet")
|
||||
caption = _(u"Write the tweet here")
|
||||
tweet = messages.tweet(self.session, title, caption, "")
|
||||
if tweet.message.get_response() == widgetUtils.OK:
|
||||
if config.app["app-settings"]["remember_mention_and_longtweet"]:
|
||||
config.app["app-settings"]["longtweet"] = tweet.message.long_tweet.GetValue()
|
||||
config.app.write()
|
||||
text = tweet.message.get_text()
|
||||
if len(text) > 280 and tweet.message.get("long_tweet") == True:
|
||||
if not hasattr(tweet, "attachments"):
|
||||
text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text)
|
||||
else:
|
||||
text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1)
|
||||
if not hasattr(tweet, "attachments") or len(tweet.attachments) == 0:
|
||||
call_threaded(self.session.api_call, call_name="update_status", status=text, _sound="tweet_send.ogg")
|
||||
else:
|
||||
call_threaded(self.post_with_media, text=text, attachments=tweet.attachments, _sound="tweet_send.ogg")
|
||||
if hasattr(tweet.message, "destroy"): tweet.message.destroy()
|
||||
self.session.settings.write()
|
||||
|
||||
def post_with_media(self, text, attachments):
|
||||
media_ids = []
|
||||
for i in attachments:
|
||||
photo = open(i["file"], "rb")
|
||||
img = self.session.twitter.twitter.upload_media(media=photo)
|
||||
self.session.twitter.twitter.create_metadata(media_id=img["media_id"], alt_text=dict(text=i["description"]))
|
||||
media_ids.append(img["media_id"])
|
||||
self.session.twitter.twitter.update_status(status=text, media_ids=media_ids)
|
||||
|
||||
def save_positions(self):
|
||||
try:
|
||||
self.session.db[self.name+"_pos"]=self.buffer.list.get_selected()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
class accountPanel(bufferController):
|
||||
def __init__(self, parent, name, account, account_id):
|
||||
super(accountPanel, self).__init__(parent, None, name)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
self.buffer = buffers.accountPanel(parent, name)
|
||||
self.type = self.buffer.type
|
||||
self.compose_function = None
|
||||
self.session = None
|
||||
self.needs_init = False
|
||||
self.account = account
|
||||
self.buffer.account = account
|
||||
self.name = name
|
||||
self.account_id = account_id
|
||||
|
||||
def setup_account(self):
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.CHECKBOX, self.autostart, menuitem=self.buffer.autostart_account)
|
||||
if self.account_id in config.app["sessions"]["ignored_sessions"]:
|
||||
self.buffer.change_autostart(False)
|
||||
else:
|
||||
self.buffer.change_autostart(True)
|
||||
if not hasattr(self, "logged"):
|
||||
self.buffer.change_login(login=False)
|
||||
widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.logout)
|
||||
else:
|
||||
self.buffer.change_login(login=True)
|
||||
widgetUtils.connect_event(self.buffer.login, widgetUtils.BUTTON_PRESSED, self.login)
|
||||
|
||||
def login(self, *args, **kwargs):
|
||||
del self.logged
|
||||
self.setup_account()
|
||||
pub.sendMessage("login", session_id=self.account_id)
|
||||
|
||||
def logout(self, *args, **kwargs):
|
||||
self.logged = False
|
||||
self.setup_account()
|
||||
pub.sendMessage("logout", session_id=self.account_id)
|
||||
|
||||
def autostart(self, *args, **kwargs):
|
||||
if self.account_id in config.app["sessions"]["ignored_sessions"]:
|
||||
self.buffer.change_autostart(True)
|
||||
config.app["sessions"]["ignored_sessions"].remove(self.account_id)
|
||||
else:
|
||||
self.buffer.change_autostart(False)
|
||||
config.app["sessions"]["ignored_sessions"].append(self.account_id)
|
||||
config.app.write()
|
||||
|
||||
class emptyPanel(bufferController):
|
||||
def __init__(self, parent, name, account):
|
||||
super(emptyPanel, self).__init__(parent=parent)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
self.buffer = buffers.emptyPanel(parent, name)
|
||||
self.type = self.buffer.type
|
||||
self.compose_function = None
|
||||
self.account = account
|
||||
self.buffer.account = account
|
||||
self.name = name
|
||||
self.session = None
|
||||
self.needs_init = True
|
||||
|
||||
class baseBufferController(bufferController):
|
||||
class baseBufferController(baseBuffers.buffer):
|
||||
def __init__(self, parent, function, name, sessionObject, account, sound=None, bufferType=None, compose_func="compose_tweet", *args, **kwargs):
|
||||
super(baseBufferController, self).__init__(parent, function, *args, **kwargs)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
@@ -271,6 +63,57 @@ class baseBufferController(bufferController):
|
||||
self.kwargs["screen_name"] = self.kwargs["user_id"]
|
||||
self.kwargs.pop("user_id")
|
||||
|
||||
def get_buffer_name(self):
|
||||
""" Get buffer name from a set of different techniques."""
|
||||
# firstly let's take the easier buffers.
|
||||
basic_buffers = dict(home_timeline=_(u"Home"), mentions=_(u"Mentions"), direct_messages=_(u"Direct messages"), sent_direct_messages=_(u"Sent direct messages"), sent_tweets=_(u"Sent tweets"), favourites=_(u"Likes"), followers=_(u"Followers"), friends=_(u"Friends"), blocked=_(u"Blocked users"), muted=_(u"Muted users"))
|
||||
if self.name in basic_buffers.keys():
|
||||
return basic_buffers[self.name]
|
||||
# Check user timelines
|
||||
elif hasattr(self, "username"):
|
||||
if "-timeline" in self.name:
|
||||
return _(u"{username}'s timeline").format(username=self.username,)
|
||||
elif "-favorite" in self.name:
|
||||
return _(u"{username}'s likes").format(username=self.username,)
|
||||
elif "-followers" in self.name:
|
||||
return _(u"{username}'s followers").format(username=self.username,)
|
||||
elif "-friends" in self.name:
|
||||
return _(u"{username}'s friends").format(username=self.username,)
|
||||
log.error("Error getting name for buffer %s" % (self.name,))
|
||||
return _(u"Unknown buffer")
|
||||
|
||||
def post_status(self, *args, **kwargs):
|
||||
title = _(u"Tweet")
|
||||
caption = _(u"Write the tweet here")
|
||||
tweet = messages.tweet(self.session, title, caption, "")
|
||||
if tweet.message.get_response() == widgetUtils.OK:
|
||||
if config.app["app-settings"]["remember_mention_and_longtweet"]:
|
||||
config.app["app-settings"]["longtweet"] = tweet.message.long_tweet.GetValue()
|
||||
config.app.write()
|
||||
text = tweet.message.get_text()
|
||||
if len(text) > 280 and tweet.message.get("long_tweet") == True:
|
||||
if not hasattr(tweet, "attachments"):
|
||||
text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text)
|
||||
else:
|
||||
text = twishort.create_tweet(self.session.settings["twitter"]["user_key"], self.session.settings["twitter"]["user_secret"], text, 1)
|
||||
if not hasattr(tweet, "attachments") or len(tweet.attachments) == 0:
|
||||
item = self.session.api_call(call_name="update_status", status=text, _sound="tweet_send.ogg", tweet_mode="extended")
|
||||
# else:
|
||||
# call_threaded(self.post_with_media, text=text, attachments=tweet.attachments, _sound="tweet_send.ogg")
|
||||
if item != None:
|
||||
pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"])
|
||||
if hasattr(tweet.message, "destroy"): tweet.message.destroy()
|
||||
self.session.settings.write()
|
||||
|
||||
def post_with_media(self, text, attachments):
|
||||
media_ids = []
|
||||
for i in attachments:
|
||||
photo = open(i["file"], "rb")
|
||||
img = self.session.twitter.upload_media(media=photo)
|
||||
self.session.twitter.create_metadata(media_id=img["media_id"], alt_text=dict(text=i["description"]))
|
||||
media_ids.append(img["media_id"])
|
||||
self.session.twitter.update_status(status=text, media_ids=media_ids)
|
||||
|
||||
def get_formatted_message(self):
|
||||
if self.type == "dm" or self.name == "direct_messages":
|
||||
return self.compose_function(self.get_right_tweet(), self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)[1]
|
||||
@@ -288,7 +131,7 @@ class baseBufferController(bufferController):
|
||||
if tweet.has_key("message"):
|
||||
message = tweet["message"]
|
||||
try:
|
||||
tweet = self.session.twitter.twitter.show_status(id=tweet_id, include_ext_alt_text=True, tweet_mode="extended")
|
||||
tweet = self.session.twitter.show_status(id=tweet_id, include_ext_alt_text=True, tweet_mode="extended")
|
||||
urls = utils.find_urls_in_text(tweet["full_text"])
|
||||
for url in range(0, len(urls)):
|
||||
try: tweet["full_text"] = tweet["full_text"].replace(urls[url], tweet["entities"]["urls"][url]["expanded_url"])
|
||||
@@ -302,7 +145,7 @@ class baseBufferController(bufferController):
|
||||
while l != False:
|
||||
tweetsList.append(tweet)
|
||||
try:
|
||||
tweet = self.session.twitter.twitter.show_status(id=l, include_ext_alt_text=True, tweet_mode="extended")
|
||||
tweet = self.session.twitter.show_status(id=l, include_ext_alt_text=True, tweet_mode="extended")
|
||||
urls = utils.find_urls_in_text(tweet["full_text"])
|
||||
for url in range(0, len(urls)):
|
||||
try: tweet["full_text"] = tweet["full_text"].replace(urls[url], tweet["entities"]["urls"][url]["expanded_url"])
|
||||
@@ -315,7 +158,7 @@ class baseBufferController(bufferController):
|
||||
tweetsList.append(tweet)
|
||||
return (tweet, tweetsList)
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True):
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
# starts stream every 3 minutes.
|
||||
current_time = time.time()
|
||||
if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True:
|
||||
@@ -337,8 +180,22 @@ class baseBufferController(bufferController):
|
||||
self.finished_timeline = True
|
||||
if number_of_items > 0 and self.name != "sent_tweets" and self.name != "sent_direct_messages" and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
self.session.sound.play(self.sound)
|
||||
# Autoread settings
|
||||
if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]:
|
||||
self.auto_read(number_of_items)
|
||||
return number_of_items
|
||||
|
||||
def auto_read(self, number_of_items):
|
||||
if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
tweet = self.session.db[self.name][-1]
|
||||
else:
|
||||
tweet = self.session.db[self.name][0]
|
||||
output.speak(_(u"New tweet in {0}").format(self.get_buffer_name()))
|
||||
output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)))
|
||||
elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
output.speak(_(u"{0} new tweets in {1}.").format(number_of_items, self.get_buffer_name()))
|
||||
|
||||
def get_more_items(self):
|
||||
elements = []
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
@@ -349,6 +206,8 @@ class baseBufferController(bufferController):
|
||||
items = self.session.get_more_items(self.function, count=self.session.settings["general"]["max_tweets_per_call"], max_id=last_id, *self.args, **self.kwargs)
|
||||
except TwythonError as e:
|
||||
output.speak(e.message, True)
|
||||
if items == None:
|
||||
return
|
||||
for i in items:
|
||||
if utils.is_allowed(i, self.session.settings, self.name) == True and utils.find_item(i["id"], self.session.db[self.name]) == None:
|
||||
i = self.session.check_quoted_status(i)
|
||||
@@ -456,10 +315,10 @@ class baseBufferController(bufferController):
|
||||
log.debug("Binding events...")
|
||||
self.buffer.set_focus_function(self.onFocus)
|
||||
widgetUtils.connect_event(self.buffer.list.list, widgetUtils.KEYPRESS, self.get_event)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_tweet, self.buffer.tweet)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_status, self.buffer.tweet)
|
||||
# if self.type == "baseBuffer":
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.retweet, self.buffer.retweet)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.direct_message, self.buffer.dm)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.share_item, self.buffer.retweet)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.send_message, self.buffer.dm)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.reply, self.buffer.reply)
|
||||
# Replace for the correct way in other platforms.
|
||||
widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu)
|
||||
@@ -471,13 +330,13 @@ class baseBufferController(bufferController):
|
||||
menu = menus.sentPanelMenu()
|
||||
elif self.name == "direct_messages":
|
||||
menu = menus.dmPanelMenu()
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.direct_message, menuitem=menu.reply)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.send_message, menuitem=menu.reply)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions)
|
||||
else:
|
||||
menu = menus.basePanelMenu()
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.reply, menuitem=menu.reply)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.retweet, menuitem=menu.retweet)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.share_item, menuitem=menu.retweet)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.fav, menuitem=menu.fav)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.unfav, menuitem=menu.unfav)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.url_, menuitem=menu.openUrl)
|
||||
@@ -548,7 +407,7 @@ class baseBufferController(bufferController):
|
||||
if len(users) > 0:
|
||||
config.app["app-settings"]["mention_all"] = message.message.mentionAll.GetValue()
|
||||
config.app.write()
|
||||
params = {"_sound": "reply_send.ogg", "in_reply_to_status_id": id,}
|
||||
params = {"_sound": "reply_send.ogg", "in_reply_to_status_id": id, "tweet_mode": "extended"}
|
||||
text = message.message.get_text()
|
||||
if twishort_enabled == False:
|
||||
excluded_ids = message.get_ids()
|
||||
@@ -568,12 +427,15 @@ class baseBufferController(bufferController):
|
||||
else:
|
||||
params["call_name"] = "update_status_with_media"
|
||||
params["media"] = message.file
|
||||
call_threaded(self.session.api_call, **params)
|
||||
|
||||
item = self.session.api_call(**params)
|
||||
if item != None:
|
||||
pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"])
|
||||
if hasattr(message.message, "destroy"): message.message.destroy()
|
||||
self.session.settings.write()
|
||||
|
||||
@_tweets_exist
|
||||
def direct_message(self, *args, **kwargs):
|
||||
def send_message(self, *args, **kwargs):
|
||||
tweet = self.get_right_tweet()
|
||||
if self.type == "dm":
|
||||
screen_name = self.session.get_user(tweet["message_create"]["sender_id"])["screen_name"]
|
||||
@@ -611,7 +473,7 @@ class baseBufferController(bufferController):
|
||||
if hasattr(dm.message, "destroy"): dm.message.destroy()
|
||||
|
||||
@_tweets_exist
|
||||
def retweet(self, *args, **kwargs):
|
||||
def share_item(self, *args, **kwargs):
|
||||
tweet = self.get_right_tweet()
|
||||
id = tweet["id"]
|
||||
if self.session.settings["general"]["retweet_mode"] == "ask":
|
||||
@@ -626,6 +488,9 @@ class baseBufferController(bufferController):
|
||||
self._retweet_with_comment(tweet, id)
|
||||
|
||||
def _retweet_with_comment(self, tweet, id, comment=''):
|
||||
# If quoting a retweet, let's quote the original tweet instead the retweet.
|
||||
if tweet.has_key("retweeted_status"):
|
||||
tweet = tweet["retweeted_status"]
|
||||
if tweet.has_key("full_text"):
|
||||
comments = tweet["full_text"]
|
||||
else:
|
||||
@@ -637,13 +502,21 @@ class baseBufferController(bufferController):
|
||||
text = retweet.message.get_text()
|
||||
text = text+" https://twitter.com/{0}/status/{1}".format(tweet["user"]["screen_name"], id)
|
||||
if retweet.image == None:
|
||||
call_threaded(self.session.api_call, call_name="update_status", _sound="retweet_send.ogg", status=text, in_reply_to_status_id=id)
|
||||
item = self.session.api_call(call_name="update_status", _sound="retweet_send.ogg", status=text, in_reply_to_status_id=id, tweet_mode="extended")
|
||||
if item != None:
|
||||
new_item = self.session.twitter.show_status(id=item["id"], include_ext_alt_text=True, tweet_mode="extended")
|
||||
pub.sendMessage("sent-tweet", data=new_item, user=self.session.db["user_name"])
|
||||
else:
|
||||
call_threaded(self.session.api_call, call_name="update_status", _sound="retweet_send.ogg", status=text, media=retweet.image)
|
||||
if hasattr(retweet.message, "destroy"): retweet.message.destroy()
|
||||
|
||||
def _direct_retweet(self, id):
|
||||
call_threaded(self.session.api_call, call_name="retweet", _sound="retweet_send.ogg", id=id)
|
||||
item = self.session.api_call(call_name="retweet", _sound="retweet_send.ogg", id=id, tweet_mode="extended")
|
||||
if item != None:
|
||||
# Retweets are returned as non-extended tweets, so let's get the object as extended
|
||||
# just before sending the event message. See https://github.com/manuelcortez/TWBlue/issues/253
|
||||
item = self.session.twitter.show_status(id=item["id"], include_ext_alt_text=True, tweet_mode="extended")
|
||||
pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"])
|
||||
|
||||
def onFocus(self, *args, **kwargs):
|
||||
tweet = self.get_tweet()
|
||||
@@ -711,13 +584,12 @@ class baseBufferController(bufferController):
|
||||
if answer == widgetUtils.YES:
|
||||
try:
|
||||
if self.name == "direct_messages" or self.name == "sent_direct_messages":
|
||||
self.session.twitter.twitter.destroy_direct_message(id=self.get_right_tweet()["id"])
|
||||
self.session.twitter.destroy_direct_message(id=self.get_right_tweet()["id"])
|
||||
self.session.db[self.name]["items"].pop(index)
|
||||
else:
|
||||
self.session.twitter.twitter.destroy_status(id=self.get_right_tweet()["id"])
|
||||
self.session.twitter.destroy_status(id=self.get_right_tweet()["id"])
|
||||
self.session.db[self.name].pop(index)
|
||||
self.buffer.list.remove_item(index)
|
||||
# if index > 0:
|
||||
except TwythonError:
|
||||
self.session.sound.play("error.ogg")
|
||||
|
||||
@@ -737,7 +609,7 @@ class baseBufferController(bufferController):
|
||||
|
||||
def get_quoted_tweet(self, tweet):
|
||||
# try:
|
||||
quoted_tweet = self.session.twitter.twitter.show_status(id=tweet["id"])
|
||||
quoted_tweet = self.session.twitter.show_status(id=tweet["id"])
|
||||
urls = utils.find_urls_in_text(quoted_tweet["text"])
|
||||
for url in range(0, len(urls)):
|
||||
try: quoted_tweet["text"] = quoted_tweet["text"].replace(urls[url], quoted_tweet["entities"]["urls"][url]["expanded_url"])
|
||||
@@ -748,7 +620,7 @@ class baseBufferController(bufferController):
|
||||
l = tweets.is_long(quoted_tweet)
|
||||
id = tweets.get_id(l)
|
||||
# try:
|
||||
original_tweet = self.session.twitter.twitter.show_status(id=id)
|
||||
original_tweet = self.session.twitter.show_status(id=id)
|
||||
urls = utils.find_urls_in_text(original_tweet["text"])
|
||||
for url in range(0, len(urls)):
|
||||
try: original_tweet["text"] = original_tweet["text"].replace(urls[url], original_tweet["entities"]["urls"][url]["expanded_url"])
|
||||
@@ -763,6 +635,8 @@ class directMessagesController(baseBufferController):
|
||||
except TwythonError as e:
|
||||
output.speak(e.message, True)
|
||||
return
|
||||
if items == None:
|
||||
return
|
||||
sent = []
|
||||
for i in items:
|
||||
if i["message_create"]["sender_id"] == self.session.db["user_id"]:
|
||||
@@ -809,7 +683,9 @@ class directMessagesController(baseBufferController):
|
||||
config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue()
|
||||
config.app.write()
|
||||
if message.image == None:
|
||||
call_threaded(self.session.api_call, call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text())
|
||||
item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended")
|
||||
if item != None:
|
||||
pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"])
|
||||
else:
|
||||
call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file)
|
||||
if hasattr(message.message, "destroy"): message.message.destroy()
|
||||
@@ -832,6 +708,17 @@ class directMessagesController(baseBufferController):
|
||||
self.session.db[self.name]["items"] = []
|
||||
self.buffer.list.clear()
|
||||
|
||||
def auto_read(self, number_of_items):
|
||||
if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
tweet = self.session.db[self.name]["items"][-1]
|
||||
else:
|
||||
tweet = self.session.db[self.name]["items"][0]
|
||||
output.speak(_(u"New direct message"))
|
||||
output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)))
|
||||
elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
output.speak(_(u"{0} new direct messages.").format(number_of_items,))
|
||||
|
||||
class sentDirectMessagesController(directMessagesController):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -862,14 +749,14 @@ class listBufferController(baseBufferController):
|
||||
self.list_id = list_id
|
||||
self.kwargs["list_id"] = list_id
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True):
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
self.get_user_ids()
|
||||
super(listBufferController, self).start_stream(mandatory, play_sound)
|
||||
super(listBufferController, self).start_stream(mandatory, play_sound, avoid_autoreading)
|
||||
|
||||
def get_user_ids(self):
|
||||
next_cursor = -1
|
||||
while(next_cursor):
|
||||
users = self.session.twitter.twitter.get_list_members(list_id=self.list_id, cursor=next_cursor, include_entities=False, skip_status=True)
|
||||
users = self.session.twitter.get_list_members(list_id=self.list_id, cursor=next_cursor, include_entities=False, skip_status=True)
|
||||
for i in users['users']:
|
||||
if i["id"] not in self.users:
|
||||
self.users.append(i["id"])
|
||||
@@ -890,58 +777,6 @@ class listBufferController(baseBufferController):
|
||||
elif dlg == widgetUtils.NO:
|
||||
return False
|
||||
|
||||
class eventsBufferController(bufferController):
|
||||
def __init__(self, parent, name, session, account, *args, **kwargs):
|
||||
super(eventsBufferController, self).__init__(parent, *args, **kwargs)
|
||||
log.debug("Initializing buffer %s, account %s" % (name, account,))
|
||||
self.invisible = True
|
||||
self.buffer = buffers.eventsPanel(parent, name)
|
||||
self.name = name
|
||||
self.account = account
|
||||
self.buffer.account = self.account
|
||||
self.compose_function = compose.compose_event
|
||||
self.session = session
|
||||
self.type = self.buffer.type
|
||||
self.get_formatted_message = self.get_message
|
||||
|
||||
def get_message(self):
|
||||
if self.buffer.list.get_count() == 0: return _(u"Empty")
|
||||
# fix this:
|
||||
return "%s. %s" % (self.buffer.list.list.GetItemText(self.buffer.list.get_selected()), self.buffer.list.list.GetItemText(self.buffer.list.get_selected(), 1))
|
||||
|
||||
def add_new_item(self, item):
|
||||
tweet = self.compose_function(item, self.session.db["user_name"], self.session.settings["general"]["show_screen_names"])
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
self.buffer.list.insert_item(False, *tweet)
|
||||
else:
|
||||
self.buffer.list.insert_item(True, *tweet)
|
||||
if self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
output.speak(" ".join(tweet), speech=self.session.settings["reporting"]["speech_reporting"], braille=self.session.settings["reporting"]["braille_reporting"])
|
||||
if self.buffer.list.get_count() == 1:
|
||||
self.buffer.list.select_item(0)
|
||||
|
||||
def clear_list(self):
|
||||
dlg = commonMessageDialogs.clear_list()
|
||||
if dlg == widgetUtils.YES:
|
||||
self.buffer.list.clear()
|
||||
|
||||
def show_menu(self, ev, pos=0, *args, **kwargs):
|
||||
if self.buffer.list.get_count() == 0: return
|
||||
menu = menus.eventsPanelMenu()
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.copy, menuitem=menu.copy)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.destroy_status, menuitem=menu.remove)
|
||||
if pos != 0:
|
||||
self.buffer.PopupMenu(menu, pos)
|
||||
else:
|
||||
self.buffer.PopupMenu(menu, ev.GetPosition())
|
||||
|
||||
def view(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="view_item")
|
||||
|
||||
def copy(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="copy_to_clipboard")
|
||||
|
||||
class peopleBufferController(baseBufferController):
|
||||
def __init__(self, parent, function, name, sessionObject, account, bufferType=None, *args, **kwargs):
|
||||
super(peopleBufferController, self).__init__(parent, function, name, sessionObject, account, bufferType="peoplePanel", *args, **kwargs)
|
||||
@@ -1012,12 +847,14 @@ class peopleBufferController(baseBufferController):
|
||||
config.app["app-settings"]["longtweet"] = message.message.long_tweet.GetValue()
|
||||
config.app.write()
|
||||
if message.image == None:
|
||||
call_threaded(self.session.api_call, call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text())
|
||||
item = self.session.api_call(call_name="update_status", _sound="reply_send.ogg", status=message.message.get_text(), tweet_mode="extended")
|
||||
if item != None:
|
||||
pub.sendMessage("sent-tweet", data=item, user=self.session.db["user_name"])
|
||||
else:
|
||||
call_threaded(self.session.api_call, call_name="update_status_with_media", _sound="reply_send.ogg", status=message.message.get_text(), media=message.file)
|
||||
if hasattr(message.message, "destroy"): message.message.destroy()
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True):
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
# starts stream every 3 minutes.
|
||||
current_time = time.time()
|
||||
if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True:
|
||||
@@ -1031,6 +868,9 @@ class peopleBufferController(baseBufferController):
|
||||
self.finished_timeline = True
|
||||
if val > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
self.session.sound.play(self.sound)
|
||||
# Autoread settings
|
||||
if avoid_autoreading == False and mandatory == True and val > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]:
|
||||
self.auto_read(val)
|
||||
return val
|
||||
|
||||
def get_more_items(self):
|
||||
@@ -1039,6 +879,8 @@ class peopleBufferController(baseBufferController):
|
||||
except TwythonError as e:
|
||||
output.speak(e.message, True)
|
||||
return
|
||||
if items == None:
|
||||
return
|
||||
for i in items:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
self.session.db[self.name]["items"].insert(0, i)
|
||||
@@ -1103,7 +945,7 @@ class peopleBufferController(baseBufferController):
|
||||
|
||||
def show_menu(self, ev, pos=0, *args, **kwargs):
|
||||
menu = menus.peoplePanelMenu()
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.direct_message, menuitem=menu.reply)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.send_message, menuitem=menu.reply)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.user_actions, menuitem=menu.userActions)
|
||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.details, menuitem=menu.details)
|
||||
# widgetUtils.connect_event(menu, widgetUtils.MENU, self.lists, menuitem=menu.lists)
|
||||
@@ -1117,8 +959,18 @@ class peopleBufferController(baseBufferController):
|
||||
def details(self, *args, **kwargs):
|
||||
pub.sendMessage("execute-action", action="user_details")
|
||||
|
||||
def auto_read(self, number_of_items):
|
||||
if number_of_items == 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
tweet = self.session.db[self.name]["items"][-1]
|
||||
else:
|
||||
tweet = self.session.db[self.name["items"]][0]
|
||||
output.speak(" ".join(self.compose_function(tweet, self.session.db, self.session.settings["general"]["relative_times"], self.session.settings["general"]["show_screen_names"], self.session)))
|
||||
elif number_of_items > 1 and self.name in self.session.settings["other_buffers"]["autoread_buffers"] and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and self.session.settings["sound"]["session_mute"] == False:
|
||||
output.speak(_(u"{0} new followers.").format(number_of_items))
|
||||
|
||||
class searchBufferController(baseBufferController):
|
||||
def start_stream(self, mandatory=False, play_sound=True):
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
# starts stream every 3 minutes.
|
||||
current_time = time.time()
|
||||
if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True:
|
||||
@@ -1134,6 +986,9 @@ class searchBufferController(baseBufferController):
|
||||
self.put_items_on_list(num)
|
||||
if num > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
self.session.sound.play(self.sound)
|
||||
# Autoread settings
|
||||
if avoid_autoreading == False and mandatory == True and num > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]:
|
||||
self.auto_read(num)
|
||||
return num
|
||||
|
||||
def remove_buffer(self, force=False):
|
||||
@@ -1161,6 +1016,8 @@ class searchBufferController(baseBufferController):
|
||||
items = self.session.search(self.name, count=self.session.settings["general"]["max_tweets_per_call"], max_id=last_id, *self.args, **self.kwargs)
|
||||
except TwythonError as e:
|
||||
output.speak(e.message, True)
|
||||
if items == None:
|
||||
return
|
||||
for i in items:
|
||||
if utils.is_allowed(i, self.session.settings, self.name) == True and utils.find_item(i["id"], self.session.db[self.name]) == None:
|
||||
i = self.session.check_quoted_status(i)
|
||||
@@ -1197,7 +1054,7 @@ class searchPeopleBufferController(peopleBufferController):
|
||||
if self.kwargs.has_key("page") == False:
|
||||
self.kwargs["page"] = 1
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True):
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=True):
|
||||
# starts stream every 3 minutes.
|
||||
current_time = time.time()
|
||||
if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory==True:
|
||||
@@ -1214,6 +1071,9 @@ class searchPeopleBufferController(peopleBufferController):
|
||||
self.put_items_on_list(number_of_items)
|
||||
if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
self.session.sound.play(self.sound)
|
||||
# Autoread settings
|
||||
if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]:
|
||||
self.auto_read(number_of_items)
|
||||
return number_of_items
|
||||
|
||||
def get_more_items(self, *args, **kwargs):
|
||||
@@ -1223,6 +1083,8 @@ class searchPeopleBufferController(peopleBufferController):
|
||||
except TwythonError as e:
|
||||
output.speak(e.message, True)
|
||||
return
|
||||
if items == None:
|
||||
return
|
||||
for i in items:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
self.session.db[self.name]["items"].insert(0, i)
|
||||
@@ -1259,7 +1121,7 @@ class searchPeopleBufferController(peopleBufferController):
|
||||
elif dlg == widgetUtils.NO:
|
||||
return False
|
||||
|
||||
class trendsBufferController(bufferController):
|
||||
class trendsBufferController(baseBuffers.buffer):
|
||||
def __init__(self, parent, name, session, account, trendsFor, *args, **kwargs):
|
||||
super(trendsBufferController, self).__init__(parent=parent, session=session)
|
||||
self.trendsFor = trendsFor
|
||||
@@ -1278,7 +1140,7 @@ class trendsBufferController(bufferController):
|
||||
self.get_formatted_message = self.get_message
|
||||
self.reply = self.search_topic
|
||||
|
||||
def start_stream(self, mandatory=False, play_sound=True):
|
||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
# starts stream every 3 minutes.
|
||||
current_time = time.time()
|
||||
if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True:
|
||||
@@ -1309,7 +1171,7 @@ class trendsBufferController(bufferController):
|
||||
log.debug("Binding events...")
|
||||
self.buffer.list.list.Bind(wx.EVT_CHAR_HOOK, self.get_event)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.tweet_about_this_trend, self.buffer.tweetTrendBtn)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_tweet, self.buffer.tweet)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.post_status, self.buffer.tweet)
|
||||
widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_ITEM_RIGHT_CLICK, self.show_menu)
|
||||
widgetUtils.connect_event(self.buffer.list.list, wx.EVT_LIST_KEY_DOWN, self.show_menu_by_key)
|
||||
widgetUtils.connect_event(self.buffer, widgetUtils.BUTTON_PRESSED, self.search_topic, self.buffer.search_topic)
|
||||
@@ -1383,7 +1245,7 @@ class trendsBufferController(bufferController):
|
||||
|
||||
class conversationBufferController(searchBufferController):
|
||||
|
||||
def start_stream(self, start=False, mandatory=False, play_sound=True):
|
||||
def start_stream(self, start=False, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||
# starts stream every 3 minutes.
|
||||
current_time = time.time()
|
||||
if self.execution_time == 0 or current_time-self.execution_time >= 180 or mandatory == True:
|
||||
@@ -1396,7 +1258,7 @@ class conversationBufferController(searchBufferController):
|
||||
tweet = self.tweet
|
||||
while tweet["in_reply_to_status_id"] != None:
|
||||
try:
|
||||
tweet = self.session.twitter.twitter.show_status(id=tweet["in_reply_to_status_id"], tweet_mode="extended")
|
||||
tweet = self.session.twitter.show_status(id=tweet["in_reply_to_status_id"], tweet_mode="extended")
|
||||
except TwythonError as err:
|
||||
break
|
||||
self.statuses.insert(0, tweet)
|
||||
@@ -1415,6 +1277,9 @@ class conversationBufferController(searchBufferController):
|
||||
self.put_items_on_list(number_of_items)
|
||||
if number_of_items > 0 and self.sound != None and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"] and play_sound == True:
|
||||
self.session.sound.play(self.sound)
|
||||
# Autoread settings
|
||||
if avoid_autoreading == False and mandatory == True and number_of_items > 0 and self.name in self.session.settings["other_buffers"]["autoread_buffers"]:
|
||||
self.auto_read(number_of_items)
|
||||
return number_of_items
|
||||
|
||||
def remove_buffer(self, force=False):
|
@@ -3,7 +3,7 @@ import widgetUtils
|
||||
import output
|
||||
from wxUI.dialogs import lists
|
||||
from twython import TwythonError
|
||||
from twitter import compose, utils
|
||||
from sessions.twitter import compose, utils
|
||||
from pubsub import pub
|
||||
|
||||
class listsController(object):
|
||||
@@ -29,7 +29,7 @@ class listsController(object):
|
||||
return [compose.compose_list(item) for item in self.session.db["lists"]]
|
||||
|
||||
def get_user_lists(self, user):
|
||||
self.lists = self.session.twitter.twitter.show_lists(reverse=True, screen_name=user)
|
||||
self.lists = self.session.twitter.show_lists(reverse=True, screen_name=user)
|
||||
return [compose.compose_list(item) for item in self.lists]
|
||||
|
||||
def create_list(self, *args, **kwargs):
|
||||
@@ -43,7 +43,7 @@ class listsController(object):
|
||||
else:
|
||||
mode = "private"
|
||||
try:
|
||||
new_list = self.session.twitter.twitter.create_list(name=name, description=description, mode=mode)
|
||||
new_list = self.session.twitter.create_list(name=name, description=description, mode=mode)
|
||||
self.session.db["lists"].append(new_list)
|
||||
self.dialog.lista.insert_item(False, *compose.compose_list(new_list))
|
||||
except TwythonError as e:
|
||||
@@ -63,7 +63,7 @@ class listsController(object):
|
||||
else:
|
||||
mode = "private"
|
||||
try:
|
||||
self.session.twitter.twitter.update_list(list_id=list["id"], name=name, description=description, mode=mode)
|
||||
self.session.twitter.update_list(list_id=list["id"], name=name, description=description, mode=mode)
|
||||
self.session.get_lists()
|
||||
self.dialog.populate_list(self.get_all_lists(), True)
|
||||
except TwythonError as e:
|
||||
@@ -75,7 +75,7 @@ class listsController(object):
|
||||
list = self.session.db["lists"][self.dialog.get_item()]["id"]
|
||||
if lists.remove_list() == widgetUtils.YES:
|
||||
try:
|
||||
self.session.twitter.twitter.delete_list(list_id=list)
|
||||
self.session.twitter.delete_list(list_id=list)
|
||||
self.session.db["lists"].pop(self.dialog.get_item())
|
||||
self.dialog.lista.remove_item(self.dialog.get_item())
|
||||
except TwythonError as e:
|
||||
@@ -90,7 +90,7 @@ class listsController(object):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list_id = self.lists[self.dialog.get_item()]["id"]
|
||||
try:
|
||||
list = self.session.twitter.twitter.subscribe_to_list(list_id=list_id)
|
||||
list = self.session.twitter.subscribe_to_list(list_id=list_id)
|
||||
item = utils.find_item(list["id"], self.session.db["lists"])
|
||||
self.session.db["lists"].append(list)
|
||||
except TwythonError as e:
|
||||
@@ -100,7 +100,7 @@ class listsController(object):
|
||||
if self.dialog.lista.get_count() == 0: return
|
||||
list_id = self.lists[self.dialog.get_item()]["id"]
|
||||
try:
|
||||
list = self.session.twitter.twitter.unsubscribe_from_list(list_id=list_id)
|
||||
list = self.session.twitter.unsubscribe_from_list(list_id=list_id)
|
||||
self.session.db["lists"].remove(list)
|
||||
except TwythonError as e:
|
||||
output.speak("error %s: %s" % (e.status_code, e.msg))
|
||||
|
@@ -2,7 +2,9 @@
|
||||
import platform
|
||||
system = platform.system()
|
||||
import application
|
||||
import requests
|
||||
import youtube_utils
|
||||
import arrow
|
||||
if system == "Windows":
|
||||
from update import updater
|
||||
from wxUI import (view, dialogs, commonMessageDialogs, sysTrayIcon)
|
||||
@@ -18,12 +20,13 @@ if system == "Windows":
|
||||
# from issueReporter import issueReporter
|
||||
elif system == "Linux":
|
||||
from gtkUI import (view, commonMessageDialogs)
|
||||
from twitter import utils, compose
|
||||
from sessions.twitter import utils, compose
|
||||
from sessionmanager import manager, sessionManager
|
||||
|
||||
import buffersController
|
||||
from controller.buffers import baseBuffers, twitterBuffers
|
||||
import messages
|
||||
from sessionmanager import session as session_
|
||||
import sessions
|
||||
from sessions.twitter import session as session_
|
||||
from pubsub import pub
|
||||
import sound
|
||||
import output
|
||||
@@ -39,6 +42,7 @@ import logging
|
||||
import webbrowser
|
||||
from mysc import localization
|
||||
import os
|
||||
import languageHandler
|
||||
|
||||
log = logging.getLogger("mainController")
|
||||
|
||||
@@ -54,13 +58,13 @@ class Controller(object):
|
||||
name_ str: The name for the buffer
|
||||
user str: The account for the buffer.
|
||||
for example you may want to search the home_timeline buffer for the tw_blue2 user.
|
||||
Return type: buffersController.buffer object."""
|
||||
Return type: buffers.buffer object."""
|
||||
for i in self.buffers:
|
||||
if i.name == name_ and i.account == user: return i
|
||||
|
||||
def get_current_buffer(self):
|
||||
""" Get the current focused bufferObject.
|
||||
Return type: BuffersController.buffer object."""
|
||||
Return type: buffers.buffer object."""
|
||||
buffer = self.view.get_current_buffer()
|
||||
if hasattr(buffer, "account"):
|
||||
buffer = self.search_buffer(buffer.name, buffer.account)
|
||||
@@ -69,7 +73,7 @@ class Controller(object):
|
||||
def get_best_buffer(self):
|
||||
""" Get the best buffer for doing something using the session object.
|
||||
This function is useful when you need to open a timeline or post a tweet, and the user is in a buffer without a session, for example the events buffer.
|
||||
Return type: buffersController.buffer object."""
|
||||
Return type: twitterBuffers.buffer object."""
|
||||
# Gets the parent buffer to know what account is doing an action
|
||||
view_buffer = self.view.get_current_buffer()
|
||||
# If the account has no session attached, we will need to search the first available non-empty buffer for that account to use its session.
|
||||
@@ -108,27 +112,6 @@ class Controller(object):
|
||||
[results.append(self.search_buffer(i.name, i.account)) for i in buffers if i.account == account and (i.type != "account")]
|
||||
return results
|
||||
|
||||
def bind_stream_events(self):
|
||||
""" Binds all the streaming events with their functions."""
|
||||
log.debug("Binding events for the Twitter stream API...")
|
||||
pub.subscribe(self.manage_home_timelines, "item-in-home")
|
||||
pub.subscribe(self.manage_mentions, "mention")
|
||||
pub.subscribe(self.manage_direct_messages, "direct-message")
|
||||
pub.subscribe(self.manage_sent_tweets, "sent-tweet")
|
||||
pub.subscribe(self.manage_events, "event")
|
||||
pub.subscribe(self.manage_followers, "follower")
|
||||
pub.subscribe(self.manage_friend, "friend")
|
||||
pub.subscribe(self.manage_unfollowing, "unfollowing")
|
||||
pub.subscribe(self.manage_favourite, "favourite")
|
||||
pub.subscribe(self.manage_unfavourite, "unfavourite")
|
||||
pub.subscribe(self.manage_blocked_user, "blocked-user")
|
||||
pub.subscribe(self.manage_unblocked_user, "unblocked-user")
|
||||
pub.subscribe(self.manage_item_in_timeline, "item-in-timeline")
|
||||
pub.subscribe(self.manage_item_in_list, "item-in-list")
|
||||
pub.subscribe(self.on_tweet_deleted, "tweet-deleted")
|
||||
pub.subscribe(self.manage_stream_errors, "stream-error")
|
||||
# pub.subscribe(self.restart_streams, "restart-streams")
|
||||
|
||||
def bind_other_events(self):
|
||||
""" Binds the local application events with their functions."""
|
||||
log.debug("Binding other application events...")
|
||||
@@ -142,6 +125,13 @@ class Controller(object):
|
||||
pub.subscribe(self.search_topic, "search")
|
||||
pub.subscribe(self.update_sent_dms, "sent-dms-updated")
|
||||
pub.subscribe(self.more_dms, "more-sent-dms")
|
||||
pub.subscribe(self.manage_sent_tweets, "sent-tweet")
|
||||
pub.subscribe(self.manage_friend, "friend")
|
||||
pub.subscribe(self.manage_unfollowing, "unfollowing")
|
||||
pub.subscribe(self.manage_favourite, "favourite")
|
||||
pub.subscribe(self.manage_unfavourite, "unfavourite")
|
||||
pub.subscribe(self.manage_blocked_user, "blocked-user")
|
||||
pub.subscribe(self.manage_unblocked_user, "unblocked-user")
|
||||
if system == "Windows":
|
||||
pub.subscribe(self.invisible_shorcuts_changed, "invisible-shorcuts-changed")
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.show_hide, menuitem=self.view.show_hide)
|
||||
@@ -165,7 +155,7 @@ class Controller(object):
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_reply, self.view.reply)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.post_retweet, self.view.retweet)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.add_to_favourites, self.view.fav)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_favourites, self.view.fav)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.remove_from_favourites, self.view.unfav)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.view_item, self.view.view)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.reverse_geocode, menuitem=self.view.view_coordinates)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.delete, self.view.delete)
|
||||
@@ -179,6 +169,7 @@ class Controller(object):
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.check_for_updates, self.view.check_for_updates)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.about, menuitem=self.view.about)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.visit_website, menuitem=self.view.visit_website)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.get_soundpacks, menuitem=self.view.get_soundpacks)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.manage_accounts, self.view.manage_accounts)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.update_profile, menuitem=self.view.updateProfile)
|
||||
widgetUtils.connect_event(self.view, widgetUtils.MENU, self.user_details, menuitem=self.view.details)
|
||||
@@ -234,8 +225,6 @@ class Controller(object):
|
||||
# This saves the current account (important in invisible mode)
|
||||
self.current_account = ""
|
||||
self.view.prepare()
|
||||
if application.streaming_lives():
|
||||
self.bind_stream_events()
|
||||
self.bind_other_events()
|
||||
if system == "Windows":
|
||||
self.set_systray_icon()
|
||||
@@ -255,12 +244,12 @@ class Controller(object):
|
||||
def do_work(self):
|
||||
""" Creates the buffer objects for all accounts. This does not starts the buffer streams, only creates the objects."""
|
||||
log.debug("Creating buffers for all sessions...")
|
||||
for i in session_.sessions:
|
||||
for i in sessions.sessions:
|
||||
log.debug("Working on session %s" % (i,))
|
||||
if session_.sessions[i].is_logged == False:
|
||||
self.create_ignored_session_buffer(session_.sessions[i])
|
||||
if sessions.sessions[i].is_logged == False:
|
||||
self.create_ignored_session_buffer(sessions.sessions[i])
|
||||
continue
|
||||
self.create_buffers(session_.sessions[i])
|
||||
self.create_buffers(sessions.sessions[i])
|
||||
|
||||
# Connection checker executed each minute.
|
||||
self.checker_function = RepeatingTimer(60, self.check_connection)
|
||||
@@ -273,27 +262,27 @@ class Controller(object):
|
||||
|
||||
def start(self):
|
||||
""" Starts all buffer objects. Loads their items."""
|
||||
for i in session_.sessions:
|
||||
if session_.sessions[i].is_logged == False: continue
|
||||
self.start_buffers(session_.sessions[i])
|
||||
self.set_buffer_positions(session_.sessions[i])
|
||||
for i in sessions.sessions:
|
||||
if sessions.sessions[i].is_logged == False: continue
|
||||
self.start_buffers(sessions.sessions[i])
|
||||
self.set_buffer_positions(sessions.sessions[i])
|
||||
if config.app["app-settings"]["play_ready_sound"] == True:
|
||||
session_.sessions[session_.sessions.keys()[0]].sound.play("ready.ogg")
|
||||
sessions.sessions[sessions.sessions.keys()[0]].sound.play("ready.ogg")
|
||||
if config.app["app-settings"]["speak_ready_msg"] == True:
|
||||
output.speak(_(u"Ready"))
|
||||
self.started = True
|
||||
|
||||
def create_ignored_session_buffer(self, session):
|
||||
self.accounts.append(session.settings["twitter"]["user_name"])
|
||||
account = buffersController.accountPanel(self.view.nb, session.settings["twitter"]["user_name"], session.settings["twitter"]["user_name"], session.session_id)
|
||||
account = baseBuffers.accountPanel(self.view.nb, session.settings["twitter"]["user_name"], session.settings["twitter"]["user_name"], session.session_id)
|
||||
account.logged = False
|
||||
account.setup_account()
|
||||
self.buffers.append(account)
|
||||
self.view.add_buffer(account.buffer , name=session.settings["twitter"]["user_name"])
|
||||
|
||||
def login_account(self, session_id):
|
||||
for i in session_.sessions:
|
||||
if session_.sessions[i].session_id == session_id: session = session_.sessions[i]
|
||||
for i in sessions.sessions:
|
||||
if sessions.sessions[i].session_id == session_id: session = sessions.sessions[i]
|
||||
session.login()
|
||||
session.db = dict()
|
||||
self.create_buffers(session, False)
|
||||
@@ -305,100 +294,96 @@ class Controller(object):
|
||||
session.get_user_info()
|
||||
if createAccounts == True:
|
||||
self.accounts.append(session.db["user_name"])
|
||||
account = buffersController.accountPanel(self.view.nb, session.db["user_name"], session.db["user_name"], session.session_id)
|
||||
account = baseBuffers.accountPanel(self.view.nb, session.db["user_name"], session.db["user_name"], session.session_id)
|
||||
account.setup_account()
|
||||
self.buffers.append(account)
|
||||
self.view.add_buffer(account.buffer , name=session.db["user_name"])
|
||||
for i in session.settings['general']['buffer_order']:
|
||||
if i == 'home':
|
||||
home = buffersController.baseBufferController(self.view.nb, "get_home_timeline", "home_timeline", session, session.db["user_name"], sound="tweet_received.ogg", tweet_mode="extended")
|
||||
home = twitterBuffers.baseBufferController(self.view.nb, "get_home_timeline", "home_timeline", session, session.db["user_name"], sound="tweet_received.ogg", tweet_mode="extended")
|
||||
self.buffers.append(home)
|
||||
self.view.insert_buffer(home.buffer, name=_(u"Home"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
elif i == 'mentions':
|
||||
mentions = buffersController.baseBufferController(self.view.nb, "get_mentions_timeline", "mentions", session, session.db["user_name"], sound="mention_received.ogg", tweet_mode="extended")
|
||||
mentions = twitterBuffers.baseBufferController(self.view.nb, "get_mentions_timeline", "mentions", session, session.db["user_name"], sound="mention_received.ogg", tweet_mode="extended")
|
||||
self.buffers.append(mentions)
|
||||
self.view.insert_buffer(mentions.buffer, name=_(u"Mentions"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
elif i == 'dm':
|
||||
dm = buffersController.directMessagesController(self.view.nb, "get_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg", full_text=True, items="events")
|
||||
dm = twitterBuffers.directMessagesController(self.view.nb, "get_direct_messages", "direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message", sound="dm_received.ogg", full_text=True, items="events")
|
||||
self.buffers.append(dm)
|
||||
self.view.insert_buffer(dm.buffer, name=_(u"Direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
elif i == 'sent_dm':
|
||||
sent_dm = buffersController.sentDirectMessagesController(self.view.nb, "", "sent_direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message")
|
||||
sent_dm = twitterBuffers.sentDirectMessagesController(self.view.nb, "", "sent_direct_messages", session, session.db["user_name"], bufferType="dmPanel", compose_func="compose_direct_message")
|
||||
self.buffers.append(sent_dm)
|
||||
self.view.insert_buffer(sent_dm.buffer, name=_(u"Sent Direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
self.view.insert_buffer(sent_dm.buffer, name=_(u"Sent direct messages"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
elif i == 'sent_tweets':
|
||||
sent_tweets = buffersController.baseBufferController(self.view.nb, "get_user_timeline", "sent_tweets", session, session.db["user_name"], screen_name=session.db["user_name"], tweet_mode="extended")
|
||||
sent_tweets = twitterBuffers.baseBufferController(self.view.nb, "get_user_timeline", "sent_tweets", session, session.db["user_name"], screen_name=session.db["user_name"], tweet_mode="extended")
|
||||
self.buffers.append(sent_tweets)
|
||||
self.view.insert_buffer(sent_tweets.buffer, name=_(u"Sent tweets"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
elif i == 'favorites':
|
||||
favourites = buffersController.baseBufferController(self.view.nb, "get_favorites", "favourites", session, session.db["user_name"], sound="favourite.ogg", tweet_mode="extended")
|
||||
favourites = twitterBuffers.baseBufferController(self.view.nb, "get_favorites", "favourites", session, session.db["user_name"], sound="favourite.ogg", tweet_mode="extended")
|
||||
self.buffers.append(favourites)
|
||||
self.view.insert_buffer(favourites.buffer, name=_(u"Likes"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
elif i == 'followers':
|
||||
followers = buffersController.peopleBufferController(self.view.nb, "get_followers_list", "followers", session, session.db["user_name"], sound="update_followers.ogg", screen_name=session.db["user_name"])
|
||||
followers = twitterBuffers.peopleBufferController(self.view.nb, "get_followers_list", "followers", session, session.db["user_name"], sound="update_followers.ogg", screen_name=session.db["user_name"])
|
||||
self.buffers.append(followers)
|
||||
self.view.insert_buffer(followers.buffer, name=_(u"Followers"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
elif i == 'friends':
|
||||
friends = buffersController.peopleBufferController(self.view.nb, "get_friends_list", "friends", session, session.db["user_name"], screen_name=session.db["user_name"])
|
||||
friends = twitterBuffers.peopleBufferController(self.view.nb, "get_friends_list", "friends", session, session.db["user_name"], screen_name=session.db["user_name"])
|
||||
self.buffers.append(friends)
|
||||
self.view.insert_buffer(friends.buffer, name=_(u"Friends"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
elif i == 'blocks':
|
||||
blocks = buffersController.peopleBufferController(self.view.nb, "list_blocks", "blocked", session, session.db["user_name"])
|
||||
blocks = twitterBuffers.peopleBufferController(self.view.nb, "list_blocks", "blocked", session, session.db["user_name"])
|
||||
self.buffers.append(blocks)
|
||||
self.view.insert_buffer(blocks.buffer, name=_(u"Blocked users"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
elif i == 'muted':
|
||||
muted = buffersController.peopleBufferController(self.view.nb, "list_mutes", "muted", session, session.db["user_name"])
|
||||
muted = twitterBuffers.peopleBufferController(self.view.nb, "list_mutes", "muted", session, session.db["user_name"])
|
||||
self.buffers.append(muted)
|
||||
self.view.insert_buffer(muted.buffer, name=_(u"Muted users"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
elif i == 'events' and application.streaming_lives():
|
||||
events = buffersController.eventsBufferController(self.view.nb, "events", session, session.db["user_name"], bufferType="dmPanel", screen_name=session.db["user_name"])
|
||||
self.buffers.append(events)
|
||||
self.view.insert_buffer(events.buffer, name=_(u"Events"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
timelines = buffersController.emptyPanel(self.view.nb, "timelines", session.db["user_name"])
|
||||
timelines = baseBuffers.emptyPanel(self.view.nb, "timelines", session.db["user_name"])
|
||||
self.buffers.append(timelines)
|
||||
self.view.insert_buffer(timelines.buffer , name=_(u"Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
for i in session.settings["other_buffers"]["timelines"]:
|
||||
tl = buffersController.baseBufferController(self.view.nb, "get_user_timeline", "%s-timeline" % (i,), session, session.db["user_name"], sound="tweet_timeline.ogg", bufferType=None, user_id=i, tweet_mode="extended")
|
||||
tl = twitterBuffers.baseBufferController(self.view.nb, "get_user_timeline", "%s-timeline" % (i,), session, session.db["user_name"], sound="tweet_timeline.ogg", bufferType=None, user_id=i, tweet_mode="extended")
|
||||
self.buffers.append(tl)
|
||||
self.view.insert_buffer(tl.buffer, name=_(u"Timeline for {}").format(i,), pos=self.view.search("timelines", session.db["user_name"]))
|
||||
favs_timelines = buffersController.emptyPanel(self.view.nb, "favs_timelines", session.db["user_name"])
|
||||
favs_timelines = baseBuffers.emptyPanel(self.view.nb, "favs_timelines", session.db["user_name"])
|
||||
self.buffers.append(favs_timelines)
|
||||
self.view.insert_buffer(favs_timelines.buffer , name=_(u"Likes timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
for i in session.settings["other_buffers"]["favourites_timelines"]:
|
||||
tl = buffersController.baseBufferController(self.view.nb, "get_favorites", "%s-favorite" % (i,), session, session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=i, tweet_mode="extended")
|
||||
tl = twitterBuffers.baseBufferController(self.view.nb, "get_favorites", "%s-favorite" % (i,), session, session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=i, tweet_mode="extended")
|
||||
self.buffers.append(tl)
|
||||
self.view.insert_buffer(tl.buffer, name=_(u"Likes for {}").format(i,), pos=self.view.search("favs_timelines", session.db["user_name"]))
|
||||
followers_timelines = buffersController.emptyPanel(self.view.nb, "followers_timelines", session.db["user_name"])
|
||||
followers_timelines = baseBuffers.emptyPanel(self.view.nb, "followers_timelines", session.db["user_name"])
|
||||
self.buffers.append(followers_timelines)
|
||||
self.view.insert_buffer(followers_timelines.buffer , name=_(u"Followers' Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
for i in session.settings["other_buffers"]["followers_timelines"]:
|
||||
tl = buffersController.peopleBufferController(self.view.nb, "get_followers_list", "%s-followers" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i)
|
||||
tl = twitterBuffers.peopleBufferController(self.view.nb, "get_followers_list", "%s-followers" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i)
|
||||
self.buffers.append(tl)
|
||||
self.view.insert_buffer(tl.buffer, name=_(u"Followers for {}").format(i,), pos=self.view.search("followers_timelines", session.db["user_name"]))
|
||||
friends_timelines = buffersController.emptyPanel(self.view.nb, "friends_timelines", session.db["user_name"])
|
||||
friends_timelines = baseBuffers.emptyPanel(self.view.nb, "friends_timelines", session.db["user_name"])
|
||||
self.buffers.append(friends_timelines)
|
||||
self.view.insert_buffer(friends_timelines.buffer , name=_(u"Friends' Timelines"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
for i in session.settings["other_buffers"]["friends_timelines"]:
|
||||
tl = buffersController.peopleBufferController(self.view.nb, "get_friends_list", "%s-friends" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i)
|
||||
tl = twitterBuffers.peopleBufferController(self.view.nb, "get_friends_list", "%s-friends" % (i,), session, session.db["user_name"], sound="new_event.ogg", user_id=i)
|
||||
self.buffers.append(tl)
|
||||
self.view.insert_buffer(tl.buffer, name=_(u"Friends for {}").format(i,), pos=self.view.search("friends_timelines", session.db["user_name"]))
|
||||
lists = buffersController.emptyPanel(self.view.nb, "lists", session.db["user_name"])
|
||||
lists = baseBuffers.emptyPanel(self.view.nb, "lists", session.db["user_name"])
|
||||
self.buffers.append(lists)
|
||||
self.view.insert_buffer(lists.buffer , name=_(u"Lists"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
for i in session.settings["other_buffers"]["lists"]:
|
||||
tl = buffersController.listBufferController(self.view.nb, "get_list_statuses", "%s-list" % (i,), session, session.db["user_name"], bufferType=None, sound="list_tweet.ogg", list_id=utils.find_list(i, session.db["lists"]), tweet_mode="extended")
|
||||
tl = twitterBuffers.listBufferController(self.view.nb, "get_list_statuses", "%s-list" % (i,), session, session.db["user_name"], bufferType=None, sound="list_tweet.ogg", list_id=utils.find_list(i, session.db["lists"]), tweet_mode="extended")
|
||||
session.lists.append(tl)
|
||||
self.buffers.append(tl)
|
||||
self.view.insert_buffer(tl.buffer, name=_(u"List for {}").format(i), pos=self.view.search("lists", session.db["user_name"]))
|
||||
searches = buffersController.emptyPanel(self.view.nb, "searches", session.db["user_name"])
|
||||
searches = baseBuffers.emptyPanel(self.view.nb, "searches", session.db["user_name"])
|
||||
self.buffers.append(searches)
|
||||
self.view.insert_buffer(searches.buffer , name=_(u"Searches"), pos=self.view.search(session.db["user_name"], session.db["user_name"]))
|
||||
for i in session.settings["other_buffers"]["tweet_searches"]:
|
||||
tl = buffersController.searchBufferController(self.view.nb, "search", "%s-searchterm" % (i,), session, session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=i, tweet_mode="extended")
|
||||
tl = twitterBuffers.searchBufferController(self.view.nb, "search", "%s-searchterm" % (i,), session, session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=i, tweet_mode="extended")
|
||||
self.buffers.append(tl)
|
||||
self.view.insert_buffer(tl.buffer, name=_(u"Search for {}").format(i), pos=self.view.search("searches", session.db["user_name"]))
|
||||
for i in session.settings["other_buffers"]["trending_topic_buffers"]:
|
||||
buffer = buffersController.trendsBufferController(self.view.nb, "%s_tt" % (i,), session, session.db["user_name"], i, sound="trends_updated.ogg")
|
||||
buffer = twitterBuffers.trendsBufferController(self.view.nb, "%s_tt" % (i,), session, session.db["user_name"], i, sound="trends_updated.ogg")
|
||||
buffer.start_stream(play_sound=False)
|
||||
buffer.searchfunction = self.search
|
||||
self.buffers.append(buffer)
|
||||
@@ -411,8 +396,8 @@ class Controller(object):
|
||||
i.buffer.list.select_item(session.db[str(i.name+"_pos")])
|
||||
|
||||
def logout_account(self, session_id):
|
||||
for i in session_.sessions:
|
||||
if session_.sessions[i].session_id == session_id: session = session_.sessions[i]
|
||||
for i in sessions.sessions:
|
||||
if sessions.sessions[i].session_id == session_id: session = sessions.sessions[i]
|
||||
user = session.db["user_name"]
|
||||
delete_buffers = []
|
||||
for i in self.buffers:
|
||||
@@ -446,12 +431,12 @@ class Controller(object):
|
||||
buffer.session.settings["other_buffers"]["tweet_searches"].append(term)
|
||||
buffer.session.settings.write()
|
||||
args = {"lang": dlg.get_language(), "result_type": dlg.get_result_type()}
|
||||
search = buffersController.searchBufferController(self.view.nb, "search", "%s-searchterm" % (term,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended", **args)
|
||||
search = twitterBuffers.searchBufferController(self.view.nb, "search", "%s-searchterm" % (term,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", q=term, tweet_mode="extended", **args)
|
||||
else:
|
||||
log.error("A buffer for the %s search term is already created. You can't create a duplicate buffer." % (term,))
|
||||
return
|
||||
elif dlg.get("users") == True:
|
||||
search = buffersController.searchPeopleBufferController(self.view.nb, "search_users", "%s-searchUser" % (term,), buffer.session, buffer.session.db["user_name"], bufferType=None, sound="search_updated.ogg", q=term)
|
||||
search = twitterBuffers.searchPeopleBufferController(self.view.nb, "search_users", "%s-searchUser" % (term,), buffer.session, buffer.session.db["user_name"], bufferType=None, sound="search_updated.ogg", q=term)
|
||||
search.start_stream(mandatory=True)
|
||||
pos=self.view.search("searches", buffer.session.db["user_name"])
|
||||
self.insert_buffer(search, pos)
|
||||
@@ -572,13 +557,12 @@ class Controller(object):
|
||||
dlg.populate_list([compose.compose_list(item) for item in buff.session.db["lists"]])
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
try:
|
||||
list = buff.session.twitter.twitter.add_list_member(list_id=buff.session.db["lists"][dlg.get_item()]["id"], screen_name=user)
|
||||
list = buff.session.twitter.add_list_member(list_id=buff.session.db["lists"][dlg.get_item()]["id"], screen_name=user)
|
||||
older_list = utils.find_item(buff.session.db["lists"][dlg.get_item()]["id"], buff.session.db["lists"])
|
||||
listBuffer = self.search_buffer("%s-list" % (buff.session.db["lists"][dlg.get_item()]["name"].lower()), buff.session.db["user_name"])
|
||||
if listBuffer != None: listBuffer.get_user_ids()
|
||||
buff.session.db["lists"].pop(older_list)
|
||||
buff.session.db["lists"].append(list)
|
||||
if listBuffer != None: pub.sendMessage("restart-streams", streams=["timelinesStream"], session=buff.session)
|
||||
except TwythonError as e:
|
||||
output.speak("error %s: %s" % (e.error_code, e.msg))
|
||||
|
||||
@@ -601,13 +585,12 @@ class Controller(object):
|
||||
dlg.populate_list([compose.compose_list(item) for item in buff.session.db["lists"]])
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
try:
|
||||
list = buff.session.twitter.twitter.delete_list_member(list_id=buff.session.db["lists"][dlg.get_item()]["id"], screen_name=user)
|
||||
list = buff.session.twitter.delete_list_member(list_id=buff.session.db["lists"][dlg.get_item()]["id"], screen_name=user)
|
||||
older_list = utils.find_item(buff.session.db["lists"][dlg.get_item()]["id"], buff.session.db["lists"])
|
||||
listBuffer = self.search_buffer("%s-list" % (buff.session.db["lists"][dlg.get_item()]["name"].lower()), buff.session.db["user_name"])
|
||||
if listBuffer != None: listBuffer.get_user_ids()
|
||||
buff.session.db["lists"].pop(older_list)
|
||||
buff.session.db["lists"].append(list)
|
||||
if listBuffer != None: pub.sendMessage("restart-streams", streams=["timelinesStream"], session=buff.session)
|
||||
except TwythonError as e:
|
||||
output.speak("error %s: %s" % (e.error_code, e.msg))
|
||||
|
||||
@@ -664,14 +647,12 @@ class Controller(object):
|
||||
for i in self.buffers: i.save_positions()
|
||||
log.debug("Exiting...")
|
||||
log.debug("Saving global configuration...")
|
||||
for item in session_.sessions:
|
||||
if session_.sessions[item].logged == False: continue
|
||||
log.debug("Disconnecting streams for %s session" % (session_.sessions[item].session_id,))
|
||||
if hasattr(session_.sessions[item], "main_stream"): session_.sessions[item].main_stream.disconnect()
|
||||
if hasattr(session_.sessions[item], "timelinesStream"): session_.sessions[item].timelinesStream.disconnect()
|
||||
session_.sessions[item].sound.cleaner.cancel()
|
||||
log.debug("Shelving database for " + session_.sessions[item].session_id)
|
||||
session_.sessions[item].shelve()
|
||||
for item in sessions.sessions:
|
||||
if sessions.sessions[item].logged == False: continue
|
||||
log.debug("Disconnecting streams for %s session" % (sessions.sessions[item].session_id,))
|
||||
sessions.sessions[item].sound.cleaner.cancel()
|
||||
log.debug("Shelving database for " + sessions.sessions[item].session_id)
|
||||
sessions.sessions[item].shelve()
|
||||
if system == "Windows":
|
||||
self.systrayIcon.RemoveIcon()
|
||||
widgetUtils.exit_application()
|
||||
@@ -762,25 +743,25 @@ class Controller(object):
|
||||
|
||||
def post_tweet(self, event=None):
|
||||
buffer = self.get_best_buffer()
|
||||
buffer.post_tweet()
|
||||
buffer.post_status()
|
||||
|
||||
def post_reply(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
if buffer.name == "direct_messages":
|
||||
buffer.direct_message()
|
||||
buffer.send_message()
|
||||
else:
|
||||
buffer.reply()
|
||||
|
||||
def send_dm(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
buffer.direct_message()
|
||||
buffer.send_message()
|
||||
|
||||
def post_retweet(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
if buffer.type == "dm" or buffer.type == "people" or buffer.type == "events":
|
||||
return
|
||||
else:
|
||||
buffer.retweet()
|
||||
buffer.share_item()
|
||||
|
||||
def add_to_favourites(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
@@ -804,7 +785,7 @@ class Controller(object):
|
||||
return
|
||||
else:
|
||||
id = buffer.get_tweet()["id"]
|
||||
tweet = buffer.session.twitter.twitter.show_status(id=id, include_ext_alt_text=True, tweet_mode="extended")
|
||||
tweet = buffer.session.twitter.show_status(id=id, include_ext_alt_text=True, tweet_mode="extended")
|
||||
if tweet["favorited"] == False:
|
||||
call_threaded(buffer.session.api_call, call_name="create_favorite", _sound="favourite.ogg", id=id)
|
||||
else:
|
||||
@@ -812,14 +793,17 @@ class Controller(object):
|
||||
|
||||
def view_item(self, *args, **kwargs):
|
||||
buffer = self.get_current_buffer()
|
||||
if buffer.type == "baseBuffer" or buffer.type == "favourites_timeline" or buffer.type == "list" or buffer.type == "search":
|
||||
tweet, tweetsList = buffer.get_full_tweet()
|
||||
msg = messages.viewTweet(tweet, tweetsList)
|
||||
elif buffer.type == "account" or buffer.type == "empty":
|
||||
if buffer.type == "account" or buffer.type == "empty":
|
||||
return
|
||||
elif buffer.name == "sent_tweets":
|
||||
elif buffer.type == "baseBuffer" or buffer.type == "favourites_timeline" or buffer.type == "list" or buffer.type == "search":
|
||||
tweet, tweetsList = buffer.get_full_tweet()
|
||||
msg = messages.viewTweet(tweet, tweetsList)
|
||||
msg = messages.viewTweet(tweet, tweetsList, utc_offset=buffer.session.db["utc_offset"])
|
||||
elif buffer.type == "dm":
|
||||
non_tweet = buffer.get_formatted_message()
|
||||
item = buffer.get_right_tweet()
|
||||
original_date = arrow.get(item["created_timestamp"][:-3])
|
||||
date = original_date.replace(seconds=buffer.session.db["utc_offset"]).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage())
|
||||
msg = messages.viewTweet(non_tweet, [], False, date=date)
|
||||
else:
|
||||
non_tweet = buffer.get_formatted_message()
|
||||
msg = messages.viewTweet(non_tweet, [], False)
|
||||
@@ -839,7 +823,7 @@ class Controller(object):
|
||||
users = utils.get_all_users(tweet, buff.session.db)
|
||||
dlg = dialogs.userSelection.selectUserDialog(users=users, default=default)
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
usr = utils.if_user_exists(buff.session.twitter.twitter, dlg.get_user())
|
||||
usr = utils.if_user_exists(buff.session.twitter, dlg.get_user())
|
||||
if usr != None:
|
||||
if usr == dlg.get_user():
|
||||
commonMessageDialogs.suspended_user()
|
||||
@@ -848,9 +832,6 @@ class Controller(object):
|
||||
if usr["following"] == False:
|
||||
commonMessageDialogs.no_following()
|
||||
return
|
||||
if application.streaming_lives():
|
||||
answer = commonMessageDialogs.protected_user()
|
||||
if answer == widgetUtils.NO: return
|
||||
tl_type = dlg.get_action()
|
||||
if tl_type == "tweets":
|
||||
if usr["statuses_count"] == 0:
|
||||
@@ -859,7 +840,7 @@ class Controller(object):
|
||||
if usr["id_str"] in buff.session.settings["other_buffers"]["timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
tl = buffersController.baseBufferController(self.view.nb, "get_user_timeline", "%s-timeline" % (usr["id_str"],), buff.session, buff.session.db["user_name"], bufferType=None, sound="tweet_timeline.ogg", user_id=usr["id_str"], tweet_mode="extended")
|
||||
tl = twitterBuffers.baseBufferController(self.view.nb, "get_user_timeline", "%s-timeline" % (usr["id_str"],), buff.session, buff.session.db["user_name"], bufferType=None, sound="tweet_timeline.ogg", user_id=usr["id_str"], tweet_mode="extended")
|
||||
try:
|
||||
tl.start_stream(play_sound=False)
|
||||
except TwythonAuthError:
|
||||
@@ -870,7 +851,6 @@ class Controller(object):
|
||||
self.view.insert_buffer(tl.buffer, name=_(u"Timeline for {}").format(dlg.get_user()), pos=pos)
|
||||
buff.session.settings["other_buffers"]["timelines"].append(usr["id_str"])
|
||||
pub.sendMessage("buffer-title-changed", buffer=tl)
|
||||
pub.sendMessage("restart-streams", streams=["timelinesStream"], session=buff.session)
|
||||
buff.session.sound.play("create_timeline.ogg")
|
||||
elif tl_type == "favourites":
|
||||
if usr["favourites_count"] == 0:
|
||||
@@ -879,7 +859,7 @@ class Controller(object):
|
||||
if usr["id_str"] in buff.session.settings["other_buffers"]["favourites_timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
tl = buffersController.baseBufferController(self.view.nb, "get_favorites", "%s-favorite" % (usr["id_str"],), buff.session, buff.session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=usr["id_str"], tweet_mode="extended")
|
||||
tl = twitterBuffers.baseBufferController(self.view.nb, "get_favorites", "%s-favorite" % (usr["id_str"],), buff.session, buff.session.db["user_name"], bufferType=None, sound="favourites_timeline_updated.ogg", user_id=usr["id_str"], tweet_mode="extended")
|
||||
try:
|
||||
tl.start_stream(play_sound=False)
|
||||
except TwythonAuthError:
|
||||
@@ -898,7 +878,7 @@ class Controller(object):
|
||||
if usr["id_str"] in buff.session.settings["other_buffers"]["followers_timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
tl = buffersController.peopleBufferController(self.view.nb, "get_followers_list", "%s-followers" % (usr["id_str"],), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr["id_str"])
|
||||
tl = twitterBuffers.peopleBufferController(self.view.nb, "get_followers_list", "%s-followers" % (usr["id_str"],), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr["id_str"])
|
||||
try:
|
||||
tl.start_stream(play_sound=False)
|
||||
except TwythonAuthError:
|
||||
@@ -917,7 +897,7 @@ class Controller(object):
|
||||
if usr["id_str"] in buff.session.settings["other_buffers"]["friends_timelines"]:
|
||||
commonMessageDialogs.timeline_exist()
|
||||
return
|
||||
tl = buffersController.peopleBufferController(self.view.nb, "get_friends_list", "%s-friends" % (usr["id_str"],), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr["id_str"])
|
||||
tl = twitterBuffers.peopleBufferController(self.view.nb, "get_friends_list", "%s-friends" % (usr["id_str"],), buff.session, buff.session.db["user_name"], sound="new_event.ogg", user_id=usr["id_str"])
|
||||
try:
|
||||
tl.start_stream(play_sound=False)
|
||||
except TwythonAuthError:
|
||||
@@ -937,11 +917,10 @@ class Controller(object):
|
||||
buffer = self.get_current_buffer()
|
||||
id = buffer.get_right_tweet()["id_str"]
|
||||
user = buffer.get_right_tweet()["user"]["screen_name"]
|
||||
search = buffersController.conversationBufferController(self.view.nb, "search", "%s-searchterm" % (id,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", since_id=id, q="@{0}".format(user,))
|
||||
search = twitterBuffers.conversationBufferController(self.view.nb, "search", "%s-searchterm" % (id,), buffer.session, buffer.session.db["user_name"], bufferType="searchPanel", sound="search_updated.ogg", since_id=id, q="@{0}".format(user,))
|
||||
search.tweet = buffer.get_right_tweet()
|
||||
search.start_stream(start=True)
|
||||
pos=self.view.search("searches", buffer.session.db["user_name"])
|
||||
# self.buffers.append(search)
|
||||
self.insert_buffer(search, pos)
|
||||
self.view.insert_buffer(search.buffer, name=_(u"Conversation with {0}").format(user), pos=pos)
|
||||
|
||||
@@ -965,7 +944,7 @@ class Controller(object):
|
||||
if trends.dialog.get_response() == widgetUtils.OK:
|
||||
woeid = trends.get_woeid()
|
||||
if woeid in buff.session.settings["other_buffers"]["trending_topic_buffers"]: return
|
||||
buffer = buffersController.trendsBufferController(self.view.nb, "%s_tt" % (woeid,), buff.session, buff.account, woeid, sound="trends_updated.ogg")
|
||||
buffer = twitterBuffers.trendsBufferController(self.view.nb, "%s_tt" % (woeid,), buff.session, buff.account, woeid, sound="trends_updated.ogg")
|
||||
buffer.searchfunction = self.search
|
||||
pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"])
|
||||
self.view.insert_buffer(buffer.buffer, name=_(u"Trending topics for %s") % (trends.get_string()), pos=pos)
|
||||
@@ -980,7 +959,7 @@ class Controller(object):
|
||||
if tweet["coordinates"] != None:
|
||||
x = tweet["coordinates"]["coordinates"][0]
|
||||
y = tweet["coordinates"]["coordinates"][1]
|
||||
address = geocoder.reverse_geocode(y, x)
|
||||
address = geocoder.reverse_geocode(y, x, language = languageHandler.curLang)
|
||||
if event == None: output.speak(address[0].__str__().decode("utf-8"))
|
||||
else: self.view.show_address(address[0].__str__().decode("utf-8"))
|
||||
else:
|
||||
@@ -1000,7 +979,7 @@ class Controller(object):
|
||||
if tweet["coordinates"] != None:
|
||||
x = tweet["coordinates"]["coordinates"][0]
|
||||
y = tweet["coordinates"]["coordinates"][1]
|
||||
address = geocoder.reverse_geocode(y, x)
|
||||
address = geocoder.reverse_geocode(y, x, language = languageHandler.curLang)
|
||||
dlg = commonMessageDialogs.view_geodata(address[0].__str__())
|
||||
else:
|
||||
output.speak(_(u"There are no coordinates in this tweet"))
|
||||
@@ -1270,32 +1249,6 @@ class Controller(object):
|
||||
if message != None:
|
||||
output.speak(message, speech=session.settings["reporting"]["speech_reporting"], braille=session.settings["reporting"]["braille_reporting"])
|
||||
|
||||
def manage_home_timelines(self, data, user):
|
||||
buffer = self.search_buffer("home_timeline", user)
|
||||
if buffer == None: return
|
||||
play_sound = "tweet_received.ogg"
|
||||
if "home_timeline" not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.notify(buffer.session, play_sound=play_sound)
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_mentions(self, data, user):
|
||||
buffer = self.search_buffer("mentions", user)
|
||||
if buffer == None: return
|
||||
play_sound = "mention_received.ogg"
|
||||
message = _(u"One mention from %s ") % (data["user"]["name"])
|
||||
if "mentions" not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.notify(buffer.session, play_sound=play_sound, message=message)
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_direct_messages(self, data, user):
|
||||
buffer = self.search_buffer("direct_messages", user)
|
||||
if buffer == None: return
|
||||
play_sound = "dm_received.ogg"
|
||||
message = _(u"New direct message")
|
||||
if "direct_messages" not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.notify(buffer.session, play_sound=play_sound, message=message)
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_sent_dm(self, data, user):
|
||||
buffer = self.search_buffer("sent_direct_messages", user)
|
||||
if buffer == None: return
|
||||
@@ -1307,38 +1260,27 @@ class Controller(object):
|
||||
def manage_sent_tweets(self, data, user):
|
||||
buffer = self.search_buffer("sent_tweets", user)
|
||||
if buffer == None: return
|
||||
play_sound = "tweet_send.ogg"
|
||||
if "sent_tweets" not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.notify(buffer.session, play_sound=play_sound)
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_events(self, data, user):
|
||||
buffer = self.search_buffer("events", user)
|
||||
if buffer == None: return
|
||||
play_sound = "new_event.ogg"
|
||||
if "events" not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.notify(buffer.session, play_sound=play_sound)
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_followers(self, data, user):
|
||||
buffer = self.search_buffer("followers", user)
|
||||
if buffer == None: return
|
||||
play_sound = "update_followers.ogg"
|
||||
if "followers" not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.notify(buffer.session, play_sound=play_sound)
|
||||
# if "sent_tweets" not in buffer.session.settings["other_buffers"]["muted_buffers"]:
|
||||
# self.notify(buffer.session, play_sound=play_sound)
|
||||
data = buffer.session.check_quoted_status(data)
|
||||
data = buffer.session.check_long_tweet(data)
|
||||
if data == False: # Long tweet deleted from twishort.
|
||||
return
|
||||
if buffer.session.settings["general"]["reverse_timelines"] == False:
|
||||
buffer.session.db[buffer.name].append(data)
|
||||
else:
|
||||
buffer.session.db[buffer.name].insert(0, data)
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_friend(self, data, user):
|
||||
buffer = self.search_buffer("friends", user)
|
||||
if buffer == None: return
|
||||
buffer.add_new_item(data)
|
||||
pub.sendMessage("restart-streams", streams=["main_stream"], session=buffer.session)
|
||||
|
||||
def manage_unfollowing(self, item, user):
|
||||
buffer = self.search_buffer("friends", user)
|
||||
if buffer == None: return
|
||||
buffer.remove_item(item)
|
||||
pub.sendMessage("restart-streams", streams=["main_stream"], session=buffer.session)
|
||||
|
||||
def manage_favourite(self, data, user):
|
||||
buffer = self.search_buffer("favourites", user)
|
||||
@@ -1357,29 +1299,11 @@ class Controller(object):
|
||||
buffer = self.search_buffer("blocked", user)
|
||||
if buffer == None: return
|
||||
buffer.add_new_item(data)
|
||||
pub.sendMessage("restart-streams", streams=["main_stream"], session=buffer.session)
|
||||
|
||||
def manage_unblocked_user(self, item, user):
|
||||
buffer = self.search_buffer("blocked", user)
|
||||
if buffer == None: return
|
||||
buffer.remove_item(item)
|
||||
pub.sendMessage("restart-streams", streams=["main_stream"], session=buffer.session)
|
||||
|
||||
def manage_item_in_timeline(self, data, user, who):
|
||||
buffer = self.search_buffer("%s-timeline" % (who,), user)
|
||||
if buffer == None: return
|
||||
play_sound = "tweet_timeline.ogg"
|
||||
if "%s-timeline" % (who,) not in buffer.session.settings["other_buffers"]["muted_buffers"] and buffer.session.settings["sound"]["session_mute"] == False:
|
||||
self.notify(buffer.session, play_sound=play_sound, message=_(u"One tweet from %s") % (data["user"]["name"]))
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def manage_item_in_list(self, data, user, where):
|
||||
buffer = self.search_buffer("%s" % (where,), user)
|
||||
if buffer == None: return
|
||||
play_sound = "list_tweet.ogg"
|
||||
if "%s" % (where,) not in buffer.session.settings["other_buffers"]["muted_buffers"] and buffer.session.settings["sound"]["session_mute"] == False:
|
||||
self.notify(buffer.session, play_sound=play_sound, message=_(u"One tweet from %s") % (data["user"]["name"]))
|
||||
buffer.add_new_item(data)
|
||||
|
||||
def start_buffers(self, session):
|
||||
log.debug("starting buffers... Session %s" % (session.session_id,))
|
||||
@@ -1406,37 +1330,18 @@ class Controller(object):
|
||||
continue
|
||||
if change_title:
|
||||
pub.sendMessage("buffer-title-changed", buffer=i)
|
||||
if application.streaming_lives():
|
||||
log.debug("Starting the streaming endpoint")
|
||||
session.start_streaming()
|
||||
|
||||
def set_positions(self):
|
||||
for i in session_.sessions:
|
||||
for i in sessions.sessions:
|
||||
self.set_buffer_positions(i)
|
||||
|
||||
def manage_stream_errors(self, session):
|
||||
log.error(" Restarting %s session streams. It will be destroyed" % (session,))
|
||||
s = session_.sessions[session]
|
||||
try:
|
||||
if hasattr(s, "main_stream"):
|
||||
s.main_stream.disconnect()
|
||||
log.error("main stream disconnected")
|
||||
del s.main_stream
|
||||
if hasattr(s, "timelinesStream"):
|
||||
s.timelinesStream.disconnect()
|
||||
del s.timelinesStream
|
||||
except AttributeError:
|
||||
pass
|
||||
s.counter = 0
|
||||
# s.listen_stream_error()
|
||||
|
||||
def check_connection(self):
|
||||
if self.started == False:
|
||||
return
|
||||
for i in session_.sessions:
|
||||
for i in sessions.sessions:
|
||||
try:
|
||||
if session_.sessions[i].is_logged == False: continue
|
||||
session_.sessions[i].check_connection()
|
||||
if sessions.sessions[i].is_logged == False: continue
|
||||
sessions.sessions[i].check_connection()
|
||||
except TwythonError: # We shouldn't allow this function to die.
|
||||
pass
|
||||
|
||||
@@ -1444,32 +1349,32 @@ class Controller(object):
|
||||
buff = self.search_buffer("home_timeline", account)
|
||||
if create == True:
|
||||
if buffer == "favourites":
|
||||
favourites = buffersController.baseBufferController(self.view.nb, "get_favorites", "favourites", buff.session, buff.session.db["user_name"])
|
||||
favourites = twitterBuffers.baseBufferController(self.view.nb, "get_favorites", "favourites", buff.session, buff.session.db["user_name"], tweet_mode="extended")
|
||||
self.buffers.append(favourites)
|
||||
self.view.insert_buffer(favourites.buffer, name=_(u"Likes"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"]))
|
||||
favourites.start_stream(play_sound=False)
|
||||
if buffer == "followers":
|
||||
followers = buffersController.peopleBufferController(self.view.nb, "get_followers_list", "followers", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"])
|
||||
followers = twitterBuffers.peopleBufferController(self.view.nb, "get_followers_list", "followers", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"])
|
||||
self.buffers.append(followers)
|
||||
self.view.insert_buffer(followers.buffer, name=_(u"Followers"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"]))
|
||||
followers.start_stream(play_sound=False)
|
||||
elif buffer == "friends":
|
||||
friends = buffersController.peopleBufferController(self.view.nb, "get_friends_list", "friends", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"])
|
||||
friends = twitterBuffers.peopleBufferController(self.view.nb, "get_friends_list", "friends", buff.session, buff.session.db["user_name"], screen_name=buff.session.db["user_name"])
|
||||
self.buffers.append(friends)
|
||||
self.view.insert_buffer(friends.buffer, name=_(u"Friends"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"]))
|
||||
friends.start_stream(play_sound=False)
|
||||
elif buffer == "blocked":
|
||||
blocks = buffersController.peopleBufferController(self.view.nb, "list_blocks", "blocked", buff.session, buff.session.db["user_name"])
|
||||
blocks = twitterBuffers.peopleBufferController(self.view.nb, "list_blocks", "blocked", buff.session, buff.session.db["user_name"])
|
||||
self.buffers.append(blocks)
|
||||
self.view.insert_buffer(blocks.buffer, name=_(u"Blocked users"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"]))
|
||||
blocks.start_stream(play_sound=False)
|
||||
elif buffer == "muted":
|
||||
muted = buffersController.peopleBufferController(self.view.nb, "get_muted_users_list", "muted", buff.session, buff.session.db["user_name"])
|
||||
muted = twitterBuffers.peopleBufferController(self.view.nb, "get_muted_users_list", "muted", buff.session, buff.session.db["user_name"])
|
||||
self.buffers.append(muted)
|
||||
self.view.insert_buffer(muted.buffer, name=_(u"Muted users"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"]))
|
||||
muted.start_stream(play_sound=False)
|
||||
elif buffer == "events":
|
||||
events = buffersController.eventsBufferController(self.view.nb, "events", buff.session, buff.session.db["user_name"], bufferType="dmPanel", screen_name=buff.session.db["user_name"])
|
||||
events = twitterBuffers.eventsBufferController(self.view.nb, "events", buff.session, buff.session.db["user_name"], bufferType="dmPanel", screen_name=buff.session.db["user_name"])
|
||||
self.buffers.append(events)
|
||||
self.view.insert_buffer(events.buffer, name=_(u"Events"), pos=self.view.search(buff.session.db["user_name"], buff.session.db["user_name"]))
|
||||
elif create == False:
|
||||
@@ -1478,7 +1383,7 @@ class Controller(object):
|
||||
if create in buff.session.settings["other_buffers"]["lists"]:
|
||||
output.speak(_(u"This list is already opened"), True)
|
||||
return
|
||||
tl = buffersController.listBufferController(self.view.nb, "get_list_statuses", create+"-list", buff.session, buff.session.db["user_name"], bufferType=None, list_id=utils.find_list(create, buff.session.db["lists"]))
|
||||
tl = twitterBuffers.listBufferController(self.view.nb, "get_list_statuses", create+"-list", buff.session, buff.session.db["user_name"], bufferType=None, list_id=utils.find_list(create, buff.session.db["lists"]), tweet_mode="extended")
|
||||
buff.session.lists.append(tl)
|
||||
pos=self.view.search("lists", buff.session.db["user_name"])
|
||||
self.insert_buffer(tl, pos)
|
||||
@@ -1486,13 +1391,6 @@ class Controller(object):
|
||||
tl.start_stream(play_sound=False)
|
||||
buff.session.settings["other_buffers"]["lists"].append(create)
|
||||
buff.session.settings.write()
|
||||
pub.sendMessage("restart-streams", streams=["timelinesStream"], session=buff.session)
|
||||
|
||||
def restart_streams(self, streams=[], session=None):
|
||||
for i in streams:
|
||||
log.debug("Restarting the %s stream" % (i,))
|
||||
session.remove_stream(i)
|
||||
session.check_connection()
|
||||
|
||||
def invisible_shorcuts_changed(self, registered):
|
||||
if registered == True:
|
||||
@@ -1505,22 +1403,51 @@ class Controller(object):
|
||||
def about(self, *args, **kwargs):
|
||||
self.view.about_dialog()
|
||||
|
||||
def get_soundpacks(self, *args, **kwargs):
|
||||
# This should redirect users of other languages to the right version of the TWBlue website.
|
||||
lang = languageHandler.curLang[:2]
|
||||
url = application.url
|
||||
final_url = "{0}/{1}/soundpacks".format(url, lang)
|
||||
try:
|
||||
response = requests.get(final_url)
|
||||
except:
|
||||
output.speak(_(u"An error happened while trying to connect to the server. Please try later."))
|
||||
return
|
||||
# There is no twblue.es/en, so if English is the language used this should be False anyway.
|
||||
if response.status_code == 200 and lang != "en":
|
||||
webbrowser.open_new_tab(final_url)
|
||||
else:
|
||||
webbrowser.open_new_tab(application.url+"/soundpacks")
|
||||
|
||||
def visit_website(self, *args, **kwargs):
|
||||
webbrowser.open(application.url)
|
||||
# This should redirect users of other languages to the right version of the TWBlue website.
|
||||
lang = languageHandler.curLang[:2]
|
||||
url = application.url
|
||||
final_url = "{0}/{1}".format(url, lang)
|
||||
try:
|
||||
response = requests.get(final_url)
|
||||
except:
|
||||
output.speak(_(u"An error happened while trying to connect to the server. Please try later."))
|
||||
return
|
||||
# There is no twblue.es/en, so if English is the language used this should be False anyway.
|
||||
if response.status_code == 200 and lang != "en":
|
||||
webbrowser.open_new_tab(final_url)
|
||||
else:
|
||||
webbrowser.open_new_tab(application.url)
|
||||
|
||||
def manage_accounts(self, *args, **kwargs):
|
||||
sm = sessionManager.sessionManagerController(started=True)
|
||||
sm.fill_list()
|
||||
sm.show()
|
||||
for i in sm.new_sessions:
|
||||
self.create_buffers(session_.sessions[i])
|
||||
call_threaded(self.start_buffers, session_.sessions[i])
|
||||
self.create_buffers(sessions.sessions[i])
|
||||
call_threaded(self.start_buffers, sessions.sessions[i])
|
||||
for i in sm.removed_sessions:
|
||||
if session_.sessions[i].logged == True:
|
||||
self.logout_account(session_.sessions[i].session_id)
|
||||
self.destroy_buffer(session_.sessions[i].settings["twitter"]["user_name"], session_.sessions[i].settings["twitter"]["user_name"])
|
||||
self.accounts.remove(session_.sessions[i].settings["twitter"]["user_name"])
|
||||
session_.sessions.pop(i)
|
||||
if sessions.sessions[i].logged == True:
|
||||
self.logout_account(sessions.sessions[i].session_id)
|
||||
self.destroy_buffer(sessions.sessions[i].settings["twitter"]["user_name"], sessions.sessions[i].settings["twitter"]["user_name"])
|
||||
self.accounts.remove(sessions.sessions[i].settings["twitter"]["user_name"])
|
||||
sessions.sessions.pop(i)
|
||||
|
||||
def update_profile(self, *args, **kwargs):
|
||||
r = user.profileController(self.get_best_buffer().session)
|
||||
@@ -1614,16 +1541,10 @@ class Controller(object):
|
||||
return
|
||||
else:
|
||||
output.speak(_(u"Updating buffer..."))
|
||||
n = bf.start_stream(mandatory=True)
|
||||
n = bf.start_stream(mandatory=True, avoid_autoreading=True)
|
||||
if n != None:
|
||||
output.speak(_(u"{0} items retrieved").format(n,))
|
||||
|
||||
def on_tweet_deleted(self, data):
|
||||
id = data["delete"]["status"]["id"]
|
||||
for i in self.buffers:
|
||||
if hasattr(i, "remove_tweet") and hasattr(i, "name"):
|
||||
i.remove_tweet(id)
|
||||
|
||||
def buffer_title_changed(self, buffer):
|
||||
if "-timeline" in buffer.name:
|
||||
title = _(u"Timeline for {}").format(buffer.username,)
|
||||
@@ -1678,5 +1599,5 @@ class Controller(object):
|
||||
sent_dms.put_more_items(data)
|
||||
|
||||
def save_data_in_db(self):
|
||||
for i in session_.sessions:
|
||||
session_.sessions[i].shelve()
|
||||
for i in sessions.sessions:
|
||||
sessions.sessions[i].shelve()
|
||||
|
@@ -2,6 +2,8 @@
|
||||
import re
|
||||
import platform
|
||||
import attach
|
||||
import arrow
|
||||
import languageHandler
|
||||
system = platform.system()
|
||||
import widgetUtils
|
||||
import output
|
||||
@@ -17,7 +19,7 @@ if system == "Windows":
|
||||
from extra.AudioUploader import audioUploader
|
||||
elif system == "Linux":
|
||||
from gtkUI.dialogs import message
|
||||
from twitter import utils
|
||||
from sessions.twitter import utils
|
||||
|
||||
class basicTweet(object):
|
||||
""" This class handles the tweet main features. Other classes should derive from this class."""
|
||||
@@ -193,7 +195,7 @@ class dm(basicTweet):
|
||||
c.show_menu("dm")
|
||||
|
||||
class viewTweet(basicTweet):
|
||||
def __init__(self, tweet, tweetList, is_tweet=True):
|
||||
def __init__(self, tweet, tweetList, is_tweet=True, utc_offset=0, date=""):
|
||||
""" This represents a tweet displayer. However it could be used for showing something wich is not a tweet, like a direct message or an event.
|
||||
param tweet: A dictionary that represents a full tweet or a string for non-tweets.
|
||||
param tweetList: If is_tweet is set to True, this could be a list of quoted tweets.
|
||||
@@ -229,6 +231,8 @@ class viewTweet(basicTweet):
|
||||
favs_count = str(tweet["favorite_count"])
|
||||
# Gets the client from where this tweet was made.
|
||||
source = str(re.sub(r"(?s)<.*?>", "", tweet["source"].encode("utf-8")))
|
||||
original_date = arrow.get(tweet["created_at"], "ddd MMM DD H:m:s Z YYYY", locale="en")
|
||||
date = original_date.replace(seconds=utc_offset).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage())
|
||||
if text == "":
|
||||
if tweet.has_key("message"):
|
||||
value = "message"
|
||||
@@ -250,13 +254,13 @@ class viewTweet(basicTweet):
|
||||
for z in tweet["retweeted_status"]["extended_entities"]["media"]:
|
||||
if z.has_key("ext_alt_text") and z["ext_alt_text"] != None:
|
||||
image_description.append(z["ext_alt_text"])
|
||||
self.message = message.viewTweet(text, rt_count, favs_count, source.decode("utf-8"))
|
||||
self.message = message.viewTweet(text, rt_count, favs_count, source.decode("utf-8"), date)
|
||||
self.message.set_title(len(text))
|
||||
[self.message.set_image_description(i) for i in image_description]
|
||||
else:
|
||||
self.title = _(u"View item")
|
||||
text = tweet
|
||||
self.message = message.viewNonTweet(text)
|
||||
self.message = message.viewNonTweet(text, date)
|
||||
widgetUtils.connect_event(self.message.spellcheck, widgetUtils.BUTTON_PRESSED, self.spellcheck)
|
||||
widgetUtils.connect_event(self.message.translateButton, widgetUtils.BUTTON_PRESSED, self.translate)
|
||||
if self.contain_urls() == True:
|
||||
|
@@ -138,8 +138,6 @@ class accountSettingsController(globalSettingsController):
|
||||
widgetUtils.connect_event(self.dialog.general.au, widgetUtils.BUTTON_PRESSED, self.manage_autocomplete)
|
||||
self.dialog.set_value("general", "relative_time", self.config["general"]["relative_times"])
|
||||
self.dialog.set_value("general", "show_screen_names", self.config["general"]["show_screen_names"])
|
||||
if application.streaming_lives():
|
||||
self.dialog.set_value("general", "apiCalls", self.config["general"]["max_api_calls"])
|
||||
self.dialog.set_value("general", "itemsPerApiCall", self.config["general"]["max_tweets_per_call"])
|
||||
self.dialog.set_value("general", "reverse_timelines", self.config["general"]["reverse_timelines"])
|
||||
rt = self.config["general"]["retweet_mode"]
|
||||
@@ -191,8 +189,6 @@ class accountSettingsController(globalSettingsController):
|
||||
self.needs_restart = True
|
||||
self.config["general"]["relative_times"] = self.dialog.get_value("general", "relative_time")
|
||||
self.config["general"]["show_screen_names"] = self.dialog.get_value("general", "show_screen_names")
|
||||
if application.streaming_lives():
|
||||
self.config["general"]["max_api_calls"] = self.dialog.get_value("general", "apiCalls")
|
||||
self.config["general"]["max_tweets_per_call"] = self.dialog.get_value("general", "itemsPerApiCall")
|
||||
if self.config["general"]["persist_size"] != self.dialog.get_value("general", "persist_size"):
|
||||
if self.dialog.get_value("general", "persist_size") == '':
|
||||
@@ -293,8 +289,6 @@ class accountSettingsController(globalSettingsController):
|
||||
all_buffers['friends']=_(u"Friends")
|
||||
all_buffers['blocks']=_(u"Blocked users")
|
||||
all_buffers['muted']=_(u"Muted users")
|
||||
if application.streaming_lives():
|
||||
all_buffers['events']=_(u"Events")
|
||||
list_buffers = []
|
||||
hidden_buffers=[]
|
||||
for i in all_buffers.keys():
|
||||
|
@@ -8,7 +8,7 @@ class trendingTopicsController(object):
|
||||
self.countries = {}
|
||||
self.cities = {}
|
||||
self.dialog = trends.trendingTopicsDialog()
|
||||
self.information = session.twitter.twitter.get_available_trends()
|
||||
self.information = session.twitter.get_available_trends()
|
||||
self.split_information()
|
||||
widgetUtils.connect_event(self.dialog.country, widgetUtils.RADIOBUTTON, self.get_places)
|
||||
widgetUtils.connect_event(self.dialog.city, widgetUtils.RADIOBUTTON, self.get_places)
|
||||
|
@@ -41,9 +41,9 @@ class profileController(object):
|
||||
self.do_update()
|
||||
|
||||
def get_data(self, screen_name):
|
||||
self.data = self.session.twitter.twitter.show_user(screen_name=screen_name)
|
||||
self.data = self.session.twitter.show_user(screen_name=screen_name)
|
||||
if screen_name != self.session.db["user_name"]:
|
||||
self.friendship_status = self.session.twitter.twitter.show_friendship(source_screen_name=self.session.db["user_name"], target_screen_name=screen_name)
|
||||
self.friendship_status = self.session.twitter.show_friendship(source_screen_name=self.session.db["user_name"], target_screen_name=screen_name)
|
||||
|
||||
def fill_profile_fields(self):
|
||||
self.dialog.set_name(self.data["name"])
|
||||
@@ -81,11 +81,11 @@ class profileController(object):
|
||||
url = self.dialog.get("url")
|
||||
if self.file != None:
|
||||
try:
|
||||
self.session.twitter.twitter.update_profile_image(image=self.file)
|
||||
self.session.twitter.update_profile_image(image=self.file)
|
||||
except TwythonError as e:
|
||||
output.speak(u"Error %s. %s" % (e.error_code, e.msg))
|
||||
try:
|
||||
self.session.twitter.twitter.update_profile(name=name, description=description, location=location, url=url)
|
||||
self.session.twitter.update_profile(name=name, description=description, location=location, url=url)
|
||||
except TwythonError as e:
|
||||
output.speak(u"Error %s. %s" % (e.error_code, e.msg))
|
||||
|
||||
|
@@ -29,43 +29,43 @@ class userActionsController(object):
|
||||
|
||||
def follow(self, user):
|
||||
try:
|
||||
self.session.twitter.twitter.create_friendship(screen_name=user )
|
||||
self.session.twitter.create_friendship(screen_name=user )
|
||||
except TwythonError as err:
|
||||
output.speak("Error %s: %s" % (err.error_code, err.msg), True)
|
||||
|
||||
def unfollow(self, user):
|
||||
try:
|
||||
id = self.session.twitter.twitter.destroy_friendship(screen_name=user )
|
||||
id = self.session.twitter.destroy_friendship(screen_name=user )
|
||||
except TwythonError as err:
|
||||
output.speak("Error %s: %s" % (err.error_code, err.msg), True)
|
||||
|
||||
def mute(self, user):
|
||||
try:
|
||||
id = self.session.twitter.twitter.create_mute(screen_name=user )
|
||||
id = self.session.twitter.create_mute(screen_name=user )
|
||||
except TwythonError as err:
|
||||
output.speak("Error %s: %s" % (err.error_code, err.msg), True)
|
||||
|
||||
def unmute(self, user):
|
||||
try:
|
||||
id = self.session.twitter.twitter.destroy_mute(screen_name=user )
|
||||
id = self.session.twitter.destroy_mute(screen_name=user )
|
||||
except TwythonError as err:
|
||||
output.speak("Error %s: %s" % (err.error_code, err.msg), True)
|
||||
|
||||
def report(self, user):
|
||||
try:
|
||||
id = self.session.twitter.twitter.report_spam(screen_name=user )
|
||||
id = self.session.twitter.report_spam(screen_name=user )
|
||||
except TwythonError as err:
|
||||
output.speak("Error %s: %s" % (err.error_code, err.msg), True)
|
||||
|
||||
def block(self, user):
|
||||
try:
|
||||
id = self.session.twitter.twitter.create_block(screen_name=user )
|
||||
id = self.session.twitter.create_block(screen_name=user )
|
||||
except TwythonError as err:
|
||||
output.speak("Error %s: %s" % (err.error_code, err.msg), True)
|
||||
|
||||
def unblock(self, user):
|
||||
try:
|
||||
id = self.session.twitter.twitter.destroy_block(screen_name=user )
|
||||
id = self.session.twitter.destroy_block(screen_name=user )
|
||||
except TwythonError as err:
|
||||
output.speak("Error %s: %s" % (err.error_code, err.msg), True)
|
||||
|
||||
|
@@ -45,7 +45,7 @@ search = string(default="alt+win+-")
|
||||
edit_keystrokes = string(default="alt+win+k")
|
||||
view_user_lists = string(default="alt+win+l")
|
||||
get_more_items = string(default="alt+win+pageup")
|
||||
reverse_geocode = string(default="alt+win+g")
|
||||
reverse_geocode = string(default="control+win+g")
|
||||
view_reverse_geocode = string(default="alt+win+shift+g")
|
||||
get_trending_topics = string(default="control+win+t")
|
||||
check_for_updates = string(default="alt+win+u")
|
||||
|
@@ -50,6 +50,7 @@ actions = {
|
||||
"check_for_updates": _(u"Check and download updates"),
|
||||
"lists_manager": _(u"Opens the list manager, which allows you to create, edit, delete and open lists in buffers."),
|
||||
"configuration": _(u"Opens the global settings dialogue"),
|
||||
"list_manager": _(u"Opens the list manager"),
|
||||
"accountConfiguration": _(u"Opens the account settings dialogue"),
|
||||
"audio": _(u"Try to play an audio file"),
|
||||
"update_buffer": _(u"Updates the buffer and retrieves possible lost items there."),
|
||||
|
@@ -5,7 +5,7 @@ import paths
|
||||
import os
|
||||
import logging
|
||||
log = logging.getLogger("sessionmanager.manager")
|
||||
import session_exceptions
|
||||
from sessions import session_exceptions
|
||||
|
||||
manager = None
|
||||
def setup():
|
||||
|
@@ -12,7 +12,8 @@ import paths
|
||||
import time
|
||||
import os
|
||||
import logging
|
||||
import session
|
||||
import sessions
|
||||
from sessions.twitter import session
|
||||
import manager
|
||||
import config_utils
|
||||
import config
|
||||
@@ -76,12 +77,12 @@ class sessionManagerController(object):
|
||||
def do_ok(self):
|
||||
log.debug("Starting sessions...")
|
||||
for i in self.sessions:
|
||||
if session.sessions.has_key(i) == True: continue
|
||||
if sessions.sessions.has_key(i) == True: continue
|
||||
s = session.Session(i)
|
||||
s.get_configuration()
|
||||
if i not in config.app["sessions"]["ignored_sessions"]:
|
||||
s.login()
|
||||
session.sessions[i] = s
|
||||
sessions.sessions[i] = s
|
||||
self.new_sessions[i] = s
|
||||
# self.view.destroy()
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
import wx
|
||||
from multiplatform_widgets import widgets
|
||||
import application
|
||||
|
||||
class sessionManagerWindow(wx.Dialog):
|
||||
def __init__(self):
|
||||
super(sessionManagerWindow, self).__init__(parent=None, title=_(u"Session manager"), size=wx.DefaultSize)
|
||||
@@ -73,19 +74,4 @@ class sessionManagerWindow(wx.Dialog):
|
||||
self.configuration.Hide()
|
||||
|
||||
def destroy(self):
|
||||
self.Destroy()
|
||||
|
||||
class authorisationDialog(wx.Dialog):
|
||||
def __init__(self):
|
||||
super(authorisationDialog, self).__init__(parent=None, title=_(u"Authorising account..."))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
static = wx.StaticText(panel, wx.NewId(), _(u"Enter your PIN code here"))
|
||||
self.text = wx.TextCtrl(panel, -1)
|
||||
self.ok = wx.Button(panel, wx.ID_OK)
|
||||
self.cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
sizer.Add(self.text, 0, wx.ALL, 5)
|
||||
sizer.Add(self.cancel, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
min = sizer.CalcMin()
|
||||
self.SetClientSize(min)
|
||||
self.Destroy()
|
5
src/sessions/__init__.py
Normal file
5
src/sessions/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" this package contains code related to Sessions.
|
||||
In TWBlue, a session module defines everything a social network needs to be used in the program."""
|
||||
# let's define a global object for storing sessions across the program.
|
||||
sessions = {}
|
116
src/sessions/base.py
Normal file
116
src/sessions/base.py
Normal file
@@ -0,0 +1,116 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" A base class to be derived in possible new sessions for TWBlue and services."""
|
||||
import paths
|
||||
import output
|
||||
import time
|
||||
import sound
|
||||
import logging
|
||||
import config_utils
|
||||
import shelve
|
||||
import application
|
||||
import os
|
||||
import session_exceptions as Exceptions
|
||||
log = logging.getLogger("sessionmanager.session")
|
||||
|
||||
class baseSession(object):
|
||||
""" toDo: Decorators does not seem to be working when using them in an inherited class."""
|
||||
|
||||
# Decorators.
|
||||
|
||||
def _require_login(fn):
|
||||
""" Decorator for checking if the user is logged in.
|
||||
Some functions may need this to avoid making unneeded calls."""
|
||||
def f(self, *args, **kwargs):
|
||||
if self.logged == True:
|
||||
fn(self, *args, **kwargs)
|
||||
else:
|
||||
raise Exceptions.NotLoggedSessionError("You are not logged in yet.")
|
||||
return f
|
||||
|
||||
def _require_configuration(fn):
|
||||
""" Check if the user has a configured session."""
|
||||
def f(self, *args, **kwargs):
|
||||
if self.settings != None:
|
||||
fn(self, *args, **kwargs)
|
||||
else:
|
||||
raise Exceptions.NotConfiguredSessionError("Not configured.")
|
||||
return f
|
||||
|
||||
def __init__(self, session_id):
|
||||
""" session_id (str): The name of the folder inside the config directory where the session is located."""
|
||||
super(baseSession, self).__init__()
|
||||
self.session_id = session_id
|
||||
self.logged = False
|
||||
self.settings = None
|
||||
self.db={}
|
||||
|
||||
@property
|
||||
def is_logged(self):
|
||||
return self.logged
|
||||
|
||||
def get_configuration(self):
|
||||
""" Get settings for a session."""
|
||||
file_ = "%s/session.conf" % (self.session_id,)
|
||||
log.debug("Creating config file %s" % (file_,))
|
||||
self.settings = config_utils.load_config(paths.config_path(file_), paths.app_path("Conf.defaults"))
|
||||
self.init_sound()
|
||||
self.deshelve()
|
||||
|
||||
def init_sound(self):
|
||||
try: self.sound = sound.soundSystem(self.settings["sound"])
|
||||
except: pass
|
||||
|
||||
@_require_configuration
|
||||
def login(self, verify_credentials=True):
|
||||
pass
|
||||
|
||||
@_require_configuration
|
||||
def authorise(self):
|
||||
pass
|
||||
|
||||
def shelve(self):
|
||||
"""Shelve the database to allow for persistance."""
|
||||
shelfname=paths.config_path(str(self.session_id)+"/cache.db")
|
||||
if self.settings["general"]["persist_size"] == 0:
|
||||
if os.path.exists(shelfname):
|
||||
os.remove(shelfname)
|
||||
return
|
||||
try:
|
||||
if not os.path.exists(shelfname):
|
||||
output.speak("Generating database, this might take a while.",True)
|
||||
shelf=shelve.open(paths.config_path(shelfname),'c')
|
||||
for key,value in self.db.items():
|
||||
if type(key) != str and type(key) != unicode:
|
||||
output.speak("Uh oh, while shelving the database, a key of type " + str(type(key)) + " has been found. It will be converted to type str, but this will cause all sorts of problems on deshelve. Please bring this to the attention of the " + application.name + " developers immediately. More information about the error will be written to the error log.",True)
|
||||
log.error("Uh oh, " + str(key) + " is of type " + str(type(key)) + "!")
|
||||
# Convert unicode objects to UTF-8 strings before shelve these objects.
|
||||
if type(value) == list and self.settings["general"]["persist_size"] != -1 and len(value) > self.settings["general"]["persist_size"]:
|
||||
shelf[str(key.encode("utf-8"))]=value[self.settings["general"]["persist_size"]:]
|
||||
else:
|
||||
shelf[str(key.encode("utf-8"))]=value
|
||||
shelf.close()
|
||||
except:
|
||||
output.speak("An exception occurred while shelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True)
|
||||
log.exception("Exception while shelving" + shelfname)
|
||||
os.remove(shelfname)
|
||||
|
||||
def deshelve(self):
|
||||
"""Import a shelved database."""
|
||||
shelfname=paths.config_path(str(self.session_id)+"/cache.db")
|
||||
if self.settings["general"]["persist_size"] == 0:
|
||||
if os.path.exists(shelfname):
|
||||
os.remove(shelfname)
|
||||
return
|
||||
try:
|
||||
shelf=shelve.open(paths.config_path(shelfname),'c')
|
||||
for key,value in shelf.items():
|
||||
self.db[key]=value
|
||||
shelf.close()
|
||||
except:
|
||||
output.speak("An exception occurred while deshelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True)
|
||||
log.exception("Exception while deshelving" + shelfname)
|
||||
try:
|
||||
os.remove(shelfname)
|
||||
except:
|
||||
pass
|
||||
|
1
src/sessions/twitter/__init__.py
Normal file
1
src/sessions/twitter/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
@@ -75,35 +75,6 @@ def compose_tweet(tweet, db, relative_times, show_screen_names=False, session=No
|
||||
if config.app['app-settings']['handle_longtweets']: pass
|
||||
return [user+", ", text, ts+", ", source]
|
||||
|
||||
def compose_dm(tweet, db, relative_times, show_screen_names=False, session=None):
|
||||
""" It receives a tweet and returns a list with the user, text for the tweet or message, date and the client where user is."""
|
||||
if system == "Windows":
|
||||
original_date = arrow.get(tweet["created_at"], "ddd MMM DD H:m:s Z YYYY", locale="en")
|
||||
if relative_times == True:
|
||||
ts = original_date.humanize(locale=languageHandler.getLanguage())
|
||||
else:
|
||||
ts = original_date.replace(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage())
|
||||
else:
|
||||
ts = tweet["created_at"]
|
||||
text = StripChars(tweet["text"])
|
||||
source = "DM"
|
||||
if db["user_name"] == tweet["sender"]["screen_name"]:
|
||||
if show_screen_names:
|
||||
user = _(u"Dm to %s ") % (tweet["recipient"]["screen_name"],)
|
||||
else:
|
||||
user = _(u"Dm to %s ") % (tweet["recipient"]["name"],)
|
||||
else:
|
||||
if show_screen_names:
|
||||
user = tweet["sender"]["screen_name"]
|
||||
else:
|
||||
user = tweet["sender"]["name"]
|
||||
if text[-1] in chars: text=text+"."
|
||||
urls = utils.find_urls_in_text(text)
|
||||
for url in range(0, len(urls)):
|
||||
try: text = text.replace(urls[url], tweet["entities"]["urls"][url]["expanded_url"])
|
||||
except IndexError: pass
|
||||
return [user+", ", text, ts+", ", source]
|
||||
|
||||
def compose_direct_message(item, db, relative_times, show_screen_names=False, session=None):
|
||||
# for a while this function will be together with compose_dm.
|
||||
# this one composes direct messages based on events (new API Endpoints).
|
||||
@@ -193,58 +164,6 @@ def compose_followers_list(tweet, db, relative_times=True, show_screen_names=Fal
|
||||
ts2 = _("Unavailable")
|
||||
return [_(u"%s (@%s). %s followers, %s friends, %s tweets. Last tweeted %s. Joined Twitter %s") % (tweet["name"], tweet["screen_name"], tweet["followers_count"], tweet["friends_count"], tweet["statuses_count"], ts2, ts)]
|
||||
|
||||
def compose_event(data, username, show_screen_names=False, session=None):
|
||||
if show_screen_names:
|
||||
value = "screen_name"
|
||||
else:
|
||||
value = "name"
|
||||
if data["event"] == "block":
|
||||
event = _("You've blocked %s") % (data["target"][value])
|
||||
elif data["event"] == "unblock":
|
||||
event = _(u"You've unblocked %s") % (data["target"][value])
|
||||
elif data["event"] == "follow":
|
||||
if data["target"]["screen_name"] == username:
|
||||
event = _(u"%s(@%s) has followed you") % (data["source"]["name"], data["source"]["screen_name"])
|
||||
elif data["source"]["screen_name"] == username:
|
||||
event = _(u"You've followed %s(@%s)") % (data["target"]["name"], data["target"]["screen_name"])
|
||||
elif data["event"] == "unfollow":
|
||||
event = _(u"You've unfollowed %s (@%s)") % (data["target"]["name"], data["target"]["screen_name"])
|
||||
elif data["event"] == "favorite":
|
||||
if data["source"]["screen_name"] == username:
|
||||
event = _(u"You've liked: %s, %s") % (data["target"][value], data["target_object"]["text"])
|
||||
else:
|
||||
event = _(u"%s(@%s) has liked: %s") % (data["source"]["name"], data["source"]["screen_name"], data["target_object"]["text"])
|
||||
elif data["event"] == "unfavorite":
|
||||
if data["source"]["screen_name"] == username: event = _(u"You've unliked: %s, %s") % (data["target"][value], data["target_object"]["text"])
|
||||
else: event = _(u"%s(@%s) has unliked: %s") % (data["source"]["name"], data["source"]["screen_name"], data["target_object"]["text"])
|
||||
elif data["event"] == "list_created":
|
||||
event = _(u"You've created the list %s") % (data["target_object"]["name"])
|
||||
elif data["event"] == "list_destroyed":
|
||||
event = _("You've deleted the list %s") % (data["target_object"]["name"])
|
||||
elif data["event"] == "list_updated":
|
||||
event = _("You've updated the list %s") % (data["target_object"]["name"])
|
||||
elif data["event"] == "list_member_added":
|
||||
if data["source"]["screen_name"] == username: event = _(u"You've added %s(@%s) to the list %s") % (data["target"]["name"], data["target"]["screen_name"], data["target_object"]["name"])
|
||||
else: event = _(u"%s(@%s) has added you to the list %s") % (data["source"]["name"], data["source"]["screen_name"], data["target_object"]["name"])
|
||||
elif data["event"] == "list_member_removed":
|
||||
if data["source"]["screen_name"] == username: event = _(u"You'be removed %s(@%s) from the list %s") % (data["target"]["name"], data["target"]["screen_name"], data["target_object"]["name"])
|
||||
else: event = _(u"%s(@%s) has removed you from the list %s") % (data["source"]["name"], data["source"]["screen_name"], data["target_object"]["name"])
|
||||
elif data["event"] == "list_user_subscribed":
|
||||
if data["source"]["screen_name"] == username: event = _(u"You've subscribed to the list %s, which is owned by %s(@%s)") % (data["target_object"]["name"], data["target"]["name"], data["target"]["screen_name"])
|
||||
else: event = _(u"%s(@%s) has subscribed you to the list %s") % (data["source"]["name"], data["source"]["screen_name"], data["target_object"]["name"])
|
||||
elif data["event"] == "list_user_unsubscribed":
|
||||
if data["source"]["screen_name"] == username: event = _(u"You've unsubscribed from the list %s, which is owned by %s(@%s)") % (data["target_object"]["name"], data["target"]["name"], data["target"]["screen_name"])
|
||||
else: event = _("You've been unsubscribed from the list %s, which is owned by %s(@%s)") % (data["target_object"]["name"], data["source"]["name"], data["source"]["screen_name"])
|
||||
elif data["event"] == "retweeted_retweet":
|
||||
if data["source"]["screen_name"] == username: event = _(u"You have retweeted a retweet from %s(@%s): %s") % (data["target"]["name"], data["target"]["screen_name"], data["target_object"]["retweeted_status"]["text"])
|
||||
else: event = _(u"%s(@%s) has retweeted your retweet: %s") % (data["source"]["name"], data["source"]["screen_name"], data["target_object"]["retweeted_status"]["text"])
|
||||
elif data["event"] == "quoted_tweet":
|
||||
event = _(u"@{0} quoted your tweet: {1}").format(data["source"]["screen_name"], data["target_object"]["text"])
|
||||
else:
|
||||
event = _("Unknown")
|
||||
log.error("event: %s\n target: %s\n source: %s\n target_object: %s" % (data["event"], data["target"], data["source"], data["target_object"]))
|
||||
return [time.strftime("%I:%M %p"), event]
|
||||
|
||||
def compose_list(list):
|
||||
name = list["name"]
|
||||
if list["description"] == None: description = _(u"No description available")
|
2
src/sessions/twitter/long_tweets/__init__.py
Normal file
2
src/sessions/twitter/long_tweets/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" this package holds different modules to extract information regarding long tweets. A long tweet contains more than one tweet (such a quoted tweet), or is made via services like twishort."""
|
@@ -16,9 +16,12 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
############################################################
|
||||
from twitter import utils
|
||||
from sessions.twitter import utils
|
||||
|
||||
def is_long(tweet):
|
||||
""" Check if the passed tweet contains a quote in its metadata.
|
||||
tweet dict: a tweet dictionary.
|
||||
returns True if a quote is detected, False otherwise."""
|
||||
if tweet.has_key("quoted_status_id") and tweet.has_key("quoted_status"):
|
||||
return tweet["quoted_status_id"]
|
||||
elif tweet.has_key("retweeted_status") and tweet["retweeted_status"].has_key("quoted_status_id") and tweet["retweeted_status"].has_key("quoted_status"):
|
||||
@@ -26,6 +29,9 @@ def is_long(tweet):
|
||||
return False
|
||||
|
||||
def clear_url(tweet):
|
||||
""" Reads data from a quoted tweet and removes the link to the Status from the tweet's text.
|
||||
tweet dict: a tweet dictionary.
|
||||
returns a tweet dictionary without the URL to the status ID in its text to display."""
|
||||
if tweet.has_key("retweeted_status"):
|
||||
if tweet["retweeted_status"].has_key("full_text"):
|
||||
value = "full_text"
|
@@ -16,20 +16,26 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
############################################################
|
||||
import logging
|
||||
import requests
|
||||
import keys
|
||||
import logging
|
||||
log = logging.getLogger("long_tweets.twishort")
|
||||
from twitter import utils
|
||||
from requests_oauthlib import OAuth1Session
|
||||
from sessions.twitter import utils
|
||||
|
||||
log = logging.getLogger("long_tweets.twishort")
|
||||
|
||||
def get_twishort_uri(url):
|
||||
""" Takes A twishort URl and returns the twishort ID.
|
||||
url str: an url like http://twishort.com/id.
|
||||
returns a twishort ID if the URL is valid, False otherwise."""
|
||||
try:
|
||||
return url.split("twishort.com/")[1]
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def is_long(tweet):
|
||||
""" Check if the passed tweet is made with Twishort.
|
||||
returns True if is a long tweet, False otherwise."""
|
||||
long = False
|
||||
for url in range(0, len(tweet["entities"]["urls"])):
|
||||
try:
|
||||
@@ -53,17 +59,25 @@ def is_long(tweet):
|
||||
return long
|
||||
|
||||
def get_full_text(uri):
|
||||
""" Get Twishort's full text.
|
||||
uri str: Twishort's identifier.
|
||||
returns the contents of the tweet."""
|
||||
try:
|
||||
r = requests.get("http://api.twishort.com/1.1/get.json", params={"uri": uri, "api_key": keys.keyring.get("twishort_api_key")})
|
||||
msg = r.json()["text"]
|
||||
# Try to parse possible HTML entities.
|
||||
from twitter.compose import StripChars
|
||||
from sessions.twitter.compose import StripChars
|
||||
msg = StripChars(msg)
|
||||
return msg
|
||||
except:
|
||||
return False
|
||||
|
||||
def create_tweet(user_token, user_secret, text, media=0):
|
||||
""" Send a tweet to be extended by using Twishort.
|
||||
user_token, user_secret str: Twitter user access key and secret, used by TWBlue to authorise against Twitter.
|
||||
text str: Tweet text, max 10000 characters.
|
||||
media int: Not used currently.
|
||||
Returns text to be placed in the Tweet if the post has been succeeded, 0 otherwise."""
|
||||
twitter = OAuth1Session(keys.keyring.get("api_key"), client_secret=keys.keyring.get("api_secret"), resource_owner_key=user_token, resource_owner_secret=user_secret)
|
||||
twishort_key=keys.keyring.get("twishort_api_key")
|
||||
x_auth_service_provider = "https://api.twitter.com/1.1/account/verify_credentials.json"
|
||||
@@ -84,4 +98,4 @@ def create_tweet(user_token, user_secret, text, media=0):
|
||||
return response.json()["text_to_tweet"]
|
||||
except:
|
||||
print "There was a problem creating a long tweet"
|
||||
return 0
|
||||
return 0
|
@@ -1,65 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" The main session object. Here are the twitter functions to interact with the "model" of TWBlue."""
|
||||
import wx
|
||||
import urllib2
|
||||
import config
|
||||
import twitter
|
||||
from keys import keyring
|
||||
import session_exceptions as Exceptions
|
||||
import paths
|
||||
import output
|
||||
import time
|
||||
import sound
|
||||
import logging
|
||||
from twitter import utils, compose
|
||||
from twython import TwythonError, TwythonRateLimitError, TwythonAuthError
|
||||
import config_utils
|
||||
import shelve
|
||||
import application
|
||||
""" This is the main session needed to access all Twitter Features."""
|
||||
import os
|
||||
from mysc.thread_utils import stream_threaded, call_threaded
|
||||
import time
|
||||
import logging
|
||||
import webbrowser
|
||||
import wx
|
||||
import config
|
||||
import output
|
||||
import application
|
||||
from pubsub import pub
|
||||
log = logging.getLogger("sessionmanager.session")
|
||||
from long_tweets import tweets, twishort
|
||||
from twython import Twython, TwythonError, TwythonRateLimitError, TwythonAuthError
|
||||
from mysc.thread_utils import call_threaded
|
||||
from keys import keyring
|
||||
from sessions import base
|
||||
from sessions.twitter import utils, compose
|
||||
from sessions.twitter.long_tweets import tweets, twishort
|
||||
from wxUI import authorisationDialog
|
||||
|
||||
sessions = {}
|
||||
log = logging.getLogger("sessions.twitterSession")
|
||||
|
||||
class Session(object):
|
||||
class Session(base.baseSession):
|
||||
""" A session object where we will save configuration, the twitter object and a local storage for saving the items retrieved through the Twitter API methods"""
|
||||
|
||||
# Decorators.
|
||||
|
||||
def _require_login(fn):
|
||||
|
||||
""" Decorator for checking if the user is logged in(a twitter object has credentials) on twitter.
|
||||
Some functions may need this to avoid making unneeded twitter API calls."""
|
||||
|
||||
def f(self, *args, **kwargs):
|
||||
if self.logged == True:
|
||||
fn(self, *args, **kwargs)
|
||||
else:
|
||||
raise Exceptions.NotLoggedSessionError("You are not logged in yet.")
|
||||
return f
|
||||
|
||||
def _require_configuration(fn):
|
||||
|
||||
""" Check if the user has a configured session."""
|
||||
|
||||
def f(self, *args, **kwargs):
|
||||
if self.settings != None:
|
||||
fn(self, *args, **kwargs)
|
||||
else:
|
||||
raise Exceptions.NotConfiguredSessionError("Not configured.")
|
||||
return f
|
||||
|
||||
def order_buffer(self, name, data, ignore_older=True):
|
||||
|
||||
""" Put the new items in the local database.
|
||||
""" Put new items in the local database.
|
||||
name str: The name for the buffer stored in the dictionary.
|
||||
data list: A list with tweets.
|
||||
ignore_older bool: if set to True, items older than the first element on the list will be ignored.
|
||||
returns the number of items that have been added in this execution"""
|
||||
|
||||
num = 0
|
||||
last_id = None
|
||||
if self.db.has_key(name) == False:
|
||||
@@ -89,18 +57,18 @@ class Session(object):
|
||||
return num
|
||||
|
||||
def order_cursored_buffer(self, name, data):
|
||||
|
||||
""" Put the new items on the local database. Useful for cursored buffers (followers, friends, users of a list and searches)
|
||||
""" Put new items on the local database. Useful for cursored buffers (followers, friends, users of a list and searches)
|
||||
name str: The name for the buffer stored in the dictionary.
|
||||
data list: A list with items and some information about cursors.
|
||||
returns the number of items that have been added in this execution"""
|
||||
# Direct messages should be added to db in other function.
|
||||
# Because they will be populating two buffers with one endpoint.
|
||||
if name == "direct_messages":
|
||||
return self.order_direct_messages(data)
|
||||
num = 0
|
||||
if self.db.has_key(name) == False:
|
||||
self.db[name] = {}
|
||||
self.db[name]["items"] = []
|
||||
# if len(self.db[name]["items"]) > 0:
|
||||
for i in data:
|
||||
if utils.find_item(i["id"], self.db[name]["items"]) == None:
|
||||
if self.settings["general"]["reverse_timelines"] == False: self.db[name]["items"].append(i)
|
||||
@@ -109,6 +77,9 @@ class Session(object):
|
||||
return num
|
||||
|
||||
def order_direct_messages(self, data):
|
||||
""" Add incoming and sent direct messages to their corresponding database items.
|
||||
data list: A list of direct messages to add.
|
||||
returns the number of incoming messages processed in this execution, and sends an event with data regarding amount of sent direct messages added."""
|
||||
incoming = 0
|
||||
sent = 0
|
||||
if self.db.has_key("direct_messages") == False:
|
||||
@@ -116,7 +87,7 @@ class Session(object):
|
||||
self.db["direct_messages"]["items"] = []
|
||||
for i in data:
|
||||
if i["message_create"]["sender_id"] == self.db["user_id"]:
|
||||
if utils.find_item(i["id"], self.db["sent_direct_messages"]["items"]) == None:
|
||||
if self.db.has_key("sent_direct_messages") and utils.find_item(i["id"], self.db["sent_direct_messages"]["items"]) == None:
|
||||
if self.settings["general"]["reverse_timelines"] == False: self.db["sent_direct_messages"]["items"].append(i)
|
||||
else: self.db["sent_direct_messages"]["items"].insert(0, i)
|
||||
sent = sent+1
|
||||
@@ -128,104 +99,95 @@ class Session(object):
|
||||
pub.sendMessage("sent-dms-updated", total=sent, account=self.db["user_name"])
|
||||
return incoming
|
||||
|
||||
def __init__(self, session_id):
|
||||
|
||||
""" session_id (str): The name of the folder inside the config directory where the session is located."""
|
||||
|
||||
super(Session, self).__init__()
|
||||
self.session_id = session_id
|
||||
self.logged = False
|
||||
self.settings = None
|
||||
self.twitter = twitter.twitter.twitter()
|
||||
self.db={}
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Session, self).__init__(*args, **kwargs)
|
||||
self.reconnection_function_active = False
|
||||
self.counter = 0
|
||||
self.lists = []
|
||||
pub.subscribe(self.add_friends, "friends-receibed")
|
||||
|
||||
@property
|
||||
def is_logged(self):
|
||||
return self.logged
|
||||
|
||||
def get_configuration(self):
|
||||
|
||||
""" Gets settings for a session."""
|
||||
|
||||
file_ = "%s/session.conf" % (self.session_id,)
|
||||
# try:
|
||||
log.debug("Creating config file %s" % (file_,))
|
||||
self.settings = config_utils.load_config(paths.config_path(file_), paths.app_path("Conf.defaults"))
|
||||
self.init_sound()
|
||||
self.deshelve()
|
||||
# except:
|
||||
# log.exception("The session configuration has failed.")
|
||||
# self.settings = None
|
||||
|
||||
def init_sound(self):
|
||||
try: self.sound = sound.soundSystem(self.settings["sound"])
|
||||
except: pass
|
||||
|
||||
@_require_configuration
|
||||
# @_require_configuration
|
||||
def login(self, verify_credentials=True):
|
||||
|
||||
""" Log into twitter using credentials from settings.
|
||||
if the user account isn't authorised, it needs to call self.authorise() before login."""
|
||||
|
||||
if self.settings["twitter"]["user_key"] != None and self.settings["twitter"]["user_secret"] != None:
|
||||
try:
|
||||
log.debug("Logging in to twitter...")
|
||||
self.twitter.login(self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"], verify_credentials)
|
||||
self.twitter = Twython(keyring.get("api_key"), keyring.get("api_secret"), self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"])
|
||||
if verify_credentials == True:
|
||||
self.credentials = self.twitter.verify_credentials()
|
||||
self.logged = True
|
||||
log.debug("Logged.")
|
||||
self.counter = 0
|
||||
except:
|
||||
except IOError:
|
||||
log.error("The login attempt failed.")
|
||||
self.logged = False
|
||||
else:
|
||||
self.logged = False
|
||||
raise Exceptions.RequireCredentialsSessionError
|
||||
|
||||
@_require_configuration
|
||||
# @_require_configuration
|
||||
def authorise(self):
|
||||
|
||||
""" Authorises a Twitter account. This function needs to be called for each new session, after self.get_configuration() and before self.login()"""
|
||||
|
||||
if self.logged == True:
|
||||
raise Exceptions.AlreadyAuthorisedError("The authorisation process is not needed at this time.")
|
||||
else:
|
||||
self.twitter.authorise()
|
||||
twitter = Twython(keyring.get("api_key"), keyring.get("api_secret"))
|
||||
self.auth = twitter.get_authentication_tokens(callback_url="oob")
|
||||
webbrowser.open_new_tab(self.auth['auth_url'])
|
||||
self.authorisation_dialog = authorisationDialog()
|
||||
self.authorisation_dialog.cancel.Bind(wx.EVT_BUTTON, self.authorisation_cancelled)
|
||||
self.authorisation_dialog.ok.Bind(wx.EVT_BUTTON, self.authorisation_accepted)
|
||||
self.authorisation_dialog.ShowModal()
|
||||
|
||||
def verify_authorisation(self, pincode):
|
||||
twitter = Twython(keyring.get("api_key"), keyring.get("api_secret"), self.auth['oauth_token'], self.auth['oauth_token_secret'])
|
||||
final = twitter.get_authorized_tokens(pincode)
|
||||
self.settings["twitter"]["user_key"] = final["oauth_token"]
|
||||
self.settings["twitter"]["user_secret"] = final["oauth_token_secret"]
|
||||
self.settings.write()
|
||||
del self.auth
|
||||
|
||||
def authorisation_cancelled(self, *args, **kwargs):
|
||||
""" Destroy the authorization dialog. """
|
||||
self.authorisation_dialog.Destroy()
|
||||
del self.authorisation_dialog
|
||||
|
||||
def authorisation_accepted(self, *args, **kwargs):
|
||||
""" Gets the PIN code entered by user and validate it through Twitter."""
|
||||
pincode = self.authorisation_dialog.text.GetValue()
|
||||
self.twitter.verify_authorisation(self.settings, pincode)
|
||||
self.verify_authorisation(pincode)
|
||||
self.authorisation_dialog.Destroy()
|
||||
|
||||
def get_more_items(self, update_function, users=False, dm=False, name=None, *args, **kwargs):
|
||||
""" Get more items for twitter objects.
|
||||
update_function str: function to call for getting more items. Must be member of self.twitter.
|
||||
users, dm bool: If any of these is set to True, the function will treat items as users or dm (they need different handling).
|
||||
name str: name of the database item to put new element in."""
|
||||
results = []
|
||||
data = getattr(self.twitter.twitter, update_function)(*args, **kwargs)
|
||||
if kwargs.has_key("cursor") and kwargs["cursor"] == 0:
|
||||
output.speak(_(u"There are no more items to retrieve in this buffer."))
|
||||
return
|
||||
data = getattr(self.twitter, update_function)(*args, **kwargs)
|
||||
if users == True:
|
||||
if type(data) == dict and data.has_key("next_cursor"):
|
||||
self.db[name]["cursor"] = data["next_cursor"]
|
||||
if data.has_key("next_cursor"): # There are more objects to retrieve.
|
||||
self.db[name]["cursor"] = data["next_cursor"]
|
||||
else: # Set cursor to 0, wich means no more items available.
|
||||
self.db[name]["cursor"] = 0
|
||||
for i in data["users"]: results.append(i)
|
||||
elif type(data) == list:
|
||||
results.extend(data[1:])
|
||||
elif dm == True:
|
||||
self.db[name]["cursor"] = data["next_cursor"]
|
||||
if data.has_key("next_cursor"): # There are more objects to retrieve.
|
||||
self.db[name]["cursor"] = data["next_cursor"]
|
||||
else: # Set cursor to 0, wich means no more items available.
|
||||
self.db[name]["cursor"] = 0
|
||||
for i in data["events"]: results.append(i)
|
||||
else:
|
||||
results.extend(data[1:])
|
||||
return results
|
||||
|
||||
def api_call(self, call_name, action="", _sound=None, report_success=False, report_failure=True, preexec_message="", *args, **kwargs):
|
||||
|
||||
""" Make a call to the Twitter API. If there is a connectionError or another exception not related to Twitter, It will call the method again at least 25 times, waiting a while between calls. Useful for post methods.
|
||||
If twitter returns an error, it will not call the method anymore.
|
||||
call_name str: The method to call
|
||||
@@ -234,17 +196,17 @@ class Session(object):
|
||||
_sound str: a sound to play if the call is executed properly.
|
||||
report_success and report_failure bool: These are self explanatory. True or False.
|
||||
preexec_message str: A message to speak to the user while the method is running, example: "trying to follow x user"."""
|
||||
|
||||
finished = False
|
||||
tries = 0
|
||||
if preexec_message:
|
||||
output.speak(preexec_message, True)
|
||||
while finished==False and tries < 25:
|
||||
try:
|
||||
val = getattr(self.twitter.twitter, call_name)(*args, **kwargs)
|
||||
val = getattr(self.twitter, call_name)(*args, **kwargs)
|
||||
finished = True
|
||||
except TwythonError as e:
|
||||
output.speak(e.message)
|
||||
val = None
|
||||
if e.error_code != 403 and e.error_code != 404:
|
||||
tries = tries+1
|
||||
time.sleep(5)
|
||||
@@ -260,50 +222,45 @@ class Session(object):
|
||||
return val
|
||||
|
||||
def search(self, name, *args, **kwargs):
|
||||
tl = self.twitter.twitter.search(*args, **kwargs)
|
||||
""" Search in twitter, passing args and kwargs as arguments to the Twython function."""
|
||||
tl = self.twitter.search(*args, **kwargs)
|
||||
tl["statuses"].reverse()
|
||||
return tl["statuses"]
|
||||
|
||||
@_require_login
|
||||
# @_require_login
|
||||
def get_favourites_timeline(self, name, *args, **kwargs):
|
||||
|
||||
""" Gets favourites for the authenticated user or a friend or follower.
|
||||
name str: Name for storage in the database."""
|
||||
|
||||
tl = self.call_paged(self.twitter.twitter.get_favorites, *args, **kwargs)
|
||||
name str: Name for storage in the database.
|
||||
args and kwargs are passed directly to the Twython function."""
|
||||
tl = self.call_paged("get_favorites", *args, **kwargs)
|
||||
return self.order_buffer(name, tl)
|
||||
|
||||
def call_paged(self, update_function, *args, **kwargs):
|
||||
|
||||
""" Makes a call to the Twitter API methods several times. Useful for get methods.
|
||||
this function is needed for retrieving more than 200 items.
|
||||
update_function str: The function to call. This function must be child of self.twitter.twitter
|
||||
update_function str: The function to call. This function must be child of self.twitter
|
||||
args and kwargs are passed to update_function.
|
||||
returns a list with all items retrieved."""
|
||||
|
||||
if application.streaming_lives():
|
||||
max = int(self.settings["general"]["max_api_calls"])-1
|
||||
else:
|
||||
max = 0
|
||||
max = 0
|
||||
results = []
|
||||
data = getattr(self.twitter.twitter, update_function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
data = getattr(self.twitter, update_function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
results.extend(data)
|
||||
for i in range(0, max):
|
||||
if i == 0: max_id = results[-1]["id"]
|
||||
else: max_id = results[0]["id"]
|
||||
data = getattr(self.twitter.twitter, update_function)(max_id=max_id, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
data = getattr(self.twitter, update_function)(max_id=max_id, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
results.extend(data)
|
||||
results.reverse()
|
||||
return results
|
||||
|
||||
@_require_login
|
||||
# @_require_login
|
||||
def get_user_info(self):
|
||||
|
||||
""" Retrieves some information required by TWBlue for setup."""
|
||||
f = self.twitter.twitter.get_account_settings()
|
||||
f = self.twitter.get_account_settings()
|
||||
sn = f["screen_name"]
|
||||
self.settings["twitter"]["user_name"] = sn
|
||||
self.db["user_name"] = sn
|
||||
self.db["user_id"] = self.twitter.twitter.show_user(screen_name=sn)["id_str"]
|
||||
self.db["user_id"] = self.twitter.show_user(screen_name=sn)["id_str"]
|
||||
try:
|
||||
self.db["utc_offset"] = f["time_zone"]["utc_offset"]
|
||||
except KeyError:
|
||||
@@ -311,32 +268,26 @@ class Session(object):
|
||||
# Get twitter's supported languages and save them in a global variable
|
||||
#so we won't call to this method once per session.
|
||||
if len(application.supported_languages) == 0:
|
||||
application.supported_languages = self.twitter.twitter.get_supported_languages()
|
||||
application.supported_languages = self.twitter.get_supported_languages()
|
||||
self.get_lists()
|
||||
self.get_muted_users()
|
||||
self.settings.write()
|
||||
|
||||
@_require_login
|
||||
# @_require_login
|
||||
def get_lists(self):
|
||||
|
||||
""" Gets the lists that the user is subscribed to and stores them in the database. Returns None."""
|
||||
|
||||
self.db["lists"] = self.twitter.twitter.show_lists(reverse=True)
|
||||
self.db["lists"] = self.twitter.show_lists(reverse=True)
|
||||
|
||||
@_require_login
|
||||
# @_require_login
|
||||
def get_muted_users(self):
|
||||
|
||||
""" Gets muted users (oh really?)."""
|
||||
self.db["muted_users"] = self.twitter.list_mute_ids()["ids"]
|
||||
|
||||
self.db["muted_users"] = self.twitter.twitter.list_mute_ids()["ids"]
|
||||
|
||||
@_require_login
|
||||
# @_require_login
|
||||
def get_stream(self, name, function, *args, **kwargs):
|
||||
|
||||
""" Retrieves the items for a regular stream.
|
||||
name str: Name to save items to the database.
|
||||
function str: A function to get the items."""
|
||||
|
||||
last_id = -1
|
||||
if self.db.has_key(name):
|
||||
try:
|
||||
@@ -350,13 +301,12 @@ class Session(object):
|
||||
self.order_buffer(name, tl)
|
||||
|
||||
def get_cursored_stream(self, name, function, items="users", get_previous=False, *args, **kwargs):
|
||||
|
||||
""" Gets items for API calls that require using cursors to paginate the results.
|
||||
name str: Name to save it in the database.
|
||||
function str: Function that provides the items.
|
||||
items: When the function returns the list with results, items will tell how the order function should be look.
|
||||
for example get_followers_list returns a list and users are under list["users"], here the items should point to "users"."""
|
||||
|
||||
items: When the function returns the list with results, items will tell how the order function should be look. for example get_followers_list returns a list and users are under list["users"], here the items should point to "users".
|
||||
get_previous bool: wether this function will be used to get previous items in a buffer or load the buffer from scratch.
|
||||
returns number of items retrieved."""
|
||||
items_ = []
|
||||
try:
|
||||
if self.db[name].has_key("cursor") and get_previous:
|
||||
@@ -366,143 +316,33 @@ class Session(object):
|
||||
except KeyError:
|
||||
cursor = -1
|
||||
if cursor != -1:
|
||||
tl = getattr(self.twitter.twitter, function)(cursor=cursor, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
tl = getattr(self.twitter, function)(cursor=cursor, count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
else:
|
||||
tl = getattr(self.twitter.twitter, function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
tl = getattr(self.twitter, function)(count=self.settings["general"]["max_tweets_per_call"], *args, **kwargs)
|
||||
tl[items].reverse()
|
||||
num = self.order_cursored_buffer(name, tl[items])
|
||||
# Recently, Twitter's new endpoints have cursor if there are more results.
|
||||
if tl.has_key("next_cursor"):
|
||||
self.db[name]["cursor"] = tl["next_cursor"]
|
||||
else:
|
||||
self.db[name]["cursor"] = 0
|
||||
return num
|
||||
|
||||
def start_streaming(self):
|
||||
|
||||
""" Start the streaming for sending tweets in realtime."""
|
||||
if application.streaming_lives():
|
||||
if not hasattr(self, "main_stream"):
|
||||
self.get_timelines()
|
||||
if not hasattr(self, "timelinesStream"):
|
||||
self.get_main_stream()
|
||||
|
||||
def get_main_stream(self):
|
||||
if application.streaming_lives():
|
||||
log.debug("Starting the main stream...")
|
||||
self.main_stream = twitter.buffers.stream.streamer(keyring.get("api_key"), keyring.get("api_secret"), self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"], self)
|
||||
stream_threaded(self.main_stream.user, self.session_id)
|
||||
|
||||
def get_timelines(self):
|
||||
if application.streaming_lives():
|
||||
log.debug("Starting the timelines stream...")
|
||||
self.timelinesStream = twitter.buffers.indibidual.timelinesStreamer(keyring.get("api_key"), keyring.get("api_secret"), self.settings["twitter"]["user_key"], self.settings["twitter"]["user_secret"], session=self)
|
||||
ids = ""
|
||||
for i in self.settings["other_buffers"]["timelines"]:
|
||||
ids = ids + "%s, " % (self.db[i+"-timeline"][0]["user"]["id_str"])
|
||||
for i in self.lists:
|
||||
for z in i.users:
|
||||
ids += str(z) + ", "
|
||||
if ids != "":
|
||||
stream_threaded(self.timelinesStream.statuses.filter, self.session_id, follow=ids)
|
||||
|
||||
def add_friends(self):
|
||||
if application.streaming_lives():
|
||||
try:
|
||||
self.timelinesStream.set_friends(self.main_stream.friends)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def listen_stream_error(self):
|
||||
if hasattr(self, "main_stream") and application.streaming_lives():
|
||||
log.debug("Disconnecting the main stream...")
|
||||
self.main_stream.disconnect()
|
||||
del self.main_stream
|
||||
if hasattr(self, "timelinesStream") and application.streaming_lives():
|
||||
log.debug("disconnecting the timelines stream...")
|
||||
self.timelinesStream.disconnect()
|
||||
del self.timelinesStream
|
||||
|
||||
def check_connection(self):
|
||||
""" Restart the Twitter object every 5 executions. It is useful for dealing with requests timeout and other oddities."""
|
||||
log.debug("Executing check connection...")
|
||||
instan = 0
|
||||
self.counter += 1
|
||||
if self.counter >= 4:
|
||||
log.debug("Restarting connection after 5 minutes.")
|
||||
del self.twitter
|
||||
self.logged = False
|
||||
self.twitter = twitter.twitter.twitter()
|
||||
self.login(False)
|
||||
self.counter = 0
|
||||
if self.reconnection_function_active == True: return
|
||||
self.reconnection_function_active = True
|
||||
if not hasattr(self, "main_stream") and application.streaming_lives():
|
||||
self.get_main_stream()
|
||||
if not hasattr(self, "timelinesStream") and application.streaming_lives():
|
||||
self.get_timelines()
|
||||
self.reconnection_function_active = False
|
||||
if hasattr(self, "timelinesStream") and not hasattr(self.timelinesStream, "friends"):
|
||||
self.add_friends()
|
||||
# try:
|
||||
# urllib2.urlopen("http://74.125.228.231", timeout=5)
|
||||
# except urllib2.URLError:
|
||||
# pub.sendMessage("stream-error", session=self.session_id)
|
||||
|
||||
def remove_stream(self, stream):
|
||||
if application.streaming_lives():
|
||||
if stream == "timelinesStream":
|
||||
if hasattr(self, "timelinesStream"):
|
||||
self.timelinesStream.disconnect()
|
||||
del self.timelinesStream
|
||||
else:
|
||||
self.main_stream.disconnect()
|
||||
del self.main_stream
|
||||
|
||||
def shelve(self):
|
||||
"Shelve the database to allow for persistance."
|
||||
shelfname=paths.config_path(str(self.session_id)+"/cache.db")
|
||||
if self.settings["general"]["persist_size"] == 0:
|
||||
if os.path.exists(shelfname):
|
||||
os.remove(shelfname)
|
||||
return
|
||||
try:
|
||||
if not os.path.exists(shelfname):
|
||||
output.speak("Generating database, this might take a while.",True)
|
||||
shelf=shelve.open(paths.config_path(shelfname),'c')
|
||||
for key,value in self.db.items():
|
||||
if type(key) != str and type(key) != unicode:
|
||||
output.speak("Uh oh, while shelving the database, a key of type " + str(type(key)) + " has been found. It will be converted to type str, but this will cause all sorts of problems on deshelve. Please bring this to the attention of the " + application.name + " developers immediately. More information about the error will be written to the error log.",True)
|
||||
log.error("Uh oh, " + str(key) + " is of type " + str(type(key)) + "!")
|
||||
# Convert unicode objects to UTF-8 strings before shelve these objects.
|
||||
if type(value) == list and self.settings["general"]["persist_size"] != -1 and len(value) > self.settings["general"]["persist_size"]:
|
||||
shelf[str(key.encode("utf-8"))]=value[self.settings["general"]["persist_size"]:]
|
||||
else:
|
||||
shelf[str(key.encode("utf-8"))]=value
|
||||
shelf.close()
|
||||
except:
|
||||
output.speak("An exception occurred while shelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True)
|
||||
log.exception("Exception while shelving" + shelfname)
|
||||
os.remove(shelfname)
|
||||
|
||||
def deshelve(self):
|
||||
"Import a shelved database."
|
||||
shelfname=paths.config_path(str(self.session_id)+"/cache.db")
|
||||
if self.settings["general"]["persist_size"] == 0:
|
||||
if os.path.exists(shelfname):
|
||||
os.remove(shelfname)
|
||||
return
|
||||
try:
|
||||
shelf=shelve.open(paths.config_path(shelfname),'c')
|
||||
for key,value in shelf.items():
|
||||
self.db[key]=value
|
||||
shelf.close()
|
||||
except:
|
||||
output.speak("An exception occurred while deshelving the " + application.name + " database. It will be deleted and rebuilt automatically. If this error persists, send the error log to the " + application.name + " developers.",True)
|
||||
log.exception("Exception while deshelving" + shelfname)
|
||||
try:
|
||||
os.remove(shelfname)
|
||||
except:
|
||||
pass
|
||||
|
||||
def check_quoted_status(self, tweet):
|
||||
""" Helper for get_quoted_tweet. Get a quoted status inside a tweet and create a special tweet with all info available.
|
||||
tweet dict: A tweet dictionary.
|
||||
Returns a quoted tweet or the original tweet if is not a quote"""
|
||||
status = tweets.is_long(tweet)
|
||||
if status != False and config.app["app-settings"]["handle_longtweets"]:
|
||||
quoted_tweet = self.get_quoted_tweet(tweet)
|
||||
@@ -510,6 +350,7 @@ class Session(object):
|
||||
return tweet
|
||||
|
||||
def get_quoted_tweet(self, tweet):
|
||||
""" Process a tweet and extract all information related to the quote."""
|
||||
quoted_tweet = tweet
|
||||
if tweet.has_key("full_text"):
|
||||
value = "full_text"
|
||||
@@ -539,6 +380,9 @@ class Session(object):
|
||||
return compose.compose_quoted_tweet(quoted_tweet, original_tweet)
|
||||
|
||||
def check_long_tweet(self, tweet):
|
||||
""" Process a tweet and add extra info if it's a long tweet made with Twyshort.
|
||||
tweet dict: a tweet object.
|
||||
returns a tweet with a new argument message, or original tweet if it's not a long tweet."""
|
||||
long = twishort.is_long(tweet)
|
||||
if long != False and config.app["app-settings"]["handle_longtweets"]:
|
||||
message = twishort.get_full_text(long)
|
||||
@@ -562,22 +406,28 @@ class Session(object):
|
||||
return tweet
|
||||
|
||||
def get_user(self, id):
|
||||
""" Returns an user object associated with an ID.
|
||||
id str: User identifier, provided by Twitter.
|
||||
returns an user dict."""
|
||||
if self.db.has_key("users") == False or self.db["users"].has_key(id) == False:
|
||||
user = self.twitter.twitter.show_user(id=id)
|
||||
user = self.twitter.show_user(id=id)
|
||||
self.db["users"][user["id_str"]] = user
|
||||
return user
|
||||
else:
|
||||
return self.db["users"][id]
|
||||
|
||||
def get_user_by_screen_name(self, screen_name):
|
||||
""" Returns an user identifier associated with a screen_name.
|
||||
screen_name str: User name, such as tw_blue2, provided by Twitter.
|
||||
returns an user ID."""
|
||||
if self.db.has_key("users") == False:
|
||||
user = utils.if_user_exists(self.twitter.twitter, screen_name)
|
||||
user = utils.if_user_exists(self.twitter, screen_name)
|
||||
self.db["users"][user["id_str"]] = user
|
||||
return user["id_str"]
|
||||
else:
|
||||
for i in self.db["users"].keys():
|
||||
if self.db["users"][i]["screen_name"] == screen_name:
|
||||
return self.db["users"][i]["id_str"]
|
||||
user = utils.if_user_exists(self.twitter.twitter, screen_name)
|
||||
user = utils.if_user_exists(self.twitter, screen_name)
|
||||
self.db["users"][user["id_str"]] = user
|
||||
return user["id_str"]
|
17
src/sessions/twitter/wxUI.py
Normal file
17
src/sessions/twitter/wxUI.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import wx
|
||||
|
||||
class authorisationDialog(wx.Dialog):
|
||||
def __init__(self):
|
||||
super(authorisationDialog, self).__init__(parent=None, title=_(u"Authorising account..."))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
static = wx.StaticText(panel, wx.NewId(), _(u"Enter your PIN code here"))
|
||||
self.text = wx.TextCtrl(panel, -1)
|
||||
self.ok = wx.Button(panel, wx.ID_OK)
|
||||
self.cancel = wx.Button(panel, wx.ID_CANCEL)
|
||||
sizer.Add(self.text, 0, wx.ALL, 5)
|
||||
sizer.Add(self.cancel, 0, wx.ALL, 5)
|
||||
panel.SetSizer(sizer)
|
||||
min = sizer.CalcMin()
|
||||
self.SetClientSize(min)
|
@@ -112,7 +112,7 @@ data_files = get_data(),
|
||||
options = {
|
||||
'py2exe': {
|
||||
'optimize':2,
|
||||
'packages': ["pubsub", "pubsub.core", "pubsub.core.kwargs", "dbhash"],
|
||||
'packages': ["pubsub", "pubsub.core", "pubsub.core.kwargs", "dbhash", "oauthlib.oauth1.rfc5849.endpoints.resource", "oauthlib.oauth2.rfc6749.endpoints.resource"],
|
||||
'dll_excludes': ["MPR.dll", "api-ms-win-core-apiquery-l1-1-0.dll", "api-ms-win-core-console-l1-1-0.dll", "api-ms-win-core-delayload-l1-1-1.dll", "api-ms-win-core-errorhandling-l1-1-1.dll", "api-ms-win-core-file-l1-2-0.dll", "api-ms-win-core-handle-l1-1-0.dll", "api-ms-win-core-heap-obsolete-l1-1-0.dll", "api-ms-win-core-libraryloader-l1-1-1.dll", "api-ms-win-core-localization-l1-2-0.dll", "api-ms-win-core-processenvironment-l1-2-0.dll", "api-ms-win-core-processthreads-l1-1-1.dll", "api-ms-win-core-profile-l1-1-0.dll", "api-ms-win-core-registry-l1-1-0.dll", "api-ms-win-core-synch-l1-2-0.dll", "api-ms-win-core-sysinfo-l1-2-0.dll", "api-ms-win-security-base-l1-2-0.dll", "api-ms-win-core-heap-l1-2-0.dll", "api-ms-win-core-interlocked-l1-2-0.dll", "api-ms-win-core-localization-obsolete-l1-1-0.dll", "api-ms-win-core-string-l1-1-0.dll", "api-ms-win-core-string-obsolete-l1-1-0.dll", "WLDAP32.dll", "MSVCP90.dll", "CRYPT32.dll", "mfc90.dll"],
|
||||
'compressed': True
|
||||
},
|
||||
|
BIN
src/sounds/FreakyBlue/Image.ogg
Normal file
BIN
src/sounds/FreakyBlue/Image.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/audio.ogg
Normal file
BIN
src/sounds/FreakyBlue/audio.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/create_timeline.ogg
Normal file
BIN
src/sounds/FreakyBlue/create_timeline.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/delete_timeline.ogg
Normal file
BIN
src/sounds/FreakyBlue/delete_timeline.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/dm_received.ogg
Normal file
BIN
src/sounds/FreakyBlue/dm_received.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/dm_sent.ogg
Normal file
BIN
src/sounds/FreakyBlue/dm_sent.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/error.ogg
Normal file
BIN
src/sounds/FreakyBlue/error.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/favourite.ogg
Normal file
BIN
src/sounds/FreakyBlue/favourite.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/favourites_timeline_updated.ogg
Normal file
BIN
src/sounds/FreakyBlue/favourites_timeline_updated.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/geo.ogg
Normal file
BIN
src/sounds/FreakyBlue/geo.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/limit.ogg
Normal file
BIN
src/sounds/FreakyBlue/limit.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/list_tweet.ogg
Normal file
BIN
src/sounds/FreakyBlue/list_tweet.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/max_length.ogg
Normal file
BIN
src/sounds/FreakyBlue/max_length.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/mention_received.ogg
Normal file
BIN
src/sounds/FreakyBlue/mention_received.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/new_event.ogg
Normal file
BIN
src/sounds/FreakyBlue/new_event.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/ready.ogg
Normal file
BIN
src/sounds/FreakyBlue/ready.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/reply_send.ogg
Normal file
BIN
src/sounds/FreakyBlue/reply_send.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/retweet_send.ogg
Normal file
BIN
src/sounds/FreakyBlue/retweet_send.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/search_updated.ogg
Normal file
BIN
src/sounds/FreakyBlue/search_updated.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/trends_updated.ogg
Normal file
BIN
src/sounds/FreakyBlue/trends_updated.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/tweet_received.ogg
Normal file
BIN
src/sounds/FreakyBlue/tweet_received.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/tweet_send.ogg
Normal file
BIN
src/sounds/FreakyBlue/tweet_send.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/tweet_timeline.ogg
Normal file
BIN
src/sounds/FreakyBlue/tweet_timeline.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/update_followers.ogg
Normal file
BIN
src/sounds/FreakyBlue/update_followers.ogg
Normal file
Binary file not shown.
BIN
src/sounds/FreakyBlue/volume_changed.ogg
Normal file
BIN
src/sounds/FreakyBlue/volume_changed.ogg
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
import buffers, utils, compose, twitter
|
@@ -1,32 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import BaseHTTPServer
|
||||
import application
|
||||
from urlparse import urlparse, parse_qs
|
||||
from pubsub import pub
|
||||
|
||||
logged = False
|
||||
verifier = None
|
||||
|
||||
class handler(BaseHTTPServer.BaseHTTPRequestHandler, object):
|
||||
|
||||
def do_GET(self):
|
||||
global logged
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "text/html")
|
||||
self.end_headers()
|
||||
logged = True
|
||||
params = parse_qs(urlparse(self.path).query)
|
||||
global verifier
|
||||
verifier = params.get('oauth_verifier', [None])[0]
|
||||
self.wfile.write(u"You have successfully logged into Twitter with {0}. You can close this window now.".format(application.name))
|
||||
pub.sendMessage("authorisation-accepted")
|
||||
pub.unsubscribe(self.cancelled, "authorisation-cancelled")
|
||||
self.finish()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
pub.subscribe(self.cancelled, "authorisation-cancelled")
|
||||
super(handler, self).__init__(*args, **kwargs)
|
||||
|
||||
def cancelled(self):
|
||||
pub.unsubscribe(self.cancelled, "authorisation-cancelled")
|
||||
self.finish()
|
@@ -1 +0,0 @@
|
||||
import stream, indibidual
|
@@ -1,77 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import config
|
||||
from requests.auth import HTTPProxyAuth
|
||||
from twitter import compose, utils
|
||||
from twython import TwythonStreamer
|
||||
from pubsub import pub
|
||||
import logging as original_logger
|
||||
log = original_logger.getLogger("TimelinesStream")
|
||||
|
||||
class timelinesStreamer(TwythonStreamer):
|
||||
def __init__(self, app_key, app_secret, oauth_token, oauth_token_secret, timeout=300, retry_count=None, retry_in=10, client_args=None, handlers=None, chunk_size=1, session=None):
|
||||
self.session = session
|
||||
super(timelinesStreamer, self).__init__(app_key, app_secret, oauth_token, oauth_token_secret, timeout=60, retry_count=None, retry_in=180, handlers=None, chunk_size=1)
|
||||
self.lists = self.session.lists
|
||||
|
||||
def on_error(self, status_code, data):
|
||||
log.error("error in stream: %s: %s" % (status_code, data))
|
||||
# pub.sendMessage("stream-error", session=self.session.session_id)
|
||||
|
||||
def on_timeout(self, *args, **kwargs):
|
||||
log.error("Twitter timeout Error")
|
||||
# pub.sendMessage("stream-error", session=self.session.session_id)
|
||||
|
||||
def check_tls(self, data):
|
||||
for i in self.session.settings["other_buffers"]["timelines"]:
|
||||
if data["user"]["id_str"] == i:
|
||||
if utils.find_item(data["id"], self.session.db["%s-timeline" % (i,)]) != None:
|
||||
log.error("duplicated tweet. Ignoring it...")
|
||||
return
|
||||
# try:
|
||||
if utils.is_allowed(data, self.session.settings, "%s-timeline" % (i,)):
|
||||
data_ = self.session.check_quoted_status(data)
|
||||
data_ = self.session.check_long_tweet(data_)
|
||||
data = data_
|
||||
# except ValueError:
|
||||
# pass
|
||||
if self.session.settings["general"]["reverse_timelines"] == False: self.session.db["%s-timeline" % (i,)].append(data)
|
||||
else: self.session.db["%s-timeline" % (i,)].insert(0, data)
|
||||
pub.sendMessage("item-in-timeline", data= data, user= self.session.db["user_name"], who= i)
|
||||
return
|
||||
for i in self.session.lists:
|
||||
try:
|
||||
i.users.index(data["user"]["id"])
|
||||
usr = data["in_reply_to_user_id"]
|
||||
if (usr != None and usr in self.friends) or data.has_key("retweeted_status"):
|
||||
data = self.session.check_quoted_status(data)
|
||||
data = self.session.check_long_tweet(data)
|
||||
if self.session.settings["general"]["reverse_timelines"] == False: self.session.db["%s" % (i.name,)].append(data)
|
||||
else: self.session.db["%s" % (i.name,)].insert(0, data)
|
||||
pub.sendMessage("item-in-list", data=data, user=self.session.db["user_name"], where=i.name)
|
||||
elif usr == None:
|
||||
data = self.session.check_quoted_status(data)
|
||||
data = self.session.check_long_tweet(data)
|
||||
if self.session.settings["general"]["reverse_timelines"] == False: self.session.db["%s" % (i.name,)].append(data)
|
||||
else: self.session.db["%s" % (i.name,)].insert(0, data)
|
||||
pub.sendMessage("item-in-list", data=data, user=self.session.db["user_name"], where=i.name)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def set_friends(self, friends):
|
||||
self.friends = friends
|
||||
|
||||
def on_success(self, data):
|
||||
if "text" in data:
|
||||
if data.has_key("extended_tweet"):
|
||||
data["full_text"] = data["extended_tweet"]["full_text"]
|
||||
if data.has_key("retweeted_status"):
|
||||
if data["retweeted_status"].has_key("extended_tweet"):
|
||||
data["retweeted_status"]["full_text"] = data["retweeted_status"]["extended_tweet"]["full_text"]
|
||||
data["retweeted_status"]["entities"] = data["retweeted_status"]["extended_tweet"]["entities"]
|
||||
data["full_text"] = data["text"]
|
||||
if data.has_key("quoted_status"):
|
||||
if data["quoted_status"].has_key("extended_tweet"):
|
||||
data["quoted_status"]["full_text"] = data["quoted_status"]["extended_tweet"]["full_text"]
|
||||
data["quoted_status"]["entities"] = data["quoted_status"]["extended_tweet"]["entities"]
|
||||
# data["full_text"] = data["text"]
|
||||
self.check_tls(data)
|
@@ -1,193 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import config
|
||||
from requests.auth import HTTPProxyAuth
|
||||
from twitter import utils
|
||||
from twython import TwythonStreamer
|
||||
from pubsub import pub
|
||||
import logging as original_logger
|
||||
log = original_logger.getLogger("MainStream")
|
||||
|
||||
class streamer(TwythonStreamer):
|
||||
def __init__(self, app_key, app_secret, oauth_token, oauth_token_secret, sessionObject, *a, **kw):
|
||||
super(streamer, self).__init__(app_key, app_secret, oauth_token, oauth_token_secret, *a, **kw)
|
||||
self.session = sessionObject
|
||||
self.muted_users = self.session.db["muted_users"]
|
||||
# self.blocked_users = []
|
||||
|
||||
def on_timeout(self, *args, **kwargs):
|
||||
log.error("Twitter timeout Error")
|
||||
# pub.sendMessage("stream-error", session=self.session.session_id)
|
||||
|
||||
def on_error(self, status_code, data):
|
||||
log.error("Error %s: %s" % (status_code, data))
|
||||
# pub.sendMessage("stream-error", session=self.session.session_id)
|
||||
|
||||
def get_user(self):
|
||||
return self.session.db["user_name"]
|
||||
|
||||
def put_data(self, place, data):
|
||||
if self.session.db.has_key(place):
|
||||
if utils.find_item(data["id"], self.session.db[place]) != None:
|
||||
log.error("duplicated tweet. Ignoring it...")
|
||||
return False
|
||||
# try:
|
||||
if utils.is_allowed(data, self.session.settings, place):
|
||||
data_ = self.session.check_quoted_status(data)
|
||||
data_ = self.session.check_long_tweet(data_)
|
||||
data = data_
|
||||
# except:
|
||||
# pass
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
self.session.db[place].append(data)
|
||||
else:
|
||||
self.session.db[place].insert(0, data)
|
||||
utils.is_audio(data)
|
||||
return True
|
||||
return False
|
||||
|
||||
def block_user(self, data):
|
||||
id = data["target"]["id"]
|
||||
if id in self.friends:
|
||||
self.friends.remove(id)
|
||||
if "blocks" in self.session.settings["general"]["buffer_order"]:
|
||||
self.session.db["blocked"]["items"].append(data["target"])
|
||||
pub.sendMessage("blocked-user", data=data["target"], user=self.get_user())
|
||||
|
||||
def unblock(self, data):
|
||||
if "blocks" in self.session.settings["general"]["buffer_order"] == True:
|
||||
item = utils.find_item(data["target"]["id"], self.session.db["blocked"]["items"])
|
||||
self.session.db["blocked"]["items"].pop(item)
|
||||
pub.sendMessage("unblocked-user", item=item, user=self.get_user())
|
||||
|
||||
def check_send(self, data):
|
||||
if self.session.db["user_name"] == data["user"]["screen_name"]:
|
||||
d = self.put_data("sent_tweets", data)
|
||||
if d != False:
|
||||
pub.sendMessage("sent-tweet", data=data, user=self.get_user())
|
||||
|
||||
def check_favs(self, data):
|
||||
if data["source"]["screen_name"] == self.session.db["user_name"]:
|
||||
d = self.put_data("favourites", data["target_object"])
|
||||
if d != False:
|
||||
pub.sendMessage("favourite", data=data["target_object"], user=self.get_user())
|
||||
|
||||
def check_mentions(self, data):
|
||||
if "@%s" % (self.session.db["user_name"]) in data["text"]:
|
||||
d = self.put_data("mentions", data)
|
||||
if d != False:
|
||||
pub.sendMessage("mention", data=data, user=self.get_user())
|
||||
|
||||
def set_quoted_tweet(self, data):
|
||||
if data["source"]["screen_name"] != self.session.db["user_name"]:
|
||||
d = self.put_data("mentions", data["target_object"])
|
||||
if d != False:
|
||||
pub.sendMessage("mention", data=data["target_object"], user=self.get_user())
|
||||
|
||||
def process_dm(self, data):
|
||||
return
|
||||
if self.session.db["user_name"] != data["direct_message"]["sender"]["screen_name"]:
|
||||
# d = self.put_data("sent_direct_messages", data["direct_message"])
|
||||
# if d != False:
|
||||
# pub.sendMessage("sent-dm", data=data["direct_message"], user=self.get_user())
|
||||
# else:
|
||||
d = self.put_data("direct_messages", data["direct_message"])
|
||||
if d != False:
|
||||
pub.sendMessage("direct-message", data=data["direct_message"], user=self.get_user())
|
||||
|
||||
def check_follower(self, data):
|
||||
if data["target"]["screen_name"] == self.session.db["user_name"]:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
self.session.db["followers"]["items"].append(data["source"])
|
||||
else:
|
||||
self.session.db["followers"]["items"].insert(0, data["source"])
|
||||
pub.sendMessage("follower", data=data["source"], user = self.get_user())
|
||||
else:
|
||||
if self.session.settings["general"]["reverse_timelines"] == False:
|
||||
self.session.db["friends"]["items"].append(data["target"])
|
||||
else:
|
||||
self.session.db["friends"]["items"].insert(0, data["target"])
|
||||
pub.sendMessage("friend", data=data["target"], user=self.get_user())
|
||||
|
||||
###
|
||||
def remove_fav(self, data):
|
||||
if self.session.db["user_name"] == data["source"]["screen_name"]:
|
||||
item = utils.find_item(data["target_object"]["id"], self.session.db["favourites"])
|
||||
self.session.db["favourites"].pop(item)
|
||||
pub.sendMessage("unfavourite", item=item, user=self.get_user())
|
||||
|
||||
def remove_friend(self, data):
|
||||
if "friends" in self.session.settings["general"]["buffer_order"]:
|
||||
item = utils.find_item(data["target"]["id"], self.session.db["friends"]["items"])
|
||||
if item > 0:
|
||||
self.friends.pop(item)
|
||||
pub.sendMessage("unfollowing", item=item, user=self.get_user())
|
||||
|
||||
def on_success(self, data):
|
||||
try:
|
||||
# if "delete" in data:
|
||||
# pub.sendMessage("tweet-deleted", data=data)
|
||||
if "direct_message" in data:
|
||||
self.process_dm(data)
|
||||
elif "friends" in data:
|
||||
self.friends = data["friends"]
|
||||
pub.sendMessage("friends-receibed")
|
||||
elif "text" in data:
|
||||
if data.has_key("extended_tweet"):
|
||||
data["full_text"] = data["extended_tweet"]["full_text"]
|
||||
data["entities"] = data["extended_tweet"]["entities"]
|
||||
if data.has_key("retweeted_status"):
|
||||
if data["retweeted_status"].has_key("extended_tweet"):
|
||||
data["retweeted_status"]["full_text"] = data["retweeted_status"]["extended_tweet"]["full_text"]
|
||||
data["retweeted_status"]["entities"] = data["retweeted_status"]["extended_tweet"]["entities"]
|
||||
data["full_text"] = data["text"]
|
||||
if data.has_key("quoted_status"):
|
||||
if data["quoted_status"].has_key("extended_tweet"):
|
||||
data["quoted_status"]["full_text"] = data["quoted_status"]["extended_tweet"]["full_text"]
|
||||
data["quoted_status"]["entities"] = data["quoted_status"]["extended_tweet"]["entities"]
|
||||
# data["full_text"] = data["quoted_status"]["full_text"]
|
||||
if data["user"]["id"] in self.muted_users: return
|
||||
self.check_mentions(data)
|
||||
self.check_send(data)
|
||||
if data["user"]["id"] in self.friends or data["user"]["screen_name"] == self.session.db["user_name"]:
|
||||
d = self.put_data("home_timeline", data)
|
||||
if d != False:
|
||||
pub.sendMessage("item-in-home", data=data, user=self.get_user())
|
||||
elif data.has_key("event"):
|
||||
if "favorite" == data["event"] and "favorites" in self.session.settings["general"]["buffer_order"]:
|
||||
self.check_favs(data)
|
||||
elif "unfavorite" == data["event"] and "favorites" in self.session.settings["general"]["buffer_order"]:
|
||||
self.remove_fav(data)
|
||||
elif "follow" == data["event"] and "followers" in self.session.settings["general"]["buffer_order"]:
|
||||
self.check_follower(data)
|
||||
elif "unfollow" == data["event"] and "friends" in self.session.settings["general"]["buffer_order"]:
|
||||
self.remove_friend(data)
|
||||
elif "block" == data["event"]:
|
||||
self.block_user(data)
|
||||
elif "unblock" == data["event"]:
|
||||
self.unblock(data)
|
||||
elif "list_created" == data["event"]:
|
||||
item = utils.find_item(data["target_object"]["id"], self.session.db["lists"])
|
||||
if item != None: self.session.db["lists"].append(data["target_object"])
|
||||
elif "list_destroyed" == data["event"]:
|
||||
item = utils.find_item(data["target_object"]["id"], self.session.db["lists"])
|
||||
if item != None: self.session.db["lists"].pop(item)
|
||||
self.parent.remove_list(data["target_object"]["id"])
|
||||
elif "list_member_added" == data["event"] and data["source"]["screen_name"] == self.get_user():
|
||||
pub.sendMessage("new-list-member-added", **{"id":str(data["target"]["id"]), "list":data["target_object"], "user":self.get_user()})
|
||||
elif "list_member_added" == data["event"] and data["target"]["screen_name"] == self.get_user():
|
||||
self.session.db["lists"].append(data["target_object"])
|
||||
elif "list_member_removed" == data["event"] and data["source"]["screen_name"] == self.get_user():
|
||||
pub.sendMessage("list-member-deleted", **{"id":str(data["target"]["id"]), "list":data["target_object"], "user":self.get_user()})
|
||||
elif "list_member_removed" == data["event"] and data["target"] == self.get_user():
|
||||
id = data["target_object"]["id"]
|
||||
list = utils.find_item(id, self.session.db["lists"])
|
||||
if list != None: self.session.db["lists"].pop(list)
|
||||
pub.sendMessage("list-deleted", **{"item":list, "user":self.get_user()})
|
||||
elif "quoted_tweet" == data["event"]:
|
||||
self.set_quoted_tweet(data)
|
||||
|
||||
if "events" in self.session.settings["general"]["buffer_order"]:
|
||||
pub.sendMessage("event", data= data, user= self.get_user())
|
||||
# self.sound.play("new_event.ogg")
|
||||
except KeyboardInterrupt:
|
||||
pass
|
@@ -1,31 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import config
|
||||
import random
|
||||
import webbrowser
|
||||
from twython import Twython, TwythonError
|
||||
from keys import keyring
|
||||
from requests import certs
|
||||
import logging
|
||||
log = logging.getLogger("sessionTwitter")
|
||||
|
||||
class twitter(object):
|
||||
|
||||
def login(self, user_key, user_secret, verify_credentials):
|
||||
self.twitter = Twython(keyring.get("api_key"), keyring.get("api_secret"), user_key, user_secret)
|
||||
if verify_credentials == True:
|
||||
self.credentials = self.twitter.verify_credentials()
|
||||
|
||||
def authorise(self):
|
||||
twitter = Twython(keyring.get("api_key"), keyring.get("api_secret"))
|
||||
self.auth = twitter.get_authentication_tokens(callback_url="oob")
|
||||
webbrowser.open_new_tab(self.auth['auth_url'])
|
||||
|
||||
def verify_authorisation(self, settings, pincode):
|
||||
self.twitter = Twython(keyring.get("api_key"), keyring.get("api_secret"), self.auth['oauth_token'], self.auth['oauth_token_secret'])
|
||||
final = self.twitter.get_authorized_tokens(pincode)
|
||||
self.save_configuration(settings, final["oauth_token"], final["oauth_token_secret"])
|
||||
|
||||
def save_configuration(self, settings, user_key, user_secret):
|
||||
settings["twitter"]["user_key"] = user_key
|
||||
settings["twitter"]["user_secret"] = user_secret
|
||||
settings.write()
|
@@ -19,7 +19,7 @@ Questions, comments? ryan@venodesigns.net
|
||||
"""
|
||||
|
||||
__author__ = 'Ryan McGrath <ryan@venodesigns.net>'
|
||||
__version__ = '3.6.0'
|
||||
__version__ = '3.7.0'
|
||||
|
||||
from .api import Twython
|
||||
from .streaming import TwythonStreamer
|
||||
|
@@ -19,6 +19,7 @@ from requests_oauthlib import OAuth1, OAuth2
|
||||
from . import __version__
|
||||
from .advisory import TwythonDeprecationWarning
|
||||
from .compat import json, urlencode, parse_qsl, quote_plus, str, is_py2
|
||||
from .compat import urlsplit
|
||||
from .endpoints import EndpointsMixin
|
||||
from .exceptions import TwythonError, TwythonAuthError, TwythonRateLimitError
|
||||
from .helpers import _transparent_params
|
||||
@@ -134,13 +135,13 @@ class Twython(EndpointsMixin, object):
|
||||
def __repr__(self):
|
||||
return '<Twython: %s>' % (self.app_key)
|
||||
|
||||
def _request(self, url, method='GET', params=None, api_call=None, encode_json=False):
|
||||
def _request(self, url, method='GET', params=None, api_call=None, json_encoded=False):
|
||||
"""Internal request method"""
|
||||
method = method.lower()
|
||||
params = params or {}
|
||||
|
||||
func = getattr(self.client, method)
|
||||
if type(params) is dict and encode_json == False:
|
||||
if isinstance(params, dict) and json_encoded == False:
|
||||
params, files = _transparent_params(params)
|
||||
else:
|
||||
params = params
|
||||
@@ -152,18 +153,17 @@ class Twython(EndpointsMixin, object):
|
||||
if k in ('timeout', 'allow_redirects', 'stream', 'verify'):
|
||||
requests_args[k] = v
|
||||
|
||||
if method == 'get':
|
||||
if method == 'get' or method == 'delete':
|
||||
requests_args['params'] = params
|
||||
else:
|
||||
|
||||
if encode_json == False:
|
||||
requests_args.update({
|
||||
'files': files,
|
||||
'data': params,
|
||||
})
|
||||
# Check for json_encoded so we will sent params as "data" or "json"
|
||||
if json_encoded:
|
||||
data_key = "json"
|
||||
else:
|
||||
requests_args.update({
|
||||
'json': params,
|
||||
data_key = "data"
|
||||
requests_args.update({
|
||||
data_key: params,
|
||||
'files': files,
|
||||
})
|
||||
try:
|
||||
response = func(url, **requests_args)
|
||||
@@ -202,14 +202,14 @@ class Twython(EndpointsMixin, object):
|
||||
error_message,
|
||||
error_code=response.status_code,
|
||||
retry_after=response.headers.get('X-Rate-Limit-Reset'))
|
||||
content=""
|
||||
content = ''
|
||||
try:
|
||||
if response.status_code == 204:
|
||||
content = response.content
|
||||
else:
|
||||
content = response.json()
|
||||
except ValueError:
|
||||
if response.content!="":
|
||||
if response.content != '':
|
||||
raise TwythonError('Response was not valid JSON. \
|
||||
Unable to decode.')
|
||||
|
||||
@@ -235,14 +235,14 @@ class Twython(EndpointsMixin, object):
|
||||
|
||||
return error_message
|
||||
|
||||
def request(self, endpoint, method='GET', params=None, version='1.1', encode_json=False):
|
||||
def request(self, endpoint, method='GET', params=None, version='1.1', json_encoded=False):
|
||||
"""Return dict of response received from Twitter's API
|
||||
|
||||
:param endpoint: (required) Full url or Twitter API endpoint
|
||||
(e.g. search/tweets)
|
||||
:type endpoint: string
|
||||
:param method: (optional) Method of accessing data, either
|
||||
GET or POST. (default GET)
|
||||
GET, POST or DELETE. (default GET)
|
||||
:type method: string
|
||||
:param params: (optional) Dict of parameters (if any) accepted
|
||||
the by Twitter API endpoint you are trying to
|
||||
@@ -251,6 +251,9 @@ class Twython(EndpointsMixin, object):
|
||||
:param version: (optional) Twitter API version to access
|
||||
(default 1.1)
|
||||
:type version: string
|
||||
:param json_encoded: (optional) Flag to indicate if this method should send data encoded as json
|
||||
(default False)
|
||||
:type json_encoded: bool
|
||||
|
||||
:rtype: dict
|
||||
"""
|
||||
@@ -266,7 +269,7 @@ class Twython(EndpointsMixin, object):
|
||||
url = '%s/%s.json' % (self.api_url % version, endpoint)
|
||||
|
||||
content = self._request(url, method=method, params=params,
|
||||
api_call=url, encode_json=encode_json)
|
||||
api_call=url, json_encoded=json_encoded)
|
||||
|
||||
return content
|
||||
|
||||
@@ -274,9 +277,13 @@ class Twython(EndpointsMixin, object):
|
||||
"""Shortcut for GET requests via :class:`request`"""
|
||||
return self.request(endpoint, params=params, version=version)
|
||||
|
||||
def post(self, endpoint, params=None, version='1.1', encode_json=False):
|
||||
def post(self, endpoint, params=None, version='1.1', json_encoded=False):
|
||||
"""Shortcut for POST requests via :class:`request`"""
|
||||
return self.request(endpoint, 'POST', params=params, version=version, encode_json=encode_json)
|
||||
return self.request(endpoint, 'POST', params=params, version=version, json_encoded=json_encoded)
|
||||
|
||||
def delete(self, endpoint, params=None, version='1.1', json_encoded=False):
|
||||
"""Shortcut for delete requests via :class:`request`"""
|
||||
return self.request(endpoint, 'DELETE', params=params, version=version, json_encoded=json_encoded)
|
||||
|
||||
def get_lastfunction_header(self, header, default_return_value=None):
|
||||
"""Returns a specific header from the last API call
|
||||
@@ -513,19 +520,27 @@ class Twython(EndpointsMixin, object):
|
||||
|
||||
try:
|
||||
if function.iter_mode == 'id':
|
||||
if 'max_id' not in params:
|
||||
# Add 1 to the id because since_id and
|
||||
# max_id are inclusive
|
||||
if hasattr(function, 'iter_metadata'):
|
||||
since_id = content[function.iter_metadata].get('since_id_str')
|
||||
# Set max_id in params to one less than lowest tweet id
|
||||
if hasattr(function, 'iter_metadata'):
|
||||
# Get supplied next max_id
|
||||
metadata = content.get(function.iter_metadata)
|
||||
if 'next_results' in metadata:
|
||||
next_results = urlsplit(metadata['next_results'])
|
||||
params = dict(parse_qsl(next_results.query))
|
||||
else:
|
||||
since_id = content[0]['id_str']
|
||||
params['since_id'] = (int(since_id) - 1)
|
||||
# No more results
|
||||
raise StopIteration
|
||||
else:
|
||||
# Twitter gives tweets in reverse chronological order:
|
||||
params['max_id'] = str(int(content[-1]['id_str']) - 1)
|
||||
elif function.iter_mode == 'cursor':
|
||||
params['cursor'] = content['next_cursor_str']
|
||||
except (TypeError, ValueError): # pragma: no cover
|
||||
raise TwythonError('Unable to generate next page of search \
|
||||
results, `page` is not a number.')
|
||||
except (KeyError, AttributeError): #pragma no cover
|
||||
raise TwythonError('Unable to generate next page of search \
|
||||
results, content has unexpected structure.')
|
||||
|
||||
@staticmethod
|
||||
def unicode2utf8(text):
|
||||
@@ -587,6 +602,8 @@ class Twython(EndpointsMixin, object):
|
||||
|
||||
if display_text_start <= temp['start'] <= display_text_end:
|
||||
temp['replacement'] = mention_html
|
||||
temp['start'] -= display_text_start
|
||||
temp['end'] -= display_text_start
|
||||
entities.append(temp)
|
||||
else:
|
||||
# Make the '@username' at the start, before
|
||||
@@ -598,8 +615,8 @@ class Twython(EndpointsMixin, object):
|
||||
if 'hashtags' in tweet['entities']:
|
||||
for entity in tweet['entities']['hashtags']:
|
||||
temp = {}
|
||||
temp['start'] = entity['indices'][0]
|
||||
temp['end'] = entity['indices'][1]
|
||||
temp['start'] = entity['indices'][0] - display_text_start
|
||||
temp['end'] = entity['indices'][1] - display_text_start
|
||||
|
||||
url_html = '<a href="https://twitter.com/search?q=%%23%(hashtag)s" class="twython-hashtag">#%(hashtag)s</a>' % {'hashtag': entity['text']}
|
||||
|
||||
@@ -610,8 +627,8 @@ class Twython(EndpointsMixin, object):
|
||||
if 'symbols' in tweet['entities']:
|
||||
for entity in tweet['entities']['symbols']:
|
||||
temp = {}
|
||||
temp['start'] = entity['indices'][0]
|
||||
temp['end'] = entity['indices'][1]
|
||||
temp['start'] = entity['indices'][0] - display_text_start
|
||||
temp['end'] = entity['indices'][1] - display_text_start
|
||||
|
||||
url_html = '<a href="https://twitter.com/search?q=%%24%(symbol)s" class="twython-symbol">$%(symbol)s</a>' % {'symbol': entity['text']}
|
||||
|
||||
@@ -622,8 +639,8 @@ class Twython(EndpointsMixin, object):
|
||||
if 'urls' in tweet['entities']:
|
||||
for entity in tweet['entities']['urls']:
|
||||
temp = {}
|
||||
temp['start'] = entity['indices'][0]
|
||||
temp['end'] = entity['indices'][1]
|
||||
temp['start'] = entity['indices'][0] - display_text_start
|
||||
temp['end'] = entity['indices'][1] - display_text_start
|
||||
|
||||
if use_display_url and entity.get('display_url') and not use_expanded_url:
|
||||
shown_url = entity['display_url']
|
||||
@@ -640,26 +657,30 @@ class Twython(EndpointsMixin, object):
|
||||
else:
|
||||
suffix_text = suffix_text.replace(orig_tweet_text[temp['start']:temp['end']], url_html)
|
||||
|
||||
if 'media' in tweet['entities']:
|
||||
for entity in tweet['entities']['media']:
|
||||
temp = {}
|
||||
temp['start'] = entity['indices'][0]
|
||||
temp['end'] = entity['indices'][1]
|
||||
if 'media' in tweet['entities'] and len(tweet['entities']['media']) > 0:
|
||||
# We just link to the overall URL for the tweet's media,
|
||||
# rather than to each individual item.
|
||||
# So, we get the URL from the first media item:
|
||||
entity = tweet['entities']['media'][0]
|
||||
|
||||
if use_display_url and entity.get('display_url') and not use_expanded_url:
|
||||
shown_url = entity['display_url']
|
||||
elif use_expanded_url and entity.get('expanded_url'):
|
||||
shown_url = entity['expanded_url']
|
||||
else:
|
||||
shown_url = entity['url']
|
||||
temp = {}
|
||||
temp['start'] = entity['indices'][0]
|
||||
temp['end'] = entity['indices'][1]
|
||||
|
||||
url_html = '<a href="%s" class="twython-media">%s</a>' % (entity['url'], shown_url)
|
||||
if use_display_url and entity.get('display_url') and not use_expanded_url:
|
||||
shown_url = entity['display_url']
|
||||
elif use_expanded_url and entity.get('expanded_url'):
|
||||
shown_url = entity['expanded_url']
|
||||
else:
|
||||
shown_url = entity['url']
|
||||
|
||||
if display_text_start <= temp['start'] <= display_text_end:
|
||||
temp['replacement'] = url_html
|
||||
entities.append(temp)
|
||||
else:
|
||||
suffix_text = suffix_text.replace(orig_tweet_text[temp['start']:temp['end']], url_html)
|
||||
url_html = '<a href="%s" class="twython-media">%s</a>' % (entity['url'], shown_url)
|
||||
|
||||
if display_text_start <= temp['start'] <= display_text_end:
|
||||
temp['replacement'] = url_html
|
||||
entities.append(temp)
|
||||
else:
|
||||
suffix_text = suffix_text.replace(orig_tweet_text[temp['start']:temp['end']], url_html)
|
||||
|
||||
# Now do all the replacements, starting from the end, so that the
|
||||
# start/end indices still work:
|
||||
|
@@ -25,7 +25,7 @@ except ImportError:
|
||||
|
||||
if is_py2:
|
||||
from urllib import urlencode, quote_plus
|
||||
from urlparse import parse_qsl
|
||||
from urlparse import parse_qsl, urlsplit
|
||||
|
||||
str = unicode
|
||||
basestring = basestring
|
||||
@@ -33,7 +33,7 @@ if is_py2:
|
||||
|
||||
|
||||
elif is_py3:
|
||||
from urllib.parse import urlencode, quote_plus, parse_qsl
|
||||
from urllib.parse import urlencode, quote_plus, parse_qsl, urlsplit
|
||||
|
||||
str = str
|
||||
basestring = (str, bytes)
|
||||
|
@@ -10,8 +10,8 @@ as a keyword argument.
|
||||
|
||||
e.g. Twython.retweet(id=12345)
|
||||
|
||||
This map is organized the order functions are documented at:
|
||||
https://dev.twitter.com/docs/api/1.1
|
||||
Official documentation for Twitter API endpoints can be found at:
|
||||
https://developer.twitter.com/en/docs/api-reference-index
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -34,7 +34,7 @@ class EndpointsMixin(object):
|
||||
@screen_name) for the authenticating user.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/get/statuses/mentions_timeline
|
||||
https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-mentions_timeline
|
||||
|
||||
"""
|
||||
return self.get('statuses/mentions_timeline', params=params)
|
||||
@@ -42,9 +42,10 @@ class EndpointsMixin(object):
|
||||
|
||||
def get_user_timeline(self, **params):
|
||||
"""Returns a collection of the most recent Tweets posted by the user
|
||||
indicated by the screen_name or user_id parameters.
|
||||
indicated by the ``screen_name`` or ``user_id`` parameters.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-user_timeline
|
||||
|
||||
"""
|
||||
return self.get('statuses/user_timeline', params=params)
|
||||
@@ -54,7 +55,8 @@ class EndpointsMixin(object):
|
||||
"""Returns a collection of the most recent Tweets and retweets
|
||||
posted by the authenticating user and the users they follow.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/statuses/home_timeline
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-home_timeline
|
||||
|
||||
"""
|
||||
return self.get('statuses/home_timeline', params=params)
|
||||
@@ -64,7 +66,8 @@ class EndpointsMixin(object):
|
||||
"""Returns the most recent tweets authored by the authenticating user
|
||||
that have been retweeted by others.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/statuses/retweets_of_me
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-retweets_of_me
|
||||
|
||||
"""
|
||||
return self.get('statuses/retweets_of_me', params=params)
|
||||
@@ -74,34 +77,38 @@ class EndpointsMixin(object):
|
||||
def get_retweets(self, **params):
|
||||
"""Returns up to 100 of the first retweets of a given tweet.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/statuses/retweets/%3Aid
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-retweet-id
|
||||
|
||||
"""
|
||||
return self.get('statuses/retweets/%s' % params.get('id'),
|
||||
params=params)
|
||||
|
||||
def show_status(self, **params):
|
||||
"""Returns a single Tweet, specified by the id parameter
|
||||
"""Returns a single Tweet, specified by the ``id`` parameter
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/statuses/show/%3Aid
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-show-id
|
||||
|
||||
"""
|
||||
return self.get('statuses/show/%s' % params.get('id'), params=params)
|
||||
|
||||
def lookup_status(self, **params):
|
||||
"""Returns fully-hydrated tweet objects for up to 100 tweets per
|
||||
request, as specified by comma-separated values passed to the id
|
||||
request, as specified by comma-separated values passed to the ``id``
|
||||
parameter.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/statuses/lookup
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-lookup
|
||||
|
||||
"""
|
||||
return self.post('statuses/lookup', params=params)
|
||||
|
||||
def destroy_status(self, **params):
|
||||
"""Destroys the status specified by the required ID parameter
|
||||
"""Destroys the status specified by the required ``id`` parameter
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/statuses/destroy/%3Aid
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-destroy-id
|
||||
|
||||
"""
|
||||
return self.post('statuses/destroy/%s' % params.get('id'))
|
||||
@@ -109,15 +116,17 @@ class EndpointsMixin(object):
|
||||
def update_status(self, **params):
|
||||
"""Updates the authenticating user's current status, also known as tweeting
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/statuses/update
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update
|
||||
|
||||
"""
|
||||
return self.post('statuses/update', params=params)
|
||||
|
||||
def retweet(self, **params):
|
||||
"""Retweets a tweet specified by the id parameter
|
||||
"""Retweets a tweet specified by the ``id`` parameter
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/statuses/retweet/%3Aid
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-retweet-id
|
||||
|
||||
"""
|
||||
return self.post('statuses/retweet/%s' % params.get('id'))
|
||||
@@ -127,7 +136,7 @@ class EndpointsMixin(object):
|
||||
for upload. In other words, it creates a Tweet with a picture attached.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/post/statuses/update_with_media
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-statuses-update_with_media
|
||||
|
||||
"""
|
||||
warnings.warn(
|
||||
@@ -140,12 +149,13 @@ class EndpointsMixin(object):
|
||||
def upload_media(self, **params):
|
||||
"""Uploads media file to Twitter servers. The file will be available to be attached
|
||||
to a status for 60 minutes. To attach to a update, pass a list of returned media ids
|
||||
to the 'update_status' method using the 'media_ids' param.
|
||||
to the :meth:`update_status` method using the ``media_ids`` param.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/rest/reference/post/media/upload
|
||||
https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload
|
||||
|
||||
"""
|
||||
# https://dev.twitter.com/rest/reference/get/media/upload-status
|
||||
# https://developer.twitter.com/en/docs/media/upload-media/api-reference/get-media-upload-status
|
||||
if params and params.get('command', '') == 'STATUS':
|
||||
return self.get('https://upload.twitter.com/1.1/media/upload.json', params=params)
|
||||
|
||||
@@ -153,7 +163,10 @@ class EndpointsMixin(object):
|
||||
|
||||
def create_metadata(self, **params):
|
||||
""" Adds metadata to a media element, such as image descriptions for visually impaired.
|
||||
Docs: https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create
|
||||
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create
|
||||
|
||||
"""
|
||||
params = json.dumps(params)
|
||||
return self.post("https://upload.twitter.com/1.1/media/metadata/create.json", params=params)
|
||||
@@ -161,7 +174,7 @@ class EndpointsMixin(object):
|
||||
def upload_video(self, media, media_type, media_category=None, size=None, check_progress=False):
|
||||
"""Uploads video file to Twitter servers in chunks. The file will be available to be attached
|
||||
to a status for 60 minutes. To attach to a update, pass a list of returned media ids
|
||||
to the 'update_status' method using the 'media_ids' param.
|
||||
to the :meth:`update_status` method using the ``media_ids`` param.
|
||||
|
||||
Upload happens in 3 stages:
|
||||
- INIT call with size of media to be uploaded(in bytes). If this is more than 15mb, twitter will return error.
|
||||
@@ -171,7 +184,8 @@ class EndpointsMixin(object):
|
||||
Twitter media upload api expects each chunk to be not more than 5mb. We are sending chunk of 1mb each.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/rest/public/uploading-media#chunkedupload
|
||||
https://developer.twitter.com/en/docs/media/upload-media/uploading-media/chunked-media-upload
|
||||
|
||||
"""
|
||||
upload_url = 'https://upload.twitter.com/1.1/media/upload.json'
|
||||
if not size:
|
||||
@@ -216,7 +230,7 @@ class EndpointsMixin(object):
|
||||
|
||||
response = self.post(upload_url, params=params)
|
||||
|
||||
# Only get the status if explicity asked to
|
||||
# Only get the status if explicity asked to
|
||||
# Default to False
|
||||
if check_progress:
|
||||
|
||||
@@ -250,16 +264,18 @@ class EndpointsMixin(object):
|
||||
"""Returns information allowing the creation of an embedded
|
||||
representation of a Tweet on third party sites.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/statuses/oembed
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-oembed
|
||||
|
||||
"""
|
||||
return self.get('statuses/oembed', params=params)
|
||||
|
||||
def get_retweeters_ids(self, **params):
|
||||
"""Returns a collection of up to 100 user IDs belonging to users who
|
||||
have retweeted the tweet specified by the id parameter.
|
||||
have retweeted the tweet specified by the ``id`` parameter.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/statuses/retweeters/ids
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-retweeters-ids
|
||||
|
||||
"""
|
||||
return self.get('statuses/retweeters/ids', params=params)
|
||||
@@ -270,7 +286,8 @@ class EndpointsMixin(object):
|
||||
def search(self, **params):
|
||||
"""Returns a collection of relevant Tweets matching a specified query.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/search/tweets
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets
|
||||
|
||||
"""
|
||||
return self.get('search/tweets', params=params)
|
||||
@@ -282,7 +299,8 @@ class EndpointsMixin(object):
|
||||
def get_direct_messages(self, **params):
|
||||
"""Returns the 20 most recent direct messages sent to the authenticating user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/direct_messages
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/list-events
|
||||
|
||||
"""
|
||||
return self.get('direct_messages/events/list', params=params)
|
||||
@@ -291,36 +309,40 @@ class EndpointsMixin(object):
|
||||
def get_sent_messages(self, **params):
|
||||
"""Returns the 20 most recent direct messages sent by the authenticating user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/direct_messages/sent
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/get-sent-message
|
||||
|
||||
"""
|
||||
return self.get('direct_messages/sent', params=params)
|
||||
get_sent_messages.iter_mode = 'id'
|
||||
|
||||
def get_direct_message(self, **params):
|
||||
"""Returns a single direct message, specified by an id parameter.
|
||||
"""Returns a single direct message, specified by an ``id`` parameter.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/direct_messages/show
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/get-event
|
||||
|
||||
"""
|
||||
return self.get('direct_messages/events/show', params=params)
|
||||
|
||||
def destroy_direct_message(self, **params):
|
||||
"""Destroys the direct message specified in the required id parameter
|
||||
"""Destroys the direct message specified in the required ``id`` parameter
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/direct_messages/destroy
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/delete-message-event
|
||||
|
||||
"""
|
||||
return self.post('direct_messages/destroy', params=params)
|
||||
return self.delete('direct_messages/events/destroy', params=params)
|
||||
|
||||
def send_direct_message(self, **params):
|
||||
"""Sends a new direct message to the specified user from the
|
||||
authenticating user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/direct_messages/new
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/new-event
|
||||
|
||||
"""
|
||||
return self.post('direct_messages/events/new', params=params, encode_json=True)
|
||||
return self.post('direct_messages/events/new', params=params, json_encoded=True)
|
||||
|
||||
# Friends & Followers
|
||||
def get_user_ids_of_blocked_retweets(self, **params):
|
||||
@@ -328,7 +350,7 @@ class EndpointsMixin(object):
|
||||
user does not want to receive retweets from.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/get/friendships/no_retweets/ids
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-no_retweets-ids
|
||||
|
||||
"""
|
||||
return self.get('friendships/no_retweets/ids', params=params)
|
||||
@@ -337,7 +359,8 @@ class EndpointsMixin(object):
|
||||
"""Returns a cursored collection of user IDs for every user the
|
||||
specified user is following (otherwise known as their "friends").
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/friends/ids
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-ids
|
||||
|
||||
"""
|
||||
return self.get('friends/ids', params=params)
|
||||
@@ -348,7 +371,8 @@ class EndpointsMixin(object):
|
||||
"""Returns a cursored collection of user IDs for every user
|
||||
following the specified user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/followers/ids
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-ids
|
||||
|
||||
"""
|
||||
return self.get('followers/ids', params=params)
|
||||
@@ -357,9 +381,10 @@ class EndpointsMixin(object):
|
||||
|
||||
def lookup_friendships(self, **params):
|
||||
"""Returns the relationships of the authenticating user to the
|
||||
comma-separated list of up to 100 screen_names or user_ids provided.
|
||||
comma-separated list of up to 100 ``screen_names`` or ``user_ids`` provided.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/friendships/lookup
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-lookup
|
||||
|
||||
"""
|
||||
return self.get('friendships/lookup', params=params)
|
||||
@@ -368,7 +393,8 @@ class EndpointsMixin(object):
|
||||
"""Returns a collection of numeric IDs for every user who has a
|
||||
pending request to follow the authenticating user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/friendships/incoming
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-incoming
|
||||
|
||||
"""
|
||||
return self.get('friendships/incoming', params=params)
|
||||
@@ -379,7 +405,8 @@ class EndpointsMixin(object):
|
||||
"""Returns a collection of numeric IDs for every protected user for
|
||||
whom the authenticating user has a pending follow request.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/friendships/outgoing
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-outgoing
|
||||
|
||||
"""
|
||||
return self.get('friendships/outgoing', params=params)
|
||||
@@ -388,18 +415,20 @@ class EndpointsMixin(object):
|
||||
|
||||
def create_friendship(self, **params):
|
||||
"""Allows the authenticating users to follow the user specified
|
||||
in the ID parameter.
|
||||
in the ``id`` parameter.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/friendships/create
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-create
|
||||
|
||||
"""
|
||||
return self.post('friendships/create', params=params)
|
||||
|
||||
def destroy_friendship(self, **params):
|
||||
"""Allows the authenticating user to unfollow the user specified
|
||||
in the ID parameter.
|
||||
in the ``id`` parameter.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/friendships/destroy
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-destroy
|
||||
|
||||
"""
|
||||
return self.post('friendships/destroy', params=params)
|
||||
@@ -408,7 +437,8 @@ class EndpointsMixin(object):
|
||||
"""Allows one to enable or disable retweets and device notifications
|
||||
from the specified user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/friendships/update
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/post-friendships-update
|
||||
|
||||
"""
|
||||
return self.post('friendships/update', params=params)
|
||||
@@ -417,7 +447,8 @@ class EndpointsMixin(object):
|
||||
"""Returns detailed information about the relationship between two
|
||||
arbitrary users.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/friendships/show
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friendships-show
|
||||
|
||||
"""
|
||||
return self.get('friendships/show', params=params)
|
||||
@@ -426,7 +457,8 @@ class EndpointsMixin(object):
|
||||
"""Returns a cursored collection of user objects for every user the
|
||||
specified user is following (otherwise known as their "friends").
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/friends/list
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-friends-list
|
||||
|
||||
"""
|
||||
return self.get('friends/list', params=params)
|
||||
@@ -437,7 +469,8 @@ class EndpointsMixin(object):
|
||||
"""Returns a cursored collection of user objects for users
|
||||
following the specified user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/followers/list
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-followers-list
|
||||
|
||||
"""
|
||||
return self.get('followers/list', params=params)
|
||||
@@ -449,7 +482,8 @@ class EndpointsMixin(object):
|
||||
"""Returns settings (including current trend, geo and sleep time
|
||||
information) for the authenticating user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/account/settings
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-settings
|
||||
|
||||
"""
|
||||
return self.get('account/settings', params=params)
|
||||
@@ -460,7 +494,7 @@ class EndpointsMixin(object):
|
||||
code and an error message if not.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/get/account/verify_credentials
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials
|
||||
|
||||
"""
|
||||
return self.get('account/verify_credentials', params=params)
|
||||
@@ -468,7 +502,8 @@ class EndpointsMixin(object):
|
||||
def update_account_settings(self, **params):
|
||||
"""Updates the authenticating user's settings.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/account/settings
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-settings
|
||||
|
||||
"""
|
||||
return self.post('account/settings', params=params)
|
||||
@@ -486,7 +521,8 @@ class EndpointsMixin(object):
|
||||
"""Sets values that users are able to set under the "Account" tab of their
|
||||
settings page.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/account/update_profile
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile
|
||||
|
||||
"""
|
||||
return self.post('account/update_profile', params=params)
|
||||
@@ -495,26 +531,35 @@ class EndpointsMixin(object):
|
||||
"""Updates the authenticating user's profile background image.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/post/account/update_profile_background_image
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_background_image
|
||||
|
||||
"""
|
||||
return self.post('account/update_profile_banner', params=params)
|
||||
|
||||
def update_profile_colors(self, **params):
|
||||
def update_profile_colors(self, **params): # pragma: no cover
|
||||
"""Sets one or more hex values that control the color scheme of the
|
||||
authenticating user's profile page on twitter.com.
|
||||
|
||||
This method is deprecated, replaced by the ``profile_link_color``
|
||||
parameter to :meth:`update_profile`.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/post/account/update_profile_colors
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile
|
||||
|
||||
"""
|
||||
warnings.warn(
|
||||
'This method is deprecated. You should use the'
|
||||
' profile_link_color parameter in Twython.update_profile instead.',
|
||||
TwythonDeprecationWarning,
|
||||
stacklevel=2
|
||||
)
|
||||
return self.post('account/update_profile_colors', params=params)
|
||||
|
||||
def update_profile_image(self, **params): # pragma: no cover
|
||||
"""Updates the authenticating user's profile image.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/post/account/update_profile_image
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_image
|
||||
|
||||
"""
|
||||
return self.post('account/update_profile_image', params=params)
|
||||
@@ -523,7 +568,8 @@ class EndpointsMixin(object):
|
||||
"""Returns a collection of user objects that the authenticating user
|
||||
is blocking.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/blocks/list
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-blocks-list
|
||||
|
||||
"""
|
||||
return self.get('blocks/list', params=params)
|
||||
@@ -533,7 +579,8 @@ class EndpointsMixin(object):
|
||||
def list_block_ids(self, **params):
|
||||
"""Returns an array of numeric user ids the authenticating user is blocking.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/blocks/ids
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-blocks-ids
|
||||
|
||||
"""
|
||||
return self.get('blocks/ids', params=params)
|
||||
@@ -543,35 +590,39 @@ class EndpointsMixin(object):
|
||||
def create_block(self, **params):
|
||||
"""Blocks the specified user from following the authenticating user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/blocks/create
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-blocks-create
|
||||
|
||||
"""
|
||||
return self.post('blocks/create', params=params)
|
||||
|
||||
def destroy_block(self, **params):
|
||||
"""Un-blocks the user specified in the ID parameter for the
|
||||
"""Un-blocks the user specified in the ``id`` parameter for the
|
||||
authenticating user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/blocks/destroy
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-blocks-destroy
|
||||
|
||||
"""
|
||||
return self.post('blocks/destroy', params=params)
|
||||
|
||||
def lookup_user(self, **params):
|
||||
"""Returns fully-hydrated user objects for up to 100 users per request,
|
||||
as specified by comma-separated values passed to the user_id and/or
|
||||
screen_name parameters.
|
||||
as specified by comma-separated values passed to the ``user_id`` and/or
|
||||
``screen_name`` parameters.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/users/lookup
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-lookup
|
||||
|
||||
"""
|
||||
return self.get('users/lookup', params=params)
|
||||
|
||||
def show_user(self, **params):
|
||||
"""Returns a variety of information about the user specified by the
|
||||
required user_id or screen_name parameter.
|
||||
required ``user_id`` or ``screen_name`` parameter.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/users/show
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-show
|
||||
|
||||
"""
|
||||
return self.get('users/show', params=params)
|
||||
@@ -580,7 +631,8 @@ class EndpointsMixin(object):
|
||||
"""Provides a simple, relevance-based search interface to public user
|
||||
accounts on Twitter.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/users/search
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-search
|
||||
|
||||
"""
|
||||
return self.get('users/search', params=params)
|
||||
@@ -606,7 +658,7 @@ class EndpointsMixin(object):
|
||||
Returns HTTP 200 upon success.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/post/account/remove_profile_banner
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-remove_profile_banner
|
||||
|
||||
"""
|
||||
return self.post('account/remove_profile_banner', params=params)
|
||||
@@ -615,7 +667,7 @@ class EndpointsMixin(object):
|
||||
"""Uploads a profile banner on behalf of the authenticating user.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/post/account/update_profile_banner
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/post-account-update_profile_banner
|
||||
|
||||
"""
|
||||
return self.post('account/update_profile_background_image',
|
||||
@@ -625,7 +677,8 @@ class EndpointsMixin(object):
|
||||
"""Returns a map of the available size variations of the specified
|
||||
user's profile banner.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/users/profile_banner
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-users-profile_banner
|
||||
|
||||
"""
|
||||
return self.get('users/profile_banner', params=params)
|
||||
@@ -634,7 +687,8 @@ class EndpointsMixin(object):
|
||||
"""Returns a collection of user objects that the authenticating user
|
||||
is muting.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/mutes/users/list
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-mutes-users-list
|
||||
|
||||
"""
|
||||
return self.get('mutes/users/list', params=params)
|
||||
@@ -645,7 +699,8 @@ class EndpointsMixin(object):
|
||||
"""Returns an array of numeric user ids the authenticating user
|
||||
is muting.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/mutes/users/ids
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/get-mutes-users-ids
|
||||
|
||||
"""
|
||||
return self.get('mutes/users/ids', params=params)
|
||||
@@ -656,16 +711,18 @@ class EndpointsMixin(object):
|
||||
"""Mutes the specified user, preventing their tweets appearing
|
||||
in the authenticating user's timeline.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/mutes/users/create
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-mutes-users-create
|
||||
|
||||
"""
|
||||
return self.post('mutes/users/create', params=params)
|
||||
|
||||
def destroy_mute(self, **params):
|
||||
"""Un-mutes the user specified in the user or ID parameter for
|
||||
"""Un-mutes the user specified in the user or ``id`` parameter for
|
||||
the authenticating user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/mutes/users/destroy
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-mutes-users-destroy
|
||||
|
||||
"""
|
||||
return self.post('mutes/users/destroy', params=params)
|
||||
@@ -675,7 +732,7 @@ class EndpointsMixin(object):
|
||||
"""Access the users in a given category of the Twitter suggested user list.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/get/users/suggestions/%3Aslug
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions-slug
|
||||
|
||||
"""
|
||||
return self.get('users/suggestions/%s' % params.get('slug'),
|
||||
@@ -684,7 +741,8 @@ class EndpointsMixin(object):
|
||||
def get_user_suggestions(self, **params):
|
||||
"""Access to Twitter's suggested user list.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/users/suggestions
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions
|
||||
|
||||
"""
|
||||
return self.get('users/suggestions', params=params)
|
||||
@@ -695,7 +753,7 @@ class EndpointsMixin(object):
|
||||
user.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/get/users/suggestions/%3Aslug/members
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-suggestions-slug-members
|
||||
|
||||
"""
|
||||
return self.get('users/suggestions/%s/members' % params.get('slug'),
|
||||
@@ -706,26 +764,29 @@ class EndpointsMixin(object):
|
||||
"""Returns the 20 most recent Tweets favorited by the authenticating
|
||||
or specified user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/favorites/list
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-favorites-list
|
||||
|
||||
"""
|
||||
return self.get('favorites/list', params=params)
|
||||
get_favorites.iter_mode = 'id'
|
||||
|
||||
def destroy_favorite(self, **params):
|
||||
"""Un-favorites the status specified in the ID parameter as the
|
||||
"""Un-favorites the status specified in the ``id`` parameter as the
|
||||
authenticating user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/favorites/destroy
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-favorites-destroy
|
||||
|
||||
"""
|
||||
return self.post('favorites/destroy', params=params)
|
||||
|
||||
def create_favorite(self, **params):
|
||||
"""Favorites the status specified in the ID parameter as the
|
||||
"""Favorites the status specified in the ``id`` parameter as the
|
||||
authenticating user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/favorites/create
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-favorites-create
|
||||
|
||||
"""
|
||||
return self.post('favorites/create', params=params)
|
||||
@@ -735,7 +796,8 @@ class EndpointsMixin(object):
|
||||
"""Returns all lists the authenticating or specified user subscribes to,
|
||||
including their own.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/lists/list
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-list
|
||||
|
||||
"""
|
||||
return self.get('lists/list', params=params)
|
||||
@@ -743,7 +805,8 @@ class EndpointsMixin(object):
|
||||
def get_list_statuses(self, **params):
|
||||
"""Returns a timeline of tweets authored by members of the specified list.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/lists/statuses
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-statuses
|
||||
|
||||
"""
|
||||
return self.get('lists/statuses', params=params)
|
||||
@@ -752,7 +815,8 @@ class EndpointsMixin(object):
|
||||
def delete_list_member(self, **params):
|
||||
"""Removes the specified member from the list.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/lists/members/destroy
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-destroy
|
||||
|
||||
"""
|
||||
return self.post('lists/members/destroy', params=params)
|
||||
@@ -760,7 +824,8 @@ class EndpointsMixin(object):
|
||||
def get_list_memberships(self, **params):
|
||||
"""Returns the lists the specified user has been added to.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/lists/memberships
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-memberships
|
||||
|
||||
"""
|
||||
return self.get('lists/memberships', params=params)
|
||||
@@ -770,7 +835,8 @@ class EndpointsMixin(object):
|
||||
def get_list_subscribers(self, **params):
|
||||
"""Returns the subscribers of the specified list.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/lists/subscribers
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscribers
|
||||
|
||||
"""
|
||||
return self.get('lists/subscribers', params=params)
|
||||
@@ -781,7 +847,7 @@ class EndpointsMixin(object):
|
||||
"""Subscribes the authenticated user to the specified list.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/post/lists/subscribers/create
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-subscribers-create
|
||||
|
||||
"""
|
||||
return self.post('lists/subscribers/create', params=params)
|
||||
@@ -789,7 +855,8 @@ class EndpointsMixin(object):
|
||||
def is_list_subscriber(self, **params):
|
||||
"""Check if the specified user is a subscriber of the specified list.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/lists/subscribers/show
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscribers-show
|
||||
|
||||
"""
|
||||
return self.get('lists/subscribers/show', params=params)
|
||||
@@ -798,7 +865,7 @@ class EndpointsMixin(object):
|
||||
"""Unsubscribes the authenticated user from the specified list.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/post/lists/subscribers/destroy
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-subscribers-destroy
|
||||
|
||||
"""
|
||||
return self.post('lists/subscribers/destroy', params=params)
|
||||
@@ -808,7 +875,7 @@ class EndpointsMixin(object):
|
||||
list of member ids or screen names.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/post/lists/members/create_all
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-create_all
|
||||
|
||||
"""
|
||||
return self.post('lists/members/create_all', params=params)
|
||||
@@ -816,7 +883,8 @@ class EndpointsMixin(object):
|
||||
def is_list_member(self, **params):
|
||||
"""Check if the specified user is a member of the specified list.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/lists/members/show
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-members-show
|
||||
|
||||
"""
|
||||
return self.get('lists/members/show', params=params)
|
||||
@@ -824,7 +892,8 @@ class EndpointsMixin(object):
|
||||
def get_list_members(self, **params):
|
||||
"""Returns the members of the specified list.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/lists/members
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-members
|
||||
|
||||
"""
|
||||
return self.get('lists/members', params=params)
|
||||
@@ -834,7 +903,8 @@ class EndpointsMixin(object):
|
||||
def add_list_member(self, **params):
|
||||
"""Add a member to a list.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/lists/members/create
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-create
|
||||
|
||||
"""
|
||||
return self.post('lists/members/create', params=params)
|
||||
@@ -842,7 +912,8 @@ class EndpointsMixin(object):
|
||||
def delete_list(self, **params):
|
||||
"""Deletes the specified list.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/lists/destroy
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-destroy
|
||||
|
||||
"""
|
||||
return self.post('lists/destroy', params=params)
|
||||
@@ -850,7 +921,8 @@ class EndpointsMixin(object):
|
||||
def update_list(self, **params):
|
||||
"""Updates the specified list.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/lists/update
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-update
|
||||
|
||||
"""
|
||||
return self.post('lists/update', params=params)
|
||||
@@ -858,7 +930,8 @@ class EndpointsMixin(object):
|
||||
def create_list(self, **params):
|
||||
"""Creates a new list for the authenticated user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/lists/create
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-create
|
||||
|
||||
"""
|
||||
return self.post('lists/create', params=params)
|
||||
@@ -866,7 +939,8 @@ class EndpointsMixin(object):
|
||||
def get_specific_list(self, **params):
|
||||
"""Returns the specified list.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/lists/show
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-show
|
||||
|
||||
"""
|
||||
return self.get('lists/show', params=params)
|
||||
@@ -874,7 +948,8 @@ class EndpointsMixin(object):
|
||||
def get_list_subscriptions(self, **params):
|
||||
"""Obtain a collection of the lists the specified user is subscribed to.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/lists/subscriptions
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-subscriptions
|
||||
|
||||
"""
|
||||
return self.get('lists/subscriptions', params=params)
|
||||
@@ -886,7 +961,7 @@ class EndpointsMixin(object):
|
||||
comma-separated list of member ids or screen names.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/post/lists/members/destroy_all
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-members-destroy_all
|
||||
|
||||
"""
|
||||
return self.post('lists/members/destroy_all', params=params)
|
||||
@@ -894,7 +969,8 @@ class EndpointsMixin(object):
|
||||
def show_owned_lists(self, **params):
|
||||
"""Returns the lists owned by the specified Twitter user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/lists/ownerships
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-ownerships
|
||||
|
||||
"""
|
||||
return self.get('lists/ownerships', params=params)
|
||||
@@ -905,16 +981,17 @@ class EndpointsMixin(object):
|
||||
def get_saved_searches(self, **params):
|
||||
"""Returns the authenticated user's saved search queries.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/saved_searches/list
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/tweets/search/api-reference/get-saved_searches-list
|
||||
|
||||
"""
|
||||
return self.get('saved_searches/list', params=params)
|
||||
|
||||
def show_saved_search(self, **params):
|
||||
"""Retrieve the information for the saved search represented by the given id.
|
||||
"""Retrieve the information for the saved search represented by the given ``id``.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/get/saved_searches/show/%3Aid
|
||||
https://developer.twitter.com/en/docs/tweets/search/api-reference/get-saved_searches-show-id
|
||||
|
||||
"""
|
||||
return self.get('saved_searches/show/%s' % params.get('id'),
|
||||
@@ -923,7 +1000,8 @@ class EndpointsMixin(object):
|
||||
def create_saved_search(self, **params):
|
||||
"""Create a new saved search for the authenticated user.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/saved_searches/create
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-mutes-users-create
|
||||
|
||||
"""
|
||||
return self.post('saved_searches/create', params=params)
|
||||
@@ -932,7 +1010,7 @@ class EndpointsMixin(object):
|
||||
"""Destroys a saved search for the authenticating user.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/post/saved_searches/destroy/%3Aid
|
||||
https://developer.twitter.com/en/docs/tweets/search/api-reference/post-saved_searches-destroy-id
|
||||
|
||||
"""
|
||||
return self.post('saved_searches/destroy/%s' % params.get('id'),
|
||||
@@ -942,7 +1020,8 @@ class EndpointsMixin(object):
|
||||
def get_geo_info(self, **params):
|
||||
"""Returns all the information about a known place.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/geo/id/%3Aplace_id
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/geo/place-information/api-reference/get-geo-id-place_id
|
||||
|
||||
"""
|
||||
return self.get('geo/id/%s' % params.get('place_id'), params=params)
|
||||
@@ -951,7 +1030,8 @@ class EndpointsMixin(object):
|
||||
"""Given a latitude and a longitude, searches for up to 20 places
|
||||
that can be used as a place_id when updating a status.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/geo/reverse_geocode
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/geo/places-near-location/api-reference/get-geo-reverse_geocode
|
||||
|
||||
"""
|
||||
return self.get('geo/reverse_geocode', params=params)
|
||||
@@ -959,7 +1039,8 @@ class EndpointsMixin(object):
|
||||
def search_geo(self, **params):
|
||||
"""Search for places that can be attached to a statuses/update.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/geo/search
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/geo/places-near-location/api-reference/get-geo-search
|
||||
|
||||
"""
|
||||
return self.get('geo/search', params=params)
|
||||
@@ -985,7 +1066,8 @@ class EndpointsMixin(object):
|
||||
"""Returns the top 10 trending topics for a specific WOEID, if
|
||||
trending information is available for it.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/trends/place
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/trends/trends-for-location/api-reference/get-trends-place
|
||||
|
||||
"""
|
||||
return self.get('trends/place', params=params)
|
||||
@@ -993,7 +1075,8 @@ class EndpointsMixin(object):
|
||||
def get_available_trends(self, **params):
|
||||
"""Returns the locations that Twitter has trending topic information for.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/trends/available
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-available
|
||||
|
||||
"""
|
||||
return self.get('trends/available', params=params)
|
||||
@@ -1002,7 +1085,8 @@ class EndpointsMixin(object):
|
||||
"""Returns the locations that Twitter has trending topic information
|
||||
for, closest to a specified location.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/trends/closest
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-closest
|
||||
|
||||
"""
|
||||
return self.get('trends/closest', params=params)
|
||||
@@ -1011,7 +1095,8 @@ class EndpointsMixin(object):
|
||||
def report_spam(self, **params): # pragma: no cover
|
||||
"""Report the specified user as a spam account to Twitter.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/users/report_spam
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/accounts-and-users/mute-block-report-users/api-reference/post-users-report_spam
|
||||
|
||||
"""
|
||||
return self.post('users/report_spam', params=params)
|
||||
@@ -1021,7 +1106,8 @@ class EndpointsMixin(object):
|
||||
"""Allows a registered application to revoke an issued OAuth 2 Bearer
|
||||
Token by presenting its client credentials.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/post/oauth2/invalidate_token
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/basics/authentication/api-reference/invalidate_token
|
||||
|
||||
"""
|
||||
return self.post('oauth2/invalidate_token', params=params)
|
||||
@@ -1030,7 +1116,8 @@ class EndpointsMixin(object):
|
||||
def get_twitter_configuration(self, **params):
|
||||
"""Returns the current configuration used by Twitter
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/help/configuration
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/developer-utilities/configuration/api-reference/get-help-configuration
|
||||
|
||||
"""
|
||||
return self.get('help/configuration', params=params)
|
||||
@@ -1039,7 +1126,8 @@ class EndpointsMixin(object):
|
||||
"""Returns the list of languages supported by Twitter along with
|
||||
their ISO 639-1 code.
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/help/languages
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/developer-utilities/supported-languages/api-reference/get-help-languages
|
||||
|
||||
"""
|
||||
return self.get('help/languages', params=params)
|
||||
@@ -1047,7 +1135,8 @@ class EndpointsMixin(object):
|
||||
def get_privacy_policy(self, **params):
|
||||
"""Returns Twitter's Privacy Policy
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/help/privacy
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/developer-utilities/privacy-policy/api-reference/get-help-privacy
|
||||
|
||||
"""
|
||||
return self.get('help/privacy', params=params)
|
||||
@@ -1055,7 +1144,8 @@ class EndpointsMixin(object):
|
||||
def get_tos(self, **params):
|
||||
"""Return the Twitter Terms of Service
|
||||
|
||||
Docs: https://dev.twitter.com/docs/api/1.1/get/help/tos
|
||||
Docs:
|
||||
https://developer.twitter.com/en/docs/developer-utilities/terms-of-service/api-reference/get-help-tos
|
||||
|
||||
"""
|
||||
return self.get('help/tos', params=params)
|
||||
@@ -1065,13 +1155,13 @@ class EndpointsMixin(object):
|
||||
specified resource families.
|
||||
|
||||
Docs:
|
||||
https://dev.twitter.com/docs/api/1.1/get/application/rate_limit_status
|
||||
https://developer.twitter.com/en/docs/developer-utilities/rate-limit-status/api-reference/get-application-rate_limit_status
|
||||
|
||||
"""
|
||||
return self.get('application/rate_limit_status', params=params)
|
||||
|
||||
|
||||
# from https://dev.twitter.com/docs/error-codes-responses
|
||||
# from https://developer.twitter.com/en/docs/ads/general/guides/response-codes
|
||||
TWITTER_HTTP_STATUS_CODE = {
|
||||
200: ('OK', 'Success!'),
|
||||
304: ('Not Modified', 'There was no new data to return.'),
|
||||
|
@@ -169,9 +169,9 @@ class TwythonStreamer(object):
|
||||
Returns True if other handlers for this message should be invoked.
|
||||
|
||||
Feel free to override this to handle your streaming data how you
|
||||
want it handled.
|
||||
See https://dev.twitter.com/docs/streaming-apis/messages for messages
|
||||
sent along in stream responses.
|
||||
want it handled. See
|
||||
https://developer.twitter.com/en/docs/tweets/filter-realtime/guides/streaming-message-types
|
||||
for messages sent along in stream responses.
|
||||
|
||||
:param data: data recieved from the stream
|
||||
:type data: dict
|
||||
|
@@ -44,9 +44,10 @@ class TwythonStreamerTypes(object):
|
||||
class TwythonStreamerTypesStatuses(object):
|
||||
"""Class for different statuses endpoints
|
||||
|
||||
Available so TwythonStreamer.statuses.filter() is available.
|
||||
Just a bit cleaner than TwythonStreamer.statuses_filter(),
|
||||
statuses_sample(), etc. all being single methods in TwythonStreamer
|
||||
Available so :meth:`TwythonStreamer.statuses.filter()` is available.
|
||||
Just a bit cleaner than :meth:`TwythonStreamer.statuses_filter()`,
|
||||
:meth:`statuses_sample()`, etc. all being single methods in
|
||||
:class:`TwythonStreamer`.
|
||||
|
||||
"""
|
||||
def __init__(self, streamer):
|
||||
@@ -59,7 +60,7 @@ class TwythonStreamerTypesStatuses(object):
|
||||
:param \*\*params: Parameters to send with your stream request
|
||||
|
||||
Accepted params found at:
|
||||
https://dev.twitter.com/docs/api/1.1/post/statuses/filter
|
||||
https://developer.twitter.com/en/docs/tweets/filter-realtime/api-reference/post-statuses-filter
|
||||
"""
|
||||
url = 'https://stream.twitter.com/%s/statuses/filter.json' \
|
||||
% self.streamer.api_version
|
||||
@@ -71,7 +72,7 @@ class TwythonStreamerTypesStatuses(object):
|
||||
:param \*\*params: Parameters to send with your stream request
|
||||
|
||||
Accepted params found at:
|
||||
https://dev.twitter.com/docs/api/1.1/get/statuses/sample
|
||||
https://developer.twitter.com/en/docs/tweets/sample-realtime/api-reference/get-statuses-sample
|
||||
"""
|
||||
url = 'https://stream.twitter.com/%s/statuses/sample.json' \
|
||||
% self.streamer.api_version
|
||||
@@ -95,7 +96,7 @@ class TwythonStreamerTypesStatuses(object):
|
||||
:param \*\*params: Parameters to send with your stream request
|
||||
|
||||
Accepted params found at:
|
||||
https://dev.twitter.com/docs/api/1.1/post/statuses/filter
|
||||
https://developer.twitter.com/en/docs/tweets/filter-realtime/api-reference/post-statuses-filter
|
||||
"""
|
||||
self.params = params
|
||||
|
||||
@@ -104,4 +105,4 @@ class TwythonStreamerTypesStatuses(object):
|
||||
|
||||
url = 'https://stream.twitter.com/%s/statuses/filter.json' \
|
||||
% self.streamer.api_version
|
||||
self.streamer._request(url, 'POST', params=self.params)
|
||||
self.streamer._request(url, 'POST', params=self.params)
|
||||
|
@@ -4,6 +4,7 @@ import wx
|
||||
import application
|
||||
import output
|
||||
import config
|
||||
import widgetUtils
|
||||
import baseDialog
|
||||
from multiplatform_widgets import widgets
|
||||
|
||||
@@ -102,14 +103,6 @@ class generalAccount(wx.Panel, baseDialog.BaseWXDialog):
|
||||
sizer.Add(self.au, 0, wx.ALL, 5)
|
||||
self.relative_time = wx.CheckBox(self, wx.ID_ANY, _(U"Relative timestamps"))
|
||||
sizer.Add(self.relative_time, 0, wx.ALL, 5)
|
||||
if application.streaming_lives():
|
||||
apiCallsBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
apiCallsBox.Add(wx.StaticText(self, -1, _(u"API calls (One API call = 200 tweets, two API calls = 400 tweets, etc):")), 0, wx.ALL, 5)
|
||||
self.apiCalls = wx.SpinCtrl(self, wx.ID_ANY)
|
||||
self.apiCalls.SetRange(1, 10)
|
||||
self.apiCalls.SetSize(self.apiCalls.GetBestSize())
|
||||
apiCallsBox.Add(self.apiCalls, 0, wx.ALL, 5)
|
||||
sizer.Add(apiCallsBox, 0, wx.ALL, 5)
|
||||
tweetsPerCallBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
tweetsPerCallBox.Add(wx.StaticText(self, -1, _(u"Items on each API call")), 0, wx.ALL, 5)
|
||||
self.itemsPerApiCall = wx.SpinCtrl(self, wx.ID_ANY)
|
||||
@@ -276,6 +269,9 @@ class sound(wx.Panel):
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
volume = wx.StaticText(self, -1, _(u"Volume"))
|
||||
self.volumeCtrl = wx.Slider(self)
|
||||
# Connect a key handler here to handle volume slider being inverted when moving with up and down arrows.
|
||||
# see https://github.com/manuelcortez/TWBlue/issues/261
|
||||
widgetUtils.connect_event(self.volumeCtrl, widgetUtils.KEYPRESS, self.on_keypress)
|
||||
self.volumeCtrl.SetRange(0, 100)
|
||||
self.volumeCtrl.SetSize(self.volumeCtrl.GetBestSize())
|
||||
volumeBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
@@ -313,6 +309,18 @@ class sound(wx.Panel):
|
||||
sizer.Add(self.indicate_img, 0, wx.ALL, 5)
|
||||
self.SetSizer(sizer)
|
||||
|
||||
def on_keypress(self, event, *args, **kwargs):
|
||||
""" Invert movement of up and down arrow keys when dealing with a wX Slider.
|
||||
See https://github.com/manuelcortez/TWBlue/issues/261
|
||||
and http://trac.wxwidgets.org/ticket/2068
|
||||
"""
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode == wx.WXK_UP:
|
||||
return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()+1)
|
||||
elif keycode == wx.WXK_DOWN:
|
||||
return self.volumeCtrl.SetValue(self.volumeCtrl.GetValue()-1)
|
||||
event.Skip()
|
||||
|
||||
def get(self, control):
|
||||
return getattr(self, control).GetStringSelection()
|
||||
|
||||
|
@@ -113,6 +113,13 @@ class addUserListDialog(listViewer):
|
||||
# self.subscriptors.Disable()
|
||||
# self.members.Disable()
|
||||
self.deleteBtn.Disable()
|
||||
widgetUtils.connect_event(self.lista.list, widgetUtils.KEYPRESS, self.on_keypress)
|
||||
|
||||
def on_keypress(self, event):
|
||||
"""Catch return and execute ok()"""
|
||||
if event.GetKeyCode() == wx.WXK_RETURN:
|
||||
return self.ok()
|
||||
event.Skip()
|
||||
|
||||
def ok(self, *args, **kwargs):
|
||||
self.EndModal(wx.ID_OK)
|
||||
@@ -129,6 +136,13 @@ class removeUserListDialog(listViewer):
|
||||
# self.subscriptors.Disable()
|
||||
# self.members.Disable()
|
||||
self.deleteBtn.Disable()
|
||||
widgetUtils.connect_event(self.lista.list, widgetUtils.KEYPRESS, self.on_keypress)
|
||||
|
||||
def on_keypress(self, event):
|
||||
"""Catch return and execute EndModal()"""
|
||||
if event.GetKeyCode() == wx.WXK_RETURN:
|
||||
return self.EndModal(wx.ID_OK)
|
||||
event.Skip()
|
||||
|
||||
def remove_list():
|
||||
return wx.MessageDialog(None, _("Do you really want to delete this list?"), _("Delete"), wx.YES_NO).ShowModal()
|
||||
|
@@ -298,7 +298,7 @@ class viewTweet(widgetUtils.BaseDialog):
|
||||
def set_title(self, lenght):
|
||||
self.SetTitle(_(u"Tweet - %i characters ") % (lenght,))
|
||||
|
||||
def __init__(self, text, rt_count, favs_count,source, *args, **kwargs):
|
||||
def __init__(self, text, rt_count, favs_count, source, date="", *args, **kwargs):
|
||||
super(viewTweet, self).__init__(None, size=(850,850))
|
||||
panel = wx.Panel(self)
|
||||
label = wx.StaticText(panel, -1, _(u"Tweet"))
|
||||
@@ -339,11 +339,21 @@ class viewTweet(widgetUtils.BaseDialog):
|
||||
sourceBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sourceBox.Add(sourceLabel, 0, wx.ALL, 5)
|
||||
sourceBox.Add(sourceTweet, 0, wx.ALL, 5)
|
||||
dateLabel = wx.StaticText(panel, -1, _(u"Date: "))
|
||||
dateTweet = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE)
|
||||
dc = wx.WindowDC(dateTweet)
|
||||
dc.SetFont(dateTweet.GetFont())
|
||||
(x, y) = dc.GetTextExtent("0"*100)
|
||||
dateTweet.SetSize((x, y))
|
||||
dateBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
dateBox.Add(dateLabel, 0, wx.ALL, 5)
|
||||
dateBox.Add(dateTweet, 0, wx.ALL, 5)
|
||||
infoBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
infoBox.Add(rtBox, 0, wx.ALL, 5)
|
||||
infoBox.Add(favsBox, 0, wx.ALL, 5)
|
||||
infoBox.Add(sourceBox, 0, wx.ALL, 5)
|
||||
mainBox.Add(infoBox, 0, wx.ALL, 5)
|
||||
mainBox.Add(dateBox, 0, wx.ALL, 5)
|
||||
self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize)
|
||||
self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize)
|
||||
self.unshortenButton.Disable()
|
||||
@@ -390,7 +400,7 @@ class viewTweet(widgetUtils.BaseDialog):
|
||||
|
||||
class viewNonTweet(widgetUtils.BaseDialog):
|
||||
|
||||
def __init__(self, text, *args, **kwargs):
|
||||
def __init__(self, text, date="", *args, **kwargs):
|
||||
super(viewNonTweet, self).__init__(None, size=(850,850))
|
||||
self.SetTitle(_(u"View"))
|
||||
panel = wx.Panel(self)
|
||||
@@ -406,6 +416,17 @@ class viewNonTweet(widgetUtils.BaseDialog):
|
||||
textBox.Add(self.text, 1, wx.EXPAND, 5)
|
||||
mainBox = wx.BoxSizer(wx.VERTICAL)
|
||||
mainBox.Add(textBox, 0, wx.ALL, 5)
|
||||
if date != "":
|
||||
dateLabel = wx.StaticText(panel, -1, _(u"Date: "))
|
||||
date = wx.TextCtrl(panel, -1, date, size=wx.DefaultSize, style=wx.TE_READONLY|wx.TE_MULTILINE)
|
||||
dc = wx.WindowDC(date)
|
||||
dc.SetFont(date.GetFont())
|
||||
(x, y) = dc.GetTextExtent("0"*100)
|
||||
date.SetSize((x, y))
|
||||
dateBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
dateBox.Add(dateLabel, 0, wx.ALL, 5)
|
||||
dateBox.Add(date, 0, wx.ALL, 5)
|
||||
mainBox.Add(dateBox, 0, wx.ALL, 5)
|
||||
self.spellcheck = wx.Button(panel, -1, _("Check &spelling..."), size=wx.DefaultSize)
|
||||
self.unshortenButton = wx.Button(panel, -1, _(u"&Expand URL"), size=wx.DefaultSize)
|
||||
self.unshortenButton.Disable()
|
||||
|
@@ -74,6 +74,7 @@ class mainFrame(wx.Frame):
|
||||
self.check_for_updates = help.Append(wx.ID_ANY, _(u"&Check for updates"))
|
||||
self.reportError = help.Append(wx.ID_ANY, _(u"&Report an error"))
|
||||
self.visit_website = help.Append(-1, _(u"{0}'s &website").format(application.name,))
|
||||
self.get_soundpacks = help.Append(-1, _(u"Get soundpacks for TWBlue"))
|
||||
self.about = help.Append(-1, _(u"About &{0}").format(application.name,))
|
||||
|
||||
# Add all to the menu Bar
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{"current_version": "1",
|
||||
{"current_version": "9",
|
||||
"description": "Snapshot version.",
|
||||
"date": "unknown",
|
||||
"downloads":
|
||||
{"Windows32": "https://twblue.es/pubs/snapshot.zip"}}
|
||||
{"Windows32": "https://twblue.es/snapshot.zip"}}
|
Submodule windows-dependencies updated: 814ea75d5d...c80247f5e1
Reference in New Issue
Block a user