<%pre>

#include <string>
#include <setup.h>
#include <tools.h>
#include <users.h>
#include <recman.h>
#include <tntconfig.h>
#include <vdr/channels.h>
#include <stringhelpers.h>
#include <livefeatures.h>

#include <vdr/videodir.h>

#define MB_PER_MINUTE 25.75 // this is just an estimate!

using namespace vdrlive;

</%pre>
<%args>
  std::string sort;
  std::string todel;
  std::string diskinfo;
  std::string filter;
  std::string deletions[];
  std::string flat;
  int history_num_back = 0;
</%args>
<%session scope="global">
  bool logged_in(false);
</%session>

<# scope="page" should be enough but does not work with tntnet 3.0 #>
<%request scope="global">
  std::string currentSort;
  std::string deleteResult;
  std::string currentFilter;
  std::string currentFlat;
</%request>

<%include>page_init.eh</%include>
<%cpp>
std::chrono::time_point<std::chrono::high_resolution_clock> timeStart = std::chrono::high_resolution_clock::now();

reply.setHeader (tnt::httpheader::cacheControl, "no-store, no-cache, max-age=0, must-revalidate, proxy-revalidate", true);
if (!logged_in && LiveSetup().UseAuth()) {
  cToSvConcat<0> targetUrl = "/login.html?redirect=";
  targetUrl.appendUrlEscaped(request.getQuery());
  return reply.redirect(targetUrl.data());
}

if (request.getMethod() != "POST") history_num_back = 0;  // we can go back in history to this page
else ++history_num_back;  // we have to go back in history to a prev page, to avoid re-send of form data

// create the "current" values of the global request parameters, based on their old values and the current arguments
// basically, this is a bad idea. Pushing "refresh" changes the sort order :( .
// Better: Urls on menue have parameters depending on the current sort option
if (! flat.empty() ) currentFlat = flat;
// sort depends on old sort, and sort parameter
currentSort = LiveSetup().GetLastSortingMode();
if (currentSort.empty() ) currentFlat == "true"?currentSort = "errorsts":currentSort = "datedesc";
if (!sort.empty()) {
  if (sort == "date")
    currentSort = (currentSort == "datedesc") ? "dateasc" : "datedesc";
  else if (sort == "datedesc" || sort == "dateasc") currentSort = sort;
  else if (sort == "name")
    currentSort = (currentSort == "nameasc") ? "namedesc" : "nameasc";
  else if (sort == "nameasc" || sort == "namedesc") currentSort = sort;
  else if (sort == "errors")
    currentSort = (currentSort == "errorsts") ? "errorsdur" : "errorsts";
  else if (sort == "errorsts" || sort == "errorsdur") currentSort = sort;
  else if (sort == "duplicates")
    currentSort = sort;
  LiveSetup().SetLastSortingMode(currentSort);
}
currentFilter = filter;

pageTitle = tr("Recordings");

if (!todel.empty()) {
  if (!cUser::CurrentUserHasRightTo(UR_DELRECS))
    throw HtmlError( tr("Sorry, no permission. Please contact your administrator!") );
  deletions.push_back(todel);
}

deleteResult = "";
if (cUser::CurrentUserHasRightTo(UR_DELRECS)) {
  for (auto it = deletions.begin(); it != deletions.end(); ++it) {
    std::string name;
    if (RecordingsManager::DeleteRecording(*it, &name) == 0) {
      cToSvConcat delRec(tr("Deleted recording:"), " ");
      delRec.appendReplace(name, "~", "/");
      delRec << "<br/>";
      deleteResult += std::string(delRec);
    }
  }
  deletions.clear();
} else {
  throw HtmlError( tr("Sorry, no permission. Please contact your administrator!") );
}

int FreeMB, UsedMB;
int Percent = cVideoDirectory::VideoDiskSpace(&FreeMB, &UsedMB);
int Minutes = int(double(FreeMB) / MB_PER_MINUTE);
int Hours = Minutes / 60;
Minutes %= 60;
diskinfo = cString::sprintf("%s %d%%  -  %2d:%02d %s", trVDR("Disk"), Percent, Hours, Minutes, trVDR("free"));


// get data for all open nodes
std::string openTreeNodes;
if (request.hasCookie("VDR-Live-Recordings-Tree-Open-Nodes")) {
  openTreeNodes = request.getCookie("VDR-Live-Recordings-Tree-Open-Nodes");
//  dsyslog("live: VDR-Live-Recordings-Tree-Open-Nodes = %s", openTreeNodes.c_str());
}
cToSvConcat<0> recording_item;
recording_item.reserve(25000);

#if TNTVERSION >= 30000
const char *TNT_ARRAY = "[]";
#else
const char *TNT_ARRAY = "";
#endif

</%cpp>
<& pageelems.doc_type &>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>VDR-Live - <$ pageTitle $></title>
    <& pageelems.stylesheets &>
    <& pageelems.create_html_js &>
    <& pageelems.ajax_js &>
<script>
const recordings_tree_creation = <$ cToSvInt(RecordingsManager::GetLastRecordingsUpdate() ) $>;
const recs = [];
const rec_ids = Object.create(null)
rec_ids["T"] = [1, 2]

// Label and Action are used for the tooltip  (like "Play in media player"), and will be HTML-encoded here
function RecordingActionS(s, id, A, Img, Label, Action) {
  s.a += '<a href=\"'
  s.a += A
  s.a += 'recording_'
  s.a += id
  s.a += '&sort=<$currentSort$>&filter=<$currentFilter$>&flat=<$currentFlat$>&history_num_back=<$history_num_back+1$>\" title=\"'
  addEncodeHtml(s, LabelAndAction(Label, Action))
  s.a += '\"><img class=\"icon\" src=\"<$LiveSetup().GetThemedLinkPrefixImg()$>'
  s.a += Img
  s.a += '\" /></a>'
}

function RecordingActionPlaylist(s, id, label) {
  s.a += '<a class=\"hidden-xs invisible\" href=\"playlist.m3u?recid=recording_'
  s.a += id
  s.a += '&sort=<$currentSort$>&filter=<$currentFilter$>&flat=<$currentFlat$>&history_num_back=<$history_num_back+1$>\" title=\"'
  addEncodeHtml(s, LabelAndAction(label, '<$tr("Play this recording in the media player")$>'))
  s.a += '\" download><img class=\"hidden-xs invisible icon\" src=\"<$LiveSetup().GetThemedLinkPrefixImg()$>playlist.png\" /></a>'
}

// do not HTML-encode title; will be HTML-encoded here!
function addEventRec_r(s, eventid, title, folder, shortText, description) {
  let http_params = '&sort=<$ sort $>&filter='
  http_params += encodeURIComponent('<$ filter $>')
  http_params += '&flat=<$ flat $>&history_num_back=<$ history_num_back+1 $>'
  addEventRec(s, 'recording_', eventid, http_params, title, folder, shortText, description)
}
</script>

  <script type="text/javascript" src="js/live/treeview.js"></script>
  <script>
  const tv = new Treeview("<$ LiveSetup().GetThemedLinkPrefixImg()$>icon_overlay_minus.png", "<$ LiveSetup().GetThemedLinkPrefixImg()$>icon_overlay_plus.png", "<$ LiveSetup().GetThemedLinkPrefixImg()$>folder_open.png", "<$ LiveSetup().GetThemedLinkPrefixImg()$>folder_closed.png");
  </script>
</head>
<body onpagehide="saveScrollPosition('content')" onpageshow="restoreScrollPosition(); clearCheckboxes(document.getElementById('form_recordings'))">
  <& pageelems.logo &>
<%cpp>
const char *active_r;
if (flat == "true") active_r = "recordings_flat";
else active_r = "recordings";

if (!deleteResult.empty()) {
</%cpp>
  <& menu active=(active_r) component="recordings.delete_error" filter=(filter) &>
<%cpp>
} else {
</%cpp>
  <& menu active=(active_r) component="recordings.sort_options" filter=(filter) &>
<%cpp>
}
</%cpp>
  <div id="content">
    <div class="spacebar"><# spacer with fade-out effect #></div>
    <# we enclose the recordings in a table to allow width control through 'siteprefs.css'; #>
    <# do not classify as 'listing' to avoid row separators                                 #>
    <table class="recordings-list" cellspacing="0" cellpadding="0"><tbody>
    <tr><td>
      <div class="boxheader"><div class="caption"><$ std::string(tr("List of recordings")) + " (" + diskinfo + ")" $></div></div>
    </td></tr>
<%cpp>
    int rec_cnt;
    {
      LOCK_RECORDINGS_READ;
      rec_cnt = Recordings->Count();  // Access VDRs global cRecordings Recordings instance.
    }
    if (rec_cnt == 0) {
</%cpp>
      <# add the message in a table row beneath the header, because the message alone looks weird #>
      <tr class="recording_item">
        <td class="message"><$ tr("No recordings found") $></td>
      </tr>
<%cpp>
    } else {
// get and set sort order
// define sort order, and reverse (for recordings)
// use current sort order and selected sort option for that
      bool reverse = false;
      RecordingsManager::eSortOrder sortOrder = RecordingsManager::eSortOrder::name; // default
      if (currentSort.compare(0, 4,  "date"  , 4) == 0) sortOrder = RecordingsManager::eSortOrder::date;
      if (currentSort.compare(0, 6,  "errors", 6) == 0) sortOrder = RecordingsManager::eSortOrder::errors;
      if (currentSort.compare(0, 8,  "errorsdur", 8) == 0) sortOrder = RecordingsManager::eSortOrder::durationDeviation;
      if (currentSort.compare(0, 10, "duplicates", 10) == 0) sortOrder = RecordingsManager::eSortOrder::duplicatesLanguage;
      if (currentSort == "datedesc" || currentSort == "namedesc") reverse = true;
      RecordingsManager::setSortOrder(sortOrder, reverse, currentFilter);  // this also updates the recordings, if required

// get root directory
      RecordingsItemDirPtr recItemRoot;
      if (currentSort.compare(0, 10, "duplicates", 10) == 0) {
        DuplicatesRecordingsTreePtr duplicatesRecordingsTree(RecordingsManager::GetDuplicatesRecordingsTree());
        if (currentFlat == "true")
          recItemRoot = duplicatesRecordingsTree->getFlatRoot();
        else
          recItemRoot = duplicatesRecordingsTree->getRoot();
      } else {
        if (currentFlat == "true")
          recItemRoot = std::make_shared<RecordingsItemDirFlat>();
        else
          recItemRoot = RecordingsManager::GetRecordingsTree()->getRoot();
      }

      uintptr_t irecording_item = (uintptr_t)&recording_item;
      uintptr_t iRecItemRoot = (uintptr_t)&recItemRoot;
      uintptr_t iOpenTreeNodes = (uintptr_t)&openTreeNodes;
</%cpp>
    <tr><td>
      <form method="post" name="recordings" id="form_recordings" action="recordings.ecpp">
        <div class="recordings">
          <ul class="recordingslist" style="display: revert-layer;">
            <& recordings.recordings_item iRecItem=(iRecItemRoot) irecording_item=(irecording_item) iOpenTreeNodes=(iOpenTreeNodes) &>
          </ul>
        </div>
        <input type="hidden" name="sort" value="<$ currentSort $>">
        <input type="hidden" name="filter" value="<$ currentFilter $>">
        <input type="hidden" name="flat" value="<$ currentFlat $>">
        <input type="hidden" name="history_num_back" value="<$ history_num_back $>">
%       if (!recording_item.empty()) {
        <div class="withmargin hidden-xs">
          <button class="red" type="submit"><$ tr("Delete selected") $></button>
<#        <button class="green" type="button" onclick="clearCheckboxes(document.getElementById('form_recordings'))" ><$ tr("Uncheck all checkboxes") $></button> #>
        </div>
%       }
      </form>
    </td></tr>
<%cpp>
    }
std::chrono::duration<double> timeNeeded = std::chrono::high_resolution_clock::now() - timeStart;
dsyslog("live, time recordings.ecpp: %f", timeNeeded.count());
</%cpp>
    </tbody></table>
    <div class="spacebar"><# spacer with fade-out effect #></div>
  </div>
</body>
</html>
<%include>page_exit.eh</%include>

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

<%def recordings_item>
<%args>
  uintptr_t iRecItem = 0;         // current dir, which is displayed here. Including subdirs
  uintptr_t irecording_item = 0;  // memory used to create the text we send to the browser
  uintptr_t iOpenTreeNodes = 0;   // list (folder hashes) of open folders
  std::string parentIdHash;       // empty for root (level 0)
</%args>
<%cpp>
// get rec item of this (current) dir
RecordingsItemDirPtr recItemThisDir = *(static_cast<RecordingsItemDirPtr *>((void *)iRecItem) );
cToSvConcat<0> *recording_item = static_cast<cToSvConcat<0> *>((void *)irecording_item );
std::string openTreeNodes= *(static_cast<std::string *>((void *)iOpenTreeNodes) );
int level = recItemThisDir->Level();

// data for dirs, and prepare loop over dirs
const_rec_iterator<RecordingsItemDirPtr> l_dir_iterator = recItemThisDir->get_dir_iterator();
if (!recItemThisDir->dirEntriesSorted() && currentSort == "namedesc") l_dir_iterator.set_backwards(true);

bool hasSubDirs = false;
for (const RecordingsItemDirPtr &recItem: l_dir_iterator) {
// this is the loop over the subdirs
// each subdir is a node, which can be expanded (or not)
// each subdir has an identifier in <ul> tag: fldr_<$ idHash $>

// search trough directory for new recordings
  bool newR = false;
  if ( LiveSetup().GetMarkNewRec() ) newR = recItem->checkNew();
// calculate idHash: uniquely defines this node
  cToSvXxHash32 idHash(cToSvConcat(parentIdHash, recItem->Name()));
  iRecItem = (uintptr_t)&recItem;
</%cpp>
  <li class="recording">
    <div class="recording_item" onclick = "tv.Toggle(this, 'fldr_<$ idHash $>')">
    <table><tr>
      <%cpp> if(level > 0) { </%cpp>
        <td class = "space">
          <img src="img/transparent.png" style="width: calc(var(--icon-width, 16px) * <$ level $>); height: var(--icon-height, 16px)" />
        </td>
      <%cpp> } </%cpp>
      <td class="space">
        <img class="iconic button recording-expander" src="<$ LiveSetup().GetThemedLinkPrefixImg()$>icon_overlay_plus.png" />
      </td><td class="space">
        <img class="recording_folder" src="<$ LiveSetup().GetThemedLinkPrefixImg()$>folder_closed.png" />
      </td>
%         if (!recItem->scraperImage().path.empty() ) {
        <td class = space>
          <div class="thumb">
            <img data-src="/tvscraper/<$ recItem->scraperImage().path $>"
              class="<$ recItem->scraperImage().width > recItem->scraperImage().height?"thumb":"thumbpt" $>"
            />
          </div>
        </td>
%         }
    <td class="recording_folder_name<$ (newR ? "_new" : "") $>">
      <$ recItem->Name() $>
    </td></tr></table>
    </div>
    <ul id="fldr_<$ idHash $>" class="recordingslist" style="display: none;">
      <& recordings.recordings_item iRecItem=(iRecItem) irecording_item=(irecording_item) parentIdHash=(idHash) iOpenTreeNodes=(iOpenTreeNodes) &>
    </ul>
  </li>
  <%cpp>
  hasSubDirs = true;
} // end of loop over subdirs
// now the items

const_rec_iterator<RecordingsItemRec*> l_rec_iterator = recItemThisDir->get_rec_iterator();

// do we have to get/write the recording details?
// we have to, if currentFlat == true || level == 0 || this folder is open (cookie)
bool write_recs = level == 0;
if (!write_recs) {
// check: is this folder open (cookie)?
  auto equal_fldf = [parentIdHash](cSv f) { return f.length() > 5 && f.compare(5, std::string_view::npos, parentIdHash) == 0; };
  cSplit splitOpenTreeNodes(openTreeNodes, ',', eSplitDelimBeginEnd::optional);
  write_recs = std::find_if(splitOpenTreeNodes.begin(), splitOpenTreeNodes.end(), equal_fldf) != splitOpenTreeNodes.end();
}
if (write_recs) {
  </%cpp>
<script>
  <%cpp>
  std::chrono::time_point<std::chrono::high_resolution_clock> timeStart_recs = std::chrono::high_resolution_clock::now();
  for (const RecordingsItemRec *rPtr: l_rec_iterator)
  {
    recording_item->clear();
    rPtr->AppendAsJSArray(*recording_item);
  </%cpp>
recs[<$$cToSvInt(rPtr->Id())$>]=[<$$ *recording_item $>]
  <%cpp>
  }
  std::chrono::duration<double> timeNeeded_recs = std::chrono::high_resolution_clock::now() - timeStart_recs;
//  dsyslog("live, time recordings.ecpp recs lv 0: %f", timeNeeded_recs.count());
  l_rec_iterator.set_begin();
  </%cpp>

</script>
  <%cpp>
}
  if (l_rec_iterator == iterator_end()) {
    if (!hasSubDirs) {
      </%cpp>
      <script>
        rec_ids["fldr_<$ parentIdHash $>"] = []
        document.write(
          '<li class="recording">' +
            '<table class="recordings" width="100%">' +
              '<tbody>' +
                '<tr class="recording_item">' +
                <%cpp> if(level > 0) { </%cpp>
                  '<td class = "space">' +
                    '<img src="img/transparent.png" style="width: calc(var(--icon-width, 16px) * <$ level $>); height: var(--icon-height, 16px)" />' +
                  '</td>' +
                <%cpp> } </%cpp>
                  '<td class="message"><$ tr("No matching recordings found") $></td>' +
                '</tr>' +
              '</tbody>' +
            '</table>' +
          '</li>'
        )
      </script>
      <%cpp>
    }
  } else {
    bool first = true;
    const char *displayFolder = "1";
    recording_item->clear();
    RecordingsItemRec::AppendAsJSArray(*recording_item, l_rec_iterator, first);
    </%cpp>
      <script>
%   if (level == 0) {
        document.write(rec_string_d([<$level$>, <$displayFolder$>, [ <$$ *recording_item $> ]]))
%   } else if (!parentIdHash.empty()) {
        rec_ids["fldr_<$ parentIdHash $>"] = [<$level$>, <$displayFolder$>, [ <$$ *recording_item $> ]]
%   }
      </script>
    <%cpp>
  }
</%cpp>
</%def>

<# ---------------------------------------------------------------------- #>
<%def sort_options>
<%cpp> { </%cpp>
<span class="label bold"><$ tr("Sort:") $> </span>
<a href="recordings.html?sort=<$ (currentSort == "nameasc") ? "namedesc" : "nameasc"$>&filter=<? !currentFilter.empty() ? currentFilter ?>&flat=<$currentFlat$>" <& setactive current="name" &> ><$ tr("Name") $></a>
<span class="sep">|</span>
<a href="recordings.html?sort=<$ (currentSort == "datedesc") ? "dateasc" : "datedesc"$>&filter=<? !currentFilter.empty() ? currentFilter ?>&flat=<$currentFlat$>" <& setactive current="date" &> ><$ tr("Date") $></a>
<span class="sep">|</span>
<a href="recordings.html?sort=duplicates&filter=<? !currentFilter.empty() ? currentFilter ?>&flat=<$currentFlat$>" <& setactive current="duplicates" &> ><$ tr("Duplicates") $></a>
<%cpp>
#if VDRVERSNUM >= 20505
</%cpp>
<span class="sep">|</span>
<a href="recordings.html?sort=<$ (currentSort == "errorsts") ? "errorsdur" : "errorsts" $>&filter=<? !currentFilter.empty() ? currentFilter ?>&flat=<$currentFlat$>" <& setactive current="errors" &>><$ tr("Errors") $></a>
<%cpp>
#endif
</%cpp>
<span class="sep">|</span>
<span class="label bold" title="<$tr("Look in recordings titles and subtitles for the given string and display only the matching ones. You may also use perl compatible regular expressions (PCRE).")$>" >
  <label for="filter"><$ tr("Filter") $>:</label>
  <input type="text" name="filter" value="<$ currentFilter $>" id="filter" onchange="filterRecordings(this, '<$ currentSort $>', '<$currentFlat$>')" />
</span>
<img onclick="clearRecordingsFilter(document.getElementById('filter'), '<$ currentSort $>', '<$currentFlat$>')" class="icon button clear-filter" src="<$ LiveSetup().GetThemedLink("img", "icon_overlay_cross.png") $>" alt="" <& tooltip.hint text=(tr("Clear filter")) &>/>
<%cpp>
if (currentFlat != "true") {
</%cpp>
<span class="sep">|</span>
<img onclick="ExpandAll()" class="icon button expand-all" src="<$ LiveSetup().GetThemedLink("img", "icon_overlay_plus.png") $>" alt="" <& tooltip.hint text=(tr("Expand all folders")) &>/>
<img onclick="CollapseAll()" class="icon button collapse-all" src="<$ LiveSetup().GetThemedLink("img", "icon_overlay_minus.png") $>" alt="" <& tooltip.hint text=(tr("Collapse all folders")) &>/>
<%cpp>
}
</%cpp>
<br />
<%cpp> } </%cpp>
</%def>

<# ---------------------------------------------------------------------- #>
<%def setactive>
<%args>
std::string current;
</%args>
<%cpp>
if (currentSort.compare(0, current.length(), current) == 0) { </%cpp>class="active"<%cpp> } </%cpp>
</%def>

<# ---------------------------------------------------------------------- #>
<%def del_rec>
<%args>
  std::string id;
  std::string sort;
  std::string filter;
  std::string flat;
  int history_num_back = 0;
  std::string className;
  std::string label;
  std::string breaksAtLeft;
  std::string breaksAtRight;
</%args>
<%cpp> { </%cpp><a href="epginfo.html?epgid=del_<$ id $>&sort=<$sort$>&filter=<$filter$>&flat=<$flat$>&history_num_back=<$history_num_back+1$>" <& tooltip.hint label=(label) className=("click-action") breaksAtLeft=(breaksAtLeft) breaksAtRight=(breaksAtRight) text=(tr("Delete this recording")) &>><img class="<$ className $>" src="<$ LiveSetup().GetThemedLink("img", "del.png") $>" alt="" /></a><%cpp> } </%cpp>
</%def>

<# ---------------------------------------------------------------------- #>
<%def edit_rec>
<%args>
  std::string id;
  std::string sort;
  std::string filter;
  std::string flat;
  int history_num_back = 0;
  std::string className;
  std::string label;
  std::string breaksAtLeft;
  std::string breaksAtRight;
</%args>
<%cpp> { </%cpp><a href="edit_recording.html?recid=<$ id $>&sort=<$sort$>&filter=<$filter$>&flat=<$flat$>&history_num_back=<$history_num_back+1$>"><img class="<$ className $>" src="<$ LiveSetup().GetThemedLink("img", "edit.png") $>" alt="" <& tooltip.hint label=(label) className=("click-action") breaksAtLeft=(breaksAtLeft) breaksAtRight=(breaksAtRight) text=(tr("Edit recording")) &> /></a><%cpp> } </%cpp>
</%def>

<# ---------------------------------------------------------------------- #>
<%def todel>
<%args>
  std::string todel;
  std::string confirmed;
  std::string history_num_back;
</%args>
<%cpp>
  std::string recording_Name;
  {
    LOCK_RECORDINGS_READ;
    const cRecording *recording = RecordingsManager::GetByHash(todel, Recordings);
    if (recording == nullptr)
      throw HtmlError(tr("Couldn't find recording or no recordings available"));
    recording_Name = recording->Name();
  }
  if (!cUser::CurrentUserHasRightTo(UR_DELRECS))
    throw HtmlError( tr("Sorry, no permission. Please contact your administrator!") );
  if (confirmed == "confirmed") {
    RecordingsManager::DeleteRecording(todel);
</%cpp>
<!DOCTYPE html>
<html>
  <script>
    history.go(-<$ history_num_back $>);
  </script>
</html>
%  } else {
<div class="epg_description" id="del_<$ todel $>">
  <div class="station">
    <div class="boxheader"><div class="caption"><$ tr("Delete recordings") $></div></div>
  </div>
  <div class="epg_content">
    <form>
      <input type="hidden" name="epgid" value="<$todel$>" \>
      <input type="hidden" name="delete_rec" value="confirmed" \>
      <input type="hidden" name="history_num_back" value="<$ history_num_back $>" id="history_del_<$ todel $>"\>
      <div class="about_head"><$ cToSvFormatted(tr("Delete recording \"%s\"?"), recording_Name.empty()?"No recording name available":recording_Name.c_str() ) $></div>
      <div class="about_section">
        <div class="tabular">
          <div class="about_left">
            <button id="confirm_del_<$ todel $>" class="green" type="button" onclick="delete_rec_back('<$ todel $>', <$ history_num_back $>)"><$ tr("Delete")$></button>
          </div>
          <div class="about_right">
<# if previous page is epginfo.html, just go back one page #>
<script>
function cancel_delete() {
  if (document.referrer.indexOf("epginfo.html?") != -1) {
    history.go(-1);
  } else {
    history.go(-<$ history_num_back $>);
  }
}
</script>
            <button id="close_del_<$ todel $>" type="button" class="red" onclick="back_depending_referrer(1, <$history_num_back $>)"><$ tr("Cancel") $></button>
          </div>
        </div>
      </div>
    </form>
  </div>
</div>
% }
</%def>


<# ---------------------------------------------------------------------- #>
<%def rec_tools>
<%args>
  std::string id;
  std::string title;
  std::string s_IMDB_ID;
  std::string sort;
  std::string filter;
  std::string flat;
  int history_num_back = 0;
</%args>
<%cpp>
cToSvConcat label = "";
constexpr auto breaksAtRight = "~";
const RecordingsItemRec* recPtr = RecordingsManager::GetByIdHash(id);
if (recPtr) {
  time_t startTime = recPtr->StartTime();
  label.appendDateTime(tr("%a,"), startTime );      // day of week
  label.concat(' ');
  label.appendDateTime(tr("%b %d %y"), startTime);  // date
  label.concat(", ");
  label.appendDateTime(tr("%I:%M %p"), startTime);  // time
  label.append(tr(" - ")).append(title);
}
</%cpp>
%   if (cDevice::PrimaryDevice() && cDevice::PrimaryDevice()->HasDecoder() ) {
<& pageelems.ajax_action_href action="play_recording" param=(id) tip=(tr("Play this recording")) label=(label) breaksAtRight=(breaksAtRight) image="play.png" alt="" className="icon" &>
%   }
<& pageelems.hls_recording recId=(id) className="icon" label=(label) breaksAtRight=(breaksAtRight) &>
<& pageelems.m3u_playlist_recording recid=(id) className="icon" label=(label) breaksAtRight=(breaksAtRight) &>
<& pageelems.imdb_info_href title=(title) s_IMDB_ID=(s_IMDB_ID) className="icon" label=(label) breaksAtRight=(breaksAtRight) &>
<& recordings.edit_rec id=(id) sort=(sort) filter=(filter) flat=(flat) history_num_back=(history_num_back) className="icon" label=(label) breaksAtRight=(breaksAtRight) &>
<& recordings.del_rec id=(id) sort=(sort) filter=(filter) flat=(flat) history_num_back=(history_num_back) className="icon" label=(label) breaksAtRight=(breaksAtRight) &>
<%cpp>
if (recPtr) {
  const char *sdhd = nullptr;
  cToSvConcat frameParams;
  StringAppendFrameParams(frameParams, recPtr);
  switch (recPtr->FrameWidth()) {
    case 720:
      sdhd = "720x576";
      break;
    case 1280:
      sdhd = "1280x720";
      break;
    case 1920:
      sdhd = "1920x1080";
      break;
    case 3840:
      sdhd = "3840x2160";
      break;
    default:
      break;
  }
  int video_SD_HD = recPtr->SD_HD();
  if (!sdhd) sdhd = video_SD_HD == 0 ? "sd": video_SD_HD == 1 ? "hd": "ud";
  cToSvConcat duration;
  AppendDuration(duration, tr("%d:%02d"), recPtr->Duration() );
</%cpp>
<div id="icons-<$id$>" class="recording_status"></div>
<script class="injectIcons">
injectErrorHdSdIcon(\"icons-<$id$>\", <$cToSvInt(recPtr->RecordingErrors())$>, <$cToSvInt(recPtr->DurationDeviation())$>, \"<$sdhd$>\", \"<$recPtr->ChannelName()$>\", \"<$duration$>\", <$ cToSvInt(recPtr->NumberTsFiles()) $>, \"<$frameParams$>\")
</script>
<%cpp>
}
</%cpp>
</%def>

<# ---------------------------------------------------------------------- #>
<%def archived_disc>
<%args>
  std::string archived;
  std::string title;
  std::string s_IMDB_ID;
</%args>
<img src="<$ LiveSetup().GetThemedLink("img", "on_dvd.png") $>" alt="on_dvd" <& tooltip.hint text=(archived) &> />
<& pageelems.imdb_info_href title=(title) s_IMDB_ID=(s_IMDB_ID)&>
</%def>

<# ---------------------------------------------------------------------- #>
<%def delete_error>
<& recordings.sort_options &>
<%cpp> { reply.out() << deleteResult; } </%cpp>
</%def>
