| | 1590 | /// Sort programs by original Watchlist rules |
| | 1591 | void PlaybackBox::OrderByClassicStrategy(TitleMap& selections, ProgramOrder& ordered) |
| | 1592 | { |
| | 1593 | QDateTime now = MythDate::current(); |
| | 1594 | int baseValue = m_watchListMaxAge * 2 / 3; |
| | 1595 | |
| | 1596 | QMap<int, int> recType; |
| | 1597 | QMap<int, int> maxEpisodes; |
| | 1598 | QMap<int, int> avgDelay; |
| | 1599 | QMap<int, int> spanHours; |
| | 1600 | QMap<int, int> delHours; |
| | 1601 | QMap<int, int> nextHours; |
| | 1602 | |
| | 1603 | MSqlQuery query(MSqlQuery::InitCon()); |
| | 1604 | query.prepare("SELECT recordid, type, maxepisodes, avg_delay, " |
| | 1605 | "next_record, last_record, last_delete FROM record;"); |
| | 1606 | |
| | 1607 | if (query.exec()) |
| | 1608 | { |
| | 1609 | while (query.next()) |
| | 1610 | { |
| | 1611 | int recid = query.value(0).toInt(); |
| | 1612 | recType[recid] = query.value(1).toInt(); |
| | 1613 | maxEpisodes[recid] = query.value(2).toInt(); |
| | 1614 | avgDelay[recid] = query.value(3).toInt(); |
| | 1615 | |
| | 1616 | QDateTime next_record = |
| | 1617 | MythDate::as_utc(query.value(4).toDateTime()); |
| | 1618 | QDateTime last_record = |
| | 1619 | MythDate::as_utc(query.value(5).toDateTime()); |
| | 1620 | QDateTime last_delete = |
| | 1621 | MythDate::as_utc(query.value(6).toDateTime()); |
| | 1622 | |
| | 1623 | // Time between the last and next recordings |
| | 1624 | spanHours[recid] = 1000; |
| | 1625 | if (last_record.isValid() && next_record.isValid()) |
| | 1626 | spanHours[recid] = |
| | 1627 | last_record.secsTo(next_record) / 3600 + 1; |
| | 1628 | |
| | 1629 | // Time since the last episode was deleted |
| | 1630 | delHours[recid] = 1000; |
| | 1631 | if (last_delete.isValid()) |
| | 1632 | delHours[recid] = last_delete.secsTo(now) / 3600 + 1; |
| | 1633 | |
| | 1634 | // Time until the next recording if any |
| | 1635 | if (next_record.isValid()) |
| | 1636 | nextHours[recid] = now.secsTo(next_record) / 3600 + 1; |
| | 1637 | } |
| | 1638 | } |
| | 1639 | |
| | 1640 | TitleMap::iterator it = selections.begin(); |
| | 1641 | while (it != selections.end()) |
| | 1642 | { |
| | 1643 | uint score = 0; |
| | 1644 | ProgramInfo* p = it.value(); |
| | 1645 | int recid = p->GetRecordingRuleID(); |
| | 1646 | int avgd = avgDelay[recid]; |
| | 1647 | |
| | 1648 | if (avgd == 0) |
| | 1649 | avgd = 100; |
| | 1650 | |
| | 1651 | // Set the intervals beyond range if there is no record entry |
| | 1652 | if (spanHours[recid] == 0) |
| | 1653 | { |
| | 1654 | spanHours[recid] = 1000; |
| | 1655 | delHours[recid] = 1000; |
| | 1656 | } |
| | 1657 | |
| | 1658 | // add point equal to baseValue for each additional episode |
| | 1659 | if (recid && maxEpisodes[recid] == 0) |
| | 1660 | score += (m_watchlistCount[extract_watchlist_title(*p)] - 1) * |
| | 1661 | baseValue; |
| | 1662 | |
| | 1663 | // add points every 3hr leading up to the next recording |
| | 1664 | if (nextHours[recid] > 0 && nextHours[recid] < baseValue * 3) |
| | 1665 | score += (baseValue * 3 - nextHours[recid]) / 3; |
| | 1666 | |
| | 1667 | int hrs = p->GetScheduledEndTime().secsTo(now) / 3600; |
| | 1668 | if (hrs < 1) |
| | 1669 | hrs = 1; |
| | 1670 | |
| | 1671 | // add points for a new recording that decrease each hour |
| | 1672 | if (hrs < 42) |
| | 1673 | score += 42 - hrs; |
| | 1674 | |
| | 1675 | // add points for how close the recorded time of day is to 'now' |
| | 1676 | score += abs((hrs % 24) - 12) * 2; |
| | 1677 | |
| | 1678 | // Daily |
| | 1679 | if (spanHours[recid] < 50 || |
| | 1680 | recType[recid] == kDailyRecord) |
| | 1681 | { |
| | 1682 | if (delHours[recid] < m_watchListBlackOut * 4) |
| | 1683 | { |
| | 1684 | LOG(VB_GUI, LOG_DEBUG, |
| | 1685 | QString("Watchlist: Recently deleted daily: %1") |
| | 1686 | .arg(p->GetTitle())); |
| | 1687 | |
| | 1688 | it = selections.erase(it); |
| | 1689 | continue; |
| | 1690 | } |
| | 1691 | else |
| | 1692 | { |
| | 1693 | LOG(VB_GUI, LOG_DEBUG, QString("Watchlist: Daily interval: %1") |
| | 1694 | .arg(p->GetTitle())); |
| | 1695 | |
| | 1696 | if (maxEpisodes[recid] > 0) |
| | 1697 | score += (baseValue / 2) + (hrs / 24); |
| | 1698 | else |
| | 1699 | score += (baseValue / 5) + hrs; |
| | 1700 | } |
| | 1701 | } |
| | 1702 | // Weekly |
| | 1703 | else if (nextHours[recid] || |
| | 1704 | recType[recid] == kWeeklyRecord) |
| | 1705 | |
| | 1706 | { |
| | 1707 | if (delHours[recid] < (m_watchListBlackOut * 24) - 4) |
| | 1708 | { |
| | 1709 | LOG(VB_GUI, LOG_DEBUG, |
| | 1710 | QString("Watchlist: Recently deleted weekly: %1") |
| | 1711 | .arg(p->GetTitle())); |
| | 1712 | |
| | 1713 | it = selections.erase(it); |
| | 1714 | continue; |
| | 1715 | } |
| | 1716 | else |
| | 1717 | { |
| | 1718 | LOG(VB_GUI, LOG_DEBUG, QString("Watchlist: Weekly interval: %1") |
| | 1719 | .arg(p->GetTitle())); |
| | 1720 | |
| | 1721 | if (maxEpisodes[recid] > 0) |
| | 1722 | score += (baseValue / 2) + (hrs / 24); |
| | 1723 | else |
| | 1724 | score += (baseValue / 3) + (baseValue * hrs / 24 / 4); |
| | 1725 | } |
| | 1726 | } |
| | 1727 | // Not recurring |
| | 1728 | else |
| | 1729 | { |
| | 1730 | if (delHours[recid] < (m_watchListBlackOut * 48) - 4) |
| | 1731 | { |
| | 1732 | it = selections.erase(it); |
| | 1733 | continue; |
| | 1734 | } |
| | 1735 | else |
| | 1736 | { |
| | 1737 | // add points for a new Single or final episode |
| | 1738 | if (hrs < 36) |
| | 1739 | score += baseValue * (36 - hrs) / 36; |
| | 1740 | |
| | 1741 | if (avgd != 100) |
| | 1742 | { |
| | 1743 | if (maxEpisodes[recid] > 0) |
| | 1744 | score += (baseValue / 2) + (hrs / 24); |
| | 1745 | else |
| | 1746 | score += (baseValue / 3) + (baseValue * hrs / 24 / 4); |
| | 1747 | } |
| | 1748 | else if ((hrs / 24) < m_watchListMaxAge) |
| | 1749 | score += hrs / 24; |
| | 1750 | else |
| | 1751 | score += m_watchListMaxAge; |
| | 1752 | } |
| | 1753 | } |
| | 1754 | |
| | 1755 | // Factor based on the average time shift delay. |
| | 1756 | // Scale the avgd range of 0 thru 200 hours to 133% thru 67% |
| | 1757 | int delaypct = avgd / 3 + 67; |
| | 1758 | |
| | 1759 | if (avgd < 100) |
| | 1760 | score = score * (200 - delaypct) / 100; |
| | 1761 | else if (avgd > 100) |
| | 1762 | score = score * 100 / delaypct; |
| | 1763 | |
| | 1764 | // use score as primary key in top 32 bits, |
| | 1765 | // use age in secs as a secondary key in low 32 bits to ensure equal |
| | 1766 | // scores are ordered oldest first. Copes with progs up to 136 yrs old |
| | 1767 | score_type longScore = (static_cast<score_type>(score) << 32) |
| | 1768 | | p->GetScheduledStartTime().secsTo(now); |
| | 1769 | |
| | 1770 | ordered.insert(longScore, p); |
| | 1771 | |
| | 1772 | ++it; |
| | 1773 | |
| | 1774 | LOG(VB_GUI, LOG_DEBUG, QString("Watchlist:%1 %2 %3 %4") |
| | 1775 | .arg(score, 5) |
| | 1776 | .arg(longScore, 12) |
| | 1777 | .arg(p->GetTitle()) |
| | 1778 | .arg(MythDate::toString(p->GetScheduledStartTime(), |
| | 1779 | MythDate::kDateShort))); |
| | 1780 | } |
| | 1781 | } |
| | 1782 | |
| 1933 | | MSqlQuery query(MSqlQuery::InitCon()); |
| 1934 | | query.prepare("SELECT recordid, type, maxepisodes, avg_delay, " |
| 1935 | | "next_record, last_record, last_delete FROM record;"); |
| 1936 | | |
| 1937 | | if (query.exec()) |
| 1938 | | { |
| 1939 | | while (query.next()) |
| 1940 | | { |
| 1941 | | int recid = query.value(0).toInt(); |
| 1942 | | recType[recid] = query.value(1).toInt(); |
| 1943 | | maxEpisodes[recid] = query.value(2).toInt(); |
| 1944 | | avgDelay[recid] = query.value(3).toInt(); |
| 1945 | | |
| 1946 | | QDateTime next_record = |
| 1947 | | MythDate::as_utc(query.value(4).toDateTime()); |
| 1948 | | QDateTime last_record = |
| 1949 | | MythDate::as_utc(query.value(5).toDateTime()); |
| 1950 | | QDateTime last_delete = |
| 1951 | | MythDate::as_utc(query.value(6).toDateTime()); |
| 1952 | | |
| 1953 | | // Time between the last and next recordings |
| 1954 | | spanHours[recid] = 1000; |
| 1955 | | if (last_record.isValid() && next_record.isValid()) |
| 1956 | | spanHours[recid] = |
| 1957 | | last_record.secsTo(next_record) / 3600 + 1; |
| 1958 | | |
| 1959 | | // Time since the last episode was deleted |
| 1960 | | delHours[recid] = 1000; |
| 1961 | | if (last_delete.isValid()) |
| 1962 | | delHours[recid] = last_delete.secsTo(now) / 3600 + 1; |
| 1963 | | |
| 1964 | | // Time until the next recording if any |
| 1965 | | if (next_record.isValid()) |
| 1966 | | nextHours[recid] = now.secsTo(next_record) / 3600 + 1; |
| 1967 | | } |
| 1968 | | } |
| 1969 | | |
| 1970 | | TitleMap::iterator it = watchEpisode.begin(); |
| 1971 | | while (it != watchEpisode.end()) |
| 1972 | | { |
| 1973 | | uint score = 0; |
| 1974 | | ProgramInfo* p = it.value(); |
| 1975 | | int recid = p->GetRecordingRuleID(); |
| 1976 | | int avgd = avgDelay[recid]; |
| 1977 | | |
| 1978 | | if (avgd == 0) |
| 1979 | | avgd = 100; |
| 1980 | | |
| 1981 | | // Set the intervals beyond range if there is no record entry |
| 1982 | | if (spanHours[recid] == 0) |
| 1983 | | { |
| 1984 | | spanHours[recid] = 1000; |
| 1985 | | delHours[recid] = 1000; |
| 1986 | | } |
| 1987 | | |
| 1988 | | // add point equal to baseValue for each additional episode |
| 1989 | | if (recid && maxEpisodes[recid] == 0) |
| 1990 | | { |
| 1991 | | score += (m_watchlistCount[extract_watchlist_title(*p)] - 1) * |
| 1992 | | baseValue; |
| 1993 | | } |
| 1994 | | |
| 1995 | | // add points every 3hr leading up to the next recording |
| 1996 | | if (nextHours[recid] > 0 && nextHours[recid] < baseValue * 3) |
| 1997 | | { |
| 1998 | | score += (baseValue * 3 - nextHours[recid]) / 3; |
| 1999 | | } |
| 2000 | | |
| 2001 | | int hrs = p->GetScheduledEndTime().secsTo(now) / 3600; |
| 2002 | | if (hrs < 1) |
| 2003 | | hrs = 1; |
| 2004 | | |
| 2005 | | // add points for a new recording that decrease each hour |
| 2006 | | if (hrs < 42) |
| 2007 | | { |
| 2008 | | score += 42 - hrs; |
| 2009 | | } |
| 2010 | | |
| 2011 | | // add points for how close the recorded time of day is to 'now' |
| 2012 | | score += abs((hrs % 24) - 12) * 2; |
| 2013 | | |
| 2014 | | // Daily |
| 2015 | | if (spanHours[recid] < 50 || |
| 2016 | | recType[recid] == kDailyRecord) |
| 2017 | | { |
| 2018 | | if (delHours[recid] < m_watchListBlackOut * 4) |
| 2019 | | { |
| 2020 | | LOG(VB_GUI, LOG_DEBUG, |
| 2021 | | QString("Watchlist: Recently deleted daily: %1") |
| 2022 | | .arg(p->GetTitle())); |
| 2023 | | it = watchEpisode.erase(it); |
| 2024 | | continue; |
| 2025 | | } |
| 2026 | | else |
| 2027 | | { |
| 2028 | | LOG(VB_GUI, LOG_DEBUG, QString("Watchlist: Daily interval: %1") |
| 2029 | | .arg(p->GetTitle())); |
| 2030 | | |
| 2031 | | if (maxEpisodes[recid] > 0) |
| 2032 | | { |
| 2033 | | score += (baseValue / 2) + (hrs / 24); |
| 2034 | | } |
| 2035 | | else |
| 2036 | | { |
| 2037 | | score += (baseValue / 5) + hrs; |
| 2038 | | } |
| 2039 | | } |
| 2040 | | } |
| 2041 | | // Weekly |
| 2042 | | else if (nextHours[recid] || |
| 2043 | | recType[recid] == kWeeklyRecord) |
| 2044 | | |
| 2045 | | { |
| 2046 | | if (delHours[recid] < (m_watchListBlackOut * 24) - 4) |
| 2047 | | { |
| 2048 | | LOG(VB_GUI, LOG_DEBUG, |
| 2049 | | QString("Watchlist: Recently deleted weekly: %1") |
| 2050 | | .arg(p->GetTitle())); |
| 2051 | | it = watchEpisode.erase(it); |
| 2052 | | continue; |
| 2053 | | } |
| 2054 | | else |
| 2055 | | { |
| 2056 | | LOG(VB_GUI, LOG_DEBUG, QString("Watchlist: Weekly interval: %1") |
| 2057 | | .arg(p->GetTitle())); |
| 2058 | | |
| 2059 | | if (maxEpisodes[recid] > 0) |
| 2060 | | { |
| 2061 | | score += (baseValue / 2) + (hrs / 24); |
| 2062 | | } |
| 2063 | | else |
| 2064 | | { |
| 2065 | | score += (baseValue / 3) + (baseValue * hrs / 24 / 4); |
| 2066 | | } |
| 2067 | | } |
| 2068 | | } |
| 2069 | | // Not recurring |
| 2070 | | else |
| 2071 | | { |
| 2072 | | if (delHours[recid] < (m_watchListBlackOut * 48) - 4) |
| 2073 | | { |
| 2074 | | it = watchEpisode.erase(it); |
| 2075 | | continue; |
| 2076 | | } |
| 2077 | | else |
| 2078 | | { |
| 2079 | | // add points for a new Single or final episode |
| 2080 | | if (hrs < 36) |
| 2081 | | { |
| 2082 | | score += baseValue * (36 - hrs) / 36; |
| 2083 | | } |
| 2084 | | |
| 2085 | | if (avgd != 100) |
| 2086 | | { |
| 2087 | | if (maxEpisodes[recid] > 0) |
| 2088 | | { |
| 2089 | | score += (baseValue / 2) + (hrs / 24); |
| 2090 | | } |
| 2091 | | else |
| 2092 | | { |
| 2093 | | score += (baseValue / 3) + (baseValue * hrs / 24 / 4); |
| 2094 | | } |
| 2095 | | } |
| 2096 | | else if ((hrs / 24) < m_watchListMaxAge) |
| 2097 | | { |
| 2098 | | score += hrs / 24; |
| 2099 | | } |
| 2100 | | else |
| 2101 | | { |
| 2102 | | score += m_watchListMaxAge; |
| 2103 | | } |
| 2104 | | } |
| 2105 | | } |
| 2106 | | |
| 2107 | | // Factor based on the average time shift delay. |
| 2108 | | // Scale the avgd range of 0 thru 200 hours to 133% thru 67% |
| 2109 | | int delaypct = avgd / 3 + 67; |
| 2110 | | |
| 2111 | | if (avgd < 100) |
| 2112 | | { |
| 2113 | | score = score * (200 - delaypct) / 100; |
| 2114 | | } |
| 2115 | | else if (avgd > 100) |
| 2116 | | { |
| 2117 | | score = score * 100 / delaypct; |
| 2118 | | } |
| 2119 | | |
| 2120 | | // use score as primary key in top 32 bits, |
| 2121 | | // use age in secs as a secondary key in low 32 bits to ensure equal |
| 2122 | | // scores are ordered oldest first. Copes with progs up to 136 yrs old |
| 2123 | | score_type longScore = (static_cast<score_type>(score) << 32) |
| 2124 | | | p->GetScheduledStartTime().secsTo(now); |
| 2125 | | |
| 2126 | | watchList.insert(longScore, p); |
| 2127 | | |
| 2128 | | ++it; |
| 2129 | | |
| 2130 | | LOG(VB_GUI, LOG_DEBUG, QString("Watchlist:%1 %2 %3 %4") |
| 2131 | | .arg(score, 5) |
| 2132 | | .arg(longScore, 14) |
| 2133 | | .arg(p->GetTitle()) |
| 2134 | | .arg(MythDate::toString(p->GetScheduledStartTime(), |
| 2135 | | MythDate::kDateShort))); |
| 2136 | | } |
| | 2119 | OrderByClassicStrategy(watchEpisode, watchList); |