a rather silly shelve-based tagging thing, commiting before I scrap the code and start over with SQLite
authorterom
Wed, 16 Jan 2008 16:28:00 +0000
changeset 20 6c774496bb00
parent 19 8d3ffd87cb0b
child 21 b75f9514e797
a rather silly shelve-based tagging thing, commiting before I scrap the code and start over with SQLite
de-cgi-bin/tags.py
lib/req.py
lib/shorturl.py
lib/tags.py
lib/utils.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/de-cgi-bin/tags.py	Wed Jan 16 16:28:00 2008 +0000
@@ -0,0 +1,93 @@
+#!/usr/bin/env python2.4
+#
+# DeGAL - A pretty simple web image gallery
+# Copyright (C) 2007 Tero Marttila
+# http://marttila.de/~terom/degal/
+#
+# 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, write to the
+# Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+
+import cgi
+
+import inc
+from lib import tags, template, req, shorturl, utils, settings
+
+tag_list = [tag for tag in req.get_str("tags", "").split("/") if tag]
+
+tag_db = tags.TagDB()
+shorturl_db = shorturl.DB()
+
+root = len(tag_list) + 1
+
+class Tag (object) :
+    def __init__ (self, name, count) :
+        self.title = "%s (%d)" % (name, count)
+        self.name = utils.url(name, trailing=True)
+
+class TagView (object) :
+    def __init__ (self, tag_list) :
+        img_codes = tag_db.imgs(tag_list)
+        more_tags = tag_db.tags(tag_list)
+
+        self.images = []
+
+        for index, key in enumerate(img_codes) :
+            dir, fname = shorturl_db.image_info(key)
+
+            img = Image(key, dir, fname, index)
+            self.images.append(img)
+
+        self.tags = [Tag(name, count) for (name, count) in more_tags]
+
+    def render (self) :
+        descr = ""
+        return template.gallery.render(
+            stylesheet_url      = utils.url("style.css", up=root),
+            
+            breadcrumb          = [(utils.url(up=root), "Index"), (utils.url(up=root-1), "Tags")] + [(utils.url(up=root-(n+1), trailing=True), tag) for n, tag in enumerate(tag_list)],
+
+            title               = "Tags :: %s" % (" » ".join(tag_list) or "All"),
+
+            num_pages           = 1,
+            cur_page            = 0,
+
+            dirs                = self.tags,
+            images              = self.images,
+
+            description         = descr,
+
+            shorturl            = None,
+            shorturl_code       = None,
+        )
+    
+class Image (object) :
+    def __init__ (self, key, dir, fname, index) :
+        self.fname = fname
+        self.name = utils.url_join(dir, fname, abs=True)
+        self.html_name = utils.url_join(dir, fname + ".html", abs=True)
+        self.thumb_name = utils.url_join(dir, settings.THUMB_DIR, fname, abs=True)
+        self.preview_name = utils.url_join(dir, settings.PREVIEW_DIR, fname, abs=True)
+
+        self.shorturl = key
+
+        self.prev = self.next = None
+
+tagview = TagView(tag_list)
+
+print "Content-Type: text/html"
+print
+print tagview.render()
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/req.py	Wed Jan 16 16:28:00 2008 +0000
@@ -0,0 +1,50 @@
+# DeGAL - A pretty simple web image gallery
+# Copyright (C) 2007 Tero Marttila
+# http://marttila.de/~terom/degal/
+#
+# 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, write to the
+# Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+
+import cgi
+import Cookie
+import os
+
+vars = cgi.FieldStorage()
+
+# the cookie with the user's current series
+cookie = Cookie.SimpleCookie(os.environ.get('HTTP_COOKIE', None))
+
+class token (object) :
+    pass
+
+REQUIRED_PARAM = token()
+
+def get_str (key, default=REQUIRED_PARAM) :
+    if key in vars :
+        return vars[key].value
+    elif default is REQUIRED_PARAM :
+        raise ValueError("Required param %s" % key)
+    else :
+        return default
+
+def get_int (key, default=REQUIRED_PARAM) :
+    if key in vars :
+        return int(vars[key].value)
+    elif default is REQUIRED_PARAM :
+        raise ValueError("Required param %s" % key)
+    else :
+        return default
+
--- a/lib/shorturl.py	Wed Jan 16 14:58:03 2008 +0000
+++ b/lib/shorturl.py	Wed Jan 16 16:28:00 2008 +0000
@@ -124,4 +124,22 @@
             raise ValueError("%s is not an img" % key)
 
         return dirpath, fname
+    
+    def shorturls_for (self, paths) :
+        ret = []
 
+        for key in self.db.keys() :
+            if key.startswith('_') :
+                continue
+
+            type, dir, fname = self.db[key]
+            path = os.path.join(dir.lstrip('.').lstrip('/'), fname) 
+            if path in paths :
+                ret.append(key)
+                paths.remove(path)
+        
+        if paths :
+            raise ValueError("Paths not found: %s" % " ".join(paths))
+
+        return ret
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/tags.py	Wed Jan 16 16:28:00 2008 +0000
@@ -0,0 +1,89 @@
+import shelve
+
+class TagDB (object) :
+    _imgs_cache = {}
+
+    def __init__ (self, read_only=True) :
+        self.img_tags = shelve.open("img_tags", read_only and 'r' or 'c')
+        self.tag_imgs = shelve.open("tag_imgs", read_only and 'r' or 'c')
+
+    def tag (self, img, tag) :
+        """
+            Associate the given image with the given tag
+        """
+
+        if img not in self.img_tags :
+            self.img_tags[img] = set([tag])
+        else :
+            s = self.img_tags[img]
+            s.add(tag)
+            self.img_tags[img] = s
+
+
+        if tag not in self.tag_imgs :
+            self.tag_imgs[tag] = set([img])
+        else :
+            s = self.tag_imgs[tag]
+            s.add(img)
+            self.tag_imgs[tag] = s
+
+        print "%s <-> %s" % (img, tag)
+    
+    def imgs (self, tags) :
+        """
+            Get the set of images that have the given set of tags
+        """
+
+        cache_key = "/".join(tags)
+        
+        if cache_key in self._imgs_cache :
+            return self._imgs_cache[cache_key]
+
+        if not tags :
+            return set(self.img_tags.keys())
+
+        img_sets = [self.tag_imgs[tag] for tag in tags]
+        
+        res = None
+
+        for img_set in img_sets :
+            if res :
+                res = res & img_set
+            else :
+                res = img_set
+
+        self._imgs_cache[cache_key] = res
+        
+        return res
+    
+    def tags (self, tags) :
+        """
+            Get the set of tags that are present in the set of images specified by these tags, sorted by count
+
+            This is currently implemented quite inefficiently... giev SQL db?
+        """
+        
+        imgs = self.imgs(tags)
+        
+        ret = []
+        
+        for tag in self.tag_imgs.keys() :
+            if tag in tags :
+                continue
+
+            count = len(self.tag_imgs[tag] & imgs)
+
+            if count :
+                ret.append((tag, count))
+
+        def my_cmp ((at, ac), (bt, bc)) :
+            return cmp((ac, at), (bc, bt))
+
+        ret.sort(reverse=True)
+
+        return ret
+    
+    def close (self) :
+        self.img_tags.close()
+        self.tag_imgs.close()
+
--- a/lib/utils.py	Wed Jan 16 14:58:03 2008 +0000
+++ b/lib/utils.py	Wed Jan 16 16:28:00 2008 +0000
@@ -47,8 +47,9 @@
 def url (*parts, **kwargs) :
     abs = kwargs.pop('abs', False)
     up = kwargs.pop('up', 0)
+    trailing = kwargs.pop('trailing', False)
     
-    return '/'.join(([""]*int(abs)) + ([".."]*up) + list(parts))
+    return '/'.join(([""]*int(abs)) + ([".."]*up) + list(parts) + ([""]*int(trailing)))
 
 url_join = url