Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/model.py
diff options
context:
space:
mode:
Diffstat (limited to 'model.py')
-rw-r--r--model.py403
1 files changed, 403 insertions, 0 deletions
diff --git a/model.py b/model.py
new file mode 100644
index 0000000..d2c5ade
--- /dev/null
+++ b/model.py
@@ -0,0 +1,403 @@
+# -*- coding: UTF-8 -*-
+#Copyright (c) 2008, Media Modifications Ltd.
+
+#Permission is hereby granted, free of charge, to any person obtaining a copy
+#of this software and associated documentation files (the "Software"), to deal
+#in the Software without restriction, including without limitation the rights
+#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+#copies of the Software, and to permit persons to whom the Software is
+#furnished to do so, subject to the following conditions:
+
+#The above copyright notice and this permission notice shall be included in
+#all copies or substantial portions of the Software.
+
+#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+#THE SOFTWARE.
+
+from gettext import gettext as _
+from xml.dom.minidom import parse
+import logging
+import uuid
+import os
+import time
+import json
+
+import gobject
+import gst
+
+import sugar.profile
+import sugar.env
+
+
+import constants
+from instance import Instance
+from recorded import Recorded
+import utils
+import serialize
+from collab import RecordCollab
+from glive import Glive
+from gplay import Gplay
+
+logger = logging.getLogger('model')
+
+class Model:
+ def __init__(self, activity_obj):
+ self.activity = activity_obj
+
+ self.collab = RecordCollab(self.activity, self)
+ self.glive = Glive(self.activity, self)
+ self.gplay = Gplay(self.activity)
+ self.gplay.connect('playback-status-changed', self._playback_status_changed)
+
+ self._mode = None
+ self._state = constants.STATE_READY
+ self._countdown_value = 0
+ self._countdown_handle = None
+ self._timer_value = 0
+ self._timer_duration = 0
+ self._timer_handle = None
+
+ self.mediaHashs = {}
+ for key, value in constants.MEDIA_INFO.items():
+ self.mediaHashs[key] = []
+
+ def write_file(self, path):
+ ui_serialized = self.activity.serialize()
+ self.mediaHashs['ui'] = ui_serialized
+ dom = serialize.saveMediaHash(self.mediaHashs, self.activity)
+ ui_data = json.dumps(ui_serialized)
+ ui_el = dom.createElement('ui')
+ ui_el.appendChild(dom.createTextNode(ui_data))
+ dom.documentElement.appendChild(ui_el)
+
+ fd = open(path, "w")
+ dom.writexml(fd)
+ fd.close()
+
+ def read_file(self, path):
+ try:
+ dom = parse(path)
+ except Exception, e:
+ logger.error('read_file: %s' % e)
+ return
+
+ serialize.fillMediaHash(dom, self.mediaHashs)
+ for i in dom.documentElement.getElementsByTagName('ui'):
+ for ui_el in i.childNodes:
+ self.activity.deserialize(json.loads(ui_el.data))
+
+ for recd in self.mediaHashs[self._mode]:
+ self.activity.add_thumbnail(recd, True)
+
+ def get_has_camera(self):
+ return self.glive.get_has_camera()
+
+ def get_nickname(self):
+ return sugar.profile.get_nick_name()
+
+ def get_mode(self):
+ return self._mode
+
+ def change_mode(self, mode):
+ if mode == self._mode:
+ return
+
+ self._mode = mode
+
+ self.activity.remove_all_thumbnails()
+ for recd in self.mediaHashs[mode]:
+ self.activity.add_thumbnail(recd, True)
+
+ #self.activity.set_mode(mode)
+ self.set_state(constants.STATE_READY)
+
+ if mode == constants.MODE_PHOTO:
+ self.glive.play()
+
+ def ui_frozen(self):
+ return not self._state == constants.STATE_READY
+
+ def set_state(self, state):
+ self._state = state
+
+ if state == constants.STATE_READY:
+ self.gplay.stop()
+
+ # if we aren't using Xv (e.g. glive is playing as PIP in video
+ # mode), then stop the pipeline so that we switch back to Xv
+ # in the call that follows.
+ if self.glive.get_has_camera() and not self.glive.is_using_xv():
+ self.glive.stop()
+
+ self.glive.play()
+
+ self.activity.set_state(state)
+
+ def get_state(self):
+ return self._state
+
+ def set_progress(self, value, text):
+ self.activity.set_progress(value, text)
+
+ def _timer_tick(self):
+ self._timer_value = self._timer_value - 1
+ value = self._timer_value
+ progress_value = 1 - (float(value) / float(self._timer_duration))
+
+ mins = value / 60
+ secs = value % 60
+ text = _('%d:%02d remaining') % (mins, secs)
+
+ self.set_progress(progress_value, text)
+
+ if self._timer_value <= 0:
+ self._timer_handle = None
+ self._timer_value = 0
+ self._stop_media_capture()
+ return False
+
+ return True
+
+ def _start_media_capture(self):
+ if self._mode == constants.MODE_PHOTO:
+ self.activity.set_shutter_sensitive(False)
+ self.glive.take_photo()
+ return
+
+ #self._timer_value = self.activity.get_selected_duration()
+ #self._timer_duration = self._timer_value
+ #self._timer_handle = gobject.timeout_add(1000, self._timer_tick)
+
+ #self.activity.set_shutter_sensitive(True)
+ #self.set_state(constants.STATE_RECORDING)
+
+ if self._mode == constants.MODE_VIDEO:
+ quality = self.activity.get_selected_quality()
+ self.glive.record_video(quality)
+ elif self._mode == constants.MODE_AUDIO:
+ self.glive.record_audio()
+
+ def _stop_media_capture(self):
+ if self._timer_handle:
+ gobject.source_remove(self._timer_handle)
+ self._timer_handle = None
+ self._timer_value = 0
+
+ self.set_progress(0, '')
+
+ if self._mode == constants.MODE_VIDEO:
+ self.glive.stop_recording_video()
+ elif self._mode == constants.MODE_AUDIO:
+ self.glive.stop_recording_audio()
+
+ self.set_state(constants.STATE_PROCESSING)
+
+
+
+ def _countdown_tick(self):
+ self._countdown_value = self._countdown_value - 1
+ value = self._countdown_value
+ self.activity.set_countdown(value)
+
+ if value <= 0:
+ self._countdown_handle = None
+ self._countdown_value = 0
+ self.shutter_sound(self._start_media_capture)
+ return False
+
+ return True
+
+ def do_shutter(self):
+ # if recording, stop
+ if self._state == constants.STATE_RECORDING:
+ self._stop_media_capture()
+ return
+
+ # if timer is selected, start countdown
+ #timer = self.activity.get_selected_timer()
+ #if timer > 0:
+ # self.activity.set_shutter_sensitive(False)
+ #self._countdown_value = self.activity.get_selected_timer()
+ # self._countdown_handle = gobject.timeout_add(1000, self._countdown_tick)
+ #return
+
+ # otherwise, capture normally
+ self._start_media_capture()
+
+ # called from gstreamer thread
+ def still_ready(self, pixbuf):
+ gobject.idle_add(self.activity.show_still, pixbuf)
+
+ def add_recd(self, recd):
+ self.mediaHashs[recd.type].append(recd)
+ if self._mode == recd.type:
+ self.activity.add_thumbnail(recd, True)
+
+ if not recd.buddy:
+ self.collab.share_recd(recd)
+
+ # called from gstreamer thread
+ def save_photo(self, pixbuf):
+ recd = self.createNewRecorded(constants.TYPE_PHOTO)
+
+ imgpath = os.path.join(Instance.instancePath, recd.mediaFilename)
+ pixbuf.save(imgpath, "jpeg")
+
+ pixbuf = utils.generate_thumbnail(pixbuf)
+ pixbuf.save(recd.make_thumb_path(), "png")
+
+ #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)
+
+ # called from gstreamer thread
+ def save_video(self, path, still):
+ recd = self.createNewRecorded(constants.TYPE_VIDEO)
+ os.rename(path, os.path.join(Instance.instancePath, recd.mediaFilename))
+
+ still = utils.generate_thumbnail(still)
+ still.save(recd.make_thumb_path(), "png")
+
+ self.createNewRecordedMd5Sums( recd )
+
+ gobject.idle_add(self.add_recd, recd, priority=gobject.PRIORITY_HIGH)
+ gobject.idle_add(self.set_state, constants.STATE_READY)
+
+ def save_audio(self, path, still):
+ recd = self.createNewRecorded(constants.TYPE_AUDIO)
+ os.rename(path, os.path.join(Instance.instancePath, recd.mediaFilename))
+
+ if still:
+ image_path = os.path.join(Instance.instancePath, "audioPicture.png")
+ image_path = utils.getUniqueFilepath(image_path, 0)
+ still.save(image_path, "png")
+ recd.audioImageFilename = os.path.basename(image_path)
+
+ still = utils.generate_thumbnail(still)
+ still.save(recd.make_thumb_path(), "png")
+
+ self.createNewRecordedMd5Sums( recd )
+
+ gobject.idle_add(self.add_recd, recd, priority=gobject.PRIORITY_HIGH)
+ gobject.idle_add(self.set_state, constants.STATE_READY)
+
+ def _playback_status_changed(self, widget, status, value):
+ self.activity.set_playback_scale(value)
+ if status == gst.STATE_NULL:
+ self.activity.set_paused(True)
+
+ def play_audio(self, recd):
+ self.gplay.set_location("file://" + recd.getMediaFilepath())
+ self.gplay.play()
+ self.activity.set_paused(False)
+
+ def play_video(self, recd):
+ self.gplay.set_location("file://" + recd.getMediaFilepath())
+ self.glive.stop()
+ self.gplay.play()
+ self.glive.play(use_xv=False)
+ self.activity.set_paused(False)
+
+ def play_pause(self):
+ if self.gplay.get_state() == gst.STATE_PLAYING:
+ self.gplay.pause()
+ self.activity.set_paused(True)
+ else:
+ self.gplay.play()
+ 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):
+ for mh in self.mediaHashs.values():
+ for recd in mh:
+ if recd.thumbMd5 == md5 or recd.mediaMd5 == md5:
+ return recd
+
+ return None
+
+ def createNewRecorded(self, type):
+ recd = Recorded()
+
+ recd.recorderName = self.get_nickname()
+ recd.recorderHash = Instance.keyHashPrintable
+
+ #to create a file, use the hardware_id+time *and* check if available or not
+ nowtime = int(time.time())
+ recd.time = nowtime
+ recd.type = type
+
+ mediaThumbFilename = str(recd.recorderHash) + "_" + str(recd.time)
+ mediaFilename = mediaThumbFilename
+ mediaFilename = mediaFilename + "." + constants.MEDIA_INFO[type]['ext']
+ mediaFilepath = os.path.join( Instance.instancePath, mediaFilename )
+ mediaFilepath = utils.getUniqueFilepath( mediaFilepath, 0 )
+ recd.mediaFilename = os.path.basename( mediaFilepath )
+
+ stringType = constants.MEDIA_INFO[type]['istr']
+
+ # Translators: photo by photographer, e.g. "Photo by Mary"
+ recd.title = _('%s by %s') % (stringType, recd.recorderName)
+
+ color = sugar.profile.get_color()
+ recd.colorStroke = color.get_stroke_color()
+ recd.colorFill = color.get_fill_color()
+
+ logger.debug('createNewRecorded: ' + str(recd))
+ return recd
+
+ def createNewRecordedMd5Sums( self, recd ):
+ recd.thumbMd5 = recd.mediaMd5 = str(uuid.uuid4())
+
+ #load the thumbfile
+ if recd.thumbFilename:
+ thumbFile = os.path.join(Instance.instancePath, recd.thumbFilename)
+ recd.thumbBytes = os.stat(thumbFile)[6]
+
+ recd.tags = ""
+
+ #load the mediafile
+ mediaFile = os.path.join(Instance.instancePath, recd.mediaFilename)
+ mBytes = os.stat(mediaFile)[6]
+ recd.mediaBytes = mBytes
+
+ def delete_recd(self, recd):
+ recd.deleted = True
+ self.mediaHashs[recd.type].remove(recd)
+
+ if recd.meshUploading:
+ return
+
+ #remove files from the filesystem if not on the datastore
+ if recd.datastoreId == None:
+ mediaFile = recd.getMediaFilepath()
+ if os.path.exists(mediaFile):
+ os.remove(mediaFile)
+
+ thumbFile = recd.getThumbFilepath()
+ if thumbFile and os.path.exists(thumbFile):
+ os.remove(thumbFile)
+ else:
+ #remove from the datastore here, since once gone, it is gone...
+ serialize.removeMediaFromDatastore(recd)
+
+ def request_download(self, recd):
+ self.activity.show_still(recd.getThumbPixbuf())
+ self.set_state(constants.STATE_DOWNLOADING)
+ self.collab.request_download(recd)
+ self.activity.update_download_progress(recd)
+