2022-10-18 22:39:32 -04:00
|
|
|
<style>
|
|
|
|
#rssdownloaderpage_content {
|
|
|
|
height: calc(100% - 30px);
|
|
|
|
}
|
|
|
|
|
|
|
|
#RssDownloader {
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
#leftRssDownloaderColumn {
|
|
|
|
width: 25%;
|
|
|
|
float: left;
|
|
|
|
}
|
|
|
|
|
|
|
|
#rulesTable,
|
|
|
|
#rssDownloaderArticlesTable {
|
|
|
|
overflow: auto;
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
#centerRssDownloaderColumn {
|
|
|
|
width: 50%;
|
|
|
|
float: left;
|
|
|
|
}
|
|
|
|
|
|
|
|
#rightRssDownloaderColumn {
|
|
|
|
width: 25%;
|
|
|
|
float: left;
|
|
|
|
}
|
|
|
|
|
|
|
|
.fullWidth {
|
|
|
|
width: 100%;
|
|
|
|
max-width: none;
|
|
|
|
box-sizing: border-box;
|
|
|
|
}
|
|
|
|
|
|
|
|
.noWrap {
|
|
|
|
white-space: nowrap;
|
|
|
|
}
|
|
|
|
|
|
|
|
#rssDownloaderFeeds {
|
|
|
|
height: calc(100% - 355px);
|
|
|
|
overflow: hidden;
|
|
|
|
}
|
|
|
|
|
|
|
|
#rssDownloaderFeedsTable {
|
|
|
|
height: calc(100% - 21px);
|
|
|
|
width: 100%;
|
|
|
|
overflow: auto;
|
|
|
|
}
|
|
|
|
|
|
|
|
#saveButton {
|
|
|
|
margin-top: 5px;
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
.articleTableFeed td {
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
|
|
|
|
.articleTableArticle td {
|
|
|
|
padding-left: 22px;
|
|
|
|
}
|
|
|
|
|
|
|
|
#rssDownloaderDisabled {
|
|
|
|
color: red;
|
|
|
|
font-style: italic;
|
|
|
|
margin-bottom: 10px;
|
|
|
|
}
|
|
|
|
|
|
|
|
#rulesTable table,
|
|
|
|
#rssDownloaderFeedsTable table,
|
|
|
|
#rssDownloaderArticlesTable table {
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ignoreDaysValue {
|
|
|
|
width: 4em;
|
|
|
|
}
|
|
|
|
|
|
|
|
#lastMatchDiv {
|
|
|
|
float: right;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ruleSettings {
|
|
|
|
padding: 4px 10px 4px 10px
|
|
|
|
}
|
|
|
|
|
|
|
|
#topMenuBar {
|
|
|
|
height: 26px;
|
|
|
|
}
|
|
|
|
|
|
|
|
#rulesTableDesc {
|
|
|
|
vertical-align: middle;
|
|
|
|
}
|
|
|
|
|
|
|
|
.imageButton {
|
|
|
|
height: 22px;
|
|
|
|
width: 24px;
|
|
|
|
margin: 1px 2px 1px 2px;
|
|
|
|
border: 1px solid;
|
|
|
|
border-radius: 2px;
|
|
|
|
background-color: #efefef;
|
|
|
|
border-color: #767676;
|
|
|
|
background-position: center center;
|
|
|
|
vertical-align: middle;
|
|
|
|
}
|
|
|
|
|
|
|
|
.imageButton:hover {
|
|
|
|
background-color: #e5e5e5;
|
|
|
|
border-color: #4f4f4f;
|
|
|
|
}
|
|
|
|
|
|
|
|
.imageButton:active {
|
|
|
|
background-color: #f5f5f5;
|
|
|
|
border-color: #8d8d8d;
|
|
|
|
}
|
|
|
|
|
|
|
|
#newRuleButton {
|
|
|
|
float: right;
|
|
|
|
background-image: url('images/list-add.svg');
|
|
|
|
}
|
|
|
|
|
|
|
|
#deleteRuleButton {
|
|
|
|
float: right;
|
|
|
|
background-image: url('images/edit-clear.svg');
|
|
|
|
}
|
|
|
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
<div id="RssDownloader" class="RssDownloader">
|
|
|
|
<div id="rssDownloaderDisabled" class="invisible">
|
2022-11-30 13:49:48 -05:00
|
|
|
Auto downloading of RSS torrents is disabled now! You can enable it in application settings.
|
2022-10-18 22:39:32 -04:00
|
|
|
</div>
|
|
|
|
<div id="leftRssDownloaderColumn">
|
|
|
|
<div id="topMenuBar">
|
2022-11-30 13:49:48 -05:00
|
|
|
<b id="rulesTableDesc">Download Rules</b>
|
2022-10-18 22:39:32 -04:00
|
|
|
<button id="newRuleButton" class="imageButton" onclick="qBittorrent.RssDownloader.addRule()"></button>
|
|
|
|
<button id="deleteRuleButton" class="imageButton" onclick="qBittorrent.RssDownloader.removeSelectedRule()"></button>
|
|
|
|
</div>
|
|
|
|
<div id="rulesTable">
|
|
|
|
<div id="rulesSelectionCheckBoxList">
|
|
|
|
<div id="rssDownloaderRuleFixedHeaderDiv" class="dynamicTableFixedHeaderDiv invisible">
|
|
|
|
<table class="dynamicTable unselectable">
|
|
|
|
<thead>
|
|
|
|
<tr class="dynamicTableHeader"></tr>
|
|
|
|
</thead>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
<div id="rssDownloaderRuleTableDiv" class="dynamicTableDiv">
|
|
|
|
<table class="dynamicTable unselectable">
|
|
|
|
<thead>
|
|
|
|
<tr class="dynamicTableHeader"></tr>
|
|
|
|
</thead>
|
|
|
|
<tbody></tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div id="centerRssDownloaderColumn">
|
|
|
|
<fieldset class="settings" id="ruleSettings">
|
2022-11-30 13:49:48 -05:00
|
|
|
<legend>Rule Definition</legend>
|
2022-10-18 22:39:32 -04:00
|
|
|
<div class="formRow">
|
|
|
|
<input disabled type="checkbox" id="useRegEx" onclick="qBittorrent.RssDownloader.setElementTitles()" />
|
2022-11-30 13:49:48 -05:00
|
|
|
<label for="useRegEx">Use Regular Expressions</label>
|
2022-10-18 22:39:32 -04:00
|
|
|
</div>
|
|
|
|
<table class="fullWidth">
|
|
|
|
<tr>
|
|
|
|
<td>
|
2022-11-30 13:49:48 -05:00
|
|
|
<label for="mustContainText" class="noWrap">Must Contain:</label>
|
2022-10-18 22:39:32 -04:00
|
|
|
</td>
|
|
|
|
<td class="fullWidth">
|
|
|
|
<input disabled type="text" id="mustContainText" class="fullWidth" autocorrect="off" autocapitalize="none" />
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>
|
2022-11-30 13:49:48 -05:00
|
|
|
<label for="mustNotContainText" class="noWrap">Must Not Contain:</label>
|
2022-10-18 22:39:32 -04:00
|
|
|
</td>
|
|
|
|
<td class="fullWidth">
|
|
|
|
<input disabled type="text" id="mustNotContainText" class="fullWidth" autocorrect="off" autocapitalize="none" />
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td>
|
2022-11-30 13:49:48 -05:00
|
|
|
<label for="episodeFilterText" class="noWrap">Episode Filter:</label>
|
2022-10-18 22:39:32 -04:00
|
|
|
</td>
|
|
|
|
<td class="fullWidth">
|
|
|
|
<input disabled type="text" id="episodeFilterText" class="fullWidth" autocorrect="off" autocapitalize="none" />
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
<div class="formRow" title="QBT_TR(Smart Episode Filter will check the episode number to prevent downloading of duplicates.
|
2022-11-30 15:05:46 -05:00
|
|
|
Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also support - as a separator)">
|
2022-10-18 22:39:32 -04:00
|
|
|
<input disabled type="checkbox" id="useSmartFilter" />
|
2022-11-30 13:49:48 -05:00
|
|
|
<label for="useSmartFilter">Use Smart Episode Filter</label>
|
2022-10-18 22:39:32 -04:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<hr>
|
|
|
|
|
|
|
|
<table class="fullWidth">
|
|
|
|
<tr>
|
|
|
|
<td>
|
2022-11-30 13:49:48 -05:00
|
|
|
<label class="noWrap">Assign Category:</label>
|
2022-10-18 22:39:32 -04:00
|
|
|
</td>
|
|
|
|
<td class="fullWidth">
|
|
|
|
<select disabled id="assignCategoryCombobox" class="fullWidth">
|
|
|
|
<option value=""></option>
|
|
|
|
</select>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
<div class="formRow">
|
|
|
|
<input disabled type="checkbox" id="savetoDifferentDir" />
|
2022-11-30 13:49:48 -05:00
|
|
|
<label for="savetoDifferentDir">Save to a Different Directory</label>
|
2022-10-18 22:39:32 -04:00
|
|
|
</div>
|
|
|
|
<table class="fullWidth">
|
|
|
|
<tr>
|
|
|
|
<td>
|
2022-11-30 13:49:48 -05:00
|
|
|
<label class="noWrap" for="saveToText">Save to:</label>
|
2022-10-18 22:39:32 -04:00
|
|
|
</td>
|
|
|
|
<td class="fullWidth">
|
|
|
|
<input disabled type="text" class="fullWidth" id="saveToText" autocorrect="off" autocapitalize="none" />
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
<table>
|
|
|
|
<tr>
|
2022-11-30 13:49:48 -05:00
|
|
|
<td><label for="ignoreDaysValue">Ignore Subsequent Matches for (0 to Disable)</label></td>
|
|
|
|
<td><input type="number" id="ignoreDaysValue" min="0" /> days</td>
|
2022-10-18 22:39:32 -04:00
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
<div id="lastMatchDiv">
|
2022-11-30 13:49:48 -05:00
|
|
|
<span id="lastMatchText">Last Match: Unknown</span>
|
2022-10-18 22:39:32 -04:00
|
|
|
</div>
|
|
|
|
<table class="fullWidth">
|
|
|
|
<tr>
|
|
|
|
<td>
|
2022-11-30 13:49:48 -05:00
|
|
|
<label class="noWrap">Add Paused:</label>
|
2022-10-18 22:39:32 -04:00
|
|
|
</td>
|
|
|
|
<td class="fullWidth">
|
|
|
|
<select disabled id="addPausedCombobox" class="fullWidth">
|
2022-11-30 13:49:48 -05:00
|
|
|
<option value="default">Use global settings</option>
|
|
|
|
<option value="always">Always</option>
|
|
|
|
<option value="never">Never</option>
|
2022-10-18 22:39:32 -04:00
|
|
|
</select>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
<table class="fullWidth">
|
|
|
|
<tr>
|
|
|
|
<td>
|
2022-11-30 13:49:48 -05:00
|
|
|
<label class="noWrap">Torrent content layout:</label>
|
2022-10-18 22:39:32 -04:00
|
|
|
</td>
|
|
|
|
<td class="fullWidth">
|
|
|
|
<select disabled id="contentLayoutCombobox" class="fullWidth">
|
2022-11-30 13:49:48 -05:00
|
|
|
<option value="Default">Use global settings</option>
|
|
|
|
<option value="Original">Original</option>
|
|
|
|
<option value="Subfolder">Create subfolder</option>
|
|
|
|
<option value="NoSubfolder">Don't create subfolder</option>
|
2022-10-18 22:39:32 -04:00
|
|
|
</select>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
</fieldset>
|
|
|
|
<fieldset class="settings" id="rssDownloaderFeeds">
|
2022-11-30 13:49:48 -05:00
|
|
|
<legend>Apply Rule to Feeds:</legend>
|
2022-10-18 22:39:32 -04:00
|
|
|
<div id="rssDownloaderFeedsTable">
|
|
|
|
<div id="rssDownloaderFeedSelectionFixedHeaderDiv" class="dynamicTableFixedHeaderDiv invisible">
|
|
|
|
<table class="dynamicTable unselectable">
|
|
|
|
<thead>
|
|
|
|
<tr class="dynamicTableHeader"></tr>
|
|
|
|
</thead>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
<div id="rssDownloaderFeedSelectionTableDiv" class="dynamicTableDiv">
|
|
|
|
<table class="dynamicTable unselectable">
|
|
|
|
<thead>
|
|
|
|
<tr class="dynamicTableHeader"></tr>
|
|
|
|
</thead>
|
|
|
|
<tbody></tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</fieldset>
|
|
|
|
<button disabled id="saveButton" onclick="qBittorrent.RssDownloader.saveSettings()">
|
2022-11-30 13:49:48 -05:00
|
|
|
Save
|
2022-10-18 22:39:32 -04:00
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<div id="rightRssDownloaderColumn">
|
2022-11-30 13:49:48 -05:00
|
|
|
<b id="articleTableDesc">Matching RSS Articles</b>
|
2022-10-18 22:39:32 -04:00
|
|
|
<div id="rssDownloaderArticlesTable">
|
|
|
|
<div id="rssDownloaderArticlesFixedHeaderDiv" class="dynamicTableFixedHeaderDiv invisible">
|
|
|
|
<table class="dynamicTable unselectable">
|
|
|
|
<thead>
|
|
|
|
<tr class="dynamicTableHeader"></tr>
|
|
|
|
</thead>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
<div id="rssDownloaderArticlesTableDiv" class="dynamicTableDiv">
|
|
|
|
<table class="dynamicTable unselectable">
|
|
|
|
<thead>
|
|
|
|
<tr class="dynamicTableHeader"></tr>
|
|
|
|
</thead>
|
|
|
|
<tbody></tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<ul id="rssDownloaderRuleMenu" class="contextMenu">
|
2022-11-30 15:05:46 -05:00
|
|
|
<li><a href="#addRule"><img src="images/list-add.svg" alt="Add new rule..." /> QBT_TR(Add new rule...</a></li>
|
|
|
|
<li><a href="#deleteRule"><img src="images/edit-clear.svg" alt="Delete rule" /> QBT_TR(Delete rule</a></li>
|
|
|
|
<li class="separator"><a href="#renameRule"><img src="images/edit-rename.svg" alt="Rename rule..." /> QBT_TR(Rename rule...</a></li>
|
|
|
|
<li class="separator"><a href="#clearDownloadedEpisodes"><img src="images/edit-clear.svg" alt="Clear downloaded episodes..." /> QBT_TR(Clear downloaded episodes...</a></li>
|
2022-10-18 22:39:32 -04:00
|
|
|
</ul>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
if (window.qBittorrent === undefined) {
|
|
|
|
window.qBittorrent = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
window.qBittorrent.RssDownloader = (() => {
|
|
|
|
const exports = () => {
|
|
|
|
return {
|
|
|
|
updateRulesList: updateRulesList,
|
|
|
|
showRule: showRule,
|
|
|
|
renameRule: renameRule,
|
|
|
|
modifyRuleState: modifyRuleState,
|
|
|
|
saveSettings: saveSettings,
|
|
|
|
rssDownloaderRulesTable: rssDownloaderRulesTable,
|
|
|
|
rssDownloaderFeedSelectionTable: rssDownloaderFeedSelectionTable,
|
|
|
|
setElementTitles: setElementTitles,
|
|
|
|
addRule: addRule,
|
|
|
|
removeSelectedRule: removeSelectedRule
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
let rssDownloaderRulesTable = new window.qBittorrent.DynamicTable.RssDownloaderRulesTable();
|
|
|
|
let rssDownloaderFeedSelectionTable = new window.qBittorrent.DynamicTable.RssDownloaderFeedSelectionTable();
|
|
|
|
let rssDownloaderArticlesTable = new window.qBittorrent.DynamicTable.RssDownloaderArticlesTable();
|
|
|
|
|
|
|
|
let rulesList = {};
|
|
|
|
let feedList = [];
|
|
|
|
|
|
|
|
const initRssDownloader = () => {
|
|
|
|
new Request.JSON({
|
|
|
|
url: 'api/v2/app/preferences',
|
|
|
|
method: 'get',
|
|
|
|
noCache: true,
|
|
|
|
onFailure: () => {
|
|
|
|
alert('Could not contact qBittorrent');
|
|
|
|
},
|
|
|
|
onSuccess: (pref) => {
|
|
|
|
if (!pref.rss_auto_downloading_enabled)
|
|
|
|
$('rssDownloaderDisabled').removeClass('invisible');
|
|
|
|
|
|
|
|
// recalculate height
|
|
|
|
let warningHeight = $('rssDownloaderDisabled').getBoundingClientRect().height;
|
|
|
|
|
|
|
|
$('leftRssDownloaderColumn').style.height = 'calc(100% - ' + warningHeight + 'px)';
|
|
|
|
$('centerRssDownloaderColumn').style.height = 'calc(100% - ' + warningHeight + 'px)';
|
|
|
|
$('rightRssDownloaderColumn').style.height = 'calc(100% - ' + warningHeight + 'px)';
|
|
|
|
|
|
|
|
$('rulesTable').style.height = 'calc(100% - ' + $('rulesTableDesc').getBoundingClientRect().height + 'px)';
|
|
|
|
$('rssDownloaderArticlesTable').style.height = 'calc(100% - ' + $('articleTableDesc').getBoundingClientRect().height + 'px)';
|
|
|
|
|
|
|
|
let centerRowNotTableHeight = $('saveButton').getBoundingClientRect().height
|
|
|
|
+ $('ruleSettings').getBoundingClientRect().height + 15;
|
|
|
|
|
|
|
|
$('rssDownloaderFeeds').style.height = 'calc(100% - ' + centerRowNotTableHeight + 'px)';
|
|
|
|
|
|
|
|
// firefox calculates the height of the table inside fieldset differently and thus doesn't need the offset
|
|
|
|
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
|
|
|
|
$('rssDownloaderFeedsTable').style.height = '100%';
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
let outsideTableHeight = ($('rssDownloaderFeedsTable').getBoundingClientRect().top - $('rssDownloaderFeeds').getBoundingClientRect().top) - 10;
|
|
|
|
$('rssDownloaderFeedsTable').style.height = 'calc(100% - ' + outsideTableHeight + 'px)';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}).send();
|
|
|
|
|
|
|
|
const rssDownloaderRuleContextMenu = new window.qBittorrent.ContextMenu.RssDownloaderRuleContextMenu({
|
|
|
|
targets: '',
|
|
|
|
menu: 'rssDownloaderRuleMenu',
|
|
|
|
actions: {
|
|
|
|
addRule: addRule,
|
|
|
|
deleteRule: removeSelectedRule,
|
|
|
|
renameRule: (el) => {
|
|
|
|
renameRule(rssDownloaderRulesTable.rows[rssDownloaderRulesTable.selectedRows[0]].full_data.name);
|
|
|
|
},
|
|
|
|
clearDownloadedEpisodes: (el) => {
|
|
|
|
clearDownloadedEpisodes(rssDownloaderRulesTable.selectedRows
|
|
|
|
.map((sRow) => rssDownloaderRulesTable.rows[sRow].full_data.name));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
offsets: {
|
|
|
|
x: -22,
|
|
|
|
y: -4
|
|
|
|
}
|
|
|
|
});
|
|
|
|
rssDownloaderRulesTable.setup('rssDownloaderRuleTableDiv', 'rssDownloaderRuleFixedHeaderDiv', rssDownloaderRuleContextMenu);
|
|
|
|
rssDownloaderFeedSelectionTable.setup('rssDownloaderFeedSelectionTableDiv', 'rssDownloaderFeedSelectionFixedHeaderDiv');
|
|
|
|
rssDownloaderArticlesTable.setup('rssDownloaderArticlesTableDiv', 'rssDownloaderArticlesFixedHeaderDiv');
|
|
|
|
|
|
|
|
rssDownloaderRuleContextMenu.addTarget($('rulesTable'));
|
|
|
|
// deselect feed when clicking on empty part of table
|
|
|
|
$('rulesTable').addEventListener('click', (e) => {
|
|
|
|
rssDownloaderRulesTable.deselectAll();
|
|
|
|
rssDownloaderRulesTable.deselectRow();
|
|
|
|
showRule('');
|
|
|
|
});
|
|
|
|
$('rulesTable').addEventListener('contextmenu', (e) => {
|
|
|
|
if (e.toElement.nodeName === 'DIV') {
|
|
|
|
rssDownloaderRulesTable.deselectAll();
|
|
|
|
rssDownloaderRulesTable.deselectRow();
|
|
|
|
rssDownloaderRuleContextMenu.updateMenuItems();
|
|
|
|
showRule('');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// get all categories and add to combobox
|
|
|
|
new Request.JSON({
|
|
|
|
url: 'api/v2/torrents/categories',
|
|
|
|
noCache: true,
|
|
|
|
method: 'get',
|
|
|
|
onSuccess: (response) => {
|
|
|
|
let combobox = $('assignCategoryCombobox');
|
|
|
|
for (let cat in response) {
|
|
|
|
let option = document.createElement('option');
|
|
|
|
option.text = option.value = cat;
|
|
|
|
combobox.add(option);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}).send();
|
|
|
|
// get all rss feed
|
|
|
|
new Request.JSON({
|
|
|
|
url: 'api/v2/rss/items',
|
|
|
|
noCache: true,
|
|
|
|
method: 'get',
|
|
|
|
data: {
|
|
|
|
withData: false
|
|
|
|
},
|
|
|
|
onSuccess: (response) => {
|
|
|
|
feedList = [];
|
|
|
|
let flatten = (root) => {
|
|
|
|
for (let child in root) {
|
|
|
|
if (root[child].uid !== undefined)
|
|
|
|
feedList.push({ name: child, url: root[child].url });
|
|
|
|
else
|
|
|
|
flatten(root[child]);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
flatten(response);
|
|
|
|
}
|
|
|
|
}).send();
|
|
|
|
$('savetoDifferentDir').addEvent('click', () => {
|
|
|
|
$('saveToText').disabled = !$('savetoDifferentDir').checked;
|
|
|
|
});
|
|
|
|
updateRulesList();
|
|
|
|
};
|
|
|
|
|
|
|
|
const updateRulesList = () => {
|
|
|
|
// get all rules
|
|
|
|
new Request.JSON({
|
|
|
|
url: 'api/v2/rss/rules',
|
|
|
|
noCache: true,
|
|
|
|
method: 'get',
|
|
|
|
onSuccess: (response) => {
|
|
|
|
rssDownloaderRulesTable.clear();
|
|
|
|
let rowCount = 0;
|
|
|
|
for (let rule in response) {
|
|
|
|
rssDownloaderRulesTable.updateRowData({
|
|
|
|
rowId: rowCount++,
|
|
|
|
checked: response[rule].enabled,
|
|
|
|
name: rule
|
|
|
|
});
|
|
|
|
}
|
|
|
|
rssDownloaderRulesTable.updateTable(false);
|
|
|
|
rulesList = response;
|
|
|
|
}
|
|
|
|
}).send();
|
|
|
|
};
|
|
|
|
|
|
|
|
const modifyRuleState = (rule, setting, newState, callback = () => {}) => {
|
|
|
|
rulesList[rule][setting] = newState;
|
|
|
|
new Request({
|
|
|
|
url: 'api/v2/rss/setRule',
|
|
|
|
noCache: true,
|
|
|
|
method: 'post',
|
|
|
|
data: {
|
|
|
|
ruleName: rule,
|
|
|
|
ruleDef: JSON.stringify(rulesList[rule])
|
|
|
|
},
|
|
|
|
onSuccess: () => {
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
}).send();
|
|
|
|
};
|
|
|
|
|
|
|
|
const addRule = () => {
|
|
|
|
new MochaUI.Window({
|
|
|
|
id: 'newRulePage',
|
2022-11-30 13:49:48 -05:00
|
|
|
title: 'New rule name',
|
2022-10-18 22:39:32 -04:00
|
|
|
loadMethod: 'iframe',
|
|
|
|
contentURL: 'newrule.html',
|
|
|
|
scrollbars: false,
|
|
|
|
resizable: false,
|
|
|
|
maximizable: false,
|
|
|
|
width: 350,
|
|
|
|
height: 100
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const renameRule = (rule) => {
|
|
|
|
new MochaUI.Window({
|
|
|
|
id: 'renameRulePage',
|
2022-11-30 13:49:48 -05:00
|
|
|
title: 'Rule renaming',
|
2022-10-18 22:39:32 -04:00
|
|
|
loadMethod: 'iframe',
|
|
|
|
contentURL: 'rename_rule.html?rule=' + encodeURIComponent(rule),
|
|
|
|
scrollbars: false,
|
|
|
|
resizable: false,
|
|
|
|
maximizable: false,
|
|
|
|
width: 350,
|
|
|
|
height: 100
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const removeSelectedRule = () => {
|
|
|
|
if (rssDownloaderRulesTable.selectedRows.length === 0)
|
|
|
|
return;
|
|
|
|
removeRules(rssDownloaderRulesTable.selectedRows.map((sRow) =>
|
|
|
|
rssDownloaderRulesTable.rows[sRow].full_data.name));
|
|
|
|
};
|
|
|
|
|
|
|
|
const removeRules = (rules) => {
|
|
|
|
const encodedRules = rules.map((rule) => encodeURIComponent(rule));
|
|
|
|
new MochaUI.Window({
|
|
|
|
id: 'removeRulePage',
|
2022-11-30 13:49:48 -05:00
|
|
|
title: 'Rule deletion confirmation',
|
2022-10-18 22:39:32 -04:00
|
|
|
loadMethod: 'iframe',
|
|
|
|
contentURL: 'confirmruledeletion.html?rules=' + encodeURIComponent(encodedRules.join('|')),
|
|
|
|
scrollbars: false,
|
|
|
|
resizable: false,
|
|
|
|
maximizable: false,
|
|
|
|
width: 360,
|
|
|
|
height: 80
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const clearDownloadedEpisodes = (rules) => {
|
|
|
|
const encodedRules = rules.map((rule) => encodeURIComponent(rule));
|
|
|
|
new MochaUI.Window({
|
|
|
|
id: 'clearRulesPage',
|
2022-11-30 13:49:48 -05:00
|
|
|
title: 'New rule name',
|
2022-10-18 22:39:32 -04:00
|
|
|
loadMethod: 'iframe',
|
|
|
|
contentURL: 'confirmruleclear.html?rules=' + encodeURIComponent(encodedRules.join('|')),
|
|
|
|
scrollbars: false,
|
|
|
|
resizable: false,
|
|
|
|
maximizable: false,
|
|
|
|
width: 350,
|
|
|
|
height: 85
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const saveSettings = () => {
|
|
|
|
let lastSelectedRow = rssDownloaderRulesTable.selectedRows[rssDownloaderRulesTable.selectedRows.length - 1];
|
|
|
|
let rule = rssDownloaderRulesTable.rows[lastSelectedRow].full_data.name;
|
|
|
|
|
|
|
|
rulesList[rule].useRegex = $('useRegEx').checked;
|
|
|
|
rulesList[rule].mustContain = $('mustContainText').value;
|
|
|
|
rulesList[rule].mustNotContain = $('mustNotContainText').value;
|
|
|
|
rulesList[rule].episodeFilter = $('episodeFilterText').value;
|
|
|
|
rulesList[rule].smartFilter = $('useSmartFilter').checked;
|
|
|
|
rulesList[rule].assignedCategory = $('assignCategoryCombobox').value;
|
|
|
|
rulesList[rule].savePath = $('savetoDifferentDir').checked ? $('saveToText').value : '';
|
|
|
|
rulesList[rule].ignoreDays = parseInt($('ignoreDaysValue').value);
|
|
|
|
|
|
|
|
switch ($('addPausedCombobox').value) {
|
|
|
|
case 'default':
|
|
|
|
rulesList[rule].addPaused = null;
|
|
|
|
break;
|
|
|
|
case 'always':
|
|
|
|
rulesList[rule].addPaused = true;
|
|
|
|
break;
|
|
|
|
case 'never':
|
|
|
|
rulesList[rule].addPaused = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ($('contentLayoutCombobox').value) {
|
|
|
|
case 'Default':
|
|
|
|
rulesList[rule].torrentContentLayout = null;
|
|
|
|
break;
|
|
|
|
case 'Original':
|
|
|
|
rulesList[rule].torrentContentLayout = 'Original';
|
|
|
|
break;
|
|
|
|
case 'Subfolder':
|
|
|
|
rulesList[rule].torrentContentLayout = 'Subfolder';
|
|
|
|
break;
|
|
|
|
case 'NoSubfolder':
|
|
|
|
rulesList[rule].torrentContentLayout = 'NoSubfolder';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
rulesList[rule].affectedFeeds = rssDownloaderFeedSelectionTable.rows.filter((row) => row.full_data.checked)
|
|
|
|
.map((row) => row.full_data.url)
|
|
|
|
.getValues();
|
|
|
|
|
|
|
|
new Request({
|
|
|
|
url: 'api/v2/rss/setRule',
|
|
|
|
noCache: true,
|
|
|
|
method: 'post',
|
|
|
|
data: {
|
|
|
|
ruleName: rule,
|
|
|
|
ruleDef: JSON.stringify(rulesList[rule])
|
|
|
|
},
|
|
|
|
onSuccess: () => {
|
|
|
|
updateMatchingArticles(rule);
|
|
|
|
}
|
|
|
|
}).send();
|
|
|
|
};
|
|
|
|
|
|
|
|
const updateMatchingArticles = (ruleName) => {
|
|
|
|
new Request.JSON({
|
|
|
|
url: 'api/v2/rss/matchingArticles',
|
|
|
|
noCache: true,
|
|
|
|
method: 'get',
|
|
|
|
data: {
|
|
|
|
ruleName: ruleName
|
|
|
|
},
|
|
|
|
onSuccess: (response) => {
|
|
|
|
rssDownloaderArticlesTable.clear();
|
|
|
|
let rowCount = 0;
|
|
|
|
for (let feed in response) {
|
|
|
|
rssDownloaderArticlesTable.updateRowData({
|
|
|
|
rowId: rowCount++,
|
|
|
|
name: feed,
|
|
|
|
isFeed: true
|
|
|
|
});
|
|
|
|
response[feed].each((article) => {
|
|
|
|
rssDownloaderArticlesTable.updateRowData({
|
|
|
|
rowId: rowCount++,
|
|
|
|
name: article,
|
|
|
|
isFeed: false
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
rssDownloaderArticlesTable.updateTable(false);
|
|
|
|
}
|
|
|
|
}).send();
|
|
|
|
};
|
|
|
|
|
|
|
|
const showRule = (ruleName) => {
|
|
|
|
if (ruleName === '') {
|
|
|
|
// disable all
|
|
|
|
$('saveButton').disabled = true;
|
|
|
|
$('useRegEx').disabled = true;
|
|
|
|
$('mustContainText').disabled = true;
|
|
|
|
$('mustNotContainText').disabled = true;
|
|
|
|
$('episodeFilterText').disabled = true;
|
|
|
|
$('useSmartFilter').disabled = true;
|
|
|
|
$('assignCategoryCombobox').disabled = true;
|
|
|
|
$('savetoDifferentDir').disabled = true;
|
|
|
|
$('saveToText').disabled = true;
|
|
|
|
$('ignoreDaysValue').disabled = true;
|
|
|
|
$('addPausedCombobox').disabled = true;
|
|
|
|
$('contentLayoutCombobox').disabled = true;
|
|
|
|
|
|
|
|
// reset all boxes
|
|
|
|
$('useRegEx').checked = false;
|
|
|
|
$('mustContainText').value = '';
|
|
|
|
$('mustNotContainText').value = '';
|
|
|
|
$('episodeFilterText').value = '';
|
|
|
|
$('useSmartFilter').checked = false;
|
|
|
|
$('assignCategoryCombobox').value = 'default';
|
|
|
|
$('savetoDifferentDir').checked = false;
|
|
|
|
$('saveToText').value = '';
|
|
|
|
$('ignoreDaysValue').value = 0;
|
2022-11-30 13:49:48 -05:00
|
|
|
$('lastMatchText').textContent = 'Last Match: Unknown';
|
2022-10-18 22:39:32 -04:00
|
|
|
$('addPausedCombobox').value = 'default';
|
|
|
|
$('contentLayoutCombobox').value = 'Default';
|
|
|
|
rssDownloaderFeedSelectionTable.clear();
|
|
|
|
rssDownloaderArticlesTable.clear();
|
|
|
|
|
|
|
|
$('mustContainText').title = '';
|
|
|
|
$('mustNotContainText').title = '';
|
|
|
|
$('episodeFilterText').title = '';
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// enable all
|
|
|
|
$('saveButton').disabled = false;
|
|
|
|
$('useRegEx').disabled = false;
|
|
|
|
$('mustContainText').disabled = false;
|
|
|
|
$('mustNotContainText').disabled = false;
|
|
|
|
$('episodeFilterText').disabled = false;
|
|
|
|
$('useSmartFilter').disabled = false;
|
|
|
|
$('assignCategoryCombobox').disabled = false;
|
|
|
|
$('savetoDifferentDir').disabled = false;
|
|
|
|
$('savetoDifferentDir').checked = rulesList[ruleName].savePath ? false : true;
|
|
|
|
$('saveToText').disabled = rulesList[ruleName].savePath ? false : true;
|
|
|
|
$('ignoreDaysValue').disabled = false;
|
|
|
|
$('addPausedCombobox').disabled = false;
|
|
|
|
$('contentLayoutCombobox').disabled = false;
|
|
|
|
|
|
|
|
// load rule settings
|
|
|
|
$('useRegEx').checked = rulesList[ruleName].useRegex;
|
|
|
|
$('mustContainText').value = rulesList[ruleName].mustContain;
|
|
|
|
$('mustNotContainText').value = rulesList[ruleName].mustNotContain;
|
|
|
|
$('episodeFilterText').value = rulesList[ruleName].episodeFilter;
|
|
|
|
$('useSmartFilter').checked = rulesList[ruleName].smartFilter;
|
|
|
|
|
|
|
|
$('assignCategoryCombobox').value = rulesList[ruleName].assignedCategory ? rulesList[ruleName].assignedCategory : 'default';
|
|
|
|
$('savetoDifferentDir').checked = rulesList[ruleName].savePath !== '';
|
|
|
|
$('saveToText').value = rulesList[ruleName].savePath;
|
|
|
|
$('ignoreDaysValue').value = rulesList[ruleName].ignoreDays;
|
|
|
|
|
|
|
|
// calculate days since last match
|
|
|
|
if (rulesList[ruleName].lastMatch !== '') {
|
|
|
|
let timeDiffInMs = new Date().getTime() - new Date(rulesList[ruleName].lastMatch).getTime();
|
|
|
|
let daysAgo = Math.floor(timeDiffInMs / (1000 * 60 * 60 * 24)).toString();
|
2022-11-30 13:49:48 -05:00
|
|
|
$('lastMatchText').textContent = ' Last Match: %1 days ago'.replace('%1', daysAgo);
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
else {
|
2022-11-30 13:49:48 -05:00
|
|
|
$('lastMatchText').textContent = 'Last Match: Unknown';
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rulesList[ruleName].addPaused === null)
|
|
|
|
$('addPausedCombobox').value = 'default';
|
|
|
|
else
|
|
|
|
$('addPausedCombobox').value = rulesList[ruleName].addPaused ? 'always' : 'never';
|
|
|
|
|
|
|
|
if (rulesList[ruleName].torrentContentLayout === null)
|
|
|
|
$('contentLayoutCombobox').value = 'Default';
|
|
|
|
else
|
|
|
|
$('contentLayoutCombobox').value = rulesList[ruleName].torrentContentLayout;
|
|
|
|
|
|
|
|
setElementTitles();
|
|
|
|
|
|
|
|
rssDownloaderFeedSelectionTable.clear();
|
|
|
|
let rowCount = 0;
|
|
|
|
feedList.forEach((feed) => {
|
|
|
|
rssDownloaderFeedSelectionTable.updateRowData({
|
|
|
|
rowId: rowCount++,
|
|
|
|
checked: rulesList[ruleName].affectedFeeds.contains(feed.url),
|
|
|
|
name: feed.name,
|
|
|
|
url: feed.url
|
|
|
|
});
|
|
|
|
});
|
|
|
|
rssDownloaderFeedSelectionTable.updateTable(false);
|
|
|
|
updateMatchingArticles(ruleName);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const setElementTitles = () => {
|
|
|
|
let mainPart;
|
|
|
|
if ($('useRegEx').checked) {
|
2022-11-30 13:49:48 -05:00
|
|
|
mainPart = 'Regex mode: use Perl-compatible regular expressions\n\n';
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
else {
|
2022-11-30 13:49:48 -05:00
|
|
|
mainPart = 'Wildcard mode: you can use\n\n'
|
|
|
|
+ ' ● ? to match any single character\n'
|
|
|
|
+ ' ● * to match zero or more of any characters\n'
|
|
|
|
+ ' ● Whitespaces count as AND operators (all words, any order)\n'
|
|
|
|
+ ' ● | is used as OR operator\n\n'
|
|
|
|
+ 'If word order is important use * instead of whitespace.\n\n';
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
2022-11-30 13:49:48 -05:00
|
|
|
let secondPart = 'An expression with an empty %1 clause (e.g. %2)'
|
2022-10-18 22:39:32 -04:00
|
|
|
.replace('%1', '|').replace('%2', 'expr|');
|
|
|
|
|
2022-11-30 13:49:48 -05:00
|
|
|
$('mustContainText').title = mainPart + secondPart + ' will match all articles.';
|
|
|
|
$('mustNotContainText').title = mainPart + secondPart + ' will exclude all articles.';
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2022-11-30 13:49:48 -05:00
|
|
|
let episodeFilterTitle = 'Matches articles based on episode filter.\n\n'
|
|
|
|
+ 'Example: '
|
2022-10-18 22:39:32 -04:00
|
|
|
+ '1x2;8-15;5;30-;'
|
2022-11-30 13:49:48 -05:00
|
|
|
+ ' will match 2, 5, 8 through 15, 30 and onward episodes of season one\n\n'
|
|
|
|
+ 'Episode filter rules: \n\n'
|
|
|
|
+ ' ● Season number is a mandatory non-zero value\n'
|
|
|
|
+ ' ● Episode number is a mandatory positive value\n'
|
|
|
|
+ ' ● Filter must end with semicolon\n'
|
|
|
|
+ ' ● Three range types for episodes are supported: \n'
|
|
|
|
+ ' ● Single number: <b>1x25;</b> matches episode 25 of season one\n'
|
|
|
|
+ ' ● Normal range: <b>1x25-40;</b> matches episodes 25 through 40 of season one\n'
|
|
|
|
+ ' ● Infinite range: <b>1x25-;</b> matches episodes 25 and upward of season one, and all episodes of later seasons';
|
2022-10-18 22:39:32 -04:00
|
|
|
|
|
|
|
episodeFilterTitle = episodeFilterTitle.replace(/<b>/g, '').replace(/<\/b>/g, '');
|
|
|
|
$('episodeFilterText').title = episodeFilterTitle;
|
|
|
|
};
|
|
|
|
|
|
|
|
initRssDownloader();
|
|
|
|
return exports();
|
|
|
|
})();
|
|
|
|
|
|
|
|
Object.freeze(window.qBittorrent.RssDownloader);
|
|
|
|
</script>
|