Salut robob,
Ta réponse me fait plaisir, car j'attendais des réactions. En effet, mon travail n'est qu'un premier jet, et il y a certainement des tas de choses à améliorer et à compléter !
Ceci dit, je m'empresse de préciser que je n'ai rien inventé, tout le mérite en revient à l'auteur de "foo_http_control", un dénommé oblikoamorale, sur le forum hydrogenaudio. Si tu vas sur son thread (
ici), tu verras qu'il ne s'est pas contenté de coder le serveur côté foobar, mais qu'il a également créé un "template" de page web de télécommande fonctionnel. D'ailleurs, d'autres personnes se sont inspirées de son template pour coder le leur, pour différents smartphones ou tablettes, et on peut les télécharger sur le même thread.
En ce qui concerne mon template, j'ai volontairement gardé un aspect visuel le plus simple possible, car avec le wifi la page web met un temps non négligeable pour se recharger depuis le serveur à chaque commande envoyée, et si elle est surchargée d'images de fond stockées sur le serveur, elle mettra un temps encore plus long à se recharger.
C'est pourquoi je n'ai utilisé que des éléments qui sont générés directement par le navigateur sur la tablette, comme les couleurs de fond, les lignes de séparation, les encadrements, et même les boutons. Il n'y a que l'image de la pochette et les titres de l'album qui se rechargent à chaque fois depuis le serveur.
Mais si le temps de chargement ne te dérange pas, c'est clair que tu peux grandement améliorer le design en utilisant des images de fond et des boutons qui sont stockés sur le serveur. Quand je parle de temps de chargement, avec mon template la page se recharge en une demi seconde environ, donc il reste de la marge !

Pour les playlists ce n'est pas un problème, le template original les gère sans problèmes, moi je les ai enlevées car je ne les utilise pas. Même chose pour le réglage de volume, d'origine il y en a un.
Par contre, pour l'affichage des mini jacquettes, j'ai un doute, je ne sais pas si c'est faisable, car cela dépend du serveur, et le serveur d'oblikoamorale n'est pas modifiable tel quel, il faudrait tout un environnement de développement sous windows, cher et sophistiqué, et maîtriser des langages comme le C++, ce qui n'est pas mon cas.........

C'est le même problème pour le choix des sorties audio du lecteur.
Quant à lancer et arrêter foobar depuis la télécommande, ce n'est pas possible en l'état, car le serveur est installé DANS foobar sour forme de plugin, donc foobar doit être lancé avant. Si tu veux pouvoir le faire, alors il te faut utiliser une prise de contrôle à distance, installée sur la tablette, et qui te permettra de contrôler windows et tous les programmes depuis la tablette.
Pour le code, pas de problèmes, je veux bien le mettre à disposition. Il y a deux pages, c'est de l'ajax (html, css, javascript, xml).
Page de la bibliothèque (foo_httpcontrol_browser_tpl.html):
- Code: Tout sélectionner
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>browser - foo_httpcontrol</title>
<link rel="shortcut Icon" href="/tablet/favicon.ico" type="image/x-icon" />
<meta name="author" lang="fr" content="Pierre Ingold">
<script language="JavaScript" type="text/javascript">
<!--
function getXMLHTTP()
{
try {return new ActiveXObject("Msxml2.XMLHTTP");}
catch(e) {try {return new ActiveXObject("Microsoft.XMLHTTP");}
catch(e) {}}
if(typeof XMLHttpRequest != "undefined") {return new XMLHttpRequest();}
return null;
}
function EmptyPlaylist()
{
httpRequestStatus = getXMLHTTP();
try {
httpRequestStatus.open("GET", '/tablet/?cmd=EmptyPlaylist¶m3=NoResponse', true);
httpRequestStatus.send(null);
}
catch(e) { }
}
function ReplaceAndEnqueueStep3()
{
delete httpRequestStatus;
httpRequestStatus = getXMLHTTP();
try {
httpRequestStatus.open("GET", '/tablet/?param3=foo_is_enqueueing.html', true);
httpRequestStatus.onreadystatechange = function() {
if (httpRequestStatus.readyState == 4)
{
if (httpRequestStatus.responseText == "0")
{
window.location.href = "/tablet/?cmd=Start";
}
setTimeout("ReplaceAndEnqueueStep3()", 1000);
}
};
httpRequestStatus.send(null);
}
catch(e) { };
}
function ReplaceAndEnqueuePreStep3()
{
if (httpRequestStatus.readyState == 4)
{
setTimeout("ReplaceAndEnqueueStep3()", 1000);
}
}
function ReplaceAndEnqueueStep2()
{
if (httpRequestStatus.readyState == 4)
{
delete httpRequestStatus;
httpRequestStatus = getXMLHTTP();
try {
httpRequestStatus.open("GET", '/tablet/?cmd=Browse¶m1=[PATH]¶m2=EnqueueDir¶m3=NoResponse', true);
httpRequestStatus.onreadystatechange = ReplaceAndEnqueuePreStep3;
httpRequestStatus.send(null);
}
catch(e) { };
}
}
function ReplaceAndEnqueueStep1()
{
httpRequestStatus = getXMLHTTP();
try {
httpRequestStatus.open("GET", '/tablet/?cmd=EmptyPlaylist¶m3=NoResponse', true);
httpRequestStatus.onreadystatechange = ReplaceAndEnqueueStep2;
httpRequestStatus.send(null);
}
catch(e) { };
}
function ReplaceAndEnqueuesubdirStep3()
{
delete httpRequestStatus;
httpRequestStatus = getXMLHTTP();
try {
httpRequestStatus.open("GET", '/tablet/?param3=foo_is_enqueueing.html', true);
httpRequestStatus.onreadystatechange = function() {
if (httpRequestStatus.readyState == 4)
{
if (httpRequestStatus.responseText == "0")
{
window.location.href = "/tablet/?cmd=Start";
}
setTimeout("ReplaceAndEnqueuesubdirStep3()", 1000);
}
};
httpRequestStatus.send(null);
}
catch(e) { };
}
function ReplaceAndEnqueuesubdirPreStep3()
{
if (httpRequestStatus.readyState == 4)
{
setTimeout("ReplaceAndEnqueuesubdirStep3()", 1000);
}
}
function ReplaceAndEnqueuesubdirStep2()
{
if (httpRequestStatus.readyState == 4)
{
delete httpRequestStatus;
httpRequestStatus = getXMLHTTP();
try {
httpRequestStatus.open("GET", '/tablet/?cmd=Browse¶m1=[PATH]¶m2=EnqueueDirSubdirs¶m3=NoResponse', true);
httpRequestStatus.onreadystatechange = ReplaceAndEnqueuesubdirPreStep3;
httpRequestStatus.send(null);
}
catch(e) { };
}
}
function ReplaceAndEnqueuesubdirStep1()
{
httpRequestStatus = getXMLHTTP();
try {
httpRequestStatus.open("GET", '/tablet/?cmd=EmptyPlaylist¶m3=NoResponse', true);
httpRequestStatus.onreadystatechange = ReplaceAndEnqueuesubdirStep2;
httpRequestStatus.send(null);
}
catch(e) { };
}
//-->
</script>
<style type="text/css">
<!--
html, body {
height: 100%;
}
body {
margin: 0;
padding: 0;
font-family:verdana, arial, helvetica, sans-serif;
background-color: #505050;
text-align: center;
}
#header {
position: fixed;
top: 5px;
right: 0px;
left: 0px;
bottom: 0;
height: 60px;
background-color: #505050;
text-align: center;
text-decoration: none;
}
input {
width:100px;
height: 45px;
background-color:#C5D6FC;
color:#0000FF;
text-align: center;
text-decoration: none;
font-size: large;
margin: 0;
padding: 0;
}
#main {
position: absolute;
top: 65px;
right: 0px;
bottom: 0px;
left: 0px;
margin-right:10px;
margin-bottom:15px;
margin-left:10px;
padding-top:10px;
padding-right: 5px;
padding-left : 5px;
overflow:auto;
background-color: #505050;
border:2px solid #0000FF;
}
.dir {
font-weight: normal;
text-transform: uppercase;
font-size:22px;
}
table {
border-collapse: collapse;
width: 100%;
margin-top: 1px;
margin-bottom: 1px;
background-color:#0000FF;
}
table td {
padding: 6px;
font-family:Verdana, Arial, Helvetica, sans-serif;
font-size:19px;
}
tr.odd td {
background-color: #464646;
color: #00FF00;
}
tr.even td {
background-color: #464646;
color: #00FF00;
}
tr.rodd td {
background-color: #464646;
color: A5D6FC;
}
tr.reven td {
background-color: #464646;
color: A5D6FC;
}
td.c1 {
width: 80%;
}
td.c2 {
text-align: right;
white-space: nowrap;
width: 5%;
padding-right: 5px;
}
td.c3 {
text-align: left;
white-space: nowrap;
width: 5%;
padding-left: 5px;
padding-right: 10px;
}
td.c4 {
text-align: right;
white-space: nowrap;
width: 10%;
}
a, a.current, a.current:hover {
text-decoration: none;
color: A5D6FC;
}
a:hover {
color: red;
}
form {
margin-top: 5px;
border: 0;
}
a img {
border: none;
text-decoration: none;
}
.arrondi{
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
-khtml-border-radius: 5px;
-ms-border-radius: 5px;
background: -moz-linear-gradient(top, #A5D6FC, #C5D6FC);
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#A5D6FC), to(#C5D6FC));
}
.arrondi:active{
background:#C5D6FC;
background: #C5D6FC;
}
-->
</style>
</head>
<body>
<div id= "header">
<form action="/tablet/" method="get" name="cmd_form" target="_self">
<input name="Replace" title="Replace current directory including subdirectories" type="button" value="REPLACE" onclick="javascript:ReplaceAndEnqueuesubdirStep1()" class="arrondi">
<input name="Empty Playlist" title="Empty Playlist" type="button" value="EMPTY" onclick="javascript:EmptyPlaylist()" class="arrondi">
<a title="Enqueue current directory including subdirectories" href="/tablet/?cmd=Browse&param1=[PATH]&param2=EnqueueDirSubdirs"><input type="button" value="ENQUEUE" class="arrondi"></a>
<a title="Play Queue" href="/tablet/?cmd=Start"><input type="button" value="PLAY" class="arrondi"></a>
<input name="cmd" type="hidden" value="Browse">
<input name="param1" type="hidden" value="">
<input name="param2" type="hidden" value="">
</form>
</div>
<div id="main">
[BROWSER]
<!--[PGT] ms-->
</div>
</body>
</html>
Page des commandes (foo_httpcontrol_controls_tpl.html):
- Code: Tout sélectionner
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
<html>
<head>
<title>[HELPER1X]foobar2000</title>
<link rel="shortcut Icon" href="/tablet/favicon.ico" type="image/x-icon" />
<meta name="author" lang="fr" content="Pierre Ingold">
<script language="JavaScript" type="text/javascript">
<!--
var mouseX = 0;
var p_key = 0;
var act = 0;
function KeyPress(e) {
p_key = e;
if (p_key == 16) // shift -- focus
act = 3;
else if (p_key == 17) // ctrl -- remove
act = 4;
else if (p_key == 81) // q -- enqueue
act = 1;
else if (p_key == 87) // w -- dequeue
act = 2;
else
act = 0;
document.getElementById('Actions').selectedIndex = act;
}
function pad(str, chr, count) {
var str_out = str.toString();
while (str_out.length < count)
str_out = chr + str_out;
return str_out;
}
function pc(c, p) {
var com = c || ''; var par = p || '';
with (document.cmd_form)
{
cmd.value = com;
param1.value = par;
submit();
}
}
function format_time(time) {
mins = Math.floor(time / 60);
secs = pad(time % 60, '0', 2);
return mins+":"+secs;
}
function set_t_pos(time) {
var str = format_time(time) + " / ";
document.getElementById("t_time").innerHTML = str + ( [ITEM_PLAYING_LEN] > 0 ? format_time([ITEM_PLAYING_LEN]) : '?' );
}
function set_np_width(t_sec, t_length) {
var np_width = document.getElementById("npd").offsetWidth;
np_width = np_width < 100 ? 100: np_width;
document.getElementById('np').style.width=Math.floor(np_width * t_sec / t_length) + "px";
}
function t_playback_timer(t_sec, t_length) {
if (t_sec <= t_length && t_length != 0)
{
set_t_pos(t_sec);
if (t_length != 0)
set_np_width(t_sec, t_length);
setTimeout('t_playback_timer('+(t_sec+1)+','+t_length+')',1000);
}
}
function a(track) { // do a(ction) on clicked entry
if (act == 0) pc('Start', track);
else if (act == 1) pc('QueueItems', track);
else if (act == 2) pc('DequeueItems', track);
else if (act == 3) pc('SetFocus', track);
else if (act == 4) pc('Del', track);
}
function np_onclick() {
with (document)
pc('Seek', Math.round((mouseX-getElementById("np").offsetLeft)*100 / (getElementById("npd").offsetWidth)) );
}
function mouse_capture_init() {
if (document.layers? true : false)
captureEvents(Event.MOUSEMOVE)
document.onmousemove = handleMouseMove;
}
function handleMouseMove(evt) {
if (evt)
mouseX=evt.clientX;
else
if (event)
mouseX=event.x;
return false;
}
function fit() {
with (document.getElementById('playlist'))
{
style.position = 'static'; // important for the onresize event
style.overflowY = 'auto';
style.top = offsetTop + 'px';
style.left = offsetLeft + 'px';
style.right = offsetLeft + 'px';
style.bottom = '8px'; // fit this to your taste
style.position = 'fixed';
var npelem = document.getElementById("nowplaying");
if (npelem)
{
scrolltop = npelem.offsetTop - offsetHeight/2;
if (scrolltop > 0)
scrollTop = scrolltop;
}
}
}
document.onkeydown = function(evt) { KeyPress(evt?evt.keyCode:event.keyCode); }
var testin = [PLAYBACK_ORDER];
function afficher(form1) {
switch (testin)
{
case 0:
document.form1.output.value=("Play Normal");
break;
case 1:
document.form1.output.value=("Repeat All");
break;
case 2:
document.form1.output.value=("Repeat Track");
break;
case 3:
document.form1.output.value=("Play Random");
break;
default:
document.form1.output.value=("Error");
break;
}
}
//-->
</script>
<style type="text/css">
<!--
html, body {
height: 100%;
}
body {
margin:0;
padding: 0;
font-family:verdana, arial, helvetica, sans-serif;
font-size:16px;
background-color:#505050;
color:#A5D6FC;
}
#global {
position:relative;
width:100%;
height:100%;
background-color:#505050;
}
#main_1 {
height:70px;
margin:0;
padding: 0;
background-color:#505050;
}
#leftheader {
float:left;
height:70px;
width:330px;
background-color:#505050;
padding-left:20px;
}
#total_time {
margin-top:8px;
padding:0px;
color:#A5D6FC;
}
#pqtt {
color:yellow;
}
#trackinfo {
margin-top:10px;
padding:0px;
}
#info {
color:#00FF00;
font-family:verdana, arial, helvetica, sans-serif;
font-size:16px;
padding: 0;
}
#header {
margin-left:350px;
height:70px;
width:670Px;
background-color:#505050;
}
#track_title {
margin-top:8px;
font-variant: small-caps;
background-color: #505050;
color: yellow;
padding-top: 4px;
text-align:center;
}
.track_t {
padding:5px;
font-size: 16px;
}
#main_2 {
clear:both;
margin:0;
padding: 0;
background-color:#505050;
}
#sidebar {
float:left;
width:320px;
background-color:#505050;
padding-left:20px;
}
#cover {
width:290px;
margin-bottom:6px;
padding:0;
border:2px solid #0000FF;
}
#order {
width:120px;
height: 20px;
background-color:#505050;
color:#00FF00;
text-align: left;
font-size:16px;
font-weight:normal;
margin: 0;
padding: 0;
border: none;
}
input {
width:54px;
height: 45px;
background-color:#C5D6FC;
color:#0000FF;
font-weight:bold;
text-align: center;
font-size:15px;
margin: 0;
padding: 0;
}
#status {
color:#00FF00;
font-family:verdana, arial, helvetica, sans-serif;
font-size:16px;
font-weight:normal;
margin: 0;
padding: 0;
}
#t_time {
}
.track_p {
padding:10px;
font-size:26px;
color:red;
}
#npd {
position: relative;
background-color: #A5D6FC;
font-size: 7px;
margin-left: 0px;
margin-right: 20px;
margin-top : 15px;
margin-bottom: 0;
padding-right: 6em;
white-space: pre-wrap;
cursor: move;
}
#np {
position: absolute;
top:0;
right:0;
bottom:0;
left:0;
heigth: 7px;
opacity: .99;
background-color: #FF0000;
}
#playlist {
width:635Px;
height:495px;
margin-top:4px;
margin-left:25px;
margin-bottom:0px;
padding-top:5px;
background-color:#505050;
border:2px solid #0000FF;
text-align:center;
}
table {
text-align:left;
margin:auto;
}
table td {
font-family:Verdana, Arial, Helvetica, sans-serif;
font-size:16px;
color:A5D6FC;
padding: 5px;
}
tr.npr td {
background-color: #505050;
}
/* playlist entries highlight */
tr.o td {
background-color: #505050;
} /* o(dd) */
tr.e td {
background-color: #505050;
} /* e(ven) */
tr.prev td {
} /* prev(iously played) */
tr.focus td {
color:red;
} /* focus(ed) */
tr.queue td {
background-color: #505050;
} /* queue(d) #ecebff */
td.t {
text-align: right;
} /* t(otal time) */
td.q {
text-align: right;
} /* q(ueue order) */
#browser {
position:absolute;
margin-top:520px;
margin-left:430px;
}
#refresh {
position:absolute;
margin-top:520px;
margin-left:740px;
}
#big {
width:200px;
height: 50px;
background-color:#C5D6FC;
color:#0000FF;
text-align: center;
font-size: large;
font-weight:normal;
margin-top: 10px ;
padding: 0;
}
a, a.current, a.current:hover {
color:A5D6FC;
}
a:hover {
text-decoration: none;
color: #FF0000;
}
form {
}
p {
line-height:8px;
}
.arrondi{
-moz-border-radius: 5px 5px 5px 5px;
-webkit-border-radius: 5px;
-khtml-border-radius: 5px;
-ms-border-radius: 5px;
background: -moz-linear-gradient(top, #A5D6FC, #C5D6FC);
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#A5D6FC), to(#C5D6FC));
}
.arrondi:active{
background:#C5D6FC;
background: #C5D6FC;
}
.arrondi2{
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
-khtml-border-radius: 2px;
-ms-border-radius: 2px;
}
-->
</style>
</head>
<body onload="mouse_capture_init(); fit(); afficher(form1);" onresize="fit();">
<div id="global">
<div id="main_1">
<div id="leftheader">
<div id="total_time">Total Time: <span id="pqtt">[PLAYLIST_TOTAL_TIME][QUEUE_TOTAL_TIME]</span></div>
<div id="trackinfo">Track Info: <span id="info">[HELPER3X]</span></div>
</div>
<div id="header">
<div id="track_title" class="track_t">[HELPER2X]</div>
</div>
</div>
<div id="main_2">
<div id="sidebar">
<div id="cover"><a href="javascript:pc();"><img src="[ALBUMART]" width="290px" height="290px" border="none"></a></div>
<form name="form1">
Playback Order: <input id="order" title="playback order" type="text" name="output" value="()";>
</form>
<p>
<input name="0" title="default" type="button" value="nor" onclick="pc('PlaybackOrder',this.name);" class="arrondi">
<input name="2" title="repeat track" type="button" value="one" onclick="pc('PlaybackOrder',this.name);" class="arrondi">
<input name="1" title="repeat playlist" type="button" value="all" onclick="pc('PlaybackOrder',this.name);" class="arrondi">
<input name="3" title="random" type="button" value="?" onclick="pc('PlaybackOrder',this.name);" class="arrondi">
</p>
<hr height="2px" width="290px" color="#0000FF" align="left"></hr>
<form action="/tablet/" method="get" name="cmd_form" target="_self">
Playback Status: <span id="status"></span>
<p>
<input name="Stop" title="Stop playback" type="button" value="#" onclick="pc(this.name);" class="arrondi">
<input name="PlayOrPause" title="Pause/resume playback" type="button" value="||" onclick="pc(this.name);" class="arrondi">
<input name="Start" title="Start playback" type="button" value="|>" onclick="pc(this.name);" class="arrondi">
<input name="StartPrevious" title="Play previous track" type="button" value="||<" onclick="pc(this.name);" class="arrondi">
<input name="StartNext" title="Play next track" type="button" value=">||" onclick="pc(this.name);" class="arrondi">
</p>
<hr height="2px" width="290px" color="#0000FF" align="left"></hr>
<label id="Actions" title="Playlist action on click"></label>
<p>
<div id="tracktime">Track Time: <span id="t_time" class="track_p"></span></div>
</p>
<p>
<div id="npd" onclick="np_onclick();" class="arrondi2"><span id="np" class="arrondi2"></span>a</div>
</p>
<input name="cmd" type="hidden" value=""><input name="param1" type="hidden" value="">
</form>
<script language="JavaScript" type="text/javascript">
<!--
with (document)
{
act = [LAST_ACTION];
getElementById('Actions').selectedIndex = act;
var i_p;
if ('[PLAYLIST_ITEM_PLAYING]' != '?')
i_p = parseInt('[PLAYLIST_ITEM_PLAYING]') + 1;
else
i_p = '?';
if ([IS_PLAYING]) { // start progressbar if playing
t_playback_timer([TRACK_POS],[TRACK_LEN]);
if (([TRACK_LEN]>0))
setTimeout('pc()',([TRACK_LEN]-[TRACK_POS])*1000 + 500);
getElementById('status').innerHTML = ' Playing ' + i_p + ' / [PLAYLIST_PLAYING_ITEMS_COUNT] ';
}
else if ([IS_PAUSED]) { // adjust progressbar width if paused
set_np_width([TRACK_POS], [TRACK_LEN]);
set_t_pos([TRACK_POS]);
getElementById('status').innerHTML = ' Paused ' + i_p + ' / [PLAYLIST_PLAYING_ITEMS_COUNT] ';
} else { // hide unnecessary track info if stopped
counter = getElementById("counter");
if (counter)
counter.innerHTML = "";
getElementById("status").innerHTML = "Stopped";
getElementById("npd").style.visibility = "hidden";
}
if ([IS_ENQUEUEING] ) {
getElementById('status').innerHTML = '[ Enqueuement in progress ] ' + getElementById('status').innerHTML;
setTimeout('pc()',5000);
}
track = getElementById("track_title");
if (track && track.innerHTML == '' && ([IS_PLAYING] || [IS_PAUSED])) // if playing but track info is not loaded yet, reload page
setTimeout('pc()',500);
npp = getElementById("np"); // adjust progressbar width and height, and opacity hack for IE6
if (npp)
with (npp.style) {
// if (getElementById("np").offsetHeight >= 2 )
// height=getElementById("np").offsetHeight*2-2+"px";
// left=getElementById("npd").offsetLeft+"px";
filter = "alpha(opacity=50)";
}
}
//-->
</script>
</div>
<div id="playlist">
<table>[PLAYLIST]
<tr><td></td></tr>
</table>
</div>
<div id="browser">
<input id="big" title="browse library" type="button" name="Browse" value="BROWSE LIBRARY"; onclick="pc(this.name)"; class="arrondi"></input>
</div>
<div id="refresh">
<input id="big" title="Refresh Page" type="button" name="Refresh" value="REFRESH" onclick="pc(this.name);" class="arrondi"></input>
</div>
</div>
</div>
</body>
</html>
Voilà, j'attends tes idées !
A+