#!/usr/bin/perl my %infoProvider; my @infoOrdering; ## # Register an information provider with the current providers # # @param[in] $name The name of the provider # @param[in] %details A hashref of the information required by the # provider # after => any provider which this info is after # before => any provider which this info is before # isa => any provider which this is a member of # func => the function to call to provide info # private => a private value to pass to the function sub registerInfoProvider { my ($name, %details) = @_; $details{'name'} = $name; # For diagnostic purposes if (!defined $details{'after'} && !defined $details{'before'} && !defined $details{'isa'}) { # If they didn't say anything about where it goes, # place it in the middle. $details{'isa'} = 'middle'; } $infoProvider{$name} = \%details; # Clear the array to force it to be rebuilt @infoOrdering = (); } ## # Deregister an information provider # # @param[in] $name The name of the provider sub deregisterInfoProvider { my ($name) = @_; delete $infoProvider{$name}; # Clear the array to force it to be rebuilt @infoOrdering = (); } ## # Add information to the current list of items # # @param[in] $client The client this request is coming from # @param[in] $line The line to add # @param[in] $content The operation to perform when this item is selected. # May be a hashref of information to search for: # 'type' => a type of search: # ALBUM = album+track search # = contributor role search # GENRE = genre+contrib+album+track search # YEAR = year+album+track search # 'obj' => the value searched # Or may be a code ref to execute the code in the form # func($client); # Or may be undef to never push right. sub addInfo { my $client = shift; my $line = shift; my $content = shift; print "Adding $line\n"; push (@{$client->trackInfoLines}, $line); push (@{$client->trackInfoContent}, $content); } ## # Add the 'title' information to the information. # # Should call addInfo to add information to the menu. # # @param[in] $client The client this request is coming from # @param[in] $private A private value passed on registration # @param[in] $url The URL to which this information refers # @param[in] $track The track reference sub infoTitle { my ($client, $private, $url, $track) = @_; print "Title\n"; } # The 'top', 'middle' and 'bottom' groups, so that we can add items in absolute # positions registerInfoProvider('top', ('isa' => '') ); registerInfoProvider('middle', ('isa' => '') ); registerInfoProvider('bottom', ('isa' => '') ); registerInfoProvider('title', ( 'after' => 'top', 'func' => \&infoTitle )); registerInfoProvider('audioscrobbler', ( 'before' => 'title', 'func' => sub { print "AScrobbler\n"; } )); registerInfoProvider('lyrics', ( 'after' => 'top', 'before' => 'title', 'func' => sub { print "LYRICS\n"; } )); registerInfoProvider('contributors', ( 'after' => 'title', 'func' => sub { print "Contribs\n"; } )); registerInfoProvider('album', ( 'after' => 'contributors', 'func' => sub { print "Album\n"; } )); registerInfoProvider('tracknum', ( 'after' => 'album', 'func' => sub { print "TrackNum\n"; } )); registerInfoProvider('year', ( 'after' => 'tracknum', 'func' => sub { print "Year\n"; } )); registerInfoProvider('genres', ( 'after' => 'year', 'func' => sub { print "Genres\n"; } )); registerInfoProvider('type', ( 'after' => 'genres', 'func' => sub { print "Type\n"; } )); registerInfoProvider('comment', ( 'after' => 'type', 'func' => sub { print "Comment\n"; } )); registerInfoProvider('duration', ( 'after' => 'comment', 'func' => sub { print "Duration\n"; } )); registerInfoProvider('replaygain', ( 'after' => 'duration', 'func' => sub { print "Replaygain\n"; } )); registerInfoProvider('rating', ( 'after' => 'replaygain', 'func' => sub { print "Rating\n"; } )); registerInfoProvider('formatinfo', ( 'after' => 'rating' )); registerInfoProvider('fileinfo', ( 'after' => 'formatinfo' )); registerInfoProvider('favorite', ( 'after' => 'fileinfo' )); # File information registerInfoProvider('filesize', ( 'isa' => 'fileinfo', 'func' => sub { print "Filesize\n"; } )); registerInfoProvider('modtime', ( 'isa' => 'fileinfo', 'func' => sub { print "ModTime\n"; } )); registerInfoProvider('url', ( 'isa' => 'fileinfo', 'func' => sub { print "URL\n"; } )); # Format information registerInfoProvider('bitrate', ( 'isa' => 'formatinfo', 'func' => sub { print "Bitrate\n"; } )); registerInfoProvider('samplerate', ( 'isa' => 'formatinfo', 'func' => sub { print "Samplerate\n"; } )); registerInfoProvider('samplesize', ( 'isa' => 'formatinfo', 'func' => sub { print "Samplesize\n"; } )); registerInfoProvider('drm', ( 'isa' => 'formatinfo', 'func' => sub { print "DRM\n"; } )); registerInfoProvider('lastthing', ( 'before' => 'bottom', 'func' => sub { print "LAST\n"; } )); my %thing; $client = \%thing; @{$client->{'trackInfoLines'}} = (); @{$client->{'trackInfoContent'}} = (); # If we don't have a ordering, generate one if (scalar(@infoOrdering) == 0) { # We don't know what order the entries should be in, # so work that out. generateInfoOrderingItem($client, 'top', undef); generateInfoOrderingItem($client, 'middle', undef); generateInfoOrderingItem($client, 'bottom', undef); } print "\nUnordered:\n"; for $ref (values %infoProvider) { print "$ref->{'name'} [$ref->{'before'} > $ref->{'after'}]\n"; } print "\nOrdered:\n"; for $ref (@infoOrdering) { print "$ref->{'name'}\n"; } # print "\nRun the ordering:\n"; # for my $ref (@infoOrdering) # { # if (defined $ref->{'func'}) # { # $ref->{'func'}($client, $ref->{'private'}, $url, $track); # } # } ## # Adds an item to the ordering list, following any # 'after', 'before' and 'isa' requirements that the # registered providers have requested. # # @param[in] $client The client we're ordering for # @param[in] $name The name of the item to add # @param[in] $previous The item before this one, for 'before' processing sub generateInfoOrderingItem { my $client = shift; my $name = shift; my $previous = shift; my $item; # Check for the 'before' items which are 'after' the last item if (defined $previous) { for $item (sort { $a cmp $b } grep { defined $infoProvider{$_}->{'after'} && $infoProvider{$_}->{'after'} eq $previous && defined $infoProvider{$_}->{'before'} && $infoProvider{$_}->{'before'} eq $name } keys %infoProvider) { &generateInfoOrderingItem($client, $item, $previous); } } # Now the before items which are just before this item for $item (sort { $a cmp $b } grep { !defined $infoProvider{$_}->{'after'} && defined $infoProvider{$_}->{'before'} && $infoProvider{$_}->{'before'} eq $name } keys %infoProvider) { &generateInfoOrderingItem($client, $item, $previous); } # Add the item itself push @infoOrdering, $infoProvider{$name}; # Now any items that are members of the group for $item (sort { $a cmp $b } grep { defined $infoProvider{$_}->{'isa'} && $infoProvider{$_}->{'isa'} eq $name } keys %infoProvider) { &generateInfoOrderingItem($client, $item, undef); } # Any 'after' items for $item (sort { $a cmp $b } grep { defined $infoProvider{$_}->{'after'} && $infoProvider{$_}->{'after'} eq $name && !defined $infoProvider{$_}->{'before'} } keys %infoProvider) { &generateInfoOrderingItem($client, $item, $name); } }