<%pre>
#include "../services.h"

#include <livefeatures.h>
#include <setup.h>
#include <timers.h>
#include <tools.h>
#include <epg_events.h>
#include <tntfeatures.h>

using namespace vdrlive;

std::string toString(const std::vector<std::string> &vec) {
  if (vec.size() == 0) return "";
  std::string result;
  for (const std::string &str:vec) {
    if (!result.empty() ) result.append(", ");
    result.append(str);
  }
  return result;
}

std::string toString(const std::vector<cActor> &vec) {
  if (vec.size() == 0) return "";
  std::string result;
  for (const cActor &actor:vec) {
    if (!result.empty() ) result.append(", ");
    result.append(actor.name);
    if (!actor.role.empty() ) {
      result.append(" (");
      result.append(actor.role);
      result.append(")");
    }
  }
  return result;
}
bool getLanguage(std::string &language, const char *env_name) {
  const char *env_language = std::getenv(env_name);
  bool found = env_language && strlen(env_language) >= 2;
  if (found) language.append(env_language, 2);
  return found;
}

</%pre>
<%session scope="global">
int update_status(1);
</%session>

<# ---------------------------------------------------------------------- #>

<%def doc_type>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
</%def>

<# ---------------------------------------------------------------------- #>

<%def create_html_js>
<script type="text/javascript" src="js/live/createHtml.js"></script>
<script type="text/javascript" src="js.html"></script>
</%def>

<%def stylesheets>
<link rel="stylesheet" type="text/css" href="css/styles.css"/>
<link rel="stylesheet" type="text/css" href="<$ LiveSetup().GetThemedLink("css", "theme.css") $>"/>
<link rel="stylesheet" type="text/css" href="css/siteprefs.css"/>
<script type="text/javascript" src="js/live/scrolling.js"></script>
<script type="text/javascript" src="js/live/epg_tt_box.js"></script>
</%def>

<# ---------------------------------------------------------------------- #>

<%def logo>
<# start of fixed page header #>
<div id="header">
<# header content follows #>
<# page header follows #>
<%cpp>
  bool showLogo = LiveSetup().GetShowLogo();
  bool showInfoBox = LiveSetup().GetShowInfoBox();
  if (showLogo || showInfoBox) {
</%cpp>
<div class="page_header">
<%cpp>
    if (showLogo) {
</%cpp>
<a href="<$ LiveSetup().GetStartScreenLink()$>">
<img src="<$ LiveSetup().GetThemedLink("img", "logo.png") $>" alt="VDR Live!" class="logo<? showInfoBox ? " with-infobox" ?>" /></a>
<%cpp>
    }
</%cpp>
<%cpp>if (showInfoBox) { </%cpp><& infobox &><%cpp> } </%cpp>
</div>
<%cpp>
  }
</%cpp>
<div id="navigation">
<# content div kept open, menus provided by other file #>
</%def>

<# ---------------------------------------------------------------------- #>

<%def hide_element>
<%args>
  int hide = 1;
</%args>
<%cpp> if (hide) { </%cpp>style="visibility: hidden"<%cpp> } </%cpp>
</%def>

<# ---------------------------------------------------------------------- #>

<%def progressbar>
<%args>
  int progress = 0;
  std::string id;
  int duration = -1; // invalid duration as default
</%args>
<%cpp>
  std::string cls("__progress");
  if ((duration >= 0) && ((progress < 0) || (duration == 0)))
    cls +="_invisible";
</%cpp>
<div class="<$ cls $>"><div class="__elapsed" <%cpp> if (!id.empty()) { </%cpp>id="<$ id $>" <%cpp> } </%cpp>style="width: <$ progress $>%"></div></div>
</%def>

<# ---------------------------------------------------------------------- #>

<%def ajax_action_href>
<%args>
  std::string action;
  std::string tip;
  std::string param;
  std::string image;
  std::string alt;
  std::string id;
  std::string className;
  std::string label;
  std::string breaksAtLeft;
  std::string breaksAtRight;
  uintptr_t iCounter = 0;
</%args>
<%cpp>
bool isVisible = id.empty();
int *pCounter = static_cast<int *>((void *)iCounter);
if (pCounter && isVisible) (*pCounter)++;
</%cpp>
<a <%cpp> if (!id.empty()) { </%cpp>id="<$ id $>" <%cpp> } </%cpp><& hide_element hide=(isVisible ? 0 : 1) &> href="vdr_request/<$ action $>?param=<$ param $>" <%cpp>if (!tip.empty()) { </%cpp><& tooltip.hint label=(label) className=("click-action") breaksAtLeft=(breaksAtLeft) breaksAtRight=(breaksAtRight) text=(tip) &> <%cpp> } </%cpp>><img class="<$ className $>" src="<$ LiveSetup().GetThemedLink("img", image) $>" alt="<$ alt $>" /></a>
</%def>

<# ---------------------------------------------------------------------- #>

<%def imdb_info_href>
<%args>
  std::string title;
  std::string s_IMDB_ID;
  std::string className;
  std::string label;
  std::string breaksAtLeft;
  std::string breaksAtRight;
  uintptr_t iCounter = 0;
</%args>
<%cpp>
// generation of IMDb link to be checked here, otherwise inconsistent
if (LiveSetup().GetShowIMDb())
{
  int *pCounter = static_cast<int *>((void *)iCounter);
  if (pCounter) (*pCounter)++;
  if (s_IMDB_ID.empty() ) { </%cpp>
<a href="http://www.imdb.com/find?s=all&q=<$ (!title.empty() && title[0] == '%')?cToSvUrlEscaped(cSv(title).substr(1)):cToSvUrlEscaped(title) $>"
<%cpp> } else { </%cpp>
<a href="http://www.imdb.com/title/<$ s_IMDB_ID $>"
<%cpp> } </%cpp>
 target="_blank"><img class="<$ className $>" src="<$ LiveSetup().GetThemedLink("img", "imdb.png") $>" alt="" <& tooltip.hint label=(label) className=("click-action") breaksAtLeft=(breaksAtLeft) breaksAtRight=(breaksAtRight) text=(tr("Find more in the IMDb (Internet Movie Database)")) &> /></a>
<%cpp>
}
</%cpp>
</%def>

<# ---------------------------------------------------------------------- #>

<%def hls_channel>
<%args>
  std::string channelId;
  std::string className;
  std::string label;
  std::string breaksAtLeft;
  std::string breaksAtRight;
  uintptr_t iCounter = 0;
</%args>
<%cpp>
if (LiveSetup().GetUseStreamdev() && LiveFeatures<features::streamdev_server>().Loaded()) {
  int *pCounter = static_cast<int *>((void *)iCounter);
  if (pCounter) (*pCounter)++;
</%cpp>
<a href="stream.html?channelid=<$ channelId $>"><img class="<$ className $>" src="<$ LiveSetup().GetThemedLink("img", "stream_button.png") $>" alt="" <& tooltip.hint label=(label) className=("click-action") breaksAtLeft=(breaksAtLeft) breaksAtRight=(breaksAtRight) text=(tr("Play this channel in the browser")) &> /></a>
<%cpp>
}
</%cpp>
</%def>

<# ---------------------------------------------------------------------- #>

<%def hls_recording>
<%args>
  std::string recId;
  std::string className;
  std::string label;
  std::string breaksAtLeft;
  std::string breaksAtRight;
  uintptr_t iCounter = 0;
</%args>
<%cpp>
if (LiveSetup().GetUseStreamdev() && LiveFeatures<features::streamdev_server>().Loaded()) {
  int *pCounter = static_cast<int *>((void *)iCounter);
  if (pCounter) (*pCounter)++;
</%cpp>
<a href="stream.html?recid=<$ recId $>"><img class="<$ className $>" src="<$ LiveSetup().GetThemedLink("img", "stream_button.png") $>" alt="" <& tooltip.hint label=(label) className=("click-action") breaksAtLeft=(breaksAtLeft) breaksAtRight=(breaksAtRight) text=(tr("Play this recording in the browser")) &> /></a>
<%cpp>
}
</%cpp>
</%def>

<# ---------------------------------------------------------------------- #>

<%def m3u_playlist_channel>
<%args>
  std::string channelId;
  std::string className;
  std::string label;
  std::string breaksAtLeft;
  std::string breaksAtRight;
  uintptr_t iCounter = 0;
</%args>
<%cpp>
if (LiveFeatures<features::streamdev_server>().Loaded()) {
  int *pCounter = static_cast<int *>((void *)iCounter);
  if (pCounter) (*pCounter)++;
</%cpp>
<a href="playlist.m3u?channelid=<$ channelId $>" download><img class="<$ className $>" src="<$ LiveSetup().GetThemedLink("img", "playlist.png") $>" alt="" <& tooltip.hint label=(label) className=("click-action") breaksAtLeft=(breaksAtLeft) breaksAtRight=(breaksAtRight) text=(tr("Play this channel in the media player")) &> /></a>
<%cpp>
}
</%cpp>
</%def>

<# ---------------------------------------------------------------------- #>

<%def m3u_playlist_recording>
<%args>
  std::string recid;
  std::string linkText;
  std::string className;
  std::string label;
  std::string breaksAtLeft;
  std::string breaksAtRight;
  uintptr_t iCounter = 0;
</%args>
<%cpp>
#if TNT_WATCHDOG_SILENCE
// <a href="intent://my.example.com:8080/test.mp4#Intent;scheme=http;package=org.videolan.vlc;end">OPEN IN VLC</a>

// std::string server = request.getHost();
// server = server.substr(0, server.rfind(':'));
// cToSvConcat url("intent://", server, ":", LiveSetup().GetServerPort(), "/recstream.html?recid=", recid, "#Intent;scheme=http;package=org.videolan.vlc;end");

int *pCounter = static_cast<int *>((void *)iCounter);
if (pCounter) (*pCounter)++;

cToSvConcat url("playlist.m3u?recid=", recid);
{
</%cpp><a href="<$ url $>" download><img class="<$ className $>" src="<$ LiveSetup().GetThemedLink("img", "playlist.png") $>" alt="" <& tooltip.hint label=(label) className=("click-action") breaksAtLeft=(breaksAtLeft) breaksAtRight=(breaksAtRight) text=(tr("Play this recording in the media player")) &> /> <$ linkText $></a>
<%cpp>
}
#endif
</%cpp>
</%def>

<# ---------------------------------------------------------------------- #>
<# stream_recording: marked for deletion #>

<%def stream_recording>
<%args>
  std::string recid;
  std::string linkText;
  std::string className;
  std::string label;
  std::string breaksAtLeft;
  std::string breaksAtRight;
  uintptr_t iCounter = 0;
</%args>
<%cpp>
#if TNT_WATCHDOG_SILENCE
cToSvConcat rfid;
{
  const cRecording* recording = nullptr;
  LOCK_RECORDINGS_READ
  if (!recid.empty()) recording = RecordingsManager::GetByHash(recid, Recordings);
  if (recording) {
    struct stat st;
    if (stat(recording->FileName(), &st) == 0)
      rfid.appendFormatted("%lu:%llu.rec", (unsigned long) st.st_dev, (unsigned long long) st.st_ino);
  }
}
if (!rfid.empty() ) {
  int *pCounter = static_cast<int *>((void *)iCounter);
  if (pCounter) (*pCounter)++;
</%cpp><a href="http://localhost:<$cToSvConcat(LiveSetup().GetStreamdevPort())$>/<$rfid$>.ts"><img class="<$ className $>" src="<$ LiveSetup().GetThemedLink("img", "playlist.png") $>" alt="" <& tooltip.hint label=(label) className=("click-action") breaksAtLeft=(breaksAtLeft) breaksAtRight=(breaksAtRight) text=(tr("Stream this recording")) &> /> <$ linkText $></a>
<%cpp>
}
#endif
</%cpp>
</%def>

<# ---------------------------------------------------------------------- #>

<%def event_timer>
<%args>
  std::string epgid;
  std::string className;
  uintptr_t iCounter = 0;
</%args>
<%cpp>
  constexpr auto fileNameBreaks = "~";
  tChannelID channelid;
  tEventID eventid;
  EpgEvents::DecodeDomId(epgid, channelid, eventid);
  std::string timerId;
  bool timerRecording = false;
  bool timerActive = true;
  {
    LOCK_TIMERS_READ;
    const cTimer* timer = TimerManager::GetTimer(eventid, channelid, Timers);
    if (timer) {
      timerId = SortedTimers::GetTimerId(*timer);
      timerRecording = timer->Recording();
      timerActive = timer->Flags() & tfActive;
    }
  }
  cToSvConcat label;
  {
    LOCK_SCHEDULES_READ;
    const cEvent* event = EpgEvents::GetEventByEpgId(epgid, Schedules);
    if (event) label.appendDateTime(tr("%I:%M %p"), event->StartTime()).append(tr(" - ")).append(event->Title());
  }
  if (!timerId.empty() ) {
</%cpp>
    <& pageelems.edit_timer timerId=(timerId) imgName=(timerRecording || timerActive? "record_timer_active.png" : "record_timer_inactive.png") className=(timerRecording ? "icon fading" : "icon") label=(label) breaksAtRight=(fileNameBreaks) iCounter=(iCounter) &>
<%cpp>
  } else {
    int *pCounter = static_cast<int *>((void *)iCounter);
    if (pCounter) (*pCounter)++;
</%cpp>
    <a href="edit_timer.html?epgid=<$ epgid $>"><img class="<$ className $>" src="<$ LiveSetup().GetThemedLink("img", "record.png") $>" alt="" <& tooltip.hint text=(tr("Record this")) label=(label) className=("click-action") &> /></a>
<%cpp>
  }
</%cpp>
</%def>

<# ---------------------------------------------------------------------- #>

<%def edit_timer>
<%args>
  std::string timerId;
  std::string imgName = "edit.png";
  std::string label;
  std::string className;
  std::string breaksAtLeft;
  std::string breaksAtRight;
  uintptr_t iCounter = 0;
</%args>
<%cpp>
  int *pCounter = static_cast<int *>((void *)iCounter);
  if (pCounter) (*pCounter)++;
</%cpp>
  <a href="edit_timer.html?timerid=<$ SortedTimers::EncodeDomId(timerId) $>"><img class="<$ className $>" src="<$ LiveSetup().GetThemedLink("img", imgName) $>" alt="" <& tooltip.hint label=(label) className=("click-action") breaksAtLeft=(breaksAtLeft) breaksAtRight=(breaksAtRight) text=(tr("Edit timer")) &> /></a>
</%def>


<# ---------------------------------------------------------------------- #>

<%def ajax_js>
  <script type="text/javascript" src="js/mootools/mootools.v1.11.js"></script>
  <script type="text/javascript" src="js/live/liveajax.js"></script>
  <script type="text/javascript" src="js/live/infowin.js"></script>
  <script type="text/javascript" src="js/live/hinttips.js"></script>
  <script type="text/javascript" src="js/live/browserwin.js"></script>
  <script type="text/javascript" src="js/live/pageenhance.js"></script>
  <script type="text/javascript"><!--
    var liveEnhanced = new PageEnhance({
        infoWinOptions: {
          resizeImg: '<$ LiveSetup().GetThemedLink("img", "resize.png") $>',
          closeImg: '<$ LiveSetup().GetThemedLink("img", "icon_overlay_cross.png") $>',
          pinImg: '<$ LiveSetup().GetThemedLink("img", "icon_overlay_pin.png") $>',
          pinnedImg: '<$ LiveSetup().GetThemedLink("img", "icon_overlay_pinned.png") $>',
          loadingMsg: '<$ tr("Loading data ...") $>',
          errorMsg: '<$ tr("An error occurred!") $>'
        },
        notifyStrings: {
          successMsg: '<img src="<$ LiveSetup().GetThemedLink("img", "active.png") $>" alt=""> <$ tr("Request succeeded") $>',
          errorMsg: '<img src="<$ LiveSetup().GetThemedLink("img", "del.png") $>" alt=""> <$ tr("Request failed!") $>'
        }
      });
  --></script>
<%cpp>
    if (LiveSetup().GetShowInfoBox()) {
</%cpp>
  <script type="text/javascript" src="js/live/vdr_status.js"></script>
  <script type="text/javascript"><!--
    var InfoBox = new LiveVdrInfo('ibox.xml', 'infobox');
    window.addEvent('domready', function(){
      InfoBox.request(<%cpp> if (update_status) { reply.sout() << "true"; } else { reply.sout() << "false"; } </%cpp>);
    });
    window.addEvent('unload', function(){
      InfoBox.pageFinished();
    });
  --></script>
<%cpp>
    }
</%cpp>
</%def>

<# ---------------------------------------------------------------------- #>

<%def infobox>
<div id="infobox">
  <div class="statuscontent">
    <div class="st_header">
      <div id="infobox_caption" class="caption"><$ tr("Retrieving status ...") $></div>
      <div id="infobox_timenow" class="now">--:--</div>
    </div>
    <div class="st_content">
      <div id="infobox_name" class="name"></div>
      <div id="infobox_duration" class="duration">--:--</div>
    </div>
    <div class="st_controls">
      <div class="st_update">
        <a href="javascript:InfoBox.toggleUpdate()" <& tooltip.hint text=(tr("Toggle updates on/off")) &>><img id="statusReloadBtn" src="<$ LiveSetup().GetThemedLink("img", "stop_update.png") $>" alt="" /></a>
      </div>
      <div id="infobox_recording_buttons" style="display: none">
        <& ajax_action_href action=("stop_recording") id=("infobox_stop") image=("stop.png") tip=(tr("Stop playback")) &>
        <& ajax_action_href action=("play_recording") id=("infobox_play") image=("play.png") tip=(tr("Resume playback")) &>
        <& ajax_action_href action=("pause_recording") id=("infobox_pause") image=("pause.png") tip=(tr("Pause playback")) &>
        <& ajax_action_href action=("rwd_recording") id=("infobox_rwd") image=("rwd.png") tip=(tr("Fast rewind")) &>
        <& ajax_action_href action=("ffw_recording") id=("infobox_ffw") image=("ffw.png") tip=(tr("Fast forward")) &>
      </div>
      <div id="infobox_channel_buttons">
        <& ajax_action_href action=("switch_channel") id=("infobox_prevchan") image=("one_downarrow.png") tip=(tr("Previous channel")) &>
        <& ajax_action_href action=("switch_channel") id=("infobox_nextchan") image=("one_uparrow.png") tip=(tr("Next channel")) &>
      </div>
      <div class="st_pbar">
        <& progressbar id=("infobox_elapsed") &>
      </div>
    </div>
  </div>
  <div style="display: none;">
    <span id="__infobox_request_err"><$ tr("No server response!") $></span>
    <span id="__infobox_update_err"><$ tr("Failed to update infobox!") $></span>
  </div>
</div>
</%def>

<# ---------------------------------------------------------------------- #>

<%def epg_tool_box>
<%args>
  int detail;           // 0 = event table, 1 = event infowin, 2 = recording infowin
  std::string epgid;
  std::string title;
  time_t startTime;
  time_t endTime;
  int lastCurrentChanel = int();
  std::string s_IMDB_ID;
</%args>
<%cpp>
  int duration = EpgEvents::Duration(startTime, endTime);
  int elapsed = EpgEvents::ElapsedTime(startTime, endTime);
  tEventID eventId = tEventID();
  tChannelID channelId = tChannelID();
  int xsVisibleIcons = 0;
  int xsInvisibleIcons = 0;

  // using a flexbox, we do not have to differentiate between horizontal and vertical display;
  // for insertion in tables (detail == 0), we need to provide spacers for actions items being
  // temporarily unavailable, like actions for transient events
  EpgEvents::DecodeDomId(epgid, channelId, eventId);
  cToSvDateTime label(tr("%I:%M %p"), startTime);
  label.append(tr(" - ")).append(title);
</%cpp>
  <div><& pageelems.event_timer epgid=(epgid) className="icon" iCounter=((uintptr_t)&xsVisibleIcons) &></div>
% if (cDevice::PrimaryDevice() && cDevice::PrimaryDevice()->HasDecoder() ) {
    <div><& pageelems.ajax_action_href action="switch_channel" tip=(tr("Switch to this channel")) param=(channelId) image="zap.png" className="icon" label=(label) alt="" iCounter=((uintptr_t)&xsVisibleIcons) &></div>
% } if (LiveFeatures<features::epgsearch>().Recent()) {
%     if (eventId != 0) {
%       xsVisibleIcons++;
  <div><a href="searchresults.html?searchplain=<$$ cToSvUrlEscaped(title) $>"><img class="icon" src="<$ LiveSetup().GetThemedLink("img", "search.png") $>" alt="" <& tooltip.hint text=(tr("Search for repeats")) label=(label) className=("click-action") &> /></a></div>
%     } else if (!detail) {
  <# as we wrap on small screens and tabulation becomes void, we just hide a transparent icon #>
  <div class="hidden-xs spacer"><img class="icon" src="img/transparent.png" alt="" /></div>
%     }
% } if ((duration == 0) || (elapsed >= 0)) {
  <div class="hidden-xs invisible"><& pageelems.hls_channel channelId=(channelId) className="icon" label=(label) iCounter=((uintptr_t)&xsInvisibleIcons) &></div>
  <div class="hidden-xs invisible"><& pageelems.m3u_playlist_channel channelId=(channelId) className="icon" label=(label) iCounter=((uintptr_t)&xsInvisibleIcons) &></div>
%  } else if (!detail) {
  <# as we wrap on small screens and tabulation becomes void, we just hide a transparent icon #>
  <div class="hidden-xs"><img class="icon" src="img/transparent.png" alt="" /></div>
  <div class="hidden-xs"><img class="icon" src="img/transparent.png" alt="" /></div>
% } if (!title.empty()) {
  <div><& pageelems.imdb_info_href title=(title) s_IMDB_ID=(s_IMDB_ID) className="icon" label=(label) iCounter=((uintptr_t)&xsVisibleIcons) &></div>
% } else if (!detail ) {
  <div class="hidden-xs"><img class="icon" src="img/transparent.png" alt="" /></div>
<%cpp>
  } if (!detail) {
</%cpp>
  <# just for indicating that we need 2 columns (for more than 3 icons) on small screens #>
  <div class="notpresent xs-visible-<$ xsVisibleIcons $> xs-invisible-<$ xsInvisibleIcons $> xs-columns-<$ (xsVisibleIcons  + 2) / 3 $>"></div>
<%cpp>
  }
  if (eventId != 0 && detail > 1) {
    const char *sdhd = nullptr;
    std::string channel_Name;
    {
      LOCK_CHANNELS_READ;
      LOCK_SCHEDULES_READ;
      const cEvent* event;
      const cChannel* channel;
      EpgEvents::GetEventChannelByEpgId(event, channel, epgid, Channels, Schedules);
      cGetScraperVideo getScraperVideo(event, nullptr);
      bool scraperDataAvailable = getScraperVideo.call(LiveSetup().GetPluginTvscraper());
      if (scraperDataAvailable) {
        int video_SD_HD = getScraperVideo.m_scraperVideo->getHD();
        sdhd = video_SD_HD == 0 ? "sd": video_SD_HD == 1 ? "hd": video_SD_HD == 2 ? "ud" : nullptr;
        if (channel) channel_Name = cSv(channel->Name());
      }
    }
    if (sdhd) {
</%cpp>
<div id="icons-<$epgid$>" class="event_status"></div>
<script class="injectIcons">
injectHdSdIcon(\"icons-<$epgid$>\", \"<$sdhd$>\", \"<$ channel_Name $>\", \"\")
</script>
%} }
</%def>

<# ---------------------------------------------------------------------- #>

<%def epg_tt_box>
<%args>
  std::string boxId;
  std::string caption;
  std::string tools_comp;
  std::string time;
  std::string channel;
  std::string title;
  std::string short_descr;
  std::string long_descr;
  std::string filename;
  std::string archived;
  std::string epgImage;
  uintptr_t iepgEvent;
  int elapsed = -1;
  std::string sort;
  std::string filter;
  std::string flat;
  int history_num_back = 0;
</%args>
  <div class="epg_description" id="<$ (boxId) $>">
    <div class="station">
      <div class="boxheader">
<%cpp>
struct sEpisode2 {
    int number;
    int season;
    int absoluteNumber;
    std::string name;
    std::string firstAired;
    int runtime;
    std::string overview;
    float vote_average;
    int vote_count;
    cTvMedia episodeImage;
    std::string IMDB_ID;
};
struct sScraperMovieOrTv {
    bool found;
    bool movie;
    std::string title;
    std::string originalTitle;
    std::string tagline;
    std::string overview;
    std::vector<std::string> genres;
    std::string homepage;
    std::string releaseDate;  // for TV shows: firstAired
    bool adult;
    int runtime;
    float popularity;
    float voteAverage;
    int voteCount;
    std::vector<std::string> productionCountries;
    std::string IMDB_ID;
    std::vector<cTvMedia> posters;
    std::vector<cTvMedia> banners;
    std::vector<cTvMedia> fanarts;
// only for movies
    int budget;
    int revenue;
    int collectionId;
    std::string collectionName;
// only for TV Shows
    std::string status;
    std::vector<std::string> networks;
    int lastSeason;
// episode related
    bool episodeFound;
    cTvMedia seasonPoster;
    sEpisode2 episode;
};

EpgInfoPtr epgEvent = iepgEvent?static_cast<EpgInfo*>((void *)iepgEvent):nullptr;
sScraperMovieOrTv scraperMovieOrTv;
scraperMovieOrTv.found = false;

if (epgEvent && epgEvent->ScraperVideoAvailable()) {
  scraperMovieOrTv.found = true;
  tvType type = epgEvent->GetScraperVideo()->getVideoType();
//  esyslog("live: type = %i", (int)type);
  if (type == tMovie) scraperMovieOrTv.movie = true;
  else {
    if (type == tSeries) scraperMovieOrTv.movie = false;
    else scraperMovieOrTv.found = false;
  }
}
if (scraperMovieOrTv.found) {
  scraperMovieOrTv.found = epgEvent->GetScraperVideo()->getMovieOrTv(&scraperMovieOrTv.title, &scraperMovieOrTv.originalTitle, &scraperMovieOrTv.tagline, &scraperMovieOrTv.overview, &scraperMovieOrTv.genres, &scraperMovieOrTv.homepage, &scraperMovieOrTv.releaseDate, &scraperMovieOrTv.adult, &scraperMovieOrTv.runtime, &scraperMovieOrTv.popularity, &scraperMovieOrTv.voteAverage, &scraperMovieOrTv.voteCount, &scraperMovieOrTv.productionCountries, &scraperMovieOrTv.IMDB_ID, &scraperMovieOrTv.budget, &scraperMovieOrTv.revenue, &scraperMovieOrTv.collectionId, &scraperMovieOrTv.collectionName, &scraperMovieOrTv.status, &scraperMovieOrTv.networks, &scraperMovieOrTv.lastSeason);
}

std::vector<std::unique_ptr<cCharacter>> scraperCharacters;
if (scraperMovieOrTv.found) {
  scraperCharacters = epgEvent->GetScraperVideo()->getCharacters(false);
  scraperMovieOrTv.posters = epgEvent->GetScraperVideo()->getImages(eOrientation::portrait, 3, false);
  scraperMovieOrTv.banners = epgEvent->GetScraperVideo()->getImages(eOrientation::banner, 3, false);
  scraperMovieOrTv.fanarts = epgEvent->GetScraperVideo()->getImages(eOrientation::landscape, 3, false);
  scraperMovieOrTv.episodeFound = epgEvent->GetScraperVideo()->getEpisode(&scraperMovieOrTv.episode.name, &scraperMovieOrTv.episode.overview, &scraperMovieOrTv.episode.absoluteNumber, &scraperMovieOrTv.episode.firstAired, &scraperMovieOrTv.episode.runtime, &scraperMovieOrTv.episode.vote_average, &scraperMovieOrTv.episode.vote_count, &scraperMovieOrTv.episode.IMDB_ID);
  if (scraperMovieOrTv.episodeFound) {
    scraperMovieOrTv.episode.number = epgEvent->GetScraperVideo()->getEpisodeNumber();
    scraperMovieOrTv.episode.season = epgEvent->GetScraperVideo()->getSeasonNumber();
    scraperMovieOrTv.episode.episodeImage = epgEvent->GetScraperVideo()->getImage(cImageLevels(eImageLevel::episodeMovie), cOrientations(eOrientation::landscape), false);
    scraperMovieOrTv.seasonPoster = epgEvent->GetScraperVideo()->getImage(cImageLevels(eImageLevel::seasonMovie), cOrientations(eOrientation::portrait), false);
  }
}

const bool episodeFound = scraperMovieOrTv.found && (!scraperMovieOrTv.movie) && scraperMovieOrTv.episodeFound;
if (scraperMovieOrTv.found) {
//  esyslog("live: create caption menu");
</%cpp>
        <div class = "caption">
          <a id="<$ boxId $>_epg_m"     class = "active"   onclick="displayEPG('<$ boxId $>')" ><$ trVDR("EPG") $></a>
          <span class="sep">|</span>
          <a id="<$ boxId $>_scraper_m" class = "inactive" onclick="displayScraper('<$ boxId $>')"><$ tr("Scraper") $></a>
          <span class="sep">|</span>
          <a id="<$ boxId $>_actors_m"  class = "inactive" onclick="displayActors('<$ boxId $>')" ><$ tr("Actors") $></a>
          <span class="sep">|</span>
          <a id="<$ boxId $>_artwork_m" class = "inactive" onclick="displayArtwork('<$ boxId $>')" ><$ tr("Artwork") $></a>
        </div>
<%cpp>
} else {
</%cpp>
        <div class="caption"><$ (caption) $></div>
<%cpp>
}
</%cpp>
      </div>
    </div>
%   size_t endEventType = boxId.find_first_of('_');
    <div class="epg_content epg_<$ endEventType != std::string::npos ? boxId.substr(0, endEventType) : "unknown" $>">
      <div class="epg_tools">
        <div class="tools">
          <& (tools_comp) id=(boxId) archived=(archived) detail=(2) title=(title) s_IMDB_ID=(scraperMovieOrTv.IMDB_ID) sort=(sort) filter=(filter) flat=(flat) history_num_back=(history_num_back) &>
        </div>
      </div>
      <div class="epg_info">
        <div class="info">
          <div class="spacebar"><# spacer with fade-out effect #></div>
          <div class="event_details">
            <div class="time_channel">
              <div class="time">
%               if (!archived.empty()) {
                  <span class="bold"><$ (archived + " ") $></span>
%               }
                <$ (time) $>
              </div>
%             if (!filename.empty() && !channel.empty()) {
                <div class="channel"><$ (channel) $></div>
%             }
            </div>
            <div class="duration">
<%cpp>
if (epgEvent && epgEvent->isRecording() ) {  // recording
</%cpp>
              <span title="<$tr("Recording length")$>"><$ FormatDuration(tr("%d:%02d"), epgEvent->Duration())$></span> / <span title="<$tr("Event duration")$>"><$FormatDuration(tr("%d:%02d"), epgEvent->EventDuration())$></span>
<%cpp>
}
if (elapsed >= 0) {
</%cpp>
              <div class="progress"><& pageelems.progressbar progress=(elapsed) &></div>
<%cpp>
}
</%cpp>
            </div>
          </div>
          <div class="title"><$ (title) $></div>
          <div class="short"><$ (short_descr) $></div>
          <div class="description" id=<$ boxId $>_description>
          <span id = "<$ boxId $>_epg_image" class="epg_images">
<%cpp>
  std::list<std::string> images = EpgEvents::EpgImages(boxId);
  for(std::list<std::string>::iterator it = images.begin(); it != images.end(); ++it ) {
</%cpp>
         <a href="/epgimages/<$ *it $>" target="_blank">
            <img src="/epgimages/<$ *it $>" class="epg_image"/>
         </a>
% } bool scraperImage = false;
% if(!epgImage.empty() ) { scraperImage = true;
    <a href="/tvscraper/<$ epgImage $>" target="_blank">
      <img src="/tvscraper/<$ epgImage $>" class="epg_image"/>
    </a>
% } if (episodeFound && !scraperMovieOrTv.episode.episodeImage.path.empty() ) { scraperImage = true;
    <a href="/tvscraper/<$ scraperMovieOrTv.episode.episodeImage.path $>" target="_blank">
      <img src="/tvscraper/<$ scraperMovieOrTv.episode.episodeImage.path $>" class="epg_image"/>
    </a>
<%cpp>
  }  // episodeFound && !scraperMovieOrTv.episode.episodeImage.path.empty()
  if (!scraperImage) {
    std::list<std::string> images1 = EpgEvents::RecImages(boxId, filename);
    size_t delimPos = boxId.find_last_of('_');
    std::string recId = (delimPos)?boxId.substr(delimPos+1):boxId;

    for(std::list<std::string>::iterator it = images1.begin(); it != images1.end(); ++it ) {
</%cpp>
      <a href="/recimages/<$ recId $>/<$ *it $>" target="_blank">
        <img src="/recimages/<$ recId $>/<$ *it $>" class="epg_image"/>
      </a>
<%cpp>
    }
  }
</%cpp>
          </span> <# id = "<$ boxId $>_epg_image" class="epg_images"  #>

<# -----------------  scraper data -----------------  #>
<div id = '<$ boxId $>_scraper' hidden>
<%cpp>
std::string loc_name;
getLanguage(loc_name, "LANGUAGE") ||
getLanguage(loc_name, "LC_ALL") ||
getLanguage(loc_name, "LC_MESSAGES") ||
getLanguage(loc_name, "LANG");
if (loc_name.empty() ) {
  loc_name = std::locale("").name().substr(0,2);
  if (loc_name.length() != 2 || loc_name[0] == 'C' || loc_name[0] == '*' || loc_name[0] == 'L') loc_name = "en"; //  use en as default
}

if (scraperMovieOrTv.found) {
</%cpp>
  <div class="scraper_list"><$ tr("Title:") $>         <$ (scraperMovieOrTv.title ) $></div>
<%cpp>
  if (!scraperMovieOrTv.originalTitle.empty() ) {
</%cpp>
  <div class="scraper_list"><$ tr("Original title:") $> <$ (scraperMovieOrTv.originalTitle ) $></div>
<%cpp>
  }
  if (episodeFound) {
</%cpp>
    <div class="scraper_list"><$ tr("Episode:") $> S<$ cSv(cToSvInt(scraperMovieOrTv.episode.season )) $>E<$ cSv(cToSvInt(scraperMovieOrTv.episode.number)) $><$scraperMovieOrTv.episode.absoluteNumber?concat("A", cToSvInt(scraperMovieOrTv.episode.absoluteNumber)):""$> <$ scraperMovieOrTv.episode.name $></div>
    <div class="scraper_list"><$ tr("Episode overview:") $>   <$ (scraperMovieOrTv.episode.overview ) $></div>
<%cpp>
    if (scraperMovieOrTv.episode.vote_average != 0 ) {
</%cpp>
      <div class="scraper_list"><$ tr("Episode vote average/count:") $> <$ (scraperMovieOrTv.episode.vote_average) $> / <$ (scraperMovieOrTv.episode.vote_count ) $></div>
<%cpp>
    }
</%cpp>
    <div class="scraper_list"><$ tr("Episode first aired:") $> <$ (scraperMovieOrTv.episode.firstAired ) $></div>
%   if (scraperMovieOrTv.episode.runtime > 0) {
      <div class="scraper_list"><$ tr("Episode runtime:") $> <$ FormatDuration(tr("%d:%02d"), scraperMovieOrTv.episode.runtime*60) $></div>
%   }
%   if (!scraperMovieOrTv.episode.IMDB_ID.empty() ) {
      <a href="https://www.imdb.com/title/<$ (scraperMovieOrTv.episode.IMDB_ID ) $>" target="_blank"> <$ tr("IMDb episode") $> </a>
<%cpp>
    }
    bool charFound = false;
    for (const auto &character:scraperCharacters)
      if (character->getType() == eCharacterType::guestStar ||
          character->getType() == eCharacterType::writer ||
          character->getType() == eCharacterType::director) { charFound = true; break; }
    if (charFound) {
</%cpp>
      <div class="scraper_list"><$ tr("Guest stars and crew") $></div>
      <div class="cast_crew tabular">
%   for (const auto &character:scraperCharacters) {
%     if (character->getType() != eCharacterType::guestStar) continue;
        <div class="cast_role"> <$ character->getCharacterName() $> </div>
        <div> <a href="https://<$ loc_name $>.wikipedia.org/wiki/<$ cToSvUrlEscaped(cToSvReplace(character->getPersonName(), " ", "_")) $>" target="_blank"><$ character->getPersonName() $></a> </div>
%   }
%   for (const auto &character:scraperCharacters) {
%     if (character->getType() != eCharacterType::writer) continue;
        <div class="cast_role"> <$ tr("Writer") $> </div>
        <div> <a href="https://<$ loc_name $>.wikipedia.org/wiki/<$ cToSvUrlEscaped(cToSvReplace(character->getPersonName(), " ", "_")) $>" target="_blank"><$ character->getPersonName() $></a> </div>
%   }
%   for (const auto &character:scraperCharacters) {
%     if (character->getType() != eCharacterType::director) continue;
        <div class="cast_role"> <$ tr("Director") $> </div>
        <div> <a href="https://<$ loc_name $>.wikipedia.org/wiki/<$ cToSvUrlEscaped(cToSvReplace(character->getPersonName(), " ", "_")) $>" target="_blank"><$ character->getPersonName() $></a> </div>
%   }
      </div>
<%cpp>
    }  // end if !episode.<Guest stars and crew>.empty()
  }  // end if episode found
  if (!scraperMovieOrTv.tagline.empty() ) {
</%cpp>
  <div class="scraper_list"><$ tr("Tagline:") $>        <$ (scraperMovieOrTv.tagline ) $></div>
% }
  <div class="scraper_list"><$ tr("Overview:") $>       <$ (scraperMovieOrTv.overview ) $></div>
  <div class="scraper_list"><$ tr("Genres:") $>         <$ toString(scraperMovieOrTv.genres ) $></div>
% if (!scraperMovieOrTv.homepage.empty() ) {
  <div class="scraper_list"><a href ="<$ (scraperMovieOrTv.homepage) $>" target="_blank"><$ tr("Homepage") $></a></div>
% }
  <div class="scraper_list"><$ tr("Release date:") $>   <$ (scraperMovieOrTv.releaseDate ) $></div>
% if (scraperMovieOrTv.runtime > 0) {
  <div class="scraper_list"><$ tr("Runtime:") $>        <$ FormatDuration(tr("%d:%02d"), scraperMovieOrTv.runtime*60) $></div>
% }
<%cpp>
  if (scraperMovieOrTv.popularity != 0) {
</%cpp>
  <div class="scraper_list"><$ tr("Popularity:") $>     <$ (scraperMovieOrTv.popularity ) $></div>
<%cpp>
  }
  if (scraperMovieOrTv.voteAverage  != 0) {
</%cpp>
  <div class="scraper_list"><$ tr("Vote average/count:") $> <$ (scraperMovieOrTv.voteAverage ) $> / <$ (scraperMovieOrTv.voteCount) $></div>
<%cpp>
  }
</%cpp>
<#
  <div class="scraper_list">Production Countries: <$ toString(scraperMovieOrTv.productionCountries) $></div>
#>
% if (!scraperMovieOrTv.IMDB_ID.empty() ) {
    <div class="scraper_list">
      <a href="https://www.imdb.com/title/<$ (scraperMovieOrTv.IMDB_ID ) $>" target="_blank" <& tooltip.hint text=(tr("Find more in the IMDb (Internet Movie Database)")) className="click-action" &>> <$ tr("IMDb") $> </a>
    </div>
% }
<#
  <div class="scraper_list">Poster URL:     <$ (scraperMovieOrTv.posterUrl ) $></div>
  <div class="scraper_list">Fanart URL:     <$ (scraperMovieOrTv.fanartUrl ) $></div>
#>
<%cpp>
  if (scraperMovieOrTv.movie) {
    if (scraperMovieOrTv.budget) {
</%cpp>
    <div class="scraper_list"><$ tr("Budget:") $>         <$ (scraperMovieOrTv.budget ) $></div>
<%cpp>
    }
    if (scraperMovieOrTv.revenue) {
</%cpp>
    <div class="scraper_list"><$ tr("Revenue:") $>        <$ (scraperMovieOrTv.revenue) $></div>
<%cpp>
    }
</%cpp>
<#
    <div class="scraper_list">collectionId:   <$ (scraperMovieOrTv.collectionId) $></div>
#>
<%cpp>
    if (!scraperMovieOrTv.collectionName.empty() ) {
</%cpp>
    <div class="scraper_list"><$ tr("Collection name:") $> <$ (scraperMovieOrTv.collectionName) $></div>
<%cpp>
    }
  } else {  // TV show
</%cpp>
    <# shouldn't we translate the status as well? #>
    <div class="scraper_list"><$ tr("Status:") $>         <$ (scraperMovieOrTv.status    ) $></div>
<#
    <div class="scraper_list">Networks:       <$ toString(scraperMovieOrTv.networks) $></div>
#>
<%cpp>
  }
  bool charFound = false;
  for (const auto &character:scraperCharacters)
    if (character->getType() == eCharacterType::actor) { charFound = true; break; }
  if (!charFound && scraperMovieOrTv.movie) {
    for (const auto &character:scraperCharacters)
      if (character->getType() == eCharacterType::writer ||
          character->getType() == eCharacterType::director) { charFound = true; break; }
  }
  if (charFound) {
</%cpp>
    <div class="scraper_list"><$ tr("Cast and crew") $></div>
    <div class="cast_crew tabular">
%   for (const auto &character:scraperCharacters) {
%     if (character->getType() != eCharacterType::actor) continue;
      <div class="cast_role"> <$ character->getCharacterName() $> </div>
      <div> <a href="https://<$ loc_name $>.wikipedia.org/wiki/<$ cToSvUrlEscaped(cToSvReplace(character->getPersonName(), " ", "_")) $>" target="_blank"><$ character->getPersonName() $></a>  </div>
%   }
%   if (scraperMovieOrTv.movie) {
%     for (const auto &character:scraperCharacters) {
%       if (character->getType() != eCharacterType::writer) continue;
        <div class="cast_role"> <$ tr("Writer") $> </div>
        <div> <a href="https://<$ loc_name $>.wikipedia.org/wiki/<$ cToSvUrlEscaped(cToSvReplace(character->getPersonName(), " ", "_")) $>" target="_blank"><$ character->getPersonName() $></a> </div>
%     }
%     for (const auto &character:scraperCharacters) {
%       if (character->getType() != eCharacterType::director) continue;
        <div class="cast_role"> <$ tr("Director") $> </div>
        <div> <a href="https://<$ loc_name $>.wikipedia.org/wiki/<$ cToSvUrlEscaped(cToSvReplace(character->getPersonName(), " ", "_")) $>" target="_blank"><$ character->getPersonName() $></a> </div>
%     }
%   }
    </div>
<%cpp>
  }
}
</%cpp>
</div>
<# -----------------  actors -----------------  #>
<div id="<$ boxId $>_actors" hidden>
<%cpp>
if (scraperMovieOrTv.found) {
</%cpp>
  <div class="event_actors">
<%cpp>
  for (const auto &character:scraperCharacters) {
    if (character->getImage().path.empty() ) continue;  // only actors with images
</%cpp>
    <div class="actor">
      <div class="actor_photo"><a href="/tvscraper/<$ character->getImage().path $>" target="_blank"><img class="photo" src="/tvscraper/<$ character->getImage().path $>" alt="<$ character->getPersonName() $>: <$ character->getCharacterName() $>" /></a></div>
      <div class="actor_name"><a href="https://<$ loc_name $>.wikipedia.org/wiki/<$ cToSvUrlEscaped(cToSvReplace(character->getPersonName(), " ", "_")) $>" target="_blank"><$ character->getPersonName() $></a></div>
      <div class="character"><$ character->getCharacterName() $></div>
    </div>
<%cpp>
  } // for character in scraperCharacters
</%cpp>
  </div>
<%cpp>
}
</%cpp>
</div>
<# -----------------  posters / artwork -----------------  #>
<div id="<$ boxId $>_artwork" hidden>
<%cpp>
  const uintptr_t media_p = (uintptr_t)&(scraperMovieOrTv.posters);
  const uintptr_t media_b = (uintptr_t)&(scraperMovieOrTv.banners);
  const uintptr_t media_f = (uintptr_t)&(scraperMovieOrTv.fanarts);
</%cpp>
<& media media_p=(media_p) &>
<& media media_p=(media_f) &>
<& media media_p=(media_b) &>
</div>
<# -----------------  epg -----------------  #>
<div id="<$ boxId $>_epg">
<%cpp>
if (!long_descr.empty()) {
  cToSvConcat long_descr_html_esc = "<p>";
  AppendHtmlEscapedAndCorrectNonUTF8(long_descr_html_esc, long_descr, "</p><p>");
  long_descr_html_esc.append("</p>");
  reply.out() << long_descr_html_esc;
}

if (epgEvent) {
  bool empty = true;
  cToSvConcat supplemental_info;
  for (int i = 0; epgEvent->Contents(i); i++) {
    const char *s = cEvent::ContentToString(epgEvent->Contents(i));
    if (!isempty(s)) {
      if (empty) {
        supplemental_info.concat(tr("Content"), ": ");
        empty = false;
      } else {
        supplemental_info.append(", ");
      }
      supplemental_info.append(s);
    }
  }
  if (epgEvent->ParentalRating()) {
    if (!empty) {
      supplemental_info.append("\n");
    }
    supplemental_info.concat(tr("Parental rating"), ": ");
    supplemental_info.appendFormatted(trVDR("ParentalRating$from %d"), epgEvent->ParentalRating());
    empty = false;
  }
  if (!empty) {
    cToSvConcat supplemental_info_html_esc = "<p class=\"epg_event_info\">";
    AppendHtmlEscapedAndCorrectNonUTF8(supplemental_info_html_esc, supplemental_info);
    supplemental_info_html_esc.append("</p>");
    reply.out() << supplemental_info_html_esc;
  }
}
</%cpp>
        </div>
      </div>
      <div class="spacebar"><# spacer with fade-out effect #></div></div>
    </div>
  </div>
</div>
</%def>

<# ------------  display std::vector<cTvMedia> #>
<%def media>
<%args>
        uintptr_t media_p;
</%args>
<%cpp>
const std::vector<cTvMedia> *media_v = static_cast<std::vector<cTvMedia> *>((void *)media_p);
for (const cTvMedia &media: *media_v) {
</%cpp>
  <a class="artwork" href="/tvscraper/<$ media.path $>" target="_blank">
    <img class="artwork" src="/tvscraper/<$ media.path $>" />
  </a>
<%cpp>
}
</%cpp>
</%def>

<# ---------------------------------------------------------------------- #>

<%def about_tt_box>
  <div class="epg_description" id="aboutBox">
    <div class="station">
      <div class="boxheader"><div class="caption"><$ tr(LIVESUMMARY) $></div></div>
    </div>
    <div class="epg_content"><div class="about_content">
      <div class="about_head"><$ tr("Authors") $></div>
      <div class="about_section">
        <div class="tabular">
          <div class="about_left"><$ tr("Project Idea") $>:</div>
          <div class="about_right">Thomas Keil (Thomas)</div>
          <div class="about_left"><$ tr("Webserver") $>:</div>
          <div class="about_right">Sascha Volkenandt (LordJaxom)</div>
          <div class="about_left"><$ tr("Current Maintainer") $>:</div>
          <div class="about_right">Markus Ehrnsperger (MarkusE @ <a href="https://www.vdr-portal.de">VDR Portal</a>)</div>
          <div class="about_left"><$ tr("Previous Maintainer") $>:</div>
          <div class="about_right">Jasmin Jessich (jasminj)</div>
          <div class="about_left"><$ tr("Project leader") $>:</div>
          <div class="about_right">Dieter Hametner (tadi)</div>
          <div class="about_left"><$ tr("Content") $>:</div>
          <div class="about_right">Christian Wieninger (winni)</div>
          <div class="about_left"><$ tr("Graphics") $>:</div>
          <div class="about_right">Michael Br&uuml;ckner (skiller2k1)</div>
        </div>
      </div>
      <div class="about_head"><$ tr("Information") $></div>
      <div class="about_section">
        <div class="tabular">
          <div class="about_left"><$ tr("LIVE version") $>:</div>
          <div class="about_right"><$ LIVEVERSION $><$ VERSION_SUFFIX $></div>
          <div class="about_left"><$ tr("VDR version") $>:</div>
          <div class="about_right"><$ VDRVERSION $></div>
        </div>
      </div>
      <div class="about_head"><$ tr("Features") $></div>
      <div class="about_section">
        <div class="tabular">
          <div class="about_left">EPGsearch:</div>
          <div class="about_right">
%            Features< features::epgsearch >& epgsearch = LiveFeatures< features::epgsearch >();
            <img src="<$ LiveSetup().GetThemedLink("img", epgsearch.Recent() ? "active.png" : "inactive.png") $>"/>
%            if ( epgsearch.Recent() ) {
              <$ tr("active") $>: <$ epgsearch.Version() $>
%            } else {
              <$ tr("required") $>: <$ epgsearch.MinVersion() $>
%            }
            (<a href="https://github.com/vdr-projects/vdr-plugin-epgsearch" target="_blank"><$ tr("Homepage") $></a>)<br/>
          </div>
          <div class="about_left">StreamDev server:</div>
          <div class="about_right">
<%cpp>
            Features< features::streamdev_server >& streamdev = LiveFeatures< features::streamdev_server >();
</%cpp>
            <img src="<$ LiveSetup().GetThemedLink("img", streamdev.Loaded() ? "active.png" : "inactive.png") $>"/>
<%cpp>
            if ( streamdev.Loaded() ) {
</%cpp>
              <$ tr("active") $>: <$ streamdev.Version() $>
<%cpp>
            } else {
</%cpp>
              <$ tr("required") $>: <$ streamdev.MinVersion() $>
<%cpp>
            }
</%cpp>
            (<a href="https://github.com/vdr-projects/vdr-plugin-streamdev" target="_blank"><$ tr("Homepage") $></a>)<br/>
          </div>
          <div class="about_left">TvScraper:</div>
          <div class="about_right">
%            Features< features::tvscraper >& tvscraper = LiveFeatures< features::tvscraper >();
            <img src="<$ LiveSetup().GetThemedLink("img", tvscraper.Recent() ? "active.png" : "inactive.png") $>"/>
%            if ( tvscraper.Recent() ) {
              <$ tr("active") $>: <$ tvscraper.Version() $>
%            } else {
              <$ tr("required") $>: <$ tvscraper.MinVersion() $>
%            }
            (<a href="https://github.com/MarkusEh/vdr-plugin-tvscraper" target="_blank"><$ tr("Homepage") $></a>)<br/>
          </div>
        </div>
      </div>
      <div class="about_head"><$ tr("Information providers") $></div>
      <div class="about_section">
        <div class="about_line">Movie information provided by <a target="_blank" href="https://www.themoviedb.org/">TMDB</a>. This product uses the TMDB API but is not endorsed or certified by TMDB.</div>
        <div class="about_line">Information provided by TheTVDB.com. Please consider <a target="_blank" href="https://u10505776.ct.sendgrid.net/ls/click?upn=xMYYCP13hVd-2BZPpbVcMPHeLXfv-2BPRdIsKm2qSeirIHi7kH9am8IxD-2BavFbeqGqIXIcjH_INgc0CXRkIvGU-2BJ1W6HLAynNbR0UBoMb2tkpDdezO3QRj-2FQPQAMrtJKVcB0N7eSvbYpjQTDNOQBf2pb94uDgGr0-2BXyXFk7Oyfva30BASYCRLvtRQyi5eOCAbH8fon7UETlPydobeLA3Recu9OsXol8c7Ng4pDAsH6KsFF8CH7HQoVxivnpKrQW2v4ek7U-2BYlWmH31o9Koke3vq-2FDsQ0P-2BiKLECU3LgttsntUcN8fnUs-3D">supporting them.</a></div>
      </div>
      <div class="about_head"><$ tr("Bugs and suggestions") $></div>
      <div class="about_section">
        <div class="about_line"><$ tr("If you encounter any bugs or would like to suggest new features, please use our bugtracker") $>:<br/>
          <a target="_blank" href="https://github.com/MarkusEh/vdr-plugin-live/issues">https://github.com/MarkusEh/vdr-plugin-live/issues</a></div>
      </div>
    </div></div>
  </div>
</%def>
