-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgruvi.php
executable file
·242 lines (201 loc) · 10.9 KB
/
gruvi.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
<?php
/* Random URL image file list generator for the Image Viewer app on the Squeezebox Touch, Radio etc. with:
-Random selection of files and random shuffle of the lists between every call to this PHP-file on
independent web servers, ,or with periodic cron jobs on the LMS internal web server.
-Locally cached copies of the images with reduced sizes to minimize load on the LMS, players and network
-Image files hosted on a web server of your chosing and fittet to the players' screen sizes
-Choice between images with or without capitons
-Choice of number of cached files and expiry time for reload of new batches of random images
-Added support for multiple image folders with internal probability weighing for the random image selection
and with the choice between serial and parallel processing of the ImageMagick conversions between folders.
Choice between total independence from the LMS server on any web server, or run in LMS internal web server.
No more versions or plugins conflicts, no more spinning
disks on the NAS, heavy machinery required to run 24/7 etc... ;-)
This was my very first complete PHP-script ever, so sorry for the bad and ugly coding, without
any error or exception handling. It barely does what it's supposed to do, but gets the job done
for the time being, if you can get it to work. I'm on the forum from time to time, but don't have
the resources to provide any reliable support.
Feel free to copy and improve as you feel fit! I did so much research and copying myself,
that I don't remember all the people I should be thanking.
!! Special thanks to the primus motors on the Squeezebox community forum who keeps both the
best audio community and the best music server/player ecosystem ever still alive and kicking!!
Nice also if any suggestions for improvements to this script were posted back on this forum thread!
by vegz78...
Originally posted in this Squeezebox forum thread:
https://forums.slimdevices.com/showthread.php?108498-Announce-GRUVI-generate-random-URLs_for-viewing-images
*/
//Global variables
$LIST_SIZE = 60; //Number of random images to be processed and included in the image URL list
$FILE_AGE_MAX = 2880; //Time in minutes before a random image file pointed to in the list is changed
$CAPTIONS = True; //True = Captions ON, False = Captions OFF
$GRUVI_LOGO = True; //True = GRUVI logo as first image = ON, False = GRUVI logo OFF
$IMG_SOURCE = array("/mnt/Path_to_image_folder1", "/mnt/Path_to_image_folder2"); //Path to one or more image folders
$SOURCE_WEIGHT = array(0.3, 0.7); //Relative weights between the above chosen image folders, must be as many weights as the
//number of folders above and add up to 1
$URL_ROOT = 'http://192.168.x.y:9000/html/'; //Host web server address on internal LMS web server
//$URL_ROOT = 'http://192.168.x.y/'; //Host web server address on most independent web serversr
$IMAGE_ROOT = 'gruvi_img/'; //Storage folder for converted images in the www-directory
$PARALLEL_CONVERT = False; //If multiple $IMG_SOURCEs, each can be converted in parallel, but takes a toll on weaker e.g. RPi servers
//Check consistency between number of sources and weights, exit otherwise
$noOfSources = count($IMG_SOURCE);
$noOfWeights = count($SOURCE_WEIGHT);
$sumOfWeights = array_sum($SOURCE_WEIGHT);
if ($noOfSources != $noOfWeights || $sumOfWeights != 1) {
exit("Inconsistency between number of sources and weights.\n");
}
//Identify player type and set corresponding player specific variables
$isTouch = false;
$FILE_NAME = 'sbradio.txt';
$FILE_SUFFIX = '.jpg';
$BEGIN_NAME = '.radio_start';
$X_WIDTH = 320;
$Y_HEIGHT = 240;
$C_HEIGHT = 22;
$P_SIZE = 10;
if(isset($_SERVER['HTTP_USER_AGENT']) || isset($argv[1]) && $argv[1] == "Touch") {
if(isset($_SERVER['HTTP_USER_AGENT'])) {
$playerType = $_SERVER['HTTP_USER_AGENT']; //Identifier for the different player types
} elseif(isset($argv[1]) && $argv[1] == "Touch") {
$playerType = "fab4";
}
if (strpos($playerType, 'fab4') !== false) {
$isTouch = true; //TRUE if Squeezebox Touch, FALSE otherwise
$FILE_NAME = 'sbtouch.txt'; //URL list file name for the Touch
$FILE_SUFFIX = '_fab4.jpg'; //Image file suffix for the Touch
$BEGIN_NAME = '.touch_start';
$X_WIDTH = 480;
$Y_HEIGHT = 272;
$C_HEIGHT = 25;
$P_SIZE = 11;
}
}
//Check if the local optimized copies of files exist or must be created OR if they are too old and must be replaced with new images OR
//if they're too small, which is assumed to be a Gruvi fill-images from first run.
$fileArray = array(); //Array of files which should be updated or created
for ($i = 1; $i <= $LIST_SIZE; $i++) {
if (!file_exists("{$IMAGE_ROOT}{$i}{$FILE_SUFFIX}") || (time() - filemtime("{$IMAGE_ROOT}{$i}{$FILE_SUFFIX}"))/60 > $FILE_AGE_MAX || filesize("{$IMAGE_ROOT}{$i}{$FILE_SUFFIX}") < 5120) {
$fileArray[] = $i;
}
}
//Special case where no image no. 1 exists, typically first run of script, where all image files need to be generated before the player's
//image viewer starts. A background shell job for generating the correct amount of Gruvi fill-images is here generated and run.
if (!file_exists("{$IMAGE_ROOT}1{$FILE_SUFFIX}")) {
$fp = fopen ($IMAGE_ROOT . $BEGIN_NAME, 'w');
fwrite($fp, '/usr/bin/convert -background \'#0005\' -fill white -gravity center -size ' . escapeshellarg($X_WIDTH) . 'x' . escapeshellarg($Y_HEIGHT) . ' -pointsize 60 caption:GRUVI ' . escapeshellarg($IMAGE_ROOT) . '1' . escapeshellarg($FILE_SUFFIX) . "\n");
$fileArray = array();
$fileArray[] = 1;
for ($i=2; $i <= $LIST_SIZE; $i++) {
fwrite($fp, "cp {$IMAGE_ROOT}1{$FILE_SUFFIX} {$IMAGE_ROOT}{$i}{$FILE_SUFFIX}\n");
$fileArray[] = $i;
}
fwrite($fp, "cp {$IMAGE_ROOT}1{$FILE_SUFFIX} {$IMAGE_ROOT}gruvi_logo{$FILE_SUFFIX}\n");
fclose($fp);
exec('chmod 777 ' . escapeshellarg($IMAGE_ROOT . $BEGIN_NAME));
exec(escapeshellarg($IMAGE_ROOT . $BEGIN_NAME) . ' >> /dev/null 2>&1 &');
}
//Update the file for the players with the URL list for the Image Viewer applet to read
$indexList = array();
for ($i = 1; $i <= $LIST_SIZE; $i++) {
$indexList[] = $i;
}
shuffle($indexList); //For random image viewer starts
$fp = fopen($FILE_NAME, 'w');
if ($GRUVI_LOGO) {
fwrite($fp, $URL_ROOT . $IMAGE_ROOT . "gruvi_logo" . $FILE_SUFFIX ."\n");
}
for ($i = 0; $i <= $LIST_SIZE-1; $i++) {
fwrite($fp, $URL_ROOT . $IMAGE_ROOT . $indexList[$i] . $FILE_SUFFIX ."\n");
}
fclose($fp);
//Send image URL file to Image Viewer via gruvi.php HTML output
//Flush output buffer to allow web server to show URL list before gruvi.php is finished
//Solution inspired by https://stackoverflow.com/a/14469376/12802435
readfile($FILE_NAME);
if (ob_get_contents()) {
ob_end_flush();
}
flush();
session_write_close();
//Distribute weighted number of images pr. source by use of the Largest Remainder Method
$fileArraySize = count($fileArray);
$sourceDist = array();
for ($i=0; $i<$noOfSources; $i++) {
$sourceDist[] = floor($SOURCE_WEIGHT[$i]*$fileArraySize);
}
arsort($sourceDist);
$sourceSum = 0;
$index = array();
foreach ($sourceDist as $key => $val) {
$index[] = $key;
$sourceSum += $val;
}
$sourceDiff = $fileArraySize-$sourceSum;
for ($i=0; $i<$sourceDiff; $i++) {
$sourceDist[$index[$i]] += 1;
}
//Start image and file operations if any images are missing or old
$fileNameIndex = 0;
if ($fileArraySize >=1) {
//Check if conversions from a previous run of gruvi.php is already running, exit to prevent system overload
//Solution borrowed from https://www.exakat.io/en/prevent-multiple-php-scripts-at-the-same-time/
$lockFolder = $IMAGE_ROOT . 'gruvi.lock';
if (@mkdir($lockFolder, 0700)) {
}else {
exit();
}
//If parallel conversion not allowed, open file once
if (!$PARALLEL_CONVERT) {
$fp = fopen ($IMAGE_ROOT . $BEGIN_NAME, 'w');
}
//For each image folder that needs processing
for ($x=0; $x<$noOfSources;$x++){
//Traverse directory and subdirectories recursively and populate array with filenames
$fileArraySize = $sourceDist[$x];
$fileNameArray = array();
$Directory = new RecursiveDirectoryIterator($IMG_SOURCE[$x]);
$Iterator = new RecursiveIteratorIterator($Directory);
$Regex = new RegexIterator($Iterator, '/^(?!._).+(.jpe?g)$/i', RecursiveRegexIterator::GET_MATCH);
foreach($Regex as $name => $Regex) {
$fileNameArray[] = $name;
}
//Shuffle the array, and generate and run shell script to extract and resize the needed number of random new image files
shuffle($fileNameArray);
//If parallel conversion allowed, open file for every image folder
if ($PARALLEL_CONVERT) {
$fp = fopen ($IMAGE_ROOT . $BEGIN_NAME, 'w');
}
//For each image file that needs processing in each folder
for ($i = 0; $i <= $fileArraySize-1; $i++) {
//Captions ON
if ($CAPTIONS) {
$exploded = explode("/", $fileNameArray[$fileNameIndex]);
$event = $exploded[count($exploded)-2]; //Makes parent directory available as string for caption text
$fileName = $exploded[count($exploded)-1]; //Makes file name available as string for caption text
//exec('/usr/bin/convert \\( ' . escapeshellarg($fileNameArray[$i]) . ' -auto-orient -background none -resize 480x480 -gravity center -extent 480x272 \\) \\( -background \'#0005\' -fill white -gravity west -size 480x25 -pointsize 11 caption:' . escapeshellarg($fileName. "\n") . escapeshellarg($event) . ' \\) -gravity south -composite ' . escapeshellarg($IMAGE_ROOT) . escapeshellarg($fileArray[$i]) . escapeshellarg($FILE_SUFFIX) . ' >> dev/null 2>&1 &');
fwrite($fp, '/usr/bin/convert \\( \'' . $fileNameArray[$fileNameIndex] . '\' -auto-orient -background none -resize ' . escapeshellarg($X_WIDTH . 'x' . $X_WIDTH) . ' -gravity center -extent ' . escapeshellarg($X_WIDTH . 'x' . $Y_HEIGHT) . ' \\) \\( -background \'#0005\' -fill white -gravity west -size ' . escapeshellarg($X_WIDTH . 'x' . $C_HEIGHT) . ' -pointsize ' . escapeshellarg($P_SIZE) . ' caption:\'' . $fileName . '\n' . $event . '\' \\) -gravity south -composite ' . escapeshellarg($IMAGE_ROOT) . escapeshellarg($fileArray[$fileNameIndex]) . escapeshellarg($FILE_SUFFIX) . "\n");
}
//Captions OFF
else {
fwrite($fp, '/usr/bin/convert \'' . $fileNameArray[$fileNameIndex] . '\' -auto-orient -background none -resize ' . escapeshellarg($X_WIDTH . 'x' . $X_WIDTH) . ' -gravity center -extent ' . escapeshellarg($X_WIDTH . 'x' . $Y_HEIGHT) . ' ' . escapeshellarg($IMAGE_ROOT) . escapeshellarg($fileArray[$fileNameIndex]) . escapeshellarg($FILE_SUFFIX) . "\n");
}
$fileNameIndex++;
}
//Remove lock folder
if ($x == ($noOfSources - 1)) {
fwrite($fp, 'rmdir ' . escapeshellarg($lockFolder) . "\n");
}
//If parallel conversion is allowed, process each folder immediately
if ($PARALLEL_CONVERT) {
fclose($fp);
exec('chmod 777 ' . escapeshellarg($IMAGE_ROOT . $BEGIN_NAME));
exec(escapeshellarg($IMAGE_ROOT . $BEGIN_NAME) . ' >> /dev/null 2>&1 &');
}
}
//If parallel conversion is not allowed, process when all folders are finished
if (!$PARALLEL_CONVERT) {
fclose($fp);
exec('chmod 777 ' . escapeshellarg($IMAGE_ROOT . $BEGIN_NAME));
exec(escapeshellarg($IMAGE_ROOT . $BEGIN_NAME) . ' >> /dev/null 2>&1 &');
}
}
?>