mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2025-04-20 09:31:43 -04:00
Sync upstream.
This commit is contained in:
commit
a49c4fa4f1
12
README.md
12
README.md
@ -29,10 +29,10 @@ Although most dependencies can be found in the windows-dependencies directory, w
|
||||
|
||||
#### Dependencies packaged in windows installers
|
||||
|
||||
* [Python,](http://python.org) version 2.7.13
|
||||
* [Python,](http://python.org) version 2.7.14
|
||||
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.
|
||||
* [wxPython](http://www.wxpython.org) for Python 2.7, version 3.0.2.0
|
||||
* [Python windows extensions (pywin32)](http://www.sourceforge.net/projects/pywin32/) for python 2.7, build 220
|
||||
* [Python windows extensions (pywin32)](http://www.sourceforge.net/projects/pywin32/) for python 2.7, build 221
|
||||
* [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
|
||||
|
||||
@ -85,19 +85,19 @@ This dependency has been built using pure basic 4.61. Its source can be found at
|
||||
|
||||
#### Dependencies required to build the installer
|
||||
|
||||
* [NSIS,](http://nsis.sourceforge.net/) version 3.01
|
||||
* [NSIS,](http://nsis.sourceforge.net/) version 3.02.1
|
||||
|
||||
#### Dependencies required to build the portableApps.com format archive
|
||||
|
||||
* [NSIS Portable,](http://portableapps.com/apps/development/nsis_portable) version 3.0
|
||||
* [NSIS Portable,](http://portableapps.com/apps/development/nsis_portable) version 3.02.1
|
||||
* [PortableApps.com Launcher,](http://portableapps.com/apps/development/portableapps.com_launcher) version 2.2.1
|
||||
* [PortableApps.com Installer,](http://portableapps.com/apps/development/portableapps.com_installer) version 3.4.4
|
||||
* [PortableApps.com Installer,](http://portableapps.com/apps/development/portableapps.com_installer) version 3.5.5
|
||||
|
||||
Important! Install these 3 apps into the same folder, otherwise you won't be able to build the pa.c version. For example: D:\portableApps\NSISPortable, D:\PortableApps\PortableApps.com installer, ...
|
||||
|
||||
#### Dependencies to make the spell checker multilingual ####
|
||||
|
||||
In order to add the support for spell checking in more languages than english you need to add some additional dictionaries to pyenchant. These are located on the dictionaries folder under windows-dependencies. Simply copy them to the share/enchant/myspell folder located in your enchant installation or in the compiled copy of TWBlue.
|
||||
In order to add the support for spell checking in more languages than english you need to add some additional dictionaries to pyenchant. These are located on the dictionaries folder under windows-dependencies. Simply copy them to the share/enchant/myspell folder located in your enchant installation. They will be automatically copied when building a binary version.
|
||||
|
||||
### Running TW Blue from source
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = 'TWBlue'
|
||||
snapshot = False
|
||||
if snapshot == False:
|
||||
version = "0.91"
|
||||
version = "0.92"
|
||||
update_url = 'http://twblue.es/updates/twblue_ngen.json'
|
||||
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json'
|
||||
else:
|
||||
|
@ -2,6 +2,14 @@
|
||||
|
||||
## changes in this version
|
||||
|
||||
* When authorising an account, you will see a dialogue with a cancel button, in case you want to abort the process. Also, NVDA will not be blocked when the process starts. ([#101](https://github.com/manuelcortez/TWBlue/issues/101))
|
||||
* In the translator module, the list of available languages is fetched automatically from the provider. That means all of these languages will work and there will not be inconsistencies. Also we've removed the first combo box, because the language is detected automatically by Yandex'S API. ([#153](https://github.com/manuelcortez/TWBlue/issues/153))
|
||||
* Trending topics, searches and conversation buffers will use mute settings set for the session in wich they were opened. ([#157](https://github.com/manuelcortez/TWBlue/issues/157))
|
||||
* And more. ([#156,](https://github.com/manuelcortez/TWBlue/issues/156) [#163,](https://github.com/manuelcortez/TWBlue/issues/163) [#159,](https://github.com/manuelcortez/TWBlue/issues/159))
|
||||
|
||||
## changes in version 0.91 and 0.92
|
||||
|
||||
* Fixed incorrect unicode handling when copying tweet to clipboard. ([#150](https://github.com/manuelcortez/TWBlue/issues/150))
|
||||
* TWBlue will show an error when trying to open a timeline for a suspended user. ([#128](https://github.com/manuelcortez/TWBlue/issues/128))
|
||||
* Removed TwUp as service as it no longer exists. ([#112](https://github.com/manuelcortez/TWBlue/issues/112))
|
||||
* Release audio files after uploading them. ([#130](https://github.com/manuelcortez/TWBlue/issues/130))
|
||||
|
@ -20,8 +20,8 @@ CommercialUse=true
|
||||
EULAVersion=2
|
||||
|
||||
[Version]
|
||||
PackageVersion=0.91.0.0
|
||||
DisplayVersion=0.91
|
||||
PackageVersion=0.92.0.0
|
||||
DisplayVersion=0.92
|
||||
|
||||
[Control]
|
||||
Icons=1
|
||||
|
@ -15,10 +15,10 @@ SetCompressor /solid lzma
|
||||
SetDatablockOptimize on
|
||||
VIAddVersionKey ProductName "TWBlue"
|
||||
VIAddVersionKey LegalCopyright "Copyright 2016 Manuel Cortéz."
|
||||
VIAddVersionKey ProductVersion "0.91"
|
||||
VIAddVersionKey FileVersion "0.91"
|
||||
VIProductVersion "0.91.0.0"
|
||||
VIFileVersion "0.91.0.0"
|
||||
VIAddVersionKey ProductVersion "0.92"
|
||||
VIAddVersionKey FileVersion "0.92"
|
||||
VIProductVersion "0.92.0.0"
|
||||
VIFileVersion "0.92.0.0"
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!define MUI_LICENSEPAGE_RADIOBUTTONS
|
||||
!insertmacro MUI_PAGE_LICENSE "license.txt"
|
||||
@ -72,10 +72,10 @@ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "D
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "UninstallString" '"$INSTDIR\uninstall.exe"'
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "InstallLocation" $INSTDIR
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" "Publisher" "Manuel Cortéz"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "0.91"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "DisplayVersion" "0.92"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "URLInfoAbout" "http://twblue.es"
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMajor" 0
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 91
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "VersionMinor" 92
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoModify" 1
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\twblue" "NoRepair" 1
|
||||
SectionEnd
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = 'TWBlue'
|
||||
snapshot = False
|
||||
if snapshot == False:
|
||||
version = "0.91"
|
||||
version = "0.92"
|
||||
update_url = 'http://twblue.es/updates/twblue_ngen.json'
|
||||
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json'
|
||||
else:
|
||||
|
@ -28,21 +28,5 @@ def convert_soundcloud (url):
|
||||
else:
|
||||
raise TypeError('%r is not streamable' % url)
|
||||
|
||||
@matches_url('http://twup.me')
|
||||
def convert_twup(url):
|
||||
result = re.match("^http://twup.me/(?P<audio_id>[A-Za-z0-9]+/?)$", url, re.I)
|
||||
if not result or result.group("audio_id") is None:
|
||||
raise TypeError('%r is not a valid URL' % url)
|
||||
audio_id = result.group("audio_id")
|
||||
return 'http://twup.me/%s' % audio_id
|
||||
|
||||
#@matches_url('http://sndup.net')
|
||||
#def convert_sndup(url):
|
||||
# result = re.match("^http://sndup.net/(?P<audio_id>[a-z0-9]+/?)(|d|l|a)/?$", url, re.I)
|
||||
# if not result or result.group("audio_id") is None:
|
||||
# raise TypeError('%r is not a valid URL' % url)
|
||||
# audio_id = result.group("audio_id")
|
||||
# return 'http://sndup.net/%s/a' % audio_id
|
||||
|
||||
def convert_generic_audio(url):
|
||||
return url
|
||||
|
@ -157,7 +157,7 @@ class bufferController(object):
|
||||
for i in attachments:
|
||||
photo = open(i["file"], "rb")
|
||||
img = self.session.twitter.twitter.upload_media(media=photo)
|
||||
self.session.twitter.twitter.set_description(media_id=img["media_id"], alt_text=dict(text=i["description"]))
|
||||
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)
|
||||
|
||||
@ -988,7 +988,7 @@ class searchBufferController(baseBufferController):
|
||||
# return None
|
||||
num = self.session.order_buffer(self.name, val)
|
||||
self.put_items_on_list(num)
|
||||
if num > 0:
|
||||
if num > 0 and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.session.sound.play("search_updated.ogg")
|
||||
return num
|
||||
|
||||
@ -1068,7 +1068,7 @@ class searchPeopleBufferController(peopleBufferController):
|
||||
number_of_items = self.session.order_cursored_buffer(self.name, val)
|
||||
log.debug("Number of items retrieved: %d" % (number_of_items,))
|
||||
self.put_items_on_list(number_of_items)
|
||||
if number_of_items > 0:
|
||||
if number_of_items > 0 and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.session.sound.play("search_updated.ogg")
|
||||
return number_of_items
|
||||
|
||||
@ -1148,6 +1148,7 @@ class trendsBufferController(bufferController):
|
||||
self.name_ = data[0]["locations"][0]["name"]
|
||||
self.trends = data[0]["trends"]
|
||||
self.put_items_on_the_list()
|
||||
if self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.session.sound.play(self.sound)
|
||||
|
||||
def put_items_on_the_list(self):
|
||||
@ -1270,7 +1271,7 @@ class conversationBufferController(searchBufferController):
|
||||
number_of_items = self.session.order_buffer(self.name, self.statuses)
|
||||
log.debug("Number of items retrieved: %d" % (number_of_items,))
|
||||
self.put_items_on_list(number_of_items)
|
||||
if number_of_items > 0:
|
||||
if number_of_items > 0 and self.session.settings["sound"]["session_mute"] == False and self.name not in self.session.settings["other_buffers"]["muted_buffers"]:
|
||||
self.session.sound.play("search_updated.ogg")
|
||||
return number_of_items
|
||||
|
||||
|
@ -478,11 +478,10 @@ class Controller(object):
|
||||
return
|
||||
start = page.buffer.list.get_selected()
|
||||
for i in xrange(start, count):
|
||||
if string.lower() in page.buffer.list.get_text_column(i, 1).lower():
|
||||
page.buffer.list.select_item(i)
|
||||
if string.lower() in page.get_message().lower():
|
||||
return output.speak(page.get_message(), True)
|
||||
output.speak(_(u"{0} not found.").format(string,), True)
|
||||
page.buffer.list.select_item(start)
|
||||
|
||||
def seekLeft(self, *args, **kwargs):
|
||||
try:
|
||||
@ -931,8 +930,8 @@ class Controller(object):
|
||||
self.view.insert_buffer(buffer.buffer, name=_(u"Trending topics for %s") % (trends.get_string()), pos=pos)
|
||||
self.buffers.append(buffer)
|
||||
buffer.start_stream()
|
||||
timer = RepeatingTimer(300, buffer.start_stream)
|
||||
timer.start()
|
||||
buffer.timer = RepeatingTimer(300, buffer.start_stream)
|
||||
buffer.timer.start()
|
||||
buffer.session.settings["other_buffers"]["trending_topic_buffers"].append(woeid)
|
||||
buffer.session.settings.write()
|
||||
|
||||
@ -987,9 +986,10 @@ class Controller(object):
|
||||
buff = self.view.search(buffer.name, buffer.account)
|
||||
answer = buffer.remove_buffer()
|
||||
if answer == False: return
|
||||
if hasattr(buff, "timer"):
|
||||
log.debug("destroying buffer...")
|
||||
if hasattr(buffer, "timer"):
|
||||
log.debug("Stopping timer...")
|
||||
buff.timer.cancel()
|
||||
buffer.timer.cancel()
|
||||
log.debug("Timer cancelled.")
|
||||
self.right()
|
||||
self.view.delete_buffer(buff)
|
||||
|
@ -40,9 +40,8 @@ class basicTweet(object):
|
||||
dlg = translator.gui.translateDialog()
|
||||
if dlg.get_response() == widgetUtils.OK:
|
||||
text_to_translate = self.message.get_text()
|
||||
source = [x[0] for x in translator.translator.available_languages()][dlg.get("source_lang")]
|
||||
dest = [x[0] for x in translator.translator.available_languages()][dlg.get("dest_lang")]
|
||||
msg = translator.translator.translate(text=text_to_translate, source=source, target=dest)
|
||||
msg = translator.translator.translate(text=text_to_translate, target=dest)
|
||||
self.message.set_text(msg)
|
||||
self.text_processor()
|
||||
self.message.text_focus()
|
||||
|
@ -1,11 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from yandex_translate import YandexTranslate
|
||||
|
||||
def translate(text="", source="auto", target="en"):
|
||||
def translate(text="", target="en"):
|
||||
t = YandexTranslate("trnsl.1.1.20161012T134532Z.d01b9c75fc39aa74.7d1be75a5166a80583eeb020e10f584168da6bf7")
|
||||
return t.translate(text, target)["text"][0]
|
||||
|
||||
vars = dict(text=text, lang=target)
|
||||
return t.translate(**vars)["text"][0]
|
||||
|
||||
supported_langs = None
|
||||
d = None
|
||||
languages = {
|
||||
"af": _(u"Afrikaans"),
|
||||
"sq": _(u"Albanian"),
|
||||
@ -71,7 +73,7 @@ languages = {
|
||||
"ps": _(u"Pashto"),
|
||||
"fa": _(u"Persian"),
|
||||
"pl": _(u"Polish"),
|
||||
"pt-PT": _(u"Portuguese"),
|
||||
"pt": _(u"Portuguese"),
|
||||
"pa": _(u"Punjabi"),
|
||||
"ro": _(u"Romanian"),
|
||||
"ru": _(u"Russian"),
|
||||
@ -101,8 +103,11 @@ languages = {
|
||||
}
|
||||
|
||||
def available_languages():
|
||||
l = languages.keys()
|
||||
d = languages.values()
|
||||
l.insert(0, '')
|
||||
d.insert(0, _(u"autodetect"))
|
||||
return sorted(zip(l, d))
|
||||
global supported_langs, d
|
||||
if supported_langs == None and d == None:
|
||||
t = YandexTranslate("trnsl.1.1.20161012T134532Z.d01b9c75fc39aa74.7d1be75a5166a80583eeb020e10f584168da6bf7")
|
||||
supported_langs = t.langs
|
||||
d = []
|
||||
for i in supported_langs:
|
||||
d.append(languages[i])
|
||||
return sorted(zip(supported_langs, d))
|
||||
|
@ -25,15 +25,11 @@ class translateDialog(baseDialog.BaseWXDialog):
|
||||
super(translateDialog, self).__init__(None, -1, title=_(u"Translate message"))
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
staticSource = wx.StaticText(panel, -1, _(u"Source language"))
|
||||
self.source_lang = wx.ComboBox(panel, -1, choices=[x[1] for x in translator.available_languages()], style = wx.CB_READONLY)
|
||||
self.source_lang.SetFocus()
|
||||
staticDest = wx.StaticText(panel, -1, _(u"Target language"))
|
||||
self.source_lang.SetSelection(0)
|
||||
self.dest_lang = wx.ComboBox(panel, -1, choices=[x[1] for x in translator.available_languages()], style = wx.CB_READONLY)
|
||||
self.dest_lang.SetFocus()
|
||||
self.dest_lang.SetSelection(0)
|
||||
listSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
listSizer.Add(staticSource)
|
||||
listSizer.Add(self.source_lang)
|
||||
listSizer.Add(staticDest)
|
||||
listSizer.Add(self.dest_lang)
|
||||
ok = wx.Button(panel, wx.ID_OK)
|
||||
|
@ -1,5 +1,6 @@
|
||||
# -*- 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
|
||||
@ -16,10 +17,11 @@ import config_utils
|
||||
import shelve
|
||||
import application
|
||||
import os
|
||||
from mysc.thread_utils import stream_threaded
|
||||
from mysc.thread_utils import stream_threaded, call_threaded
|
||||
from pubsub import pub
|
||||
log = logging.getLogger("sessionmanager.session")
|
||||
from long_tweets import tweets, twishort
|
||||
from wxUI import authorisationDialog
|
||||
|
||||
sessions = {}
|
||||
|
||||
@ -166,7 +168,20 @@ class Session(object):
|
||||
if self.logged == True:
|
||||
raise Exceptions.AlreadyAuthorisedError("The authorisation process is not needed at this time.")
|
||||
else:
|
||||
self.twitter.authorise(self.settings)
|
||||
self.authorisation_thread = call_threaded(self.twitter.authorise, self.settings)
|
||||
self.authorisation_dialog = authorisationDialog()
|
||||
self.authorisation_dialog.cancel.Bind(wx.EVT_BUTTON, self.authorisation_cancelled)
|
||||
pub.subscribe(self.authorisation_accepted, "authorisation-accepted")
|
||||
self.authorisation_dialog.ShowModal()
|
||||
|
||||
def authorisation_cancelled(self, *args, **kwargs):
|
||||
pub.sendMessage("authorisation-cancelled")
|
||||
self.authorisation_dialog.Destroy()
|
||||
del self.authorisation_dialog
|
||||
|
||||
def authorisation_accepted(self):
|
||||
pub.unsubscribe(self.authorisation_accepted, "authorisation-accepted")
|
||||
self.authorisation_dialog.Destroy()
|
||||
|
||||
def get_more_items(self, update_function, users=False, name=None, *args, **kwargs):
|
||||
results = []
|
||||
|
@ -74,3 +74,16 @@ class sessionManagerWindow(wx.Dialog):
|
||||
|
||||
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)
|
||||
self.text = wx.TextCtrl(panel, -1, _("Waiting for account authorisation..."), style=wx.TE_READONLY|wx.TE_MULTILINE)
|
||||
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)
|
@ -118,13 +118,11 @@ class URLStream(object):
|
||||
transformer = audio_services.find_url_transformer(self.url)
|
||||
self.url = transformer(self.url)
|
||||
log.debug("Transformed URL: %s. Prepared" % (self.url,))
|
||||
self.prepared = True
|
||||
else:
|
||||
self.url = url
|
||||
log.debug("Transformed URL: %s. Prepared" % (self.url,))
|
||||
self.prepared = True
|
||||
|
||||
|
||||
def seek(self,step):
|
||||
pos=self.stream.get_position()
|
||||
pos=self.stream.bytes_to_seconds(pos)
|
||||
@ -154,7 +152,7 @@ class URLStream(object):
|
||||
self.stream.volume = float(volume)
|
||||
self.stream.play()
|
||||
log.debug("played")
|
||||
# call_threaded(self.delete_when_done)
|
||||
self.prepared=False
|
||||
|
||||
def stop_audio(self,delete=False):
|
||||
if hasattr(self, "stream"):
|
||||
@ -167,6 +165,7 @@ class URLStream(object):
|
||||
if delete:
|
||||
del self.stream
|
||||
log.debug("Deleted audio stream.")
|
||||
self.prepared=False
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
@ -2,11 +2,12 @@
|
||||
import BaseHTTPServer
|
||||
import application
|
||||
from urlparse import urlparse, parse_qs
|
||||
from pubsub import pub
|
||||
|
||||
logged = False
|
||||
verifier = None
|
||||
|
||||
class handler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
class handler(BaseHTTPServer.BaseHTTPRequestHandler, object):
|
||||
|
||||
def do_GET(self):
|
||||
global logged
|
||||
@ -18,4 +19,14 @@ class handler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
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()
|
@ -184,7 +184,7 @@ def compose_event(data, username, show_screen_names=False):
|
||||
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 suscribed you to the list %s") % (data["source"]["name"], data["source"]["screen_name"], data["target_object"]["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"])
|
||||
|
@ -29,7 +29,12 @@ def find_urls (tweet):
|
||||
i = "full_text"
|
||||
else:
|
||||
i = "text"
|
||||
return [s[0] for s in url_re.findall(tweet[i])]
|
||||
shorten_urls = find_urls_in_text(tweet[i])
|
||||
for url in range(0, len(shorten_urls)):
|
||||
try:
|
||||
urls.append(tweet["entities"]["urls"][url]["expanded_url"])
|
||||
except: pass
|
||||
return urls
|
||||
|
||||
def find_item(id, listItem):
|
||||
for i in range(0, len(listItem)):
|
||||
|
@ -19,7 +19,7 @@ Questions, comments? ryan@venodesigns.net
|
||||
"""
|
||||
|
||||
__author__ = 'Ryan McGrath <ryan@venodesigns.net>'
|
||||
__version__ = '3.3.0'
|
||||
__version__ = '3.6.0'
|
||||
|
||||
from .api import Twython
|
||||
from .streaming import TwythonStreamer
|
||||
|
@ -145,6 +145,7 @@ class Twython(EndpointsMixin, object):
|
||||
else:
|
||||
params = params
|
||||
files = list()
|
||||
|
||||
requests_args = {}
|
||||
for k, v in self.client_args.items():
|
||||
# Maybe this should be set as a class variable and only done once?
|
||||
@ -195,17 +196,16 @@ class Twython(EndpointsMixin, object):
|
||||
error_message,
|
||||
error_code=response.status_code,
|
||||
retry_after=response.headers.get('X-Rate-Limit-Reset'))
|
||||
|
||||
content=""
|
||||
try:
|
||||
if response.status_code == 204:
|
||||
content = response.content
|
||||
else:
|
||||
content = response.json()
|
||||
except ValueError:
|
||||
# Send the response as is for working with /media/metadata/create.json.
|
||||
content = response.content
|
||||
# raise TwythonError('Response was not valid JSON. \
|
||||
# Unable to decode.')
|
||||
if response.content!="":
|
||||
raise TwythonError('Response was not valid JSON. \
|
||||
Unable to decode.')
|
||||
|
||||
return content
|
||||
|
||||
@ -258,8 +258,10 @@ class Twython(EndpointsMixin, object):
|
||||
url = endpoint
|
||||
else:
|
||||
url = '%s/%s.json' % (self.api_url % version, endpoint)
|
||||
|
||||
content = self._request(url, method=method, params=params,
|
||||
api_call=url)
|
||||
|
||||
return content
|
||||
|
||||
def get(self, endpoint, params=None, version='1.1'):
|
||||
@ -473,6 +475,11 @@ class Twython(EndpointsMixin, object):
|
||||
>>> print result
|
||||
|
||||
"""
|
||||
if not callable(function):
|
||||
raise TypeError('.cursor() takes a Twython function as its first \
|
||||
argument. Did you provide the result of a \
|
||||
function call?')
|
||||
|
||||
if not hasattr(function, 'iter_mode'):
|
||||
raise TwythonError('Unable to create generator for Twython \
|
||||
method "%s"' % function.__name__)
|
||||
@ -531,7 +538,7 @@ class Twython(EndpointsMixin, object):
|
||||
|
||||
@staticmethod
|
||||
def html_for_tweet(tweet, use_display_url=True, use_expanded_url=False, expand_quoted_status=False):
|
||||
"""Return HTML for a tweet (urls, mentions, hashtags replaced with links)
|
||||
"""Return HTML for a tweet (urls, mentions, hashtags, symbols replaced with links)
|
||||
|
||||
:param tweet: Tweet object from received from Twitter API
|
||||
:param use_display_url: Use display URL to represent link
|
||||
@ -547,62 +554,116 @@ class Twython(EndpointsMixin, object):
|
||||
if 'retweeted_status' in tweet:
|
||||
tweet = tweet['retweeted_status']
|
||||
|
||||
if 'extended_tweet' in tweet:
|
||||
tweet = tweet['extended_tweet']
|
||||
|
||||
orig_tweet_text = tweet.get('full_text') or tweet['text']
|
||||
|
||||
display_text_range = tweet.get('display_text_range') or [0, len(orig_tweet_text)]
|
||||
display_text_start, display_text_end = display_text_range[0], display_text_range[1]
|
||||
display_text = orig_tweet_text[display_text_start:display_text_end]
|
||||
prefix_text = orig_tweet_text[0:display_text_start]
|
||||
suffix_text = orig_tweet_text[display_text_end:len(orig_tweet_text)]
|
||||
|
||||
if 'entities' in tweet:
|
||||
text = tweet['text']
|
||||
entities = tweet['entities']
|
||||
# We'll put all the bits of replacement HTML and their starts/ends
|
||||
# in this list:
|
||||
entities = []
|
||||
|
||||
# Mentions
|
||||
for entity in sorted(entities['user_mentions'],
|
||||
key=lambda mention: len(mention['screen_name']), reverse=True):
|
||||
start, end = entity['indices'][0], entity['indices'][1]
|
||||
if 'user_mentions' in tweet['entities']:
|
||||
for entity in tweet['entities']['user_mentions']:
|
||||
temp = {}
|
||||
temp['start'] = entity['indices'][0]
|
||||
temp['end'] = entity['indices'][1]
|
||||
|
||||
mention_html = '<a href="https://twitter.com/%(screen_name)s" class="twython-mention">@%(screen_name)s</a>'
|
||||
text = re.sub(r'(?<!>)' + tweet['text'][start:end] + '(?!</a>)',
|
||||
mention_html % {'screen_name': entity['screen_name']}, text)
|
||||
mention_html = '<a href="https://twitter.com/%(screen_name)s" class="twython-mention">@%(screen_name)s</a>' % {'screen_name': entity['screen_name']}
|
||||
|
||||
if display_text_start <= temp['start'] <= display_text_end:
|
||||
temp['replacement'] = mention_html
|
||||
entities.append(temp)
|
||||
else:
|
||||
# Make the '@username' at the start, before
|
||||
# display_text, into a link:
|
||||
sub_expr = r'(?<!>)' + orig_tweet_text[temp['start']:temp['end']] + '(?!</a>)'
|
||||
prefix_text = re.sub(sub_expr, mention_html, prefix_text)
|
||||
|
||||
# Hashtags
|
||||
for entity in sorted(entities['hashtags'],
|
||||
key=lambda hashtag: len(hashtag['text']), reverse=True):
|
||||
start, end = entity['indices'][0], entity['indices'][1]
|
||||
if 'hashtags' in tweet['entities']:
|
||||
for entity in tweet['entities']['hashtags']:
|
||||
temp = {}
|
||||
temp['start'] = entity['indices'][0]
|
||||
temp['end'] = entity['indices'][1]
|
||||
|
||||
hashtag_html = '<a href="https://twitter.com/search?q=%%23%(hashtag)s" class="twython-hashtag">#%(hashtag)s</a>'
|
||||
text = re.sub(r'(?<!>)' + tweet['text'][start:end] + '(?!</a>)',
|
||||
hashtag_html % {'hashtag': entity['text']}, text)
|
||||
url_html = '<a href="https://twitter.com/search?q=%%23%(hashtag)s" class="twython-hashtag">#%(hashtag)s</a>' % {'hashtag': entity['text']}
|
||||
|
||||
# Urls
|
||||
for entity in entities['urls']:
|
||||
start, end = entity['indices'][0], entity['indices'][1]
|
||||
if use_display_url and entity.get('display_url') \
|
||||
and not use_expanded_url:
|
||||
temp['replacement'] = url_html
|
||||
entities.append(temp)
|
||||
|
||||
# Symbols
|
||||
if 'symbols' in tweet['entities']:
|
||||
for entity in tweet['entities']['symbols']:
|
||||
temp = {}
|
||||
temp['start'] = entity['indices'][0]
|
||||
temp['end'] = entity['indices'][1]
|
||||
|
||||
url_html = '<a href="https://twitter.com/search?q=%%24%(symbol)s" class="twython-symbol">$%(symbol)s</a>' % {'symbol': entity['text']}
|
||||
|
||||
temp['replacement'] = url_html
|
||||
entities.append(temp)
|
||||
|
||||
# URLs
|
||||
if 'urls' in tweet['entities']:
|
||||
for entity in tweet['entities']['urls']:
|
||||
temp = {}
|
||||
temp['start'] = entity['indices'][0]
|
||||
temp['end'] = entity['indices'][1]
|
||||
|
||||
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']
|
||||
|
||||
url_html = '<a href="%s" class="twython-url">%s</a>'
|
||||
text = text.replace(tweet['text'][start:end],
|
||||
url_html % (entity['url'], shown_url))
|
||||
url_html = '<a href="%s" class="twython-url">%s</a>' % (entity['url'], shown_url)
|
||||
|
||||
# Media
|
||||
if 'media' in entities:
|
||||
for entity in entities['media']:
|
||||
start, end = entity['indices'][0], entity['indices'][1]
|
||||
if use_display_url and entity.get('display_url') \
|
||||
and not use_expanded_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)
|
||||
|
||||
if 'media' in tweet['entities']:
|
||||
for entity in tweet['entities']['media']:
|
||||
temp = {}
|
||||
temp['start'] = entity['indices'][0]
|
||||
temp['end'] = entity['indices'][1]
|
||||
|
||||
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']
|
||||
|
||||
url_html = '<a href="%s" class="twython-media">%s</a>'
|
||||
text = text.replace(tweet['text'][start:end],
|
||||
url_html % (entity['url'], shown_url))
|
||||
url_html = '<a href="%s" class="twython-media">%s</a>' % (entity['url'], shown_url)
|
||||
|
||||
if expand_quoted_status and tweet.get('is_quote_status'):
|
||||
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:
|
||||
for entity in sorted(entities, key=lambda e: e['start'], reverse=True):
|
||||
display_text = display_text[0:entity['start']] + entity['replacement'] + display_text[entity['end']:]
|
||||
|
||||
quote_text = ''
|
||||
if expand_quoted_status and tweet.get('is_quote_status') and tweet.get('quoted_status'):
|
||||
quoted_status = tweet['quoted_status']
|
||||
text += '<blockquote class="twython-quote">%(quote)s<cite><a href="%(quote_tweet_link)s">' \
|
||||
quote_text += '<blockquote class="twython-quote">%(quote)s<cite><a href="%(quote_tweet_link)s">' \
|
||||
'<span class="twython-quote-user-name">%(quote_user_name)s</span>' \
|
||||
'<span class="twython-quote-user-screenname">@%(quote_user_screen_name)s</span></a>' \
|
||||
'</cite></blockquote>' % \
|
||||
@ -612,4 +673,9 @@ class Twython(EndpointsMixin, object):
|
||||
'quote_user_name': quoted_status['user']['name'],
|
||||
'quote_user_screen_name': quoted_status['user']['screen_name']}
|
||||
|
||||
return text
|
||||
return '%(prefix)s%(display)s%(suffix)s%(quote)s' % {
|
||||
'prefix': '<span class="twython-tweet-prefix">%s</span>' % prefix_text if prefix_text else '',
|
||||
'display': display_text,
|
||||
'suffix': '<span class="twython-tweet-suffix">%s</span>' % suffix_text if suffix_text else '',
|
||||
'quote': quote_text
|
||||
}
|
||||
|
@ -17,10 +17,12 @@ https://dev.twitter.com/docs/api/1.1
|
||||
import json
|
||||
import os
|
||||
import warnings
|
||||
try:
|
||||
from StringIO import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
from io import BytesIO
|
||||
from time import sleep
|
||||
#try:
|
||||
#from StringIO import StringIO
|
||||
#except ImportError:
|
||||
#from io import StringIO
|
||||
|
||||
from .advisory import TwythonDeprecationWarning
|
||||
|
||||
@ -143,15 +145,20 @@ class EndpointsMixin(object):
|
||||
Docs:
|
||||
https://dev.twitter.com/rest/reference/post/media/upload
|
||||
"""
|
||||
# https://dev.twitter.com/rest/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)
|
||||
|
||||
return self.post('https://upload.twitter.com/1.1/media/upload.json', params=params)
|
||||
|
||||
def set_description(self, **params):
|
||||
""" Adds a description to an image."""
|
||||
# This method only accepts strings, no dictionaries.
|
||||
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
|
||||
"""
|
||||
params = json.dumps(params)
|
||||
return self.post("media/metadata/create", params=params)
|
||||
return self.post("https://upload.twitter.com/1.1/media/metadata/create.json", params=params)
|
||||
|
||||
def upload_video(self, media, media_type, size=None):
|
||||
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.
|
||||
@ -176,7 +183,8 @@ class EndpointsMixin(object):
|
||||
params = {
|
||||
'command': 'INIT',
|
||||
'media_type': media_type,
|
||||
'total_bytes': size
|
||||
'total_bytes': size,
|
||||
'media_category': media_category
|
||||
}
|
||||
response_init = self.post(upload_url, params=params)
|
||||
media_id = response_init['media_id']
|
||||
@ -187,7 +195,7 @@ class EndpointsMixin(object):
|
||||
data = media.read(1*1024*1024)
|
||||
if not data:
|
||||
break
|
||||
media_chunk = StringIO()
|
||||
media_chunk = BytesIO()
|
||||
media_chunk.write(data)
|
||||
media_chunk.seek(0)
|
||||
|
||||
@ -205,7 +213,38 @@ class EndpointsMixin(object):
|
||||
'command': 'FINALIZE',
|
||||
'media_id': media_id
|
||||
}
|
||||
return self.post(upload_url, params=params)
|
||||
|
||||
response = self.post(upload_url, params=params)
|
||||
|
||||
# Only get the status if explicity asked to
|
||||
# Default to False
|
||||
if check_progress:
|
||||
|
||||
# Stage 4: STATUS call if still processing
|
||||
params = {
|
||||
'command': 'STATUS',
|
||||
'media_id': media_id
|
||||
}
|
||||
|
||||
# added code to handle if media_category is NOT set and check_progress=True
|
||||
# the API will return a NoneType object in this case
|
||||
try:
|
||||
processing_state = response.get('processing_info').get('state')
|
||||
except AttributeError:
|
||||
return response
|
||||
|
||||
if processing_state:
|
||||
while (processing_state == 'pending' or processing_state == 'in_progress') :
|
||||
# get the secs to wait
|
||||
check_after_secs = response.get('processing_info').get('check_after_secs')
|
||||
|
||||
if check_after_secs:
|
||||
sleep(check_after_secs)
|
||||
response = self.get(upload_url, params=params)
|
||||
# get new state after waiting
|
||||
processing_state = response.get('processing_info').get('state')
|
||||
|
||||
return response
|
||||
|
||||
def get_oembed_tweet(self, **params):
|
||||
"""Returns information allowing the creation of an embedded
|
||||
|
@ -10,7 +10,7 @@ logger = logging.getLogger("updater")
|
||||
|
||||
def do_update(endpoint=application.update_url):
|
||||
try:
|
||||
update.perform_update(endpoint=endpoint, current_version=application.version, app_name=application.name, update_available_callback=available_update_dialog, progress_callback=progress_callback, update_complete_callback=update_finished)
|
||||
result = update.perform_update(endpoint=endpoint, current_version=application.version, app_name=application.name, update_available_callback=available_update_dialog, progress_callback=progress_callback, update_complete_callback=update_finished)
|
||||
except:
|
||||
if endpoint == application.update_url:
|
||||
logger.error("Update failed! Using mirror URL...")
|
||||
@ -18,3 +18,4 @@ def do_update(endpoint=application.update_url):
|
||||
else:
|
||||
logger.exception("Update failed.")
|
||||
output.speak("An exception occurred while attempting to update " + application.name + ". If this message persists, contact the " + application.name + " developers. More information about the exception has been written to the error log.",True)
|
||||
return result
|
@ -25,7 +25,7 @@ def unshorten (url, service=None, **kwargs):
|
||||
|
||||
|
||||
def default_service ():
|
||||
return shorteners.TinyurlShortener
|
||||
return shorteners.AcortameShortener
|
||||
|
||||
def find_service (service, **kwargs):
|
||||
for i in shorteners.__all__:
|
||||
|
@ -6,4 +6,5 @@ from tinyarrows import TinyArrowsShortener
|
||||
from tinyurl import TinyurlShortener
|
||||
from xedcc import XedccShortener
|
||||
from clckru import ClckruShortener
|
||||
__all__ = ["HKCShortener", "IsgdShortener", "OnjmeShortener", "TinyArrowsShortener", "TinyurlShortener", "XedccShortener", "ClckruShortener"]
|
||||
from acortame import AcortameShortener
|
||||
__all__ = ["HKCShortener", "IsgdShortener", "OnjmeShortener", "TinyArrowsShortener", "TinyurlShortener", "XedccShortener", "ClckruShortener", "AcortameShortener"]
|
||||
|
27
src/url_shortener/shorteners/acortame.py
Normal file
27
src/url_shortener/shorteners/acortame.py
Normal file
@ -0,0 +1,27 @@
|
||||
from url_shortener import URLShortener
|
||||
import requests
|
||||
import urllib
|
||||
class AcortameShortener (URLShortener):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.name = "acorta.me"
|
||||
super(AcortameShortener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = requests.get ("https://acorta.me/api.php?action=shorturl&format=simple&url=" + urllib.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
return 'acorta.me' in url
|
||||
|
||||
def unshorten (self, url):
|
||||
if not 'acorta.me' in url:
|
||||
#use generic expand method
|
||||
return super(AcortameShortener, self).unshorten(url)
|
||||
answer = url
|
||||
api = requests.get ("https://acorta.me/api.php?action=expand&format=simple&shorturl=" + urllib.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
@ -1,19 +1,18 @@
|
||||
import urllib
|
||||
|
||||
import requests
|
||||
from url_shortener import URLShortener
|
||||
|
||||
|
||||
class ClckruShortener (URLShortener):
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "clck.ru"
|
||||
return super(ClckruShortener, self).__init__(*args, **kwargs)
|
||||
super(ClckruShortener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = urllib.urlopen ("http://clck.ru/--?url=" + urllib.quote(url))
|
||||
if api.getcode() == 200:
|
||||
answer = api.read()
|
||||
api.close()
|
||||
api = requests.get ("http://clck.ru/--?url=" + urllib.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
|
@ -1,5 +1,5 @@
|
||||
import urllib
|
||||
|
||||
import requests
|
||||
from url_shortener import URLShortener
|
||||
|
||||
class HKCShortener (URLShortener):
|
||||
@ -9,10 +9,9 @@ class HKCShortener (URLShortener):
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = urllib.urlopen ("http://hkc.im/yourls-api.php?action=shorturl&format=simple&url=" + urllib.quote(url))
|
||||
if api.getcode() == 200:
|
||||
answer = api.read()
|
||||
api.close()
|
||||
api = requests.get ("http://hkc.im/yourls-api.php?action=shorturl&format=simple&url=" + urllib.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
|
@ -1,19 +1,18 @@
|
||||
import urllib
|
||||
|
||||
import requests
|
||||
from url_shortener import URLShortener
|
||||
|
||||
|
||||
class IsgdShortener (URLShortener):
|
||||
def __init__ (self, *args, **kwargs):
|
||||
self.name = "Is.gd"
|
||||
return super(IsgdShortener, self).__init__(*args, **kwargs)
|
||||
super(IsgdShortener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = urllib.urlopen ("http://is.gd/api.php?longurl=" + urllib.quote(url))
|
||||
if api.getcode() == 200:
|
||||
answer = api.read()
|
||||
api.close()
|
||||
api = requests.get ("http://is.gd/api.php?longurl=" + urllib.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
|
@ -1,5 +1,5 @@
|
||||
import urllib
|
||||
|
||||
import requests
|
||||
from url_shortener import URLShortener
|
||||
|
||||
class OnjmeShortener (URLShortener):
|
||||
@ -9,10 +9,9 @@ class OnjmeShortener (URLShortener):
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = urllib.urlopen ("http://onj.me/yourls-api.php?action=shorturl&format=simple&url=" + urllib.quote(url))
|
||||
if api.getcode() == 200:
|
||||
answer = api.read()
|
||||
api.close()
|
||||
api = requests.get ("http://onj.me/yourls-api.php?action=shorturl&format=simple&url=" + urllib.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
|
@ -1,5 +1,5 @@
|
||||
import urllib
|
||||
|
||||
import requests
|
||||
from url_shortener import URLShortener
|
||||
|
||||
class TinyArrowsShortener (URLShortener):
|
||||
@ -9,8 +9,10 @@ class TinyArrowsShortener (URLShortener):
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
answer = urllib.urlopen("http://tinyarro.ws/api-create.php?utfpure=1&url=%s" % urllib.quote(url)).read()
|
||||
api = requests.get("http://tinyarro.ws/api-create.php?utfpure=1&url=%s" % urllib.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer.decode('UTF-8')
|
||||
|
||||
def created_url(self, url):
|
||||
return False
|
||||
return "tinyarro.ws" in url
|
||||
|
@ -1,4 +1,5 @@
|
||||
from url_shortener import URLShortener
|
||||
import requests
|
||||
import urllib
|
||||
class TinyurlShortener (URLShortener):
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -6,12 +7,10 @@ class TinyurlShortener (URLShortener):
|
||||
super(TinyurlShortener, self).__init__(*args, **kwargs)
|
||||
|
||||
def _shorten (self, url):
|
||||
|
||||
answer = url
|
||||
api = urllib.urlopen ("http://tinyurl.com/api-create.php?url=" + urllib.quote(url))
|
||||
if api.getcode() == 200:
|
||||
answer = api.read()
|
||||
api.close()
|
||||
api = requests.get ("http://tinyurl.com/api-create.php?url=" + urllib.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
|
@ -1,6 +1,4 @@
|
||||
from httplib import HTTPConnection
|
||||
from urlparse import urlparse
|
||||
|
||||
import requests
|
||||
|
||||
class URLShortener (object):
|
||||
|
||||
@ -22,12 +20,18 @@ class URLShortener (object):
|
||||
raise NotImplementedError
|
||||
|
||||
def unshorten(self, url):
|
||||
working = urlparse(url)
|
||||
if not working.netloc:
|
||||
raise TypeError, "Unable to parse URL."
|
||||
con = HTTPConnection(working.netloc)
|
||||
con.connect()
|
||||
con.request('GET', working.path)
|
||||
resp = con.getresponse()
|
||||
con.close()
|
||||
return resp.getheader('location')
|
||||
try:
|
||||
r=requests.head(url)
|
||||
if 'location' in r.headers.keys():
|
||||
if 'dropbox.com' in r.headers['location']:
|
||||
return handle_dropbox(r.headers['location'])
|
||||
else:
|
||||
return r.headers['location']
|
||||
except:
|
||||
return url #we cannot expand
|
||||
|
||||
def handle_dropbox(url):
|
||||
if url.endswith("dl=1"):
|
||||
return url
|
||||
else:
|
||||
return url.replace("dl=0", "dl=1")
|
||||
|
@ -1,5 +1,5 @@
|
||||
import urllib
|
||||
|
||||
import requests
|
||||
from url_shortener import URLShortener
|
||||
|
||||
class XedccShortener (URLShortener):
|
||||
@ -9,10 +9,9 @@ class XedccShortener (URLShortener):
|
||||
|
||||
def _shorten (self, url):
|
||||
answer = url
|
||||
api = urllib.urlopen ("http://xed.cc/yourls-api.php?action=shorturl&format=simple&url=" + urllib.quote(url))
|
||||
if api.getcode() == 200:
|
||||
answer = api.read()
|
||||
api.close()
|
||||
api = requests.get ("http://xed.cc/yourls-api.php?action=shorturl&format=simple&url=" + urllib.quote(url))
|
||||
if api.status_code == 200:
|
||||
answer = api.text
|
||||
return answer
|
||||
|
||||
def created_url (self, url):
|
||||
|
@ -26,8 +26,7 @@ class searchDialog(baseDialog.BaseWXDialog):
|
||||
radioSizer.Add(self.users, 0, wx.ALL, 5)
|
||||
sizer.Add(radioSizer, 0, wx.ALL, 5)
|
||||
lang = wx.StaticText(panel, -1, _(u"&Language for results: "))
|
||||
langs = [x[1] for x in translator.translator.available_languages()]
|
||||
langs[:] = langs[1:]
|
||||
langs = [x for x in translator.translator.languages.values()]
|
||||
langs.insert(0, _(u"any"))
|
||||
self.lang = wx.ComboBox(panel, -1, choices=langs, value=langs[0], style = wx.CB_READONLY)
|
||||
langBox = wx.BoxSizer(wx.HORIZONTAL)
|
||||
@ -51,7 +50,12 @@ class searchDialog(baseDialog.BaseWXDialog):
|
||||
self.SetClientSize(sizer.CalcMin())
|
||||
|
||||
def get_language(self):
|
||||
return [x[0] for x in translator.translator.available_languages()][self.lang.GetSelection()]
|
||||
l = self.lang.GetStringSelection()
|
||||
if l == _(u"any"):
|
||||
return ""
|
||||
for langcode, langname in translator.translator.languages.iteritems():
|
||||
if langname == l:
|
||||
return langcode
|
||||
|
||||
def get_result_type(self):
|
||||
r = self.resultstype.GetValue()
|
||||
|
@ -1,4 +1,4 @@
|
||||
{"current_version": "0.91",
|
||||
{"current_version": "0.92",
|
||||
"description": "The first version for the new generation of TWBlue.",
|
||||
"date": "day_name_abr month day_numb, 2016",
|
||||
"downloads":
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit f8bd2d8c6ce174f31cb28c47172935a5162af546
|
||||
Subproject commit 990bb47acc45df5bc7996aae676c27a4a3467edd
|
Loading…
x
Reference in New Issue
Block a user