| main | console | Legend - Hand of God | web | contact |
| music browser | playground |
The Music Browser uses the MySQL database created by the music.dbIndex script. It allows you to sort your music by different criteria and to stream it. Simply point your browser to the site and click on the item you want to listen to. The script will then create a .m3u playlist which can then be loaded into your favorite music player.
The music will then be streamed from the server.
The script has the ability to display album covers on the album info page. Therefore, all you have to do is to copy a file cover.(png,jpg,gif) into the album's directory. The script will look for such a file and -if available- display it
Here are some screenshots (click for larger images)
Note1: I've tested it only in a LAN with 2 PCs, so I don't know what happens if the same file is accessed simultaneously by different computers. It should work though
Note2: XMMS does not support seeking in streams. This is not a bug in my script, but in the player. Use AlsaPlayer instead
Note3: music.cgi will only stream the mp3 files. The helper script stream.ogg will stream ogg files.
1#!/bin/sh 2# the next line restarts using tclsh \ 3exec tclsh "$0" "$@" 4 5 6# 7# required packages: 8# base64 (tcllib) 9# mysqltcl 10# 11 12 13# in test_mode, the created m3u file is displayed, not passed to the player 14set test_mode no 15 16# should the playcount be displayed/used 17set use_playcount yes 18 19# how many items should be displayed in the "most played"-boxes 20set playcount_nr 5 21 22 23# display a randomly selected album? 24set use_random_album yes 25 26# keep track of last_played date and display it? 27set use_last_played yes 28 29# colors used for tables 30set global_first_color "#FFFFFF" ;# every odd row 31set global_second_color "#E9E9E9" ;# every even row 32set global_hilite_color "#B0FFF6" ;# one given row 33 34 35catch { 36 lappend auto_path /usr/local/lib 37 38 # load base64 extension 39 package require base64 40 41 # load mysql extension 42 package require mysqltcl 43 44 # mysql settings 45 set config(host) "localhost" 46 set config(user) "tcl" 47 set config(pass) "tcl" 48 set config(base) "music" 49 50 # table names 51 set config(albums) "albums" 52 set config(artists) "artists" 53 set config(songs) "songs" 54 55 56 57 58 # display all environment variables 59 proc show_env {} { 60 global env 61 puts "<pre>" 62 foreach i [parray env] {puts $i} 63 puts "</pre>" 64 } 65 66 67 # connect to the database 68 proc db_connect {} { 69 global config db 70 catch {set db [mysqlconnect -host $config(host) -user $config(user) -pass $config(pass) -db $config(base)]} sql_result 71 72 # if connection was successful, we'll get a variable db 73 if {![info exists db]} then { 74 header 75 puts $sql_result 76 footer 77 78 unset sql_result 79 exit 80 } 81 unset sql_result 82 83 # check whether all tables exist 84 set listOfTables [mysqlinfo $db tables] 85 86 foreach i [list $config(albums) $config(artists) $config(songs)] { 87 if {[lsearch $listOfTables $i] == "-1"} then { 88 header 89 puts "table \"$i\" missing" 90 footer 91 unset listOfTables 92 exit 93 } 94 } 95 } 96 97 98 # returns a masked & 99 proc & {} { 100 return "&" 101 } 102 103 # randomizes a list 104 proc lrandomize {list} { 105 # first create a element-random value pair list 106 set l {} 107 foreach e $list { 108 lappend l [list $e [expr {rand()}]] 109 } 110 111 # then extract randomized elements 112 set list {} 113 foreach e [lsort -index 1 $l] { 114 lappend list [lindex $e 0] 115 } 116 return $list 117 } 118 119 # converts seconds into 'nice' time values 120 proc transform_secs {in} { 121 122 set m [expr $in / 60] 123 set s [expr $in % 60] 124 125 if {$m < 10} then {set m "0$m"} 126 if {$s < 10} then {set s "0$s"} 127 128 # hrs, if necessary 129 if {$m > 59} then { 130 set h [expr $m / 60] 131 set m [expr $m % 60] 132 if {$h < 10} then {set h "0$h"} 133 if {$m < 10} then {set m "0$m"} 134 set m "$h:$m" 135 } 136 137 return "$m:$s" 138 } 139 140 # takes a list of filenames, and creates a playlist 141 # tracks is a list of {songID filename title artist length} items 142 proc send_playlist {tracks} { 143 global env test_mode 144 145 if {! $test_mode} then { 146 puts "Content-type: audio/x-mpegurl" 147 puts "Content-Disposition: attachment; filename=playlist.m3u\n" 148 } else { 149 header 150 puts "<pre>" 151 } 152 153 puts "#EXTM3U" 154 foreach i $tracks { 155 set id [lindex $i 0] 156 set file [lindex $i 1] 157 set title [lindex $i 2] 158 set artist [lindex $i 3] 159 set length [lindex $i 4] 160 161 162 # 163 # mp3 files will be streamed from inside music.cgi, ogg files don't like that, so they'll be 164 # streamed by the helper script stream.ogg 165 # 166 if {[file extension $file] == ".ogg"} then { 167 set link "http://$env(SERVER_NAME)/cgi-bin/stream.ogg?$id" 168 } else { 169 set link "http://$env(SERVER_NAME)$env(SCRIPT_NAME)?stream=$id" 170 } 171 172 173 # 174 # if the file is requested from the server host, return the true filename 175 # 176 if {$env(SERVER_ADDR) == $env(REMOTE_ADDR)} then { 177 set link $file 178 } 179 180 puts "#EXTINF:$length,$artist - $title" 181 puts "$link" 182 183 unset i id file title artist length link 184 } 185 unset tracks 186 187 188 if {$test_mode} then { 189 footer 190 } 191 192 } 193 194 195 # the header of all pages 196 proc header {} { 197 # show the browser what's coming :) 198 puts "Content-type: text/html\n" 199 puts "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">" 200 puts "<html>" 201 puts " <head>" 202 puts " <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;charset=utf-8\">" 203 puts " <title>Music Browser</title>" 204 puts " <script type=\"text/javascript\">" 205 puts " <!--" 206 puts " function toggle(el) {" 207 puts " var target = document.getElementById(el);" 208 puts " if (target.style.visibility == \"hidden\")" 209 puts " {" 210 puts " target.style.visibility = \"visible\";" 211 puts " target.style.height = \"auto\";" 212 puts " } else {" 213 puts " target.style.visibility = \"hidden\";" 214 puts " target.style.height = \"0px\";" 215 puts " }" 216 puts " }" 217 puts " //-->" 218 puts " </script>" 219 puts " <style type=\"text/css\">" 220 puts " <!--" 221 puts " div.box {" 222 puts " background-color: white;" 223 puts " margin: 4px;" 224 puts " border: 1px solid #8CACBB;" 225 puts " }" 226 puts "" 227 puts " div.box-title {" 228 puts " background-color: #C7D0D9;" 229 puts " padding-left: 0px;" 230 puts " padding-right: 0px;" 231 puts " border-bottom: 1px solid #8CACBB;" 232 puts " text-align: center;" 233 puts " font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;" 234 puts " font-size: 10px;" 235 puts " color: #555575;" 236 puts " }" 237 puts "" 238 puts " div.box-data {" 239 puts " padding-left: 5px;" 240 puts " padding-right: 5px;" 241 puts " padding-bottom: 4px;" 242 puts " }" 243 puts "" 244 puts " td.box-data-contents {" 245 puts " font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;" 246 puts " font-size: 10px;" 247 puts " color: black;" 248 puts " text-align: left;" 249 puts " }" 250 puts "" 251 puts " a.box-data-link {" 252 puts " font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;" 253 puts " font-size: 10px;" 254 puts " text-decoration: none;" 255 puts " color: #436976;" 256 puts " }" 257 puts "" 258 puts " a.box-menu-link {" 259 puts " font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;" 260 puts " font-size: 10px;" 261 puts " text-decoration: none;" 262 puts " color: #555575;" 263 puts " }" 264 puts " -->" 265 puts " </style>" 266 267 puts " </head>" 268 puts " <body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" alink=\"#0000FF\" vlink=\"#0000FF\">\n" 269 270 # the 'nav-bar' 271 navibar 272 } 273 274 275 # returns a link 276 proc makeLink {href desc {title ""} {class ""}} { 277 if {$class == ""} then {set class "box-data-link"} 278 279 if {$title == ""} then { 280 switch $desc { 281 "play|all" {set title "play album"} 282 "rand" {set title "play album in random order"} 283 "info" {set title "show album info"} 284 "select" {set title "play selected songs"} 285 } 286 } 287 288 289 return "<a class=\"$class\" href=\"$href\" title=\"$title\">$desc</a>" 290 } 291 292 293 # navi-bar 294 proc navibar {} { 295 global env cmd val 296 297 set albumLink [makeLink "$env(SCRIPT_NAME)?sort=album" "album" "show all albums sorted by title"] 298 set genreLink [makeLink "$env(SCRIPT_NAME)?sort=genre" "genre" "show all albums sorted by genre"] 299 set songLink [makeLink "$env(SCRIPT_NAME)?sort=song" "song" "show all songs sorted by title"] 300 set yearLink [makeLink "$env(SCRIPT_NAME)?sort=year" "year" "show all albums sorted by year"] 301 302 if {$cmd == "sort"} then { 303 switch -glob $val { 304 "album*" {set albumLink "album"} 305 "genre" {set genreLink "genre"} 306 "song*" {set songLink "song"} 307 "year" {set yearLink "year"} 308 } 309 } 310 311 puts " <table border=\"0\" align=\"center\">" 312 puts " <tr>" 313 puts " <td>" 314 puts " <div class=\"box\">" 315 puts " <div class=\"box-title\">Menu</div>" 316 puts " <div class=\"box-data\">" 317 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">" 318 puts " <tr>" 319 puts " <td class=\"box-data-contents\">$albumLink</td>" 320 puts " <td class=\"box-data-contents\"> $genreLink</td>" 321 puts " <td class=\"box-data-contents\"> $songLink</td>" 322 puts " <td class=\"box-data-contents\"> $yearLink</td>" 323 puts " </tr>" 324 puts " </table>" 325 puts " </div>" 326 puts " </div>" 327 puts " </td>" 328 puts " </tr>" 329 puts " </table>\n" 330 331 unset albumLink genreLink songLink yearLink 332 } 333 334 # last_played album 335 proc last_played {} { 336 global db env config 337 338 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" 339 puts " <tr>" 340 puts " <td>" 341 puts " <div class=\"box\">" 342 puts " <div class=\"box-title\">Last Played Album</div>" 343 puts " <div class=\"box-data\">" 344 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"2\">" 345 346 foreach i [mysqlsel $db "SELECT albumID, artist, title, last_played 347 FROM $config(albums) 348 ORDER BY last_played DESC, artist, title 349 LIMIT 1" -list] { 350 351 set albumID [lindex $i 0] 352 set artistName [lindex $i 1] 353 set title [lindex $i 2] 354 355 set infoLink [makeLink "$env(SCRIPT_NAME)?info=album[&]id=[set albumID]" "info"] 356 357 puts " <tr>" 358 puts " <td class=\"box-data-contents\">$artistName - $title</td>" 359 puts " <td class=\"box-data-contents\" valign=\"top\"> $infoLink</td>" 360 puts " </tr>" 361 362 unset i albumID artistName title infoLink 363 } 364 365 puts " </table>" 366 puts " </div>" 367 puts " </div>" 368 puts " </td>" 369 puts " </tr>" 370 puts " </table>" 371 372 } 373 374 # displays a box with a randomly selected album 375 proc random_album {} { 376 global db env config 377 378 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" 379 puts " <tr>" 380 puts " <td>" 381 puts " <div class=\"box\">" 382 puts " <div class=\"box-title\">Random Album</div>" 383 puts " <div class=\"box-data\">" 384 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"2\">" 385 386 foreach i [mysqlsel $db "SELECT albumID, artist, title 387 FROM $config(albums) 388 ORDER BY rand() 389 LIMIT 1" -list] { 390 391 set albumID [lindex $i 0] 392 set artistName [lindex $i 1] 393 set title [lindex $i 2] 394 395 set infoLink [makeLink "$env(SCRIPT_NAME)?info=album[&]id=[set albumID]" "info"] 396 397 puts " <tr>" 398 puts " <td class=\"box-data-contents\">$artistName - $title</td>" 399 puts " <td class=\"box-data-contents\" valign=\"top\"> $infoLink</td>" 400 puts " </tr>" 401 402 unset i albumID artistName title infoLink 403 } 404 405 puts " </table>" 406 puts " </div>" 407 puts " </div>" 408 puts " </td>" 409 puts " </tr>" 410 puts " </table>" 411 412 } 413 414 # most played albums/songs 415 proc most_played {} { 416 global db env config playcount_nr 417 418 foreach type {albums songs} { 419 420 if {$type == "albums"} then { 421 set db_to_use $config(albums) 422 } else { 423 set db_to_use $config(songs) 424 } 425 426 427 if {[mysqlsel $db "select count(*) from $db_to_use where playcount <> '0'" -list] == 0} then { 428 unset type 429 continue 430 } 431 432 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" 433 puts " <tr>" 434 puts " <td>" 435 puts " <div class=\"box\">" 436 puts " <div class=\"box-title\">Most Played [string totitle $type]</div>" 437 puts " <div class=\"box-data\">" 438 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"2\">" 439 440 switch $type { 441 442 "albums" { 443 set list [mysqlsel $db "SELECT albumID, artist, title, playcount 444 FROM $db_to_use WHERE playcount <> '0' 445 ORDER BY playcount DESC, artist, title 446 LIMIT $playcount_nr" -list] 447 } 448 "songs" { 449 set list [mysqlsel $db "SELECT albumID, $config(artists).name AS artist, title, playcount, songID 450 FROM $db_to_use, $config(artists) 451 WHERE playcount <> '0' AND $config(songs).artistID = $config(artists).artistID 452 ORDER BY playcount DESC, artist, title 453 LIMIT $playcount_nr;" -list] 454 } 455 } 456 457 foreach i $list { 458 set albumID [lindex $i 0] 459 set artistName [lindex $i 1] 460 set title [lindex $i 2] 461 set playcount [lindex $i 3] 462 463 464 if {$type == "albums"} then { 465 set infoLink [makeLink "$env(SCRIPT_NAME)?info=album[&]id=[set albumID]" "info"] 466 } else { 467 set songID [lindex $i 4] 468 set infoLink [makeLink "$env(SCRIPT_NAME)?info=album[&]id=[set albumID][&]highlight=[set songID]" "info"] 469 unset songID 470 } 471 472 puts " <tr>" 473 puts " <td class=\"box-data-contents\" valign=\"top\" style=\"text-align:right\">$playcount</td>" 474 puts " <td class=\"box-data-contents\">$artistName - $title</td>" 475 puts " <td class=\"box-data-contents\" valign=\"top\"> $infoLink</td>" 476 puts " </tr>" 477 478 unset i albumID artistName title playcount infoLink 479 } 480 unset list 481 482 puts " </table>" 483 puts " </div>" 484 puts " </div>" 485 puts " </td>" 486 puts " </tr>" 487 puts " </table>" 488 489 if {$type == "albums"} then { 490 # display the least played albums 491 least_played 492 } 493 494 unset type db_to_use 495 } 496 } 497 498 # least played albums 499 proc least_played {} { 500 global db env config playcount_nr 501 502 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" 503 puts " <tr>" 504 puts " <td>" 505 puts " <div class=\"box\">" 506 puts " <div class=\"box-title\">Least Played Albums</div>" 507 puts " <div class=\"box-data\">" 508 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"2\">" 509 510 foreach i [mysqlsel $db "SELECT albumID, artist, title, playcount 511 FROM $config(albums) 512 ORDER BY playcount, artist, title 513 LIMIT $playcount_nr" -list] { 514 515 set albumID [lindex $i 0] 516 set artistName [lindex $i 1] 517 set title [lindex $i 2] 518 set playcount [lindex $i 3] 519 520 set infoLink [makeLink "$env(SCRIPT_NAME)?info=album[&]id=[set albumID]" "info"] 521 522 puts " <tr>" 523 puts " <td class=\"box-data-contents\" valign=\"top\" style=\"text-align:right\">$playcount</td>" 524 puts " <td class=\"box-data-contents\">$artistName - $title</td>" 525 puts " <td class=\"box-data-contents\" valign=\"top\"> $infoLink</td>" 526 puts " </tr>" 527 528 unset i albumID artistName title playcount infoLink 529 } 530 531 puts " </table>" 532 puts " </div>" 533 puts " </div>" 534 puts " </td>" 535 puts " </tr>" 536 puts " </table>" 537 } 538 539 540 # the footer of all pages 541 proc footer {} { 542 puts "\n </body>" 543 puts "</html>" 544 } 545 546 set query $env(QUERY_STRING) 547 if {$query == ""} then { 548 puts "Location: $env(SCRIPT_NAME)?sort=genre\n\n" 549 } 550 551 # a query is of the form 'command=value', here it is separated 552 set cmd [lindex [split $query "="] 0] 553 set val [join [lrange [split $query "="] 1 end] "="] 554 555 556 switch $cmd { 557 558 "sort" { 559 # 560 # display the listings of the available media 561 # 562 563 # connect to database 564 db_connect 565 566 # emit the header 567 header 568 569 # show the lists 570 switch -glob $val { 571 "album*" { 572 # 573 # sort albums by title 574 # 575 576 # val = "album&by=title" or val = "album" 577 578 # sortby = {'title','artist','length'} 579 set sortby [lindex [split [lindex [split $val "&"] end] "="] end] 580 if {$sortby == "album"} then {set sortby "title"} 581 582 puts " <table border=\"0\" align=\"center\">" 583 puts " <tr>" 584 puts " <td>\n" 585 puts " <div class=\"box\">" 586 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">" 587 puts " <tr>" 588 589 set titleLink [makeLink "$env(SCRIPT_NAME)?sort=album[&]by=title" "Title" "sort list by album titles" "box-menu-link"] 590 set artistLink [makeLink "$env(SCRIPT_NAME)?sort=album[&]by=artist" "Artist" "sort list by artists" "box-menu-link"] 591 set lengthLink [makeLink "$env(SCRIPT_NAME)?sort=album[&]by=length" "Length" "sort list by length" "box-menu-link"] 592 593 puts " <td><div class=\"box-title\" style=\"text-align:left\">$titleLink </div></td>" 594 puts " <td><div class=\"box-title\" style=\"text-align:left\">$artistLink </div></td>" 595 puts " <td><div class=\"box-title\" style=\"text-align:right\">$lengthLink</div></td>" 596 puts " </tr>" 597 598 unset titleLink artistLink lengthLink 599 600 switch $sortby { 601 "artist" {set sqlOrderClause "ORDER BY artist, title"} 602 "length" {set sqlOrderClause "ORDER BY length, artist, title"} 603 default {set sqlOrderClause "ORDER BY title, artist"} 604 } 605 606 # display them 607 foreach album [mysqlsel $db "SELECT $config(albums).albumID, 608 $config(artists).artistID AS artistID, 609 $config(albums).artist AS artist, 610 $config(albums).title AS title, 611 sum($config(songs).length) AS length 612 613 FROM $config(albums), $config(artists), $config(songs) 614 WHERE artist = $config(artists).name 615 AND $config(albums).albumID = $config(songs).albumID 616 GROUP BY $config(albums).albumID 617 $sqlOrderClause" -list] { 618 619 set albumID [lindex $album 0] 620 set artistID [lindex $album 1] 621 set artist [lindex $album 2] 622 set title [lindex $album 3] 623 set length [lindex $album 4] 624 625 set titleLink [makeLink "$env(SCRIPT_NAME)?info=album[&]id=$albumID" $title "show album info"] 626 set artistLink [makeLink "$env(SCRIPT_NAME)?info=artist[&]id=[set artistID]" $artist "show all albums by this artist"] 627 628 puts " <tr>" 629 puts " <td valign=\"top\" class=\"box-data-contents\" nowrap>$titleLink </td>" 630 puts " <td valign=\"top\" class=\"box-data-contents\" nowrap>$artistLink </td>" 631 puts " <td valign=\"top\" class=\"box-data-contents\" style=\"text-align:right\">[transform_secs $length]</td>" 632 puts " </tr>" 633 634 unset album albumID artistID artist title titleLink artistLink 635 } 636 unset sqlOrderClause 637 638 puts " </table>" 639 puts " </div>\n" 640 puts " </td>" 641 puts " </tr>" 642 puts " </table>" 643 unset sortby 644 } 645 646 647 "genre" { 648 # 649 # sort albums by genre 650 # 651 652 puts " <table border=\"0\" align=\"center\">" 653 puts " <tr>" 654 655 puts " <td width=\"1\" valign=\"top\">" 656 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" 657 puts " <tr>" 658 puts " <td>" 659 puts " <div class=\"box\">" 660 puts " <div class=\"box-title\">Statistics</div>" 661 puts " <div class=\"box-data\">" 662 663 set son [mysqlsel $db "SELECT count(*) FROM $config(songs)" -list] 664 set art [mysqlsel $db "SELECT count(*) FROM $config(artists)" -list] 665 set alb [mysqlsel $db "SELECT count(*) FROM $config(albums)" -list] 666 set run [mysqlsel $db "SELECT sum(length) FROM $config(songs)" -list] 667 668 # if the db is empty, $run will be "{{}}" 669 if {[string is integer $run]} then { 670 set run [transform_secs $run] 671 } else { 672 set run 0 673 } 674 675 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">" 676 puts " <tr>" 677 puts " <td class=\"box-data-contents\">Albums: </td>" 678 puts " <td class=\"box-data-contents\" style=\"text-align:right\">$alb</td>" 679 puts " </tr>" 680 puts " <tr>" 681 puts " <td class=\"box-data-contents\">Artists: </td>" 682 puts " <td class=\"box-data-contents\" style=\"text-align:right\">$art</td>" 683 puts " </tr>" 684 puts " <tr>" 685 puts " <td class=\"box-data-contents\">Songs: </td>" 686 puts " <td class=\"box-data-contents\" style=\"text-align:right\">$son</td>" 687 puts " </tr>" 688 puts " <tr>" 689 puts " <td class=\"box-data-contents\">Runtime: </td>" 690 puts " <td class=\"box-data-contents\" style=\"text-align:right\">$run</td>" 691 puts " </tr>" 692 puts " </table>" 693 694 unset alb art son run 695 696 puts " </div>" 697 puts " </div>" 698 puts " </td>" 699 puts " </tr>" 700 puts " </table>" 701 puts " </td>\n" 702 703 704 puts " <td valign=\"top\">\n" 705 706 foreach genre [mysqlsel $db "SELECT DISTINCT genre 707 FROM $config(albums) 708 ORDER BY genre" -flatlist] { 709 710 # html id tags don't allow spaces in them, exchange with underscores 711 regsub -all " " $genre "_" genreID 712 713 set genreLink [makeLink "javascript:toggle('$genreID')" $genre "click to display genre $genre" "box-menu-link"] 714 715 puts " <div class=\"box\">" 716 puts " <div class=\"box-title\">$genreLink</div>" 717 puts " <div class=\"box-data\" id=\"$genreID\" style=\"visibility:hidden; height: 0px\">" 718 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" 719 720 foreach album [mysqlsel $db "SELECT artist, title, albumID 721 FROM $config(albums) 722 WHERE genre = '$genre' 723 ORDER BY artist, title" -list] { 724 725 set albumArtist [lindex $album 0] 726 set albumTitle [lindex $album 1] 727 set albumID [lindex $album 2] 728 729 set playLink [makeLink "$env(SCRIPT_NAME)?play=album[&]id=[set albumID]" "play"] 730 set randLink [makeLink "$env(SCRIPT_NAME)?play=album[&]id=[set albumID][&]style=random" "rand"] 731 set infoLink [makeLink "$env(SCRIPT_NAME)?info=album[&]id=[set albumID]" "info"] 732 733 # song collections will only have the randLink 734 if {$genre == "Other"} then {set playLink ""} 735 736 set panel "[set playLink][set randLink][set infoLink]" 737 738 puts " <tr>" 739 puts " <td class=\"box-data-contents\" valign=\"top\" align=\"center\" width=\"20\"></td>" 740 puts " <td class=\"box-data-contents\">$albumArtist - $albumTitle<br>$panel</td>" 741 puts " </tr>" 742 743 unset album albumArtist albumTitle albumID playLink randLink infoLink panel 744 } 745 746 puts " </table>" 747 puts " </div>" 748 puts " </div>\n" 749 750 unset genre genreID genreLink 751 } 752 753 puts " </td>\n" 754 755 if {$use_playcount || $use_last_played || $use_random_album} then { 756 puts " <td valign=\"top\">" 757 758 if {$use_last_played} then { 759 last_played 760 } 761 762 if {$use_random_album} then { 763 random_album 764 } 765 766 if {$use_playcount} then { 767 most_played 768 } 769 770 puts " </td>\n" 771 } 772 773 puts " </tr>" 774 puts " </table>" 775 776 } 777 778 "song*" { 779 # 780 # sort by song-title 781 # 782 783 # val = "song&by=title" or val = "song" 784 785 # sortby = {'title','artist','album','length'} 786 set sortby [lindex [split [lindex [split $val "&"] end] "="] end] 787 if {$sortby == "song"} then {set sortby "title"} 788 789 set seleLink [makeLink "javascript:document.forms\[0\].submit();" "selection" "play selected songs"] 790 791 puts " <table border=\"0\" align=\"center\">" 792 puts " <tr>\n" 793 794 puts " <td width=\"1\" valign=\"top\">" 795 puts " <table border=\"0\">" 796 puts " <tr>" 797 puts " <td>" 798 puts " <div class=\"box\">" 799 puts " <div class=\"box-title\">Play</div>" 800 puts " <div class=\"box-data\">" 801 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">" 802 puts " <tr>" 803 puts " <td class=\"box-data-contents\">$seleLink</td>" 804 puts " </tr>" 805 puts " </table>" 806 puts " </div>" 807 puts " </div>" 808 puts " </td>" 809 puts " </tr>" 810 puts " </table>" 811 puts " </td>\n" 812 813 puts " <td align=\"center\" valign=\"top\">" 814 puts " <table border=\"0\">" 815 puts " <tr>" 816 puts " <td>" 817 puts " <form action=\"$env(SCRIPT_NAME)?play=selection\" method=\"post\">" 818 puts " <div class=\"box\">" 819 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">" 820 puts " <tr>" 821 822 set titleLink [makeLink "$env(SCRIPT_NAME)?sort=song[&]by=title" "Title" "sort list by song titles" "box-menu-link"] 823 set artistLink [makeLink "$env(SCRIPT_NAME)?sort=song[&]by=artist" "Artist" "sort list by artists" "box-menu-link"] 824 set albumLink [makeLink "$env(SCRIPT_NAME)?sort=song[&]by=album" "Album" "sort list by album names" "box-menu-link"] 825 set lengthLink [makeLink "$env(SCRIPT_NAME)?sort=song[&]by=length" "Length" "sort list by length" "box-menu-link"] 826 827 puts " <td><div class=\"box-title\" style=\"text-align:left\"> </div></td>" 828 puts " <td><div class=\"box-title\" style=\"text-align:left\">$titleLink </div></td>" 829 puts " <td><div class=\"box-title\" style=\"text-align:left\">$artistLink </div></td>" 830 puts " <td><div class=\"box-title\" style=\"text-align:left\">$albumLink </div></td>" 831 puts " <td><div class=\"box-title\" style=\"text-align:right\">$lengthLink</div></td>" 832 puts " </tr>" 833 834 unset seleLink titleLink artistLink albumLink lengthLink 835 836 switch $sortby { 837 "artist" {set sqlOrderClause "ORDER BY artist, album, song"} 838 "album" {set sqlOrderClause "ORDER BY album, song, artist"} 839 "length" {set sqlOrderClause "ORDER BY $config(songs).length DESC, song, artist, album"} 840 default {set sqlOrderClause "ORDER BY song, artist, album"} 841 } 842 843 # display them 844 set wholeLength 0 845 set row_count 0 846 foreach song [mysqlsel $db "SELECT $config(songs).songID, $config(songs).albumID, $config(songs).artistID, $config(songs).length, 847 $config(songs).title AS song, $config(artists).name AS artist, $config(albums).title as album, 848 $config(albums).genre as genre 849 FROM $config(songs), $config(artists), $config(albums) 850 WHERE $config(artists).artistID = $config(songs).artistID 851 AND $config(songs).albumID = $config(albums).albumID 852 $sqlOrderClause" -list] { 853 854 set songID [lindex $song 0] 855 set albumID [lindex $song 1] 856 set artistID [lindex $song 2] 857 set length [lindex $song 3] 858 set title [lindex $song 4] 859 860 set artist [lindex $song 5] 861 set album [lindex $song 6] 862 set genre [lindex $song 7] 863 864 if {$genre == "Opera"} then { 865 unset song title length albumID songID artistID artist album genre 866 continue 867 } 868 869 # set background color 870 incr row_count 871 if {[expr $row_count % 2] != "0"} then { 872 set row_color $global_first_color 873 } else { 874 set row_color $global_second_color 875 } 876 877 set songLink [makeLink "$env(SCRIPT_NAME)?play=song[&]id=$songID" $title "play song"] 878 set albumLink [makeLink "$env(SCRIPT_NAME)?info=album[&]id=$albumID" $album "show album info"] 879 set artistLink [makeLink "$env(SCRIPT_NAME)?info=artist[&]id=[set artistID]" $artist "show all songs by this artist"] 880 881 set wholeLength [expr $wholeLength + $length] 882 puts " <tr>" 883 puts " <td valign=\"top\" class=\"box-data-contents\" style=\"background-color: $row_color\"><input type=\"checkbox\" name=\"$songID\"></td>" 884 puts " <td valign=\"top\" class=\"box-data-contents\" style=\"background-color: $row_color\">$songLink </td>" 885 puts " <td valign=\"top\" class=\"box-data-contents\" style=\"background-color: $row_color\">$artistLink </td>" 886 puts " <td valign=\"top\" class=\"box-data-contents\" style=\"background-color: $row_color\">$albumLink </td>" 887 puts " <td valign=\"top\" class=\"box-data-contents\" style=\"background-color: $row_color; text-align:right\">[transform_secs $length]</td>" 888 puts " </tr>" 889 890 unset song title length albumID songID artistID artist album songLink albumLink artistLink genre row_color 891 } 892 unset sqlOrderClause row_count 893 894 puts " </table>" 895 puts " </div>" 896 puts " </form>" 897 puts " </td>" 898 puts " </tr>" 899 puts " </table>" 900 puts " </td>\n" 901 902 puts " <td width=\"1\" valign=\"top\">" 903 puts " <table border=\"0\">" 904 puts " <tr>" 905 puts " <td>" 906 puts " <div class=\"box\">" 907 puts " <div class=\"box-title\">Runtime</div>" 908 puts " <div class=\"box-data\">" 909 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">" 910 puts " <tr>" 911 puts " <td class=\"box-data-contents\">[transform_secs $wholeLength]</td>" 912 puts " </tr>" 913 puts " </table>" 914 puts " </div>" 915 puts " </div>" 916 puts " </td>" 917 puts " </tr>" 918 puts " </table>" 919 puts " </td>\n" 920 921 puts " </tr>" 922 puts " </table>" 923 unset wholeLength sortby 924 } 925 926 "year" { 927 # 928 # sort by year 929 # 930 puts " <table border=\"0\" align=\"center\">" 931 puts " <tr>" 932 puts " <td align=\"center\">\n" 933 934 foreach year [mysqlsel $db "SELECT DISTINCT year FROM $config(albums) ORDER BY year DESC" -list] { 935 if {$year == 0} then {unset year; continue} 936 937 puts " <table>" 938 puts " <tr>" 939 puts " <td>" 940 puts " <div class=\"box\">" 941 puts " <div class=\"box-title\">$year</div>" 942 puts " <div class=\"box-data\">" 943 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" 944 945 foreach album [mysqlsel $db "SELECT albumID, artist, title 946 FROM $config(albums) 947 WHERE year = '$year' 948 ORDER BY artist, title" -list] { 949 950 set albumID [lindex $album 0] 951 set albumArtist [lindex $album 1] 952 set albumTitle [lindex $album 2] 953 954 set infoLink [makeLink "$env(SCRIPT_NAME)?info=album[&]id=[set albumID]" "info"] 955 956 puts " <tr>" 957 puts " <td class=\"box-data-contents\">$albumArtist - $albumTitle</td>" 958 puts " <td class=\"box-data-contents\" valign=\"top\"> $infoLink</td>" 959 puts " </tr>" 960 961 unset album albumArtist albumTitle albumID infoLink 962 } 963 964 puts " </table>" 965 puts " </div>" 966 puts " </div>" 967 puts " </td>" 968 puts " </tr>" 969 puts " </table>\n" 970 971 puts " <p></p>\n" 972 unset year 973 } 974 975 puts " </td>" 976 puts " </tr>" 977 puts " </table>" 978 } 979 980 default { 981 puts "Don't know how to sort by \"$val\"" 982 } 983 } 984 # disconnect from the database 985 mysqlclose $db 986 unset db 987 988 # emit the footer 989 footer 990 } 991 992 993 "info" { 994 # 995 # info pages 996 # 997 998 # connect to database 999 db_connect 1000 1001 # the header 1002 header 1003 1004 # val == "album&id=130" 1005 set val [split $val "&"] 1006 1007 set type [lindex $val 0] 1008 set id [lindex [split [lindex $val 1] "="] 1] 1009 1010 switch $type { 1011 1012 "album" { 1013 # 1014 # display album info 1015 # 1016 1017 # if val has a highlight argument (like "album&id=130&highlight=1547"), the highlight value will contain the 1018 # songID, if no such argument is given, it will be empty 1019 set songID_to_highlight [lindex [split [lindex $val 2] "="] 1] 1020 1021 # receive information from database 1022 set albumID $id 1023 set list [mysqlsel $db "SELECT artist, title, genre, year, playcount FROM $config(albums) WHERE albumID = '$albumID'" -flatlist] 1024 1025 if {$list == ""} then { 1026 # the specified ID doesn't exist 1027 1028 puts "no album with ID \"$albumID\"" 1029 unset albumID list 1030 } else { 1031 1032 set albumArtist [lindex $list 0] 1033 set albumTitle [lindex $list 1] 1034 set albumGenre [lindex $list 2] 1035 set albumYear [lindex $list 3] 1036 set albumPlayed [lindex $list 4] 1037 set albumLength "0" 1038 unset list 1039 1040 1041 # if we have a compilation, display just the artist's name ('various') 1042 # otherwise display a link to the artist's info page 1043 1044 if {$albumArtist == "Various"} then { 1045 set albumArtistLink "$albumArtist" 1046 } else { 1047 set artistID [mysqlsel $db "SELECT DISTINCT artistID FROM $config(songs) WHERE albumID = '$albumID'" -list] 1048 set albumArtistLink [makeLink "$env(SCRIPT_NAME)?info=artist[&]id=[set artistID]" $albumArtist "show all songs by this artist"] 1049 1050 unset artistID 1051 } 1052 1053 1054 # print first part of web page 1055 puts " <table border=\"0\" width=\"100%\">" 1056 puts " <tr>\n" 1057 1058 # print album info 1059 puts " <td valign=\"top\" width=\"33%\" align=\"right\">" 1060 puts " <table border=\"0\">" 1061 puts " <tr>" 1062 puts " <td>" 1063 puts " <div class=\"box\">" 1064 puts " <div class=\"box-title\">Info</div>" 1065 puts " <div class=\"box-data\">" 1066 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" 1067 puts " <tr>" 1068 puts " <td class=\"box-data-contents\">Artist:</td>" 1069 puts " <td class=\"box-data-contents\">$albumArtistLink</td>" 1070 puts " </tr>" 1071 puts " <tr>" 1072 puts " <td class=\"box-data-contents\" valign=\"top\">Album: </td>" 1073 puts " <td class=\"box-data-contents\">$albumTitle</td>" 1074 puts " </tr>" 1075 puts " <tr>" 1076 puts " <td class=\"box-data-contents\">Genre:</td>" 1077 puts " <td class=\"box-data-contents\">$albumGenre</td>" 1078 puts " </tr>" 1079 1080 if {$albumYear > 0} then { 1081 puts " <tr>" 1082 puts " <td class=\"box-data-contents\">Year:</td>" 1083 puts " <td class=\"box-data-contents\">$albumYear</td>" 1084 puts " </tr>" 1085 } 1086 1087 if {$use_playcount && $albumPlayed > 0} then { 1088 puts " <tr>" 1089 puts " <td class=\"box-data-contents\">played:</td>" 1090 puts " <td class=\"box-data-contents\">$albumPlayed</td>" 1091 puts " </tr>" 1092 } 1093 1094 puts " </table>" 1095 puts " </div>" 1096 puts " </div>" 1097 puts " </td>" 1098 puts " </tr>" 1099 puts " </table>" 1100 1101 # print play links 1102 set playLink [makeLink "$env(SCRIPT_NAME)?play=album[&]id=[set albumID]" "all" "play album"] 1103 set randLink [makeLink "$env(SCRIPT_NAME)?play=album[&]id=[set albumID][&]style=random" "rand"] 1104 set seleLink [makeLink "javascript:document.forms\[0\].submit();" "select"] 1105 1106 puts " <table border=\"0\">" 1107 puts " <tr>" 1108 puts " <td>" 1109 puts " <div class=\"box\">" 1110 puts " <div class=\"box-title\">Play</div>" 1111 puts " <div class=\"box-data\">" 1112 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">" 1113 puts " <tr>" 1114 if {$albumGenre != "Other"} then { 1115 puts " <td class=\"box-data-contents\">$playLink </td>" 1116 } 1117 puts " <td class=\"box-data-contents\">$randLink </td>" 1118 puts " <td class=\"box-data-contents\">$seleLink</td>" 1119 puts " </tr>" 1120 puts " </table>" 1121 puts " </div>" 1122 puts " </div>" 1123 puts " </td>" 1124 puts " </tr>" 1125 puts " </table>" 1126 1127 puts " </td>\n" 1128 1129 # print list of songs 1130 1131 puts " <td valign=\"top\" width=\"34%\" align=\"center\">" 1132 puts " <table border=\"0\">" 1133 puts " <tr>" 1134 puts " <td>" 1135 puts " <form action=\"$env(SCRIPT_NAME)?play=selection\" method=\"post\">" 1136 puts " <div class=\"box\">" 1137 puts " <div class=\"box-title\">Songs</div>" 1138 puts " <div class=\"box-data\">" 1139 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" 1140 1141 if {$albumGenre == "Other"} then { 1142 # sort alphabtically 1143 set sqlOrderClause "artist, song" 1144 } else { 1145 # sort by tracknr 1146 set sqlOrderClause "$config(songs).tracknr" 1147 } 1148 1149 # now emit the songs 1150 set row_count 0 1151 foreach song [mysqlsel $db "SELECT $config(artists).name AS artist, $config(songs).title AS song, $config(songs).songID, 1152 $config(songs).length, $config(songs).tracknr 1153 FROM $config(songs), $config(artists) 1154 WHERE albumID = '$albumID' AND $config(songs).artistID = $config(artists).artistID 1155 ORDER BY $sqlOrderClause" -list] { 1156 1157 set songArtist [lindex $song 0] 1158 set songTitle [lindex $song 1] 1159 set songID [lindex $song 2] 1160 set songLength [lindex $song 3] 1161 1162 # set background color 1163 incr row_count 1164 if {[expr $row_count % 2] != "0"} then { 1165 set row_color $global_first_color 1166 } else { 1167 set row_color $global_second_color 1168 } 1169 1170 if {$songID == $songID_to_highlight} then { 1171 set row_color $global_hilite_color 1172 } 1173 1174 # calculate complete runtime of the album 1175 set albumLength [expr $albumLength + $songLength] 1176 1177 # format length of song 1178 set songLength [transform_secs $songLength] 1179 1180 if {$songArtist != $albumArtist} then {set songTitle "$songArtist - $songTitle"} 1181 1182 set songLink [makeLink "$env(SCRIPT_NAME)?play=song[&]id=$songID" "<font color=\"#000000\">$songTitle</font>" "play song"] 1183 1184 puts " <tr>" 1185 puts " <td valign=\"top\" class=\"box-data-contents\" style=\"background-color: $row_color\"><input type=\"checkbox\" name=\"$songID\"></td>" 1186 puts " <td class=\"box-data-contents\" style=\"background-color: $row_color\">$songLink</td>" 1187 puts " <td valign=\"top\" class=\"box-data-contents\" style=\"background-color: $row_color; text-align: right\"> $songLength</td>" 1188 puts " </tr>" 1189 unset song songArtist songTitle songLength songID songLink row_color 1190 } 1191 unset sqlOrderClause row_count 1192 1193 puts " <tr>" 1194 puts " <td colspan=\"2\"></td>" 1195 puts " <td class=\"box-data-contents\" colspan=\"1\" valign=\"top\" style=\"text-align:right\">[transform_secs $albumLength]</td>" 1196 puts " </tr>" 1197 puts " </table>" 1198 1199 puts " </div>" 1200 puts " </div>" 1201 puts " </form>" 1202 puts " </td>" 1203 puts " </tr>" 1204 puts " </table>" 1205 puts " </td>\n" 1206 1207 # print cover 1208 puts " <td valign=\"top\" width=\"33%\" align=\"left\">" 1209 puts " <table border=\"0\">" 1210 puts " <tr>" 1211 puts " <td>" 1212 puts " <div class=\"box\">" 1213 puts " <div class=\"box-title\">Cover</div>" 1214 puts " <div class=\"box-data\" style=\"padding-left: 0px; padding-right: 0px; padding-bottom: 0px\">" 1215 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" 1216 puts " <tr>" 1217 puts " <td class=\"box-data-contents\"><img src=\"$env(SCRIPT_NAME)?cover=$albumID\" title=\"$albumArtist - $albumTitle\" alt=\"$albumArtist - $albumTitle\"></td>" 1218 puts " </tr>" 1219 puts " </table>" 1220 puts " </div>" 1221 puts " </div>" 1222 puts " </td>" 1223 puts " </tr>" 1224 puts " </table>" 1225 puts " </td>\n" 1226 1227 # print rest of web page 1228 puts " </tr>" 1229 puts " </table>" 1230 1231 unset seleLink playLink randLink 1232 unset albumID albumArtist albumArtistLink albumTitle albumGenre albumYear albumPlayed albumLength 1233 } 1234 unset songID_to_highlight 1235 } 1236 1237 "artist" { 1238 # 1239 # display artist info 1240 # 1241 1242 # receive artist name 1243 set artistID $id 1244 set artistName [lindex [mysqlsel $db "SELECT name FROM $config(artists) WHERE artistID = '$artistID'" -flatlist] 0] 1245 1246 if {$artistName == ""} then { 1247 # the specified ID doesn't exist 1248 1249 puts "no artist with ID \"$artistID\"" 1250 unset artistID artistName 1251 } else { 1252 1253 # print first part of web page 1254 puts " <table border=\"0\" width=\"100%\">" 1255 puts " <tr>\n" 1256 1257 # print play links 1258 1259 set playLink [makeLink "$env(SCRIPT_NAME)?play=artist[&]id=[set artistID]" "all" "play all songs sorted by album and tracknr"] 1260 set sortLink [makeLink "$env(SCRIPT_NAME)?play=artist[&]id=[set artistID][&]style=sorted" "sort" "play all songs sorted by title"] 1261 set randLink [makeLink "$env(SCRIPT_NAME)?play=artist[&]id=[set artistID][&]style=random" "rand" "play all songs in random order"] 1262 set seleLink [makeLink "javascript:document.forms\[0\].submit();" "select"] 1263 1264 1265 1266 puts " <td width=\"33%\" valign=\"top\" align=\"right\">" 1267 puts " <table border=\"0\">" 1268 puts " <tr>" 1269 puts " <td>" 1270 puts " <div class=\"box\">" 1271 puts " <div class=\"box-title\">Play</div>" 1272 puts " <div class=\"box-data\">" 1273 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">" 1274 puts " <tr>" 1275 puts " <td class=\"box-data-contents\">$playLink </td>" 1276 puts " <td class=\"box-data-contents\">$sortLink </td>" 1277 puts " <td class=\"box-data-contents\">$randLink </td>" 1278 puts " <td class=\"box-data-contents\">$seleLink</td>" 1279 puts " </tr>" 1280 puts " </table>" 1281 puts " </div>" 1282 puts " </div>" 1283 puts " </td>" 1284 puts " </tr>" 1285 puts " </table>" 1286 puts " </td>\n" 1287 1288 1289 # print songs/albums 1290 puts " <td width=\"34%\" valign=\"top\" align=\"center\">" 1291 puts " <table border=\"0\">" 1292 puts " <tr>" 1293 puts " <td>" 1294 puts " <form action=\"$env(SCRIPT_NAME)?play=selection\" method=\"post\">" 1295 1296 set artistLength 0 1297 set artistNrSongs 0 1298 set artistNrAlbums 0 1299 1300 # all albums from this artist 1301 foreach album [mysqlsel $db "SELECT DISTINCT $config(songs).albumID, $config(albums).title AS title 1302 FROM $config(songs), $config(albums) 1303 WHERE artistID = '$artistID' AND $config(songs).albumID = $config(albums).albumID 1304 ORDER BY title" -list] { 1305 1306 set albumID [lindex $album 0] 1307 set albumTitle [lindex $album 1] 1308 1309 set albumLink [makeLink "$env(SCRIPT_NAME)?info=album[&]id=$albumID" $albumTitle "show album info" "box-menu-link"] 1310 1311 puts " <div class=\"box\">" 1312 puts " <div class=\"box-title\">$albumLink</div>" 1313 puts " <div class=\"box-data\">" 1314 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">" 1315 1316 # each song of those albums (of this artist) 1317 set row_count 0 1318 foreach song [mysqlsel $db "SELECT tracknr, title, length, songID 1319 FROM $config(songs) 1320 WHERE artistID = '$artistID' AND albumID = '$albumID' 1321 ORDER BY tracknr" -list] { 1322 1323 set trackNr [lindex $song 0] 1324 set songTitle [lindex $song 1] 1325 set songLength [lindex $song 2] 1326 set songID [lindex $song 3] 1327 1328 # set background color 1329 incr row_count 1330 if {[expr $row_count % 2] != "0"} then { 1331 set row_color $global_first_color 1332 } else { 1333 set row_color $global_second_color 1334 } 1335 1336 # calculate complete runtime of this artist 1337 set artistLength [expr $artistLength + $songLength] 1338 1339 # format length of song 1340 set songLength [transform_secs $songLength] 1341 1342 set songLink [makeLink "$env(SCRIPT_NAME)?play=song[&]id=$songID" "<font color=\"#000000\">$songTitle</font>" "play song"] 1343 1344 puts " <tr>" 1345 puts " <td valign=\"top\" class=\"box-data-contents\" style=\"background-color: $row_color\" width=\"1\"><input type=\"checkbox\" name=\"$songID\"></td>" 1346 puts " <td class=\"box-data-contents\" style=\"background-color: $row_color\">$songLink</td>" 1347 puts " <td valign=\"top\" class=\"box-data-contents\" style=\"background-color: $row_color; text-align:right\"> $songLength</td>" 1348 puts " </tr>" 1349 1350 set artistNrSongs [expr $artistNrSongs + 1] 1351 1352 unset song trackNr songTitle songLength songID songLink row_color 1353 } 1354 unset row_count 1355 1356 puts " </table>" 1357 puts " </div>" 1358 puts " </div>" 1359 puts " <p></p>" 1360 1361 set artistNrAlbums [expr $artistNrAlbums + 1] 1362 1363 unset album albumID albumTitle albumLink 1364 } 1365 1366 puts " </form>" 1367 puts " </td>" 1368 puts " </tr>" 1369 puts " </table>" 1370 puts " </td>\n" 1371 1372 # stats 1373 puts " <td width=\"33%\" valign=\"top\" align=\"left\">" 1374 puts " <table border=\"0\">" 1375 puts " <tr>" 1376 puts " <td>" 1377 puts " <div class=\"box\">" 1378 puts " <div class=\"box-title\">$artistName</div>" 1379 puts " <div class=\"box-data\">" 1380 puts " <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">" 1381 puts " <tr>" 1382 puts " <td class=\"box-data-contents\">Nr of Songs </td>" 1383 puts " <td class=\"box-data-contents\">$artistNrSongs</td>" 1384 puts " </tr>" 1385 puts " <tr>" 1386 puts " <td class=\"box-data-contents\">Nr of Albums: </td>" 1387 puts " <td class=\"box-data-contents\">$artistNrAlbums</td>" 1388 puts " </tr>" 1389 puts " <tr>" 1390 puts " <td class=\"box-data-contents\">Total Runtime: </td>" 1391 puts " <td class=\"box-data-contents\">[transform_secs $artistLength]</td>" 1392 puts " </tr>" 1393 puts " </table>" 1394 puts " </div>" 1395 puts " </div>" 1396 puts " </td>" 1397 puts " </tr>" 1398 puts " </table>" 1399 puts " </td>\n" 1400 1401 # print rest of web page 1402 puts " </tr>" 1403 puts " </table>" 1404 1405 1406 unset artistID artistName 1407 unset seleLink playLink sortLink randLink artistLength artistNrSongs artistNrAlbums 1408 } 1409 } 1410 1411 default { 1412 puts "Don't have information of type \"$type\"" 1413 } 1414 1415 } 1416 1417 # disconnect from the database 1418 mysqlclose $db 1419 unset db 1420 1421 # emit the footer 1422 footer 1423 1424 unset type id 1425 } 1426 1427 1428 "cover" { 1429 # 1430 # returns the image for this album 1431 # 1432 1433 # connect to database 1434 db_connect 1435 1436 # gets fs path for the album 1437 set path [mysqlsel $db "SELECT directory FROM $config(albums) WHERE albumID = '$val'" -list] 1438 1439 # check whether there's an cover for that album 1440 set coverReturned no 1441 foreach ext {png jpg jpeg gif} { 1442 set file [file join $path "cover.$ext"] 1443 1444 if {[file exists $file] && [file readable $file] && !$coverReturned} then { 1445 # 1446 # cover was found, now display it 1447 # 1448 1449 if {$ext == "jpg"} then {set ext "jpeg"} 1450 1451 # read image 1452 set img [open $file r] 1453 1454 # emit image 1455 1456 puts "Content-type: image/[set ext]\n" 1457 fconfigure $img -translation binary -encoding binary 1458 fconfigure stdout -translation binary -encoding binary 1459 fcopy $img stdout 1460 1461 # close image 1462 close $img 1463 unset img 1464 1465 # prevent further covers from being emitted 1466 set coverReturned yes 1467 1468 unset file ext 1469 break 1470 } 1471 unset file ext 1472 } 1473 unset path 1474 1475 1476 if {!$coverReturned} then { 1477 # no cover was returned -> no one was available -> return a standard image 1478 1479 # empty image 1480 # set img "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAADUlEQVR42mNgYGBgAAAABQABeqhXUAAAAABJRU5ErkJggg==" 1481 # puts "Content-type: image/png\n" 1482 1483 # 'no image available' image 1484 set img "R0lGODlhWgBaALMAAMrKynJycqOjo4qKirq6utnZ2ZaWlvX19ebm5v///wAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAABaAFoAAAT/MMlJq7046827/2AojmRpnmiqrmzrvnAsz3Rt33iu73zv/8CgcEgsGo/IpHLJbDqf0KjUiKhar9isdsvtYl3esHjcBSOQVTP63Eof3Sx4Ua6iD+0ofFBv4v/8JHQIBQcSBWwXgzGAI3QEAQQSkBmPi4grjgEBZ5MJAAQAFIpVn4MEbAcEpxIIoG6fBRaMIpkGBgmTj7oTlQaQAwECAgGFwY+EAQaPtwQDj6Gil3XSjwgBAJAH157EEr3MAQkFAYSE1qDdBAbaBAUCAxWzIZkJzZDjsfje4bb14fgHDAwYpipcPQPjBti6FU0NhUraJuUy6C9Bv0r4IEKyJgDbrW0A/6BNkAeCHrdIHrftswhOHDlrCicBEKaOmy+RrKSlkHeA0LxYrAyEMiBAQs9C8XTmURrjUTCkGUh+kIqDagerNrBu0Doy1lELXycc4sA1KtMPGMlZ0Dehk4ayGPAUAHXga5pWqxTpw3tm3CdonWAlOlvCji6FuCI5Ozcs1b+XkBon3JXLmcqGbXRWOTAsgTBrVWIdS3tINDm/nuFlu/dOFuFAOj36OgkPwYCB5Ejbxl1AX6V7ART2S+qQwkRJkwTcwjb3sbvlp7cJTIwrVEjXxScME9ht2BnZ10iDB5AQWCiZyS6PfN1I6di4hO3YCUs885rsROAOvm//DXta/+2gHzx2/uF3R4AlIZjDgEmR4eCDZWQG4YQUKjjFhRhmqOGGHHbo4YcghijiiCSWaOKJKKao4oostujiizCyGAEAOw==" 1485 puts "Content-type: image/gif\n" 1486 1487 puts -nonewline [::base64::decode $img] 1488 1489 unset img 1490 } 1491 1492 unset coverReturned 1493 1494 # disconnect from the database 1495 mysqlclose $db 1496 unset db 1497 1498 } 1499 1500 1501 "play" { 1502 # 1503 # a album/song was chosen, create a playlist und redirect the user to it 1504 # 1505 1506 # val == "album&id=130&style=sorted" 1507 1508 set val [split $val "&"] ;# {album id=130 style=sorted} 1509 1510 set type [lindex $val 0] ;# album 1511 set id [lindex [split [lindex $val 1] "="] 1] ;# 130 1512 set style [lindex [split [lindex $val 2] "="] 1] ;# sorted 1513 1514 1515 # 1516 # check whether style is allowed 1517 # 1518 1519 switch $type { 1520 1521 "album" { 1522 if {$style != "random" && $style != ""} then { 1523 header 1524 puts "style \"$style\" not allowed here" 1525 footer 1526 break 1527 } 1528 1529 } 1530 1531 "artist" { 1532 if {$style != "random" && $style != "sorted" && $style != ""} then { 1533 header 1534 puts "style \"$style\" not allowed here" 1535 footer 1536 break 1537 } 1538 } 1539 1540 default { 1541 if {$style != ""} then { 1542 header 1543 puts "style \"$style\" not allowed here" 1544 footer 1545 break 1546 } 1547 } 1548 } 1549 1550 # connect to database 1551 db_connect 1552 1553 switch $type { 1554 1555 "song" { 1556 # a single song was chosen 1557 1558 set list [mysqlsel $db "SELECT $config(songs).songID, $config(artists).name, $config(songs).title, $config(songs).length, 1559 $config(songs).file 1560 FROM $config(songs), $config(artists) 1561 WHERE songID = '$id' AND $config(songs).artistID = $config(artists).artistID" -flatlist] 1562 1563 if {$list == ""} then { 1564 header 1565 puts "no song with ID \"$id\"" 1566 footer 1567 } else { 1568 1569 set songID [lindex $list 0] 1570 set artist [lindex $list 1] 1571 set title [lindex $list 2] 1572 set length [lindex $list 3] 1573 set file [lindex $list 4] 1574 1575 send_playlist [list [list $songID $file $title $artist $length]] 1576 1577 # increase playcount 1578 if {$use_playcount && !$test_mode} then { 1579 set pc [mysqlsel $db "SELECT playcount FROM $config(songs) WHERE songID = '$songID'" -list] 1580 incr pc 1581 mysqlexec $db "UPDATE $config(songs) SET playcount='$pc' WHERE songID = '$songID'" 1582 unset pc 1583 } 1584 1585 unset songID artist title length file 1586 1587 } 1588 1589 unset list 1590 } 1591 1592 "album" { 1593 # an album was chosen 1594 1595 if {[mysqlsel $db "SELECT albumID FROM $config(albums) WHERE albumID = '$id'"] == 0} then { 1596 # album does not exist 1597 header 1598 puts "no album with ID \"$id\"" 1599 footer 1600 } else { 1601 1602 # get all songs 1603 set listOut [mysqlsel $db "SELECT $config(songs).songID, $config(songs).file, $config(songs).title, $config(artists).name, 1604 $config(songs).length 1605 FROM $config(songs), $config(artists) 1606 WHERE $config(songs).albumID = '$id' AND $config(artists).artistID = $config(songs).artistID 1607 ORDER BY $config(songs).tracknr" -list] 1608 1609 # randomize list? 1610 if {$style == "random"} then {set listOut [lrandomize $listOut]} 1611 1612 # emit playlist 1613 send_playlist $listOut 1614 unset listOut 1615 1616 # increase playcount 1617 if {$use_playcount && !$test_mode} then { 1618 set pc [mysqlsel $db "SELECT playcount FROM $config(albums) WHERE albumID = '$id'" -list] 1619 incr pc 1620 mysqlexec $db "UPDATE $config(albums) SET playcount='$pc' WHERE albumID = '$id'" 1621 unset pc 1622 } 1623 1624 # update last_played value 1625 if {$use_last_played && !$test_mode} then { 1626 set last_played [clock format [clock seconds] -format "%Y-%m-%d %T"] 1627 mysqlexec $db "UPDATE $config(albums) SET last_played='$last_played' WHERE albumID = '$id'" 1628 unset last_played 1629 } 1630 1631 1632 } 1633 } 1634 1635 "artist" { 1636 # play all songs of an artist 1637 1638 if {[mysqlsel $db "SELECT artistID FROM $config(songs) WHERE artistID = '$id'"] == 0} then { 1639 # artist does not exist 1640 header 1641 puts "no artist with ID \"$id\"" 1642 footer 1643 } else { 1644 1645 if {$style == "sorted"} then { 1646 # sort all songs by title 1647 set listOut [mysqlsel $db "SELECT $config(songs).songID, $config(songs).file, $config(songs).title, $config(artists).name, 1648 $config(songs).length 1649 FROM $config(songs), $config(artists) 1650 WHERE $config(songs).artistID = '$id' 1651 AND $config(songs).artistID = $config(artists).artistID 1652 ORDER BY $config(songs).title" -list] 1653 } else { 1654 # sort by albumName, then by tracknr 1655 set listOut [mysqlsel $db "SELECT $config(songs).songID, $config(songs).file, $config(songs).title, $config(artists).name, 1656 $config(songs).length 1657 FROM $config(songs), $config(artists), $config(albums) 1658 WHERE $config(songs).artistID = '$id' 1659 AND $config(songs).artistID = $config(artists).artistID 1660 AND $config(songs).albumID = $config(albums).albumID 1661 ORDER BY $config(albums).title, $config(songs).tracknr" -list] 1662 } 1663 1664 # randomize list? 1665 if {$style == "random"} then {set listOut [lrandomize $listOut]} 1666 1667 # emit playlist 1668 send_playlist $listOut 1669 1670 unset listOut 1671 } 1672 } 1673 1674 "selection" { 1675 # plays a selection of songs 1676 1677 if {![info exists env(CONTENT_LENGTH)] || $env(CONTENT_LENGTH) == 0} then { 1678 header 1679 puts "no selection was made" 1680 footer 1681 } else { 1682 # the songs were sent via the POST method 1683 # thus the list has to be read from standard input 1684 set songs [read stdin $env(CONTENT_LENGTH)] ;# songs == 1210=on&1214=on&1225=on 1685 regsub -all "=on" $songs "" songs ;# songs == 1210&1214&1225 1686 1687 # create playlist 1688 set songList {} 1689 foreach songID [split $songs "&"] { 1690 lappend songList [mysqlsel $db "SELECT $config(songs).songID, $config(songs).file, $config(songs).title, 1691 $config(artists).name, $config(songs).length 1692 FROM $config(songs), $config(artists) 1693 WHERE songID = '$songID' 1694 AND $config(songs).artistID = $config(artists).artistID" -flatlist] 1695 unset songID 1696 } 1697 unset songs 1698 1699 1700 # redirect to playlist 1701 send_playlist $songList 1702 1703 unset songList 1704 } 1705 } 1706 1707 default { 1708 header 1709 puts "Don't know how to play \"$type\"" 1710 footer 1711 } 1712 } 1713 1714 # disconnect from the database 1715 mysqlclose $db 1716 unset db 1717 1718 unset type id style 1719 } 1720 1721 1722 "stream" { 1723 # 1724 # stream the requested file 1725 # 1726 1727 # 1728 # the functionality to stream an ogg vorbis audio file is here, but somehow, it isn't liked by the audio 1729 # programs, so only mp3 files will arrive here, waiting to be streamed 1730 # 1731 1732 # connect to database 1733 db_connect 1734 1735 # get file name 1736 set file [mysqlsel $db "select file from $config(songs) where songID = '$val'" -list] 1737 1738 # disconnect from the database 1739 mysqlclose $db 1740 1741 # send mime type 1742 if {[file extension $file] == ".mp3"} then { 1743 puts "Content-Type: application/octet-stream" 1744 } else { 1745 puts "Content-Type: application/x-ogg" 1746 } 1747 1748 # send file name 1749 puts "Content-Disposition: attachment; filename=[file tail $file]" 1750 1751 # send file size 1752 puts "Content-Length: [file size $file]\n" 1753 1754 # send file 1755 set fd [open $file r] 1756 1757 fconfigure $fd -translation binary -encoding binary 1758 fconfigure stdout -translation binary -encoding binary 1759 1760 fcopy $fd stdout 1761 1762 close $fd 1763 1764 unset file fd 1765 1766 } 1767 1768 1769 default { 1770 header 1771 puts "Unknown command \"$cmd\"" 1772 footer 1773 } 1774 } 1775 1776 unset query cmd val 1777} err 1778if {$err != ""} then {puts "Content-Type: text/html\n\n<hr>\n<h1>Script Error</h1>\n<pre>\n$errorInfo\n</pre>\n<hr>"} 1779 1780 1781array unset config 1782unset test_mode use_playcount playcount_nr use_random_album use_last_played err 1783unset global_first_color global_second_color global_hilite_color 1784 1785exit 0