Author: duncan
Date: Sun Feb 18 10:49:40 2007
New Revision: 9232

Added:
   branches/rel-1/freevo/src/audio/plugins/album_tree.py   (contents, props 
changed)
Modified:
   branches/rel-1/freevo/ChangeLog
   branches/rel-1/freevo/Docs/CREDITS
   branches/rel-1/freevo/local_conf.py.example

Log:
[ 1662741 ] Audio Albumtree Plugin
Plugin from Martijn Voncken added


Modified: branches/rel-1/freevo/ChangeLog
==============================================================================
--- branches/rel-1/freevo/ChangeLog     (original)
+++ branches/rel-1/freevo/ChangeLog     Sun Feb 18 10:49:40 2007
@@ -22,6 +22,7 @@
  * Replaced mmpython with kaa.base and kaa.metadata (F#1580712)
  * Replaced PIL with kaa.imlib2 (F#1580712)
  * New apple trailers plugin (disabled by default) (F#1580418)
+ * New audio album tree 
http://freevo.sourceforge.net/cgi-bin/doc/PluginAudioAlbumTree (F#1662741)
  * New Bluetooth phone support to act as a remote control (F#1622143)
  * New buttonbar plug-in that displays buttons on the bottom of the screen 
(F#1633140)
  * New CD/DVD burn plug-in added (F#1605919)

Modified: branches/rel-1/freevo/Docs/CREDITS
==============================================================================
--- branches/rel-1/freevo/Docs/CREDITS  (original)
+++ branches/rel-1/freevo/Docs/CREDITS  Sun Feb 18 10:49:40 2007
@@ -60,6 +60,9 @@
 Occasional contributors:
 ------------------------
 
+Martijn Voncken <[EMAIL PROTECTED]>
+o Album tree audio plug-in
+
 Adam Charrett <[EMAIL PROTECTED]>
 o Buttonbar plug-in
 o Screensaver plug-in

Modified: branches/rel-1/freevo/local_conf.py.example
==============================================================================
--- branches/rel-1/freevo/local_conf.py.example (original)
+++ branches/rel-1/freevo/local_conf.py.example Sun Feb 18 10:49:40 2007
@@ -1087,8 +1087,9 @@
 # This will enable only new episodes to be recorded
 # ONLY_NEW_DETECTION = True
 
-#
+# 
================================================================================
 # Watching TV
+# 
================================================================================
 #
 # XXX You must change this to fit your local conditions!
 #
@@ -1113,6 +1114,10 @@
 # TV_DEVICE = '/dev/video0'
 # TV_INPUT = 0
 # 
+# 
================================================================================
+# Listening to radio
+# 
================================================================================
+#
 # Radio device default is None, /dev/video24 for ivtv
 # RADIO_DEVICE = '/dev/radio'
 
@@ -1558,3 +1563,16 @@
 # AMAZON_QUERY_ENCODING = 'latin-1'
 # plugin.activate('audio.coversearch')
 
+# plugin.activate('audio.album_tree')
+# see http://freevo.sourceforge.net/cgi-bin/doc/PluginAudioAlbumTree
+# AUDIO_ALBUM_TREE_SPEC = []
+# AUDIO_ALBUM_TREE_SPEC.append({'name':'Artist/Album/Track'
+#      ,'spec':["artist","album","track||'-'||title"]
+#      ,'alt_grouping':[None,None,'track']
+#     })
+# AUDIO_ALBUM_TREE_SPEC.append({'name':'(A-Z)/Artist/Album-Year/Track'
+#     ,'spec':["upper(substr(artist,0,1))"
+#             ,"artist","album||'-'||year"
+#             ,"track||'-'||title"]
+#     ,'alt_grouping':[None,None,'year||album','track']
+#     })

Added: branches/rel-1/freevo/src/audio/plugins/album_tree.py
==============================================================================
--- (empty file)
+++ branches/rel-1/freevo/src/audio/plugins/album_tree.py       Sun Feb 18 
10:49:40 2007
@@ -0,0 +1,353 @@
+# -*- coding: iso-8859-1 -*-
+# -----------------------------------------------------------------------
+# album_tree.py 0.5.1 plugin for the audio player
+# -----------------------------------------------------------------------
+# $Id$
+# Author:      Martijn Voncken(2005)
+# Todo:        need more(all) tags in the database(mmpython->extendedmeta)
+#              gui:the bar on the left is gone?
+#              couldn't figure out how to use playlist.Playlist() object.
+# -----------------------------------------------------------------------
+# Freevo - A Home Theater PC framework
+# Copyright (C) 2002 Krister Lagerstrom, et al. 
+# Please see the file freevo/Docs/CREDITS for a complete list of authors.
+#
+# 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 MER-
+# CHANTABILITY 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 config
+import plugin
+import menu
+import rc #what is rc??
+#import audio.player
+
+from event import *
+from util.dbutil import *
+db = MetaDatabase()
+
+import freevo.playlist as playlist #namespaces :( not the playlist-pligin
+from audio import audioitem
+from gui import ProgressBox
+
+class treeSpec(object):
+    """
+    see: PluginInterface() below for freevo plugin doc.
+    this class contains no freevo specific code 
+    Inspired by foobar2000 albumlist (NOT playlist tree)    
+    (http://www.hydrogenaudio.org/forums/index.php?showforum=28)
+    This is a tree/not a playlist generator.
+    generates ugly sql(only as ugly as the spec),but sqlite is fast enough.    
+    operates directly on a sqlite cursor.    
+    see http://www.sqlite.org/lang_expr.html for "scripting" functions 
+    """
+    def __init__(self,name='unnamed',cursor=None,spec=None,alt_grouping=None):
+        self.spec = spec
+        self.name = name
+        self.alt_grouping = alt_grouping
+        self.cursor = cursor
+        
+    def get_query(self,data):
+        """
+        builds query        
+        """
+        
+        where = []
+        for i,item in enumerate(self.spec):
+            if i < len(data):
+                where.append('%s="%s"' % (item,data[i]))
+            else:
+                break        
+        if where:
+            wheresql = ' where ' + ' and '.join(where)
+        else:
+            wheresql = ''
+                
+        #group by:        
+        grouping = self.spec[i]
+        if self.alt_grouping and self.alt_grouping[i]:
+            grouping = self.alt_grouping[i]
+            
+        #last level in tree-->,no-count ; use path,filename + order by instead 
of group by
+        if len(self.spec) -1 == len(data):            
+            query = 'select %s,path,filename from music'% (self.spec[i],)
+            query += wheresql
+            query += ' order by ' + grouping
+        #normal/not last level in tree
+        else:            
+            query = 'select %s,count() from music'% (self.spec[i],)
+            query += wheresql
+            query += ' group by %s order by %s'  % (grouping,grouping)
+            
+        
+        return query     
+        
+    def execute(self,data):
+        self.cursor.execute(self.get_query(data))
+        return list(self.cursor) 
+        #should return an iterator/generator instead of a list?
+        #dont confuse others/need count for progress -->return list
+
+class PluginInterface(plugin.MainMenuPlugin):
+    """
+album_tree v0.51
+http://freevo.sourceforge.net/cgi-bin/doc/PluginAudioAlbumTree
+= Summary =
+Plugin to browse songs in a tree-like way.
+
+Requires pysqlite.   
+
+Tested on freevo 1.5.3 and a 12.000 mp3/6.0 MB database.
+
+= Pre Installation =
+
+The sqlite-meta-database should be available.
+
+The audio.rating and audio.logger plugin allso use this database
+,you can skip the rest of the pre-install if those plugins 
+are already succesfully installed. 
+
+ *install pysqlite,sqlite
+ *edit your local_config.py : Configure AUDIO_ITEMS 
+ ('''AudioConfig''' ,don't leave it at the default!)
+ *run {{{freevo cache}}}
+ *wait.....
+ *The meta database should be available now.
+          
+= Installation =
+
+ *Download freevo-audio-album-tree-0.x.x.tgz
+ *{{{
+tar -zxvf freevo-audio-album-tree-0.x.x.tgz
+cd freevo-audio-album-tree0.x.x
+python setup.py
+}}}
+
+= Configuration =
+
+     Edit your local_config.py and add this:
+{{{
+plugin.activate('audio.album_tree')
+AUDIO_ALBUM_TREE_SPEC = []
+
+#You could add all trees below:, but probably you only want 1 or 2 of them:
+AUDIO_ALBUM_TREE_SPEC.append({'name':'Artist/Album/Track'
+     ,'spec':["artist","album","track||'-'||title"]
+     ,'alt_grouping':[None,None,'track']
+    })
+#A case sensitive tree like above...
+#Is easy to convert to a convert to a case insensitive tree like below:
+AUDIO_ALBUM_TREE_SPEC.append({'name':'nocase:artist/album/Track'
+     ,'spec':["lower(artist)","lower(album)","track||'-'||title"]
+     ,'alt_grouping':[None,None,'track']
+    })
+
+#my favorite layout:
+AUDIO_ALBUM_TREE_SPEC.append({'name':'(A-Z)/Artist/Album-Year/Track'
+    ,'spec':["upper(substr(artist,0,1))"
+            ,"artist","album||'-'||year"
+            ,"track||'-'||title"]
+    ,'alt_grouping':[None,None,'year||album','track']
+    })
+
+#you can comment out a tree definition like this:
+#AUDIO_ALBUM_TREE_SPEC.append({'name':'Artist-Album/Track'
+#    ,'spec':["artist||'-'||album","track||'-'||title"]
+#    ,'alt_grouping':[None,'track']
+#    })
+
+#More Examples:
+AUDIO_ALBUM_TREE_SPEC.append({'name':'Year/Artist-Album/Track'
+    ,'spec':["year","artist||'-'||album","track||'-'||title"]
+    ,'alt_grouping':[None,None,None,'track']
+    })
+
+AUDIO_ALBUM_TREE_SPEC.append({'name':'Dirtitle/Artist/Album/Track'
+    ,'spec':["dirtitle","artist","album","track||'-'||title"]
+    ,'alt_grouping':[None,None,None,'track']
+    })
+
+#see http://www.sqlite.org/lang_expr.html for "scripting" functions
+}}}
+
+= Post Installation =
+New plugins are not immediately visible on the freevo webserver.
+
+You might want to restart the  [wiki:Webserver freevo webserver] after the 
installation of a new plugin.
+    """
+    def __init__(self):        
+        plugin.MainMenuPlugin.__init__(self)        
+        #config.EVENTS['audio']['DISPLAY'] = Event(FUNCTION_CALL, 
arg=self.detach)
+        self.show_item = menu.MenuItem(_('Album 
Tree'),action=self.onchoose_main)
+        self.show_item.type = 'audio'
+        plugin.register(self,'audio.album_tree')
+               
+        if (not config.__dict__.has_key('AUDIO_ALBUM_TREE_SPEC') ) or  (not 
config.AUDIO_ALBUM_TREE_SPEC):
+            print '*ALBUM_TREE:"config.AUDIO_ALBUM_TREE_SPEC" is 
empty:DEMO-MODE:USING PREDEFINED TREES'
+            self.load_demo()
+        else:
+            self.load_spec(config.AUDIO_ALBUM_TREE_SPEC)
+            
+    def load_spec(self,spec_list):
+        """
+        load definitions from config
+        """
+        curs = db.cursor
+        self.album_tree_list = []
+        for specdef in spec_list:
+            tree = treeSpec(specdef['name'],curs,specdef['spec'])
+            if specdef.has_key('alt_grouping'):
+                tree.alt_grouping = specdef['alt_grouping']
+            self.album_tree_list.append(tree)
+        
+    def load_demo(self):
+        """
+        load predefined testing layout
+        """
+        curs = db.cursor
+        self.album_tree_list = [        
+        treeSpec('Artist/Album/Track',curs
+                ,["artist","album","track||'-'||title"],[None,None,'track'])
+
+        ,treeSpec('(A-Z)/Artist/Year-Album/Track',curs
+        ,["upper(substr(artist,0,1))",
+        "artist","album||'-'||year"
+        ,"track||'-'||title"],[None,None,'year||album','track'])
+
+
+        ,treeSpec('Artist-Album/Track',curs
+                ,["artist||'-'||album","track||'-'||title"],[None,'track'])
+                
+        ,treeSpec('a-z/artist/title-album-track',curs
+                ,["lower(substr(artist,0,1))"
+                ,"lower(artist)","title||'-'||album||'-'||track"])
+                
+        ,treeSpec('Year/Artist-Album/Track',curs,
+                ["year","artist||'-'||album","track||'-'||title"]
+                ,[None,None,None,'track'])
+        #demo:
+        ,treeSpec('Dirtitle/Artist/Album/Track',curs
+            ,["dirtitle","artist","album","track||'-'||title"]
+            ,[None,None,None,'track'])
+                
+        ]
+        
+        #treespec below:
+        #INSANE,but this is what i like about foobar2000.
+        #NOT YET POSSIBLE, "album_artist" tag is not in sql database.
+        #Surprisingly:sqlite can handle it pretty fast.
+        #treeSpec('a-z/album_artist/album/track-(artist)-title',curs
+        #        ,["lower(substr(ifnull(album_artist,artist),0,1))",
+        #           "ifnull(album_artist,artist)"
+        #           
,"album","track||'-'||nullif(artist,ifnull(album_artist,artist))||'-'||title"]
+        #           ,[None,None,None,None,'track'])
+        
+
+    def items(self, parent):
+        return [ self.show_item ]
+
+    def actions(self):
+        #todo: add random 10 etc..
+        return []
+    
+    def onchoose_main(self,arg=None, menuw=None):
+        """
+        main menu
+        """
+        #
+        items = []
+        for tree in self.album_tree_list:
+            items.append(menu.MenuItem(tree.name
+                ,action=self.onchoose_node,arg=[tree,[]]) )
+
+        myobjectmenu = menu.Menu(_('Album Tree'), items,
+                                 reload_func=menuw.back_one_menu )
+        rc.app(None)
+        menuw.pushmenu(myobjectmenu)
+        menuw.refresh()
+
+    def onchoose_node(self,arg=None, menuw=None):
+        """
+        browse through a tree specification
+        """
+        tree = arg[0]
+        data = arg[1]
+        title = '-'.join(data)
+
+        mylistofitems =  []           
+        
+        if len(tree.spec) -1 <> len(data): #non-tracks
+            for tree_item,count in tree.execute(data):
+                mylistofitems.append(                 
+                    menu.MenuItem("%s(%i)" % (tree_item ,count)
+                    ,action=self.onchoose_node,arg=[tree,data + [tree_item]]))
+        else: #tracks
+            self.onchoose_last_node(tree,data,menuw)
+            return
+        
+        #should be impossible?
+        if (len(mylistofitems) == 0):
+            mylistofitems += [menu.MenuItem(_('No Objects found'),
+                              menuw.back_one_menu, 0)]
+
+        myobjectmenu = menu.Menu(title, mylistofitems)
+                                 #reload_func=menuw.back_one_menu )
+        rc.app(None)
+        menuw.pushmenu(myobjectmenu)
+        menuw.refresh()
+        
+    def onchoose_last_node(self,tree,data,menuw):
+        """
+        last node in tree generates a playlist.
+        """
+        title = '-'.join(data)
+        #creating of audio items is slow.
+        #need a progress-bar.
+        pl = playlist.Playlist(
+                name='-'.join(data)
+                ,playlist=[]
+                ,display_type='audiocd') 
+        
+        tracks = tree.execute(data)  #returns list of (desc,path,filename)     
  
+
+
+        pop = ProgressBox(text=_('Generating playlist...'), full=len(tracks))
+        pop.show()                                           
+        items = []
+        i = 0
+        for desc,path,filename in tracks:
+            filepath = os.path.join(path,filename)
+            item = audioitem.AudioItem(filepath,parent=pl)
+            item.name = desc
+            item.track = i
+            items.append( item)        
+            pop.tick()
+            i+=1
+        pop.destroy()
+        
+        pl.playlist = items 
+        
+        #note/question for core developers:
+        #command below causes strange errors?
+        #plugin.__plugin_type_list__ is empty??? but it's Not?
+        #pl.browse(arg=None,menuw=menuw)
+        #print 'LIST=',plugin.__plugin_type_list__['mimetype']
+        #workaround: not all features of a real playlist :(
+        
+        mymenu = menu.Menu(title, pl.playlist,item_types="audio")
+        menuw.pushmenu(mymenu)
+
+
+

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to