Jump to content
Wulfie Reanimator

Radio / Parcel Music URL Changer (With Menu)

Recommended Posts

This was inspired by a similar script written by Franklyn Constantine, but uses none of his code.

Main differences between his version and mine:

  • Mine uses only one state. (His uses four)
  • Mine uses only one extra function. (His uses two)
  • Mine uses 12 global variables. (His uses 24)
  • My code has 93 lines, excluding comments, curly brackets, and blank lines. (His has 201)
  • Mine doesn't have an "options menu." (His could change access level and the channel)
    • Mine does have a group-only toggle, must be changed in-script.
    • Mine uses a channel based on the object's own key.
  • Mine uses llTextBox for user-input. (His uses local chat)
  • Mine tries to gracefully validate and fix user-input. (His just tells the user to try again.)
    • A valid URL must have at least one period in it, eg: "mystream.cool"
      If this condition isn't met, an error is shown to the user.
    • The user doesn't have to include "http://" or "https://", the script will add it.
  • Mine has no license, do whatever you want with it.

Basically: This is a notecard and menu-based system that allows the current parcel's music URL to be changed. You must make a notecard with button name and URL pairs (separated by semicolon), per line, so that the script can create a menu for you. Here's an example:

button 1;http://listen.radionomy.com/DRIVE
cool button;http://listen.radionomy.com/DRIVE

# Lines like this will be ignored!
# Empty lines will be ignored too.

D R I V E;http://listen.radionomy.com/DRIVE
button 4;http://listen.radionomy.com/DRIVE

His code can be found here: https://pastebin.com/2fKkrche

My version:

integer group_only = TRUE;

string  note_name = "stations";
integer note_line;

string  station_name = "none";
list    station_names;
list    station_urls;

integer page_num;
integer page_count;

integer ready;
integer menu_channel;
integer input_handle;
key     waiting_from;

show(key avatar, integer page)
{
    integer start = (9 * page) - !!page;
    list menu = ["<<", "URL", ">>"] + llList2List(station_names, start, start + 8);
    llDialog(avatar, "Current station: " + station_name, menu, menu_channel);
}

default
{
    touch_start(integer n)
    {
        if (!ready) return;
        key avatar = llDetectedKey(0);
        if (avatar == llGetOwner() ||               // owner
            !group_only ||                          // anybody
            (group_only && llSameGroup(avatar)))    // any group member
        {
            show(avatar, page_num = 0);
        }
        else llInstantMessage(avatar, "You're not allowed to use this.");
    }

    listen(integer chat, string _, key avatar, string input)
    {
        // Next page with roll-over
        if (input == ">>")
        {
            if (++page_num >= page_count) page_num = 0;
            show(avatar, page_num);
        }
        // Last page with roll-over
        else if (input == "<<")
        {
            if (--page_num < 0) page_num = page_count - 1;
            show(avatar, page_num);
        }
        // Initiate user-input
        else if (input == "URL")
        {
            waiting_from = avatar;
            llListenRemove(input_handle); // Remove previous, if any
            input_handle = llListen(menu_channel + 1, "", avatar, "");
            llTextBox(avatar, "Enter a stream URL", menu_channel + 1);
            llSetTimerEvent(30);
        }
        // Parse user-input
        else if (chat == menu_channel + 1)
        {
            if (llSubStringIndex(input, ".") == -1)
            {
                llInstantMessage(avatar, "I don't think that's a real URL.");
                return;
            }
            if (llSubStringIndex(input, "://") == -1) input = "http://" + input;

            station_name = "custom choice";
            llSetParcelMusicURL(input);
            llInstantMessage(avatar, "Now listening to \"" + station_name + "\"");
            llListenRemove(input_handle);
            waiting_from = NULL_KEY;
            llSetTimerEvent(0);
        }
        else
        {
            integer index = llListFindList(station_names, (list)input);
            if (index == -1)
            {
                llInstantMessage(avatar, "That's not on the menu.");
                return;
            }

            station_name = llList2String(station_names, index);
            llSetParcelMusicURL(llList2String(station_urls, index));
            llInstantMessage(avatar, "Now listening to \"" + station_name + "\"");
            llSetTimerEvent(0);
        }
    }

    timer()
    {
        llInstantMessage(waiting_from, "You didn't give a stream URL fast enough.");
        llListenRemove(input_handle);
        waiting_from = NULL_KEY;
        llSetTimerEvent(0);
    }

    // Changed/state_entry/dataserver are only used to initialize the script.
    // The main functionality is in touch_start/listen/timer.
    changed(integer change)
    {
        if (change & CHANGED_OWNER ||
            change & CHANGED_INVENTORY)
            llResetScript();
    }

    state_entry()
    {
        if (llGetInventoryType(note_name) == INVENTORY_NOTECARD)
        {
            llOwnerSay("Loading stations...");
            llGetNotecardLine(note_name, note_line);
        }
        else llOwnerSay("No \"" + note_name + "\" notecard found.");
    }

    // Parse a notecard in this format:
    // Menu button name;Station stream url
    dataserver(key id, string data)
    {
        if (data == EOF)
        {
            page_count = 1 + llGetListLength(station_urls) / 9;
            menu_channel = (integer)("0x" + llGetSubString(llGetKey(), 0, 7));
            llListen(menu_channel, "", "", "");
            ready = TRUE;
            llOwnerSay((string)llGetListLength(station_urls) + " stations added.");
        }
        else
        {
            string first = llGetSubString(data, 0, 0);
            if (first != "#" && first != "")
            {
                integer separator = llSubStringIndex(data, ";");
                if (separator == -1)
                {
                    llOwnerSay("Missing \";\" on line " + (string)(note_line + 1));
                    llGetNotecardLine(note_name, ++note_line);
                    return;
                }

                string button = llGetSubString(data, 0, separator - 1);
                button = llGetSubString(button, 0, 11);

                string url = llGetSubString(data, separator + 1, -1);
                if (llSubStringIndex(url, "://") == -1) url = "http://" + url;

                station_names += button;
                station_urls += url;
            }
            llGetNotecardLine(note_name, ++note_line);
        }
    }
}

Unfortunately I don't have land or a group to deed this with, so I can't fully test for all possible issues, but I've done my best in making sure this works and by all reason should work as-is without deeding to a group.

Edited by Wulfie Reanimator
  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

I have a group with group-owned land and a Linden camper owned by my building alt which is set to the same group. If either would be of use to you for testing, I'd be happy to invite you to the group and send LMs.

I'd really like to have parcel music for the camper site but can't find a reasonable stream. When I have some spare energy, maybe I'll try again with your script so at least I could change it when it got annoying :)

  • Like 1

Share this post


Link to post
Share on other sites
9 hours ago, Bitsy Buccaneer said:

I have a group with group-owned land and a Linden camper owned by my building alt which is set to the same group. If either would be of use to you for testing, I'd be happy to invite you to the group and send LMs.

I'd really like to have parcel music for the camper site but can't find a reasonable stream. When I have some spare energy, maybe I'll try again with your script so at least I could change it when it got annoying :)

I'd appreciate it!

  • Like 2

Share this post


Link to post
Share on other sites

@Wulfie Reanimator,

Nice work.  My wish list. 

1. Make it so that the NoteCard (NC) goes in a non-deeded prim, transmitting updates to the Radio (deeded prim).

2. Add a NC setting letting us tell the Radio what hour to reset to Channel 1.

I use an @Alicia Stella script that I modified to reset to Channel 1 every day at 6 a.m. SLT, but I did it in the LSL code, not the NC. Her script is sold in her store full perms, but I don't have the right to post it here.

I too have land you can use, if you need more, I'll send you the group and LM.

Edited by Erwin Solo
  • Like 1

Share this post


Link to post
Share on other sites

Didn't see this here, was frustrated with my primmy no-mod / no-copy radios, and decided yesterday to finally just write one myself.

Here's my take on this concept, not yet integrated with notecards, but has a schedule system:

 

list stations = [
"http://ais.rastamusic.com:80/rastamusic.mp3",
"http://hestia2.cdnstream.com/1301_128",
"http://radiolatina.info:7218",
"http://france1.coollabel-productions.com:8142",
"http://janus.shoutca.st:8233/stream/1/",
"http://rootslegacy.fr:8080",
"http://star.jointil.net/proxy/jrn_reggae?mp=/stream",
"http://sc-reggae.1.fm:7000/",
"http://198.178.123.20:7000",
"http://uplink.duplexfx.com:8042"
];

list stationNames = [
"Rasta Music",
"Reggae141.com",
"SalsaMexico",
"Reggae Mix France",
"Sensimedia",
"Roots Legacy",
"Joint Radio Reggae",
"ReggaeTrade Radio 1FM",
"PONdENDS.COM",
"181.FM - Jammin 181"
];

integer radioMessenger = 0;

string getSchedule() {
    integer now = (integer)llGetWallclock();
    integer hours = now / 3600;
    
    if (hours >= 23) return llList2String(stations,0);
    else if (hours >= 21) return llList2String(stations,5);
    else if (hours >= 19) return llList2String(stations,4);
    else if (hours >= 17) return llList2String(stations,3);
    else if (hours >= 15) return llList2String(stations,2);
    else if (hours >= 13) return llList2String(stations,1);
    else if (hours >= 11) return llList2String(stations,0);
    else if (hours >= 9) return llList2String(stations,5);
    else if (hours >= 7) return llList2String(stations,4);
    else if (hours >= 5) return llList2String(stations,3);
    else if (hours >= 3) return llList2String(stations,2);
    else if (hours >= 1) return llList2String(stations,1);
    else return llList2String(stations,0);
}

testMemory()
{
    llScriptProfiler(PROFILE_SCRIPT_MEMORY);
    integer usedMemory = llGetUsedMemory();
    llSetMemoryLimit( (usedMemory + 500) );
    llScriptProfiler(PROFILE_NONE);
}

default
{
    state_entry()
    {
        llSetParcelMusicURL(getSchedule());
        llSetTimerEvent(300);
        testMemory();
    }
 
    timer()
    {
        llSetParcelMusicURL(getSchedule());
        if (radioMessenger && radioMessenger !=0) {
            llListenRemove(radioMessenger);
            radioMessenger = 0;
        }
        testMemory();
    }
    touch_start(integer total_number)
    {
        key user = llDetectedKey(0);
        radioMessenger = llListen(739, "", user, "");
        llDialog(user, "Select a desired radio station", stationNames, 739);
    }
    listen(integer channel, string name, key id, string message)
    {
        string stationFrequency = "";
        integer stationNumber = llListFindList(stationNames, [message]);
        if (stationNumber != -1) {
            stationFrequency = llList2String(stations, stationNumber);
        }

        llRegionSayTo(id, 0, "Setting the radio to station " + (string)(stationNumber+1) + ": " + message + " (" + stationFrequency + ")");
        llSetParcelMusicURL(stationFrequency);
        testMemory();
    }
}

Still have some alterations to make over time.

Edited by Pussycat Catnap
  • Like 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...