Difference between revisions of "Shoutcast - radio controller v0.3 (remake of similar scripts)"
(Created page with "{{LSL header}} This script controls a shoutcast radio receiver and lets you select the stations that you configured on a notecard. Menu driven. Output of station description, gen…") |
m |
||
Line 1: | Line 1: | ||
{{LSL | {{LSL Header}} | ||
This script controls a shoutcast radio receiver and lets you select the stations that you configured on a notecard. Menu driven. Output of station description, genre and current song title using Xy text. | This script controls a shoutcast radio receiver and lets you select the stations that you configured on a notecard. Menu driven. Output of station description, genre and current song title using Xy text. | ||
<lsl> | <lsl> |
Revision as of 14:54, 9 February 2011
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
This script controls a shoutcast radio receiver and lets you select the stations that you configured on a notecard. Menu driven. Output of station description, genre and current song title using Xy text. <lsl> // Shoutcast - radio controller v0.3 // Logic Scripts (Flennan Roffo) // (c) 2010 - Flennan Roffo (Logic Scripts) // // Remake of similar script: // + LandOwnersRadio V2.0 by Scripter Coba (( menu driven / notecard config script to select the radio station and sets parcel music url )) // + Raven radio infoboard by Jamie Otis (( worked at the basis of sis service [sis.slserver.com/sis.php] used Xy text display )) // + currentPlaying by Darkie Minotaur (( used the /7.html info to fetch current song title info, displayed as float text )) // // Purpose: // * Sets the parcel audio URL and displays the channel info // * Uses Xytext to display the info. // * Fetches song title info from the shoutcast url // Extra Features -- 0.1 release // * On/Off option // * Allows multiple menus (if options per menu > 12) using a prev/next button // * Checks if your url is well-formatted // * Will delete genres for which no stations exist // * Will skip stations that have same url and same genre (you can however have an identical station url under different genres). // * New notecard format ////////////////////////////////////////////////////////////////////////////////////////// // Extra Features -- 0.2 release // * Configurable button text // * Gets parcel URL and automatically sets the genre/station and on/off status accordingly (<-- doesn't work) ////////////////////////////////////////////////////////////////////////////////////////// // Update -- 0.3 release // * Fixed bug (only first station in genre displayed in menu) // * Auto reset script when config card updated ////////////////////////////////////////////////////////////////////////////////////////// // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. ///////////////////////////////////////////////////////////////////////////////////////////
integer DEBUG=0;
string info_notecard="Radio Control info"; /////// EDITABLE \\\\\\ string config_notecard="Radio Control config"; /////// EDITABLE \\\\\\ string comment_char="#"; /////// EDITABLE \\\\\\ list sep_char_list= ["|"]; /////// EDITABLE \\\\\\ float update_time=5.0; /////// EDITABLE \\\\\\ string no_title_info="(no title info available)"; /////// EDITABLE \\\\\\
// not used currently - for showing info on current song title elsewhere in the region integer broadcast_channel=-1234; /////// EDITABLE \\\\\\
// Buttons
string button_MAIN = "MAIN"; string button_HELP = "HELP"; string button_NEXT = ">>"; string button_PREV = "<<"; string button_ON = "ON"; string button_OFF = "OFF";
// Lists
list category_list=[];
list station_category=[]; list station_name=[]; list station_desc=[]; list station_url=[];
string last_title_info="";
integer radio_status=0; string parcel_url=""; integer lineno=0; key reqid=NULL_KEY; key httpreq_id=NULL_KEY; integer config_error=FALSE; integer flag; integer section=0; integer owner_access=TRUE; integer group_access=FALSE; integer public_access=TRUE; list banned_keys=[];
integer menu_channel; integer listen_handle; integer menu_type=0; integer menu_num=0; integer category_index=0; integer station_index=0;
integer num_categories=0; integer num_stations=0;
DebugSay(string msg) {
if (DEBUG) llSay(0,"(debug) " + msg);
}
retrieve_titelinfo() {
string url=llList2String(station_url,station_index); httpreq_id=llHTTPRequest(url + "/7.html HTTP/1.0\nUser-Agent: LSL Script (Mozilla Compatible)\n\n",[],"");
}
display_line(string line, string message) {
// Setup XYtext Variables integer DISPLAY_STRING = 204000; integer DISPLAY_EXTENDED = 204001; integer REMAP_INDICES = 204002; integer RESET_INDICES = 204003; integer SET_CELL_INFO = 204004; integer SET_FONT_TEXTURE = 204005; integer SET_THICKNESS = 204006; integer SET_COLOR = 204007;
llMessageLinked(LINK_SET,DISPLAY_STRING,message,line);
}
clear_display() {
// Clears the display display_line("1","Radio Station ID"); display_line("2","Music Genre...."); display_line("3","Now Playing....");
}
make_menu(key id) {
menu_channel=random_channel();
if (radio_status == 0) { menu_type=0; menu_num=0; llDialog(id,"Menu: Status\n\nRadio is OFF", [ "ON", "HELP" ],menu_channel); } else { if (menu_type ==0) { llDialog(id,"Menu: Genres", category_menu(menu_num),menu_channel); } else { llDialog(id,"Menu: Stations\nGenre: " + llList2String(category_list,category_index), station_menu(menu_num),menu_channel); } }
if (listen_handle != 0) llListenRemove(listen_handle); listen_handle=llListen(menu_channel,"",id,"");
}
list category_menu(integer num) { // compile menu list of category list
// if there are more catagories then can be displayed in the menu // compile a submenu, including options for main menu and more and a blank item. integer len=llGetListLength(category_list); list menu=[];
if (len > 9) { integer last_sub=(len-1)/9; // submenus start at 0. 9th entry is in submenu 0, 10th in 1, etc.
if (num > last_sub) { llWhisper(0,"error: wrong submenu number: " + (string) num + "."); return [ "MAIN" ]; } else { integer first=9*num;
while (--len >= first) menu+=(list)llList2String(category_list,len);
if (num == 0) menu+=(list)button_HELP; else menu+=(list)button_MAIN;
if (num == 0) menu+=(list)button_OFF; else menu+=(list)button_PREV;
if (num != last_sub) menu+=(list)button_NEXT; } } else { while (--len >= 0) menu+=(list)llList2String(category_list,len);
menu+=(list)button_OFF; menu+=(list)button_HELP; } DebugSay("main menu: " + llList2CSV(menu));
return menu; // order_buttons(menu);
}
integer stations_in_category(integer cat) {
integer count=0; integer i; integer len=llGetListLength(station_category); string category=llList2String(category_list,cat);
for (i=0; i < len; i++) if (category == llList2String(category_list,i)) count++;
return count;
}
list order_buttons(list buttons) {
integer offset; list fixt; integer flag=0;
while((offset = llGetListLength(buttons))) { if (offset > 3) flag=1; else flag=0;
fixt += llList2List(buttons, offset = -3 * flag, -1); buttons = llDeleteSubList(buttons, offset, -1); }
return fixt;
}
list station_list(integer category) {
list s=[]; integer i; string cname=llList2String(category_list,category_index);
for (i = 0; i < llGetListLength(station_name); i++) if (llList2String(station_category,i) == cname) s+=(list)llList2String(station_name,i);
return s;
}
list station_menu(integer num) {
// compile menu list of station names // if there are more stations then can be displayed in the menu // compile a submenu, including options for main menu and more and a blank item.
list stations=station_list(category_index); integer len=llGetListLength(stations); list menu=[];
llSay(0,"Category: " + llList2String(category_list,category_index)); llSay(0,"Stations: " + llDumpList2String(stations,",")); if (len > 11) { integer last_sub=(len-1)/9;
if (num >= last_sub) { llWhisper(0,"error: wrong submenu number: " + (string) num + "."); return [ "MAIN" ]; } else { integer first=9*num; integer last=9*num+8;
menu+=(list)button_MAIN;
if (num > 0) menu+=(list)button_PREV;
if (num < last_sub) menu+=(list)button_NEXT;
if (len > last) len =last; while (--len >= first) menu+=(list)llList2String(stations,len); } } else { menu+=(list)button_MAIN;
while (--len >= 0) menu+=(list)llList2String(stations,len); }
DebugSay("station menu: " + llList2CSV(menu)); return menu; // order_buttons(menu);
}
integer has_access(key id) {
if (llListFindList(banned_keys,(list)id) != -1) return FALSE;
if (owner_access && id == llGetOwner()) return TRUE;
if (group_access && llSameGroup(id)) return TRUE;
if (public_access) return TRUE;
return FALSE;
}
integer random_channel() {
integer min=-2147483647; integer max=-1000;
return (integer) (min + llFrand(max-min));
}
integer check_url(string url) {
integer pos=0;
if (llGetSubString(url,0,6) == "http://") pos=7; if (llGetSubString(url,0,7) == "https://") pos=8;
if (pos==0) return FALSE;
string str_ip_port=llGetSubString(url,pos,-1); list list_ip_port=llParseString2List(str_ip_port,[":"],[]); // split in ip-adress and port list list_ip=llParseString2List(llList2String(list_ip_port,0),["."],[]); // split ip-adress elements
if (llGetListLength(list_ip_port) != 2 || llGetListLength(list_ip) != 4) return FALSE;
integer i; integer test;
for (i=0;i<4;i++) { test=llList2Integer(list_ip,i); if (llList2String(list_ip,i) != (string)test) return FALSE; if (test < 0 || test > 255) return FALSE; }
test=llList2Integer(list_ip_port,1); if (llList2String(list_ip_port,1) != (string)test) return FALSE;
return TRUE;
}
integer true_value(string input) {
string value=llToLower(llGetSubString(input,0,0));
if (value == "y" || value == "t" || value =="1") return TRUE;
return FALSE;
}
integer process_line(string dataline) {
string line=llStringTrim(dataline,STRING_TRIM); integer index=llSubStringIndex(line,comment_char); if (index==0) // line starts with comment - ignore line return TRUE;
if (index!=-1) line=llStringTrim(llGetSubString(line,0,index-1),STRING_TRIM_TAIL); // skip everything after comment_char and trim tail
if (line=="") // Ignore blank lines return TRUE;
if (llToLower(line) == "[access]") { section = 1; return TRUE; } else if (llToLower(line) == "[banned]") { section = 2; return TRUE; } else if (llToLower(line) == "[genre]") { section = 3; return TRUE; } else if (llToLower(line) == "[station]") { section = 4; return TRUE; } else if (llGetSubString(line,0,0) == "[" && llGetSubString(line,-1,-1) == "]") { llWhisper(0,"error: malformed section found at line " + (string)lineno + ".\n" + dataline); config_error=TRUE; return FALSE; }
if (section == 0) { llWhisper(0,"error: no section found on line: " + (string) lineno); config_error = TRUE; return FALSE; }
list breakup=llParseString2List(line,["="],[]); string field=llStringTrim(llList2String(breakup,0),STRING_TRIM); string values=llStringTrim(llList2String(breakup,1),STRING_TRIM);
if (section == 1) // access { field=llToLower(field);
if (field=="owner") { owner_access=true_value(values); return TRUE; } else if (field=="group") { group_access=true_value(values); return TRUE; } else if (field=="public") { public_access=true_value(values); return TRUE; } else { llWhisper(0,"error: invalid option on line: " + (string)lineno + ".\n" + dataline); config_error=TRUE; return FALSE; }
} else if (section == 2) // ban list { key try=(key) field;
if (try) { banned_keys+=(list)((key) field); return TRUE; } else return FALSE; } else if (section == 3) // categories {
// DebugSay("category: '" + field + "'");
if (llListFindList(category_list,(list)field) == -1) { category_list+=(list)field; } else llWhisper(0,"genre: '" + field + "' already entered; double entry skipped.");
return TRUE; } else if (section == 4) // stations { list parse=llParseString2List(line,sep_char_list, []); string category=llStringTrim(llList2String(parse,0),STRING_TRIM); string name=llStringTrim(llList2String(parse,1),STRING_TRIM); string desc=llStringTrim(llList2String(parse,2),STRING_TRIM); string url=llStringTrim(llToLower(llList2String(parse,3)),STRING_TRIM); if (!available_category(category)) { llWhisper(0,"error: unknown genre on line: " + (string)lineno + ".\n" + dataline); DebugSay("genre: '" + category + "'"); config_error=TRUE; return FALSE; } if (check_url(url)) { if (llListFindList(station_url,(list)url) == -1 || llListFindList(station_category,(list)category) == -1) { num_stations++; station_category+=(list)category; station_name+=(list)name; station_desc+=(list)desc; station_url+=(list)url; return TRUE; } else { llWhisper(0,"This station is already entered under the same genre and same url and is skipped.\nStation: " + name + "\nGenre: '" + category + "'\nURL: " + url); return TRUE; } } else { llWhisper(0,"error: malformed url on line: " + (string)lineno + ".\n" + dataline); config_error=TRUE; return FALSE; } } return FALSE;
}
set_parcel_url(string url)
{
parcel_url=url; llSetParcelMusicURL(parcel_url);
if (parcel_url=="") { clear_display(); display_line("1","Radio is OFF"); display_line("2",""); display_line("3",""); } else { llWhisper(0,"station now set to " + llList2String(station_desc,station_index) + "."); display_line("1","Station: " + llList2String(station_desc,station_index)); display_line("2","Genre : " + llList2String(category_list,category_index)); display_line("3","Now playing....."); llSetTimerEvent(update_time); }
}
integer available_category(string category) {
integer i; integer len=llGetListLength(category_list);
for (i=0;i<len;i++) if (llToLower(category) == llToLower(llList2String(category_list,i))) return TRUE;
return FALSE;
}
integer empty_category(string category) {
integer i; integer len=llGetListLength(station_category);
for (i=0; i < len; i++) if (llToLower(category) == llToLower(llList2String(station_category,i))) return FALSE;
return TRUE;
}
skip_empty_categories() {
integer i=0;
while (i<llGetListLength(category_list)) { if (empty_category(llList2String(category_list,i))) { llWhisper(0,"Warning: Genre '" + llList2String(category_list,i) + "' contains no stations and is deleted."); category_list=llDeleteSubList(category_list,i,i); } else i++; } num_categories=llGetListLength(category_list);
}
///////////////////////////////////////////// // state default ////////////////////////////////////////////
default {
state_entry() { flag=FALSE; lineno=0; config_error=FALSE; num_stations=0; num_categories=0; radio_status=0; menu_num=0; menu_type=0; if (llGetInventoryType(config_notecard) != INVENTORY_NONE) { reqid=llGetNotecardLine(config_notecard,lineno++); llWhisper(0, "Reading config notecard..."); display_line("1","Reading configuration."); display_line("2","Wait...."); display_line("3",""); } else { llWhisper(0,"No config notecard '" + config_notecard + "' present."); state offline; } }
on_rez(integer param) { llResetScript(); }
dataserver(key id, string data) { if (reqid==id) { if (data==EOF) { skip_empty_categories(); llWhisper(0,"Configuration ok.\n" + (string)num_categories + " genres and " + (string)num_stations + " stations."); display_line("1","Configuration OK"); display_line("2","Genres : " + (string)num_categories); display_line("3","Stations: " + (string)num_stations); state menu; } else { if (process_line(data)) reqid=llGetNotecardLine(config_notecard,lineno++); else if (config_error) { llWhisper(0,"errors found in configuration. please correct them."); state offline; } } } }
touch_start(integer total_num) { }
changed(integer ch) { if (ch & CHANGED_INVENTORY && flag) llResetScript(); }
}
///////////////////////////////////////////// // state offline ////////////////////////////////////////////
state offline {
state_entry() { llWhisper(0,"Reset on owner touch."); } touch_start(integer t) { if (llDetectedKey(0)==llGetOwner()) llResetScript(); }
}
///////////////////////////////////////////// // state menu ////////////////////////////////////////////
state menu {
state_entry() { menu_type=0; menu_num=0; listen_handle=0; }
changed(integer param) { if (param & CHANGED_INVENTORY) llResetScript(); } on_rez(integer param) { llResetScript(); }
touch_start(integer total_num) { key toucher=llDetectedKey(0);
if (has_access(toucher)) { make_menu(toucher); } else llWhisper(0,"sorry, no access."); }
listen(integer chan, string name,key id,string msg) { integer index;
if (menu_type == 0) // main menu { if (msg == button_MAIN) { menu_type=0; menu_num =0; make_menu(id); } else if (msg == button_NEXT) { menu_num++; make_menu(id); } else if (msg == button_PREV) { menu_num--; make_menu(id); } else if (msg == button_ON) { radio_status=1; set_parcel_url(parcel_url); display_line("1","Radio is ON"); menu_num=0; llWhisper(0,"Radio now turned on."); make_menu(id); } else if (msg == button_OFF) { radio_status=0; set_parcel_url(""); llSetTimerEvent(0.0); llWhisper(0,"Radio now turned off."); } else if (msg == button_HELP) { if (llGetInventoryType(info_notecard) == INVENTORY_NOTECARD) { llGiveInventory(id,info_notecard); } else llWhisper(0,"sorry, help not available."); } else if (radio_status == 1) { index = llListFindList(category_list, (list)msg);
if (index == -1) llWhisper(0,"error: genre not found: " + msg); else { category_index=index; llWhisper(0,"Genre now set to " + llList2String(category_list,category_index) + "."); menu_type=1; menu_num=0; make_menu(id); } } } else if (menu_type == 1 && radio_status == 1) // station menu { if (msg == button_MAIN) { menu_type=0; menu_num =0; make_menu(id); } else if (msg == button_NEXT) { menu_num++; make_menu(id); } else if (msg == button_PREV) { menu_num--; make_menu(id); } else { index = llListFindList(station_name, (list)msg);
if (index == -1) llWhisper(0,"error: station not found: " + msg); else { station_index=index; string new_url=llList2String(station_url,station_index);
if (new_url != parcel_url) { set_parcel_url(new_url); } } } } }
timer() { retrieve_titelinfo(); llSetTimerEvent(update_time); }
http_response(key id, integer status, list meta, string body) { if (id == httpreq_id) { if (status == 200) { string feed = llGetSubString(body,llSubStringIndex(body, "<body>") + llStringLength("<body>"), llSubStringIndex(body,"</body>") - 1); list feed_list = llParseString2List(feed,[","],[]); string current_title_info= llList2String(feed_list,6); integer length = llGetListLength(feed_list); if(llList2String(feed_list,7)) { integer a = 7; for(; a<length; ++a) { current_title_info += ", " + llList2String(feed_list,a); } } if (current_title_info != last_title_info) { last_title_info = current_title_info; display_line("3","Title : " + current_title_info); } } else { display_line("3","Title : " + no_title_info); } } }
}
////////////////////////////// // end of script ///////////////////////////// </lsl>