User:Opensource Obscure/FFHUD
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
FFHUD: a simple FriendFeed HUD
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>