The Radio Playist is starting to piss me off

Now that I have the main script working, I need to be able to receive email notifications. This is where I am stuck. I cannot for the life of me find a console based mail client that will allow this. All of the clients require a user to control them. This is driving me nuts. I have tried a perl script that I found and that didn’t seem to work. I thought about trying to use links with a defined command set but I don’t think that will work either.

I’m starting to think maybe I can set up my own e-mail server. Maybe I can have the mail server perform an action (run a script) when it receives certain e-mails. One problem I have with this is that my ISP (Cox) seems to block access to port 25. There seems to be a way around it if you have a valid MX record. I went to my Domain Name provider and added an MX record for myself. Now I think I should be able to route e-mail through Cox’s mail servers. I’m not sure that I really need this, though. They might only be blocking outbound e-mail and not inbound. I can’t figure it out.

Screw it. I’m just going to go for it and see what happens. I’m installing postfix on my server and I’m going to try to get all of this working.

I started out following this guide, but it includes a lot of other programs I don’t need. I don’t want anti virus or spam protection or anything like that. I just want a really basic mail server.

OK. So I’ve spent several hours trying to figure out how the heck to solve this problem and I think I’ve finally found my answer. It is a Perl script written specifically to retrieve e-mail messages from GMail accounts. Before it would run on my system I had to install two Perl modules using cpan:

install Mail:Smilie: :POP3Client
install IO::Socket::SSL

I saved the script to my computer, added execute permissions (chmod +x) and changed the variables to match my own g-mail account. I ran the script and presto, I had my e-mail… finally. I wish I had found this a lot sooner. I also wish I was a better programmer. So now, I have a way to use a script to retrieve my e-mail. I just have to modify this script to locate any messages with only the word “Radio” as the subject, and then call my other script.

I have added a few lines of code to the script in order to test for the occurrence of the word “Radio” as well as to get the time that the e-mail message was sent. The time is crucial in order to tell when the song was actually played. The code I changed looks as follows:

————————-CODE———————-

# loop over msgs

for($i = 1; $i <= $pop->Count(); $i++) {

print $pop->Head($i) . “\n”; #Print out header info
#print $pop->Body($i) . “\n”;
if($pop->Head($i) =~ m/Radio/) { # If the header contaisn the word Radio anwhere
print “Found Radio!\n”; # Tell me if found it
if($pop->Head($i) =~ m/(\d\d)Smilie: :(\d\d):\d\d/) { # If the header contains a date
print “Message Time: $1:$2\n”; # Print out the hour and minute
}
}
print “\n”;
}

———————–END CODE——————————

So far, this works perfectly. I can tell that the word radio is present. If it finds it, it will grab the time and print it. Now I just need to convert the time into a 12 hour format and save the hour, minute, and AM/PM setting in three variables. Once they are saved, I can set a cron job to run 30 minutes from the current time to call my bash script with the variables as arguments. The 30 minute delay is required because the playlist on the website does not get updated for anywhere between 10-30 minutes typically. I’m off to work on a time conversion function.

So here’s my quick and dirty (probably terribly innefficient) time conversion program.

—————————–CODE———————————

# Function to convert time to 12 hour time.
sub timeConvert {
($hour1) = @_; # set these variables to = inputs
print “timeConvert: $hour1\n”;
if ($hour1 =~ “00″Smilie: ;) { # if it’s midnight
$hour2=”12″; # change from 00 to 12
$ap2=”AM”; # set to AM
return;
}
$hour1 += 0; # convert the string to int
if ($hour1 < 12) { # if its morning
$ap2=”AM”; # set to am
return;
}
if ($hour1 =~ 12) { # if its noon
$ap2=”PM”; # set to PM
return;
}
if ($hour1 > 12) { # if it’s after noon
print “Greater than 12\n”;
$ap2=”PM”; # set to pm

$hour2=$hour1 – 12; # convert to 12 hour format
return;
}
return;
}

———————-END CODE———————

The function takes in an hour value and performs all of those checks on it. Based on the time it will convert the hour value as necessary, and then set the AM/PM variable. My next step will be to get this Perl script to call my bash script as soon as it sees a Radio message. I will deal with setting the cron job later.

Well, that was easy. One simple command did the trick.

exec “playlist.bash $hour2 $2 $ap2″;

I added this into the if condition that checks for a time in the email header. This way, it won’t call the playlist script unless it finds a time and converts it first. I sent a new text message to my g-mail account and ran the script. Everything worked perfectly. The only problem is that the time now is 4:35PM and the song it returned to me was played at 4:16 PM. That’s the delay problem I was referring too before. Now I have to get the script to wait 30 minutes before checking for the song.

First I had to fix my system to have the correct time and date:

date 04301637

That did the trick, but I just remembered my bash script has a fatal flaw that I should fix now before I forget about it. If the song is played at the very beginning or end of the hour, the script does not take into consideration the fact that there are only 60 minutes in an hour. It could potentially try to look for a song played at 2:60, which obviously would not exist. I need to write a conversion function for the minute and hour for the bash script in this event. I’ll do that next.

I had to add a whole bunch of nested if statements in order to get the job done. When I say “had too” I really mean I’m not really sure the best way to do this and that’s the only way I could think of right now. It looks really messy but it gets the job done. The whole section looks like this:

————————–CODE——————————-

if [[ $artist = "" ]] #–If we didn’t find an artist
then #–Then increment the minute
m=`expr $m + 1`
if [[ $m = 60 ]] #–Obviously we can’t check 2:60 oclock
then
h=`expr $h + 1` #increment the hour and
m=00 # change the minute
if [[ $h = 12 ]] # might need to toggle AM PM
then
if [[ $a = "AM" ]]
then
a=”PM”
else
a=”AM”
fi
c=1
fi
fi
if [[ $h = 13 ]] # Now we also need to check for the hour being too high
then
h=1
fi
echo “time: $h:$m $a”
artist=`cat savedPage.html | grep “>$h:$m $a” -A 1 | tail -n1 | sed ‘s/<td nowrap><span class=blackMain11px>//’ | sed ‘s/<\/td>/\n/’ | head -n1`
if [[ $artist = "" ]] # if the artist still has not been found
then # then set the time back to normal
if [[ $c = 1 ]] # if we changed the am/pm setting
then # then reset it
a=$3
c=0
fi
h=$1
m=$2
fi
fi

while [[ $artist = "" ]] #–If we didn’t find an artist
do # then continue to subtract a minute till we find one
m=`expr $m – 1`
if [[ $m = -1 ]] #–Obviously we can’t check 2:-1 oclock
then
h=`expr $h – 1` #decrement the hour and
m=59 # change the minute
if [[ $h = 0 ]] # Need to change from 0:00 to 12:00
then
h=11
fi
if [[ $h = 11 ]] # this is where we might need to toggle AM/PM
then
if [[ $m = 59 ]]
then
if [[ $a = "AM" ]]
then
a=”PM”
else
a=”AM”
fi
fi
fi
fi
if [[ $h = 13 ]] # Now we also need to check for the hour being too high
then
h=1
fi
fi
if [[ $m -lt 10 ]] # the earlier correction stuff makes anything<0 look like: 12:1 instead of 12:01. We have to add that zero
then
m=”0$m”
fi
echo “time: $h:$m $a”
artist=`cat savedPage.html | grep “>$h:$m $a” -A 1 | tail -n1 | sed ‘s/<td nowrap><span class=blackMain11px>//’ | sed ‘s/<\/td>/\n/’ | head -n1`
done

————————-END CODE—————————-

Ah, god it hurts to look at. I really should switch this whole thing over to Perl. Why I don’t just quit now and do that I don’t know. At least it’s all set now.

OK, I think I’ve fixed that problem but I just discovered another one I had not even thought of before. If I try to search for the time 12:03, it MAY return a song that was actually played at 2:03 because it doesn’t check the value before that number. I’m going to have to fix my grep search string.

That turned out to be WAY easier than I expected. The way the playlist html code is set up, there is always a ‘>’ character right before the time value. All I had to do was add that to the beginning of my grep search. It now looks like this:

artist=`cat savedPage.html | grep “>$h:$m $a” -A 1 | tail -n1 | sed ‘s/<td nowrap><span class=blackMain11px>//’ | sed ‘s/<\/td>/\n/’ | head -n1`

Piece of cake. Now what’s left from here? The time delay. What is the best way for me to do this? I suppose I’ll have the perl script constantly running in the background, checking my e-mail every five minutes for a new message. If it finds the message, I’ll have it set a cron job to run 30 minutes from the current time. The cron job will call the bash script, which will then save the artist and song title to a file on my system. I also have to delete the messages after I’ve read them to prevent me from reading them over and over again.

I’m going to start with having the script set the cron job. According to this reference article cron takes 24 hour time. This should be easier for me considering the g-mail time comes in as a 24-hour time.

And apparently cron is used when you want a job to run more than once. That is, every day, week, month, etc. What I want to use is the “At”command. I found this nice reference for the at command. at also takes a 24 hour time, so I need to set up a new function in the perl script to come up with the future time, and set the at job.

Holy crap. So I just did some googling for the heck of it and discovered that I can actually just use the date command to get the date in the future. In my case I can just run:

date –date=’30 minutes”

This tells me the time 30 minutes from now. The at command wants to take a date in the form “mmddhhmm”. I should be able to just output the date command in that format and pipe it to the at command. This is going to be so much easier than I thought. I love Linux!

So I added a new perl function:

———————-CODE————————–

# Function to get the curent time and set an at job in 30 minutes
sub setJob {
my $future = `date –date=’30 minutes’ -t +%m%d%H%M`;
print “future= $future”;
exec “at -f ./playlist.bash -t $future”;
return;
}

——————-END CODE————————–

And I set it to be called where I used to have the perl script directly call the bash script. Now I just have to set the bash script to save all songs saved into a file. To do this, I deleted the end of the bash script where it printed the song to the screen and replaced it with this:

#——Save the artist and song——
date=`date +%m-%d-%Y` # det todays date so we can start a list for all songs found today
echo “$artist – $song” >> /media/radioLists/$date # save song in file

This creates a text file with the name being equal to todays date. That way I can have a list for every day I find a song. It saves the lists in my media directory which is shared via Samba.

I guess all that is left is to get the Perl script to check my mail every five minutes and set up GMail to delete the messages I have already read. I think the easiest way to do this would be to just set cron jobs. I can set up one cron job for every five minutes of an hour. Those jobs will run every hour, daily.

I also noticed that although I set up GMail to delete my messages once they are accessed with POP, it isn’t working. I added a line into my Perl script to set each Radio message to be deleted.

Now it’s testing time. I switched on the Radio and hear “Linkin Park’s – What I’ve done”. That was at 6:30. I sent a text message to my e-mail address while the song was playing. Now I have to wait until 6:35 to see if the cron job will actually start and if my Perl script will actually set the at job correctly. If all goes according to plan, I should basically be finished with this project.

The time has come. My Radio e-mail has dissapeared so that’s a good sign. The cron jobs are working. Now did the at job get set? No. There was a problem or two with the script. For one, it took me about 20 minutes to figure out that the message was actually being deleting before I got the time from it. I had to move the Delete command to a later spot in the Perl script. Second, the Perl script needed an absolute path to the bash script for the AT command. Once I fixed that, it all seems to work.

I turned on the radio at 7:37 and the song Psycho was playing by Puddle of Mudd. The script was delayed due to the problems I mentioned in the last paragraph, but it will run. I’m waiting for 7:19PM to find out if this thing will actually work. If yes, then I am done until I find a problem. Or if I decide to port the entire thing to Perl, which would be a really good idea. We’ll see…

Nope.  It didn’t work.  I can’t figure this out.  It look like cron actually runs the Perl script and the Perl script sets an at job.  I noticed that since I moved the pop->Delete(); command to a different place it’s stopped working, but the real problem is that the bash script doesn’t seem to be functioning properly.  The AT job starts, but then never finishes.  I can see all the Grep, Sed, Tail, etc processes using “ps -A” but they all say <Defunct>.  They keep disappearing and re-appearing.  I’m starting to wonder if the Perl script isn’t creating the AT job correctly for some reason.  Although, both scripts work fine if I run them myself…  MY friend Brian suggested that I give all commands in my bash script absolute paths.  I’ve tried that and it does the same thing.  The script works fine when I call it myself but not when the at process calls it.  I can’t figure this out.  I was thinking maybe I have to give Perl all of the absolute paths as well, but if it’s actually setting an at job than that couldn’t be the problem.  I’m really at a loss here.

Tomorrow I’ll probably have to start adding some kind of logging features.  Also, since Perl seems to be working fine maybe I’ll just start porting the Bash code over to Perl.  It couldn’t hurt I suppose…

Category(s): Scripting

Leave a Reply

Your email address will not be published. Required fields are marked *

*

 

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Powered by Sweet Captcha
Verify your real existence,
Drag the missing digit to the phone
  • captcha
  • captcha
  • captcha
  • captcha