Merge branch 'release/0.6.0'

This commit is contained in:
Adam 2015-01-18 13:06:48 +08:00
commit 663cb0691b
83 changed files with 2766 additions and 2249 deletions

View file

@ -1,3 +1,43 @@
### 0.6.0 (2015-01-18 05:05:00 UTC)
* Add network logos BBC Canada, Crackle, El Rey Network, SKY Atlantic, and Watch
* Change Yahoo! screen network logo
* Add and update Discovery Network's channel logos
* Add A&E Network International/Scripps Networks International channel logos
* Remove non required duplicate network logos
* Add lowercase PM to the General Config/Interface/Time style selection
* Change General Config/Interface/Trim zero padding to Trim date and time, now handles 2:00 pm > 2 pm
* Fix trim zero of military time hour to not use 12 hr time
* Change ThePirateBay to use oldpiratebay as a temporary fix
* Change Search Settings/Torrent/Deluge option texts for improved understanding
* Fix Womble's Index searching (ssl disabled for now, old categories are the new active ones again)
* Fix Add From Trending Show page to work with Trakt changes
* Add anime unit test cases (port from lad1337/sickbeard)
* Fix normal tv show regex (port from midgetspy/sickbeard)
* Fix anime regex (port from lad1337/sickbeard)
* Add pull request checkout option to General Config/Advanced Settings
* Add BTN api call parameter debug logging
* Fix anime searches on BTN provider
* Change replace "Daily-Search" with "Recent-Search"
* Add daily search to recent search renaming to config migration code
* Fix 'NoneType' object is not iterable in trakt module
* Add log message for when trakt does not return a watchlist
* Change Coming Episodes calendar view to a fluid layout, change episode layout design, and add day and month in column headers
* Add isotope plug-in to Coming Episodes calendar view to enable sort columns by Date, Network, and Show name
* Add imagesLoaded plug-in to prevent layout breakage by calling isotope to update content after a page auto-refresh
* Change Coming Episodes to "Episodes" page (API endpoint is not renamed)
* Add coming episodes to episode view renaming to config migration code
* Change Layout term "Calender" to "Day by Day" on Episodes page
* Fix saving of sort modes to config file on Episodes page
* Add qTip episode plots to "Day by Day" on Episodes page
* Add article sorting to networks on Episodes page
* Add toggle sort direction and multidimensional sort to isotope on Episodes page
* Add text "[paused]" where appropriate to shows on layout Day by Day on Episodes page
* Change Epsiodes page auto refresh from 10 to 30 mins
* Add UI tweaks
* Fix progress bars disappearing on home page
### 0.5.0 (2014-12-21 11:40:00 UTC)
* Fix searches freezing due to unescaped ignored or required words

View file

@ -149,10 +149,6 @@ inc_top.tmpl
margin-bottom: -15px;
}
#contentWrapper {
/* background: url("../images/bg.png") repeat 0 0 transparent; */
}
[class^="icon-"],
[class*=" icon-"] {
background-image: url("../images/glyphicons-halflings.png");
@ -301,18 +297,18 @@ inc_top.tmpl
}
.ui-tabs {
padding: 0px;
padding: 0;
background: none;
border-width: 0px;
border-width: 0;
}
.ui-tabs .ui-tabs-nav {
padding-left: 0px;
padding-left: 0;
background: transparent;
border-width: 0px 0px 0px 0px;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
border-radius: 0px;
border-width: 0 0 0 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
}
.ui-tabs .ui-tabs-panel {
@ -331,15 +327,6 @@ inc_top.tmpl
border-top-right-radius: 5px;
}
#content {
width: 95%;
min-width: 875px;
padding: 15px;
margin-left: auto;
margin-right: auto;
clear: both;
}
#SubMenu {
padding-right: 20px;
clear: both;
@ -353,7 +340,7 @@ inc_top.tmpl
margin-left: auto;
margin-right: auto;
margin-top: 50px;
margin-bottom: 0px;
margin-bottom: 0;
}
[class^="menu-icon-"], [class*=" menu-icon-"] {
@ -379,83 +366,83 @@ inc_top.tmpl
}
.menu-icon-addshow {
background-position: 0px 0px;
background-position: 0 0;
}
.menu-icon-anime {
background-position: -21px 0px;
background-position: -21px 0;
}
.menu-icon-backlog-view {
background-position: -42px 0px;
background-position: -42px 0;
}
.menu-icon-backlog {
background-position: -63px 0px;
background-position: -63px 0;
}
.menu-icon-bittorrent {
background-position: -84px 0px;
background-position: -84px 0;
}
.menu-icon-config-index {
background-position: -105px 0px;
background-position: -105px 0;
}
.menu-icon-config {
background-position: -126px 0px;
background-position: -126px 0;
}
.menu-icon-failed-download {
background-position: -147px 0px;
background-position: -147px 0;
}
.menu-icon-home {
background-position: -168px 0px;
background-position: -168px 0;
}
.menu-icon-manage {
background-position: -189px 0px;
background-position: -189px 0;
}
.menu-icon-manage-searches {
background-position: -210px 0px;
background-position: -210px 0;
}
.menu-icon-poster {
background-position: -231px 0px;
background-position: -231px 0;
}
.menu-icon-postprocess {
background-position: -252px 0px;
background-position: -252px 0;
}
.menu-icon-restart {
background-position: -273px 0px;
background-position: -273px 0;
}
.menu-icon-shutdown {
background-position: -294px 0px;
background-position: -294px 0;
}
.menu-icon-update {
background-position: -315px 0px;
background-position: -315px 0;
}
.menu-icon-viewlog-errors {
background-position: -336px 0px;
background-position: -336px 0;
}
.menu-icon-viewlog {
background-position: -357px 0px;
background-position: -357px 0;
}
.menu-icon-xbmc {
background-position: -378px 0px;
background-position: -378px 0;
}
.menu-icon-help {
background-position: -399px 0px;
background-position: -399px 0;
}
[class^="submenu-icon-"], [class*=" submenu-icon-"] {
@ -465,27 +452,27 @@ inc_top.tmpl
}
.submenu-icon-anime {
background-position: -21px 0px;
background-position: -21px 0;
}
.submenu-icon-bittorrent {
background-position: -84px 0px;
background-position: -84px 0;
}
.submenu-icon-failed-download {
background-position: -147px 0px;
background-position: -147px 0;
}
.submenu-icon-restart {
background-position: -273px 0px;
background-position: -273px 0;
}
.submenu-icon-shutdown {
background-position: -294px 0px;
background-position: -294px 0;
}
.submenu-icon-xbmc {
background-position: -378px 0px;
background-position: -378px 0;
}
/* =======================================================================
@ -622,42 +609,42 @@ home.tmpl
}
.show .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br {
border-bottom-right-radius: 0px;
border-bottom-right-radius: 0;
}
.show .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl {
border-bottom-left-radius: 0px;
border-bottom-left-radius: 0;
}
.show .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr {
border-top-right-radius: 0px;
border-top-right-radius: 0;
}
.show .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl {
border-top-left-radius: 0px;
border-top-left-radius: 0;
}
.show .ui-widget-content {
border-top: 1px solid #111;
border-bottom: 1px solid #111;
border-left: 0px;
border-right: 0px;
border-left: 0;
border-right: 0;
}
.show .progress-80 {
border-radius: 0px;
border-radius: 0;
}
.show .progress-60 {
border-radius: 0px;
border-radius: 0;
}
.show .progress-40 {
border-radius: 0px;
border-radius: 0;
}
.show .progress-20 {
border-radius: 0px;
border-radius: 0;
}
.show-title {
@ -665,7 +652,7 @@ home.tmpl
overflow: hidden;
white-space: nowrap;
font-size: 11px;
margin: 4px 4px 0px 4px;
margin: 4px 4px 0 4px;
}
.show-title:after {
@ -688,7 +675,7 @@ home.tmpl
overflow: hidden;
white-space: nowrap;
font-size: 11px;
margin: 0px 4px 4px 4px;
margin: 0 4px 4px 4px;
}
.show-date:after {
@ -828,7 +815,7 @@ home_trendingShows.tmpl
white-space: nowrap;
font-size: 12px;
overflow: hidden;
/* text-shadow: 1px 1px 0px #000;*/
/* text-shadow: 1px 1px 0 #000;*/
padding-left: 4px;
margin: 0;
}
@ -928,7 +915,7 @@ ul.tags li {
border: 1px solid #111;
color: #FFF;
font: 14px/18px "Open Sans", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif;
text-shadow: 0px 1px rgba(0, 0, 0, 0.8);
text-shadow: 0 1px rgba(0, 0, 0, 0.8);
float: left;
}
@ -1168,7 +1155,7 @@ td.col-search {
}
/* =======================================================================
comingEpisodes.tmpl
episodeView.tmpl
========================================================================== */
.sort_data {
@ -1227,7 +1214,7 @@ h2.day, h2.network {
letter-spacing: 1px;
color: #FFF;
text-align: center;
text-shadow: -1px -1px 0px rgba(0, 0, 0, 0.3);
text-shadow: -1px -1px 0 rgba(0, 0, 0, 0.3);
background-color: #15528F;
}
@ -1236,7 +1223,7 @@ h2.day, h2.network {
clear: both;
border: 1px solid #ccc;
margin: auto;
padding: 0px;
padding: 0;
text-align: left;
width: 750px;
border-radius: 5px;
@ -1325,17 +1312,42 @@ h2.day, h2.network {
color: #09A2FF;
}
table.cal-odd {
.day-of-week .day-number {
background-color: #15528F;
color: #fff;
}
.today .day-number .number, .today .day-number .month, .today .day-number .day {
color: #8dbeee;
}
.odd .daybyday-show {
background-color: #333;
}
table.cal-even {
.even .daybyday-show {
background-color: #3d3d3d;
}
.calendarShow .text .airtime {
color:#fff
.daybyday-show .episode-blank {
background-color: rgba(0,0,0,.1);
border-radius: 3px;
}
.calendarShow .text .episode-title {
color:#aaa
.day-of-week .poster img {
border-color: #111;
}
.day-of-week .text .airtime,
.day-of-week .text .episode,
.day-of-week .text .episode .name {
color: #fff;
}
.day-of-week .text .episode .season,
.day-of-week .text .episode .number {
color: rgb(9, 162, 255);
}
.day-of-week .text .episode {
color: rgb(141, 190, 238);
}
/* =======================================================================
@ -1372,12 +1384,7 @@ config*.tmpl
}
#config div.field-pair {
padding: 12px 0px;
}
#config div.field-pair input {
float: left;
margin-right: 6px;
padding: 12px 0;
}
#config .nocheck, #config div #customQuality, .metadataDiv {
@ -1562,7 +1569,7 @@ td.tableright {
text-align: left;
vertical-align: middle;
width: 225px;
padding: 6px 0px;
padding: 6px 0;
}
.optionWrapper div.selectChoices {
@ -1596,7 +1603,6 @@ Global
========================================================================== */
span.path {
padding: 3px 6px;
color: #09A2FF;
background-color: #333;
}
@ -1614,7 +1620,7 @@ span.quality {
background-image:linear-gradient(to bottom, rgba(255, 255, 255, 0.08),rgba(255, 255, 255, 0) 50%,rgba(0, 0, 0, 0) 50%,rgba(0, 0, 0, 0.25));
-webkit-box-shadow:inset 0 1px rgba(255, 255, 255, 0.1),inset 0 -1px 3px rgba(0, 0, 0, 0.3),inset 0 0 0 1px rgba(255, 255, 255, 0.08),0 1px 2px rgba(0, 0, 0, 0.15);
box-shadow:inset 0 1px rgba(255, 255, 255, 0.1),inset 0 -1px 3px rgba(0, 0, 0, 0.3),inset 0 0 0 1px rgba(255, 255, 255, 0.08),0 1px 2px rgba(0, 0, 0, 0.15);
text-shadow: 0px 1px rgba(0, 0, 0, 0.8);
text-shadow: 0 1px rgba(0, 0, 0, 0.8);
color: #FFFFFF;
display: inline-block;
padding: 2px 4px;
@ -1734,7 +1740,7 @@ div.blackwhitelist span {
}
div.blackwhitelist.anidb, div.blackwhitelist.manual {
margin: 7px 0px;
margin: 7px 0;
}
@ -1751,7 +1757,7 @@ body {
}
input[type="radio"] {
margin: 2px 0px 0px;
margin: 2px 0 0;
line-height: normal;
}
@ -1766,7 +1772,7 @@ input, textarea, select, .uneditable-input {
}
.navbar-brand {
padding: 0px;
padding: 0;
}
/* navbar styling */
@ -1906,7 +1912,7 @@ fieldset[disabled] .navbar-default .btn-link:focus {
.dropdown-menu {
background-color: #333;
border: 1px solid rgba(0, 0, 0, 0.15);
box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.176);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.176);
}
.form-control {
@ -2384,10 +2390,10 @@ pnotify.css
background-image: -o-linear-gradient(#333, #3d3d3d) !important;
filter: progid:dximagetransform.microsoft.gradient(startColorstr=#333, endColorstr=#3d3d3d) !important;
-ms-filter: progid:dximagetransform.microsoft.gradient(startColorstr=#333, endColorstr=#3d3d3d) !important;
-moz-box-shadow: 0px 0px 2px #000;
-webkit-box-shadow: 0px 0px 2px #000;
-o-box-shadow: 0px 0px 2px #000;
box-shadow: 0px 0px 2px #000;
-moz-box-shadow: 0 0 2px #000;
-webkit-box-shadow: 0 0 2px #000;
-o-box-shadow: 0 0 2px #000;
box-shadow: 0 0 2px #000;
}
.ui-pnotify-title {
@ -2648,10 +2654,19 @@ span.token-input-delete-token {
background-color: rgb(40, 40, 40);
}
/*.episodeview-daybyday .time .time-min,*/
.episodeview-daybyday .time .time-hr-min,
.episodeview-daybyday .time .time-am-pm,
#addRootDirTable td label .filepath,
.grey-text {
color:#999
}
/*.episodeview-daybyday .time .time-hr-min{
display:none
}
.episodeview-daybyday .time .time-min{
font-size: 11px;
}*/
#newShowPortal #displayText .show-name,
#newShowPortal #displayText .show-dest,
@ -2687,7 +2702,7 @@ jquery.confirm.css
top: 50%;
margin: -130px 0 0 -230px;
border: 1px solid #111;
box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.175);
box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.175);
}
#confirmBox h1,
@ -2701,13 +2716,13 @@ jquery.confirm.css
color: #fff;
margin: 0;
font-size: 22px;
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.75);
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.75);
}
#confirmBox p {
padding-top: 20px;
color: #fff;
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.75);
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.75);
}
#confirmButtons {
@ -2722,7 +2737,7 @@ jquery.confirm.css
display: inline-block;
color: #fff;
text-align:center;
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.75);
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.75);
background-clip: padding-box;
border: 1px solid #111;
border-radius: 3px;

View file

@ -149,10 +149,6 @@ inc_top.tmpl
margin-bottom: -15px;
}
#contentWrapper {
/* background: url("../images/bg.png") repeat 0 0 transparent; */
}
[class^="icon-"],
[class*=" icon-"] {
background-image: url("../images/glyphicons-halflings.png");
@ -289,18 +285,18 @@ inc_top.tmpl
}
.ui-tabs {
padding: 0px;
padding: 0;
background: none;
border-width: 0px;
border-width: 0;
}
.ui-tabs .ui-tabs-nav {
padding-left: 0px;
padding-left: 0;
background: transparent;
border-width: 0px 0px 0px 0px;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
border-radius: 0px;
border-width: 0 0 0 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
}
.ui-tabs .ui-tabs-panel {
@ -318,15 +314,6 @@ inc_top.tmpl
border-top-right-radius: 5px;
}
#content {
width: 95%;
min-width: 875px;
padding: 15px;
margin-left: auto;
margin-right: auto;
clear: both;
}
#SubMenu {
padding-right: 20px;
clear: both;
@ -340,7 +327,7 @@ inc_top.tmpl
margin-left: auto;
margin-right: auto;
margin-top: 50px;
margin-bottom: 0px;
margin-bottom: 0;
}
[class^="menu-icon-"], [class*=" menu-icon-"] {
@ -366,83 +353,83 @@ inc_top.tmpl
}
.menu-icon-addshow {
background-position: 0px 0px;
background-position: 0 0;
}
.menu-icon-anime {
background-position: -21px 0px;
background-position: -21px 0;
}
.menu-icon-backlog-view {
background-position: -42px 0px;
background-position: -42px 0;
}
.menu-icon-backlog {
background-position: -63px 0px;
background-position: -63px 0;
}
.menu-icon-bittorrent {
background-position: -84px 0px;
background-position: -84px 0;
}
.menu-icon-config-index {
background-position: -105px 0px;
background-position: -105px 0;
}
.menu-icon-config {
background-position: -126px 0px;
background-position: -126px 0;
}
.menu-icon-failed-download {
background-position: -147px 0px;
background-position: -147px 0;
}
.menu-icon-home {
background-position: -168px 0px;
background-position: -168px 0;
}
.menu-icon-manage {
background-position: -189px 0px;
background-position: -189px 0;
}
.menu-icon-manage-searches {
background-position: -210px 0px;
background-position: -210px 0;
}
.menu-icon-poster {
background-position: -231px 0px;
background-position: -231px 0;
}
.menu-icon-postprocess {
background-position: -252px 0px;
background-position: -252px 0;
}
.menu-icon-restart {
background-position: -273px 0px;
background-position: -273px 0;
}
.menu-icon-shutdown {
background-position: -294px 0px;
background-position: -294px 0;
}
.menu-icon-update {
background-position: -315px 0px;
background-position: -315px 0;
}
.menu-icon-viewlog-errors {
background-position: -336px 0px;
background-position: -336px 0;
}
.menu-icon-viewlog {
background-position: -357px 0px;
background-position: -357px 0;
}
.menu-icon-xbmc {
background-position: -378px 0px;
background-position: -378px 0;
}
.menu-icon-help {
background-position: -399px 0px;
background-position: -399px 0;
}
[class^="submenu-icon-"], [class*=" submenu-icon-"] {
@ -452,27 +439,27 @@ inc_top.tmpl
}
.submenu-icon-anime {
background-position: -21px 0px;
background-position: -21px 0;
}
.submenu-icon-bittorrent {
background-position: -84px 0px;
background-position: -84px 0;
}
.submenu-icon-failed-download {
background-position: -147px 0px;
background-position: -147px 0;
}
.submenu-icon-restart {
background-position: -273px 0px;
background-position: -273px 0;
}
.submenu-icon-shutdown {
background-position: -294px 0px;
background-position: -294px 0;
}
.submenu-icon-xbmc {
background-position: -378px 0px;
background-position: -378px 0;
}
/* =======================================================================
@ -609,42 +596,42 @@ home.tmpl
}
.show .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br {
border-bottom-right-radius: 0px;
border-bottom-right-radius: 0;
}
.show .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl {
border-bottom-left-radius: 0px;
border-bottom-left-radius: 0;
}
.show .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr {
border-top-right-radius: 0px;
border-top-right-radius: 0;
}
.show .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl {
border-top-left-radius: 0px;
border-top-left-radius: 0;
}
.show .ui-widget-content {
border-top: 1px solid #111;
border-bottom: 1px solid #111;
border-left: 0px;
border-right: 0px;
border-left: 0;
border-right: 0;
}
.show .progress-80 {
border-radius: 0px;
border-radius: 0;
}
.show .progress-60 {
border-radius: 0px;
border-radius: 0;
}
.show .progress-40 {
border-radius: 0px;
border-radius: 0;
}
.show .progress-20 {
border-radius: 0px;
border-radius: 0;
}
.show-title {
@ -652,7 +639,7 @@ home.tmpl
overflow: hidden;
white-space: nowrap;
font-size: 11px;
margin: 4px 4px 0px 4px;
margin: 4px 4px 0 4px;
}
.show-title:after {
@ -675,7 +662,7 @@ home.tmpl
overflow: hidden;
white-space: nowrap;
font-size: 11px;
margin: 0px 4px 4px 4px;
margin: 0 4px 4px 4px;
}
.show-date:after {
@ -815,7 +802,7 @@ home_trendingShows.tmpl
white-space: nowrap;
font-size: 12px;
overflow: hidden;
/* text-shadow: 1px 1px 0px #000;*/
/* text-shadow: 1px 1px 0 #000;*/
padding-left: 4px;
margin: 0;
}
@ -917,7 +904,7 @@ ul.tags li {
border: 1px solid #111;
color: #FFF;
font: 14px/18px "Open Sans", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif;
text-shadow: 0px 1px rgba(0, 0, 0, 0.8);
text-shadow: 0 1px rgba(0, 0, 0, 0.8);
float: left;
}
@ -1074,7 +1061,7 @@ tr.seasonheader {
padding-top: 10px;
text-align: left;
border: none;
color: #fff;
color: #000;
}
th.col-checkbox,
@ -1157,7 +1144,7 @@ td.col-search {
}
/* =======================================================================
comingEpisodes.tmpl
episodeView.tmpl
========================================================================== */
.sort_data {
@ -1219,7 +1206,7 @@ h2.day, h2.network {
letter-spacing: 1px;
color: #FFF;
text-align: center;
text-shadow: -1px -1px 0px rgba(0, 0, 0, 0.3);
text-shadow: -1px -1px 0 rgba(0, 0, 0, 0.3);
background-color: #333;
}
@ -1228,7 +1215,7 @@ h2.day, h2.network {
clear: both;
border: 1px solid #ccc;
margin: auto;
padding: 0px;
padding: 0;
text-align: left;
width: 750px;
border-radius: 5px;
@ -1307,17 +1294,39 @@ h2.day, h2.network {
vertical-align: middle;
}
table.cal-odd {
background-color: #ddd;
.day-of-week .day-number {
background-color: #333;
color: #fff;
}
table.cal-even {
background-color: #d2d2d2;
.today .day-number .number, .today .day-number .month, .today .day-number .day {
color: #c7db40;
}
.calendarShow .text .airtime {
color:#000
.odd .daybyday-show {
background-color: #F5F1E4;
}
.calendarShow .text .episode-title {
color:#888
.even .daybyday-show {
background-color: #DFDACF;
}
.day-of-week .poster img {
border-color: #CCC;
}
.day-of-week .text .airtime,
.day-of-week .text .episode,
.day-of-week .text .episode .name {
color: #000;
}
.day-of-week .text .episode .season,
.day-of-week .text .episode .number {
color: rgb(9, 133, 225);
/*color: #3d3d3d;*/
}
.day-of-week .text .episode {
color: #888;
}
/* =======================================================================
@ -1355,12 +1364,7 @@ config*.tmpl
}
#config div.field-pair {
padding: 12px 0px;
}
#config div.field-pair input {
float: left;
margin-right: 6px;
padding: 12px 0;
}
#config .nocheck, #config div #customQuality, .metadataDiv {
@ -1538,7 +1542,7 @@ td.tableright {
text-align: left;
vertical-align: middle;
width: 225px;
padding: 6px 0px;
padding: 6px 0;
}
.optionWrapper div.selectChoices {
@ -1572,7 +1576,6 @@ Global
========================================================================== */
span.path {
padding: 3px 6px;
color: #8b0000;
background-color: #f5f1e4;
}
@ -1594,7 +1597,7 @@ span.quality {
background-image:linear-gradient(to bottom, rgba(255, 255, 255, 0.08),rgba(255, 255, 255, 0) 50%,rgba(0, 0, 0, 0) 50%,rgba(0, 0, 0, 0.25));
-webkit-box-shadow:inset 0 1px rgba(255, 255, 255, 0.1),inset 0 -1px 3px rgba(0, 0, 0, 0.3),inset 0 0 0 1px rgba(255, 255, 255, 0.08),0 1px 2px rgba(0, 0, 0, 0.15);
box-shadow:inset 0 1px rgba(255, 255, 255, 0.1),inset 0 -1px 3px rgba(0, 0, 0, 0.3),inset 0 0 0 1px rgba(255, 255, 255, 0.08),0 1px 2px rgba(0, 0, 0, 0.15);
text-shadow: 0px 1px rgba(0, 0, 0, 0.8);
text-shadow: 0 1px rgba(0, 0, 0, 0.8);
color: #FFFFFF;
display: inline-block;
padding: 2px 4px;
@ -1714,7 +1717,7 @@ div.blackwhitelist span {
}
div.blackwhitelist.anidb, div.blackwhitelist.manual {
margin: 7px 0px;
margin: 7px 0;
}
@ -1730,7 +1733,7 @@ body {
}
input[type="radio"] {
margin: 2px 0px 0px;
margin: 2px 0 0;
line-height: normal;
}
@ -1745,7 +1748,7 @@ input, textarea, select, .uneditable-input {
}
.navbar-brand {
padding: 0px;
padding: 0;
}
/* navbar styling */
@ -1884,7 +1887,7 @@ fieldset[disabled] .navbar-default .btn-link:focus {
.dropdown-menu {
background-color: #F5F1E4;
border: 1px solid rgba(0, 0, 0, 0.15);
box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.176);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.176);
}
.form-control {
@ -2596,6 +2599,8 @@ span.token-input-delete-token {
background-color: rgb(245, 245, 245);
}
.episodeview-daybyday .time .time-min,
.episodeview-daybyday .time .time-am-pm,
#addRootDirTable td label .filepath,
.grey-text {
color:#666
@ -2635,7 +2640,7 @@ jquery.confirm.css
top: 50%;
margin: -130px 0 0 -230px;
border: 1px solid #111;
box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.175);
box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.175);
}
#confirmBox h1,
@ -2649,13 +2654,13 @@ jquery.confirm.css
color: #fff;
margin: 0;
font-size: 22px;
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.75);
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.75);
}
#confirmBox p {
padding-top: 20px;
color: #000;
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.75);
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
}
#confirmButtons {
@ -2670,7 +2675,7 @@ jquery.confirm.css
display: inline-block;
color: #fff;
text-align:center;
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.75);
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.75);
background-clip: padding-box;
border: 1px solid #111;
border-radius: 3px;

View file

@ -149,8 +149,11 @@ inc_top.tmpl
margin-bottom: -15px;
}
#contentWrapper {
/* background: url("../images/bg.png") repeat 0 0 transparent; */
#contentWrapper .episodeview-banner,
#contentWrapper .episodeview-daybyday,
#contentWrapper .episodeview-list,
#contentWrapper .episodeview-poster{
padding-top:45px;
}
[class^="icon-"],
@ -285,18 +288,18 @@ inc_top.tmpl
}
.ui-tabs {
padding: 0px;
padding: 0;
background: none;
border-width: 0px;
border-width: 0;
}
.ui-tabs .ui-tabs-nav {
padding-left: 0px;
padding-left: 0;
background: transparent;
border-width: 0px 0px 0px 0px;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
border-radius: 0px;
border-width: 0 0 0 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
}
.ui-tabs .ui-tabs-panel {
@ -336,7 +339,7 @@ inc_top.tmpl
margin-left: auto;
margin-right: auto;
margin-top: 50px;
margin-bottom: 0px;
margin-bottom: 0;
}
[class^="menu-icon-"], [class*=" menu-icon-"] {
@ -362,83 +365,83 @@ inc_top.tmpl
}
.menu-icon-addshow {
background-position: 0px 0px;
background-position: 0 0;
}
.menu-icon-anime {
background-position: -21px 0px;
background-position: -21px 0;
}
.menu-icon-backlog-view {
background-position: -42px 0px;
background-position: -42px 0;
}
.menu-icon-backlog {
background-position: -63px 0px;
background-position: -63px 0;
}
.menu-icon-bittorrent {
background-position: -84px 0px;
background-position: -84px 0;
}
.menu-icon-config-index {
background-position: -105px 0px;
background-position: -105px 0;
}
.menu-icon-config {
background-position: -126px 0px;
background-position: -126px 0;
}
.menu-icon-failed-download {
background-position: -147px 0px;
background-position: -147px 0;
}
.menu-icon-home {
background-position: -168px 0px;
background-position: -168px 0;
}
.menu-icon-manage {
background-position: -189px 0px;
background-position: -189px 0;
}
.menu-icon-manage-searches {
background-position: -210px 0px;
background-position: -210px 0;
}
.menu-icon-poster {
background-position: -231px 0px;
background-position: -231px 0;
}
.menu-icon-postprocess {
background-position: -252px 0px;
background-position: -252px 0;
}
.menu-icon-restart {
background-position: -273px 0px;
background-position: -273px 0;
}
.menu-icon-shutdown {
background-position: -294px 0px;
background-position: -294px 0;
}
.menu-icon-update {
background-position: -315px 0px;
background-position: -315px 0;
}
.menu-icon-viewlog-errors {
background-position: -336px 0px;
background-position: -336px 0;
}
.menu-icon-viewlog {
background-position: -357px 0px;
background-position: -357px 0;
}
.menu-icon-xbmc {
background-position: -378px 0px;
background-position: -378px 0;
}
.menu-icon-help {
background-position: -399px 0px;
background-position: -399px 0;
}
[class^="submenu-icon-"], [class*=" submenu-icon-"] {
@ -448,27 +451,27 @@ inc_top.tmpl
}
.submenu-icon-anime {
background-position: -21px 0px;
background-position: -21px 0;
}
.submenu-icon-bittorrent {
background-position: -84px 0px;
background-position: -84px 0;
}
.submenu-icon-failed-download {
background-position: -147px 0px;
background-position: -147px 0;
}
.submenu-icon-restart {
background-position: -273px 0px;
background-position: -273px 0;
}
.submenu-icon-shutdown {
background-position: -294px 0px;
background-position: -294px 0;
}
.submenu-icon-xbmc {
background-position: -378px 0px;
background-position: -378px 0;
}
/* =======================================================================
@ -626,26 +629,26 @@ home.tmpl
}
.show .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br {
border-bottom-right-radius: 0px;
border-bottom-right-radius: 0;
}
.show .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl {
border-bottom-left-radius: 0px;
border-bottom-left-radius: 0;
}
.show .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr {
border-top-right-radius: 0px;
border-top-right-radius: 0;
}
.show .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl {
border-top-left-radius: 0px;
border-top-left-radius: 0;
}
.show .ui-widget-content {
border-top: 1px solid #111;
border-bottom: 1px solid #111;
border-left: 0px;
border-right: 0px;
border-left: 0;
border-right: 0;
}
.ui-progressbar .ui-progressbar-value {
height:20px
@ -661,19 +664,19 @@ home.tmpl
}
.show .progress-80 {
border-radius: 0px;
border-radius: 0;
}
.show .progress-60 {
border-radius: 0px;
border-radius: 0;
}
.show .progress-40 {
border-radius: 0px;
border-radius: 0;
}
.show .progress-20 {
border-radius: 0px;
border-radius: 0;
}
.show-title {
@ -681,7 +684,7 @@ home.tmpl
overflow: hidden;
white-space: nowrap;
font-size: 11px;
margin: 4px 4px 0px 4px;
margin: 4px 4px 0 4px;
}
.show-title:after {
@ -704,7 +707,7 @@ home.tmpl
overflow: hidden;
white-space: nowrap;
font-size: 11px;
margin: 0px 4px 4px 4px;
margin: 0 4px 4px 4px;
}
.show-date:after {
@ -791,34 +794,27 @@ home_addShows.tmpl
========================================================================== */
#addShowPortal {
width: 750px;
width: 748px;
padding: 10px 0;
margin-right: auto;
margin-left: auto;
}
#addShowPortal a {
/* padding: 10px;*/
padding: 0px 20px;
padding: 0 20px;
width: 360px;
float: left;
margin: 0 15px 15px 0;
margin: 0 7px 14px;
}
div.button {
display: table-cell;
vertical-align: middle;
/* padding-left: 10px;*/
}
div.buttontext {
display: table-cell;
/*
padding-left: 20px;
padding: 10px 15px;
*/
padding: 10px 0px 10px 15px;
padding: 10px 0 10px 15px;
text-align: left;
white-space: normal;
}
@ -826,7 +822,7 @@ div.buttontext p {
margin: 0
}
div.buttontext h3 {
margin-top: 0px;
margin-top: 0;
}
div.buttontext p {
@ -970,7 +966,6 @@ home_trendingShows.tmpl
white-space: nowrap;
font-size: 12px;
overflow: hidden;
/* text-shadow: 1px 1px 0px #000;*/
padding-left: 4px;
margin: 0;
}
@ -1104,7 +1099,7 @@ ul.tags li {
border: 1px solid #111;
color: #FFF;
font: 14px/18px "Open Sans", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif;
text-shadow: 0px 1px rgba(0, 0, 0, 0.8);
text-shadow: 0 1px rgba(0, 0, 0, 0.8);
float: left;
}
@ -1347,7 +1342,7 @@ td.col-search {
}
/* =======================================================================
comingEpisodes.tmpl
episodeView.tmpl
========================================================================== */
.sort_data {
@ -1409,7 +1404,7 @@ h2.day, h2.network {
letter-spacing: 1px;
color: #FFF;
text-align: center;
text-shadow: -1px -1px 0px rgba(0, 0, 0, 0.3);
text-shadow: -1px -1px 0 rgba(0, 0, 0, 0.3);
background-color: #333;
}
@ -1418,7 +1413,7 @@ h2.day, h2.network {
clear: both;
border: 1px solid #ccc;
margin: auto;
padding: 0px;
padding: 0;
text-align: left;
width: 750px;
border-radius: 5px;
@ -1497,46 +1492,87 @@ h2.day, h2.network {
vertical-align: middle;
}
.calendarWrapper {
width:1000px;
.daybydayWrapper {
max-width: 1400px;
margin: 0 auto;
padding:0 3px
padding: 0 /*3px*/
}
.calendarTable {
.day-of-week {
float: left;
width:142px !important;
white-space:nowrap;
table-layout:fixed !important;
width: 14.28%;
padding: 0 2px;
}
.calendarShow {
padding:0 !important
.day-of-week .day-number {
position: relative;
height: 40px;
}
.calendarShow .poster {
padding-bottom:2px
}
.calendarShow .poster img {
width:142px;
height:auto
.day-of-week .day-number .number {
position: absolute;
right: 5px;
font-weight: bold;
font-size: 32px;
line-height: 38px;
}
.calendarShow .text {
padding:0 5px 10px 5px
.day-of-week .day-number .day {
position: absolute;
left: 5px;
top: 3px;
text-transform: uppercase;
font-weight: bold;
}
.calendarShow .text .airtime,
.calendarShow .text .episode-title {
.day-of-week .day-number .month {
position: absolute;
left: 5px;
bottom: 3px;
text-transform: uppercase;
}
.daybyday-show {
margin-top: 4px;
padding: 4px;
width: 100%
}
.day-of-week .poster img {
border: 1px solid;
border-radius: 5px;
margin-bottom: 2px;
display: block;
margin-left: auto;
margin-right: auto;
}
.day-of-week .text .airtime,
.day-of-week .text .episode {
overflow: hidden;
text-overflow: ellipsis;
display: block;
font-size:11px
font-size: 12px;
}
.calendarShow .show-status {
padding:5px 10px 10px;
text-align:center
.day-of-week .text .episode .season,
.day-of-week .text .episode .number {
font-weight: 900;
}
.day-of-week .text .episode .season {
margin-right: 2px;
}
.day-of-week .text .episode .number {
margin-left: 2px;
}
.day-of-week .episode-blank {
width: 250px;
height: 32px;
text-align: center;
font-style: italic;
display: table-cell;
vertical-align: middle;
font-size: 12px;
}
/* =======================================================================
@ -1591,10 +1627,13 @@ config*.tmpl
padding: 12px 0
}
.stepDiv .component-desc select,
.stepDiv .component-desc input,
#config div.field-pair select,
#config div.field-pair input {
margin-right: 6px;
}
.stepDiv .component-desc select,
.stepDiv .component-desc input {
margin-right: 15px;
}
@ -1870,7 +1909,7 @@ div.metadata_example label {
line-height: 21px;
display: block;
padding: 3px;
margin: 0px;
margin: 0;
}
div.metadata_options input {
margin-right: 3px;
@ -1883,7 +1922,7 @@ div.metadataDiv .disabled {
.notifier-icon {
float: left;
margin: 6px 4px 0px 0px;
margin: 6px 4px 0 0;
}
/* =======================================================================
@ -1915,7 +1954,7 @@ td.tableright {
text-align: left;
vertical-align: middle;
width: 225px;
padding: 6px 0px;
padding: 6px 0;
}
.optionWrapper div.selectChoices {
@ -1949,9 +1988,8 @@ Global
========================================================================== */
span.path {
padding: 3px 6px;
color: #8b0000;
background-color: #f5f1e4;
padding: 3px;
margin-left: 3px;
}
.align-left {
@ -1971,7 +2009,7 @@ span.quality {
background-image:linear-gradient(to bottom, rgba(255, 255, 255, 0.08),rgba(255, 255, 255, 0) 50%,rgba(0, 0, 0, 0) 50%,rgba(0, 0, 0, 0.25));
-webkit-box-shadow:inset 0 1px rgba(255, 255, 255, 0.1),inset 0 -1px 3px rgba(0, 0, 0, 0.3),inset 0 0 0 1px rgba(255, 255, 255, 0.08),0 1px 2px rgba(0, 0, 0, 0.15);
box-shadow:inset 0 1px rgba(255, 255, 255, 0.1),inset 0 -1px 3px rgba(0, 0, 0, 0.3),inset 0 0 0 1px rgba(255, 255, 255, 0.08),0 1px 2px rgba(0, 0, 0, 0.15);
text-shadow: 0px 1px rgba(0, 0, 0, 0.8);
text-shadow: 0 1px rgba(0, 0, 0, 0.8);
color: #FFFFFF;
display: inline-block;
padding: 2px 4px;
@ -2091,7 +2129,7 @@ div.blackwhitelist span {
}
div.blackwhitelist.anidb, div.blackwhitelist.manual {
margin: 7px 0px;
margin: 7px 0;
}
@ -2111,12 +2149,12 @@ html * {
}
input[type="checkbox"] {
margin: 2px 0px 0px;
margin: 2px 0 0;
line-height: normal;
}
input[type="radio"] {
margin: 2px 0px 0px;
margin: 2px 0 0;
line-height: normal;
}
@ -2131,7 +2169,7 @@ input, textarea, select, .uneditable-input {
}
.navbar-brand {
padding: 0px;
padding: 0;
}
/* navbar styling */
@ -2258,7 +2296,7 @@ fieldset[disabled] .navbar-default .btn-link:focus {
.dropdown-menu {
background-color: #F5F1E4;
border: 1px solid rgba(0, 0, 0, 0.15);
box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.176);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.176);
}
.form-control {
@ -2815,7 +2853,7 @@ div.formpaginate .prev, div.formpaginate .next {
.stepDiv.parent-folder {
padding: 15px 0 0;
width: 430px;
margin: 0px auto;
margin: 0 auto;
}
.stepDiv .nocheck {
@ -3153,6 +3191,15 @@ span.token-input-delete-token {
z-index: 0;
background-image: url(../images/poster-dark.jpg)
}
.time-am-pm {
margin-left: 2px;
}
#content.episodeview-banner .time-am-pm,
#content.episodeview-poster .time-am-pm {
margin-left: 0;
}
/* =======================================================================
jquery.confirm.css
========================================================================== */
@ -3177,7 +3224,7 @@ jquery.confirm.css
top: 50%;
margin: -130px 0 0 -230px;
border: 1px solid #111;
box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.175);
box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.175);
}
#confirmBox h1,
@ -3212,7 +3259,7 @@ jquery.confirm.css
display: inline-block;
color: #fff;
text-align:center;
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.75);
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.75);
background-clip: padding-box;
border: 1px solid #111;
border-radius: 3px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -90,8 +90,8 @@ addOption("postprocess", "process_method", "&process_method=copy");
addOption("postprocess", "type", "&type=manual")
addOption("sb.setdefaults", "Optional Param", "", 1);
addList("sb.setdefaults", "Exclude Paused Shows on ComingEps", "&future_show_paused=0", "sb.setdefaults-status");
addList("sb.setdefaults", "Include Paused Shows on ComingEps", "&future_show_paused=1", "sb.setdefaults-status");
addList("sb.setdefaults", "Exclude Paused Shows on EpisodeView", "&future_show_paused=0", "sb.setdefaults-status");
addList("sb.setdefaults", "Include Paused Shows on EpisodeView", "&future_show_paused=1", "sb.setdefaults-status");
addOption("sb.setdefaults-status", "Optional Param", "", 1);
addList("sb.setdefaults-status", "Wanted", "&status=wanted", "sb.setdefaults-opt");

View file

@ -1,549 +0,0 @@
#import sickbeard
#import datetime
#from sickbeard.common import *
#from sickbeard import sbdatetime
#from sickbeard.helpers import anon_url
#set global $title = 'Coming Episodes'
#set global $header = 'Coming Episodes'
#set global $sbPath = '..'
#set global $topmenu = 'comingEpisodes'
#import os.path
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_top.tmpl')
#set $sort = $sickbeard.COMING_EPS_SORT
<script type="text/javascript" src="$sbRoot/js/ajaxEpSearch.js?$sbPID"></script>
#if $varExists('header')
<h1 class="header">$header</h1>
#else
<h1 class="title">$title</h1>
#end if
<style type="text/css">
#SubMenu {display:none}
#contentWrapper {padding-top:30px}
</style>
<div class="h2footer pull-right">
<span>Layout:
<select name="layout" class="form-control form-control-inline input-sm" onchange="location = this.options[this.selectedIndex].value;">
<option value="$sbRoot/setComingEpsLayout/?layout=poster" #if 'poster' == $sickbeard.COMING_EPS_LAYOUT then 'selected="selected"' else ''#>Poster</option>
<option value="$sbRoot/setComingEpsLayout/?layout=calendar" #if 'calendar' == $sickbeard.COMING_EPS_LAYOUT then 'selected="selected"' else ''#>Calendar</option>
<option value="$sbRoot/setComingEpsLayout/?layout=banner" #if 'banner' == $sickbeard.COMING_EPS_LAYOUT then 'selected="selected"' else ''#>Banner</option>
<option value="$sbRoot/setComingEpsLayout/?layout=list" #if 'list' == $sickbeard.COMING_EPS_LAYOUT then 'selected="selected"' else ''#>List</option>
</select>
</span>
&nbsp;
<span>Sort By:
<select name="sort" class="form-control form-control-inline input-sm" onchange="location = this.options[this.selectedIndex].value;">
<option value="$sbRoot/setComingEpsSort/?sort=date" #if 'date' == $sickbeard.COMING_EPS_SORT then 'selected="selected"' else ''#>Date</option>
<option value="$sbRoot/setComingEpsSort/?sort=network" #if 'network' == $sickbeard.COMING_EPS_SORT then 'selected="selected"' else ''#>Network</option>
<option value="$sbRoot/setComingEpsSort/?sort=show" #if 'show' == $sickbeard.COMING_EPS_SORT then 'selected="selected"' else ''#>Show</option>
</select>
</span>
&nbsp;
<span>View Paused:
<select name="viewpaused" class="form-control form-control-inline input-sm" onchange="location = this.options[this.selectedIndex].value;">
<option value="$sbRoot/toggleComingEpsDisplayPaused"<%= (' selected="selected"', '')[True == sickbeard.COMING_EPS_DISPLAY_PAUSED] %>>Hidden</option>
<option value="$sbRoot/toggleComingEpsDisplayPaused"<%= ('', ' selected="selected"')[True == sickbeard.COMING_EPS_DISPLAY_PAUSED] %>>Shown</option>
</select>
</span>
</div>
<div class="key pull-right">
#if 'calendar' != $layout:
<b>Key:</b>
<span class="listing-key listing-overdue">Missed</span>
<span class="listing-key listing-current">Current</span>
<span class="listing-key listing-default">Future</span>
<span class="listing-key listing-toofar">Distant</span>
#end if
<a class="btn btn-inline forceBacklog" href="webcal://$sbHost:$sbHttpPort/calendar">
<i class="icon-calendar icon-white"></i>Subscribe</a>
</div>
<br>
#if 'list' == $layout:
<!-- start list view //-->
<script type="text/javascript" src="$sbRoot/js/plotTooltip.js?$sbPID"></script>
<script type="text/javascript" charset="utf-8">
<!--
\$.tablesorter.addParser({
id: 'loadingNames',
is: function(s) {
return false
},
format: function(s) {
if (0 == s.indexOf('Loading...'))
return s.replace('Loading...', '000')
#if not $sickbeard.SORT_ARTICLE:
return (s || '').replace(/^(?:(?:A(?!\s+to)n?)|The)\s(\w)/i, '$1')
#else:
return (s || '')
#end if
},
type: 'text'
});
\$.tablesorter.addParser({
id: 'quality',
is: function(s) {
return false
},
format: function(s) {
return s.replace('hd1080p', 5).replace('hd720p', 4).replace('hd', 3).replace('sd', 2).replace('any', 1).replace('best', 0).replace('custom', 7)
},
type: 'numeric'
});
\$.tablesorter.addParser({
id: 'cDate',
is: function(s) {
return false
},
format: function(s) {
return s
},
type: 'numeric'
});
\$(document).ready(function(){
#set $sort_codes = {'date': 0, 'show': 1, 'network': 4}
#if $sort not in $sort_codes:
$sort = 'date'
#end if
sortList = [[$sort_codes[$sort], 0]];
\$('#showListTable:has(tbody tr)').tablesorter({
widgets: ['stickyHeaders'],
sortList: sortList,
textExtraction: {
0: function(node) { return \$(node).find('span').text().toLowerCase() },
4: function(node) { return \$(node).find('img').attr('alt') },
5: function(node) { return \$(node).find('span').text().toLowerCase() }
},
headers: {
0: { sorter: 'cDate' },
1: { sorter: 'loadingNames' },
2: { sorter: false },
3: { sorter: false },
4: { sorter: 'loadingNames' },
5: { sorter: 'quality' },
6: { sorter: false },
7: { sorter: false },
8: { sorter: false }
}
});
\$('#sbRoot').ajaxEpSearch();
#set $fuzzydate = 'airdate'
#if $sickbeard.FUZZY_DATING:
fuzzyMoment({
containerClass : '.${fuzzydate}',
dateHasTime : true,
dateFormat : '${sickbeard.DATE_PRESET}',
timeFormat : '${sickbeard.TIME_PRESET}',
trimZero : #if $sickbeard.TRIM_ZERO then 'true' else 'false'#
});
#end if
});
//-->
</script>
#set $show_div = 'listing-default'
<input type="hidden" id="sbRoot" value="$sbRoot" />
<table id="showListTable" class="sickbeardTable tablesorter seasonstyle" cellspacing="1" border="0" cellpadding="0">
<thead>
<tr>
<th>Airdate</th>
<th>Show</th>
<th class="nowrap">Next Ep</th>
<th>Next Ep Name</th>
<th>Network</th>
<th>Quality</th>
<th>Indexers</th>
<th>Search</th>
</tr>
</thead>
<tbody style="text-shadow:none;">
#for $cur_result in $sql_results:
#set $cur_indexer = int($cur_result['indexer'])
#set $runtime = $cur_result['runtime']
#if int($cur_result['paused']) and not $sickbeard.COMING_EPS_DISPLAY_PAUSED:
#continue
#end if
#set $cur_ep_airdate = $cur_result['localtime'].date()
#if $runtime:
#set $cur_ep_enddate = $cur_result['localtime'] + datetime.timedelta(minutes = $runtime)
#if $cur_ep_enddate < $today:
#set $show_div = 'listing-overdue'
#elif $cur_ep_airdate >= $next_week.date():
#set $show_div = 'listing-toofar'
#elif $cur_ep_airdate >= $today.date() and $cur_ep_airdate < $next_week.date():
#if $cur_ep_airdate == $today.date():
#set $show_div = 'listing-current'
#else:
#set $show_div = 'listing-default'
#end if
#end if
#end if
<!-- start $cur_result['show_name'] //-->
<tr class="$show_div">
## forced to use a div to wrap airdate, the column sort went crazy with a span
<td align="center" class="nowrap">
<div class="${fuzzydate}">$sbdatetime.sbdatetime.sbfdatetime($cur_result['localtime']).decode($sickbeard.SYS_ENCODING)</div><span class="sort_data">$time.mktime($cur_result['localtime'].timetuple())</span>
</td>
<td class="tvShow"><a href="$sbRoot/home/displayShow?show=${cur_result['showid']}">$cur_result['show_name']</a>
#if int($cur_result['paused']):
<span class="pause">[paused]</span>
#end if
</td>
<td class="nowrap" align="center">
<%= 'S%02iE%02i' % (int(cur_result['season']), int(cur_result['episode'])) %>
</td>
<td>
#if $cur_result['description']:
<img alt='' src='$sbRoot/images/info32.png' height='16' width='16' class='plotInfo' id="plot_info_<%= '%s_%s_%s' % (str(cur_result['showid']), str(cur_result['season']), str(cur_result['episode'])) %>" />
#else:
<img alt="" src="$sbRoot/images/info32.png" width="16" height="16" class="plotInfoNone" />
#end if
$cur_result['name']
</td>
<td align="center">
$cur_result['network']
</td>
<td align="center">
#if int($cur_result['quality']) in $qualityPresets:
<span class="quality $qualityPresetStrings[int($cur_result['quality'])]">$qualityPresetStrings[int($cur_result['quality'])]</span>
#else:
<span class="quality Custom">Custom</span>
#end if
</td>
<td align="center" style="vertical-align: middle;">
#if $cur_result['imdb_id']:
<a href="<%= anon_url('http://www.imdb.com/title/', cur_result['imdb_id']) %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false" title="http://www.imdb.com/title/${cur_result['imdb_id']}"><img alt="[imdb]" height="16" width="16" src="$sbRoot/images/imdb.png" />
#end if
<a href="<%= anon_url(sickbeard.indexerApi(cur_indexer).config['show_url'], cur_result['showid']) %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false" title="$sickbeard.indexerApi($cur_indexer).config['show_url']${cur_result['showid']}"><img alt="$sickbeard.indexerApi($cur_indexer).name" height="16" width="16" src="$sbRoot/images/$sickbeard.indexerApi($cur_indexer).config['icon']" /></a>
</td>
<td align="center">
<a href="$sbRoot/home/searchEpisode?show=${cur_result['showid']}&amp;season=$cur_result['season']&amp;episode=$cur_result['episode']" title="Manual Search" id="forceUpdate-${cur_result['showid']}" class="forceUpdate epSearch"><img alt="[search]" height="16" width="16" src="$sbRoot/images/search16.png" id="forceUpdateImage-${cur_result['showid']}" /></a>
</td>
</tr>
<!-- end $cur_result['show_name'] //-->
#end for
</tbody>
<tfoot>
<tr>
<th rowspan="1" colspan="10" align="center">&nbsp</th>
</tr>
</tfoot>
</table>
<!-- end list view //-->
#else if $layout in ['banner', 'poster']:
<!-- start non list view //-->
<script type="text/javascript" charset="utf-8">
<!--
\$(document).ready(function(){
\$('#sbRoot').ajaxEpSearch({'size': 16, 'loadingImage': 'loading16' + themeSpinner + '.gif'});
\$('.ep_summary').hide();
\$('.ep_summaryTrigger').click(function() {
\$(this).next('.ep_summary').slideToggle('normal', function() {
\$(this).prev('.ep_summaryTrigger').attr('src', function(i, src) {
return \$(this).next('.ep_summary').is(':visible') ? src.replace('plus','minus') : src.replace('minus','plus')
});
});
});
#set $fuzzydate = 'airdate'
#if $sickbeard.FUZZY_DATING:
fuzzyMoment({
dtInline : true,
dtGlue : ' at ',
containerClass : '.${fuzzydate}',
dateHasTime : true,
dateFormat : '${sickbeard.DATE_PRESET}',
timeFormat : '${sickbeard.TIME_PRESET}',
trimZero : #if $sickbeard.TRIM_ZERO then 'true' else 'false'#
});
#end if
});
//-->
</script>
#set $cur_segment = None
#set $too_late_header = False
#set $missed_header = False
#set $today_header = False
#set $show_div = 'ep_listing listing-default'
#if 'show' == $sort:
<br /><br />
#end if
#for $cur_result in $sql_results:
#set $cur_indexer = int($cur_result['indexer'])
<!-- start $cur_result['show_name'] //-->
#if int($cur_result['paused']) and not $sickbeard.COMING_EPS_DISPLAY_PAUSED:
#continue
#end if
#set $runtime = $cur_result['runtime']
#if 'network' == $sort:
#set $show_network = $cur_result['network'] if $cur_result['network'] else 'no network'
#if $cur_segment != $show_network:
<div class="comingepheader">
<br><h2 class="network">$show_network</h2>
#set $cur_segment = $cur_result['network']
#end if
#set $cur_ep_airdate = $cur_result['localtime'].date()
#if $runtime:
#set $cur_ep_enddate = $cur_result['localtime'] + datetime.timedelta(minutes = $runtime)
#if $cur_ep_enddate < $today:
#set $show_div = 'ep_listing listing-overdue'
#elif $cur_ep_airdate >= $next_week.date():
#set $show_div = 'ep_listing listing-toofar'
#elif $cur_ep_enddate >= $today and $cur_ep_airdate < $next_week.date():
#if $cur_ep_airdate == $today.date():
#set $show_div = 'ep_listing listing-current'
#else:
#set $show_div = 'ep_listing listing-default'
#end if
#end if
#end if
#elif 'date' == $sort:
#set $cur_ep_airdate = $cur_result['localtime'].date()
#if $cur_segment != $cur_ep_airdate:
#if $runtime:
#set $cur_ep_enddate = $cur_result['localtime'] + datetime.timedelta(minutes = $runtime)
#if $cur_ep_enddate < $today and $cur_ep_airdate != $today.date() and not $missed_header:
<br /><h2 class="day">Missed</h2>
#set $missed_header = True
#elif $cur_ep_airdate >= $next_week.date() and not $too_late_header:
<br /><h2 class="day">Later</h2>
#set $too_late_header = True
#elif $cur_ep_enddate >= $today and $cur_ep_airdate < $next_week.date():
#if $cur_ep_airdate == $today.date():
<br /><h2 class="day">$sbdatetime.sbdatetime.sbfdate($cur_ep_airdate, '%A').decode($sickbeard.SYS_ENCODING).capitalize() <span style="font-size: 14px; vertical-align: top;">[Today]</span></h2>
#set $today_header = True
#else:
<br /><h2 class="day">$sbdatetime.sbdatetime.sbfdate($cur_ep_airdate, '%A').decode($sickbeard.SYS_ENCODING).capitalize()</h2>
#end if
#end if
#end if
#set $cur_segment = $cur_ep_airdate
#end if
#if $cur_ep_airdate == $today.date() and not $today_header:
<div class="comingepheader">
<br /><h2 class="day">$sbdatetime.sbdatetime.sbfdate($cur_ep_airdate, '%A').decode($sickbeard.SYS_ENCODING).capitalize() <span style="font-size: 14px; vertical-align: top;">[Today]</span></h2>
#set $today_header = True
#end if
#if $runtime:
#set $cur_ep_enddate = $cur_result['localtime'] + datetime.timedelta(minutes = $runtime)
#if $cur_ep_enddate < $today:
#set $show_div = 'ep_listing listing-overdue'
#elif $cur_ep_airdate >= $next_week.date():
#set $show_div = 'ep_listing listing-toofar'
#elif $cur_ep_enddate >= $today and $cur_ep_airdate < $next_week.date():
#if $cur_ep_airdate == $today.date():
#set $show_div = 'ep_listing listing-current'
#else:
#set $show_div = 'ep_listing listing-default'
#end if
#end if
#end if
#elif 'show' == $sort:
#set $cur_ep_airdate = $cur_result['localtime'].date()
#if $runtime:
#set $cur_ep_enddate = $cur_result['localtime'] + datetime.timedelta(minutes = $runtime)
#if $cur_ep_enddate < $today:
#set $show_div = 'ep_listing listing-overdue listingradius'
#elif $cur_ep_airdate >= $next_week.date():
#set $show_div = 'ep_listing listing-toofar listingradius'
#elif $cur_ep_enddate >= $today and $cur_ep_airdate < $next_week.date():
#if $cur_ep_airdate == $today.date():
#set $show_div = 'ep_listing listing-current listingradius'
#else:
#set $show_div = 'ep_listing listing-default listingradius'
#end if
#end if
#end if
#end if
<div class="$show_div" id="listing-${cur_result['showid']}">
<div class="tvshowDiv">
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<th #if 'banner' == $layout then 'class="nobg"' else 'rowspan="2"'# valign="top">
<a href="$sbRoot/home/displayShow?show=${cur_result['showid']}"><img alt="" class="#if 'banner' == $layout then 'bannerThumb' else 'posterThumb'#" src="$sbRoot/showPoster/?show=${cur_result['showid']}&amp;which=#if 'poster' == $layout then 'poster_thumb' else $layout#" /></a>
</th>
#if 'banner' == $layout:
</tr>
<tr>
#end if
<td class="next_episode">
<div class="clearfix">
<span class="tvshowTitle">
<a href="$sbRoot/home/displayShow?show=${cur_result['showid']}">$cur_result['show_name']
#if int($cur_result['paused']):
<span class="pause">[paused]</span>
#end if
</a></span>
<span class="tvshowTitleIcons">
#if $cur_result['imdb_id']:
<a href="<%= anon_url('http://www.imdb.com/title/', cur_result['imdb_id']) %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false" title="http://www.imdb.com/title/${cur_result['imdb_id']}"><img alt="[imdb]" height="16" width="16" src="$sbRoot/images/imdb.png" />
#end if
<a href="<%= anon_url(sickbeard.indexerApi(cur_indexer).config['show_url'], cur_result['showid']) %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false" title="$sickbeard.indexerApi($cur_indexer).config['show_url']${cur_result['showid']}"><img alt="$sickbeard.indexerApi($cur_indexer).name" height="16" width="16" src="$sbRoot/images/$sickbeard.indexerApi($cur_indexer).config['icon']" /></a>
<span><a href="$sbRoot/home/searchEpisode?show=${cur_result['showid']}&amp;season=$cur_result['season']&amp;episode=$cur_result['episode']" title="Manual Search" id="forceUpdate-${cur_result['showid']}" class="epSearch forceUpdate"><img alt="[search]" height="16" width="16" src="$sbRoot/images/search16.png" id="forceUpdateImage-${cur_result['showid']}" /></a></span>
</span>
</div>
<span class="title">Next Episode:</span> <span><%= 'S%02iE%02i' % (int(cur_result['season']), int(cur_result['episode'])) %> - $cur_result['name']</span>
<div class="clearfix">
<span class="title">Airs: </span><span class="${fuzzydate}">$sbdatetime.sbdatetime.sbfdatetime($cur_result['localtime']).decode($sickbeard.SYS_ENCODING)</span><%= ('', '<span> on %s</span>' % str(cur_result['network']))[None is not cur_result['network']] %>
</div>
<div class="clearfix">
<span class="title">Quality:</span>
#if int($cur_result['quality']) in $qualityPresets:
<span class="quality $qualityPresetStrings[int($cur_result['quality'])]">$qualityPresetStrings[int($cur_result['quality'])]</span>
#else:
<span class="quality Custom">Custom</span>
#end if
</div>
</td>
</tr>
<tr>
<td style="vertical-align: top;">
<div>
#if $cur_result['description']:
<span class="title" style="vertical-align:middle;">Plot:</span>
<img class="ep_summaryTrigger" src="$sbRoot/images/plus.png" height="16" width="16" alt="" title="Toggle Summary" /><div class="ep_summary">$cur_result['description']</div>
#else:
<span class="title ep_summaryTriggerNone" style="vertical-align:middle;">Plot:</span>
<img class="ep_summaryTriggerNone" src="$sbRoot/images/plus.png" height="16" width="16" alt="" />
#end if
</div>
</td>
</tr>
</table>
</div>
</div>
<!-- end $cur_result['show_name'] //-->
#end for
<!-- end non list view //-->
#end if
#if 'calendar' == $layout:
#set $today = datetime.date.today()
#set $dates = [$today + datetime.timedelta(days = $i) for $i in range(7)]
#set $tbl_day = 0
<br>
<br>
<div class="calendarWrapper">
<input type="hidden" id="sbRoot" value="$sbRoot" />
#for $day in $dates
#set $tbl_day += 1
<table class="sickbeardTable tablesorter calendarTable <%= 'cal-%s' % (('even', 'odd')[1 == tbl_day % 2]) %>" cellspacing="0" border="0" cellpadding="0">
<thead><tr><th>$sbdatetime.sbdatetime.sbfdate($day, '%A').decode($sickbeard.SYS_ENCODING).capitalize()</th></tr></thead>
<tbody>
#set $day_has_show = False
#for $cur_result in $sql_results:
#if int($cur_result['paused']) and not $sickbeard.COMING_EPS_DISPLAY_PAUSED:
#continue
#end if
#set $cur_indexer = int($cur_result['indexer'])
#set $runtime = $cur_result['runtime']
#set $airday = $cur_result['localtime'].date()
#if $airday == $day:
#set $day_has_show = True
#set $airtime = $sbdatetime.sbdatetime.sbftime($cur_result['localtime']).decode($sickbeard.SYS_ENCODING)
#if $sickbeard.TRIM_ZERO:
#set $airtime = re.sub(r'0(\d:\d\d)', r'\1', $airtime, 0, re.IGNORECASE | re.MULTILINE)
#end if
<tr>
<td class="calendarShow">
<div class="poster">
<a title="${cur_result['show_name']}" href="$sbRoot/home/displayShow?show=${cur_result['showid']}"><img alt="" src="$sbRoot/showPoster/?show=${cur_result['showid']}&amp;which=poster_thumb" /></a>
</div>
<div class="text">
<span class="airtime">
${airtime} on $cur_result["network"]
</span>
<span class="episode-title" title="$cur_result['name']">
<%= 'S%02iE%02i' % (int(cur_result['season']), int(cur_result['episode'])) %> - $cur_result['name']
</span>
</div>
</td> <!-- end $cur_result['show_name'] -->
</tr>
#end if
#end for
#if not $day_has_show:
<tr><td class="calendarShow"><span class="show-status">No shows for this day</span></td></tr>
#end if
</tbody>
</table>
#end for
<!-- end calender view //-->
</div>
#end if
<div class="clearfix"></div>
<script type="text/javascript" charset="utf-8">
<!--
window.setInterval('location.reload(true)', 600000); // Refresh every 10 minutes
//-->
</script>
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_bottom.tmpl')

View file

@ -246,10 +246,10 @@
</div>
<div class="field-pair show_if_fuzzy_dating#if True == $sickbeard.FUZZY_DATING then '' else ' metadataDiv'#">
<label for="trim_zero">
<span class="component-title">Trim zero padding</span>
<span class="component-title">Trim date and time</span>
<span class="component-desc">
<input type="checkbox" name="trim_zero" id="trim_zero" #if True == $sickbeard.TRIM_ZERO then 'checked="checked"' else ''#/>
<p>remove the leading number "0" shown on hour of day, and date of month</p>
<p>display minimalist date and time i.e. <del>02:00</del> = 2:00, <del>02:00pm</del> = 2pm, <del>03 Jan</del> = 3 Jan</p>
</span>
</label>
</div>
@ -280,10 +280,11 @@
<span class="component-desc">
<select id="time_presets" name="time_preset" class="form-control input-sm">
#for $cur_preset in $time_presets:
<option value="$cur_preset" #if $cur_preset == $sickbeard.TIME_PRESET_W_SECONDS then 'selected="selected"' else ''#>$sbdatetime.now().sbftime(show_seconds=True,t_preset=$cur_preset)</option>
#set $show_seconds = not $sickbeard.FUZZY_DATING
<option value="$cur_preset" #if $cur_preset == $sickbeard.TIME_PRESET_W_SECONDS then 'selected="selected"' else ''#>$sbdatetime.now().sbftime(show_seconds=$show_seconds, t_preset=$cur_preset)</option>
#end for
</select>
<span><b>note:</b> seconds are only shown on the History page</span>
<span id="trim_info_seconds"><b>note:</b> seconds are only shown on the History page</span>
</span>
</label>
</div>
@ -460,6 +461,24 @@
</label>
</div>
#set pulls = sickbeard.versionCheckScheduler.action.list_remote_pulls()
#if len(pulls) > 0 and $sickbeard.BRANCH != 'master':
<div class="field-pair">
<label>
<span class="component-title">Pull request:</span>
<span class="component-desc">
<select id="pullRequestVersion" class="form-control form-control-inline input-sm pull-left">
#for $cur_branch in $pulls:
<option value="$cur_branch.fetch_name()" #if $cur_branch == $sickbeard.BRANCH then 'selected="selected"' else ''#>$cur_branch</option>
#end for
</select>
<input class="btn btn-inline" style="margin-left: 6px;" type="button" id="pullRequestCheckout" value="Checkout Pull Request">
<div class="clear-left"><p>select pull request to test (restart required)</p></div>
</span>
</label>
</div>
#end if
<div class="field-pair">
<label for="git_remote">
<span class="component-title">Git remote for branch</span>
@ -551,7 +570,7 @@
</div><!-- /component-group3 //-->
<br/>
<h6 class="pull-right"><b>All non-absolute folder locations are relative to <span class="path">$sickbeard.DATA_DIR</span></b> </h6>
<h6 class="pull-right"><b class="boldest">All non-absolute folder locations are relative to <span class="path">$sickbeard.DATA_DIR</span></b></h6>
<input type="submit" class="btn pull-left config_submitter button" value="Save Changes" />
</div><!-- /config-components -->

View file

@ -214,13 +214,13 @@
</div>
#end if
#if $hasattr($curNewznabProvider, 'enable_daily'):
#if $hasattr($curNewznabProvider, 'enable_recentsearch'):
<div class="field-pair">
<label for="${curNewznabProvider.getID()}_enable_daily">
<span class="component-title">Enable daily searches</span>
<label for="${curNewznabProvider.getID()}_enable_recentsearch">
<span class="component-title">Enable recent searches</span>
<span class="component-desc">
<input type="checkbox" name="${curNewznabProvider.getID()}_enable_daily" id="${curNewznabProvider.getID()}_enable_daily" <%= html_checked if curNewznabProvider.enable_daily else '' %>/>
<p>perform daily searches at provider</p>
<input type="checkbox" name="${curNewznabProvider.getID()}_enable_recentsearch" id="${curNewznabProvider.getID()}_enable_recentsearch" <%= html_checked if curNewznabProvider.enable_recentsearch else '' %>/>
<p>perform recent searches at provider</p>
</span>
</label>
</div>
@ -292,13 +292,13 @@
#end if
#if $hasattr($curNzbProvider, 'enable_daily'):
#if $hasattr($curNzbProvider, 'enable_recentsearch'):
<div class="field-pair">
<label for="${curNzbProvider.getID()}_enable_daily">
<span class="component-title">Enable daily searches</span>
<label for="${curNzbProvider.getID()}_enable_recentsearch">
<span class="component-title">Enable recent searches</span>
<span class="component-desc">
<input type="checkbox" name="${curNzbProvider.getID()}_enable_daily" id="${curNzbProvider.getID()}_enable_daily" <%= html_checked if curNzbProvider.enable_daily else '' %>/>
<p>enable provider to perform daily searches.</p>
<input type="checkbox" name="${curNzbProvider.getID()}_enable_recentsearch" id="${curNzbProvider.getID()}_enable_recentsearch" <%= html_checked if curNzbProvider.enable_recentsearch else '' %>/>
<p>enable provider to perform recent searches.</p>
</span>
</label>
</div>
@ -512,13 +512,13 @@
</div>
#end if
#if $hasattr($curTorrentProvider, 'enable_daily'):
#if $hasattr($curTorrentProvider, 'enable_recentsearch'):
<div class="field-pair">
<label for="${curTorrentProvider.getID()}_enable_daily">
<span class="component-title">Enable daily searches</span>
<label for="${curTorrentProvider.getID()}_enable_recentsearch">
<span class="component-title">Enable recent searches</span>
<span class="component-desc">
<input type="checkbox" name="${curTorrentProvider.getID()}_enable_daily" id="${curTorrentProvider.getID()}_enable_daily" <%= html_checked if curTorrentProvider.enable_daily else '' %>/>
<p>enable provider to perform daily searches.</p>
<input type="checkbox" name="${curTorrentProvider.getID()}_enable_recentsearch" id="${curTorrentProvider.getID()}_enable_recentsearch" <%= html_checked if curTorrentProvider.enable_recentsearch else '' %>/>
<p>enable provider to perform recent searches.</p>
</span>
</label>
</div>

View file

@ -90,10 +90,10 @@
<div class="field-pair">
<label>
<span class="component-title">Daily search frequency</span>
<span class="component-title">Recent search frequency</span>
<span class="component-desc">
<input type="text" name="dailysearch_frequency" value="$sickbeard.DAILYSEARCH_FREQUENCY" class="form-control input-sm input75" />
<p>time in minutes between searches (min. $sickbeard.MIN_DAILYSEARCH_FREQUENCY)</p>
<input type="text" name="recentsearch_frequency" value="$sickbeard.RECENTSEARCH_FREQUENCY" class="form-control input-sm input75" />
<p>time in minutes between searches (min. $sickbeard.MIN_RECENTSEARCH_FREQUENCY)</p>
</span>
</label>
</div>
@ -139,11 +139,11 @@
</div>
<div class="field-pair">
<label for="dailysearch_startup">
<span class="component-title">Daily search on startup</span>
<label for="recentsearch_startup">
<span class="component-title">Recent search on startup</span>
<span class="component-desc">
<input type="checkbox" name="dailysearch_startup" id="dailysearch_startup" <%= html_checked if sickbeard.DAILYSEARCH_STARTUP == True else '' %>/>
<p>start daily search on startup of SickGear</p>
<input type="checkbox" name="recentsearch_startup" id="recentsearch_startup" <%= html_checked if sickbeard.RECENTSEARCH_STARTUP == True else '' %>/>
<p>start recent search on startup of SickGear</p>
</span>
</label>
</div>
@ -421,6 +421,7 @@
<div class="clear-left">
<p id="host_desc_torrent">URL to your torrent client (e.g. http://localhost:8000/)</p>
<p id="host_desc_rtorrent" style="display:none"><b>Note:</b> <i>rTorrent</i> client URLs use e.g. scgi://localhost:5000/</p>
<p id="host_desc_deluge" style="display:none">URL to your Deluge WebUI (e.g. http://localhost:8112/)</p>
</div>
</span>
</label>
@ -436,7 +437,7 @@
</label>
</div>
<div class="field-pair">
<div class="field-pair" id="torrent_username_option">
<label>
<span class="component-title" id="username_title">Client username</span>
<span class="component-desc">

View file

@ -0,0 +1,695 @@
#import sickbeard
#import datetime
#from sickbeard.common import *
#from sickbeard import sbdatetime
#from sickbeard.helpers import anon_url
#set global $title = 'Episode View'
#set global $header = 'Episode View'
#set global $sbPath = '..'
#set global $topmenu = 'episodeView'
#import os.path
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_top.tmpl')
#set $sort = $sickbeard.EPISODE_VIEW_SORT
#set $table_sort_header_codes = {'time': 0, 'show': 1, 'network': 4}
#if $sort not in $table_sort_header_codes:
#set $sort = 'time'
#end if
#if 'daybyday' != $layout:
<script type="text/javascript" src="$sbRoot/js/ajaxEpSearch.js?$sbPID"></script>
#end if
#if $varExists('header')
<h1 class="header">$header</h1>
#else
<h1 class="title">$title</h1>
#end if
#if 'daybyday' == $layout:
<script type="text/javascript" src="$sbRoot/js/plotTooltip.js?$sbPID"></script>
<script type="text/javascript" charset="utf-8">
<!--
\$(document).ready(function(){
var \$container = [];
\$.each(\$('[id^=day]'), function(){\$container.push(\$('#' + \$(this).attr('id')))});
jQuery.each(\$container, function(j) {
this.isotope({
itemSelector: '.daybyday-show',
sortBy : '$sort',
layoutMode: 'vertical',
transitionDuration: 0,
getSortData: {
network: function(itemElem) {
return \$(itemElem).attr('data-network') || '';
},
showname: function(itemElem) {
return \$(itemElem).attr('data-name') || '';
},
season: function(itemElem) {
var season = \$(itemElem).attr('data-season') || '0';
return season.length && parseInt(season, 10);
},
episode: function(itemElem) {
var episode = \$(itemElem).attr('data-episode') || '0';
return episode.length && parseInt(episode, 10);
},
time: function(itemElem) {
var time = \$(itemElem).attr('data-time') || '0';
return time.length && parseInt(time, 10);
}
}
});
});
imagesLoaded('.daybyday-show', function() {
jQuery.each(\$container, function(j) {
this.isotope('layout');
});
});
var uiSortBy = (function(sortBy) {
var sortCriteria;
switch (sortBy) {
case 'network':
sortCriteria = ['network', 'time', 'showname', 'season', 'episode'];
break;
case 'show':
sortCriteria = ['showname', 'time', 'season', 'episode'];
break;
case 'time':
default:
sortCriteria = ['time', 'showname', 'season', 'episode'];
break;
}
jQuery.each(\$container, function(j) {
this.isotope({
sortBy: sortCriteria,
sortAscending: 'asc' == \$('#sort-dir').attr('data-sort-dir')
});
});
});
\$('#sort').on('change', function() {
uiSortBy(this.value);
\$.get(this.options[this.selectedIndex].getAttribute('data-sort'));
});
\$('#sort-dir').on('click', function() {
var sortdir = \$(this).attr('data-sort-dir'),
newdir = ('asc' == sortdir ? 'desc' : 'asc');
\$(this).attr('data-sort-dir', newdir);
\$(this).attr('title', 'Click to sort ' + sortdir + 'ending');
\$(this).removeClass(sortdir).addClass(newdir);
uiSortBy(\$('#sort').val());
});
});
//-->
</script>
#end if
<style type="text/css">
#SubMenu {display:none}
#if 'daybyday' == $layout:
.caret {
cursor: pointer;
vertical-align: middle;
margin-right: 2px;
}
.asc {
border-top: 0;
border-bottom: 8px solid;
}
.desc {
border-top: 8px solid;
border-bottom: 0;
}
#end if
</style>
<div class="h2footer pull-right">
<span>Layout:
<select name="layout" class="form-control form-control-inline input-sm" onchange="location = this.options[this.selectedIndex].value;">
<option value="$sbRoot/setEpisodeViewLayout/?layout=banner" #if 'banner' == $sickbeard.EPISODE_VIEW_LAYOUT then 'selected="selected"' else ''#>Banner</option>
<option value="$sbRoot/setEpisodeViewLayout/?layout=daybyday" #if 'daybyday' == $sickbeard.EPISODE_VIEW_LAYOUT then 'selected="selected"' else ''#>Day by Day</option>
<option value="$sbRoot/setEpisodeViewLayout/?layout=list" #if 'list' == $sickbeard.EPISODE_VIEW_LAYOUT then 'selected="selected"' else ''#>List</option>
<option value="$sbRoot/setEpisodeViewLayout/?layout=poster" #if 'poster' == $sickbeard.EPISODE_VIEW_LAYOUT then 'selected="selected"' else ''#>Poster</option>
</select>
</span>
&nbsp;
<span>Sort
#if 'daybyday' == $layout:
<span id="sort-dir" data-sort-dir="asc" class="caret asc" title="Click to sort descending">&nbsp;</span>
#end if
By
#if 'daybyday' == $layout:
<select name="sort" id="sort" class="form-control form-control-inline input-sm">
<option value="network" data-sort="$sbRoot/setEpisodeViewSort/?sort=network&redir=0" #if 'network' == $sort then 'selected="selected"' else ''#>Network</option>
<option value="show" data-sort="$sbRoot/setEpisodeViewSort/?sort=show&redir=0" #if 'show' == $sort then 'selected="selected"' else ''#>Show</option>
<option value="time" data-sort="$sbRoot/setEpisodeViewSort/?sort=time&redir=0" #if 'time' == $sort then 'selected="selected"' else ''#>Time</option>
#else
<select name="sort" class="form-control form-control-inline input-sm" onchange="location = this.options[this.selectedIndex].value;">
<option value="$sbRoot/setEpisodeViewSort/?sort=time" #if 'time' == $sort then 'selected="selected"' else ''#>Date/Time</option>
<option value="$sbRoot/setEpisodeViewSort/?sort=network" #if 'network' == $sort then 'selected="selected"' else ''#>Network</option>
<option value="$sbRoot/setEpisodeViewSort/?sort=show" #if 'show' == $sort then 'selected="selected"' else ''#>Show</option>
#end if
</select>
</span>
&nbsp;
<span>View Paused:
<select name="viewpaused" class="form-control form-control-inline input-sm" onchange="location = this.options[this.selectedIndex].value;">
<option value="$sbRoot/toggleEpisodeViewDisplayPaused"<%= (' selected="selected"', '')[True == sickbeard.EPISODE_VIEW_DISPLAY_PAUSED] %>>Hidden</option>
<option value="$sbRoot/toggleEpisodeViewDisplayPaused"<%= ('', ' selected="selected"')[True == sickbeard.EPISODE_VIEW_DISPLAY_PAUSED] %>>Shown</option>
</select>
</span>
</div>
<div class="key pull-right">
#if 'daybyday' != $layout:
<b>Key:</b>
<span class="listing-key listing-overdue">Missed</span>
<span class="listing-key listing-current">Current</span>
<span class="listing-key listing-default">Future</span>
<span class="listing-key listing-toofar">Distant</span>
#end if
<a class="btn btn-inline forceBacklog" href="webcal://$sbHost:$sbHttpPort/calendar">
<i class="icon-calendar icon-white"></i>Subscribe</a>
</div>
<br>
#if 'list' == $layout:
<!-- start list view //-->
<script type="text/javascript" src="$sbRoot/js/plotTooltip.js?$sbPID"></script>
<script type="text/javascript" charset="utf-8">
<!--
\$.tablesorter.addParser({
id: 'loadingNames',
is: function(s) {
return false
},
format: function(s) {
if(0 == s.indexOf('Loading...'))
return s.replace('Loading...', '000')
return (s || '')
},
type: 'text'
});
\$.tablesorter.addParser({
id: 'quality',
is: function(s) {
return false
},
format: function(s) {
return s.replace('hd1080p', 5).replace('hd720p', 4).replace('hd', 3).replace('sd', 2).replace('any', 1).replace('best', 0).replace('custom', 7)
},
type: 'numeric'
});
\$.tablesorter.addParser({
id: 'cDate',
is: function(s) {
return false
},
format: function(s) {
return s
},
type: 'numeric'
});
\$(document).ready(function(){
sortList = [[$table_sort_header_codes[$sort], 0]];
\$('#showListTable:has(tbody tr)').tablesorter({
widgets: ['stickyHeaders'],
sortList: sortList,
textExtraction: {
0: function(node) {return \$(node).find('span').text().toLowerCase() || ''},
1: function(node) {return \$(node).find('a').attr('data-name') || ''},
4: function(node) {return \$(node).find('span').attr('data-network') || ''},
5: function(node) {return \$(node).find('span').text().toLowerCase() || ''}
},
headers: {
0: {sorter: 'cDate'},
1: {sorter: 'loadingNames'},
2: {sorter: false},
3: {sorter: false},
4: {sorter: 'loadingNames'},
5: {sorter: 'quality'},
6: {sorter: false},
7: {sorter: false},
8: {sorter: false}
}
});
\$('#sbRoot').ajaxEpSearch();
#set $fuzzydate = 'airdate'
#if $sickbeard.FUZZY_DATING:
fuzzyMoment({
containerClass : '.${fuzzydate}',
dateHasTime : true,
dateFormat : '${sickbeard.DATE_PRESET}',
timeFormat : '${sickbeard.TIME_PRESET}',
trimZero : #if $sickbeard.TRIM_ZERO then 'true' else 'false'#
});
#end if
});
//-->
</script>
#set $show_div = 'listing-default'
<input type="hidden" id="sbRoot" value="$sbRoot" />
<table id="showListTable" class="sickbeardTable tablesorter seasonstyle" cellspacing="1" border="0" cellpadding="0">
<thead>
<tr>
<th>Airdate</th>
<th>Show</th>
<th class="nowrap">Next Ep</th>
<th>Next Ep Name</th>
<th>Network</th>
<th>Quality</th>
<th>Indexers</th>
<th>Search</th>
</tr>
</thead>
<tbody style="text-shadow:none;">
#for $cur_result in $sql_results:
#set $cur_indexer = int($cur_result['indexer'])
#set $runtime = $cur_result['runtime']
#if int($cur_result['paused']) and not $sickbeard.EPISODE_VIEW_DISPLAY_PAUSED:
#continue
#end if
#set $cur_ep_airdate = $cur_result['localtime'].date()
#if $runtime:
#set $cur_ep_enddate = $cur_result['localtime'] + datetime.timedelta(minutes = $runtime)
#if $cur_ep_enddate < $today:
#set $show_div = 'listing-overdue'
#elif $cur_ep_airdate >= $next_week.date():
#set $show_div = 'listing-toofar'
#elif $cur_ep_airdate >= $today.date() and $cur_ep_airdate < $next_week.date():
#if $cur_ep_airdate == $today.date():
#set $show_div = 'listing-current'
#else:
#set $show_div = 'listing-default'
#end if
#end if
#end if
<!-- start $cur_result['show_name'] //-->
<tr class="$show_div">
## forced to use a div to wrap airdate, the column sort went crazy with a span
<td align="center" class="nowrap">
<div class="${fuzzydate}">$sbdatetime.sbdatetime.sbfdatetime($cur_result['localtime']).decode($sickbeard.SYS_ENCODING)</div><span class="sort_data">$time.mktime($cur_result['localtime'].timetuple())</span>
</td>
<td class="tvShow"><a href="$sbRoot/home/displayShow?show=${cur_result['showid']}" data-name="$cur_result['data_show_name']">$cur_result['show_name']</a>
#if int($cur_result['paused']):
<span class="pause">[paused]</span>
#end if
</td>
<td class="nowrap" align="center">
<%= 'S%02iE%02i' % (int(cur_result['season']), int(cur_result['episode'])) %>
</td>
<td>
#if $cur_result['description']:
<img alt="" src="$sbRoot/images/info32.png" height="16" width="16" class="plotInfo" id="plot_info_<%= '%s_%s_%s' % (str(cur_result['showid']), str(cur_result['season']), str(cur_result['episode'])) %>" />
#else:
<img alt="" src="$sbRoot/images/info32.png" width="16" height="16" class="plotInfoNone" />
#end if
$cur_result['name']
</td>
<td align="center">
<span data-network="$cur_result['data_network']">$cur_result['network']</span>
</td>
<td align="center">
#if int($cur_result['quality']) in $qualityPresets:
<span class="quality $qualityPresetStrings[int($cur_result['quality'])]">$qualityPresetStrings[int($cur_result['quality'])]</span>
#else:
<span class="quality Custom">Custom</span>
#end if
</td>
<td align="center" style="vertical-align: middle;">
#if $cur_result['imdb_id']:
<a href="<%= anon_url('http://www.imdb.com/title/', cur_result['imdb_id']) %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false" title="http://www.imdb.com/title/${cur_result['imdb_id']}"><img alt="[imdb]" height="16" width="16" src="$sbRoot/images/imdb.png" />
#end if
<a href="<%= anon_url(sickbeard.indexerApi(cur_indexer).config['show_url'], cur_result['showid']) %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false" title="$sickbeard.indexerApi($cur_indexer).config['show_url']${cur_result['showid']}"><img alt="$sickbeard.indexerApi($cur_indexer).name" height="16" width="16" src="$sbRoot/images/$sickbeard.indexerApi($cur_indexer).config['icon']" /></a>
</td>
<td align="center">
<a href="$sbRoot/home/searchEpisode?show=${cur_result['showid']}&amp;season=$cur_result['season']&amp;episode=$cur_result['episode']" title="Manual Search" id="forceUpdate-${cur_result['showid']}" class="forceUpdate epSearch"><img alt="[search]" height="16" width="16" src="$sbRoot/images/search16.png" id="forceUpdateImage-${cur_result['showid']}" /></a>
</td>
</tr>
<!-- end $cur_result['show_name'] //-->
#end for
</tbody>
<tfoot>
<tr>
<th rowspan="1" colspan="10" align="center">&nbsp</th>
</tr>
</tfoot>
</table>
<!-- end list view //-->
#else if $layout in ['banner', 'poster']:
<!-- start non list view //-->
<script type="text/javascript" charset="utf-8">
<!--
\$(document).ready(function(){
\$('#sbRoot').ajaxEpSearch({'size': 16, 'loadingImage': 'loading16' + themeSpinner + '.gif'});
\$('.ep_summary').hide();
\$('.ep_summaryTrigger').click(function() {
\$(this).next('.ep_summary').slideToggle('normal', function() {
\$(this).prev('.ep_summaryTrigger').attr('src', function(i, src) {
return \$(this).next('.ep_summary').is(':visible') ? src.replace('plus','minus') : src.replace('minus','plus')
});
});
});
#set $fuzzydate = 'airdate'
#if $sickbeard.FUZZY_DATING:
fuzzyMoment({
dtInline : true,
dtGlue : ' at ',
containerClass : '.${fuzzydate}',
dateHasTime : true,
dateFormat : '${sickbeard.DATE_PRESET}',
timeFormat : '${sickbeard.TIME_PRESET}',
trimZero : #if $sickbeard.TRIM_ZERO then 'true' else 'false'#
});
#end if
});
//-->
</script>
#set $cur_segment = None
#set $too_late_header = False
#set $missed_header = False
#set $today_header = False
#set $show_div = 'ep_listing listing-default'
#if 'show' == $sort:
<br /><br />
#end if
#for $cur_result in $sql_results:
#set $cur_indexer = int($cur_result['indexer'])
#if int($cur_result['paused']) and not $sickbeard.EPISODE_VIEW_DISPLAY_PAUSED:
#continue
#end if
#set $runtime = $cur_result['runtime']
#if 'network' == $sort:
#set $show_network = $cur_result['network'] if $cur_result['network'] else 'no network'
#if $cur_segment != $show_network:
<div class="episode-view-header">
<br><h2 class="network">$show_network</h2>
#set $cur_segment = $cur_result['network']
#end if
#set $cur_ep_airdate = $cur_result['localtime'].date()
#if $runtime:
#set $cur_ep_enddate = $cur_result['localtime'] + datetime.timedelta(minutes = $runtime)
#if $cur_ep_enddate < $today:
#set $show_div = 'ep_listing listing-overdue'
#elif $cur_ep_airdate >= $next_week.date():
#set $show_div = 'ep_listing listing-toofar'
#elif $cur_ep_enddate >= $today and $cur_ep_airdate < $next_week.date():
#if $cur_ep_airdate == $today.date():
#set $show_div = 'ep_listing listing-current'
#else:
#set $show_div = 'ep_listing listing-default'
#end if
#end if
#end if
#elif 'time' == $sort:
#set $cur_ep_airdate = $cur_result['localtime'].date()
#if $cur_segment != $cur_ep_airdate:
#if $runtime:
#set $cur_ep_enddate = $cur_result['localtime'] + datetime.timedelta(minutes = $runtime)
#if $cur_ep_enddate < $today and $cur_ep_airdate != $today.date() and not $missed_header:
<br /><h2 class="day">Missed</h2>
#set $missed_header = True
#elif $cur_ep_airdate >= $next_week.date() and not $too_late_header:
<br /><h2 class="day">Later</h2>
#set $too_late_header = True
#elif $cur_ep_enddate >= $today and $cur_ep_airdate < $next_week.date():
#if $cur_ep_airdate == $today.date():
<br /><h2 class="day">$sbdatetime.sbdatetime.sbfdate($cur_ep_airdate, '%A').decode($sickbeard.SYS_ENCODING).capitalize() <span style="font-size: 14px; vertical-align: top;">[Today]</span></h2>
#set $today_header = True
#else:
<br /><h2 class="day">$sbdatetime.sbdatetime.sbfdate($cur_ep_airdate, '%A').decode($sickbeard.SYS_ENCODING).capitalize()</h2>
#end if
#end if
#end if
#set $cur_segment = $cur_ep_airdate
#end if
#if $cur_ep_airdate == $today.date() and not $today_header:
<div class="episode-view-header">
<br /><h2 class="day">$sbdatetime.sbdatetime.sbfdate($cur_ep_airdate, '%A').decode($sickbeard.SYS_ENCODING).capitalize() <span style="font-size: 14px; vertical-align: top;">[Today]</span></h2>
#set $today_header = True
#end if
#if $runtime:
#set $cur_ep_enddate = $cur_result['localtime'] + datetime.timedelta(minutes = $runtime)
#if $cur_ep_enddate < $today:
#set $show_div = 'ep_listing listing-overdue'
#elif $cur_ep_airdate >= $next_week.date():
#set $show_div = 'ep_listing listing-toofar'
#elif $cur_ep_enddate >= $today and $cur_ep_airdate < $next_week.date():
#if $cur_ep_airdate == $today.date():
#set $show_div = 'ep_listing listing-current'
#else:
#set $show_div = 'ep_listing listing-default'
#end if
#end if
#end if
#elif 'show' == $sort:
#set $cur_ep_airdate = $cur_result['localtime'].date()
#if $runtime:
#set $cur_ep_enddate = $cur_result['localtime'] + datetime.timedelta(minutes = $runtime)
#if $cur_ep_enddate < $today:
#set $show_div = 'ep_listing listing-overdue listingradius'
#elif $cur_ep_airdate >= $next_week.date():
#set $show_div = 'ep_listing listing-toofar listingradius'
#elif $cur_ep_enddate >= $today and $cur_ep_airdate < $next_week.date():
#if $cur_ep_airdate == $today.date():
#set $show_div = 'ep_listing listing-current listingradius'
#else:
#set $show_div = 'ep_listing listing-default listingradius'
#end if
#end if
#end if
#end if
<!-- start $cur_result['show_name'] //-->
<div class="$show_div" id="listing-${cur_result['showid']}">
<div class="tvshowDiv">
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<th #if 'banner' == $layout then 'class="nobg"' else 'rowspan="2"'# valign="top">
<a href="$sbRoot/home/displayShow?show=${cur_result['showid']}"><img alt="" class="#if 'banner' == $layout then 'bannerThumb' else 'posterThumb'#" src="$sbRoot/showPoster/?show=${cur_result['showid']}&amp;which=#if 'poster' == $layout then 'poster_thumb' else $layout#" /></a>
</th>
#if 'banner' == $layout:
</tr>
<tr>
#end if
<td class="next_episode">
<div class="clearfix">
<span class="tvshowTitle">
<a href="$sbRoot/home/displayShow?show=${cur_result['showid']}" data-name="$cur_result['data_show_name']">$cur_result['show_name']
#if int($cur_result['paused']):
<span class="pause">[paused]</span>
#end if
</a></span>
<span class="tvshowTitleIcons">
#if $cur_result['imdb_id']:
<a href="<%= anon_url('http://www.imdb.com/title/', cur_result['imdb_id']) %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false" title="http://www.imdb.com/title/${cur_result['imdb_id']}"><img alt="[imdb]" height="16" width="16" src="$sbRoot/images/imdb.png" />
#end if
<a href="<%= anon_url(sickbeard.indexerApi(cur_indexer).config['show_url'], cur_result['showid']) %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false" title="$sickbeard.indexerApi($cur_indexer).config['show_url']${cur_result['showid']}"><img alt="$sickbeard.indexerApi($cur_indexer).name" height="16" width="16" src="$sbRoot/images/$sickbeard.indexerApi($cur_indexer).config['icon']" /></a>
<span><a href="$sbRoot/home/searchEpisode?show=${cur_result['showid']}&amp;season=$cur_result['season']&amp;episode=$cur_result['episode']" title="Manual Search" id="forceUpdate-${cur_result['showid']}" class="epSearch forceUpdate"><img alt="[search]" height="16" width="16" src="$sbRoot/images/search16.png" id="forceUpdateImage-${cur_result['showid']}" /></a></span>
</span>
</div>
<span class="title">Next Episode:</span> <span><%= 'S%02iE%02i' % (int(cur_result['season']), int(cur_result['episode'])) %> - $cur_result['name']</span>
<div class="clearfix">
<span class="title">Airdate: </span><span class="${fuzzydate}">$sbdatetime.sbdatetime.sbfdatetime($cur_result['localtime']).decode($sickbeard.SYS_ENCODING)</span><%= ('', '<span> on %s</span>' % str(cur_result['network']))[None is not cur_result['network']] %>
</div>
<div class="clearfix">
<span class="title">Quality:</span>
#if int($cur_result['quality']) in $qualityPresets:
<span class="quality $qualityPresetStrings[int($cur_result['quality'])]">$qualityPresetStrings[int($cur_result['quality'])]</span>
#else:
<span class="quality Custom">Custom</span>
#end if
</div>
</td>
</tr>
<tr>
<td style="vertical-align: top;">
<div>
#if $cur_result['description']:
<span class="title" style="vertical-align:middle;">Plot:</span>
<img class="ep_summaryTrigger" src="$sbRoot/images/plus.png" height="16" width="16" alt="" title="Toggle Summary" /><div class="ep_summary">$cur_result['description']</div>
#else:
<span class="title ep_summaryTriggerNone" style="vertical-align:middle;">Plot:</span>
<img class="ep_summaryTriggerNone" src="$sbRoot/images/plus.png" height="16" width="16" alt="" />
#end if
</div>
</td>
</tr>
</table>
</div>
</div>
<!-- end $cur_result['show_name'] //-->
#end for
<!-- end non list view //-->
#end if
#if 'daybyday' == $layout:
#set $today = datetime.date.today()
#set $dates = [$today + datetime.timedelta(days = $i) for $i in range(7)]
#set $tbl_day = 0
<input type="hidden" id="sbRoot" value="$sbRoot" />
<br>
<br>
<div class="daybydayWrapper"> <!-- style="width:1600px" -->
#for $day in $dates
#set $tbl_day += 1
#set $col_class = ''
#if 1 == $tbl_day
#set $col_class = 'today'
#end if
#set $col_class = '%s %s' % ($col_class, ('even', 'odd')[1 == tbl_day % 2])
<div class="day-of-week $col_class">
<div class="day-number">
<div class="number">$sbdatetime.sbdatetime.sbfdate($day, ' %d').decode($sickbeard.SYS_ENCODING).replace(' 0', ' ')</div>
<div class="day">
<span class="visible-lg">$sbdatetime.sbdatetime.sbfdate($day, '%A').decode($sickbeard.SYS_ENCODING).capitalize()</span>
<span class="hidden-lg">$sbdatetime.sbdatetime.sbfdate($day, '%a').decode($sickbeard.SYS_ENCODING).capitalize()</span>
</div>
<div class="month">
<span class="visible-lg">$sbdatetime.sbdatetime.sbfdate($day, '%B').decode($sickbeard.SYS_ENCODING).capitalize()</span>
<span class="hidden-lg">$sbdatetime.sbdatetime.sbfdate($day, '%b').decode($sickbeard.SYS_ENCODING).capitalize()</span>
</div>
</div>
<div id="$sbdatetime.sbdatetime.sbfdate($day, 'day%w')">
#set $day_has_show = False
#for $cur_result in $sql_results:
#if int($cur_result['paused']) and not $sickbeard.EPISODE_VIEW_DISPLAY_PAUSED:
#continue
#end if
#set $cur_indexer = int($cur_result['indexer'])
#set $runtime = $cur_result['runtime']
#set $airday = $cur_result['localtime'].date()
#if $airday == $day:
#set $day_has_show = True
#set $airtime = $sbdatetime.sbdatetime.sbftime($cur_result['localtime'], markup=True).decode($sickbeard.SYS_ENCODING)
#set $img_tag = '<img'
#set $plot_class = 'class="img-responsive'
#set $title_text = ''
#if $cur_result['description']:
#set $img_tag += ' id="plot_info_%s_%s_%s"' % (str($cur_result['showid']), str($cur_result['season']), str($cur_result['episode']))
#set $plot_class += ' plot-daybyday'
#else
#set $title_text = $cur_result['show_name']
#end if
<div id="show-$cur_result['showid']" class="daybyday-show" data-name="$cur_result['data_show_name']" data-season="$cur_result['season']" data-episode="$cur_result['episode']" data-network="$cur_result['data_network']" data-time="$time.mktime($cur_result['localtime'].timetuple())">
<div class="poster">
<a title="${title_text}" href="$sbRoot/home/displayShow?show=${cur_result['showid']}">
${img_tag} ${plot_class}" alt="" src="$sbRoot/showPoster/?show=${cur_result['showid']}&amp;which=poster_thumb" /></a>
</div>
<div class="text">
<div class="airtime">
<span class="time">${airtime}</span> <span class="network pull-right grey-text">$cur_result['network']</span>
</div>
<div class="episode" title="$cur_result['name']">
<span class="season"><%= '%i' % int(cur_result['season']) %></span>x<span class="number"><%= '%02i' % int(cur_result['episode']) %></span>
<span class="name">$cur_result['name']</span>
#if int($cur_result['paused']):
<span class="pause">[paused]</span>
#end if
</div>
</div>
</div><!-- end show-$cur_result['showid'] //-->
#end if
#end for
#if not $day_has_show:
<div class="daybyday-show">
<span class="episode-blank">No shows for this day</span>
</div>
#end if
</div>
</div>
#end for
</div>
<!-- end calender view //-->
#end if
<div class="clearfix"></div>
<script type="text/javascript" charset="utf-8">
<!--
window.setInterval('location.reload(true)', 30*60000); // Refresh every xx minutes
//-->
</script>
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_bottom.tmpl')

View file

@ -366,13 +366,13 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name))
if (classvalue<20) {
classtoadd = "progress-20"
}
if (classvalue>20 && classvalue<60) {
if (classvalue>=20 && classvalue<60) {
classtoadd = "progress-40"
}
if (classvalue>40 && classvalue<80) {
if (classvalue>=40 && classvalue<80) {
classtoadd = "progress-60"
}
if (classvalue>80) {
if (classvalue>=80) {
classtoadd = "progress-80"
}
\$("\#progressbar$curShow.indexerid > .ui-progressbar-value").addClass(classtoadd);
@ -596,13 +596,13 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name))
if (classvalue<20) {
classtoadd = "progress-20"
}
if (classvalue>20 && classvalue<60) {
if (classvalue>=20 && classvalue<60) {
classtoadd = "progress-40"
}
if (classvalue>40 && classvalue<80) {
if (classvalue>=40 && classvalue<80) {
classtoadd = "progress-60"
}
if (classvalue>80) {
if (classvalue>=80) {
classtoadd = "progress-80"
}
\$("\#progressbar$curShow.indexerid > .ui-progressbar-value").addClass(classtoadd);

View file

@ -11,7 +11,7 @@
#set global $sbPath='..'
#set global $topmenu='comingEpisodes'
#set global $topmenu='episodeView'
#import os.path
#include $os.path.join($sickbeard.PROG_DIR, 'gui/slick/interfaces/default/inc_top.tmpl')
@ -129,7 +129,7 @@
#else
#for $cur_show in $trending_shows:
#set $image = re.sub(r'(.*)(\..*?)$', r'\1-300\2', $cur_show['images']['poster'], 0, re.IGNORECASE | re.MULTILINE)
#set $image = re.sub(r'(.*)/original/(.+)$', r'\1/thumb/\2', $cur_show['images']['poster'], 0, re.IGNORECASE | re.MULTILINE)
<div class="trakt_show <%= ('notinlibrary', 'inlibrary')[':' in cur_show['show_id']] %>" data-name="$cur_show['title']" data-rating="$cur_show['ratings']['percentage']" data-votes="$cur_show['ratings']['votes']">
<div class="traktContainer">

View file

@ -62,7 +62,7 @@
)[0 < ep_snatched]
%>
&nbsp;/&nbsp;<span class="footerhighlight">$ep_total</span> episodes downloaded
| daily search: <span class="footerhighlight"><%= str(sickbeard.dailySearchScheduler.timeLeft()).split('.')[0] %></span>
| recent search: <span class="footerhighlight"><%= str(sickbeard.recentSearchScheduler.timeLeft()).split('.')[0] %></span>
| backlog search: <span class="footerhighlight">$sbdatetime.sbdatetime.sbfdate($sickbeard.backlogSearchScheduler.nextRun())</span>
</div>

View file

@ -57,6 +57,7 @@
<script type="text/javascript" src="$sbRoot/js/lib/jquery.form-3.35.js?$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/lib/jquery.ui.touch-punch-0.2.2.min.js?$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/lib/isotope.pkgd.min.js?$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/lib/imagesloaded.pkgd.min.js?$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/lib/jquery.confirm.js?$sbPID"></script>
<script type="text/javascript" src="$sbRoot/js/script.js?$sbPID"></script>
@ -149,8 +150,8 @@
</ul>
</li>
<li id="NAVcomingEpisodes">
<a href="$sbRoot/comingEpisodes/" tabindex="$tab#set $tab += 1#">Coming Episodes</a>
<li id="NAVepisodeView">
<a href="$sbRoot/episodeView/" tabindex="$tab#set $tab += 1#">Episodes</a>
</li>
<li id="NAVhistory">
@ -261,6 +262,6 @@
#except (NameError, NotFound):
#pass
#end try
#set $page_class = ('', ' class="%s"' % '_'.join($items).lower().replace(' ', '-'))[0 < len($items)]
#set $page_class = ('', ' class="%s"' % '_'.join($items).lower().replace(' ', '-').replace('_', '-'))[0 < len($items)]
<div id="contentWrapper">
<div id="content"$page_class>

View file

@ -29,9 +29,9 @@ Currently running<br />
#end if
<br />
<h3>Daily Search:</h3>
<h3>Recent Search:</h3>
<a class="btn" href="$sbRoot/manage/manageSearches/forceSearch"><i class="icon-exclamation-sign"></i> Force</a>
#if not $dailySearchStatus:
#if not $recentSearchStatus:
Not in progress<br />
#else:
In Progress<br />
@ -53,7 +53,7 @@ In Progress<br />
<h3>Search Queue:</h3>
Backlog: <i>$queueLength['backlog'] pending items</i></br>
Daily: <i>$queueLength['daily'] pending items</i></br>
Recent: <i>$queueLength['recent'] pending items</i></br>
Manual: <i>$queueLength['manual'] pending items</i></br>
Failed: <i>$queueLength['failed'] pending items</i></br>
</div>

View file

@ -1,45 +1,87 @@
$(document).ready(function(){
$('.enabler').each(function(){
var enabler = $('.enabler'),
viewIf = $('.viewIf');
enabler.each(function(){
if (!$(this).prop('checked'))
$('#content_' + $(this).attr('id')).hide();
});
$('.enabler').click(function(){
enabler.click(function(){
var content_id = $('#content_' + $(this).attr('id'));
if ($(this).prop('checked'))
$('#content_' + $(this).attr('id')).fadeIn('fast', 'linear');
content_id.fadeIn('fast', 'linear');
else
$('#content_' + $(this).attr('id')).fadeOut('fast', 'linear');
content_id.fadeOut('fast', 'linear');
});
$('.viewIf').click(function(){
viewIf.each(function(){
$(($(this).prop('checked') ? '.hide_if_' : '.show_if_') + $(this).attr('id')).hide();
});
viewIf.click(function(){
var if_id = '_if_' + $(this).attr('id');
if ($(this).prop('checked')) {
$('.hide_if_' + $(this).attr('id')).css('display','none');
$('.show_if_' + $(this).attr('id')).fadeIn('fast', 'linear');
$('.hide' + if_id).fadeOut('fast', 'linear');
$('.show' + if_id).fadeIn('fast', 'linear');
} else {
$('.show_if_' + $(this).attr('id')).css('display','none');
$('.hide_if_' + $(this).attr('id')).fadeIn('fast', 'linear');
$('.show' + if_id).fadeOut('fast', 'linear');
$('.hide' + if_id).fadeIn('fast', 'linear');
}
});
var ui_update_trim_zero = (function() {
var secs = ('00' + new Date().getSeconds().toString()).slice(-2),
elSecs = $('#trim_info_seconds'),
elTrimZero = $('#trim_zero');
elTrimZero.each(function() {
var checked = $(this).prop('checked') && $('#fuzzy_dating').prop('checked');
$('#time_presets').find('option').each(function() {
var text = ($(this).text());
$(this).text(checked
? text.replace(/(\b\d+:\d\d):\d+/mg, '$1')
: text.replace(/(\b\d+:\d\d)(?:.\d+)?/mg, '$1:' + secs));
});
});
if ($('#fuzzy_dating').prop('checked'))
if (elTrimZero.prop('checked'))
elSecs.fadeOut('fast', 'linear');
else
elSecs.fadeIn('fast', 'linear');
else
elSecs.fadeIn('fast', 'linear');
});
$('#trim_zero, #fuzzy_dating').click(function() {
ui_update_trim_zero();
});
ui_update_trim_zero();
$('.datePresets').click(function(){
var def = $('#date_presets').val()
if ($(this).prop('checked') && '%x' == def) {
def = '%a, %b %d, %Y'
var elDatePresets = $('#date_presets'),
defaultPreset = elDatePresets.val();
if ($(this).prop('checked') && '%x' == defaultPreset) {
defaultPreset = '%a, %b %d, %Y';
$('#date_use_system_default').html('1')
} else if (!$(this).prop('checked') && '1' == $('#date_use_system_default').html())
def = '%x'
defaultPreset = '%x';
$('#date_presets').attr('name', 'date_preset_old')
$('#date_presets').attr('id', 'date_presets_old')
elDatePresets.attr('name', 'date_preset_old');
elDatePresets.attr('id', 'date_presets_old');
$('#date_presets_na').attr('name', 'date_preset')
$('#date_presets_na').attr('id', 'date_presets')
var elDatePresets_na = $('#date_presets_na');
elDatePresets_na.attr('name', 'date_preset');
elDatePresets_na.attr('id', 'date_presets');
$('#date_presets_old').attr('name', 'date_preset_na')
$('#date_presets_old').attr('id', 'date_presets_na')
var elDatePresets_old = $('#date_presets_old');
elDatePresets_old.attr('name', 'date_preset_na');
elDatePresets_old.attr('id', 'date_presets_na');
if (def)
$('#date_presets').val(def)
if (defaultPreset)
elDatePresets.val(defaultPreset)
});
// bind 'myForm' and provide a simple callback function
@ -69,8 +111,11 @@ $(document).ready(function(){
});
$('#branchCheckout').click(function(){
url = sbRoot + '/home/branchCheckout?branch=' + $('#branchVersion').val();
window.location.href = url;
window.location.href = sbRoot + '/home/branchCheckout?branch=' + $('#branchVersion').val();
});
$('#pullRequestCheckout').click(function(){
window.location.href = sbRoot + '/home/pullRequestCheckout?branch=' + $('#pullRequestVersion').val();
});
});

View file

@ -62,7 +62,9 @@ $(document).ready(function(){
$(label_warning_deluge).hide();
$(host_desc_rtorrent).hide();
$(host_desc_deluge).hide();
$(host_desc_torrent).show();
$(torrent_username_option).show();
$(torrent_verify_cert_option).hide();
$(torrent_path_option).show();
$(torrent_path_option).find('.fileBrowser').show();
@ -86,6 +88,9 @@ $(document).ready(function(){
client = 'Deluge';
$(torrent_verify_cert_option).show();
$(label_warning_deluge).show();
$(host_desc_torrent).hide();
$(host_desc_deluge).show();
$(torrent_username_option).hide();
//$('#directory_title').text(client + directory);
} else if ('download_station' == selectedProvider){
client = 'Synology DS';

View file

@ -21,11 +21,11 @@
jd = (function (str) {
var token_map = ['a', 'ddd', 'A', 'dddd', 'b', 'MMM', 'B', 'MMMM', 'd', 'DD', 'm', 'MM', 'y', 'YY', 'Y', 'YYYY', 'x', 'L',
'H', 'HH', 'I', 'hh', 'M', 'mm', 'S', 'ss', 'p', 'A'],
'H', 'HH', 'I', 'hh', 'M', 'mm', 'S', 'ss', 'p', 'A', 'P', 'a'],
result = '';
for (var i = 0; i < str.length; i++)
if (/[aAbBdmyYxHIMSp]/.test(str[i])) {
if (/[aAbBdmyYxHIMSpP]/.test(str[i])) {
for (var t = 0; t < token_map.length; t = t + 2)
if (str[i] == token_map[t]) {
result += token_map[t + 1];
@ -36,8 +36,8 @@
return result;
}),
dateToken = jd(dateFormat),
timeToken = jd(timeFormat),
dateTemplate = jd(dateFormat),
timeTemplate = jd(timeFormat),
addQTip = (function() {
$(this).css('cursor', 'help');
@ -60,32 +60,50 @@
});
if (trimZero) {
timeToken = timeToken.replace(/hh/ig, 'h');
dateToken = dateToken.replace(/\bDD\b/g, 'D');
timeTemplate = timeTemplate.replace(/hh/g, 'h');
timeTemplate = timeTemplate.replace(/HH/g, 'H');
dateTemplate = dateTemplate.replace(/\bDD\b/g, 'D');
}
$(containerClass).each(function() {
var input = $(this).text(),
dateA = '[<span class="fd">',
dtSeparator = ' ',
timeA = '</span>]', timeB = '[' + timeA;
timeA = '</span>]', timeB = '[' + timeA,
timeToken = timeTemplate;
if (dateWithTime) {
var timeMeta = input.match(/^.{6,}?([,\s]+)(\d{1,2}).(?:\d{2,2})(?:.(\d{2,2}))?(?:\s([ap]m))?$/im);
var timeMeta = input.match(/([,\s]+)(\d{1,2})(?:(.)(\d\d)(?:(.)(\d\d))?)?(?:\s?([ap]m))?$/im);
if (null != timeMeta) {
dtSeparator = (! /undefined/i.test(typeof(timeMeta[1])) ? timeMeta[1] : dtSeparator);
// adjust timeToken to num digits of input hours
timeToken = (! /undefined/i.test(typeof(timeMeta[2])) && 1 == timeMeta[2].length ? timeToken.replace(/hh/ig, 'h') : timeToken);
// adjust timeToken to remove min if input has one and there is a pm
timeToken = (trimZero && ! /undefined/i.test(typeof(timeMeta[7]))
&& (/undefined/i.test(typeof(timeMeta[4]))
|| '00' == timeMeta[4]) ? timeToken.replace(/.mm/ig, '') : timeToken);
// adjust timeToken to use seconds if input has them
timeToken = (! /undefined/i.test(typeof(timeMeta[3])) && 2 == timeMeta[3].length ? timeToken : timeToken.replace(/.ss/, ''));
timeToken = (! /undefined/i.test(typeof(timeMeta[5])) && 2 == timeMeta[5].length ? timeToken : timeToken.replace(/.ss/, ''));
// adjust timeToken to am/pm or AM/PM if input has it
timeToken = (! /undefined/i.test(typeof(timeMeta[4])) && 2 == timeMeta[4].length ? timeToken.replace(/A$/, (/[ap]m/.test(timeMeta[4]) ? 'a' : 'A')) : timeToken);
timeToken = (! /undefined/i.test(typeof(timeMeta[7])) && 2 == timeMeta[7].length ? timeToken.replace(/A$/, (/[ap]m/.test(timeMeta[7]) ? 'a' : 'A')) : timeToken);
}
var token_build = (/h+/i.test(timeToken) ? timeToken.replace(/^(h+).*/i, '[<span class="time-hr">]$1[</span>]') : '');
if (/m+/i.test(timeToken)) {
token_build += (! /undefined/i.test(typeof(timeMeta[3])) ? '[<span class="time-hr-min">]' + timeMeta[3] + '[</span>]' : '')
+ (! /undefined/i.test(typeof(timeMeta[4])) ? timeToken.replace(/.*?(m+).*/i, '[<span class="time-min">]$1[</span>]') : '');
if (/s+/i.test(timeToken)) {
token_build += (! /undefined/i.test(typeof(timeMeta[5])) ? '[<span class="time-min-sec">]' + timeMeta[5] + '[</span>]' : '')
+ (! /undefined/i.test(typeof(timeMeta[6])) ? timeToken.replace(/.*?(s+).*/i, '[<span class="time-sec">]$1[</span>]') : '');
}
}
timeToken = token_build + (! /undefined/i.test(typeof(timeMeta[7])) ? timeToken.replace(/.*?[\s0-9](a).*/i, '[<span class="time-am-pm">]$1[</span>]') : '');
timeA = '</span>' + dtGlue + '<span class="ft">]' + timeToken + '[' + timeA;
timeB = '[</span>' + dtGlue + '<span class="ft">]' + timeToken + timeB;
}
var inputTokens = dateToken + dtSeparator + (dateWithTime ? timeToken : 'HH:mm:ss');
var inputTokens = dateTemplate + dtSeparator + (dateWithTime ? timeToken : 'HH:mm:ss');
if (! moment(input + (dateWithTime ? '' : dtSeparator + '00:00:00'), inputTokens).isValid())
return;
@ -152,11 +170,11 @@
if (dateWithTime && qTipTime)
$(this).attr('title',(n?'4) ':'') + airdatetime.format(inputTokens)).each(addQTip);
else
$(this).attr('title',(n?'5) ':'') + airdate.format(dateToken)).each(addQTip);
$(this).attr('title',(n?'5) ':'') + airdate.format(dateTemplate)).each(addQTip);
else
if (dateWithTime && qTipTime)
$(this).find('.ft').attr('title',(n?'6) ':'') + airdatetime.format(inputTokens)).each(addQTip);
else
$(this).find('.ft').attr('title',(n?'7) ':'') + airdate.format(dateToken)).each(addQTip);
$(this).find('.ft').attr('title',(n?'7) ':'') + airdate.format(dateTemplate)).each(addQTip);
});
}

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
$(function () {
$('.plotInfo').each(function () {
$('.plotInfo, .plot-daybyday').each(function () {
var match = $(this).attr('id').match(/^plot_info_(\d+)_(\d+)_(\d+)$/);
$(this).qtip({
content: {

View file

@ -42,7 +42,7 @@ from sickbeard import searchBacklog, showUpdater, versionChecker, properFinder,
from sickbeard import helpers, db, exceptions, show_queue, search_queue, scheduler, show_name_helpers
from sickbeard import logger
from sickbeard import naming
from sickbeard import dailysearcher
from sickbeard import searchRecent
from sickbeard import scene_numbering, scene_exceptions, name_cache
from indexers.indexer_api import indexerApi
from indexers.indexer_exceptions import indexer_shownotfound, indexer_exception, indexer_error, indexer_episodenotfound, \
@ -58,7 +58,7 @@ CFG = None
CONFIG_FILE = None
# This is the version of the config we EXPECT to find
CONFIG_VERSION = 5
CONFIG_VERSION = 7
# Default encryption version (0 for None)
ENCRYPTION_VERSION = 0
@ -78,7 +78,7 @@ NO_RESIZE = False
# system events
events = None
dailySearchScheduler = None
recentSearchScheduler = None
backlogSearchScheduler = None
showUpdateScheduler = None
versionCheckScheduler = None
@ -196,19 +196,19 @@ CHECK_PROPERS_INTERVAL = None
ALLOW_HIGH_PRIORITY = False
AUTOPOSTPROCESSER_FREQUENCY = None
DAILYSEARCH_FREQUENCY = None
RECENTSEARCH_FREQUENCY = None
UPDATE_FREQUENCY = None
DAILYSEARCH_STARTUP = False
RECENTSEARCH_STARTUP = False
BACKLOG_FREQUENCY = None
BACKLOG_STARTUP = False
DEFAULT_AUTOPOSTPROCESSER_FREQUENCY = 10
DEFAULT_DAILYSEARCH_FREQUENCY = 40
DEFAULT_RECENTSEARCH_FREQUENCY = 40
DEFAULT_BACKLOG_FREQUENCY = 21
DEFAULT_UPDATE_FREQUENCY = 1
MIN_AUTOPOSTPROCESSER_FREQUENCY = 1
MIN_DAILYSEARCH_FREQUENCY = 10
MIN_RECENTSEARCH_FREQUENCY = 10
MIN_BACKLOG_FREQUENCY = 10
MIN_UPDATE_FREQUENCY = 1
@ -419,10 +419,10 @@ GUI_NAME = None
HOME_LAYOUT = None
HISTORY_LAYOUT = None
DISPLAY_SHOW_SPECIALS = False
COMING_EPS_LAYOUT = None
COMING_EPS_DISPLAY_PAUSED = False
COMING_EPS_SORT = None
COMING_EPS_MISSED_RANGE = None
EPISODE_VIEW_LAYOUT = None
EPISODE_VIEW_SORT = None
EPISODE_VIEW_DISPLAY_PAUSED = False
EPISODE_VIEW_MISSED_RANGE = None
FUZZY_DATING = False
TRIM_ZERO = False
DATE_PRESET = None
@ -459,7 +459,7 @@ TRAKT_API_KEY = 'abd806c54516240c76e4ebc9c5ccf394'
__INITIALIZED__ = False
def get_backlog_cycle_time():
cycletime = DAILYSEARCH_FREQUENCY * 2 + 7
cycletime = RECENTSEARCH_FREQUENCY * 2 + 7
return max([cycletime, 720])
def initialize(consoleLogging=True):
@ -477,7 +477,7 @@ def initialize(consoleLogging=True):
PLEX_SERVER_HOST, PLEX_HOST, PLEX_USERNAME, PLEX_PASSWORD, DEFAULT_BACKLOG_FREQUENCY, MIN_BACKLOG_FREQUENCY, BACKLOG_STARTUP, SKIP_REMOVED_FILES, \
showUpdateScheduler, __INITIALIZED__, LAUNCH_BROWSER, UPDATE_SHOWS_ON_START, TRASH_REMOVE_SHOW, TRASH_ROTATE_LOGS, HOME_SEARCH_FOCUS, SORT_ARTICLE, showList, loadingShowList, \
NEWZNAB_DATA, NZBS, NZBS_UID, NZBS_HASH, INDEXER_DEFAULT, INDEXER_TIMEOUT, USENET_RETENTION, TORRENT_DIR, \
QUALITY_DEFAULT, FLATTEN_FOLDERS_DEFAULT, SUBTITLES_DEFAULT, STATUS_DEFAULT, DAILYSEARCH_STARTUP, \
QUALITY_DEFAULT, FLATTEN_FOLDERS_DEFAULT, SUBTITLES_DEFAULT, STATUS_DEFAULT, RECENTSEARCH_STARTUP, \
GROWL_NOTIFY_ONSNATCH, GROWL_NOTIFY_ONDOWNLOAD, GROWL_NOTIFY_ONSUBTITLEDOWNLOAD, TWITTER_NOTIFY_ONSNATCH, TWITTER_NOTIFY_ONDOWNLOAD, TWITTER_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_GROWL, GROWL_HOST, GROWL_PASSWORD, USE_PROWL, PROWL_NOTIFY_ONSNATCH, PROWL_NOTIFY_ONDOWNLOAD, PROWL_NOTIFY_ONSUBTITLEDOWNLOAD, PROWL_API, PROWL_PRIORITY, PROG_DIR, \
USE_PYTIVO, PYTIVO_NOTIFY_ONSNATCH, PYTIVO_NOTIFY_ONDOWNLOAD, PYTIVO_NOTIFY_ONSUBTITLEDOWNLOAD, PYTIVO_UPDATE_LIBRARY, PYTIVO_HOST, PYTIVO_SHARE_NAME, PYTIVO_TIVO_NAME, \
@ -485,12 +485,12 @@ def initialize(consoleLogging=True):
USE_PUSHALOT, PUSHALOT_NOTIFY_ONSNATCH, PUSHALOT_NOTIFY_ONDOWNLOAD, PUSHALOT_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHALOT_AUTHORIZATIONTOKEN, \
USE_PUSHBULLET, PUSHBULLET_NOTIFY_ONSNATCH, PUSHBULLET_NOTIFY_ONDOWNLOAD, PUSHBULLET_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHBULLET_API, PUSHBULLET_DEVICE, \
versionCheckScheduler, VERSION_NOTIFY, AUTO_UPDATE, NOTIFY_ON_UPDATE, PROCESS_AUTOMATICALLY, UNPACK, CPU_PRESET, \
KEEP_PROCESSED_DIR, PROCESS_METHOD, TV_DOWNLOAD_DIR, MIN_DAILYSEARCH_FREQUENCY, DEFAULT_UPDATE_FREQUENCY, MIN_UPDATE_FREQUENCY, UPDATE_FREQUENCY, \
KEEP_PROCESSED_DIR, PROCESS_METHOD, TV_DOWNLOAD_DIR, MIN_RECENTSEARCH_FREQUENCY, DEFAULT_UPDATE_FREQUENCY, MIN_UPDATE_FREQUENCY, UPDATE_FREQUENCY, \
showQueueScheduler, searchQueueScheduler, ROOT_DIRS, CACHE_DIR, ACTUAL_CACHE_DIR, TIMEZONE_DISPLAY, \
NAMING_PATTERN, NAMING_MULTI_EP, NAMING_ANIME_MULTI_EP, NAMING_FORCE_FOLDERS, NAMING_ABD_PATTERN, NAMING_CUSTOM_ABD, NAMING_SPORTS_PATTERN, NAMING_CUSTOM_SPORTS, NAMING_ANIME_PATTERN, NAMING_CUSTOM_ANIME, NAMING_STRIP_YEAR, \
RENAME_EPISODES, AIRDATE_EPISODES, properFinderScheduler, PROVIDER_ORDER, autoPostProcesserScheduler, \
WOMBLE, OMGWTFNZBS, OMGWTFNZBS_USERNAME, OMGWTFNZBS_APIKEY, providerList, newznabProviderList, torrentRssProviderList, \
EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, DAILYSEARCH_FREQUENCY, \
EXTRA_SCRIPTS, USE_TWITTER, TWITTER_USERNAME, TWITTER_PASSWORD, TWITTER_PREFIX, RECENTSEARCH_FREQUENCY, \
USE_BOXCAR, BOXCAR_USERNAME, BOXCAR_PASSWORD, BOXCAR_NOTIFY_ONDOWNLOAD, BOXCAR_NOTIFY_ONSUBTITLEDOWNLOAD, BOXCAR_NOTIFY_ONSNATCH, \
USE_BOXCAR2, BOXCAR2_ACCESSTOKEN, BOXCAR2_NOTIFY_ONDOWNLOAD, BOXCAR2_NOTIFY_ONSUBTITLEDOWNLOAD, BOXCAR2_NOTIFY_ONSNATCH, \
USE_PUSHOVER, PUSHOVER_USERKEY, PUSHOVER_APIKEY, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHOVER_NOTIFY_ONSNATCH, \
@ -498,8 +498,8 @@ def initialize(consoleLogging=True):
USE_SYNOLOGYNOTIFIER, SYNOLOGYNOTIFIER_NOTIFY_ONSNATCH, SYNOLOGYNOTIFIER_NOTIFY_ONDOWNLOAD, SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_EMAIL, EMAIL_HOST, EMAIL_PORT, EMAIL_TLS, EMAIL_USER, EMAIL_PASSWORD, EMAIL_FROM, EMAIL_NOTIFY_ONSNATCH, EMAIL_NOTIFY_ONDOWNLOAD, EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD, EMAIL_LIST, \
USE_LISTVIEW, METADATA_XBMC, METADATA_XBMC_12PLUS, METADATA_MEDIABROWSER, METADATA_PS3, metadata_provider_dict, \
NEWZBIN, NEWZBIN_USERNAME, NEWZBIN_PASSWORD, GIT_PATH, MOVE_ASSOCIATED_FILES, POSTPONE_IF_SYNC_FILES, dailySearchScheduler, NFO_RENAME, \
GUI_NAME, HOME_LAYOUT, HISTORY_LAYOUT, DISPLAY_SHOW_SPECIALS, COMING_EPS_LAYOUT, COMING_EPS_SORT, COMING_EPS_DISPLAY_PAUSED, COMING_EPS_MISSED_RANGE, FUZZY_DATING, TRIM_ZERO, DATE_PRESET, TIME_PRESET, TIME_PRESET_W_SECONDS, THEME_NAME, \
NEWZBIN, NEWZBIN_USERNAME, NEWZBIN_PASSWORD, GIT_PATH, MOVE_ASSOCIATED_FILES, POSTPONE_IF_SYNC_FILES, recentSearchScheduler, NFO_RENAME, \
GUI_NAME, HOME_LAYOUT, HISTORY_LAYOUT, DISPLAY_SHOW_SPECIALS, EPISODE_VIEW_LAYOUT, EPISODE_VIEW_SORT, EPISODE_VIEW_DISPLAY_PAUSED, EPISODE_VIEW_MISSED_RANGE, FUZZY_DATING, TRIM_ZERO, DATE_PRESET, TIME_PRESET, TIME_PRESET_W_SECONDS, THEME_NAME, \
POSTER_SORTBY, POSTER_SORTDIR, \
METADATA_WDTV, METADATA_TIVO, METADATA_MEDE8ER, IGNORE_WORDS, REQUIRE_WORDS, CALENDAR_UNPROTECTED, CREATE_MISSING_SHOW_DIRS, \
ADD_SHOWS_WO_DIR, USE_SUBTITLES, SUBTITLES_LANGUAGES, SUBTITLES_DIR, SUBTITLES_SERVICES_LIST, SUBTITLES_SERVICES_ENABLED, SUBTITLES_HISTORY, SUBTITLES_FINDER_FREQUENCY, subtitlesFinderScheduler, \
@ -674,7 +674,7 @@ def initialize(consoleLogging=True):
ALLOW_HIGH_PRIORITY = bool(check_setting_int(CFG, 'General', 'allow_high_priority', 1))
DAILYSEARCH_STARTUP = bool(check_setting_int(CFG, 'General', 'dailysearch_startup', 1))
RECENTSEARCH_STARTUP = bool(check_setting_int(CFG, 'General', 'recentsearch_startup', 1))
BACKLOG_STARTUP = bool(check_setting_int(CFG, 'General', 'backlog_startup', 1))
SKIP_REMOVED_FILES = bool(check_setting_int(CFG, 'General', 'skip_removed_files', 0))
@ -685,10 +685,10 @@ def initialize(consoleLogging=True):
if AUTOPOSTPROCESSER_FREQUENCY < MIN_AUTOPOSTPROCESSER_FREQUENCY:
AUTOPOSTPROCESSER_FREQUENCY = MIN_AUTOPOSTPROCESSER_FREQUENCY
DAILYSEARCH_FREQUENCY = check_setting_int(CFG, 'General', 'dailysearch_frequency',
DEFAULT_DAILYSEARCH_FREQUENCY)
if DAILYSEARCH_FREQUENCY < MIN_DAILYSEARCH_FREQUENCY:
DAILYSEARCH_FREQUENCY = MIN_DAILYSEARCH_FREQUENCY
RECENTSEARCH_FREQUENCY = check_setting_int(CFG, 'General', 'recentsearch_frequency',
DEFAULT_RECENTSEARCH_FREQUENCY)
if RECENTSEARCH_FREQUENCY < MIN_RECENTSEARCH_FREQUENCY:
RECENTSEARCH_FREQUENCY = MIN_RECENTSEARCH_FREQUENCY
MIN_BACKLOG_FREQUENCY = get_backlog_cycle_time()
BACKLOG_FREQUENCY = check_setting_int(CFG, 'General', 'backlog_frequency', DEFAULT_BACKLOG_FREQUENCY)
@ -944,10 +944,10 @@ def initialize(consoleLogging=True):
HOME_LAYOUT = check_setting_str(CFG, 'GUI', 'home_layout', 'poster')
HISTORY_LAYOUT = check_setting_str(CFG, 'GUI', 'history_layout', 'detailed')
DISPLAY_SHOW_SPECIALS = bool(check_setting_int(CFG, 'GUI', 'display_show_specials', 1))
COMING_EPS_LAYOUT = check_setting_str(CFG, 'GUI', 'coming_eps_layout', 'banner')
COMING_EPS_DISPLAY_PAUSED = bool(check_setting_int(CFG, 'GUI', 'coming_eps_display_paused', 0))
COMING_EPS_SORT = check_setting_str(CFG, 'GUI', 'coming_eps_sort', 'date')
COMING_EPS_MISSED_RANGE = check_setting_int(CFG, 'GUI', 'coming_eps_missed_range', 7)
EPISODE_VIEW_LAYOUT = check_setting_str(CFG, 'GUI', 'episode_view_layout', 'banner')
EPISODE_VIEW_SORT = check_setting_str(CFG, 'GUI', 'episode_view_sort', 'time')
EPISODE_VIEW_DISPLAY_PAUSED = bool(check_setting_int(CFG, 'GUI', 'episode_view_display_paused', 0))
EPISODE_VIEW_MISSED_RANGE = check_setting_int(CFG, 'GUI', 'episode_view_missed_range', 7)
FUZZY_DATING = bool(check_setting_int(CFG, 'GUI', 'fuzzy_dating', 0))
TRIM_ZERO = bool(check_setting_int(CFG, 'GUI', 'trim_zero', 0))
DATE_PRESET = check_setting_str(CFG, 'GUI', 'date_preset', '%x')
@ -1022,11 +1022,10 @@ def initialize(consoleLogging=True):
curTorrentProvider.getID() + '_search_fallback',
0))
if hasattr(curTorrentProvider, 'enable_daily'):
curTorrentProvider.enable_daily = bool(check_setting_int(CFG, curTorrentProvider.getID().upper(),
curTorrentProvider.getID() + '_enable_daily',
1))
if hasattr(curTorrentProvider, 'enable_recentsearch'):
curTorrentProvider.enable_recentsearch = bool(check_setting_int(CFG, curTorrentProvider.getID().upper(),
curTorrentProvider.getID() +
'_enable_recentsearch', 1))
if hasattr(curTorrentProvider, 'enable_backlog'):
curTorrentProvider.enable_backlog = bool(check_setting_int(CFG, curTorrentProvider.getID().upper(),
curTorrentProvider.getID() + '_enable_backlog',
@ -1050,11 +1049,10 @@ def initialize(consoleLogging=True):
curNzbProvider.search_fallback = bool(check_setting_int(CFG, curNzbProvider.getID().upper(),
curNzbProvider.getID() + '_search_fallback',
0))
if hasattr(curNzbProvider, 'enable_daily'):
curNzbProvider.enable_daily = bool(check_setting_int(CFG, curNzbProvider.getID().upper(),
curNzbProvider.getID() + '_enable_daily',
if hasattr(curNzbProvider, 'enable_recentsearch'):
curNzbProvider.enable_recentsearch = bool(check_setting_int(CFG, curNzbProvider.getID().upper(),
curNzbProvider.getID() + '_enable_recentsearch',
1))
if hasattr(curNzbProvider, 'enable_backlog'):
curNzbProvider.enable_backlog = bool(check_setting_int(CFG, curNzbProvider.getID().upper(),
curNzbProvider.getID() + '_enable_backlog',
@ -1124,11 +1122,11 @@ def initialize(consoleLogging=True):
cycleTime=datetime.timedelta(seconds=3),
threadName="SEARCHQUEUE")
update_interval = datetime.timedelta(minutes=DAILYSEARCH_FREQUENCY)
dailySearchScheduler = scheduler.Scheduler(dailysearcher.DailySearcher(),
update_interval = datetime.timedelta(minutes=RECENTSEARCH_FREQUENCY)
recentSearchScheduler = scheduler.Scheduler(searchRecent.RecentSearcher(),
cycleTime=update_interval,
threadName="DAILYSEARCHER",
run_delay=update_now if DAILYSEARCH_STARTUP
threadName="RECENTSEARCHER",
run_delay=update_now if RECENTSEARCH_STARTUP
else update_interval)
update_interval = datetime.timedelta(minutes=BACKLOG_FREQUENCY)
@ -1181,15 +1179,15 @@ def start():
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
subtitlesFinderScheduler, USE_SUBTITLES, traktCheckerScheduler, \
dailySearchScheduler, events, started
recentSearchScheduler, events, started
with INIT_LOCK:
if __INITIALIZED__:
# start sysetm events queue
events.start()
# start the daily search scheduler
dailySearchScheduler.start()
# start the recent search scheduler
recentSearchScheduler.start()
# start the backlog scheduler
backlogSearchScheduler.start()
@ -1230,7 +1228,7 @@ def halt():
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
subtitlesFinderScheduler, traktCheckerScheduler, \
dailySearchScheduler, events, started
recentSearchScheduler, events, started
with INIT_LOCK:
@ -1245,10 +1243,10 @@ def halt():
except:
pass
dailySearchScheduler.stop.set()
logger.log(u"Waiting for the DAILYSEARCH thread to exit")
recentSearchScheduler.stop.set()
logger.log(u"Waiting for the RECENTSEARCH thread to exit")
try:
dailySearchScheduler.join(10)
recentSearchScheduler.join(10)
except:
pass
@ -1397,13 +1395,13 @@ def save_config():
new_config['General']['torrent_method'] = TORRENT_METHOD
new_config['General']['usenet_retention'] = int(USENET_RETENTION)
new_config['General']['autopostprocesser_frequency'] = int(AUTOPOSTPROCESSER_FREQUENCY)
new_config['General']['dailysearch_frequency'] = int(DAILYSEARCH_FREQUENCY)
new_config['General']['recentsearch_frequency'] = int(RECENTSEARCH_FREQUENCY)
new_config['General']['backlog_frequency'] = int(BACKLOG_FREQUENCY)
new_config['General']['update_frequency'] = int(UPDATE_FREQUENCY)
new_config['General']['download_propers'] = int(DOWNLOAD_PROPERS)
new_config['General']['check_propers_interval'] = CHECK_PROPERS_INTERVAL
new_config['General']['allow_high_priority'] = int(ALLOW_HIGH_PRIORITY)
new_config['General']['dailysearch_startup'] = int(DAILYSEARCH_STARTUP)
new_config['General']['recentsearch_startup'] = int(RECENTSEARCH_STARTUP)
new_config['General']['backlog_startup'] = int(BACKLOG_STARTUP)
new_config['General']['skip_removed_files'] = int(SKIP_REMOVED_FILES)
new_config['General']['quality_default'] = int(QUALITY_DEFAULT)
@ -1526,9 +1524,9 @@ def save_config():
if hasattr(curTorrentProvider, 'search_fallback'):
new_config[curTorrentProvider.getID().upper()][curTorrentProvider.getID() + '_search_fallback'] = int(
curTorrentProvider.search_fallback)
if hasattr(curTorrentProvider, 'enable_daily'):
new_config[curTorrentProvider.getID().upper()][curTorrentProvider.getID() + '_enable_daily'] = int(
curTorrentProvider.enable_daily)
if hasattr(curTorrentProvider, 'enable_recentsearch'):
new_config[curTorrentProvider.getID().upper()][curTorrentProvider.getID() + '_enable_recentsearch'] = int(
curTorrentProvider.enable_recentsearch)
if hasattr(curTorrentProvider, 'enable_backlog'):
new_config[curTorrentProvider.getID().upper()][curTorrentProvider.getID() + '_enable_backlog'] = int(
curTorrentProvider.enable_backlog)
@ -1550,9 +1548,9 @@ def save_config():
if hasattr(curNzbProvider, 'search_fallback'):
new_config[curNzbProvider.getID().upper()][curNzbProvider.getID() + '_search_fallback'] = int(
curNzbProvider.search_fallback)
if hasattr(curNzbProvider, 'enable_daily'):
new_config[curNzbProvider.getID().upper()][curNzbProvider.getID() + '_enable_daily'] = int(
curNzbProvider.enable_daily)
if hasattr(curNzbProvider, 'enable_recentsearch'):
new_config[curNzbProvider.getID().upper()][curNzbProvider.getID() + '_enable_recentsearch'] = int(
curNzbProvider.enable_recentsearch)
if hasattr(curNzbProvider, 'enable_backlog'):
new_config[curNzbProvider.getID().upper()][curNzbProvider.getID() + '_enable_backlog'] = int(
curNzbProvider.enable_backlog)
@ -1765,10 +1763,10 @@ def save_config():
new_config['GUI']['home_layout'] = HOME_LAYOUT
new_config['GUI']['history_layout'] = HISTORY_LAYOUT
new_config['GUI']['display_show_specials'] = int(DISPLAY_SHOW_SPECIALS)
new_config['GUI']['coming_eps_layout'] = COMING_EPS_LAYOUT
new_config['GUI']['coming_eps_display_paused'] = int(COMING_EPS_DISPLAY_PAUSED)
new_config['GUI']['coming_eps_sort'] = COMING_EPS_SORT
new_config['GUI']['coming_eps_missed_range'] = int(COMING_EPS_MISSED_RANGE)
new_config['GUI']['episode_view_layout'] = EPISODE_VIEW_LAYOUT
new_config['GUI']['episode_view_display_paused'] = int(EPISODE_VIEW_DISPLAY_PAUSED)
new_config['GUI']['episode_view_sort'] = EPISODE_VIEW_SORT
new_config['GUI']['episode_view_missed_range'] = int(EPISODE_VIEW_MISSED_RANGE)
new_config['GUI']['fuzzy_dating'] = int(FUZZY_DATING)
new_config['GUI']['trim_zero'] = int(TRIM_ZERO)
new_config['GUI']['date_preset'] = DATE_PRESET

View file

@ -27,6 +27,8 @@ from sickbeard import helpers
from sickbeard import logger
from sickbeard import naming
from sickbeard import db
from sickbeard import providers
from sickbeard.providers.generic import GenericProvider
naming_ep_type = ("%(seasonnumber)dx%(episodenumber)02d",
"s%(seasonnumber)02de%(episodenumber)02d",
@ -155,13 +157,13 @@ def change_AUTOPOSTPROCESSER_FREQUENCY(freq):
sickbeard.autoPostProcesserScheduler.cycleTime = datetime.timedelta(minutes=sickbeard.AUTOPOSTPROCESSER_FREQUENCY)
def change_DAILYSEARCH_FREQUENCY(freq):
sickbeard.DAILYSEARCH_FREQUENCY = to_int(freq, default=sickbeard.DEFAULT_DAILYSEARCH_FREQUENCY)
def change_RECENTSEARCH_FREQUENCY(freq):
sickbeard.RECENTSEARCH_FREQUENCY = to_int(freq, default=sickbeard.DEFAULT_RECENTSEARCH_FREQUENCY)
if sickbeard.DAILYSEARCH_FREQUENCY < sickbeard.MIN_DAILYSEARCH_FREQUENCY:
sickbeard.DAILYSEARCH_FREQUENCY = sickbeard.MIN_DAILYSEARCH_FREQUENCY
if sickbeard.RECENTSEARCH_FREQUENCY < sickbeard.MIN_RECENTSEARCH_FREQUENCY:
sickbeard.RECENTSEARCH_FREQUENCY = sickbeard.MIN_RECENTSEARCH_FREQUENCY
sickbeard.dailySearchScheduler.cycleTime = datetime.timedelta(minutes=sickbeard.DAILYSEARCH_FREQUENCY)
sickbeard.recentSearchScheduler.cycleTime = datetime.timedelta(minutes=sickbeard.RECENTSEARCH_FREQUENCY)
def change_BACKLOG_FREQUENCY(freq):
sickbeard.BACKLOG_FREQUENCY = to_int(freq, default=sickbeard.DEFAULT_BACKLOG_FREQUENCY)
@ -445,7 +447,9 @@ class ConfigMigrator():
2: 'Sync backup number with version number',
3: 'Rename omgwtfnzb variables',
4: 'Add newznab catIDs',
5: 'Metadata update'
5: 'Metadata update',
6: 'Rename daily search to recent search',
7: 'Rename coming episodes to episode view'
}
def migrate_config(self):
@ -712,3 +716,27 @@ class ConfigMigrator():
sickbeard.METADATA_WDTV = _migrate_metadata(metadata_wdtv, 'WDTV', use_banner)
sickbeard.METADATA_TIVO = _migrate_metadata(metadata_tivo, 'TIVO', use_banner)
sickbeard.METADATA_MEDE8ER = _migrate_metadata(metadata_mede8er, 'Mede8er', use_banner)
# Migration v6: Rename daily search to recent search
def _migrate_v6(self):
sickbeard.RECENTSEARCH_FREQUENCY = check_setting_int(self.config_obj, 'General', 'dailysearch_frequency',
sickbeard.DEFAULT_RECENTSEARCH_FREQUENCY)
sickbeard.RECENTSEARCH_STARTUP = bool(check_setting_int(self.config_obj, 'General', 'dailysearch_startup', 1))
if sickbeard.RECENTSEARCH_FREQUENCY < sickbeard.MIN_RECENTSEARCH_FREQUENCY:
sickbeard.RECENTSEARCH_FREQUENCY = sickbeard.MIN_RECENTSEARCH_FREQUENCY
for curProvider in providers.sortedProviderList():
if hasattr(curProvider, 'enable_recentsearch'):
curProvider.enable_recentsearch = bool(check_setting_int(self.config_obj, curProvider.getID().upper(),
curProvider.getID() + '_enable_dailysearch', 1))
def _migrate_v7(self):
sickbeard.EPISODE_VIEW_LAYOUT = check_setting_str(self.config_obj, 'GUI', 'coming_eps_layout', 'banner')
sickbeard.EPISODE_VIEW_SORT = check_setting_str(self.config_obj, 'GUI', 'coming_eps_sort', 'time')
if 'date' == sickbeard.EPISODE_VIEW_SORT:
sickbeard.EPISODE_VIEW_SORT = 'time'
sickbeard.EPISODE_VIEW_DISPLAY_PAUSED = bool(check_setting_int(self.config_obj, 'GUI', 'coming_eps_display_paused', 0))
sickbeard.EPISODE_VIEW_MISSED_RANGE = check_setting_int(self.config_obj, 'GUI', 'coming_eps_missed_range', 7)

View file

@ -93,3 +93,26 @@ class GitHub(object):
['repos', self.github_repo_user, self.github_repo, 'branches'],
params={'per_page': 100})
return access_API
def pull_requests(self):
access_API = self._access_API(
['repos', self.github_repo_user, self.github_repo, 'pulls'],
params={'per_page': 100})
pull = []
for x in access_API:
try:
pull.append(PullRequest(x['head']['ref'], x['number']))
except:
continue
return pull
class PullRequest(object):
def __init__(self, ref, number):
self.ref = ref
self.number = number
def __repr__(self):
return '%s: %s' % (self.number, self.ref)
def fetch_name(self):
return 'pull/%s/head:pull/%s/%s' % (self.number, self.number, self.ref)

View file

@ -26,8 +26,9 @@ import os.path
import regexes
import sickbeard
from sickbeard import logger, helpers, scene_numbering, common, exceptions, scene_exceptions, encodingKludge as ek, db
from sickbeard import logger, helpers, scene_numbering, common, scene_exceptions, encodingKludge as ek, db
from dateutil import parser
from sickbeard.exceptions import ex
class NameParser(object):
@ -36,13 +37,14 @@ class NameParser(object):
ANIME_REGEX = 2
def __init__(self, file_name=True, showObj=None, tryIndexers=False, convert=False,
naming_pattern=False):
naming_pattern=False, testing=False):
self.file_name = file_name
self.showObj = showObj
self.tryIndexers = tryIndexers
self.convert = convert
self.naming_pattern = naming_pattern
self.testing = testing
if self.showObj and not self.showObj.is_anime:
self._compile_regexes(self.NORMAL_REGEX)
@ -78,7 +80,7 @@ class NameParser(object):
def _compile_regexes(self, regexMode):
if regexMode == self.ANIME_REGEX:
logger.log(u"Using ANIME regexs", logger.DEBUG)
uncompiled_regex = [regexes.anime_regexes, regexes.normal_regexes]
uncompiled_regex = [regexes.anime_regexes]
elif regexMode == self.NORMAL_REGEX:
logger.log(u"Using NORMAL regexs", logger.DEBUG)
uncompiled_regex = [regexes.normal_regexes]
@ -86,7 +88,8 @@ class NameParser(object):
logger.log(u"Using ALL regexes", logger.DEBUG)
uncompiled_regex = [regexes.normal_regexes, regexes.anime_regexes]
self.compiled_regexes = []
self.compiled_regexes = {0: [], 1: []}
index = 0
for regexItem in uncompiled_regex:
for cur_pattern_num, (cur_pattern_name, cur_pattern) in enumerate(regexItem):
try:
@ -94,7 +97,8 @@ class NameParser(object):
except re.error, errormsg:
logger.log(u"WARNING: Invalid episode_pattern, %s. %s" % (errormsg, cur_pattern))
else:
self.compiled_regexes.append((cur_pattern_num, cur_pattern_name, cur_regex))
self.compiled_regexes[index].append([cur_pattern_num, cur_pattern_name, cur_regex])
index += 1
def _parse_string(self, name):
if not name:
@ -102,8 +106,8 @@ class NameParser(object):
matches = []
bestResult = None
for (cur_regex_num, cur_regex_name, cur_regex) in self.compiled_regexes:
for regex in self.compiled_regexes:
for (cur_regex_num, cur_regex_name, cur_regex) in self.compiled_regexes[regex]:
match = cur_regex.match(name)
if not match:
@ -150,13 +154,19 @@ class NameParser(object):
result.ab_episode_numbers = [ep_ab_num]
result.score += 1
if 'air_date' in named_groups:
air_date = match.group('air_date')
if 'air_year' in named_groups and 'air_month' in named_groups and 'air_day' in named_groups:
year = int(match.group('air_year'))
month = int(match.group('air_month'))
day = int(match.group('air_day'))
# make an attempt to detect YYYY-DD-MM formats
if month > 12:
tmp_month = month
month = day
day = tmp_month
try:
result.air_date = parser.parse(air_date, fuzzy=True).date()
result.score += 1
except:
continue
result.air_date = datetime.date(year, month, day)
except ValueError, e:
raise InvalidNameException(ex(e))
if 'extra_info' in named_groups:
tmp_extra_info = match.group('extra_info')
@ -194,13 +204,16 @@ class NameParser(object):
show = helpers.get_show(bestResult.series_name, self.tryIndexers)
# confirm passed in show object indexer id matches result show object indexer id
if show:
if show and not self.testing:
if self.showObj and show.indexerid != self.showObj.indexerid:
show = None
bestResult.show = show
elif not show and self.showObj:
bestResult.show = self.showObj
if bestResult.show and bestResult.show.is_anime and len(self.compiled_regexes[1]) > 1 and regex != 1:
continue
# if this is a naming pattern test or result doesn't have a show object then return best result
if not bestResult.show or self.naming_pattern:
return bestResult
@ -259,7 +272,7 @@ class NameParser(object):
new_episode_numbers.append(e)
new_season_numbers.append(s)
elif bestResult.show.is_anime and len(bestResult.ab_episode_numbers):
elif bestResult.show.is_anime and len(bestResult.ab_episode_numbers) and not self.testing:
scene_season = scene_exceptions.get_scene_exception_by_name(bestResult.series_name)[1]
for epAbsNo in bestResult.ab_episode_numbers:
a = epAbsNo
@ -275,7 +288,7 @@ class NameParser(object):
new_episode_numbers.extend(e)
new_season_numbers.append(s)
elif bestResult.season_number and len(bestResult.episode_numbers):
elif bestResult.season_number and len(bestResult.episode_numbers) and not self.testing:
for epNo in bestResult.episode_numbers:
s = bestResult.season_number
e = epNo
@ -416,7 +429,7 @@ class NameParser(object):
file_name_result = self._parse_string(base_file_name)
# use only the direct parent dir
dir_name = os.path.basename(dir_name)
dir_name = ek.ek(os.path.basename, dir_name)
# parse the dirname for extra info if needed
dir_name_result = self._parse_string(dir_name)
@ -452,6 +465,10 @@ class NameParser(object):
final_result.quality = self._combine_results(file_name_result, dir_name_result, 'quality')
if not final_result.show:
if self.testing:
pass
#final_result.which_regex = []
else:
raise InvalidShowException(
"Unable to parse " + name.encode(sickbeard.SYS_ENCODING, 'xmlcharrefreplace'))
@ -506,7 +523,7 @@ class ParseResult(object):
self.air_date = air_date
self.which_regex = []
self.which_regex = None
self.show = show
self.score = score
@ -530,14 +547,14 @@ class ParseResult(object):
return False
if self.ab_episode_numbers != other.ab_episode_numbers:
return False
if self.show != other.show:
return False
if self.score != other.score:
return False
if self.quality != other.quality:
return False
if self.version != other.version:
return False
#if self.show != other.show:
# return False
#if self.score != other.score:
# return False
#if self.quality != other.quality:
# return False
#if self.version != other.version:
# return False
return True
@ -556,6 +573,7 @@ class ParseResult(object):
to_return += str(self.air_date)
if self.ab_episode_numbers:
to_return += ' [ABS: ' + str(self.ab_episode_numbers) + ']'
if self.is_anime:
if self.version:
to_return += ' [ANIME VER: ' + str(self.version) + ']'

View file

@ -30,8 +30,9 @@ normal_regexes = [
e(?P<extra_ep_num>\d+))+ # E03/etc and separator
[. _-]*((?P<extra_info>.+?) # Source_Quality_Etc-
((?<![. _-])(?<!WEB) # Make sure this is really the release group
-(?P<release_group>[^- ]+([. _-]\[.*\])?))?)?$ # Group
'''),
-(?P<release_group>[^- ]+))?)?$ # Group
'''
),
('fov_repeat',
# Show.Name.1x02.1x03.Source.Quality.Etc-Group
@ -44,8 +45,9 @@ normal_regexes = [
(?P<extra_ep_num>\d+))+ # 03/etc and separator
[. _-]*((?P<extra_info>.+?) # Source_Quality_Etc-
((?<![. _-])(?<!WEB) # Make sure this is really the release group
-(?P<release_group>[^- ]+([. _-]\[.*\])?))?)?$ # Group
'''),
-(?P<release_group>[^- ]+))?)?$ # Group
'''
),
('standard',
# Show.Name.S01E02.Source.Quality.Etc-Group
@ -62,8 +64,9 @@ normal_regexes = [
(?P<extra_ep_num>(?!(1080|720|480)[pi])\d+))* # additional E03/etc
[. _-]*((?P<extra_info>.+?) # Source_Quality_Etc-
((?<![. _-])(?<!WEB) # Make sure this is really the release group
-(?P<release_group>[^- ]+([. _-]\[.*\])?))?)?$ # Group
'''),
-(?P<release_group>[^- ]+))?)?$ # Group
'''
),
('fov',
# Show_Name.1x02.Source_Quality_Etc-Group
@ -80,31 +83,23 @@ normal_regexes = [
\d+))* # additional x03/etc
[\]. _-]*((?P<extra_info>.+?) # Source_Quality_Etc-
((?<![. _-])(?<!WEB) # Make sure this is really the release group
-(?P<release_group>[^- ]+([. _-]\[.*\])?))?)?$ # Group
'''),
-(?P<release_group>[^- ]+))?)?$ # Group
'''
),
('scene_date_format',
# Show.Name.2010.11.23.Source.Quality.Etc-Group
# Show Name - 2010-11-23 - Ep Name
'''
^((?P<series_name>.+?)[. _-]+)? # Show_Name and separator
(?P<air_date>(\d+[. _-]\d+[. _-]\d+)|(\d+\w+[. _-]\w+[. _-]\d+))
(?P<air_year>\d{4})[. _-]+ # 2010 and separator
(?P<air_month>\d{2})[. _-]+ # 11 and separator
(?P<air_day>\d{2}) # 23 and separator
[. _-]*((?P<extra_info>.+?) # Source_Quality_Etc-
((?<![. _-])(?<!WEB) # Make sure this is really the release group
-(?P<release_group>[^- ]+([. _-]\[.*\])?))?)?$ # Group
'''),
('scene_sports_format',
# Show.Name.100.Event.2010.11.23.Source.Quality.Etc-Group
# Show.Name.2010.11.23.Source.Quality.Etc-Group
# Show Name - 2010-11-23 - Ep Name
-(?P<release_group>[^- ]+))?)?$ # Group
'''
^(?P<series_name>.*?(UEFA|MLB|ESPN|WWE|MMA|UFC|TNA|EPL|NASCAR|NBA|NFL|NHL|NRL|PGA|SUPER LEAGUE|FORMULA|FIFA|NETBALL|MOTOGP).*?)[. _-]+
((?P<series_num>\d{1,3})[. _-]+)?
(?P<air_date>(\d+[. _-]\d+[. _-]\d+)|(\d+\w+[. _-]\w+[. _-]\d+))[. _-]+
((?P<extra_info>.+?)((?<![. _-])
(?<!WEB)-(?P<release_group>[^- ]+([. _-]\[.*\])?))?)?$
'''),
),
('stupid',
# tpz-abc102
@ -113,7 +108,8 @@ normal_regexes = [
(?!264) # don't count x264
(?P<season_num>\d{1,2}) # 1
(?P<ep_num>\d{2})$ # 02
'''),
'''
),
('verbose',
# Show Name Season 1 Episode 2 Ep Name
@ -124,7 +120,8 @@ normal_regexes = [
episode[. _-]+ # episode and separator
(?P<ep_num>\d+)[. _-]+ # 02 and separator
(?P<extra_info>.+)$ # Source_Quality_Etc-
'''),
'''
),
('season_only',
# Show.Name.S01.Source.Quality.Etc-Group
@ -134,7 +131,7 @@ normal_regexes = [
(?P<season_num>\d+)[. _-]* # S01 and optional separator
[. _-]*((?P<extra_info>.+?) # Source_Quality_Etc-
((?<![. _-])(?<!WEB) # Make sure this is really the release group
-(?P<release_group>[^- ]+([. _-]\[.*\])?))?)?$ # Group
-(?P<release_group>[^- ]+))?)?$ # Group
'''
),
@ -149,7 +146,7 @@ normal_regexes = [
(?P<extra_ep_num>(?!(1080|720|480)[pi])(\d+|[ivx]+))[. _-]) # second ep num
([. _-]*(?P<extra_info>.+?) # Source_Quality_Etc-
((?<![. _-])(?<!WEB) # Make sure this is really the release group
-(?P<release_group>[^- ]+([. _-]\[.*\])?))?)?$ # Group
-(?P<release_group>[^- ]+))?)?$ # Group
'''
),
@ -167,22 +164,7 @@ normal_regexes = [
(\d+|([ivx]+(?=[. _-]))))[. _-])* # second ep num
([. _-]*(?P<extra_info>.+?) # Source_Quality_Etc-
((?<![. _-])(?<!WEB) # Make sure this is really the release group
-(?P<release_group>[^- ]+([. _-]\[.*\])?))?)?$ # Group
'''
),
('no_season',
# Show Name - 01 - Ep Name
# 01 - Ep Name
# 01 - Ep Name
'''
^((?P<series_name>.+?)(?:[. _-]{2,}|[. _]))? # Show_Name and separator
(?P<ep_num>\d{1,3}) # 02
(?:-(?P<extra_ep_num>\d{1,3}))* # -03-04-05 etc
\s?of?\s?\d{1,3}? # of joiner (with or without spaces) and series total ep
[. _-]+((?P<extra_info>.+?) # Source_Quality_Etc-
((?<![. _-])(?<!WEB) # Make sure this is really the release group
-(?P<release_group>[^- ]+([. _-]\[.*\])?))?)?$ # Group
-(?P<release_group>[^- ]+))?)?$ # Group
'''
),
@ -193,23 +175,37 @@ normal_regexes = [
(?P<season_num>\d{1,2}) # 1
(?P<ep_num>\d{2}) # 02 and separator
([. _-]+(?P<extra_info>(?!\d{3}[. _-]+)[^-]+) # Source_Quality_Etc-
(-(?P<release_group>[^- ]+([. _-]\[.*\])?))?)?$ # Group
'''),
(-(?P<release_group>.+))?)?$ # Group
'''
),
('no_season',
# Show Name - 01 - Ep Name
# 01 - Ep Name
'''
^((?P<series_name>.+?)(?:[. _-]{2,}|[. _]))? # Show_Name and separator
(?P<ep_num>\d{1,2}) # 01
(?:-(?P<extra_ep_num>\d{1,2}))* # 02
[. _-]+((?P<extra_info>.+?) # Source_Quality_Etc-
((?<![. _-])(?<!WEB) # Make sure this is really the release group
-(?P<release_group>[^- ]+))?)?$ # Group
'''
),
]
anime_regexes = [
('anime_ultimate',
"""
'''
^(?:\[(?P<release_group>.+?)\][ ._-]*)
(?P<series_name>.+?)[ ._-]+
(?P<ep_ab_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3})
(-(?P<extra_ab_ep_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))?[ ._-]+?
(?P<ep_ab_num>\d{1,3})
(-(?P<extra_ab_ep_num>\d{1,3}))?[ ._-]+?
(?:v(?P<version>[0-9]))?
(?:[\w\.]*)
(?:(?:(?:[\[\(])(?P<extra_info>\d{3,4}[xp]?\d{0,4}[\.\w\s-]*)(?:[\]\)]))|(?:\d{3,4}[xp]))
(?:[ ._]?\[(?P<crc>\w+)\])?
.*?
"""
'''
),
('anime_standard',
# [Group Name] Show Name.13-14
@ -221,42 +217,38 @@ anime_regexes = [
'''
^(\[(?P<release_group>.+?)\][ ._-]*)? # Release Group and separator
(?P<series_name>.+?)[ ._-]+ # Show_Name and separator
(?P<ep_ab_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # E01
(-(?P<extra_ab_ep_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # E02
(?P<ep_ab_num>\d{1,3}) # E01
(-(?P<extra_ab_ep_num>\d{1,3}))? # E02
(v(?P<version>[0-9]))? # version
[ ._-]+\[(?P<extra_info>\d{3,4}[xp]?\d{0,4}[\.\w\s-]*)\] # Source_Quality_Etc-
(\[(?P<crc>\w{8})\])? # CRC
.*? # Separator and EOL
'''),
('anime_standard_round',
# TODO examples
# [Stratos-Subs]_Infinite_Stratos_-_12_(1280x720_H.264_AAC)_[379759DB]
# [ShinBunBu-Subs] Bleach - 02-03 (CX 1280x720 x264 AAC)
'''
^(\[(?P<release_group>.+?)\][ ._-]*)? # Release Group and separator
(?P<series_name>.+?)[ ._-]+ # Show_Name and separator
(?P<ep_ab_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # E01
(-(?P<extra_ab_ep_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # E02
(?P<ep_ab_num>\d{1,3}) # E01
(-(?P<extra_ab_ep_num>\d{1,3}))? # E02
(v(?P<version>[0-9]))? # version
[ ._-]+\((?P<extra_info>(CX[ ._-]?)?\d{3,4}[xp]?\d{0,4}[\.\w\s-]*)\) # Source_Quality_Etc-
(\[(?P<crc>\w{8})\])? # CRC
.*? # Separator and EOL
'''),
('anime_slash',
# [SGKK] Bleach 312v1 [720p/MKV]
'''
^(\[(?P<release_group>.+?)\][ ._-]*)? # Release Group and separator
(?P<series_name>.+?)[ ._-]+ # Show_Name and separator
(?P<ep_ab_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # E01
(-(?P<extra_ab_ep_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # E02
(?P<ep_ab_num>\d{1,3}) # E01
(-(?P<extra_ab_ep_num>\d{1,3}))? # E02
(v(?P<version>[0-9]))? # version
[ ._-]+\[(?P<extra_info>\d{3,4}p) # Source_Quality_Etc-
(\[(?P<crc>\w{8})\])? # CRC
.*? # Separator and EOL
'''),
('anime_standard_codec',
# [Ayako]_Infinite_Stratos_-_IS_-_07_[H264][720p][EB7838FC]
# [Ayako] Infinite Stratos - IS - 07v2 [H264][720p][44419534]
@ -264,26 +256,15 @@ anime_regexes = [
'''
^(\[(?P<release_group>.+?)\][ ._-]*)? # Release Group and separator
(?P<series_name>.+?)[ ._]* # Show_Name and separator
([ ._-]+-[ ._-]+[A-Z]+[ ._-]+)?[ ._-]+ # funny stuff, this is sooo nuts ! this will kick me in the butt one day
(?P<ep_ab_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # E01
(-(?P<extra_ab_ep_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # E02
([ ._-]+-[ ._-]+[A-Z]+[ ._-]+)?[ ._-]+ # this will kick me in the butt one day
(?P<ep_ab_num>\d{1,3}) # E01
(-(?P<extra_ab_ep_num>\d{1,3}))? # E02
(v(?P<version>[0-9]))? # version
([ ._-](\[\w{1,2}\])?\[[a-z][.]?\w{2,4}\])? # codec
[ ._-]*\[(?P<extra_info>(\d{3,4}[xp]?\d{0,4})?[\.\w\s-]*)\] # Source_Quality_Etc-
(\[(?P<crc>\w{8})\])?
(\[(?P<crc>\w{8})\])? # CRC
.*? # Separator and EOL
'''),
('anime_codec_crc',
'''
^(?:\[(?P<release_group>.*?)\][ ._-]*)?
(?:(?P<series_name>.*?)[ ._-]*)?
(?:(?P<ep_ab_num>(((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))[ ._-]*).+?
(?:\[(?P<codec>.*?)\][ ._-]*)
(?:\[(?P<crc>\w{8})\])?
.*?
'''),
('anime_and_normal',
# Bleach - s16e03-04 - 313-314
# Bleach.s16e03-04.313-314
@ -294,15 +275,14 @@ anime_regexes = [
[eE](?P<ep_num>\d+) # epipisode E02
(([. _-]*e|-) # linking e/- char
(?P<extra_ep_num>\d+))* # additional E03/etc
([ ._-]{2,}|[ ._]+) # if "-" is used to separate at least something else has to be there(->{2,}) "s16e03-04-313-314" would make sens any way
((?P<ep_ab_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # absolute number
(-(?P<extra_ab_ep_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # "-" as separator and anditional absolute number, all optinal
([ ._-]{2,}|[ ._]+) # if "-" is used to separate at least something else has to be
# there(->{2,}) "s16e03-04-313-314" would make sens any way
(?P<ep_ab_num>\d{1,3}) # absolute number
(-(?P<extra_ab_ep_num>\d{1,3}))* # "-" as separator and anditional absolute number, all optinal
(v(?P<version>[0-9]))? # the version e.g. "v2"
.*?
'''
),
('anime_and_normal_x',
# Bleach - s16e03-04 - 313-314
# Bleach.s16e03-04.313-314
@ -313,23 +293,23 @@ anime_regexes = [
[xX](?P<ep_num>\d+) # epipisode E02
(([. _-]*e|-) # linking e/- char
(?P<extra_ep_num>\d+))* # additional E03/etc
([ ._-]{2,}|[ ._]+) # if "-" is used to separate at least something else has to be there(->{2,}) "s16e03-04-313-314" would make sens any way
((?P<ep_ab_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # absolute number
(-(?P<extra_ab_ep_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # "-" as separator and anditional absolute number, all optinal
([ ._-]{2,}|[ ._]+) # if "-" is used to separate at least something else has to be
# there(->{2,}) "s16e03-04-313-314" would make sens any way
(?P<ep_ab_num>\d{1,3}) # absolute number
(-(?P<extra_ab_ep_num>\d{1,3}))* # "-" as separator and anditional absolute number, all optinal
(v(?P<version>[0-9]))? # the version e.g. "v2"
.*?
'''
),
('anime_and_normal_reverse',
# Bleach - 313-314 - s16e03-04
'''
^(?P<series_name>.+?)[ ._-]+ # start of string and series name and non optinal separator
(?P<ep_ab_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # absolute number
(-(?P<extra_ab_ep_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # "-" as separator and anditional absolute number, all optinal
(?P<ep_ab_num>\d{1,3}) # absolute number
(-(?P<extra_ab_ep_num>\d{1,3}))* # "-" as separator and anditional absolute number, all optinal
(v(?P<version>[0-9]))? # the version e.g. "v2"
([ ._-]{2,}|[ ._]+) # if "-" is used to separate at least something else has to be there(->{2,}) "s16e03-04-313-314" would make sens any way
([ ._-]{2,}|[ ._]+) # if "-" is used to separate at least something else has to be
# there(->{2,}) "s16e03-04-313-314" would make sens any way
[sS](?P<season_num>\d+)[. _-]* # S01 and optional separator
[eE](?P<ep_num>\d+) # epipisode E02
(([. _-]*e|-) # linking e/- char
@ -337,12 +317,11 @@ anime_regexes = [
.*?
'''
),
('anime_and_normal_front',
# 165.Naruto Shippuuden.s08e014
'''
^(?P<ep_ab_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # start of string and absolute number
(-(?P<extra_ab_ep_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # "-" as separator and anditional absolute number, all optinal
^(?P<ep_ab_num>\d{1,3}) # start of string and absolute number
(-(?P<extra_ab_ep_num>\d{1,3}))* # "-" as separator and anditional absolute number, all optinal
(v(?P<version>[0-9]))?[ ._-]+ # the version e.g. "v2"
(?P<series_name>.+?)[ ._-]+
[sS](?P<season_num>\d+)[. _-]* # S01 and optional separator
@ -352,13 +331,12 @@ anime_regexes = [
.*?
'''
),
('anime_ep_name',
'''
^(?:\[(?P<release_group>.+?)\][ ._-]*)
(?P<series_name>.+?)[ ._-]+
(?P<ep_ab_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3})
(-(?P<extra_ab_ep_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))?[ ._-]*?
(?P<ep_ab_num>\d{1,3})
(-(?P<extra_ab_ep_num>\d{1,3}))*[ ._-]*?
(?:v(?P<version>[0-9])[ ._-]+?)?
(?:.+?[ ._-]+?)?
\[(?P<extra_info>\w+)\][ ._-]?
@ -366,16 +344,34 @@ anime_regexes = [
.*?
'''
),
('anime_bare',
# One Piece - 102
# [ACX]_Wolf's_Spirit_001.mkv
'''
^(\[(?P<release_group>.+?)\][ ._-]*)?
(?P<series_name>.+?)[ ._-]+ # Show_Name and separator
(?P<ep_ab_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}) # E01
(-(?P<extra_ab_ep_num>((?!(1080|720|480)[pi])|(?![hx].?264))\d{1,3}))? # E02
(?<!H.)(?P<ep_ab_num>\d{3})(?!0p) # E01, while avoiding H.264 and 1080p from being matched
(-(?P<extra_ab_ep_num>\d{3}))* # E02
(v(?P<version>[0-9]))? # v2
.*? # Separator and EOL
''')
'''),
('standard',
# Show.Name.S01E02.Source.Quality.Etc-Group
# Show Name - S01E02 - My Ep Name
# Show.Name.S01.E03.My.Ep.Name
# Show.Name.S01E02E03.Source.Quality.Etc-Group
# Show Name - S01E02-03 - My Ep Name
# Show.Name.S01.E02.E03
'''
^((?P<series_name>.+?)[. _-]+)? # Show_Name and separator
s(?P<season_num>\d+)[. _-]* # S01 and optional separator
e(?P<ep_num>\d+) # E02 and separator
(([. _-]*e|-) # linking e/- char
(?P<extra_ep_num>(?!(1080|720|480)[pi])\d+))* # additional E03/etc
[. _-]*((?P<extra_info>.+?) # Source_Quality_Etc-
((?<![. _-])(?<!WEB) # Make sure this is really the release group
-(?P<release_group>[^- ]+))?)?$ # Group
'''
),
]

View file

@ -83,6 +83,7 @@ class TraktNotifier:
# Start by getting all episodes in the watchlist
watchlist = TraktCall("user/watchlist/episodes.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD)
if watchlist is not None:
# Convert watchlist to only contain current show
for show in watchlist:
# Check if tvdb_id exists
@ -100,6 +101,9 @@ class TraktNotifier:
data_show['episodes'].append(ep)
if data_show is not None:
TraktCall("show/episode/unwatchlist/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD, data_show)
else:
logger.log('Failed to get watchlist from trakt. Unable to remove episode from watchlist',
logger.ERROR)
def test_notify(self, api, username, password):
"""

View file

@ -97,7 +97,7 @@ def getNewznabProviderList(data):
providerDict[curDefault.name].needs_auth = curDefault.needs_auth
providerDict[curDefault.name].search_mode = curDefault.search_mode
providerDict[curDefault.name].search_fallback = curDefault.search_fallback
providerDict[curDefault.name].enable_daily = curDefault.enable_daily
providerDict[curDefault.name].enable_recentsearch = curDefault.enable_recentsearch
providerDict[curDefault.name].enable_backlog = curDefault.enable_backlog
return filter(lambda x: x, providerList)
@ -109,13 +109,13 @@ def makeNewznabProvider(configString):
search_mode = 'eponly'
search_fallback = 0
enable_daily = 0
enable_recentsearch = 0
enable_backlog = 0
try:
values = configString.split('|')
if len(values) == 9:
name, url, key, catIDs, enabled, search_mode, search_fallback, enable_daily, enable_backlog = values
name, url, key, catIDs, enabled, search_mode, search_fallback, enable_recentsearch, enable_backlog = values
else:
name = values[0]
url = values[1]
@ -129,7 +129,7 @@ def makeNewznabProvider(configString):
newznab = sys.modules['sickbeard.providers.newznab']
newProvider = newznab.NewznabProvider(name, url, key=key, catIDs=catIDs, search_mode=search_mode,
search_fallback=search_fallback, enable_daily=enable_daily,
search_fallback=search_fallback, enable_recentsearch=enable_recentsearch,
enable_backlog=enable_backlog)
newProvider.enabled = enabled == '1'
@ -157,13 +157,13 @@ def makeTorrentRssProvider(configString):
cookies = None
search_mode = 'eponly'
search_fallback = 0
enable_daily = 0
enable_recentsearch = 0
enable_backlog = 0
try:
values = configString.split('|')
if len(values) == 8:
name, url, cookies, enabled, search_mode, search_fallback, enable_daily, enable_backlog = values
name, url, cookies, enabled, search_mode, search_fallback, enable_recentsearch, enable_backlog = values
else:
name = values[0]
url = values[1]
@ -178,7 +178,7 @@ def makeTorrentRssProvider(configString):
except:
return
newProvider = torrentRss.TorrentRssProvider(name, url, cookies, search_mode, search_fallback, enable_daily,
newProvider = torrentRss.TorrentRssProvider(name, url, cookies, search_mode, search_fallback, enable_recentsearch,
enable_backlog)
newProvider.enabled = enabled == '1'

View file

@ -136,6 +136,8 @@ class BTNProvider(generic.TorrentProvider):
server = jsonrpclib.Server(self.url)
parsedJSON = {}
logger.log(u'Searching with parameters: %s' % params, logger.DEBUG)
try:
parsedJSON = server.getTorrents(apikey, params, int(results_per_page), int(offset))
@ -201,8 +203,6 @@ class BTNProvider(generic.TorrentProvider):
if ep_obj.show.air_by_date or ep_obj.show.sports:
# Search for the year of the air by date show
current_params['name'] = str(ep_obj.airdate).split('-')[0]
elif ep_obj.show.is_anime:
current_params['name'] = "%d" % ep_obj.scene_absolute_number
else:
current_params['name'] = 'Season ' + str(ep_obj.scene_season)
@ -238,8 +238,6 @@ class BTNProvider(generic.TorrentProvider):
# BTN uses dots in dates, we just search for the date since that
# combined with the series identifier should result in just one episode
search_params['name'] = date_str.replace('-', '.')
elif ep_obj.show.anime:
search_params['name'] = "%i" % int(ep_obj.scene_absolute_number)
else:
# Do a general name search for the episode, formatted like SXXEYY
search_params['name'] = "S%02dE%02d" % (ep_obj.scene_season, ep_obj.scene_episode)

View file

@ -56,7 +56,7 @@ class GenericProvider:
self.search_mode = None
self.search_fallback = False
self.enable_daily = False
self.enable_recentsearch = False
self.enable_backlog = False
self.cache = tvcache.TVCache(self)

View file

@ -43,7 +43,7 @@ from lib.bencode import bdecode
class NewznabProvider(generic.NZBProvider):
def __init__(self, name, url, key='', catIDs='5030,5040', search_mode='eponly', search_fallback=False,
enable_daily=False, enable_backlog=False):
enable_recentsearch=False, enable_backlog=False):
generic.NZBProvider.__init__(self, name)
@ -55,7 +55,7 @@ class NewznabProvider(generic.NZBProvider):
self.search_mode = search_mode
self.search_fallback = search_fallback
self.enable_daily = enable_daily
self.enable_recentsearch = enable_recentsearch
self.enable_backlog = enable_backlog
# a 0 in the key spot indicates that no key is needed
@ -77,7 +77,7 @@ class NewznabProvider(generic.NZBProvider):
def configStr(self):
return self.name + '|' + self.url + '|' + self.key + '|' + self.catIDs + '|' + str(
int(self.enabled)) + '|' + self.search_mode + '|' + str(int(self.search_fallback)) + '|' + str(
int(self.enable_daily)) + '|' + str(int(self.enable_backlog))
int(self.enable_recentsearch)) + '|' + str(int(self.enable_backlog))
def imageName(self):
if ek.ek(os.path.isfile,

View file

@ -36,7 +36,7 @@ from lib.bencode import bdecode
class TorrentRssProvider(generic.TorrentProvider):
def __init__(self, name, url, cookies='', search_mode='eponly', search_fallback=False, enable_daily=False,
def __init__(self, name, url, cookies='', search_mode='eponly', search_fallback=False, enable_recentsearch=False,
enable_backlog=False):
generic.TorrentProvider.__init__(self, name)
self.cache = TorrentRssCache(self)
@ -48,7 +48,7 @@ class TorrentRssProvider(generic.TorrentProvider):
self.search_mode = search_mode
self.search_fallback = search_fallback
self.enable_daily = enable_daily
self.enable_recentsearch = enable_recentsearch
self.enable_backlog = enable_backlog
self.cookies = cookies
@ -59,7 +59,7 @@ class TorrentRssProvider(generic.TorrentProvider):
self.enabled,
self.search_mode or '',
self.search_fallback,
self.enable_daily,
self.enable_recentsearch,
self.enable_backlog)
def imageName(self):

View file

@ -61,11 +61,11 @@ class ThePirateBayProvider(generic.TorrentProvider):
self.proxy = ThePirateBayWebproxy()
self.url = 'http://pirateproxy.net/'
self.url = 'http://oldpiratebay.org/'
self.searchurl = self.url + 'search/%s/0/7/200' # order by seed
self.searchurl = self.url + 'search.php?q=%s&Torrent_sort=seeders.desc' # order by seed
self.re_title_url = '/torrent/(?P<id>\d+)/(?P<title>.*?)//1".+?(?P<url>magnet.*?)//1".+?(?P<seeders>\d+)</td>.+?(?P<leechers>\d+)</td>'
self.re_title_url = 'href=["\'](?P<url>magnet:.*?)&.*?/torrent/(?P<id>\d+)/(?P<title>.*?)".+?seeders-row sy">(?P<seeders>\d+)</td>.+?leechers-row ly">(?P<leechers>\d+)</td>'
def isEnabled(self):
return self.enabled

View file

@ -30,7 +30,7 @@ class WombleProvider(generic.NZBProvider):
generic.NZBProvider.__init__(self, "Womble's Index")
self.enabled = False
self.cache = WombleCache(self)
self.url = 'https://newshost.co.za/'
self.url = 'http://newshost.co.za/'
def isEnabled(self):
return self.enabled
@ -53,7 +53,7 @@ class WombleCache(tvcache.TVCache):
return
cl = []
for url in [self.provider.url + 'rss/?sec=tv-sd&fr=false', self.provider.url + 'rss/?sec=tv-hd&fr=false']:
for url in [self.provider.url + 'rss/?sec=tv-x264&fr=false', self.provider.url + 'rss/?sec=tv-sd&fr=false', self.provider.url + 'rss/?sec=tv-hd&fr=false']:
logger.log(u"Womble's Index cache update URL: " + url, logger.DEBUG)
data = self.getRSSFeed(url)
@ -63,12 +63,11 @@ class WombleCache(tvcache.TVCache):
# By now we know we've got data and no auth errors, all we need to do is put it in the database
for item in data.entries:
ci = self._parseItem(item)
title, url = self._get_title_and_url(item)
ci = self._parseItem(title, url)
if ci is not None:
cl.append(ci)
if len(cl) > 0:
myDB = self._getDB()
myDB.mass_action(cl)
@ -81,4 +80,3 @@ class WombleCache(tvcache.TVCache):
return data != 'Invalid Link'
provider = WombleProvider()

View file

@ -19,6 +19,7 @@
import datetime
import locale
import functools
import re
import sickbeard
from sickbeard.network_timezones import sb_timezone
@ -82,12 +83,12 @@ date_presets = ('%Y-%m-%d',
'%A, %b %d, %Y',
'%B %d, %Y',
'%a, %B %d, %Y',
'%A, %B %d, %Y'
)
'%A, %B %d, %Y')
time_presets = ('%I:%M:%S %p',
'%H:%M:%S'
)
'%I:%M:%S %P',
'%H:%M:%S')
# helper class
class static_or_instance(object):
@ -104,142 +105,98 @@ class sbdatetime(datetime.datetime):
@static_or_instance
def convert_to_setting(self, dt=None):
obj = (dt, self)[self is not None]
try:
if sickbeard.TIMEZONE_DISPLAY == 'local':
if self is None:
return dt.astimezone(sb_timezone)
else:
return self.astimezone(sb_timezone)
else:
if self is None:
return dt
else:
return self
if 'local' == sickbeard.TIMEZONE_DISPLAY:
return obj.astimezone(sb_timezone)
except:
if self is None:
return dt
else:
return self
pass
return obj
@static_or_instance
def setlocale(self, setlocale=True, use_has_locale=None, locale_str=''):
if setlocale:
try:
if None is use_has_locale or use_has_locale:
locale.setlocale(locale.LC_TIME, locale_str)
except:
if None is not use_has_locale:
sbdatetime.has_locale = False
pass
# display Time in SickGear Format
@static_or_instance
def sbftime(self, dt=None, show_seconds=False, t_preset=None):
def sbftime(self, dt=None, show_seconds=False, t_preset=None, setlocale=True, markup=False):
try:locale.setlocale(locale.LC_TIME, '')
except:pass
try:
if sbdatetime.has_locale:
locale.setlocale(locale.LC_TIME, 'us_US')
except:
sbdatetime.has_locale = False
sbdatetime.setlocale(setlocale=setlocale, use_has_locale=sbdatetime.has_locale, locale_str='us_US')
strt = ''
try:
if self is None:
if dt is not None:
if t_preset is not None:
strt = dt.strftime(t_preset)
elif show_seconds:
strt = dt.strftime(sickbeard.TIME_PRESET_W_SECONDS)
else:
strt = dt.strftime(sickbeard.TIME_PRESET)
else:
if t_preset is not None:
strt = self.strftime(t_preset)
elif show_seconds:
strt = self.strftime(sickbeard.TIME_PRESET_W_SECONDS)
else:
strt = self.strftime(sickbeard.TIME_PRESET)
finally:
try:
if sbdatetime.has_locale:
locale.setlocale(locale.LC_TIME, '')
except:
sbdatetime.has_locale = False
obj = (dt, self)[self is not None]
if None is not obj:
tmpl = (((sickbeard.TIME_PRESET, sickbeard.TIME_PRESET_W_SECONDS)[show_seconds]),
t_preset)[None is not t_preset]
tmpl = (tmpl.replace(':%S', ''), tmpl)[show_seconds]
strt = obj.strftime(tmpl.replace('%P', '%p'))
if sickbeard.TRIM_ZERO:
strt = re.sub(r'^0(\d:\d\d)', r'\1', strt)
if re.search(r'(?im)%p$', tmpl):
if '%p' in tmpl:
strt = strt.upper()
elif '%P' in tmpl:
strt = strt.lower()
if sickbeard.TRIM_ZERO:
strt = re.sub(r'(?im)^(\d+)(?::00)?(\s?[ap]m)', r'\1\2', strt)
if markup:
match = re.search(r'(?im)(\d{1,2})(?:(.)(\d\d)(?:(.)(\d\d))?)?(?:\s?([ap]m))?$', strt)
if match:
strt = ('%s%s%s%s%s%s' % (
('<span class="time-hr">%s</span>' % match.group(1), '')[None is match.group(1)],
('<span class="time-hr-min">%s</span>' % match.group(2), '')[None is match.group(2)],
('<span class="time-min">%s</span>' % match.group(3), '')[None is match.group(3)],
('<span class="time-min-sec">%s</span>' % match.group(4), '')[None is match.group(4)],
('<span class="time-sec">%s</span>' % match.group(5), '')[None is match.group(5)],
('<span class="time-am-pm">%s</span>' % match.group(6), '')[None is match.group(6)]))
finally:
sbdatetime.setlocale(setlocale=setlocale, use_has_locale=sbdatetime.has_locale)
return strt
# display Date in SickGear Format
@static_or_instance
def sbfdate(self, dt=None, d_preset=None):
def sbfdate(self, dt=None, d_preset=None, setlocale=True):
try:
locale.setlocale(locale.LC_TIME, '')
except:
pass
sbdatetime.setlocale(setlocale=setlocale)
strd = ''
try:
if self is None:
if dt is not None:
if d_preset is not None:
strd = dt.strftime(d_preset)
else:
strd = dt.strftime(sickbeard.DATE_PRESET)
else:
if d_preset is not None:
strd = self.strftime(d_preset)
else:
strd = self.strftime(sickbeard.DATE_PRESET)
obj = (dt, self)[self is not None]
if None is not obj:
strd = obj.strftime((sickbeard.DATE_PRESET, d_preset)[None is not d_preset])
finally:
try:
locale.setlocale(locale.LC_TIME, '')
except:
pass
sbdatetime.setlocale(setlocale=setlocale)
return strd
# display Datetime in SickGear Format
@static_or_instance
def sbfdatetime(self, dt=None, show_seconds=False, d_preset=None, t_preset=None):
def sbfdatetime(self, dt=None, show_seconds=False, d_preset=None, t_preset=None, markup=False):
try:
locale.setlocale(locale.LC_TIME, '')
except:
pass
sbdatetime.setlocale()
strd = ''
obj = (dt, self)[self is not None]
try:
if self is None:
if dt is not None:
if d_preset is not None:
strd = dt.strftime(d_preset)
else:
strd = dt.strftime(sickbeard.DATE_PRESET)
try:
if sbdatetime.has_locale:
locale.setlocale(locale.LC_TIME, 'us_US')
except:
sbdatetime.has_locale = False
if t_preset is not None:
strd += u', ' + dt.strftime(t_preset)
elif show_seconds:
strd += u', ' + dt.strftime(sickbeard.TIME_PRESET_W_SECONDS)
else:
strd += u', ' + dt.strftime(sickbeard.TIME_PRESET)
else:
if d_preset is not None:
strd = self.strftime(d_preset)
else:
strd = self.strftime(sickbeard.DATE_PRESET)
try:
if sbdatetime.has_locale:
locale.setlocale(locale.LC_TIME, 'us_US')
except:
sbdatetime.has_locale = False
if t_preset is not None:
strd += u', ' + self.strftime(t_preset)
elif show_seconds:
strd += u', ' + self.strftime(sickbeard.TIME_PRESET_W_SECONDS)
else:
strd += u', ' + self.strftime(sickbeard.TIME_PRESET)
finally:
try:
if sbdatetime.has_locale:
locale.setlocale(locale.LC_TIME, '')
except:
sbdatetime.has_locale = False
if None is not obj:
strd = u'%s, %s' % (obj.strftime((sickbeard.DATE_PRESET, d_preset)[None is not d_preset]),
sbdatetime.sbftime(dt, show_seconds, t_preset, False, markup))
finally:
sbdatetime.setlocale(use_has_locale=sbdatetime.has_locale)
return strd

View file

@ -375,7 +375,7 @@ def searchForNeededEpisodes():
episodes.extend(wantedEpisodes(curShow, fromDate))
providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive() and x.enable_daily]
providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive() and x.enable_recentsearch]
for curProvider in providers:
# spawn separate threads for each provider so we don't need to wait for providers with slow network operation
@ -435,7 +435,7 @@ def searchForNeededEpisodes():
if not didSearch:
logger.log(
u"No NZB/Torrent providers found or enabled in the SickGear config for daily searches. Please check your settings.",
u"No NZB/Torrent providers found or enabled in the SickGear config for recent searches. Please check your settings.",
logger.ERROR)
return foundResults.values()

View file

@ -32,7 +32,7 @@ from sickbeard import network_timezones
from sickbeard.exceptions import ex
class DailySearcher():
class RecentSearcher():
def __init__(self):
self.lock = threading.Lock()
self.amActive = False
@ -97,8 +97,8 @@ class DailySearcher():
myDB = db.DBConnection()
myDB.mass_action(sql_l)
# queue episode for daily search
dailysearch_queue_item = sickbeard.search_queue.DailySearchQueueItem()
sickbeard.searchQueueScheduler.action.add_item(dailysearch_queue_item)
# queue episode for recent search
recentsearch_queue_item = sickbeard.search_queue.RecentSearchQueueItem()
sickbeard.searchQueueScheduler.action.add_item(recentsearch_queue_item)
self.amActive = False

View file

@ -33,7 +33,7 @@ from sickbeard.search import pickBestResult
search_queue_lock = threading.Lock()
BACKLOG_SEARCH = 10
DAILY_SEARCH = 20
RECENT_SEARCH = 20
FAILED_SEARCH = 30
MANUAL_SEARCH = 40
@ -95,17 +95,17 @@ class SearchQueue(generic_queue.GenericQueue):
return True
return False
def is_dailysearch_in_progress(self):
def is_recentsearch_in_progress(self):
for cur_item in self.queue + [self.currentItem]:
if isinstance(cur_item, DailySearchQueueItem):
if isinstance(cur_item, RecentSearchQueueItem):
return True
return False
def queue_length(self):
length = {'backlog': 0, 'daily': 0, 'manual': 0, 'failed': 0}
length = {'backlog': 0, 'recent': 0, 'manual': 0, 'failed': 0}
for cur_item in self.queue:
if isinstance(cur_item, DailySearchQueueItem):
length['daily'] += 1
if isinstance(cur_item, RecentSearchQueueItem):
length['recent'] += 1
elif isinstance(cur_item, BacklogQueueItem):
length['backlog'] += 1
elif isinstance(cur_item, ManualSearchQueueItem):
@ -116,8 +116,8 @@ class SearchQueue(generic_queue.GenericQueue):
def add_item(self, item):
if isinstance(item, DailySearchQueueItem):
# daily searches
if isinstance(item, RecentSearchQueueItem):
# recent searches
generic_queue.GenericQueue.add_item(self, item)
elif isinstance(item, BacklogQueueItem) and not self.is_in_queue(item.show, item.segment):
# backlog searches
@ -128,16 +128,16 @@ class SearchQueue(generic_queue.GenericQueue):
else:
logger.log(u"Not adding item, it's already in the queue", logger.DEBUG)
class DailySearchQueueItem(generic_queue.QueueItem):
class RecentSearchQueueItem(generic_queue.QueueItem):
def __init__(self):
self.success = None
generic_queue.QueueItem.__init__(self, 'Daily Search', DAILY_SEARCH)
generic_queue.QueueItem.__init__(self, 'Recent Search', RECENT_SEARCH)
def run(self):
generic_queue.QueueItem.run(self)
try:
logger.log("Beginning daily search for new episodes")
logger.log("Beginning recent search for new episodes")
foundResults = search.searchForNeededEpisodes()
if not len(foundResults):

View file

@ -97,7 +97,7 @@ class TVCache():
myDB.action('DELETE FROM [' + self.providerID + '] WHERE 1')
def _get_title_and_url(self, item):
# override this in the provider if daily search has a different data layout to backlog searches
# override this in the provider if recent search has a different data layout to backlog searches
return self.provider._get_title_and_url(item)
def _getRSSData(self):
@ -222,7 +222,7 @@ class TVCache():
return True
def shouldClearCache(self):
# if daily search hasn't used our previous results yet then don't clear the cache
# if recent search hasn't used our previous results yet then don't clear the cache
if self.lastUpdate > self.lastSearch:
return False

View file

@ -115,9 +115,15 @@ class CheckVersion():
if self.updater.need_update():
return self.updater.update()
def fetch(self, pull_request):
return self.updater.fetch(pull_request)
def list_remote_branches(self):
return self.updater.list_remote_branches()
def list_remote_pulls(self):
return self.updater.list_remote_pulls()
def get_branch(self):
return self.updater.branch
@ -400,6 +406,17 @@ class GitUpdateManager(UpdateManager):
return re.findall('\S+\Wrefs/heads/(.*)', branches)
return []
def list_remote_pulls(self):
gh = github.GitHub(self.github_repo_user, self.github_repo, self.branch)
return gh.pull_requests()
def fetch(self, pull_request):
output, err, exit_status = self._run_git(self._git_path, 'fetch -f %s %s' % (sickbeard.GIT_REMOTE, pull_request)) # @UnusedVariable
if exit_status == 0:
return True
return False
class SourceUpdateManager(UpdateManager):
def __init__(self):
@ -597,3 +614,7 @@ class SourceUpdateManager(UpdateManager):
def list_remote_branches(self):
gh = github.GitHub(self.github_repo_user, self.github_repo, self.branch)
return [x['name'] for x in gh.branches() if x and 'name' in x]
def list_remote_pulls(self):
# we don't care about testers that don't use git
return []

View file

@ -711,7 +711,7 @@ class CMD_ComingEpisodes(ApiCall):
self.sort, args = self.check_params(args, kwargs, "sort", "date", False, "string", ["date", "show", "network"])
self.type, args = self.check_params(args, kwargs, "type", "today|missed|soon|later", False, "list",
["missed", "later", "today", "soon"])
self.paused, args = self.check_params(args, kwargs, "paused", sickbeard.COMING_EPS_DISPLAY_PAUSED, False, "int",
self.paused, args = self.check_params(args, kwargs, "paused", sickbeard.EPISODE_VIEW_DISPLAY_PAUSED, False, "int",
[0, 1])
# super, missing, help
ApiCall.__init__(self, handler, args, kwargs)
@ -725,7 +725,7 @@ class CMD_ComingEpisodes(ApiCall):
tomorrow = (datetime.date.today() + datetime.timedelta(days=1)).toordinal()
next_week_dt = (datetime.date.today() + datetime.timedelta(days=7))
next_week = (next_week_dt + datetime.timedelta(days=1)).toordinal()
recently = (yesterday_dt - datetime.timedelta(days=sickbeard.COMING_EPS_MISSED_RANGE)).toordinal()
recently = (yesterday_dt - datetime.timedelta(days=sickbeard.EPISODE_VIEW_MISSED_RANGE)).toordinal()
done_show_list = []
qualList = Quality.DOWNLOADED + Quality.SNATCHED + [ARCHIVED, IGNORED]
@ -758,31 +758,27 @@ class CMD_ComingEpisodes(ApiCall):
# multi dimension sort
sorts = {
'date': (lambda a, b: cmp(
(a['parsed_datetime'],
(a['show_name'], remove_article(a['show_name']))[not sickbeard.SORT_ARTICLE],
a['season'], a['episode']),
(b['parsed_datetime'],
(b['show_name'], remove_article(b['show_name']))[not sickbeard.SORT_ARTICLE],
b['season'], b['episode']))),
'show': (lambda a, b: cmp(
((a['show_name'], remove_article(a['show_name']))[not sickbeard.SORT_ARTICLE],
a['parsed_datetime'], a['season'], a['episode']),
((b['show_name'], remove_article(b['show_name']))[not sickbeard.SORT_ARTICLE],
b['parsed_datetime'], b['season'], b['episode']))),
(a['parsed_datetime'], a['data_show_name'], a['season'], a['episode']),
(b['parsed_datetime'], b['data_show_name'], b['season'], b['episode']))),
'network': (lambda a, b: cmp(
(a['network'], a['parsed_datetime'],
(a['show_name'], remove_article(a['show_name']))[not sickbeard.SORT_ARTICLE],
a['season'], a['episode']),
(b['network'], b['parsed_datetime'],
(b['show_name'], remove_article(b['show_name']))[not sickbeard.SORT_ARTICLE],
b['season'], b['episode'])))
(a['data_network'], a['parsed_datetime'], a['data_show_name'], a['season'], a['episode']),
(b['data_network'], b['parsed_datetime'], b['data_show_name'], b['season'], b['episode']))),
'show': (lambda a, b: cmp(
(a['data_show_name'], a['parsed_datetime'], a['season'], a['episode']),
(b['data_show_name'], b['parsed_datetime'], b['season'], b['episode'])))
}
def value_maybe_article(value=''):
return (remove_article(value.lower()), value.lower())[sickbeard.SORT_ARTICLE]
# add parsed_datetime to the dict
for index, item in enumerate(sql_results):
sql_results[index]['parsed_datetime'] = network_timezones.parse_date_time(item['airdate'], item['airs'], item['network'])
sql_results[index]['data_show_name'] = value_maybe_article(item['show_name'])
sql_results[index]['data_network'] = value_maybe_article(item['network'])
sql_results.sort(sorts[self.sort])
finalEpResults = {}
# add all requested types or all
@ -1507,7 +1503,7 @@ class CMD_SickBeardGetDefaults(ApiCall):
data = {"status": statusStrings[sickbeard.STATUS_DEFAULT].lower(),
"flatten_folders": int(sickbeard.FLATTEN_FOLDERS_DEFAULT), "initial": anyQualities,
"archive": bestQualities, "future_show_paused": int(sickbeard.COMING_EPS_DISPLAY_PAUSED)}
"archive": bestQualities, "future_show_paused": int(sickbeard.EPISODE_VIEW_DISPLAY_PAUSED)}
return _responds(RESULT_SUCCESS, data)
@ -1756,7 +1752,7 @@ class CMD_SickBeardSetDefaults(ApiCall):
sickbeard.FLATTEN_FOLDERS_DEFAULT = int(self.flatten_folders)
if self.future_show_paused != None:
sickbeard.COMING_EPS_DISPLAY_PAUSED = int(self.future_show_paused)
sickbeard.EPISODE_VIEW_DISPLAY_PAUSED = int(self.future_show_paused)
return _responds(RESULT_SUCCESS, msg="Saved defaults")

View file

@ -67,7 +67,7 @@ from lib.dateutil import tz
from lib.unrar2 import RarFile
from lib import subliminal
from trakt import TraktCall
from lib.trakt import TraktCall
try:
import json
@ -300,7 +300,7 @@ class MainHandler(RequestHandler):
def setPosterSortBy(self, sort):
if sort not in ('name', 'date', 'network', 'progress'):
if sort not in ('name', 'time', 'network', 'progress'):
sort = 'name'
sickbeard.POSTER_SORTBY = sort
@ -326,36 +326,40 @@ class MainHandler(RequestHandler):
redirect("/home/displayShow?show=" + show)
def setComingEpsLayout(self, layout):
if layout not in ('poster', 'banner', 'list', 'calendar'):
def setEpisodeViewLayout(self, layout):
if layout not in ('poster', 'banner', 'list', 'daybyday'):
layout = 'banner'
if layout == 'calendar':
sickbeard.COMING_EPS_SORT = 'date'
if 'daybyday' == layout:
sickbeard.EPISODE_VIEW_SORT = 'time'
sickbeard.COMING_EPS_LAYOUT = layout
sickbeard.EPISODE_VIEW_LAYOUT = layout
redirect("/comingEpisodes/")
sickbeard.save_config()
def toggleComingEpsDisplayPaused(self, *args, **kwargs):
redirect("/episodeView/")
sickbeard.COMING_EPS_DISPLAY_PAUSED = not sickbeard.COMING_EPS_DISPLAY_PAUSED
def toggleEpisodeViewDisplayPaused(self, *args, **kwargs):
redirect("/comingEpisodes/")
sickbeard.EPISODE_VIEW_DISPLAY_PAUSED = not sickbeard.EPISODE_VIEW_DISPLAY_PAUSED
def setComingEpsSort(self, sort):
if sort not in ('date', 'network', 'show'):
sort = 'date'
sickbeard.save_config()
if sickbeard.COMING_EPS_LAYOUT == 'calendar':
sort = 'date'
redirect("/episodeView/")
sickbeard.COMING_EPS_SORT = sort
def setEpisodeViewSort(self, sort, redir=1):
if sort not in ('time', 'network', 'show'):
sort = 'time'
redirect("/comingEpisodes/")
sickbeard.EPISODE_VIEW_SORT = sort
def comingEpisodes(self, layout="None"):
""" display the coming episodes """
sickbeard.save_config()
if int(redir):
redirect("/episodeView/")
def episodeView(self, layout="None"):
""" display the episodes """
today_dt = datetime.date.today()
#today = today_dt.toordinal()
yesterday_dt = today_dt - datetime.timedelta(days=1)
@ -363,8 +367,8 @@ class MainHandler(RequestHandler):
tomorrow = (datetime.date.today() + datetime.timedelta(days=1)).toordinal()
next_week_dt = (datetime.date.today() + datetime.timedelta(days=7))
next_week = (next_week_dt + datetime.timedelta(days=1)).toordinal()
if not (layout and layout in ('calendar')) and not (sickbeard.COMING_EPS_LAYOUT and sickbeard.COMING_EPS_LAYOUT in ('calendar')):
recently = (yesterday_dt - datetime.timedelta(days=sickbeard.COMING_EPS_MISSED_RANGE)).toordinal()
if not (layout and layout in 'daybyday') and not (sickbeard.EPISODE_VIEW_LAYOUT and sickbeard.EPISODE_VIEW_LAYOUT in 'daybyday'):
recently = (yesterday_dt - datetime.timedelta(days=sickbeard.EPISODE_VIEW_MISSED_RANGE)).toordinal()
else:
recently = yesterday
@ -379,7 +383,7 @@ class MainHandler(RequestHandler):
for cur_result in sql_results:
done_show_list.append(int(cur_result["showid"]))
if not (layout and layout in ('calendar')) and not (sickbeard.COMING_EPS_LAYOUT and sickbeard.COMING_EPS_LAYOUT in ('calendar')):
if not (layout and layout in 'daybyday') and not (sickbeard.EPISODE_VIEW_LAYOUT and sickbeard.EPISODE_VIEW_LAYOUT in 'daybyday'):
more_sql_results = myDB.select(
"SELECT *, tv_shows.status as show_status FROM tv_episodes outer_eps, tv_shows WHERE season != 0 AND showid NOT IN (" + ','.join(
['?'] * len(
@ -395,49 +399,44 @@ class MainHandler(RequestHandler):
sql_results = list(set(sql_results))
# multi dimension sort
sorts = {
'date': (lambda a, b: cmp(
(a['localtime'],
(a['show_name'], remove_article(a['show_name']))[not sickbeard.SORT_ARTICLE],
a['season'], a['episode']),
(b['localtime'],
(b['show_name'], remove_article(b['show_name']))[not sickbeard.SORT_ARTICLE],
b['season'], b['episode']))),
'show': (lambda a, b: cmp(
((a['show_name'], remove_article(a['show_name']))[not sickbeard.SORT_ARTICLE],
a['localtime'], a['season'], a['episode']),
((b['show_name'], remove_article(b['show_name']))[not sickbeard.SORT_ARTICLE],
b['localtime'], b['season'], b['episode']))),
'network': (lambda a, b: cmp(
(a['network'], a['localtime'],
(a['show_name'], remove_article(a['show_name']))[not sickbeard.SORT_ARTICLE],
a['season'], a['episode']),
(b['network'], b['localtime'],
(b['show_name'], remove_article(b['show_name']))[not sickbeard.SORT_ARTICLE],
b['season'], b['episode'])))
}
# make a dict out of the sql results
sql_results = [dict(row) for row in sql_results]
# multi dimension sort
sorts = {
'network': (lambda a, b: cmp(
(a['data_network'], a['localtime'], a['data_show_name'], a['season'], a['episode']),
(b['data_network'], b['localtime'], b['data_show_name'], b['season'], b['episode']))),
'show': (lambda a, b: cmp(
(a['data_show_name'], a['localtime'], a['season'], a['episode']),
(b['data_show_name'], b['localtime'], b['season'], b['episode']))),
'time': (lambda a, b: cmp(
(a['localtime'], a['data_show_name'], a['season'], a['episode']),
(b['localtime'], b['data_show_name'], b['season'], b['episode'])))
}
def value_maybe_article(value=''):
return (remove_article(value.lower()), value.lower())[sickbeard.SORT_ARTICLE]
# add localtime to the dict
for index, item in enumerate(sql_results):
sql_results[index]['localtime'] = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(item['airdate'],
item['airs'], item['network']))
sql_results[index]['data_show_name'] = value_maybe_article(item['show_name'])
sql_results[index]['data_network'] = value_maybe_article(item['network'])
sql_results.sort(sorts[sickbeard.COMING_EPS_SORT])
sql_results.sort(sorts[sickbeard.EPISODE_VIEW_SORT])
t = PageTemplate(headers=self.request.headers, file="comingEpisodes.tmpl")
t = PageTemplate(headers=self.request.headers, file="episodeView.tmpl")
t.next_week = datetime.datetime.combine(next_week_dt, datetime.time(tzinfo=network_timezones.sb_timezone))
t.today = datetime.datetime.now(network_timezones.sb_timezone)
t.sql_results = sql_results
# Allow local overriding of layout parameter
if layout and layout in ('poster', 'banner', 'list','calendar'):
if layout and layout in ('banner', 'daybyday', 'list', 'poster'):
t.layout = layout
else:
t.layout = sickbeard.COMING_EPS_LAYOUT
t.layout = sickbeard.EPISODE_VIEW_LAYOUT
return _munge(t)
@ -549,7 +548,7 @@ class PageTemplate(Template):
self.sbPID = str(sickbeard.PID)
self.menu = [
{'title': 'Home', 'key': 'home'},
{'title': 'Coming Episodes', 'key': 'comingEpisodes'},
{'title': 'Episodes', 'key': 'episodeView'},
{'title': 'History', 'key': 'history'},
{'title': 'Manage', 'key': 'manage'},
{'title': 'Config', 'key': 'config'},
@ -630,7 +629,7 @@ class ManageSearches(MainHandler):
# t.backlogPI = sickbeard.backlogSearchScheduler.action.getProgressIndicator()
t.backlogPaused = sickbeard.searchQueueScheduler.action.is_backlog_paused() # @UndefinedVariable
t.backlogRunning = sickbeard.searchQueueScheduler.action.is_backlog_in_progress() # @UndefinedVariable
t.dailySearchStatus = sickbeard.dailySearchScheduler.action.amActive # @UndefinedVariable
t.recentSearchStatus = sickbeard.recentSearchScheduler.action.amActive # @UndefinedVariable
t.findPropersStatus = sickbeard.properFinderScheduler.action.amActive # @UndefinedVariable
t.queueLength = sickbeard.searchQueueScheduler.action.queue_length()
@ -658,10 +657,10 @@ class ManageSearches(MainHandler):
def forceSearch(self, *args, **kwargs):
# force it to run the next time it looks
result = sickbeard.dailySearchScheduler.forceRun()
result = sickbeard.recentSearchScheduler.forceRun()
if result:
logger.log(u"Daily search forced")
ui.notifications.message('Daily search started')
logger.log(u"Recent search forced")
ui.notifications.message('Recent search started')
redirect("/manage/manageSearches/")
@ -1628,10 +1627,10 @@ class ConfigSearch(MainHandler):
def saveSearch(self, use_nzbs=None, use_torrents=None, nzb_dir=None, sab_username=None, sab_password=None,
sab_apikey=None, sab_category=None, sab_host=None, nzbget_username=None, nzbget_password=None,
nzbget_category=None, nzbget_priority=None, nzbget_host=None, nzbget_use_https=None,
backlog_days=None, backlog_frequency=None, dailysearch_frequency=None,
backlog_days=None, backlog_frequency=None, recentsearch_frequency=None,
nzb_method=None, torrent_method=None, usenet_retention=None,
download_propers=None, check_propers_interval=None, allow_high_priority=None,
backlog_startup=None, dailysearch_startup=None,
backlog_startup=None, recentsearch_startup=None,
torrent_dir=None, torrent_username=None, torrent_password=None, torrent_host=None,
torrent_label=None, torrent_path=None, torrent_verify_cert=None,
torrent_seed_time=None, torrent_paused=None, torrent_high_bandwidth=None, ignore_words=None, require_words=None):
@ -1644,7 +1643,7 @@ class ConfigSearch(MainHandler):
if not config.change_TORRENT_DIR(torrent_dir):
results += ["Unable to create directory " + os.path.normpath(torrent_dir) + ", dir not changed."]
config.change_DAILYSEARCH_FREQUENCY(dailysearch_frequency)
config.change_RECENTSEARCH_FREQUENCY(recentsearch_frequency)
config.change_BACKLOG_FREQUENCY(backlog_frequency)
sickbeard.BACKLOG_DAYS = config.to_int(backlog_days, default=7)
@ -1664,7 +1663,7 @@ class ConfigSearch(MainHandler):
sickbeard.ALLOW_HIGH_PRIORITY = config.checkbox_to_value(allow_high_priority)
sickbeard.DAILYSEARCH_STARTUP = config.checkbox_to_value(dailysearch_startup)
sickbeard.RECENTSEARCH_STARTUP = config.checkbox_to_value(recentsearch_startup)
sickbeard.BACKLOG_STARTUP = config.checkbox_to_value(backlog_startup)
sickbeard.SAB_USERNAME = sab_username
@ -2092,10 +2091,10 @@ class ConfigProviders(MainHandler):
newznabProviderDict[cur_id].search_fallback = 0
try:
newznabProviderDict[cur_id].enable_daily = config.checkbox_to_value(
kwargs[cur_id + '_enable_daily'])
newznabProviderDict[cur_id].enable_recentsearch = config.checkbox_to_value(
kwargs[cur_id + '_enable_recentsearch'])
except:
newznabProviderDict[cur_id].enable_daily = 0
newznabProviderDict[cur_id].enable_recentsearch = 0
try:
newznabProviderDict[cur_id].enable_backlog = config.checkbox_to_value(
@ -2258,12 +2257,12 @@ class ConfigProviders(MainHandler):
except:
curTorrentProvider.search_fallback = 0 # these exceptions are catching unselected checkboxes
if hasattr(curTorrentProvider, 'enable_daily'):
if hasattr(curTorrentProvider, 'enable_recentsearch'):
try:
curTorrentProvider.enable_daily = config.checkbox_to_value(
kwargs[curTorrentProvider.getID() + '_enable_daily'])
curTorrentProvider.enable_recentsearch = config.checkbox_to_value(
kwargs[curTorrentProvider.getID() + '_enable_recentsearch'])
except:
curTorrentProvider.enable_daily = 0 # these exceptions are actually catching unselected checkboxes
curTorrentProvider.enable_recentsearch = 0 # these exceptions are actually catching unselected checkboxes
if hasattr(curTorrentProvider, 'enable_backlog'):
try:
@ -2300,12 +2299,12 @@ class ConfigProviders(MainHandler):
except:
curNzbProvider.search_fallback = 0 # these exceptions are actually catching unselected checkboxes
if hasattr(curNzbProvider, 'enable_daily'):
if hasattr(curNzbProvider, 'enable_recentsearch'):
try:
curNzbProvider.enable_daily = config.checkbox_to_value(
kwargs[curNzbProvider.getID() + '_enable_daily'])
curNzbProvider.enable_recentsearch = config.checkbox_to_value(
kwargs[curNzbProvider.getID() + '_enable_recentsearch'])
except:
curNzbProvider.enable_daily = 0 # these exceptions are actually catching unselected checkboxes
curNzbProvider.enable_recentsearch = 0 # these exceptions are actually catching unselected checkboxes
if hasattr(curNzbProvider, 'enable_backlog'):
try:
@ -2980,7 +2979,7 @@ class NewHomeAddShows(MainHandler):
tvdbs = ['tvdb_id', 'tvrage_id']
for index, tvdb in enumerate(tvdbs):
try:
item[u'show_id'] = item[tvdb]
item[u'show_id'] = str(item[tvdb])
tvshow = helpers.findCertainShow(sickbeard.showList, int(item[tvdb]))
except:
continue
@ -3628,6 +3627,17 @@ class Home(MainHandler):
ui.notifications.message('Checking out branch: ', branch)
return self.update(sickbeard.PID)
def pullRequestCheckout(self, branch):
pull_request = branch
branch = branch.split(':')[1]
fetched = sickbeard.versionCheckScheduler.action.fetch(pull_request)
if fetched:
sickbeard.BRANCH = branch
ui.notifications.message('Checking out branch: ', branch)
return self.update(sickbeard.PID)
else:
return redirect('/home/')
def displayShow(self, show=None):
if show is None:

View file

@ -3,12 +3,14 @@ import unittest
import test_lib as test
import sys, os.path
sys.path.append(os.path.abspath('..'))
sys.path.append(os.path.abspath('../lib'))
from sickbeard.name_parser import parser
import sickbeard
sickbeard.SYS_ENCODING = 'UTF-8'
DEBUG = VERBOSE = False
@ -66,7 +68,7 @@ simple_test_cases = {
'show.name.2010.222.123.source.quality.etc-group': parser.ParseResult(None, 'show name 2010.222', 1, [23], 'source.quality.etc', 'group'),
'Show.Name.102': parser.ParseResult(None, 'Show Name', 1, [2]),
'the.event.401.hdtv-lol': parser.ParseResult(None, 'the event', 4, [1], 'hdtv', 'lol'),
'show.name.2010.special.hdtv-blah': None,
# 'show.name.2010.special.hdtv-blah': None,
},
'stupid': {
@ -110,6 +112,86 @@ simple_test_cases = {
'2010-11-23 - Ep Name': parser.ParseResult(None, extra_info='Ep Name', air_date=datetime.date(2010, 11, 23)),
'Show.Name.2010.11.23.WEB-DL': parser.ParseResult(None, 'Show Name', None, [], 'WEB-DL', None, datetime.date(2010, 11, 23)),
},
'anime_ultimate': {
'[Tsuki] Bleach - 301 [1280x720][61D1D4EE]': parser.ParseResult(None, 'Bleach', None, [], '1280x720', 'Tsuki', None, [301]),
'[Tsuki] Fairy Tail - 70 [1280x720][C4807111]': parser.ParseResult(None, 'Fairy Tail', None, [], '1280x720', 'Tsuki', None, [70]),
'[SGKK] Bleach 312v2 [720p MKV]': parser.ParseResult(None, 'Bleach', None, [], '720p MKV', 'SGKK', None, [312]),
'[BSS-Anon] Tengen Toppa Gurren Lagann - 22-23 [1280x720][h264][6039D9AF]': parser.ParseResult(None, 'Tengen Toppa Gurren Lagann', None, [], '1280x720', 'BSS-Anon', None, [22, 23]),
'[SJSUBS]_Naruto_Shippuden_-_02_[480p AAC]': parser.ParseResult(None, 'Naruto Shippuden', None, [], '480p AAC', 'SJSUBS', None, [2]),
'[SFW-Chihiro] Dance in the Vampire Bund - 12 [1920x1080 Blu-ray FLAC][2F6DBC66].mkv': parser.ParseResult(None, 'Dance in the Vampire Bund', None, [], '1920x1080 Blu-ray FLAC', 'SFW-Chihiro', None, [12]),
'[SHiN-gx] Hanasaku Iroha - 01 [1280x720 h.264 AAC][BDC36683]': parser.ParseResult(None, 'Hanasaku Iroha', None, [], '1280x720 h.264 AAC', 'SHiN-gx', None, [1]),
'[SFW-Chihiro] Dance in the Vampire Bund - 02 [1920x1080 Blu-ray FLAC][C1FA0A09]': parser.ParseResult(None, 'Dance in the Vampire Bund', None, [], '1920x1080 Blu-ray FLAC', 'SFW-Chihiro', None, [2]),
'[HorribleSubs] No. 6 - 11 [720p]': parser.ParseResult(None, 'No. 6', None, [], '720p', 'HorribleSubs', None, [11]),
'[HorribleSubs] D Gray-Man - 312 (480p) [F501C9BE]': parser.ParseResult(None, 'D Gray-Man', None, [], '480p', 'HorribleSubs', None, [312]),
'[SGKK] Tengen Toppa Gurren Lagann - 45-46 (720p h264) [F501C9BE]': parser.ParseResult(None, 'Tengen Toppa Gurren Lagann', None, [], '720p h264', 'SGKK', None, [45, 46]),
'[Stratos-Subs]_Infinite_Stratos_-_12_(1280x720_H.264_AAC)_[379759DB]': parser.ParseResult(None, 'Infinite Stratos', None, [], '1280x720_H.264_AAC', 'Stratos-Subs', None, [12]),
'[ShinBunBu-Subs] Bleach - 02-03 (CX 1280x720 x264 AAC)': parser.ParseResult(None, 'Bleach', None, [], 'CX 1280x720 x264 AAC', 'ShinBunBu-Subs', None, [02, 03]),
'[Doki] Hanasaku Iroha - 03 (848x480 h264 AAC) [CB1AA73B]': parser.ParseResult(None, 'Hanasaku Iroha', None, [], '848x480 h264 AAC', 'Doki', None, [03]),
'[UTW]_Fractal_-_01_[h264-720p][96D3F1BF]': parser.ParseResult(None, 'Fractal', None, [], 'h264-720p', 'UTW', None, [1]),
'[a-s]_inuyasha_-_028_rs2_[BFDDF9F2]': parser.ParseResult(None, 'inuyasha', None, [], 'BFDDF9F2', 'a-s', None, [28]),
'[HorribleSubs] Fairy Tail S2 - 37 [1080p]': parser.ParseResult(None,'Fairy Tail S2', None, [], '1080p', 'HorribleSubs', None, [37]),
'[HorribleSubs] Sword Art Online II - 23 [720p]': parser.ParseResult(None, 'Sword Art Online II', None, [], '720p', 'HorribleSubs', None, [23])
},
'anime_ep_name': {
'[TzaTziki]_One_Piece_279_Chopper_Man_1_[720p][8AE5F25D]': parser.ParseResult(None, 'One Piece', None, [], '720p', 'TzaTziki', None, [279]),
"[ACX]Wolf's_Rain_-_04_-_Scars_in_the_Wasteland_[octavarium]_[82B7E357]": parser.ParseResult(None, "Wolf's Rain", None, [], 'octavarium', 'ACX', None, [4]),
'[ACX]Black Lagoon - 02v2 - Mangrove Heaven [SaintDeath] [7481F875]': parser.ParseResult(None, 'Black Lagoon', None, [], 'SaintDeath', 'ACX', None, [2]),
},
"anime_standard_round": {
'[SGKK] Bleach - 312v2 (1280x720 h264 AAC) [F501C9BE]': parser.ParseResult(None, 'Bleach', None, [], '1280x720 h264 AAC', 'SGKK', None, [312]),
},
'anime_slash': {
'[SGKK] Bleach 312v1 [720p/MKV]': parser.ParseResult(None, 'Bleach', None, [], '720p', 'SGKK', None, [312]),
'[SGKK] Bleach 312 [480p/MKV]': parser.ParseResult(None, 'Bleach', None, [], '480p', 'SGKK', None, [312])
},
'anime_standard_codec': {
'[Ayako]_Infinite_Stratos_-_IS_-_07_[H264][720p][EB7838FC]': parser.ParseResult(None, 'Infinite Stratos', None, [], '720p', 'Ayako', None, [7]),
'[Ayako] Infinite Stratos - IS - 07v2 [H264][720p][44419534]': parser.ParseResult(None, 'Infinite Stratos', None, [], '720p', 'Ayako', None, [7]),
'[Ayako-Shikkaku] Oniichan no Koto Nanka Zenzen Suki Janain Dakara ne - 10 [LQ][h264][720p] [8853B21C]': parser.ParseResult(None, 'Oniichan no Koto Nanka Zenzen Suki Janain Dakara ne', None, [], '720p', 'Ayako-Shikkaku', None, [10]),
'[Tsuki] Fairy Tail - 72 [XviD][C4807111]': parser.ParseResult(None, 'Fairy Tail', None, [], 'C4807111', 'Tsuki', None, [72]),
'Bubblegum Crisis Tokyo 2040 - 25 [aX] [F4E2E558]': parser.ParseResult(None, 'Bubblegum Crisis Tokyo 2040', None, [], "aX", None, None, [25]),
},
'anime_and_normal': {
'Bleach - s02e03 - 012 - Name & Name': parser.ParseResult(None, 'Bleach', 2, [3], None, None, None, [12]),
'Bleach - s02e03e04 - 012-013 - Name & Name': parser.ParseResult(None, 'Bleach', 2, [3, 4], None, None, None, [12, 13]),
'Bleach - s16e03-04 - 313-314': parser.ParseResult(None, 'Bleach', 16, [3, 4], None, None, None, [313, 314]),
'Blue Submarine No. 6 s16e03e04 313-314': parser.ParseResult(None, 'Blue Submarine No. 6', 16, [3, 4], None, None, None, [313, 314]),
'Bleach.s16e03-04.313-314': parser.ParseResult(None, 'Bleach', 16, [3, 4], None, None, None, [313, 314]),
'.hack roots s01e01 001.mkv': parser.ParseResult(None, 'hack roots', 1, [1], None, None, None, [1]),
'.hack sign s01e01 001.mkv': parser.ParseResult(None, 'hack sign', 1, [1], None, None, None, [1])
},
'anime_and_normal_reverse': {
'Bleach - 012 - s02e03 - Name & Name': parser.ParseResult(None, 'Bleach', 2, [3], None, None, None, [12]),
'Blue Submarine No. 6 - 012-013 - s02e03e04 - Name & Name': parser.ParseResult(None, 'Blue Submarine No. 6', 2, [3, 4], None, None, None, [12, 13]),
'07-GHOST - 012-013 - s02e03e04 - Name & Name': parser.ParseResult(None, '07-GHOST', 2, [3, 4], None, None, None, [12, 13]),
'3x3 Eyes - 012-013 - s02e03-04 - Name & Name': parser.ParseResult(None, '3x3 Eyes', 2, [3, 4], None, None, None, [12, 13]),
},
'anime_and_normal_front': {
'165.Naruto Shippuuden.s08e014': parser.ParseResult(None, 'Naruto Shippuuden', 8, [14], None, None, None, [165]),
'165-166.Naruto Shippuuden.s08e014e015': parser.ParseResult(None, 'Naruto Shippuuden', 8, [14, 15], None, None, None, [165, 166]),
'165-166.07-GHOST.s08e014-015': parser.ParseResult(None, '07-GHOST', 8, [14, 15], None, None, None, [165, 166]),
'165-166.3x3 Eyes.S08E014E015': parser.ParseResult(None, '3x3 Eyes', 8, [14, 15], None, None, None, [165, 166]),
},
'anime_bare': {
'One Piece 102': parser.ParseResult(None, 'One Piece', None, [], None, None, None, [102]),
'bleach - 010': parser.ParseResult(None, 'bleach', None, [], None, None, None, [10]),
'Naruto Shippuden - 314v2': parser.ParseResult(None, 'Naruto Shippuden', None, [], None, None, None, [314]),
'Blue Submarine No. 6 104-105': parser.ParseResult(None, 'Blue Submarine No. 6', None, [], None, None, None, [104, 105]),
'Samurai X: Trust & Betrayal (OVA) 001-002': parser.ParseResult(None, 'Samurai X: Trust & Betrayal (OVA)', None, [], None, None, None, [1, 2]),
"[ACX]_Wolf's_Spirit_001.mkv": parser.ParseResult(None, "Wolf's Spirit", None, [], None, 'ACX', None, [1])
}
}
combination_test_cases = [
@ -159,7 +241,6 @@ failure_cases = ['7sins-jfcs01e09-720p-bluray-x264']
class UnicodeTests(test.SickbeardTestDBCase):
def _test_unicode(self, name, result):
np = parser.NameParser(True)
@ -175,8 +256,8 @@ class UnicodeTests(test.SickbeardTestDBCase):
for (name, result) in unicode_test_cases:
self._test_unicode(name, result)
class FailureCaseTests(test.SickbeardTestDBCase):
class FailureCaseTests(test.SickbeardTestDBCase):
def _test_name(self, name):
np = parser.NameParser(True)
try:
@ -192,8 +273,8 @@ class FailureCaseTests(test.SickbeardTestDBCase):
for name in failure_cases:
self.assertTrue(self._test_name(name))
class ComboTests(test.SickbeardTestDBCase):
class ComboTests(test.SickbeardTestDBCase):
def _test_combo(self, name, result, which_regexes):
if VERBOSE:
@ -211,7 +292,6 @@ class ComboTests(test.SickbeardTestDBCase):
print test_result, test_result.which_regex
print result, which_regexes
self.assertEqual(test_result, result)
for cur_regex in which_regexes:
self.assertTrue(cur_regex in test_result.which_regex)
@ -224,8 +304,8 @@ class ComboTests(test.SickbeardTestDBCase):
# paths when test is run on Windows.
self._test_combo(os.path.normpath(name), result, which_regexes)
class BasicTests(test.SickbeardTestDBCase):
class BasicTests(test.SickbeardTestDBCase):
def _test_names(self, np, section, transform=None, verbose=False):
if VERBOSE or verbose:
@ -246,105 +326,146 @@ class BasicTests(test.SickbeardTestDBCase):
else:
test_result = np.parse(cur_test)
if DEBUG or verbose:
try:
# self.assertEqual(test_result.which_regex, [section])
self.assertEqual(test_result, result)
except:
print 'air_by_date:', test_result.is_air_by_date, 'air_date:', test_result.air_date
print 'anime:', test_result.is_anime, 'ab_episode_numbers:', test_result.ab_episode_numbers
print test_result
print result
self.assertEqual(test_result.which_regex, [section])
self.assertEqual(test_result, result)
raise
#def test_standard_names(self):
# np = parser.NameParser(False)
# self._test_names(np, 'standard')
#
#def test_standard_repeat_names(self):
# np = parser.NameParser(False)
# self._test_names(np, 'standard_repeat')
#
#def test_fov_names(self):
# np = parser.NameParser(False)
# self._test_names(np, 'fov')
#
#def test_fov_repeat_names(self):
# np = parser.NameParser(False)
# self._test_names(np, 'fov_repeat')
#
#def test_bare_names(self):
# np = parser.NameParser(False)
# self._test_names(np, 'bare')
#
#def test_stupid_names(self):
# np = parser.NameParser(False)
# self._test_names(np, 'stupid')
#
#def test_no_season_names(self):
# np = parser.NameParser(False)
# self._test_names(np, 'no_season')
#
#def test_no_season_general_names(self):
# np = parser.NameParser(False)
# self._test_names(np, 'no_season_general')
#
#def test_no_season_multi_ep_names(self):
# np = parser.NameParser(False)
# self._test_names(np, 'no_season_multi_ep')
#
#def test_season_only_names(self):
# np = parser.NameParser(False)
# self._test_names(np, 'season_only')
#
#def test_scene_date_format_names(self):
# np = parser.NameParser(False)
# self._test_names(np, 'scene_date_format')
#
#def test_standard_file_names(self):
# np = parser.NameParser()
# self._test_names(np, 'standard', lambda x: x + '.avi')
#
#def test_standard_repeat_file_names(self):
# np = parser.NameParser()
# self._test_names(np, 'standard_repeat', lambda x: x + '.avi')
#
#def test_fov_file_names(self):
# np = parser.NameParser()
# self._test_names(np, 'fov', lambda x: x + '.avi')
#
#def test_fov_repeat_file_names(self):
# np = parser.NameParser()
# self._test_names(np, 'fov_repeat', lambda x: x + '.avi')
#
#def test_bare_file_names(self):
# np = parser.NameParser()
# self._test_names(np, 'bare', lambda x: x + '.avi')
#
#def test_stupid_file_names(self):
# np = parser.NameParser()
# self._test_names(np, 'stupid', lambda x: x + '.avi')
#
#def test_no_season_file_names(self):
# np = parser.NameParser()
# self._test_names(np, 'no_season', lambda x: x + '.avi')
#
#def test_no_season_general_file_names(self):
# np = parser.NameParser()
# self._test_names(np, 'no_season_general', lambda x: x + '.avi')
#
#def test_no_season_multi_ep_file_names(self):
# np = parser.NameParser()
# self._test_names(np, 'no_season_multi_ep', lambda x: x + '.avi')
#
#def test_season_only_file_names(self):
# np = parser.NameParser()
# self._test_names(np, 'season_only', lambda x: x + '.avi')
#
#def test_scene_date_format_file_names(self):
# np = parser.NameParser()
# self._test_names(np, 'scene_date_format', lambda x: x + '.avi')
def test_standard_names(self):
np = parser.NameParser(False, testing=True)
self._test_names(np, 'standard')
def test_standard_repeat_names(self):
np = parser.NameParser(False, testing=True)
self._test_names(np, 'standard_repeat')
def test_fov_names(self):
np = parser.NameParser(False, testing=True)
self._test_names(np, 'fov')
def test_fov_repeat_names(self):
np = parser.NameParser(False, testing=True)
self._test_names(np, 'fov_repeat')
def test_bare_names(self):
np = parser.NameParser(False, testing=True)
self._test_names(np, 'bare')
def test_stupid_names(self):
np = parser.NameParser(False, testing=True)
self._test_names(np, 'stupid')
def test_no_season_names(self):
np = parser.NameParser(False, testing=True)
self._test_names(np, 'no_season')
def test_no_season_general_names(self):
np = parser.NameParser(False, testing=True)
self._test_names(np, 'no_season_general')
def test_no_season_multi_ep_names(self):
np = parser.NameParser(False, testing=True)
self._test_names(np, 'no_season_multi_ep')
def test_season_only_names(self):
np = parser.NameParser(False, testing=True)
self._test_names(np, 'season_only')
def test_scene_date_format_names(self):
np = parser.NameParser(False, testing=True)
self._test_names(np, 'scene_date_format')
def test_standard_file_names(self):
np = parser.NameParser(testing=True)
self._test_names(np, 'standard', lambda x: x + '.avi')
def test_standard_repeat_file_names(self):
np = parser.NameParser(testing=True)
self._test_names(np, 'standard_repeat', lambda x: x + '.avi')
def test_fov_file_names(self):
np = parser.NameParser(testing=True)
self._test_names(np, 'fov', lambda x: x + '.avi')
def test_fov_repeat_file_names(self):
np = parser.NameParser(testing=True)
self._test_names(np, 'fov_repeat', lambda x: x + '.avi')
def test_bare_file_names(self):
np = parser.NameParser(testing=True)
self._test_names(np, 'bare', lambda x: x + '.avi')
def test_stupid_file_names(self):
np = parser.NameParser(testing=True)
self._test_names(np, 'stupid', lambda x: x + '.avi')
def test_no_season_file_names(self):
np = parser.NameParser(testing=True)
self._test_names(np, 'no_season', lambda x: x + '.avi')
def test_no_season_general_file_names(self):
np = parser.NameParser(testing=True)
self._test_names(np, 'no_season_general', lambda x: x + '.avi')
def test_no_season_multi_ep_file_names(self):
np = parser.NameParser(testing=True)
self._test_names(np, 'no_season_multi_ep', lambda x: x + '.avi')
def test_season_only_file_names(self):
np = parser.NameParser(testing=True)
self._test_names(np, 'season_only', lambda x: x + '.avi')
def test_scene_date_format_file_names(self):
np = parser.NameParser(testing=True)
self._test_names(np, 'scene_date_format', lambda x: x + '.avi')
def test_combination_names(self):
pass
def test_anime_ultimate(self):
np = parser.NameParser(False, TVShow(is_anime=True), testing=True)
self._test_names(np, 'anime_ultimate')
def test_anime_ep_name(self):
np = parser.NameParser(False, TVShow(is_anime=True), testing=True)
self._test_names(np, 'anime_ep_name')
def test_anime_slash(self):
np = parser.NameParser(False, TVShow(is_anime=True), testing=True)
self._test_names(np, 'anime_slash')
def test_anime_codec(self):
np = parser.NameParser(False, TVShow(is_anime=True), testing=True)
self._test_names(np, 'anime_standard_codec')
def test_anime_and_normal(self):
np = parser.NameParser(False, TVShow(is_anime=True), testing=True)
self._test_names(np, 'anime_and_normal')
def test_anime_and_normal_reverse(self):
np = parser.NameParser(False, TVShow(is_anime=True), testing=True)
self._test_names(np, 'anime_and_normal_reverse')
def test_anime_and_normal_front(self):
np = parser.NameParser(False, TVShow(is_anime=True), testing=True)
self._test_names(np, 'anime_and_normal_front')
def test_anime_bare(self):
np = parser.NameParser(False, TVShow(is_anime=True), testing=True)
self._test_names(np, 'anime_bare')
class TVShow(object):
def __init__(self, is_anime=False):
self.is_anime = is_anime
if __name__ == '__main__':
if len(sys.argv) > 1:
suite = unittest.TestLoader().loadTestsFromName('name_parser_tests.BasicTests.test_' + sys.argv[1])