Source

FluidInYourEar / fluidocalypse / fluid_utils.py

# -*- coding: utf-8 -*-

import random

from django.core.cache import cache

from fom.errors  import Fluid404Error
from fom.mapping import Object, Namespace, Tag
from fom.session import Fluid

from django_fluidproxy import FluidAPIProxy


# Instantiate FluidDB connection
fluid = Fluid( "http://sandbox.fluidinfo.com" )
fluid.db.client.login( "test", "test" )
fluid.bind()

proxy = FluidAPIProxy( fluid )


# NOTE: If everything cached at same time on the search page needs to refresh at same time,
#       this would be SLOW: so set some randomly selected options
CACHE_TIMEOUTS = [ 60 * 60 * timeout for timeout in ( 1, 1, 2, 3, 5, 8, 13, 21 ) ]



def _get_value( path, urlargs=None ):
    """ Returns value at path - using local cache if possible """
    return proxy.get( path, urlargs, random.choice(CACHE_TIMEOUTS) )
    

class Band( object ):
    """ Encapsulates a band """
    def __init__( self, object_id ):
        self.object_id = object_id

    def __getattr__( self, name ):
        if name == "name":
            return _get_value( "/objects/%s/metaljoe/music/band_name" % self.object_id )
        
        elif name == "tag_paths":
            return _get_value( "/objects/%s" % self.object_id )["tagPaths"]
        
        raise AttributeError


class Genre( object ):
    """ Encapsulates a genre """
    def __init__( self, genre_tag ):
        self.description = cache.get( genre_tag )
        if not self.description:
            self.description = Tag( genre_tag ).description
            cache.set( genre_tag, self.description, random.choice(CACHE_TIMEOUTS) )


def get_genre( genre ):
    """ Returns Genre object for a given genre """
    return Genre( "metaljoe/music/genre/%s" % genre )


def is_known_band( band_name ):
    """ Returns True if recognised band, False if not """
    bands = _get_value( "/objects", urlargs={ "query": 'metaljoe/music/band_name = "%s"' % band_name } )

    if bands["ids"]:
        return True
    return False


def is_known_genre( genre ):
    """ Returns True if recognised genre, False if not """
    try:
        _ = _get_value( "/tags/metaljoe/music/genre/%s" % genre )
        return True
    except Fluid404Error:
        return False


def get_all_bands():
    """ Returns list of all known bands """
    # NOTE: monumentally slow
    response = _get_value( "/objects", urlargs={ "query": "has metaljoe/music/band_name" } )
    
    return sorted( [ Band( object_id ).name for object_id in response["ids"] ] )


def get_all_genres():
    """ Returns list of all known genres """
    # NOTE: slow
    return [ ( get_genre( tag ).description, tag ) for tag in sorted( Namespace( u"metaljoe/music/genre" ).tag_names ) ]


def get_band_information( band ):
    """ Returns dictionary of band information """
    response = _get_value( "/objects", urlargs={ "query": 'metaljoe/music/band_name = "%s"' % band } )

    band_info = { "related_bands" : [],
                  "related_genres": [],
                }

    for object_id in response[ "ids" ]:
        band_object = Band( object_id )
        for tag_path in band_object.tag_paths:
            if tag_path == "metaljoe/music/related_bands":
                path = "/objects/%s/%s" % ( object_id, tag_path )
                band_info[ "related_bands" ] = [ ( band_name, is_known_band(band_name) ) for band_name in _get_value( path ) ]
            elif tag_path.startswith( "metaljoe/music/genre" ):
                band_info[ "related_genres" ].append( ( tag_path[21:], Genre( tag_path ).description ) )
            elif tag_path == "metaljoe/music/source_url":
                band_info[ "source_url" ] = _get_value( "/objects/%s/%s" % ( object_id, tag_path ) )

    band_info[ "related_bands" ].sort()
    band_info[ "related_genres" ].sort()

    return band_info


def get_related_bands_for( genre ):
    """ Returns list of related bands for genre """
    bands = _get_value( "/objects", urlargs={ "query": "has metaljoe/music/genre/%s" % genre } )

    related_bands = []
    for object_id in bands["ids"]:
        related_bands.append( Band( object_id ).name )

    return sorted(related_bands)


def get_related_genres_for( genre ):
    """ Returns list of related genres for genre, with counts """
    current_genre_tag = "metaljoe/music/genre/%s" % genre
    
    response = fluid.db( "GET", "/objects", urlargs={ "query": "has metaljoe/music/genre/%s" % genre } )
    
    related_genres = {}
    for object_id in response.value["ids"]:
        band = Band( object_id )
        tags = [ tag[21:] for tag in band.tag_paths if tag.startswith("metaljoe/music/genre/") and tag != current_genre_tag ]

        for tag in tags:
            if tag not in related_genres:
                related_genres[tag] = 0
            related_genres[tag] += 1

    values = related_genres.values()
    
    if len( values ) == 0: # no related genres, so exit early
        return []

    font_min = 1.2
    font_max = 2.5
    tag_min  = min( values )
    tag_max  = max( values )

    scale_factor = ( font_max - font_min ) / max( tag_max - tag_min, 1 ) 
    def font_size( count ):
        """ See http://blog.jeremymartin.name/2008/03/efficient-tag-cloud-algorithm.html
            Works much better than the one on Wikipedia
        """
        return font_min + ( ( tag_max - ( tag_max - ( count - tag_min ) ) ) * scale_factor )

    related_genres = [ ( get_genre(key).description, key, font_size(value) ) for key, value in related_genres.items() ]
    related_genres.sort()

    return related_genres
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.