Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorflavio <fdanesse@gmail.com>2012-12-14 11:49:36 (GMT)
committer flavio <fdanesse@gmail.com>2012-12-14 11:49:36 (GMT)
commit8013824cb97b266c88a5bddb52aa96e263038035 (patch)
treeac4eb2dedbca57902aa0adf9d19b0b3932612fa6
parent4d9f6a58b18105ee123edf98f76070858c7c5f8c (diff)
Corrections
-rw-r--r--aplay.py6
-rw-r--r--button.py19
-rw-r--r--collab.py78
-rw-r--r--glive.py110
-rw-r--r--gplay.py12
-rw-r--r--hw.py9
-rw-r--r--iconcombobox.py8
-rw-r--r--instance.py3
-rw-r--r--mediaview.py14
-rw-r--r--model.py17
-rw-r--r--record.py19
-rw-r--r--recorded.py32
-rw-r--r--recordtube.py59
-rw-r--r--serialize.py40
14 files changed, 317 insertions, 109 deletions
diff --git a/aplay.py b/aplay.py
index d418c5d..db3ebfe 100644
--- a/aplay.py
+++ b/aplay.py
@@ -11,6 +11,7 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst
@@ -23,18 +24,23 @@ import constants
logger = logging.getLogger('record:aplay.py')
def play(file, done_cb=None):
+
player.set_state(Gst.State.NULL)
def eos_cb(bus, message):
+
bus.disconnect_by_func(eos_cb)
player.set_state(Gst.State.NULL)
+
if done_cb is not None:
done_cb()
def error_cb(bus, message):
+
err, debug = message.parse_error()
logger.error('play_pipe: %s %s' % (err, debug))
player.set_state(Gst.State.NULL)
+
if done_cb is not None:
done_cb()
diff --git a/button.py b/button.py
index 6c9048e..74dc588 100644
--- a/button.py
+++ b/button.py
@@ -1,21 +1,27 @@
import gi
from gi.repository import GObject
from gi.repository import Gtk
+from gi.repository import GdkPixbuf
+
from gettext import gettext as _
from sugar3.graphics.palette import Palette
from sugar3.graphics.tray import TrayButton
+
import constants
import utils
class RecdButton(TrayButton):
+
__gsignals__ = {
'remove-requested': (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, ()),
'copy-clipboard-requested': (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, ()),
}
def __init__(self, recd):
+
super(RecdButton, self).__init__()
+
self._recd = recd
self.set_icon_widget(self.get_image())
@@ -32,6 +38,7 @@ class RecdButton(TrayButton):
self._add_copy_menu_item()
def _add_copy_menu_item( self ):
+
if self._recd.buddy and not self._recd.downloadedFromBuddy:
return
@@ -41,27 +48,37 @@ class RecdButton(TrayButton):
self._copy_menu_item.show()
def get_recd(self):
+
return self._recd
def get_image(self):
+
img = Gtk.Image()
ipb = self._recd.getThumbPixbuf()
+
if self._recd.type == constants.TYPE_PHOTO:
path = 'object-photo.svg'
+
elif self._recd.type == constants.TYPE_VIDEO:
path = 'object-video.svg'
+
elif self._recd.type == constants.TYPE_AUDIO:
path = 'object-audio.svg'
pixbuf = utils.load_colored_svg(path, self._recd.colorStroke, self._recd.colorFill)
+
if ipb:
- ipb.composite(pixbuf, 8, 8, ipb.get_width(), ipb.get_height(), 8, 8, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
+ ipb.composite(pixbuf, 8, 8, ipb.get_width(),
+ ipb.get_height(), 8, 8, 1, 1, GdkPixbuf.InterpType.BILINEAR, 255)
+
img.set_from_pixbuf(pixbuf)
img.show()
return img
def cleanup(self):
+
self._rem_menu_item.disconnect(self._rem_menu_item_handler)
+
if self._copy_menu_item_handler != None:
self._copy_menu_item.disconnect(self._copy_menu_item_handler)
diff --git a/collab.py b/collab.py
index d951f7c..78e8a17 100644
--- a/collab.py
+++ b/collab.py
@@ -19,30 +19,42 @@ from recorded import Recorded
logger = logging.getLogger('collab')
-class RecordCollab(object):
+class RecordCollab(GObject.GObject):
+
def __init__(self, activity_obj, model):
+
+ GObject.GObject.__init__(self)
+
self.activity = activity_obj
self.model = model
self._tube = None
self._collab_timeout = 10000
def set_activity_shared(self):
+
self._setup()
self._tubes_channel.OfferDBusTube(constants.DBUS_SERVICE, {})
def share_recd(self, recd):
+
if not self._tube:
return
+
xmlstr = serialize.getRecdXmlMeshString(recd)
self._tube.notifyBudsOfNewRecd(Instance.keyHashPrintable, xmlstr)
def joined(self):
+
if not self.activity.get_shared_activity():
return
+
self._setup()
- self._tubes_channel.ListTubes(reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb)
+ self._tubes_channel.ListTubes(
+ reply_handler = self._list_tubes_reply_cb,
+ error_handler = self._list_tubes_error_cb)
def request_download(self, recd):
+
if recd.meshDownloading:
logger.debug("meshInitRoundRobin: we are in midst of downloading this file...")
return
@@ -53,14 +65,17 @@ class RecordCollab(object):
self._req_recd_from_buddy(recd, recd.recorderHash, recd.recorderName)
def _list_tubes_reply_cb(self, tubes):
+
for tube_info in tubes:
self._new_tube_cb(*tube_info)
@staticmethod
def _list_tubes_error_cb(e):
+
logger.error('ListTubes() failed: %s', e)
def _setup(self):
+
# sets up the tubes...
if not self.activity.get_shared_activity():
logger.error('_setup: Failed to share or join activity')
@@ -70,6 +85,7 @@ class RecordCollab(object):
try:
name, path = pservice.get_preferred_connection()
self._connection = telepathy.client.Connection(name, path)
+
except:
logger.error('_setup: Failed to get_preferred_connection')
@@ -78,16 +94,21 @@ class RecordCollab(object):
room = None
tubes_chan = None
text_chan = None
+
for channel_path in channel_paths:
channel = telepathy.client.Channel(bus_name, channel_path)
htype, handle = channel.GetHandle()
+
if htype == telepathy.HANDLE_TYPE_ROOM:
- logger.debug('Found our room: it has handle#%d "%s"', handle, self._connection.InspectHandles(htype, [handle])[0])
+ logger.debug('Found our room: it has handle#%d "%s"',
+ handle, self._connection.InspectHandles(htype, [handle])[0])
room = handle
ctype = channel.GetChannelType()
+
if ctype == telepathy.CHANNEL_TYPE_TUBES:
logger.debug('Found our Tubes channel at %s', channel_path)
tubes_chan = channel
+
elif ctype == telepathy.CHANNEL_TYPE_TEXT:
logger.debug('Found our Text channel at %s', channel_path)
text_chan = channel
@@ -95,6 +116,7 @@ class RecordCollab(object):
if not room:
logger.error("Presence service didn't create a room")
return
+
if not text_chan:
logger.error("Presence service didn't create a text channel")
return
@@ -102,7 +124,9 @@ class RecordCollab(object):
# Make sure we have a Tubes channel - PS doesn't yet provide one
if not tubes_chan:
logger.debug("Didn't find our Tubes channel, requesting one...")
- tubes_chan = self._connection.request_channel(telepathy.CHANNEL_TYPE_TUBES, telepathy.HANDLE_TYPE_ROOM, room, True)
+ tubes_chan = self._connection.request_channel(
+ telepathy.CHANNEL_TYPE_TUBES,
+ telepathy.HANDLE_TYPE_ROOM, room, True)
self._tubes_channel = tubes_chan[telepathy.CHANNEL_TYPE_TUBES]
self._text_channel = text_chan[telepathy.CHANNEL_INTERFACE_GROUP]
@@ -110,13 +134,17 @@ class RecordCollab(object):
self._tubes_channel.connect_to_signal('NewTube', self._new_tube_cb)
def _new_tube_cb(self, id, initiator, type, service, params, state):
- logger.debug('New tube: ID=%d initator=%d type=%d service=%s params=%r state=%d', id, initiator, type, service, params, state)
+
+ logger.debug('New tube: ID=%d initator=%d type=%d service=%s params=%r state=%d',
+ id, initiator, type, service, params, state)
if type != telepathy.TUBE_TYPE_DBUS or service != constants.DBUS_SERVICE:
return
if state == telepathy.TUBE_STATE_LOCAL_PENDING:
self._tubes_channel.AcceptDBusTube(id)
- tube_connection = TubeConnection(self._connection, self._tubes_channel, id, group_iface=self._text_channel)
+
+ tube_connection = TubeConnection(self._connection,
+ self._tubes_channel, id, group_iface=self._text_channel)
self._tube = RecordTube(tube_connection)
self._tube.connect("new-recd", self._new_recd_cb)
self._tube.connect("recd-request", self._recd_request_cb)
@@ -124,17 +152,22 @@ class RecordCollab(object):
self._tube.connect("recd-unavailable", self._recd_unavailable_cb)
def _new_recd_cb(self, remote_object, recorder, xmlstr):
+
logger.debug('new_recd_cb')
dom = None
+
try:
dom = xml.dom.minidom.parseString(xmlstr)
+
except:
logger.error('Unable to parse mesh xml')
+
if not dom:
return
recd = Recorded()
recd = serialize.fillRecdFromNode(recd, dom.documentElement)
+
if not recd:
logger.debug('_newRecdCb: recd is None. Unable to parse XML')
return
@@ -145,6 +178,7 @@ class RecordCollab(object):
self.model.add_recd(recd)
def _req_recd_from_buddy(self, recd, sender, nick):
+
recd.triedMeshBuddies.append(sender)
recd.meshDownloadingFrom = sender
recd.meshDownloadingFromNick = nick
@@ -156,23 +190,29 @@ class RecordCollab(object):
self._tube.requestRecdBits(Instance.keyHashPrintable, sender, recd.mediaMd5)
def _next_round_robin_buddy(self, recd):
+
logger.debug('meshNextRoundRobinBuddy')
+
if recd.meshReqCallbackId:
GObject.source_remove(recd.meshReqCallbackId)
recd.meshReqCallbackId = 0
# delete any stub of a partially downloaded file
path = recd.getMediaFilepath()
+
if path and os.path.exists(path):
os.remove(path)
good_buddy_obj = None
buds = self.activity._shared_activity.get_joined_buddies()
+
for buddy_obj in buds:
buddy = util.sha_data(buddy_obj.props.key)
buddy = util.printable_hash(buddy)
+
if recd.triedMeshBuddies.count(buddy) > 0:
logger.debug('mnrrb: weve already tried bud ' + buddy_obj.props.nick)
+
else:
logger.debug('mnrrb: ask next buddy: ' + buddy_obj.props.nick)
good_buddy_obj = buddy_obj
@@ -182,6 +222,7 @@ class RecordCollab(object):
buddy = util.sha_data(good_buddy_obj.props.key)
buddy = util.printable_hash(buddy)
self._req_recd_from_buddy(recd, buddy, good_buddy_obj.props.nick)
+
else:
logger.debug('weve tried all buddies here, and no one has this recd')
recd.meshDownloading = False
@@ -190,9 +231,11 @@ class RecordCollab(object):
self.activity.update_download_progress(recd)
def _recd_request_cb(self, remote_object, remote_person, md5sum):
+
#if we are here, it is because someone has been told we have what they want.
#we need to send them that thing, whatever that thing is
recd = self.model.get_recd_by_md5(md5sum)
+
if not recd:
logger.debug('_recdRequestCb: we dont have the recd they asked for')
self._tube.unavailableRecd(md5sum, Instance.keyHashPrintable, remote_person)
@@ -223,6 +266,7 @@ class RecordCollab(object):
self._tube.broadcastRecd(recd.mediaMd5, path, remote_person)
recd.meshUploading = False
+
#if you were deleted while uploading, now throw away those bits now
if recd.deleted:
recd.doDeleteRecorded(recd)
@@ -232,21 +276,28 @@ class RecordCollab(object):
if recd.downloadedFromBuddy:
logger.debug('_meshCheckOnRecdRequest: recdRequesting.downloadedFromBuddy')
+
if recd.meshReqCallbackId:
GObject.source_remove(recd.meshReqCallbackId)
recd.meshReqCallbackId = 0
+
return False
+
if recd.deleted:
logger.debug('_meshCheckOnRecdRequest: recdRequesting.deleted')
+
if recd.meshReqCallbackId:
GObject.source_remove(recd.meshReqCallbackId)
recd.meshReqCallbackId = 0
+
return False
+
if recd.meshDownloadingProgress:
logger.debug('_meshCheckOnRecdRequest: recdRequesting.meshDownloadingProgress')
#we've received some bits since last we checked, so keep waiting... they'll all get here eventually!
recd.meshDownloadingProgress = False
return True
+
else:
logger.debug('_meshCheckOnRecdRequest: ! recdRequesting.meshDownloadingProgress')
#that buddy we asked info from isn't responding; next buddy!
@@ -255,19 +306,25 @@ class RecordCollab(object):
return False
def _recd_bits_arrived_cb(self, remote_object, md5sum, part, num_parts, bytes, sender):
+
recd = self.model.get_recd_by_md5(md5sum)
+
if not recd:
logger.debug('_recdBitsArrivedCb: thx 4 yr bits, but we dont even have that photo')
return
+
if recd.deleted:
logger.debug('_recdBitsArrivedCb: thx 4 yr bits, but we deleted that photo')
return
+
if recd.downloadedFromBuddy:
logger.debug('_recdBitsArrivedCb: weve already downloadedFromBuddy')
return
+
if not recd.buddy:
logger.debug('_recdBitsArrivedCb: uh, we took this photo, so dont need your bits')
return
+
if recd.meshDownloadingFrom != sender:
logger.debug('_recdBitsArrivedCb: wrong bits ' + str(sender) + ", exp:" + str(recd.meshDownloadingFrom))
return
@@ -285,6 +342,7 @@ class RecordCollab(object):
if part > num_parts:
logger.error('More parts than required have arrived')
return
+
if part != num_parts:
return
@@ -294,6 +352,7 @@ class RecordCollab(object):
recd.meshDownloading = False
recd.meshDownlodingPercent = 1.0
recd.downloadedFromBuddy = True
+
if recd.type == constants.TYPE_AUDIO:
path = recd.getMediaFilepath()
bundle_path = os.path.join(Instance.instancePath, "audioBundle")
@@ -319,21 +378,26 @@ class RecordCollab(object):
self.activity.remote_recd_available(recd)
def _recd_unavailable_cb(self, remote_object, md5sum, sender):
+
logger.debug('_recdUnavailableCb: sux, we want to see that photo')
recd = self.model.get_recd_by_md5(md5sum)
+
if not recd:
logger.debug('_recdUnavailableCb: actually, we dont even know about that one..')
return
+
if recd.deleted:
logger.debug('_recdUnavailableCb: actually, since we asked, we deleted.')
return
+
if not recd.buddy:
logger.debug('_recdUnavailableCb: uh, odd, we took that photo and have it already.')
return
+
if recd.downloadedFromBuddy:
logger.debug('_recdUnavailableCb: we already downloaded it... you might have been slow responding.')
return
+
if recd.meshDownloadingFrom != sender:
logger.debug('_recdUnavailableCb: we arent asking you for a copy now. slow response, pbly.')
return
-
diff --git a/glive.py b/glive.py
index 0747e86..48e28d1 100644
--- a/glive.py
+++ b/glive.py
@@ -39,8 +39,8 @@ import utils
logger = logging.getLogger('glive')
OGG_TRAITS = {
- 0: { 'width': 160, 'height': 120, 'quality': 16 },
- 1: { 'width': 400, 'height': 300, 'quality': 16 } }
+ 0: { 'width': 160, 'height': 120, 'quality': 16 },
+ 1: { 'width': 400, 'height': 300, 'quality': 16 } }
class Glive:
PHOTO_MODE_PHOTO = 0
@@ -50,6 +50,7 @@ class Glive:
self.activity = activity_obj
self.model = model
+
self._eos_cb = None
self._has_camera = False
self._can_limit_framerate = False
@@ -68,6 +69,7 @@ class Glive:
self._detect_camera()
self._pipeline = Gst.Pipeline()
+
self._create_photobin()
self._create_audiobin()
self._create_videobin()
@@ -86,7 +88,7 @@ class Glive:
v4l2src = Gst.ElementFactory.make('v4l2src', 'v4l2src')
- if v4l2src.props.device_name is None:
+ if v4l2src.get_property('device-name') is None:
return
self._has_camera = True
@@ -97,15 +99,25 @@ class Glive:
# can't find a way to do this (at this time, XO-1 cafe camera driver
# doesn't support framerate changes, but gstreamer caps suggest
# otherwise)
+
pipeline = Gst.Pipeline()
+
+ # WARNING **: 0.10-style raw video caps are being created. Should be video/x-raw,format=(string)
caps = Gst.Caps.from_string('video/x-raw-yuv,framerate=10/1')
+ camerafilter = Gst.ElementFactory.make("capsfilter", "capsfilter")
+ camerafilter.set_property("caps", caps)
+
fsink = Gst.ElementFactory.make('fakesink', 'fakesink')
+
pipeline.add(v4l2src)
- # FIXME: TypeError: argument dest: Expected Gst.Element, but got gi.repository.Gst.Caps
- #pipeline.add(caps)
+ pipeline.add(camerafilter)
pipeline.add(fsink)
- v4l2src.link(fsink)
+
+ v4l2src.link(camerafilter)
+ camerafilter.link(fsink)
+
self._can_limit_framerate = pipeline.set_state(Gst.State.PAUSED) != Gst.StateChangeReturn.FAILURE
+
pipeline.set_state(Gst.State.NULL)
def get_has_camera(self):
@@ -115,7 +127,7 @@ class Glive:
def _create_photobin(self):
queue = Gst.ElementFactory.make("queue", "pbqueue")
- queue.set_property("leaky", True)
+ queue.set_property("leaky", 1)
queue.set_property("max-size-buffers", 1)
colorspace = Gst.ElementFactory.make("videoconvert", "pbcolorspace")
@@ -151,8 +163,9 @@ class Glive:
if not hwdev_available:
src.set_property("device", "default")
+ # WARNING **: 0.10-style raw audio caps are being created. Should be audio/x-raw,format=(string)
srccaps = Gst.Caps.from_string("audio/x-raw-int,rate=16000,channels=1,depth=16")
-
+
# guarantee perfect stream, important for A/V sync
rate = Gst.ElementFactory.make("audiorate", 'audiorate')
@@ -161,7 +174,7 @@ class Glive:
# (possibly a gstreamer/ALSA bug -- even if it gets caught up, it
# should be able to resync without problem)
queue = Gst.ElementFactory.make("queue", "audioqueue")
- queue.set_property("leaky", True) # prefer fresh data
+ queue.set_property("leaky", 1) # prefer fresh data
queue.set_property("max-size-time", 5000000000) # 5 seconds
queue.set_property("max-size-buffers", 500)
queue.connect("overrun", self._log_queue_overrun)
@@ -172,13 +185,14 @@ class Glive:
sink.set_property("location", os.path.join(Instance.instancePath, "output.wav"))
self._audiobin = Gst.Bin()
+
self._audiobin.add(src)
self._audiobin.add(rate)
self._audiobin.add(queue)
self._audiobin.add(enc)
self._audiobin.add(sink)
- rate.link(rate)
+ src.link(rate)
rate.link(queue)
queue.link(enc)
enc.link(sink)
@@ -192,9 +206,9 @@ class Glive:
scale = Gst.ElementFactory.make("videoscale", "vbscale")
- scalecapsfilter = Gst.ElementFactory.make("capsfilter", "scalecaps")
-
+ # WARNING **: 0.10-style raw video caps are being created. Should be video/x-raw,format=(string)
scalecaps = Gst.Caps.from_string('video/x-raw-yuv,width=160,height=120')
+ scalecapsfilter = Gst.ElementFactory.make("capsfilter", "scalecaps")
scalecapsfilter.set_property("caps", scalecaps)
colorspace = Gst.ElementFactory.make("videoconvert", "vbcolorspace")
@@ -208,6 +222,7 @@ class Glive:
sink.set_property("location", os.path.join(Instance.instancePath, "output.ogg"))
self._videobin = Gst.Bin()
+
self._videobin.add(queue)
self._videobin.add(scale)
self._videobin.add(scalecapsfilter)
@@ -225,7 +240,7 @@ class Glive:
pad = queue.get_static_pad("sink")
self._videobin.add_pad(Gst.GhostPad.new("sink", pad))
-
+
def _create_xbin(self):
scale = Gst.ElementFactory.make("videoscale", 'videoscale')
@@ -237,6 +252,7 @@ class Glive:
xsink.set_property("sync", False)
self._xbin = Gst.Bin()
+
self._xbin.add(scale)
self._xbin.add(cspace)
self._xbin.add(xsink)
@@ -260,13 +276,6 @@ class Glive:
return
src = Gst.ElementFactory.make("v4l2src", "camsrc")
-
- try:
- # old gst-plugins-good does not have this property
- src.set_property("queue-size", 2)
-
- except:
- pass
# if possible, it is important to place the framerate limit directly
# on the v4l2src so that it gets communicated all the way down to the
@@ -286,23 +295,27 @@ class Glive:
# the FPS value.
rate = Gst.ElementFactory.make("videorate", 'videorate')
ratecaps = Gst.Caps.from_string('video/x-raw-yuv,framerate=10/1')
-
+
tee = Gst.ElementFactory.make("tee", "tee")
queue = Gst.ElementFactory.make("queue", "dispqueue")
# prefer fresh frames
- queue.set_property("leaky", True)
+ queue.set_property("leaky", 1)
queue.set_property("max-size-buffers", 2)
self._pipeline.add(src)
self._pipeline.add(rate)
self._pipeline.add(tee)
self._pipeline.add(queue)
+
src.link(rate)
- # FIXME: TypeError: argument dest: Expected Gst.Element, but got gi.repository.Gst.Caps
+ # FIXME: TypeError: Expected Gst.Element, but got GObjectMeta
#rate.link(srccaps)
+
rate.link(tee)
+ # FIXME: TypeError: Expected Gst.Element, but got GObjectMeta
#tee.link(ratecaps)
+
tee.link(queue)
self._xvsink = Gst.ElementFactory.make("xvimagesink", "xsink")
@@ -406,6 +419,7 @@ class Glive:
return self._pipeline.get_state(0)[1]
def stop_recording_audio(self):
+
# We should be able to simply pause and remove the audiobin, but
# this seems to cause a gstreamer segfault. So we stop the whole
# pipeline while manipulating it.
@@ -423,16 +437,16 @@ class Glive:
self.model.still_ready(self._audio_pixbuf)
line = 'filesrc location=' + audio_path + ' name=audioFilesrc ! wavparse name=audioWavparse ! audioconvert name=audioAudioconvert ! vorbisenc name=audioVorbisenc ! oggmux name=audioOggmux ! filesink name=audioFilesink'
- audioline = gst.parse_launch(line)
+ audioline = Gst.parse_launch(line)
taglist = self._get_tags(constants.TYPE_AUDIO)
if self._audio_pixbuf:
pixbuf_b64 = utils.getStringFromPixbuf(self._audio_pixbuf)
- taglist[Gst.TAG_EXTENDED_COMMENT] = "coverart=" + pixbuf_b64
+ #taglist[Gst.TAG_EXTENDED_COMMENT] = "coverart=" + pixbuf_b64
vorbis_enc = audioline.get_by_name('audioVorbisenc')
- vorbis_enc.merge_tags(taglist, Gst.TAG_MERGE_REPLACE_ALL)
+ #vorbis_enc.merge_tags(taglist, Gst.TagMergeMode.REPLACE_ALL)
audioFilesink = audioline.get_by_name('audioFilesink')
audioOggFilepath = os.path.join(Instance.instancePath, "output.ogg")
@@ -442,11 +456,13 @@ class Glive:
audioBus.add_signal_watch()
self._audio_transcode_handler = audioBus.connect('message', self._onMuxedAudioMessageCb, audioline)
self._transcode_id = GObject.timeout_add(200, self._transcodeUpdateCb, audioline)
+
audioline.set_state(Gst.State.PLAYING)
def _get_tags(self, type):
tl = Gst.TagList()
+ """
tl[Gst.TAG_ARTIST] = self.model.get_nickname()
tl[Gst.TAG_COMMENT] = "olpc"
#this is unfortunately, unreliable
@@ -457,7 +473,7 @@ class Glive:
# Translators: photo by photographer, e.g. "Photo by Mary"
tl[Gst.TAG_TITLE] = _('%(type)s by %(name)s') % {'type': stringType,
- 'name': self.model.get_nickname()}
+ 'name': self.model.get_nickname()}"""
return tl
def _take_photo(self, photo_mode):
@@ -510,10 +526,11 @@ class Glive:
return
self._ogg_quality = quality
+
self._config_videobin(OGG_TRAITS[quality]['quality'],
OGG_TRAITS[quality]['width'],
OGG_TRAITS[quality]['height'])
-
+
# If we use pad blocking and adjust the pipeline on-the-fly, the
# resultant video has bad A/V sync :(
# If we pause the pipeline while adjusting it, the A/V sync is better
@@ -552,7 +569,7 @@ class Glive:
self._eos_cb = self._video_eos
self._pipeline.get_by_name('camsrc').send_event(Gst.Event.new_eos())
self._audiobin.get_by_name('absrc').send_event(Gst.Event.new_eos())
-
+
def _video_eos(self):
self._pipeline.set_state(Gst.State.NULL)
@@ -561,7 +578,7 @@ class Glive:
self._pipeline.remove(self._audiobin)
self.model.shutter_sound()
-
+
if len(self._thumb_pipes) > 0:
thumbline = self._thumb_pipes[-1]
thumbline.get_by_name('thumb_fakesink').disconnect(self._thumb_handoff_handler)
@@ -572,10 +589,12 @@ class Glive:
# FIXME: inform model of failure?
return
- line = 'filesrc location=' + ogg_path + ' name=thumbFilesrc ! oggdemux name=thumbOggdemux ! theoradec name=thumbTheoradec ! tee name=thumb_tee ! queue name=thumb_queue ! ffmpegcolorspace name=thumbFfmpegcolorspace ! jpegenc name=thumbJPegenc ! fakesink name=thumb_fakesink'
+ line = 'filesrc location=' + ogg_path + ' name=thumbFilesrc ! oggdemux name=thumbOggdemux ! theoradec name=thumbTheoradec ! tee name=thumb_tee ! queue name=thumb_queue ! videoconvert name=thumbFfmpegcolorspace ! jpegenc name=thumbJPegenc ! fakesink name=thumb_fakesink'
+
thumbline = Gst.parse_launch(line)
+
thumb_queue = thumbline.get_by_name('thumb_queue')
- thumb_queue.set_property("leaky", True)
+ thumb_queue.set_property("leaky", 1)
thumb_queue.set_property("max-size-buffers", 1)
thumb_tee = thumbline.get_by_name('thumb_tee')
thumb_fakesink = thumbline.get_by_name('thumb_fakesink')
@@ -584,18 +603,19 @@ class Glive:
self._thumb_pipes.append(thumbline)
self._thumb_exposure_open = True
thumbline.set_state(Gst.State.PLAYING)
-
+
def copyThumbPic(self, fsink, buffer, pad, user_data=None):
if not self._thumb_exposure_open:
return
self._thumb_exposure_open = False
- loader = GdkPibuf.PixbufLoader.new_with_mime_type("image/jpeg")
- loader.write(buffer)
- loader.close()
- self.thumbBuf = loader.get_pixbuf()
- self.model.still_ready(self.thumbBuf)
+ #loader = GdkPixbuf.PixbufLoader.new_with_mime_type("image/jpeg")
+ # FIXME: TypeError: Must be sequence, not Buffer
+ #loader.write(buffer)
+ #loader.close()
+ #self.thumbBuf = loader.get_pixbuf()
+ #self.model.still_ready(self.thumbBuf)
self._thumb_element('thumb_tee').unlink(self._thumb_element('thumb_queue'))
@@ -604,9 +624,10 @@ class Glive:
muxFilepath = os.path.join(Instance.instancePath, "mux.ogg")
muxline = Gst.parse_launch('filesrc location=' + str(oggFilepath) + ' name=muxVideoFilesrc ! oggdemux name=muxOggdemux ! theoraparse ! oggmux name=muxOggmux ! filesink location=' + str(muxFilepath) + ' name=muxFilesink filesrc location=' + str(wavFilepath) + ' name=muxAudioFilesrc ! wavparse name=muxWavparse ! audioconvert name=muxAudioconvert ! vorbisenc name=muxVorbisenc ! muxOggmux.')
+
taglist = self._get_tags(constants.TYPE_VIDEO)
vorbis_enc = muxline.get_by_name('muxVorbisenc')
- vorbis_enc.merge_tags(taglist, Gst.TAG_MERGE_REPLACE_ALL)
+ #vorbis_enc.merge_tags(taglist, Gst.TagMergeMode.REPLACE_ALL)
muxBus = muxline.get_bus()
muxBus.add_signal_watch()
@@ -630,13 +651,13 @@ class Glive:
def _query_position(self, pipe):
try:
- position, format = pipe.query_position(Gst.FORMAT_TIME)
+ position, format = pipe.query_position(Gst.Format.TIME)
except:
- position = Gste.CLOCK_TIME_NONE
+ position = Gst.CLOCK_TIME_NONE
try:
- duration, format = pipe.query_duration(Gst.FORMAT_TIME)
+ duration, format = pipe.query_duration(Gst.Format.TIME)
except:
duration = Gst.CLOCK_TIME_NONE
@@ -645,7 +666,7 @@ class Glive:
def _onMuxedVideoMessageCb(self, bus, message, pipe):
- if message.type != Gst.MESSAGE_EOS:
+ if message.type != Gst.MessageType.EOS:
return True
GObject.source_remove(self._video_transcode_handler)
@@ -667,7 +688,7 @@ class Glive:
def _onMuxedAudioMessageCb(self, bus, message, pipe):
- if message.type != Gst.MESSAGE_EOS:
+ if message.type != Gst.MessageType.EOS:
return True
GObject.source_remove(self._audio_transcode_handler)
@@ -682,6 +703,7 @@ class Glive:
oggFilepath = os.path.join(Instance.instancePath, "output.ogg")
os.remove( wavFilepath )
self.model.save_audio(oggFilepath, self._audio_pixbuf)
+
return False
def _bus_message_handler(self, bus, message):
diff --git a/gplay.py b/gplay.py
index 5cc34f3..52d34cf 100644
--- a/gplay.py
+++ b/gplay.py
@@ -74,17 +74,19 @@ class Gplay(GObject.GObject):
duration = self._player.query_duration(Gst.Format.TIME, None)[0]
location = duration * (position / 100)
- event = gst.event_new_seek(
+ event = Gst.Event.new_seek(
1.0, Gst.Format.TIME,
Gst.SeekFlags.FLUSH |
Gst.SeekFlags.ACCURATE,
- gst.SeekType.SET, location,
- gst.SeekType.NONE, 0)
+ Gst.SeekType.SET, location,
+ Gst.SeekType.NONE, 0)
res = self._player.send_event(event)
if res:
- self._player.set_new_stream_time(0L)
+ # FIXME: 'Pipeline' object has no attribute 'new_stream_time'
+ #self._player.set_new_stream_time(0L)
+ pass
def pause(self):
@@ -112,7 +114,7 @@ class Gplay(GObject.GObject):
position = self._player.query_position(Gst.Format.TIME)[0]
duration = self._player.query_duration(Gst.Format.TIME)[0]
- except gst.QueryError:
+ except:
return True
value = (float(position) / float(duration)) * 100.0
diff --git a/hw.py b/hw.py
index d678e37..0f9f325 100644
--- a/hw.py
+++ b/hw.py
@@ -18,20 +18,27 @@
import os
def _get_dmi(node):
+
path = os.path.join('/sys/class/dmi/id', node)
+
try:
return open(path).readline().strip()
+
except:
return None
def get_xo_version():
+
if _get_dmi('product_name') != 'XO':
return 0
+
version = _get_dmi('product_version')
+
if version == '1':
return 1
+
if version == '1.5':
return 1.5
+
else:
return 0
-
diff --git a/iconcombobox.py b/iconcombobox.py
index 077fa7a..18d7f82 100644
--- a/iconcombobox.py
+++ b/iconcombobox.py
@@ -24,10 +24,11 @@ from gi.repository import Gtk
from sugar3.graphics.combobox import ComboBox
from sugar3.graphics import style
-
class IconComboBox(Gtk.ToolItem):
- def __init__(self, icon_name, **kwargs):
- Gtk.ToolItem.__init__(self, **kwargs)
+
+ def __init__(self, icon_name):
+
+ Gtk.ToolItem.__init__(self)
self.icon_name = icon_name
self.set_border_width(style.DEFAULT_PADDING)
@@ -39,4 +40,5 @@ class IconComboBox(Gtk.ToolItem):
self.add(self.combo)
def append_item(self, i, text):
+
self.combo.append_item(i, text, icon_name=self.icon_name)
diff --git a/instance.py b/instance.py
index 259bc2d..61d8747 100644
--- a/instance.py
+++ b/instance.py
@@ -4,6 +4,7 @@ from sugar3 import profile
from sugar3 import util
class Instance:
+
key = profile.get_pubkey()
keyHash = util.sha_data(key)
@@ -12,11 +13,13 @@ class Instance:
instancePath = None
def __init__(self, ca):
+
self.__class__.instancePath = os.path.join(ca.get_activity_root(), "instance")
recreateTmp()
def recreateTmp():
+
if (not os.path.exists(Instance.instancePath)):
os.makedirs(Instance.instancePath)
diff --git a/mediaview.py b/mediaview.py
index 4832a4a..afc7ada 100644
--- a/mediaview.py
+++ b/mediaview.py
@@ -21,6 +21,7 @@ class XoIcon(Gtk.Image):
super(XoIcon, self).__init__()
def set_colors(self, stroke, fill):
+
pixbuf = utils.load_colored_svg('xo-guy.svg', stroke, fill)
self.set_from_pixbuf(pixbuf)
@@ -296,13 +297,6 @@ class MediaView(Gtk.EventBox):
MODE_STILL = 3
MODE_INFO_PHOTO = 4
MODE_INFO_VIDEO = 5
-
- @staticmethod
- def _raise_widget(widget):
-
- widget.show()
- widget.realize()
- widget.get_property('window').raise_()
def __init__(self):
@@ -377,13 +371,13 @@ class MediaView(Gtk.EventBox):
def _show_controls(self):
if self._mode in (MediaView.MODE_LIVE, MediaView.MODE_VIDEO, MediaView.MODE_PHOTO, MediaView.MODE_STILL):
- self._raise_widget(self._full_button)
+ self._full_button.show()
if self._mode in (MediaView.MODE_VIDEO, MediaView.MODE_PHOTO):
- self._raise_widget(self._info_button)
+ self._info_button.show()
if self._mode in (MediaView.MODE_VIDEO, MediaView.MODE_PHOTO):
- self._raise_widget(self._video)
+ self._video.show()
def _hide_controls(self):
diff --git a/model.py b/model.py
index be1c2c2..771f08f 100644
--- a/model.py
+++ b/model.py
@@ -125,6 +125,7 @@ class Model:
self._mode = mode
self.activity.remove_all_thumbnails()
+
for recd in self.mediaHashs[mode]:
self.activity.add_thumbnail(recd, True)
@@ -272,6 +273,7 @@ class Model:
return True
def do_shutter(self):
+
# if recording, stop
if self._state == constants.STATE_RECORDING:
self._stop_media_capture()
@@ -291,6 +293,7 @@ class Model:
# called from gstreamer thread
def still_ready(self, pixbuf):
+
GObject.idle_add(self.activity.show_still, pixbuf)
def add_recd(self, recd):
@@ -305,6 +308,7 @@ class Model:
# called from gstreamer thread
def save_photo(self, pixbuf):
+
recd = self.createNewRecorded(constants.TYPE_PHOTO)
imgpath = os.path.join(Instance.instancePath, recd.mediaFilename)
@@ -315,9 +319,8 @@ class Model:
#now that we've saved both the image and its pixbuf, we get their md5s
self.createNewRecordedMd5Sums( recd )
- GObject.idle_add(self.add_recd, recd, priority=GObject.PRIORITY_HIGH)
- GObject.idle_add(self.activity.set_shutter_sensitive,
- True, priority=GObject.PRIORITY_HIGH)
+ GObject.idle_add(self.add_recd, recd)
+ GObject.idle_add(self.activity.set_shutter_sensitive, True)
# called from gstreamer thread
def save_video(self, path, still):
@@ -330,7 +333,7 @@ class Model:
self.createNewRecordedMd5Sums( recd )
- GObject.idle_add(self.add_recd, recd, priority=GObject.PRIORITY_HIGH)
+ GObject.idle_add(self.add_recd, recd)
GObject.idle_add(self.set_state, constants.STATE_READY)
def save_audio(self, path, still):
@@ -349,7 +352,7 @@ class Model:
self.createNewRecordedMd5Sums( recd )
- GObject.idle_add(self.add_recd, recd, priority=GObject.PRIORITY_HIGH)
+ GObject.idle_add(self.add_recd, recd)
GObject.idle_add(self.set_state, constants.STATE_READY)
def _playback_status_changed(self, widget, status, value):
@@ -384,12 +387,15 @@ class Model:
self.activity.set_paused(False)
def start_seek(self):
+
self.gplay.pause()
def do_seek(self, position):
+
self.gplay.seek(position)
def end_seek(self):
+
self.gplay.play()
def get_recd_by_md5(self, md5):
@@ -431,6 +437,7 @@ class Model:
recd.colorFill = color.get_fill_color()
logger.debug('createNewRecorded: ' + str(recd))
+
return recd
def createNewRecordedMd5Sums( self, recd ):
diff --git a/record.py b/record.py
index 271a7a5..302a783 100644
--- a/record.py
+++ b/record.py
@@ -132,7 +132,7 @@ class Record(activity.Activity):
def _visibility_changed(self, widget, event):
self.model.set_visible(event.state != Gdk.VisibilityState.FULLY_OBSCURED)
-
+
def _shared_cb(self, activity):
self.model.collab.set_activity_shared()
@@ -389,7 +389,8 @@ class Record(activity.Activity):
self._title_label.show()
self._record_container.set_title_visible(True)
- func(recd.recorderName, recd.colorStroke, recd.colorFill, utils.getDateString(recd.time), recd.tags)
+ func(recd.recorderName, recd.colorStroke,
+ recd.colorFill, utils.getDateString(recd.time), recd.tags)
def _media_view_full_clicked(self, widget):
@@ -428,6 +429,7 @@ class Record(activity.Activity):
def set_state(self, state):
radio_state = (state == constants.STATE_READY)
+
for item in (self._photo_button, self._audio_button, self._video_button):
if item:
item.set_sensitive(radio_state)
@@ -504,7 +506,8 @@ class Record(activity.Activity):
media_path = recd.getMediaFilepath()
tmp_path = utils.getUniqueFilepath(media_path, 0)
shutil.copyfile(media_path, tmp_path)
- Gtk.Clipboard().set_with_data([('text/uri-list', 0, 0)], self._clipboard_get, self._clipboard_clear, tmp_path)
+ Gtk.Clipboard().set_with_data([('text/uri-list', 0, 0)],
+ self._clipboard_get, self._clipboard_clear, tmp_path)
def _clipboard_get(self, clipboard, selection_data, info, path):
@@ -543,7 +546,6 @@ class Record(activity.Activity):
for child in self._thumb_tray.get_children():
self._remove_thumbnail(child)
- pass
def show_still(self, pixbuf):
@@ -786,6 +788,8 @@ class CountdownImage(Gtk.Image):
w = 55
h = w
+ # FIXME: No more Pixmap
+ """
pixmap = GdK.Pixmap(self.get_window(), w, h, -1)
ctx = pixmap.cairo_create()
ctx.rectangle(0, 0, w, h)
@@ -815,7 +819,7 @@ class CountdownImage(Gtk.Image):
ctx.translate(-3, 0)
pctx.show_layout(play)
- return pixmap
+ return pixmap"""
def set_value(self, num):
@@ -824,7 +828,6 @@ class CountdownImage(Gtk.Image):
self.set_from_pixmap(self._countdown_images[num], None)
-
class ShutterButton(Gtk.Button):
def __init__(self):
@@ -864,7 +867,6 @@ class ShutterButton(Gtk.Button):
self.set_image(self._rec_red_image)
-
class PlayButton(Gtk.Button):
def __init__(self):
@@ -891,7 +893,6 @@ class PlayButton(Gtk.Button):
self.set_image(self._pause_image)
-
class RecordControl():
def __init__(self, toolbar):
@@ -971,7 +972,6 @@ class RecordControl():
self.quality.combo.set_active(idx)
-
class TimerCombo(IconComboBox):
TIMERS = (0, 5, 10)
@@ -1007,7 +1007,6 @@ class TimerCombo(IconComboBox):
return ngettext('%s second', '%s seconds', x) % x
-
class DurationCombo(IconComboBox):
DURATIONS = (2, 4, 6)
diff --git a/recorded.py b/recorded.py
index 8343b35..3ed5ffc 100644
--- a/recorded.py
+++ b/recorded.py
@@ -29,7 +29,9 @@ import utils
import serialize
class Recorded:
+
def __init__( self ):
+
self.type = -1
self.time = None
self.recorderName = None
@@ -75,27 +77,29 @@ class Recorded:
self.deleted = False
-
def setTitle( self, newTitle ):
+
if self.title == newTitle:
return
+
self.title = newTitle
self.metaChange = True
-
def setTags( self, newTags ):
+
self.tags = newTags
self.metaChange = True
-
def isClipboardCopyable( self ):
+
copyme = True
+
if (self.buddy):
if (not self.downloadedFromBuddy):
return False
+
return copyme
-
#scenarios:
#launch, your new thumb -- Journal/session
#launch, your new media -- Journal/session
@@ -107,57 +111,69 @@ class Recorded:
#relaunch, their old media -- datastoreObject->file (hold onto the datastore object, delete if deleted) | ([request->]) Journal/session/buddy
def getThumbPixbuf( self ):
+
thumbFilepath = self.getThumbFilepath()
+
if thumbFilepath and os.path.isfile(thumbFilepath):
return GdkPixbuf.Pixbuf.new_from_file(thumbFilepath)
+
else:
return None
-
def getThumbFilepath( self ):
+
if not self.thumbFilename:
return None
+
return os.path.join(Instance.instancePath, self.thumbFilename)
def make_thumb_path(self):
+
thumbFilename = self.mediaFilename + "_thumb.jpg"
thumbFilepath = os.path.join(Instance.instancePath, thumbFilename)
thumbFilepath = utils.getUniqueFilepath(thumbFilepath, 0)
self.thumbFilename = os.path.basename(thumbFilepath)
+
return self.getThumbFilepath()
def getAudioImagePixbuf( self ):
+
audioPixbuf = None
if self.audioImageFilename == None:
audioPixbuf = self.getThumbPixbuf()
+
else:
audioFilepath = self.getAudioImageFilepath()
+
if (audioFilepath != None):
audioPixbuf = GdkPixbuf.Pixbuf.new_from_file(audioFilepath)
return audioPixbuf
-
def getAudioImageFilepath( self ):
+
if (self.audioImageFilename != None):
audioFilepath = os.path.join(Instance.instancePath, self.audioImageFilename)
return os.path.abspath(audioFilepath)
+
else:
return self.getThumbFilepath()
-
def getMediaFilepath(self):
+
if (self.datastoreId == None):
if (not self.buddy):
#just taken by you, so it is in the tempSessionDir
mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
return os.path.abspath(mediaFilepath)
+
else:
if (self.downloadedFromBuddy):
#the user has requested the high-res version, and it has downloaded
mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
return os.path.abspath(mediaFilepath)
+
else:
if self.mediaFilename == None:
#creating a new filepath, probably just got here from the mesh
@@ -167,6 +183,7 @@ class Recorded:
self.mediaFilename = os.path.basename(recdPath)
mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
return os.path.abspath(mediaFilepath)
+
else:
mediaFilepath = os.path.join(Instance.instancePath, self.mediaFilename)
return os.path.abspath(mediaFilepath)
@@ -175,6 +192,7 @@ class Recorded:
#first, get the datastoreObject and hold the reference in this Recorded instance
if (self.datastoreOb == None):
self.datastoreOb = serialize.getMediaFromDatastore( self )
+
if (self.datastoreOb == None):
print("RecordActivity error -- unable to get datastore object in getMediaFilepath")
return None
diff --git a/recordtube.py b/recordtube.py
index b3c82d2..c443070 100644
--- a/recordtube.py
+++ b/recordtube.py
@@ -25,102 +25,131 @@ class RecordTube(ExportedGObject):
def __init__(self, tube):
+
super(RecordTube, self).__init__(tube, constants.DBUS_PATH)
+
self.tube = tube
- self.idNotify = self.tube.add_signal_receiver(self._newRecdTubeCb, 'notifyBudsOfNewRecd', constants.DBUS_IFACE, path=constants.DBUS_PATH, sender_keyword='sender')
- self.idRequest = self.tube.add_signal_receiver(self._reqRecdTubeCb, 'requestRecdBits', constants.DBUS_IFACE, path=constants.DBUS_PATH, sender_keyword='sender')
- self.idBroadcast = self.tube.add_signal_receiver(self._getRecdTubeCb, 'broadcastRecdBits', constants.DBUS_IFACE, path=constants.DBUS_PATH, sender_keyword='sender', byte_arrays=True)
- self.idUnavailable = self.tube.add_signal_receiver(self._unavailableRecdTubeCb, 'unavailableRecd', constants.DBUS_IFACE, path=constants.DBUS_PATH, sender_keyword='sender')
-
+ self.idNotify = self.tube.add_signal_receiver(
+ self._newRecdTubeCb, 'notifyBudsOfNewRecd',
+ constants.DBUS_IFACE, path=constants.DBUS_PATH,
+ sender_keyword='sender')
+
+ self.idRequest = self.tube.add_signal_receiver(
+ self._reqRecdTubeCb, 'requestRecdBits',
+ constants.DBUS_IFACE, path=constants.DBUS_PATH,
+ sender_keyword='sender')
+
+ self.idBroadcast = self.tube.add_signal_receiver(
+ self._getRecdTubeCb, 'broadcastRecdBits',
+ constants.DBUS_IFACE, path=constants.DBUS_PATH,
+ sender_keyword='sender', byte_arrays=True)
+
+ self.idUnavailable = self.tube.add_signal_receiver(
+ self._unavailableRecdTubeCb, 'unavailableRecd',
+ constants.DBUS_IFACE, path=constants.DBUS_PATH,
+ sender_keyword='sender')
@signal(dbus_interface=constants.DBUS_IFACE, signature='ss') #dual s for 2x strings
def notifyBudsOfNewRecd(self, recorder, recdXml):
+
logger.debug('Ive taken a new pho-ideo-audio! I hereby send you an xml thumb of said media via this interface.')
- def _newRecdTubeCb(self, recorder, recdXml, sender=None):
+ def _newRecdTubeCb(self, recorder, recdXml, sender = None):
+
logger.debug("_newRecdTubeCb from " + recorder )
+
if sender == self.tube.get_unique_name():
logger.debug("_newRecdTubeCb: sender is my bus name, so ignore my own signal")
return
+
elif (recorder == Instance.keyHashPrintable):
logger.debug('_newRecdTubeCb: excuse me? you are asking me to share a photo with myself?')
return
self.emit( "new-recd", str(recorder), str(recdXml) )
-
@signal(dbus_interface=constants.DBUS_IFACE, signature='sss') #triple s for 3x strings
def requestRecdBits(self, whoWantsIt, whoTheyWantItFrom, recdMd5sumOfIt ):
+
logger.debug('I am requesting a high-res version of someones media.')
-
- def _reqRecdTubeCb(self, whoWantsIt, whoTheyWantItFrom, recdMd5sumOfIt, sender=None):
+ def _reqRecdTubeCb(self, whoWantsIt, whoTheyWantItFrom, recdMd5sumOfIt, sender = None):
+
if sender == self.tube.get_unique_name():
logger.debug("_reqRecdTubeCb: sender is my bus name, so ignore my own signal")
return
+
elif (whoWantsIt == Instance.keyHashPrintable):
logger.debug('_reqRecdTubeCb: excuse me? you are asking me to share a photo with myself?')
return
+
elif (whoTheyWantItFrom != Instance.keyHashPrintable):
logger.debug('_reqRecdTubeCb: ive overhead someone wants a photo, but not from me')
return
self.emit( "recd-request", str(whoWantsIt), str(recdMd5sumOfIt) )
-
def broadcastRecd(self, md5, filepath, sendThisTo ):
+
size = os.path.getsize(filepath)
f = open(filepath)
chunk_size = 1000
chunks = size / chunk_size
+
if (size%chunk_size != 0):
chunks += 1
for chunk in range(chunks):
bytes = f.read(chunk_size)
+
if chunk == 0:
logger.debug("sending " + str(chunk+1) + " of " + str(chunks) + " to " + sendThisTo )
+
if chunk == chunks-1:
logger.debug("sending " + str(chunk+1) + " of " + str(chunks) + " to " + sendThisTo )
+
self.broadcastRecdBits(md5, chunk+1, chunks, bytes, sendThisTo, Instance.keyHashPrintable)
f.close()
return True
-
@signal(dbus_interface=constants.DBUS_IFACE, signature='suuayss')
def broadcastRecdBits(self, md5, part, numparts, bytes, sendTo, fromWho ):
pass
-
def _getRecdTubeCb(self, md5, part, numparts, bytes, sentTo, fromWho, sender=None):
+
if sender == self.tube.get_unique_name():
#record.Record.log.debug("_reqRecdTubeCb: sender is my bus name, so ignore my own signal")
return
+
if (fromWho == Instance.keyHashPrintable):
#record.Record.log.debug('_getRecdTubeCb: i dont want bits from meself, thx anyway. schizophrenic?')
return
+
if (sentTo != Instance.keyHashPrintable):
#record.Record.log.debug('_getRecdTubeCb: ive overhead someone sending bits, but not to me!')
return
self.emit( "recd-bits-arrived", md5, part, numparts, bytes, fromWho )
-
@signal(dbus_interface=constants.DBUS_IFACE, signature='sss') #triple s for 3x strings
def unavailableRecd(self, md5sumOfIt, whoDoesntHaveIt, whoAskedForIt):
+
logger.debug('unavailableRecd: id love to share this photo, but i am without a copy meself chum')
-
- def _unavailableRecdTubeCb( self, md5sumOfIt, whoDoesntHaveIt, whoAskedForIt, sender=None):
+ def _unavailableRecdTubeCb( self, md5sumOfIt, whoDoesntHaveIt, whoAskedForIt, sender = None):
+
if sender == self.tube.get_unique_name():
logger.debug("_unavailableRecdTubeCb: sender is my bus name, so ignore my own signal")
return
+
if whoDoesntHaveIt == Instance.keyHashPrintable:
logger.debug('_unavailableRecdTubeCb: yes, i know i dont have it, i just told you/me/us.')
return
+
if whoAskedForIt != Instance.keyHashPrintable:
logger.debug('_unavailableRecdTubeCb: ive overheard someone doesnt have a photo, but i didnt ask for that one anyways')
return
diff --git a/serialize.py b/serialize.py
index bd451cd..a52c6ca 100644
--- a/serialize.py
+++ b/serialize.py
@@ -16,29 +16,38 @@ import utils
logger = logging.getLogger('serialize')
def fillMediaHash(doc, mediaHashs):
+
for key, value in constants.MEDIA_INFO.items():
+
recdElements = doc.documentElement.getElementsByTagName(value['name'])
+
for el in recdElements:
_loadMediaIntoHash( el, mediaHashs[key] )
def _loadMediaIntoHash(el, hash):
+
addToHash = True
recd = recorded.Recorded()
recd = fillRecdFromNode(recd, el)
+
if recd:
if recd.datastoreId:
#quickly check: if you have a datastoreId that the file hasn't been deleted,
#cause if you do, we need to flag your removal
#2904 trac
recd.datastoreOb = getMediaFromDatastore( recd )
+
if not recd.datastoreOb:
addToHash = False
+
else:
#name might have been changed in the journal, so reflect that here
if recd.title != recd.datastoreOb.metadata['title']:
recd.setTitle(recd.datastoreOb.metadata['title'])
+
if recd.tags != recd.datastoreOb.metadata['tags']:
recd.setTags(recd.datastoreOb.metadata['tags'])
+
if recd.buddy:
recd.downloadedFromBuddy = True
@@ -48,6 +57,7 @@ def _loadMediaIntoHash(el, hash):
hash.append(recd )
def getMediaFromDatastore(recd):
+
if not recd.datastoreId:
return None
@@ -56,12 +66,15 @@ def getMediaFromDatastore(recd):
return recd.datastoreOb
mediaObject = None
+
try:
mediaObject = datastore.get(recd.datastoreId)
+
finally:
return mediaObject
def removeMediaFromDatastore(recd):
+
#before this method is called, the media are removed from the file
if not recd.datastoreId or not recd.datastoreOb:
return
@@ -72,11 +85,13 @@ def removeMediaFromDatastore(recd):
recd.datastoreId = None
recd.datastoreOb = None
+
finally:
#todo: add error message here
pass
def fillRecdFromNode(recd, el):
+
if el.getAttributeNode('type'):
recd.type = int(el.getAttribute('type'))
@@ -91,6 +106,7 @@ def fillRecdFromNode(recd, el):
if el.getAttributeNode('tags'):
recd.tags = el.getAttribute('tags')
+
else:
recd.tags = ""
@@ -119,6 +135,7 @@ def fillRecdFromNode(recd, el):
recd.thumbBytes = el.getAttribute('thumbBytes')
bt = el.getAttributeNode('base64Thumb')
+
if bt:
try:
thumbPath = os.path.join(Instance.instancePath, "datastoreThumb.jpg")
@@ -127,10 +144,12 @@ def fillRecdFromNode(recd, el):
thumbImg.save(thumbPath, "jpeg", {"quality":"85"} )
recd.thumbFilename = os.path.basename(thumbPath)
logger.debug("saved thumbFilename")
+
except:
logger.error("unable to getRecdBase64Thumb")
ai = el.getAttributeNode('audioImage')
+
if (not ai == None):
try:
audioImagePath = os.path.join(Instance.instancePath, "audioImage.png")
@@ -139,10 +158,12 @@ def fillRecdFromNode(recd, el):
audioImage.save(audioImagePath, "png", {} )
recd.audioImageFilename = os.path.basename(audioImagePath)
logger.debug("loaded audio image and set audioImageFilename")
+
except:
logger.error("unable to load audio image")
datastoreNode = el.getAttributeNode('datastoreId')
+
if datastoreNode:
recd.datastoreId = datastoreNode.nodeValue
@@ -150,6 +171,7 @@ def fillRecdFromNode(recd, el):
def getRecdXmlMeshString(recd):
+
impl = getDOMImplementation()
recdXml = impl.createDocument(None, 'recd', None)
root = recdXml.documentElement
@@ -160,10 +182,12 @@ def getRecdXmlMeshString(recd):
return writer.getvalue()
def _addRecdXmlAttrs(el, recd, forMeshTransmit):
+
el.setAttribute('type', str(recd.type))
if (recd.type == constants.TYPE_AUDIO) and (not forMeshTransmit):
aiPixbuf = recd.getAudioImagePixbuf()
+
if aiPixbuf:
aiPixbufString = str(utils.getStringFromPixbuf(aiPixbuf))
el.setAttribute('audioImage', aiPixbufString)
@@ -190,19 +214,23 @@ def _addRecdXmlAttrs(el, recd, forMeshTransmit):
el.setAttribute('version', '54')
pixbuf = recd.getThumbPixbuf()
+
if pixbuf:
thumb64 = str(utils.getStringFromPixbuf(pixbuf))
el.setAttribute('base64Thumb', thumb64)
def saveMediaHash(mediaHashs, activity):
+
impl = getDOMImplementation()
album = impl.createDocument(None, 'album', None)
root = album.documentElement
#flag everything for saving...
atLeastOne = False
+
for type, value in constants.MEDIA_INFO.items():
typeName = value['name']
+
for recd in mediaHashs[type]:
recd.savedXml = False
recd.savedMedia = False
@@ -212,6 +240,7 @@ def saveMediaHash(mediaHashs, activity):
if atLeastOne:
for type, value in constants.MEDIA_INFO.items():
typeName = value['name']
+
for recd in mediaHashs[type]:
mediaEl = album.createElement(typeName)
root.appendChild(mediaEl)
@@ -220,14 +249,17 @@ def saveMediaHash(mediaHashs, activity):
return album
def _saveMedia(el, recd, activity):
+
if recd.buddy == True and recd.datastoreId == None and not recd.downloadedFromBuddy:
recd.savedMedia = True
_saveXml(el, recd)
+
else:
recd.savedMedia = False
_saveMediaToDatastore(el, recd, activity)
def _saveXml(el, recd):
+
_addRecdXmlAttrs(el, recd, False)
recd.savedXml = True
@@ -240,9 +272,11 @@ def _saveMediaToDatastore(el, recd, activity):
#However, they might have changed the name of the file
if recd.metaChange:
recd.datastoreOb = getMediaFromDatastore(recd)
+
if recd.datastoreOb.metadata['title'] != recd.title:
recd.datastoreOb.metadata['title'] = recd.title
datastore.write(recd.datastoreOb)
+
if recd.datastoreOb.metadata['tags'] != recd.tags:
recd.datastoreOb.metadata['tags'] = recd.tags
datastore.write(recd.datastoreOb)
@@ -264,6 +298,7 @@ def _saveMediaToDatastore(el, recd, activity):
datastorePreviewPixbuf = recd.getThumbPixbuf()
if recd.type == constants.TYPE_AUDIO:
datastorePreviewPixbuf = recd.getAudioImagePixbuf()
+
elif recd.type == constants.TYPE_PHOTO:
datastorePreviewFilepath = recd.getMediaFilepath()
datastorePreviewPixbuf = GdkPixbuf.Pixbuf.new_from_file(datastorePreviewFilepath)
@@ -271,8 +306,11 @@ def _saveMediaToDatastore(el, recd, activity):
if datastorePreviewPixbuf:
datastorePreviewWidth = 300
datastorePreviewHeight = 225
+
if datastorePreviewPixbuf.get_width() != datastorePreviewWidth:
- datastorePreviewPixbuf = datastorePreviewPixbuf.scale_simple(datastorePreviewWidth, datastorePreviewHeight, GdkPixbuf.InterpType.NEAREST)
+ datastorePreviewPixbuf = datastorePreviewPixbuf.scale_simple(
+ datastorePreviewWidth, datastorePreviewHeight,
+ GdkPixbuf.InterpType.NEAREST)
datastorePreviewBase64 = utils.getStringFromPixbuf(datastorePreviewPixbuf)
mediaObject.metadata['preview'] = datastorePreviewBase64