mirror of
				https://github.com/SuperBFG7/ympd
				synced 2025-10-31 13:53:00 +00:00 
			
		
		
		
	various fixups
This commit is contained in:
		
							
								
								
									
										138
									
								
								htdocs/css/slider.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								htdocs/css/slider.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | ||||
| /*! | ||||
|  * Slider for Bootstrap | ||||
|  * | ||||
|  * Copyright 2012 Stefan Petre | ||||
|  * Licensed under the Apache License v2.0 | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  */ | ||||
| .slider { | ||||
|   display: inline-block; | ||||
|   vertical-align: middle; | ||||
|   position: relative; | ||||
| } | ||||
| .slider.slider-horizontal { | ||||
|   width: 210px; | ||||
|   height: 20px; | ||||
| } | ||||
| .slider.slider-horizontal .slider-track { | ||||
|   height: 10px; | ||||
|   width: 100%; | ||||
|   margin-top: -5px; | ||||
|   top: 50%; | ||||
|   left: 0; | ||||
| } | ||||
| .slider.slider-horizontal .slider-selection { | ||||
|   height: 100%; | ||||
|   top: 0; | ||||
|   bottom: 0; | ||||
| } | ||||
| .slider.slider-horizontal .slider-handle { | ||||
|   margin-left: -10px; | ||||
|   margin-top: -5px; | ||||
| } | ||||
| .slider.slider-horizontal .slider-handle.triangle { | ||||
|   border-width: 0 10px 10px 10px; | ||||
|   width: 0; | ||||
|   height: 0; | ||||
|   border-bottom-color: #0480be; | ||||
|   margin-top: 0; | ||||
| } | ||||
| .slider.slider-vertical { | ||||
|   height: 210px; | ||||
|   width: 20px; | ||||
| } | ||||
| .slider.slider-vertical .slider-track { | ||||
|   width: 10px; | ||||
|   height: 100%; | ||||
|   margin-left: -5px; | ||||
|   left: 50%; | ||||
|   top: 0; | ||||
| } | ||||
| .slider.slider-vertical .slider-selection { | ||||
|   width: 100%; | ||||
|   left: 0; | ||||
|   top: 0; | ||||
|   bottom: 0; | ||||
| } | ||||
| .slider.slider-vertical .slider-handle { | ||||
|   margin-left: -5px; | ||||
|   margin-top: -10px; | ||||
| } | ||||
| .slider.slider-vertical .slider-handle.triangle { | ||||
|   border-width: 10px 0 10px 10px; | ||||
|   width: 1px; | ||||
|   height: 1px; | ||||
|   border-left-color: #0480be; | ||||
|   margin-left: 0; | ||||
| } | ||||
| .slider input { | ||||
|   display: none; | ||||
| } | ||||
| .slider .tooltip-inner { | ||||
|   white-space: nowrap; | ||||
| } | ||||
| .slider-track { | ||||
|   position: absolute; | ||||
|   cursor: pointer; | ||||
|   background-color: #f7f7f7; | ||||
|   background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); | ||||
|   background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); | ||||
|   background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); | ||||
|   background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); | ||||
|   background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); | ||||
|   background-repeat: repeat-x; | ||||
|   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); | ||||
|   -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); | ||||
|   -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); | ||||
|   box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); | ||||
|   -webkit-border-radius: 4px; | ||||
|   -moz-border-radius: 4px; | ||||
|   border-radius: 4px; | ||||
| } | ||||
| .slider-selection { | ||||
|   position: absolute; | ||||
|   background-color: #f7f7f7; | ||||
|   background-image: -moz-linear-gradient(top, #f9f9f9, #f5f5f5); | ||||
|   background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f9f9f9), to(#f5f5f5)); | ||||
|   background-image: -webkit-linear-gradient(top, #f9f9f9, #f5f5f5); | ||||
|   background-image: -o-linear-gradient(top, #f9f9f9, #f5f5f5); | ||||
|   background-image: linear-gradient(to bottom, #f9f9f9, #f5f5f5); | ||||
|   background-repeat: repeat-x; | ||||
|   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0); | ||||
|   -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); | ||||
|   -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); | ||||
|   box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); | ||||
|   -webkit-box-sizing: border-box; | ||||
|   -moz-box-sizing: border-box; | ||||
|   box-sizing: border-box; | ||||
|   -webkit-border-radius: 4px; | ||||
|   -moz-border-radius: 4px; | ||||
|   border-radius: 4px; | ||||
| } | ||||
| .slider-handle { | ||||
|   position: absolute; | ||||
|   width: 20px; | ||||
|   height: 20px; | ||||
|   background-color: #0e90d2; | ||||
|   background-image: -moz-linear-gradient(top, #149bdf, #0480be); | ||||
|   background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); | ||||
|   background-image: -webkit-linear-gradient(top, #149bdf, #0480be); | ||||
|   background-image: -o-linear-gradient(top, #149bdf, #0480be); | ||||
|   background-image: linear-gradient(to bottom, #149bdf, #0480be); | ||||
|   background-repeat: repeat-x; | ||||
|   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); | ||||
|   -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); | ||||
|   -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); | ||||
|   box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); | ||||
|   opacity: 0.8; | ||||
|   border: 0px solid transparent; | ||||
| } | ||||
| .slider-handle.round { | ||||
|   -webkit-border-radius: 20px; | ||||
|   -moz-border-radius: 20px; | ||||
|   border-radius: 20px; | ||||
| } | ||||
| .slider-handle.triangle { | ||||
|   background: transparent none; | ||||
| } | ||||
| @@ -14,6 +14,7 @@ | ||||
|  | ||||
|   <!-- Custom styles for this template --> | ||||
|   <link href="css/starter-template.css" rel="stylesheet"> | ||||
|   <link href="css/slider.css" rel="stylesheet"> | ||||
|  | ||||
|   <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --> | ||||
|   <!--[if lt IE 9]> | ||||
| @@ -53,18 +54,19 @@ | ||||
|           <div class="btn-toolbar navbar-btn navbar-right" role="toolbar"> | ||||
|             <div class="btn-group"> | ||||
|               <button type="button" class="btn btn-default"> | ||||
|                 <span class="glyphicon glyphicon-backward"></span> | ||||
|                 <span class="glyphicon glyphicon-backward" onclick="socket.send('MPD_API_SET_NEXT')"></span> | ||||
|               </button> | ||||
|               <button type="button" class="btn btn-default" data-toggle="button"> | ||||
|                 <span class="glyphicon glyphicon-pause"></span> | ||||
|               <button type="button" class="btn btn-default" onclick="socket.send('MPD_API_SET_PAUSE')"> | ||||
|                 <span id="play-icon" class="glyphicon glyphicon-pause"></span> | ||||
|               </button> | ||||
|               <button type="button" class="btn btn-default" onclick="test();"> | ||||
|               <button type="button" class="btn btn-default" onclick="socket.send('MPD_API_SET_PREV')"> | ||||
|                 <span class="glyphicon glyphicon-forward"></span> | ||||
|               </button> | ||||
|             </div> | ||||
|             <div class="btn-group"> | ||||
|               <button id="volume" type="button" class="btn btn-default" data-toggle="button"> | ||||
|                 <span id="volume-icon" class="glyphicon glyphicon-volume-off"></span> | ||||
|               <button type="button" class="btn btn-toolbar btn-default"> | ||||
|                 <span id="volume-icon" class="glyphicon glyphicon-volume-up"></span> | ||||
|                 <input type="text" class="span2" value="0" data-slider-min="0" data-slider-max="100" data-slider-step="5" id="volumeslider" data-slider-tooltip="hide"> | ||||
|               </button> | ||||
|             </div> | ||||
|           </div> | ||||
| @@ -74,7 +76,7 @@ | ||||
|     </div> | ||||
|  | ||||
|     <div class="progress progress-striped active"> | ||||
|       <div class="progress-bar"  role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 45%"> | ||||
|       <div id="progressbar" class="progress-bar"  role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 45%"> | ||||
|         <span class="sr-only">60% Complete</span> | ||||
|       </div> | ||||
|     </div> | ||||
| @@ -86,34 +88,16 @@ | ||||
|           <div class="panel-heading">Playlist</div> | ||||
|  | ||||
|           <!-- Table --> | ||||
|           <table class="table"> | ||||
|           <table id="salamisandwich" class="table"> | ||||
|             <thead> | ||||
|               <tr> | ||||
|                 <th>#</th> | ||||
|                 <th>Track</th> | ||||
|                 <th>Last Name</th> | ||||
|                 <th>Username</th> | ||||
|                 <th>Title</th> | ||||
|                 <th>Duration</th> | ||||
|               </tr> | ||||
|             </thead> | ||||
|             <tbody> | ||||
|               <tr> | ||||
|                 <td>1</td> | ||||
|                 <td>Mark</td> | ||||
|                 <td>Otto</td> | ||||
|                 <td>@mdo</td> | ||||
|               </tr> | ||||
|               <tr> | ||||
|                 <td>2</td> | ||||
|                 <td>Jacob</td> | ||||
|                 <td>Thornton</td> | ||||
|                 <td>@fat</td> | ||||
|               </tr> | ||||
|               <tr> | ||||
|                 <td>3</td> | ||||
|                 <td>Larry</td> | ||||
|                 <td>the Bird</td> | ||||
|                 <td>@twitter</td> | ||||
|               </tr> | ||||
|             </tbody> | ||||
|           </table> | ||||
|         </div> | ||||
| @@ -125,8 +109,9 @@ | ||||
|     <!-- Bootstrap core JavaScript | ||||
|     ================================================== --> | ||||
|     <!-- Placed at the end of the document so the pages load faster --> | ||||
|     <script src="https://code.jquery.com/jquery-1.10.2.min.js"></script> | ||||
|     <script src="js/jquery-1.10.2.min.js"></script> | ||||
|     <script src="js/bootstrap.min.js"></script> | ||||
|     <script src="js/bootstrap-slider.js"></script> | ||||
|     <script src="js/mpd.js"></script> | ||||
|   </body> | ||||
|   </html> | ||||
|   | ||||
							
								
								
									
										388
									
								
								htdocs/js/bootstrap-slider.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										388
									
								
								htdocs/js/bootstrap-slider.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,388 @@ | ||||
| /* ========================================================= | ||||
|  * bootstrap-slider.js v2.0.0 | ||||
|  * http://www.eyecon.ro/bootstrap-slider | ||||
|  * ========================================================= | ||||
|  * Copyright 2012 Stefan Petre | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * ========================================================= */ | ||||
|   | ||||
| !function( $ ) { | ||||
|  | ||||
| 	var Slider = function(element, options) { | ||||
| 		this.element = $(element); | ||||
| 		this.picker = $('<div class="slider">'+ | ||||
| 							'<div class="slider-track">'+ | ||||
| 								'<div class="slider-selection"></div>'+ | ||||
| 								'<div class="slider-handle"></div>'+ | ||||
| 								'<div class="slider-handle"></div>'+ | ||||
| 							'</div>'+ | ||||
| 							'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'+ | ||||
| 						'</div>') | ||||
| 							.insertBefore(this.element) | ||||
| 							.append(this.element); | ||||
| 		this.id = this.element.data('slider-id')||options.id; | ||||
| 		if (this.id) { | ||||
| 			this.picker[0].id = this.id; | ||||
| 		} | ||||
|  | ||||
| 		if (typeof Modernizr !== 'undefined' && Modernizr.touch) { | ||||
| 			this.touchCapable = true; | ||||
| 		} | ||||
|  | ||||
| 		var tooltip = this.element.data('slider-tooltip')||options.tooltip; | ||||
|  | ||||
| 		this.tooltip = this.picker.find('.tooltip'); | ||||
| 		this.tooltipInner = this.tooltip.find('div.tooltip-inner'); | ||||
|  | ||||
| 		this.orientation = this.element.data('slider-orientation')||options.orientation; | ||||
| 		switch(this.orientation) { | ||||
| 			case 'vertical': | ||||
| 				this.picker.addClass('slider-vertical'); | ||||
| 				this.stylePos = 'top'; | ||||
| 				this.mousePos = 'pageY'; | ||||
| 				this.sizePos = 'offsetHeight'; | ||||
| 				this.tooltip.addClass('right')[0].style.left = '100%'; | ||||
| 				break; | ||||
| 			default: | ||||
| 				this.picker | ||||
| 					.addClass('slider-horizontal') | ||||
| 					.css('width', this.element.outerWidth()); | ||||
| 				this.orientation = 'horizontal'; | ||||
| 				this.stylePos = 'left'; | ||||
| 				this.mousePos = 'pageX'; | ||||
| 				this.sizePos = 'offsetWidth'; | ||||
| 				this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px'; | ||||
| 				break; | ||||
| 		} | ||||
|  | ||||
| 		this.min = this.element.data('slider-min')||options.min; | ||||
| 		this.max = this.element.data('slider-max')||options.max; | ||||
| 		this.step = this.element.data('slider-step')||options.step; | ||||
| 		this.value = this.element.data('slider-value')||options.value; | ||||
| 		if (this.value[1]) { | ||||
| 			this.range = true; | ||||
| 		} | ||||
|  | ||||
| 		this.selection = this.element.data('slider-selection')||options.selection; | ||||
| 		this.selectionEl = this.picker.find('.slider-selection'); | ||||
| 		if (this.selection === 'none') { | ||||
| 			this.selectionEl.addClass('hide'); | ||||
| 		} | ||||
| 		this.selectionElStyle = this.selectionEl[0].style; | ||||
|  | ||||
|  | ||||
| 		this.handle1 = this.picker.find('.slider-handle:first'); | ||||
| 		this.handle1Stype = this.handle1[0].style; | ||||
| 		this.handle2 = this.picker.find('.slider-handle:last'); | ||||
| 		this.handle2Stype = this.handle2[0].style; | ||||
|  | ||||
| 		var handle = this.element.data('slider-handle')||options.handle; | ||||
| 		switch(handle) { | ||||
| 			case 'round': | ||||
| 				this.handle1.addClass('round'); | ||||
| 				this.handle2.addClass('round'); | ||||
| 				break | ||||
| 			case 'triangle': | ||||
| 				this.handle1.addClass('triangle'); | ||||
| 				this.handle2.addClass('triangle'); | ||||
| 				break | ||||
| 		} | ||||
|  | ||||
| 		if (this.range) { | ||||
| 			this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); | ||||
| 			this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); | ||||
| 		} else { | ||||
| 			this.value = [ Math.max(this.min, Math.min(this.max, this.value))]; | ||||
| 			this.handle2.addClass('hide'); | ||||
| 			if (this.selection == 'after') { | ||||
| 				this.value[1] = this.max; | ||||
| 			} else { | ||||
| 				this.value[1] = this.min; | ||||
| 			} | ||||
| 		} | ||||
| 		this.diff = this.max - this.min; | ||||
| 		this.percentage = [ | ||||
| 			(this.value[0]-this.min)*100/this.diff, | ||||
| 			(this.value[1]-this.min)*100/this.diff, | ||||
| 			this.step*100/this.diff | ||||
| 		]; | ||||
|  | ||||
| 		this.offset = this.picker.offset(); | ||||
| 		this.size = this.picker[0][this.sizePos]; | ||||
|  | ||||
| 		this.formater = options.formater; | ||||
|  | ||||
| 		this.layout(); | ||||
|  | ||||
| 		if (this.touchCapable) { | ||||
| 			// Touch: Bind touch events: | ||||
| 			this.picker.on({ | ||||
| 				touchstart: $.proxy(this.mousedown, this) | ||||
| 			}); | ||||
| 		} else { | ||||
| 			this.picker.on({ | ||||
| 				mousedown: $.proxy(this.mousedown, this) | ||||
| 			}); | ||||
| 		} | ||||
|  | ||||
| 		if (tooltip === 'show') { | ||||
| 			this.picker.on({ | ||||
| 				mouseenter: $.proxy(this.showTooltip, this), | ||||
| 				mouseleave: $.proxy(this.hideTooltip, this) | ||||
| 			}); | ||||
| 		} else { | ||||
| 			this.tooltip.addClass('hide'); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	Slider.prototype = { | ||||
| 		constructor: Slider, | ||||
|  | ||||
| 		over: false, | ||||
| 		inDrag: false, | ||||
| 		 | ||||
| 		showTooltip: function(){ | ||||
| 			this.tooltip.addClass('in'); | ||||
| 			//var left = Math.round(this.percent*this.width); | ||||
| 			//this.tooltip.css('left', left - this.tooltip.outerWidth()/2); | ||||
| 			this.over = true; | ||||
| 		}, | ||||
| 		 | ||||
| 		hideTooltip: function(){ | ||||
| 			if (this.inDrag === false) { | ||||
| 				this.tooltip.removeClass('in'); | ||||
| 			} | ||||
| 			this.over = false; | ||||
| 		}, | ||||
|  | ||||
| 		layout: function(){ | ||||
| 			this.handle1Stype[this.stylePos] = this.percentage[0]+'%'; | ||||
| 			this.handle2Stype[this.stylePos] = this.percentage[1]+'%'; | ||||
| 			if (this.orientation == 'vertical') { | ||||
| 				this.selectionElStyle.top = Math.min(this.percentage[0], this.percentage[1]) +'%'; | ||||
| 				this.selectionElStyle.height = Math.abs(this.percentage[0] - this.percentage[1]) +'%'; | ||||
| 			} else { | ||||
| 				this.selectionElStyle.left = Math.min(this.percentage[0], this.percentage[1]) +'%'; | ||||
| 				this.selectionElStyle.width = Math.abs(this.percentage[0] - this.percentage[1]) +'%'; | ||||
| 			} | ||||
| 			if (this.range) { | ||||
| 				this.tooltipInner.text( | ||||
| 					this.formater(this.value[0]) +  | ||||
| 					' : ' +  | ||||
| 					this.formater(this.value[1]) | ||||
| 				); | ||||
| 				this.tooltip[0].style[this.stylePos] = this.size * (this.percentage[0] + (this.percentage[1] - this.percentage[0])/2)/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px'; | ||||
| 			} else { | ||||
| 				this.tooltipInner.text( | ||||
| 					this.formater(this.value[0]) | ||||
| 				); | ||||
| 				this.tooltip[0].style[this.stylePos] = this.size * this.percentage[0]/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px'; | ||||
| 			} | ||||
| 		}, | ||||
|  | ||||
| 		mousedown: function(ev) { | ||||
|  | ||||
| 			// Touch: Get the original event: | ||||
| 			if (this.touchCapable && ev.type === 'touchstart') { | ||||
| 				ev = ev.originalEvent; | ||||
| 			} | ||||
|  | ||||
| 			this.offset = this.picker.offset(); | ||||
| 			this.size = this.picker[0][this.sizePos]; | ||||
|  | ||||
| 			var percentage = this.getPercentage(ev); | ||||
|  | ||||
| 			if (this.range) { | ||||
| 				var diff1 = Math.abs(this.percentage[0] - percentage); | ||||
| 				var diff2 = Math.abs(this.percentage[1] - percentage); | ||||
| 				this.dragged = (diff1 < diff2) ? 0 : 1; | ||||
| 			} else { | ||||
| 				this.dragged = 0; | ||||
| 			} | ||||
|  | ||||
| 			this.percentage[this.dragged] = percentage; | ||||
| 			this.layout(); | ||||
|  | ||||
| 			if (this.touchCapable) { | ||||
| 				// Touch: Bind touch events: | ||||
| 				$(document).on({ | ||||
| 					touchmove: $.proxy(this.mousemove, this), | ||||
| 					touchend: $.proxy(this.mouseup, this) | ||||
| 				}); | ||||
| 			} else { | ||||
| 				$(document).on({ | ||||
| 					mousemove: $.proxy(this.mousemove, this), | ||||
| 					mouseup: $.proxy(this.mouseup, this) | ||||
| 				}); | ||||
| 			} | ||||
|  | ||||
| 			this.inDrag = true; | ||||
| 			var val = this.calculateValue(); | ||||
| 			this.element.trigger({ | ||||
| 					type: 'slideStart', | ||||
| 					value: val | ||||
| 				}).trigger({ | ||||
| 					type: 'slide', | ||||
| 					value: val | ||||
| 				}); | ||||
| 			return false; | ||||
| 		}, | ||||
|  | ||||
| 		mousemove: function(ev) { | ||||
| 			 | ||||
| 			// Touch: Get the original event: | ||||
| 			if (this.touchCapable && ev.type === 'touchmove') { | ||||
| 				ev = ev.originalEvent; | ||||
| 			} | ||||
|  | ||||
| 			var percentage = this.getPercentage(ev); | ||||
| 			if (this.range) { | ||||
| 				if (this.dragged === 0 && this.percentage[1] < percentage) { | ||||
| 					this.percentage[0] = this.percentage[1]; | ||||
| 					this.dragged = 1; | ||||
| 				} else if (this.dragged === 1 && this.percentage[0] > percentage) { | ||||
| 					this.percentage[1] = this.percentage[0]; | ||||
| 					this.dragged = 0; | ||||
| 				} | ||||
| 			} | ||||
| 			this.percentage[this.dragged] = percentage; | ||||
| 			this.layout(); | ||||
| 			var val = this.calculateValue(); | ||||
| 			this.element | ||||
| 				.trigger({ | ||||
| 					type: 'slide', | ||||
| 					value: val | ||||
| 				}) | ||||
| 				.data('value', val) | ||||
| 				.prop('value', val); | ||||
| 			return false; | ||||
| 		}, | ||||
|  | ||||
| 		mouseup: function(ev) { | ||||
| 			if (this.touchCapable) { | ||||
| 				// Touch: Bind touch events: | ||||
| 				$(document).off({ | ||||
| 					touchmove: this.mousemove, | ||||
| 					touchend: this.mouseup | ||||
| 				}); | ||||
| 			} else { | ||||
| 				$(document).off({ | ||||
| 					mousemove: this.mousemove, | ||||
| 					mouseup: this.mouseup | ||||
| 				}); | ||||
| 			} | ||||
|  | ||||
| 			this.inDrag = false; | ||||
| 			if (this.over == false) { | ||||
| 				this.hideTooltip(); | ||||
| 			} | ||||
| 			this.element; | ||||
| 			var val = this.calculateValue(); | ||||
| 			this.element | ||||
| 				.trigger({ | ||||
| 					type: 'slideStop', | ||||
| 					value: val | ||||
| 				}) | ||||
| 				.data('value', val) | ||||
| 				.prop('value', val); | ||||
| 			return false; | ||||
| 		}, | ||||
|  | ||||
| 		calculateValue: function() { | ||||
| 			var val; | ||||
| 			if (this.range) { | ||||
| 				val = [ | ||||
| 					(this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step), | ||||
| 					(this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step) | ||||
| 				]; | ||||
| 				this.value = val; | ||||
| 			} else { | ||||
| 				val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step); | ||||
| 				this.value = [val, this.value[1]]; | ||||
| 			} | ||||
| 			return val; | ||||
| 		}, | ||||
|  | ||||
| 		getPercentage: function(ev) { | ||||
| 			if (this.touchCapable) { | ||||
| 				ev = ev.touches[0]; | ||||
| 			} | ||||
| 			var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size; | ||||
| 			percentage = Math.round(percentage/this.percentage[2])*this.percentage[2]; | ||||
| 			return Math.max(0, Math.min(100, percentage)); | ||||
| 		}, | ||||
|  | ||||
| 		getValue: function() { | ||||
| 			if (this.range) { | ||||
| 				return this.value; | ||||
| 			} | ||||
| 			return this.value[0]; | ||||
| 		}, | ||||
|  | ||||
| 		setValue: function(val) { | ||||
| 			this.value = val; | ||||
|  | ||||
| 			if (this.range) { | ||||
| 				this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); | ||||
| 				this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); | ||||
| 			} else { | ||||
| 				this.value = [ Math.max(this.min, Math.min(this.max, this.value))]; | ||||
| 				this.handle2.addClass('hide'); | ||||
| 				if (this.selection == 'after') { | ||||
| 					this.value[1] = this.max; | ||||
| 				} else { | ||||
| 					this.value[1] = this.min; | ||||
| 				} | ||||
| 			} | ||||
| 			this.diff = this.max - this.min; | ||||
| 			this.percentage = [ | ||||
| 				(this.value[0]-this.min)*100/this.diff, | ||||
| 				(this.value[1]-this.min)*100/this.diff, | ||||
| 				this.step*100/this.diff | ||||
| 			]; | ||||
| 			this.layout(); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	$.fn.slider = function ( option, val ) { | ||||
| 		return this.each(function () { | ||||
| 			var $this = $(this), | ||||
| 				data = $this.data('slider'), | ||||
| 				options = typeof option === 'object' && option; | ||||
| 			if (!data)  { | ||||
| 				$this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults,options)))); | ||||
| 			} | ||||
| 			if (typeof option == 'string') { | ||||
| 				data[option](val); | ||||
| 			} | ||||
| 		}) | ||||
| 	}; | ||||
|  | ||||
| 	$.fn.slider.defaults = { | ||||
| 		min: 0, | ||||
| 		max: 10, | ||||
| 		step: 1, | ||||
| 		orientation: 'horizontal', | ||||
| 		value: 5, | ||||
| 		selection: 'before', | ||||
| 		tooltip: 'show', | ||||
| 		handle: 'round', | ||||
| 		formater: function(value) { | ||||
| 			return value; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	$.fn.slider.Constructor = Slider; | ||||
|  | ||||
| }( window.jQuery ); | ||||
							
								
								
									
										6
									
								
								htdocs/js/jquery-1.10.2.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								htdocs/js/jquery-1.10.2.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -6,16 +6,42 @@ if (typeof MozWebSocket != "undefined") { | ||||
| 	socket = new WebSocket(get_appropriate_ws_url(), "ympd-client"); | ||||
| } | ||||
|  | ||||
|  | ||||
| try { | ||||
| 	socket.onopen = function() { | ||||
| 		console.log("Connected"); | ||||
| 		init(); | ||||
| 	}  | ||||
|  | ||||
| 	socket.onmessage =function got_packet(msg) { | ||||
| 		console.log(msg.data); | ||||
| 	}  | ||||
| 		var obj = JSON.parse(msg.data); | ||||
| 		switch (obj.type) { | ||||
| 		  case "playlist": | ||||
| 		  	for (var song in obj.data) { | ||||
| 		  		var minutes = Math.floor(obj.data[song].duration / 60); | ||||
| 		  		var seconds = obj.data[song].duration - minutes * 60; | ||||
|  | ||||
| 		  		$('#salamisandwich tr:last').after( | ||||
| 		  			"<tr id=\"playlist_" + obj.data[song].id + "\"><td>" + obj.data[song].id + "</td>" + | ||||
| 		  			"<td>"+ obj.data[song].uri +"</td>" + | ||||
| 		  			"<td>"+ obj.data[song].title.replace(/%07/g, '"') +"</td>" +  | ||||
| 		  			"<td>"+ minutes + ":" + (seconds < 10 ? '0' : '') + seconds +"</td></tr>"); | ||||
| 		  	} | ||||
| 		    break; | ||||
| 		  case "state": | ||||
| 		  	$('#volumeslider').slider('setValue', obj.data.volume) | ||||
| 		  	var progress = Math.floor(100*obj.data.elapsedTime/obj.data.totalTime) + "%"; | ||||
| 		  	$('#progressbar').width(progress); | ||||
| 		  	$('#playlist_'+obj.data.currentsongid).addClass('active'); | ||||
| 		  	updatePlayIcon(obj.data.state); | ||||
| 		  	updateVolumeIcon(obj.data.volume); | ||||
|  | ||||
| 		  	break; | ||||
| 		  default: | ||||
| 		    alert("Sie bleiben leider dumm"); | ||||
| 		    break; | ||||
| 		} | ||||
| 	} | ||||
| 	socket.onclose = function(){ | ||||
| 		console.log("Disconnected"); | ||||
|  | ||||
| @@ -24,6 +50,10 @@ try { | ||||
| 	alert('<p>Error' + exception);   | ||||
| } | ||||
|  | ||||
| $('#volumeslider').slider().on('slide', function(event) { | ||||
|     socket.send("MPD_API_SET_VOLUME,"+event.value); | ||||
| }); | ||||
|  | ||||
| function get_appropriate_ws_url() | ||||
| { | ||||
| 	var pcol; | ||||
| @@ -48,20 +78,42 @@ function get_appropriate_ws_url() | ||||
| 	return pcol + u[0]; | ||||
| } | ||||
|  | ||||
| var updateVolumeIcon = function(mute) | ||||
| var updateVolumeIcon = function(volume) | ||||
| { | ||||
| 	$("#volume-icon").removeClass("glyphicon-volume-off"); | ||||
| 	$("#volume-icon").removeClass("glyphicon-volume-up"); | ||||
| 	$("#volume-icon").removeClass("glyphicon-volume-down"); | ||||
|  | ||||
| 	if(mute) { | ||||
| 	if(volume == 0) { | ||||
| 		$("#volume-icon").addClass("glyphicon-volume-off"); | ||||
| 		$("#volume").button('toggle') | ||||
| 	} else if (volume < 50) { | ||||
| 		$("#volume-icon").addClass("glyphicon-volume-down"); | ||||
| 	} else { | ||||
| 		$("#volume-icon").addClass("glyphicon-volume-up"); | ||||
| 		$("#volume").button('reset') | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var updatePlayIcon = function(state) | ||||
| { | ||||
| 	$("#play-icon").removeClass("glyphicon-play"); | ||||
| 	$("#play-icon").removeClass("glyphicon-pause"); | ||||
| 	$("#play-icon").removeClass("glyphicon-stop"); | ||||
|  | ||||
| 	if(state == 1) { | ||||
| 		$("#play-icon").addClass("glyphicon-stop"); | ||||
| 	} else if(state == 2) { | ||||
| 		$("#play-icon").addClass("glyphicon-pause"); | ||||
| 	} else { | ||||
| 		$("#play-icon").addClass("glyphicon-play"); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| function init() { | ||||
| 	socket.send("MPD_API_GET_PLAYLIST"); | ||||
| 	socket.send("MPD_API_GET_STATE"); | ||||
| } | ||||
|  | ||||
| function test() { | ||||
| 	socket.send("MPD_API_GET_PLAYLIST"); | ||||
| } | ||||
|   | ||||
| @@ -14,8 +14,13 @@ struct serveable { | ||||
| static const struct serveable whitelist[] = { | ||||
| 	{ "/css/bootstrap.css", "text/css" }, | ||||
| 	{ "/css/starter-template.css", "text/css" }, | ||||
| 	{ "/css/slider.css", "text/css" }, | ||||
|  | ||||
| 	{ "/js/bootstrap.min.js", "text/javascript" }, | ||||
| 	{ "/js/mpd.js", "text/javascript" }, | ||||
| 	{ "/js/jquery-1.10.2.min.js", "text/javascript" }, | ||||
| 	{ "/js/bootstrap-slider.js", "text/javascript" }, | ||||
| 	 | ||||
| 	{ "/fonts/glyphicons-halflings-regular.woff", "application/x-font-woff"}, | ||||
| 	{ "/fonts/glyphicons-halflings-regular.svg", "image/svg+xml"}, | ||||
| 	{ "/fonts/glyphicons-halflings-regular.ttf", "application/x-font-ttf"}, | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
| #include "http_server.h" | ||||
| #include "mpd_client.h" | ||||
|  | ||||
| static struct libwebsocket_protocols protocols[] = { | ||||
| struct libwebsocket_protocols protocols[] = { | ||||
| 	/* first protocol must always be HTTP handler */ | ||||
| 	{ | ||||
| 		"http-only",		/* name */ | ||||
| @@ -40,6 +40,7 @@ int main(int argc, char **argv) | ||||
| 	const char *iface = NULL; | ||||
| 	struct lws_context_creation_info info; | ||||
| 	unsigned int oldus = 0; | ||||
| 	protocol_array = protocols; | ||||
|  | ||||
| 	atexit(bye); | ||||
| 	memset(&info, 0, sizeof info); | ||||
|   | ||||
							
								
								
									
										126
									
								
								src/mpd_client.c
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								src/mpd_client.c
									
									
									
									
									
								
							| @@ -13,9 +13,12 @@ | ||||
|  | ||||
| #include "mpd_client.h" | ||||
|  | ||||
| #define MAX_SIZE 9000*10 | ||||
|  | ||||
| struct mpd_connection *conn = NULL; | ||||
| enum mpd_conn_states mpd_conn_state = MPD_DISCONNECTED; | ||||
| enum mpd_state mpd_play_state = MPD_STATE_UNKNOWN; | ||||
| static int global_send; | ||||
|  | ||||
| callback_ympd(struct libwebsocket_context *context, | ||||
| 	struct libwebsocket *wsi, | ||||
| @@ -23,12 +26,18 @@ callback_ympd(struct libwebsocket_context *context, | ||||
| 	void *user, void *in, size_t len) | ||||
| { | ||||
| 	int n, m; | ||||
| 	/*unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 + | ||||
| 		LWS_SEND_BUFFER_POST_PADDING];*/ | ||||
| 	char *buf; | ||||
| 	char *buf = NULL, *p; | ||||
| 	struct per_session_data__ympd *pss = (struct per_session_data__ympd *)user; | ||||
|  | ||||
| 	//memset(buf, 0, sizeof(buf)); | ||||
| 	//if(global_send || (pss != NULL && pss->do_send)) | ||||
| 	//{ | ||||
| 		buf = (char *)malloc(MAX_SIZE + LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING); | ||||
|  | ||||
| 		if(buf == NULL) | ||||
| 			return -1; | ||||
|  | ||||
| 		p = &buf[LWS_SEND_BUFFER_PRE_PADDING]; | ||||
| 	//} | ||||
|  | ||||
| 	switch (reason) { | ||||
| 		case LWS_CALLBACK_ESTABLISHED: | ||||
| @@ -37,22 +46,24 @@ callback_ympd(struct libwebsocket_context *context, | ||||
| 			break; | ||||
|  | ||||
| 		case LWS_CALLBACK_SERVER_WRITEABLE: | ||||
|  | ||||
| 			if(pss->do_send & DO_SEND_STATE) | ||||
| 			n = mpd_put_state(buf); | ||||
| 			{ | ||||
| 				n = mpd_put_state(p); | ||||
| 				pss->do_send &= ~DO_SEND_STATE; | ||||
| 			} | ||||
| 			else if(pss->do_send & DO_SEND_PLAYLIST) | ||||
| 			{ | ||||
| 			printf("Before buf is %ud\n",buf); | ||||
| 			n = mpd_put_playlist(&buf); | ||||
| 			printf("n is %d, buf is %ud\n", n, buf); | ||||
| 				n = mpd_put_playlist(p); | ||||
| 				pss->do_send &= ~DO_SEND_PLAYLIST; | ||||
| 			} | ||||
| 			else if(pss->do_send & DO_SEND_TRACK_INFO) | ||||
| 			n = mpd_put_current_song(buf); | ||||
| 				n = mpd_put_current_song(p); | ||||
| 			else | ||||
| 			return 0; | ||||
| 			{ | ||||
| 				n = mpd_put_state(p); | ||||
| 			} | ||||
|  | ||||
| 		m = libwebsocket_write(wsi, buf, n, LWS_WRITE_TEXT); | ||||
| 			m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT); | ||||
| 			if (m < n) { | ||||
| 				lwsl_err("ERROR %d writing to socket\n", n); | ||||
| 				return -1; | ||||
| @@ -60,10 +71,39 @@ callback_ympd(struct libwebsocket_context *context, | ||||
| 			break; | ||||
|  | ||||
| 		case LWS_CALLBACK_RECEIVE: | ||||
| 			printf("Got %s\n", (char *)in); | ||||
|  | ||||
| 			if(!strcmp((const char *)in, MPD_API_GET_STATE)) | ||||
| 				pss->do_send |= DO_SEND_STATE; | ||||
| 		if(!strcmp((const char *)in, MPD_API_GET_PLAYLIST)) | ||||
| 			else if(!strcmp((const char *)in, MPD_API_GET_PLAYLIST)) | ||||
| 				pss->do_send |= DO_SEND_PLAYLIST; | ||||
| 			else if(!strcmp((const char *)in, MPD_API_SET_PAUSE)) | ||||
| 			{ | ||||
| 				mpd_send_toggle_pause(conn); | ||||
| 				mpd_response_finish(conn); | ||||
| 			} | ||||
| 			else if(!strcmp((const char *)in, MPD_API_SET_PREV)) | ||||
| 			{ | ||||
| 				mpd_send_previous(conn); | ||||
| 				mpd_response_finish(conn); | ||||
| 			} | ||||
| 			else if(!strcmp((const char *)in, MPD_API_SET_NEXT)) | ||||
| 			{ | ||||
| 				mpd_send_next(conn); | ||||
| 				mpd_response_finish(conn); | ||||
| 			} | ||||
| 			else if(!strncmp((const char *)in, MPD_API_SET_VOLUME, sizeof(MPD_API_SET_VOLUME)-1)) | ||||
| 			{ | ||||
| 				unsigned int volume; | ||||
| 				if(sscanf(in, "MPD_API_SET_VOLUME,%ud", &volume) && volume < 100) | ||||
| 				{ | ||||
| 					printf("Setting volume to %d\n", volume); | ||||
| 					mpd_run_set_volume(conn, volume); | ||||
|  | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
|  | ||||
|  | ||||
| 		break; | ||||
| 	/* | ||||
| @@ -89,7 +129,7 @@ void mpd_loop() | ||||
| 		case MPD_DISCONNECTED: | ||||
| 			/* Try to connect */ | ||||
|  | ||||
| 		conn = mpd_connection_new("127.0.0.1", 6600, 3000); | ||||
| 		conn = mpd_connection_new("10.23.44.2", 6600, 3000); | ||||
| 		if (conn == NULL) { | ||||
| 			lwsl_err("%s", "Out of memory"); | ||||
| 			mpd_conn_state = MPD_FAILURE; | ||||
| @@ -119,9 +159,19 @@ void mpd_loop() | ||||
|  | ||||
| } | ||||
|  | ||||
| const char* encode_string(const char *str) | ||||
| { | ||||
| 	char *ptr = (char *)str; | ||||
| 	while(*ptr++ != '\0') | ||||
| 		if(*ptr=='"') | ||||
| 			*ptr=' '; | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| int mpd_put_state(char* buffer) | ||||
| { | ||||
| 	struct mpd_status *status; | ||||
| 	int len; | ||||
|  | ||||
| 	status = mpd_run_status(conn); | ||||
| 	if (!status) { | ||||
| @@ -130,11 +180,12 @@ int mpd_put_state(char* buffer) | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	sprintf(buffer,  | ||||
| 	len = snprintf(buffer, MAX_SIZE, | ||||
| 		"{\"type\":\"state\", \"data\":{" | ||||
| 		" \"state\":%d, \"volume\":%d, \"repeat\":%d," | ||||
|         " \"single\":%d, \"consume\":%d, \"random\":%d, " | ||||
|         " \"songpos\": %d, \"elapsedTime\": %d, \"totalTime\":%d" | ||||
|         " \"songpos\": %d, \"elapsedTime\": %d, \"totalTime\":%d, " | ||||
|         " \"currentsongid\": %d" | ||||
| 	    "}}",  | ||||
| 		mpd_status_get_state(status), | ||||
| 		mpd_status_get_volume(status),  | ||||
| @@ -144,10 +195,13 @@ int mpd_put_state(char* buffer) | ||||
| 		mpd_status_get_random(status), | ||||
| 		mpd_status_get_song_pos(status), | ||||
| 		mpd_status_get_elapsed_time(status), | ||||
| 		mpd_status_get_total_time(status)); | ||||
| 		mpd_status_get_total_time(status), | ||||
| 		mpd_status_get_song_id(status)); | ||||
|  | ||||
| 	printf("buffer: %s\n", buffer); | ||||
| 	mpd_status_free(status); | ||||
| 	mpd_response_finish(conn); | ||||
| 	//printf("status: %d\n", mpd_response_finish(conn)); | ||||
| 	return len; | ||||
| } | ||||
|  | ||||
| int mpd_put_current_song(char* buffer) | ||||
| @@ -167,27 +221,37 @@ int mpd_put_current_song(char* buffer) | ||||
| 	mpd_response_finish(conn); | ||||
| } | ||||
|  | ||||
| int mpd_put_playlist(char** buffer) | ||||
| int mpd_put_playlist(char* buffer) | ||||
| { | ||||
| 	mpd_send_list_queue_range_meta(conn, 0, 10); | ||||
| 	int max_size = 1024*200; | ||||
| 	*buffer = (char **)malloc(max_size + LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING); | ||||
| 	printf("Buffer init: %p %ud\n", *buffer, *buffer); | ||||
|  | ||||
| 	char *p = &((*buffer)[LWS_SEND_BUFFER_PRE_PADDING]); | ||||
|  | ||||
| 	char *cur = buffer; | ||||
| 	const char *end = buffer + MAX_SIZE; | ||||
| 	struct mpd_entity *entity; | ||||
| 	struct mpd_song const *song; | ||||
|  | ||||
| 	mpd_send_list_queue_meta(conn); | ||||
|  | ||||
| 	cur += snprintf(cur, end  - cur, "{\"type\": \"playlist\", \"data\": [ "); | ||||
|  | ||||
| 	for(entity = mpd_recv_entity(conn); entity; entity = mpd_recv_entity(conn)) { | ||||
|  | ||||
| 		if(mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) { | ||||
| 			struct mpd_song* song = mpd_entity_get_song(entity); | ||||
| 			p += snprintf(p, max_size, "ID: %d, Song: %s\n", mpd_song_get_id(song), mpd_song_get_uri(song)); | ||||
| 			song = mpd_entity_get_song(entity); | ||||
| 			cur += snprintf(cur, end  - cur,  | ||||
| 				"{\"id\":%d, \"uri\":\"%s\", \"duration\":%d, \"title\":\"%s\"},", | ||||
| 				mpd_song_get_id(song), | ||||
| 				mpd_song_get_uri(song), | ||||
| 				mpd_song_get_duration(song), | ||||
| 				encode_string(mpd_song_get_tag(song, MPD_TAG_TITLE, 0)) | ||||
| 			); | ||||
| 		} | ||||
|  | ||||
| 		if(entity != NULL) | ||||
| 		mpd_entity_free(entity); | ||||
| 	} | ||||
| 	//printf("status: %d\n", mpd_response_finish(conn)); | ||||
|  | ||||
| 	printf("strlen is %d\n", strlen(p)); | ||||
| 	return strlen(*buffer + LWS_SEND_BUFFER_PRE_PADDING) +1; | ||||
| 	/* remove last ',' */ | ||||
| 	cur--; | ||||
| 	cur += snprintf(cur, end  - cur, "] }"); | ||||
| 	printf("buffer: %s\n", buffer); | ||||
| 	return cur - buffer; | ||||
| } | ||||
| @@ -4,6 +4,8 @@ | ||||
| #define DO_SEND_PLAYLIST   (1 << 1) | ||||
| #define DO_SEND_TRACK_INFO (1 << 2) | ||||
|  | ||||
| struct libwebsocket_protocols *protocol_array; | ||||
|  | ||||
| struct per_session_data__ympd { | ||||
| 	int do_send; | ||||
| }; | ||||
| @@ -25,6 +27,9 @@ enum mpd_conn_states { | ||||
| #define MPD_API_SET_PLAY         "MPD_API_SET_PLAY" | ||||
| #define MPD_API_SET_STOP         "MPD_API_SET_STOP" | ||||
| #define MPD_API_SET_SEEK         "MPD_API_SET_SEEK" | ||||
| #define MPD_API_SET_NEXT         "MPD_API_SET_PREV" | ||||
| #define MPD_API_SET_PREV         "MPD_API_SET_NEXT" | ||||
|  | ||||
|  | ||||
|  | ||||
| int callback_ympd(struct libwebsocket_context *context, | ||||
| @@ -35,4 +40,4 @@ int callback_ympd(struct libwebsocket_context *context, | ||||
| void mpd_connect(); | ||||
| int mpd_put_state(char* buffer); | ||||
| int mpd_put_current_song(char* buffer); | ||||
| int mpd_put_playlist(char** buffer); | ||||
| int mpd_put_playlist(char* buffer); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Andrew Karpow
					Andrew Karpow