source: gutenbach/debian/lib/sipbmp3-filter @ de4ce86

debianmacno-cupsnodebathenaweb
Last change on this file since de4ce86 was de4ce86, checked in by geofft <geofft>, 16 years ago

Use braces instead of parens for bold, 'cause too many song names use parens

  • Property mode set to 100755
File size: 6.5 KB
Line 
1#!/usr/athena/bin/perl
2# Play the data on STDIN as an audio file
3#
4# $Id: sipbmp3-filter,v 1.24 2008-11-04 04:21:19 geofft Exp $
5# $Source: /tmp/tmp.UFBNno9997/RCS/sipbmp3-filter,v $
6#
7# TODO
8# ----
9# Make this structured code. It's a mess.
10# Repeat what we just played for EXT files too
11# Support HTTP Auth on ogg streams
12# License, cleanup and package
13#
14# Jered Floyd <jered@mit.edu> takes very little credit for this code
15# apparently neither does Quentin Smith <quentin@mit.edu>
16
17use Image::ExifTool qw(ImageInfo);
18use File::Spec::Functions;
19use LWP::UserAgent;
20use Data::Dumper;
21
22my $ua = new LWP::UserAgent;
23
24close(STDERR);
25open(STDERR, ">>", "/tmp/sipbmp3.log") or warn "Couldn't open log: $!";
26
27$ENV{"TERM"}="vt100";
28
29print STDERR "STDERR FROM SPOOL FILTER\n";
30
31# set real uid to be effective uid
32$< = $>;
33
34# Select the correct output device and set the volume
35#system("amixer -q set Headphone 100\% unmute");
36
37# The command line we get from lpd is (no spaces between options and args):
38#  -C lpr -C class
39#  -A LPRng internal identifier
40#  -H originating host
41#  -J lpr -J jobname (default: list of files)
42#  -L lpr -U username
43#  -P logname
44#  -Q queuename (lpr -Q)
45#  -Z random user-specified options
46#  -a printcap af (accounting file name)
47#  -d printcap sd entry (spool dir)
48#  -e print job data file name (currently being processed)
49#  -h print job originiating host (same as -H)
50#  -j job number in spool queue
51#  -k print job control file name
52#  -l printcap pl (page length)
53#  -n user name (same as -L)
54#  -s printcap sf (status file)
55#  -w printcap pw (page width)
56#  -x printcap px (page x dimension)
57#  -y printcap py (page y dimension)
58# accounting file name
59
60printf(STDERR "Got \@ARGV: %s\n", Dumper(\@ARGV));
61
62my %opts;
63
64my @NEWARGV;
65
66foreach my $arg (@ARGV) {
67  if ($arg =~ m/^-([a-zA-Z])(.*)$/) {
68    $opts{$1} = $2;
69  } else {
70    push @NEWARGV, @ARGV;
71  }
72}
73
74@ARGV = @NEWARGV;
75
76printf(STDERR Dumper(\%opts));
77
78# Status messages at start of playback
79open(ZEPHYR, '|/usr/athena/bin/zwrite -d -n -c sipb-auto -i ' .
80  'sipbmp3@zsr -s "SIPB LPR music spooler"');
81print(ZEPHYR "$opts{'n'}\@$opts{'H'} is playing:\n");
82
83# So, the file we're currently processing is "-d/-e".
84
85# Read the metadata information from the file.
86my ($filepath) = catfile($opts{'d'}, $opts{'e'});
87my ($fileinfo) = ImageInfo($filepath);
88my ($magic) = $fileinfo->{FileType};
89
90if ($magic) {
91    printf(ZEPHYR "%s file %s\n", $magic, $opts{'J'});
92    printf(ZEPHYR "\@b{%s}\n", $fileinfo->{'Title'}) if exists $fileinfo->{'Title'};
93    foreach my $key (qw/Artist Album AlbumArtist/) {
94        printf(ZEPHYR "%s\n", $fileinfo->{$key}) if exists $fileinfo->{$key};
95    }
96}
97elsif ($opts{'C'} eq 'Z') {
98    $filepath = resolve_external_reference($filepath, \%opts);
99    print STDERR "Resolved external reference to $filepath\n";
100    printf(ZEPHYR "%s\n", $filepath);
101    close(ZEPHYR);
102}
103elsif (-T $filepath) {
104    split_playlist($filepath, \%opts);
105    close(ZEPHYR);
106    exit 0;
107}
108#printf(STDERR "Job priority %s\n", $opts{'C'}) if $opts{'C'} eq 'Z';
109#printf(ZEPHYR "Job priority %s\n", $opts{'C'}) if ($opts{'C'} && ($opts{'C'} ne 'A'));
110close(ZEPHYR);
111play_mplayer_audio($filepath, \%opts);
112
113# Play an external stream reference
114sub resolve_external_reference {
115    # Retrieve those command line opts.
116    my ($filepath, $opts) = @_;
117
118    my $format, $uri, $userpass;
119
120    if (<STDIN> =~ /^(\S+)/) {
121        $uri=$1;
122
123        my $response = $ua->head($uri);
124       
125        $contenttype=($response->content_type() or "unknown");
126       
127        if ($contenttype eq "audio/mpeg") { $format="MP3" }
128        elsif ($contenttype eq "application/x-ogg") { $format="OGG" }
129        elsif ($contenttype eq "application/ogg") { $format="OGG" }
130        elsif ($contenttype eq "audio/x-scpls") { $format="SHOUTCAST" }
131        else {
132            print ZEPHYR
133                "Unknown Content-Type $contenttype for URI $uri\n";
134        }
135    } else {
136        print ZEPHYR "Couldn't read URI for external reference\n";
137        return $filepath;
138    }
139
140    if ($format eq "SHOUTCAST") {
141        print ZEPHYR "Shoutcast playlist...\n";
142        #Don't close ZEPHYR yet, will print the name of the stream if available
143        return &get_shoutcast($uri);
144    } elsif ($format eq "MP3") {
145    } elsif ($format eq "OGG") {
146    } else {
147      print ZEPHYR "Unrecognized stream format: $format\n";
148    }
149    return $uri;
150}
151
152sub split_playlist {
153    my ($file, $opts) = @_;
154
155    my $i = 0;
156   
157    while (<STDIN>) {
158        chomp;
159        if (/^([^#]\S+)/) {
160            printf (STDERR "Found line: %s\n", $_);
161            open(LPR, "|-", qw/mit-lpr -Psipbmp3@localhost -CZ/, '-J'.$opts->{J});
162            print LPR $1;
163            close(LPR);
164        $i++;
165        }
166    }
167    printf(ZEPHYR "Playlist containing %d valid entries, split into separate jobs.\n", $i);
168}
169
170# Process a Shoutcast playlist
171# get_shoutcast(URI)
172sub get_shoutcast {
173  my $uri = shift(@_);
174 
175  my $response = $ua->get($uri);
176
177  foreach (split("\n", $response->content())) {
178      if (/^File\d+=(\S+)/) {
179          push(@uris, $1);
180      }
181      if (/^Title\d+=(.+)$/) {
182          push(@titles, $1);
183      }
184  }
185 
186  # choose a random server
187  $server = int(rand scalar(@uris));
188  # print the name of the stream if available
189  print ZEPHYR "$titles[$server]\n";
190  return $uris[$server];
191}
192
193sub play_mplayer_audio {
194    my ($filepath, $opts) = @_;
195
196    # Prepare to write status:
197    open(ZEPHYR, '|/usr/athena/bin/zwrite -d -n -c sipb-auto -i ' .
198         'sipbmp3@zsr -s "SIPB LPR music spooler"');
199   
200    # fork for mpg123
201    my $pid = open(MP3STATUS, "-|");
202    unless (defined $pid) {
203        print ZEPHYR "Couldn't fork: $!\n";
204        close(ZEPHYR);
205        return;
206    }
207   
208    if ($pid) { #parent
209        # Check if there were any errors
210        if ($_ = <MP3STATUS>) {
211            print ZEPHYR "Playback completed with the following errors:\n";
212            print ZEPHYR $_;
213            while (<MP3STATUS>) {
214                print ZEPHYR $_;
215            }
216        } else {
217            print ZEPHYR "Playback completed successfully.\n";
218        }
219        close(MP3STATUS) || print ZEPHYR "mplayer exited $?\n";
220       
221        close(ZEPHYR);
222    }
223  else { # child
224      # redirect STDERR to STDOUT
225      open STDERR, '>&STDOUT';
226      # make sure that mplayer doesn't try to intepret the file as keyboard input
227      close(STDIN);
228      open(STDIN, "/dev/null");
229      #print STDERR Dumper([qw|/usr/bin/mplayer -nolirc -ao alsa -quiet|, $filepath]);
230      my @args = (qw|/usr/bin/mplayer -vo null -nolirc -ao alsa -cache 512 -really-quiet|, $filepath);
231      #print STDERR "About to exec: ", Dumper([@args]);
232      exec(@args) ||
233          die "Couldn't exec";
234  }
235}
236
237# ID3 comments often have useless crap because tools like iTunes were
238# written by drooling idiots
239sub filter_comment {
240  my $comment = shift(@_);
241
242  if ($comment =~ /^engiTunes_CDDB/) {
243    return undef;
244  }
245  return $comment;
246}
247
248
Note: See TracBrowser for help on using the repository browser.