continuously show lyrics (on terminal, using less)
[soepkiptng.git] / q
blobb1a9e133c51b7039df266287192fe7cb7e56bb88
1 #!/usr/bin/perl
2 ############################################################################
3 # soepkiptng (c) copyright 2000 Eric Lammerts <eric@lammerts.org>.
4 # $Id$
5 ############################################################################
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License, version 2, as
8 # published by the Free Software Foundation.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # A copy of the GNU General Public License is available on the World Wide Web
16 # at `http://www.gnu.org/copyleft/gpl.html'. You can also obtain it by
17 # writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
19 ############################################################################
21 use integer;
22 use Cwd 'abs_path';
23 use DBI;
24 use Socket;
25 use Getopt::Std;
27 # find program directory
28 $_ = $0;
29 while(-l) {
30 my $l = readlink or die "readlink $_: $!\n";
31 if($l =~ m|^/|) { $_ = $l; } else { s|[^/]*$|/$l|; }
33 m|(.*)/|;
34 my $progdir = abs_path($1);
36 require "$progdir/soepkiptng.lib";
38 getopts('avnc:g');
40 read_configfile(\%conf, $opt_c);
42 eval "use Term::ReadKey;";
43 if($@) {
44 warn "Term::ReadKey not found; assuming 80-column terminal.\n";
45 $screen_width = 80;
46 } else {
47 if(-t) {
48 ($screen_width) = GetTerminalSize();
49 } else {
50 $screen_width = 80;
54 sub albumtrack($$) {
55 my ($album, $track) = @_;
57 if($track) {
58 my $nr = "[$track]";
59 $album = substr($album, 0, $w_al - length($nr));
60 if(length($album) != $w_al - length($nr)) { $album .= " "; }
61 $album .= $nr;
62 } else {
63 $album = substr($album, 0, $w_al);
65 $album;
68 sub splitrange($$) {
69 my ($val, $max) = @_;
70 my @ret;
72 $val =~ s/\b\s+\b/,/g;
73 s/\s//g;
74 foreach(split /,/, $val) {
75 if(/(\d*)-(\d*)/) {
76 my ($b, $e, $i);
77 $b = $1;
78 $e = $2 || $max;
79 for($i = $b; $i <= $e; $i++) {
80 push @ret, $i;
82 } else {
83 push @ret, $_;
86 @ret;
89 sub killit($) {
90 my ($killid) = @_;
91 ($song_id) = kill_song('', $killid);
92 if(!defined($song_id)) {
93 print "not killing (song $killid not playing anymore)\n";
94 return undef;
96 ($t, $a, $al, $tr) = $dbh->selectrow_array(
97 "SELECT song.title,artist.name,album.name,song.track" .
98 " FROM song,artist,album" .
99 " WHERE song.id=$song_id" .
100 " AND song.artist_id=artist.id AND song.album_id=album.id"
102 printf "next: %s - %02d. %s [%s]\n", $a, $tr, $t, $al;
105 $| = 1;
107 $dbh = DBI->connect("DBI:$conf{db_type}:$conf{db_name}:$conf{db_host}",
108 $conf{db_user}, $conf{db_pass}) or die "can't connect to database";
110 if($opt_n) {
111 open F, $conf{statusfile} or exit;
112 $nowplaying = <F>;
113 close F;
115 my $user = (getpwuid $<)[6] || getpwuid $< || "uid $<";
116 $user =~ s/,.*//;
117 my $song = add_song_next($dbh, $nowplaying, $user);
119 print "Adding next song ($song->{track}, $song->{title}).\n";
120 exit;
123 $screen_width = 80 if $screen_width == 0; # just in case
124 $w_a = $screen_width * 25 / 100;
125 $w_t = $screen_width * 45 / 100;
126 $w_al = $screen_width - $w_a - $w_t - 7;
127 $w_a > 0 && $w_t > 0 && $w_al > 0 or die "screen size too small.\n";
129 if($0 =~ /qr$/ || @ARGV) {
130 my @a;
131 foreach(@ARGV) {
132 $q = '';
133 if(s/^-//) { $q = " NOT"; }
134 s/^\^// or $_ = "%$_";
135 s/\$$// or $_ .= "%";
137 if($0 =~ /qa$/) {
138 $q .= " artist.name LIKE ?";
139 push @a, $_;
141 elsif($0 =~ /ql$/) {
142 $q .= " album.name LIKE ?";
143 push @a, $_;
145 elsif($0 =~ /qt$/) {
146 $q .= " song.title LIKE ?";
147 push @a, $_;
149 else {
150 $q .= " (song.title LIKE ? OR artist.name LIKE ? OR album.name LIKE ?)";
151 push @a, $_, $_, $_;
153 push @q, $q;
155 if($opt_g) {
156 push @q, "track > 0";
158 if($0 =~ /qr$/) {
159 push @q, " last_played=0 AND (unix_timestamp(now()) - unix_timestamp(time_added)) < 7*86400";
161 $q = "SELECT title,artist.name as artist,album.name as album,song.id as id,track,filename,length,encoding" .
162 " FROM song,artist,album" .
163 " WHERE song.artist_id=artist.id AND song.album_id=album.id" .
164 " AND present AND " . join(" AND ", @q) .
165 " ORDER BY artist.name,album.name,song.track,song.title";
166 #warn $q;
167 $sth = $dbh->prepare($q);
168 $sth->execute(@a);
170 $head = sprintf("\n %-${w_a}s %-${w_t}s %-${w_al}s\n %s %s %s\n",
171 'Artist', 'Song', 'Album', '-'x$w_a, '-'x$w_t, '-'x$w_al);
173 $i = 1;
174 while($_ = $sth->fetchrow_hashref) {
175 if($opt_g) {
176 my $f = $_->{filename};
177 $f =~ s|//+|/|g;
178 $f =~ s|^(.*)/|| or die;
179 my $d = $1;
180 $d =~ s|^.*/|| or die;
181 $f =~ s|\.[^.]+$||;
182 $f =~ /([^-\w])/ and die "\nERROR: invalid character ($1) in filename ($f)!\n";
183 if(defined($dirname)) {
184 $dirname eq $d or die "\nERROR: inconsistent dirname ($dirname, $d)\n";
185 } else {
186 $dirname = $d;
187 $g_output .= ">$dirname\n";
189 $_->{title} =~ s/^(\W+)/<$1>/;
190 $g_output .= "-$_->{track}\n" if $_->{track};
191 $g_output .= "/$f\n";
192 next;
194 print STDERR $head;
195 $head = '';
196 printf STDERR "%-3s %-${w_a}.${w_a}s %-${w_t}.${w_t}s %-${w_al}.${w_al}s\n",
197 "$i.", $_->{artist}, $_->{title}, albumtrack($_->{album}, $_->{track});
198 $opt_v and printf STDERR "%d:%02d %s %s\n", $_->{length} / 60, $_->{length} % 60,
199 $_->{encoding}, $_->{filename};
200 $id[$i] = $_->{id};
201 $i++;
203 if($opt_g) {
204 print $g_output;
205 exit 0;
207 exit if $i == 1;
208 if($opt_a) {
209 $i == 2 or die "More than 1 hit\n";
210 $_ = 1;
211 } else {
212 print STDERR "\nAdd (a=all): ";
213 $_ = <STDIN>;
214 exit unless /\S/;
217 my $user = (getpwuid $<)[6] || getpwuid $< || "uid $<";
218 $user =~ s/,.*//;
219 if(/^a/i) {
220 for($n = 1; $n < $i; $n++) {
221 add_song($dbh, $user, $id[$n]) or warn "can't add song.\n";
223 } else {
224 foreach(splitrange($_, $i)) {
225 add_song($dbh, $user, $id[$_]) or warn "can't add song.\n"
226 if $id[$_];
231 printf "\n %-${w_a}s %-${w_t}s %-${w_al}s\n %s %s %s\n",
232 'Artist', 'Song', 'Album', '-'x$w_a, '-'x$w_t, '-'x$w_al;
234 $i = 1;
235 if($_ = get_nowplaying($dbh)) {
236 printf "1.* %-${w_a}.${w_a}s %-${w_t}.${w_t}s %-${w_al}.${w_al}s\n",
237 $_->{artist}, $_->{title}, albumtrack($_->{album}, $_->{track});
238 if($_->{id}) { $delid[$i++] = $_->{id}; }
239 $nowid = $_->{id};
242 $query = "SELECT song.title,artist.name,album.name,song.id,song.track" .
243 " FROM song,artist,album,queue" .
244 " WHERE song.id=queue.song_id" .
245 " AND song.artist_id=artist.id AND song.album_id=album.id" .
246 " ORDER BY queue.song_order";
247 $sth = $dbh->prepare($query);
248 $rv = $sth->execute;
249 while(@q = $sth->fetchrow_array) {
250 printf "%-3s %-${w_a}.${w_a}s %-${w_t}.${w_t}s %-${w_al}.${w_al}s\n",
251 "$i.", $q[1], $q[0], albumtrack($q[2], $q[4]);
252 $delid[$i] = $q[3];
253 $i++;
256 $opt_a and exit;
257 print STDERR "\nDelete (a=all): ";
258 $_ = <STDIN>;
259 exit unless /\S/;
260 if(/^S/) {
261 shuffle_queue($dbh);
262 } elsif(/^a/i) {
263 $sth = $dbh->prepare("DELETE FROM queue");
264 $sth->execute();
265 killit($nowid);
266 } else {
267 foreach(splitrange($_, $i)) {
268 if($_ == 1) { killit($nowid); }
269 else { del_song($dbh, $delid[$_]) if $delid[$_]; }
273 $sth->finish;
274 $dbh->disconnect;