mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2025-08-28 18:51:34 +00:00
Compare commits
18 Commits
snapshot11
...
snapshot12
Author | SHA1 | Date | |
---|---|---|---|
89985cf6bd | |||
cc4568b968 | |||
d7132ecaf6 | |||
720e0e6c24 | |||
9763d8b26c | |||
f512267b6d | |||
241de0264d | |||
5c7bce1258 | |||
e24543be12 | |||
422c780d0c | |||
![]() |
96a592a4f9 | ||
d4bf33ca6d | |||
e5b33160e0 | |||
c8d83ed9e7 | |||
16b2e16614 | |||
221d1d413b | |||
4391e3d3de | |||
c5e9e97c84 |
@@ -2,6 +2,14 @@
|
|||||||
|
|
||||||
## changes in this version
|
## changes in this version
|
||||||
|
|
||||||
|
* TWBlue can open a Tweet or user directly in Twitter. There is a new option in the context menu for people and tweet buffers, and also, the shortcut control+win+alt+Enter will open the focused item in Twitter.
|
||||||
|
* Some keystrokes were remapped in the Windows 10 Keymap:
|
||||||
|
* Read location of a tweet: Ctrl+Win+G. ([#177](https://github.com/manuelcortez/TWBlue/pull/177))
|
||||||
|
* Open global settings dialogue: Ctrl+Win+Alt+O.
|
||||||
|
* Mute/unmute current session: Control + Windows + Alt + M.
|
||||||
|
* Fixed an error that was preventing TWBlue to load the direct messages buffer if an user who sent a message has been deleted.
|
||||||
|
* Added support for playing audios posted in [AnyAudio.net](http://anyaudio.net) directly from TWBlue. Thanks to [Sam Tupy](http://www.samtupy.com/)
|
||||||
|
* Custom buffer ordering will not be reset every time the application restarts after an account setting has been modified.
|
||||||
* 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.
|
* 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))
|
* 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))
|
* 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))
|
||||||
@@ -14,7 +22,6 @@
|
|||||||
* 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 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))
|
* 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))
|
* 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.
|
* 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.
|
* 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.
|
* It is possible to add a tweet to the likes buffer from the menu bar again.
|
||||||
|
@@ -21,6 +21,11 @@ chardet
|
|||||||
urllib3
|
urllib3
|
||||||
youtube-dl
|
youtube-dl
|
||||||
python-vlc
|
python-vlc
|
||||||
pywin32
|
pypiwin32
|
||||||
certifi
|
certifi
|
||||||
backports.functools_lru_cache
|
backports.functools_lru_cache
|
||||||
|
git+https://github.com/manuelcortez/twython
|
||||||
|
git+https://github.com/manuelcortez/libloader
|
||||||
|
git+https://github.com/manuelcortez/platform_utils
|
||||||
|
git+https://github.com/manuelcortez/accessible_output2
|
||||||
|
git+https://github.com/chrisnorman7/sound_lib
|
@@ -1,33 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
import ctypes
|
|
||||||
import os
|
|
||||||
import types
|
|
||||||
from platform_utils import paths
|
|
||||||
|
|
||||||
def load_library(libname, cdll=False):
|
|
||||||
if paths.is_frozen():
|
|
||||||
libfile = os.path.join(paths.embedded_data_path(), 'accessible_output2', 'lib', libname)
|
|
||||||
else:
|
|
||||||
libfile = os.path.join(paths.module_path(), 'lib', libname)
|
|
||||||
if cdll:
|
|
||||||
return ctypes.cdll[libfile]
|
|
||||||
else:
|
|
||||||
return ctypes.windll[libfile]
|
|
||||||
|
|
||||||
def get_output_classes():
|
|
||||||
from . import outputs
|
|
||||||
module_type = types.ModuleType
|
|
||||||
classes = [m.output_class for m in outputs.__dict__.values() if type(m) == module_type and hasattr(m, 'output_class')]
|
|
||||||
return sorted(classes, key=lambda c: c.priority)
|
|
||||||
|
|
||||||
def find_datafiles():
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
from glob import glob
|
|
||||||
import accessible_output2
|
|
||||||
if platform.system() != 'Windows':
|
|
||||||
return []
|
|
||||||
path = os.path.join(accessible_output2.__path__[0], 'lib', '*.dll')
|
|
||||||
results = glob(path)
|
|
||||||
dest_dir = os.path.join('accessible_output2', 'lib')
|
|
||||||
return [(dest_dir, results)]
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,20 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
import platform
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
from . import nvda
|
|
||||||
from . import jaws
|
|
||||||
from . import sapi5
|
|
||||||
from . import window_eyes
|
|
||||||
from . import system_access
|
|
||||||
from . import dolphin
|
|
||||||
from . import pc_talker
|
|
||||||
#import sapi4
|
|
||||||
|
|
||||||
if platform.system() == 'Darwin':
|
|
||||||
from . import voiceover
|
|
||||||
from . import say
|
|
||||||
|
|
||||||
if platform.system() == 'Linux':
|
|
||||||
from . import e_speak
|
|
||||||
|
|
||||||
from . import auto
|
|
@@ -1,42 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
import accessible_output2
|
|
||||||
from .base import Output, OutputError
|
|
||||||
|
|
||||||
class Auto(Output):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
output_classes = accessible_output2.get_output_classes()
|
|
||||||
self.outputs = []
|
|
||||||
for output in output_classes:
|
|
||||||
try:
|
|
||||||
a=output()
|
|
||||||
self.outputs.append(a)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_first_available_output(self):
|
|
||||||
for output in self.outputs:
|
|
||||||
if output.is_active():
|
|
||||||
return output
|
|
||||||
return None
|
|
||||||
|
|
||||||
def speak(self, *args, **kwargs):
|
|
||||||
output = self.get_first_available_output()
|
|
||||||
if output:
|
|
||||||
output.speak(*args, **kwargs)
|
|
||||||
|
|
||||||
def braille(self, *args, **kwargs):
|
|
||||||
output = self.get_first_available_output()
|
|
||||||
if output:
|
|
||||||
output.braille(*args, **kwargs)
|
|
||||||
|
|
||||||
def output(self, *args, **kwargs):
|
|
||||||
output = self.get_first_available_output()
|
|
||||||
if output:
|
|
||||||
output.speak(*args, **kwargs)
|
|
||||||
output.braille(*args, **kwargs)
|
|
||||||
|
|
||||||
def is_system_output(self):
|
|
||||||
output = self.get_first_available_output()
|
|
||||||
if output:
|
|
||||||
return output.is_system_output()
|
|
@@ -1,47 +0,0 @@
|
|||||||
from accessible_output2 import load_library
|
|
||||||
import platform
|
|
||||||
|
|
||||||
class OutputError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class Output(object):
|
|
||||||
name = "Unnamed Output"
|
|
||||||
lib32 = None
|
|
||||||
lib64 = None
|
|
||||||
argtypes = {}
|
|
||||||
cdll = False
|
|
||||||
priority = 100
|
|
||||||
system_output = False
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.is_32bit = platform.architecture()[0] == "32bit"
|
|
||||||
if self.lib32 and self.is_32bit:
|
|
||||||
self.lib = load_library(self.lib32, cdll=self.cdll)
|
|
||||||
elif self.lib64:
|
|
||||||
self.lib = load_library(self.lib64, cdll=self.cdll)
|
|
||||||
else:
|
|
||||||
self.lib = None
|
|
||||||
if self.lib is not None:
|
|
||||||
for func in self.argtypes:
|
|
||||||
try:
|
|
||||||
getattr(self.lib, func).argtypes = self.argtypes[func]
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def output(self, text, **options):
|
|
||||||
output = False
|
|
||||||
if self.speak(text, **options):
|
|
||||||
output = True
|
|
||||||
if self.braille(text, **options):
|
|
||||||
output = True
|
|
||||||
if not output:
|
|
||||||
raise RuntimeError("Output %r does not have any method defined to output" % self)
|
|
||||||
|
|
||||||
def is_system_output(self):
|
|
||||||
return self.system_output
|
|
||||||
|
|
||||||
def speak(self, **optiont):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def braille(self, *args, **options):
|
|
||||||
return False
|
|
@@ -1,33 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
import os
|
|
||||||
import ctypes
|
|
||||||
|
|
||||||
from .base import Output
|
|
||||||
|
|
||||||
class Dolphin (Output):
|
|
||||||
"""Supports dolphin products."""
|
|
||||||
|
|
||||||
name = 'Dolphin'
|
|
||||||
lib32 = 'dolapi.dll'
|
|
||||||
argtypes = {
|
|
||||||
'DolAccess_Command': (ctypes.c_wchar_p, ctypes.c_int, ctypes.c_int),
|
|
||||||
'DolAccess_Action': (ctypes.c_int,),
|
|
||||||
}
|
|
||||||
|
|
||||||
def speak(self, text, interrupt=0):
|
|
||||||
if interrupt:
|
|
||||||
self.silence()
|
|
||||||
#If we don't call this, the API won't let us speak.
|
|
||||||
if self.is_active():
|
|
||||||
self.lib.DolAccess_Command(text, (len(text)*2)+2, 1)
|
|
||||||
|
|
||||||
def silence(self):
|
|
||||||
self.lib.DolAccess_Action(141)
|
|
||||||
|
|
||||||
def is_active(self):
|
|
||||||
try:
|
|
||||||
return self.lib.DolAccess_GetSystem() in (1, 4, 8)
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
output_class = Dolphin
|
|
@@ -1,31 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
from .base import Output
|
|
||||||
|
|
||||||
try:
|
|
||||||
import espeak.core
|
|
||||||
except:
|
|
||||||
raise RuntimeError("Cannot find espeak.core. Please install python-espeak")
|
|
||||||
|
|
||||||
class ESpeak(Output):
|
|
||||||
"""Speech output supporting ESpeak on Linux
|
|
||||||
Note this requires python-espeak to be installed
|
|
||||||
This can be done on Debian distros by using apt-get install python-espeak
|
|
||||||
Or through this tarball: https://launchpad.net/python-espeak
|
|
||||||
"""
|
|
||||||
name = "Linux ESpeak"
|
|
||||||
|
|
||||||
def is_active(self):
|
|
||||||
try:
|
|
||||||
import espeak.core
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def speak(self, text, interrupt = 0):
|
|
||||||
if interrupt:
|
|
||||||
self.silence()
|
|
||||||
espeak.core.synth(text)
|
|
||||||
def silence(self):
|
|
||||||
espeak.core.cancel()
|
|
||||||
|
|
||||||
output_class = ESpeak
|
|
@@ -1,34 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
import win32gui
|
|
||||||
from libloader.com import load_com
|
|
||||||
import pywintypes
|
|
||||||
|
|
||||||
from .base import Output, OutputError
|
|
||||||
|
|
||||||
class Jaws (Output):
|
|
||||||
"""Output supporting the Jaws for Windows screen reader."""
|
|
||||||
|
|
||||||
name = 'jaws'
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super (Jaws, self).__init__(*args, **kwargs)
|
|
||||||
try:
|
|
||||||
self.object = load_com("FreedomSci.JawsApi", "jfwapi")
|
|
||||||
except pywintypes.com_error:
|
|
||||||
raise OutputError
|
|
||||||
|
|
||||||
def braille(self, text, **options):
|
|
||||||
# HACK: replace " with ', Jaws doesn't seem to understand escaping them with \
|
|
||||||
text = text.replace('"', "'")
|
|
||||||
self.object.RunFunction("BrailleString(\"%s\")" % text)
|
|
||||||
|
|
||||||
def speak(self, text, interrupt=False):
|
|
||||||
self.object.SayString(' %s' % text, interrupt)
|
|
||||||
|
|
||||||
def is_active(self):
|
|
||||||
try:
|
|
||||||
return self.object.SayString('',0) == True or win32gui.FindWindow("JFWUI2", "JAWS") != 0
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
output_class = Jaws
|
|
@@ -1,37 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import ctypes
|
|
||||||
|
|
||||||
from platform_utils import paths
|
|
||||||
from libloader import load_library
|
|
||||||
from .base import Output
|
|
||||||
|
|
||||||
class NVDA(Output):
|
|
||||||
"""Supports The NVDA screen reader"""
|
|
||||||
name = "NVDA"
|
|
||||||
lib32 = 'nvdaControllerClient32.dll'
|
|
||||||
lib64 = 'nvdaControllerClient64.dll'
|
|
||||||
argtypes = {
|
|
||||||
'nvdaController_brailleMessage': (ctypes.c_wchar_p,),
|
|
||||||
'nvdaController_speakText': (ctypes.c_wchar_p,),
|
|
||||||
}
|
|
||||||
|
|
||||||
def is_active(self):
|
|
||||||
try:
|
|
||||||
return self.lib.nvdaController_testIfRunning() == 0
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def braille(self, text, **options):
|
|
||||||
self.lib.nvdaController_brailleMessage(text)
|
|
||||||
|
|
||||||
def speak(self, text, interrupt=False):
|
|
||||||
if interrupt:
|
|
||||||
self.silence()
|
|
||||||
self.lib.nvdaController_speakText(text)
|
|
||||||
|
|
||||||
def silence(self):
|
|
||||||
self.lib.nvdaController_cancelSpeech()
|
|
||||||
|
|
||||||
output_class = NVDA
|
|
@@ -1,24 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
import ctypes
|
|
||||||
from .base import Output
|
|
||||||
|
|
||||||
class PCTalker(Output):
|
|
||||||
lib32 = 'pctkusr.dll'
|
|
||||||
lib64 = 'pctkusr64.dll'
|
|
||||||
cdll = True
|
|
||||||
argtypes = {
|
|
||||||
'PCTKPRead': (ctypes.c_char_p, ctypes.c_int, ctypes.c_int)
|
|
||||||
}
|
|
||||||
|
|
||||||
def speak(self, text, interrupt=False):
|
|
||||||
if interrupt:
|
|
||||||
self.silence()
|
|
||||||
self.lib.PCTKPRead(text.encode('cp932', 'replace'), 0, 1)
|
|
||||||
|
|
||||||
def silence(self):
|
|
||||||
self.lib.PCTKVReset()
|
|
||||||
|
|
||||||
def is_active(self):
|
|
||||||
return self.lib.PCTKStatus() != 0
|
|
||||||
|
|
||||||
output_class = PCTalker
|
|
@@ -1,143 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
from builtins import range
|
|
||||||
from libloader.com import load_com
|
|
||||||
from .base import Output
|
|
||||||
|
|
||||||
import logging
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class Sapi4(Output):
|
|
||||||
|
|
||||||
name = 'sapi4'
|
|
||||||
priority = 102
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
sapi4 = load_com("{EEE78591-FE22-11D0-8BEF-0060081841DE}")
|
|
||||||
self._voiceNo = sapi4.Find(0)
|
|
||||||
sapi4.Select(self._voiceNo)
|
|
||||||
sapi4.Speak(" ")
|
|
||||||
self.__object = sapi4
|
|
||||||
self._voice_list = self._available_voices()
|
|
||||||
|
|
||||||
def _set_capabilities(self):
|
|
||||||
sapi4 = self.__object
|
|
||||||
try:
|
|
||||||
sapi4.Pitch = sapi4.Pitch
|
|
||||||
self._min_pitch = sapi4.MinPitch
|
|
||||||
self._max_pitch = sapi4.MaxPitch
|
|
||||||
self._has_pitch = True
|
|
||||||
except:
|
|
||||||
self._min_pitch = 0
|
|
||||||
self._max_pitch = 0
|
|
||||||
self._has_pitch = False
|
|
||||||
try:
|
|
||||||
sapi4.Speed = sapi4.Speed
|
|
||||||
self._min_rate = sapi4.MinSpeed
|
|
||||||
self._max_rate = sapi4.MaxSpeed
|
|
||||||
self._has_rate = True
|
|
||||||
except:
|
|
||||||
self._min_rate = 0
|
|
||||||
self._max_rate = 0
|
|
||||||
self._has_rate = False
|
|
||||||
try:
|
|
||||||
sapi4.VolumeLeft = sapi4.VolumeLeft
|
|
||||||
self._min_volume = sapi4.MinVolumeLeft
|
|
||||||
self._max_volume = sapi4.MaxVolumeLeft
|
|
||||||
self._has_volume = True
|
|
||||||
except:
|
|
||||||
self._min_volume = 0
|
|
||||||
self._max_volume = 0
|
|
||||||
self._has_volume = False
|
|
||||||
|
|
||||||
def _available_voices(self):
|
|
||||||
voice_list = []
|
|
||||||
for voice_no in range(1, self.__object.CountEngines):
|
|
||||||
voice_list.append(self.__object.ModeName(voice_no))
|
|
||||||
return voice_list
|
|
||||||
|
|
||||||
@property
|
|
||||||
def available_voices(self):
|
|
||||||
return self._voice_list
|
|
||||||
|
|
||||||
def list_voices(self):
|
|
||||||
return self.available_voices
|
|
||||||
|
|
||||||
def get_voice(self):
|
|
||||||
return self.__object.ModeName(self._voice_no)
|
|
||||||
|
|
||||||
def set_voice(self, value):
|
|
||||||
self._voice_no = self.list_voices().index(value) + 1
|
|
||||||
self.__object.Select(self._voice_no)
|
|
||||||
self.silence()
|
|
||||||
self.__object.Speak(" ")
|
|
||||||
self._set_capabilities()
|
|
||||||
|
|
||||||
def get_pitch(self):
|
|
||||||
if self.has_pitch:
|
|
||||||
return self.__object.Pitch
|
|
||||||
|
|
||||||
def set_pitch(self, value):
|
|
||||||
if self.has_pitch:
|
|
||||||
self.__object.Pitch = value
|
|
||||||
|
|
||||||
def get_rate(self):
|
|
||||||
if self.has_rate:
|
|
||||||
return self.__object.Speed
|
|
||||||
|
|
||||||
def set_rate(self, value):
|
|
||||||
if self.has_rate:
|
|
||||||
self.__object.Speed = value
|
|
||||||
|
|
||||||
def get_volume(self):
|
|
||||||
if self.has_volume:
|
|
||||||
return self.__object.VolumeLeft
|
|
||||||
|
|
||||||
def set_volume(self, value):
|
|
||||||
if self.has_volume:
|
|
||||||
self.__object.VolumeLeft = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def has_pitch(self):
|
|
||||||
return self._has_pitch
|
|
||||||
|
|
||||||
@property
|
|
||||||
def has_rate(self):
|
|
||||||
return self._has_rate
|
|
||||||
|
|
||||||
@property
|
|
||||||
def has_volume(self):
|
|
||||||
return self._has_volume
|
|
||||||
|
|
||||||
@property
|
|
||||||
def min_pitch(self):
|
|
||||||
return self._min_pitch
|
|
||||||
|
|
||||||
@property
|
|
||||||
def max_pitch(self):
|
|
||||||
return self._max_pitch
|
|
||||||
|
|
||||||
@property
|
|
||||||
def min_rate(self):
|
|
||||||
return self._min_rate
|
|
||||||
|
|
||||||
@property
|
|
||||||
def max_rate(self):
|
|
||||||
return self._max_rate
|
|
||||||
|
|
||||||
@property
|
|
||||||
def min_volume(self):
|
|
||||||
return self._min_volume
|
|
||||||
|
|
||||||
@property
|
|
||||||
def max_volume(self):
|
|
||||||
return self._max_volume
|
|
||||||
|
|
||||||
def speak(self, text, interrupt=False):
|
|
||||||
if interrupt:
|
|
||||||
self.silence()
|
|
||||||
self.__object.Speak(text)
|
|
||||||
|
|
||||||
def silence(self):
|
|
||||||
self.__object.AudioReset()
|
|
||||||
|
|
||||||
output_class = Sapi4
|
|
@@ -1,95 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
from collections import OrderedDict
|
|
||||||
from libloader.com import load_com
|
|
||||||
from .base import Output, OutputError
|
|
||||||
import pywintypes
|
|
||||||
import logging
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
SVSFDefault = 0
|
|
||||||
SVSFlagsAsync = 1
|
|
||||||
SVSFPurgeBeforeSpeak = 2
|
|
||||||
SVSFIsFilename = 4
|
|
||||||
SVSFIsXML = 8
|
|
||||||
SVSFIsNotXML = 16
|
|
||||||
SVSFPersistXML = 32
|
|
||||||
|
|
||||||
class SAPI5(Output):
|
|
||||||
has_volume = True
|
|
||||||
has_rate = True
|
|
||||||
has_pitch = True
|
|
||||||
min_pitch = -10
|
|
||||||
max_pitch = 10
|
|
||||||
min_rate = -10
|
|
||||||
max_rate = 10
|
|
||||||
min_volume = 0
|
|
||||||
max_volume = 100
|
|
||||||
name = "sapi5"
|
|
||||||
priority = 101
|
|
||||||
system_output = True
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
try:
|
|
||||||
self.object = load_com("SAPI.SPVoice")
|
|
||||||
self._voices = self._available_voices()
|
|
||||||
except pywintypes.com_error:
|
|
||||||
raise OutputError
|
|
||||||
self._pitch = 0
|
|
||||||
|
|
||||||
def _available_voices(self):
|
|
||||||
_voices = OrderedDict()
|
|
||||||
for v in self.object.GetVoices():
|
|
||||||
_voices[v.GetDescription()] = v
|
|
||||||
return _voices
|
|
||||||
|
|
||||||
def list_voices(self):
|
|
||||||
return list(self._voices.keys())
|
|
||||||
|
|
||||||
def get_voice(self):
|
|
||||||
return self.object.Voice.GetDescription()
|
|
||||||
|
|
||||||
def set_voice(self, value):
|
|
||||||
log.debug("Setting SAPI5 voice to \"%s\"" % value)
|
|
||||||
self.object.Voice = self._voices[value]
|
|
||||||
# For some reason SAPI5 does not reset audio after changing the voice
|
|
||||||
# By setting the audio device after changing voices seems to fix this
|
|
||||||
# This was noted from information at:
|
|
||||||
# http://lists.nvaccess.org/pipermail/nvda-dev/2011-November/022464.html
|
|
||||||
self.object.AudioOutput = self.object.AudioOutput
|
|
||||||
|
|
||||||
def get_pitch(self):
|
|
||||||
return self._pitch
|
|
||||||
|
|
||||||
def set_pitch(self, value):
|
|
||||||
log.debug("Setting pitch to %d" % value)
|
|
||||||
self._pitch = value
|
|
||||||
|
|
||||||
def get_rate(self):
|
|
||||||
return self.object.Rate
|
|
||||||
|
|
||||||
def set_rate(self, value):
|
|
||||||
log.debug("Setting rate to %d" % value)
|
|
||||||
self.object.Rate = value
|
|
||||||
|
|
||||||
def get_volume(self):
|
|
||||||
return self.object.Volume
|
|
||||||
|
|
||||||
def set_volume(self, value):
|
|
||||||
self.object.Volume = value
|
|
||||||
|
|
||||||
def speak(self, text, interrupt=False):
|
|
||||||
if interrupt:
|
|
||||||
self.silence()
|
|
||||||
# We need to do the pitch in XML here
|
|
||||||
textOutput = "<pitch absmiddle=\"%d\">%s</pitch>" % (round(self._pitch), text.replace("<", "<"))
|
|
||||||
self.object.Speak(textOutput, SVSFlagsAsync | SVSFIsXML)
|
|
||||||
|
|
||||||
def silence(self):
|
|
||||||
self.object.Speak("", SVSFlagsAsync | SVSFPurgeBeforeSpeak)
|
|
||||||
|
|
||||||
def is_active(self):
|
|
||||||
if self.object:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
output_class = SAPI5
|
|
@@ -1,21 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
import os
|
|
||||||
from .base import Output
|
|
||||||
|
|
||||||
class AppleSay(Output):
|
|
||||||
"""Speech output supporting the Apple Say subsystem."""
|
|
||||||
name = 'Apple Say'
|
|
||||||
def __init__(self, voice = 'Alex', rate = '300'):
|
|
||||||
self.voice = voice
|
|
||||||
self.rate = rate
|
|
||||||
super(AppleSay, self).__init__()
|
|
||||||
def is_active(self):
|
|
||||||
return not os.system('which say')
|
|
||||||
def speak(self, text, interrupt = 0):
|
|
||||||
if interrupt:
|
|
||||||
self.silence()
|
|
||||||
os.system('say -v %s -r %s "%s" &' % (self.voice, self.rate, text))
|
|
||||||
def silence(self):
|
|
||||||
os.system('killall say')
|
|
||||||
|
|
||||||
output_class = AppleSay
|
|
@@ -1,29 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
import ctypes
|
|
||||||
from .base import Output
|
|
||||||
|
|
||||||
class SystemAccess (Output):
|
|
||||||
"""Supports System Access and System Access Mobile"""
|
|
||||||
|
|
||||||
name = "System Access"
|
|
||||||
lib32 = 'saapi32.dll'
|
|
||||||
argtypes = {
|
|
||||||
'SA_BrlShowTextW': (ctypes.c_wchar_p,),
|
|
||||||
'SA_SayW': (ctypes.c_wchar_p,),
|
|
||||||
}
|
|
||||||
priority = 99
|
|
||||||
|
|
||||||
def braille(self, text, **options):
|
|
||||||
self.lib.SA_BrlShowTextW(text)
|
|
||||||
|
|
||||||
def speak(self, text, interrupt=False):
|
|
||||||
if self.is_active():
|
|
||||||
self.dll.SA_SayW(str(text))
|
|
||||||
|
|
||||||
def is_active(self):
|
|
||||||
try:
|
|
||||||
return self.dll.SA_IsRunning()
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
output_class = SystemAccess
|
|
@@ -1 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
@@ -1,33 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
import win32gui
|
|
||||||
from libloader.com import load_com
|
|
||||||
from .base import Output, OutputError
|
|
||||||
import pywintypes
|
|
||||||
|
|
||||||
class WindowEyes (Output):
|
|
||||||
"""Speech output supporting the WindowEyes screen reader"""
|
|
||||||
|
|
||||||
name = 'Window-Eyes'
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(WindowEyes, self).__init__(*args, **kwargs)
|
|
||||||
try:
|
|
||||||
self.object = load_com("gwspeak.speak")
|
|
||||||
except pywintypes.com_error:
|
|
||||||
raise OutputError
|
|
||||||
|
|
||||||
def speak(self, text, interrupt=0):
|
|
||||||
if interrupt:
|
|
||||||
self.silence()
|
|
||||||
self.object.SpeakString(text)
|
|
||||||
|
|
||||||
def silence (self):
|
|
||||||
self.object.Silence()
|
|
||||||
|
|
||||||
def is_active(self):
|
|
||||||
try:
|
|
||||||
return win32gui.FindWindow("GWMExternalControl", "External Control") != 0
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
output_class = WindowEyes
|
|
@@ -8,7 +8,7 @@ if snapshot == False:
|
|||||||
update_url = 'https://twblue.es/updates/stable.php'
|
update_url = 'https://twblue.es/updates/stable.php'
|
||||||
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json'
|
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/stable.json'
|
||||||
else:
|
else:
|
||||||
version = "11"
|
version = "12"
|
||||||
update_url = 'https://twblue.es/updates/snapshot.php'
|
update_url = 'https://twblue.es/updates/snapshot.php'
|
||||||
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json'
|
mirror_update_url = 'https://raw.githubusercontent.com/manuelcortez/TWBlue/next-gen/updates/snapshots.json'
|
||||||
authors = [u"Manuel Cortéz", u"José Manuel Delicado"]
|
authors = [u"Manuel Cortéz", u"José Manuel Delicado"]
|
||||||
|
@@ -33,5 +33,12 @@ def convert_soundcloud (url):
|
|||||||
def convert_youtube_long (url):
|
def convert_youtube_long (url):
|
||||||
return youtube_utils.get_video_url(url)
|
return youtube_utils.get_video_url(url)
|
||||||
|
|
||||||
|
@matches_url ('http://anyaudio.net/listen')
|
||||||
|
def convert_anyaudio(url):
|
||||||
|
values = url.split("audio=")
|
||||||
|
if len(values) != 2:
|
||||||
|
raise TypeError('%r is not streamable' % url)
|
||||||
|
return "http://anyaudio.net/audiodownload?audio=%s" % (values[1],)
|
||||||
|
|
||||||
def convert_generic_audio(url):
|
def convert_generic_audio(url):
|
||||||
return url
|
return url
|
||||||
|
@@ -128,7 +128,7 @@ class baseBufferController(baseBuffers.buffer):
|
|||||||
tweetsList = []
|
tweetsList = []
|
||||||
tweet_id = tweet["id"]
|
tweet_id = tweet["id"]
|
||||||
message = None
|
message = None
|
||||||
if tweet.has_key("message"):
|
if "message" in tweet:
|
||||||
message = tweet["message"]
|
message = tweet["message"]
|
||||||
try:
|
try:
|
||||||
tweet = self.session.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")
|
||||||
@@ -241,7 +241,7 @@ class baseBufferController(baseBuffers.buffer):
|
|||||||
if self.name[:-9] in self.session.settings["other_buffers"]["timelines"]:
|
if self.name[:-9] in self.session.settings["other_buffers"]["timelines"]:
|
||||||
self.session.settings["other_buffers"]["timelines"].remove(self.name[:-9])
|
self.session.settings["other_buffers"]["timelines"].remove(self.name[:-9])
|
||||||
self.session.settings.write()
|
self.session.settings.write()
|
||||||
if self.session.db.has_key(self.name):
|
if self.name in self.session.db:
|
||||||
self.session.db.pop(self.name)
|
self.session.db.pop(self.name)
|
||||||
return True
|
return True
|
||||||
elif dlg == widgetUtils.NO:
|
elif dlg == widgetUtils.NO:
|
||||||
@@ -254,7 +254,7 @@ class baseBufferController(baseBuffers.buffer):
|
|||||||
if dlg == widgetUtils.YES:
|
if dlg == widgetUtils.YES:
|
||||||
if self.name[:-9] in self.session.settings["other_buffers"]["favourites_timelines"]:
|
if self.name[:-9] in self.session.settings["other_buffers"]["favourites_timelines"]:
|
||||||
self.session.settings["other_buffers"]["favourites_timelines"].remove(self.name[:-9])
|
self.session.settings["other_buffers"]["favourites_timelines"].remove(self.name[:-9])
|
||||||
if self.session.db.has_key(self.name):
|
if self.name in self.session.db:
|
||||||
self.session.db.pop(self.name)
|
self.session.db.pop(self.name)
|
||||||
self.session.settings.write()
|
self.session.settings.write()
|
||||||
return True
|
return True
|
||||||
@@ -344,6 +344,8 @@ class baseBufferController(baseBuffers.buffer):
|
|||||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view)
|
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.copy, menuitem=menu.copy)
|
||||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.destroy_status, menuitem=menu.remove)
|
widgetUtils.connect_event(menu, widgetUtils.MENU, self.destroy_status, menuitem=menu.remove)
|
||||||
|
if hasattr(menu, "openInBrowser"):
|
||||||
|
widgetUtils.connect_event(menu, widgetUtils.MENU, self.open_in_browser, menuitem=menu.openInBrowser)
|
||||||
if pos != 0:
|
if pos != 0:
|
||||||
self.buffer.PopupMenu(menu, pos)
|
self.buffer.PopupMenu(menu, pos)
|
||||||
else:
|
else:
|
||||||
@@ -377,7 +379,7 @@ class baseBufferController(baseBuffers.buffer):
|
|||||||
self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
|
self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
|
||||||
|
|
||||||
def get_tweet(self):
|
def get_tweet(self):
|
||||||
if self.session.db[self.name][self.buffer.list.get_selected()].has_key("retweeted_status"):
|
if "retweeted_status" in self.session.db[self.name][self.buffer.list.get_selected()]:
|
||||||
tweet = self.session.db[self.name][self.buffer.list.get_selected()]["retweeted_status"]
|
tweet = self.session.db[self.name][self.buffer.list.get_selected()]["retweeted_status"]
|
||||||
else:
|
else:
|
||||||
tweet = self.session.db[self.name][self.buffer.list.get_selected()]
|
tweet = self.session.db[self.name][self.buffer.list.get_selected()]
|
||||||
@@ -392,7 +394,7 @@ class baseBufferController(baseBuffers.buffer):
|
|||||||
tweet = self.get_right_tweet()
|
tweet = self.get_right_tweet()
|
||||||
screen_name = tweet["user"]["screen_name"]
|
screen_name = tweet["user"]["screen_name"]
|
||||||
id = tweet["id"]
|
id = tweet["id"]
|
||||||
twishort_enabled = tweet.has_key("twishort")
|
twishort_enabled = "twishort" in tweet
|
||||||
users = utils.get_all_mentioned(tweet, self.session.db, field="screen_name")
|
users = utils.get_all_mentioned(tweet, self.session.db, field="screen_name")
|
||||||
ids = utils.get_all_mentioned(tweet, self.session.db, field="id_str")
|
ids = utils.get_all_mentioned(tweet, self.session.db, field="id_str")
|
||||||
# Build the window title
|
# Build the window title
|
||||||
@@ -489,9 +491,9 @@ class baseBufferController(baseBuffers.buffer):
|
|||||||
|
|
||||||
def _retweet_with_comment(self, tweet, id, comment=''):
|
def _retweet_with_comment(self, tweet, id, comment=''):
|
||||||
# If quoting a retweet, let's quote the original tweet instead the retweet.
|
# If quoting a retweet, let's quote the original tweet instead the retweet.
|
||||||
if tweet.has_key("retweeted_status"):
|
if "retweeted_status" in tweet:
|
||||||
tweet = tweet["retweeted_status"]
|
tweet = tweet["retweeted_status"]
|
||||||
if tweet.has_key("full_text"):
|
if "full_text" in tweet:
|
||||||
comments = tweet["full_text"]
|
comments = tweet["full_text"]
|
||||||
else:
|
else:
|
||||||
comments = tweet["text"]
|
comments = tweet["text"]
|
||||||
@@ -627,6 +629,12 @@ class baseBufferController(baseBuffers.buffer):
|
|||||||
except IndexError: pass
|
except IndexError: pass
|
||||||
return compose.compose_quoted_tweet(quoted_tweet, original_tweet, self.session.db, self.session.settings["general"]["relative_times"])
|
return compose.compose_quoted_tweet(quoted_tweet, original_tweet, self.session.db, self.session.settings["general"]["relative_times"])
|
||||||
|
|
||||||
|
def open_in_browser(self, *args, **kwargs):
|
||||||
|
tweet = self.get_tweet()
|
||||||
|
output.speak(_(u"Opening item in web browser..."))
|
||||||
|
url = "https://twitter.com/{screen_name}/status/{tweet_id}".format(screen_name=tweet["user"]["screen_name"], tweet_id=tweet["id"])
|
||||||
|
webbrowser.open(url)
|
||||||
|
|
||||||
class directMessagesController(baseBufferController):
|
class directMessagesController(baseBufferController):
|
||||||
|
|
||||||
def get_more_items(self):
|
def get_more_items(self):
|
||||||
@@ -719,11 +727,14 @@ class directMessagesController(baseBufferController):
|
|||||||
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:
|
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,))
|
output.speak(_(u"{0} new direct messages.").format(number_of_items,))
|
||||||
|
|
||||||
|
def open_in_browser(self, *args, **kwargs):
|
||||||
|
output.speak(_(u"This action is not supported in the buffer yet."))
|
||||||
|
|
||||||
class sentDirectMessagesController(directMessagesController):
|
class sentDirectMessagesController(directMessagesController):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(sentDirectMessagesController, self).__init__(*args, **kwargs)
|
super(sentDirectMessagesController, self).__init__(*args, **kwargs)
|
||||||
if self.session.db.has_key("sent_direct_messages") == False:
|
if ("sent_direct_messages" in self.session.db) == False:
|
||||||
self.session.db["sent_direct_messages"] = {"items": []}
|
self.session.db["sent_direct_messages"] = {"items": []}
|
||||||
|
|
||||||
def get_more_items(self):
|
def get_more_items(self):
|
||||||
@@ -770,7 +781,7 @@ class listBufferController(baseBufferController):
|
|||||||
if dlg == widgetUtils.YES:
|
if dlg == widgetUtils.YES:
|
||||||
if self.name[:-5] in self.session.settings["other_buffers"]["lists"]:
|
if self.name[:-5] in self.session.settings["other_buffers"]["lists"]:
|
||||||
self.session.settings["other_buffers"]["lists"].remove(self.name[:-5])
|
self.session.settings["other_buffers"]["lists"].remove(self.name[:-5])
|
||||||
if self.session.db.has_key(self.name):
|
if self.name in self.session.db:
|
||||||
self.session.db.pop(self.name)
|
self.session.db.pop(self.name)
|
||||||
self.session.settings.write()
|
self.session.settings.write()
|
||||||
return True
|
return True
|
||||||
@@ -805,7 +816,7 @@ class peopleBufferController(baseBufferController):
|
|||||||
if dlg == widgetUtils.YES:
|
if dlg == widgetUtils.YES:
|
||||||
if self.name[:-10] in self.session.settings["other_buffers"]["followers_timelines"]:
|
if self.name[:-10] in self.session.settings["other_buffers"]["followers_timelines"]:
|
||||||
self.session.settings["other_buffers"]["followers_timelines"].remove(self.name[:-10])
|
self.session.settings["other_buffers"]["followers_timelines"].remove(self.name[:-10])
|
||||||
if self.session.db.has_key(self.name):
|
if self.name in self.session.db:
|
||||||
self.session.db.pop(self.name)
|
self.session.db.pop(self.name)
|
||||||
self.session.settings.write()
|
self.session.settings.write()
|
||||||
return True
|
return True
|
||||||
@@ -819,7 +830,7 @@ class peopleBufferController(baseBufferController):
|
|||||||
if dlg == widgetUtils.YES:
|
if dlg == widgetUtils.YES:
|
||||||
if self.name[:-8] in self.session.settings["other_buffers"]["friends_timelines"]:
|
if self.name[:-8] in self.session.settings["other_buffers"]["friends_timelines"]:
|
||||||
self.session.settings["other_buffers"]["friends_timelines"].remove(self.name[:-8])
|
self.session.settings["other_buffers"]["friends_timelines"].remove(self.name[:-8])
|
||||||
if self.session.db.has_key(self.name):
|
if self.name in self.session.db:
|
||||||
self.session.db.pop(self.name)
|
self.session.db.pop(self.name)
|
||||||
self.session.settings.write()
|
self.session.settings.write()
|
||||||
return True
|
return True
|
||||||
@@ -951,6 +962,8 @@ class peopleBufferController(baseBufferController):
|
|||||||
# widgetUtils.connect_event(menu, widgetUtils.MENU, self.lists, menuitem=menu.lists)
|
# widgetUtils.connect_event(menu, widgetUtils.MENU, self.lists, menuitem=menu.lists)
|
||||||
widgetUtils.connect_event(menu, widgetUtils.MENU, self.view, menuitem=menu.view)
|
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.copy, menuitem=menu.copy)
|
||||||
|
if hasattr(menu, "openInBrowser"):
|
||||||
|
widgetUtils.connect_event(menu, widgetUtils.MENU, self.open_in_browser, menuitem=menu.openInBrowser)
|
||||||
if pos != 0:
|
if pos != 0:
|
||||||
self.buffer.PopupMenu(menu, pos)
|
self.buffer.PopupMenu(menu, pos)
|
||||||
else:
|
else:
|
||||||
@@ -969,6 +982,12 @@ class peopleBufferController(baseBufferController):
|
|||||||
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:
|
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))
|
output.speak(_(u"{0} new followers.").format(number_of_items))
|
||||||
|
|
||||||
|
def open_in_browser(self, *args, **kwargs):
|
||||||
|
tweet = self.get_tweet()
|
||||||
|
output.speak(_(u"Opening item in web browser..."))
|
||||||
|
url = "https://twitter.com/{screen_name}".format(screen_name=tweet["screen_name"])
|
||||||
|
webbrowser.open(url)
|
||||||
|
|
||||||
class searchBufferController(baseBufferController):
|
class searchBufferController(baseBufferController):
|
||||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||||
# starts stream every 3 minutes.
|
# starts stream every 3 minutes.
|
||||||
@@ -1000,7 +1019,7 @@ class searchBufferController(baseBufferController):
|
|||||||
if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]:
|
if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]:
|
||||||
self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11])
|
self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11])
|
||||||
self.session.settings.write()
|
self.session.settings.write()
|
||||||
if self.session.db.has_key(self.name):
|
if self.name in self.session.db:
|
||||||
self.session.db.pop(self.name)
|
self.session.db.pop(self.name)
|
||||||
return True
|
return True
|
||||||
elif dlg == widgetUtils.NO:
|
elif dlg == widgetUtils.NO:
|
||||||
@@ -1051,7 +1070,7 @@ class searchPeopleBufferController(peopleBufferController):
|
|||||||
self.args = args
|
self.args = args
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
self.function = function
|
self.function = function
|
||||||
if self.kwargs.has_key("page") == False:
|
if ("page" in self.kwargs) == False:
|
||||||
self.kwargs["page"] = 1
|
self.kwargs["page"] = 1
|
||||||
|
|
||||||
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=True):
|
def start_stream(self, mandatory=False, play_sound=True, avoid_autoreading=True):
|
||||||
@@ -1115,7 +1134,7 @@ class searchPeopleBufferController(peopleBufferController):
|
|||||||
if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]:
|
if self.name[:-11] in self.session.settings["other_buffers"]["tweet_searches"]:
|
||||||
self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11])
|
self.session.settings["other_buffers"]["tweet_searches"].remove(self.name[:-11])
|
||||||
self.session.settings.write()
|
self.session.settings.write()
|
||||||
if self.session.db.has_key(self.name):
|
if self.name in self.session.db:
|
||||||
self.session.db.pop(self.name)
|
self.session.db.pop(self.name)
|
||||||
return True
|
return True
|
||||||
elif dlg == widgetUtils.NO:
|
elif dlg == widgetUtils.NO:
|
||||||
@@ -1188,7 +1207,7 @@ class trendsBufferController(baseBuffers.buffer):
|
|||||||
if self.name[:-3] in self.session.settings["other_buffers"]["trending_topic_buffers"]:
|
if self.name[:-3] in self.session.settings["other_buffers"]["trending_topic_buffers"]:
|
||||||
self.session.settings["other_buffers"]["trending_topic_buffers"].remove(self.name[:-3])
|
self.session.settings["other_buffers"]["trending_topic_buffers"].remove(self.name[:-3])
|
||||||
self.session.settings.write()
|
self.session.settings.write()
|
||||||
if self.session.db.has_key(self.name):
|
if self.name in self.session.db:
|
||||||
self.session.db.pop(self.name)
|
self.session.db.pop(self.name)
|
||||||
return True
|
return True
|
||||||
elif dlg == widgetUtils.NO:
|
elif dlg == widgetUtils.NO:
|
||||||
@@ -1243,6 +1262,9 @@ class trendsBufferController(baseBuffers.buffer):
|
|||||||
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
|
if ev.GetKeyCode() == wx.WXK_WINDOWS_MENU:
|
||||||
self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
|
self.show_menu(widgetUtils.MENU, pos=self.buffer.list.list.GetPosition())
|
||||||
|
|
||||||
|
def open_in_browser(self, *args, **kwargs):
|
||||||
|
output.speak(_(u"This action is not supported in the buffer, yet."))
|
||||||
|
|
||||||
class conversationBufferController(searchBufferController):
|
class conversationBufferController(searchBufferController):
|
||||||
|
|
||||||
def start_stream(self, start=False, mandatory=False, play_sound=True, avoid_autoreading=False):
|
def start_stream(self, start=False, mandatory=False, play_sound=True, avoid_autoreading=False):
|
||||||
@@ -1288,7 +1310,7 @@ class conversationBufferController(searchBufferController):
|
|||||||
else:
|
else:
|
||||||
dlg = widgetUtils.YES
|
dlg = widgetUtils.YES
|
||||||
if dlg == widgetUtils.YES:
|
if dlg == widgetUtils.YES:
|
||||||
if self.session.db.has_key(self.name):
|
if self.name in self.session.db:
|
||||||
self.session.db.pop(self.name)
|
self.session.db.pop(self.name)
|
||||||
return True
|
return True
|
||||||
elif dlg == widgetUtils.NO:
|
elif dlg == widgetUtils.NO:
|
||||||
|
@@ -30,7 +30,7 @@ class filter(object):
|
|||||||
if i["name"] in langs:
|
if i["name"] in langs:
|
||||||
langcodes.append(i["code"])
|
langcodes.append(i["code"])
|
||||||
d = dict(in_buffer=self.buffer.name, word=term, regexp=regexp, in_lang=lang_option, languages=langcodes, if_word_exists=contains, allow_rts=allow_rts, allow_quotes=allow_quotes, allow_replies=allow_replies)
|
d = dict(in_buffer=self.buffer.name, word=term, regexp=regexp, in_lang=lang_option, languages=langcodes, if_word_exists=contains, allow_rts=allow_rts, allow_quotes=allow_quotes, allow_replies=allow_replies)
|
||||||
if self.buffer.session.settings["filters"].has_key(title):
|
if title in self.buffer.session.settings["filters"]:
|
||||||
return commonMessageDialogs.existing_filter()
|
return commonMessageDialogs.existing_filter()
|
||||||
self.buffer.session.settings["filters"][title] = d
|
self.buffer.session.settings["filters"][title] = d
|
||||||
self.buffer.session.settings.write()
|
self.buffer.session.settings.write()
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import absolute_import
|
||||||
import platform
|
import platform
|
||||||
system = platform.system()
|
system = platform.system()
|
||||||
import application
|
import application
|
||||||
@@ -8,15 +9,15 @@ import arrow
|
|||||||
if system == "Windows":
|
if system == "Windows":
|
||||||
from update import updater
|
from update import updater
|
||||||
from wxUI import (view, dialogs, commonMessageDialogs, sysTrayIcon)
|
from wxUI import (view, dialogs, commonMessageDialogs, sysTrayIcon)
|
||||||
import settings
|
from . import settings
|
||||||
from extra import SoundsTutorial, ocr
|
from extra import SoundsTutorial, ocr
|
||||||
import keystrokeEditor
|
import keystrokeEditor
|
||||||
from keyboard_handler.wx_handler import WXKeyboardHandler
|
from keyboard_handler.wx_handler import WXKeyboardHandler
|
||||||
import userActionsController
|
from . import userActionsController
|
||||||
import trendingTopics
|
from . import trendingTopics
|
||||||
import user
|
from . import user
|
||||||
import listsController
|
from . import listsController
|
||||||
import filterController
|
from . import filterController
|
||||||
# from issueReporter import issueReporter
|
# from issueReporter import issueReporter
|
||||||
elif system == "Linux":
|
elif system == "Linux":
|
||||||
from gtkUI import (view, commonMessageDialogs)
|
from gtkUI import (view, commonMessageDialogs)
|
||||||
@@ -24,7 +25,7 @@ from sessions.twitter import utils, compose
|
|||||||
from sessionmanager import manager, sessionManager
|
from sessionmanager import manager, sessionManager
|
||||||
|
|
||||||
from controller.buffers import baseBuffers, twitterBuffers
|
from controller.buffers import baseBuffers, twitterBuffers
|
||||||
import messages
|
from . import messages
|
||||||
import sessions
|
import sessions
|
||||||
from sessions.twitter import session as session_
|
from sessions.twitter import session as session_
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
@@ -392,7 +393,7 @@ class Controller(object):
|
|||||||
def set_buffer_positions(self, session):
|
def set_buffer_positions(self, session):
|
||||||
"Sets positions for buffers if values exist in the database."
|
"Sets positions for buffers if values exist in the database."
|
||||||
for i in self.buffers:
|
for i in self.buffers:
|
||||||
if i.account == session.db["user_name"] and session.db.has_key(i.name+"_pos") and hasattr(i.buffer,'list'):
|
if i.account == session.db["user_name"] and i.name+"_pos" in session.db and hasattr(i.buffer,'list'):
|
||||||
i.buffer.list.select_item(session.db[str(i.name+"_pos")])
|
i.buffer.list.select_item(session.db[str(i.name+"_pos")])
|
||||||
|
|
||||||
def logout_account(self, session_id):
|
def logout_account(self, session_id):
|
||||||
@@ -655,6 +656,9 @@ class Controller(object):
|
|||||||
sessions.sessions[item].shelve()
|
sessions.sessions[item].shelve()
|
||||||
if system == "Windows":
|
if system == "Windows":
|
||||||
self.systrayIcon.RemoveIcon()
|
self.systrayIcon.RemoveIcon()
|
||||||
|
pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name))
|
||||||
|
if os.path.exists(pidpath):
|
||||||
|
os.remove(pidpath)
|
||||||
widgetUtils.exit_application()
|
widgetUtils.exit_application()
|
||||||
|
|
||||||
def follow(self, *args, **kwargs):
|
def follow(self, *args, **kwargs):
|
||||||
@@ -808,6 +812,11 @@ class Controller(object):
|
|||||||
non_tweet = buffer.get_formatted_message()
|
non_tweet = buffer.get_formatted_message()
|
||||||
msg = messages.viewTweet(non_tweet, [], False)
|
msg = messages.viewTweet(non_tweet, [], False)
|
||||||
|
|
||||||
|
def view_in_browser(self, *args, **kwargs):
|
||||||
|
buffer = self.get_current_buffer()
|
||||||
|
if hasattr(buffer, "open_in_browser"):
|
||||||
|
buffer.open_in_browser()
|
||||||
|
|
||||||
def open_favs_timeline(self, *args, **kwargs):
|
def open_favs_timeline(self, *args, **kwargs):
|
||||||
self.open_timeline(default="favourites")
|
self.open_timeline(default="favourites")
|
||||||
|
|
||||||
@@ -1563,7 +1572,7 @@ class Controller(object):
|
|||||||
output.speak(_(u"Invalid buffer"))
|
output.speak(_(u"Invalid buffer"))
|
||||||
return
|
return
|
||||||
tweet = buffer.get_tweet()
|
tweet = buffer.get_tweet()
|
||||||
if tweet.has_key("entities") == False or tweet["entities"].has_key("media") == False:
|
if ("entities" in tweet) == False or ("media" in tweet["entities"]) == False:
|
||||||
output.speak(_(u"This tweet doesn't contain images"))
|
output.speak(_(u"This tweet doesn't contain images"))
|
||||||
return
|
return
|
||||||
if len(tweet["entities"]["media"]) > 1:
|
if len(tweet["entities"]["media"]) > 1:
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import absolute_import
|
||||||
import re
|
import re
|
||||||
import platform
|
import platform
|
||||||
import attach
|
from . import attach
|
||||||
import arrow
|
import arrow
|
||||||
import languageHandler
|
import languageHandler
|
||||||
system = platform.system()
|
system = platform.system()
|
||||||
@@ -206,25 +207,25 @@ class viewTweet(basicTweet):
|
|||||||
text = ""
|
text = ""
|
||||||
for i in xrange(0, len(tweetList)):
|
for i in xrange(0, len(tweetList)):
|
||||||
# tweets with message keys are longer tweets, the message value is the full messaje taken from twishort.
|
# tweets with message keys are longer tweets, the message value is the full messaje taken from twishort.
|
||||||
if tweetList[i].has_key("message") and tweetList[i]["is_quote_status"] == False:
|
if "message" in tweetList[i] and tweetList[i]["is_quote_status"] == False:
|
||||||
value = "message"
|
value = "message"
|
||||||
else:
|
else:
|
||||||
value = "full_text"
|
value = "full_text"
|
||||||
if tweetList[i].has_key("retweeted_status") and tweetList[i]["is_quote_status"] == False:
|
if "retweeted_status" in tweetList[i] and tweetList[i]["is_quote_status"] == False:
|
||||||
if tweetList[i].has_key("message") == False:
|
if ("message" in tweetList[i]) == False:
|
||||||
text = text + "rt @%s: %s\n" % (tweetList[i]["retweeted_status"]["user"]["screen_name"], tweetList[i]["retweeted_status"]["full_text"])
|
text = text + "rt @%s: %s\n" % (tweetList[i]["retweeted_status"]["user"]["screen_name"], tweetList[i]["retweeted_status"]["full_text"])
|
||||||
else:
|
else:
|
||||||
text = text + "rt @%s: %s\n" % (tweetList[i]["retweeted_status"]["user"]["screen_name"], tweetList[i][value])
|
text = text + "rt @%s: %s\n" % (tweetList[i]["retweeted_status"]["user"]["screen_name"], tweetList[i][value])
|
||||||
else:
|
else:
|
||||||
text = text + " @%s: %s\n" % (tweetList[i]["user"]["screen_name"], tweetList[i][value])
|
text = text + " @%s: %s\n" % (tweetList[i]["user"]["screen_name"], tweetList[i][value])
|
||||||
# tweets with extended_entities could include image descriptions.
|
# tweets with extended_entities could include image descriptions.
|
||||||
if tweetList[i].has_key("extended_entities") and tweetList[i]["extended_entities"].has_key("media"):
|
if "extended_entities" in tweetList[i] and "media" in tweetList[i]["extended_entities"]:
|
||||||
for z in tweetList[i]["extended_entities"]["media"]:
|
for z in tweetList[i]["extended_entities"]["media"]:
|
||||||
if z.has_key("ext_alt_text") and z["ext_alt_text"] != None:
|
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||||
image_description.append(z["ext_alt_text"])
|
image_description.append(z["ext_alt_text"])
|
||||||
if tweetList[i].has_key("retweeted_status") and tweetList[i]["retweeted_status"].has_key("extended_entities") and tweetList[i]["retweeted_status"]["extended_entities"].has_key("media"):
|
if "retweeted_status" in tweetList[i] and "extended_entities" in tweetList[i]["retweeted_status"] and "media" in tweetList[i]["retweeted_status"]["extended_entities"]:
|
||||||
for z in tweetList[i]["retweeted_status"]["extended_entities"]["media"]:
|
for z in tweetList[i]["retweeted_status"]["extended_entities"]["media"]:
|
||||||
if z.has_key("ext_alt_text") and z["ext_alt_text"] != None:
|
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||||
image_description.append(z["ext_alt_text"])
|
image_description.append(z["ext_alt_text"])
|
||||||
# set rt and likes counters.
|
# set rt and likes counters.
|
||||||
rt_count = str(tweet["retweet_count"])
|
rt_count = str(tweet["retweet_count"])
|
||||||
@@ -234,25 +235,25 @@ class viewTweet(basicTweet):
|
|||||||
original_date = arrow.get(tweet["created_at"], "ddd MMM DD H:m:s Z YYYY", locale="en")
|
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())
|
date = original_date.replace(seconds=utc_offset).format(_(u"MMM D, YYYY. H:m"), locale=languageHandler.getLanguage())
|
||||||
if text == "":
|
if text == "":
|
||||||
if tweet.has_key("message"):
|
if "message" in tweet:
|
||||||
value = "message"
|
value = "message"
|
||||||
else:
|
else:
|
||||||
value = "full_text"
|
value = "full_text"
|
||||||
if tweet.has_key("retweeted_status"):
|
if "retweeted_status" in tweet:
|
||||||
if tweet.has_key("message") == False:
|
if ("message" in tweet) == False:
|
||||||
text = "rt @%s: %s" % (tweet["retweeted_status"]["user"]["screen_name"], tweet["retweeted_status"]["full_text"])
|
text = "rt @%s: %s" % (tweet["retweeted_status"]["user"]["screen_name"], tweet["retweeted_status"]["full_text"])
|
||||||
else:
|
else:
|
||||||
text = "rt @%s: %s" % (tweet["retweeted_status"]["user"]["screen_name"], tweet[value])
|
text = "rt @%s: %s" % (tweet["retweeted_status"]["user"]["screen_name"], tweet[value])
|
||||||
else:
|
else:
|
||||||
text = tweet[value]
|
text = tweet[value]
|
||||||
text = self.clear_text(text)
|
text = self.clear_text(text)
|
||||||
if tweet.has_key("extended_entities") and tweet["extended_entities"].has_key("media"):
|
if "extended_entities" in tweet and "media" in tweet["extended_entities"]:
|
||||||
for z in tweet["extended_entities"]["media"]:
|
for z in tweet["extended_entities"]["media"]:
|
||||||
if z.has_key("ext_alt_text") and z["ext_alt_text"] != None:
|
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||||
image_description.append(z["ext_alt_text"])
|
image_description.append(z["ext_alt_text"])
|
||||||
if tweet.has_key("retweeted_status") and tweet["retweeted_status"].has_key("extended_entities") and tweet["retweeted_status"]["extended_entities"].has_key("media"):
|
if "retweeted_status" in tweet and "extended_entities" in tweet["retweeted_status"] and "media" in tweet["retweeted_status"]["extended_entities"]:
|
||||||
for z in tweet["retweeted_status"]["extended_entities"]["media"]:
|
for z in tweet["retweeted_status"]["extended_entities"]["media"]:
|
||||||
if z.has_key("ext_alt_text") and z["ext_alt_text"] != None:
|
if "ext_alt_text" in z and z["ext_alt_text"] != None:
|
||||||
image_description.append(z["ext_alt_text"])
|
image_description.append(z["ext_alt_text"])
|
||||||
self.message = message.viewTweet(text, rt_count, favs_count, source.decode("utf-8"), date)
|
self.message = message.viewTweet(text, rt_count, favs_count, source.decode("utf-8"), date)
|
||||||
self.message.set_title(len(text))
|
self.message.set_title(len(text))
|
||||||
|
@@ -18,7 +18,7 @@ import config_utils
|
|||||||
log = logging.getLogger("Settings")
|
log = logging.getLogger("Settings")
|
||||||
import keys
|
import keys
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from platform_utils.autostart import windows as autostart_windows
|
from mysc import autostart as autostart_windows
|
||||||
|
|
||||||
class globalSettingsController(object):
|
class globalSettingsController(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -211,7 +211,7 @@ class accountSettingsController(globalSettingsController):
|
|||||||
else:
|
else:
|
||||||
self.config["general"]["retweet_mode"] = "comment"
|
self.config["general"]["retweet_mode"] = "comment"
|
||||||
buffers_list = self.dialog.buffers.get_list()
|
buffers_list = self.dialog.buffers.get_list()
|
||||||
if set(self.config["general"]["buffer_order"]) != set(buffers_list) or buffers_list != self.config["general"]["buffer_order"]:
|
if buffers_list != self.config["general"]["buffer_order"]:
|
||||||
self.needs_restart = True
|
self.needs_restart = True
|
||||||
self.config["general"]["buffer_order"] = buffers_list
|
self.config["general"]["buffer_order"] = buffers_list
|
||||||
self.config["reporting"]["speech_reporting"] = self.dialog.get_value("reporting", "speech_reporting")
|
self.config["reporting"]["speech_reporting"] = self.dialog.get_value("reporting", "speech_reporting")
|
||||||
@@ -291,10 +291,14 @@ class accountSettingsController(globalSettingsController):
|
|||||||
all_buffers['muted']=_(u"Muted users")
|
all_buffers['muted']=_(u"Muted users")
|
||||||
list_buffers = []
|
list_buffers = []
|
||||||
hidden_buffers=[]
|
hidden_buffers=[]
|
||||||
for i in all_buffers.keys():
|
all_buffers_keys = all_buffers.keys()
|
||||||
if i in self.config["general"]["buffer_order"]:
|
# Check buffers shown first.
|
||||||
|
for i in self.config["general"]["buffer_order"]:
|
||||||
|
if i in all_buffers_keys:
|
||||||
list_buffers.append((i, all_buffers[i], True))
|
list_buffers.append((i, all_buffers[i], True))
|
||||||
else:
|
# This second pass will retrieve all hidden buffers.
|
||||||
|
for i in all_buffers_keys:
|
||||||
|
if i not in self.config["general"]["buffer_order"]:
|
||||||
hidden_buffers.append((i, all_buffers[i], False))
|
hidden_buffers.append((i, all_buffers[i], False))
|
||||||
list_buffers.extend(hidden_buffers)
|
list_buffers.extend(hidden_buffers)
|
||||||
return list_buffers
|
return list_buffers
|
||||||
|
@@ -71,7 +71,7 @@ class userActionsController(object):
|
|||||||
|
|
||||||
def ignore_client(self, user):
|
def ignore_client(self, user):
|
||||||
tweet = self.buffer.get_right_tweet()
|
tweet = self.buffer.get_right_tweet()
|
||||||
if tweet.has_key("sender"):
|
if "sender" in tweet:
|
||||||
output.speak(_(u"You can't ignore direct messages"))
|
output.speak(_(u"You can't ignore direct messages"))
|
||||||
return
|
return
|
||||||
client = re.sub(r"(?s)<.*?>", "", tweet["source"])
|
client = re.sub(r"(?s)<.*?>", "", tweet["source"])
|
||||||
|
@@ -16,10 +16,11 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
############################################################
|
############################################################
|
||||||
|
from __future__ import absolute_import
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import wx_ui
|
from . import wx_ui
|
||||||
import wx_transfer_dialogs
|
from . import wx_transfer_dialogs
|
||||||
import transfer
|
from . import transfer
|
||||||
import output
|
import output
|
||||||
import tempfile
|
import tempfile
|
||||||
import sound
|
import sound
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import absolute_import
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
from utils import convert_bytes
|
from .utils import convert_bytes
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
log = logging.getLogger("extra.AudioUploader.transfer")
|
log = logging.getLogger("extra.AudioUploader.transfer")
|
||||||
from requests_toolbelt.multipart.encoder import MultipartEncoder, MultipartEncoderMonitor
|
from requests_toolbelt.multipart.encoder import MultipartEncoder, MultipartEncoderMonitor
|
||||||
@@ -75,9 +76,9 @@ class Upload(object):
|
|||||||
data = self.response.json()
|
data = self.response.json()
|
||||||
except:
|
except:
|
||||||
return _("Error in file upload: {0}").format(self.data.content,)
|
return _("Error in file upload: {0}").format(self.data.content,)
|
||||||
if data.has_key("url") and data["url"] != "0":
|
if "url" in data and data["url"] != "0":
|
||||||
return data["url"]
|
return data["url"]
|
||||||
elif data.has_key("error") and data["error"] != "0":
|
elif "error" in data and data["error"] != "0":
|
||||||
return data["error"]
|
return data["error"]
|
||||||
else:
|
else:
|
||||||
return _("Error in file upload: {0}").format(self.data.content,)
|
return _("Error in file upload: {0}").format(self.data.content,)
|
@@ -1,6 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import absolute_import
|
||||||
import wx
|
import wx
|
||||||
from utils import *
|
from .utils import *
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
|
|
||||||
class UploadDialog(widgetUtils.BaseDialog):
|
class UploadDialog(widgetUtils.BaseDialog):
|
||||||
|
@@ -1 +1,2 @@
|
|||||||
from soundsTutorial import soundsTutorial
|
from __future__ import absolute_import
|
||||||
|
from .soundsTutorial import soundsTutorial
|
||||||
|
@@ -1,15 +1,16 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import absolute_import
|
||||||
import platform
|
import platform
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import os
|
import os
|
||||||
import paths
|
import paths
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger("extra.SoundsTutorial.soundsTutorial")
|
log = logging.getLogger("extra.SoundsTutorial.soundsTutorial")
|
||||||
import soundsTutorial_constants
|
from . import soundsTutorial_constants
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
import wx_ui as UI
|
from . import wx_ui as UI
|
||||||
elif platform.system() == "Linux":
|
elif platform.system() == "Linux":
|
||||||
import gtk_ui as UI
|
from . import gtk_ui as UI
|
||||||
|
|
||||||
class soundsTutorial(object):
|
class soundsTutorial(object):
|
||||||
def __init__(self, sessionObject):
|
def __init__(self, sessionObject):
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
#-*- coding: utf-8 -*-
|
#-*- coding: utf-8 -*-
|
||||||
import reverse_sort
|
from __future__ import absolute_import
|
||||||
|
#-*- coding: utf-8 -*-
|
||||||
|
from . import reverse_sort
|
||||||
import application
|
import application
|
||||||
actions = reverse_sort.reverse_sort([ ("audio", _(u"Audio tweet.")),
|
actions = reverse_sort.reverse_sort([ ("audio", _(u"Audio tweet.")),
|
||||||
("create_timeline", _(u"User timeline buffer created.")),
|
("create_timeline", _(u"User timeline buffer created.")),
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import spellchecker
|
from __future__ import absolute_import
|
||||||
|
from . import spellchecker
|
||||||
import platform
|
import platform
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
from wx_ui import *
|
from .wx_ui import *
|
@@ -1,14 +1,15 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import absolute_import
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import wx_ui
|
from . import wx_ui
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import output
|
import output
|
||||||
import config
|
import config
|
||||||
import languageHandler
|
import languageHandler
|
||||||
import enchant
|
import enchant
|
||||||
import paths
|
import paths
|
||||||
import twitterFilter
|
from . import twitterFilter
|
||||||
from enchant.checker import SpellChecker
|
from enchant.checker import SpellChecker
|
||||||
from enchant.errors import DictNotFoundError
|
from enchant.errors import DictNotFoundError
|
||||||
from enchant import tokenize
|
from enchant import tokenize
|
||||||
@@ -52,7 +53,7 @@ class spellChecker(object):
|
|||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
try:
|
try:
|
||||||
self.checker.next()
|
next(self.checker)
|
||||||
textToSay = _(u"Misspelled word: %s") % (self.checker.word,)
|
textToSay = _(u"Misspelled word: %s") % (self.checker.word,)
|
||||||
context = u"... %s %s %s" % (self.checker.leading_context(10), self.checker.word, self.checker.trailing_context(10))
|
context = u"... %s %s %s" % (self.checker.leading_context(10), self.checker.word, self.checker.trailing_context(10))
|
||||||
self.dialog.set_title(textToSay)
|
self.dialog.set_title(textToSay)
|
||||||
|
@@ -1,2 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import completion, settings
|
from __future__ import absolute_import
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import completion, settings
|
@@ -1,7 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import absolute_import
|
||||||
import output
|
import output
|
||||||
import storage
|
from . import storage
|
||||||
import wx_menu
|
from . import wx_menu
|
||||||
|
|
||||||
class autocompletionUsers(object):
|
class autocompletionUsers(object):
|
||||||
def __init__(self, window, session_id):
|
def __init__(self, window, session_id):
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import storage
|
from __future__ import absolute_import
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import storage
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import wx_manage
|
from . import wx_manage
|
||||||
from wxUI import commonMessageDialogs
|
from wxUI import commonMessageDialogs
|
||||||
|
|
||||||
class autocompletionManage(object):
|
class autocompletionManage(object):
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import storage
|
from __future__ import absolute_import
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import storage
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import wx_settings
|
from . import wx_settings
|
||||||
import manage
|
from . import manage
|
||||||
import output
|
import output
|
||||||
from mysc.thread_utils import call_threaded
|
from mysc.thread_utils import call_threaded
|
||||||
|
|
||||||
|
@@ -1,2 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import OCRSpace
|
from __future__ import absolute_import
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import OCRSpace
|
@@ -1,6 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import translator
|
from __future__ import absolute_import
|
||||||
|
from . import translator
|
||||||
import platform
|
import platform
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
import wx_ui as gui
|
from . import wx_ui as gui
|
||||||
|
|
@@ -16,7 +16,26 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
############################################################
|
############################################################
|
||||||
import translator
|
from __future__ import absolute_import
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
############################################################
|
||||||
|
# Copyright (c) 2013, 2014 Manuel Eduardo Cortéz Vallejo <manuel@manuelcortez.net>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
############################################################
|
||||||
|
from . import translator
|
||||||
import wx
|
import wx
|
||||||
from wxUI.dialogs import baseDialog
|
from wxUI.dialogs import baseDialog
|
||||||
|
|
||||||
|
@@ -1,15 +1,18 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
""" This module contains some bugfixes for packages used in TWBlue."""
|
""" This module contains some bugfixes for packages used in TWBlue."""
|
||||||
|
from __future__ import absolute_import
|
||||||
import sys
|
import sys
|
||||||
import fix_arrow # A few new locales for Three languages in arrow.
|
from . import fix_arrow # A few new locales for Three languages in arrow.
|
||||||
import fix_urllib3_warnings # Avoiding some SSL warnings related to Twython.
|
from . import fix_libloader # Regenerates comcache properly.
|
||||||
import fix_win32com
|
from . import fix_urllib3_warnings # Avoiding some SSL warnings related to Twython.
|
||||||
import fix_requests #fix cacert.pem location for TWBlue binary copies
|
from . import fix_win32com
|
||||||
|
from . import fix_requests #fix cacert.pem location for TWBlue binary copies
|
||||||
def setup():
|
def setup():
|
||||||
fix_arrow.fix()
|
fix_arrow.fix()
|
||||||
if hasattr(sys, "frozen"):
|
if hasattr(sys, "frozen"):
|
||||||
fix_win32com.fix()
|
fix_win32com.fix()
|
||||||
fix_requests.fix(True)
|
fix_requests.fix(True)
|
||||||
|
fix_libloader.fix()
|
||||||
else:
|
else:
|
||||||
fix_requests.fix(False)
|
fix_requests.fix(False)
|
||||||
fix_urllib3_warnings.fix()
|
fix_urllib3_warnings.fix()
|
36
src/fixes/fix_libloader.py
Normal file
36
src/fixes/fix_libloader.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import win32com
|
||||||
|
import paths
|
||||||
|
win32com.__gen_path__=paths.com_path()
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
sys.path.append(os.path.join(win32com.__gen_path__, "."))
|
||||||
|
from win32com.client import gencache
|
||||||
|
from pywintypes import com_error
|
||||||
|
from libloader import com
|
||||||
|
|
||||||
|
fixed=False
|
||||||
|
|
||||||
|
def patched_getmodule(modname):
|
||||||
|
mod=__import__(modname)
|
||||||
|
return sys.modules[modname]
|
||||||
|
|
||||||
|
def load_com(*names):
|
||||||
|
global fixed
|
||||||
|
if fixed==False:
|
||||||
|
gencache._GetModule=patched_getmodule
|
||||||
|
com.prepare_gencache()
|
||||||
|
fixed=True
|
||||||
|
result = None
|
||||||
|
for name in names:
|
||||||
|
try:
|
||||||
|
result = gencache.EnsureDispatch(name)
|
||||||
|
break
|
||||||
|
except com_error:
|
||||||
|
continue
|
||||||
|
if result is None:
|
||||||
|
raise com_error("Unable to load any of the provided com objects.")
|
||||||
|
return result
|
||||||
|
|
||||||
|
def fix():
|
||||||
|
com.load_com = load_com
|
@@ -34,3 +34,4 @@ configuration = string(default="control+win+o")
|
|||||||
accountConfiguration = string(default="control+win+shift+o")
|
accountConfiguration = string(default="control+win+shift+o")
|
||||||
update_buffer = string(default="control+win+shift+u")
|
update_buffer = string(default="control+win+shift+u")
|
||||||
ocr_image = string(default="win+alt+o")
|
ocr_image = string(default="win+alt+o")
|
||||||
|
open_in_browser = string(default="alt+control+win+return")
|
@@ -53,3 +53,4 @@ configuration = string(default="control+win+o")
|
|||||||
accountConfiguration = string(default="control+win+shift+o")
|
accountConfiguration = string(default="control+win+shift+o")
|
||||||
update_buffer = string(default="control+win+shift+u")
|
update_buffer = string(default="control+win+shift+u")
|
||||||
ocr_image = string(default="win+alt+o")
|
ocr_image = string(default="win+alt+o")
|
||||||
|
open_in_browser = string(default="alt+control+win+return")
|
@@ -39,7 +39,7 @@ copy_to_clipboard = string(default="alt+win+shift+c")
|
|||||||
add_to_list = string(default="alt+win+a")
|
add_to_list = string(default="alt+win+a")
|
||||||
remove_from_list = string(default="alt+win+shift+a")
|
remove_from_list = string(default="alt+win+shift+a")
|
||||||
toggle_buffer_mute = string(default="alt+win+shift+m")
|
toggle_buffer_mute = string(default="alt+win+shift+m")
|
||||||
toggle_session_mute = string(default="alt+win+m")
|
toggle_session_mute = string(default="control+alt+win+m")
|
||||||
toggle_autoread = string(default="alt+win+e")
|
toggle_autoread = string(default="alt+win+e")
|
||||||
search = string(default="alt+win+-")
|
search = string(default="alt+win+-")
|
||||||
edit_keystrokes = string(default="alt+win+k")
|
edit_keystrokes = string(default="alt+win+k")
|
||||||
@@ -50,7 +50,8 @@ view_reverse_geocode = string(default="alt+win+shift+g")
|
|||||||
get_trending_topics = string(default="control+win+t")
|
get_trending_topics = string(default="control+win+t")
|
||||||
check_for_updates = string(default="alt+win+u")
|
check_for_updates = string(default="alt+win+u")
|
||||||
list_manager = string(default="alt+win+shift+l")
|
list_manager = string(default="alt+win+shift+l")
|
||||||
configuration = string(default="control+win+o")
|
configuration = string(default="control+win+alt+o")
|
||||||
accountConfiguration = string(default="control+win+shift+o")
|
accountConfiguration = string(default="control+win+shift+o")
|
||||||
update_buffer = string(default="control+alt+shift+u")
|
update_buffer = string(default="control+alt+shift+u")
|
||||||
ocr_image = string(default="win+alt+o")
|
ocr_image = string(default="win+alt+o")
|
||||||
|
open_in_browser = string(default="alt+control+win+return")
|
@@ -55,3 +55,4 @@ list_manager = string(default="control+win+shift+l")
|
|||||||
configuration = string(default="control+win+o")
|
configuration = string(default="control+win+o")
|
||||||
accountConfiguration = string(default="control+win+shift+o")
|
accountConfiguration = string(default="control+win+shift+o")
|
||||||
update_buffer = string(default="control+win+shift+u")
|
update_buffer = string(default="control+win+shift+u")
|
||||||
|
open_in_browser = string(default="alt+control+win+return")
|
@@ -56,3 +56,4 @@ configuration = string(default="control+win+o")
|
|||||||
accountConfiguration = string(default="control+win+shift+o")
|
accountConfiguration = string(default="control+win+shift+o")
|
||||||
update_buffer = string(default="control+win+shift+u")
|
update_buffer = string(default="control+win+shift+u")
|
||||||
ocr_image = string(default="win+alt+o")
|
ocr_image = string(default="win+alt+o")
|
||||||
|
open_in_browser = string(default="alt+control+win+return")
|
@@ -1,4 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from builtins import object
|
||||||
import application
|
import application
|
||||||
import platform
|
import platform
|
||||||
import exceptions
|
import exceptions
|
||||||
|
@@ -1 +1,2 @@
|
|||||||
from keystrokeEditor import KeystrokeEditor
|
from __future__ import absolute_import
|
||||||
|
from .keystrokeEditor import KeystrokeEditor
|
@@ -1,8 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import absolute_import
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import config
|
import config
|
||||||
import wx_ui
|
from . import wx_ui
|
||||||
import constants
|
from . import constants
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
|
|
||||||
class KeystrokeEditor(object):
|
class KeystrokeEditor(object):
|
||||||
|
@@ -32,7 +32,7 @@ class keystrokeEditorDialog(baseDialog.BaseWXDialog):
|
|||||||
selection = self.keys.get_selected()
|
selection = self.keys.get_selected()
|
||||||
self.keys.clear()
|
self.keys.clear()
|
||||||
for i in keystrokes:
|
for i in keystrokes:
|
||||||
if actions.has_key(i) == False:
|
if (i in actions) == False:
|
||||||
continue
|
continue
|
||||||
action = actions[i]
|
action = actions[i]
|
||||||
self.actions.append(i)
|
self.actions.append(i)
|
||||||
|
@@ -1,7 +0,0 @@
|
|||||||
from .libloader import *
|
|
||||||
|
|
||||||
__version__ = 0.1
|
|
||||||
__author__ = 'Christopher Toth <q@q-continuum.net>'
|
|
||||||
__doc__ = """
|
|
||||||
Quickly and easily load shared libraries from various platforms. Also includes a libloader.com module for loading com modules on Windows.
|
|
||||||
"""
|
|
@@ -1,35 +0,0 @@
|
|||||||
from pywintypes import com_error
|
|
||||||
import win32com
|
|
||||||
import paths
|
|
||||||
win32com.__gen_path__=paths.com_path()
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
sys.path.append(os.path.join(win32com.__gen_path__, "."))
|
|
||||||
from win32com.client import gencache
|
|
||||||
fixed=False
|
|
||||||
|
|
||||||
def prepare_gencache():
|
|
||||||
gencache.is_readonly = False
|
|
||||||
gencache.GetGeneratePath()
|
|
||||||
|
|
||||||
def patched_getmodule(modname):
|
|
||||||
mod=__import__(modname)
|
|
||||||
return sys.modules[modname]
|
|
||||||
|
|
||||||
def load_com(*names):
|
|
||||||
global fixed
|
|
||||||
if fixed==False:
|
|
||||||
gencache._GetModule=patched_getmodule
|
|
||||||
prepare_gencache()
|
|
||||||
fixed=True
|
|
||||||
result = None
|
|
||||||
for name in names:
|
|
||||||
try:
|
|
||||||
result = gencache.EnsureDispatch(name)
|
|
||||||
break
|
|
||||||
except com_error:
|
|
||||||
continue
|
|
||||||
if result is None:
|
|
||||||
raise com_error("Unable to load any of the provided com objects.")
|
|
||||||
return result
|
|
||||||
|
|
@@ -1,56 +0,0 @@
|
|||||||
import ctypes
|
|
||||||
import collections
|
|
||||||
import platform
|
|
||||||
import os
|
|
||||||
|
|
||||||
TYPES = {
|
|
||||||
'Linux': {
|
|
||||||
'loader': ctypes.CDLL,
|
|
||||||
'functype': ctypes.CFUNCTYPE,
|
|
||||||
'prefix': 'lib',
|
|
||||||
'extension': '.so'
|
|
||||||
},
|
|
||||||
'Darwin': {
|
|
||||||
'loader': ctypes.CDLL,
|
|
||||||
'functype': ctypes.CFUNCTYPE,
|
|
||||||
'prefix': 'lib',
|
|
||||||
'extension': '.dylib'
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
TYPES['Windows'] = {
|
|
||||||
'loader': ctypes.WinDLL,
|
|
||||||
'functype': ctypes.WINFUNCTYPE,
|
|
||||||
'prefix': "",
|
|
||||||
'extension': '.dll'
|
|
||||||
}
|
|
||||||
|
|
||||||
class LibraryLoadError(OSError): pass
|
|
||||||
|
|
||||||
def load_library(library, x86_path='.', x64_path='.', *args, **kwargs):
|
|
||||||
lib = find_library_path(library, x86_path=x86_path, x64_path=x64_path)
|
|
||||||
loaded = _do_load(str(lib), *args, **kwargs)
|
|
||||||
if loaded is not None:
|
|
||||||
return loaded
|
|
||||||
raise LibraryLoadError('unable to load %r. Provided library path: %r' % (library, lib))
|
|
||||||
|
|
||||||
def _do_load(file, *args, **kwargs):
|
|
||||||
loader = TYPES[platform.system()]['loader']
|
|
||||||
return loader(file, *args, **kwargs)
|
|
||||||
|
|
||||||
def find_library_path(libname, x86_path='.', x64_path='.'):
|
|
||||||
libname = '%s%s' % (TYPES[platform.system()]['prefix'], libname)
|
|
||||||
if platform.architecture()[0] == '64bit':
|
|
||||||
path = os.path.join(x64_path, libname)
|
|
||||||
else:
|
|
||||||
path = os.path.join(x86_path, libname)
|
|
||||||
ext = get_library_extension()
|
|
||||||
path = '%s%s' % (path, ext)
|
|
||||||
return os.path.abspath(path)
|
|
||||||
|
|
||||||
|
|
||||||
def get_functype():
|
|
||||||
return TYPES[platform.system()]['functype']
|
|
||||||
|
|
||||||
def get_library_extension():
|
|
||||||
return TYPES[platform.system()]['extension']
|
|
25
src/main.py
25
src/main.py
@@ -1,5 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import platform
|
import platform
|
||||||
|
from win32com.client import GetObject
|
||||||
|
|
||||||
""" there are lots of things not implemented for Gtk+ yet.
|
""" there are lots of things not implemented for Gtk+ yet.
|
||||||
We've started this effort 1 Apr 2015 so it isn't fully functional. We will remove the ifs statements when are no needed"""
|
We've started this effort 1 Apr 2015 so it isn't fully functional. We will remove the ifs statements when are no needed"""
|
||||||
|
|
||||||
@@ -86,6 +88,7 @@ def setup():
|
|||||||
if hasattr(sm.view, "destroy"):
|
if hasattr(sm.view, "destroy"):
|
||||||
sm.view.destroy()
|
sm.view.destroy()
|
||||||
del sm
|
del sm
|
||||||
|
check_pid()
|
||||||
r = mainController.Controller()
|
r = mainController.Controller()
|
||||||
r.view.show()
|
r.view.show()
|
||||||
r.do_work()
|
r.do_work()
|
||||||
@@ -102,4 +105,26 @@ def donation():
|
|||||||
webbrowser.open_new_tab(_("https://twblue.es/donate"))
|
webbrowser.open_new_tab(_("https://twblue.es/donate"))
|
||||||
config.app["app-settings"]["donation_dialog_displayed"] = True
|
config.app["app-settings"]["donation_dialog_displayed"] = True
|
||||||
|
|
||||||
|
def is_running(pid):
|
||||||
|
"Check if the process with ID pid is running. Adapted from https://stackoverflow.com/a/568589"
|
||||||
|
WMI = GetObject('winmgmts:')
|
||||||
|
processes = WMI.InstancesOf('Win32_Process')
|
||||||
|
return [process.Properties_('ProcessID').Value for process in processes if process.Properties_('ProcessID').Value == pid]
|
||||||
|
|
||||||
|
def check_pid():
|
||||||
|
"Insures that only one copy of the application is running at a time."
|
||||||
|
pidpath = os.path.join(os.getenv("temp"), "{}.pid".format(application.name))
|
||||||
|
if os.path.exists(pidpath):
|
||||||
|
with open(pidpath) as fin:
|
||||||
|
pid = int(fin.read())
|
||||||
|
if is_running(pid):
|
||||||
|
# Display warning dialog
|
||||||
|
commonMessageDialogs.common_error(_(u"{0} is already running. Close the other instance before starting this one. If you're sure that {0} isn't running, try deleting the file at {1}. If you're unsure of how to do this, contact the {0} developers.").format(application.name, pidpath))
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
commonMessageDialogs.dead_pid()
|
||||||
|
# Write the new PID
|
||||||
|
with open(pidpath,"w") as cam:
|
||||||
|
cam.write(str(os.getpid()))
|
||||||
|
|
||||||
setup()
|
setup()
|
||||||
|
@@ -1 +1,2 @@
|
|||||||
import widgets
|
from __future__ import absolute_import
|
||||||
|
from . import widgets
|
@@ -1,6 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
""" A cross platform notification system.
|
""" A cross platform notification system.
|
||||||
Under Linux, the wx.NotificationMessage does not show a notification on the taskbar, so we decided to use dbus for showing notifications for linux and wx for Windows."""
|
Under Linux, the wx.NotificationMessage does not show a notification on the taskbar, so we decided to use dbus for showing notifications for linux and wx for Windows."""
|
||||||
|
from __future__ import absolute_import
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
notify = None
|
notify = None
|
||||||
@@ -8,10 +9,10 @@ notify = None
|
|||||||
def setup():
|
def setup():
|
||||||
global notify
|
global notify
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
import windows
|
from . import windows
|
||||||
notify = windows.notification()
|
notify = windows.notification()
|
||||||
elif platform.system() == "Linux":
|
elif platform.system() == "Linux":
|
||||||
import linux
|
from . import linux
|
||||||
notify = linux.notification()
|
notify = linux.notification()
|
||||||
|
|
||||||
def send(title, text):
|
def send(title, text):
|
||||||
|
@@ -1,16 +0,0 @@
|
|||||||
# Replacement for py2exe distributed module
|
|
||||||
# Avoids the use of the standard py2exe console.
|
|
||||||
# Just import this file and it should go away
|
|
||||||
|
|
||||||
import sys
|
|
||||||
if hasattr(sys,"frozen"): # true only if we are running as a py2exe app
|
|
||||||
class Blackhole(object):
|
|
||||||
def write(self,text):
|
|
||||||
pass
|
|
||||||
def flush(self):
|
|
||||||
pass
|
|
||||||
sys.stdout = Blackhole()
|
|
||||||
sys.stderr = Blackhole()
|
|
||||||
del Blackhole
|
|
||||||
del sys
|
|
||||||
|
|
@@ -1,51 +0,0 @@
|
|||||||
import ctypes
|
|
||||||
import collections
|
|
||||||
import platform
|
|
||||||
import os
|
|
||||||
|
|
||||||
TYPES = {
|
|
||||||
'Linux': {
|
|
||||||
'loader': ctypes.CDLL,
|
|
||||||
'functype': ctypes.CFUNCTYPE,
|
|
||||||
'prefix': 'lib',
|
|
||||||
'extension': '.so'
|
|
||||||
},
|
|
||||||
'Darwin': {
|
|
||||||
'loader': ctypes.CDLL,
|
|
||||||
'functype': ctypes.CFUNCTYPE,
|
|
||||||
'prefix': 'lib',
|
|
||||||
'extension': '.dylib'
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
TYPES['Windows'] = {
|
|
||||||
'loader': ctypes.WinDLL,
|
|
||||||
'functype': ctypes.WINFUNCTYPE,
|
|
||||||
'prefix': "",
|
|
||||||
'extension': '.dll'
|
|
||||||
}
|
|
||||||
|
|
||||||
class LibraryLoadError(Exception): pass
|
|
||||||
|
|
||||||
def load_library(library, x86_path='.', x64_path='.', *args, **kwargs):
|
|
||||||
lib = find_library_path(library, x86_path=x86_path, x64_path=x64_path)
|
|
||||||
loaded = _do_load(lib, *args, **kwargs)
|
|
||||||
if loaded is not None:
|
|
||||||
return loaded
|
|
||||||
raise LibraryLoadError('unable to load %r. Provided library path: %r' % (library, lib))
|
|
||||||
|
|
||||||
def _do_load(file, *args, **kwargs):
|
|
||||||
loader = TYPES[platform.system()]['loader']
|
|
||||||
return loader(file, *args, **kwargs)
|
|
||||||
|
|
||||||
def find_library_path(libname, x86_path='.', x64_path='.'):
|
|
||||||
libname = '%s%s' % (TYPES[platform.system()]['prefix'], libname)
|
|
||||||
if platform.machine() == 'x86_64':
|
|
||||||
path = os.path.join(x64_path, libname)
|
|
||||||
else:
|
|
||||||
path = os.path.join(x86_path, libname)
|
|
||||||
ext = TYPES[platform.system()]['extension']
|
|
||||||
return '%s%s' % (path, ext)
|
|
||||||
|
|
||||||
def get_functype():
|
|
||||||
return TYPES[platform.system()]['functype']
|
|
@@ -1,114 +0,0 @@
|
|||||||
import inspect
|
|
||||||
import platform
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import string
|
|
||||||
import unicodedata
|
|
||||||
|
|
||||||
|
|
||||||
def app_data_path(app_name=None):
|
|
||||||
"""Cross-platform method for determining where to put application data."""
|
|
||||||
"""Requires the name of the application"""
|
|
||||||
plat = platform.system()
|
|
||||||
if plat == 'Windows':
|
|
||||||
import winpaths
|
|
||||||
path = winpaths.get_appdata()
|
|
||||||
elif plat == 'Darwin':
|
|
||||||
path = os.path.join(os.path.expanduser('~'), 'Library', 'Application Support')
|
|
||||||
elif plat == 'Linux':
|
|
||||||
path = os.path.expanduser('~')
|
|
||||||
app_name = '.%s' % app_name.replace(' ', '_')
|
|
||||||
return os.path.join(path, app_name)
|
|
||||||
|
|
||||||
def prepare_app_data_path(app_name):
|
|
||||||
"""Creates the application's data directory, given its name."""
|
|
||||||
dir = app_data_path(app_name)
|
|
||||||
return ensure_path(dir)
|
|
||||||
|
|
||||||
def embedded_data_path():
|
|
||||||
if platform.system() == 'Darwin' and is_frozen():
|
|
||||||
return os.path.abspath(os.path.join(executable_directory(), '..', 'Resources'))
|
|
||||||
return app_path()
|
|
||||||
|
|
||||||
def is_frozen():
|
|
||||||
"""Return a bool indicating if application is compressed"""
|
|
||||||
import imp
|
|
||||||
return hasattr(sys, 'frozen') or imp.is_frozen("__main__")
|
|
||||||
|
|
||||||
def get_executable():
|
|
||||||
"""Returns the full executable path/name if frozen, or the full path/name of the main module if not."""
|
|
||||||
if is_frozen():
|
|
||||||
if platform.system() != 'Darwin':
|
|
||||||
return sys.executable
|
|
||||||
#On darwin, sys.executable points to python. We want the full path to the exe we ran.
|
|
||||||
exedir = os.path.abspath(os.path.dirname(sys.executable))
|
|
||||||
items = os.listdir(exedir)
|
|
||||||
items.remove('python')
|
|
||||||
return os.path.join(exedir, items[0])
|
|
||||||
#Not frozen
|
|
||||||
try:
|
|
||||||
import __main__
|
|
||||||
return os.path.abspath(__main__.__file__)
|
|
||||||
except AttributeError:
|
|
||||||
return sys.argv[0]
|
|
||||||
|
|
||||||
def get_module(level=2):
|
|
||||||
"""Hacky method for deriving the caller of this function's module."""
|
|
||||||
return inspect.getmodule(inspect.stack()[level][0]).__file__
|
|
||||||
|
|
||||||
def executable_directory():
|
|
||||||
"""Always determine the directory of the executable, even when run with py2exe or otherwise frozen"""
|
|
||||||
executable = get_executable()
|
|
||||||
path = os.path.abspath(os.path.dirname(executable))
|
|
||||||
return path
|
|
||||||
|
|
||||||
def app_path():
|
|
||||||
"""Return the root of the application's directory"""
|
|
||||||
path = executable_directory()
|
|
||||||
if is_frozen() and platform.system() == 'Darwin':
|
|
||||||
path = os.path.abspath(os.path.join(path, '..', '..'))
|
|
||||||
return path
|
|
||||||
|
|
||||||
def module_path(level=2):
|
|
||||||
return os.path.abspath(os.path.dirname(get_module(level)))
|
|
||||||
|
|
||||||
def documents_path():
|
|
||||||
"""On windows, returns the path to My Documents. On OSX, returns the user's Documents folder. For anything else, returns the user's home directory."""
|
|
||||||
plat = platform.system()
|
|
||||||
if plat == 'Windows':
|
|
||||||
import winpaths
|
|
||||||
path = winpaths.get_my_documents()
|
|
||||||
elif plat == 'Darwin':
|
|
||||||
path = os.path.join(os.path.expanduser('~'), 'Documents')
|
|
||||||
else:
|
|
||||||
path = os.path.expanduser('~')
|
|
||||||
return path
|
|
||||||
|
|
||||||
def safe_filename(filename):
|
|
||||||
"""Given a filename, returns a safe version with no characters that would not work on different platforms."""
|
|
||||||
SAFE_FILE_CHARS = "'-_.()[]{}!@#$%^&+=`~ "
|
|
||||||
filename = unicode(filename)
|
|
||||||
new_filename = ''.join(c for c in filename if c in SAFE_FILE_CHARS or c.isalnum())
|
|
||||||
#Windows doesn't like directory names ending in space, macs consider filenames beginning with a dot as hidden, and windows removes dots at the ends of filenames.
|
|
||||||
return new_filename.strip(' .')
|
|
||||||
|
|
||||||
def ensure_path(path):
|
|
||||||
if not os.path.exists(path):
|
|
||||||
os.makedirs(path)
|
|
||||||
return path
|
|
||||||
|
|
||||||
def start_file(path):
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
os.startfile(path)
|
|
||||||
else:
|
|
||||||
subprocess.Popen(['open', path])
|
|
||||||
|
|
||||||
def get_applications_path():
|
|
||||||
"""Return the directory where applications are commonly installed on the system."""
|
|
||||||
plat = platform.system()
|
|
||||||
if plat == 'Windows':
|
|
||||||
import winpaths
|
|
||||||
return winpaths.get_program_files()
|
|
||||||
elif plat == 'Darwin':
|
|
||||||
return '/Applications'
|
|
@@ -1,27 +0,0 @@
|
|||||||
import platform
|
|
||||||
import ctypes
|
|
||||||
import os
|
|
||||||
import signal
|
|
||||||
|
|
||||||
|
|
||||||
def kill_windows_process(pid):
|
|
||||||
PROCESS_TERMINATE = 1
|
|
||||||
SYNCHRONIZE=1048576
|
|
||||||
handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, False, pid)
|
|
||||||
ctypes.windll.kernel32.TerminateProcess(handle, -1)
|
|
||||||
ctypes.windll.kernel32.WaitForSingleObject(handle, 1000)
|
|
||||||
ctypes.windll.kernel32.CloseHandle(handle)
|
|
||||||
|
|
||||||
def kill_unix_process(pid):
|
|
||||||
try:
|
|
||||||
os.kill(pid, signal.SIGKILL)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def kill_process(pid):
|
|
||||||
if pid < 0:
|
|
||||||
return
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
kill_windows_process(pid)
|
|
||||||
else:
|
|
||||||
kill_unix_process(pid)
|
|
@@ -1,10 +0,0 @@
|
|||||||
import _winreg
|
|
||||||
|
|
||||||
SHELL_REGKEY = ur"Directory\shell"
|
|
||||||
|
|
||||||
def context_menu_integrate(item_key_name, item_display_text, item_command):
|
|
||||||
app_menu_key = _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, SHELL_REGKEY, 0, _winreg.KEY_WRITE)
|
|
||||||
menu_item_key = _winreg.CreateKey(app_menu_key, item_key_name)
|
|
||||||
_winreg.SetValueEx(menu_item_key, None, None, _winreg.REG_SZ, item_display_text)
|
|
||||||
item_command_key = _winreg.CreateKey(menu_item_key, 'command')
|
|
||||||
_winreg.SetValueEx(item_command_key, None, None, _winreg.REG_SZ, item_command)
|
|
@@ -1,9 +0,0 @@
|
|||||||
import platform
|
|
||||||
import webbrowser
|
|
||||||
|
|
||||||
def open(url):
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
browser = webbrowser.get('windows-default')
|
|
||||||
else:
|
|
||||||
browser = webbrowser
|
|
||||||
browser.open_new_tab(url)
|
|
@@ -1,20 +1,21 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import absolute_import
|
||||||
import shutil
|
import shutil
|
||||||
import widgetUtils
|
import widgetUtils
|
||||||
import platform
|
import platform
|
||||||
import output
|
import output
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
import wxUI as view
|
from . import wxUI as view
|
||||||
from controller import settings
|
from controller import settings
|
||||||
elif platform.system() == "Linux":
|
elif platform.system() == "Linux":
|
||||||
import gtkUI as view
|
from . import gtkUI as view
|
||||||
import paths
|
import paths
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import sessions
|
import sessions
|
||||||
from sessions.twitter import session
|
from sessions.twitter import session
|
||||||
import manager
|
from . import manager
|
||||||
import config_utils
|
import config_utils
|
||||||
import config
|
import config
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ class sessionManagerController(object):
|
|||||||
def do_ok(self):
|
def do_ok(self):
|
||||||
log.debug("Starting sessions...")
|
log.debug("Starting sessions...")
|
||||||
for i in self.sessions:
|
for i in self.sessions:
|
||||||
if sessions.sessions.has_key(i) == True: continue
|
if (i in sessions.sessions) == True: continue
|
||||||
s = session.Session(i)
|
s = session.Session(i)
|
||||||
s.get_configuration()
|
s.get_configuration()
|
||||||
if i not in config.app["sessions"]["ignored_sessions"]:
|
if i not in config.app["sessions"]["ignored_sessions"]:
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
""" A base class to be derived in possible new sessions for TWBlue and services."""
|
""" A base class to be derived in possible new sessions for TWBlue and services."""
|
||||||
|
from __future__ import absolute_import
|
||||||
import paths
|
import paths
|
||||||
import output
|
import output
|
||||||
import time
|
import time
|
||||||
@@ -9,7 +10,7 @@ import config_utils
|
|||||||
import shelve
|
import shelve
|
||||||
import application
|
import application
|
||||||
import os
|
import os
|
||||||
import session_exceptions as Exceptions
|
from . import session_exceptions as Exceptions
|
||||||
log = logging.getLogger("sessionmanager.session")
|
log = logging.getLogger("sessionmanager.session")
|
||||||
|
|
||||||
class baseSession(object):
|
class baseSession(object):
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import absolute_import
|
||||||
import platform
|
import platform
|
||||||
system = platform.system()
|
system = platform.system()
|
||||||
import utils
|
from . import utils
|
||||||
import re
|
import re
|
||||||
import htmlentitydefs
|
import htmlentitydefs
|
||||||
import time
|
import time
|
||||||
@@ -10,7 +11,7 @@ import languageHandler
|
|||||||
import arrow
|
import arrow
|
||||||
import logging
|
import logging
|
||||||
import config
|
import config
|
||||||
from long_tweets import twishort, tweets
|
from .long_tweets import twishort, tweets
|
||||||
log = logging.getLogger("compose")
|
log = logging.getLogger("compose")
|
||||||
|
|
||||||
def StripChars(s):
|
def StripChars(s):
|
||||||
@@ -38,13 +39,13 @@ def compose_tweet(tweet, db, relative_times, show_screen_names=False, session=No
|
|||||||
ts = original_date.replace(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage())
|
ts = original_date.replace(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage())
|
||||||
else:
|
else:
|
||||||
ts = tweet["created_at"]
|
ts = tweet["created_at"]
|
||||||
if tweet.has_key("message"):
|
if "message" in tweet:
|
||||||
value = "message"
|
value = "message"
|
||||||
elif tweet.has_key("full_text"):
|
elif "full_text" in tweet:
|
||||||
value = "full_text"
|
value = "full_text"
|
||||||
else:
|
else:
|
||||||
value = "text"
|
value = "text"
|
||||||
if tweet.has_key("retweeted_status") and value != "message":
|
if "retweeted_status" in tweet and value != "message":
|
||||||
text = StripChars(tweet["retweeted_status"][value])
|
text = StripChars(tweet["retweeted_status"][value])
|
||||||
else:
|
else:
|
||||||
text = StripChars(tweet[value])
|
text = StripChars(tweet[value])
|
||||||
@@ -53,16 +54,16 @@ def compose_tweet(tweet, db, relative_times, show_screen_names=False, session=No
|
|||||||
else:
|
else:
|
||||||
user = tweet["user"]["name"]
|
user = tweet["user"]["name"]
|
||||||
source = re.sub(r"(?s)<.*?>", "", tweet["source"])
|
source = re.sub(r"(?s)<.*?>", "", tweet["source"])
|
||||||
if tweet.has_key("retweeted_status"):
|
if "retweeted_status" in tweet:
|
||||||
if tweet.has_key("message") == False and tweet["retweeted_status"]["is_quote_status"] == False:
|
if ("message" in tweet) == False and tweet["retweeted_status"]["is_quote_status"] == False:
|
||||||
text = "RT @%s: %s" % (tweet["retweeted_status"]["user"]["screen_name"], text)
|
text = "RT @%s: %s" % (tweet["retweeted_status"]["user"]["screen_name"], text)
|
||||||
elif tweet["retweeted_status"]["is_quote_status"]:
|
elif tweet["retweeted_status"]["is_quote_status"]:
|
||||||
text = "%s" % (text)
|
text = "%s" % (text)
|
||||||
else:
|
else:
|
||||||
text = "RT @%s: %s" % (tweet["retweeted_status"]["user"]["screen_name"], text)
|
text = "RT @%s: %s" % (tweet["retweeted_status"]["user"]["screen_name"], text)
|
||||||
if tweet.has_key("message") == False:
|
if ("message" in tweet) == False:
|
||||||
urls = utils.find_urls_in_text(text)
|
urls = utils.find_urls_in_text(text)
|
||||||
if tweet.has_key("retweeted_status"):
|
if "retweeted_status" in tweet:
|
||||||
for url in range(0, len(urls)):
|
for url in range(0, len(urls)):
|
||||||
try:
|
try:
|
||||||
text = text.replace(urls[url], tweet["retweeted_status"]["entities"]["urls"][url]["expanded_url"])
|
text = text.replace(urls[url], tweet["retweeted_status"]["entities"]["urls"][url]["expanded_url"])
|
||||||
@@ -110,14 +111,14 @@ def compose_direct_message(item, db, relative_times, show_screen_names=False, se
|
|||||||
|
|
||||||
def compose_quoted_tweet(quoted_tweet, original_tweet, show_screen_names=False, session=None):
|
def compose_quoted_tweet(quoted_tweet, original_tweet, 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."""
|
""" 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 quoted_tweet.has_key("retweeted_status"):
|
if "retweeted_status" in quoted_tweet:
|
||||||
if quoted_tweet["retweeted_status"].has_key("full_text"):
|
if "full_text" in quoted_tweet["retweeted_status"]:
|
||||||
value = "full_text"
|
value = "full_text"
|
||||||
else:
|
else:
|
||||||
value = "text"
|
value = "text"
|
||||||
text = StripChars(quoted_tweet["retweeted_status"][value])
|
text = StripChars(quoted_tweet["retweeted_status"][value])
|
||||||
else:
|
else:
|
||||||
if quoted_tweet.has_key("full_text"):
|
if "full_text" in quoted_tweet:
|
||||||
value = "full_text"
|
value = "full_text"
|
||||||
else:
|
else:
|
||||||
value = "text"
|
value = "text"
|
||||||
@@ -127,13 +128,13 @@ def compose_quoted_tweet(quoted_tweet, original_tweet, show_screen_names=False,
|
|||||||
else:
|
else:
|
||||||
quoting_user = quoted_tweet["user"]["name"]
|
quoting_user = quoted_tweet["user"]["name"]
|
||||||
source = re.sub(r"(?s)<.*?>", "", quoted_tweet["source"])
|
source = re.sub(r"(?s)<.*?>", "", quoted_tweet["source"])
|
||||||
if quoted_tweet.has_key("retweeted_status"):
|
if "retweeted_status" in quoted_tweet:
|
||||||
text = "rt @%s: %s" % (quoted_tweet["retweeted_status"]["user"]["screen_name"], text)
|
text = "rt @%s: %s" % (quoted_tweet["retweeted_status"]["user"]["screen_name"], text)
|
||||||
if text[-1] in chars: text=text+"."
|
if text[-1] in chars: text=text+"."
|
||||||
original_user = original_tweet["user"]["screen_name"]
|
original_user = original_tweet["user"]["screen_name"]
|
||||||
if original_tweet.has_key("message"):
|
if "message" in original_tweet:
|
||||||
original_text = original_tweet["message"]
|
original_text = original_tweet["message"]
|
||||||
elif original_tweet.has_key("full_text"):
|
elif "full_text" in original_tweet:
|
||||||
original_text = StripChars(original_tweet["full_text"])
|
original_text = StripChars(original_tweet["full_text"])
|
||||||
else:
|
else:
|
||||||
original_text = StripChars(original_tweet["text"])
|
original_text = StripChars(original_tweet["text"])
|
||||||
@@ -151,7 +152,7 @@ def compose_followers_list(tweet, db, relative_times=True, show_screen_names=Fal
|
|||||||
ts = original_date.replace(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage())
|
ts = original_date.replace(seconds=db["utc_offset"]).format(_(u"dddd, MMMM D, YYYY H:m:s"), locale=languageHandler.getLanguage())
|
||||||
else:
|
else:
|
||||||
ts = tweet["created_at"]
|
ts = tweet["created_at"]
|
||||||
if tweet.has_key("status"):
|
if "status" in tweet:
|
||||||
if len(tweet["status"]) > 4 and system == "Windows":
|
if len(tweet["status"]) > 4 and system == "Windows":
|
||||||
original_date2 = arrow.get(tweet["status"]["created_at"], "ddd MMM D H:m:s Z YYYY", locale="en")
|
original_date2 = arrow.get(tweet["status"]["created_at"], "ddd MMM D H:m:s Z YYYY", locale="en")
|
||||||
if relative_times:
|
if relative_times:
|
||||||
|
@@ -22,9 +22,9 @@ def is_long(tweet):
|
|||||||
""" Check if the passed tweet contains a quote in its metadata.
|
""" Check if the passed tweet contains a quote in its metadata.
|
||||||
tweet dict: a tweet dictionary.
|
tweet dict: a tweet dictionary.
|
||||||
returns True if a quote is detected, False otherwise."""
|
returns True if a quote is detected, False otherwise."""
|
||||||
if tweet.has_key("quoted_status_id") and tweet.has_key("quoted_status"):
|
if "quoted_status_id" in tweet and "quoted_status" in tweet:
|
||||||
return tweet["quoted_status_id"]
|
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"):
|
elif "retweeted_status" in tweet and "quoted_status_id" in tweet["retweeted_status"] and "quoted_status" in tweet["retweeted_status"]:
|
||||||
return tweet["retweeted_status"]["quoted_status_id"]
|
return tweet["retweeted_status"]["quoted_status_id"]
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -32,8 +32,8 @@ def clear_url(tweet):
|
|||||||
""" Reads data from a quoted tweet and removes the link to the Status from the tweet's text.
|
""" Reads data from a quoted tweet and removes the link to the Status from the tweet's text.
|
||||||
tweet dict: a tweet dictionary.
|
tweet dict: a tweet dictionary.
|
||||||
returns a tweet dictionary without the URL to the status ID in its text to display."""
|
returns a tweet dictionary without the URL to the status ID in its text to display."""
|
||||||
if tweet.has_key("retweeted_status"):
|
if "retweeted_status" in tweet:
|
||||||
if tweet["retweeted_status"].has_key("full_text"):
|
if "full_text" in tweet["retweeted_status"]:
|
||||||
value = "full_text"
|
value = "full_text"
|
||||||
else:
|
else:
|
||||||
value = "text"
|
value = "text"
|
||||||
@@ -41,7 +41,7 @@ def clear_url(tweet):
|
|||||||
try: tweet["message"] = tweet["message"].replace(urls[-1], "")
|
try: tweet["message"] = tweet["message"].replace(urls[-1], "")
|
||||||
except IndexError: pass
|
except IndexError: pass
|
||||||
else:
|
else:
|
||||||
if tweet.has_key("full_text"):
|
if "full_text" in tweet:
|
||||||
value = "full_text"
|
value = "full_text"
|
||||||
else:
|
else:
|
||||||
value = "text"
|
value = "text"
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
############################################################
|
############################################################
|
||||||
|
from __future__ import print_function
|
||||||
import logging
|
import logging
|
||||||
import requests
|
import requests
|
||||||
import keys
|
import keys
|
||||||
@@ -47,7 +48,7 @@ def is_long(tweet):
|
|||||||
# see https://github.com/manuelcortez/TWBlue/issues/103
|
# see https://github.com/manuelcortez/TWBlue/issues/103
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
if long == False and tweet.has_key("retweeted_status"):
|
if long == False and "retweeted_status" in tweet:
|
||||||
for url in range(0, len(tweet["retweeted_status"]["entities"]["urls"])):
|
for url in range(0, len(tweet["retweeted_status"]["entities"]["urls"])):
|
||||||
try:
|
try:
|
||||||
if tweet["retweeted_status"]["entities"]["urls"][url] != None and "twishort.com" in tweet["retweeted_status"]["entities"]["urls"][url]["expanded_url"]:
|
if tweet["retweeted_status"]["entities"]["urls"][url] != None and "twishort.com" in tweet["retweeted_status"]["entities"]["urls"][url]["expanded_url"]:
|
||||||
@@ -97,5 +98,5 @@ def create_tweet(user_token, user_secret, text, media=0):
|
|||||||
try:
|
try:
|
||||||
return response.json()["text_to_tweet"]
|
return response.json()["text_to_tweet"]
|
||||||
except:
|
except:
|
||||||
print "There was a problem creating a long tweet"
|
print("There was a problem creating a long tweet")
|
||||||
return 0
|
return 0
|
@@ -1,5 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
""" This is the main session needed to access all Twitter Features."""
|
""" This is the main session needed to access all Twitter Features."""
|
||||||
|
from __future__ import absolute_import
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
@@ -15,7 +16,7 @@ from keys import keyring
|
|||||||
from sessions import base
|
from sessions import base
|
||||||
from sessions.twitter import utils, compose
|
from sessions.twitter import utils, compose
|
||||||
from sessions.twitter.long_tweets import tweets, twishort
|
from sessions.twitter.long_tweets import tweets, twishort
|
||||||
from wxUI import authorisationDialog
|
from .wxUI import authorisationDialog
|
||||||
|
|
||||||
log = logging.getLogger("sessions.twitterSession")
|
log = logging.getLogger("sessions.twitterSession")
|
||||||
|
|
||||||
@@ -30,9 +31,9 @@ class Session(base.baseSession):
|
|||||||
returns the number of items that have been added in this execution"""
|
returns the number of items that have been added in this execution"""
|
||||||
num = 0
|
num = 0
|
||||||
last_id = None
|
last_id = None
|
||||||
if self.db.has_key(name) == False:
|
if (name in self.db) == False:
|
||||||
self.db[name] = []
|
self.db[name] = []
|
||||||
if self.db.has_key("users") == False:
|
if ("users" in self.db) == False:
|
||||||
self.db["users"] = {}
|
self.db["users"] = {}
|
||||||
if ignore_older and len(self.db[name]) > 0:
|
if ignore_older and len(self.db[name]) > 0:
|
||||||
if self.settings["general"]["reverse_timelines"] == False:
|
if self.settings["general"]["reverse_timelines"] == False:
|
||||||
@@ -51,8 +52,8 @@ class Session(base.baseSession):
|
|||||||
if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i)
|
if self.settings["general"]["reverse_timelines"] == False: self.db[name].append(i)
|
||||||
else: self.db[name].insert(0, i)
|
else: self.db[name].insert(0, i)
|
||||||
num = num+1
|
num = num+1
|
||||||
if i.has_key("user") == True:
|
if ("user" in i) == True:
|
||||||
if self.db["users"].has_key(i["user"]["id"]) == False:
|
if (i["user"]["id"] in self.db["users"]) == False:
|
||||||
self.db["users"][i["user"]["id"]] = i["user"]
|
self.db["users"][i["user"]["id"]] = i["user"]
|
||||||
return num
|
return num
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ class Session(base.baseSession):
|
|||||||
if name == "direct_messages":
|
if name == "direct_messages":
|
||||||
return self.order_direct_messages(data)
|
return self.order_direct_messages(data)
|
||||||
num = 0
|
num = 0
|
||||||
if self.db.has_key(name) == False:
|
if (name in self.db) == False:
|
||||||
self.db[name] = {}
|
self.db[name] = {}
|
||||||
self.db[name]["items"] = []
|
self.db[name]["items"] = []
|
||||||
for i in data:
|
for i in data:
|
||||||
@@ -82,12 +83,12 @@ class Session(base.baseSession):
|
|||||||
returns the number of incoming messages processed in this execution, and sends an event with data regarding amount of sent direct messages added."""
|
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
|
incoming = 0
|
||||||
sent = 0
|
sent = 0
|
||||||
if self.db.has_key("direct_messages") == False:
|
if ("direct_messages" in self.db) == False:
|
||||||
self.db["direct_messages"] = {}
|
self.db["direct_messages"] = {}
|
||||||
self.db["direct_messages"]["items"] = []
|
self.db["direct_messages"]["items"] = []
|
||||||
for i in data:
|
for i in data:
|
||||||
if i["message_create"]["sender_id"] == self.db["user_id"]:
|
if i["message_create"]["sender_id"] == self.db["user_id"]:
|
||||||
if self.db.has_key("sent_direct_messages") and utils.find_item(i["id"], self.db["sent_direct_messages"]["items"]) == None:
|
if "sent_direct_messages" in self.db 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)
|
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)
|
else: self.db["sent_direct_messages"]["items"].insert(0, i)
|
||||||
sent = sent+1
|
sent = sent+1
|
||||||
@@ -164,13 +165,13 @@ class Session(base.baseSession):
|
|||||||
users, dm bool: If any of these is set to True, the function will treat items as users or dm (they need different handling).
|
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."""
|
name str: name of the database item to put new element in."""
|
||||||
results = []
|
results = []
|
||||||
if kwargs.has_key("cursor") and kwargs["cursor"] == 0:
|
if "cursor" in kwargs and kwargs["cursor"] == 0:
|
||||||
output.speak(_(u"There are no more items to retrieve in this buffer."))
|
output.speak(_(u"There are no more items to retrieve in this buffer."))
|
||||||
return
|
return
|
||||||
data = getattr(self.twitter, update_function)(*args, **kwargs)
|
data = getattr(self.twitter, update_function)(*args, **kwargs)
|
||||||
if users == True:
|
if users == True:
|
||||||
if type(data) == dict and data.has_key("next_cursor"):
|
if type(data) == dict and "next_cursor" in data:
|
||||||
if data.has_key("next_cursor"): # There are more objects to retrieve.
|
if "next_cursor" in data: # There are more objects to retrieve.
|
||||||
self.db[name]["cursor"] = data["next_cursor"]
|
self.db[name]["cursor"] = data["next_cursor"]
|
||||||
else: # Set cursor to 0, wich means no more items available.
|
else: # Set cursor to 0, wich means no more items available.
|
||||||
self.db[name]["cursor"] = 0
|
self.db[name]["cursor"] = 0
|
||||||
@@ -178,7 +179,7 @@ class Session(base.baseSession):
|
|||||||
elif type(data) == list:
|
elif type(data) == list:
|
||||||
results.extend(data[1:])
|
results.extend(data[1:])
|
||||||
elif dm == True:
|
elif dm == True:
|
||||||
if data.has_key("next_cursor"): # There are more objects to retrieve.
|
if "next_cursor" in data: # There are more objects to retrieve.
|
||||||
self.db[name]["cursor"] = data["next_cursor"]
|
self.db[name]["cursor"] = data["next_cursor"]
|
||||||
else: # Set cursor to 0, wich means no more items available.
|
else: # Set cursor to 0, wich means no more items available.
|
||||||
self.db[name]["cursor"] = 0
|
self.db[name]["cursor"] = 0
|
||||||
@@ -289,7 +290,7 @@ class Session(base.baseSession):
|
|||||||
name str: Name to save items to the database.
|
name str: Name to save items to the database.
|
||||||
function str: A function to get the items."""
|
function str: A function to get the items."""
|
||||||
last_id = -1
|
last_id = -1
|
||||||
if self.db.has_key(name):
|
if name in self.db:
|
||||||
try:
|
try:
|
||||||
if self.db[name][0]["id"] > self.db[name][-1]["id"]:
|
if self.db[name][0]["id"] > self.db[name][-1]["id"]:
|
||||||
last_id = self.db[name][0]["id"]
|
last_id = self.db[name][0]["id"]
|
||||||
@@ -309,7 +310,7 @@ class Session(base.baseSession):
|
|||||||
returns number of items retrieved."""
|
returns number of items retrieved."""
|
||||||
items_ = []
|
items_ = []
|
||||||
try:
|
try:
|
||||||
if self.db[name].has_key("cursor") and get_previous:
|
if "cursor" in self.db[name] and get_previous:
|
||||||
cursor = self.db[name]["cursor"]
|
cursor = self.db[name]["cursor"]
|
||||||
else:
|
else:
|
||||||
cursor = -1
|
cursor = -1
|
||||||
@@ -322,7 +323,7 @@ class Session(base.baseSession):
|
|||||||
tl[items].reverse()
|
tl[items].reverse()
|
||||||
num = self.order_cursored_buffer(name, tl[items])
|
num = self.order_cursored_buffer(name, tl[items])
|
||||||
# Recently, Twitter's new endpoints have cursor if there are more results.
|
# Recently, Twitter's new endpoints have cursor if there are more results.
|
||||||
if tl.has_key("next_cursor"):
|
if "next_cursor" in tl:
|
||||||
self.db[name]["cursor"] = tl["next_cursor"]
|
self.db[name]["cursor"] = tl["next_cursor"]
|
||||||
else:
|
else:
|
||||||
self.db[name]["cursor"] = 0
|
self.db[name]["cursor"] = 0
|
||||||
@@ -352,7 +353,7 @@ class Session(base.baseSession):
|
|||||||
def get_quoted_tweet(self, tweet):
|
def get_quoted_tweet(self, tweet):
|
||||||
""" Process a tweet and extract all information related to the quote."""
|
""" Process a tweet and extract all information related to the quote."""
|
||||||
quoted_tweet = tweet
|
quoted_tweet = tweet
|
||||||
if tweet.has_key("full_text"):
|
if "full_text" in tweet:
|
||||||
value = "full_text"
|
value = "full_text"
|
||||||
else:
|
else:
|
||||||
value = "text"
|
value = "text"
|
||||||
@@ -360,16 +361,16 @@ class Session(base.baseSession):
|
|||||||
for url in range(0, len(urls)):
|
for url in range(0, len(urls)):
|
||||||
try: quoted_tweet[value] = quoted_tweet[value].replace(urls[url], quoted_tweet["entities"]["urls"][url]["expanded_url"])
|
try: quoted_tweet[value] = quoted_tweet[value].replace(urls[url], quoted_tweet["entities"]["urls"][url]["expanded_url"])
|
||||||
except IndexError: pass
|
except IndexError: pass
|
||||||
if quoted_tweet.has_key("quoted_status"):
|
if "quoted_status" in quoted_tweet:
|
||||||
original_tweet = quoted_tweet["quoted_status"]
|
original_tweet = quoted_tweet["quoted_status"]
|
||||||
elif quoted_tweet.has_key("retweeted_status") and quoted_tweet["retweeted_status"].has_key("quoted_status"):
|
elif "retweeted_status" in quoted_tweet and "quoted_status" in quoted_tweet["retweeted_status"]:
|
||||||
original_tweet = quoted_tweet["retweeted_status"]["quoted_status"]
|
original_tweet = quoted_tweet["retweeted_status"]["quoted_status"]
|
||||||
else:
|
else:
|
||||||
return quoted_tweet
|
return quoted_tweet
|
||||||
original_tweet = self.check_long_tweet(original_tweet)
|
original_tweet = self.check_long_tweet(original_tweet)
|
||||||
if original_tweet.has_key("full_text"):
|
if "full_text" in original_tweet:
|
||||||
value = "full_text"
|
value = "full_text"
|
||||||
elif original_tweet.has_key("message"):
|
elif "message" in original_tweet:
|
||||||
value = "message"
|
value = "message"
|
||||||
else:
|
else:
|
||||||
value = "text"
|
value = "text"
|
||||||
@@ -386,13 +387,13 @@ class Session(base.baseSession):
|
|||||||
long = twishort.is_long(tweet)
|
long = twishort.is_long(tweet)
|
||||||
if long != False and config.app["app-settings"]["handle_longtweets"]:
|
if long != False and config.app["app-settings"]["handle_longtweets"]:
|
||||||
message = twishort.get_full_text(long)
|
message = twishort.get_full_text(long)
|
||||||
if tweet.has_key("quoted_status"):
|
if "quoted_status" in tweet:
|
||||||
tweet["quoted_status"]["message"] = message
|
tweet["quoted_status"]["message"] = message
|
||||||
if tweet["quoted_status"]["message"] == False: return False
|
if tweet["quoted_status"]["message"] == False: return False
|
||||||
tweet["quoted_status"]["twishort"] = True
|
tweet["quoted_status"]["twishort"] = True
|
||||||
for i in tweet["quoted_status"]["entities"]["user_mentions"]:
|
for i in tweet["quoted_status"]["entities"]["user_mentions"]:
|
||||||
if "@%s" % (i["screen_name"]) not in tweet["quoted_status"]["message"] and i["screen_name"] != tweet["user"]["screen_name"]:
|
if "@%s" % (i["screen_name"]) not in tweet["quoted_status"]["message"] and i["screen_name"] != tweet["user"]["screen_name"]:
|
||||||
if tweet["quoted_status"].has_key("retweeted_status") and tweet["retweeted_status"]["user"]["screen_name"] == i["screen_name"]:
|
if "retweeted_status" in tweet["quoted_status"] and tweet["retweeted_status"]["user"]["screen_name"] == i["screen_name"]:
|
||||||
continue
|
continue
|
||||||
tweet["quoted_status"]["message"] = u"@%s %s" % (i["screen_name"], tweet["message"])
|
tweet["quoted_status"]["message"] = u"@%s %s" % (i["screen_name"], tweet["message"])
|
||||||
else:
|
else:
|
||||||
@@ -401,7 +402,7 @@ class Session(base.baseSession):
|
|||||||
tweet["twishort"] = True
|
tweet["twishort"] = True
|
||||||
for i in tweet["entities"]["user_mentions"]:
|
for i in tweet["entities"]["user_mentions"]:
|
||||||
if "@%s" % (i["screen_name"]) not in tweet["message"] and i["screen_name"] != tweet["user"]["screen_name"]:
|
if "@%s" % (i["screen_name"]) not in tweet["message"] and i["screen_name"] != tweet["user"]["screen_name"]:
|
||||||
if tweet.has_key("retweeted_status") and tweet["retweeted_status"]["user"]["screen_name"] == i["screen_name"]:
|
if "retweeted_status" in tweet and tweet["retweeted_status"]["user"]["screen_name"] == i["screen_name"]:
|
||||||
continue
|
continue
|
||||||
return tweet
|
return tweet
|
||||||
|
|
||||||
@@ -409,8 +410,12 @@ class Session(base.baseSession):
|
|||||||
""" Returns an user object associated with an ID.
|
""" Returns an user object associated with an ID.
|
||||||
id str: User identifier, provided by Twitter.
|
id str: User identifier, provided by Twitter.
|
||||||
returns an user dict."""
|
returns an user dict."""
|
||||||
if self.db.has_key("users") == False or self.db["users"].has_key(id) == False:
|
if ("users" in self.db) == False or (id in self.db["users"]) == False:
|
||||||
|
try:
|
||||||
user = self.twitter.show_user(id=id)
|
user = self.twitter.show_user(id=id)
|
||||||
|
except TwythonError:
|
||||||
|
user = dict(screen_name="deleted_account", name="Deleted account")
|
||||||
|
return user
|
||||||
self.db["users"][user["id_str"]] = user
|
self.db["users"][user["id_str"]] = user
|
||||||
return user
|
return user
|
||||||
else:
|
else:
|
||||||
@@ -420,7 +425,7 @@ class Session(base.baseSession):
|
|||||||
""" Returns an user identifier associated with a screen_name.
|
""" Returns an user identifier associated with a screen_name.
|
||||||
screen_name str: User name, such as tw_blue2, provided by Twitter.
|
screen_name str: User name, such as tw_blue2, provided by Twitter.
|
||||||
returns an user ID."""
|
returns an user ID."""
|
||||||
if self.db.has_key("users") == False:
|
if ("users" in self.db) == False:
|
||||||
user = utils.if_user_exists(self.twitter, screen_name)
|
user = utils.if_user_exists(self.twitter, screen_name)
|
||||||
self.db["users"][user["id_str"]] = user
|
self.db["users"][user["id_str"]] = user
|
||||||
return user["id_str"]
|
return user["id_str"]
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import print_function
|
||||||
import url_shortener, re
|
import url_shortener, re
|
||||||
import output
|
import output
|
||||||
from twython import TwythonError
|
from twython import TwythonError
|
||||||
@@ -24,32 +25,32 @@ def find_urls_in_text(text):
|
|||||||
def find_urls (tweet):
|
def find_urls (tweet):
|
||||||
urls = []
|
urls = []
|
||||||
# Let's add URLS from tweet entities.
|
# Let's add URLS from tweet entities.
|
||||||
if tweet.has_key("message_create"):
|
if "message_create" in tweet:
|
||||||
entities = tweet["message_create"]["message_data"]["entities"]
|
entities = tweet["message_create"]["message_data"]["entities"]
|
||||||
else:
|
else:
|
||||||
entities = tweet["entities"]
|
entities = tweet["entities"]
|
||||||
for i in entities["urls"]:
|
for i in entities["urls"]:
|
||||||
if i["expanded_url"] not in urls:
|
if i["expanded_url"] not in urls:
|
||||||
urls.append(i["expanded_url"])
|
urls.append(i["expanded_url"])
|
||||||
if tweet.has_key("quoted_status"):
|
if "quoted_status" in tweet:
|
||||||
for i in tweet["quoted_status"]["entities"]["urls"]:
|
for i in tweet["quoted_status"]["entities"]["urls"]:
|
||||||
if i["expanded_url"] not in urls:
|
if i["expanded_url"] not in urls:
|
||||||
urls.append(i["expanded_url"])
|
urls.append(i["expanded_url"])
|
||||||
if tweet.has_key("retweeted_status"):
|
if "retweeted_status" in tweet:
|
||||||
for i in tweet["retweeted_status"]["entities"]["urls"]:
|
for i in tweet["retweeted_status"]["entities"]["urls"]:
|
||||||
if i["expanded_url"] not in urls:
|
if i["expanded_url"] not in urls:
|
||||||
urls.append(i["expanded_url"])
|
urls.append(i["expanded_url"])
|
||||||
if tweet["retweeted_status"].has_key("quoted_status"):
|
if "quoted_status" in tweet["retweeted_status"]:
|
||||||
for i in tweet["retweeted_status"]["quoted_status"]["entities"]["urls"]:
|
for i in tweet["retweeted_status"]["quoted_status"]["entities"]["urls"]:
|
||||||
if i["expanded_url"] not in urls:
|
if i["expanded_url"] not in urls:
|
||||||
urls.append(i["expanded_url"])
|
urls.append(i["expanded_url"])
|
||||||
if tweet.has_key("message"):
|
if "message" in tweet:
|
||||||
i = "message"
|
i = "message"
|
||||||
elif tweet.has_key("full_text"):
|
elif "full_text" in tweet:
|
||||||
i = "full_text"
|
i = "full_text"
|
||||||
else:
|
else:
|
||||||
i = "text"
|
i = "text"
|
||||||
if tweet.has_key("message_create"):
|
if "message_create" in tweet:
|
||||||
extracted_urls = find_urls_in_text(tweet["message_create"]["message_data"]["text"])
|
extracted_urls = find_urls_in_text(tweet["message_create"]["message_data"]["text"])
|
||||||
else:
|
else:
|
||||||
extracted_urls = find_urls_in_text(tweet[i])
|
extracted_urls = find_urls_in_text(tweet[i])
|
||||||
@@ -82,7 +83,7 @@ def is_audio(tweet):
|
|||||||
try:
|
try:
|
||||||
if len(find_urls(tweet)) < 1:
|
if len(find_urls(tweet)) < 1:
|
||||||
return False
|
return False
|
||||||
if tweet.has_key("message_create"):
|
if "message_create" in tweet:
|
||||||
entities = tweet["message_create"]["message_data"]["entities"]
|
entities = tweet["message_create"]["message_data"]["entities"]
|
||||||
else:
|
else:
|
||||||
entities = tweet["entities"]
|
entities = tweet["entities"]
|
||||||
@@ -91,22 +92,22 @@ def is_audio(tweet):
|
|||||||
if i["text"] == "audio":
|
if i["text"] == "audio":
|
||||||
return True
|
return True
|
||||||
except IndexError:
|
except IndexError:
|
||||||
print tweet["entities"]["hashtags"]
|
print(tweet["entities"]["hashtags"])
|
||||||
log.exception("Exception while executing is_audio hashtag algorithm")
|
log.exception("Exception while executing is_audio hashtag algorithm")
|
||||||
|
|
||||||
def is_geocoded(tweet):
|
def is_geocoded(tweet):
|
||||||
if tweet.has_key("coordinates") and tweet["coordinates"] != None:
|
if "coordinates" in tweet and tweet["coordinates"] != None:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def is_media(tweet):
|
def is_media(tweet):
|
||||||
if tweet.has_key("message_create"):
|
if "message_create" in tweet:
|
||||||
entities = tweet["message_create"]["message_data"]["entities"]
|
entities = tweet["message_create"]["message_data"]["entities"]
|
||||||
else:
|
else:
|
||||||
entities = tweet["entities"]
|
entities = tweet["entities"]
|
||||||
if entities.has_key("media") == False:
|
if ("media" in entities) == False:
|
||||||
return False
|
return False
|
||||||
for i in entities["media"]:
|
for i in entities["media"]:
|
||||||
if i.has_key("type") and i["type"] == "photo":
|
if "type" in i and i["type"] == "photo":
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -121,10 +122,10 @@ def get_all_mentioned(tweet, conf, field="screen_name"):
|
|||||||
|
|
||||||
def get_all_users(tweet, conf):
|
def get_all_users(tweet, conf):
|
||||||
string = []
|
string = []
|
||||||
if tweet.has_key("retweeted_status"):
|
if "retweeted_status" in tweet:
|
||||||
string.append(tweet["user"]["screen_name"])
|
string.append(tweet["user"]["screen_name"])
|
||||||
tweet = tweet["retweeted_status"]
|
tweet = tweet["retweeted_status"]
|
||||||
if tweet.has_key("sender"):
|
if "sender" in tweet:
|
||||||
string.append(tweet["sender"]["screen_name"])
|
string.append(tweet["sender"]["screen_name"])
|
||||||
else:
|
else:
|
||||||
if tweet["user"]["screen_name"] != conf["user_name"]:
|
if tweet["user"]["screen_name"] != conf["user_name"]:
|
||||||
@@ -161,16 +162,16 @@ def api_call(parent=None, call_name=None, preexec_message="", success="", succes
|
|||||||
|
|
||||||
def is_allowed(tweet, settings, buffer_name):
|
def is_allowed(tweet, settings, buffer_name):
|
||||||
clients = settings["twitter"]["ignored_clients"]
|
clients = settings["twitter"]["ignored_clients"]
|
||||||
if tweet.has_key("sender"): return True
|
if "sender" in tweet: return True
|
||||||
allowed = True
|
allowed = True
|
||||||
tweet_data = {}
|
tweet_data = {}
|
||||||
if tweet.has_key("retweeted_status"):
|
if "retweeted_status" in tweet:
|
||||||
tweet_data["retweet"] = True
|
tweet_data["retweet"] = True
|
||||||
if tweet["in_reply_to_status_id_str"] != None:
|
if tweet["in_reply_to_status_id_str"] != None:
|
||||||
tweet_data["reply"] = True
|
tweet_data["reply"] = True
|
||||||
if tweet.has_key("quoted_status"):
|
if "quoted_status" in tweet:
|
||||||
tweet_data["quote"] = True
|
tweet_data["quote"] = True
|
||||||
if tweet.has_key("retweeted_status"): tweet = tweet["retweeted_status"]
|
if "retweeted_status" in tweet: tweet = tweet["retweeted_status"]
|
||||||
source = re.sub(r"(?s)<.*?>", "", tweet["source"])
|
source = re.sub(r"(?s)<.*?>", "", tweet["source"])
|
||||||
for i in clients:
|
for i in clients:
|
||||||
if i.lower() == source.lower():
|
if i.lower() == source.lower():
|
||||||
@@ -178,7 +179,7 @@ def is_allowed(tweet, settings, buffer_name):
|
|||||||
return filter_tweet(tweet, tweet_data, settings, buffer_name)
|
return filter_tweet(tweet, tweet_data, settings, buffer_name)
|
||||||
|
|
||||||
def filter_tweet(tweet, tweet_data, settings, buffer_name):
|
def filter_tweet(tweet, tweet_data, settings, buffer_name):
|
||||||
if tweet.has_key("full_text"):
|
if "full_text" in tweet:
|
||||||
value = "full_text"
|
value = "full_text"
|
||||||
else:
|
else:
|
||||||
value = "text"
|
value = "text"
|
||||||
@@ -187,23 +188,23 @@ def filter_tweet(tweet, tweet_data, settings, buffer_name):
|
|||||||
regexp = settings["filters"][i]["regexp"]
|
regexp = settings["filters"][i]["regexp"]
|
||||||
word = settings["filters"][i]["word"]
|
word = settings["filters"][i]["word"]
|
||||||
# Added if/else for compatibility reasons.
|
# Added if/else for compatibility reasons.
|
||||||
if settings["filters"][i].has_key("allow_rts"):
|
if "allow_rts" in settings["filters"][i]:
|
||||||
allow_rts = settings["filters"][i]["allow_rts"]
|
allow_rts = settings["filters"][i]["allow_rts"]
|
||||||
else:
|
else:
|
||||||
allow_rts = "True"
|
allow_rts = "True"
|
||||||
if settings["filters"][i].has_key("allow_quotes"):
|
if "allow_quotes" in settings["filters"][i]:
|
||||||
allow_quotes = settings["filters"][i]["allow_quotes"]
|
allow_quotes = settings["filters"][i]["allow_quotes"]
|
||||||
else:
|
else:
|
||||||
allow_quotes = "True"
|
allow_quotes = "True"
|
||||||
if settings["filters"][i].has_key("allow_replies"):
|
if "allow_replies" in settings["filters"][i]:
|
||||||
allow_replies = settings["filters"][i]["allow_replies"]
|
allow_replies = settings["filters"][i]["allow_replies"]
|
||||||
else:
|
else:
|
||||||
allow_replies = "True"
|
allow_replies = "True"
|
||||||
if allow_rts == "False" and tweet_data.has_key("retweet"):
|
if allow_rts == "False" and "retweet" in tweet_data:
|
||||||
return False
|
return False
|
||||||
if allow_quotes == "False" and tweet_data.has_key("quote"):
|
if allow_quotes == "False" and "quote" in tweet_data:
|
||||||
return False
|
return False
|
||||||
if allow_replies == "False" and tweet_data.has_key("reply"):
|
if allow_replies == "False" and "reply" in tweet_data:
|
||||||
return False
|
return False
|
||||||
if word != "" and settings["filters"][i]["if_word_exists"]:
|
if word != "" and settings["filters"][i]["if_word_exists"]:
|
||||||
if word in tweet[value]:
|
if word in tweet[value]:
|
||||||
|
21
src/sound.py
21
src/sound.py
@@ -1,16 +1,18 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import sys
|
|
||||||
import url_shortener
|
|
||||||
import audio_services
|
|
||||||
import os
|
import os
|
||||||
import logging as original_logger
|
import logging as original_logger
|
||||||
log = original_logger.getLogger("sound")
|
import sys
|
||||||
import paths
|
|
||||||
import sound_lib
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import platform
|
import platform
|
||||||
|
import tempfile
|
||||||
|
import glob
|
||||||
|
import url_shortener
|
||||||
|
import audio_services
|
||||||
|
import paths
|
||||||
|
import sound_lib
|
||||||
import output
|
import output
|
||||||
import youtube_utils
|
import youtube_utils
|
||||||
|
import application
|
||||||
system = platform.system()
|
system = platform.system()
|
||||||
if system=="Windows" and not hasattr(sys, 'frozen'): # We are running from source on Windows
|
if system=="Windows" and not hasattr(sys, 'frozen'): # We are running from source on Windows
|
||||||
current_dir=os.getcwd()
|
current_dir=os.getcwd()
|
||||||
@@ -18,13 +20,14 @@ if system=="Windows" and not hasattr(sys, 'frozen'): # We are running from sourc
|
|||||||
import vlc
|
import vlc
|
||||||
if system=="Windows" and not hasattr(sys, 'frozen'): # Restore the original folder
|
if system=="Windows" and not hasattr(sys, 'frozen'): # Restore the original folder
|
||||||
os.chdir(current_dir)
|
os.chdir(current_dir)
|
||||||
|
import sound_lib.output, sound_lib.input, sound_lib.stream
|
||||||
from mysc.repeating_timer import RepeatingTimer
|
from mysc.repeating_timer import RepeatingTimer
|
||||||
from mysc.thread_utils import call_threaded
|
from mysc.thread_utils import call_threaded
|
||||||
import application
|
|
||||||
import tempfile
|
|
||||||
import glob
|
|
||||||
URLPlayer = None
|
URLPlayer = None
|
||||||
|
|
||||||
|
log = original_logger.getLogger("sound")
|
||||||
|
|
||||||
def setup():
|
def setup():
|
||||||
global URLPlayer
|
global URLPlayer
|
||||||
if not URLPlayer:
|
if not URLPlayer:
|
||||||
|
@@ -1,25 +0,0 @@
|
|||||||
import output, input, recording, stream
|
|
||||||
|
|
||||||
__author__ = 'Christopher Toth'
|
|
||||||
__version__ = 0.73
|
|
||||||
|
|
||||||
def find_datafiles():
|
|
||||||
from glob import glob
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import sound_lib
|
|
||||||
path = os.path.join(sound_lib.__path__[0], 'lib')
|
|
||||||
system = platform.system()
|
|
||||||
if system == 'Windows':
|
|
||||||
file_ext = '*.dll'
|
|
||||||
elif system == 'Darwin':
|
|
||||||
file_ext = '*.dylib'
|
|
||||||
else:
|
|
||||||
file_ext = '*.so'
|
|
||||||
if platform.architecture()[0] == '32bit' or platform.system() == 'Darwin':
|
|
||||||
arch = 'x86'
|
|
||||||
else:
|
|
||||||
arch = 'x64'
|
|
||||||
dest_dir = os.path.join('sound_lib', 'lib', arch)
|
|
||||||
source = glob(os.path.join(path, arch, file_ext))
|
|
||||||
return [(dest_dir, source)]
|
|
@@ -1,285 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
from .external.pybass import *
|
|
||||||
from .main import bass_call, bass_call_0, BassError, update_3d_system, FlagObject
|
|
||||||
from ctypes import pointer, c_float, c_long, c_ulong, c_buffer
|
|
||||||
|
|
||||||
class Channel (FlagObject):
|
|
||||||
"""A "channel" can be a sample playback channel (HCHANNEL), a sample stream (HSTREAM), a MOD music (HMUSIC), or a recording (HRECORD). Each "Channel" function can be used with one or more of these channel types."""
|
|
||||||
|
|
||||||
def __init__ (self, handle):
|
|
||||||
self.handle = handle
|
|
||||||
self.attribute_mapping = {
|
|
||||||
'eaxmix': BASS_ATTRIB_EAXMIX,
|
|
||||||
'frequency': BASS_ATTRIB_FREQ,
|
|
||||||
'pan': BASS_ATTRIB_PAN,
|
|
||||||
'volume': BASS_ATTRIB_VOL
|
|
||||||
}
|
|
||||||
|
|
||||||
def add_attributes_to_mapping(self, **attrs):
|
|
||||||
self.attribute_mapping.update(**attrs)
|
|
||||||
|
|
||||||
def play (self, restart=False):
|
|
||||||
"""Starts (or resumes) playback of a sample, stream, MOD music, or recording."""
|
|
||||||
return bass_call(BASS_ChannelPlay, self.handle, restart)
|
|
||||||
|
|
||||||
def play_blocking(self, restart=False):
|
|
||||||
self.play(restart=restart)
|
|
||||||
while self.is_playing:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def pause (self):
|
|
||||||
return bass_call(BASS_ChannelPause, self.handle)
|
|
||||||
|
|
||||||
def is_active (self):
|
|
||||||
"Checks if a sample, stream, or MOD music is active (playing) or stalled. Can also check if a recording is in progress."""
|
|
||||||
return bass_call_0(BASS_ChannelIsActive, self.handle)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_playing(self):
|
|
||||||
return self.is_active() == BASS_ACTIVE_PLAYING
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_paused(self):
|
|
||||||
return self.is_active() == BASS_ACTIVE_PAUSED
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_stopped(self):
|
|
||||||
return self.is_active() == BASS_ACTIVE_STOPPED
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_stalled(self):
|
|
||||||
return self.is_active() == BASS_ACTIVE_STALLED
|
|
||||||
|
|
||||||
def get_position (self, mode=BASS_POS_BYTE):
|
|
||||||
"""Retrieves the playback position of a sample, stream, or MOD music. Can also be used with a recording channel."""
|
|
||||||
return bass_call_0(BASS_ChannelGetPosition, self.handle, mode)
|
|
||||||
|
|
||||||
def set_position (self, pos, mode=BASS_POS_BYTE):
|
|
||||||
"""Sets the playback position of a sample, MOD music, or stream."""
|
|
||||||
return bass_call(BASS_ChannelSetPosition, self.handle, pos, mode)
|
|
||||||
|
|
||||||
position = property(get_position, set_position)
|
|
||||||
|
|
||||||
def stop (self):
|
|
||||||
"""Stops a sample, stream, MOD music, or recording."""
|
|
||||||
return bass_call(BASS_ChannelStop, self.handle)
|
|
||||||
|
|
||||||
def update (self, length=0):
|
|
||||||
"""Updates the playback buffer of a stream or MOD music."""
|
|
||||||
return bass_call(BASS_ChannelUpdate, self.handle, length)
|
|
||||||
|
|
||||||
def get_length (self, mode=BASS_POS_BYTE):
|
|
||||||
return bass_call_0(BASS_ChannelGetLength, self.handle, mode)
|
|
||||||
|
|
||||||
__len__ = get_length
|
|
||||||
|
|
||||||
def __bool__(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_device(self):
|
|
||||||
"""Retrieves the device that a channel is using."""
|
|
||||||
return bass_call_0( BASS_ChannelGetDevice, self.handle)
|
|
||||||
|
|
||||||
def set_device (self, device):
|
|
||||||
"""Changes the device that a stream, MOD music or sample is using."""
|
|
||||||
bass_call(BASS_ChannelSetDevice, self.handle, device)
|
|
||||||
|
|
||||||
device = property(get_device, set_device)
|
|
||||||
|
|
||||||
def set_fx(self, type, priority=0):
|
|
||||||
"""Sets an effect on a stream, MOD music, or recording channel."""
|
|
||||||
return SoundEffect(bass_call(BASS_ChannelSetFX, type, priority))
|
|
||||||
|
|
||||||
def bytes_to_seconds(self, position=None):
|
|
||||||
"""Translates a byte position into time (seconds), based on a channel's format."""
|
|
||||||
position = position or self.position
|
|
||||||
return bass_call_0(BASS_ChannelBytes2Seconds, self.handle, position)
|
|
||||||
|
|
||||||
def length_in_seconds(self):
|
|
||||||
return self.bytes_to_seconds(self.get_length())
|
|
||||||
|
|
||||||
|
|
||||||
def seconds_to_bytes(self, position):
|
|
||||||
"""Translates a time (seconds) position into bytes, based on a channel's format."""
|
|
||||||
return bass_call_0(BASS_ChannelSeconds2Bytes, self.handle, position)
|
|
||||||
|
|
||||||
def get_attribute(self, attribute):
|
|
||||||
"""Retrieves the value of a channel's attribute."""
|
|
||||||
value = pointer(c_float())
|
|
||||||
if attribute in self.attribute_mapping:
|
|
||||||
attribute = self.attribute_mapping[attribute]
|
|
||||||
bass_call(BASS_ChannelGetAttribute, self.handle, attribute, value)
|
|
||||||
return value.contents.value
|
|
||||||
|
|
||||||
def set_attribute(self, attribute, value):
|
|
||||||
"""Sets the value of a channel's attribute."""
|
|
||||||
if attribute in self.attribute_mapping:
|
|
||||||
attribute = self.attribute_mapping[attribute]
|
|
||||||
return bass_call(BASS_ChannelSetAttribute, self.handle, attribute, value)
|
|
||||||
|
|
||||||
def slide_attribute(self, attribute, value, time):
|
|
||||||
"""Slides a channel's attribute from its current value to a new value."""
|
|
||||||
if attribute in self.attribute_mapping:
|
|
||||||
attribute = self.attribute_mapping[attribute]
|
|
||||||
return bass_call(BASS_ChannelSlideAttribute, self.handle, attribute, value, time*1000)
|
|
||||||
|
|
||||||
def is_sliding (self, attribute=None):
|
|
||||||
"""Checks if an attribute (or any attribute) of a sample, stream, or MOD music is sliding."""
|
|
||||||
return bass_call_0(BASS_ChannelIsSliding, self.handle, attribute)
|
|
||||||
|
|
||||||
def get_info(self):
|
|
||||||
"""Retrieves information on a channel."""
|
|
||||||
value = pointer(BASS_CHANNELINFO())
|
|
||||||
bass_call(BASS_ChannelGetInfo, self.handle, value)
|
|
||||||
return value[0]
|
|
||||||
|
|
||||||
def get_level(self):
|
|
||||||
"""Retrieves the level (peak amplitude) of a stream, MOD music or recording channel."""
|
|
||||||
return bass_call_0(BASS_ChannelGetLevel, self.handle)
|
|
||||||
|
|
||||||
def lock(self):
|
|
||||||
"""Locks a stream, MOD music or recording channel to the current thread."""
|
|
||||||
return bass_call(BASS_ChannelLock, self.handle, True)
|
|
||||||
|
|
||||||
def unlock(self):
|
|
||||||
"""Unlocks a stream, MOD music or recording channel from the current thread."""
|
|
||||||
return bass_call(BASS_ChannelLock, self.handle, False)
|
|
||||||
|
|
||||||
def get_3d_attributes(self):
|
|
||||||
"""Retrieves the 3D attributes of a sample, stream, or MOD music channel with 3D functionality."""
|
|
||||||
answer = dict(mode=c_ulong(), min=c_float(), max=c_float(), iangle=c_ulong(), oangle=c_ulong(), outvol=c_float())
|
|
||||||
bass_call(BASS_ChannelGet3DAttributes, self.handle, pointer(answer['mode']), pointer(answer['min']), pointer(answer['max']), pointer(answer['iangle']), pointer(answer['oangle']), pointer(answer['outvol']))
|
|
||||||
for k in answer:
|
|
||||||
answer[k] = answer[k].value()
|
|
||||||
return answer
|
|
||||||
|
|
||||||
@update_3d_system
|
|
||||||
def set_3d_attributes(self, mode=-1, min=0.0, max=0.0, iangle=-1, oangle=-1, outvol=-1):
|
|
||||||
"""Sets the 3D attributes of a sample, stream, or MOD music channel with 3D functionality."""
|
|
||||||
return bass_call(BASS_ChannelSet3DAttributes, self.handle, mode, min, max, iangle, oangle, outvol)
|
|
||||||
|
|
||||||
def get_3d_position(self):
|
|
||||||
"""Retrieves the 3D position of a sample, stream, or MOD music channel with 3D functionality."""
|
|
||||||
answer = dict(position=BASS_3DVECTOR(), orientation=BASS_3DVECTOR(), velocity=BASS_3DVECTOR())
|
|
||||||
bass_call(BASS_ChannelGet3DPosition, self.handle, pointer(answer['position']), pointer(answer['orientation']), pointer(answer['velocity']))
|
|
||||||
return answer
|
|
||||||
|
|
||||||
@update_3d_system
|
|
||||||
def set_3d_position(self, position=None, orientation=None, velocity=None):
|
|
||||||
"""Sets the 3D position of a sample, stream, or MOD music channel with 3D functionality."""
|
|
||||||
if position:
|
|
||||||
position = pointer(position)
|
|
||||||
if orientation:
|
|
||||||
orientation = pointer(orientation)
|
|
||||||
if velocity:
|
|
||||||
velocity = pointer(velocity)
|
|
||||||
return bass_call(BASS_ChannelSet3DPosition, self.handle, position, orientation, velocity)
|
|
||||||
|
|
||||||
def set_link(self, handle):
|
|
||||||
"""Links two MOD music or stream channels together."""
|
|
||||||
bass_call(BASS_ChannelSetLink, self.handle, handle)
|
|
||||||
|
|
||||||
def remove_link(self, handle):
|
|
||||||
"""Removes a link between two MOD music or stream channels."""
|
|
||||||
return bass_call(BASS_ChannelRemoveLink, self.handle, handle)
|
|
||||||
|
|
||||||
def __iadd__(self, other):
|
|
||||||
"""Convenience method to link this channel to another. Calls set_link on the passed in item's handle"""
|
|
||||||
self.set_link(other.handle)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __isub__(self, other):
|
|
||||||
"""Convenience method to unlink this channel from another. Calls remove_link on the passed in item's handle"""
|
|
||||||
self.remove_link(other.handle)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def get_frequency(self):
|
|
||||||
return self.get_attribute(BASS_ATTRIB_FREQ )
|
|
||||||
|
|
||||||
def set_frequency(self, frequency):
|
|
||||||
self.set_attribute(BASS_ATTRIB_FREQ, frequency)
|
|
||||||
|
|
||||||
frequency = property(fget=get_frequency, fset=set_frequency)
|
|
||||||
|
|
||||||
def get_pan(self):
|
|
||||||
return self.get_attribute(BASS_ATTRIB_PAN)
|
|
||||||
|
|
||||||
def set_pan(self, pan):
|
|
||||||
return self.set_attribute(BASS_ATTRIB_PAN, pan)
|
|
||||||
|
|
||||||
pan = property(fget=get_pan, fset=set_pan)
|
|
||||||
|
|
||||||
def get_volume(self):
|
|
||||||
return self.get_attribute(BASS_ATTRIB_VOL)
|
|
||||||
|
|
||||||
def set_volume(self, volume):
|
|
||||||
self.set_attribute(BASS_ATTRIB_VOL, volume)
|
|
||||||
|
|
||||||
volume = property(fget=get_volume, fset=set_volume)
|
|
||||||
|
|
||||||
def get_data(self, length=16384):
|
|
||||||
buf = c_buffer(length)
|
|
||||||
bass_call_0(BASS_ChannelGetData, self.handle, pointer(buf), length)
|
|
||||||
return buf
|
|
||||||
|
|
||||||
|
|
||||||
#This is less and less of a one-to-one mapping,
|
|
||||||
#But I feel that it's better to be consistent with ourselves
|
|
||||||
#Than with the library. We won't punish ourselves
|
|
||||||
#For their bad decisions
|
|
||||||
|
|
||||||
def get_looping(self):
|
|
||||||
return bass_call_0(BASS_ChannelFlags, self.handle, BASS_SAMPLE_LOOP, 0) == 20
|
|
||||||
|
|
||||||
def set_looping(self, looping):
|
|
||||||
if looping:
|
|
||||||
return bass_call_0(BASS_ChannelFlags, self.handle, BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP)
|
|
||||||
return bass_call_0(BASS_ChannelFlags, self.handle, 0, BASS_SAMPLE_LOOP)
|
|
||||||
|
|
||||||
looping = property(fget=get_looping, fset=set_looping)
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
try:
|
|
||||||
self.free()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_x(self):
|
|
||||||
return self.get_3d_position()['position'].x
|
|
||||||
|
|
||||||
def set_x(self, val):
|
|
||||||
pos = self.get_3d_position()
|
|
||||||
pos['position'].x = val
|
|
||||||
self.set_3d_position(**pos)
|
|
||||||
|
|
||||||
x = property(fget=get_x, fset=set_x)
|
|
||||||
|
|
||||||
def get_y(self):
|
|
||||||
return self.get_3d_position()['position'].y
|
|
||||||
|
|
||||||
def set_y(self, val):
|
|
||||||
pos = self.get_3d_position()
|
|
||||||
pos['position'].y = val
|
|
||||||
self.set_3d_position(**pos)
|
|
||||||
|
|
||||||
y = property(fget=get_y, fset=set_y)
|
|
||||||
|
|
||||||
def get_z(self):
|
|
||||||
return self.get_3d_position()['position'].z
|
|
||||||
|
|
||||||
def set_z(self, val):
|
|
||||||
pos = self.get_3d_position()
|
|
||||||
pos['position'].z = val
|
|
||||||
self.set_3d_position(**pos)
|
|
||||||
|
|
||||||
z = property(fget=get_z, fset=set_z)
|
|
||||||
|
|
||||||
def get_attributes(self):
|
|
||||||
"""Retrieves all values of all attributes from this object and displays them in a dictionary whose keys are determined by this object's attribute_mapping"""
|
|
||||||
res = {}
|
|
||||||
for k in self.attribute_mapping:
|
|
||||||
try:
|
|
||||||
res[k] = self.get_attribute(k)
|
|
||||||
except BassError:
|
|
||||||
pass
|
|
||||||
return res
|
|
@@ -1,57 +0,0 @@
|
|||||||
import collections
|
|
||||||
import ctypes
|
|
||||||
from sound_lib.external import pybass
|
|
||||||
from sound_lib.main import bass_call, bass_call_0
|
|
||||||
|
|
||||||
class BassConfig(collections.Mapping):
|
|
||||||
config_map = {
|
|
||||||
'3d_algorithm': pybass.BASS_CONFIG_3DALGORITHM,
|
|
||||||
'buffer': pybass.BASS_CONFIG_BUFFER ,
|
|
||||||
'curve_vol': pybass.BASS_CONFIG_CURVE_VOL,
|
|
||||||
'curve_pan': pybass.BASS_CONFIG_CURVE_PAN,
|
|
||||||
'dev_buffer': pybass.BASS_CONFIG_DEV_BUFFER,
|
|
||||||
'dev_default': pybass.BASS_CONFIG_DEV_DEFAULT,
|
|
||||||
'float_dsp': pybass.BASS_CONFIG_FLOATDSP,
|
|
||||||
'gvol_music': pybass.BASS_CONFIG_GVOL_MUSIC,
|
|
||||||
'gvol_sample': pybass.BASS_CONFIG_GVOL_SAMPLE,
|
|
||||||
'gvol_stream': pybass.BASS_CONFIG_GVOL_STREAM,
|
|
||||||
'music_virtual': pybass.BASS_CONFIG_MUSIC_VIRTUAL,
|
|
||||||
'net_agent': pybass.BASS_CONFIG_NET_AGENT,
|
|
||||||
'net_buffer': pybass.BASS_CONFIG_NET_BUFFER,
|
|
||||||
'net_passive': pybass.BASS_CONFIG_NET_PASSIVE,
|
|
||||||
'net_playlist': pybass.BASS_CONFIG_NET_PLAYLIST,
|
|
||||||
'net_prebuf': pybass.BASS_CONFIG_NET_PREBUF,
|
|
||||||
'net_proxy': pybass.BASS_CONFIG_NET_PROXY,
|
|
||||||
'net_read_timeout': pybass.BASS_CONFIG_NET_READTIMEOUT,
|
|
||||||
'net_timeout': pybass.BASS_CONFIG_NET_TIMEOUT,
|
|
||||||
'pause_no_play': pybass.BASS_CONFIG_PAUSE_NOPLAY,
|
|
||||||
'rec_buffer': pybass.BASS_CONFIG_REC_BUFFER,
|
|
||||||
'src': pybass.BASS_CONFIG_SRC,
|
|
||||||
'src_sample': pybass.BASS_CONFIG_SRC_SAMPLE,
|
|
||||||
'unicode': pybass.BASS_CONFIG_UNICODE,
|
|
||||||
'update_period': pybass.BASS_CONFIG_UPDATEPERIOD,
|
|
||||||
'update_threads': pybass.BASS_CONFIG_UPDATETHREADS,
|
|
||||||
'verify': pybass.BASS_CONFIG_VERIFY,
|
|
||||||
'vista_speakers': pybass.BASS_CONFIG_VISTA_SPEAKERS,
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr_config = (pybass.BASS_CONFIG_NET_AGENT, pybass.BASS_CONFIG_NET_PROXY)
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
key = self.config_map.get(key, key)
|
|
||||||
if key in self.ptr_config:
|
|
||||||
return ctypes.string_at(bass_call(pybass.BASS_GetConfigPtr, key))
|
|
||||||
return bass_call_0(pybass.BASS_GetConfig, key)
|
|
||||||
|
|
||||||
def __setitem__(self, key, val):
|
|
||||||
key = self.config_map.get(key, key)
|
|
||||||
if key in self.ptr_config:
|
|
||||||
return bass_call(pybass.BASS_SetConfigPtr, key, ctypes.create_string_buffer(val))
|
|
||||||
return bass_call(pybass.BASS_SetConfig, key, val)
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
for key in self.config_map.keys():
|
|
||||||
yield key
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self.config_map)
|
|
@@ -1 +0,0 @@
|
|||||||
from .tempo import Tempo
|
|
@@ -1,39 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
from sound_lib.external import pybass
|
|
||||||
from .effect import SoundEffect
|
|
||||||
|
|
||||||
class Chorus(SoundEffect):
|
|
||||||
effect_type = pybass.BASS_FX_DX8_CHORUS
|
|
||||||
struct = pybass.BASS_DX8_CHORUS
|
|
||||||
|
|
||||||
class Echo(SoundEffect):
|
|
||||||
effect_type = pybass.BASS_FX_DX8_ECHO
|
|
||||||
struct = pybass.BASS_DX8_ECHO
|
|
||||||
|
|
||||||
class Compressor(SoundEffect):
|
|
||||||
effect_type = pybass.BASS_FX_DX8_COMPRESSOR
|
|
||||||
struct = pybass.BASS_DX8_COMPRESSOR
|
|
||||||
|
|
||||||
class Reverb(SoundEffect):
|
|
||||||
effect_type = pybass.BASS_FX_DX8_REVERB
|
|
||||||
struct = pybass.BASS_DX8_REVERB
|
|
||||||
|
|
||||||
class Distortion(SoundEffect):
|
|
||||||
effect_type = pybass.BASS_FX_DX8_DISTORTION
|
|
||||||
struct = pybass.BASS_DX8_DISTORTION
|
|
||||||
|
|
||||||
class Flanger(SoundEffect):
|
|
||||||
effect_type = pybass.BASS_FX_DX8_FLANGER
|
|
||||||
struct = pybass.BASS_DX8_FLANGER
|
|
||||||
|
|
||||||
class Gargle(SoundEffect):
|
|
||||||
effect_type = pybass.BASS_FX_DX8_GARGLE
|
|
||||||
struct = pybass.BASS_DX8_GARGLE
|
|
||||||
|
|
||||||
class I3DL2Reverb(SoundEffect):
|
|
||||||
effect_type = pybass.BASS_FX_DX8_I3DL2REVERB
|
|
||||||
struct = pybass.BASS_DX8_I3DL2REVERB
|
|
||||||
|
|
||||||
class ParamEq(SoundEffect):
|
|
||||||
effect_type = pybass.BASS_FX_DX8_PARAMEQ
|
|
||||||
struct = pybass.BASS_DX8_PARAMEQ
|
|
@@ -1,14 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
from sound_lib.external import pybass_fx
|
|
||||||
from .effect import SoundEffect
|
|
||||||
|
|
||||||
class Volume(SoundEffect):
|
|
||||||
effect_type = pybass_fx.BASS_FX_BFX_VOLUME
|
|
||||||
struct = pybass_fx.BASS_BFX_VOLUME
|
|
||||||
|
|
||||||
class PeakEq(SoundEffect):
|
|
||||||
effect_type = pybass_fx.BASS_FX_BFX_PEAKEQ
|
|
||||||
struct = pybass_fx.BASS_BFX_PEAKEQ
|
|
||||||
class DAmp(SoundEffect):
|
|
||||||
effect_type = pybass_fx.BASS_FX_BFX_DAMP
|
|
||||||
struct = pybass_fx.BASS_BFX_DAMP
|
|
@@ -1,71 +0,0 @@
|
|||||||
from future.builtins import object
|
|
||||||
from sound_lib.main import bass_call
|
|
||||||
import ctypes
|
|
||||||
from sound_lib.external import pybass
|
|
||||||
import string #for the alphabet!
|
|
||||||
|
|
||||||
class SoundEffect(object):
|
|
||||||
|
|
||||||
def __init__(self, channel, type=None, priority=0):
|
|
||||||
self.original_channel = channel
|
|
||||||
if hasattr(channel, 'handle'):
|
|
||||||
channel = channel.handle
|
|
||||||
if type is None:
|
|
||||||
type = self.effect_type
|
|
||||||
self.effect_type = type
|
|
||||||
self.priority = priority
|
|
||||||
self.handle = bass_call(pybass.BASS_ChannelSetFX, channel, type, priority)
|
|
||||||
|
|
||||||
def get_parameters(self):
|
|
||||||
"""Retrieves the parameters of an effect."""
|
|
||||||
res = {}
|
|
||||||
params = self.struct()
|
|
||||||
bass_call(pybass.BASS_FXGetParameters, self.handle, ctypes.pointer(params))
|
|
||||||
for f in params._fields_:
|
|
||||||
res[f[0]] = getattr(params, f[0])
|
|
||||||
return res
|
|
||||||
|
|
||||||
def set_parameters(self, parameters):
|
|
||||||
params = self.struct()
|
|
||||||
for p, v in parameters.items():
|
|
||||||
setattr(params, p, v)
|
|
||||||
bass_call(pybass.BASS_FXSetParameters, self.handle, ctypes.pointer(params))
|
|
||||||
|
|
||||||
def __dir__(self):
|
|
||||||
res = dir(self.__class__)
|
|
||||||
return res + self._get_pythonic_effect_fields()
|
|
||||||
|
|
||||||
def _get_effect_fields(self):
|
|
||||||
return [i[0] for i in self.struct._fields_]
|
|
||||||
|
|
||||||
def _get_pythonic_effect_fields(self):
|
|
||||||
return [self._bass_to_python(i) for i in self._get_effect_fields() if not i.startswith('_') ]
|
|
||||||
|
|
||||||
def _bass_to_python(self, func):
|
|
||||||
for c in string.ascii_lowercase:
|
|
||||||
func = func.replace(c.upper(), '_%s' % c)
|
|
||||||
if func.startswith('_'):
|
|
||||||
func = func[1:]
|
|
||||||
return func[2:]
|
|
||||||
|
|
||||||
def _python_to_bass(self, func):
|
|
||||||
for c in string.ascii_lowercase:
|
|
||||||
func = func.replace('_%s' % c, c.upper())
|
|
||||||
func = '%s%s' % (func[0].upper(), func[1:])
|
|
||||||
for f in self._get_effect_fields():
|
|
||||||
if f.endswith(func):
|
|
||||||
func = f
|
|
||||||
return func
|
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
|
||||||
return self.get_parameters()[self._python_to_bass(attr)]
|
|
||||||
|
|
||||||
def __setattr__(self, attr, val):
|
|
||||||
if attr not in self._get_pythonic_effect_fields():
|
|
||||||
return super(SoundEffect, self).__setattr__(attr, val)
|
|
||||||
params = self.get_parameters()
|
|
||||||
key = self._python_to_bass(attr)
|
|
||||||
if key not in params:
|
|
||||||
raise AttributeError('Unable to set attribute, suspect issue with base name-munging code')
|
|
||||||
params[key] = val
|
|
||||||
self.set_parameters(params)
|
|
@@ -1,65 +0,0 @@
|
|||||||
import ctypes
|
|
||||||
from sound_lib.external import pybass, pybass_fx
|
|
||||||
from sound_lib.stream import BaseStream
|
|
||||||
from sound_lib.channel import Channel
|
|
||||||
from sound_lib.main import bass_call, bass_call_0
|
|
||||||
|
|
||||||
class Tempo(BaseStream):
|
|
||||||
|
|
||||||
def __init__(self, channel, flags=0, loop=False, software=False, three_d=False, sample_fx=False, autofree=False, decode=False, free_source=False):
|
|
||||||
flags = flags | self.flags_for(loop=False, software=False, three_d=False, sample_fx=False, autofree=False, decode=False, free_source=False)
|
|
||||||
self.channel = channel
|
|
||||||
if isinstance(channel, Channel):
|
|
||||||
channel = channel.handle
|
|
||||||
handle = bass_call(pybass_fx.BASS_FX_TempoCreate, channel, flags)
|
|
||||||
super(Tempo, self).__init__(handle)
|
|
||||||
self.add_attributes_to_mapping(
|
|
||||||
tempo=pybass_fx.BASS_ATTRIB_TEMPO,
|
|
||||||
tempo_pitch=pybass_fx.BASS_ATTRIB_TEMPO_PITCH,
|
|
||||||
tempo_freq=pybass_fx.BASS_ATTRIB_TEMPO_FREQ,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@property
|
|
||||||
def tempo(self):
|
|
||||||
"""The tempo of a channel."""
|
|
||||||
return self.get_attribute(pybass_fx.BASS_ATTRIB_TEMPO)
|
|
||||||
|
|
||||||
@tempo.setter
|
|
||||||
def tempo(self, val):
|
|
||||||
self.set_attribute('tempo', val)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def tempo_pitch(self):
|
|
||||||
return self.get_attribute('tempo_pitch')
|
|
||||||
|
|
||||||
@tempo_pitch.setter
|
|
||||||
def tempo_pitch(self, val):
|
|
||||||
self.set_attribute('tempo_pitch', val)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def tempo_freq(self):
|
|
||||||
return self.get_attribute('tempo_freq')
|
|
||||||
|
|
||||||
@tempo_freq.setter
|
|
||||||
def tempo_freq(self, val):
|
|
||||||
self.set_attribute('tempo_freq', val)
|
|
||||||
|
|
||||||
def setup_flag_mapping(self):
|
|
||||||
super(Tempo, self).setup_flag_mapping()
|
|
||||||
self.flag_mapping.update({
|
|
||||||
'free_source': pybass_fx.BASS_FX_FREESOURCE,
|
|
||||||
})
|
|
||||||
|
|
||||||
def get_source(self):
|
|
||||||
source = pybass_fx.BASS_FX_TempoGetSource(self.handle)
|
|
||||||
if source == self.channel.handle:
|
|
||||||
source = self.channel
|
|
||||||
return source
|
|
||||||
|
|
||||||
source = property(fget=get_source)
|
|
||||||
|
|
||||||
def get_rate_ratio(self):
|
|
||||||
return bass_call(pybass_fx.BASS_FX_TempoGetRateRatio, self.handle)
|
|
||||||
|
|
||||||
rate_ratio = property(fget=get_rate_ratio)
|
|
@@ -1,81 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
from .external import pybass, pybassenc
|
|
||||||
from .main import bass_call, bass_call_0, FlagObject
|
|
||||||
|
|
||||||
class Encoder(FlagObject):
|
|
||||||
|
|
||||||
def setup_flag_mapping(self):
|
|
||||||
#super(Encoder, self).setup_flag_mapping()
|
|
||||||
self.flag_mapping = {
|
|
||||||
'pcm': pybassenc.BASS_ENCODE_PCM,
|
|
||||||
'no_header': pybassenc.BASS_ENCODE_NOHEAD,
|
|
||||||
'rf64': pybassenc.BASS_ENCODE_RF64,
|
|
||||||
'big_endian': pybassenc.BASS_ENCODE_BIGEND,
|
|
||||||
'fp_8bit': pybassenc.BASS_ENCODE_FP_8BIT,
|
|
||||||
'fp_16bit': pybassenc.BASS_ENCODE_FP_16BIT,
|
|
||||||
'fp_24bit': pybassenc.BASS_ENCODE_FP_24BIT,
|
|
||||||
'fp_32bit': pybassenc.BASS_ENCODE_FP_32BIT,
|
|
||||||
'queue': pybassenc.BASS_ENCODE_QUEUE,
|
|
||||||
'limit': pybassenc.BASS_ENCODE_LIMIT,
|
|
||||||
'no_limit': pybassenc.BASS_ENCODE_CAST_NOLIMIT,
|
|
||||||
'pause': pybassenc.BASS_ENCODE_PAUSE,
|
|
||||||
'autofree': pybassenc.BASS_ENCODE_AUTOFREE,
|
|
||||||
'unicode': pybass.BASS_UNICODE,
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, source, command_line, pcm=False, no_header=False, rf64=False, big_endian=False, fp_8bit=False, fp_16bit=False, fp_24bit=False, fp_32bit=False, queue=False, limit=False, no_limit=False, pause=True, autofree=False, callback=None, user=None):
|
|
||||||
self.setup_flag_mapping()
|
|
||||||
flags = self.flags_for(pcm=pcm, no_header=no_header, rf64=rf64, big_endian=big_endian, fp_8bit=fp_8bit, fp_16bit=fp_16bit, fp_24bit=fp_24bit, fp_32bit=fp_32bit, queue=queue, limit=limit, no_limit=no_limit, pause=pause, autofree=autofree) #fwiw!
|
|
||||||
self.source = source
|
|
||||||
source_handle = source.handle
|
|
||||||
if callback is None:
|
|
||||||
callback = lambda *a: None
|
|
||||||
callback = pybassenc.ENCODEPROC(callback)
|
|
||||||
self.callback = callback
|
|
||||||
self.handle = bass_call(pybassenc.BASS_Encode_Start, source_handle, command_line, flags, callback, user)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def paused(self):
|
|
||||||
return bass_call_0(pybassenc.BASS_Encode_IsActive, self.handle) == pybass.BASS_ACTIVE_PAUSED
|
|
||||||
|
|
||||||
@paused.setter
|
|
||||||
def paused(self, paused):
|
|
||||||
return bass_call(pybassenc.BASS_Encode_SetPaused, self.handle, paused)
|
|
||||||
|
|
||||||
def is_stopped(self):
|
|
||||||
return bass_call_0(pybassenc.BASS_Encode_IsActive, self.handle) == pybass.BASS_ACTIVE_STOPPED
|
|
||||||
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
return bass_call(pybassenc.BASS_Encode_Stop, self.handle)
|
|
||||||
|
|
||||||
class BroadcastEncoder(Encoder):
|
|
||||||
|
|
||||||
def __init__(self, source_encoder, server, password, content, name=None, url=None, genre=None, description=None, headers=None, bitrate=0, public=False):
|
|
||||||
contents = {
|
|
||||||
'mp3': pybassenc.BASS_ENCODE_TYPE_MP3,
|
|
||||||
'ogg': pybassenc.BASS_ENCODE_TYPE_OGG,
|
|
||||||
'aac': pybassenc.BASS_ENCODE_TYPE_AAC
|
|
||||||
}
|
|
||||||
if content in contents:
|
|
||||||
content = contents[content]
|
|
||||||
self.source_encoder = source_encoder
|
|
||||||
handle = source_encoder.handle
|
|
||||||
self.server = server
|
|
||||||
self.password = password
|
|
||||||
self.status = bass_call(pybassenc.BASS_Encode_CastInit, handle, server, password, content, name, url, genre, description, headers, bitrate, public)
|
|
||||||
|
|
||||||
def set_title(self, title=None, url=None):
|
|
||||||
return bass_call(pybassenc.BASS_Encode_CastSetTitle, self.source_encoder.handle, title, url)
|
|
||||||
|
|
||||||
def get_stats(self, type, password=None):
|
|
||||||
types = {
|
|
||||||
'shoutcast': pybassenc.BASS_ENCODE_STATS_SHOUT,
|
|
||||||
'icecast': pybassenc.BASS_ENCODE_STATS_ICE,
|
|
||||||
'icecast_server': pybassenc.BASS_ENCODE_STATS_ICESERV,
|
|
||||||
}
|
|
||||||
if type in types:
|
|
||||||
type = types[type]
|
|
||||||
if password is None:
|
|
||||||
password = self.password
|
|
||||||
return bass_call(pybassenc.BASS_Encode_CastGetStats, self.handle, type, password)
|
|
9
src/sound_lib/external/__init__.py
vendored
9
src/sound_lib/external/__init__.py
vendored
@@ -1,9 +0,0 @@
|
|||||||
import platform
|
|
||||||
#if platform.system() == 'Windows':
|
|
||||||
# import sound_lib.external.pybasswma
|
|
||||||
if platform.system() != 'Darwin':
|
|
||||||
import sound_lib.external.pybass_aac
|
|
||||||
import sound_lib.external.pybass_alac
|
|
||||||
import sound_lib.external.pybassopus
|
|
||||||
import sound_lib.external.pybassflac
|
|
||||||
import sound_lib.external.pybassmidi
|
|
9
src/sound_lib/external/paths.py
vendored
9
src/sound_lib/external/paths.py
vendored
@@ -1,9 +0,0 @@
|
|||||||
import os
|
|
||||||
from platform_utils.paths import module_path, is_frozen, embedded_data_path
|
|
||||||
|
|
||||||
if is_frozen():
|
|
||||||
x86_path = os.path.join(embedded_data_path(), 'sound_lib', 'lib', 'x86')
|
|
||||||
x64_path = os.path.join(embedded_data_path(), 'sound_lib', 'lib', 'x64')
|
|
||||||
else:
|
|
||||||
x86_path = os.path.join(module_path(), '..', 'lib', 'x86')
|
|
||||||
x64_path = os.path.join(module_path(), '..', 'lib', 'x64')
|
|
1120
src/sound_lib/external/pybass.py
vendored
1120
src/sound_lib/external/pybass.py
vendored
File diff suppressed because it is too large
Load Diff
54
src/sound_lib/external/pybass_aac.py
vendored
54
src/sound_lib/external/pybass_aac.py
vendored
@@ -1,54 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
# Copyright(c) Max Kolosov 2009 maxkolosov@inbox.ru
|
|
||||||
# http://vosolok2008.narod.ru
|
|
||||||
# BSD license
|
|
||||||
|
|
||||||
__version__ = '0.1'
|
|
||||||
__versionTime__ = '2009-11-15'
|
|
||||||
__author__ = 'Max Kolosov <maxkolosov@inbox.ru>'
|
|
||||||
__doc__ = '''
|
|
||||||
pybass_aac.py - is ctypes python module for
|
|
||||||
BASS_AAC - extension to the BASS audio library that enables the playback
|
|
||||||
of Advanced Audio Coding and MPEG-4 streams (http://www.maresweb.de).
|
|
||||||
'''
|
|
||||||
|
|
||||||
import os, sys, ctypes
|
|
||||||
from . import pybass
|
|
||||||
from .paths import x86_path, x64_path
|
|
||||||
import libloader
|
|
||||||
|
|
||||||
bass_aac_module = libloader.load_library('bass_aac', x86_path=x86_path, x64_path=x64_path)
|
|
||||||
func_type = libloader.get_functype()
|
|
||||||
#Register the plugin with the Bass plugin system.
|
|
||||||
pybass.BASS_PluginLoad(libloader.find_library_path('bass_aac', x86_path=x86_path, x64_path=x64_path), 0)
|
|
||||||
|
|
||||||
QWORD = pybass.QWORD
|
|
||||||
HSTREAM = pybass.HSTREAM
|
|
||||||
DOWNLOADPROC = pybass.DOWNLOADPROC
|
|
||||||
BASS_FILEPROCS = pybass.BASS_FILEPROCS
|
|
||||||
|
|
||||||
|
|
||||||
# Additional BASS_SetConfig options
|
|
||||||
BASS_CONFIG_MP4_VIDEO = 0x10700 # play the audio from MP4 videos
|
|
||||||
|
|
||||||
# Additional tags available from BASS_StreamGetTags (for MP4 files)
|
|
||||||
BASS_TAG_MP4 = 7 # MP4/iTunes metadata
|
|
||||||
|
|
||||||
BASS_AAC_STEREO = 0x400000 # downmatrix to stereo
|
|
||||||
|
|
||||||
# BASS_CHANNELINFO type
|
|
||||||
BASS_CTYPE_STREAM_AAC = 0x10b00 # AAC
|
|
||||||
BASS_CTYPE_STREAM_MP4 = 0x10b01 # MP4
|
|
||||||
|
|
||||||
|
|
||||||
#HSTREAM BASSAACDEF(BASS_AAC_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags);
|
|
||||||
BASS_AAC_StreamCreateFile = func_type(HSTREAM, ctypes.c_byte, ctypes.c_void_p, QWORD, QWORD, ctypes.c_ulong)(('BASS_AAC_StreamCreateFile', bass_aac_module))
|
|
||||||
#HSTREAM BASSAACDEF(BASS_AAC_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user);
|
|
||||||
BASS_AAC_StreamCreateURL = func_type(HSTREAM, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_ulong, DOWNLOADPROC, ctypes.c_void_p)(('BASS_AAC_StreamCreateURL', bass_aac_module))
|
|
||||||
#HSTREAM BASSAACDEF(BASS_AAC_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *procs, void *user);
|
|
||||||
BASS_AAC_StreamCreateFileUser = func_type(HSTREAM, ctypes.c_ulong, ctypes.c_ulong, ctypes.POINTER(BASS_FILEPROCS), ctypes.c_void_p)(('BASS_AAC_StreamCreateFileUser', bass_aac_module))
|
|
||||||
#HSTREAM BASSAACDEF(BASS_MP4_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags);
|
|
||||||
BASS_MP4_StreamCreateFile = func_type(HSTREAM, ctypes.c_byte, ctypes.c_void_p, QWORD, QWORD, ctypes.c_ulong)(('BASS_MP4_StreamCreateFile', bass_aac_module))
|
|
||||||
#HSTREAM BASSAACDEF(BASS_MP4_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *procs, void *user);
|
|
||||||
BASS_MP4_StreamCreateFileUser = func_type(HSTREAM, ctypes.c_ulong, ctypes.c_ulong, ctypes.POINTER(BASS_FILEPROCS), ctypes.c_void_p)(('BASS_MP4_StreamCreateFileUser', bass_aac_module))
|
|
||||||
|
|
24
src/sound_lib/external/pybass_alac.py
vendored
24
src/sound_lib/external/pybass_alac.py
vendored
@@ -1,24 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
"BASS_ALAC wrapper by Christopher Toth"""
|
|
||||||
|
|
||||||
import ctypes
|
|
||||||
import os
|
|
||||||
from . import pybass
|
|
||||||
from .paths import x86_path, x64_path
|
|
||||||
import libloader
|
|
||||||
|
|
||||||
bass_fx_module = libloader.load_library('bass_alac', x86_path=x86_path, x64_path=x64_path)
|
|
||||||
func_type = libloader.get_functype()
|
|
||||||
|
|
||||||
pybass.BASS_PluginLoad(libloader.find_library_path('bass_alac', x86_path=x86_path, x64_path=x64_path), 0)
|
|
||||||
|
|
||||||
BASS_TAG_MP4 = 7
|
|
||||||
BASS_CTYPE_STREAM_ALAC = 0x10e00
|
|
||||||
|
|
||||||
|
|
||||||
#HSTREAM BASSALACDEF(BASS_ALAC_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags);
|
|
||||||
BASS_ALAC_StreamCreateFile = func_type(pybass.HSTREAM, ctypes.c_byte, ctypes.c_void_p, pybass.QWORD, pybass.QWORD, ctypes.c_ulong)
|
|
||||||
|
|
||||||
#HSTREAM BASSALACDEF(BASS_ALAC_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *procs, void *user);
|
|
||||||
BASS_ALAC_StreamCreateFileUser = func_type(pybass.HSTREAM, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_void_p)
|
|
||||||
|
|
384
src/sound_lib/external/pybass_fx.py
vendored
384
src/sound_lib/external/pybass_fx.py
vendored
@@ -1,384 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
from future.builtins import range
|
|
||||||
"BASS_FX wrapper by Christopher Toth"""
|
|
||||||
|
|
||||||
import ctypes
|
|
||||||
import os
|
|
||||||
from . import pybass
|
|
||||||
from .paths import x86_path, x64_path
|
|
||||||
import libloader
|
|
||||||
|
|
||||||
bass_fx_module = libloader.load_library('bass_fx', x86_path=x86_path, x64_path=x64_path)
|
|
||||||
func_type = libloader.get_functype()
|
|
||||||
|
|
||||||
|
|
||||||
#Error codes returned by BASS_ErrorGetCode
|
|
||||||
BASS_ERROR_FX_NODECODE = 4000
|
|
||||||
BASS_ERROR_FX_BPMINUSE = 4001
|
|
||||||
|
|
||||||
#Tempo / Reverse / BPM / Beat flag
|
|
||||||
BASS_FX_FREESOURCE = 0x10000
|
|
||||||
|
|
||||||
#BASS_FX Version
|
|
||||||
BASS_FX_GetVersion = func_type(ctypes.c_ulong)(('BASS_FX_GetVersion', bass_fx_module))
|
|
||||||
|
|
||||||
|
|
||||||
"""D S P (Digital Signal Processing)"""
|
|
||||||
|
|
||||||
"""
|
|
||||||
Multi-channel order of each channel is as follows:
|
|
||||||
3 channels left-front, right-front, center.
|
|
||||||
4 channels left-front, right-front, left-rear/side, right-rear/side.
|
|
||||||
6 channels (5.1) left-front, right-front, center, LFE, left-rear/side, right-rear/side.
|
|
||||||
8 channels (7.1) left-front, right-front, center, LFE, left-rear/side, right-rear/side, left-rear center, right-rear center.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#DSP channels flags
|
|
||||||
BASS_BFX_CHANALL = -1 #all channels at once (as by default)
|
|
||||||
BASS_BFX_CHANNONE = 0 #disable an effect for all channels
|
|
||||||
BASS_BFX_CHAN1 = 1 #left-front channel
|
|
||||||
BASS_BFX_CHAN2 = 2 #right-front channel
|
|
||||||
BASS_BFX_CHAN3 = 4 #see above info
|
|
||||||
BASS_BFX_CHAN4 = 8 #see above info
|
|
||||||
BASS_BFX_CHAN5 = 16
|
|
||||||
BASS_BFX_CHAN6 = 32
|
|
||||||
BASS_BFX_CHAN7 = 64
|
|
||||||
BASS_BFX_CHAN8 = 128
|
|
||||||
|
|
||||||
#DSP effects
|
|
||||||
(
|
|
||||||
BASS_FX_BFX_ROTATE,
|
|
||||||
BASS_FX_BFX_ECHO,
|
|
||||||
BASS_FX_BFX_FLANGER,
|
|
||||||
BASS_FX_BFX_VOLUME,
|
|
||||||
BASS_FX_BFX_PEAKEQ,
|
|
||||||
BASS_FX_BFX_REVERB,
|
|
||||||
BASS_FX_BFX_LPF,
|
|
||||||
BASS_FX_BFX_MIX,
|
|
||||||
BASS_FX_BFX_DAMP,
|
|
||||||
BASS_FX_BFX_AUTOWAH,
|
|
||||||
BASS_FX_BFX_ECHO2,
|
|
||||||
BASS_FX_BFX_PHASER,
|
|
||||||
BASS_FX_BFX_ECHO3,
|
|
||||||
BASS_FX_BFX_CHORUS,
|
|
||||||
BASS_FX_BFX_APF,
|
|
||||||
BASS_FX_BFX_COMPRESSOR,
|
|
||||||
BASS_FX_BFX_DISTORTION,
|
|
||||||
BASS_FX_BFX_COMPRESSOR2,
|
|
||||||
BASS_FX_BFX_VOLUME_ENV,
|
|
||||||
BASS_FX_BFX_BQF,
|
|
||||||
) = range(0x10000, 0x10000+20)
|
|
||||||
|
|
||||||
#BiQuad filters
|
|
||||||
(
|
|
||||||
BASS_BFX_BQF_LOWPASS,
|
|
||||||
BASS_BFX_BQF_HIGHPASS,
|
|
||||||
BASS_BFX_BQF_BANDPASS, #constant 0 dB peak gain
|
|
||||||
BASS_BFX_BQF_BANDPASS_Q, #constant skirt gain, peak gain = Q
|
|
||||||
BASS_BFX_BQF_NOTCH,
|
|
||||||
BASS_BFX_BQF_ALLPASS,
|
|
||||||
BASS_BFX_BQF_PEAKINGEQ,
|
|
||||||
BASS_BFX_BQF_LOWSHELF,
|
|
||||||
BASS_BFX_BQF_HIGHSHELF,
|
|
||||||
) = range(9)
|
|
||||||
|
|
||||||
#Echo
|
|
||||||
class BASS_BFX_ECHO(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fLevel', ctypes.c_float), #[0....1....n] linear
|
|
||||||
('lDelay', ctypes.c_int), #[1200..30000]
|
|
||||||
]
|
|
||||||
|
|
||||||
#Flanger
|
|
||||||
class BASS_BFX_FLANGER(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fWetDry', ctypes.c_float), #[0....1....n] linear
|
|
||||||
('fSpeed', ctypes.c_float), #[0......0.09]
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#volume
|
|
||||||
class BASS_BFX_VOLUME(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s or 0 for global volume control
|
|
||||||
('fVolume', ctypes.c_float), #[0....1....n] linear
|
|
||||||
]
|
|
||||||
|
|
||||||
#Peaking Equalizer
|
|
||||||
class BASS_BFX_PEAKEQ(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('lBand', ctypes.c_int), #[0...............n] more bands means more memory & cpu usage
|
|
||||||
('fBandwidth', ctypes.c_float), #[0.1...........<10] in octaves - fQ is not in use (Bandwidth has a priority over fQ)
|
|
||||||
('fQ', ctypes.c_float), #[0...............1] the EE kinda definition (linear) (if Bandwidth is not in use)
|
|
||||||
('fCenter', ctypes.c_float), #[1Hz..<info.freq/2] in Hz
|
|
||||||
('fGain', ctypes.c_float), #[-15dB...0...+15dB] in dB
|
|
||||||
('lChannel', ctypes.c_float), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#Reverb
|
|
||||||
class BASS_BFX_REVERB(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fLevel', ctypes.c_float), #[0....1....n] linear
|
|
||||||
('lDelay', ctypes.c_int), #[1200..10000]
|
|
||||||
]
|
|
||||||
|
|
||||||
#Low Pass Filter
|
|
||||||
class BASS_BFX_LPF(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fResonance', ctypes.c_float), #[0.01...........10]
|
|
||||||
('fCutOffFreq', ctypes.c_float), #[1Hz...info.freq/2] cutoff frequency
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#Swap, remap and mix
|
|
||||||
class BASS_BFX_MIX(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('lChannel', ctypes.c_int), #an array of channels to mix using BASS_BFX_CHANxxx flag/s (lChannel[0] is left channel...)
|
|
||||||
]
|
|
||||||
|
|
||||||
#Dynamic Amplification
|
|
||||||
class BASS_BFX_DAMP(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fTarget', ctypes.c_float), #target volume level [0<......1] linear
|
|
||||||
('fQuiet', ctypes.c_float), #quiet volume level [0.......1] linear
|
|
||||||
('fRate', ctypes.c_float), #amp adjustment rate [0.......1] linear
|
|
||||||
('fGain', ctypes.c_float), #amplification level [0...1...n] linear
|
|
||||||
('fDelay', ctypes.c_float), #delay in seconds before increasing level [0.......n] linear
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#Auto WAH
|
|
||||||
class BASS_BFX_AUTOWAH(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fDryMix', ctypes.c_float), #dry (unaffected) signal mix [-2......2]
|
|
||||||
('fWetMix', ctypes.c_float), #wet (affected) signal mix [-2......2]
|
|
||||||
('fFeedback', ctypes.c_float), #feedback [-1......1]
|
|
||||||
('fRate', ctypes.c_float), #rate of sweep in cycles per second [0<....<10]
|
|
||||||
('fRange', ctypes.c_float), #sweep range in octaves [0<....<10]
|
|
||||||
('fFreq', ctypes.c_float), #base frequency of sweep Hz [0<...1000]
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#Echo 2
|
|
||||||
class BASS_BFX_ECHO2(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fDryMix', ctypes.c_float), #dry (unaffected) signal mix [-2......2]
|
|
||||||
('fWetMix', ctypes.c_float), #wet (affected) signal mix [-2......2]
|
|
||||||
('fFeedback', ctypes.c_float), #feedback [-1......1]
|
|
||||||
('fDelay', ctypes.c_float), #delay sec [0<......n]
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#Phaser
|
|
||||||
class BASS_BFX_PHASER(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fDryMix', ctypes.c_float), #dry (unaffected) signal mix [-2......2]
|
|
||||||
('fWetMix', ctypes.c_float), #wet (affected) signal mix [-2......2]
|
|
||||||
('fFeedback', ctypes.c_float), #feedback [-1......1]
|
|
||||||
('fRate', ctypes.c_float), #rate of sweep in cycles per second [0<....<10]
|
|
||||||
('fRange', ctypes.c_float), #sweep range in octaves [0<....<10]
|
|
||||||
('fFreq', ctypes.c_float), #base frequency of sweep [0<...1000]
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#Echo 3
|
|
||||||
class BASS_BFX_ECHO3(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fDryMix', ctypes.c_float), #dry (unaffected) signal mix [-2......2]
|
|
||||||
('fWetMix', ctypes.c_float), #wet (affected) signal mix [-2......2]
|
|
||||||
('fDelay', ctypes.c_float), #delay sec [0<......n]
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#Chorus
|
|
||||||
class BASS_BFX_CHORUS(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fDryMix', ctypes.c_float), #dry (unaffected) signal mix [-2......2]
|
|
||||||
('fWetMix', ctypes.c_float), #wet (affected) signal mix [-2......2]
|
|
||||||
('fFeedback', ctypes.c_float), #feedback [-1......1]
|
|
||||||
('fMinSweep', ctypes.c_float), #minimal delay ms [0<...6000]
|
|
||||||
('fMaxSweep', ctypes.c_float), #maximum delay ms [0<...6000]
|
|
||||||
('fRate', ctypes.c_float), #rate ms/s [0<...1000]
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#All Pass Filter
|
|
||||||
class BASS_BFX_APF(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fGain', ctypes.c_float), #reverberation time [-1=<..<=1]
|
|
||||||
('fDelay', ctypes.c_float), #delay sec [0<....<=n]
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#Compressor
|
|
||||||
class BASS_BFX_COMPRESSOR(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fThreshold', ctypes.c_float), #compressor threshold [0<=...<=1]
|
|
||||||
('fAttacktime', ctypes.c_float), #attack time ms [0<.<=1000]
|
|
||||||
('fReleasetime', ctypes.c_float), #release time ms [0<.<=5000]
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#Distortion
|
|
||||||
class BASS_BFX_DISTORTION(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fDrive', ctypes.c_float), #distortion drive [0<=...<=5]
|
|
||||||
('fDryMix', ctypes.c_float), #dry (unaffected) signal mix [-5<=..<=5]
|
|
||||||
('fWetMix', ctypes.c_float), #wet (affected) signal mix [-5<=..<=5]
|
|
||||||
('fFeedback', ctypes.c_float), #feedback [-1<=..<=1]
|
|
||||||
('fVolume', ctypes.c_float), #distortion volume [0=<...<=2]
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
#Compressor 2
|
|
||||||
class BASS_BFX_COMPRESSOR2(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('fGain', ctypes.c_float), #output gain of signal after compression [-60....60] in dB
|
|
||||||
('fThreshold', ctypes.c_float), #point at which compression begins [-60.....0] in dB
|
|
||||||
('fRatio', ctypes.c_float), #compression ratio [1.......n]
|
|
||||||
('fAttack', ctypes.c_float), #attack time in ms [0.01.1000]
|
|
||||||
('fRelease', ctypes.c_float), #release time in ms [0.01.5000]
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
class BASS_BFX_ENV_NODE(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('pos', ctypes.c_long), #node position in seconds (1st envelope node must be at position 0)
|
|
||||||
('val', ctypes.c_float), #node value
|
|
||||||
]
|
|
||||||
|
|
||||||
#Volume envelope
|
|
||||||
class BASS_BFX_VOLUME_ENV(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
('lNodeCount', ctypes.c_int), #number of nodes
|
|
||||||
('pNodes', BASS_BFX_ENV_NODE), #the nodes
|
|
||||||
('bFollow', ctypes.c_bool), #follow source position
|
|
||||||
]
|
|
||||||
|
|
||||||
#BiQuad Filters
|
|
||||||
|
|
||||||
class BASS_BFX_BQF(ctypes.Structure):
|
|
||||||
_fields_ = [
|
|
||||||
('lFilter', ctypes.c_int), #BASS_BFX_BQF_xxx filter types
|
|
||||||
('fCenter', ctypes.c_float), #[1Hz..<info.freq/2] Cutoff (central) frequency in Hz
|
|
||||||
('fGain', ctypes.c_float), #[-15dB...0...+15dB] Used only for PEAKINGEQ and Shelving filters in dB
|
|
||||||
('fBandwidth', ctypes.c_float), #[0.1...........<10] Bandwidth in octaves (fQ is not in use (fBandwidth has a priority over fQ))
|
|
||||||
#(between -3 dB frequencies for BANDPASS and NOTCH or between midpoint
|
|
||||||
#(fGgain/2) gain frequencies for PEAKINGEQ)
|
|
||||||
('fQ', ctypes.c_float), #[0.1.............1] The EE kinda definition (linear) (if fBandwidth is not in use)
|
|
||||||
('fS', ctypes.c_float), #[0.1.............1] A "shelf slope" parameter (linear) (used only with Shelving filters)
|
|
||||||
#when fS = 1, the shelf slope is as steep as you can get it and remain monotonically
|
|
||||||
#increasing or decreasing gain with frequency.
|
|
||||||
('lChannel', ctypes.c_int), #BASS_BFX_CHANxxx flag/s
|
|
||||||
]
|
|
||||||
|
|
||||||
"""TEMPO / PITCH SCALING / SAMPLERATE"""
|
|
||||||
|
|
||||||
"""NOTES: 1. Supported only - mono / stereo - channels
|
|
||||||
2. Enable Tempo supported flags in BASS_FX_TempoCreate and the others to source handle.
|
|
||||||
tempo attributes (BASS_ChannelSet/GetAttribute)"""
|
|
||||||
|
|
||||||
(
|
|
||||||
BASS_ATTRIB_TEMPO,
|
|
||||||
BASS_ATTRIB_TEMPO_PITCH,
|
|
||||||
BASS_ATTRIB_TEMPO_FREQ,
|
|
||||||
) = range(0x10000, 0x10000+3)
|
|
||||||
|
|
||||||
#tempo attributes options
|
|
||||||
#[option] [value]
|
|
||||||
|
|
||||||
(
|
|
||||||
BASS_ATTRIB_TEMPO_OPTION_USE_AA_FILTER, #TRUE (default) / FALSE
|
|
||||||
BASS_ATTRIB_TEMPO_OPTION_AA_FILTER_LENGTH, #32 default (8 .. 128 taps)
|
|
||||||
BASS_ATTRIB_TEMPO_OPTION_USE_QUICKALGO, #TRUE / FALSE (default)
|
|
||||||
BASS_ATTRIB_TEMPO_OPTION_SEQUENCE_MS, #82 default, 0 = automatic
|
|
||||||
BASS_ATTRIB_TEMPO_OPTION_SEEKWINDOW_MS, #28 default, 0 = automatic
|
|
||||||
BASS_ATTRIB_TEMPO_OPTION_OVERLAP_MS, #8 default
|
|
||||||
BASS_ATTRIB_TEMPO_OPTION_PREVENT_CLICK, #TRUE / FALSE (default)
|
|
||||||
) = range(0x10000, 0x10000+7)
|
|
||||||
|
|
||||||
#HSTREAM BASS_FXDEF(BASS_FX_TempoCreate)(DWORD chan, DWORD flags);
|
|
||||||
BASS_FX_TempoCreate = func_type(pybass.HSTREAM, ctypes.c_ulong, ctypes.c_ulong)(('BASS_FX_TempoCreate', bass_fx_module))
|
|
||||||
|
|
||||||
#DWORD BASS_FXDEF(BASS_FX_TempoGetSource)(HSTREAM chan);
|
|
||||||
BASS_FX_TempoGetSource = func_type(ctypes.c_ulong, pybass.HSTREAM)(('BASS_FX_TempoGetSource', bass_fx_module))
|
|
||||||
|
|
||||||
#float BASS_FXDEF(BASS_FX_TempoGetRateRatio)(HSTREAM chan);
|
|
||||||
BASS_FX_TempoGetRateRatio = func_type(ctypes.c_float, pybass.HSTREAM)(('BASS_FX_TempoGetRateRatio', bass_fx_module))
|
|
||||||
|
|
||||||
"""R E V E R S E"""
|
|
||||||
"""NOTES: 1. MODs won't load without BASS_MUSIC_PRESCAN flag.
|
|
||||||
2. Enable Reverse supported flags in BASS_FX_ReverseCreate and the others to source handle."""
|
|
||||||
|
|
||||||
#reverse attribute (BASS_ChannelSet/GetAttribute)
|
|
||||||
BASS_ATTRIB_REVERSE_DIR = 0x11000
|
|
||||||
|
|
||||||
#playback directions
|
|
||||||
BASS_FX_RVS_REVERSE = -1
|
|
||||||
BASS_FX_RVS_FORWARD = 1
|
|
||||||
|
|
||||||
#HSTREAM BASS_FXDEF(BASS_FX_ReverseCreate)(DWORD chan, float dec_block, DWORD flags);
|
|
||||||
BASS_FX_ReverseCreate = func_type(pybass.HSTREAM, ctypes.c_ulong, ctypes.c_float, ctypes.c_ulong)(('BASS_FX_ReverseCreate', bass_fx_module))
|
|
||||||
|
|
||||||
#DWORD BASS_FXDEF(BASS_FX_ReverseGetSource)(HSTREAM chan);
|
|
||||||
BASS_FX_ReverseGetSource = func_type(ctypes.c_ulong, pybass.HSTREAM)(('BASS_FX_ReverseGetSource', bass_fx_module))
|
|
||||||
|
|
||||||
"""B P M (Beats Per Minute)"""
|
|
||||||
|
|
||||||
#bpm flags
|
|
||||||
BASS_FX_BPM_BKGRND = 1 #if in use, then you can do other processing while detection's in progress. Not available in MacOSX yet. (BPM/Beat)
|
|
||||||
BASS_FX_BPM_MULT2 = 2 #if in use, then will auto multiply bpm by 2 (if BPM < minBPM*2)
|
|
||||||
|
|
||||||
#translation options
|
|
||||||
(
|
|
||||||
BASS_FX_BPM_TRAN_X2, #multiply the original BPM value by 2 (may be called only once & will change the original BPM as well!)
|
|
||||||
BASS_FX_BPM_TRAN_2FREQ, #BPM value to Frequency
|
|
||||||
BASS_FX_BPM_TRAN_FREQ2, #Frequency to BPM value
|
|
||||||
BASS_FX_BPM_TRAN_2PERCENT, #BPM value to Percents
|
|
||||||
BASS_FX_BPM_TRAN_PERCENT2 , #Percents to BPM value
|
|
||||||
) = range(5)
|
|
||||||
|
|
||||||
#typedef void (CALLBACK BPMPROCESSPROC)(DWORD chan, float percent);
|
|
||||||
BPMPROCESSPROC = func_type(None, ctypes.c_float)
|
|
||||||
|
|
||||||
#typedef void (CALLBACK BPMPROC)(DWORD chan, float bpm, void *user);
|
|
||||||
BPMPROC = func_type(None, ctypes.c_long, ctypes.c_float, ctypes.c_void_p)
|
|
||||||
|
|
||||||
#float BASS_FXDEF(BASS_FX_BPM_DecodeGet)(DWORD chan, double startSec, double endSec, DWORD minMaxBPM, DWORD flags, BPMPROCESSPROC *proc);
|
|
||||||
BASS_FX_BPM_DecodeGet = func_type(ctypes.c_float, ctypes.c_ulong, ctypes.c_double, ctypes.c_double, ctypes.c_ulong, ctypes.c_ulong, BPMPROCESSPROC)(('BASS_FX_BPM_DecodeGet', bass_fx_module))
|
|
||||||
|
|
||||||
#BOOL BASS_FXDEF(BASS_FX_BPM_CallbackSet)(DWORD handle, BPMPROC *proc, double period, DWORD minMaxBPM, DWORD flags, void *user);
|
|
||||||
BASS_FX_BPM_CallbackSet = func_type(ctypes.c_bool, ctypes.c_ulong, BPMPROC, ctypes.c_double, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_void_p)(('BASS_FX_BPM_CallbackSet', bass_fx_module))
|
|
||||||
|
|
||||||
#BOOL BASS_FXDEF(BASS_FX_BPM_CallbackReset)(DWORD handle);
|
|
||||||
BASS_FX_BPM_CallbackReset = func_type(ctypes.c_bool, ctypes.c_ulong)(('BASS_FX_BPM_CallbackReset', bass_fx_module))
|
|
||||||
|
|
||||||
#float BASS_FXDEF(BASS_FX_BPM_Translate)(DWORD handle, float val2tran, DWORD trans);
|
|
||||||
BASS_FX_BPM_Translate = func_type(ctypes.c_float, ctypes.c_ulong, ctypes.c_float, ctypes.c_ulong)(('BASS_FX_BPM_Translate', bass_fx_module))
|
|
||||||
|
|
||||||
#BOOL BASS_FXDEF(BASS_FX_BPM_Free)(DWORD handle);
|
|
||||||
BASS_FX_BPM_Free = func_type(ctypes.c_bool, ctypes.c_ulong)(('BASS_FX_BPM_Free', bass_fx_module))
|
|
||||||
|
|
||||||
""" Beat """
|
|
||||||
|
|
||||||
#typedef void (CALLBACK BPMBEATPROC)(DWORD chan, double beatpos, void *user);
|
|
||||||
BPMBEATPROC = func_type(None, ctypes.c_ulong, ctypes.c_double, ctypes.c_void_p)
|
|
||||||
|
|
||||||
#BOOL BASS_FXDEF(BASS_FX_BPM_BeatCallbackSet)(DWORD handle, BPMBEATPROC *proc, void *user);
|
|
||||||
BASS_FX_BPM_BeatCallbackSet = func_type(ctypes.c_bool, ctypes.c_ulong, ctypes.c_void_p)(('BASS_FX_BPM_BeatCallbackSet', bass_fx_module))
|
|
||||||
|
|
||||||
#BOOL BASS_FXDEF(BASS_FX_BPM_BeatCallbackReset)(DWORD handle);
|
|
||||||
BASS_FX_BPM_BeatCallbackReset = func_type(ctypes.c_bool, ctypes.c_ulong)(('BASS_FX_BPM_BeatCallbackReset', bass_fx_module))
|
|
||||||
|
|
||||||
#BOOL BASS_FXDEF(BASS_FX_BPM_BeatDecodeGet)(DWORD chan, double startSec, double endSec, DWORD flags, BPMBEATPROC *proc, void *user);
|
|
||||||
BASS_FX_BPM_BeatDecodeGet = func_type(ctypes.c_bool, ctypes.c_ulong, ctypes.c_double, ctypes.c_double, ctypes.c_ulong, BPMBEATPROC, ctypes.c_void_p)(('BASS_FX_BPM_BeatDecodeGet', bass_fx_module))
|
|
||||||
|
|
||||||
#BOOL BASS_FXDEF(BASS_FX_BPM_BeatSetParameters)(DWORD handle, float bandwidth, float centerfreq, float beat_rtime);
|
|
||||||
BASS_FX_BPM_BeatSetParameters = func_type(ctypes.c_bool, ctypes.c_ulong, ctypes.c_float, ctypes.c_float, ctypes.c_float)(('BASS_FX_BPM_BeatSetParameters', bass_fx_module))
|
|
||||||
|
|
||||||
#BOOL BASS_FXDEF(BASS_FX_BPM_BeatGetParameters)(DWORD handle, float *bandwidth, float *centerfreq, float *beat_rtime);
|
|
||||||
BASS_FX_BPM_BeatGetParameters = func_type(ctypes.c_bool, ctypes.c_ulong, ctypes.c_float, ctypes.c_float, ctypes.c_float)(('BASS_FX_BPM_BeatGetParameters', bass_fx_module))
|
|
||||||
|
|
||||||
#BOOL BASS_FXDEF(BASS_FX_BPM_BeatFree)(DWORD handle);
|
|
||||||
BASS_FX_BPM_BeatFree = func_type(ctypes.c_bool, ctypes.c_ulong)(('BASS_FX_BPM_BeatFree', bass_fx_module))
|
|
170
src/sound_lib/external/pybassenc.py
vendored
170
src/sound_lib/external/pybassenc.py
vendored
@@ -1,170 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
from future.builtins import range
|
|
||||||
"BASSENC wrapper by Christopher Toth"""
|
|
||||||
|
|
||||||
import ctypes
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
from . import pybass
|
|
||||||
from .paths import x86_path, x64_path
|
|
||||||
import libloader
|
|
||||||
|
|
||||||
bassenc_module = libloader.load_library('bassenc', x86_path=x86_path, x64_path=x64_path)
|
|
||||||
func_type = libloader.get_functype()
|
|
||||||
|
|
||||||
HENCODE = ctypes.c_ulong #encoder handle
|
|
||||||
|
|
||||||
#Additional error codes returned by BASS_ErrorGetCode
|
|
||||||
BASS_ERROR_ACM_CANCEL = 2000 #ACM codec selection cancelled
|
|
||||||
pybass.error_descriptions[BASS_ERROR_ACM_CANCEL] = "ACM codec selection cancelled"
|
|
||||||
BASS_ERROR_CAST_DENIED = 2100 #access denied (invalid password)
|
|
||||||
pybass.error_descriptions[BASS_ERROR_CAST_DENIED] = "access denied (invalid password)"
|
|
||||||
|
|
||||||
#Additional BASS_SetConfig options
|
|
||||||
BASS_CONFIG_ENCODE_PRIORITY = 0x10300
|
|
||||||
BASS_CONFIG_ENCODE_QUEUE = 0x10301
|
|
||||||
BASS_CONFIG_ENCODE_CAST_TIMEOUT = 0x10310
|
|
||||||
|
|
||||||
#Additional BASS_SetConfigPtr options
|
|
||||||
BASS_CONFIG_ENCODE_CAST_PROXY = 0x10311
|
|
||||||
|
|
||||||
#BASS_Encode_Start flags
|
|
||||||
BASS_ENCODE_NOHEAD = 1 #don't send a WAV header to the encoder
|
|
||||||
BASS_ENCODE_FP_8BIT = 2 #convert floating-point sample data to 8-bit integer
|
|
||||||
BASS_ENCODE_FP_16BIT = 4 #convert floating-point sample data to 16-bit integer
|
|
||||||
BASS_ENCODE_FP_24BIT = 6#convert floating-point sample data to 24-bit integer
|
|
||||||
BASS_ENCODE_FP_32BIT = 8 #convert floating-point sample data to 32-bit integer
|
|
||||||
BASS_ENCODE_BIGEND = 16 #big-endian sample data
|
|
||||||
BASS_ENCODE_PAUSE = 32 #start encoding paused
|
|
||||||
BASS_ENCODE_PCM = 64 #write PCM sample data (no encoder)
|
|
||||||
BASS_ENCODE_RF64 = 128 #send an RF64 header
|
|
||||||
BASS_ENCODE_MONO = 256 #convert to mono (if not already)
|
|
||||||
BASS_ENCODE_QUEUE = 512 #queue data to feed encoder asynchronously
|
|
||||||
BASS_ENCODE_CAST_NOLIMIT = 0x1000 #don't limit casting data rate
|
|
||||||
BASS_ENCODE_LIMIT = 0x2000 #limit data rate to real-time
|
|
||||||
BASS_ENCODE_AUTOFREE = 0x40000 #free the encoder when the channel is freed
|
|
||||||
|
|
||||||
#BASS_Encode_GetACMFormat flags
|
|
||||||
BASS_ACM_DEFAULT = 1 #use the format as default selection
|
|
||||||
BASS_ACM_RATE = 2 #only list formats with same sample rate as the source channel
|
|
||||||
BASS_ACM_CHANS = 4 #only list formats with same number of channels (eg. mono/stereo)
|
|
||||||
BASS_ACM_SUGGEST = 8 #suggest a format (HIWORD=format tag)
|
|
||||||
|
|
||||||
#BASS_Encode_GetCount counts
|
|
||||||
|
|
||||||
(
|
|
||||||
BASS_ENCODE_COUNT_IN, #sent to encoder
|
|
||||||
BASS_ENCODE_COUNT_OUT, #received from encoder
|
|
||||||
BASS_ENCODE_COUNT_CAST, #sent to cast server
|
|
||||||
BASS_ENCODE_COUNT_QUEUE, #queued
|
|
||||||
BASS_ENCODE_COUNT_QUEUE_LIMIT, #queue limit
|
|
||||||
BASS_ENCODE_COUNT_QUEUE_FAIL, #failed to queue
|
|
||||||
) = range(6)
|
|
||||||
|
|
||||||
#BASS_Encode_CastInit content MIME types
|
|
||||||
|
|
||||||
BASS_ENCODE_TYPE_MP3 = "audio/mpeg"
|
|
||||||
BASS_ENCODE_TYPE_OGG = "application/ogg"
|
|
||||||
BASS_ENCODE_TYPE_AAC = "audio/aacp"
|
|
||||||
|
|
||||||
#BASS_Encode_CastGetStats types
|
|
||||||
|
|
||||||
BASS_ENCODE_STATS_SHOUT = 0 #Shoutcast stats
|
|
||||||
BASS_ENCODE_STATS_ICE = 1 #Icecast mount-point stats
|
|
||||||
BASS_ENCODE_STATS_ICESERV = 2 #Icecast server stats
|
|
||||||
|
|
||||||
#typedef void (CALLBACK ENCODEPROC)(HENCODE handle, DWORD channel, const void *buffer, DWORD length, void *user);
|
|
||||||
ENCODEPROC = func_type(None, HENCODE, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_ulong, ctypes.c_void_p)
|
|
||||||
|
|
||||||
#typedef void (CALLBACK ENCODEPROCEX)(HENCODE handle, DWORD channel, const void *buffer, DWORD length, QWORD offset, void *user);
|
|
||||||
ENCODEPROCEX = func_type(None, HENCODE, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_ulong, pybass.QWORD, ctypes.c_void_p)
|
|
||||||
|
|
||||||
#typedef BOOL (CALLBACK ENCODECLIENTPROC)(HENCODE handle, BOOL connect, const char *client, char *headers, void *user);
|
|
||||||
ENCODECLIENTPROC = func_type(ctypes.c_byte, HENCODE, ctypes.c_byte, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_void_p)
|
|
||||||
|
|
||||||
#typedef void (CALLBACK ENCODENOTIFYPROC)(HENCODE handle, DWORD status, void *user);
|
|
||||||
ENCODENOTIFYPROC = func_type(None, HENCODE, ctypes.c_ulong, ctypes.c_void_p)
|
|
||||||
|
|
||||||
#Encoder notifications
|
|
||||||
BASS_ENCODE_NOTIFY_ENCODER = 1 #encoder died
|
|
||||||
BASS_ENCODE_NOTIFY_CAST = 2 #cast server connection died
|
|
||||||
BASS_ENCODE_NOTIFY_CAST_TIMEOUT = 0x10000 #cast timeout
|
|
||||||
BASS_ENCODE_NOTIFY_QUEUE_FULL = 0x10001 #queue is out of space
|
|
||||||
|
|
||||||
#BASS_Encode_ServerInit flags
|
|
||||||
BASS_ENCODE_SERVER_NOHTTP = 1 #no HTTP headers
|
|
||||||
|
|
||||||
#DWORD BASSENCDEF(BASS_Encode_GetVersion)();
|
|
||||||
BASS_Encode_GetVersion = func_type(ctypes.c_ulong)(('BASS_Encode_GetVersion', bassenc_module))
|
|
||||||
|
|
||||||
#HENCODE BASSENCDEF(BASS_Encode_Start)(DWORD handle, const char *cmdline, DWORD flags, ENCODEPROC *proc, void *user);
|
|
||||||
BASS_Encode_Start = func_type(HENCODE, ctypes.c_ulong, ctypes.c_char_p, ctypes.c_ulong, ENCODEPROC, ctypes.c_void_p)(('BASS_Encode_Start', bassenc_module))
|
|
||||||
|
|
||||||
#HENCODE BASSENCDEF(BASS_Encode_StartLimit)(DWORD handle, const char *cmdline, DWORD flags, ENCODEPROC *proc, void *user, DWORD limit);
|
|
||||||
BASS_Encode_StartLimit = func_type(HENCODE, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_ulong, ENCODEPROC, ctypes.c_void_p, ctypes.c_ulong)(('BASS_Encode_StartLimit', bassenc_module))
|
|
||||||
|
|
||||||
#BOOL BASSENCDEF(BASS_Encode_AddChunk)(HENCODE handle, const char *id, const void *buffer, DWORD length);
|
|
||||||
BASS_Encode_AddChunk = func_type(ctypes.c_byte, HENCODE, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_ulong)(('BASS_Encode_AddChunk', bassenc_module))
|
|
||||||
|
|
||||||
#DWORD BASSENCDEF(BASS_Encode_IsActive)(DWORD handle);
|
|
||||||
BASS_Encode_IsActive = func_type(ctypes.c_ulong, ctypes.c_ulong)(('BASS_Encode_IsActive', bassenc_module))
|
|
||||||
|
|
||||||
#BOOL BASSENCDEF(BASS_Encode_Stop)(DWORD handle);
|
|
||||||
BASS_Encode_Stop = func_type(ctypes.c_byte, ctypes.c_ulong)(('BASS_Encode_Stop', bassenc_module))
|
|
||||||
|
|
||||||
#BOOL BASSENCDEF(BASS_Encode_StopEx)(DWORD handle, BOOL queue);
|
|
||||||
BASS_Encode_StopEx = func_type(ctypes.c_byte, ctypes.c_ulong, ctypes.c_byte)
|
|
||||||
|
|
||||||
#BOOL BASSENCDEF(BASS_Encode_SetPaused)(DWORD handle, BOOL paused);
|
|
||||||
BASS_Encode_SetPaused = func_type(ctypes.c_byte, ctypes.c_ulong, ctypes.c_byte)(('BASS_Encode_SetPaused', bassenc_module))
|
|
||||||
|
|
||||||
#BOOL BASSENCDEF(BASS_Encode_Write)(DWORD handle, const void *buffer, DWORD length);
|
|
||||||
BASS_Encode_Write = func_type(ctypes.c_byte, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_ulong)(('BASS_Encode_Write', bassenc_module))
|
|
||||||
|
|
||||||
#BOOL BASSENCDEF(BASS_Encode_SetNotify)(DWORD handle, ENCODENOTIFYPROC *proc, void *user);
|
|
||||||
BASS_Encode_SetNotify = func_type(ctypes.c_byte, ctypes.c_ulong, ENCODENOTIFYPROC, ctypes.c_void_p)(('BASS_Encode_SetNotify', bassenc_module))
|
|
||||||
|
|
||||||
#QWORD BASSENCDEF(BASS_Encode_GetCount)(DWORD handle, DWORD count);
|
|
||||||
BASS_Encode_GetCount = func_type(pybass.QWORD, ctypes.c_ulong, ctypes.c_ulong)(('BASS_Encode_GetCount', bassenc_module))
|
|
||||||
|
|
||||||
#BOOL BASSENCDEF(BASS_Encode_SetChannel)(DWORD handle, DWORD channel);
|
|
||||||
BASS_Encode_SetChannel = func_type(ctypes.c_byte, ctypes.c_ulong, ctypes.c_ulong)
|
|
||||||
|
|
||||||
#DWORD BASSENCDEF(BASS_Encode_GetChannel)(HENCODE handle);
|
|
||||||
BASS_Encode_GetChannel = func_type(ctypes.c_ulong, HENCODE)(('BASS_Encode_GetChannel', bassenc_module))
|
|
||||||
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
#DWORD BASSENCDEF(BASS_Encode_GetACMFormat)(DWORD handle, void *form, DWORD formlen, const char *title, DWORD flags);
|
|
||||||
BASS_Encode_GetACMFormat = func_type(ctypes.c_ulong, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_ulong, ctypes.c_char_p, ctypes.c_ulong)(('BASS_Encode_GetACMFormat', bassenc_module))
|
|
||||||
|
|
||||||
#HENCODE BASSENCDEF(BASS_Encode_StartACM)(DWORD handle, const void *form, DWORD flags, ENCODEPROC *proc, void *user);
|
|
||||||
BASS_Encode_StartACM = func_type(HENCODE, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_ulong, ENCODEPROC, ctypes.c_void_p)(('BASS_Encode_StartACM', bassenc_module))
|
|
||||||
|
|
||||||
#HENCODE BASSENCDEF(BASS_Encode_StartACMFile)(DWORD handle, const void *form, DWORD flags, const char *file);
|
|
||||||
BASS_Encode_StartACMFile = func_type(HENCODE, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_ulong, ctypes.c_char_p)(('BASS_Encode_StartACMFile', bassenc_module))
|
|
||||||
|
|
||||||
|
|
||||||
if platform.system() == 'Darwin':
|
|
||||||
#HENCODE BASSENCDEF(BASS_Encode_StartCA)(DWORD handle, DWORD ftype, DWORD atype, DWORD flags, DWORD bitrate, ENCODEPROCEX *proc, void *user);
|
|
||||||
BASS_Encode_StartCA = func_type(HENCODE, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ENCODEPROCEX, ctypes.c_void_p)(('ENCODEPROCEX ', bassenc_module))
|
|
||||||
#HENCODE BASSENCDEF(BASS_Encode_StartCAFile)(DWORD handle, DWORD ftype, DWORD atype, DWORD flags, DWORD bitrate, const char *file);
|
|
||||||
BASS_Encode_StartCAFile = func_type(HENCODE, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_char_p)(('BASS_Encode_StartCAFile', bassenc_module))
|
|
||||||
#Broadcasting
|
|
||||||
|
|
||||||
#BOOL BASSENCDEF(BASS_Encode_CastInit)(HENCODE handle, const char *server, const char *pass, const char *content, const char *name, const char *url, const char *genre, const char *desc, const char *headers, DWORD bitrate, BOOL pub);
|
|
||||||
BASS_Encode_CastInit = func_type(ctypes.c_byte, HENCODE, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_byte)(('BASS_Encode_CastInit', bassenc_module))
|
|
||||||
|
|
||||||
#BOOL BASSENCDEF(BASS_Encode_CastSetTitle)(HENCODE handle, const char *title, const char *url);
|
|
||||||
BASS_Encode_CastSetTitle = func_type(ctypes.c_byte, HENCODE, ctypes.c_char_p, ctypes.c_char_p)(('BASS_Encode_CastSetTitle', bassenc_module))
|
|
||||||
|
|
||||||
#const char *BASSENCDEF(BASS_Encode_CastGetStats)(HENCODE handle, DWORD type, const char *pass);
|
|
||||||
BASS_Encode_CastGetStats = func_type(ctypes.c_char_p, HENCODE, ctypes.c_ulong, ctypes.c_char_p)(('BASS_Encode_CastGetStats', bassenc_module))
|
|
||||||
|
|
||||||
#Local audio server
|
|
||||||
|
|
||||||
#DWORD BASSENCDEF(BASS_Encode_ServerInit)(HENCODE handle, const char *port, DWORD buffer, DWORD burst, DWORD flags, ENCODECLIENTPROC *proc, void *user);
|
|
||||||
BASS_Encode_ServerInit = func_type(ctypes.c_ulong, HENCODE, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ENCODECLIENTPROC, ctypes.c_void_p)(('BASS_Encode_ServerInit', bassenc_module))
|
|
||||||
|
|
||||||
#BOOL BASSENCDEF(BASS_Encode_ServerKick)(HENCODE handle, const char *client);
|
|
||||||
BASS_Encode_ServerKick = func_type(ctypes.c_byte, HENCODE, ctypes.c_char_p)(('BASS_Encode_ServerKick', bassenc_module))
|
|
||||||
|
|
41
src/sound_lib/external/pybassflac.py
vendored
41
src/sound_lib/external/pybassflac.py
vendored
@@ -1,41 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
# Copyright(c) Max Kolosov 2009 maxkolosov@inbox.ru
|
|
||||||
# http://vosolok2008.narod.ru
|
|
||||||
# BSD license
|
|
||||||
|
|
||||||
__version__ = '0.1'
|
|
||||||
__versionTime__ = '2009-11-15'
|
|
||||||
__author__ = 'Max Kolosov <maxkolosov@inbox.ru>'
|
|
||||||
__doc__ = '''
|
|
||||||
pybassflac.py - is ctypes python module for
|
|
||||||
BASSFLAC - extension to the BASS audio library,
|
|
||||||
enabling the playing of FLAC (Free Lossless Audio Codec) encoded files.
|
|
||||||
'''
|
|
||||||
|
|
||||||
import os, sys, ctypes
|
|
||||||
from . import pybass
|
|
||||||
from .paths import x86_path, x64_path
|
|
||||||
import libloader
|
|
||||||
|
|
||||||
bassflac_module = libloader.load_library('bassflac', x86_path=x86_path, x64_path=x64_path)
|
|
||||||
func_type = libloader.get_functype()
|
|
||||||
#Register the plugin with the Bass plugin system.
|
|
||||||
pybass.BASS_PluginLoad(libloader.find_library_path('bassflac', x86_path=x86_path, x64_path=x64_path), 0)
|
|
||||||
|
|
||||||
QWORD = pybass.QWORD
|
|
||||||
HSTREAM = pybass.HSTREAM
|
|
||||||
DOWNLOADPROC = pybass.DOWNLOADPROC
|
|
||||||
BASS_FILEPROCS = pybass.BASS_FILEPROCS
|
|
||||||
|
|
||||||
# BASS_CHANNELINFO type
|
|
||||||
BASS_CTYPE_STREAM_FLAC = 0x10900
|
|
||||||
BASS_CTYPE_STREAM_FLAC_OGG = 0x10901
|
|
||||||
|
|
||||||
|
|
||||||
#HSTREAM BASSFLACDEF(BASS_FLAC_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags);
|
|
||||||
BASS_FLAC_StreamCreateFile = func_type(HSTREAM, ctypes.c_byte, ctypes.c_void_p, QWORD, QWORD, ctypes.c_ulong)(('BASS_FLAC_StreamCreateFile', bassflac_module))
|
|
||||||
#HSTREAM BASSFLACDEF(BASS_FLAC_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user);
|
|
||||||
BASS_FLAC_StreamCreateURL = func_type(HSTREAM, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_ulong, DOWNLOADPROC, ctypes.c_void_p)(('BASS_FLAC_StreamCreateURL', bassflac_module))
|
|
||||||
#HSTREAM BASSFLACDEF(BASS_FLAC_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *procs, void *user);
|
|
||||||
BASS_FLAC_StreamCreateFileUser = func_type(HSTREAM, ctypes.c_ulong, ctypes.c_ulong, ctypes.POINTER(BASS_FILEPROCS), ctypes.c_void_p)(('BASS_FLAC_StreamCreateFileUser', bassflac_module))
|
|
||||||
|
|
204
src/sound_lib/external/pybassmidi.py
vendored
204
src/sound_lib/external/pybassmidi.py
vendored
@@ -1,204 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
# Copyright(c) Max Kolosov 2009 maxkolosov@inbox.ru
|
|
||||||
# http://vosolok2008.narod.ru
|
|
||||||
# BSD license
|
|
||||||
|
|
||||||
__version__ = '0.1'
|
|
||||||
__versionTime__ = '2009-11-15'
|
|
||||||
__author__ = 'Max Kolosov <maxkolosov@inbox.ru>'
|
|
||||||
__doc__ = '''
|
|
||||||
pybassmidi.py - is ctypes python module for
|
|
||||||
BASSMIDI - extension to the BASS audio library,
|
|
||||||
enabling the playing of MIDI files and real-time events,
|
|
||||||
using SF2 soundfonts to provide the sounds.
|
|
||||||
'''
|
|
||||||
|
|
||||||
import sys, ctypes, platform, os
|
|
||||||
from . import pybass
|
|
||||||
from .paths import x86_path, x64_path
|
|
||||||
import libloader
|
|
||||||
|
|
||||||
bassmidi_module = libloader.load_library('bassmidi', x86_path=x86_path, x64_path=x64_path)
|
|
||||||
func_type = libloader.get_functype()
|
|
||||||
#Register the plugin with the Bass plugin system.
|
|
||||||
pybass.BASS_PluginLoad(libloader.find_library_path('bassmidi', x86_path=x86_path, x64_path=x64_path), 0)
|
|
||||||
|
|
||||||
HSOUNDFONT = ctypes.c_ulong
|
|
||||||
|
|
||||||
QWORD = pybass.QWORD
|
|
||||||
HSTREAM = pybass.HSTREAM
|
|
||||||
DOWNLOADPROC = pybass.DOWNLOADPROC
|
|
||||||
BASS_FILEPROCS = pybass.BASS_FILEPROCS
|
|
||||||
|
|
||||||
|
|
||||||
# Additional BASS_SetConfig options
|
|
||||||
BASS_CONFIG_MIDI_COMPACT = 0x10400
|
|
||||||
BASS_CONFIG_MIDI_VOICES = 0x10401
|
|
||||||
BASS_CONFIG_MIDI_AUTOFONT = 0x10402
|
|
||||||
|
|
||||||
# Additional BASS_SetConfigPtr options
|
|
||||||
BASS_CONFIG_MIDI_DEFFONT = 0x10403
|
|
||||||
|
|
||||||
# Additional sync types
|
|
||||||
BASS_SYNC_MIDI_MARKER = 0x10000
|
|
||||||
BASS_SYNC_MIDI_CUE = 0x10001
|
|
||||||
BASS_SYNC_MIDI_LYRIC = 0x10002
|
|
||||||
BASS_SYNC_MIDI_TEXT = 0x10003
|
|
||||||
BASS_SYNC_MIDI_EVENT = 0x10004
|
|
||||||
BASS_SYNC_MIDI_TICK = 0x10005
|
|
||||||
BASS_SYNC_MIDI_TIMESIG = 0x10006
|
|
||||||
|
|
||||||
# Additional BASS_MIDI_StreamCreateFile/etc flags
|
|
||||||
BASS_MIDI_DECAYEND = 0x1000
|
|
||||||
BASS_MIDI_NOFX = 0x2000
|
|
||||||
BASS_MIDI_DECAYSEEK = 0x4000
|
|
||||||
|
|
||||||
class BASS_MIDI_FONT(ctypes.Structure):
|
|
||||||
_fields_ = [('font', HSOUNDFONT),#HSOUNDFONT font; // soundfont
|
|
||||||
('preset', ctypes.c_int),#int preset; // preset number (-1=all)
|
|
||||||
('bank', ctypes.c_int)#int bank;
|
|
||||||
]
|
|
||||||
|
|
||||||
class BASS_MIDI_FONTINFO(ctypes.Structure):
|
|
||||||
_fields_ = [('name', ctypes.c_char_p),#const char *name;
|
|
||||||
('copyright', ctypes.c_char_p),#const char *copyright;
|
|
||||||
('comment', ctypes.c_char_p),#const char *comment;
|
|
||||||
('presets', ctypes.c_ulong),#DWORD presets; // number of presets/instruments
|
|
||||||
('samsize', ctypes.c_ulong),#DWORD samsize; // total size (in bytes) of the sample data
|
|
||||||
('samload', ctypes.c_ulong),#DWORD samload; // amount of sample data currently loaded
|
|
||||||
('samtype', ctypes.c_ulong)#DWORD samtype; // sample format (CTYPE) if packed
|
|
||||||
]
|
|
||||||
|
|
||||||
class BASS_MIDI_MARK(ctypes.Structure):
|
|
||||||
_fields_ = [('track', ctypes.c_ulong),#DWORD track; // track containing marker
|
|
||||||
('pos', ctypes.c_ulong),#DWORD pos; // marker position (bytes)
|
|
||||||
('text', ctypes.c_char_p)#const char *text; // marker text
|
|
||||||
]
|
|
||||||
|
|
||||||
# Marker types
|
|
||||||
BASS_MIDI_MARK_MARKER = 0 # marker events
|
|
||||||
BASS_MIDI_MARK_CUE = 1 # cue events
|
|
||||||
BASS_MIDI_MARK_LYRIC = 2 # lyric events
|
|
||||||
BASS_MIDI_MARK_TEXT = 3 # text events
|
|
||||||
BASS_MIDI_MARK_TIMESIG = 4 # time signature
|
|
||||||
|
|
||||||
# MIDI events
|
|
||||||
MIDI_EVENT_NOTE = 1
|
|
||||||
MIDI_EVENT_PROGRAM = 2
|
|
||||||
MIDI_EVENT_CHANPRES = 3
|
|
||||||
MIDI_EVENT_PITCH = 4
|
|
||||||
MIDI_EVENT_PITCHRANGE = 5
|
|
||||||
MIDI_EVENT_DRUMS = 6
|
|
||||||
MIDI_EVENT_FINETUNE = 7
|
|
||||||
MIDI_EVENT_COARSETUNE = 8
|
|
||||||
MIDI_EVENT_MASTERVOL = 9
|
|
||||||
MIDI_EVENT_BANK = 10
|
|
||||||
MIDI_EVENT_MODULATION = 11
|
|
||||||
MIDI_EVENT_VOLUME = 12
|
|
||||||
MIDI_EVENT_PAN = 13
|
|
||||||
MIDI_EVENT_EXPRESSION = 14
|
|
||||||
MIDI_EVENT_SUSTAIN = 15
|
|
||||||
MIDI_EVENT_SOUNDOFF = 16
|
|
||||||
MIDI_EVENT_RESET = 17
|
|
||||||
MIDI_EVENT_NOTESOFF = 18
|
|
||||||
MIDI_EVENT_PORTAMENTO = 19
|
|
||||||
MIDI_EVENT_PORTATIME = 20
|
|
||||||
MIDI_EVENT_PORTANOTE = 21
|
|
||||||
MIDI_EVENT_MODE = 22
|
|
||||||
MIDI_EVENT_REVERB = 23
|
|
||||||
MIDI_EVENT_CHORUS = 24
|
|
||||||
MIDI_EVENT_CUTOFF = 25
|
|
||||||
MIDI_EVENT_RESONANCE = 26
|
|
||||||
MIDI_EVENT_RELEASE = 27
|
|
||||||
MIDI_EVENT_ATTACK = 28
|
|
||||||
MIDI_EVENT_REVERB_MACRO = 30
|
|
||||||
MIDI_EVENT_CHORUS_MACRO = 31
|
|
||||||
MIDI_EVENT_REVERB_TIME = 32
|
|
||||||
MIDI_EVENT_REVERB_DELAY = 33
|
|
||||||
MIDI_EVENT_REVERB_LOCUTOFF = 34
|
|
||||||
MIDI_EVENT_REVERB_HICUTOFF = 35
|
|
||||||
MIDI_EVENT_REVERB_LEVEL = 36
|
|
||||||
MIDI_EVENT_CHORUS_DELAY = 37
|
|
||||||
MIDI_EVENT_CHORUS_DEPTH = 38
|
|
||||||
MIDI_EVENT_CHORUS_RATE = 39
|
|
||||||
MIDI_EVENT_CHORUS_FEEDBACK = 40
|
|
||||||
MIDI_EVENT_CHORUS_LEVEL = 41
|
|
||||||
MIDI_EVENT_CHORUS_REVERB = 42
|
|
||||||
MIDI_EVENT_DRUM_FINETUNE = 50
|
|
||||||
MIDI_EVENT_DRUM_COARSETUNE = 51
|
|
||||||
MIDI_EVENT_DRUM_PAN = 52
|
|
||||||
MIDI_EVENT_DRUM_REVERB = 53
|
|
||||||
MIDI_EVENT_DRUM_CHORUS = 54
|
|
||||||
MIDI_EVENT_DRUM_CUTOFF = 55
|
|
||||||
MIDI_EVENT_DRUM_RESONANCE = 56
|
|
||||||
MIDI_EVENT_DRUM_LEVEL = 57
|
|
||||||
MIDI_EVENT_TEMPO = 62
|
|
||||||
MIDI_EVENT_MIXLEVEL = 0x10000
|
|
||||||
MIDI_EVENT_TRANSPOSE = 0x10001
|
|
||||||
|
|
||||||
class BASS_MIDI_EVENT(ctypes.Structure):
|
|
||||||
_fields_ = [('event', ctypes.c_ulong),#DWORD event; // MIDI_EVENT_xxx
|
|
||||||
('param', ctypes.c_ulong),#DWORD param;
|
|
||||||
('chan', ctypes.c_ulong),#DWORD chan;
|
|
||||||
('tick', ctypes.c_ulong),#DWORD tick; // event position (ticks)
|
|
||||||
('pos', ctypes.c_ulong)#DWORD pos; // event position (bytes)
|
|
||||||
]
|
|
||||||
|
|
||||||
# BASS_CHANNELINFO type
|
|
||||||
BASS_CTYPE_STREAM_MIDI = 0x10d00
|
|
||||||
|
|
||||||
# Additional attributes
|
|
||||||
BASS_ATTRIB_MIDI_PPQN = 0x12000
|
|
||||||
BASS_ATTRIB_MIDI_TRACK_VOL = 0x12100 # + track #
|
|
||||||
|
|
||||||
# Additional tag type
|
|
||||||
BASS_TAG_MIDI_TRACK = 0x11000 # + track #, track text : array of null-terminated ANSI strings
|
|
||||||
|
|
||||||
# BASS_ChannelGetLength/GetPosition/SetPosition mode
|
|
||||||
BASS_POS_MIDI_TICK = 2 # tick position
|
|
||||||
|
|
||||||
#HSTREAM BASSMIDIDEF(BASS_MIDI_StreamCreate)(DWORD channels, DWORD flags, DWORD freq);
|
|
||||||
BASS_MIDI_StreamCreate = func_type(HSTREAM, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong)(('BASS_MIDI_StreamCreate', bassmidi_module))
|
|
||||||
#HSTREAM BASSMIDIDEF(BASS_MIDI_StreamCreateFile)(BOOL mem, const void *file, QWORD offset, QWORD length, DWORD flags, DWORD freq);
|
|
||||||
BASS_MIDI_StreamCreateFile = func_type(HSTREAM, ctypes.c_byte, ctypes.c_void_p, QWORD, QWORD, ctypes.c_ulong, ctypes.c_ulong)(('BASS_MIDI_StreamCreateFile', bassmidi_module))
|
|
||||||
#HSTREAM BASSMIDIDEF(BASS_MIDI_StreamCreateURL)(const char *url, DWORD offset, DWORD flags, DOWNLOADPROC *proc, void *user, DWORD freq);
|
|
||||||
BASS_MIDI_StreamCreateURL = func_type(HSTREAM, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_ulong, DOWNLOADPROC, ctypes.c_void_p, ctypes.c_ulong)(('BASS_MIDI_StreamCreateURL', bassmidi_module))
|
|
||||||
#HSTREAM BASSMIDIDEF(BASS_MIDI_StreamCreateFileUser)(DWORD system, DWORD flags, const BASS_FILEPROCS *procs, void *user, DWORD freq);
|
|
||||||
BASS_MIDI_StreamCreateFileUser = func_type(HSTREAM, ctypes.c_ulong, ctypes.c_ulong, ctypes.POINTER(BASS_FILEPROCS), ctypes.c_void_p, ctypes.c_ulong)(('BASS_MIDI_StreamCreateFileUser', bassmidi_module))
|
|
||||||
#BOOL BASSMIDIDEF(BASS_MIDI_StreamGetMark)(HSTREAM handle, DWORD type, DWORD index, BASS_MIDI_MARK *mark);
|
|
||||||
BASS_MIDI_StreamGetMark = func_type(ctypes.c_byte, HSTREAM, ctypes.c_ulong, ctypes.c_ulong, ctypes.POINTER(BASS_MIDI_MARK))(('BASS_MIDI_StreamGetMark', bassmidi_module))
|
|
||||||
#BOOL BASSMIDIDEF(BASS_MIDI_StreamSetFonts)(HSTREAM handle, const BASS_MIDI_FONT *fonts, DWORD count);
|
|
||||||
BASS_MIDI_StreamSetFonts = func_type(ctypes.c_byte, HSTREAM, ctypes.POINTER(BASS_MIDI_FONT), ctypes.c_ulong)(('BASS_MIDI_StreamSetFonts', bassmidi_module))
|
|
||||||
#DWORD BASSMIDIDEF(BASS_MIDI_StreamGetFonts)(HSTREAM handle, BASS_MIDI_FONT *fonts, DWORD count);
|
|
||||||
BASS_MIDI_StreamGetFonts = func_type(ctypes.c_ulong, HSTREAM, ctypes.POINTER(BASS_MIDI_FONT), ctypes.c_ulong)(('BASS_MIDI_StreamGetFonts', bassmidi_module))
|
|
||||||
#BOOL BASSMIDIDEF(BASS_MIDI_StreamLoadSamples)(HSTREAM handle);
|
|
||||||
BASS_MIDI_StreamLoadSamples = func_type(ctypes.c_byte, HSTREAM)(('BASS_MIDI_StreamLoadSamples', bassmidi_module))
|
|
||||||
#BOOL BASSMIDIDEF(BASS_MIDI_StreamEvent)(HSTREAM handle, DWORD chan, DWORD event, DWORD param);
|
|
||||||
BASS_MIDI_StreamEvent = func_type(ctypes.c_byte, HSTREAM, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong)(('BASS_MIDI_StreamEvent', bassmidi_module))
|
|
||||||
#DWORD BASSMIDIDEF(BASS_MIDI_StreamGetEvent)(HSTREAM handle, DWORD chan, DWORD event);
|
|
||||||
BASS_MIDI_StreamGetEvent = func_type(ctypes.c_ulong, HSTREAM, ctypes.c_ulong, ctypes.c_ulong)(('BASS_MIDI_StreamGetEvent', bassmidi_module))
|
|
||||||
#DWORD BASSMIDIDEF(BASS_MIDI_StreamGetEvents)(HSTREAM handle, DWORD track, DWORD filter, BASS_MIDI_EVENT *events);
|
|
||||||
BASS_MIDI_StreamGetEvents = func_type(ctypes.c_ulong, HSTREAM, ctypes.c_ulong, ctypes.c_ulong, ctypes.POINTER(BASS_MIDI_EVENT))(('BASS_MIDI_StreamGetEvents', bassmidi_module))
|
|
||||||
#HSTREAM BASSMIDIDEF(BASS_MIDI_StreamGetChannel)(HSTREAM handle, DWORD chan);
|
|
||||||
BASS_MIDI_StreamGetChannel = func_type(HSTREAM, HSTREAM, ctypes.c_ulong)(('BASS_MIDI_StreamGetChannel', bassmidi_module))
|
|
||||||
|
|
||||||
#HSOUNDFONT BASSMIDIDEF(BASS_MIDI_FontInit)(const void *file, DWORD flags);
|
|
||||||
BASS_MIDI_FontInit = func_type(HSOUNDFONT, ctypes.c_void_p, ctypes.c_ulong)(('BASS_MIDI_FontInit', bassmidi_module))
|
|
||||||
#BOOL BASSMIDIDEF(BASS_MIDI_FontFree)(HSOUNDFONT handle);
|
|
||||||
BASS_MIDI_FontFree = func_type(ctypes.c_byte, HSOUNDFONT)(('BASS_MIDI_FontFree', bassmidi_module))
|
|
||||||
#BOOL BASSMIDIDEF(BASS_MIDI_FontGetInfo)(HSOUNDFONT handle, BASS_MIDI_FONTINFO *info);
|
|
||||||
BASS_MIDI_FontGetInfo = func_type(ctypes.c_byte, HSOUNDFONT, ctypes.POINTER(BASS_MIDI_FONTINFO))(('BASS_MIDI_FontGetInfo', bassmidi_module))
|
|
||||||
#const char *BASSMIDIDEF(BASS_MIDI_FontGetPreset)(HSOUNDFONT handle, int preset, int bank);
|
|
||||||
BASS_MIDI_FontGetPreset = func_type(ctypes.c_char_p, HSOUNDFONT, ctypes.c_int, ctypes.c_int)(('BASS_MIDI_FontGetPreset', bassmidi_module))
|
|
||||||
#BOOL BASSMIDIDEF(BASS_MIDI_FontLoad)(HSOUNDFONT handle, int preset, int bank);
|
|
||||||
BASS_MIDI_FontLoad = func_type(ctypes.c_byte, HSOUNDFONT, ctypes.c_int, ctypes.c_int)(('BASS_MIDI_FontLoad', bassmidi_module))
|
|
||||||
#BOOL BASSMIDIDEF(BASS_MIDI_FontCompact)(HSOUNDFONT handle);
|
|
||||||
BASS_MIDI_FontCompact = func_type(ctypes.c_byte, HSOUNDFONT)(('BASS_MIDI_FontCompact', bassmidi_module))
|
|
||||||
#BOOL BASSMIDIDEF(BASS_MIDI_FontPack)(HSOUNDFONT handle, const void *outfile, const void *encoder, DWORD flags);
|
|
||||||
BASS_MIDI_FontPack = func_type(ctypes.c_byte, HSOUNDFONT, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_ulong)(('BASS_MIDI_FontPack', bassmidi_module))
|
|
||||||
#BOOL BASSMIDIDEF(BASS_MIDI_FontUnpack)(HSOUNDFONT handle, const void *outfile, DWORD flags);
|
|
||||||
BASS_MIDI_FontUnpack = func_type(ctypes.c_byte, HSOUNDFONT, ctypes.c_void_p, ctypes.c_ulong)(('BASS_MIDI_FontUnpack', bassmidi_module))
|
|
||||||
#BOOL BASSMIDIDEF(BASS_MIDI_FontSetVolume)(HSOUNDFONT handle, float volume);
|
|
||||||
BASS_MIDI_FontSetVolume = func_type(ctypes.c_byte, HSOUNDFONT, ctypes.c_float)(('BASS_MIDI_FontSetVolume', bassmidi_module))
|
|
||||||
#float BASSMIDIDEF(BASS_MIDI_FontGetVolume)(HSOUNDFONT handle);
|
|
||||||
BASS_MIDI_FontGetVolume = func_type(ctypes.c_float, HSOUNDFONT)(('BASS_MIDI_FontGetVolume', bassmidi_module))
|
|
117
src/sound_lib/external/pybassmix.py
vendored
117
src/sound_lib/external/pybassmix.py
vendored
@@ -1,117 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
# Copyright(c) Max Kolosov 2009 maxkolosov@inbox.ru
|
|
||||||
# http://vosolok2008.narod.ru
|
|
||||||
# BSD license
|
|
||||||
|
|
||||||
__version__ = '0.1'
|
|
||||||
__versionTime__ = '2009-11-15'
|
|
||||||
__author__ = 'Max Kolosov <maxkolosov@inbox.ru>'
|
|
||||||
__doc__ = '''
|
|
||||||
pybassmix.py - is ctypes python module for
|
|
||||||
BASSmix - extension to the BASS audio library, providing the ability
|
|
||||||
to mix together multiple BASS channels, with resampling and matrix mixing
|
|
||||||
features. It also provides the ability to go the other way and split a
|
|
||||||
BASS channel into multiple channels.
|
|
||||||
'''
|
|
||||||
|
|
||||||
import os, sys, ctypes, platform
|
|
||||||
from . import pybass
|
|
||||||
|
|
||||||
QWORD = pybass.QWORD
|
|
||||||
HSYNC = pybass.HSYNC
|
|
||||||
HSTREAM = pybass.HSTREAM
|
|
||||||
DOWNLOADPROC = pybass.DOWNLOADPROC
|
|
||||||
SYNCPROC = pybass.SYNCPROC
|
|
||||||
BASS_FILEPROCS = pybass.BASS_FILEPROCS
|
|
||||||
|
|
||||||
from .paths import x86_path, x64_path
|
|
||||||
import libloader
|
|
||||||
|
|
||||||
bassmix_module = libloader.load_library('bassmix', x86_path=x86_path, x64_path=x64_path)
|
|
||||||
func_type = libloader.get_functype()
|
|
||||||
|
|
||||||
# additional BASS_SetConfig option
|
|
||||||
BASS_CONFIG_MIXER_FILTER = 0x10600
|
|
||||||
BASS_CONFIG_MIXER_BUFFER = 0x10601
|
|
||||||
BASS_CONFIG_SPLIT_BUFFER = 0x10610
|
|
||||||
|
|
||||||
# BASS_Mixer_StreamCreate flags
|
|
||||||
BASS_MIXER_END = 0x10000# end the stream when there are no sources
|
|
||||||
BASS_MIXER_NONSTOP = 0x20000# don't stall when there are no sources
|
|
||||||
BASS_MIXER_RESUME = 0x1000# resume stalled immediately upon new/unpaused source
|
|
||||||
|
|
||||||
# source flags
|
|
||||||
BASS_MIXER_FILTER = 0x1000# resampling filter
|
|
||||||
BASS_MIXER_BUFFER = 0x2000# buffer data for BASS_Mixer_ChannelGetData/Level
|
|
||||||
BASS_MIXER_LIMIT = 0x4000# limit mixer processing to the amount available from this source
|
|
||||||
BASS_MIXER_MATRIX = 0x10000# matrix mixing
|
|
||||||
BASS_MIXER_PAUSE = 0x20000# don't process the source
|
|
||||||
BASS_MIXER_DOWNMIX = 0x400000# downmix to stereo/mono
|
|
||||||
BASS_MIXER_NORAMPIN = 0x800000# don't ramp-in the start
|
|
||||||
|
|
||||||
# envelope node
|
|
||||||
class BASS_MIXER_NODE(ctypes.Structure):
|
|
||||||
_fields_ = [('pos', ctypes.c_ulong),#QWORD pos;
|
|
||||||
('value', ctypes.c_float)#float value;
|
|
||||||
]
|
|
||||||
|
|
||||||
# envelope types
|
|
||||||
BASS_MIXER_ENV_FREQ = 1
|
|
||||||
BASS_MIXER_ENV_VOL = 2
|
|
||||||
BASS_MIXER_ENV_PAN = 3
|
|
||||||
BASS_MIXER_ENV_LOOP = 0x10000# FLAG: loop
|
|
||||||
|
|
||||||
# additional sync type
|
|
||||||
BASS_SYNC_MIXER_ENVELOPE = 0x10200
|
|
||||||
|
|
||||||
# BASS_CHANNELINFO type
|
|
||||||
BASS_CTYPE_STREAM_MIXER = 0x10800
|
|
||||||
BASS_CTYPE_STREAM_SPLIT = 0x10801
|
|
||||||
|
|
||||||
|
|
||||||
#DWORD BASSMIXDEF(BASS_Mixer_GetVersion)();
|
|
||||||
BASS_Mixer_GetVersion = func_type(ctypes.c_ulong)(('BASS_Mixer_GetVersion', bassmix_module))
|
|
||||||
|
|
||||||
#HSTREAM BASSMIXDEF(BASS_Mixer_StreamCreate)(DWORD freq, DWORD chans, DWORD flags);
|
|
||||||
BASS_Mixer_StreamCreate = func_type(HSTREAM, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong)(('BASS_Mixer_StreamCreate', bassmix_module))
|
|
||||||
#BOOL BASSMIXDEF(BASS_Mixer_StreamAddChannel)(HSTREAM handle, DWORD channel, DWORD flags);
|
|
||||||
BASS_Mixer_StreamAddChannel = func_type(ctypes.c_byte, HSTREAM, ctypes.c_ulong, ctypes.c_ulong)(('BASS_Mixer_StreamAddChannel', bassmix_module))
|
|
||||||
#BOOL BASSMIXDEF(BASS_Mixer_StreamAddChannelEx)(HSTREAM handle, DWORD channel, DWORD flags, QWORD start, QWORD length);
|
|
||||||
BASS_Mixer_StreamAddChannelEx = func_type(ctypes.c_byte, HSTREAM, ctypes.c_ulong, ctypes.c_ulong, QWORD, QWORD)(('BASS_Mixer_StreamAddChannelEx', bassmix_module))
|
|
||||||
|
|
||||||
#HSTREAM BASSMIXDEF(BASS_Mixer_ChannelGetMixer)(DWORD handle);
|
|
||||||
BASS_Mixer_ChannelGetMixer = func_type(HSTREAM, ctypes.c_ulong)(('BASS_Mixer_ChannelGetMixer', bassmix_module))
|
|
||||||
#DWORD BASSMIXDEF(BASS_Mixer_ChannelFlags)(DWORD handle, DWORD flags, DWORD mask);
|
|
||||||
BASS_Mixer_ChannelFlags = func_type(ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong)(('BASS_Mixer_ChannelFlags', bassmix_module))
|
|
||||||
#BOOL BASSMIXDEF(BASS_Mixer_ChannelRemove)(DWORD handle);
|
|
||||||
BASS_Mixer_ChannelRemove = func_type(ctypes.c_byte, ctypes.c_ulong)(('BASS_Mixer_ChannelRemove', bassmix_module))
|
|
||||||
#BOOL BASSMIXDEF(BASS_Mixer_ChannelSetPosition)(DWORD handle, QWORD pos, DWORD mode);
|
|
||||||
BASS_Mixer_ChannelSetPosition = func_type(ctypes.c_byte, ctypes.c_ulong, QWORD, ctypes.c_ulong)(('BASS_Mixer_ChannelSetPosition', bassmix_module))
|
|
||||||
#QWORD BASSMIXDEF(BASS_Mixer_ChannelGetPosition)(DWORD handle, DWORD mode);
|
|
||||||
BASS_Mixer_ChannelGetPosition = func_type(QWORD, ctypes.c_ulong, ctypes.c_ulong)(('BASS_Mixer_ChannelGetPosition', bassmix_module))
|
|
||||||
#DWORD BASSMIXDEF(BASS_Mixer_ChannelGetLevel)(DWORD handle);
|
|
||||||
BASS_Mixer_ChannelGetLevel = func_type(ctypes.c_ulong, ctypes.c_ulong)(('BASS_Mixer_ChannelGetLevel', bassmix_module))
|
|
||||||
#DWORD BASSMIXDEF(BASS_Mixer_ChannelGetData)(DWORD handle, void *buffer, DWORD length);
|
|
||||||
BASS_Mixer_ChannelGetData = func_type(ctypes.c_ulong, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_ulong)(('BASS_Mixer_ChannelGetData', bassmix_module))
|
|
||||||
#HSYNC BASSMIXDEF(BASS_Mixer_ChannelSetSync)(DWORD handle, DWORD type, QWORD param, SYNCPROC *proc, void *user);
|
|
||||||
BASS_Mixer_ChannelSetSync = func_type(HSYNC, ctypes.c_ulong, ctypes.c_ulong, QWORD, SYNCPROC, ctypes.c_void_p)(('BASS_Mixer_ChannelSetSync', bassmix_module))
|
|
||||||
#BOOL BASSMIXDEF(BASS_Mixer_ChannelRemoveSync)(DWORD channel, HSYNC sync);
|
|
||||||
BASS_Mixer_ChannelRemoveSync = func_type(ctypes.c_byte, ctypes.c_ulong, HSYNC)(('BASS_Mixer_ChannelRemoveSync', bassmix_module))
|
|
||||||
#BOOL BASSMIXDEF(BASS_Mixer_ChannelSetMatrix)(DWORD handle, const float *matrix);
|
|
||||||
BASS_Mixer_ChannelSetMatrix = func_type(ctypes.c_byte, ctypes.c_ulong, ctypes.POINTER(ctypes.c_float))(('BASS_Mixer_ChannelSetMatrix', bassmix_module))
|
|
||||||
#BOOL BASSMIXDEF(BASS_Mixer_ChannelGetMatrix)(DWORD handle, float *matrix);
|
|
||||||
BASS_Mixer_ChannelGetMatrix = func_type(ctypes.c_byte, ctypes.c_ulong, ctypes.POINTER(ctypes.c_float))(('BASS_Mixer_ChannelGetMatrix', bassmix_module))
|
|
||||||
#BOOL BASSMIXDEF(BASS_Mixer_ChannelSetEnvelope)(DWORD handle, DWORD type, const BASS_MIXER_NODE *nodes, DWORD count);
|
|
||||||
BASS_Mixer_ChannelSetEnvelope = func_type(ctypes.c_byte, ctypes.c_ulong, ctypes.c_ulong, ctypes.POINTER(BASS_MIXER_NODE), ctypes.c_ulong)(('BASS_Mixer_ChannelSetEnvelope', bassmix_module))
|
|
||||||
#BOOL BASSMIXDEF(BASS_Mixer_ChannelSetEnvelopePos)(DWORD handle, DWORD type, QWORD pos);
|
|
||||||
BASS_Mixer_ChannelSetEnvelopePos = func_type(ctypes.c_byte, ctypes.c_ulong, ctypes.c_ulong, QWORD)(('BASS_Mixer_ChannelSetEnvelopePos', bassmix_module))
|
|
||||||
#QWORD BASSMIXDEF(BASS_Mixer_ChannelGetEnvelopePos)(DWORD handle, DWORD type, float *value);
|
|
||||||
BASS_Mixer_ChannelGetEnvelopePos = func_type(QWORD, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_float)(('BASS_Mixer_ChannelGetEnvelopePos', bassmix_module))
|
|
||||||
|
|
||||||
#HSTREAM BASSMIXDEF(BASS_Split_StreamCreate)(DWORD channel, DWORD flags, int *chanmap);
|
|
||||||
BASS_Split_StreamCreate = func_type(HSTREAM, ctypes.c_ulong, ctypes.c_ulong, ctypes.c_int)(('BASS_Split_StreamCreate', bassmix_module))
|
|
||||||
#DWORD BASSMIXDEF(BASS_Split_StreamGetSource)(HSTREAM handle);
|
|
||||||
BASS_Split_StreamGetSource = func_type(ctypes.c_ulong, HSTREAM)(('BASS_Split_StreamGetSource', bassmix_module))
|
|
||||||
#BOOL BASSMIXDEF(BASS_Split_StreamReset)(DWORD handle);
|
|
||||||
BASS_Split_StreamReset = func_type(ctypes.c_byte, ctypes.c_ulong)(('BASS_Split_StreamReset', bassmix_module))
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user