<%pre> #include #include #include #include #include #include #include "exception.h" #include "livefeatures.h" #include "setup.h" #include "tools.h" #include "timers.h" #include "epg_events.h" #include "i18n.h" using namespace std; using namespace vdrlive; struct SchedEntry { string title; string short_description; string description; string description_trunc; string start; string end; string day; string epgid; bool truncated; bool has_timer; int start_row; int row_count; }; std::vector channel_groups_names; std::vector times_names; std::vector times_start; <%args> unsigned int channel = 0; unsigned int time_para = 0; <%session scope="global"> bool logged_in(false); <%request scope="page"> unsigned int channel_group=0; unsigned int time_selected=0; <%include>page_init.eh <%cpp> if (!logged_in && LiveSetup().UseAuth()) return reply.redirect("login.html"); pageTitle = trVDR("Schedule"); ReadLock channelsLock( Channels ); if ( !channelsLock ) throw HtmlError( tr("Couldn't aquire access to channels, please try again later.") ); #define MAX_CHANNELS 5 #define MAX_DAYS 3 #define MAX_HOURS 8 #define MINUTES_PER_ROW 5 #define CHARACTERS_PER_ROW 30 // build the groups of channels to display std::vector< std::vector > channel_groups_numbers; channel_groups_names.clear(); int cur_group_count=0; for ( cChannel *listChannel = Channels.First(); listChannel; listChannel = Channels.Next( listChannel ) ) { if ( listChannel->GroupSep() || *listChannel->Name() == '\0' ) continue; if ( cur_group_count==0 ) { // first entry in this group channel_groups_names.push_back( std::string() ); channel_groups_numbers.push_back( std::vector( MAX_CHANNELS) ); } else channel_groups_names.back() += " - "; channel_groups_names.back() += std::string( listChannel->Name() ); channel_groups_numbers.back()[ cur_group_count ] = listChannel->Number(); cur_group_count++; if ( cur_group_count >= MAX_CHANNELS ) // we need a new group next round cur_group_count = 0; } if ( channel >= channel_groups_numbers.size() ) channel = channel_groups_numbers.size()-1; channel_group = channel; { // build time list times_names.clear(); times_start.clear(); // calculate time of midnight (localtime) and convert back to GMT time_t now = time(NULL); time_t now_local = time(NULL); struct tm tm_r; if ( localtime_r( &now_local, &tm_r ) == 0 ) { ostringstream builder; builder << "cannot represent timestamp " << now_local << " as local time"; throw runtime_error( builder.str() ); } tm_r.tm_hour=0; tm_r.tm_min=0; tm_r.tm_sec=0; time_t midnight = mktime( &tm_r ); // default is now rounded to full hour times_names.push_back( tr("Now") ); times_start.push_back( 3600 * ( now /3600 ) ); int i =0; // skip allready passed times while ( now>midnight+MAX_HOURS*3600*i) i++; for (; i<4*MAX_DAYS ; i++ ) { times_names.push_back(FormatDateTime( tr("%A, %x"), midnight + MAX_HOURS*3600*i) +std::string(" ")+ FormatDateTime( tr("%I:%M %p"), midnight + MAX_HOURS*3600*i) ); //times_names.push_back("today 0:00"); times_start.push_back( midnight + MAX_HOURS*3600*i ); } if ( time_para >= times_names.size() ) time_para = times_names.size()-1; time_selected=time_para; } <& pageelems.doc_type &> VDR Live - <$ pageTitle $> <& pageelems.stylesheets &> <& pageelems.ajax_js &> <& pageelems.logo &> <& menu active=("multischedule") component=("multischedule.channel_selection") &>
<%cpp> cSchedulesLock schedulesLock; cSchedules const* schedules = cSchedules::Schedules( schedulesLock ); time_t now = time(NULL); if ( time_para >= times_start.size() ) time_para = times_start.size()-1; time_t sched_start = times_start[ time_para ]; time_t sched_end = sched_start + 60 * 60 * MAX_HOURS; int sched_end_row = ( sched_end - sched_start ) / 60 / MINUTES_PER_ROW; std::list table[MAX_CHANNELS]; string channel_names[ MAX_CHANNELS]; if ( channel >= channel_groups_numbers.size() ) channel = channel_groups_numbers.size()-1; //for ( int chan = 0; chanGroupSep() || Channel->Name() == '\0' ) continue; channel_names[ j ] = Channel->Name(); cSchedule const* Schedule = schedules->GetSchedule( Channel ); if ( ! Schedule ) continue; for (const cEvent *Event = Schedule->Events()->First(); Event; Event = Schedule->Events()->Next(Event) ) { if (Event->EndTime() <= sched_start ) continue; if (Event->StartTime() >= sched_end ) continue; EpgInfoPtr epgEvent = EpgEvents::CreateEpgInfo(Channel, Event); if ( prev_row < 0 && Event->StartTime() > sched_start + MINUTES_PER_ROW ) { // insert dummy event at start table[ j ].push_back( SchedEntry() ); SchedEntry &en=table[ j ].back(); int event_start_row = (Event->StartTime() - sched_start) / 60 / MINUTES_PER_ROW; en.start_row = 0; en.row_count = event_start_row; // no title and no start time = dummy event en.title = ""; en.start = ""; prev_row = en.start_row + en.row_count; } table[ j ].push_back( SchedEntry() ); SchedEntry &en=table[j].back(); en.title = epgEvent->Title(); en.short_description = epgEvent->ShortDescr(); en.description = epgEvent->LongDescr(); en.start = epgEvent->StartTime(tr("%I:%M %p")); en.end = epgEvent->EndTime(tr("%I:%M %p")); en.day = epgEvent->StartTime(tr("%A, %b %d %Y")); en.epgid = EpgEvents::EncodeDomId(Channel->GetChannelID(), Event->EventID()); en.has_timer = LiveTimerManager().GetTimer(Event->EventID(), Channel->GetChannelID() ) != 0; en.start_row = prev_row > 0 ? prev_row : 0; int end_time = Schedule->Events()->Next(Event) ? Schedule->Events()->Next(Event)->StartTime() : Event->EndTime(); int next_event_start_row = (end_time - sched_start) / 60 / MINUTES_PER_ROW; en.row_count = next_event_start_row - en.start_row; if ( en.row_count < 1 ) en.row_count = 1; prev_row = en.start_row + en.row_count; // truncate description if too long en.truncated=false; en.description_trunc=StringWordTruncate( en.description, CHARACTERS_PER_ROW*(en.row_count-2), en.truncated ); }; if ( table[ j ].begin() == table[ j ].end() ) { // no entries... create a single dummy entry table[ j ].push_back( SchedEntry() ); SchedEntry &en=table[ j ].back(); en.start_row = 0; en.row_count = sched_end_row; // no title and no start time = dummy event en.title = ""; en.start = ""; } } <%cpp> <%cpp> for ( int channel = 0; channel< MAX_CHANNELS ; channel++) { <%cpp> } <%cpp> bool odd=true; std::list::iterator cur_event[ MAX_CHANNELS ]; for (int i=0;i now ) { row_class +=" current_row "; } row_class += odd ? " odd " : " even "; <%cpp> for ( int channel = 0; channel< MAX_CHANNELS ; channel++) { // output spacer column <%cpp> if ( cur_event[channel] == table[channel].end() || cur_event[channel]->start_row != row ) // no new event in this channel, skip it continue; SchedEntry &en=*cur_event[channel]; if (en.title.empty() && en.start.empty() ) { // empty dummy event <%cpp> ++cur_event[channel]; continue; } // output an event cell <%cpp> // move to next event for this channel ++cur_event[channel]; } <%cpp> }
<$ tr("Time") $>
 
<$ StringEscapeAndBreak(channel_names[channel]) $>
 
<%cpp> if ( minutes == 0 ) { <$ FormatDateTime( tr("%I:%M %p"), sched_start + row * 60 * MINUTES_PER_ROW ) $> <%cpp> } else {   <%cpp> }   " rowspan="<$ en.row_count $>">
<& pageelems.event_timer epgid=(en.epgid) &> <%cpp> if (LiveFeatures().Recent() ) { " alt="" <& tooltip.hint text=(tr("Search for repeats.")) &>> <%cpp> } else { <%cpp> } <& pageelems.imdb_info_href title=(en.title) &>
<$ en.start $>
<%cpp> if ( en.row_count>2 && !en.short_description.empty() ) {
<$ en.short_description.empty() ? " " : en.short_description $>
<%cpp> } if ( en.row_count>3 && ! en.description_trunc.empty() ) {
<$en.description_trunc$>... <%cpp> if ( en.truncated ) { <& tooltip.display domId=en.epgid &>> <$ tr("more") $> <%cpp> }
<%cpp> }
<%include>page_exit.eh <%def channel_selection>
% // <& pageelems.ajax_action_href action="switch_channel" tip=(tr("Switch to this channel.")) param=(Channel->GetChannelID()) image="zap.png" alt="" &> % // <& pageelems.vlc_stream_channel channelId=(Channel->GetChannelID()) &>