[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: ireminder
- To: developer at arabeyes dot org
- Subject: Re: ireminder
- From: Ahmed El-Mahmoudy <aelmahmoudy at users dot sourceforge dot net>
- Date: Sat, 7 Oct 2006 12:34:38 +0200
- User-agent: Mutt/1.5.12-2006-07-14
as-salamu alaykom
On Fri, Oct 06, 2006 at 11:06:57PM +0200, Mohammed Sameer wrote:
> perldoc -f sprintf
jazak Allahu khairan...
Attached with this email is the new version of ireminder.
Now the -azan option accepts a play command instead of an audio file.
The command can take two parameters, the first will be the prayer name,
the second will be the prayer time. Here's an example:
ireminder -azan "myazan_cmd -opt1 %s -opt2 %s"
So when ireminder runs that myazan_cmd, it will subsitute the first '%s'
with prayer name & second '%s' with prayer time.
#!/usr/bin/perl
#---
# $Id: ireminder,v 1.5 2004/12/30 00:40:55 nadim Exp $
#
# ------------
# Description:
# ------------
# Copyright (c) 2004, Arabeyes, Nadim Shaikli
#
# This is a prayer (and other Islamic events) reminder program.
# Its a wrapper that uses Arabeyes.org's ITL package (ipraytime
# to be specific) to attain all its values. The script is meant
# to be light, simple and flexible.
#
# Based on a concept/idea from
# - Ahmed El-Mahmoudy (aelmahmoudy -at- users sf net)
#
# -----------------
# Revision Details: (Updated by Revision Control System)
# -----------------
# $Date: 2004/12/30 00:40:55 $
# $Author: nadim $
# $Revision: 1.5 $
# $Source: /home/arabeyes/cvs/projects/itl/programs/itools/ireminder,v $
#
# (www.arabeyes.org - under GPL license)
#---
# TODO:
# - have it fork in the background if a similar process doesn't already
# exist else kill the other process post a confirm (optionally)
# - have it print to the console not stdout (optionally)
# - clean-up the sound/bell stuff
# - have it be able to play reminder and Azan sounds (optionally)
# - have it spawn a GUI reminder/now dialogs (optionally)
use Getopt::Long;
use FileHandle;
STDOUT->autoflush(1);
##
# Specify global variable values and init some Variables
$in_script = $0;
$in_script =~ s|^.*/([^/]*)|$1|;
##
# Find how many spaces the scripts name takes up (nicety)
$in_spaces = $in_script;
$in_spaces =~ s/\S/ /g;
$version = " (v - %I%)";
$ID = "[$in_script]";
# Process the command line
&get_args();
# Make it simple, does user need help ?
if ($opt{help}) { &help(); }
# Account for the various ways a user might enter a list
%opt = %{&listify_input(\%opt, "skip")};
%opt = %{&listify_input(\%opt, "reminder")};
# Account for various places the ipraytime binary could reside-in
@bin_paths = ("/usr/bin/", "/usr/local/bin/", "");
foreach my $entry (@bin_paths)
{
$bin_path = "${entry}ipraytime";
if (-x $bin_path)
{
# OK, found something I can use
last;
}
}
$ipraytime = $opt{ipraytime} || $bin_path;
# Search for notify-send (aelmahmoudy):
foreach my $entry (@bin_paths)
{
$bin_path = "${entry}notify-send";
if (-x $bin_path)
{
# OK, found something I can use
last;
}
}
$notifysend = $bin_path;
# Set some default reminder settings
@reminders = @{$opt{reminder}} ? @{$opt{reminder}} : (1, 5, 10, 20);
# Enumerate the events we'll track and report on
$DAY_TOT_SEC = (24 * 60 * 60);
@EVENTS = (qw/imsaak fajr shorooq zuhr asr maghrib isha/);
# Set some defaults
$doing_2moro = 0;
$time_to_use = time();
if (!-x $ipraytime)
{
&usage(1, "$ID ERROR - can't find '$ipraytime' \n");
}
# Continuously cycle through
for (;;)
{
# Get current start time
$ref_time_used = &get_time($time_to_use);
%time_used = %{$ref_time_used};
# Specify date to get info on
$date_to_use = sprintf( "%d%02d%02d",
$time_used{year},
$time_used{month},
$time_used{day} );
# Run the actual program executable and process its output
$ref_today_events = &get_ipraytime($date_to_use);
%today_events = %{$ref_today_events};
# Cycle through all the prayers (and events)
for ($i = 0; $i <= $#EVENTS; $i++)
{
# Skip any events a user might have noted on the command-line
if ( defined $opt{skip} )
{
foreach my $option (@{$opt{skip}})
{
# Make sure to make the compare case insensitive
if ( uc($option) eq uc($EVENTS[$i]) )
{
$skip_event = 1;
last;
}
}
# If a skip-hit occured, cycle out of the for loop
if ($skip_event)
{
$skip_event = 0;
next;
}
}
# Determine current time's placement within event times
$before_last = ( ($time_used{hour} <
$today_events{$EVENTS[$#EVENTS]}{hour}) ||
(($time_used{hour} ==
$today_events{$EVENTS[$#EVENTS]}{hour}) &&
($time_used{min} <
$today_events{$EVENTS[$#EVENTS]}{min})) );
$after_current = ( ($time_used{hour} >
$today_events{$EVENTS[$i]}{hour}) ||
(($time_used{hour} ==
$today_events{$EVENTS[$i]}{hour}) &&
($time_used{min} >=
$today_events{$EVENTS[$i]}{min})) );
# If we are dealing with next day (upon start), cycle through
if (!$before_last && !$doing_2moro) { last; }
# Skip the past while making sure we didn't go over
if ($before_last && $after_current)
{
next;
}
else
{
# If I'm here, then its immaterial which day I'm dealing with
$doing_2moro = 0;
# See how many seconds we have left till next prayer
if ($before_last)
{
# Get time difference between prayer and wallclock time
$sec_diff = ( $today_events{$EVENTS[$i]}{tot_sec} -
$time_used{tot_sec} );
}
else
{
# Dealing with next day prayer
# - Get portion of day left in today + tomorrow's
$sec_diff = ( ($DAY_TOT_SEC - $time_used{tot_sec}) +
$today_events{$EVENTS[$i]}{tot_sec} );
}
# Account for the reminder time and the time delta seconds
$sec_sleep = ( $sec_diff - $time_used{sec} );
# Tell user what to expect next
$str = "$ID NOTE - Next event '$EVENTS[$i]' is at ";
$str .= "$today_events{$EVENTS[$i]}";
&display($str);
# Sort numerically descending
foreach $reminder (sort {$b <=> $a} @reminders)
{
$sec_reminder = ( $reminder * 60 );
if ($sec_sleep < $sec_reminder)
{
next;
}
$sec_sleep -= $sec_reminder;
# Take a nap and wait :-)
&do_reminder($EVENTS[$i],
$sec_sleep,
\%today_events,
$reminder);
$sec_sleep = $sec_reminder;
}
# Take a nap and wait (without reminders :-)
&do_reminder($EVENTS[$i],
$sec_sleep,
0,
0);
&do_alarm($EVENTS[$i], \%today_events);
# Establish new time for next prayer
# - This is opted for instead of accounting for passed sec's
$ref_time_used = &get_time(time());
%time_used = %{$ref_time_used};
}
}
# Cycle through & advance calc 1 day forward (ie. look at next day)
$time_to_use = ( time() + $DAY_TOT_SEC );
$doing_2moro = 1;
}
### ###
######## Procedures ########
### ###
##
# Print on screen passed-in string
sub display
{
my ($string) = @_;
# Do some clean-up and backtrack per use command-line directives
if ($opt{inplace})
{
print "\r";
print " " x 78;
print "\r";
}
print $string;
if (!$opt{inplace})
{
print "\n";
}
# (aelmahmoudy): also display message in X if possible
if ( $ENV{DISPLAY} && (fork() == 0) && (-x $notifysend) )
{
(my $dummy, $string) = split (/\]/, $string, 2);
my $i = index($string, "-");
$string = substr($string, $i + 1);
# exec ("wish << EOF
#wm title . ireminder
#label .l -text \"$string\"
#button .b -text OK -command exit
#pack .l .b
#EOF");
exec ("$notifysend \"Praytime reminder\" \"$string\" ");
}
}
##
# Adjust user input to end-up with a proper array
sub listify_input
{
my ($ref_in_opt,
$in_str) = @_;
my (
%in_opt,
@in_arr,
@mod_arr,
);
%in_opt = %{$ref_in_opt};
@in_arr = @{$in_opt{$in_str}};
# Make sure to accept for instance,
# 1. -skip one -skip two
# 2. -skip "one two"
# 3. -skip "one, two"
foreach my $string (@in_arr)
{
if ($string =~ /\s+/)
{
my @sub_string = split(/[,]*\s+/, $string);
push (@mod_arr, @sub_string);
next;
}
push (@mod_arr, $string);
}
$in_opt{$in_str} = \ at mod_arr;
return(\%in_opt);
}
##
# Populate time hash/struct using the passed-in time value
sub get_time
{
my ($in_time) = @_;
my (
%tm,
);
# seconds, minutes, hours, day, month, year, day.week, day.year, DST
($tm{sec},
$tm{min},
$tm{hour},
$tm{day},
$tm{month},
$tm{year},
$tm{dayofweek},
$tm{dayofyear},
$tm{dst}) = localtime($in_time);
# Some reability corrections
$tm{month} = ($tm{month} + 1);
$tm{year} = (1900 + $tm{year});
# Set some needed values
$tm{tot_min} = ($tm{min} + (60 * $tm{hour}));
$tm{tot_sec} = (60 * $tm{tot_min});
return(\%tm);
}
##
# Populate event hash/struct based on ipraytime's output using date passed-in
sub get_ipraytime
{
my ($in_date) = @_;
my (
$aux,
@out_ipray,
$ipray,
@times,
);
if (defined $in_date)
{
$aux = "--date $in_date ";
}
@out_ipray = `$ipraytime $aux`;
# Date Fajr Shorooq Zuhr Asr Maghrib Isha
#--------------------------------------------------------------------
# [22-07-2004] 5:22 6:50 13:27 16:43 20:04 21:34
#
#Today's Imsaak : 5:17
foreach my $line (@out_ipray)
{
# Remove the carriage returns
chomp($line);
# Find the proper line to process
if ($line =~ /\[\d+-\d+-\d+\]/)
{
@entries = split (/\s\s+/, $line);
$ipray{fajr} = $entries[1];
$ipray{shorooq} = $entries[2];
$ipray{zuhr} = $entries[3];
$ipray{asr} = $entries[4];
$ipray{maghrib} = $entries[5];
$ipray{isha} = $entries[6];
}
# Grab today's imsaak time
if ($line =~ /^Today.*Imsaak\s*:\s*(\d+:\d+)\s*/)
{
$ipray{imsaak} = $1;
}
}
# Get the total number of seconds for each prayer and event
for (my $i = 0; $i <= $#EVENTS; $i++)
{
@times = split(/\:/, $ipray{$EVENTS[$i]});
$ipray{$EVENTS[$i]}{hour} = $times[0];
$ipray{$EVENTS[$i]}{min} = $times[1];
$ipray{$EVENTS[$i]}{tot_min} = ($ipray{$EVENTS[$i]}{min} +
(60 * $ipray{$EVENTS[$i]}{hour}));
$ipray{$EVENTS[$i]}{tot_sec} = (60 * $ipray{$EVENTS[$i]}{tot_min});
}
# Return the newly populated hash/structure
return (\%ipray);
}
##
# Trigger a reminder
sub do_reminder
{
my ($in_name,
$in_time,
$ref_event_struct,
$in_rem) = @_;
my (
$name,
$str,
);
%event_struct = %{$ref_event_struct};
$name = ucfirst($in_name);
# Take a nap and wait
sleep($in_time);
# See if a reminder note is warranted
if ($in_rem > 0)
{
NAME_CASE:
{
if ($in_name eq "imsaak")
{
$str = "Fasting is to commence ($event_struct{$in_name})";
last NAME_CASE;
}
if ($in_name eq "shorooq")
{
$str = "Salat Al-Fajr expires ($event_struct{$in_name})";
last NAME_CASE;
}
#default
$str = "Salat Al-$name ($event_struct{$in_name})";
}
&play_sound();
&display("$ID REMINDER - $str in $in_rem minutes !!");
}
}
##
# Trigger an alarm
sub do_alarm
{
my ($in_name,
$ref_event_struct) = @_;
my (
$name,
$event_struct,
$num_rings,
$str,
);
$name = ucfirst($in_name);
%event_struct = %{$ref_event_struct};
$num_rings = 4;
NAME_CASE:
{
if ($in_name eq "imsaak")
{
$str = "to start your Fast";
last NAME_CASE;
}
if ($in_name eq "shorooq")
{
$str = "notes passing of Salat Al-Fajr";
last NAME_CASE;
}
#default
$str = "for Salat Al-$name";
if (defined $opt{azan}) { &play_azan($name, $event_struct{$in_name}); } # (aelmahmoudy): only at salat time
}
&display("$ID $event_struct{$in_name} - Time NOW $str !!");
for(my $i = 0; $i < $num_rings; $i++)
{
&play_sound();
sleep(1);
}
}
##
# Play an azan file (aelmahmoudy)
sub play_azan
{
my ($salat_name, $salat_time) = @_;
my $playcmd = sprintf($opt{azan}, $salat_name, $salat_time) ||
"mplayer -really-quiet -noconsolecontrols /usr/share/sounds/azan.wav";
$playcmd = "$playcmd > /dev/null 2>&1";
if(fork() == 0) { exec($playcmd); exit; }
}
##
# Play a sound file (if possible) else gimme a beep :-)
sub play_sound
{
print "\a";
}
##
# Print short usage info
sub usage
{
my ($die_after,
$err_msg) = @_;
if (defined $err_msg) { print $err_msg; }
print qq
|Usage: $in_script [-ipraytime path]
$in_spaces [-skip event_name]
$in_spaces [-reminder minutes]
$in_spaces [-azan [audio_file]]
$in_spaces [-inplace]
$in_spaces [-help]
|;
if ( $die_after ) { exit(5); }
}
##
# Print one-liner help
sub help
{
&usage(0);
print qq|
-> remind user visually and via audio of Islamic prayer times & misc events
Options:
[-ipraytime path] : Specify the executable path to program
[-skip event_name] : Specify name of prayer/event to skip (list ok)
[-reminder minutes] : Specify prior to how many minutes to remind (list ok)
[-azan [command]] : Specify a command to play azan, it can be supplied with
two parameters in the form of '%s', the first will be
prayer name, the second will be prayer time
[-inplace] : Specify to print output in-place (without scrolling)
[-help] : Produce this help screen
|;
exit(10);
}
##
# Get the command line arguments
sub get_args
{
&GetOptions(
\%opt, # Hash to store all input options in
"ipraytime=s", # specify the binary ipraytime executable
"skip=s@", # array'ed list of skip events
"reminder=s@", # array'ed list of reminder times (minutes)
"azan:s", # (aelmahmoudy)
"inplace", # specify to print in-place outputs (no scroll)
"help", # print a brief help screen
) || ( $? = 257, &usage(1, "$ID ERROR - Invalid argument\n") );
}