Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/olpcfr/tools
diff options
context:
space:
mode:
Diffstat (limited to 'olpcfr/tools')
-rw-r--r--olpcfr/tools/__init__.py2
-rw-r--r--olpcfr/tools/_logger.py10
-rw-r--r--olpcfr/tools/_obj.py9
-rw-r--r--olpcfr/tools/image.py110
-rw-r--r--olpcfr/tools/registry.py48
-rw-r--r--olpcfr/tools/sound.py111
-rw-r--r--olpcfr/tools/storage.py150
7 files changed, 440 insertions, 0 deletions
diff --git a/olpcfr/tools/__init__.py b/olpcfr/tools/__init__.py
new file mode 100644
index 0000000..071fee0
--- /dev/null
+++ b/olpcfr/tools/__init__.py
@@ -0,0 +1,2 @@
+from olpcfr.tools._obj import obj
+from olpcfr.tools._logger import logger
diff --git a/olpcfr/tools/_logger.py b/olpcfr/tools/_logger.py
new file mode 100644
index 0000000..f8bb9bd
--- /dev/null
+++ b/olpcfr/tools/_logger.py
@@ -0,0 +1,10 @@
+
+# flask logger
+from olpcfr.flask import app, APP_NAME
+if app:
+ logger = app.logger
+# std logger
+else:
+ import logging
+ logger = logging.getLogger(APP_NAME)
+ logger.setLevel(logging.DEBUG)
diff --git a/olpcfr/tools/_obj.py b/olpcfr/tools/_obj.py
new file mode 100644
index 0000000..85c461a
--- /dev/null
+++ b/olpcfr/tools/_obj.py
@@ -0,0 +1,9 @@
+
+class obj(object):
+
+ def __init__(self, d):
+ for a, b in d.items():
+ if isinstance(b, (list, tuple)):
+ setattr(self, a, [obj(x) if isinstance(x, dict) else x for x in b])
+ else:
+ setattr(self, a, obj(b) if isinstance(b, dict) else b)
diff --git a/olpcfr/tools/image.py b/olpcfr/tools/image.py
new file mode 100644
index 0000000..cffc156
--- /dev/null
+++ b/olpcfr/tools/image.py
@@ -0,0 +1,110 @@
+
+# python import
+import logging, os, struct, StringIO
+
+# atoideweb import
+from atoideweb.tools import registry
+
+
+def compute_width_height(width, height, max_width, max_height, use_max=False):
+ # compute ratio
+ _ratio_scr = max_width / float(max_height)
+ _ratio_img = width / float(height)
+ # ..
+ if width > max_width\
+ or height > max_height:
+ if _ratio_img > _ratio_scr:
+ width = max_width
+ height = int(max_width / _ratio_img)
+ elif _ratio_img < _ratio_scr:
+ width = int(max_height * _ratio_img)
+ height = max_height
+ else:
+ width = max_width
+ height = max_height
+ # ..
+ return width, height
+ # ..
+ elif use_max is True:
+ return max_width, max_height
+ # ..
+ else:
+ return width, height
+
+
+def get_image_info(path):
+ """Tricky method found on Internet that returns the image info from a given
+ raw image data.
+ """
+ # little check
+ _info = registry.InfoRegistry().get_info(path)
+ # already exist
+ if _info is not None:
+ return _info
+ elif os.path.exists(path):
+ pass
+ else:
+ return None, 0, 0
+ # read file
+ _f = open(path)
+ _data = _f.read()
+ _f.close()
+ #
+ size = len(_data)
+ height = 0
+ width = 0
+ content_type = None
+
+ # handle GIFs
+ if (size >= 10) and _data[:6] in ('GIF87a', 'GIF89a'):
+ # Check to see if content_type is correct
+ content_type = 'image/gif'
+ w, h = struct.unpack("<HH", _data[6:10])
+ width = int(w)
+ height = int(h)
+
+ # See PNG 2. Edition spec (http://www.w3.org/TR/PNG/)
+ # Bytes 0-7 are below, 4-byte chunk length, then 'IHDR'
+ # and finally the 4-byte width, height
+ elif ((size >= 24) and _data.startswith('\211PNG\r\n\032\n')
+ and (_data[12:16] == 'IHDR')):
+ content_type = 'image/png'
+ w, h = struct.unpack(">LL", _data[16:24])
+ width = int(w)
+ height = int(h)
+
+ # Maybe this is for an older PNG version.
+ elif (size >= 16) and _data.startswith('\211PNG\r\n\032\n'):
+ # Check to see if we have the right content type
+ content_type = 'image/png'
+ w, h = struct.unpack(">LL", _data[8:16])
+ width = int(w)
+ height = int(h)
+
+ # handle JPEGs
+ elif (size >= 2) and _data.startswith('\377\330'):
+ content_type = 'image/jpeg'
+ jpeg = StringIO.StringIO(_data)
+ jpeg.read(2)
+ b = jpeg.read(1)
+ try:
+ while (b and ord(b) != 0xDA):
+ while (ord(b) != 0xFF): b = jpeg.read(1)
+ while (ord(b) == 0xFF): b = jpeg.read(1)
+ if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
+ jpeg.read(3)
+ h, w = struct.unpack(">HH", jpeg.read(4))
+ break
+ else:
+ jpeg.read(int(struct.unpack(">H", jpeg.read(2))[0])-2)
+ b = jpeg.read(1)
+ width = int(w)
+ height = int(h)
+ except struct.error:
+ pass
+ except ValueError:
+ pass
+ # udpate registry
+ registry.InfoRegistry().set_info(path, (content_type, width, height))
+ # ..
+ return content_type, width, height
diff --git a/olpcfr/tools/registry.py b/olpcfr/tools/registry.py
new file mode 100644
index 0000000..7e575c3
--- /dev/null
+++ b/olpcfr/tools/registry.py
@@ -0,0 +1,48 @@
+
+# python import
+import logging
+
+
+class Registry(object):
+
+ class __Singleton:
+ """Our singleton object.
+ """
+
+ def __init__(self):
+ """Create the new singleton for a simple use.
+ """
+ # ensure config
+ self.__dict = dict()
+
+ def get_info(self, path):
+ # ..
+ if path in self.__dict:
+ return self.__dict[path]
+ else:
+ return None
+
+ def set_info(self, path, info):
+ # clear previous
+ if path in self.__dict:
+ del self.__dict[path]
+ else:
+ pass
+ # ...
+ self.__dict[path] = info
+
+ # singleton instance
+ instance = None
+
+ def __new__(c, force=False):
+ """Singleton new init.
+ """
+ # if doesn't already initialized
+ if not Registry.instance \
+ or force is True:
+ # create a new instance
+ Registry.instance = Registry.__Singleton()
+ else:
+ pass
+ # return the manager object
+ return Registry.instance
diff --git a/olpcfr/tools/sound.py b/olpcfr/tools/sound.py
new file mode 100644
index 0000000..7ac6a57
--- /dev/null
+++ b/olpcfr/tools/sound.py
@@ -0,0 +1,111 @@
+
+# python import
+import gst
+# ..
+from datetime import timedelta
+
+
+class Player(object):
+
+ def __init__(self, loop=False):
+ # playing flag
+ self.playing = False
+ self.loop = loop
+ # player object
+ self.player = None
+ self._init_player()
+ # file to play
+ self._soundfile = None
+
+ def _reload_cb(self, bus, message):
+ if self.loop is True:
+ self.player.set_state(gst.STATE_READY)
+ self.player.set_state(gst.STATE_PLAYING)
+ else:
+ pass
+
+ def _error_cb(self, bus, message):
+ self.player.set_state(gst.STATE_NULL)
+
+ def _init_player(self):
+ # make player
+ self.player = gst.element_factory_make("playbin", "player")
+ # video fake
+ _fakesink = gst.element_factory_make('fakesink', "my-fakesink")
+ self.player.set_property("video-sink", _fakesink)
+ # bus ..
+ bus = self.player.get_bus()
+ bus.add_signal_watch()
+ bus.connect('message::eos', self._reload_cb)
+ bus.connect('message::error', self._error_cb)
+
+ def serialize(self):
+ # little check
+ if self._soundfile is None:
+ return None
+ else:
+ return file(self._soundfile, 'r').read()
+
+ def load(self, soundfile):
+ # file to play
+ self._soundfile = soundfile
+ # little check
+ if self._soundfile is None:
+ pass
+ else:
+ # load sound file
+ self.player.set_state(gst.STATE_NULL)
+ self.player.set_property('uri', 'file://' + self._soundfile)
+
+ def get_position(self):
+ # little check
+ if self._soundfile is None:
+ return None
+ else:
+ # ...
+ _position = self.player.query_duration(gst.FORMAT_TIME)[0]
+ # ...
+ return timedelta(seconds=(_position / gst.SECOND))
+
+ def get_duration(self):
+ # little check
+ if self._soundfile is None:
+ return None
+ else:
+ # _duration = self.player.query_duration(gst.FORMAT_TIME)[0]
+ # ..
+ _parser = gst.parse_launch("filesrc name=source ! decodebin2 ! fakesink")
+ # ..
+ _source = _parser.get_by_name("source")
+ _source.set_property("location", self._soundfile)
+ # ..
+ _parser.set_state(gst.STATE_PLAYING)
+ _parser.get_state()
+ # ..
+ _format = gst.Format(gst.FORMAT_TIME)
+ _duration = _parser.query_duration(_format)[0]
+ _parser.set_state(gst.STATE_NULL)
+ # ..
+ return timedelta(seconds=(_duration / gst.SECOND))
+
+ def seek(self, time):
+ # little check
+ if self._soundfile is None:
+ return
+ else:
+ # format time
+ _seek = time * 1000000000
+ # do seek
+ self.player.seek_simple(gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, _seek)
+
+ def play(self):
+ self.playing = True
+ self.player.set_state(gst.STATE_PLAYING)
+
+ def pause(self):
+ self.playing = False
+ self.player.set_state(gst.STATE_PAUSED)
+
+ def stop(self):
+ self.playing = False
+ self.player.set_state(gst.STATE_NULL)
diff --git a/olpcfr/tools/storage.py b/olpcfr/tools/storage.py
new file mode 100644
index 0000000..3e6ebbf
--- /dev/null
+++ b/olpcfr/tools/storage.py
@@ -0,0 +1,150 @@
+# python import
+import os
+
+# olpcfr import
+from olpcfr import BUNDLE, ROOT
+
+
+ACTIVITY_NAMES = {
+ 'paint': 'org.laptop.Oficina',
+ 'record': 'org.laptop.RecordActivity',
+ }
+
+
+def check_dir(path):
+ if os.path.exists(path):
+ pass
+ else:
+ os.mkdir(path)
+
+
+def check_file(path):
+ if os.path.exists(path):
+ pass
+ else:
+ _f = open(path, 'wb')
+ _f.write('')
+ _f.close()
+
+
+def get_path(path=None, bundle=True):
+ # ..
+ path = 'static' if path is None else path
+ # ..
+ if bundle is True:
+ return os.path.join(BUNDLE, path)
+ else:
+ return os.path.join(ROOT, path)
+
+
+def list_dir(path=None, bundle=True):
+ # ..
+ path = get_path(path=path, bundle=bundle)
+ # ..
+ return os.listdir(path)
+
+
+def get_sound_path(filename, path=None, bundle=True, ext=None):
+ # ..
+ path = get_path(path=path, bundle=bundle)
+ filename = filename if ext is None else '%s.%s' % (filename, ext)
+ # ..
+ return os.path.join(path, filename)
+
+
+def get_sound_path(filename, path=None, bundle=True, ext='ogg'):
+ # ..
+ return get_sound_path(filename, path=path, bundle=bundle, ext=ext)
+
+
+def get_image_path(filename, path=None, bundle=True, ext='png'):
+ # ..
+ return get_sound_path(filename, path=path, bundle=bundle, ext=ext)
+
+
+def __do_query(query):
+ from sugar.datastore import datastore
+ # find in ds
+ _results, _count = datastore.find(query, sorting='timestamp')
+ for _r in _results:
+ # get meta
+ _m = _r.get_metadata()
+ if 'activity' in query:
+ yield _r
+ elif _m['activity'] == '':
+ yield _r
+ else:
+ continue
+
+
+def get_journal_objects(activity_name=None, mime_type=None):
+ # init
+ _query = dict()
+ # prepare query name
+ if activity_name is None\
+ and mime_type is None:
+ return []
+ elif mime_type is None:
+ return __do_query({'activity': ACTIVITY_NAMES[activity_name]})
+ else:
+ return __do_query({'mime_type': mime_type})
+
+
+def list_info_from_journal(activity_name=None, mime_type=None):
+ # get objects first
+ _objs = get_journal_objects(activity_name=activity_name, mime_type=mime_type)
+ # make unique titles
+ _titles = {}
+ # return infos
+ for _o in _objs:
+ # get meta
+ _m = _o.get_metadata()
+ # get title
+ _t = _m['title']
+ # ensure description
+ _d = _m['description'] if 'description' in _m else ''
+ _p = _m['preview'] if 'preview' in _m else None
+ # little check
+ if _t in _titles:
+ # udpate reg
+ _titles[_t] += 1
+ # update value to show
+ _t = '%s (%s)' % (_t, _titles[_t])
+ # init title reg
+ else:
+ _titles[_t] = 1
+ # ensure info
+ yield {
+ 'activity_id' : _m['activity_id'],
+ 'description' : _d,
+ 'timestamp' : _m['timestamp'],
+ 'preview' : _p,
+ 'title' : _t,
+ }
+
+
+def list_files_from_journal(activity_name=None, mime_type=None):
+ # get objects first
+ _objs = get_journal_objects(activity_name=activity_name,
+ mime_type=mime_type)
+ # return paths
+ for _o in _objs:
+ # TODO open the files
+ yield _o.get_file_path()
+
+
+def get_path_from_journal(timestamp, mime_type):
+ from sugar.datastore import datastore
+ # ..
+ _query = {
+ 'timestamp': int(timestamp),
+ 'mime_type': mime_type
+ }
+ # find in ds
+ _results, _count = datastore.find(_query)
+ # ..
+ if _count == 1:
+ # get path
+ return _results[0].get_file_path()
+ else:
+ return None