2 // huffware script: freeview modified by fred huffhines (see original license below).
4 // my changes are licensed this way:
5 // this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
6 // do not use it in objects without fully realizing you are implicitly accepting that license.
8 // fred's changes include:
9 // + assorted tweaks that i have since forgotten the details about.
10 // + set the freeview to startup as a picture viewer, since that's my most common usage.
13 // original author info and licensing:
14 //FreeView 1.2 WebGuide (revision 4) - By CrystalShard Foo
15 //Multifunctional Picture viewer and Video control script with webguide support
16 //This script is distributed for free and must stay that way.
17 // *** If you wish to give/sell a product using this script, ***
18 // *** THEN THE SCRIPT MUST REMAIN FULL-PERM AND FREE. ***
19 // *** Failure to do so will REVOKE your right to use it! ***
20 //Help for using this script can be obtained at: http://www.slguide.com/help
21 //Feel free to modify this script and post your improvement. Leave the credits intact but feel free to add your name at its bottom.
23 //- Now using FULL_BRIGHT instead of PRIM_MATERIAL_LIGHT for the screen display
24 //- Added an ownership-change code to handle cases where FreeView gets deeded to group post Video Init.
25 //- Renamed WebGuide to TV-Guide to reflect what this thing does better.
26 //- Added a 'Fix Scale' button to Picture mode to help against user texture-scale changes.
27 //- Additional minor help-tips and code improvements
33 integer PICTURE_ROTATION_TIMER = 30; //In whole seconds
35 integer DISPLAY_ON_SIDE = ALL_SIDES; //Change this to change where the image will be displayed
37 key VIDEO_DEFAULT = "71b8ff26-087d-5f44-285b-d38df2e11a81"; //Test pattern - Used as default video texture when one is missing in parcel media
38 key BLANK = "5748decc-f629-461c-9a36-a35a221fe21f"; //Blank texture - Used when there are no textures to display in Picture mode
39 string NOTECARD = "bookmarks"; //Used to host URL bookmarks for video streams
41 integer VIDEO_BRIGHT = TRUE; //FULL_BRIGHT status for Video
42 integer PICTURE_BRIGHT = TRUE; //FULL_BRIGHT status for Picture
44 integer REMOTE_CHANNEL = 9238742;
46 integer EXTERNAL_TOUCH_CHANNEL = 1327;
47 // used by other prims to tell the viewer prim that the avatar has clicked on them.
49 integer mode = 0; //Freeview mode.
51 //Mode 1 - Picture viewer
54 integer listenHandle = -1; //Dialog menu listen handler
55 integer listenUrl = -1; //listen handler for channel 1 for when a URL is being added
56 integer listenTimer = -1; //Timer variable for removing all listeners after 2 minutes of listener inactivity
57 integer listenRemote = -1; //listen handler for the remote during initial setup
58 integer encryption = 0;
59 integer numberofnotecardlines = 0; //Stores the current number of detected notecard lines.
60 integer notecardline = 0; //Current notecard line
62 integer loop_image = FALSE; //Are we looping pictures with a timer? (picture mode)
63 integer current_texture = 0; //Current texture number in inventory being displayed (picture mode)
64 integer chan; //llDialog listen channel
65 integer notecardcheck = 0;
66 key video_texture; //Currently used video display texture for parcel media stream
70 key notecardkey = NULL_KEY;
71 key tempuser; //Temp key storge variable
72 string tempurl; //Temp string storge variable
74 integer isGroup = TRUE;
75 key groupcheck = NULL_KEY;
79 pictures() //Change mode to Picture Viewer
83 //Change prim to Light material while coloring face 0 black to prevent light-lag generation.
84 llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_NONE, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <1,1,1>, 1.0, PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, PICTURE_BRIGHT]);
86 integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
90 report("No pictures found.");
91 llSetTexture(BLANK,DISPLAY_ON_SIDE);
95 if(current_texture > check)
96 //Set to first texture if available
99 display_texture(current_texture);
102 video() //Change mode to Video
104 //Change prim to Light material while coloring face 0 black to prevent light-lag generation.
105 llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_NONE, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <1,1,1>, 1.0, PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, VIDEO_BRIGHT, PRIM_TEXTURE, DISPLAY_ON_SIDE, "62dc73ca-265f-7ca0-0453-e2a6aa60bb6f", llGetTextureScale(DISPLAY_ON_SIDE), llGetTextureOffset(DISPLAY_ON_SIDE), llGetTextureRot(DISPLAY_ON_SIDE)]);
107 report("Video mode"+moviename+": Stopped");
108 if(finditem(NOTECARD) != -1)
109 tempuser = llGetNumberOfNotecardLines(NOTECARD);
110 video_texture = llList2Key(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_TEXTURE]),0);
111 if(video_texture == NULL_KEY)
113 video_texture = VIDEO_DEFAULT;
114 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_TEXTURE,VIDEO_DEFAULT]);
115 llSay(0,"No parcel media texture found. Setting texture to default: "+(string)VIDEO_DEFAULT);
116 if(llGetLandOwnerAt(llGetPos()) != llGetOwner())
117 llSay(0,"Error: Cannot modify parcel media settings. "+llGetObjectName()+" is not owned by parcel owner.");
120 llSetTexture(video_texture,DISPLAY_ON_SIDE);
125 report("Click to power on.");
126 llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_LOW, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <0.1,0.1,0.1>, 1.0,PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, FALSE, PRIM_TEXTURE, DISPLAY_ON_SIDE, BLANK, llGetTextureScale(DISPLAY_ON_SIDE), llGetTextureOffset(DISPLAY_ON_SIDE), llGetTextureRot(DISPLAY_ON_SIDE)]);
129 integer finditem(string name) //Finds and returns an item's inventory number
132 for(i=0;i<llGetInventoryNumber(INVENTORY_NOTECARD);i++)
133 if(llGetInventoryName(INVENTORY_NOTECARD,i) == NOTECARD)
138 seturl(string url, key id) //Set parcel media URL
145 moviename = tempmoviename;
147 moviename = " ["+moviename+"]";
149 string oldurl = llList2String(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_URL]),0);
151 llOwnerSay("Setting new media URL. The old URL was: "+oldurl);
153 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_URL,url]);
158 report("Video mode"+moviename+": Playing");
159 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]);
163 llSay(0,"New media URL set.");
165 llOwnerSay("New media URL set: "+url);
168 string mediatype(string ext) //Returns a string stating the filetype of a file based on file extension
170 ext = llToLower(ext);
173 if(ext == "mov" || ext == "avi" || ext == "mpg" || ext == "mpeg" || ext == "smil")
175 if(ext == "jpg" || ext == "mpeg" || ext == "gif" || ext == "png" || ext == "pict" || ext == "tga" || ext == "tiff" || ext == "sgi" || ext == "bmp")
179 if(ext == "mp3" || ext == "wav")
184 browse(key id) //Image browser function for picture viewer mode
186 integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
189 header = "("+(string)(current_texture+1)+"/"+(string)check+") "+llGetInventoryName(INVENTORY_TEXTURE,current_texture);
191 header = "No pictures found.";
192 llDialog(id,"** Monitor Control **\n Picture Viewer mode\n- Image browser\n- "+header,["Back","Next","Menu"],chan);
198 llSetObjectDesc(str);
201 extendtimer() //Add another 2 minute to the Listen Removal timer (use when a Listen event is triggered)
203 if(listenHandle == -1)
204 listenHandle = llListen(chan,"","","");
205 listenTimer = (integer)llGetTime() + 120;
206 if(loop_image == FALSE)
210 config(key id) //Configuration menu
213 llDialog(id,"Current media URL:\n"+llList2String(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_URL]),0)+"\nTip: If the picture is abit off, try 'Align ON'",["Set URL","Align ON","Align OFF","Menu","Set Remote"],chan);
216 tell_remote(string str)
218 llShout(REMOTE_CHANNEL,llXorBase64Strings(llStringToBase64((string)encryption + str), llStringToBase64((string)encryption)));
221 menu(key id) //Dialog menus for all 3 modes
224 string title = "** Monitor control **";
230 if(mode == 1) //Pictures menu
232 title+="\n Picture Viewer mode";
234 if(loop_image == FALSE)
238 buttons+=["Video","Power off","Help","Fix scale"];
242 title+="\n Video display mode\n"+moviename+"\nTip:\nClick 'TV Guide' to view the Online bookmarks.";
243 buttons+=["Pictures","Configure","Power off","Loop","Unload","Help","Play","Stop","Pause","TV Guide","Bookmarks","Set URL"];
247 buttons += ["Pictures","Video","Help"];
249 llDialog(id,title,buttons,chan);
252 display_texture(integer check) //Display texture and set name in description (picture mode)
253 { //"Check" holds the number of textures in contents. The function uses "current_texture" to display.
254 string name = llGetInventoryName(INVENTORY_TEXTURE,current_texture);
255 llSetTexture(name,DISPLAY_ON_SIDE);
256 report("Showing picture: "+name+" ("+(string)(current_texture+1)+"/"+(string)check+")");
260 next() //Change to next texture (picture mode)
261 { //This function is used twice - by the menu and timer. Therefor, it is a dedicated function.
263 integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
266 llSetTexture(BLANK,DISPLAY_ON_SIDE);
268 report("No pictures found.");
271 if(check == current_texture)
274 display_texture(check);
281 // returns the index of the first occurrence of "pattern" inside
282 // the "full_string". if it is not found, then a negative number is returned.
283 integer find_substring(string full_string, string pattern)
284 { return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
286 // returns TRUE if the "prefix" string is the first part of "compare_with".
287 integer is_prefix(string compare_with, string prefix)
288 { return find_substring(compare_with, prefix) == 0; }
291 // huffware script: auto-retire, by fred huffhines, version 2.8.
292 // distributed under BSD-like license.
293 // !! keep in mind that this code must be *copied* into another
294 // !! script that you wish to add auto-retirement capability to.
295 // when a script has auto_retire in it, it can be dropped into an
296 // object and the most recent version of the script will destroy
297 // all older versions.
299 // the version numbers are embedded into the script names themselves.
300 // the notation for versions uses a letter 'v', followed by two numbers
301 // in the form "major.minor".
302 // major and minor versions are implicitly considered as a floating point
303 // number that increases with each newer version of the script. thus,
304 // "hazmap v0.1" might be the first script in the "hazmap" script continuum,
305 // and "hazmap v3.2" is a more recent version.
307 // example usage of the auto-retirement script:
310 // auto_retire(); // make sure newest addition is only version of script.
313 // this script is partly based on the self-upgrading scripts from markov brodsky
314 // and jippen faddoul.
317 string self = llGetScriptName(); // the name of this script.
318 list split = compute_basename_and_version(self);
319 if (llGetListLength(split) != 2) return; // nothing to do for this script.
320 string basename = llList2String(split, 0); // script name with no version attached.
321 string version_string = llList2String(split, 1); // the version found.
323 // find any scripts that match the basename. they are variants of this script.
324 for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
325 string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
326 if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
327 // found a basic match at least.
328 list inv_split = compute_basename_and_version(curr_script);
329 if (llGetListLength(inv_split) == 2) {
330 // see if this script is more ancient.
331 string inv_version_string = llList2String(inv_split, 1); // the version found.
332 // must make sure that the retiring script is completely the identical basename;
333 // just matching in the front doesn't make it a relative.
334 if ( (llList2String(inv_split, 0) == basename)
335 && ((float)inv_version_string < (float)version_string) ) {
336 // remove script with same name from inventory that has inferior version.
337 llRemoveInventory(curr_script);
344 // separates the base script name and version number. used by auto_retire.
345 list compute_basename_and_version(string to_chop_up)
347 // minimum script name is 2 characters plus a version.
348 integer space_v_posn;
349 // find the last useful space and 'v' combo.
350 for (space_v_posn = llStringLength(to_chop_up) - 3;
351 (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
353 // look for space and v but do nothing else.
355 if (space_v_posn < 2) return []; // no space found.
356 // now we zoom through the stuff after our beloved v character and find any evil
357 // space characters, which are most likely from SL having found a duplicate item
358 // name and not so helpfully renamed it for us.
360 for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
361 if (llGetSubString(to_chop_up, indy, indy) == " ") {
362 // found one; zap it. since we're going backwards we don't need to
363 // adjust the loop at all.
364 to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
367 string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
368 // ditch the space character for our numerical check.
369 string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
370 // strip out a 'v' if there is one.
371 if (llGetSubString(chop_suffix, 0, 0) == "v")
372 chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
373 // if valid floating point number and greater than zero, that works for our version.
374 string basename = to_chop_up; // script name with no version attached.
375 if ((float)chop_suffix > 0.0) {
376 // this is a big success right here.
377 basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
378 return [ basename, chop_suffix ];
380 // seems like we found nothing useful.
387 state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
388 on_rez(integer parm) { state rerun; }
390 state rerun { state_entry() { state default; } }
397 llListen(EXTERNAL_TOUCH_CHANNEL, "", NULL_KEY, "");
398 // we listen on our touch channel in all cases and in all states. this allows us
399 // to always pass along the user's touch from other prims to run the menus.
400 chan = (integer)llFrand(1000) + 1000; //Pick a random listen channel for the listener
401 if(PICTURE_ROTATION_TIMER <= 0) //Ensure the value is no less or equal 0
402 PICTURE_ROTATION_TIMER = 1;
403 llListenRemove(listenHandle);
405 last_owner = llGetOwner();
406 groupcheck = llRequestAgentData(llGetOwner(),DATA_NAME);
408 llOpenRemoteDataChannel();
409 // fred's changes to start up in picture viewing looper.
410 mode = 1; // picture viewing.
411 pictures(); // show the pictures.
413 llSetTimerEvent(PICTURE_ROTATION_TIMER); // keep showing new pics.
418 llSay(0,"Welcome to FreeView - your free, open-source television!");
422 touch_start(integer total_number)
424 //-------------------------------------------------------------------------------
425 //Listen only to owner or group member. Edit this code to change access controls.
426 if(llDetectedKey(0) != llGetOwner() && llDetectedGroup(0) == FALSE)
428 //-------------------------------------------------------------------------------
430 menu(llDetectedKey(0));
433 changed(integer change)
435 if(change == CHANGED_INVENTORY) //If inventory change
437 if(mode == 1) //If picture mode
439 integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
443 display_texture(check);
447 llSetTexture(BLANK,DISPLAY_ON_SIDE);
448 report("No pictures found.");
452 if(mode == 2) //If video mode
453 if(finditem(NOTECARD) != -1) //And bookmarks notecard present
454 if(notecardkey != llGetInventoryKey(NOTECARD))
455 tempuser = llGetNumberOfNotecardLines(NOTECARD); //Reload number of lines
457 else if(change == CHANGED_OWNER)
460 last_owner = llGetOwner();
461 groupcheck = llRequestAgentData(llGetOwner(),DATA_NAME);
465 llSay(0,"Detected change in ownership. Attempting to obtain current parcel media texture...");
471 listen(integer channel, string name, key id, string message)
473 if ( (channel == EXTERNAL_TOUCH_CHANNEL) && is_prefix(message, "touched")) {
474 // pretend we got touched by the av.
475 message = llDeleteSubString(message, 0, 6);
479 if(message == "Pictures")
482 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_STOP]);
488 if(message == "Video")
495 if(message == "Power off")
498 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_UNLOAD]);
503 if(message == "Help")
505 llSay(0,"Help documentation is available at: http://www.slguide.com/help");
510 llSay(0,"FreeView cannot load help pages while set to group without the remote.");
511 llSay(0,"For further assistance, please consult: http://slguide.com/help");
514 tell_remote("HELP"+(string)id+(string)XML_channel);
517 llLoadURL(id,"Help pages for FreeView","http://www.slguide.com?c="+(string)XML_channel+"&help=1");
521 if(message == "Browse")
527 if(message == "Next")
533 if(message == "Back")
537 integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
540 llSetTexture(BLANK,DISPLAY_ON_SIDE);
542 report("No pictures found.");
545 if(current_texture < 0)
546 current_texture = check - 1;
548 display_texture(check);
553 if(message == "Menu")
558 if(message == "Loop")
560 llSetTimerEvent(PICTURE_ROTATION_TIMER);
562 llOwnerSay("Picture will change every "+(string)PICTURE_ROTATION_TIMER+" seconds.");
565 if(message == "Unloop")
568 llOwnerSay("Picture loop disabled.");
571 if(message == "Fix scale")
573 llSay(0,"Setting display texture to 1,1 repeats and 0,0 offset.");
574 llScaleTexture(1, 1, DISPLAY_ON_SIDE);
575 llOffsetTexture(0, 0, DISPLAY_ON_SIDE);
581 if(channel == REMOTE_CHANNEL)
584 encryption = (integer)message;
585 llListenRemove(listenRemote);
587 llSay(0,"Remote configured ("+(string)id+")");
590 if(message == "TV Guide")
596 llSay(0,"** Error - This FreeView object has been deeded to group. You must use a Remote control to open the TV Guide.");
597 llSay(0,"You can set up the remote control from the Video -> Configuration menu. Please refer to the notecard for further assistance.");
600 tell_remote((string)id+(string)XML_channel+(string)llGetOwner());
603 llLoadURL(id, "Come to the Guide to Start Your Viewer Playing!", "http://slguide.com/index.php?v=" + (string)llGetKey() + "&c=" + (string)XML_channel + "&o=" + (string)llGetOwner() + "&");
607 string header = "Video mode"+moviename+": ";
609 if(message == "<< Prev")
613 notecardline = numberofnotecardlines - 1;
615 llGetNotecardLine(NOTECARD,notecardline);
618 if(message == "Next >>")
621 if(notecardline >= numberofnotecardlines)
624 llGetNotecardLine(NOTECARD,notecardline);
629 if(tempurl == "** No URL specified! **")
635 if(message == "Menu")
640 if(message == "Configure")
645 if(message == "Bookmarks")
647 if(notecardcheck != -1)
649 llDialog(id,"Error: No valid bookmark data found in notecard '"+NOTECARD+"'.",["Menu"],chan);
652 if(finditem(NOTECARD) != -1)
655 if(numberofnotecardlines < notecardline)
657 llGetNotecardLine(NOTECARD,notecardline);
660 llDialog(id,"Error: No notecard named "+NOTECARD+" found in contents.",["Menu"],chan);
664 if(llGetLandOwnerAt(llGetPos()) != llGetOwner()) //If we do not have permissions to actually do the following functions
666 llSay(0,"Error: Cannot modify parcel media settings. "+llGetObjectName()+" is not owned by parcel owner.");
671 if(listenUrl != -1 && channel == 1) //Incoming data from "Set URL" command (user spoke on channel 1)
673 llListenRemove(listenUrl);
678 if(message == "Play")
680 report(header+"Playing");
681 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]);
684 if(message == "Stop")
686 report(header+"Stopped");
687 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_STOP]);
690 if(message == "Pause")
692 report(header+"Paused");
693 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PAUSE]);
696 if(message == "Unload")
698 report(header+"Stopped");
699 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_UNLOAD]);
702 if(message == "Loop")
704 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_LOOP]);
708 if(message == "Set URL")
710 report(header+"Stopped");
711 listenUrl = llListen(1,"",id,"");
712 llDialog(id,"Please type the URL of your choice with /1 in thebegining. For example, /1 www.google.com",["Ok"],938);
715 if(message == "Align ON")
717 report(header+"Stopped");
718 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_AUTO_ALIGN,TRUE]);
722 if(message == "Align OFF")
724 report(header+"Stopped");
725 llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_AUTO_ALIGN,FALSE]);
729 if(message == "Set Remote")
731 llSay(0,"Configuring remote...");
733 llListenRemove(listenRemote);
734 listenRemote = llListen(REMOTE_CHANNEL,"","","");
735 llSay(REMOTE_CHANNEL,"SETUP");
740 dataserver(key queryid, string data)
742 if(queryid == groupcheck) //Test if object is deeded to group
744 groupcheck = NULL_KEY;
749 if(queryid == tempuser) //If just checking number of notecard lines
751 numberofnotecardlines = (integer)data;
752 notecardkey = llGetInventoryKey(NOTECARD);
754 llGetNotecardLine(NOTECARD,notecardcheck);
757 if(notecardcheck != -1)
764 llGetNotecardLine(NOTECARD,notecardcheck);
776 if(data == "" && notecardline < numberofnotecardlines) //If user just pressed "enter" in bookmarks, skip
779 llGetNotecardLine(NOTECARD,notecardline);
786 llGetNotecardLine(NOTECARD,notecardline);
789 list parsed = llParseString2List(data,["|","| "," |"," | "],[]); //Ensure no blank spaces before "http://".
790 string name = llList2String(parsed,0);
791 tempurl = llList2String(parsed,1);
793 tempurl = "** No URL specified! **";
795 tempmoviename = name;
797 llDialog(tempuser,"Bookmarks notecard ("+(string)(notecardline+1)+"/"+(string)numberofnotecardlines+")\n"+name+" ("+mediatype(llList2String(llParseString2List(tempurl,["."],[]),-1))+")\n"+tempurl,["<< Prev","Use","Next >>","Menu"],chan);
800 remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval)
802 if (type == REMOTE_DATA_CHANNEL)
804 XML_channel = channel;
806 else if(type == REMOTE_DATA_REQUEST)
808 list media_info = llParseString2List(sval, ["|"], []);
809 tempmoviename = llList2String(media_info,0);
810 seturl(llList2String(media_info,1),NULL_KEY);
811 llRemoteDataReply(channel, message_id, sval, 1);
817 if(llGetTime() > listenTimer) //If listener time expired...
819 llListenRemove(listenHandle); //Remove listeneres.
820 llListenRemove(listenUrl);
821 llListenRemove(listenRemote);
826 if(loop_image == FALSE || mode != 1) //If we're not looping pictures or are in picture mode at all
827 llSetTimerEvent(0.0); //Remove timer
830 if(loop_image == TRUE && mode == 1) //If we're looping pictures and and we're in picture mode...
831 next(); //Next picture