| 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); |