User:Opensource Obscure/FFHUD

From Second Life Wiki
< User:Opensource Obscure
Revision as of 17:35, 5 July 2008 by Opensource Obscure (talk | contribs) (updated to 0.7.1)
Jump to navigation Jump to search

FFHUD: a simple FriendFeed HUD

by Opensource Obscure

UPDATE: [release 0.7.1] has Rooms and Profile Image support and it uses only one prim. Put the 0.7.1 script in a prim and wear it as an HUD.

Instructions below refer to release 0.6.1 scripts.

FFHUD updates your FriendFeed page. It usually publishes a post structured like this:

  • LINK = SLURL of your location
  • TITLE = region name + parcel name
  • COMMENT = parcel description (if available) + your message (optional)
  • IMAGE = profile image of resident or group that owns the parcel (if available)

How it works (outdated)

  • edit script 1 and put your FriendFeed account data
  • put script 1 in a prim (you may call the prim FFHUD)
  • put script 2 in another prim (call it PARCEL INFO)
  • link the prims
  • wear the object as an HUD like this:
________ ______________
|       |             |
| FFHUD | PARCEL INFO |
|_______|_____________|
  • touch PARCEL INFO to get info about the parcel you're in and agents around (printed in chat via llOwnerSay)
  • touch FFHUD to publish a post on FriendFeed that includes available info about the parcel (SLURL, name, description, owner/owner group profile image if available)
  • say a message on channel 8 to publish a post on FriendFeed with parcel info + your message:
/8 This is my message

FFHUD has the FriendFeed favicon as fixed texture. PARCEL INFO texture changes (after touch) when a profile image is available for the parcel owners. Profile images are shown on the PARCEL INFO prim by using llSetTexture; the UUID is retrieved using the Second Life Search. The image web address (not the image itself) is sent to FriendFeed, that then retrieves and hosts a copy of the image.

Notes

This code is probably horrible and flawed. I am not a real developer and I lack programming basis. I usually read around, cut, paste and tweak code from other sources. I think I used here snippets by: Ordinal Malaprop, Cory Ondrejka, MarcoDuff Palen, Jana Kamachi and others.

Use of this script may be a violation of ToS - help to clearify this is welcome :)

Planned:

  • switch to turn off/on image support
  • FriendFeed Rooms support
  • title customization with a switch to turn it off/on
  • switch to turn off/on parcel name and/or description
  • enriched SLURL as in Ordinal Malaprop's TwitterBox
  • ...better code

If you're on FriendFeed, you may want to join the rooms dedicated to Second Life - e.g.:

script 1/2: FFHUD (outdated)

This script:

  • accepts touch event
  • listens on channel 8 for your message
  • sends a linkedmessage to script 2 (upon touch event or message on channel 8)
  • receives texture uuid from script 2 via linkedmessage
  • sends http request to friendfeed (after the linkedmessage from script 2)

<lsl>

// your FriendFeed username are here: https://friendfeed.com/account/api string user=""; // your FriendFeed username string ffkey=""; // your FriendFeed key

string baseurl="@friendfeed.com/api/share"; string text; string url; string message; string desc; key texturedefault = "632f82da-7be7-9c7a-f254-3fc41a36ae12";

azzera() {

   llSetTexture(texturedefault, ALL_SIDES);      
   text="";
   url="";
   message="";
   desc = "";

}

string strReplace(string source, string pattern, string replace) {

   while (llSubStringIndex(source, pattern) > -1) {
       integer len = llStringLength(pattern);
       integer pos = llSubStringIndex(source, pattern);
       if (llStringLength(source) == len) { source = replace; }
       else if (pos == 0) { source = replace+llGetSubString(source, pos+len, -1); }
       else if (pos == llStringLength(source)-len) { source = llGetSubString(source, 0, pos-1)+replace; }
       else { source = llGetSubString(source, 0, pos-1)+replace+llGetSubString(source, pos+len, -1); }
   }
   return source;

}


string regionname() {

   string region=llDumpList2String(llParseString2List(llGetRegionName(),[" "],[]),"+");  
   return region;

}

string parcelname() {

   list lstParcelName=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_NAME]);                
   string a = (string)lstParcelName;
   string name = llDumpList2String(llParseString2List(a,[" "],[]),"+"); 
   name = strReplace(name,"&","and");
   return name; 

}

string parceldesc() {

   list lstParcelDesc=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_DESC]);                
   string a = (string)lstParcelDesc;
   if(a != "00000000-0000-0000-0000-000000000000")
   {
       desc = llDumpList2String(llParseString2List(a,[" "],[]),"+");        
   }
   else
   {
       desc = "";
   }
   desc = strReplace(desc,"&","and");
   return desc;   

}

string slurl() {

   string simname = llDumpList2String(llParseString2List(llGetRegionName(),[" "],[]),"+");
   string regionname = simname;
   vector detectedPos = llGetRootPosition();        
   string sx = (string)llRound(detectedPos.x);
   string sy = (string)llRound(detectedPos.y);
   string sz = (string)llRound(detectedPos.z);
   string url = "http://slurl.com/secondlife/";  
   url += simname; 
   url += "/" + sx + "/" + sy + "/" + sz ; 
   return url;   

}

default {

   state_entry()
   {  
       azzera(); 
       llListen(8, "", llGetOwner(), "");           
   }

   touch_start(integer total_number)
   {
       azzera();
       llMessageLinked(2, 1, "", NULL_KEY);        
   }


   listen(integer channel, string name, key id, string message)
   {
       azzera();
       llMessageLinked(2, 1, "", NULL_KEY);
       text = "+-+MY MESSAGE:+" + message;
       text = strReplace(text,"&","and");
   }

   link_message(integer sender_num, integer num, string str, key id)    
   {
       string imageurl = "http://secondlife.com/app/image/" + (string)id + "/2";        
       text = llDumpList2String(llParseString2List(text,[" "],[]),"+");
       string post = 
       "http://" + 
       user + 
       ":" + 
       ffkey + 
       baseurl + 
       "?title=" + 
       regionname() +
       "+-+" +
       parcelname() +
       "&link=" + 
       llEscapeURL(slurl()) + 
       "&comment=" +
       "PARCEL+INFO:+" +
       parceldesc() +    
       text + 
       "&image0_url=" + 
       llEscapeURL(imageurl);
       llHTTPRequest(post, [HTTP_METHOD,"POST"], "");        
   }


   http_response(key request_id, integer status, list metadata, string body)
   {
       {
          llOwnerSay("Message sent to http://friendfeed.com/" + user);
       }
   }     

}


</lsl>


script 2/2: PARCEL INFO (outdated)

This script:

  • accepts touch event
  • gives info via chat about the parcel you're in:
    • name
    • description
    • resident or group that owns it
    • how many people are around you right now, their names and a link you can click to directly open their profile
      • this scan uses a default radius of 96 meters; change scanradius in the 1st line of script as needed
  • receives linkedmessages from script 1
  • retrieves from web the profile image texture UUID for resident or group that owns the parcel you're in
  • sends texture UUID to script 1

<lsl>

string ownerurl = "http://world.secondlife.com/resident/"; string groupurl = "http://world.secondlife.com/group/"; string code1 = "<img alt=\"profile image\" src=\"http://secondlife.com/app/image/"; string code2 = "\" class=\"parcelimg\" />"; key texturedefault = "19920f4f-d667-ab18-7234-af4623b52065"; key textureuuid = ""; string desc; float scanradius = 96.0; integer check;

string parcelname() {

   list lstParcelName=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_NAME]);                
   string a = (string)lstParcelName;
   string name = llDumpList2String(llParseString2List(a,[" "],[]),"+"); 
   return name; 

}


string parceldesc() {

   list lstParcelDesc=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_DESC]);                
   string a = (string)lstParcelDesc;  
   if(a != "00000000-0000-0000-0000-000000000000")
   {
       desc = llDumpList2String(llParseString2List(a,[" "],[]),"+") + "+-+";                
   } 
   else
   {
       desc = "";
   } 
   return desc;   

}


string parcelowner() {

   list lstParcelOwner=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_OWNER]);                
   string uuid = (string)lstParcelOwner;    
   return uuid;    

}


string parcelgroup() {

   list lstParcelGroup=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_GROUP]);              
   string uuid = (string)lstParcelGroup;
   return uuid;

}


texture() {

       string a = parcelgroup();
       if(a == "00000000-0000-0000-0000-000000000000")
       {
           llHTTPRequest( ownerurl + parcelowner(),[HTTP_METHOD,"GET"],"");               
       }  
       else
       {
           llHTTPRequest( groupurl + parcelgroup(),[HTTP_METHOD,"GET"],"");            
       }

}

infoparcel() {

   llOwnerSay("parcel name =" + parcelname());
   llOwnerSay("parcel desc =" + parceldesc());
   llOwnerSay("parcel owner = " + "secondlife:///app/agent/" + parcelowner() + "/about");   
   llOwnerSay("parcel group = "  + "secondlife:///app/group/" + parcelgroup() + "/about");
   llSensor("", NULL_KEY, AGENT, scanradius, PI);

}


default {

   state_entry()
   {
       llSetTexture(texturedefault, ALL_SIDES);        
   }

   link_message(integer sender_num, integer num, string str, key id)    
   {
       check = TRUE;
       texture();          
   }


   touch_start(integer total_number)
   {
       check = FALSE; 
       infoparcel();
       texture();
   }


   http_response(key req,integer stat, list met, string body)
   {    
       textureuuid = (key)llGetSubString(body,llSubStringIndex(body, code1)+llStringLength(code1),llSubStringIndex(body,code2)-3); 
       llSetTexture(textureuuid, ALL_SIDES);
       if (check == TRUE)
       {
           llMessageLinked(1, 2, "", textureuuid);     
       }
   }


   sensor(integer total_number)
   {
       llOwnerSay((string)total_number + " avatar" + " in " + (string)scanradius+ " meters");
       integer i;
       for (i = 0; i < total_number; i++)
       {
           llOwnerSay(llDetectedName(i) + " > secondlife:///app/agent/" + (string)llDetectedKey(i) + "/about");             
       }

   }
   no_sensor()
   {
       llOwnerSay("nobody here right now (radius=" + (string)scanradius + " meters)");
   }

}

</lsl>


*updated* FFHUD 0.7.1 - with Rooms support

</lsl> // FFHUD 0.7 // free for public use // A project started by Opensource Obscure //

// Look for your username and FriendFeed key here: https://friendfeed.com/account/api string user=""; // your FriendFeed username string ffkey=""; // your FriendFeed key

// You can send messages to a FriendFeed room: // "" -----------> default setting - you won't share messages to any room // "ffhud" ------> a test room you can freely use // "secondlife" -> an unofficial SL room - http://friendfeed.com/rooms/secondlife // Change accordingly the line below: string room="ffhud";


// after 1st click you have a few seconds to write and send // your text message before FFHUD comes back to default state. // you can change the timing below: float listentime = 20.0;


/////////////////////////////////////////////////// // you don't need to modify anything below


string desc; integer listen_handle; string baseurl="@friendfeed.com/api/share"; key request_ff; key request_texture; string ownerurl = "http://world.secondlife.com/resident/"; string groupurl = "http://world.secondlife.com/group/"; string code1 = "<img alt=\"profile image\" src=\"http://secondlife.com/app/image/"; string code2 = "\" class=\"parcelimg\" />"; key textureuuid = ""; key texturedefault = "4760a44f-06f7-622e-7429-b01570a598b0";


// let's substitute '&' character with 'and' string strReplace(string source, string pattern, string replace) {

   while (llSubStringIndex(source, pattern) > -1) {
       integer len = llStringLength(pattern);
       integer pos = llSubStringIndex(source, pattern);
       if (llStringLength(source) == len) { source = replace; }
       else if (pos == 0) { source = replace+llGetSubString(source, pos+len, -1); }
       else if (pos == llStringLength(source)-len) { source = llGetSubString(source, 0, pos-1)+replace; }
       else { source = llGetSubString(source, 0, pos-1)+replace+llGetSubString(source, pos+len, -1); }
   }
   return source;

}


// partially redundant (1) string parcelname() {

   list lstParcelName=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_NAME]);                
   string a = (string)lstParcelName;
   string name = llDumpList2String(llParseString2List(a,[" "],[]),"+"); 
   return name; 

}


// partially redundant (1) // we use this after 2nd touch if no message is provided by the user string parceldesc() {

   list lstParcelDesc=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_DESC]);                
   string a = (string)lstParcelDesc;  
   if(a != "00000000-0000-0000-0000-000000000000")
   {
       desc = llDumpList2String(llParseString2List(a,[" "],[]),"+") + "+-+";                
   } 
   else
   {
       desc = "";
   } 
   return strReplace(desc, "&", "and");   

}


// partially redundant (1) string parcelowner() {

   list lstParcelOwner=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_OWNER]);                
   string uuid = (string)lstParcelOwner;    
   return uuid;    

}


// partially redundant (1) string parcelgroup() {

   list lstParcelGroup=llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_GROUP]);              
   string uuid = (string)lstParcelGroup;
   return uuid;

}


// this comes from Cory Ondrejka I think string slurl() {

   string simname = llDumpList2String(llParseString2List(llGetRegionName(),[" "],[]),"+");
   string regionname = simname;
   vector detectedPos = llGetRootPosition();        
   string sx = (string)llRound(detectedPos.x);
   string sy = (string)llRound(detectedPos.y);
   string sz = (string)llRound(detectedPos.z);
   string url = "http://slurl.com/secondlife/";  
   url += simname; 
   url += "/" + sx + "/" + sy + "/" + sz ; 
   return url;   

}


// partially redundant (1) infoparcel() {

   llOwnerSay("parcel name = " + (string)llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_NAME]));
   llOwnerSay("parcel desc = " + (string)llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_DESC]));
   llOwnerSay("parcel owner = " + "secondlife:///app/agent/" + parcelowner() + "/about");   
   llOwnerSay("parcel group = "  + "secondlife:///app/group/" + parcelgroup() + "/about");

}


texture() {

   if (parcelgroup() == parcelowner()) // group-owned land
   {
       request_texture = llHTTPRequest(groupurl + parcelgroup(),[HTTP_METHOD,"GET"],"");            
   }  
   else // group may be set, but land is not group-owned
       // single residents have pictures more often than group so we choose them
   { 
       request_texture = llHTTPRequest(ownerurl + parcelowner(),[HTTP_METHOD,"GET"],"");               
   }

}


string prepara(string messaggio) {

   string imageurl = "http://secondlife.com/app/image/" + (string)textureuuid + "/2";       
   messaggio = llDumpList2String(llParseString2List(messaggio,[" "],[]),"+");
   string post = 
   "http://" + 
   user + 
   ":" + 
   ffkey + 
   baseurl + 
   "?title=" + 
   parcelname() +
   "&link=" + 
   llEscapeURL(slurl()) + 
   "&comment=" +      
   messaggio +
   "&room=" +
   room +
   "&image0_url=" + 
   llEscapeURL(imageurl);
   return post;

}


default {

   on_rez(integer start_param)
   {
       llOwnerSay(": Ready. Touch once to get parcel info - Touch twice to update your FriendFeed page.");         
   }
   
   state_entry()
   {
       llSetTexture(texturedefault, ALL_SIDES);         
       llSetTimerEvent(0.0);                
   }
   
   
   touch_start(integer total_number)
   {      
       infoparcel();
       texture();
       state pronto;        
   }
   // redundant (2)
   http_response(key request_id, integer status, list metadata, string body)
   {
   if(request_id == request_ff) 
       {
        llOwnerSay(": Message sent.");
       }
   
   else if(request_id == request_texture)
       {
       textureuuid = (key)llGetSubString(body,llSubStringIndex(body, code1)+llStringLength(code1),llSubStringIndex(body,code2)-3);
       llSetTexture(textureuuid, ALL_SIDES);
       }
   }                                 

}


state pronto {

   state_entry()
   {
       llSetTimerEvent(listentime);        
       llOwnerSay(": Say your message on channel 8 within 20 seconds, or touch again to send a quick post.");        
       listen_handle = llListen(8, "", llGetOwner(), "");                
   }
   
   changed(integer change) 
   { 
   if (change & (CHANGED_TELEPORT|CHANGED_REGION))
   {
       llOwnerSay(": Location changed, restarting.");           
        state default;
   }
   }


  timer()
  {
       llOwnerSay(": Time over.");        
       state default;
  }


   touch_start(integer total_number)
   {
       request_ff = llHTTPRequest(prepara(parceldesc()), [HTTP_METHOD,"POST"], ""); 
       state default;        
   } 
   
   
   listen(integer channel, string name, key id, string message)
   {
       request_ff = llHTTPRequest(prepara(message), [HTTP_METHOD,"POST"], ""); 
       state default;        
   }
   
   // redundant (2)
   http_response(key request_id, integer status, list metadata, string body)
   {
   if(request_id == request_ff) 
       {
        llOwnerSay(": Message sent.");
       }
   
   else if(request_id == request_texture)
       {
       textureuuid = (key)llGetSubString(body,llSubStringIndex(body, code1)+llStringLength(code1),llSubStringIndex(body,code2)-3);
       llSetTexture(textureuuid, ALL_SIDES);
       }
   }                                                                     


} </lsl>