From b4745123b0a94b4ca395a9c585cbc17f8aa20fc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=BD=E5=9F=B9=E8=80=85?= Date: Fri, 16 Aug 2019 10:43:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20Cinematik=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resource/sites/www.cinematik.net/browse.js | 90 ++++++++ resource/sites/www.cinematik.net/config.json | 92 ++++++++ resource/sites/www.cinematik.net/details.js | 47 +++++ .../www.cinematik.net/getSearchResult.js | 197 ++++++++++++++++++ .../getUserSeedingTorrents.js | 127 +++++++++++ 5 files changed, 553 insertions(+) create mode 100644 resource/sites/www.cinematik.net/browse.js create mode 100644 resource/sites/www.cinematik.net/config.json create mode 100644 resource/sites/www.cinematik.net/details.js create mode 100644 resource/sites/www.cinematik.net/getSearchResult.js create mode 100644 resource/sites/www.cinematik.net/getUserSeedingTorrents.js diff --git a/resource/sites/www.cinematik.net/browse.js b/resource/sites/www.cinematik.net/browse.js new file mode 100644 index 000000000..e7d4b7f12 --- /dev/null +++ b/resource/sites/www.cinematik.net/browse.js @@ -0,0 +1,90 @@ +(function($) { + console.log("this is browse.js"); + class App extends window.NexusPHPCommon { + init() { + this.initButtons(); + this.initFreeSpaceButton(); + // 设置当前页面 + PTService.pageApp = this; + } + + /** + * 初始化按钮列表 + */ + initButtons() { + this.initListButtons(); + } + + /** + * 获取下载链接 + */ + getDownloadURLs() { + let links = $( + "a.brolin[href*='details.php?id='][href*='hit=1']:has(b)" + ).toArray(); + let siteURL = PTService.site.url; + if (siteURL.substr(-1) != "/") { + siteURL += "/"; + } + + if (links.length == 0) { + // "获取下载链接失败,未能正确定位到链接"; + return this.t("getDownloadURLsFailed"); + } + + let urls = $.map(links, item => { + let url = + "download.php?id=" + + $(item) + .attr("href") + .getQueryString("id"); + if (url) { + url = siteURL + url; + } + return url; + }); + + return urls; + } + + /** + * 确认大小是否超限 + */ + confirmWhenExceedSize() { + return this.confirmSize( + $("table[border='1']:last").find( + "td:contains('MB'),td:contains('GB'),td:contains('TB')" + ) + ); + } + + /** + * 获取有效的拖放地址 + * @param {*} url + */ + getDroperURL(url) { + let siteURL = PTService.site.url; + if (siteURL.substr(-1) != "/") { + siteURL += "/"; + } + + if (!url.getQueryString) { + PTService.showNotice({ + msg: + "系统依赖函数(getQueryString)未正确加载,请尝试刷新页面或重新启用插件。" + }); + return null; + } + + let id = url.getQueryString("id"); + if (id) { + url = siteURL + "download.php?id=" + id; + } else { + url = ""; + } + + return url; + } + } + new App().init(); +})(jQuery); diff --git a/resource/sites/www.cinematik.net/config.json b/resource/sites/www.cinematik.net/config.json new file mode 100644 index 000000000..724985611 --- /dev/null +++ b/resource/sites/www.cinematik.net/config.json @@ -0,0 +1,92 @@ +{ + "name": "Cinematik", + "schema": "Cinematik", + "url": "https://www.cinematik.net/", + "icon": "https://www.cinematik.net/favicon.ico", + "tags": ["影视"], + "host": "www.cinematik.net", + "collaborator": "DXV5", + "plugins": [{ + "name": "种子详情页面", + "pages": ["/details.php"], + "scripts": ["/schemas/NexusPHP/common.js", "details.js"] + }, { + "name": "种子列表", + "pages": ["/browse.php"], + "scripts": ["/schemas/NexusPHP/common.js", "browse.js"] + }], + "searchEntryConfig": { + "page": "/browse.php", + "resultType": "html", + "parseScriptFile": "getSearchResult.js", + "queryString": "support=dvd%7Cbd&incldead=0&search=$key$&dir_name=" + }, + "searchEntry": [{ + "name": "all", + "enabled": true + }], + "torrentTagSelectors": [{ + "name": "Free", + "selector": "img[src*='freedownload.png']", + "color": "blue" + }, { + "name": "2xFree", + "selector": "img[src*='platinumdownload.png']", + "color": "green" + }, { + "name": "25%", + "selector": "img[src*='silverdownload.png']", + "color": "indigo" + }], + "selectors": { + "userBaseInfo": { + "page": "/itik-include/me.php", + "fields": { + "id": { + "selector": "div.frname a[href*='userdetails.php']", + "attribute": "href", + "filters": ["query ? query.getQueryString('id'):''"] + }, + "name": { + "selector": "div.frname a[href*='userdetails.php']" + } + } + }, + "userExtendInfo": { + "page": "/userdetails.php?id=$user.id$", + "fields": { + "uploaded": { + "selector": ["#user-default td.rowhead:contains('Uploaded') + td"], + "filters": ["query.text().replace(/,/g,'').match(/([\\d.]+ ?[ZEPTGMK]?i?B)/)", "(query && query.length>=2)?(query[1]).sizeToNumber():0"] + }, + "downloaded": { + "selector": ["#user-default td.rowhead:contains('Downloaded') + td"], + "filters": ["query.text().replace(/,/g,'').match(/([\\d.]+ ?[ZEPTGMK]?i?B)/)", "(query && query.length>=2)?(query[1]).sizeToNumber():0"] + }, + "levelName": { + "selector": "#user-default td.rowhead:contains('Class') + td" + }, + "bonus": { + "value": "N/A" + }, + "joinTime": { + "selector": "#user-default td.rowhead:contains('Join') + td", + "filters": ["query.text().split(' (')[0]", "dateTime(query).isValid()?dateTime(query).valueOf():query"] + } + } + }, + "userSeedingTorrents": { + "page": "/userdetails-tab.php?SID=&id=$user.id$&mode=7&page=0", + "fields": { + "seeding": { + "selector": ["table:first tr:not(:eq(0))"], + "filters": ["query.length"] + }, + "seedingSize": { + "selector": ["table:first tr:not(:eq(0))"], + "filters": ["jQuery.map(query.find('td:eq(4)'), (item)=>{return $(item).text();})", "_self.getTotalSize(query)"] + } + } + } + } +} \ No newline at end of file diff --git a/resource/sites/www.cinematik.net/details.js b/resource/sites/www.cinematik.net/details.js new file mode 100644 index 000000000..7e9716807 --- /dev/null +++ b/resource/sites/www.cinematik.net/details.js @@ -0,0 +1,47 @@ +(function($, window) { + console.log("this is details.js"); + class App extends window.NexusPHPCommon { + init() { + this.initButtons(); + // 设置当前页面 + PTService.pageApp = this; + } + /** + * 初始化按钮列表 + */ + initButtons() { + this.initDetailButtons(); + } + + /** + * 获取下载链接 + */ + getDownloadURL() { + let query = $("a[href*='download.php?id=']"); + let url = ""; + if (query.length > 0) { + url = query.attr("href"); + } + + if (!url) { + let id = location.href.getQueryString("id"); + url = `download.php?id=${id}`; + } + + if (!url) { + return ""; + } + + return `${location.origin}/${url}`; + } + + /** + * 获取当前种子标题 + */ + getTitle() { + let title = $("title").text(); + return title.replace("Cinematik :: ", ""); + } + } + new App().init(); +})(jQuery, window); diff --git a/resource/sites/www.cinematik.net/getSearchResult.js b/resource/sites/www.cinematik.net/getSearchResult.js new file mode 100644 index 000000000..a435498ce --- /dev/null +++ b/resource/sites/www.cinematik.net/getSearchResult.js @@ -0,0 +1,197 @@ +if (!"".getQueryString) { + String.prototype.getQueryString = function(name, split) { + if (split == undefined) split = "&"; + var reg = new RegExp( + "(^|" + split + "|\\?)" + name + "=([^" + split + "]*)(" + split + "|$)" + ), + r; + if ((r = this.match(reg))) return decodeURI(r[2]); + return null; + }; +} + +(function(options) { + class Parser { + constructor() { + this.haveData = false; + this.categories = {}; + if (/takelogin\.php/.test(options.responseText)) { + options.status = ESearchResultParseStatus.needLogin; //`[${options.site.name}]需要登录后再搜索`; + return; + } + + options.isLogged = true; + + if ( + /没有种子|No [Tt]orrents?|Your search did not match anything|用准确的关键字重试/.test( + options.responseText + ) + ) { + options.status = ESearchResultParseStatus.noTorrents; //`[${options.site.name}]没有搜索到相关的种子`; + return; + } + + this.haveData = true; + } + + /** + * 获取搜索结果 + */ + getResult() { + let site = options.site; + let results = []; + // 获取种子列表行 + let rows = options.page.find( + options.resultSelector || "table[border='1']:last > tbody > tr" + ); + if (rows.length == 0) { + options.status = ESearchResultParseStatus.torrentTableIsEmpty; //`[${options.site.name}]没有定位到种子列表,或没有相关的种子`; + return results; + } + // 获取表头 + let header = rows.eq(0).find("th,td"); + + // 用于定位每个字段所列的位置 + let fieldIndex = { + time: 10, + size: 6, + seeders: 8, + leechers: 9, + completed: 7, + comments: -1, + author: -1, + category: 0, + title: 1 + }; + + if (site.url.lastIndexOf("/") != site.url.length - 1) { + site.url += "/"; + } + + try { + // 遍历数据行 + for (let index = 1; index < rows.length; index++) { + const row = rows.eq(index); + let cells = row.find(">td"); + + let title = row.find("a[href*='details.php?id=']").first(); + if (title.length == 0) { + continue; + } + + let link = title.attr("href"); + if (link && link.substr(0, 4) !== "http") { + link = `${site.url}${link}`; + } + + let id = link.getQueryString("id"); + + // 获取下载链接 + let url = `${site.url}download.php?id=${id}`; + + let time = + fieldIndex.time == -1 + ? "" + : cells + .eq(fieldIndex.time) + .find("div.addedtor") + .text() || ""; + + let data = { + title: title.text(), + subTitle: "", + link, + url: url, + size: cells.eq(fieldIndex.size).html() || 0, + time: time, + author: + fieldIndex.author == -1 + ? "" + : cells.eq(fieldIndex.author).text() || "", + seeders: + fieldIndex.seeders == -1 + ? "" + : cells.eq(fieldIndex.seeders).text() || 0, + leechers: + fieldIndex.leechers == -1 + ? "" + : cells.eq(fieldIndex.leechers).text() || 0, + completed: + fieldIndex.completed == -1 + ? "" + : cells.eq(fieldIndex.completed).text() || 0, + comments: + fieldIndex.comments == -1 + ? "" + : cells.eq(fieldIndex.comments).text() || 0, + site: site, + entryName: options.entry.name, + category: this.getCategory(cells.eq(fieldIndex.category)), + tags: this.getTags(row, options.torrentTagSelectors) + }; + results.push(data); + } + if (results.length == 0) { + options.status = ESearchResultParseStatus.noTorrents; //`[${options.site.name}]没有搜索到相关的种子`; + } + } catch (error) { + console.error(error); + options.status = ESearchResultParseStatus.parseError; + options.errorMsg = error.stack; //`[${options.site.name}]获取种子信息出错: ${error.stack}`; + } + + return results; + } + + /** + * 获取分类 + * @param {*} cell 当前列 + */ + getCategory(cell) { + let result = { + name: "", + link: "" + }; + let link = cell.find("a:first"); + let img = link.find("img:first"); + + result.link = link.attr("href"); + if (result.link.substr(0, 4) !== "http") { + result.link = options.site.url + result.link; + } + + result.name = img.attr("alt"); + return result; + } + + /** + * 获取标签 + * @param {*} row + * @param {*} selectors + * @return array + */ + getTags(row, selectors) { + let tags = []; + if (selectors && selectors.length > 0) { + // 使用 some 避免错误的背景类名返回多个标签 + selectors.some(item => { + if (item.selector) { + let result = row.find(item.selector); + if (result.length) { + tags.push({ + name: item.name, + color: item.color + }); + return true; + } + } + }); + } + return tags; + } + } + + let parser = new Parser(options); + options.results = parser.getResult(); + console.log(options.results); +})(options); diff --git a/resource/sites/www.cinematik.net/getUserSeedingTorrents.js b/resource/sites/www.cinematik.net/getUserSeedingTorrents.js new file mode 100644 index 000000000..19e2b6669 --- /dev/null +++ b/resource/sites/www.cinematik.net/getUserSeedingTorrents.js @@ -0,0 +1,127 @@ +if ("".getQueryString === undefined) { + String.prototype.getQueryString = function(name, split) { + if (split == undefined) split = "&"; + var reg = new RegExp( + "(^|" + split + "|\\?)" + name + "=([^" + split + "]*)(" + split + "|$)" + ), + r; + if ((r = this.match(reg))) return decodeURI(r[2]); + return null; + }; +} + +(function(options, User) { + class Parser { + constructor(options, dataURL) { + this.options = options; + this.dataURL = dataURL; + this.body = null; + this.rawData = ""; + this.pageInfo = { + count: 0, + current: 0 + }; + this.result = { + seeding: 0, + seedingSize: 0 + }; + this.load(); + } + + /** + * 完成 + */ + done() { + this.options.resolve(this.result); + } + + /** + * 解析内容 + */ + parse() { + const doc = new DOMParser().parseFromString(this.rawData, "text/html"); + // 构造 jQuery 对象 + this.body = $(doc).find("body"); + + this.getPageInfo(); + + let results = new User.InfoParser(User.service).getResult( + this.body, + this.options.rule + ); + + if (results) { + this.result.seeding += results.seeding; + this.result.seedingSize += results.seedingSize; + } + + // 是否已到最后一页 + if (this.pageInfo.current < this.pageInfo.count) { + this.pageInfo.current++; + this.load(); + } else { + this.done(); + } + } + + /** + * 获取页面相关内容 + */ + getPageInfo() { + if (this.pageInfo.count > 0) { + return; + } + // 获取最大页码 + const infos = this.body + .find("a[href*='type=seeding']:contains('1'):last") + .attr("href"); + + if (infos) { + this.pageInfo.count = parseInt(infos.getQueryString("page")); + } else { + this.pageInfo.count = 1; + } + } + + /** + * 加载当前页内容 + */ + load() { + let url = this.dataURL; + if (this.pageInfo.current > 0) { + url += "&page=" + this.pageInfo.current; + } + $.get(url) + .done(result => { + this.rawData = result; + this.parse(); + }) + .fail(() => { + this.done(); + }); + } + } + + let dataURL = options.site.activeURL + options.rule.page; + dataURL = dataURL + .replace("$user.id$", options.userInfo.id) + .replace("$user.name$", options.userInfo.name) + .replace("://", "****") + .replace(/\/\//g, "/") + .replace("****", "://"); + + new Parser(options, dataURL); +})(_options, _self); +/** + * + _options 表示当前参数 + { + site, + rule, + userInfo, + resolve, + reject + } + + _self 表示 User(/src/background/user.ts) 类实例 + */