Index: mythweb/skins/default/music.css
===================================================================
--- mythweb/skins/default/music.css	(.../trunk/mythplugins)	(revision 0)
+++ mythweb/skins/default/music.css	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -0,0 +1,471 @@
+mp3act {
+	padding: 22px;
+	margin:0;
+	color: #333;
+	text-align: center;
+	font: 65% Verdana, Sans-serif;
+}
+
+h2.music{
+	font-size: 100%;
+	margin:0;
+	padding: 0 0 5px 0;
+
+}
+ul.music{
+	list-style-type: none;
+}
+a.music{
+	color: blue;
+}
+
+a.music:hover{
+	/*color: #fff;
+	background: #F21518;
+	text-decoration: none;*/
+	color: #F21518;
+}
+img{
+	border: 0;
+}
+input,select{
+	border: 1px solid #ccc;
+	border-color: #aaa #ccc #ccc #aaa;
+	background: #f3f3f3;
+	color: #555;
+	font-size: 100%;
+	padding: 2px 3px;
+	vertical-align: middle;
+
+}
+input.check{
+  border:0;
+  padding:0;
+  background: transparent;
+}
+select{
+	padding: 2px 0 2px 3px;
+}
+input:focus{
+	border: 1px solid #999;
+	background: #FBF9D3;
+	color: #000;
+	border-color: #777 #bbb #bbb #777;
+}
+
+input.btn,input.redbtn{
+	background: #244A79;
+	color: #fff;
+	padding: 2px;
+	border-color: #0E2F58;
+	font: normal 10px sans-serif;
+}
+input.redbtn{
+	background: #F21518;
+}
+input.redbtn:hover{
+	background: #BE0D0F;
+}
+input.btn:hover{
+	background: #0E2F58;
+}
+
+input.btn2{
+	font-weight: bold;
+	padding: 2px;
+}
+
+input.btn2:hover{
+	background: #eee;
+	border-color: #888;
+	color: #222;
+}
+
+.left{
+	float: left;
+}
+.right{
+	float: right;
+}
+.center{
+	text-align: center;
+}
+.clear{
+  clear: both;
+}
+.error{
+	color: #E63838;
+	font-weight: bold;
+}
+p#error{
+	color: #f20000;
+	font-weight: bold;
+}
+#breadcrumb{
+	height: 14px;
+	padding:2px 0 0 0;
+}
+#breadcrumb span{
+position: relative;
+}
+#breadcrumb span:hover ul{
+	display: block;
+}
+#breadcrumb ul{
+	z-index: 5;
+	border: 1px solid #333;
+	display: none;
+	top:12px;
+	left:0;
+	position: absolute;
+	background: transparent url("./img/music/libg.png");
+	color: #fff;
+	margin:-1px 0 0 0;
+	padding:0;
+	width: 150px;
+
+}
+#breadcrumb ul#letters{
+	left: -55px;
+	width: auto;
+}
+#breadcrumb span{
+	padding: 0;
+	margin:0;
+}
+#breadcrumb ul li{
+width: 100%;
+	padding:0;
+	margin:0;
+	z-index: 6;
+}
+#breadcrumb ul li a{
+	display: block;
+	padding: 2px 4px;
+	color: #fff;
+	margin:0;
+	z-index: 5;
+	text-decoration: none;
+	font-weight: normal;
+	font-size: 90%;
+}
+
+#breadcrumb ul#letters li{
+	float: left;
+
+}
+#breadcrumb ul#letters li a{
+	float: left;
+
+}
+#breadcrumb ul li a:hover{
+	background: #FCF7A5;
+	color: #000;
+}
+#breadcrumb ul#letters li a:hover{
+	background: #FCF7A5;
+	color: #000;
+}
+#topinfo{
+
+	font-size: 90%;
+	color: #666;
+	text-align: left;
+	padding: 0 0 4px 0;
+
+}
+p.pad{
+	padding: 0px 8px;
+}
+
+#wrap{
+	/*background: #fff;
+	border: 1px solid #ccc;*/
+	text-align: left;
+	padding: 0px;
+	margin:0;
+	position: relative;
+
+	color: #333;
+}
+
+#header{
+	position: relative;
+/*	background: #0E2F58;*/
+	height: 50px;
+	color: #fff;
+	padding: 8px 0 0px 15px;
+}
+#header #controls{
+	float: right;
+	background: transparent;
+	height: 48px;
+	margin-right: 8px;
+	width: 48%;
+	font-size: 90%;
+	line-height: 1.1em;
+	color: #fff;
+}
+
+#header #controls .buttons{
+	float: left;
+	margin: 3px 5px 0 5px;
+}
+#header #controls .current{
+	float: left;
+	margin-top: 3px;
+
+}
+#header h1{
+	color: #9ABEE5;
+	padding: 0;
+	margin:0;
+	font-size: 150%;
+}
+ul#nav{
+	position: absolute;
+	bottom:0;
+	list-style-type: none;
+	margin:0;
+	padding:0;
+}
+ul#nav li{
+	float: left;
+	margin-right: 5px;
+}
+ul#nav li a{
+	display: block;
+	background: #265990; /* #244A79; */
+	padding: 4px 5px;
+	color: #dedede;
+	text-decoration: none;
+	margin:0;
+}
+ul#nav li a:hover{
+	background: #416899;
+	color: #fff;
+}
+ul#nav li a.c{
+	background: #fff;
+	color: #F48603;
+	font-weight: bold;
+}
+#loading{
+	display: none;
+	position: absolute;
+	top: 80px;
+	color: #78B855;
+	padding: 10px;
+	background: #CCFF99;
+	border: 1px solid #78B855;
+	z-index: 4;
+	left: 30%;
+}
+#loading h1{
+  font-size: 140%;
+}
+#left{
+	float: left;
+	width: 48%;
+	margin: 15px 0 25px 15px;
+}
+#right{
+	float: right;
+	width: 45%;
+	margin: 15px 15px 25px 0;
+
+}
+.box{
+	background: #E0E0E0;
+	border: 1px solid #ccc;
+	padding: 0 0 8px 0;
+	position: relative;
+}
+#box_extra{
+	display: none;
+	z-index: 2;
+	position: absolute;
+	top: 25px;
+	left:5%;
+	width: 450px;
+	height: 230px;
+	background: transparent url("./img/music/libg.png");
+	color: #fff;
+	font-size: 110%;
+	padding: 5px;
+}
+#box_extra h2{
+	font-size: 120%;
+}
+#box_extra input{
+	background: #333;
+	border-color: #999;
+	color: #fff;
+}
+
+#box_extra select{
+	background: #333;
+	border-color: #999;
+	color: #fff;
+}
+
+.box ul{
+	margin: 0 10px;
+	padding: 0px 0px;
+	background: #f3f3f3;
+	clear: both;
+}
+.box ul li{
+	padding: 2px 0 1px 4px;
+	border: 1px solid transparent;
+	border-width: 1px 0px 1px 0px;
+	position: relative;
+	background: #f3f3f3;
+}
+
+.box ul li.alt{
+	background: #DEE6EC;
+}
+.box ul li span.user{
+	float: left;
+	width: 200px;
+}
+.box ul li small{
+	color: #888;
+	letter-spacing: -1px;
+}
+
+.box ul li span.links a{
+	text-decoration: underline;
+	color: blue;
+}
+.box ul li span.links a:hover{
+	color: red;
+}
+.box ul li:hover{
+	background: #FCF7A5;
+	color: #000;
+	border-color: #999;
+}
+.box ul li.currentplay{
+	background: #96D1EF;
+	color: #000;
+	border-color: #666;
+}
+
+.box ul li p{
+	z-index:5;
+	display: none;
+	position: absolute;
+	top: 7px;
+	font-size: 90%;
+	padding: 2px;
+	right: 15px;
+	width: 145px;
+	background: transparent url("./img/music/libg.png");
+	color: #fff;
+}
+
+.box ul li:hover p{
+	display: block;
+}
+
+.box ul li a{
+	text-decoration: none;
+	color: #333;
+}
+.box ul li a:hover{
+	color: #000;
+}
+.box ul#letters{
+	height: 18px;
+	padding-left: 5px;
+}
+
+.box ul#letters li{
+	float: left;
+	padding: 2px 2px;
+	background: none;
+	border: 1px solid transparent;
+}
+
+.box ul#letters li:hover{
+	background: #FCF7A5;
+	border-color: #999;
+}
+
+.box p{
+	padding: 0 10px;
+	margin: 8px 0 4px 0;
+
+}
+.box p img{
+	display: block;
+	width: 60px;
+	float: right;
+	padding: 2px;
+	background: #f3f3f3;
+	border: 1px solid #999;
+	margin-bottom: 4px;
+}
+.box img#bigart{
+	display: none;
+	position: absolute;
+	z-index: 2;
+	background: #f3f3f3;
+	padding: 3px;
+	border: 1px solid #666;
+	top:10px;
+	right: 80px;
+}
+.box p img:hover{
+	border-color: #555;
+	cursor: pointer;
+}
+
+.box .head{
+	padding: 4px;
+	background: #ccc;
+}
+.box .head a{
+	background: #244A79;
+	color: #fff;
+	padding: 2px;
+	text-decoration: none;
+	font: normal 9px sans-serif;
+}
+.box .head a:hover{
+	background: #0E2F58;
+}
+.box .head a.red{
+	background: #F21518;
+}
+.box .head a.red:hover{
+	background: #BE0D0F;
+}
+.box .head h2{
+	font-size: 120%;
+	padding: 0;
+}
+.box h3{
+	padding: 0 0 0 0px;
+	margin: 0 10px 0 10px;
+	font-size: 120%;
+	border-bottom: 1px solid #ccc;
+}
+
+.loginbox{
+	width: 250px;
+	margin:0 auto;
+	background: #fff;
+	border: 1px solid #ccc;
+	text-align: left;
+}
+.loginbox p{
+	padding: 8px 15px;
+	margin:0;
+}
+.noborder{
+	background: transparent;
+	border:0;
+}
Index: mythweb/skins/default/img/music/ff_big.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/ff_big.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/default/img/music/libg.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/libg.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/x-png

Index: mythweb/skins/default/img/music/rew_big.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/rew_big.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/default/img/music/paypal_donate.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/paypal_donate.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/default/img/music/vol.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/vol.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/default/img/music/rem.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/rem.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/default/img/music/up.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/up.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/default/img/music/play.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/play.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/default/img/music/play_big.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/play_big.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/default/img/music/stop_big.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/stop_big.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/default/img/music/down.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/down.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/default/img/music/add.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/add.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/default/img/music/progress_bar.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/default/img/music/progress_bar.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/music.css
===================================================================
--- mythweb/skins/grey/music.css	(.../trunk/mythplugins)	(revision 0)
+++ mythweb/skins/grey/music.css	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -0,0 +1,471 @@
+mp3act {
+	padding: 22px;
+	margin:0;
+	color: #333;
+	text-align: center;
+	font: 65% Verdana, Sans-serif;
+}
+
+h2.music{
+	font-size: 100%;
+	margin:0;
+	padding: 0 0 5px 0;
+
+}
+ul.music{
+	list-style-type: none;
+}
+a.music{
+	color: blue;
+}
+
+a.music:hover{
+	/*color: #fff;
+	background: #F21518;
+	text-decoration: none;*/
+	color: #F21518;
+}
+img{
+	border: 0;
+}
+input,select{
+	border: 1px solid #ccc;
+	border-color: #aaa #ccc #ccc #aaa;
+	background: #f3f3f3;
+	color: #555;
+	font-size: 100%;
+	padding: 2px 3px;
+	vertical-align: middle;
+	
+}
+input.check{
+  border:0;
+  padding:0;
+  background: transparent;
+}
+select{
+	padding: 2px 0 2px 3px;
+}
+input:focus{
+	border: 1px solid #999;
+	background: #FBF9D3;
+	color: #000;
+	border-color: #777 #bbb #bbb #777;
+}
+
+input.btn,input.redbtn{
+	background: #244A79;
+	color: #fff;
+	padding: 2px;
+	border-color: #0E2F58;
+	font: normal 10px sans-serif;
+}
+input.redbtn{
+	background: #F21518;	
+}
+input.redbtn:hover{
+	background: #BE0D0F;
+}
+input.btn:hover{
+	background: #0E2F58;
+}
+
+input.btn2{
+	font-weight: bold;
+	padding: 2px;
+}
+
+input.btn2:hover{
+	background: #eee;
+	border-color: #888;
+	color: #222;
+}
+
+.left{
+	float: left;
+}
+.right{
+	float: right;
+}
+.center{
+	text-align: center;
+}
+.clear{
+  clear: both;
+}
+.error{
+	color: #E63838;
+	font-weight: bold;
+}
+p#error{
+	color: #f20000;
+	font-weight: bold;
+}
+#breadcrumb{
+	height: 14px;
+	padding:2px 0 0 0;
+}
+#breadcrumb span{
+position: relative;
+}
+#breadcrumb span:hover ul{
+	display: block;
+}
+#breadcrumb ul{
+	z-index: 5;
+	border: 1px solid #333;
+	display: none;
+	top:12px;
+	left:0;
+	position: absolute;
+	background: transparent url("./img/music/libg.png");
+	color: #fff;
+	margin:-1px 0 0 0;
+	padding:0;
+	width: 150px;
+	
+}
+#breadcrumb ul#letters{
+	left: -55px;
+	width: auto;
+}
+#breadcrumb span{
+	padding: 0;
+	margin:0;
+}
+#breadcrumb ul li{
+width: 100%;
+	padding:0;
+	margin:0;
+	z-index: 6;
+}
+#breadcrumb ul li a{
+	display: block;
+	padding: 2px 4px;
+	color: #fff;
+	margin:0;
+	z-index: 5;
+	text-decoration: none;
+	font-weight: normal;
+	font-size: 90%;
+}
+
+#breadcrumb ul#letters li{
+	float: left;
+
+}
+#breadcrumb ul#letters li a{
+	float: left;
+	
+}
+#breadcrumb ul li a:hover{
+	background: #FCF7A5;
+	color: #000;
+}
+#breadcrumb ul#letters li a:hover{
+	background: #FCF7A5;
+	color: #000;
+}
+#topinfo{
+	
+	font-size: 90%;
+	color: #666;
+	text-align: left;
+	padding: 0 0 4px 0;
+	
+}
+p.pad{
+	padding: 0px 8px;
+}
+
+#wrap{
+	/*background: #fff;
+	border: 1px solid #ccc;*/
+	text-align: left;
+	padding: 0px;
+	margin:0;
+	position: relative;
+
+	color: #333;
+}
+
+#header{
+	position: relative;
+/*	background: #0E2F58;*/
+	height: 50px;
+	color: #fff;
+	padding: 8px 0 0px 15px;
+}
+#header #controls{
+	float: right;
+	background: transparent;
+	height: 48px;
+	margin-right: 8px;
+	width: 48%;
+	font-size: 90%;
+	line-height: 1.1em;
+	color: #fff;
+}
+
+#header #controls .buttons{
+	float: left;
+	margin: 3px 5px 0 5px;
+}
+#header #controls .current{
+	float: left;
+	margin-top: 3px;
+	
+}
+#header h1{
+	color: #9ABEE5;
+	padding: 0;
+	margin:0;
+	font-size: 150%;
+}
+ul#nav{
+	position: absolute;
+	bottom:0;
+	list-style-type: none;
+	margin:0;
+	padding:0;
+}
+ul#nav li{
+	float: left;
+	margin-right: 5px;
+}
+ul#nav li a{
+	display: block;
+	background: #666666; //#244A79;
+	padding: 4px 5px;
+	color: #ffffff;
+	text-decoration: none;
+	margin:0;
+}
+ul#nav li a:hover{
+	background: #416899;
+	color: #fff;
+}
+ul#nav li a.c{
+	background: #fff;
+	color: #F48603;
+	font-weight: bold;
+}
+#loading{
+	display: none;
+	position: absolute;
+	top: 80px;
+	color: #78B855;
+	padding: 10px;
+	background: #CCFF99;
+	border: 1px solid #78B855;
+	z-index: 4;
+	left: 30%;
+}
+#loading h1{
+  font-size: 140%;
+}
+#left{
+	float: left;
+	width: 48%;
+	margin: 15px 0 25px 15px;
+}
+#right{
+	float: right;
+	width: 45%;
+	margin: 15px 15px 25px 0;
+
+}
+.box{
+	background: #E0E0E0;
+	border: 1px solid #ccc;
+	padding: 0 0 8px 0;
+	position: relative;
+}
+#box_extra{
+	display: none;
+	z-index: 2;
+	position: absolute;
+	top: 25px;
+	left:5%;
+	width: 450px;
+	height: 190px;
+	background: transparent url("./img/music/libg.png");
+	color: #fff;
+	font-size: 110%;
+	padding: 5px;
+}
+#box_extra h2{
+	font-size: 120%;
+}
+#box_extra input{
+	background: #333;
+	border-color: #999;
+	color: #fff;
+}
+
+#box_extra select{
+	background: #333;
+	border-color: #999;
+	color: #fff;
+}
+
+.box ul{
+	margin: 0 10px;
+	padding: 0px 0px;
+	background: #f3f3f3;
+	clear: both;
+}
+.box ul li{
+	padding: 2px 0 1px 4px;
+	border: 1px solid transparent;
+	border-width: 1px 0px 1px 0px;
+	position: relative;
+	background: #f3f3f3; 
+}
+
+.box ul li.alt{
+	background: #DEE6EC;
+}
+.box ul li span.user{
+	float: left;
+	width: 200px;
+}
+.box ul li small{
+	color: #888;
+	letter-spacing: -1px;
+}
+
+.box ul li span.links a{
+	text-decoration: underline;
+	color: blue;
+}
+.box ul li span.links a:hover{
+	color: red;
+}
+.box ul li:hover{
+	background: #FCF7A5;
+	color: #000;
+	border-color: #999;
+}
+.box ul li.currentplay{
+	background: #96D1EF;
+	color: #000;
+	border-color: #666;
+}
+
+.box ul li p{
+	z-index:5;
+	display: none;
+	position: absolute;
+	top: 7px;
+	font-size: 90%;
+	padding: 2px;
+	right: 15px;
+	width: 145px;
+	background: transparent url("./img/music/libg.png");
+	color: #fff;
+}
+
+.box ul li:hover p{
+	display: block;
+}
+
+.box ul li a{
+	text-decoration: none;
+	color: #333;
+}
+.box ul li a:hover{
+	color: #000;
+}
+.box ul#letters{
+	height: 18px;
+	padding-left: 5px;
+}
+
+.box ul#letters li{
+	float: left;
+	padding: 2px 2px;
+	background: none;
+	border: 1px solid transparent;
+}
+
+.box ul#letters li:hover{
+	background: #FCF7A5;
+	border-color: #999;
+}
+
+.box p{
+	padding: 0 10px;
+	margin: 8px 0 4px 0;
+
+}
+.box p img{
+	display: block;
+	width: 60px;
+	float: right;
+	padding: 2px;
+	background: #f3f3f3;
+	border: 1px solid #999;
+	margin-bottom: 4px;	
+}
+.box img#bigart{
+	display: none;
+	position: absolute;
+	z-index: 2;
+	background: #f3f3f3;
+	padding: 3px;
+	border: 1px solid #666;
+	top:10px;
+	right: 80px;
+}
+.box p img:hover{
+	border-color: #555;
+	cursor: pointer;
+}
+
+.box .head{
+	padding: 4px;
+	background: #ccc;
+}
+.box .head a{
+	background: #244A79;
+	color: #fff;
+	padding: 2px;
+	text-decoration: none;
+	font: normal 9px sans-serif;
+}
+.box .head a:hover{
+	background: #0E2F58;
+}
+.box .head a.red{
+	background: #F21518;
+}	
+.box .head a.red:hover{
+	background: #BE0D0F;
+}
+.box .head h2{
+	font-size: 120%;
+	padding: 0;
+}
+.box h3{
+	padding: 0 0 0 0px;
+	margin: 0 10px 0 10px;
+	font-size: 120%;
+	border-bottom: 1px solid #ccc;
+}
+
+.loginbox{
+	width: 250px;
+	margin:0 auto;
+	background: #fff;
+	border: 1px solid #ccc;
+	text-align: left;
+}
+.loginbox p{
+	padding: 8px 15px;
+	margin:0;
+}
+.noborder{
+	background: transparent;
+	border:0;
+}
Index: mythweb/skins/grey/img/music/ff_big.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/ff_big.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/img/music/libg.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/libg.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/x-png

Index: mythweb/skins/grey/img/music/rew_big.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/rew_big.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/img/music/paypal_donate.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/paypal_donate.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/img/music/vol.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/vol.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/img/music/rem.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/rem.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/img/music/up.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/up.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/img/music/play.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/play.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/img/music/play_big.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/play_big.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/img/music/stop_big.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/stop_big.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/img/music/down.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/down.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/img/music/add.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/add.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/skins/grey/img/music/progress_bar.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: mythweb/skins/grey/img/music/progress_bar.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream
Name: svn:mimetype
   + image/gif

Index: mythweb/modules/music/mp3act_main.php
===================================================================
--- mythweb/modules/music/mp3act_main.php	(.../trunk/mythplugins)	(revision 0)
+++ mythweb/modules/music/mp3act_main.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -0,0 +1,109 @@
+<?php
+/*************************************************************************
+*  mp3act Digital Music System - A streaming and jukebox solution for your digital music collection
+*  http://www.mp3act.net
+*  Copyright (C) 2005 Jon Buda (www.jonbuda.com)
+*
+*  This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+
+*  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+*
+*  You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*************************************************************************/
+
+require_once("modules/music/mp3act_functions.php");
+require_once("modules/music/mp3act_sajax.php");
+
+GarbageCollector();
+
+$sajax_remote_uri = 'http://'.$_SERVER['HTTP_HOST'].substr($_SERVER['SCRIPT_NAME'],0,strlen($_SERVER['SCRIPT_NAME']) - 11).'music/';
+$sajax_request_type = "POST";
+sajax_init();
+sajax_export("getplaylistnames","musicLookup","playlist_rem","playlist_add","playlistInfo","clearPlaylist","buildBreadcrumb","play","playlist_move","searchMusic","viewPlaylist","getDropDown","savePlaylist","getRandItems","randAdd","deletePlaylist");
+sajax_handle_client_request();
+
+require 'modules/_shared/tmpl/'.tmpl.'/header.php';
+?>
+<link rel="Stylesheet" href="<?php echo skin_url ?>music.css" type="text/css" />
+
+	<script type="text/javascript">
+			var page = 'search';
+			var mode = '<?php echo $_SESSION['sess_playmode']; ?>';
+			var bc_parenttype = '';
+			var bc_parentitem = '';
+			var bc_childtype = '';
+			var bc_childitem = '';
+			var prevpage = '';
+			var currentpage = 'search';
+			var nowplaying = 0;
+			var isplaying = 0;
+			var clearbc = 1;
+
+  function getCookie( cookieName ) {
+      var cookies = document.cookie;
+      var substr1 = cookies.split( cookieName+'=' )
+          if ( substr1 == cookies ) return -1;
+      var substr2 = substr1[1].split( ';' );
+      var len1 = substr1[0].length + cookieName.length + 1;
+      var len2 = substr2[0].length
+      return cookies.substring( len1, len1+len2 );
+  }
+
+  function checkPlaylistLoad( playlistId, unsavedPlaylistId ) {
+    var pl_id = getCookie('mp3act_playlist_id');
+    if (pl_id < 1) return true;
+    if (playlistId == pl_id) {
+        alert ('<?php echo t('This playlist is already loaded!'); ?>');
+        return false;
+    }
+    if (unsavedPlaylistId == pl_id) {
+        return confirm('<?php echo t('This will overwrite your current, unsaved playlist. Are you sure you want to continue?'); ?>');
+    }
+    return true;
+  }
+	<?php sajax_show_javascript(); ?></script>
+	<script type="text/javascript" src="<?php echo root; ?>music/mp3act_js.js.php"></script>
+	<script type="text/javascript" src="<?php echo root; ?>music/mp3act_fat.js"></script>
+
+<div id="wrap">
+	<div id="header">
+		<div id="controls">
+
+		</div>
+		<h1 id="pagetitle"></h1>
+		<ul class="music" id="nav">
+			<li><a href="#" id="search_music" onclick="switchPage('search'); return false;" title="<?php echo t('Search the Music Database'); ?>"><?php echo t('Search'); ?></a></li>
+			<li><a href="#" id="browse" onclick="switchPage('browse'); return false;"  title="<?php echo t('Browse the Music Database'); ?>" class="c"><?php echo t('Browse'); ?></a></li>
+			<li><a href="#" id="random" onclick="switchPage('random'); return false;" title="Create Random Mixes"><?php echo t('Random'); ?></a></li>
+			<li><a href="#" id="playlists" onclick="switchPage('playlists'); return false;" title="<?php echo t('Load Saved Playlists'); ?>"><?php echo t('Playlists'); ?></a></li>
+			<li><a href="#" id="stats" onclick="switchPage('stats'); return false;" title="<?php echo t('View Server Statistics'); ?>"><?php echo t('Stats'); ?></a></li>
+            <!-- <li><?php echo t('Streaming Quality'); ?>: <select id="stream_quality"><option value="high"><?php echo t('High'); ?></option></select></li> -->
+		</ul>
+
+	</div>
+	<div id="loading"><h1><?php echo t("LOADING"); ?>...</h1></div>
+	<div id="left">
+		<h2 id="breadcrumb"></h2>
+		<div class="box" id="info">
+		</div>
+	</div>
+
+	<div id="right">
+			<div class="box">
+				<div class="head">
+					<div class="right"><a href="#" onclick="play('pl',0); return false;" title="<?php echo t('Play This Playlist Now'); ?>"><?php echo t('Play'); ?></a> <a href="#" onclick="savePL('open',0); return false;" title="<?php echo t('Save or Rename the Current Playlist'); ?>"><?php echo t('Save/Rename'); ?></a> <a href="#" onclick="plclear(); return false;" class="red" title="<?php echo t('Create a New Playlist'); ?>"><?php echo t('New'); ?></a></div>
+					<h2 id="pl_title"></h2><span id="pl_info"></span>
+				</div>
+			<ul class="music" id="playlist">
+
+			</ul>
+
+			<div id="box_extra"> </div>
+			</div>
+	</div>
+	<div class="clear"></div>
+</div>
+<iframe src="<?php echo root; ?>music/mp3act_hidden.php" frameborder="0" height="0" width="0" id="hidden" name="hidden"></iframe>
+<?
+require 'modules/_shared/tmpl/'.tmpl.'/footer.php';
+?>
\ No newline at end of file
Index: mythweb/modules/music/handler.php
===================================================================
--- mythweb/modules/music/handler.php	(.../trunk/mythplugins)	(revision 65)
+++ mythweb/modules/music/handler.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -13,297 +13,23 @@
  *
 /**/
 
-// Make sure the music directory exists
-    if (file_exists('data/music')) {
-    // File is not a directory or a symlink
-        if (!is_dir('data/music') && !is_link('data/music')) {
-            custom_error('An invalid file exists at data/music.  Please remove it in'
-                        .' order to use the music portions of MythWeb.');
-        }
-    }
-// Create the symlink, if possible.
-//
-// NOTE:  Errors have been disabled because if I turn them on, people hosting
-//        MythWeb on Windows machines will have issues.  I will turn the errors
-//        back on when I find a clean way to do so.
-//
-    else {
-        $dir = $db->query_col('SELECT data
-                                 FROM settings
-                                WHERE value="MusicLocation" AND hostname=?',
-                              hostname
-                             );
-        if ($dir) {
-            $ret = @symlink($dir, 'data/music');
-            if (!$ret) {
-                #custom_error("Could not create a symlink to $dir, the local MythMusic directory"
-                #            .' for this hostname ('.hostname.').  Please create a symlink to your'
-                #            .' MythMusic directory at data/music in order to use the music'
-                #            .' portions of MythWeb.');
-            }
-        }
-        else {
-            #custom_error('Could not find a value in the database for the MythMusic directory'
-            #            .' for this hostname ('.hostname.').  Please create a symlink to your'
-            #            .' MythMusic directory at data/music in order to use the music'
-            #            .' portions of MythWeb.');
-        }
-    }
-
-//
-//  Someday, music.php will let us stream
-//  entire playlists to any spot on planet earth
-//
-require_once tmpl_dir.'music.php';
-
-$mythmusic = new mythMusic();
-$mythmusic->display();
-
-class mythMusic {
-    var $filterPlaylist;
-    var $filterArtist;
-    var $filterAlbum;
-    var $filterGenre;
-    var $filterRank;
-    var $filterSonglist;
-    var $keepFilters;
-    var $filter;
-    var $totalCount;
-    var $offset;
-
-    var $result;
-
-
-    var $intid;
-    var $artist;
-    var $album;
-    var $title;
-    var $genre;
-    var $length;
-    var $rating;
-    var $filename;
-    var $urlfilename;
-
-    var $alphalink;
-    var $alphaoffset;
-
-    function mythMusic()
-    {
-        if($_GET['offset'] >=0 )
-            $this->offset=$_GET['offset'];
-        else
-            $this->offset=0;
-
-        /**** If alphalink set, then change offset to new value ****/
-        if ($_GET['alphalink']) {
-            $alphalink = $_GET['alphalink'];
-            $result=mysql_query("select count(1) from musicmetadata where upper(artist) < ".escape($alphalink));
-            $alphaoffset=mysql_fetch_row($result);
-            $this->offset=$alphaoffset[0];
-            mysql_free_result($result);
-        }
-
-        if($_GET['filterPlaylist'])
-        {
-            $this->filterPlaylist=$_GET['filterPlaylist'];
-            $_GET['filterPlaylist'];
-        }
-        else
-            $this->filterPlaylist="_All_";
-
-        if($_GET['filterArtist'])
-        {
-            $this->filterArtist=$_GET['filterArtist'];
-        }
-        else
-            $this->filterArtist="_All_";
-
-        if($_GET['filterAlbum'])
-        {
-            $this->filterAlbum=$_GET['filterAlbum'];
-        }
-        else
-            $this->filterAlbum="_All_";
-        if($_GET['filterGenre'])
-        {
-            $this->filterGenre=$_GET['filterGenre'];
-        }
-        else
-            $this->filterGenre="_All_";
-
-
-        if($_GET['filterRank'])
-            $this->filterRank=$_GET['filterRank'];
-        else
-            $this->filterRank="_All_";
-    }
-
-    function readRow()
-    {
-
-            if($row=mysql_fetch_row($this->result))
-            {
-                $this->intid=$row[0];
-                $this->artist=$row[1];
-                $this->album=$row[2];
-                $this->title=$row[3];
-                $this->genre=$row[4];
-                $this->length=$row[5];
-                $this->rating=$row[6];
-                $this->filename=$row[7];
-
-                $this->urlfilename=root.'data/music';
-                global $musicdir;
-                foreach (preg_split('/\//', substr($this->filename, strlen($musicdir))) as $dir) {
-                    if (!$dir) continue;
-                    $this->urlfilename .= '/'.rawurlencode(utf8tolocal($dir));
-                }
-
-                return(true);
-            }
-            return(false);
-    }
-
-
-
-    function display()
-    {
-        $music = new Theme_music();
-        $this->init($music->getMaxPerPage());
-        $music->setOffset($this->offset);
-        $music->setTotalCount($this->totalCount);
-
-        $music->print_header($this->filterPlaylist,$this->filterArtist,$this->filterAlbum,$this->filterGenre);
-        if($this->totalCount > 0)
-        {
-            while($this->readRow())
-            {
-                $music->printDetail($this->title,$this->length,$this->artist,$this->album,$this->genre,$this->urlfilename);
-            }
-        }
-        else
-        {
-            $music->printNoDetail();
-        }
-        if($this->result)
-            mysql_free_result($this->result);
-
-        $music->print_footer();
-    }
-
-    function prepFilter()
-    {
-        $prevFilter=0;
-        $thisFilter="";
-
-        if($this->filterPlaylist != "_All_")
-        {
-            $playlistResult = mysql_query("select playlistid,name,songlist,hostname from musicplaylist where playlistid=".escape($this->filterPlaylist));
-            if($playlistResult)
-            {
-                if(mysql_num_rows($playlistResult)==1)
-                {
-                    $row=mysql_fetch_row($playlistResult);
-                    if($row)
-                    {
-
-                        $this->filterSonglist=$row[2];
-                        if($prevFilter==1)
-                            $this->filter=$this->filter . "and intid in (" . $this->filterSonglist . ")";
-                        else
-                        {
-                            $this->filter="intid in (" . $this->filterSonglist . ")";
-                            $prevFilter=1;
-                        }
-
-                        $this->keepFilters="&amp;filterPlaylist=" . urlencode($this->filterPlaylist);
-
-                    }
-                }
-            }
-        }
-
-        if($this->filterArtist != "_All_" )
-        {
-            if($prevFilter==1)
-                $this->filter=$this->filter . "and artist=".escape($this->filterArtist);
-            else
-            {
-                $this->filter="artist=".escape($this->filterArtist);
-                $prevFilter=1;
-            }
-
-            $this->keepFilters="&amp;filterArtist=" . urlencode($this->filterArtist);
-
-        }
-        if($this->filterAlbum != "_All_")
-        {
-            if($prevFilter==1)
-            {
-                $this->filter= $this->filter . "and album=\"" . $this->filterAlbum . "\"";
-            }
-            else
-            {
-                $this->filter="album=\"" . $this->filterAlbum . "\"";
-                $prevFilter=1;
-            }
-            $this->keepFilters =$this->keepFilters . "&amp;filterAlbum=" . urlencode($this->filterAlbum) ;
-
-        }
-        if($this->filterGenre != "_All_")
-        {
-            if($prevFilter==1)
-            {
-                $this->filter= $this->filter . "and genre=" . $this->filterGenre ;
-            }
-            else
-            {
-                $this->filter="genre=\"" . $this->filterGenre . "\"";
-                $prevFilter=1;
-            }
-            $this->keepFilters =$this->keepFilters . "&amp;filterGenre=" . urlencode($this->filterGenre);
-
-        }
-
-        if($this->filterRank != "_All_")
-        {
-            if($prevFilter==1)
-            {
-                $this->filter=$this->filter . "and rank=" . $this->filterRank;
-            }
-            else
-            {
-                $this->filter="rank=" . $this->filterRank;
-                $prevFilter=1;
-            }
-            $this->keepFilters =$this->keepFilters . "&amp;filterRank=" . urlencode($this->filterRank);
-        }
-
-
-
-    }
-
-    function init($maxPerPage) {
-        global $db;
-        $this->prepFilter();
-        if (empty($this->filter))
-            $this->totalCount = $db->query_col('SELECT COUNT(*) FROM musicmetadata');
-        else
-            $this->totalCount = $db->query_col('SELECT COUNT(*) FROM musicmetadata WHERE '.$this->filter);
-
-        if ($this->totalCount > 0) {
-            if($this->offset > 0) {
-                $limitText='LIMIT ' . $this->offset . ',' . $maxPerPage;
-            }
-            else
-                $limitText='LIMIT ' . $maxPerPage;
-
-            if (empty($this->filter))
-                $this->result=mysql_query("select intid,artist,album,title,genre,length,rating,filename from musicmetadata order by artist,album,tracknum " . $limitText);
-            else
-                $this->result=mysql_query("select intid,artist,album,title,genre,length,rating,filename from musicmetadata where $this->filter order by artist,album,tracknum $limitText");
-        }
-    }
-}
-
-
+    if (tmpl == "compact")
+	{
+	require_once("modules/music/music_handler.php");
+	}
+    else
+	{
+        if (in_array($Path[1], array('mp3act_js.js.php', 'mp3act_fat.js', 'mp3act_hidden.php')))
+    	    {
+	    require_once 'modules/music/'.$Path[1];
+	    exit();
+		}
+	if (strstr($Path[1],"mp3act_playstream.php") != false)
+	    {
+    	    require_once 'modules/music/mp3act_playstream.php';
+	    exit();
+	    }
+    
+	require_once 'modules/music/mp3act_main.php';
+	}
+?>    
\ No newline at end of file
Index: mythweb/modules/music/mp3act_sajax.php
===================================================================
--- mythweb/modules/music/mp3act_sajax.php	(.../trunk/mythplugins)	(revision 0)
+++ mythweb/modules/music/mp3act_sajax.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -0,0 +1,304 @@
+<?php
+if (!isset($SAJAX_INCLUDED)) {
+
+	/*
+	 * GLOBALS AND DEFAULTS
+	 *
+	 */
+	$sajax_debug_mode = 0;
+	$sajax_export_list = array();
+	$sajax_request_type = "GET";
+	$sajax_remote_uri = "";
+
+	/*
+	 * CODE
+	 *
+	 */
+
+	//
+	// Initialize the Sajax library.
+	//
+	function sajax_init() {
+	}
+
+	//
+	// Helper function to return the script's own URI.
+	//
+	function sajax_get_my_uri() {
+		global $REQUEST_URI;
+
+		return $REQUEST_URI;
+	}
+	$sajax_remote_uri = sajax_get_my_uri();
+
+	//
+	// Helper function to return an eval()-usable representation
+	// of an object in JavaScript.
+	//
+	function sajax_get_js_repr($value) {
+		$type = gettype($value);
+
+		if ($type == "boolean" ||
+			$type == "integer") {
+			return "parseInt($value)";
+		}
+		elseif ($type == "double") {
+			return "parseFloat($value)";
+		}
+		elseif ($type == "array" || $type == "object" ) {
+			//
+			// XXX Arrays with non-numeric indices are not
+			// permitted according to ECMAScript, yet everyone
+			// uses them.. We'll use an object.
+			//
+			$s = "{ ";
+			if ($type == "object") {
+				$value = get_object_vars($value);
+			}
+			foreach ($value as $k=>$v) {
+				$esc_key = sajax_esc($k);
+				if (is_numeric($k))
+					$s .= "$k: " . sajax_get_js_repr($v) . ", ";
+				else
+					$s .= "\"$esc_key\": " . sajax_get_js_repr($v) . ", ";
+			}
+			return substr($s, 0, -2) . " }";
+		}
+		else {
+			$esc_val = sajax_esc($value);
+			$s = "\"$esc_val\"";
+			return $s;
+		}
+	}
+
+	function sajax_handle_client_request() {
+		global $sajax_export_list;
+
+		$mode = "";
+
+		if (! empty($_GET["rs"]))
+			$mode = "get";
+
+		if (!empty($_POST["rs"]))
+			$mode = "post";
+
+		if (empty($mode))
+			return;
+
+		$target = "";
+
+		if ($mode == "get") {
+			// Bust cache in the head
+			header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");    // Date in the past
+			header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
+			// always modified
+			header ("Cache-Control: no-cache, must-revalidate");  // HTTP/1.1
+			header ("Pragma: no-cache");                          // HTTP/1.0
+			$func_name = $_GET["rs"];
+			if (! empty($_GET["rsargs"]))
+				$args = $_GET["rsargs"];
+			else
+				$args = array();
+		}
+		else {
+			$func_name = $_POST["rs"];
+			if (! empty($_POST["rsargs"]))
+				$args = $_POST["rsargs"];
+			else
+				$args = array();
+		}
+
+		if (! in_array($func_name, $sajax_export_list))
+			echo "-:$func_name not callable";
+		else {
+			echo "+:";
+			$result = call_user_func_array($func_name, $args);
+			echo "var res = " . sajax_get_js_repr($result) . "; res;";
+		}
+		exit;
+	}
+
+	function sajax_get_common_js() {
+		global $sajax_debug_mode;
+		global $sajax_request_type;
+		global $sajax_remote_uri;
+
+		$t = strtoupper($sajax_request_type);
+		if ($t != "" && $t != "GET" && $t != "POST")
+			return "// Invalid type: $t.. \n\n";
+
+		ob_start();
+		?>
+
+		// remote scripting library
+		// (c) copyright 2005 modernmethod, inc
+		var sajax_debug_mode = <?php echo $sajax_debug_mode ? "true" : "false"; ?>;
+		var sajax_request_type = "<?php echo $t; ?>";
+		var sajax_target_id = "";
+
+		function sajax_debug(text) {
+			if (sajax_debug_mode)
+				alert("RSD: " + text)
+		}
+ 		function sajax_init_object() {
+ 			sajax_debug("sajax_init_object() called..")
+
+ 			var A;
+			try {
+				A=new ActiveXObject("Msxml2.XMLHTTP");
+			} catch (e) {
+				try {
+					A=new ActiveXObject("Microsoft.XMLHTTP");
+				} catch (oc) {
+					A=null;
+				}
+			}
+			if(!A && typeof XMLHttpRequest != "undefined")
+				A = new XMLHttpRequest();
+			if (!A)
+				sajax_debug("Could not create connection object.");
+			return A;
+		}
+		function sajax_do_call(func_name, args) {
+			var i, x, n;
+			var uri;
+			var post_data;
+			var target_id;
+
+			sajax_debug("in sajax_do_call().." + sajax_request_type + "/" + sajax_target_id);
+			target_id = sajax_target_id;
+			if (sajax_request_type == "")
+				sajax_request_type = "GET";
+
+			uri = "<?php echo $sajax_remote_uri; ?>";
+			if (sajax_request_type == "GET") {
+
+				if (uri.indexOf("?") == -1)
+					uri += "?rs=" + escape(func_name);
+				else
+					uri += "&rs=" + escape(func_name);
+				uri += "&rst=" + escape(sajax_target_id);
+				uri += "&rsrnd=" + new Date().getTime();
+
+				for (i = 0; i < args.length-1; i++)
+					uri += "&rsargs[]=" + escape(args[i]);
+
+				post_data = null;
+			}
+			else if (sajax_request_type == "POST") {
+				post_data = "rs=" + escape(func_name);
+				post_data += "&rst=" + escape(sajax_target_id);
+				post_data += "&rsrnd=" + new Date().getTime();
+
+				for (i = 0; i < args.length-1; i++)
+					post_data = post_data + "&rsargs[]=" + escape(args[i]);
+			}
+			else {
+				alert("Illegal request type: " + sajax_request_type);
+			}
+
+			x = sajax_init_object();
+			x.open(sajax_request_type, uri, true);
+
+			if (sajax_request_type == "POST") {
+				x.setRequestHeader("Method", "POST " + uri + " HTTP/1.1");
+				x.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+			}
+
+			x.onreadystatechange = function() {
+				if (x.readyState != 4)
+					return;
+
+				sajax_debug("received " + x.responseText);
+
+				var status;
+				var data;
+				status = x.responseText.charAt(0);
+				data = x.responseText.substring(2);
+				if (status == "-")
+					alert("Error: " + data);
+				else {
+					if (target_id != "")
+						document.getElementById(target_id).innerHTML = eval(data);
+					else
+						args[args.length-1](eval(data));
+				}
+			}
+			sajax_debug(func_name + " uri = " + uri + "/post = " + post_data);
+			x.send(post_data);
+			sajax_debug(func_name + " waiting..");
+			delete x;
+			return true;
+		}
+
+		<?php
+		$html = ob_get_contents();
+		ob_end_clean();
+		return $html;
+	}
+
+	function sajax_show_common_js() {
+		echo sajax_get_common_js();
+	}
+
+	// javascript escape a value
+	function sajax_esc($val)
+	{
+		$val = str_replace("\\", "\\\\", $val);
+		$val = str_replace("\r", "\\r", $val);
+		$val = str_replace("\n", "\\n", $val);
+		return str_replace('"', '\\"', $val);
+	}
+
+	function sajax_get_one_stub($func_name) {
+		ob_start();
+		?>
+
+		// wrapper for <?php echo $func_name; ?>
+
+		function x_<?php echo $func_name; ?>() {
+			sajax_do_call("<?php echo $func_name; ?>",
+				x_<?php echo $func_name; ?>.arguments);
+		}
+
+		<?php
+		$html = ob_get_contents();
+		ob_end_clean();
+		return $html;
+	}
+
+	function sajax_show_one_stub($func_name) {
+		echo sajax_get_one_stub($func_name);
+	}
+
+	function sajax_export() {
+		global $sajax_export_list;
+	  $sajax_export_list = func_get_args();
+	}
+
+	$sajax_js_has_been_shown = 0;
+	function sajax_get_javascript()
+	{
+		global $sajax_js_has_been_shown;
+		global $sajax_export_list;
+
+		$html = "";
+		if (! $sajax_js_has_been_shown) {
+			$html .= sajax_get_common_js();
+			$sajax_js_has_been_shown = 1;
+		}
+		foreach ($sajax_export_list as $func) {
+			$html .= sajax_get_one_stub($func);
+		}
+		return $html;
+	}
+
+	function sajax_show_javascript()
+	{
+		echo sajax_get_javascript();
+	}
+
+
+	$SAJAX_INCLUDED = 1;
+}
+?>
Index: mythweb/modules/music/music_handler.php
===================================================================
--- mythweb/modules/music/music_handler.php	(.../trunk/mythplugins)	(revision 0)
+++ mythweb/modules/music/music_handler.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -0,0 +1,281 @@
+<?php
+/**
+ * MythMusic browser
+ *
+ * @url         $URL: svn+ssh://xris@cvs.mythtv.org/var/lib/svn/trunk/mythplugins/mythweb/modules/music/init.php $
+ * @date        $Date: 2006-03-26 12:09:14 +0200 (So, 26 Mär 2006) $
+ * @version     $Revision: 9493 $
+ * @author      $Author: xris $
+ * @license     GPL
+ *
+ * @package     MythWeb
+ * @subpackage  Music
+ *
+/**/
+
+// Make sure the music directory exists
+    if (file_exists('data/music')) {
+    // File is not a directory or a symlink
+        if (!is_dir('data/music') && !is_link('data/music')) {
+            custom_error('An invalid file exists at data/music.  Please remove it in'
+                        .' order to use the music portions of MythWeb.');
+        }
+    }
+// Create the symlink, if possible.
+//
+// NOTE:  Errors have been disabled because if I turn them on, people hosting
+//        MythWeb on Windows machines will have issues.  I will turn the errors
+//        back on when I find a clean way to do so.
+//
+    else {
+        $dir = $db->query_col('SELECT data
+                                 FROM settings
+                                WHERE value="MusicLocation" AND hostname=?',
+                              hostname
+                             );
+        if ($dir) {
+            $ret = @symlink($dir, 'data/music');
+            if (!$ret) {
+                #custom_error("Could not create a symlink to $dir, the local MythMusic directory"
+                #            .' for this hostname ('.hostname.').  Please create a symlink to your'
+                #            .' MythMusic directory at data/music in order to use the music'
+                #            .' portions of MythWeb.');
+            }
+        }
+        else {
+            #custom_error('Could not find a value in the database for the MythMusic directory'
+            #            .' for this hostname ('.hostname.').  Please create a symlink to your'
+            #            .' MythMusic directory at data/music in order to use the music'
+            #            .' portions of MythWeb.');
+        }
+    }
+
+//
+//  Someday, music.php will let us stream
+//  entire playlists to any spot on planet earth
+//
+require_once tmpl_dir.'music.php';
+
+$mythmusic = new mythMusic();
+$mythmusic->display();
+
+class mythMusic {
+    var $filterPlaylist;
+    var $filterArtist;
+    var $filterAlbum;
+    var $filterGenre;
+    var $filterRank;
+    var $filterSonglist;
+    var $keepFilters;
+    var $filter;
+    var $totalCount;
+    var $offset;
+
+    var $result;
+
+
+    var $intid;
+    var $artist;
+    var $album;
+    var $title;
+    var $genre;
+    var $length;
+    var $rating;
+    var $filename;
+    var $urlfilename;
+
+    var $alphalink;
+    var $alphaoffset;
+
+    function mythMusic()
+    {
+        if($_GET['offset'] >=0 )
+            $this->offset=$_GET['offset'];
+        else
+            $this->offset=0;
+
+        /**** If alphalink set, then change offset to new value ****/
+        if ($_GET['alphalink']) {
+            $alphalink = mysql_real_escape_string($_GET['alphalink']);
+
+            $result = mysql_query(sprintf("SELECT COUNT(*) FROM music_songs ".
+                                          "LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id ".
+                                          "WHERE UPPER(music_artists.artist_name) < %s ".
+                                          "ORDER BY music_artists.artist_name;",
+                                          escape($_GET['alphalink'])));
+            if ($result)
+			{
+                $alphaoffset=mysql_fetch_row($result);
+                $this->offset=$alphaoffset[0];
+                mysql_free_result($result);
+            }
+        }
+
+        if($_GET['filterPlaylist'])
+        {
+            $this->filterPlaylist=$_GET['filterPlaylist'];
+            $_GET['filterPlaylist'];
+        }
+        else
+            $this->filterPlaylist="_All_";
+
+        if($_GET['filterArtist'])
+        {
+            $this->filterArtist=$_GET['filterArtist'];
+        }
+        else
+            $this->filterArtist="_All_";
+
+        if($_GET['filterAlbum'])
+        {
+            $this->filterAlbum=$_GET['filterAlbum'];
+        }
+        else
+            $this->filterAlbum="_All_";
+        if($_GET['filterGenre'])
+        {
+            $this->filterGenre=$_GET['filterGenre'];
+        }
+        else
+            $this->filterGenre="_All_";
+
+
+        if($_GET['filterRank'])
+            $this->filterRank=$_GET['filterRank'];
+        else
+            $this->filterRank="_All_";
+    }
+
+    function readRow()
+    {
+
+            if($row=mysql_fetch_row($this->result))
+            {
+                $this->intid=$row[0];
+                $this->artist=$row[1];
+                $this->album=$row[2];
+                $this->title=$row[3];
+                $this->genre=$row[4];
+                $this->length=$row[5];
+                $this->rating=$row[6];
+                $this->filename=$row[7];
+
+                $this->urlfilename=root.'data/music';
+                global $musicdir;
+                foreach (preg_split('/\//', substr($this->filename, strlen($musicdir))) as $dir) {
+                    if (!$dir) continue;
+                    $this->urlfilename .= '/'.rawurlencode(utf8tolocal($dir));
+                }
+
+                return(true);
+            }
+            return(false);
+    }
+
+
+
+    function display()
+    {
+        $music = new Theme_music();
+        $this->init($music->getMaxPerPage());
+        $music->setOffset($this->offset);
+        $music->setTotalCount($this->totalCount);
+
+        $music->print_header($this->filterPlaylist,$this->filterArtist,$this->filterAlbum,$this->filterGenre);
+        if($this->totalCount > 0)
+        {
+            while($this->readRow())
+            {
+                $music->printDetail($this->title,$this->length,$this->artist,$this->album,$this->genre,$this->urlfilename);
+            }
+        }
+        else
+        {
+            $music->printNoDetail();
+        }
+        if($this->result)
+            mysql_free_result($this->result);
+
+        $music->print_footer();
+    }
+
+    function prepFilter()
+    {
+        $this->filter="1=1"; // A true statement that will always return everything in SQL.
+
+        if($this->filterPlaylist != "_All_")
+        {
+            $playlistResult = mysql_query("SELECT playlist_id,playlist_name,playlist_songs,hostname FROM music_playlists WHERE playlist_id=".escape($this->filterPlaylist));
+            if($playlistResult)
+            {
+                if(mysql_num_rows($playlistResult)==1)
+                {
+                    $row=mysql_fetch_row($playlistResult);
+                    if($row && !empty($row[2]))
+                    {
+                        $this->filterSonglist=$row[2];
+
+                        $this->filter .= " AND song_id IN (" . $this->filterSonglist . ")";
+                        $this->keepFilters .= "&amp;filterPlaylist=" . urlencode($this->filterPlaylist);
+                    }
+                }
+            }
+        }
+
+        if($this->filterArtist != "_All_" )
+        {
+            $this->filter .= " AND artist_name=".escape($this->filterArtist);
+            $this->keepFilters .= "&amp;filterArtist=" . urlencode($this->filterArtist);
+        }
+
+        if($this->filterAlbum != "_All_")
+        {
+            $this->filter .= " AND album_name=" . escape($this->filterAlbum);
+            $this->keepFilters .= "&amp;filterAlbum=" . urlencode($this->filterAlbum) ;
+        }
+
+        if($this->filterGenre != "_All_")
+        {
+            $this->filter .= " AND genre=" . escape($this->filterGenre);
+            $this->keepFilters .= "&amp;filterGenre=" . urlencode($this->filterGenre);
+        }
+
+        if($this->filterRank != "_All_")
+        {
+            $this->filter .= " AND rank=" . escape($this->filterRank);
+            $this->keepFilters .= "&amp;filterRank=" . urlencode($this->filterRank);
+        }
+    }
+
+    function init($maxPerPage) {
+        global $db;
+        $this->prepFilter();
+        $query_base = ' FROM music_songs'.
+                      ' LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id'.
+                      ' LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id'.
+                      ' LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id'.
+                      ' WHERE '.$this->filter.
+                      ' ORDER BY artist_name,album_name,track';
+	
+        // Cannot use $db->query_col here as the preg_replace kills PHP when using large filterSongList queries
+        $this->totalCount = 0;
+        $result = mysql_query('SELECT COUNT(*)'.$query_base);
+        if ($result)
+        {
+            $row=mysql_fetch_row($result);
+            $this->totalCount=$row[0];
+            mysql_free_result($result);
+        }
+
+        if ($this->totalCount > 0) {
+            if($this->offset > 0)
+                $query_base .= ' LIMIT ' . $this->offset . ',' . $maxPerPage;
+            else
+                $query_base .= ' LIMIT ' . $maxPerPage;
+	    
+	        $this->result = mysql_query('SELECT music_songs.song_id, music_artists.artist_name, music_albums.album_name, music_songs.name, music_genres.genre, music_songs.length, music_songs.rating, music_songs.filename '.$query_base);
+        }
+    }
+}
+
+
Index: mythweb/modules/music/mp3act_js.js.php
===================================================================
--- mythweb/modules/music/mp3act_js.js.php	(.../trunk/mythplugins)	(revision 0)
+++ mythweb/modules/music/mp3act_js.js.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -0,0 +1,343 @@
+<?php
+function music_dir()
+{
+  return 'http://'.$_SERVER['HTTP_HOST'].root."music/";
+}
+?>
+    	window.onload=function(){ init(); };
+
+    	function init(){
+    		setPageTitle();
+    		x_viewPlaylist(viewPlaylist_cb);
+    		x_playlistInfo(plinfo_cb);
+    		setPLTitle();
+    		setCurrentPage();
+    		updateBox(page,0);
+    	}
+    	function empty_cb(new_data){
+
+    	}
+
+    	function setPageNav(){
+    		//document.getElementById("breadcrumb").innerHTML = prevpage;
+    	}
+
+    	function switchPage(newpage){
+    		prevpage = page;
+    		page = newpage;
+
+    		updateBox(page,0);
+    		setPageTitle();
+    		setCurrentPage();
+    		//setPageNav();
+    	}
+
+    	function setPLTitle(){
+    		document.getElementById("pl_title").innerHTML = " <? echo t("Playlist"); ?> ";
+    	}
+
+    	function viewPlaylist_cb(new_data){
+    		document.getElementById("playlist").innerHTML = new_data;
+    	}
+
+    	function setCurrentPage(){
+    		var x = document.getElementById('nav');
+    		var y = x.getElementsByTagName('a');
+    		for (var i=0;i < y.length;i++){
+ 					y[i].removeAttribute("class");
+ 					if(y[i].id == page)
+ 						y[i].setAttribute('class','c');
+				}
+    	}
+
+    	function getDropDown(type,id){
+    		x_getDropDown(type,id,getDropDown_cb);
+    	}
+
+    	function getDropDown_cb(new_data){
+    		ul = document.getElementById("browse_ul");
+    		ul.innerHTML = new_data;
+    		ul.style.display = 'block';
+    	}
+
+    	function closeDropDown(){
+    		ul = document.getElementById("browse_ul");
+    		ul.style.display = 'none';
+    		ul.innerHTML = '';
+    	}
+
+	function savePL_cb(data){
+    			var save_form = '<h2><?php echo t('Save/Rename Playlist'); ?></h2>' +
+          '<form onsubmit="return savePL(\'save\',this)" method="get" action="">' +
+          '<strong><?php echo t('Playlist Name'); ?></strong><br/>' +
+          '<?php echo t('Enter a new name for your playlist'); ?><br /><br />' +
+          '<input type="text" name="save_pl_name" id="save_pl_name" size="25" />' +
+          '<input style="left: 350px; position: absolute;" type="submit" value="<?php echo t('Save/Rename'); ?>" />' +
+          '</form>' +
+          '<br /><hr /><br />' +
+          '<input style="left: 350px; position: absolute;" type="button"' +
+          ' onclick="savePL(\'close\',0); return false;" value="<?php echo t('Cancel'); ?>" />';
+			document.getElementById("box_extra").innerHTML = save_form;
+    			document.getElementById("box_extra").style.display = 'block';
+		}
+
+	function savePL(type,data){
+        if(type=='open'){
+          savePL_cb(data);
+          return false;
+        }
+    		else if(type=='save'){
+    			var pl_name = data.save_pl_name.value;
+			    x_savePlaylist(pl_name,0,save_Playlist_cb);
+          x_playlistInfo(plinfo_cb);
+
+    			return false;
+    		}
+    		else if(type=='close')
+    			document.getElementById("box_extra").style.display = 'none';
+    	}
+
+    	function save_Playlist_cb(new_data){
+    		box = document.getElementById("box_extra");
+    		box.innerHTML = new_data;
+    		setTimeout("box.style.display='none'","1250");
+    	}
+
+    	function movePLItem(direction,item){
+				var y;
+				var temp;
+        var pos = 0;
+    	  temp = item;
+        while (temp.previousSibling)
+        {
+          pos++;
+          temp = temp.previousSibling;
+        }
+
+        if(direction == "up")
+    			y = item.previousSibling;
+    		else if(direction == "down")
+					y = item.nextSibling;
+
+				if(y && y.nodeName == 'LI'){
+    			pl_move(pos, pos + ("up" == direction ? -1 : 1));
+
+    			var temp = y.innerHTML;
+    			y.innerHTML = item.innerHTML;
+    			item.innerHTML = temp;
+    			Fat.fade_element(y.id,null,900,'#ffcc99','#f3f3f3');
+    		}
+    	}
+
+    	function setBgcolor(id, c)
+			{
+				if(id != ('pl'+nowplaying)){
+				var o = document.getElementById(id);
+				o.style.backgroundColor = c;
+				}
+			}
+
+			function setPageTitle(){
+				var pages= new Array()
+				pages["browse"]="<?php echo t("Browse Music"); ?> ";
+				pages["search"]="<?php echo t("Search Music"); ?> ";
+				pages["random"]="<?php echo t("Create a Random Mix"); ?> ";
+				pages["playlists"]="<?php echo t("Load a Saved Playlist"); ?> ";
+				pages["stats"]="<?php echo t("Server Statistics"); ?> ";
+				document.getElementById("pagetitle").innerHTML = pages[page];
+
+			}
+
+			function getRandItems(type){
+			  //document.getElementById("breadcrumb").innerHTML = '';
+			  document.getElementById("rand_items").innerHTML = '';
+				x_getRandItems(type,getRandItems_cb);
+			}
+
+			function getRandItems_cb(new_data){
+				document.getElementById("rand_items").innerHTML = new_data;
+			}
+
+			function updateBox_cb(new_data){
+				document.getElementById("info").innerHTML = new_data;
+				document.getElementById("loading").style.display = 'none';
+
+				if(clearbc==1)
+					breadcrumb();
+				clearbc = 1;
+
+			}
+
+			function updateBox(type,itemid){
+				document.getElementById("loading").style.display = 'block';
+				x_musicLookup(type,itemid,updateBox_cb);
+
+				if(type == 'genre' || type == 'letter'){
+					bc_parenttype = '';
+					bc_parentitem = '';
+				}
+				else if(type == 'album' || (type == 'artist' && bc_parenttype != '')){
+					if(bc_childtype == 'all'){
+						bc_parenttype = bc_childtype;
+						bc_parentitem = bc_childitem;
+					}
+				}
+				else if(type == 'browse' || type == 'search' || type == 'about' || type == 'prefs' || type == 'random' || type == 'admin' || type == 'playlists' || type == 'stats'){
+
+					bc_parenttype = '';
+					bc_parentitem = '';
+					itemid='';
+					type='';
+				}
+				else{
+					bc_parenttype = bc_childtype;
+					bc_parentitem = bc_childitem;
+				}
+
+				bc_childitem = itemid;
+				bc_childtype = type;
+
+			}
+
+			function deletePlaylist(id){
+				if(confirm("<?php echo t('Are you sure you want to DELETE THIS SAVED PLAYLIST?'); ?>")){
+					x_deletePlaylist(id,deletePlaylist_cb);
+				}
+			}
+
+			function deletePlaylist_cb(new_data){
+				// reload saved PL page
+				clearbc = 0;
+				x_musicLookup('playlists',0,updateBox_cb);
+				setMsgText("<?php echo t('Saved Playlist Successfully Deleted'); ?>");
+        // Also reload the playlist if we've deleted the active playlist!
+        if (new_data){
+          x_viewPlaylist(viewPlaylist_cb);
+          x_playlistInfo(plinfo_cb);
+        }
+			}
+
+			function plrem(item){
+        var temp = item;
+        var pos = 0;
+        while (temp.previousSibling)
+        {
+          pos++;
+          temp = temp.previousSibling;
+        }
+
+				x_playlist_rem(pos,plrem_cb);
+			}
+
+			function plrem_cb(rem){
+				p = document.getElementById("playlist");
+				d_nested = p.childNodes[rem];
+				throwaway_node = p.removeChild(d_nested);
+				x_playlistInfo(plinfo_cb);
+			}
+
+			function pladd(type,id){
+				x_playlist_add(type,id,pladd_cb);
+			}
+
+			function pladd_cb(new_data){
+
+				if(new_data[0] == 1){
+					x_viewPlaylist(viewPlaylist_cb);
+    			x_playlistInfo(plinfo_cb);
+				}
+                else if (new_data[0] == 2){
+                    alert(new_data[1]);
+                }
+				else{
+					document.getElementById("playlist").innerHTML += new_data[0];
+
+					for(var i=2; i < new_data[1]+2; i++){
+						Fat.fade_element(new_data[i],null,1400,'#B4EAA2','#f3f3f3');
+					}
+					x_playlistInfo(plinfo_cb);
+				}
+			}
+
+			function pl_move(item1,item2){
+				x_playlist_move(item1,item2,pl_move_cb);
+			}
+
+			function pl_move_cb(){
+					// do nothing
+			}
+
+			function plclear(){
+				x_clearPlaylist(plinfo_cb);
+				document.getElementById("playlist").innerHTML = "";
+			}
+
+			function plinfo_cb(new_data){
+				document.getElementById("pl_info").innerHTML = new_data;
+			}
+
+			function breadcrumb(){
+					x_buildBreadcrumb(page,bc_parenttype,bc_parentitem,bc_childtype,bc_childitem,breadcrumb_cb);
+			}
+
+			function breadcrumb_cb(new_data){
+				//if(new_data!="")
+					document.getElementById("breadcrumb").innerHTML = new_data;
+			}
+
+			function play(type,id){
+					document.getElementById('hidden').src = null;
+					document.getElementById("hidden").src = "<?php echo music_dir(); ?>mp3act_hidden.php?type="+type+"&id="+id+"&quality=high";
+			}
+
+			function randAdd(data){
+				var type = data.random_type.value;
+				if(type == ""){
+					setMsgText("You must choose a random type");
+					return false;
+				}
+				var num=0;
+				num = data.random_count.value;
+				var items ='';
+				if(type != 'all'){
+					for(var i=0;i<data.random_items.options.length;i++){
+						if(data.random_items.options[i].selected == true)
+						 items += ',' + data.random_items.options[i].value;
+					}
+
+					if(items == ""){
+					  setMsgText("You must choose at least one random item");
+					  return false;
+					}
+          items = items.substring(1);
+				}
+				x_randAdd(type,num,items,randadd_cb);
+				return false;
+
+			}
+
+			function randadd_cb(new_data){
+				x_viewPlaylist(viewPlaylist_cb);
+    				x_playlistInfo(plinfo_cb);
+			}
+
+			function play_cb(new_data){
+				//refresh();
+			}
+
+			function setMsgText(text){
+					document.getElementById("breadcrumb").innerHTML = "<span class='error'>"+text+"</span>";
+					Fat.fade_element('breadcrumb',null,2000,'#F5C2C2','#ffffff');
+			}
+
+			function searchMusic(form){
+				if(form.searchbox.value == '' || form.searchbox.value == '[<? echo t("enter your search terms"); ?>]'){
+					setMsgText("You Must Enter Something to Search For");
+				}
+				else{
+					document.getElementById("breadcrumb").innerHTML = "";
+					x_searchMusic(form.searchbox.value,form.search_options.value,updateBox_cb);
+				}
+				return false;
+			}
+
Index: mythweb/modules/music/mp3act_functions.php
===================================================================
--- mythweb/modules/music/mp3act_functions.php	(.../trunk/mythplugins)	(revision 0)
+++ mythweb/modules/music/mp3act_functions.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -0,0 +1,1481 @@
+<?php
+/**
+ * Common Functions for the MP3Act part of the MythWeb Music module
+ *
+ * @url         $URL: http://svn.mythtv.org/svn/trunk/mythplugins/mythweb/modules/music/mp3act_functions.php $
+ * @date        $Date: 2006-03-23 08:46:57 +0100 (Do, 23 Mär 2006) $
+ * @version     $Revision: 9478 $
+ * @author      $Author: jochen $
+ * @license     GPL
+ *
+ * @package     MythWeb
+ * @subpackage  Music
+ *
+/**/
+
+require_once('modules/music/mp3act_html_functions.php');
+
+define('MYTH_WEB_PLAYLIST_NAME', 'MythWeb Temporary Playlist');
+define('MYTH_PLAYLIST_SAVE_TIME', 60*60*24*7);
+
+/******************************************
+*  mp3act functions
+*  http://www.mp3act.net
+*  Stripped, because not all this funcionality is needed in MythWEB
+*
+******************************************/
+function pic_dir()
+{
+  return 'http://'.$_SERVER['HTTP_HOST'].skin_url.'img/music/';
+}
+
+function music_dir()
+{
+  return 'http://'.$_SERVER['HTTP_HOST'].root."music/";
+}
+
+
+function GarbageCollector()
+{
+    // Run this occasionally to tidy up.
+    if (0 == mt_rand(0, 30))
+    {
+        $query = 'DELETE FROM music_playlists '.
+            "WHERE playlist_name='".mysql_real_escape_string('MythWeb Temporary Playlist')."'".
+            ' AND (NOW() - last_accessed) > ('.MYTH_PLAYLIST_SAVE_TIME.');';
+        mysql_query($query);
+    }
+}
+
+function getplaylistnames()
+{
+  $output='';
+  $query = 'SELECT playlist_name, hostname FROM music_playlists WHERE hostname=\'\';';
+  $result = mysql_query($query);
+
+  if (!$result)
+    return '';
+
+  while ($row = mysql_fetch_array($result))
+  {
+    $output .= '<option>'.$row['playlist_name'].'</option>';
+  }
+  mysql_free_result($result);
+  return $output;
+}
+
+function genreform()
+{
+  $query = "SELECT * FROM music_genres ORDER BY genre";
+  $result = mysql_query($query);
+
+  if (!$result)
+    return '';
+
+  $output = '<select id="genre" name="genre" onchange="updateBox(\'genre\',this.options[selectedIndex].value); return false;">
+    <option value="" selected>'.t('Choose Genre..').'</option>';
+
+  while ($genre = mysql_fetch_array($result))
+  {
+    $output .= '<option value="'.$genre['genre'].'">'.$genre['genre'].'</option>';
+  }
+  $output .= '</select>';
+  mysql_free_result($result);
+  return $output;
+}
+
+function letters()
+{
+  $output = '<ul class="music" id="letters">';
+  $letters = array('#','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');
+
+  foreach($letters as $letter)
+  {
+    $output .= '<li><a class=music href="#" onclick="updateBox(\'letter\',\''.$letter.'\'); return false;">'.strtoupper($letter).'</a></li>';
+  }
+  $output .= '</ul>';
+  return $output;
+}
+
+function getDropDown($type, $id)
+{
+  return "";
+}
+
+function buildBreadcrumb($page, $parent, $parentitem, $child, $childitem)
+{
+  $childoutput='';
+  $parentoutput ='';
+  if ($page == 'browse' && $child != '')
+  {
+    $output = '<a class="music" href="#" onclick="updateBox(\'browse\',0); return false;">'.t('Browse').'</a> &#187; ';
+  }
+  switch ($child)
+  {
+    case 'album':
+      $query = 'SELECT music_albums.album_name, music_artists.artist_name, music_artists.artist_id '.
+        'FROM music_albums '.
+        'LEFT JOIN music_artists ON music_albums.artist_id=music_artists.artist_id '.
+        'WHERE music_albums.album_id='.mysql_real_escape_string($childitem);
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $row = mysql_fetch_array($result);
+      mysql_free_result($result);
+
+      $query = 'SELECT album_name, album_id '.
+        'FROM music_albums '.
+        'WHERE artist_id='.$row['artist_id'].' '.
+        'ORDER BY album_name';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $albums = '';
+      while ($row2 = mysql_fetch_array($result))
+      {
+        $albums .= '<li><a class="music" href="#"'.
+          ' onclick="updateBox(\'album\','.$row2['album_id'].'); return false;"'.
+          ' title="'.sprintf(t('View Details of %s'), $row2['album_name']).'">'.
+          $row2['album_name'].'</a></li>';
+      }
+      mysql_free_result($result);
+
+      $childoutput .= '<span><a class="music" href="#"'.
+        ' onclick="updateBox(\'artist\','.$row['artist_id'].'); return false;">'.
+        $row['artist_name'].'</a>'.
+        '<ul class="music">'.$albums.'</ul></span> &#187; '.
+        htmlentities($row['album_name']);
+      break;
+
+    case 'artist':
+      $query = 'SELECT artist_name '.
+        'FROM music_artists '.
+        'WHERE artist_id='.mysql_real_escape_string($childitem);
+      $result = mysql_query($query);
+       if (!$result)
+        break;
+      $row = mysql_fetch_array($result);
+      mysql_free_result($result);
+
+      $query = 'SELECT music_albums.album_id, album_name '.
+        'FROM music_songs '.
+        'LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id '.
+        'WHERE music_songs.artist_id='.mysql_real_escape_string($childitem).' '.
+        'GROUP BY music_albums.album_id;';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+      $albums = '';
+      while ($row2 = mysql_fetch_array($result))
+      {
+        $albums .= '<li><a class="music" href="#"'.
+          ' onclick="updateBox(\'album\','.$row2['album_id'].'); return false;"'.
+          ' title="'.sprintf(t('View Details of %s'), $row2['album_name']).'">'.
+          $row2['album_name'].'</a></li>';
+      }
+      mysql_free_result($result);
+
+      $childoutput .= '<span><a class="music" href="#"'.
+        ' onclick="updateBox(\'artist\','.$childitem.'); return false;">'.
+        $row['artist_name'].'</a>'.
+        '<ul class="music">'.$albums.'</ul></span>';
+      break;
+
+    case 'letter':
+      $childoutput .= '<span><a class="music" href="#"'.
+        ' onclick="updateBox(\'letter\',\''.$childitem.'\'); return false;">'.
+        strtoupper($childitem).'</a>'.letters().'</span>';
+      break;
+
+    case 'genre':
+    case 'all':
+      $childoutput .=  $childitem;
+      break;
+  }
+  switch ($parent)
+  {
+    case 'letter':
+      $parentoutput .= '<span><a class="music" href="#"'.
+        ' onclick=\"updateBox(\'letter\',\''.$parentitem.'\'); return false;">'.
+        strtoupper($parentitem).'</a>'.letters().'</span> &#187; ';
+      break;
+
+    case 'genre':
+    case 'all':
+      $parentoutput .= '<a class="music" href="#"'.
+        ' onclick="updateBox(\''.$parent.'\',\''.$parentitem.'\'); return false;">'.
+        $parentitem.'</a> &#187; ';
+      break;
+  }
+
+  if (isset($output))
+  {
+    return $output.$parentoutput.$childoutput;
+  }
+
+  return '';
+}
+
+function musicLookup($type, $itemid)
+{
+  $sql_itemid = "'".mysql_real_escape_string($itemid)."'";
+  switch($type)
+  {
+    case 'browse':
+      $output = '<div class="head">
+        <h2 class="music">'.t('Browse the Music Database').'</h2></div>
+        <p>
+        <strong>'.t('By Artist Beginning With').'</strong><br/>'.letters().'<br/></p>
+        <p><strong>'.t('By Genre').'</strong><br/>
+        '.genreForm().'<br/><br/>
+        <input type="button" value="'.t('Browse All Albums').'" onclick="updateBox(\'all\',\'All\'); return false;" class="btn2" />
+        </p>';
+      break;
+
+    case 'search':
+      $output = '<div class="head">
+        <h2 class="music">'.t('Search the Music Database').'</h2></div>
+        <form onsubmit="return searchMusic(this)" method="get" action="">
+        <p>
+        <strong>'.t('Keywords').'</strong><br/>
+        <input type="text" onfocus="this.select()" name="searchbox" size="35" id="searchbox" value="['.t('Enter your search terms').']" />
+        <br/><br/>
+        <strong>'.t('Narrow Your Search').'</strong>
+        <br/>
+        <select name="search_options" size="1">
+          <option value="all">'.t('All Fields').'</option>
+          <option value="artists">'.t('Artists').'</option>
+          <option value="albums">'.t('Albums').'</option>
+          <option value="songs">'.t('Songs').'</option>
+        </select><br/><br/>
+        <input type="submit" value="'.t('Submit Search').'" class="btn" /></form>
+        </p>';
+      break;
+
+    case 'letter':
+      if($itemid == "#")
+      {
+        $query = 'SELECT * FROM music_artists '.
+          "WHERE artist_name REGEXP '^[0-9].*' ".
+          'ORDER BY artist_name';
+      }
+      else
+      {
+        $query = 'SELECT * FROM music_artists '.
+          'WHERE artist_name LIKE \''.mysql_real_escape_string($itemid.'%').'\' '.
+          'ORDER BY artist_name';
+      }
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $output = '<div class="head">
+        <h2 class="music">'.sprintf(t('Artists Beginning with %s'), "'".strtoupper($itemid)."'").'</h2></div>
+        <p>
+        <strong>'.t('Artist Listing').'</strong></p>
+        <ul class="music">';
+      $alt = false;
+      while ($row = mysql_fetch_array($result))
+      {
+        $output .= '<li'.($alt ? ' class="alt"' : '').'>
+          <a class="music" href="#"
+           onclick="updateBox(\'artist\','.$row['artist_id'].'); return false;"
+           title="'.sprintf(t('View Albums by %s'), $row['artist_name']).'">'.
+          $row['artist_name'].'</a></li>';
+        $alt = !$alt;
+      }
+      mysql_free_result($result);
+      $output .= '</ul>';
+      break;
+
+    case 'all':
+      $output = '<div class="head">
+        <h2 class="music">'.t('All Albums').'</h2></div>
+        <p>
+        <strong>'.t('Album Listing').'</strong></p>
+        <ul class="music">';
+      $start = $itemid;
+      $query  = 'SELECT ma.*,mt.artist_name '.
+        'FROM music_albums AS ma '.
+        'LEFT JOIN music_artists AS mt ON ma.artist_id=mt.artist_id '.
+        'ORDER BY album_name, artist_name';
+
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $alt = false;
+      while ($row = mysql_fetch_array($result))
+      {
+        $output .= getHtmlAlbum($row['album_id'], $row['album_name'],
+          $row['artist_name']);
+      }
+      mysql_free_result($result);
+      $output .= '</ul>';
+      break;
+
+    case 'album':
+      // Get some statistics about the album
+      $query = 'SELECT COUNT(*), SEC_TO_TIME(SUM(music_songs.length)/1000) '.
+        'FROM music_songs '.
+        'WHERE music_songs.album_id='.$sql_itemid.' '.
+        'GROUP BY music_songs.album_id;';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $row = mysql_fetch_array($result);
+      mysql_free_result($result);
+      $num_tracks = $row[0];
+      $length = $row[1];
+
+      // Attempt to find some album art.
+      $query='SELECT * '.
+        'FROM music_songs '.
+        'WHERE album_id='.$sql_itemid.' '.
+        'LIMIT 1;';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $row = mysql_fetch_array($result);
+      mysql_free_result($result);
+
+      $album_art_arr = array();
+      $path = $_SERVER['DOCUMENT_ROOT'].root.'data/music/'.dirname($row['filename']);
+      $dir = @dir($path);
+      if ($dir)
+      {
+        while ($file = $dir->read())
+        {
+          $end = strtolower(substr($file, -3));
+          switch ($end)
+          {
+            case 'jpg':
+            case 'gif':
+            case 'png':
+              $album_art_arr[] = $file;
+          }
+        }
+        $dir->close();
+      }
+
+      if (!empty($album_art_arr))
+      {
+        srand(microtime()*1000000);
+        $index = mt_rand(1, count($album_art_arr)) - 1;
+
+        $album_art = root.'data/music/'.dirname($row['filename']).'/'.$album_art_arr[$index];
+      }
+
+      $output = '<div class="head">
+        <div class="right">
+        <a class="music" href="#"
+         onclick="play(\'album\','.$row['album_id'].'); return false;"
+         title="'.t('Play this Album Now').'">'.t('Play').'</a>
+        <a class="music" href="#"
+         onclick="pladd(\'album\','.$row['album_id'].'); return false;"
+         title="'.t('Add Album to Current Playlist').'">'.t('Add').'</a>
+        </div>
+        <h2 class="music">'.$row['album_name'].'</h2>
+        </div>'.
+        (!empty($album_art) ? '<center><img width="200" src="'.$album_art.'" /></center><br />' : '').
+        '<strong>'.t('Play Time').':</strong> '.$length.
+        '<br /><br />
+        <strong>'.t('Album Tracks').'</strong>
+        <ul class="music">';
+
+      $query = 'SELECT music_songs.*, SEC_TO_TIME(music_songs.length/1000) AS length, artist_name '.
+        'FROM music_songs '.
+        'LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id '.
+        'WHERE album_id='.$sql_itemid.' '.
+        'ORDER BY track';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      while ($row = mysql_fetch_array($result))
+      {
+        $output .= getHtmlSong($row['song_id'], $row['artist_name'],
+          '', $row['track'], $row['name'],
+          $row['length'], $row['numplays']);
+      }
+      mysql_free_result($result);
+      $output .= '</ul>';
+      break;
+
+    case 'genre':
+      $output = '<div class="head">
+        <h2 class="music">'.t('Songs for Genre')." '".$itemid."'</h2></div>
+        <p><strong>".t('Songs').'</strong></p>
+        <ul class="music">';
+
+      $query = 'SELECT music_songs.*, music_artists.artist_name, music_genres.genre '.
+        'FROM music_songs '.
+        'LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id '.
+        'LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id '.
+        'WHERE genre='.$sql_itemid.';';
+
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      while ($row = mysql_fetch_array($result))
+      {
+        $output .= getHtmlSong($row['song_id'], $row['artist_name'],
+          '', '', $row['name'],
+          $row['length'], $row['numplays']);
+      }
+      mysql_free_result($result);
+      $output .= '</ul>';
+      break;
+
+    case 'artist':
+      $query = 'SELECT artist_name '.
+        'FROM music_artists '.
+        'WHERE artist_id='.$sql_itemid;
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $row = mysql_fetch_array($result);
+      mysql_free_result($result);
+      $artist = $row['artist_name'];
+
+      $output = '<div class="head">
+        <h2 class="music">'.$artist.'</h2></div>
+        <p><strong>'.t('Songs').'</strong></p>
+        <ul class="music">';
+
+      $query = 'SELECT music_songs.*, SEC_TO_TIME(music_songs.length/1000) AS length, music_artists.artist_name, track, music_albums.album_name '.
+        'FROM music_songs '.
+        'LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id '.
+        'LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id '.
+        'WHERE music_songs.artist_id='.$sql_itemid.';';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      while ($row = mysql_fetch_array($result))
+      {
+        $output .= getHtmlSong($row['song_id'], '',
+          $row['album_name'], $row['track'], $row['name'],
+          $row['length'], $row['numplays']);
+      }
+      mysql_free_result($result);
+      $output .= '</ul><br />
+        <p><strong>'.sprintf(t('Albums with songs by %s'),'<i>'.$artist.'</i>').'</strong></p>
+        <ul class="music">';
+
+      $query = 'SELECT ma.album_id, album_name, ma.year, ma.artist_id, artist_name'.
+        ',SEC_TO_TIME(SUM(ms.length)/1000) AS length, COUNT(ms.song_id) AS num_tracks '.
+        'FROM music_songs AS ms '.
+        'LEFT JOIN music_albums AS ma ON ms.album_id=ma.album_id '.
+        'LEFT JOIN music_artists AS mt ON ma.artist_id=mt.artist_id '.
+        'WHERE ms.artist_id='.$sql_itemid.' '.
+        'GROUP BY ma.album_id;';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      while ($row = mysql_fetch_array($result))
+      {
+        $artist = '';
+        if ($itemid != $row['artist_id'])
+          $artist = $row['artist_name'];
+
+        $output .= getHtmlAlbum($row['album_id'], $row['album_name'],
+          $artist, $row['year'], $row['num_tracks'], $row['length']);
+      }
+      mysql_free_result($result);
+      $output .= '</ul>';
+      break;
+
+    case 'random':
+      $output = '<div class="head">
+        <h2 class="music">'.t('Random Mix Maker').'</h2></div>
+        <form onsubmit="return randAdd(this)" method="get" action="">
+        <strong>'.t('Number of Songs').'</strong><br />
+        <select name="random_count">
+        <option>10</option>
+        <option>20</option>
+        <option>30</option>
+        <option>40</option>
+        <option>50</option>
+        </select><br />
+        <strong>'.t('Random Type').'</strong><br />
+        <select name="random_type" onchange="getRandItems(this.options[selectedIndex].value); return false;">
+        <option value="">'.t('Choose Type').'...</option>
+        <option value="artists">'.t('Artists').'</option>
+        <option value="genre">'.t('Genre').'</option>
+        <option value="albums">'.t('Albums').'</option>
+        <option value="all">'.t('Everything').'</option>
+        </select><br />
+        <strong>'.t('Random Items').'</strong>
+        <span id="rand_items"></span>
+        <br /><br />
+        <input type="submit" value="'.t('Add Mix').'" class="btn" />
+        </form>';
+      break;
+
+    case 'playlists':
+      $query = 'SELECT playlist_id, playlist_name, songcount, hostname, SEC_TO_TIME(length/1000) AS length '.
+        'FROM music_playlists '.
+        'WHERE hostname=\'\'';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $output = '<div class="head">
+        <h2 class="music">'.t('Saved Playlists').'</h2></div><br />';
+
+      if (mysql_num_rows($result) == 0)
+      {
+        $output .= t('No Public Playlists');
+      }
+      else
+      {
+        $unsaved_id = 0;
+        $pl = internalGetPlaylist();
+        if (!empty($pl['playlist_name'])
+            && MYTH_WEB_PLAYLIST_NAME == $pl['playlist_name'])
+        {
+          $unsaved_id = $pl['playlist_id'];
+        }
+
+        $output .= '<ul class="music">';
+        while ($row = mysql_fetch_array($result))
+        {
+          $output .= getHtmlPlaylist($row['playlist_id'], $row['playlist_name'],
+            $row['songcount'], $row['length'], $unsaved_id);
+        }
+        $output .= '</ul>';
+      }
+      mysql_free_result($result);
+      break;
+
+    case 'saved_pl':
+      $query = 'SELECT playlist_id, playlist_name, playlist_songs, songcount, SEC_TO_TIME(length/1000) AS length '.
+        'FROM music_playlists '.
+        'WHERE playlist_id='.$sql_itemid;
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $row = mysql_fetch_array($result);
+      mysql_free_result($result);
+
+      $unsaved_id = 0;
+      $pl = internalGetPlaylist();
+      if (!empty($pl['playlist_name'])
+          && MYTH_WEB_PLAYLIST_NAME == $pl['playlist_name'])
+      {
+        $unsaved_id = $pl['playlist_id'];
+      }
+
+      $output = '<div class="head">
+        <div class="right">
+        <a class="music" href="#"
+          onclick="checkPlaylistLoad(\''.$row['playlist_id'].'\', '.$unsaved_id.')'.
+          ' && pladd(\'loadplaylist\','.$row['playlist_id'].'); return false;"
+          title="'.t('Load Playlist').'">'.t('Load').
+        '</a>
+        <a class="music" href="#"
+          onclick="pladd(\'playlist\','.$row['playlist_id'].'); return false;"
+          title="'.t('Append to Current Playlist').'">'.t('Append').
+        '</a>
+        <a class="music" href="#"
+          onclick="play(\'pl\','.$row['playlist_id'].'); return false;"
+          title="'.t('Play this Playlist Now').'">'.t('Play').
+        '</a>
+        </div>
+        <h2 class="music">'.t('View Saved Playlist').'</h2></div>
+        <p><strong>'.t('Playlist Info').'</strong><br />'.
+        sprintf('%s Songs', $row['songcount']).'<br />'.$row['length'].'</p>
+        <p><strong>'.t('Playlist Items').'</strong></p>';
+
+
+      if (empty($row['playlist_songs']))
+      {
+        $output = '<b>'.t('There are no items in this Playlist!').'</b>';
+      }
+      else
+      {
+        // Load the song information
+        $query = 'SELECT ms.song_id, mt.artist_name, ms.name, ma.album_name, ms.track'.
+            ', SEC_TO_TIME(ms.length/1000) AS length '.
+            'FROM music_songs AS ms '.
+            'LEFT JOIN music_artists AS mt ON ms.artist_id=mt.artist_id '.
+            'LEFT JOIN music_albums AS ma ON ms.album_id=ma.album_id '.
+            'WHERE ms.song_id IN ('.$row['playlist_songs'].');';
+        $result = mysql_query($query);
+        if (!$result)
+            return;
+
+        $song_info = array();
+        while ($row2 = mysql_fetch_array($result))
+        {
+            $song_info[$row2['song_id']] = $row2;
+        }
+        mysql_free_result($result);
+
+        // Load the sub-playlist information
+        // NB: MySQL 3.xx cannot use the CAST() function hense the negative number decimal
+        // conversion hack as outlined on: http://dev.mysql.com/doc/refman/4.1/en/cast-functions.html
+        $query = 'SELECT playlist_id, playlist_name, SEC_TO_TIME(length/1000) AS length, songcount '.
+            'FROM music_playlists '.
+            'WHERE (-1.0 * (playlist_id+0.0)) IN ('.$row['playlist_songs'].');';
+        $result = mysql_query($query);
+        if (!$result)
+            return;
+
+        $pl_info = array();
+        while ($row2 = mysql_fetch_array($result))
+        {
+            $pl_info[$row2['playlist_id']] = $row2;
+        }
+        mysql_free_result($result);
+
+        $songs = explode(',', $row['playlist_songs']);
+        $output .= '<ul class="music">';
+        foreach ($songs as $song_id)
+        {
+          if ($song_id > 0)
+          {
+            $row = $song_info[$song_id];
+            $output .= getHtmlSong($row['song_id'], $row['artist_name'],
+              '', '', $row['name'],
+              $row['length'], $row['numplays']);
+          }
+          else if ($song_id < 0)
+          {
+            $row = $pl_info[-1 * $song_id];
+            $output .= getHtmlPlaylist($row['playlist_id'], $row['playlist_name'],
+              $row['songcount'], $row['length'], $unsaved_id, false);
+          }
+        }
+        $output .= '</ul>';
+      }
+      break;
+
+    case 'stats':
+      $query = 'SELECT * FROM music_stats';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $row = mysql_fetch_array($result);
+      mysql_free_result($result);
+
+      $query = 'SELECT COUNT(*) AS songs FROM music_songs WHERE numplays>0';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $row2 = mysql_fetch_array($result);
+      mysql_free_result($result);
+
+      $output = '<div class="head">
+        <h2 class="music">'.t('Server Statistics').'</h2></div>
+        <p><a class="music" href="#" onclick="updateBox(\'recentadd\',0); return false;">'.
+        t('Recently Added Albums').'</a><br />
+        <a class="music" href="#" onclick="updateBox(\'recentplay\',0); return false;">'.
+        t('Recently Played Songs').'</a><br />
+        <a class="music" href="#" onclick="updateBox(\'topplay\',0); return false;">'.
+        t('Top Played Songs').'</a><br />
+        </p>
+        <h3>'.t('Local Server Statistics').'</h3>
+        <p>';
+
+      foreach (array('music_songs'   => t('Songs'),
+                     'music_albums'  => t('Albums'),
+                     'music_artists' => t('Artists'),
+                     'music_genres'  => t('Genres')) as $table => $title)
+      {
+        $result = mysql_query('SELECT COUNT(*) FROM '.$table.';');
+        if (!$result)
+          continue;
+        $count = mysql_fetch_array($result);
+        mysql_free_result($result);
+        $output .= '<strong>'.$title.':</strong> '.$count[0].'<br />';
+      }
+      $output .= '<br /><strong>'.t('Songs Played').':</strong> '.$row2['songs'].'<br /></p>';
+      break;
+
+    case 'recentadd':
+      $query = 'SELECT ma.album_name, ma.album_id, mt.artist_name, UNIX_TIMESTAMP(ms.date_entered) AS pubdate '.
+        'FROM music_songs AS ms '.
+        'LEFT JOIN music_albums AS ma ON ms.album_id=ma.album_id '.
+        'LEFT JOIN music_artists AS mt ON ms.artist_id=mt.artist_id '.
+        'GROUP BY ms.album_id '.
+        'ORDER BY ms.date_entered DESC '.
+        'LIMIT 40';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $output = '<div class="head">
+        <div class="right">
+        <a class="music" href="#"
+          onclick="switchPage(\'stats\'); return false;"
+          title="'.t('Return to Statistics Page').'">'.t('Back').'</a></div>
+        <h2 class="music">'.t('Recently Added Albums').'</h2></div>
+        <ul class="music">';
+      while ($row = mysql_fetch_array($result))
+      {
+        $output .= getHtmlAlbum($row['album_id'], $row['album_name'],
+          $row['artist_name'], '', '', '', date('m.d.Y', $row['pubdate']));
+      }
+      mysql_free_result($result);
+      $output .= '</ul>';
+      break;
+
+    case 'topplay':
+      $query = 'SELECT ma.album_name, ms.numplays, ms.name, mt.artist_name, ms.song_id '.
+        'FROM music_songs AS ms '.
+        'LEFT JOIN music_albums AS ma ON ms.album_id=ma.album_id '.
+        'LEFT JOIN music_artists AS mt ON ms.artist_id=mt.artist_id '.
+        'WHERE ms.numplays > 0 '.
+        'ORDER BY ms.numplays DESC '.
+        'LIMIT 40';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $output = '<div class="head">
+        <div class="right">
+        <a class="music" href="#"
+          onclick="switchPage(\'stats\'); return false;"
+          title="'.t('Return to Statistics Page').'">'.t('Back').'</a></div>
+        <h2 class="music">'.t('Top Played Songs').'</h2></div>
+        <ul class="music">';
+      while ($row = mysql_fetch_array($result))
+      {
+        $output .= getHtmlSong($row['song_id'], $row['artist_name'],
+          '', '', $row['name'],
+          '', '');
+      }
+      mysql_free_result($result);
+      $output .= '</ul>';
+      break;
+
+    case 'recentplay':
+      $query = 'SELECT ms.name, ms.song_id, mt.artist_name, UNIX_TIMESTAMP(ms.lastplay) AS playdate '.
+        'FROM music_songs AS ms '.
+        'LEFT JOIN music_artists AS mt ON ms.artist_id=mt.artist_id '.
+        'ORDER BY ms.lastplay DESC '.
+        'LIMIT 40';
+      $result = mysql_query($query);
+      if (!$result)
+        break;
+
+      $output = '<div class="head">
+        <div class="right">
+        <a class="music" href="#"
+          onclick="switchPage(\'stats\'); return false;"
+          title="'.t('Return to Statistics Page').'">'.t('Back').'</a></div>
+        <h2 class="music">'.t('Recently Played Songs').'</h2></div>
+        <ul class="music">';
+      while ($row = mysql_fetch_array($result))
+      {
+        $output .= getHtmlSong($row['song_id'], $row['artist_name'],
+          '', '', $row['name'],
+          '', '');
+      }
+      $output .= '</ul>';
+      break;
+  }
+
+  return $output;
+}
+
+
+function getRandItems($type)
+{
+  switch ($type)
+  {
+    case 'artists':
+      $query = 'SELECT artist_id, artist_name FROM music_artists ORDER BY artist_name';
+      break;
+    case 'genre':
+      $query = 'SELECT genre_id, genre FROM music_genres ORDER BY genre';
+      break;
+    case 'albums':
+      $query = 'SELECT album_id, album_name FROM music_albums ORDER BY album_name';
+      break;
+    default:
+      return '<br />'.t('All Songs');
+  }
+
+  $result = mysql_query($query);
+  if (!$result)
+    return '';
+
+  $options = '';
+  while ($row = mysql_fetch_array($result))
+  {
+    $options .= '<option value="'.$row[0].'">'.
+      $row[1].'</option>';
+  }
+  mysql_free_result($result);
+
+  return '<select name="random_items" multiple="multiple" size="12" style="width: 90%;">'.
+    $options.'</select>';
+}
+
+
+function searchMusic($terms, $option)
+{
+  $sql_terms = "'%".mysql_real_escape_string($terms)."%'";
+  $query = 'SELECT ms.song_id, ma.album_name, ms.track, mt.artist_name, ms.name, SEC_TO_TIME(ms.length/1000) AS length '.
+    'FROM music_songs AS ms '.
+    'LEFT JOIN music_artists AS mt ON ms.artist_id=mt.artist_id '.
+    'LEFT JOIN music_albums AS ma ON ms.album_id=ma.album_id '.
+    'WHERE 1 AND ';
+
+  if ($option == 'all')
+  {
+    $query .= '(ms.name LIKE '.$sql_terms.
+      ' OR mt.artist_name LIKE '.$sql_terms.
+      ' OR ma.album_name LIKE '.$sql_terms.')';
+  }
+  else if ($option == 'artists')
+  {
+    $query .= '(mt.artist_name LIKE '.$sql_terms.')';
+  }
+  else if ($option == 'albums')
+  {
+    $query .= '(ma.album_name LIKE '.$sql_terms.')';
+  }
+  else if ($option == 'songs')
+  {
+    $query .= '(ms.name LIKE '.$sql_terms.')';
+  }
+  $query .= ' ORDER BY mt.artist_name, ma.album_name, ms.track, ms.name';
+
+  $result = mysql_query($query);
+  if (!$result)
+    return '';
+
+  $count = mysql_num_rows($result);
+
+  $output = '<div class="head">
+    <div class="right">
+    <a class="music" href="#"
+      onclick="switchPage(\'search\'); return false;"
+      title="'.t('Begin a New Search').'">'.t('New Search').'</a></div>
+    <h2 class="music">'.sprintf(t("Found %s results for '%s'"), $count, $terms).'</h2></div>';
+
+  if($count > 0)
+  {
+    $output .= '<ul class="music">';
+    while ($row = mysql_fetch_array($result))
+    {
+      $output .= getHtmlSong($row['song_id'], $row['artist_name'],
+        $row['album_name'], $row['track'], $row['name'],
+        $row['length'], '');
+    }
+    $output .= '</ul>';
+  }
+  return $output;
+}
+
+function internalGetPlaylist($plId = 0)
+{
+  $row = array();
+  if (empty($plId))
+  {
+    if (empty($_COOKIE['mp3act_playlist_id']))
+      return $row;
+    $plId = $_COOKIE['mp3act_playlist_id'];
+  }
+
+  $query = 'SELECT playlist_id, playlist_name, playlist_songs, songcount, length AS length_in_secs'.
+    ', SEC_TO_TIME(length/1000) AS length '.
+    'FROM music_playlists '.
+    'WHERE playlist_id='.mysql_real_escape_string($plId);
+
+  $result = mysql_query($query);
+  if (!$result)
+    return $row;
+
+  if (mysql_num_rows($result) > 0)
+    $row = mysql_fetch_array($result);
+  mysql_free_result($result);
+
+  // Set the last accessed time for Temporary playlists so that
+  // we can run a garbage colnctor later.
+  if (MYTH_WEB_PLAYLIST_NAME == $row['playlist_name'])
+  {
+    $query = 'UPDATE music_playlists'.
+      ' SET last_accessed=NULL '.
+      'WHERE playlist_id='.mysql_real_escape_string($plId);
+    mysql_query($query);
+  }
+
+  return $row;
+}
+
+function internalUpdatePlaylist($songs, $count, $length)
+{
+  $plId = 0;
+  if (!empty($_COOKIE['mp3act_playlist_id']))
+    $plId = $_COOKIE['mp3act_playlist_id'];
+
+  $songlist = implode(',', $songs);
+
+  $query = 'music_playlists SET'.
+    " playlist_songs='".mysql_real_escape_string($songlist)."'".
+    ',length='.mysql_real_escape_string($length).
+    ',songcount='.mysql_real_escape_string($count);
+
+  if (empty($plId))
+  {
+    $query = 'INSERT INTO '.$query.
+      ",hostname='".mysql_real_escape_string('mythweb-'.$_SERVER['SERVER_NAME'])."'".
+      ",playlist_name='".MYTH_WEB_PLAYLIST_NAME."'";
+  }
+  else
+  {
+    $query = 'UPDATE '.$query.
+      ' WHERE playlist_id='.mysql_real_escape_string($plId);
+  }
+  mysql_query($query);
+
+  if (empty($plId))
+  {
+    $plId = mysql_insert_id();
+    if ($plId)
+    {
+      setcookie('mp3act_playlist_id', $plId, time()+MYTH_PLAYLIST_SAVE_TIME);
+      return $plId;
+    }
+  }
+  return false;
+}
+
+function viewPlaylist()
+{
+  $pl = internalGetPlaylist();
+
+  if (empty($pl['playlist_songs']))
+  {
+    return '';
+  }
+
+  // Load the song information
+  $query = 'SELECT ms.song_id, mt.artist_name, ms.name, ma.album_name, ms.track'.
+    ', SEC_TO_TIME(ms.length/1000) AS length '.
+    'FROM music_songs AS ms '.
+    'LEFT JOIN music_artists AS mt ON ms.artist_id=mt.artist_id '.
+    'LEFT JOIN music_albums AS ma ON ms.album_id=ma.album_id '.
+    'WHERE ms.song_id IN ('.$pl['playlist_songs'].');';
+  $result = mysql_query($query);
+  if (!$result)
+    return;
+
+  $song_info = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    $song_info[$row['song_id']] = $row;
+  }
+  mysql_free_result($result);
+
+  // Load the sub-playlist information
+  // NB: MySQL 3.xx cannot use the CAST() function hense the negative number decimal
+  // conversion hack as outlined on: http://dev.mysql.com/doc/refman/4.1/en/cast-functions.html
+  $query = 'SELECT playlist_id, playlist_name, SEC_TO_TIME(length/1000) AS length, songcount '.
+    'FROM music_playlists '.
+    'WHERE (-1.0 * (playlist_id+0.0)) IN ('.$pl['playlist_songs'].');';
+  $result = mysql_query($query);
+  if (!$result)
+    return;
+
+  $pl_info = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    $pl_info[$row['playlist_id']] = $row;
+  }
+  mysql_free_result($result);
+
+
+  $songs = explode(',', $pl['playlist_songs']);
+  $output = '';
+  $id=0;
+  foreach ($songs as $song_id)
+  {
+    // Create a random id for Javascript events.
+    $id = md5($song_id.mt_rand());
+    if ($song_id > 0)
+    {
+      $row = $song_info[$song_id];
+      $output .= getHtmlPlaylistEntrySong($id, $row['artist_name'],
+        $row['album_name'], $row['track'], $row['name'], $row['length']);
+    }
+    else
+    {
+      $row = $pl_info[-1 * $song_id];
+      $output .= getHtmlPlaylistEntryPlaylist($id, $row['playlist_name'],
+        $row['songcount'], $row['length']);
+    }
+  }
+  return $output;
+}
+
+
+function playlistInfo()
+{
+  $pl = internalGetPlaylist();
+
+  $info = '';
+
+  if (!empty($pl) && MYTH_WEB_PLAYLIST_NAME != $pl['playlist_name'])
+    $info = '<em>'.$pl['playlist_name'].'</em> &mdash; ';
+
+  if (empty($pl['playlist_songs']))
+  {
+    $info .= t('Playlist is empty');
+  }
+  else
+  {
+    if (1 == $pl['count'])
+      $info .= sprintf(t('%s Song (%s)'), $pl['songcount'], $pl['length']);
+    else
+      $info .= sprintf(t('%s Songs (%s)'), $pl['songcount'], $pl['length']);
+  }
+
+  return $info;
+}
+
+
+function savePlaylist($pl_name, $newpl)
+{
+  $pl = internalGetPlaylist();
+
+  if (!empty($pl['playlist_id']))
+    $pl_id = $pl['playlist_id'];
+  else
+    $pl_id = internalUpdatePlaylist(array(), 0, 0);
+
+  if (empty($pl_id))
+  {
+    $msg = t('There was a problem saving your playlist');
+  }
+  else
+  {
+    $query = 'UPDATE music_playlists SET'.
+      ' playlist_name=\''.mysql_real_escape_string($pl_name).'\''.
+      ",hostname='' ".
+      'WHERE playlist_id='.mysql_real_escape_string($pl['playlist_id']);
+
+    mysql_query($query);
+
+    if (MYTH_WEB_PLAYLIST_NAME == $pl['playlist_name'])
+      $msg = t('Playlist saved successfully');
+    else
+      $msg = t('Playlist renamed successfully');
+  }
+
+  return '<h2 class="music">'.$msg.'</h2>';
+}
+
+function clearPlaylist()
+{
+  $pl = internalGetPlaylist();
+
+  // Trash the cookie (empties the playlist)
+  setcookie('mp3act_playlist_id', false, time()-3600);
+
+  if (!empty($pl['playlist_name'])
+      && MYTH_WEB_PLAYLIST_NAME == $pl['playlist_name'])
+  {
+    deletePlaylist($pl['playlist_id']);
+  }
+
+  return t('Playlist is empty');
+}
+
+
+function deletePlaylist($id)
+{
+  $rv = 0;
+  if ($id == $_COOKIE['mp3act_playlist_id'])
+  {
+    $rv = 1;
+    setcookie('mp3act_playlist_id', false, time()-3600);
+  }
+
+  $query = 'DELETE FROM music_playlists '.
+    'WHERE playlist_id='.mysql_real_escape_string($id);
+  mysql_query($query);
+  return $rv;
+}
+
+
+function playlist_rem($itemid)
+{
+  $pl = internalGetPlaylist();
+
+  $songs = explode(',', $pl['playlist_songs']);
+  $idx = intval($itemid);
+  if (isset($songs[$idx]))
+  {
+    // Find the length of the song we are removing so we can update the p/l
+    $id = $songs[$idx];
+    if ($id > 0)
+    {
+      $query = 'SELECT length, 1 AS songcount FROM music_songs '.
+        'WHERE song_id='.mysql_real_escape_string($id);
+    }
+    else
+    {
+      $query = 'SELECT length, songcount FROM music_playlists '.
+        'WHERE playlist_id='.mysql_real_escape_string(-1 * $id);
+    }
+    $result = mysql_query($query);
+    $length = $count = 0;
+    if ($result)
+    {
+      $row = mysql_fetch_array($result);
+      mysql_free_result($result);
+      if ($row)
+      {
+        $length = $row['length'];
+        $count = $row['songcount'];
+      }
+    }
+    unset($songs[$idx]);
+    internalUpdatePlaylist($songs,
+      ($pl['songcount'] - $count),
+      ($pl['length_in_secs'] - $length));
+  }
+  return $itemid;
+}
+
+function playlist_move($item1,$item2)
+{
+  $pl = internalGetPlaylist();
+
+  $idx1 = intval($item1);
+  $idx2 = intval($item2);
+
+  $songs = explode(',',$pl['playlist_songs']);
+
+  if (!isset($songs[$idx1]) || !isset($songs[$idx2]))
+    return;
+
+  $tmp = $songs[$idx1];
+  $songs[$idx1] = $songs[$idx2];
+  $songs[$idx2] = $tmp;
+
+  $query = 'UPDATE music_playlists SET'.
+    ' playlist_songs=\''.mysql_real_escape_string(implode(',', $songs)).'\' '.
+    'WHERE playlist_id='.mysql_real_escape_string($pl['playlist_id']).';';
+  mysql_query($query);
+}
+
+function internalPlaylistAddPlaylistCheck($curPlId, $addPlId, $depth = 0)
+{
+  // Infinite loop protection (e.g. if the DB is messed up already)
+  if ($depth > 25)
+    return false;
+
+  // Looking to see if $addPlId playlist at any point includes $curPlId playlist
+  if ($curPlId == $addPlId)
+    return false;
+
+  $query = 'SELECT playlist_songs '.
+    'FROM music_playlists '.
+    'WHERE playlist_id='.mysql_real_escape_string($addPlId);
+
+  $result = mysql_query($query);
+  if (!$result)
+    return false;
+
+  $row = mysql_fetch_array($result);
+  mysql_free_result($result);
+
+  if (!$row) // Not a real playlist.
+    return false;
+
+  $songs = explode(',', $row['playlist_songs']);
+  $playlists = array_filter($songs, create_function('$n','return ($n < 0);'));
+
+  foreach ($playlists as $playlist_id)
+  {
+    if ($playlist_id > 0)
+      continue; // Shouldn't happen due to the filter above but I'm paranoid.
+
+    $playlist_id *= -1;
+
+    if (!internalPlaylistAddPlaylistCheck($curPlId, $playlist_id, $depth+1))
+      return false;
+  }
+
+  return true;
+}
+
+
+function playlist_add($type, $itemid)
+{
+  $output = array(0 => '', 1 => 0);
+
+  if ('loadplaylist' == $type)
+  {
+    clearPlaylist();
+    setcookie('mp3act_playlist_id', $itemid, time()+MYTH_PLAYLIST_SAVE_TIME);
+    $output[0] = 1;
+    return $output;
+  }
+
+  $pl = internalGetPlaylist();
+
+  if (empty($pl['playlist_songs']))
+  {
+    $songs = array();
+    $new_length = 0;
+    $new_songcount = 0;
+  }
+  else
+  {
+    $songs = explode(',', $pl['playlist_songs']);
+    $new_length = $pl['length_in_secs'];
+    $new_songcount = $pl['songcount'];
+  }
+
+  if ('playlist' == $type)
+  {
+    if (!empty($pl['playlist_id']))
+    {
+      if (!internalPlaylistAddPlaylistCheck($pl['playlist_id'], $itemid))
+      {
+        // Some sort of nasty circular dependancy.
+        $output[0] = 2;
+        $output[1] = t('Sorry, but you cannot add this playlist as it would create a circular dependancy.');
+        return $output;
+      }
+    }
+    $pl_add = internalGetPlaylist($itemid);
+    if (empty($pl_add['playlist_id']))
+    {
+    $output[0] = 2;
+    $output[1] = t('An error occured while adding your playlist.');
+    return $output;
+    }
+    $new_songcount += $pl_add['songcount'];
+    $new_length += $pl_add['length_in_secs'];
+    $songs[] = -1 * $itemid;
+
+    $id = md5((-1 * $itemid).mt_rand());
+    $output[0] .= getHtmlPlaylistEntryPlaylist($id, $pl_add['playlist_name'],
+    $pl_add['songcount'], $pl_add['length']);
+    $output[1]++;
+    $output[] = 'pl'.$id;
+
+    internalUpdatePlaylist($songs, $new_songcount, $new_length);
+
+    return $output;
+  }
+
+  $sql_itemid = mysql_real_escape_string($itemid);
+  $query = 'SELECT ms.song_id, mt.artist_name, ma.album_name,'.
+    ' length AS length_in_secs, SEC_TO_TIME(ms.length/1000) AS length, ms.name, ms.track '.
+    'FROM music_songs AS ms '.
+    'LEFT JOIN music_artists AS mt ON ms.artist_id=mt.artist_id '.
+    'LEFT JOIN music_albums AS ma ON ms.album_id=ma.album_id '.
+    'WHERE ';
+  switch ($type)
+  {
+    case 'song':
+      $query .= 'ms.song_id='.$sql_itemid;
+      break;
+    case 'album':
+      $query .= 'ms.album_id='.$sql_itemid;
+      break;
+    default:
+      return $output;
+  }
+
+  $result = mysql_query($query.' ORDER BY ms.track');
+  if (!$result)
+    return $output;
+
+  while ($row = mysql_fetch_array($result))
+  {
+    $id = md5($row['song_id'].mt_rand());
+    $output[0] .= getHtmlPlaylistEntrySong($id, $row['artist_name'],
+      $row['album_name'], $row['track'], $row['name'], $row['length']);
+    $output[1]++;
+    $output[] = 'pl'.$id;
+
+    $songs[] = $row['song_id'];
+    $new_length += $row['length_in_secs'];
+    $new_songcount++;
+  }
+  mysql_free_result($result);
+
+  internalUpdatePlaylist($songs, $new_songcount, $new_length);
+
+  return $output;
+}
+
+function randAdd($type,$num=0,$items='')
+{
+  $output = array(0 => 1);
+  // Check to see if $items matches our REGEXP.
+  if (!preg_match('/^[0-9]+(,[0-9]+)*$/', $items))
+  {
+    return $output;
+  }
+  $sql_items = mysql_real_escape_string($items);
+
+  $query = 'SELECT song_id, length '.
+    'FROM music_songs ';
+  switch($type)
+  {
+    case 'artists':
+      $query .= 'WHERE artist_id IN ('.$sql_items.') ';
+      break;
+    case 'genre':
+      $query .= 'WHERE genre_id IN ('.$sql_items.') ';
+      break;
+    case 'albums':
+      $query .= 'WHERE album_id IN ('.$sql_items.') ';
+      break;
+  }
+  $query .= 'ORDER BY RAND()+0 '.
+    'LIMIT '.mysql_real_escape_string(intval($num));
+  $result = mysql_query($query);
+
+  if (!$result)
+    return $output;
+
+  $pl = internalGetPlaylist();
+
+  if (empty($pl['playlist_songs']))
+  {
+    $songs = array();
+    $new_length = 0;
+    $new_songcount = 0;
+  }
+  else
+  {
+    $songs = explode(',', $pl['playlist_songs']);
+    $new_length = $pl['length_in_secs'];
+    $new_songcount = $pl['songcount'];
+  }
+
+  while ($row = mysql_fetch_array($result))
+  {
+    $songs[] = $row['song_id'];
+    $new_length += $row['length'];
+    $new_songcount++;
+  }
+  mysql_free_result($result);
+
+  internalUpdatePlaylist($songs, $new_songcount, $new_length);
+
+  return $output;
+}
+
+function getPlaylistM3u($id, $quality, $depth = 0)
+{
+  $tmp = '';
+  if ($depth > 20)
+    return $tmp;
+
+  $pl = internalGetPlaylist($id);
+  if (empty($pl['playlist_songs']))
+  {
+    return $tmp;
+  }
+
+  $query = 'SELECT ms.song_id, artist_name, ms.name, (ms.length/1000) AS length '.
+    'FROM music_songs AS ms '.
+    'LEFT JOIN music_artists AS mt ON ms.artist_id=mt.artist_id '.
+    'WHERE ms.song_id IN ('.mysql_real_escape_string($pl['playlist_songs']).')';
+
+  $song_info = array();
+  $result = mysql_query($query);
+  if (!$result)
+    return $tmp;
+
+  while ($row = mysql_fetch_array($result))
+  {
+    $song_info[$row['song_id']] = $row;
+  }
+  mysql_free_result($result);
+
+  $songs = explode(',', $pl['playlist_songs']);
+  foreach ($songs as $song_id)
+  {
+    if ($song_id > 0)
+    {
+      $row = $song_info[$song_id];
+      $tmp .= '#EXTINF:'.intval($row['length']).','.$row['artist_name'].' - '.$row['name']."\n";
+      $tmp .= music_dir().'mp3act_playstream.php?i='.$row['song_id'].'&q='.$quality."\n";
+    }
+    else if ($song_id < 1)
+    {
+      $tmp .= getPlaylistM3u((-1 * $song_id), $quality, $depth+1);
+    }
+  }
+
+  return $tmp;
+}
+
+function play($type, $id, $quality = 'high')
+{
+  $tmp = '';
+  $query = '';
+
+  if ('pl' == $type)
+  {
+    $tmp .= getPlaylistM3u($id, $quality);
+  }
+  else
+  {
+    $query = 'SELECT ms.song_id, artist_name, ms.name, (ms.length/1000) AS length '.
+      'FROM music_songs AS ms '.
+      'LEFT JOIN music_artists AS mt ON ms.artist_id=mt.artist_id '.
+      'WHERE ';
+
+    $sql_id = mysql_real_escape_string($id);
+    switch ($type)
+    {
+      case 'song':
+        $query .= 'ms.song_id='.$sql_id;
+        break;
+      case 'album':
+        $query .= 'ms.album_id='.$sql_id.' '.
+          'ORDER BY ms.track';
+        break;
+      default:
+        return '';
+    }
+
+    $result = mysql_query($query);
+    if ($result)
+    {
+      while ($row = mysql_fetch_array($result))
+      {
+        $tmp .= '#EXTINF:'.intval($row['length']).','.$row['artist_name'].' - '.$row['name']."\n";
+        $tmp .= music_dir().'mp3act_playstream.php?i='.$row['song_id'].'&q='.$quality."\n";
+      }
+      mysql_free_result($result);
+    }
+  }
+  session_cache_limiter('nocache');
+  header('Content-Type: audio/mpegurl;');
+  header('Content-Disposition: inline; filename="playlist.m3u"');
+  header('Expires: 0');
+  header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+  header('Pragma: nocache');
+
+  return "#EXTM3U\n".$tmp;
+}
+
+
+?>
Index: mythweb/modules/music/mp3act_hidden.php
===================================================================
--- mythweb/modules/music/mp3act_hidden.php	(.../trunk/mythplugins)	(revision 0)
+++ mythweb/modules/music/mp3act_hidden.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -0,0 +1,8 @@
+<?php
+// hidden iframe to process streaming
+require_once('modules/music/mp3act_functions.php');
+
+// Play the Music
+if ('' != $_GET['id'])
+    echo play($_GET['type'], $_GET['id'], $_GET['quality']);
+?>
Index: mythweb/modules/music/init.php
===================================================================
--- mythweb/modules/music/init.php	(.../trunk/mythplugins)	(revision 65)
+++ mythweb/modules/music/init.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -16,7 +16,7 @@
 // First, we should check to see that MythMusic is configured.
 // Make sure to turn off fatal errors in case the table isn't there.
     $db->disable_fatal_errors();
-    $has_music = $db->query_col('SELECT COUNT(*) FROM musicmetadata');
+    $has_music = $db->query_col('SELECT COUNT(*) FROM music_songs');
     $db->enable_fatal_errors();
     $db->error(false);
 
Index: mythweb/modules/music/mp3act_html_functions.php
===================================================================
--- mythweb/modules/music/mp3act_html_functions.php	(.../trunk/mythplugins)	(revision 0)
+++ mythweb/modules/music/mp3act_html_functions.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -0,0 +1,160 @@
+<?php
+
+function getHtmlSong($id, $artistName, $albumName, $trackNum, $trackName, $trackLength, $numPlays)
+{
+  static $alt = true;
+  $alt = !$alt;
+  $output = '<li'.($alt ? ' class="alt"' : '').
+    ' ondblclick="pladd(\'song\','.$id.'); return false;">
+    <a class="music" href="#"
+      onclick="pladd(\'song\','.$id.'); return false;"
+      title="'.t('Add Song to Current Playlist').'">
+    <img src="'.pic_dir().'add.gif" /></a>
+    <a class="music" href="#"
+      onclick="play(\'song\','.$id.'); return false;"
+      title="'.t('Play this Song Now').'">
+    <img src="'.pic_dir().'play.gif" /></a> ';
+
+  if (!empty($artistName))
+    $output .= (!empty($trackNum) ? $trackNum.'. ' : '').'<em>'.$artistName.'</em> - ';
+
+  $output .= $trackName;
+
+  $sub_output = '';
+
+  if (!empty($albumName))
+    $sub_output .= sprintf(t('Track #%s from the album \'%s\''), $trackNum, $albumName).'<br />';
+
+  if (!empty($numPlays))
+  {
+    if (1 == $numPlays)
+      $sub_output .= t('Played once').'<br />';
+    else
+      $sub_output .= sprintf(t('Played %s times'), $numPlays).'<br />';
+  }
+
+  if (!empty($trackLength))
+    '<em>'.$trackLength.'</em>';
+
+  if (!empty($sub_output))
+  {
+    $output .= '<p>'.$sub_output.'</p>';
+  }
+
+  $output .= '</li>';
+  return $output;
+}
+
+
+function getHtmlAlbum($id, $albumName, $artistName='', $year='', $numTracks='', $length='', $extra='')
+{
+  static $alt = true;
+  $alt = !$alt;
+  $output = '<li'.($alt ? ' class="alt"' : '').'>';
+
+  if (!empty($extra))
+    $output .= '<small>'.$extra.'</small>';
+
+  $output .= '<a class="music" href="#"
+      onclick="pladd(\'album\','.$id.'); return false;"
+      title="'.t('Add Album to Current Playlist').'">
+    <img src="'.pic_dir().'add.gif" /></a>
+    <a class="music" href="#"
+      onclick="play(\'album\','.$id.'); return false;"
+      title="'.t('Play this Album Now').'">
+    <img src="'.pic_dir().'play.gif" /></a>
+    <a class="music" href="#"
+      onclick="updateBox(\'album\','.$id.'); return false;"
+      title="'.sprintf(t('View Details of %s'), $albumName).'">'.
+    $albumName;
+
+  if (!empty($artistName))
+    $output .= ' &mdash; <em>'.$artistName.'</em>';
+
+  $output .= '</a>';
+
+  $sub_output = '';
+
+  if (!empty($year))
+    $sub_output .= t('Year').': '.$year.'<br />';
+
+  if (!empty($numTracks))
+    $sub_output .= t('# Tracks').': '.$numTracks.'<br />';
+
+  if (!empty($length))
+    $sub_output .= t('Total Length').': '.$length.'<br />';
+
+  if (!empty($sub_output))
+    $output .= '<p>'.$sub_output.'</p>';
+
+  $output .= '</li>';
+  return $output;
+}
+
+
+function getHtmlPlaylist($playlistId, $playlistName, $songcount, $length, $unsavedId = 0, $blnShowDelete = true)
+{
+  return '<li>
+    <a class="music" href="#"
+        onclick="pladd(\'playlist\','.$playlistId.'); return false;"
+        title="'.t('Add this Playlist as a Subplaylist').'">
+        <img src="'.pic_dir().'add.gif" /></a>
+    <a class="music" href="#"
+        onclick="checkPlaylistLoad(\''.$playlistId.'\', '.$unsavedId.')'.
+        ' && pladd(\'loadplaylist\','.$playlistId.'); return false;"
+        title="'.t('Load this Saved Playlist').'">
+        <img src="'.pic_dir().'add.gif" /></a>
+    <a class="music" href="#"
+        onclick="play(\'pl\','.$playlistId.'); return false;"
+        title="'.t('Play this Playlist Now').'">
+    <img src="'.pic_dir().'play.gif" /></a> '.
+    ($blnShowDelete ? '<a class="music" href="#"
+        onclick="deletePlaylist('.$playlistId.'); return false;"
+        title="'.t('DELETE this Saved Playlist').'">
+    <img src="'.pic_dir().'rem.gif" /></a> ' : '').
+    '<a class="music" href="#"
+        onclick="updateBox(\'saved_pl\','.$playlistId.'); return false;"
+        title="'.t('Click to View Playlist').'"><em>'.
+    $playlistName.
+    '</em> - '.sprintf(t('%s Songs'), $songcount).' ('.$length.')'.
+    '</a></li>';
+}
+
+function getHtmlPlaylistEntry($id, $contents)
+{
+  return '<li id="pl'.$id.'"
+      onmouseover="setBgcolor(\'pl'.$id.'\',\'#FCF7A5\');"
+      onmouseout="setBgcolor(\'pl'.$id.'\',\'#F3F3F3\');">
+    <a class="music" href="#"
+      onclick="movePLItem(\'up\',this.parentNode); return false;"
+      title="'.t('Move Item Up in Playlist').'">
+    <img src="'.pic_dir().'up.gif" /></a>
+    <a class="music" href="#"
+      onclick="movePLItem(\'down\',this.parentNode); return false;"
+      title="'.t('Move Item Down in Playlist').'">
+    <img src="'.pic_dir().'down.gif" /></a>
+    <a class="music" href="#"
+      onclick="plrem(this.parentNode); return false;"
+      title="'.t('Remove Item from Playlist').'">
+    <img src="'.pic_dir().'rem.gif" /></a> '.
+    $contents.
+    '</li>';
+}
+
+function getHtmlPlaylistEntrySong($id, $artistName, $albumName, $trackNum, $trackName, $trackLength)
+{
+  return getHtmlPlaylistEntry($id,
+    '<em>'.$artistName.'</em> - '.$trackName.
+    '<p>'.sprintf(t('Track #%s from the album \'%s\''), $trackNum, $albumName).
+    '<br />'.$trackLength.'</p>');
+}
+
+function getHtmlPlaylistEntryPlaylist($id, $playlistName, $playlistSongCount, $playlistTotalTime)
+{
+  return getHtmlPlaylistEntry($id,
+    sprintf(t('Playlist: %s'), '<em>'.$playlistName.'</em>').
+    '<p>'.sprintf(t('%s Songs'), $playlistSongCount).
+    '<br />'.sprintf(t('Total Time:  %s'), $playlistTotalTime).'</p>');
+}
+
+?>
\ No newline at end of file
Index: mythweb/modules/music/mp3act_fat.js
===================================================================
--- mythweb/modules/music/mp3act_fat.js	(.../trunk/mythplugins)	(revision 0)
+++ mythweb/modules/music/mp3act_fat.js	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -0,0 +1,81 @@
+var Fat = {
+	make_hex : function (r,g,b) 
+	{
+		r = r.toString(16); if (r.length == 1) r = '0' + r;
+		g = g.toString(16); if (g.length == 1) g = '0' + g;
+		b = b.toString(16); if (b.length == 1) b = '0' + b;
+		return "#" + r + g + b;
+	},
+	fade_all : function ()
+	{
+		var a = document.getElementsByTagName("*");
+		for (var i = 0; i < a.length; i++) 
+		{
+			var o = a[i];
+			var r = /fade-?(\w{3,6})?/.exec(o.className);
+			if (r)
+			{
+				if (!r[1]) r[1] = "";
+				if (o.id) Fat.fade_element(o.id,null,null,"#"+r[1]);
+			}
+		}
+	},
+	fade_element : function (id, fps, duration, from, to) 
+	{
+		if (!fps) fps = 30;
+		if (!duration) duration = 3000;
+		if (!from || from=="#") from = "#FFFF33";
+		if (!to) to = this.get_bgcolor(id);
+		
+		var frames = Math.round(fps * (duration / 1000));
+		var interval = duration / frames;
+		var delay = interval;
+		var frame = 0;
+		
+		if (from.length < 7) from += from.substr(1,3);
+		if (to.length < 7) to += to.substr(1,3);
+		
+		var rf = parseInt(from.substr(1,2),16);
+		var gf = parseInt(from.substr(3,2),16);
+		var bf = parseInt(from.substr(5,2),16);
+		var rt = parseInt(to.substr(1,2),16);
+		var gt = parseInt(to.substr(3,2),16);
+		var bt = parseInt(to.substr(5,2),16);
+		
+		var r,g,b,h;
+		while (frame < frames)
+		{
+			r = Math.floor(rf * ((frames-frame)/frames) + rt * (frame/frames));
+			g = Math.floor(gf * ((frames-frame)/frames) + gt * (frame/frames));
+			b = Math.floor(bf * ((frames-frame)/frames) + bt * (frame/frames));
+			h = this.make_hex(r,g,b);
+		
+			setTimeout("Fat.set_bgcolor('"+id+"','"+h+"')", delay);
+
+			frame++;
+			delay = interval * frame; 
+		}
+		setTimeout("Fat.set_bgcolor('"+id+"','"+to+"')", delay);
+	},
+	set_bgcolor : function (id, c)
+	{
+		var o = document.getElementById(id);
+		o.style.backgroundColor = c;
+	},
+	get_bgcolor : function (id)
+	{
+		var o = document.getElementById(id);
+		while(o)
+		{
+			var c;
+			if (window.getComputedStyle) c = window.getComputedStyle(o,null).getPropertyValue("background-color");
+			if (o.currentStyle) c = o.currentStyle.backgroundColor;
+			if ((c != "" && c != "transparent") || o.tagName == "BODY") { break; }
+			o = o.parentNode;
+		}
+		if (c == undefined || c == "" || c == "transparent") c = "#FFFFFF";
+		var rgb = c.match(/rgb\s*\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/);
+		if (rgb) c = this.make_hex(parseInt(rgb[1]),parseInt(rgb[2]),parseInt(rgb[3]));
+		return c;
+	}
+}
\ No newline at end of file
Index: mythweb/modules/music/tmpl/default/music.php
===================================================================
--- mythweb/modules/music/tmpl/default/music.php	(.../trunk/mythplugins)	(revision 65)
+++ mythweb/modules/music/tmpl/default/music.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -41,7 +41,7 @@
 
     function playListSelector()
     {
-        $query="SELECT playlistid, name from musicplaylist order by name";
+        $query="SELECT playlist_id, playlist_name FROM music_playlists ORDER BY playlist_name";
         $queryResults=mysql_query($query);
 
         if($queryResults)
Index: mythweb/modules/music/tmpl/compact/music.php
===================================================================
--- mythweb/modules/music/tmpl/compact/music.php	(.../trunk/mythplugins)	(revision 65)
+++ mythweb/modules/music/tmpl/compact/music.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -41,7 +41,7 @@
 
     function playListSelector()
     {
-        $query="SELECT playlistid, name from musicplaylist order by name";
+        $query="SELECT playlist_id, playlist_name FROM music_playlists ORDER BY playlist_name";
         $queryResults=mysql_query($query);
 
         if($queryResults)
Index: mythweb/modules/music/mp3act_playstream.php
===================================================================
--- mythweb/modules/music/mp3act_playstream.php	(.../trunk/mythplugins)	(revision 0)
+++ mythweb/modules/music/mp3act_playstream.php	(.../branches/music-refactor/mythplugins)	(revision 65)
@@ -0,0 +1,67 @@
+<?php
+//require_once('modules/music/mp3act_functions.php');
+
+set_time_limit(0);
+if (!empty($_GET['i']))
+{
+  $qual = 'high';
+  if (!empty($_GET['q']))
+    $qual = $_GET['q'];
+  streamPlay($_GET['i'], $qual);
+}
+
+
+function updateNumPlays($num)
+{
+  $sql_song_id = mysql_real_escape_string($num);
+  $query = 'UPDATE music_songs SET numplays=numplays+1 '.
+    'WHERE song_id='.$sql_song_id;
+   mysql_query($query);
+}
+
+function streamPlay($id)
+{
+  $query = 'SELECT mt.artist_name, ms.name, ms.filename '.
+    'FROM music_songs AS ms '.
+    'LEFT JOIN music_artists AS mt ON ms.artist_id=mt.artist_id '.
+    'WHERE ms.song_id='.mysql_real_escape_string($id);
+
+  $result = mysql_query($query);
+  if (!$result)
+    return;
+
+  $row = mysql_fetch_array($result);
+  updateNumPlays($id);
+  clearstatcache(); // flush buffer
+
+  if (false !== strpos($row['filename'], '://'))
+  {
+    header('Location: '.$row['filename']);
+    exit;
+  }
+
+  $filename = 'data/music/'.$row['filename'];
+
+  switch (substr($filename, -3))
+  {
+    case 'mp3':
+      $mime = 'audio/mpeg'; break;
+    case 'ogg':
+      $mine = 'application/ogg'; break;
+    default:
+      $mime = 'application/octet-stream';
+  }
+
+  header('Content-Type: '.$mime);
+  header('Content-Length: '.filesize($filename));
+  header('Content-Disposition: filename='.$row['artist_name'].' - '.$row['name']);
+
+  $fp = fopen($filename, 'rb');
+  while (!feof($fp))
+    echo fread($fp, 4096);
+  fclose($fp);
+  exit;
+}
+
+
+?>
\ No newline at end of file

