mirror of
https://github.com/evilhero/mylar
synced 2024-12-21 15:22:23 +00:00
Merge branch 'development'
This commit is contained in:
commit
a6bc5d1ec6
25 changed files with 2132 additions and 68 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -11,4 +11,5 @@ Thumbs.db
|
|||
ehtumbs.db
|
||||
Thumbs.db
|
||||
lib/comictaggerlib/ct_settings/
|
||||
settings.json
|
||||
settings.json
|
||||
.DS_Store
|
||||
|
|
1
Mylar.py
1
Mylar.py
|
@ -308,6 +308,7 @@ def main():
|
|||
'opds_authentication': mylar.CONFIG.OPDS_AUTHENTICATION,
|
||||
'opds_username': mylar.CONFIG.OPDS_USERNAME,
|
||||
'opds_password': mylar.CONFIG.OPDS_PASSWORD,
|
||||
'opds_pagesize': mylar.CONFIG.OPDS_PAGESIZE,
|
||||
}
|
||||
|
||||
# Try to start the server.
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
## ![Mylar Logo](https://github.com/evilhero/mylar/blob/master/data/images/mylarlogo.png) Mylar
|
||||
|
||||
## Note that feature development has stopped as we have moved to [Mylar3](https://github.com/mylar3/mylar3).
|
||||
## This means only critical bug errors will get addressed until such time as we decide not to continue supporting this version. EOL is still to be decided.
|
||||
|
||||
Mylar is an automated Comic Book (cbr/cbz) downloader program for use with NZB and torrents written in python. It supports SABnzbd, NZBGET, and many torrent clients in addition to DDL.
|
||||
|
||||
It will allow you to monitor weekly pull-lists for items belonging to user-specific series to download, as well as being able to monitor story-arcs. Support for TPB's and GN's is also now available.
|
||||
|
|
330
data/css/webviewerstyle.css
Normal file
330
data/css/webviewerstyle.css
Normal file
|
@ -0,0 +1,330 @@
|
|||
html {
|
||||
}
|
||||
header,
|
||||
main,
|
||||
footer {
|
||||
background: #757575;
|
||||
}
|
||||
body {
|
||||
color: #FFFFFF;
|
||||
background: #757575;
|
||||
}
|
||||
#breadcrumbs {
|
||||
top: 0;
|
||||
background: #BDBDBD;
|
||||
}
|
||||
#comic-info {
|
||||
display: inline;
|
||||
}
|
||||
#dash_dashboard {
|
||||
padding-left: 8px;
|
||||
display: inline-block;
|
||||
}
|
||||
#dash_library {
|
||||
padding-left: 8px;
|
||||
display: inline-block;
|
||||
}
|
||||
#dash_settings {
|
||||
padding-left: 8px;
|
||||
display: inline-block;
|
||||
}
|
||||
#directory-card-content {
|
||||
display:flex;
|
||||
color: #FFFFFF;
|
||||
background-color: #BDBDBD;
|
||||
text-position: center;
|
||||
}
|
||||
#footer {
|
||||
background: #757575;
|
||||
}
|
||||
#theme-settings .dropdown-content li>a, .dropdown-content li>span, .select-dropdown li.disabled, .select-dropdown li.disabled>span, .select-dropdown li.optgroup {
|
||||
background: #757575;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#log-modal {
|
||||
background: #BDBDBD;
|
||||
color: #FFFFFF;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
#logo-wrapper {
|
||||
background: #757575;
|
||||
}
|
||||
i {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#nav-dropdown {
|
||||
background-color: #BDBDBD;
|
||||
}
|
||||
#nav-dropdown a {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#page-settings-text {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#page-settings-right-text i {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#page-settings-left-text i {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#pagination-num a {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#pagination-num.active {
|
||||
background-color: #BDBDBD;
|
||||
}
|
||||
#read-link {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#search-modal {
|
||||
background: #BDBDBD;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#search-modal input {
|
||||
margin: 0 auto;
|
||||
}
|
||||
#settings-arrow {
|
||||
color: #BDBDBD;
|
||||
}
|
||||
#settings-button {
|
||||
background: #BDBDBD;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#settings-help {
|
||||
position: absolute;
|
||||
z-index:5000;
|
||||
color: #FFFFFF;
|
||||
background: #BDBDBD;
|
||||
}
|
||||
#size-height-button {
|
||||
background: #BDBDBD;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#size-width-button {
|
||||
background: #BDBDBD;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#size-normal-button {
|
||||
background: #BDBDBD;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#summary-pane {
|
||||
background: #BDBDBD;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#tab-row {
|
||||
background: #757575;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.btn-flat {
|
||||
background: #BDBDBD;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.card {
|
||||
position: relative;
|
||||
background-color: #BDBDBD;
|
||||
box-shadow: 1px 1px 10px 1px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
.card-image {
|
||||
position: relative;
|
||||
height: 350px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.card-image img {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
.card-content {
|
||||
height: auto;
|
||||
background: #BDBDBD;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
}
|
||||
.card-content a {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.center-cols > .col {
|
||||
float:none; /* disable the float */
|
||||
display: inline-block; /* make blocks inline-block */
|
||||
text-align: initial; /* restore text-align to default */
|
||||
vertical-align: top;
|
||||
}
|
||||
.dimmed {
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
.dropdown-button {
|
||||
background-color: #BDBDBD;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.input-field {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.input-field label {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.input-field input[type=text]:focus + label {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.input-field input[type=text]:focus {
|
||||
border-bottom: 1px solid #FFFFFF;
|
||||
box-shadow: 0 1px 0 0 #FFFFFF;
|
||||
}
|
||||
.input-field input[type=password]:focus + label {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.input-field input[type=password]:focus {
|
||||
border-bottom: 1px solid #FFFFFF;
|
||||
box-shadow: 0 1px 0 0 #FFFFFF;
|
||||
}
|
||||
.nav-wrapper .input-field input[type="search"] {
|
||||
height: auto;
|
||||
color: #FFFFFF;
|
||||
background: #BDBDBD;
|
||||
}
|
||||
.nav-wrapper .input-field input[type="search"]:focus {
|
||||
background: #BDBDBD;
|
||||
color: #FFFFFF;
|
||||
box-shadow: 0 1px 0 0 #BDBDBD;
|
||||
}
|
||||
.nav-wrapper .input-field input[type="search"]:focus ~ .material-icons.icon-close {
|
||||
right: 2rem;
|
||||
}
|
||||
.nav-wrapper .dropdown-button {
|
||||
position:absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.overlay-settings {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
color: #000;
|
||||
z-index:4000;
|
||||
min-height: 1px;
|
||||
}
|
||||
.overlay-settings-text {
|
||||
color: #FFFFFF;
|
||||
height: 900px;
|
||||
line-height: 900px;
|
||||
text-align: center;
|
||||
}
|
||||
.page-left {
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
height: 100%;
|
||||
width: 33.33%;
|
||||
}
|
||||
.page-settings {
|
||||
position: fixed;
|
||||
left: 33.33%;
|
||||
top: 0px;
|
||||
height: 100%;
|
||||
width: 33.33%;
|
||||
}
|
||||
.page-right {
|
||||
position: fixed;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
height: 100%;
|
||||
width: 33.33%;
|
||||
}
|
||||
.reader-overlay {
|
||||
position: absolute;
|
||||
background-color:#757575;
|
||||
width:100%;
|
||||
height:100%;
|
||||
top:0px;
|
||||
left:0px;
|
||||
z-index:1000;
|
||||
max-width:100%;
|
||||
}
|
||||
.reader-page-wide {
|
||||
width:100%;
|
||||
}
|
||||
.reader-page-high {
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
max-width:100%;
|
||||
}
|
||||
.reader-page-norm {
|
||||
position: absolute;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
max-width:100%;
|
||||
}
|
||||
.settings-span-left {
|
||||
display: inline-block;
|
||||
left: 0px;
|
||||
vertical-align: middle;
|
||||
line-height: normal;
|
||||
}
|
||||
.settings-span-center {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
line-height: normal;
|
||||
}
|
||||
.settings-span-right {
|
||||
display: inline-block;
|
||||
right: 0px;
|
||||
vertical-align: middle;
|
||||
line-height: normal;
|
||||
}
|
||||
.tabs .tab a {
|
||||
background: #757575;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.tabs .tab a:hover {
|
||||
color: #BDBDBD;
|
||||
}
|
||||
.tabs .indicator {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
@media only screen and (min-width : 601px) and (max-width : 1260px) {
|
||||
.toast {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width : 1261px) {
|
||||
.toast {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width : 601px) and (max-width : 1260px) {
|
||||
#toast-container {
|
||||
bottom: 0;
|
||||
top: 90%;
|
||||
right: 50%;
|
||||
transform: translate(50%, 0);
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width : 1261px) {
|
||||
#toast-container {
|
||||
bottom: 0;
|
||||
top: 90%;
|
||||
right: 50%;
|
||||
transform: translate(50%, 0);
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
${next.headIncludes()}
|
||||
|
||||
<script src="js/libs/modernizr-2.8.3.min.js"></script>
|
||||
<script src="js/libs/jquery-1.7.2.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<%
|
||||
|
@ -109,7 +110,6 @@
|
|||
<a href="#main" id="toTop"><span>Back to top</span></a>
|
||||
</div>
|
||||
|
||||
<script src="js/libs/jquery-1.7.2.min.js"></script>
|
||||
<script src="js/libs/jquery-ui.min.js"></script>
|
||||
<script src="js/common.js"></script>
|
||||
|
||||
|
|
|
@ -431,6 +431,7 @@
|
|||
%>
|
||||
%if linky:
|
||||
<a href="downloadthis?pathfile=${linky |u}"><img src="interfaces/default/images/download_icon.png" height="25" width="25" title="Download the Issue" class="highqual" /></a>
|
||||
<a href="read_comic?ish_id=${issue['IssueID']}&page_num=0&size=high"><img src="interfaces/default/images/readabook.png" height="25" width="25" title="Read the Issue in your Browser" class="highqual" /></a>
|
||||
%if linky.endswith('.cbz'):
|
||||
<a href="#issue-box" onclick="return runMetaIssue('${linky |u}', '${comic['ComicName']| u}', '${issue['Issue_Number']}', '${issue['IssueDate']}', '${issue['IssueName'] |u}');" class="issue-window"><img src="interfaces/default/images/issueinfo.png" height="25" width="25" title="View Issue Details" class="highqual" /></a>
|
||||
<div id="issue-box" class="issue-popup">
|
||||
|
|
|
@ -244,6 +244,10 @@
|
|||
<div id="opdsoptions">
|
||||
<div class="row_checkbox">
|
||||
<small>Access the OPDS server at http://mylarhost/opds/ - keep in mind your scheme (http or https), your hostname, port, and any http_root you may have set. </small></br>
|
||||
<div class="row">
|
||||
<label>OPDS Page Size</label>
|
||||
<input type="text" name="opds_pagesize" value="${config['opds_pagesize']}" size="10">
|
||||
</div>
|
||||
<input id="opds_authentication" type="checkbox" name="opds_authentication" value="1" ${config['opds_authentication']} /><label>OPDS Requires Credentials</label>
|
||||
<%
|
||||
opds_notes = "Require authentication for OPDS. If checked\nyou will need to provide a username/password.\nThe service user name will work (if set). Additionally,\nyou can provide a user with only OPDS access below.\nNOTE: If this is not checked, OPDS will be available\nwithout a password."
|
||||
|
@ -412,7 +416,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div align="center" class="row">
|
||||
<img name="sabnzbd_statusicon" id="sabnzbd_statusicon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="sabnzbd_statusicon" id="sabnzbd_statusicon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test SABnzbd" id="test_sab" style="float:center" /></br>
|
||||
<input type="text" name="sabstatus" style="text-align:center; font-size:11px;" id="sabstatus" size="50" DISABLED />
|
||||
<div name="sabversion" id="sabversion" style="font-size:11px;" align="center">
|
||||
|
@ -480,7 +484,7 @@
|
|||
</div>
|
||||
|
||||
<div align="center" class="row">
|
||||
<img name="nzbget_statusicon" id="nzbget_statusicon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="nzbget_statusicon" id="nzbget_statusicon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test NZBGet" id="test_nzbget" style="float:center" /></br>
|
||||
<input type="text" name="nzbgetstatus" style="text-align:center; font-size:11px;" id="nzbgetstatus" size="50" DISABLED />
|
||||
</div>
|
||||
|
@ -631,7 +635,7 @@
|
|||
<small>Automatically start torrent on successful loading within rtorrent client</small>
|
||||
</div>
|
||||
<div class="row">
|
||||
<img name="rtorrent_statusicon" id="rtorrent_statusicon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="rtorrent_statusicon" id="rtorrent_statusicon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test Connection" id="rtorrent_test" />
|
||||
</div>
|
||||
</fieldset>
|
||||
|
@ -690,7 +694,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<img name="deluge_status_icon" id="deluge_status_icon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="deluge_status_icon" id="deluge_status_icon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test Connection" id="deluge_test" /><br/>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
@ -732,7 +736,7 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="row">
|
||||
<img name="qbittorrent_statusicon" id="qbittorrent_statusicon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="qbittorrent_statusicon" id="qbittorrent_statusicon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test Connection" id="qbittorrent_test" />
|
||||
</div>
|
||||
</fieldset>
|
||||
|
@ -893,6 +897,10 @@
|
|||
else:
|
||||
torznab_enabled = ""
|
||||
|
||||
if torznab[2] == '1' or torznab[2] == 1:
|
||||
torznab_verify = "checked"
|
||||
else:
|
||||
torznab_verify = ""
|
||||
%>
|
||||
|
||||
<div class="config" id="torznab${torznab_number}">
|
||||
|
@ -904,13 +912,17 @@
|
|||
<label>Torznab Host</label>
|
||||
<input type="text" name="torznab_host${torznab_number}" id="torznab_host${torznab_number}" value="${torznab[1]}" size="30">
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Verify SSL</label>
|
||||
<input type="checkbox" name="torznab_verify${torznab_number}" id="torznab_verify${torznab_number}" value="${torznab[2]}">
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Torznab API</label>
|
||||
<input type="text" name="torznab_apikey${torznab_number}" id="torznab_apikey${torznab_number}" value="${torznab[2]}" size="36">
|
||||
<input type="text" name="torznab_apikey${torznab_number}" id="torznab_apikey${torznab_number}" value="${torznab[3]}" size="36">
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Torznab Category</label>
|
||||
<input type="text" name="torznab_category${torznab_number}" id="torznab_category${torznab_number}" value="${torznab[3]}" size="12">
|
||||
<input type="text" name="torznab_category${torznab_number}" id="torznab_category${torznab_number}" value="${torznab[4]}" size="12">
|
||||
</div>
|
||||
<div class="row checkbox">
|
||||
<input id="torznab_enabled${torznab_number}" type="checkbox" name="torznab_enabled${torznab_number}" value="1" ${torznab_enabled} /><label>Enabled</label>
|
||||
|
@ -1339,7 +1351,7 @@
|
|||
<input type="text" name="prowl_priority" value="${config['prowl_priority']}" size="2">
|
||||
</div>
|
||||
<div class="row">
|
||||
<img name="prowl_statusicon" id="prowl_statusicon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="prowl_statusicon" id="prowl_statusicon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test PROWL" id="prowl_test" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1367,7 +1379,7 @@
|
|||
<input type="text" name="pushover_priority" value="${config['pushover_priority']}" size="2">
|
||||
</div>
|
||||
<div align="center" class="row">
|
||||
<img name="pushover_statusicon" id="pushover_statusicon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="pushover_statusicon" id="pushover_statusicon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test Pushover" id="pushover_test" style="float:center" /></br>
|
||||
<input type="text" name="pushoverstatus" style="text-align:center; font-size:11px;" id="pushoverstatus" size="55" DISABLED />
|
||||
</div>
|
||||
|
@ -1387,7 +1399,7 @@
|
|||
<label>Boxcar Token</label>
|
||||
<input type="text" name="boxcar_token" value="${config['boxcar_token']}" size="30">
|
||||
<div class="row">
|
||||
<img name="boxcar_statusicon" id="boxcar_statusicon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="boxcar_statusicon" id="boxcar_statusicon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test Boxcar" id="boxcar_test" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1419,7 +1431,7 @@
|
|||
<small>Send to all subscribers of the channel with this tag (Optional)</small>
|
||||
</div>
|
||||
<div align="center" class="row">
|
||||
<img name="pushbullet_statusicon" id="pushbullet_statusicon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="pushbullet_statusicon" id="pushbullet_statusicon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test Pushbullet" id="pushbullet_test" style="float:center" /></br>
|
||||
<input type="text" name="pbstatus" style="text-align:center; font-size:11px;" id="pbstatus" size="55" DISABLED />
|
||||
</div>
|
||||
|
@ -1442,7 +1454,7 @@
|
|||
<input type="checkbox" name="telegram_onsnatch" value="1" ${config['telegram_onsnatch']} /><label>Notify on snatch?</label>
|
||||
</div>
|
||||
<div align="center" class="row">
|
||||
<img name="telegram_statusicon" id="telegram_statusicon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="telegram_statusicon" id="telegram_statusicon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test Telegram" id="telegram_test" style="float:center" /></br>
|
||||
<input type="text" name="telegramstatus" style="text-align:center; font-size:11px;" id="telegramstatus" size="55" DISABLED />
|
||||
</div>
|
||||
|
@ -1462,7 +1474,7 @@
|
|||
<input type="checkbox" name="slack_onsnatch" value="1" ${config['slack_onsnatch']} /><label>Notify on snatch?</label>
|
||||
</div>
|
||||
<div align="center" class="row">
|
||||
<img name="slack_statusicon" id="slack_statusicon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="slack_statusicon" id="slack_statusicon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test Slack" id="slack_test" style="float:center" /></br>
|
||||
<input type="text" name="slackstatus" style="text-align:center; font-size:11px;" id="slackstatus" size="55" DISABLED />
|
||||
</div>
|
||||
|
@ -1514,7 +1526,7 @@
|
|||
<small>Notify when comics are post processed?</small>
|
||||
</div>
|
||||
<div align="center" class="row">
|
||||
<img name="email_statusicon" id="email_statusicon" src="interfaces/default/images/successs.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<img name="email_statusicon" id="email_statusicon" src="interfaces/default/images/success.png" style="float:right;visibility:hidden;" height="20" width="20" />
|
||||
<input type="button" value="Test Email" id="email_test" style="float:center" /></br>
|
||||
<input type="text" name="emailstatus" style="text-align:center; font-size:11px;" id="emailstatus" size="55" DISABLED />
|
||||
</div>
|
||||
|
@ -2179,7 +2191,7 @@
|
|||
|
||||
$("#add_torznab").click(function() {
|
||||
var intId = $("#torznab_providers > div").size() + deletedTorznabs + 1;
|
||||
var torformfields = $("<div class=\"config\" id=\"torznab" + intId + "\"><div class=\"row\"><label>Torznab Name</label><input type=\"text\" id=\"torznab_name" + intId + "\" name=\"torznab_name" + intId + "\" size=\"36\"></div><div class=\"row\"><label>Torznab Host</label><input type=\"text\" id=\"torznab_host" + intId + "\" name=\"torznab_host" + intId + "\" + value=\"http://\" + size=\"30\"></div><div class=\"row\"><label>Torznab API</label><input type=\"text\" id=\"torznab_apikey" + intId + "\" name=\"torznab_apikey" + intId + "\" size=\"36\"></div><div class=\"row\"><label>Torznab Category</label><input type=\"text\" id=\"torznab_category" + intId + "\" name=\"torznab_category" + intId + "\" size=\"36\"></div><div class=\"row checkbox\"><input type=\"checkbox\" name=\"torznab_enabled" + intId + "\" value=\"1\" checked /><label>Enabled</label></div>");
|
||||
var torformfields = $("<div class=\"config\" id=\"torznab" + intId + "\"><div class=\"row\"><label>Torznab Name</label><input type=\"text\" id=\"torznab_name" + intId + "\" name=\"torznab_name" + intId + "\" size=\"36\"></div><div class=\"row\"><label>Torznab Host</label><input type=\"text\" id=\"torznab_host" + intId + "\" name=\"torznab_host" + intId + "\" + value=\"http://\" + size=\"30\"></div><div class=\"row checkbox\"><input id=\"torznab_verify" + intId + "\" type=\"checkbox\" name=\"torznab_verify" + intId + "\" value=\"1\"/><label>Verify SSL</label></div><div class=\"row\"><label>Torznab API</label><input type=\"text\" id=\"torznab_apikey" + intId + "\" name=\"torznab_apikey" + intId + "\" size=\"36\"></div><div class=\"row\"><label>Torznab Category</label><input type=\"text\" id=\"torznab_category" + intId + "\" name=\"torznab_category" + intId + "\" size=\"36\"></div><div class=\"row checkbox\"><input type=\"checkbox\" name=\"torznab_enabled" + intId + "\" value=\"1\" checked /><label>Enabled</label></div>");
|
||||
var tortestButton = $("<div class=\"row\"><img name=\"torznabstatus" + intId + "\" id=\"torznabstatus" + intId + "\" src=\"interfaces/default/images/success.png\" style=\"float:right;visibility:hidden;\" height=\"20\" width=\"20\" /><input type=\"button\" class=\"torznabtest\" value=\"Test\" id=\"torznab_test" + intId + "\" name=\"torznab_test" + intId + "\" style=\"float:right;margin-right:10px;\" /></div>");
|
||||
var torremoveButton = $("<div class=\"row\"><input type=\"button\" class=\"remove\" value=\"Remove\" /></div>");
|
||||
torremoveButton.click(function() {
|
||||
|
@ -2322,10 +2334,11 @@
|
|||
|
||||
$(".torznabtest").click(function () {
|
||||
var torznab = this.attributes["name"].value.replace('torznab_test', '');
|
||||
var imagechk = document.getElementById("tornabstatus"+torznab);
|
||||
var imagechk = document.getElementById("torznabstatus"+torznab);
|
||||
var name = document.getElementById("torznab_name"+torznab).value;
|
||||
var host = document.getElementById("torznab_host"+torznab).value;
|
||||
var apikey = document.getElementById("torznab_api"+torznab).value;
|
||||
var ssl = document.getElementById("torznab_verify"+torznab).checked;
|
||||
var apikey = document.getElementById("torznab_apikey"+torznab).value;
|
||||
$.get("testtorznab",
|
||||
{ name: name, host: host, ssl: ssl, apikey: apikey },
|
||||
function(data){
|
||||
|
|
16
data/interfaces/default/header.html
Normal file
16
data/interfaces/default/header.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
<%page args="jscolor=False"/>
|
||||
<head>
|
||||
<title>Mylar WebViewer</title>
|
||||
<meta name="description" content="Mylar Web Viewer">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/webviewerstyle.css">
|
||||
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/js/materialize.min.js"></script>
|
||||
% if jscolor is True:
|
||||
<script src="js/jscolor.min.js"></script>
|
||||
% endif
|
||||
</head>
|
BIN
data/interfaces/default/images/readabook.png
Normal file
BIN
data/interfaces/default/images/readabook.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
|
@ -32,17 +32,23 @@
|
|||
%if mylar.IMPORT_STATUS == 'Import completed.':
|
||||
<input type="text" name="importstatus" id="importstatus" style="text-align:center; font-size:11px;" size="60" DISABLED /></br>
|
||||
<script>
|
||||
turnitoff();
|
||||
$(function() {
|
||||
turnitoff();
|
||||
}):
|
||||
</script>
|
||||
%else:
|
||||
<input type="text" name="importstatus" id="importstatus" style="text-align:center; font-size:11px;" size="60" DISABLED /></br>
|
||||
<script>
|
||||
turniton();
|
||||
$(function() {
|
||||
turniton();
|
||||
});
|
||||
</script>
|
||||
%endif
|
||||
%else:
|
||||
<script>
|
||||
turnitoff();
|
||||
$(function() {
|
||||
turnitoff();
|
||||
});
|
||||
</script>
|
||||
<input type="text" name="importstatus" id="importstatus" style="text-align:center; font-size:11px;" size="60" value="Import is currently not running" DISABLED /></br>
|
||||
%endif
|
||||
|
@ -277,7 +283,9 @@
|
|||
};
|
||||
function turnitoff() {
|
||||
CheckEnabled = false;
|
||||
clearInterval(ImportTimer);
|
||||
if (typeof ImportTimer !== 'undefined') {
|
||||
clearInterval(ImportTimer);
|
||||
};
|
||||
};
|
||||
function turniton() {
|
||||
if (CheckEnabled == false) {
|
||||
|
|
114
data/interfaces/default/read.html
Normal file
114
data/interfaces/default/read.html
Normal file
|
@ -0,0 +1,114 @@
|
|||
<%!
|
||||
import mylar
|
||||
%>
|
||||
<%
|
||||
now_page = pages[current_page]
|
||||
%>
|
||||
<!doctype html>
|
||||
<html class="whole-page">
|
||||
<%include file="header.html" />
|
||||
|
||||
<body class="inner-page">
|
||||
<div class="reader-whole">
|
||||
% if (current_page + 1) == 1:
|
||||
<a class="btn btn-floating btn-large pulse tooltipped" id="settings-help" data-position="bottom" data-delay="50" data-tooltip="Click the center to bring up settings. Click the left and right sides of the page to change pages."><i class="material-icons">help_outline</i></a>
|
||||
% endif
|
||||
<div class="col s12 overlay-settings">
|
||||
<div class="overlay-settings-text">
|
||||
<div class="page-left">
|
||||
<span class="settings-span-left">
|
||||
<h4 style="display: none;" id="page-settings-left-text">
|
||||
<i class="large material-icons" id="settings-arrow">arrow_back</i>
|
||||
</h4>
|
||||
</span>
|
||||
</div>
|
||||
<div class="page-settings">
|
||||
<span class="settings-span-center">
|
||||
<p style="display: none;" id="page-settings-text">
|
||||
<a class="waves-effect waves-light btn-large" id="settings-button" href="index">Home</a>
|
||||
</br>
|
||||
</br>
|
||||
<b>On Page ${current_page + 1} of ${nop} Pages</b>
|
||||
</br>
|
||||
</br>
|
||||
<a class="waves-effect waves-light btn-large" id="settings-button" action="action" value="Back" onclick="window.history.go(-1); return false">Close Book</a>
|
||||
</br>
|
||||
</br>
|
||||
<b>Fit Comic to Height/Width/No Fit</b>
|
||||
</br>
|
||||
</br>
|
||||
<a class="waves-effect waves-light btn-large" id="size-width-button" href="#!">Width</a>
|
||||
<a class="waves-effect waves-light btn-large" id="size-height-button" href="#!">Height</a>
|
||||
<a class="waves-effect waves-light btn-large" id="size-normal-button" href="#!">No Fit</a>
|
||||
</p>
|
||||
</span>
|
||||
</div>
|
||||
<div class="page-right">
|
||||
<span class="settings-span-right">
|
||||
<h4 style="display: none;" id="page-settings-right-text"><i class="large material-icons" id="settings-arrow">arrow_forward</i></h4>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row reader-overlay">
|
||||
% if size == "wide":
|
||||
<img class="reader-page-wide" src="${now_page}"/>
|
||||
% elif size == "high":
|
||||
<img class="reader-page-high" src="${now_page}"/>
|
||||
% elif size == "norm":
|
||||
<img class="reader-page-norm" src="${now_page}"/>
|
||||
% else:
|
||||
<img class="reader-page-wide" src="${now_page}"/>
|
||||
% endif:
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('.modal-trigger').leanModal();
|
||||
$(".page-settings").click(function() {
|
||||
$(".page-settings").toggleClass( "dimmed" );
|
||||
$(".page-left").toggleClass( "dimmed" );
|
||||
$(".page-right").toggleClass( "dimmed" );
|
||||
$("#page-settings-text").toggle();
|
||||
$("#page-settings-left-text").toggle();
|
||||
$("#page-settings-right-text").toggle();
|
||||
});
|
||||
$(".page-right").click(function() {
|
||||
$(".whole-page").load("${mylar.CONFIG.HTTP_ROOT}read_comic?ish_id=${ish_id}&page_num=${np}&size=${size}");
|
||||
});
|
||||
$(".page-left").click(function() {
|
||||
$(".whole-page").load("${mylar.CONFIG.HTTP_ROOT}read_comic?ish_id=${ish_id}&page_num=${pp}&size=${size}");
|
||||
});
|
||||
$(document).one("keyup", function(e) {
|
||||
if (e.which == 39) {
|
||||
$(".whole-page").load("${mylar.CONFIG.HTTP_ROOT}read_comic?ish_id=${ish_id}&page_num=${np}&size=${size}");
|
||||
}
|
||||
});
|
||||
$(document).one("keyup", function(e) {
|
||||
if (e.which == 37) {
|
||||
$(".whole-page").load("${mylar.CONFIG.HTTP_ROOT}read_comic?ish_id=${ish_id}&page_num=${pp}&size=${size}");
|
||||
}
|
||||
});
|
||||
$("#size-width-button").click(function() {
|
||||
$(".reader-overlay").html("<img class='reader-page-wide' src='${now_page}'/>");
|
||||
// $.ajax({
|
||||
// url: "up_size_pref?pref=wide"
|
||||
// });
|
||||
});
|
||||
$("#size-height-button").click(function() {
|
||||
$(".reader-overlay").html("<img class='reader-page-high' src='${now_page}'/>");
|
||||
// $.ajax({
|
||||
// url: "up_size_pref?pref=high"
|
||||
// });
|
||||
});
|
||||
$("#size-normal-button").click(function() {
|
||||
$(".reader-overlay").html("<img class='reader-page-norm' src='${now_page}'/>");
|
||||
// $.ajax({
|
||||
// url: "up_size_pref?pref=norm"
|
||||
// });
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</html>
|
|
@ -369,6 +369,8 @@
|
|||
"sInfoFiltered":"(filtered from _MAX_ total issues)",
|
||||
"sSearch": ""},
|
||||
"bStateSave": true,
|
||||
"StateSave": true,
|
||||
"StateDuration": 0,
|
||||
"iDisplayLength": 25,
|
||||
"sPaginationType": "full_numbers",
|
||||
"aaSorting": [[0, 'asc']]
|
||||
|
|
10
data/js/jscolor.min.js
vendored
Normal file
10
data/js/jscolor.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1279
lib/pathlib.py
Normal file
1279
lib/pathlib.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1942,8 +1942,12 @@ class PostProcessor(object):
|
|||
logger.info('%s Post-Processing completed for: [ %s #%s ] %s' % (module, comicname, issuenumber, grab_dst))
|
||||
self._log(u"Post Processing SUCCESSFUL! ")
|
||||
|
||||
imageUrl = myDB.select('SELECT ImageURL from issues WHERE IssueID=?', [issueid])
|
||||
if imageUrl:
|
||||
imageUrl = imageUrl[0][0]
|
||||
|
||||
try:
|
||||
self.sendnotify(comicname, issueyear=None, issuenumOG=issuenumber, annchk=annchk, module=module)
|
||||
self.sendnotify(comicname, issueyear=None, issuenumOG=issuenumber, annchk=annchk, module=module, imageUrl=imageUrl)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
@ -2521,7 +2525,7 @@ class PostProcessor(object):
|
|||
rem_issueid = nfilename[xyb+3:yyb]
|
||||
logger.fdebug('issueid: %s' % rem_issueid)
|
||||
nfilename = '%s %s'.strip() % (nfilename[:xyb], nfilename[yyb+3:])
|
||||
logger.fdebug('issueid information [%s] removed successsfully: %s' % (rem_issueid, nfilename))
|
||||
logger.fdebug('issueid information [%s] removed successfully: %s' % (rem_issueid, nfilename))
|
||||
|
||||
self._log("New Filename: %s" % nfilename)
|
||||
logger.fdebug('%s New Filename: %s' % (module, nfilename))
|
||||
|
@ -2771,7 +2775,11 @@ class PostProcessor(object):
|
|||
# self.sendnotify(series, issueyear, dispiss, annchk, module)
|
||||
# return self.queue.put(self.valreturn)
|
||||
|
||||
self.sendnotify(series, issueyear, dispiss, annchk, module)
|
||||
imageUrl = myDB.select('SELECT ImageURL from issues WHERE IssueID=?', [issueid])
|
||||
if imageUrl:
|
||||
imageUrl = imageUrl[0][0]
|
||||
|
||||
self.sendnotify(series, issueyear, dispiss, annchk, module, imageUrl)
|
||||
|
||||
logger.info('%s Post-Processing completed for: %s %s' % (module, series, dispiss))
|
||||
self._log(u"Post Processing SUCCESSFUL! ")
|
||||
|
@ -2784,7 +2792,7 @@ class PostProcessor(object):
|
|||
return self.queue.put(self.valreturn)
|
||||
|
||||
|
||||
def sendnotify(self, series, issueyear, issuenumOG, annchk, module):
|
||||
def sendnotify(self, series, issueyear, issuenumOG, annchk, module, imageUrl):
|
||||
|
||||
if issueyear is None:
|
||||
prline = '%s %s' % (series, issuenumOG)
|
||||
|
@ -2812,7 +2820,7 @@ class PostProcessor(object):
|
|||
|
||||
if mylar.CONFIG.TELEGRAM_ENABLED:
|
||||
telegram = notifiers.TELEGRAM()
|
||||
telegram.notify(prline2)
|
||||
telegram.notify(prline2, imageUrl)
|
||||
|
||||
if mylar.CONFIG.SLACK_ENABLED:
|
||||
slack = notifiers.SLACK()
|
||||
|
|
|
@ -11,6 +11,7 @@ import re
|
|||
import ConfigParser
|
||||
import mylar
|
||||
from mylar import logger, helpers, encrypted
|
||||
import errno
|
||||
|
||||
config = ConfigParser.SafeConfigParser()
|
||||
|
||||
|
@ -368,6 +369,7 @@ _CONFIG_DEFINITIONS = OrderedDict({
|
|||
'OPDS_USERNAME': (str, 'OPDS', None),
|
||||
'OPDS_PASSWORD': (str, 'OPDS', None),
|
||||
'OPDS_METAINFO': (bool, 'OPDS', False),
|
||||
'OPDS_PAGESIZE': (int, 'OPDS', 30),
|
||||
|
||||
})
|
||||
|
||||
|
@ -555,7 +557,7 @@ class Config(object):
|
|||
if self.CONFIG_VERSION < 8:
|
||||
print('Checking for existing torznab configuration...')
|
||||
if not any([self.TORZNAB_NAME is None, self.TORZNAB_HOST is None, self.TORZNAB_APIKEY is None, self.TORZNAB_CATEGORY is None]):
|
||||
torznabs =[(self.TORZNAB_NAME, self.TORZNAB_HOST, self.TORZNAB_APIKEY, self.TORZNAB_CATEGORY, str(int(self.ENABLE_TORZNAB)))]
|
||||
torznabs =[(self.TORZNAB_NAME, self.TORZNAB_HOST, self.TORZNAB_VERIFY, self.TORZNAB_APIKEY, self.TORZNAB_CATEGORY, str(int(self.ENABLE_TORZNAB)))]
|
||||
setattr(self, 'EXTRA_TORZNABS', torznabs)
|
||||
config.set('Torznab', 'EXTRA_TORZNABS', str(torznabs))
|
||||
print('Successfully converted existing torznab for multiple configuration allowance. Removing old references.')
|
||||
|
@ -563,9 +565,9 @@ class Config(object):
|
|||
print('No existing torznab configuration found. Just removing config references at this point..')
|
||||
config.remove_option('Torznab', 'torznab_name')
|
||||
config.remove_option('Torznab', 'torznab_host')
|
||||
config.remove_option('Torznab', 'torznab_verify')
|
||||
config.remove_option('Torznab', 'torznab_apikey')
|
||||
config.remove_option('Torznab', 'torznab_category')
|
||||
config.remove_option('Torznab', 'torznab_verify')
|
||||
print('Successfully removed outdated config entries.')
|
||||
if self.newconfig < 9:
|
||||
#rejig rtorrent settings due to change.
|
||||
|
@ -1111,7 +1113,7 @@ class Config(object):
|
|||
return extra_newznabs
|
||||
|
||||
def get_extra_torznabs(self):
|
||||
extra_torznabs = zip(*[iter(self.EXTRA_TORZNABS.split(', '))]*5)
|
||||
extra_torznabs = zip(*[iter(self.EXTRA_TORZNABS.split(', '))]*6)
|
||||
return extra_torznabs
|
||||
|
||||
def provider_sequence(self):
|
||||
|
@ -1154,7 +1156,7 @@ class Config(object):
|
|||
|
||||
if self.ENABLE_TORZNAB:
|
||||
for ets in self.EXTRA_TORZNABS:
|
||||
if str(ets[4]) == '1': # if torznabs are enabled
|
||||
if str(ets[5]) == '1': # if torznabs are enabled
|
||||
if ets[0] == "":
|
||||
et_name = ets[1]
|
||||
else:
|
||||
|
|
|
@ -272,6 +272,11 @@ class FileChecker(object):
|
|||
logger.fdebug('[SARC] Removed Reading Order sequence from subname. Now set to : %s' % modfilename)
|
||||
|
||||
#make sure all the brackets are properly spaced apart
|
||||
if modfilename.find('\s') == -1:
|
||||
#if no spaces exist, assume decimals being used as spacers (ie. nzb name)
|
||||
modspacer = '.'
|
||||
else:
|
||||
modspacer = ' '
|
||||
m = re.findall('[^()]+', modfilename)
|
||||
cnt = 1
|
||||
#2019-12-24----fixed to accomodate naming convention like Amazing Mary Jane (2019) 002.cbr, and to account for brackets properly
|
||||
|
@ -279,10 +284,10 @@ class FileChecker(object):
|
|||
while cnt < len(m):
|
||||
#logger.fdebug('[m=%s] modfilename.find: %s' % (m[cnt], modfilename[modfilename.find('('+m[cnt]+')')+len(m[cnt])+2]))
|
||||
#logger.fdebug('mod_1: %s' % modfilename.find('('+m[cnt]+')'))
|
||||
if modfilename[modfilename.find('('+m[cnt]+')')-1] != ' ' and modfilename.find('('+m[cnt]+')') != -1:
|
||||
if modfilename[modfilename.find('('+m[cnt]+')')-1] != modspacer and modfilename.find('('+m[cnt]+')') != -1:
|
||||
#logger.fdebug('before_space: %s' % modfilename[modfilename.find('('+m[cnt]+')')-1])
|
||||
#logger.fdebug('after_space: %s' % modfilename[modfilename.find('('+m[cnt]+')')+len(m[cnt])+2])
|
||||
modfilename = '%s%s%s' % (modfilename[:modfilename.find('('+m[cnt]+')')], ' ', modfilename[modfilename.find('('+m[cnt]+')'):])
|
||||
modfilename = '%s%s%s' % (modfilename[:modfilename.find('('+m[cnt]+')')], modspacer, modfilename[modfilename.find('('+m[cnt]+')'):])
|
||||
cnt+=1
|
||||
except Exception as e:
|
||||
#logger.warn('[ERROR] %s' % e)
|
||||
|
@ -335,7 +340,7 @@ class FileChecker(object):
|
|||
issueid = modfilename[x+3:y]
|
||||
logger.fdebug('issueid: %s' % issueid)
|
||||
modfilename = '%s %s'.strip() % (modfilename[:x], modfilename[y+3:])
|
||||
logger.fdebug('issueid %s removed successsfully: %s' % (issueid, modfilename))
|
||||
logger.fdebug('issueid %s removed successfully: %s' % (issueid, modfilename))
|
||||
|
||||
#here we take a snapshot of the current modfilename, the intent is that we will remove characters that match
|
||||
#as we discover them - namely volume, issue #, years, etc
|
||||
|
@ -373,13 +378,14 @@ class FileChecker(object):
|
|||
ret_sf1 = ' '.join(sf)
|
||||
|
||||
#here we should account for some characters that get stripped out due to the regex's
|
||||
#namely, unique characters - known so far: +, &
|
||||
#namely, unique characters - known so far: +, &, @
|
||||
#c11 = '\+'
|
||||
#f11 = '\&'
|
||||
#g11 = '\''
|
||||
ret_sf1 = re.sub('\+', 'c11', ret_sf1).strip()
|
||||
ret_sf1 = re.sub('\&', 'f11', ret_sf1).strip()
|
||||
ret_sf1 = re.sub('\'', 'g11', ret_sf1).strip()
|
||||
ret_sf1 = re.sub('\@', 'h11', ret_sf1).strip()
|
||||
|
||||
#split_file = re.findall('(?imu)\([\w\s-]+\)|[-+]?\d*\.\d+|\d+[\s]COVERS+|\d{4}-\d{2}-\d{2}|\d+[(th|nd|rd|st)]+|\d+|[\w-]+|#?\d\.\d+|#[\.-]\w+|#[\d*\.\d+|\w+\d+]+|#(?<![\w\d])XCV(?![\w\d])+|#[\w+]|\)', ret_sf1, re.UNICODE)
|
||||
split_file = re.findall('(?imu)\([\w\s-]+\)|[-+]?\d*\.\d+|\d+[\s]COVERS+|\d{4}-\d{2}-\d{2}|\d+[(th|nd|rd|st)]+|[\(^\)+]|\d+|[\w-]+|#?\d\.\d+|#[\.-]\w+|#[\d*\.\d+|\w+\d+]+|#(?<![\w\d])XCV(?![\w\d])+|#[\w+]|\)', ret_sf1, re.UNICODE)
|
||||
|
@ -1131,16 +1137,19 @@ class FileChecker(object):
|
|||
if alt_series is not None:
|
||||
if 'XCV' in alt_series:
|
||||
alt_series = re.sub('XCV', x, alt_series,1)
|
||||
elif 'XCV' in alt_issue:
|
||||
if alt_issue is not None:
|
||||
if 'XCV' in alt_issue:
|
||||
alt_issue = re.sub('XCV', x, alt_issue,1)
|
||||
|
||||
series_name = re.sub('c11', '+', series_name)
|
||||
series_name = re.sub('f11', '&', series_name)
|
||||
series_name = re.sub('g11', '\'', series_name)
|
||||
series_name = re.sub('h11', '@', series_name)
|
||||
if alt_series is not None:
|
||||
alt_series = re.sub('c11', '+', alt_series)
|
||||
alt_series = re.sub('f11', '&', alt_series)
|
||||
alt_series = re.sub('g11', '\'', alt_series)
|
||||
alt_series = re.sub('h11', '@', alt_series)
|
||||
|
||||
if series_name.endswith('-'):
|
||||
series_name = series_name[:-1].strip()
|
||||
|
|
|
@ -124,7 +124,7 @@ class GC(object):
|
|||
|
||||
option_find = f.find("p", {"style": "text-align: center;"})
|
||||
i = 0
|
||||
while i <= 2:
|
||||
while (i <= 2 and option_find is not None):
|
||||
option_find = option_find.findNext(text=True)
|
||||
if 'Year' in option_find:
|
||||
year = option_find.findNext(text=True)
|
||||
|
|
|
@ -3657,6 +3657,42 @@ def newznab_test(name, host, ssl, apikey):
|
|||
logger.info('[ERROR:%s] - %s' % (code, description))
|
||||
return False
|
||||
|
||||
def torznab_test(name, host, ssl, apikey):
|
||||
from xml.dom.minidom import parseString, Element
|
||||
params = {'t': 'search',
|
||||
'apikey': apikey,
|
||||
'o': 'xml'}
|
||||
|
||||
if host[-1:] == '/':
|
||||
host = host[:-1]
|
||||
headers = {'User-Agent': str(mylar.USER_AGENT)}
|
||||
logger.info('host: %s' % host)
|
||||
try:
|
||||
r = requests.get(host, params=params, headers=headers, verify=bool(ssl))
|
||||
except Exception as e:
|
||||
logger.warn('Unable to connect: %s' % e)
|
||||
return
|
||||
else:
|
||||
try:
|
||||
data = parseString(r.content)
|
||||
except Exception as e:
|
||||
logger.warn('[WARNING] Error attempting to test: %s' % e)
|
||||
|
||||
try:
|
||||
error_code = data.getElementsByTagName('error')[0].attributes['code'].value
|
||||
except Exception as e:
|
||||
logger.info('Connected - Status code returned: %s' % r.status_code)
|
||||
if r.status_code == 200:
|
||||
return True
|
||||
else:
|
||||
logger.warn('Received response - Status code returned: %s' % r.status_code)
|
||||
return False
|
||||
|
||||
code = error_code
|
||||
description = data.getElementsByTagName('error')[0].attributes['description'].value
|
||||
logger.info('[ERROR:%s] - %s' % (code, description))
|
||||
return False
|
||||
|
||||
def get_free_space(folder):
|
||||
min_threshold = 100000000 #threshold for minimum amount of freespace available (#100mb)
|
||||
if platform.system() == "Windows":
|
||||
|
|
|
@ -176,7 +176,7 @@ def addComictoDB(comicid, mismatch=None, pullupd=None, imported=None, ogcname=No
|
|||
logger.info('Corrected year of ' + str(SeriesYear) + ' to corrected year for series that was manually entered previously of ' + str(csyear))
|
||||
SeriesYear = csyear
|
||||
|
||||
logger.info('Sucessfully retrieved details for ' + comic['ComicName'])
|
||||
logger.info('Successfully retrieved details for ' + comic['ComicName'])
|
||||
|
||||
#since the weekly issue check could return either annuals or issues, let's initialize it here so it carries through properly.
|
||||
weeklyissue_check = []
|
||||
|
|
|
@ -340,24 +340,33 @@ class TELEGRAM:
|
|||
else:
|
||||
self.token = test_token
|
||||
|
||||
def notify(self, message):
|
||||
def notify(self, message, imageUrl=None):
|
||||
# Construct message
|
||||
payload = {'chat_id': self.userid, 'text': message}
|
||||
sendMethod = "sendMessage"
|
||||
|
||||
if imageUrl:
|
||||
# Construct message
|
||||
payload = {'chat_id': self.userid, 'caption': message, 'photo': imageUrl}
|
||||
sendMethod = "sendPhoto"
|
||||
|
||||
# Send message to user using Telegram's Bot API
|
||||
try:
|
||||
response = requests.post(self.TELEGRAM_API % (self.token, "sendMessage"), json=payload, verify=True)
|
||||
except Exception, e:
|
||||
logger.info(u'Telegram notify failed: ' + str(e))
|
||||
response = requests.post(self.TELEGRAM_API % (self.token, sendMethod), json=payload, verify=True)
|
||||
except Exception as e:
|
||||
logger.info('Telegram notify failed: ' + str(e))
|
||||
|
||||
# Error logging
|
||||
sent_successfuly = True
|
||||
sent_successfully = True
|
||||
if not response.status_code == 200:
|
||||
logger.info(u'Could not send notification to TelegramBot (token=%s). Response: [%s]' % (self.token, response.text))
|
||||
sent_successfuly = False
|
||||
sent_successfully = False
|
||||
|
||||
if not sent_successfully and sendMethod != "sendMessage":
|
||||
return self.notify(message)
|
||||
|
||||
logger.info(u"Telegram notifications sent.")
|
||||
return sent_successfuly
|
||||
return sent_successfully
|
||||
|
||||
def test_notify(self):
|
||||
return self.notify('Test Message: Release the Ninjas!')
|
||||
|
|
|
@ -39,7 +39,7 @@ class OPDS(object):
|
|||
|
||||
def __init__(self):
|
||||
self.cmd = None
|
||||
self.PAGE_SIZE=30
|
||||
self.PAGE_SIZE=mylar.CONFIG.OPDS_PAGESIZE
|
||||
self.img = None
|
||||
self.issue_id = None
|
||||
self.file = None
|
||||
|
|
|
@ -762,7 +762,7 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
|
|||
break
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.warn('General Error fetching data from %s: %s' % (nzbprov, e))
|
||||
if e.r.status_code == 503:
|
||||
if str(r.status_code) == '503':
|
||||
#HTTP Error 503
|
||||
logger.warn('Aborting search due to Provider unavailability')
|
||||
foundc['status'] = False
|
||||
|
@ -1109,7 +1109,7 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
|
|||
logger.fdebug('Cleaned up title to : %s' % cleantitle)
|
||||
|
||||
#send it to the parser here.
|
||||
p_comic = filechecker.FileChecker(file=ComicTitle)
|
||||
p_comic = filechecker.FileChecker(file=ComicTitle, watchcomic=ComicName)
|
||||
parsed_comic = p_comic.listFiles()
|
||||
|
||||
logger.fdebug('parsed_info: %s' % parsed_comic)
|
||||
|
@ -1376,18 +1376,18 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
|
|||
intIss = 1000
|
||||
else:
|
||||
intIss = 9999999999
|
||||
if parsed_comic['issue_number'] is not None:
|
||||
logger.fdebug("issue we found for is : %s" % parsed_comic['issue_number'])
|
||||
comintIss = helpers.issuedigits(parsed_comic['issue_number'])
|
||||
if filecomic['justthedigits'] is not None:
|
||||
logger.fdebug("issue we found for is : %s" % filecomic['justthedigits'])
|
||||
comintIss = helpers.issuedigits(filecomic['justthedigits'])
|
||||
logger.fdebug("integer value of issue we have found : %s" % comintIss)
|
||||
else:
|
||||
comintIss = 11111111111
|
||||
|
||||
#do this so that we don't touch the actual value but just use it for comparisons
|
||||
if parsed_comic['issue_number'] is None:
|
||||
if filecomic['justthedigits'] is None:
|
||||
pc_in = None
|
||||
else:
|
||||
pc_in = helpers.issuedigits(parsed_comic['issue_number'])
|
||||
pc_in = helpers.issuedigits(filecomic['justthedigits'])
|
||||
#issue comparison now as well
|
||||
if int(intIss) == int(comintIss) or all([cmloopit == 4, findcomiciss is None, pc_in is None]) or all([cmloopit == 4, findcomiciss is None, pc_in == 1]):
|
||||
nowrite = False
|
||||
|
@ -2751,7 +2751,7 @@ def notify_snatch(sent_to, comicname, comyear, IssueNumber, nzbprov, pack):
|
|||
if mylar.CONFIG.TELEGRAM_ENABLED and mylar.CONFIG.TELEGRAM_ONSNATCH:
|
||||
logger.info(u"Sending Telegram notification")
|
||||
telegram = notifiers.TELEGRAM()
|
||||
telegram.notify(snline + " - " + snatched_name)
|
||||
telegram.notify("%s - %s - Mylar %s" % (snline, snatched_name, sent_to))
|
||||
if mylar.CONFIG.SLACK_ENABLED and mylar.CONFIG.SLACK_ONSNATCH:
|
||||
logger.info(u"Sending Slack notification")
|
||||
slack = notifiers.SLACK()
|
||||
|
|
|
@ -4692,13 +4692,17 @@ class WebInterface(object):
|
|||
if len(search_matches) > 1:
|
||||
# if we matched on more than one series above, just save those results instead of the entire search result set.
|
||||
for sres in search_matches:
|
||||
if type(sres['haveit']) == dict:
|
||||
imp_cid = sres['haveit']['comicid']
|
||||
else:
|
||||
imp_cid = sres['haveit']
|
||||
cVal = {"SRID": SRID,
|
||||
"comicid": sres['comicid']}
|
||||
#should store ogcname in here somewhere to account for naming conversions above.
|
||||
nVal = {"Series": ComicName,
|
||||
"results": len(search_matches),
|
||||
"publisher": sres['publisher'],
|
||||
"haveit": sres['haveit'],
|
||||
"haveit": imp_cid,
|
||||
"name": sres['name'],
|
||||
"deck": sres['deck'],
|
||||
"url": sres['url'],
|
||||
|
@ -4707,6 +4711,7 @@ class WebInterface(object):
|
|||
"issues": sres['issues'],
|
||||
"ogcname": ogcname,
|
||||
"comicyear": sres['comicyear']}
|
||||
#logger.fdebug('search_values: [%s]/%s' % (cVal, nVal))
|
||||
myDB.upsert("searchresults", nVal, cVal)
|
||||
logger.info('[IMPORT] There is more than one result that might be valid - normally this is due to the filename(s) not having enough information for me to use (ie. no volume label/year). Manual intervention is required.')
|
||||
#force the status here just in case
|
||||
|
@ -4718,13 +4723,17 @@ class WebInterface(object):
|
|||
# store the search results for series that returned more than one result for user to select later / when they want.
|
||||
# should probably assign some random numeric for an id to reference back at some point.
|
||||
for sres in sresults:
|
||||
if type(sres['haveit']) == dict:
|
||||
imp_cid = sres['haveit']['comicid']
|
||||
else:
|
||||
imp_cid = sres['haveit']
|
||||
cVal = {"SRID": SRID,
|
||||
"comicid": sres['comicid']}
|
||||
#should store ogcname in here somewhere to account for naming conversions above.
|
||||
nVal = {"Series": ComicName,
|
||||
"results": len(sresults),
|
||||
"publisher": sres['publisher'],
|
||||
"haveit": sres['haveit'],
|
||||
"haveit": imp_cid,
|
||||
"name": sres['name'],
|
||||
"deck": sres['deck'],
|
||||
"url": sres['url'],
|
||||
|
@ -5008,7 +5017,7 @@ class WebInterface(object):
|
|||
"dognzb_verify": helpers.checked(mylar.CONFIG.DOGNZB_VERIFY),
|
||||
"experimental": helpers.checked(mylar.CONFIG.EXPERIMENTAL),
|
||||
"enable_torznab": helpers.checked(mylar.CONFIG.ENABLE_TORZNAB),
|
||||
"extra_torznabs": sorted(mylar.CONFIG.EXTRA_TORZNABS, key=itemgetter(4), reverse=True),
|
||||
"extra_torznabs": sorted(mylar.CONFIG.EXTRA_TORZNABS, key=itemgetter(5), reverse=True),
|
||||
"newznab": helpers.checked(mylar.CONFIG.NEWZNAB),
|
||||
"extra_newznabs": sorted(mylar.CONFIG.EXTRA_NEWZNABS, key=itemgetter(5), reverse=True),
|
||||
"enable_ddl": helpers.checked(mylar.CONFIG.ENABLE_DDL),
|
||||
|
@ -5140,6 +5149,7 @@ class WebInterface(object):
|
|||
"opds_username": mylar.CONFIG.OPDS_USERNAME,
|
||||
"opds_password": mylar.CONFIG.OPDS_PASSWORD,
|
||||
"opds_metainfo": helpers.checked(mylar.CONFIG.OPDS_METAINFO),
|
||||
"opds_pagesize": mylar.CONFIG.OPDS_PAGESIZE,
|
||||
"dlstats": dlprovstats,
|
||||
"dltotals": freq_tot,
|
||||
"alphaindex": mylar.CONFIG.ALPHAINDEX
|
||||
|
@ -5286,28 +5296,41 @@ class WebInterface(object):
|
|||
newValues['AlternateFileName'] = str(alt_filename)
|
||||
|
||||
#force the check/creation of directory com_location here
|
||||
updatedir = True
|
||||
if any([mylar.CONFIG.CREATE_FOLDERS is True, os.path.isdir(orig_location)]):
|
||||
if os.path.isdir(str(com_location)):
|
||||
logger.info(u"Validating Directory (" + str(com_location) + "). Already exists! Continuing...")
|
||||
else:
|
||||
if orig_location != com_location:
|
||||
if orig_location != com_location and os.path.isdir(orig_location) is True:
|
||||
logger.fdebug('Renaming existing location [%s] to new location: %s' % (orig_location, com_location))
|
||||
try:
|
||||
os.rename(orig_location, com_location)
|
||||
except Exception as e:
|
||||
logger.warn('Unable to rename existing directory: %s' % e)
|
||||
return
|
||||
if 'No such file or directory' in e:
|
||||
checkdirectory = filechecker.validateAndCreateDirectory(com_location, True)
|
||||
if not checkdirectory:
|
||||
logger.warn('Error trying to validate/create directory. Aborting this process at this time.')
|
||||
updatedir = False
|
||||
else:
|
||||
logger.warn('Unable to rename existing directory: %s' % e)
|
||||
updatedir = False
|
||||
else:
|
||||
logger.fdebug("Updated Directory doesn't exist! - attempting to create now.")
|
||||
if orig_location != com_location and os.path.isdir(orig_location) is False:
|
||||
logger.fdebug("Original Directory (%s) doesn't exist! - attempting to create new directory (%s)" % (orig_location, com_location))
|
||||
else:
|
||||
logger.fdebug("Updated Directory doesn't exist! - attempting to create now.")
|
||||
checkdirectory = filechecker.validateAndCreateDirectory(com_location, True)
|
||||
if not checkdirectory:
|
||||
logger.warn('Error trying to validate/create directory. Aborting this process at this time.')
|
||||
return
|
||||
updatedir = False
|
||||
|
||||
newValues['ComicLocation'] = com_location
|
||||
else:
|
||||
logger.info('[Create directories False] Not creating physical directory, but updating series location in dB to: %s' % com_location)
|
||||
if updatedir is True:
|
||||
newValues['ComicLocation'] = com_location
|
||||
|
||||
myDB.upsert("comics", newValues, controlValueDict)
|
||||
logger.fdebug('Updated Series options!')
|
||||
myDB.upsert("comics", newValues, controlValueDict)
|
||||
logger.fdebug('Updated Series options!')
|
||||
raise cherrypy.HTTPRedirect("comicDetails?ComicID=%s" % ComicID)
|
||||
comic_config.exposed = True
|
||||
|
||||
|
@ -5377,7 +5400,7 @@ class WebInterface(object):
|
|||
'lowercase_filenames', 'autowant_upcoming', 'autowant_all', 'comic_cover_local', 'alternate_latest_series_covers', 'cvinfo', 'snatchedtorrent_notify',
|
||||
'prowl_enabled', 'prowl_onsnatch', 'pushover_enabled', 'pushover_onsnatch', 'boxcar_enabled',
|
||||
'boxcar_onsnatch', 'pushbullet_enabled', 'pushbullet_onsnatch', 'telegram_enabled', 'telegram_onsnatch', 'slack_enabled', 'slack_onsnatch',
|
||||
'email_enabled', 'email_enc', 'email_ongrab', 'email_onpost', 'opds_enable', 'opds_authentication', 'opds_metainfo', 'enable_ddl', 'deluge_pause'] #enable_public
|
||||
'email_enabled', 'email_enc', 'email_ongrab', 'email_onpost', 'opds_enable', 'opds_authentication', 'opds_metainfo', 'opds_pagesize', 'enable_ddl', 'deluge_pause'] #enable_public
|
||||
|
||||
for checked_config in checked_configs:
|
||||
if checked_config not in kwargs:
|
||||
|
@ -5426,6 +5449,10 @@ class WebInterface(object):
|
|||
if torznab_name == "":
|
||||
continue
|
||||
torznab_host = helpers.clean_url(kwargs['torznab_host' + torznab_number])
|
||||
try:
|
||||
torznab_verify = kwargs['torznab_verify' + torznab_number]
|
||||
except:
|
||||
torznab_verify = 0
|
||||
torznab_api = kwargs['torznab_apikey' + torznab_number]
|
||||
torznab_category = kwargs['torznab_category' + torznab_number]
|
||||
try:
|
||||
|
@ -5435,7 +5462,7 @@ class WebInterface(object):
|
|||
|
||||
del kwargs[kwarg]
|
||||
|
||||
mylar.CONFIG.EXTRA_TORZNABS.append((torznab_name, torznab_host, torznab_api, torznab_category, torznab_enabled))
|
||||
mylar.CONFIG.EXTRA_TORZNABS.append((torznab_name, torznab_host, torznab_verify, torznab_api, torznab_category, torznab_enabled))
|
||||
|
||||
mylar.CONFIG.process_kwargs(kwargs)
|
||||
|
||||
|
@ -6006,6 +6033,24 @@ class WebInterface(object):
|
|||
return 'Error - failed running test for %s' % name
|
||||
testnewznab.exposed = True
|
||||
|
||||
def testtorznab(self, name, host, ssl, apikey):
|
||||
logger.fdebug('ssl/verify: %s' % ssl)
|
||||
if 'ssl' == '0' or ssl == '1':
|
||||
ssl = bool(int(ssl))
|
||||
else:
|
||||
if ssl == 'false':
|
||||
ssl = False
|
||||
else:
|
||||
ssl = True
|
||||
result = helpers.torznab_test(name, host, ssl, apikey)
|
||||
if result is True:
|
||||
logger.info('Successfully tested %s [%s] - valid api response received' % (name, host))
|
||||
return 'Successfully tested %s!' % name
|
||||
else:
|
||||
print result
|
||||
logger.warn('Testing failed to %s [HOST:%s][SSL:%s]' % (name, host, bool(ssl)))
|
||||
return 'Error - failed running test for %s' % name
|
||||
testtorznab.exposed = True
|
||||
|
||||
def orderThis(self, **kwargs):
|
||||
return
|
||||
|
@ -6425,3 +6470,12 @@ class WebInterface(object):
|
|||
|
||||
download_specific_release.exposed = True
|
||||
|
||||
def read_comic(self, ish_id, page_num, size):
|
||||
from mylar.webviewer import WebViewer
|
||||
wv = WebViewer()
|
||||
page_num = int(page_num)
|
||||
#cherrypy.session['ishid'] = ish_id
|
||||
data = wv.read_comic(ish_id, page_num, size)
|
||||
#data = wv.read_comic(ish_id)
|
||||
return data
|
||||
read_comic.exposed = True
|
||||
|
|
168
mylar/webviewer.py
Normal file
168
mylar/webviewer.py
Normal file
|
@ -0,0 +1,168 @@
|
|||
import os
|
||||
import re
|
||||
import cherrypy
|
||||
import stat
|
||||
import zipfile
|
||||
from lib.rarfile import rarfile
|
||||
|
||||
import mylar
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
logger.debug("WebReader Requested, but PIL or pillow libraries must be installed. Please execute 'pip install pillow', then restart Mylar.")
|
||||
return serve_template(templatename="index.html", title="Home", comics=comics, alphaindex=mylar.CONFIG.ALPHAINDEX)
|
||||
|
||||
from mylar import logger, db, importer, mb, search, filechecker, helpers, updater, parseit, weeklypull, librarysync, moveit, Failed, readinglist, config
|
||||
from mylar.webserve import serve_template
|
||||
|
||||
class WebViewer(object):
|
||||
|
||||
def __init__(self):
|
||||
self.ish_id = None
|
||||
self.page_num = None
|
||||
self.kwargs = None
|
||||
self.data = None
|
||||
|
||||
if not os.path.exists(os.path.join(mylar.DATA_DIR, 'sessions')):
|
||||
os.makedirs(os.path.abspath(os.path.join(mylar.DATA_DIR, 'sessions')))
|
||||
|
||||
updatecherrypyconf = {
|
||||
'tools.gzip.on': True,
|
||||
'tools.gzip.mime_types': ['text/*', 'application/*', 'image/*'],
|
||||
'tools.sessions.timeout': 1440,
|
||||
'tools.sessions.storage_class': cherrypy.lib.sessions.FileSession,
|
||||
'tools.sessions.storage_path': os.path.join(mylar.DATA_DIR, "sessions"),
|
||||
'request.show_tracebacks': False,
|
||||
'engine.timeout_monitor.on': False,
|
||||
}
|
||||
if mylar.CONFIG.HTTP_PASSWORD is None:
|
||||
updatecherrypyconf.update({
|
||||
'tools.sessions.on': True,
|
||||
})
|
||||
|
||||
cherrypy.config.update(updatecherrypyconf)
|
||||
cherrypy.engine.signals.subscribe()
|
||||
|
||||
def read_comic(self, ish_id = None, page_num = None, size = None):
|
||||
logger.debug("WebReader Requested, looking for ish_id %s and page_num %s" % (ish_id, page_num))
|
||||
if size == None:
|
||||
user_size_pref = 'wide'
|
||||
else:
|
||||
user_size_pref = size
|
||||
|
||||
try:
|
||||
ish_id
|
||||
except:
|
||||
logger.warn("WebReader: ish_id not set!")
|
||||
|
||||
myDB = db.DBConnection()
|
||||
comic = myDB.selectone('select comics.ComicLocation, issues.Location from comics, issues where comics.comicid = issues.comicid and issues.issueid = ?' , [ish_id]).fetchone()
|
||||
if comic is None:
|
||||
logger.warn("WebReader: ish_id %s requested but not in the database!" % ish_id)
|
||||
raise cherrypy.HTTPRedirect("home")
|
||||
# cherrypy.config.update()
|
||||
comic_path = os.path.join(comic['ComicLocation'], comic['Location'])
|
||||
logger.debug("WebReader found ish_id %s at %s" % (ish_id, comic_path))
|
||||
|
||||
# cherrypy.session['ish_id'].load()
|
||||
# if 'sizepref' not in cherrypy.session:
|
||||
# cherrypy.session['sizepref'] = user_size_pref
|
||||
# user_size_pref = cherrypy.session['sizepref']
|
||||
# logger.debug("WebReader setting user_size_pref to %s" % user_size_pref)
|
||||
|
||||
scanner = ComicScanner()
|
||||
image_list = scanner.reading_images(ish_id)
|
||||
logger.debug("Image list contains %s pages" % (len(image_list)))
|
||||
if len(image_list) == 0:
|
||||
logger.debug("Unpacking ish_id %s from comic_path %s" % (ish_id, comic_path))
|
||||
scanner.user_unpack_comic(ish_id, comic_path)
|
||||
else:
|
||||
logger.debug("ish_id %s already unpacked." % ish_id)
|
||||
|
||||
num_pages = len(image_list)
|
||||
logger.debug("Found %s pages for ish_id %s from comic_path %s" % (num_pages, ish_id, comic_path))
|
||||
|
||||
if num_pages == 0:
|
||||
image_list = ['images/skipped_icon.png']
|
||||
|
||||
cookie_comic = re.sub(r'\W+', '', comic_path)
|
||||
cookie_comic = "wv_" + cookie_comic.decode('unicode_escape')
|
||||
logger.debug("about to drop a cookie for " + cookie_comic + " which represents " + comic_path)
|
||||
cookie_check = cherrypy.request.cookie
|
||||
if cookie_comic not in cookie_check:
|
||||
logger.debug("Cookie Creation")
|
||||
cookie_path = '/'
|
||||
cookie_maxage = '2419200'
|
||||
cookie_set = cherrypy.response.cookie
|
||||
cookie_set['cookie_comic'] = 0
|
||||
cookie_set['cookie_comic']['path'] = cookie_path.decode('unicode_escape')
|
||||
cookie_set['cookie_comic']['max-age'] = cookie_maxage.decode('unicode_escape')
|
||||
next_page = page_num + 1
|
||||
prev_page = page_num - 1
|
||||
else:
|
||||
logger.debug("Cookie Read")
|
||||
page_num = int(cherrypy.request.cookie['cookie_comic'].value)
|
||||
logger.debug("Cookie Set To %d" % page_num)
|
||||
next_page = page_num + 1
|
||||
prev_page = page_num - 1
|
||||
|
||||
logger.info("Reader Served")
|
||||
logger.debug("Serving comic " + comic['Location'] + " page number " + str(page_num))
|
||||
|
||||
return serve_template(templatename="read.html", pages=image_list, current_page=page_num, np=next_page, pp=prev_page, nop=num_pages, size=user_size_pref, cc=cookie_comic, comicpath=comic_path, ish_id=ish_id)
|
||||
|
||||
def up_size_pref(self, pref):
|
||||
cherrypy.session.load()
|
||||
cherrypy.session['sizepref'] = pref
|
||||
cherrypy.session.save()
|
||||
return
|
||||
|
||||
class ComicScanner(object):
|
||||
|
||||
# This method will handle scanning the directories and returning a list of them all.
|
||||
def dir_scan(self):
|
||||
logger.debug("Dir Scan Requested")
|
||||
full_paths = []
|
||||
full_paths.append(mylar.CONFIG.DESTINATION_DIR)
|
||||
for root, dirs, files in os.walk(mylar.CONFIG.DESTINATION_DIR):
|
||||
full_paths.extend(os.path.join(root, d) for d in dirs)
|
||||
|
||||
logger.info("Dir Scan Completed")
|
||||
logger.info("%i Dirs Found" % (len(full_paths)))
|
||||
return full_paths
|
||||
|
||||
def user_unpack_comic(self, ish_id, comic_path):
|
||||
logger.info("%s unpack requested" % comic_path)
|
||||
for root, dirs, files in os.walk(os.path.join(mylar.CONFIG.CACHE_DIR, "webviewer", ish_id), topdown=False):
|
||||
for f in files:
|
||||
os.chmod(os.path.join(root, f), stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 0777
|
||||
os.remove(os.path.join(root, f))
|
||||
for root, dirs, files in os.walk(os.path.join(mylar.CONFIG.CACHE_DIR, "webviewer", ish_id), topdown=False):
|
||||
for d in dirs:
|
||||
os.chmod(os.path.join(root, d), stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 0777
|
||||
os.rmdir(os.path.join(root, d))
|
||||
if comic_path.endswith(".cbr"):
|
||||
opened_rar = rarfile.RarFile(comic_path)
|
||||
opened_rar.extractall(os.path.join(mylar.CONFIG.CACHE_DIR, "webviewer", ish_id))
|
||||
elif comic_path.endswith(".cbz"):
|
||||
opened_zip = zipfile.ZipFile(comic_path)
|
||||
opened_zip.extractall(os.path.join(mylar.CONFIG.CACHE_DIR, "webviewer", ish_id))
|
||||
return
|
||||
|
||||
# This method will return a list of .jpg files in their numberical order to be fed into the reading view.
|
||||
def reading_images(self, ish_id):
|
||||
logger.debug("Image List Requested")
|
||||
image_list = []
|
||||
image_src = os.path.join(mylar.CONFIG.CACHE_DIR, "webviewer", ish_id)
|
||||
image_loc = os.path.join(mylar.CONFIG.HTTP_ROOT, 'cache', "webviewer", ish_id)
|
||||
for root, dirs, files in os.walk(image_src):
|
||||
for f in files:
|
||||
if f.endswith((".png", ".gif", ".bmp", ".dib", ".jpg", ".jpeg", ".jpe", ".jif", ".jfif", ".jfi", ".tiff", ".tif")):
|
||||
image_list.append( os.path.join(image_loc, f) )
|
||||
image_list.sort()
|
||||
logger.debug("Image List Created")
|
||||
return image_list
|
||||
|
||||
|
||||
|
Loading…
Reference in a new issue