Tag Archives: php

Web controller for Acdsee

UPDATE: 2023 It’s still working

I made a webcontroller for viewing images on a big TV.

Using a Acdsee instance with MCE Controller installed and a webserver.

https://tig.github.io/mcec/example_commands.html

Rate the picture 1-5, clear rating, slideshow start, escape, open/close image, zoom-in out and zoom-reset. Previous and next image fullscreen and delete/yes

Some used defined keys (see php file)

 if ($cmd=="I"){ $put="chars:+"; };
 if ($cmd=="O"){ $put="chars:-"; };
 if ($cmd=="R"){ $put="chars:*"; };
 if ($cmd=="Y"){ $put="chars:y"; };
 if ($cmd=="F"){ $put="chars:f"; };
 if ($cmd=="D"){ $put="delete"; };
 if ($cmd=="N"){ $put="right"; };
 if ($cmd=="P"){ $put="left"; };
 if ($cmd=="ENTER"){ $put="enter"; };
 if ($cmd=="ESC"){ $put="escape"; };

PHP Script for the buttons and creating the TCP packets for MCE.

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" />
<script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
<?php
  $ip           = "remoteserver";
  $port         = "5150";

if (empty($put)) $put = "";
if (empty($line)) $line = "";
$cmd=$_POST['cmd'];
 if ($cmd=="I"){ $put="chars:+"; };
 if ($cmd=="O"){ $put="chars:-"; };
 if ($cmd=="R"){ $put="chars:*"; };
 if ($cmd=="Y"){ $put="chars:y"; };
 if ($cmd=="F"){ $put="chars:f"; };
 if ($cmd=="D"){ $put="delete"; };
 if ($cmd=="N"){ $put="right"; };
 if ($cmd=="P"){ $put="left"; };
 if ($cmd=="ENTER"){ $put="enter"; };
 if ($cmd=="ESC"){ $put="escape"; };
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
    $task = send_cmd("$put", $fp);

 if ($cmd=="1" || $cmd=="2" || $cmd=="3" || $cmd=="4" || $cmd=="5" || $cmd=="0"){
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
        send_cmd("shiftdown:ctrl", $fp);
  fclose($fp);
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
        send_cmd("$cmd", $fp);
  fclose($fp);
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
        send_cmd("shiftup:ctrl", $fp);
  fclose($fp);
        };
if ($cmd=="S") {
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
        send_cmd("shiftdown:alt", $fp);
  fclose($fp);
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
        send_cmd("$cmd", $fp);
  fclose($fp);
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
        send_cmd("shiftup:alt", $fp);
  fclose($fp);
        };

 if ($cmd=="fnietF"){
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
        send_cmd("shiftdown:shift", $fp);
  fclose($fp);
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
        send_cmd("shiftdown:ctrl", $fp);
  fclose($fp);
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
        send_cmd("$cmd", $fp);
  fclose($fp);
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
        send_cmd("shiftup:ctrl", $fp);
  fclose($fp);
  $fp = stream_socket_client("tcp://".$ip.":".$port, $errno, $errstr, 30);
        send_cmd("shiftup:shift", $fp);
  fclose($fp);
        };



//}
  echo "<html><head><title></title></head>";
  echo "<body><center><H1>";
$callself=$_SERVER['PHP_SELF'];
echo "<div data-role=\"controlgroup\" data-type=\"horizontal\">";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"1\"><input type=\"submit\" value=\"1\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"2\"><input type=\"submit\" value=\"2\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"3\"><input type=\"submit\" value=\"3\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"4\"><input type=\"submit\" value=\"4\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"5\"><input type=\"submit\" value=\"5\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"0\"><input type=\"submit\" value=\"Rate Clear\" /></form>\n";
echo "</div>";

echo "<div data-role=\"controlgroup\" data-type=\"horizontal\">";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"S\"><input type=\"submit\" value=\"SLIDESHOW\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"ESC\"><input type=\"submit\" value=\"ESC\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"ENTER\"><input type=\"submit\" value=\"OPEN/CLOSE\" /></form>\n";
  fclose($fp);
echo "</div>";

echo "<div data-role=\"controlgroup\" data-type=\"horizontal\">";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"I\"><input type=\"submit\" value=\"ZOOMIN\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"R\"><input type=\"submit\" value=\"ZOOMRESET\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"O\"><input type=\"submit\" value=\"ZOOMOUT\" /></form>\n";
echo "</div>";

echo "<div data-role=\"controlgroup\" data-type=\"horizontal\">";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"P\"><input type=\"submit\" value=\"PREV\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"D\"><input type=\"submit\" value=\"DEL\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"Y\"><input type=\"submit\" value=\"Y\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"F\"><input type=\"submit\" value=\"FULL\" /></form>\n";
    echo "<form data-transition=\"none\" style=\"display:inline;\" name=\"input\" action=\"$callself\" method=\"post\"><input type=\"hidden\" name=\"cmd\" value=\"N\"><input type=\"submit\" value=\"NEXT\" /></form>\n";
echo "</div>";
  echo "</body></html>";
  function send_cmd($cmd, $fp){
    fwrite($fp, $cmd);
    fwrite($fp, "\n");
        return;
  }
?>

Onkyo web control hack

Back in 2009 i’ve posted my web controller for Onkyo in a forum.

Several people build on that source and made android/iphones app using this as example.

It uses pfsockopen with raw packets in php.
Spend a lot of work reverse engineering the tcp headers to be send.
Another fun trick was re-using a trick i’ve used for my ipcam controller and dartabase. (Dart game application)

Below a PDF with first page of forum

I’ve made a alteration in my logitechmediaserver (squeezebox server) which embedded a onkyo volume control part in the gui.

Volume Onkyo in LMS

Part of code

<?php
// :colorscheme elflord
// Henri Aanstoot
// Onkyo Reciever Web Interface 2009
// Version 0.6b - 23 Oct 2009
// EDIT THIS
$receiveripnumber="your.onkyo.ip.here";
$receiverlistenport="60128";
// maximum to set volume (0-100) 
// !! some have 64 max????
$volumemax=60;
// (i had to enable this port by going onto the menu's on my Onkyo
// ---- NO EDITING BELOW THIS LINE

// trick browser into staying on same page
$ibrowser = strpos($_SERVER['HTTP_USER_AGENT'],"iPhone");
if ($ibrowser == false) {
header("HTTP/1.0 204 No Response");
}
// test write to file
//$fp=fopen("test.txt", "wb");
// write to Receiver 
$fp = pfsockopen($receiveripnumber, $receiverlistenport, $errno, $errstr, 30);
//get command from post form
$command=$_POST['cmd'];
//get volume if cmd is numeric
if(is_numeric($command)) 
 {
if ($command > $volumemax) { $command=$volumemax; }
echo $command;
  $vol=str_pad(dechex($command), 2, '0', STR_PAD_LEFT);
  $command="!1MVL$vol";
 }
// Calculate header and datapacket lengths
$length=strlen($command); 
$length=$length+1;
$total=$length+16;
$code=chr($length);
// total eiscp packet to send 
$line="ISCP\x00\x00\x00\x10\x00\x00\x00$code\x01\x00\x00\x00".$command."\x0D";
#fputs($fp,$line,$total);
// write
fwrite($fp, $line);
// rest status part
//    while (!feof($fp)) {
//        echo fgets($fp, 128);
//    } 

fclose($fp);

if ($ibrowser == true) {
print "<html>
<head>
<title>Sending Command...</title>`
<meta http-equiv=\"refresh\" content=\"0;url=index.php\">
</head>
<body></body>
</html>";
}

?>

List of command’s

header,Power
!1PWR00,Poweroff
!1PWR01,Poweron
header,Muting
!1AMT00,Audio muting off
!1AMT01,Audio muting on
!1AMTQSTN,Audio muting stat
header, Speaker A/B (Main/Front?)
!1SPA00,Speaker A Off
!1SPA01,Speaker A On
!1SPB00,Speaker B Off
!1SPB01,Speaker B On
header,Sound modus
!1LMD00,STEREO
!1LMD01,DIRECT 
!1LMD02,SURROUND
!1LMD03,FILM
!1LMD04,THX
!1LMD05,ACTION
!1LMD06,MUSICAL
!1LMD07,MONO MOVIE
!1LMD08,ORCHESTRA
!1LMD09,UNPLUGGED
!1LMD0A,STUDIO-MIX
!1LMD0B,TV LOGIC
!1LMD0C,ALL CH STEREO
!1LMD0D,THEATER-DIMENSIONAL 
!1LMD0E,ENHANCED 7/ENHANCE
!1LMD0F,MONO 
!1LMD11,PURE AUDIO 
!1LMD12,MULTIPLEX
!1LMD13,FULL MONO
!1LMD14,DOLBY VIRTUAL
!1LMD40,5.1ch Surround
!1LMD40,Straight Decode*1
!1LMD41,Dolby EX/DTS ES
!1LMD41,Dolby EX*2
!1LMD42,THX Cinema
!1LMD43,THX Surround EX
!1LMD50,U2/S2 Cinema/Cinema2
!1LMD51,MusicMode
!1LMD52,Games Mode
!1LMD80,PLII/PLIIx Movie
!1LMD81,PLII/PLIIx Music
!1LMD82,Neo:6 Cinema
!1LMD83,Neo:6 Music
!1LMD84,PLII/PLIIx THX Cinema
!1LMD85,Neo:6 THX Cinema
!1LMD86,PLII/PLIIx Game
!1LMD87,Neural Surr*3
!1LMD88,Neural THX
!1LMD89,PLII THX Games
!1LMD8A,Neo:6 THX Games
!1LMDUP,Listening Mode Wrap-Around Up
!1LMDDOWN,Listening Mode Wrap-Around Down
header,Input Selector
!1SLI00,VIDEO1    VCR/DVR
!1SLI01,VIDEO2    CBL/SAT
!1SLI02,VIDEO3    GAME/TV
!1SLI03,VIDEO4    AUX1(AUX)
!1SLI04,VIDEO5    AUX2
!1SLI05,VIDEO6
!1SLI06,VIDEO7
!1SLI10,DVD
!1SLI20,TAPE(1)
!1SLI21,TAPE2
!1SLI22,PHONO
!1SLI23,CD
!1SLI24,FM
!1SLI25,AM
!1SLI26,TUNER
!1SLI27,MUSIC SERVER 
!1SLI28,INTERNET RADIO
!1SLI29,USB
!1SLI30,MULTI CH
!1SLI31,XM*1
!1SLI32,SIRIUS*1
!1SLIUP,Selector Position Wrap-Around Up
!1SLIDOWN,Selector Position Wrap-Around Down

Audio CD index

I’ve got a large Folk Music collection. And i wanted to have an overview of the Audio CD’s (mp3/flac) i’ve got from every Band or Artist.

So I made some PHP scripts and a scraping tool. To get a nice overview.

A part of it looks like this:

Most is auto-generated:

The scraper part needs eyed3 (made at a later date)

PHP Files

::::::::::::::
artist.php
::::::::::::::
<html><head><title></title>
<style type="text/css">
 img.clams { border: black dotted 1px; }
 </style>
</head><body vlink=black alink=black link=black>
<? $filebak=$file; ?>
<center><P>
<table border=2><tr><td bgcolor="#cccccc">
<P>
<?php include "list.php"; ?>
</td></tr></table>
<P>


<table>

<?php
$file=$filebak;
echo "<tr><td bgcolor=black><a name=\"$file\"><font color=white face=tahoma><b>$file</b></font></a></td></tr>"; include "readcovers.php";  
?> 

</table>
<P>
<?php if (file_exists("thumbs/$file/info.txt")){ include "thumbs/$file/info.txt"; } ?>
</body></html>
::::::::::::::
index.php
::::::::::::::
<html><head><title></title>
<style type="text/css">
 img.clams { border: black dotted 1px; }
 </style>
</head><body vlink=black alink=black link=black>
<a name="top">
<font face=tahoma color=red>missing</font> ::
<font face=tahoma color=orange>not complete</font> ::
<font face=tahoma color=blue>special</font> ::
<font face=tahoma color=green>got this one</font><P> 
<center><P>
<font face=Tahoma>TODO: List artists, per-page covers (per artist)<BR>
Sort A-Z<BR>Counters<BR>filter <i>got this one / Missing</i>
<table border=2><tr><td bgcolor="#cccccc">
<P>
<?php include "list.php"; ?>
</td></tr></table>
<P>


<table>

<?php
$dir = "thumbs/";

// Open a known directory, and proceed to read its contents
if (is_dir($dir)) {
	$dh = opendir($dir);
       	while (($file = readdir($dh)) !==false) {
           #echo "filename: $file : filetype: " . filetype($dir . $file) . "\n";
		if (filetype($dir . $file)=="dir" && $file!=="." && $file!=="..") { echo "<tr><td bgcolor=black><a name=\"$file\"><font color=white face=tahoma><b>$file</b></font></a><a href=\"#top\"> <f
ont face=tahoma color=\"grey\"><small>(top)</small></a></td></tr>"; include "readcovers.php";  }
       	}
}
       closedir($dh);
?> 

</table>
</body></html>
::::::::::::::
list.php
::::::::::::::
<html><head><title></title>
<style>
<!--
A:link {text-decoration: none; color: "#000000";}
A:visited {text-decoration: none; color: "#000000";}
A:hover {text-decoration:  none; }
//-->

</style>
</head><body>

<center><P>
<?php
$countart=0;
$dir = "thumbs/";

// Open a known directory, and proceed to read its contents
if (is_dir($dir)) {
	$dh = opendir($dir);
       	while (($file = readdir($dh)) !==false) {
		if (filetype($dir . $file)=="dir" && $file!=="." && $file!=="..") { echo "<a href=\"index.php#$file\"><font color=black face=tahoma><b>$file</b></font></a><a href=\"artist.php?file=$file\
">@</a> "; $countart=$countart+1; if ($countart==4) { $countart=0; echo "<BR>";} else { echo ":: ";}  }
       	}
}
       closedir($dh);
?> 
</body></html>
::::::::::::::
readcovers.php
::::::::::::::

<tr><td align=left>
<table><tr><td width=30></td>
<?php
$dir1 = "thumbs/$file";
$counter=0;
// Open a known directory, and proceed to read its contents
if (is_dir($dir1)) {
   if ($dh1 = opendir($dir1)) {
       while (($file1 = readdir($dh1)) !==false)  {
#echo "filename: $file : filetype: " . filetype($dir1 . $file) . "<BR>";
$fileinfo="leeg";
if ($counter==7) { echo "</tr><tr><td width=30></td>"; $counter=0; }
if ($file1!=="." && $file1!=="..") {
if (stristr("$file1", ".jpg")) { echo "<td valign=top width=105><center><img src=\"$dir1/$file1\" class=\"clams\">"; 
$fileinfo = str_replace("jpg", "txt", $file1); $counter=$counter+1;}
if (file_exists("$dir1/$fileinfo")) { echo "<br><font face=tahoma><small>"; include "$dir1/$fileinfo"; }
echo "</small></td>";
}
       }
       closedir($dh1);
   }
}
?> 
</tr></table>
</td></tr>

Scraper

mkdir -p /tmp/1
find  celtic/Celtic/ -type d | while read ; do
countmp3=$(ls "$REPLY" | egrep -i mp3$ | wc -l)
if [ $countmp3 -gt 0 ] ; then
	rm -f /tmp/1/*
	album=$( echo $REPLY | rev | cut -f1 -d/ | rev)
	artist=$( echo $REPLY | rev | cut -f2 -d/ | rev)
	countslash=$(echo "$REPLY"  | tr -cd '/' | wc -c)
	if [ $countslash -lt 4 ] ; then
		artist=$album
		album="" 
	fi 
	echo "artist : $artist - Album : $album"
	mkdir -p "thumbs/$artist"
	ls "$REPLY" | egrep -i "mp3$|flac$" | while read biggest; do  
		eyeD3 --write-images=/tmp/1  "$REPLY/$biggest"	

		if [ ! "$( ls -A /tmp/1/ )" ]  ; then cp empty.jpg /tmp/1/FRONT.jpg ;fi
		deze=$(ls -S /tmp/1/* | head -1)
		convert -resize 200x200 "$deze" "thumbs/$artist/$album.jpg" 
		echo "$album" > "thumbs/$artist/$album.txt"
	done
fi
done

I’m planning to make an version which shows every individual mp3, and shows me if they are valid mp3’s/flac and have a good cover.
(Using tiny thumbnails) (Made this, didin’t post)

Beer crate bottle counter

Post in 2002 due to screenshot .. dont know when i build it, some years before.

Using 24 pushbuttons and a IO expander, i could count the bottles in a crate. Probably used something like a hef4067 ??

Now i probably use a weight sensor or a beer cap counter using a webcam image.

Notification to email and shopping list printer.

Web Interface

Every bottle had to be placed back upside down so the opening of the bottle would not press down on the button. Later i used springs which could hold a empty bottle elevated above the button. The weight of a full bottle would press on the button.

Web part Dopcounter (screenshot at top of page)

<HTML><HEAD><TITLE>dopDB.counter running @ fash's place</TITLE></HEAD><BODY bgcolor=white text=black>
<?
if ($show){
print "<a href='index.php'>Show Last</a>";
}
else {
print "<a href='?show=1'>Show All</a>";
}
?>
<CENTER>
<?
$db = mysql_connect("localhost", "user", "pass");
mysql_select_db("dopDB",$db);
// store voor bargraph
$store=0;
$result2 = mysql_query("SELECT max(timestamp) FROM counter",$db);
$maxtimestamp = mysql_fetch_array($result2);
$result = mysql_query("SELECT * FROM counter",$db);
while ($myrow = mysql_fetch_array($result)) {
$lenght=strlen($myrow[1]);
if ( $lenght = 24)
{
if ($maxtimestamp[0] == $myrow[0] || $show)
 {
 $row1= substr("$myrow[1]", 0, 6);
 $row2= substr("$myrow[1]", 6, 6);
 $row3= substr("$myrow[1]", 12, 6);
 $row4= substr("$myrow[1]", 18, 6);
 $row1 = str_replace("1","<td><img src='dop.jpg'></td>",$row1);
 $row1 = str_replace("0","<td><img src='dopl.jpg'></td>",$row1);
 $row2 = str_replace("1","<td><img src='dop.jpg'></td>",$row2);
 $row2 = str_replace("0","<td><img src='dopl.jpg'></td>",$row2);
 $row3 = str_replace("1","<td><img src='dop.jpg'></td>",$row3);
 $row3 = str_replace("0","<td><img src='dopl.jpg'></td>",$row3);
 $row4 = str_replace("1","<td><img src='dop.jpg'></td>",$row4);
 $row4 = str_replace("0","<td><img src='dopl.jpg'></td>",$row4);
 print "<TABLE border=15 bgcolor='#aaaaaa'><TR>";
 print $row1;
 print "</tr><tr>";
 print $row2;
 print "</tr><tr>";
 print $row3;
 print "</tr><tr>";
 print $row4;
 print "</tr><table>";
 }
$dopcounter=str_replace("0","",$myrow[1]);
$totaldop=strlen($dopcounter);
if ($maxtimestamp[0] == $myrow[0] || $show)
 {
print "<P>";
print date('l dS of F Y H:i:s',$myrow[0]); 
print "<BR><H1>$totaldop bottles left</H1>";
 }
$store = $store + 1;
$storetotals[$store]=$totaldop;
if ($totaldop < 6 && $maxtimestamp[0] == $myrow[0])
 {
 print "<BR>Time to buy some beer again!<BR>";
 }
}
else
{
print "numba bottles error! check code!";
}
}
?>

<table border=0>
<tr>
<?
$storebck=$store;
if ($storebck > 50){ $store=$storebck-50; } else { $store=0; }
while ($store <= $storebck){
print "<td bgcolor=#efefff width=10 valign='bottom'>";
$double=$storetotals[$store]*2;
print "<img src='bar1.gif' width=15 height=$double></td>";
$store = $store +1;
}
?>
</tr>
<tr>
<?
if ($storebck > 50){ $store=$storebck-50; } else { $store=0; }
while ($store <= $storebck){
print "<td bgcolor=#efefff width=10 valign='bottom'>";
print "$storetotals[$store]</td>";
$store = $store +1;
}
?>
</tr>
</table>
</BODY></HTML>

Dartabase

Somewhere start 2002, i made a tool for playing darts.
Well … keeping score and history

I was multiuser, multigame with statistics and undo.
You could click on the little dartboard what your have thrown on a real board. It just kept score and told you best finish options.

Screenshot below was a digitized picture, no way accurate. Versions later the board was realtime drawn with GDlib and pixelperfect.
It even showed you previous throws.

At the end of the game it should give you the hotspots you have thrown.

Later version