diff --git a/gui/slick/css/dark.css b/gui/slick/css/dark.css index efcee90aa3f48f9f9d4004a2cc5da42f50d857db..4bf84ccd07e1438435010351179cc1c4ce13a69a 100644 --- a/gui/slick/css/dark.css +++ b/gui/slick/css/dark.css @@ -704,6 +704,11 @@ body { border-color: #3e3f3a; } +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + background-color: #124477; +} + .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { diff --git a/gui/slick/css/light.css b/gui/slick/css/light.css index fa568f726ac8cf2c66dee018212a1a754ef8f2a5..9422ab4a7fac6c647c0dce49dd837a71244281d0 100644 --- a/gui/slick/css/light.css +++ b/gui/slick/css/light.css @@ -102,12 +102,17 @@ bootstrap Overrides filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#333333'); background: -webkit-gradient(linear, left top, left bottom, from(#555), to(#333)); background: -moz-linear-gradient(top, #555, #333); - border-color: #3e3f3a; + border-color: #3e3f3a; } .navbar-default .navbar-collapse, .navbar-default .navbar-form { - border-color: #3e3f3a; + border-color: #3e3f3a; +} + +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + background-color: #333; } .dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus { @@ -127,13 +132,13 @@ tablesorter.css ========================================================================== */ .tablesorter { - width: 100%; - margin-right: auto; - margin-left: auto; - color: #000; - text-align: left; - background-color: #ddd; - border-spacing: 0; + width: 100%; + margin-right: auto; + margin-left: auto; + color: #000; + text-align: left; + background-color: #ddd; + border-spacing: 0; } /* hidden filter row */ diff --git a/gui/slick/css/style.css b/gui/slick/css/style.css index 1409ab909d8079d3d3b1b8b22eaad0a9dca0e25e..6432b901a76acc77cf16ebec024415f45fe6246a 100644 --- a/gui/slick/css/style.css +++ b/gui/slick/css/style.css @@ -1345,10 +1345,6 @@ td.col-search { comingEpisodes.mako ========================================================================== */ -.sort_data { - display: none; -} - .key { margin-bottom: 20px; } @@ -2105,7 +2101,6 @@ input, textarea, select, .uneditable-input { .navbar-default .navbar-nav > li > a:hover, .navbar-default .navbar-nav > li > a:focus { color: #ffffff; - background-color: transparent; } .navbar-default .navbar-nav > .active > a, diff --git a/gui/slick/js/lib/isotope.pkgd.min.js b/gui/slick/js/lib/isotope.pkgd.min.js index 27db8fb2e52e7d70329c596545544452043fa147..20ea20621c7013f02f3fac6c4dd573ff16795fd2 100644 Binary files a/gui/slick/js/lib/isotope.pkgd.min.js and b/gui/slick/js/lib/isotope.pkgd.min.js differ diff --git a/gui/slick/js/new/history.js b/gui/slick/js/new/history.js index be5e503b09ad1ad79eed98d97cb02a54bf3fd2e0..d4a666bcfa6d8018166fe4efcefdcb28bc50c28a 100644 --- a/gui/slick/js/new/history.js +++ b/gui/slick/js/new/history.js @@ -3,7 +3,7 @@ $(document).ready(function(){ widgets: ['zebra', 'filter'], sortList: [[0,1]], textExtraction: (function(){ - if(isMeta('sickbeard.HOME_LAYOUT', ['detailed'])){ + if(isMeta('sickbeard.HISTORY_LAYOUT', ['detailed'])){ return { 0: function(node) { return $(node).find('time').attr('datetime'); }, 4: function(node) { return $(node).find("span").text().toLowerCase(); } @@ -18,7 +18,7 @@ $(document).ready(function(){ } }()), headers: (function(){ - if(isMeta('sickbeard.HOME_LAYOUT', ['detailed'])){ + if(isMeta('sickbeard.HISTORY_LAYOUT', ['detailed'])){ return { 0: { sorter: 'realISODate' }, 4: { sorter: 'quality' } diff --git a/gui/slick/js/new/meta.js b/gui/slick/js/new/meta.js index 65056db8123a09d3fb35c48fb6eab47e16f52110..e380c88217166a3f3e4c75c096fe241721af37a9 100644 --- a/gui/slick/js/new/meta.js +++ b/gui/slick/js/new/meta.js @@ -1,7 +1,12 @@ function metaToBool(pyVar){ var meta = $('meta[data-var="' + pyVar + '"]').data('content'); - meta = (isNaN(meta) ? meta.toLowerCase() : meta.toString()); - return !(meta === 'false' || meta === 'none' || meta === '0'); + if(meta === undefined){ + console.log(pyVar + ' is empty, did you forget to add this to main.mako?'); + return meta; + } else { + meta = (isNaN(meta) ? meta.toLowerCase() : meta.toString()); + return !(meta === 'false' || meta === 'none' || meta === '0'); + } } function getMeta(pyVar){ diff --git a/gui/slick/views/comingEpisodes.mako b/gui/slick/views/comingEpisodes.mako index 345a653e31f911f1817b0353292cef36ad4167cb..b8b4f63a26c75a706a306c2351e07f3b183f0de7 100644 --- a/gui/slick/views/comingEpisodes.mako +++ b/gui/slick/views/comingEpisodes.mako @@ -112,9 +112,8 @@ <tr class="${show_div}"> <td align="center" nowrap="nowrap"> - <% airDate = sbdatetime.sbdatetime.sbfdatetime(cur_result['localtime']).decode(sickbeard.SYS_ENCODING) %> - <% isoDate = sbdatetime.sbdatetime.convert_to_setting(cur_result['localtime']).isoformat('T') %> - <time datetime="${isoDate}" class="date">${airDate}</time> + <% airDate = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(cur_result['localtime'], cur_result['airs'], cur_result['network'])) %> + <time datetime="${airDate.isoformat('T')}" class="date">${sbdatetime.sbdatetime.sbfdate(airDate)}</time> </td> <td class="tvShow" nowrap="nowrap"><a href="${srRoot}/home/displayShow?show=${cur_result['showid']}">${cur_result['show_name']}</a> diff --git a/gui/slick/views/config_general.mako b/gui/slick/views/config_general.mako index 1590a78cb4dd8f212adc2b911241b41565f1e4c1..e1b10e200a59a3c02d9b5488b3b57f7a8837dfaf 100644 --- a/gui/slick/views/config_general.mako +++ b/gui/slick/views/config_general.mako @@ -78,7 +78,7 @@ <option value="news" ${('', 'selected="selected"')[sickbeard.DEFAULT_PAGE == 'news']}>News</option> <option value="IRC" ${('', 'selected="selected"')[sickbeard.DEFAULT_PAGE == 'IRC']}>IRC</option> <option value="home" ${('', 'selected="selected"')[sickbeard.DEFAULT_PAGE == 'home']}>Shows</option> - <option value="comingEpisodes" ${('', 'selected="selected"')[sickbeard.DEFAULT_PAGE == 'comingEpisodes']}>Coming Episodes</option> + <option value="comingEpisodes" ${('', 'selected="selected"')[sickbeard.DEFAULT_PAGE == 'comingEpisodes']}>Schedule</option> <option value="history" ${('', 'selected="selected"')[sickbeard.DEFAULT_PAGE == 'history']}>History</option> </select> <span>when launching SickRage interface</span> @@ -291,7 +291,7 @@ <span class="component-title">Missed episodes range</span> <span class="component-desc"> <input type="number" step="1" min="7" name="coming_eps_missed_range" id="coming_eps_missed_range" value="${sickbeard.COMING_EPS_MISSED_RANGE}" class="form-control input-sm input75" /> - <p>Set the range in days of the missed episodes in the Coming Episode page</p> + <p>Set the range in days of the missed episodes in the Schedule page</p> </span> </label> </div> diff --git a/gui/slick/views/displayShow.mako b/gui/slick/views/displayShow.mako index 5476568f6051a7205c64de9cb79d25bc9111f2c4..98c9f8a7714fb7ea43817b5708e7f5fb187fa835 100644 --- a/gui/slick/views/displayShow.mako +++ b/gui/slick/views/displayShow.mako @@ -478,19 +478,14 @@ ${file_size} % endif </td> - % if epResult['airdate'] > int(datetime.datetime.now().toordinal()) * 100: - <% tempDate = datetime.datetime.utcfromtimestamp(0) + datetime.timedelta(seconds=epResult['airdate']) %> - % else: - <% tempDate = epResult['airdate'] %> - % endif - <% date = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(tempDate, show.airs, show.network)) %> <td class="col-airdate"> % if int(epResult['airdate']) != 1: - <time datetime="${date.isoformat('T')}" class="date">${sbdatetime.sbdatetime.sbfdate(date)}</time> + ## Lets do this exactly like ComingEpisodes and History + <% airDate = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(epResult['airdate'], show.airs, show.network)) %> + <time datetime="${airDate.isoformat('T')}" class="date">${sbdatetime.sbdatetime.sbfdatetime(airDate)}</time> % else: Never % endif - <span class="sort_data">${date.isoformat('T')}</span> </td> <td> % if sickbeard.DOWNLOAD_URL and epResult['location']: diff --git a/gui/slick/views/errorlogs.mako b/gui/slick/views/errorlogs.mako index 3a397330a690d1a07dbad22e4a9304afeff4e7f7..8f793011f7d04eb7189897c8cc918325410e83ba 100644 --- a/gui/slick/views/errorlogs.mako +++ b/gui/slick/views/errorlogs.mako @@ -8,12 +8,22 @@ <script type="text/javascript" src="${srRoot}/js/new/errorlogs.js"></script> </%block> <%block name="content"> +<% + if logLevel == sickbeard.logger.WARNING: + errors = classes.WarningViewer.errors + title = 'Logs & Errors [WARNING]' + else: + errors = classes.ErrorViewer.errors + title = 'Logs & Errors [ERROR]' +%> <h1 class="header">${title}</h1> <div class="align-left"><pre> -% if classes.ErrorViewer.errors: - % for curError in sorted(classes.ErrorViewer.errors, key=lambda error: error.time, reverse=True)[:500]: - ${curError.time} ${curError.message} +% if errors: + % for curError in sorted(errors, key=lambda error: error.time, reverse=True)[:500]: +${curError.time} ${curError.message} % endfor +% else: +There are no events to display. % endif </pre> </div> diff --git a/gui/slick/views/history.mako b/gui/slick/views/history.mako index a3a758ef3df176bb20934009f8a1d7b2b5474098..5efccb051232aeb2b4821d95286b1d80eb80d773 100644 --- a/gui/slick/views/history.mako +++ b/gui/slick/views/history.mako @@ -18,11 +18,6 @@ layout = sickbeard.HISTORY_LAYOUT history_limit = sickbeard.HISTORY_LIMIT %> -<%block name="css"> -<style type="text/css"> -.sort_data {display:none;} -</style> -</%block> <%block name="scripts"> <script type="text/javascript" src="${srRoot}/js/new/history.js"></script> </%block> diff --git a/gui/slick/views/home.mako b/gui/slick/views/home.mako index 4c6c5d43f33b663f6cfc756d1219710915822032..d40aab8ef8d8e82a556329faa634b3a777ea7020 100644 --- a/gui/slick/views/home.mako +++ b/gui/slick/views/home.mako @@ -352,13 +352,10 @@ %> <tr> % if cur_airs_next: - <% ldatetime = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(cur_airs_next, curShow.airs, curShow.network)) %> + <% airDate = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(cur_airs_next, curShow.airs, curShow.network)) %> % try: - <% temp_sbfdate_next = sbdatetime.sbdatetime.sbfdate(ldatetime) %> - <% temp_timegm_next = calendar.timegm(ldatetime.timetuple()) %> <td align="center" class="nowrap"> - <time datetime="${ldatetime.isoformat('T')}" class="date">${temp_sbfdate_next}</time> - <span class="sort_data">${temp_timegm_next}</span> + <time datetime="${airDate.isoformat('T')}" class="date">${sbdatetime.sbdatetime.sbfdate(airDate)}</time> </td> % except ValueError: <td align="center" class="nowrap"></td> @@ -368,13 +365,10 @@ % endif % if cur_airs_prev: - <% pdatetime = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(cur_airs_prev, curShow.airs, curShow.network)) %> + <% airDate = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(cur_airs_prev, curShow.airs, curShow.network)) %> % try: - <% temp_sbfdate_prev = sbdatetime.sbdatetime.sbfdate(pdatetime) %> - <% temp_timegm_prev = calendar.timegm(pdatetime.timetuple()) %> <td align="center" class="nowrap"> - <time datetime="${pdatetime.isoformat('T')}" class="date">${temp_sbfdate_prev}</time> - <span class="sort_data">${temp_timegm_prev}</span> + <time datetime="${airDate.isoformat('T')}" class="date">${sbdatetime.sbdatetime.sbfdate(airDate)}</time> </td> % except ValueError: <td align="center" class="nowrap"></td> diff --git a/gui/slick/views/layouts/main.mako b/gui/slick/views/layouts/main.mako index acf81e75a52786bb698bc5238cfa4f0dadc6564a..67709e2dcd298585018c9807b145fbd989812642 100644 --- a/gui/slick/views/layouts/main.mako +++ b/gui/slick/views/layouts/main.mako @@ -54,12 +54,12 @@ <meta data-var="sickbeard.DATE_PRESET" data-content="${sickbeard.DATE_PRESET}"> <meta data-var="sickbeard.FILTER_ROW" data-content="${sickbeard.FILTER_ROW}"> <meta data-var="sickbeard.FUZZY_DATING" data-content="${sickbeard.FUZZY_DATING}"> + <meta data-var="sickbeard.HISTORY_LAYOUT" data-content="${sickbeard.HISTORY_LAYOUT}"> <meta data-var="sickbeard.HOME_LAYOUT" data-content="${sickbeard.HOME_LAYOUT}"> <meta data-var="sickbeard.POSTER_SORTBY" data-content="${sickbeard.POSTER_SORTBY}"> <meta data-var="sickbeard.POSTER_SORTDIR" data-content="${sickbeard.POSTER_SORTDIR}"> <meta data-var="sickbeard.ROOT_DIRS" data-content="${sickbeard.ROOT_DIRS}"> <meta data-var="sickbeard.SORT_ARTICLE" data-content="${sickbeard.SORT_ARTICLE}"> - <meta data-var="sickbeard.SORT_ARTICLE" data-content="${sickbeard.SORT_ARTICLE}"> <meta data-var="sickbeard.TIME_PRESET" data-content="${sickbeard.TIME_PRESET}"> <meta data-var="sickbeard.TRIM_ZERO" data-content="${sickbeard.TRIM_ZERO}"> <%block name="metas" /> @@ -110,13 +110,6 @@ % if sbLogin: <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav navbar-right"> - <li id="NAVnews"${('', ' class="active"')[topmenu == 'news']}> - <a href="${srRoot}/news/">News</a> - </li> - <li id="NAVirc"${('', ' class="active"')[topmenu == 'irc']}> - <a href="${srRoot}/IRC/">IRC</a> - </li> - <li id="NAVhome" class="navbar-split dropdown${('', ' active')[topmenu == 'home']}"> <a href="${srRoot}/home/" class="dropdown-toggle">Shows</a> <a href="#" class="dropdown-toggle" data-toggle="dropdown"><b class="caret"></b></a> @@ -129,7 +122,7 @@ </li> <li id="NAVcomingEpisodes"${('', ' class="active"')[topmenu == 'comingEpisodes']}> - <a href="${srRoot}/comingEpisodes/">Coming Episodes</a> + <a href="${srRoot}/comingEpisodes/">Schedule</a> </li> <li id="NAVhistory"${('', ' class="active"')[topmenu == 'history']}> @@ -166,16 +159,6 @@ <div style="clear:both;"></div> </li> - <li id="NAVerrorlogs" class="navbar-split dropdown${('', ' active')[topmenu == 'errorlogs']}"> - <a href="${srRoot}/errorlogs/" class="dropdown-toggle">${logPageTitle}</a> - <a href="#" class="dropdown-toggle" data-toggle="dropdown"><b class="caret"></b></a> - <ul class="dropdown-menu"> - <li><a href="${srRoot}/errorlogs/"><i class="menu-icon-viewlog-errors"></i> View Log (Errors)</a></li> - <li><a href="${srRoot}/errorlogs/viewlog/"><i class="menu-icon-viewlog"></i> View Log</a></li> - </ul> - <div style="clear:both;"></div> - </li> - <li id="NAVconfig" class="navbar-split dropdown${('', ' active')[topmenu == 'config']}"> <a href="${srRoot}/config/" class="dropdown-toggle"><span class="visible-xs">Config</span><img src="${srRoot}/images/menu/system18.png" class="navbaricon hidden-xs" /></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown"><b class="caret"></b></a> @@ -193,20 +176,51 @@ <div style="clear:both;"></div> </li> + <% + if sickbeard.NEWS_UNREAD: + newsBadge = ' <span class="badge">'+str(sickbeard.NEWS_UNREAD)+'</span>' + else: + newsBadge = '' + + numCombined = numErrors + numWarnings + sickbeard.NEWS_UNREAD + if numCombined: + if numErrors: + toolsBadgeClass = ' btn-danger' + elif numWarnings: + toolsBadgeClass = ' btn-warning' + else: + toolsBadgeClass = '' + + toolsBadge = ' <span class="badge'+toolsBadgeClass+'">'+str(numCombined)+'</span>' + else: + toolsBadge = '' + %> <li id="NAVsystem" class="navbar-split dropdown${('', ' active')[topmenu == 'system']}"> - <a href="${srRoot}/home/status/" class="dropdown-toggle"><span class="visible-xs">Tools</span><img src="${srRoot}/images/menu/system18-2.png" class="navbaricon hidden-xs" /></a> + <a href="${srRoot}/home/status/" class="dropdown-toggle"><span class="visible-xs">Tools</span><img src="${srRoot}/images/menu/system18-2.png" class="navbaricon hidden-xs" />${toolsBadge}</a> <a href="#" class="dropdown-toggle" data-toggle="dropdown"><b class="caret"></b></a> <ul class="dropdown-menu"> + <li><a href="${srRoot}/news/"><i class="menu-icon-help"></i> News${newsBadge}</a></li> + <li><a href="${srRoot}/IRC/"><i class="menu-icon-help"></i> IRC</a></li> + <li><a href="${srRoot}/changes/"><i class="menu-icon-help"></i> Changelog</a></li> + <li><a href="https://github.com/SiCKRAGETV/SickRage/wiki/Donations" rel="noreferrer" onclick="window.open('${sickbeard.ANON_REDIRECT}' + this.href); return false;"><i class="menu-icon-help"></i> Support SickRage</a></li> + <li role="separator" class="divider"></li> + %if numErrors: + <li><a href="${srRoot}/errorlogs/"><i class="menu-icon-viewlog-errors"></i> View Errors <span class="badge btn-danger">${numErrors}</span></a></li> + %endif + %if numWarnings: + <li><a href="${srRoot}/errorlogs/?level=${sickbeard.logger.WARNING}"><i class="menu-icon-viewlog-errors"></i> View Warnings <span class="badge btn-warning">${numWarnings}</span></a></li> + %endif + <li><a href="${srRoot}/errorlogs/viewlog/"><i class="menu-icon-viewlog"></i> View Log</a></li> + <li role="separator" class="divider"></li> <li><a href="${srRoot}/home/updateCheck?pid=${sbPID}"><i class="menu-icon-update"></i> Check For Updates</a></li> - <li><a href="${srRoot}/changes"><i class="menu-icon-help"></i> Changelog</a></li> <li><a href="${srRoot}/home/restart/?pid=${sbPID}" class="confirm restart"><i class="menu-icon-restart"></i> Restart</a></li> <li><a href="${srRoot}/home/shutdown/?pid=${sbPID}" class="confirm shutdown"><i class="menu-icon-shutdown"></i> Shutdown</a></li> <li><a href="${srRoot}/logout" class="confirm logout"><i class="menu-icon-shutdown"></i> Logout</a></li> + <li role="separator" class="divider"></li> <li><a href="${srRoot}/home/status/"><i class="menu-icon-help"></i> Server Status</a></li> </ul> <div style="clear:both;"></div> </li> - <li id="donate"><a href="https://github.com/SiCKRAGETV/SickRage/wiki/Donations" rel="noreferrer" onclick="window.open('${sickbeard.ANON_REDIRECT}' + this.href); return false;"><img src="${srRoot}/images/donate.jpg" alt="[donate]" class="navbaricon hidden-xs" /></a></li> </ul> % endif </div><!-- /.navbar-collapse --> diff --git a/gui/slick/views/manage_backlogOverview.mako b/gui/slick/views/manage_backlogOverview.mako index 5bdf25c59b91a37b0b53b1a5974de9b845b7dec7..db2eca31046389ee7914da2b2ba65c24dbcc703d 100644 --- a/gui/slick/views/manage_backlogOverview.mako +++ b/gui/slick/views/manage_backlogOverview.mako @@ -79,14 +79,13 @@ Jump to Show <td class="tableright" align="center" class="nowrap"> ${curResult["name"]} </td> - <% date = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(curResult['airdate'], curShow.airs, curShow.network)) %> <td> + <% airDate = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(curResult['airdate'], curShow.airs, curShow.network)) %> % if int(curResult['airdate']) != 1: - <time datetime="${date.isoformat('T')}" class="date">${date}</time> + <time datetime="${airDate.isoformat('T')}" class="date">${sbdatetime.sbdatetime.sbfdatetime(airDate)}</time> % else: Never % endif - <span class="sort_data">${date.isoformat('T')}</span> </td> </tr> % endfor diff --git a/lib/network_timezones/README.md b/lib/network_timezones/README.md index 633853c29ace51df25c00257e2a9da109df19886..17601aba297bf2f1e44aab6925b108c95d3e68e7 100644 --- a/lib/network_timezones/README.md +++ b/lib/network_timezones/README.md @@ -1,7 +1,7 @@ Network Timezones for Sickbeard ==================== -This holds all the timezone autoupdade info for Sickbeard. Sickbeard uses this data to display the Coming Episodes in the local timezone. +This holds all the timezone autoupdade info for Sickbeard. Sickbeard uses this data to display the Schedule in the local timezone. ---------- diff --git a/readme.md b/readme.md index bf321572f0471ce0a4adefbf54fdaa0868803a20..81fb6c85b750c8a131b44712f853716fa51a5752 100644 --- a/readme.md +++ b/readme.md @@ -1,11 +1,8 @@ -SickRage +SickRage [](https://travis-ci.org/SiCKRAGETV/SickRage) ===== Automatic Video Library Manager for TV Shows. It watches for new episodes of your favorite shows, and when they are posted it does its magic. -## Branch Build Status -[](https://travis-ci.org/SiCKRAGETV/SickRage) - -## Features +#### Features - Kodi/XBMC library updates, poster/banner/fanart downloads, and NFO/TBN generation - Configurable automatic episode renaming, sorting, and other processing - Easily see what episodes you're missing, are airing soon, and more @@ -25,30 +22,24 @@ Automatic Video Library Manager for TV Shows. It watches for new episodes of you - Real SSL certificate validation - Supports Anime shows -## Screenshots --[Desktop (Full-HD)](http://imgur.com/a/4fpBk)<br> --[Mobile](http://imgur.com/a/WPyG6) +#### Screenshots +- [Desktop (Full-HD)](http://imgur.com/a/4fpBk) +- [Mobile](http://imgur.com/a/WPyG6) -## Dependencies - To run SickRage from source you will need Python 2.7.x, Mako, and PyOpenSSL +#### Dependencies + To run SickRage from source you will need Python 2.7.x and PyOpenSSL -## Feature Requests -[](http://feathub.com/SiCKRAGETV/SickRage) +#### [](http://feathub.com/SiCKRAGETV/SickRage) -## Forums +#### Forums Any questions or setup info your looking for can be found at out forums https://www.sickrage.tv -## Bug/Issues -[SickRage Issue Tracker](https://github.com/SiCKRAGETV/sickrage-issues) - -## FAQ - -https://github.com/SiCKRAGETV/SickRage/wiki/Frequently-Asked-Questions +##### [SickRage Issue Tracker](https://github.com/SiCKRAGETV/sickrage-issues) -## Wiki +##### [FAQ](https://github.com/SiCKRAGETV/SickRage/wiki/Frequently-Asked-Questions) -https://github.com/SiCKRAGETV/SickRage/wiki +##### [Wiki](https://github.com/SiCKRAGETV/SickRage/wiki) -## Important +#### Important Before using this with your existing database (sickbeard.db) please make a backup copy of it and delete any other database files such as cache.db and failed.db if present<br/> We HIGHLY recommend starting out with no database files at all to make this a fresh start but the choice is at your own risk diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 6121d816b242f36d92ccacab968bf3a876a4e644..51cb3413b8e73359bb8010f34747cded659a9d2f 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -139,6 +139,11 @@ GIT_AUTOISSUES = False GIT_NEWVER = False DEVELOPER = False +NEWS_URL = 'http://sickragetv.github.io/sickrage-news/news.md' +NEWS_LAST_READ = None +NEWS_LATEST = None +NEWS_UNREAD = 0 + INIT_LOCK = Lock() started = False @@ -602,7 +607,7 @@ def initialize(consoleLogging=True): AUTOPOSTPROCESSER_FREQUENCY, SHOWUPDATE_HOUR, DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \ ANIME_DEFAULT, NAMING_ANIME, ANIMESUPPORT, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST, \ ANIME_SPLIT_HOME, SCENE_DEFAULT, ARCHIVE_DEFAULT, DOWNLOAD_URL, BACKLOG_DAYS, GIT_ORG, GIT_REPO, GIT_USERNAME, GIT_PASSWORD, \ - GIT_AUTOISSUES, DEVELOPER, gh, DISPLAY_ALL_SEASONS, SSL_VERIFY + GIT_AUTOISSUES, DEVELOPER, gh, DISPLAY_ALL_SEASONS, SSL_VERIFY, NEWS_URL, NEWS_LAST_READ, NEWS_LATEST, NEWS_UNREAD if __INITIALIZED__: return False @@ -877,6 +882,9 @@ def initialize(consoleLogging=True): BACKLOG_DAYS = check_setting_int(CFG, 'General', 'backlog_days', 7) + NEWS_LAST_READ = check_setting_str(CFG, 'General', 'news_last_read', '1970-01-01') + NEWS_LATEST = NEWS_LAST_READ + NZB_DIR = check_setting_str(CFG, 'Blackhole', 'nzb_dir', '') TORRENT_DIR = check_setting_str(CFG, 'Blackhole', 'torrent_dir', '') @@ -1733,6 +1741,7 @@ def save_config(): new_config['General']['no_restart'] = int(NO_RESTART) new_config['General']['developer'] = int(DEVELOPER) new_config['General']['display_all_seasons'] = int(DISPLAY_ALL_SEASONS) + new_config['General']['news_last_read'] = NEWS_LAST_READ new_config['Blackhole'] = {} new_config['Blackhole']['nzb_dir'] = NZB_DIR diff --git a/sickbeard/classes.py b/sickbeard/classes.py index 05dbfe267830e5c5092eb35a56257c110459c4d9..eb96a12da5e183cec41f5ec5d97c2dd1c543257c 100644 --- a/sickbeard/classes.py +++ b/sickbeard/classes.py @@ -271,6 +271,30 @@ class ErrorViewer: return ErrorViewer.errors +class WarningViewer: + """ + Keeps a static list of (warning) UIErrors to be displayed on the UI and allows + the list to be cleared. + """ + + errors = [] + + def __init__(self): + WarningViewer.errors = [] + + @staticmethod + def add(error): + WarningViewer.errors.append(error) + + @staticmethod + def clear(): + WarningViewer.errors = [] + + @staticmethod + def get(): + return WarningViewer.errors + + class UIError: """ Represents an error to be displayed in the web UI. diff --git a/sickbeard/common.py b/sickbeard/common.py index f7214d28d32f62f6c3887f268bf2e8c585511b5a..5b47a18689c56ca6495c39c4a065c0cabaf2e551 100644 --- a/sickbeard/common.py +++ b/sickbeard/common.py @@ -270,22 +270,22 @@ class Quality: ret = Quality.SDTV elif checkName([r"web.?dl|web(rip|mux)", r"xvid|x26[45]|h.?26[45]"], all) and not checkName([r"(720|1080)[pi]"], all): ret = Quality.SDTV - elif checkName([r"(dvd(rip|mux)|b[rd](rip|mux)|blue?-?ray)(.ws)?.(xvid|divx|x26[45])"], any) and not checkName([r"(720|1080)[pi]"], all): + elif checkName([r"(dvd(rip|mux)|b[rd](rip|mux)|blue?-?ray)(.ws)?.(xvid|divx|[xh].?26[45])"], any) and not checkName([r"(720|1080)[pi]"], all): ret = Quality.SDDVD - elif checkName([r"720p", r"hd.?tv", r"x26[45]"], all) or checkName([r"hr.ws.pdtv.x26[45]"], any) and not checkName( + elif checkName([r"720p", r"hd.?tv", r"[xh].?26[45]"], all) or checkName([r"hr.ws.pdtv.[xh].?26[45]"], any) and not checkName( [r"1080[pi]"], all): ret = Quality.HDTV elif checkName([r"720p|1080i", r"hd.?tv", r"mpeg-?2"], all) or checkName([r"1080[pi].hdtv", r"h.?26[45]"], all): ret = Quality.RAWHDTV - elif checkName([r"1080p", r"hd.?tv", r"x26[45]"], all): + elif checkName([r"1080p", r"hd.?tv", r"[xh].?26[45]"], all): ret = Quality.FULLHDTV - elif checkName([r"720p", r"web.?dl|web(rip|mux)"], all) or checkName([r"720p", r"itunes", r"h.?26[45]"], all): + elif checkName([r"720p", r"web.?dl|web(rip|mux)"], all) or checkName([r"720p", r"itunes", r"[xh].?26[45]"], all): ret = Quality.HDWEBDL - elif checkName([r"1080p", r"web.?dl|web(rip|mux)"], all) or checkName([r"1080p", r"itunes", r"h.?26[45]"], all): + elif checkName([r"1080p", r"web.?dl|web(rip|mux)"], all) or checkName([r"1080p", r"itunes", r"[xh].?26[45]"], all): ret = Quality.FULLHDWEBDL - elif checkName([r"720p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"x26[45]"], all): + elif checkName([r"720p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"[xh].?26[45]"], all): ret = Quality.HDBLURAY - elif checkName([r"1080p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"x26[45]"], all): + elif checkName([r"1080p", r"blue?-?ray|hddvd|b[rd](rip|mux)", r"[xh].?26[45]"], all): ret = Quality.FULLHDBLURAY return ret diff --git a/sickbeard/logger.py b/sickbeard/logger.py index 33a59ba66b1a031dd232d967a4a89c26f3c0220b..58bee81604a2031c3d2ef0f27bae741f3ce2f33b 100644 --- a/sickbeard/logger.py +++ b/sickbeard/logger.py @@ -146,6 +146,9 @@ class Logger(object): if level == ERROR: self.logger.exception(message, *args, **kwargs) classes.ErrorViewer.add(classes.UIError(message)) + elif level == WARNING: + self.logger.exception(message, *args, **kwargs) + classes.WarningViewer.add(classes.UIError(message)) # if sickbeard.GIT_AUTOISSUES: # self.submit_errors() diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 0a48d4d52350b61ae113461735140e354bd48c3e..6022cf8bb15d66ca20a15bc46faaaea544bb8ac6 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -285,7 +285,7 @@ class TVShow(object): if noCreate: return None - logger.log(str(self.indexerid) + u": An object for episode S%02dE%02d didn't exist in the cache, trying to create it" % (season, episode), logger.DEBUG) + #logger.log(str(self.indexerid) + u": An object for episode S%02dE%02d didn't exist in the cache, trying to create it" % (season, episode), logger.DEBUG) if file: ep = TVEpisode(self, season, episode, file) @@ -1100,13 +1100,13 @@ class TVShow(object): with curEp.lock: # if it used to have a file associated with it and it doesn't anymore then set it to sickbeard.EP_DEFAULT_DELETED_STATUS if curEp.location and curEp.status in Quality.DOWNLOADED: - + if sickbeard.EP_DEFAULT_DELETED_STATUS == ARCHIVED: oldStatus, oldQuality = Quality.splitCompositeStatus(curEp.status) new_status = Quality.compositeStatus(ARCHIVED, oldQuality) else: new_status = sickbeard.EP_DEFAULT_DELETED_STATUS - + logger.log(u"%s: Location for S%02dE%02d doesn't exist, removing it and changing our status to %s" % (self.indexerid, season, episode, statusStrings[new_status]) ,logger.DEBUG) curEp.status = new_status diff --git a/sickbeard/versionChecker.py b/sickbeard/versionChecker.py index d68f3547a78442102784a68184490b9d59a62cc3..fff3694e0972e7bf5fa68bb0d508266b7c5b3258 100644 --- a/sickbeard/versionChecker.py +++ b/sickbeard/versionChecker.py @@ -80,6 +80,8 @@ class CheckVersion: logger.log(u"Update failed!") ui.notifications.message('Update failed!') + self.check_for_new_news(force) + self.amActive = False def run_backup_if_safe(self): @@ -271,6 +273,41 @@ class CheckVersion: self.updater.set_newest_text() return True + def check_for_new_news(self, force=False): + """ + Checks GitHub for the latest news. + + returns: str, a copy of the news + + force: if true the VERSION_NOTIFY setting will be ignored and a check will be forced + """ + + if not self.updater or not sickbeard.VERSION_NOTIFY and not sickbeard.AUTO_UPDATE and not force: + logger.log(u"check_for_new_news: Version checking is disabled, not checking for latest news") + return '' + + # Grab a copy of the news + logger.log(u'check_for_new_news: Checking GitHub for latest news.', logger.DEBUG) + try: + news = helpers.getURL(sickbeard.NEWS_URL, session=requests.Session()) + except Exception: + logger.log(u'check_for_new_news: Could not load news from repo.', logger.WARNING) + + last_read = time.mktime(time.strptime(sickbeard.NEWS_LAST_READ, '%Y-%m-%d')) + dates= re.finditer(r'^####(\d{4}-\d{2}-\d{2})####$', news, re.M) + + sickbeard.NEWS_UNREAD = 0 + gotLatest = False + for match in dates: + if not gotLatest: + gotLatest = True + sickbeard.NEWS_LATEST = match.group(1) + + if time.mktime(time.strptime(match.group(1), '%Y-%m-%d')) > last_read: + sickbeard.NEWS_UNREAD += 1 + + return news + def update(self): if self.updater: # update branch with current config branch value diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index aa274ccc9decab08de46a72f88ffd5f2e19eed50..feef9a4af3e2d73816a65d2f2d343f7c0ba73fb6 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -138,19 +138,9 @@ class PageTemplate(MakoTemplate): if "X-Forwarded-Proto" in rh.request.headers: self.arguments['sbHttpsEnabled'] = True if rh.request.headers['X-Forwarded-Proto'] == 'https' else False - logPageTitle = 'Logs & Errors' - if len(classes.ErrorViewer.errors): - logPageTitle += ' (' + str(len(classes.ErrorViewer.errors)) + ')' - self.arguments['logPageTitle'] = logPageTitle + self.arguments['numErrors'] = len(classes.ErrorViewer.errors) + self.arguments['numWarnings'] = len(classes.WarningViewer.errors) self.arguments['sbPID'] = str(sickbeard.PID) - self.arguments['menu'] = [ - {'title': 'Home', 'key': 'home'}, - {'title': 'Coming Episodes', 'key': 'comingEpisodes'}, - {'title': 'History', 'key': 'history'}, - {'title': 'Manage', 'key': 'manage'}, - {'title': 'Config', 'key': 'config'}, - {'title': logPageTitle, 'key': 'errorlogs'}, - ] self.arguments['title'] = "FixME" self.arguments['header'] = "FixME" @@ -511,7 +501,7 @@ class WebRoot(WebHandler): t = PageTemplate(rh=self, file='comingEpisodes.mako') return t.render(submenu=submenu, next_week=next_week1, today=today, results=results, layout=layout, - title='Coming Episodes', header='Coming Episodes', topmenu='comingEpisodes') + title='Schedule', header='Schedule', topmenu='comingEpisodes') class CalendarHandler(BaseHandler): @@ -1079,6 +1069,7 @@ class Home(WebRoot): return self.redirect('/home/') sickbeard.versionCheckScheduler.action.check_for_new_version(force=True) + sickbeard.versionCheckScheduler.action.check_for_new_news(force=True) return self.redirect('/' + sickbeard.DEFAULT_PAGE + '/') @@ -2080,7 +2071,7 @@ class HomeIRC(Home): def index(self): t = PageTemplate(rh=self, file="IRC.mako") - return t.render(topmenu="irc", header="IRC", title="IRC") + return t.render(topmenu="system", header="IRC", title="IRC") @route('/news(/?.*)') class HomeNews(Home): @@ -2089,15 +2080,19 @@ class HomeNews(Home): def index(self): try: - news = helpers.getURL('http://sickragetv.github.io/sickrage-news/news.md', session=requests.Session()) + news = sickbeard.versionCheckScheduler.action.check_for_new_news(force=True) except Exception: logger.log(u'Could not load news from repo, giving a link!', logger.DEBUG) - news = 'Could not load news from the repo. [Click here for news.md](http://sickragetv.github.io/sickrage-news/news.md)' + news = 'Could not load news from the repo. [Click here for news.md]('+sickbeard.NEWS_URL+')' + + sickbeard.NEWS_LAST_READ = sickbeard.NEWS_LATEST + sickbeard.NEWS_UNREAD = 0 + sickbeard.save_config() t = PageTemplate(rh=self, file="markdown.mako") data = markdown2.markdown(news if news else "The was a problem connecting to github, please refresh and try again", extras=['header-ids']) - return t.render(title="News", header="News", topmenu="news", data=data) + return t.render(title="News", header="News", topmenu="system", data=data) @route('/changes(/?.*)') @@ -4892,23 +4887,32 @@ class ErrorLogs(WebRoot): def ErrorLogsMenu(self): menu = [ - {'title': 'Clear Errors', 'path': 'errorlogs/clearerrors/', 'icon': 'ui-icon ui-icon-trash'}, + {'title': 'Clear Errors', 'path': 'errorlogs/clearerrors/', 'requires': self.haveErrors(), 'icon': 'ui-icon ui-icon-trash'}, + {'title': 'Clear Warnings', 'path': 'errorlogs/clearerrors/?level='+str(logger.WARNING), 'requires': self.haveWarnings(), 'icon': 'ui-icon ui-icon-trash'}, {'title': 'Submit Errors', 'path': 'errorlogs/submit_errors/', 'requires': self.haveErrors(), 'class':'sumbiterrors', 'confirm': True, 'icon': 'ui-icon ui-icon-arrowreturnthick-1-n'}, ] return menu - def index(self): + def index(self, level=logger.ERROR): t = PageTemplate(rh=self, file="errorlogs.mako") - return t.render(header="Logs & Errors", title="Logs & Errors", topmenu="errorlogs", submenu=self.ErrorLogsMenu()) + return t.render(header="Logs & Errors", title="Logs & Errors", topmenu="system", submenu=self.ErrorLogsMenu(), logLevel=int(level)) def haveErrors(self): if len(classes.ErrorViewer.errors) > 0: return True - def clearerrors(self): - classes.ErrorViewer.clear() + def haveWarnings(self): + if len(classes.WarningViewer.errors) > 0: + return True + + def clearerrors(self, level=logger.ERROR): + if int(level) == logger.WARNING: + classes.WarningViewer.clear() + else: + classes.ErrorViewer.clear() + return self.redirect("/errorlogs/") def viewlog(self, minLevel=logger.INFO, logFilter="<NONE>",logSearch=None, maxLines=500): @@ -4995,7 +4999,7 @@ class ErrorLogs(WebRoot): with ek(codecs.open, *[logger.logFile + "." + str(i), 'r', 'utf-8']) as f: data += Get_Data(minLevel, f.readlines(), len(data), regex, logFilter, logSearch, maxLines) - return t.render(header="Log File", title="Logs", topmenu="errorlogs", submenu=self.ErrorLogsMenu(), + return t.render(header="Log File", title="Logs", topmenu="system", submenu=self.ErrorLogsMenu(), logLines="".join(data), minLevel=minLevel, logNameFilters=logNameFilters, logFilter=logFilter, logSearch=logSearch)