├── src
├── icon.png
├── icon-19.png
├── icon-64.png
├── icon-128.png
├── jquery
│ ├── images
│ │ ├── animated-overlay.gif
│ │ ├── ui-icons_222222_256x240.png
│ │ ├── ui-icons_2e83ff_256x240.png
│ │ ├── ui-icons_454545_256x240.png
│ │ ├── ui-icons_888888_256x240.png
│ │ ├── ui-icons_cd0a0a_256x240.png
│ │ ├── ui-bg_flat_0_aaaaaa_40x100.png
│ │ ├── ui-bg_flat_75_ffffff_40x100.png
│ │ ├── ui-bg_glass_55_fbf9ee_1x400.png
│ │ ├── ui-bg_glass_65_ffffff_1x400.png
│ │ ├── ui-bg_glass_75_dadada_1x400.png
│ │ ├── ui-bg_glass_75_e6e6e6_1x400.png
│ │ ├── ui-bg_glass_95_fef1ec_1x400.png
│ │ └── ui-bg_highlight-soft_75_cccccc_1x100.png
│ └── jquery-ui-1.10.3.custom.min.css
├── i18n.js
├── manifest.json
├── popup.html
├── popup.js
├── search.html
├── _locales
│ ├── en
│ │ └── messages.json
│ └── zh_CN
│ │ └── messages.json
├── script
│ ├── plugin
│ │ ├── utorrent.js
│ │ ├── Base64.js
│ │ ├── deluge.js
│ │ ├── transmission.js
│ │ └── FileSaver.js
│ ├── public.js
│ ├── background.js
│ └── options.js
├── search.js
├── extension
│ ├── init.js
│ └── base.css
└── options.html
├── PT-Plugin.png
├── README.md
├── .gitignore
└── resource
├── config
├── sites
│ ├── chdbits.co.json
│ ├── hdcmct.org.json
│ ├── ourbits.club.json
│ ├── hdchina.org.json
│ ├── pt.btschool.net.json
│ ├── u2.dmhy.org.json
│ ├── open.cd.json
│ └── totheglory.im.json
└── siteTypes
│ ├── TTG.json
│ └── NexusPHP.json
└── default.json
/src/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/icon.png
--------------------------------------------------------------------------------
/PT-Plugin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/PT-Plugin.png
--------------------------------------------------------------------------------
/src/icon-19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/icon-19.png
--------------------------------------------------------------------------------
/src/icon-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/icon-64.png
--------------------------------------------------------------------------------
/src/icon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/icon-128.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 注意
2 | 本项目已升级为 PT助手Plus,即日起本项目将停止更新,请移步到新项目地址 https://github.com/ronggang/PT-Plugin-Plus
3 |
4 | 栽培者 2019.01.20
5 |
--------------------------------------------------------------------------------
/src/jquery/images/animated-overlay.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/animated-overlay.gif
--------------------------------------------------------------------------------
/src/jquery/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/src/jquery/images/ui-icons_2e83ff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-icons_2e83ff_256x240.png
--------------------------------------------------------------------------------
/src/jquery/images/ui-icons_454545_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-icons_454545_256x240.png
--------------------------------------------------------------------------------
/src/jquery/images/ui-icons_888888_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-icons_888888_256x240.png
--------------------------------------------------------------------------------
/src/jquery/images/ui-icons_cd0a0a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-icons_cd0a0a_256x240.png
--------------------------------------------------------------------------------
/src/jquery/images/ui-bg_flat_0_aaaaaa_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-bg_flat_0_aaaaaa_40x100.png
--------------------------------------------------------------------------------
/src/jquery/images/ui-bg_flat_75_ffffff_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-bg_flat_75_ffffff_40x100.png
--------------------------------------------------------------------------------
/src/jquery/images/ui-bg_glass_55_fbf9ee_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-bg_glass_55_fbf9ee_1x400.png
--------------------------------------------------------------------------------
/src/jquery/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/src/jquery/images/ui-bg_glass_75_dadada_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-bg_glass_75_dadada_1x400.png
--------------------------------------------------------------------------------
/src/jquery/images/ui-bg_glass_75_e6e6e6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-bg_glass_75_e6e6e6_1x400.png
--------------------------------------------------------------------------------
/src/jquery/images/ui-bg_glass_95_fef1ec_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-bg_glass_95_fef1ec_1x400.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.tmp
2 | *.bkp
3 | *.vscode
4 | *.bat
5 | node_modules
6 | package.json
7 | Gruntfile.js
8 | .DS_Store
9 | *.pem
10 | *.crx
11 | *.zip
--------------------------------------------------------------------------------
/resource/config/sites/chdbits.co.json:
--------------------------------------------------------------------------------
1 | {"allowSearch":true,"detailScript":"","dropScript":"","listAllTorrentUrlScript":"","site":"chdbits.co","tags":[],"type":"NexusPHP"}
--------------------------------------------------------------------------------
/resource/config/sites/hdcmct.org.json:
--------------------------------------------------------------------------------
1 | {"allowSearch":true,"detailScript":"","dropScript":"","listAllTorrentUrlScript":"","site":"hdcmct.org","tags":[],"type":"NexusPHP"}
--------------------------------------------------------------------------------
/src/jquery/images/ui-bg_highlight-soft_75_cccccc_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PT-Fans/PT-Plugin/HEAD/src/jquery/images/ui-bg_highlight-soft_75_cccccc_1x100.png
--------------------------------------------------------------------------------
/resource/config/sites/ourbits.club.json:
--------------------------------------------------------------------------------
1 | {"allowSearch":true,"detailScript":"","disableHttps":false,"dropScript":"","listAllTorrentUrlScript":"","site":"ourbits.club","tags":["电影"],"type":"NexusPHP"}
--------------------------------------------------------------------------------
/resource/config/sites/hdchina.org.json:
--------------------------------------------------------------------------------
1 | {"allowSearch":true,"detailScript":"","disableHttps":false,"dropScript":"","listAllTorrentUrlScript":"","site":"hdchina.org","tags":["音乐","电影"],"type":"NexusPHP"}
--------------------------------------------------------------------------------
/resource/config/sites/pt.btschool.net.json:
--------------------------------------------------------------------------------
1 | {"allowHttps":false,"allowSearch":true,"detailScript":"","disableHttps":true,"dropScript":"","listAllTorrentUrlScript":"","site":"pt.btschool.net","tags":[],"type":"NexusPHP"}
--------------------------------------------------------------------------------
/resource/config/sites/u2.dmhy.org.json:
--------------------------------------------------------------------------------
1 | {
2 | "allowSearch": true,
3 | "detailScript": "",
4 | "dropScript": "",
5 | "folders": [""],
6 | "listAllTorrentUrlScript": "",
7 | "passkey": "",
8 | "site": "u2.dmhy.org",
9 | "tags": ["动漫"],
10 | "type": "NexusPHP"
11 | }
--------------------------------------------------------------------------------
/resource/config/sites/open.cd.json:
--------------------------------------------------------------------------------
1 | {
2 | "allowSearch": true,
3 | "defaultFolder": "",
4 | "detailScript": "",
5 | "dropScript": "",
6 | "folders": [],
7 | "listAllTorrentUrlScript": "",
8 | "passkey": "",
9 | "site": "open.cd",
10 | "tags": ["音乐"],
11 | "type": "NexusPHP"
12 | }
--------------------------------------------------------------------------------
/src/i18n.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function() {
2 | var items = $("[system-lang]");
3 | for (var i=0;i< items.length; i++) {
4 | var item = $(items[i]);
5 | var key = item.attr("system-lang");
6 | if (key) {
7 | var text = chrome.i18n.getMessage(key);
8 | if (text) {
9 | if (item.find(".ui-button-text").length>0) {
10 | item.find(".ui-button-text").html(text);
11 | } else {
12 | item.html(text);
13 | }
14 | }
15 | }
16 | }
17 | });
--------------------------------------------------------------------------------
/resource/config/sites/totheglory.im.json:
--------------------------------------------------------------------------------
1 | {
2 | "allowSearch": true,
3 | "detailScript": "(new RegExp(/t\\/(\\d+)\\//g)).exec(location.href);var id=RegExp.$1;(\"$input-host$rssdd.php?par=\"+(new Base64).encode(\"vvv\"+id+\"|||$input-passkey$zz\"));",
4 | "dropScript": "(new RegExp(/t\\/(\\d+)\\//g)).exec(\"$input-url$\");var id=RegExp.$1;(\"$host$rssdd.php?par=\"+(new Base64).encode(\"vvv\"+id+\"|||$input-passkey$zz\"));",
5 | "folders": [""],
6 | "listAllTorrentUrlScript": "$.map($(\"a[href^='/t/']\").toArray(),function(n){(new RegExp(/t\\/(\\d+)\\//g)).exec($(n).attr(\"href\"));var id=RegExp.$1;return (\"$host$rssdd.php?par=\"+(new Base64).encode(\"vvv\"+id+\"|||$input-passkey$zz\"));});",
7 | "passkey": "",
8 | "site": "totheglory.im",
9 | "tags": ["电影", "游戏"],
10 | "type": "TTG"
11 | }
--------------------------------------------------------------------------------
/resource/config/siteTypes/TTG.json:
--------------------------------------------------------------------------------
1 | {"name":"TTG","searchPage":"/browse.php?search_field=$key$&c=M","searchResultType":"html","getSearchResultScript":"var items = $(result).find('#torrent_table tr.hover_hr');\nvar datas = [];\n$.each(items, function(index, item) {\n\titem = $(item);\n\tvar id = item.attr(\"id\");\n\tvar url=\"https://\"+site+\"/rssdd.php?par=\"+(new Base64).encode(\"vvv\"+id+\"|||\"+system.getSite(site).passkey+\"zz\");\n\tvar data = {\n\t\ttitle: item.find(\".name_left a\").html(),\n\t\tlink: \"https://\"+site+item.find(\".name_left a\").attr(\"href\"),\n\t\tdownloadURL: url,\n\t\tsize: item.find(\"td:eq(6)\").text().replace(\"\\n\",\" \"),\n\t\tdate: item.find(\"td:eq(4)\").html(),\n\t\tauthor: item.find(\"td:eq(9)\").text(),\n\t\tsource: site\n\t};\n\tdatas.push(data);\n});\n\nsystem.addSearchResult(datas);","getTorrentTotalSizeScript":"$(\"#torrent_table\").find(\"td:contains('MB'),td:contains('GB'),td:contains('TB')\")","pluginIconShowPages":["/browse.php"],"torrentListPages":["*://*/browse.php*"],"torrentDetailPages":["https://totheglory.im/t/*"],"torrentLinks":["https://totheglory.im/t/*"]}
--------------------------------------------------------------------------------
/resource/config/siteTypes/NexusPHP.json:
--------------------------------------------------------------------------------
1 | {"name":"NexusPHP","searchPage":"/torrentrss.php?rows=$rows$&ismalldescr=1&search=$key$&search_mode=1&nd=1&passkey=$passkey$","searchResultType":"xml","getSearchResultScript":"var items = $(result).find('item');\nvar datas = [];\n$.each(items, function(index, item) {\n\titem = $(item);\n\tvar data = {\n\t\ttitle: item.find(\"title\").text(),\n\t\tlink: item.find(\"link\").text(),\n\t\tdownloadURL: item.find(\"enclosure\").attr(\"url\")+\"&passkey=\"+system.getSite(site).passkey,\n\t\tsize: formatSize(item.find(\"enclosure\").attr(\"length\")),\n\t\tdate: (new Date(item.find(\"pubDate\").text())).toLocaleString(),\n\t\tauthor: item.find(\"author\").text(),\n\t\tsource: site\n\t};\n\tdatas.push(data);\n});\n\nsystem.addSearchResult(datas);","getTorrentTotalSizeScript":"$(\".torrents\").find(\"td:contains('MB'),td:contains('GB'),td:contains('TB')\")","pluginIconShowPages":["/torrents.php"],"torrentListPages":["*://*/torrents.php*"],"torrentDetailPages":["*://*/details.php*","*://*/plugin_details.php*"],"torrentLinks":["*://*/details.php*","*://*/download.php*","*://*/plugin_details.php*"]}
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "__MSG_manifest_appName__",
3 | "short_name": "__MSG_manifest_shortName__",
4 | "version": "0.0.9",
5 | "description": "__MSG_manifest_appDescription__",
6 | "manifest_version": 2,
7 | "default_locale": "zh_CN",
8 | "browser_action": {
9 | "default_icon": "icon-19.png",
10 | "default_title": "__MSG_manifest_appName__",
11 | "default_popup": "popup.html"
12 | },
13 | "permissions": [
14 | "tabs",
15 | "*://*/*",
16 | "clipboardRead",
17 | "clipboardWrite",
18 | "storage",
19 | "contextMenus"
20 | ],
21 | "icons": {
22 | "16": "icon.png",
23 | "19": "icon-19.png",
24 | "64": "icon-64.png",
25 | "128": "icon-128.png"
26 | },
27 | "options_page": "options.html",
28 | "background": {
29 | "scripts": [
30 | "jquery/jquery-1.9.1.min.js",
31 | "script/public.js",
32 | "script/plugin/Base64.js",
33 | "script/plugin/transmission.js",
34 | "script/plugin/utorrent.js",
35 | "script/plugin/deluge.js",
36 | "script/background.js"
37 | ]
38 | },
39 | "content_scripts": [{
40 | "matches": [
41 | "*://*/*"
42 | ],
43 | "css": ["extension/base.css"],
44 | "js": [
45 | "jquery/jquery-1.9.1.min.js",
46 | "script/public.js",
47 | "script/plugin/Base64.js",
48 | "extension/init.js"
49 | ]
50 | }],
51 | "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
52 | }
--------------------------------------------------------------------------------
/src/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
41 |
42 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/src/popup.js:
--------------------------------------------------------------------------------
1 | var system = {
2 | config: {},
3 | init: function(){
4 | $("#btnSearch").click(function(event) {
5 | system.search();
6 | });
7 |
8 | $("#options").click(function(event) {
9 | chrome.extension.sendMessage({
10 | action: "open-options"
11 | });
12 | });
13 |
14 | $("#search-key").on("keyup",function(e){
15 | if (e.keyCode==13)
16 | {
17 | system.search();
18 | }
19 | });
20 |
21 | chrome.extension.sendMessage({
22 | action: "read-config"
23 | },function(config){
24 | system.config = config;
25 | $("#search-key").val(config.search.key);
26 | system.initTags();
27 | });
28 | },
29 | search: function(){
30 | this.config.search.checkedTags = $.map($("#tags input:checked"),function(n){return $(n).attr("tag");});
31 | chrome.extension.sendMessage({
32 | action: "save-config",
33 | config: this.config
34 | });
35 | chrome.extension.sendMessage({
36 | action: "search-torrent",
37 | key: $("#search-key").val()
38 | });
39 | },
40 | // 初始标签
41 | initTags: function() {
42 | var tags = {};
43 | if ($.isArray(this.config.search.checkedTags))
44 | {
45 | $.each(this.config.search.checkedTags, function(index,item){
46 | tags[item] = true;
47 | });
48 | }
49 |
50 | var parent = $("#tags");
51 | parent.empty();
52 |
53 | $.each(this.config.search.tags, function(index,item){
54 | $("").attr("tag",item).prop("checked",(tags[item]?true:false)).appendTo(parent);
55 | $("").html(item).appendTo(parent);
56 | });
57 | }
58 | };
59 |
60 | $(document).ready(function() {
61 | system.init();
62 | });
--------------------------------------------------------------------------------
/src/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 搜索
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
71 |
72 |
77 |
78 |
79 |
80 |
81 |
82 | | № |
83 | 标题 |
84 | 操作 |
85 | 大小 |
86 | 发布人 |
87 | 时间 |
88 | 来源 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/src/_locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_appName": {
3 | "message": "PT Plugin"
4 | },
5 | "manifest_shortName": {
6 | "message": "PT Plugin"
7 | },
8 | "manifest_appDescription": {
9 | "message": "适用于各PT站,可使下载种子等各项操作变化更简单、快捷。配合下载服务器(如Transmission、µTorrent等),可一键下载指定的种子。"
10 | },
11 | "options_title": {
12 | "message": "Options"
13 | },
14 | "options_tab_normal": {
15 | "message": "Normal"
16 | },
17 | "options_tab_rules": {
18 | "message": "Rules"
19 | },
20 | "options_tab_site_types": {
21 | "message": "Site Types"
22 | },
23 | "options_tab_sites": {
24 | "message": "Sites"
25 | },
26 | "options_tab_clients": {
27 | "message": "Donwload Server"
28 | },
29 | "options_tab_search": {
30 | "message": "Serach"
31 | },
32 | "options_tab_backup": {
33 | "message": "Backup & Recovery"
34 | },
35 | "options_tab_help": {
36 | "message": "Help"
37 | },
38 | "options_button_save_all": {
39 | "message": "全部保存"
40 | },
41 | "options_button_save_and_close": {
42 | "message": "保存并关闭"
43 | },
44 | "options_button_addServer": {
45 | "message": "添加服务器"
46 | },
47 | "options_button_addNew": {
48 | "message": "新增"
49 | },
50 | "options_button_save": {
51 | "message": "保存"
52 | },
53 | "options_button_cancel": {
54 | "message": "取消"
55 | },
56 | "options_button_import": {
57 | "message": "新增"
58 | },
59 | "options_text_defalut_server": {
60 | "message": "默认下载服务器:"
61 | },
62 | "options_text_show_plugin_icon_page": {
63 | "message": "插件图标显示页面:"
64 | },
65 | "options_text_show_plugin_icon_page_tips": {
66 | "message": "多个页面用回车分隔"
67 | },
68 | "options_text_allow_drop_to_send": {
69 | "message": "启用拖放链接到插件图标时,直接发送链接到下载服务器"
70 | },
71 | "options_text_exceed_size_to_confirm": {
72 | "message": "当前页面种子总体积超过"
73 | },
74 | "options_text_exceed_size_to_confirm_1": {
75 | "message": "时,需要我确认。"
76 | },
77 | "options_text_selection_text_search": {
78 | "message": "启用页面内容选择搜索"
79 | },
80 | "options_text_page_rules": {
81 | "message": "页面规则"
82 | },
83 | "options_text_page_rules_tips": {
84 | "message": "多个规则用回车分隔"
85 | },
86 | "options_text_torrent_page_rules": {
87 | "message": "种子列表页面规则:"
88 | },
89 | "options_text_torrent_detail_page_rules": {
90 | "message": "种子详情页面规则:"
91 | },
92 | "options_text_torrent_links_rules": {
93 | "message": "种子链接规则:"
94 | },
95 | "options_text_site_type_list": {
96 | "message": "当前站点类型列表"
97 | },
98 | "popup_search_torrent": {
99 | "message": "搜索种子"
100 | },
101 | "popup_project_home": {
102 | "message": "访问网站"
103 | }
104 | }
--------------------------------------------------------------------------------
/src/script/plugin/utorrent.js:
--------------------------------------------------------------------------------
1 | var utorrent = {
2 | isInitialized:false
3 | ,host:""
4 | ,port:""
5 | ,path:"/gui/"
6 | ,gui:"/gui/"
7 | ,fullpath:""
8 | ,username:""
9 | ,password:""
10 | ,headers:{}
11 | ,token:""
12 | ,init:function(config,callback)
13 | {
14 | jQuery.extend(this, config);
15 |
16 | /*
17 | if (this.fullpath=="")
18 | {
19 | this.fullpath = this.host + (this.port?":"+this.port:"") + this.path;
20 | }*/
21 | if (this.username&&this.password)
22 | {
23 | this.headers["Authorization"] = "Basic "+(new Base64()).encode(this.username+":"+this.password);
24 | }
25 |
26 | this.fullpath = this.gui;
27 | this.getSessionId(this,callback);
28 | }
29 | ,getSessionId:function(me,callback)
30 | {
31 | var settings = {
32 | type: "GET"
33 | ,url:this.fullpath+"token.html?t="
34 | ,error: function(request,event,settings)
35 | {
36 |
37 | }
38 | ,success:function(resultData,textStatus)
39 | {
40 | me.token = $(resultData).html();
41 | console.log(me.token);
42 | me.isInitialized = true;
43 | if (callback)
44 | {
45 | callback();
46 | }
47 | }
48 | ,headers:this.headers
49 |
50 | };
51 | jQuery.ajax(settings);
52 | }
53 | /*
54 | // 添加种子连接
55 | this.exec({action:"add-url",s:"url"})
56 | */
57 | // 执行相关命令
58 | ,exec:function(config,callback,tags)
59 | {
60 | if (!this.isInitialized)
61 | {
62 | return false;
63 | }
64 | var data = {};
65 |
66 | jQuery.extend(data, config);
67 |
68 | var settings = {
69 | type: "GET"
70 | ,url:this.fullpath+"?token="+this.token
71 | ,dataType: 'json'
72 | ,data:data
73 | ,success:function(resultData,textStatus)
74 | {
75 | if (callback)
76 | {
77 | callback(resultData,tags);
78 | }
79 | }
80 | ,error:function(request,event,page)
81 | {
82 | console.log(request);
83 | utorrent.getSessionId(utorrent,function(){
84 | utorrent.exec(config,callback,tags);
85 | });
86 | }
87 | ,headers:this.headers
88 | };
89 | jQuery.ajax(settings);
90 | }
91 | // 添加种子
92 | ,addTorrentFromUrl:function(url,callback)
93 | {
94 | // 磁性连接(代码来自原版WEBUI)
95 | if (url.match(/^[0-9a-f]{40}$/i)) {
96 | url = 'magnet:?xt=urn:btih:'+url;
97 | }
98 | this.exec(
99 | {
100 | action:"add-url",
101 | s: url
102 | }
103 | ,function(resultData){
104 | if (callback)
105 | {
106 | var result = {
107 | status: ""
108 | ,msg: ""
109 | }
110 | if (resultData.build)
111 | {
112 | result.status = "success";
113 | result.msg = "URL已添加至 µTorrent 。";
114 | }
115 | callback(result);
116 | }
117 | console.log(resultData);
118 | }
119 | );
120 | }
121 | };
--------------------------------------------------------------------------------
/src/script/public.js:
--------------------------------------------------------------------------------
1 | String.prototype.getQueryString = function(name,split)
2 | {
3 | if (split==undefined) split="&";
4 | var reg = new RegExp("(^|"+split+"|\\?)"+ name +"=([^"+split+"]*)("+split+"|$)"), r;
5 | if (r=this.match(reg)) return decodeURI(r[2]); return null;
6 | };
7 |
8 | function log(v){
9 | console.log(v);
10 | };
11 |
12 | //公用函数定义
13 | //格式化数字
14 | Number.prototype.formatNumber = function(f)
15 | {
16 | this.fStr = function(n, f, p)
17 | {
18 | if (n==""||n==undefined)
19 | {
20 | if (f==""||f==undefined)
21 | {
22 | return "";
23 | }
24 | else
25 | {
26 | return f;
27 | }
28 | }
29 | var fc = s = r = "", pos;
30 | if (!p)
31 | {
32 | n = n.split("").reverse().join("");
33 | f = f.split("").reverse().join("");
34 | }
35 |
36 | for (var i = j = 0; i < f.length; i++, j++)
37 | {
38 | s = n.charAt(j);
39 | if (s == undefined) continue;
40 | fc = f.charAt(i);
41 | switch (fc)
42 | {
43 | case "#":
44 | r += s;
45 | pos = i;
46 | break;
47 | case "0":
48 | r = s || s == fc ? (r + s) : r + 0;
49 | pos = i;
50 | break;//原方法,这里对小数点后的处理有点问题.
51 | case ".":
52 | r += s == fc ? s : (j--, fc);
53 | break;
54 | case ",":
55 | r += s == fc ? s : (j--, fc);
56 | break;
57 | default:
58 | r += fc;
59 | j--;
60 | }
61 | }
62 | if (j != n.length && f.charAt(f.length - 1) != "0" && pos != f.length && f.charAt(pos) != "0")
63 | r = r.substr(0, pos + 1) + n.substr(j) + r.substr(pos + 1);
64 |
65 | r = (p ? r : r.split("").reverse().join("")).replace(/(^,)|(,$)|(,,+)/g, "");
66 | if (r.substr(0,1)==",")
67 | {
68 | r = r.substr(1);
69 | }
70 | if (r.substr(0,2)=="-,")
71 | {
72 | r = "-"+r.substr(2);
73 | }
74 | return r;
75 | }
76 | var n = this.toString();
77 | if (n.length == 0)
78 | return "";
79 | if (f == undefined)
80 | return this;
81 | f = f.split("."), n = n.split(".");
82 | return f.length > 1 ? this.fStr(n[0], f[0]) + "." + this.fStr(n[1], f[1], 1) : this.fStr(n[0], f[0]);
83 | };
84 |
85 | function formatSize(bytes,zeroToEmpty,type)
86 | {
87 | if (isNaN(parseFloat(bytes)))
88 | return (bytes);
89 |
90 | if (bytes==0)
91 | {
92 | if (zeroToEmpty==true)
93 | {
94 | return "";
95 | }
96 | else
97 | {
98 | if (type=="speed")
99 | {
100 | return "0.00 KB/s";
101 | }
102 | else
103 | return "0.00";
104 | }
105 | }
106 | var r = "";
107 | var u = "KB";
108 | if (bytes < 1000 * 1024)
109 | {
110 | r = (bytes / 1024);
111 | u = "KB";
112 | }
113 | else if (bytes < 1000 * 1048576)
114 | {
115 | r = (bytes / 1048576);
116 | u = "MB";
117 | }
118 | else if (bytes < 1000 * 1073741824)
119 | {
120 | r = (bytes / 1073741824);
121 | u = "GB";
122 | }
123 | else if (bytes < 1000 * 1099511627776)
124 | {
125 | r = (bytes / 1099511627776);
126 | u = "TB";
127 | }
128 | else
129 | {
130 | r = (bytes / 1125899906842624);
131 | u = "PB";
132 | }
133 |
134 | if (type=="speed")
135 | {
136 | u+="/s";
137 | }
138 |
139 | return (r.formatNumber("###,###,###,###.00 ")+u);
140 | };
--------------------------------------------------------------------------------
/src/script/plugin/Base64.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Base64 encode / decode
4 | *
5 | * @author haitao.tu
6 | * @date 2010-04-26
7 | * @email tuhaitao@foxmail.com
8 | *
9 | */
10 |
11 | function Base64() {
12 |
13 | // private property
14 | _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
15 |
16 | // public method for encoding
17 | this.encode = function (input) {
18 | var output = "";
19 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
20 | var i = 0;
21 | input = _utf8_encode(input);
22 | while (i < input.length) {
23 | chr1 = input.charCodeAt(i++);
24 | chr2 = input.charCodeAt(i++);
25 | chr3 = input.charCodeAt(i++);
26 | enc1 = chr1 >> 2;
27 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
28 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
29 | enc4 = chr3 & 63;
30 | if (isNaN(chr2)) {
31 | enc3 = enc4 = 64;
32 | } else if (isNaN(chr3)) {
33 | enc4 = 64;
34 | }
35 | output = output +
36 | _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
37 | _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
38 | }
39 | return output;
40 | }
41 |
42 | // public method for decoding
43 | this.decode = function (input) {
44 | var output = "";
45 | var chr1, chr2, chr3;
46 | var enc1, enc2, enc3, enc4;
47 | var i = 0;
48 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
49 | while (i < input.length) {
50 | enc1 = _keyStr.indexOf(input.charAt(i++));
51 | enc2 = _keyStr.indexOf(input.charAt(i++));
52 | enc3 = _keyStr.indexOf(input.charAt(i++));
53 | enc4 = _keyStr.indexOf(input.charAt(i++));
54 | chr1 = (enc1 << 2) | (enc2 >> 4);
55 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
56 | chr3 = ((enc3 & 3) << 6) | enc4;
57 | output = output + String.fromCharCode(chr1);
58 | if (enc3 != 64) {
59 | output = output + String.fromCharCode(chr2);
60 | }
61 | if (enc4 != 64) {
62 | output = output + String.fromCharCode(chr3);
63 | }
64 | }
65 | output = _utf8_decode(output);
66 | return output;
67 | }
68 |
69 | // private method for UTF-8 encoding
70 | _utf8_encode = function (string) {
71 | string = string.replace(/\r\n/g,"\n");
72 | var utftext = "";
73 | for (var n = 0; n < string.length; n++) {
74 | var c = string.charCodeAt(n);
75 | if (c < 128) {
76 | utftext += String.fromCharCode(c);
77 | } else if((c > 127) && (c < 2048)) {
78 | utftext += String.fromCharCode((c >> 6) | 192);
79 | utftext += String.fromCharCode((c & 63) | 128);
80 | } else {
81 | utftext += String.fromCharCode((c >> 12) | 224);
82 | utftext += String.fromCharCode(((c >> 6) & 63) | 128);
83 | utftext += String.fromCharCode((c & 63) | 128);
84 | }
85 |
86 | }
87 | return utftext;
88 | }
89 |
90 | // private method for UTF-8 decoding
91 | _utf8_decode = function (utftext) {
92 | var string = "";
93 | var i = 0;
94 | var c = c1 = c2 = 0;
95 | while ( i < utftext.length ) {
96 | c = utftext.charCodeAt(i);
97 | if (c < 128) {
98 | string += String.fromCharCode(c);
99 | i++;
100 | } else if((c > 191) && (c < 224)) {
101 | c2 = utftext.charCodeAt(i+1);
102 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
103 | i += 2;
104 | } else {
105 | c2 = utftext.charCodeAt(i+1);
106 | c3 = utftext.charCodeAt(i+2);
107 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
108 | i += 3;
109 | }
110 | }
111 | return string;
112 | }
113 | }
--------------------------------------------------------------------------------
/src/_locales/zh_CN/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_appName": {
3 | "message": "PT 助手"
4 | },
5 | "manifest_shortName": {
6 | "message": "PT 助手"
7 | },
8 | "manifest_appDescription": {
9 | "message": "适用于各PT站,可使下载种子等各项操作变化更简单、快捷。配合下载服务器(如Transmission、µTorrent等),可一键下载指定的种子。"
10 | },
11 | "options_title": {
12 | "message": "参数设置"
13 | },
14 | "options_tab_normal": {
15 | "message": "常规"
16 | },
17 | "options_tab_rules": {
18 | "message": "规则"
19 | },
20 | "options_tab_site_types": {
21 | "message": "站点类型"
22 | },
23 | "options_tab_sites": {
24 | "message": "站点设置"
25 | },
26 | "options_tab_clients": {
27 | "message": "下载服务器"
28 | },
29 | "options_tab_search": {
30 | "message": "搜索相关"
31 | },
32 | "options_tab_backup": {
33 | "message": "备份/恢复"
34 | },
35 | "options_tab_help": {
36 | "message": "帮助/说明"
37 | },
38 | "options_button_save_all": {
39 | "message": "全部保存"
40 | },
41 | "options_button_save_and_close": {
42 | "message": "保存并关闭"
43 | },
44 | "options_button_addServer": {
45 | "message": "添加服务器"
46 | },
47 | "options_button_addNew": {
48 | "message": "新增"
49 | },
50 | "options_button_save": {
51 | "message": "保存"
52 | },
53 | "options_button_cancel": {
54 | "message": "取消"
55 | },
56 | "options_button_import": {
57 | "message": "导入"
58 | },
59 | "options_text_defalut_server": {
60 | "message": "默认下载服务器:"
61 | },
62 | "options_text_show_plugin_icon_page": {
63 | "message": "插件图标显示页面:"
64 | },
65 | "options_text_show_plugin_icon_page_tips": {
66 | "message": "多个页面用回车分隔"
67 | },
68 | "options_text_allow_drop_to_send": {
69 | "message": "启用拖放链接到插件图标时,直接发送链接到下载服务器"
70 | },
71 | "options_text_exceed_size_to_confirm": {
72 | "message": "当前页面种子总体积超过"
73 | },
74 | "options_text_exceed_size_to_confirm_1": {
75 | "message": "时,需要我确认。"
76 | },
77 | "options_text_selection_text_search": {
78 | "message": "启用页面内容选择搜索"
79 | },
80 | "options_text_page_rules": {
81 | "message": "页面规则"
82 | },
83 | "options_text_page_rules_tips": {
84 | "message": "多个规则用回车分隔"
85 | },
86 | "options_text_torrent_page_rules": {
87 | "message": "种子列表页面规则:"
88 | },
89 | "options_text_torrent_detail_page_rules": {
90 | "message": "种子详情页面规则:"
91 | },
92 | "options_text_torrent_links_rules": {
93 | "message": "种子链接规则:"
94 | },
95 | "options_text_site_type_list": {
96 | "message": "当前站点类型列表"
97 | },
98 | "options_text_site_type_name": {
99 | "message": "名称:"
100 | },
101 | "options_text_site_type_search_page": {
102 | "message": "搜索页面:"
103 | },
104 | "options_text_site_type_result_type": {
105 | "message": "返回类型:"
106 | },
107 | "options_text_site_type_result_type_text": {
108 | "message": "文本"
109 | },
110 | "options_text_site_type_get_search_result_script": {
111 | "message": "获取搜索结果脚本:"
112 | },
113 | "options_text_site_type_get_total_size_script": {
114 | "message": "获取种子大小脚本:"
115 | },
116 | "options_text_site_type_get_total_size_script_tips": {
117 | "message": "(种子列表页)"
118 | },
119 | "options_text_table_head_no": {
120 | "message": "序号"
121 | },
122 | "options_text_table_head_name": {
123 | "message": "名称"
124 | },
125 | "options_text_table_head_action": {
126 | "message": "操作"
127 | },
128 | "options_text_table_head_name": {
129 | "message": "名称"
130 | },
131 | "options_text_table_head_name": {
132 | "message": "名称"
133 | },
134 |
135 | "popup_search_torrent": {
136 | "message": "搜索种子"
137 | },
138 | "popup_project_home": {
139 | "message": "访问网站"
140 | }
141 | }
--------------------------------------------------------------------------------
/src/script/plugin/deluge.js:
--------------------------------------------------------------------------------
1 | //Deluge
2 | // id:1,method:auth.login,params:[url,null]
3 | // 380 web.download_torrent_from_url
4 | // 2 core.add_torrent_url
5 | var deluge = {
6 | isInitialized:false
7 | ,host:""
8 | ,port:""
9 | ,path:"/json"
10 | ,gui:"/json"
11 | ,fullpath:""
12 | ,username:""
13 | ,password:""
14 | ,headers:{}
15 | ,token:""
16 | ,sessionID: ""
17 | ,requestCount: -1
18 | ,init:function(config,callback)
19 | {
20 | jQuery.extend(this, config);
21 | this.fullpath = this.gui;
22 | //this.headers["Cookies"] = "";
23 | this.getSessionId(this,callback);
24 | }
25 | ,getSessionId:function(me,callback)
26 | {
27 | var data = {
28 | id: (++this.requestCount),
29 | method: "auth.login",
30 | params: [this.password]
31 | };
32 |
33 | var settings = {
34 | type: "POST"
35 | ,url:this.fullpath
36 | ,dataType: 'json'
37 | ,data: JSON.stringify(data)
38 | ,processData: false
39 | ,success:function(resultData,textStatus)
40 | {
41 | me.isInitialized = true;
42 | if (callback)
43 | {
44 | callback(resultData);
45 | }
46 | }
47 | ,error:function(request,event,page)
48 | {
49 | console.log(request);
50 | _self.getSessionId(_self,function(){
51 | _self.exec(config,callback,tags);
52 | });
53 | }
54 | ,headers:this.headers
55 | };
56 | jQuery.ajax(settings);
57 |
58 | /*
59 | var request = new XMLHttpRequest();
60 | request.open("POST", this.fullpath, false, null, null);
61 |
62 | try {
63 | request.send(JSON.stringify(data));
64 |
65 | if (request.status == 200) {
66 | var response = JSON.parse(request.responseText);
67 | if (response.result) {
68 | me.isInitialized = true;
69 | //var cookie = request.getResponseHeader("Set-Cookie");
70 | //cookie = cookie.split(";", 1)[0];
71 | //me.sessionID = cookie;
72 | }
73 | } else if (request.status == 404) {
74 | }
75 | } catch (e) {}
76 | */
77 |
78 | }
79 | /*
80 | // 添加种子连接
81 | this.exec({action:"add-url",s:"url"})
82 | */
83 | // 执行相关命令
84 | ,exec:function(config,callback,tags)
85 | {
86 | if (!this.isInitialized)
87 | {
88 | return false;
89 | }
90 | var data = {
91 | id: (++this.requestCount)
92 | };
93 | var _self = this;
94 |
95 | jQuery.extend(data, config);
96 |
97 | var settings = {
98 | type: "POST"
99 | ,url:this.fullpath
100 | //,dataType: 'json'
101 | ,data: JSON.stringify(data)
102 | ,processData: false
103 | ,success:function(resultData,textStatus)
104 | {
105 | if (callback)
106 | {
107 | callback(resultData,tags);
108 | }
109 | }
110 | ,error:function(request,event,page)
111 | {
112 | console.log(request);
113 | _self.getSessionId(_self,function(){
114 | _self.exec(config,callback,tags);
115 | });
116 | }
117 | //,headers:this.headers
118 | };
119 | jQuery.ajax(settings);
120 | }
121 | // 添加种子
122 | ,addTorrentFromUrl:function(url,callback)
123 | {
124 | // 磁性连接(代码来自原版WEBUI)
125 | if (url.match(/^[0-9a-f]{40}$/i)) {
126 | url = 'magnet:?xt=urn:btih:'+url;
127 | }
128 | this.exec(
129 | {
130 | method:"core.add_torrent_url",
131 | params: [url,null]
132 | }
133 | ,function(resultData){
134 | if (callback)
135 | {
136 | var result = {
137 | status: ""
138 | ,msg: ""
139 | }
140 | if (!resultData.error&&resultData.result)
141 | {
142 | result.status = "success";
143 | result.msg = "URL已添加至 Deluge 。";
144 | }
145 | callback(result);
146 | }
147 | console.log(resultData);
148 | }
149 | );
150 | }
151 | };
--------------------------------------------------------------------------------
/resource/default.json:
--------------------------------------------------------------------------------
1 | {
2 | "droptosend": true,
3 | "defaultclient": "transmission",
4 | "sites": [{
5 | "allowSearch": true,
6 | "defaultFolder": "/volume1/music/OpenCD",
7 | "detailScript": "",
8 | "dropScript": "",
9 | "folders": ["/volume1/music/OpenCD"],
10 | "listAllTorrentUrlScript": "",
11 | "passkey": "",
12 | "site": "open.cd",
13 | "tags": ["音乐"],
14 | "type": "NexusPHP"
15 | }, {
16 | "allowSearch": true,
17 | "detailScript": "",
18 | "dropScript": "",
19 | "folders": ["/volume1/video/CMCT"],
20 | "listAllTorrentUrlScript": "",
21 | "passkey": "",
22 | "site": "hdcmct.org",
23 | "tags": ["电影"],
24 | "type": "NexusPHP"
25 | }, {
26 | "allowSearch": true,
27 | "detailScript": "",
28 | "dropScript": "",
29 | "folders": ["/volume1/video/U2"],
30 | "listAllTorrentUrlScript": "",
31 | "passkey": "",
32 | "site": "u2.dmhy.org",
33 | "tags": ["动漫"],
34 | "type": "NexusPHP"
35 | }, {
36 | "allowSearch": true,
37 | "detailScript": "$(\"input[type='text']\").val()",
38 | "dropScript": "var id=\"$input-url$\".getQueryString(\"id\");var url=jQuery(\"a[href*='download.php/\"+id+\"']\").attr(\"href\").replace(/download\\.php/g,\"download\").replace(\"\\/[HDW]\",\"\\/$passkey$/\");(\"$host$\"+url);",
39 | "folders": ["/volume1/video/HDChina"],
40 | "listAllTorrentUrlScript": "jQuery.map(jQuery(\"a[href^='download.php']\").toArray(),function(n){return \"$host$\"+jQuery(n).attr(\"href\").replace(/download\\.php/g,\"download\").replace(\"\\/[HDW]\",\"\\/$passkey$/\");});",
41 | "passkey": "",
42 | "site": "hdchina.org",
43 | "tags": ["电影"],
44 | "type": "HDChina"
45 | }, {
46 | "allowSearch": true,
47 | "detailScript": "(new RegExp(/t\\/(\\d+)\\//g)).exec(location.href);var id=RegExp.$1;(\"$input-host$rssdd.php?par=\"+(new Base64).encode(\"vvv\"+id+\"|||$input-passkey$zz\"));",
48 | "dropScript": "(new RegExp(/t\\/(\\d+)\\//g)).exec(\"$input-url$\");var id=RegExp.$1;(\"$host$rssdd.php?par=\"+(new Base64).encode(\"vvv\"+id+\"|||$input-passkey$zz\"));",
49 | "folders": ["/volume1/video/TTG"],
50 | "listAllTorrentUrlScript": "$.map($(\"a[href^='/t/']\").toArray(),function(n){(new RegExp(/t\\/(\\d+)\\//g)).exec($(n).attr(\"href\"));var id=RegExp.$1;return (\"$host$rssdd.php?par=\"+(new Base64).encode(\"vvv\"+id+\"|||$input-passkey$zz\"));});",
51 | "passkey": "",
52 | "site": "totheglory.im",
53 | "tags": ["电影", "游戏"],
54 | "type": "TTG"
55 | }],
56 | "transmission": {
57 | "server": "http://192.168.1.1",
58 | "port": "9091",
59 | "username": "",
60 | "password": "",
61 | "rpc": "",
62 | "autostart": false,
63 | "webui": ""
64 | },
65 | "utorrent": {
66 | "server": "",
67 | "port": "",
68 | "username": "",
69 | "password": "",
70 | "gui": "",
71 | "webui": ""
72 | },
73 | "deluge": {
74 | "server": "",
75 | "port": "",
76 | "password": "",
77 | "gui": "",
78 | "webui": ""
79 | },
80 | "pluginIconShowPages": ["/torrents.php", "/browse.php", "/rescue.php"],
81 | "contextMenuRules": {
82 | "torrentDetailPages": ["*://*/details.php*", "*://*/plugin_details.php*", "https://totheglory.im/t/*"],
83 | "torrentListPages": ["*://*/torrents.php*", "*://*/browse.php*", "*://*/rescue.php*"],
84 | "torrentLinks": ["*://*/details.php*", "*://*/download.php*", "*://*/plugin_details.php*", "https://totheglory.im/t/*"]
85 | },
86 | "siteTypes": [{
87 | "getSearchResultScript": "var items = $(result).find('item');\nvar datas = [];\n$.each(items, function(index, item) {\n\titem = $(item);\n\tvar data = {\n\t\ttitle: item.find(\"title\").text(),\n\t\tlink: item.find(\"link\").text(),\n\t\tdownloadURL: item.find(\"enclosure\").attr(\"url\")+\"&passkey=\"+system.getSite(site).passkey,\n\t\tsize: formatSize(item.find(\"enclosure\").attr(\"length\")),\n\t\tdate: (new Date(item.find(\"pubDate\").text())).toLocaleString(),\n\t\tauthor: item.find(\"author\").text(),\n\t\tsource: site\n\t};\n\tdatas.push(data);\n});\n\nsystem.addSearchResult(datas);",
88 | "getTorrentTotalSizeScript": "$(\".torrents\").find(\"td:contains('MB'),td:contains('GB'),td:contains('TB')\")",
89 | "name": "NexusPHP",
90 | "searchPage": "/torrentrss.php?rows=$rows$&ismalldescr=1&search=$key$&search_mode=1&nd=1",
91 | "searchResultType": "xml"
92 | }, {
93 | "getSearchResultScript": "var parent = $(result).find('.torrents_list');\nif (parent.length>0)\n{\n\tvar items = parent[0].rows;\n\t//log(items.length);\n\tvar datas = [];\n\t$.each(items, function(index, item) {\n\t\tif (index==0) return;\n\t\titem = $(item);\n\t\t//log(item);\n\t\tvar url=\"http://\"+site+\"/\"+item.find(\"a[href*='download.php']\").attr(\"href\").replace(/download\\.php/g,\"download\").replace(\"\\/[HDW]\",\"/\"+system.getSite(site).passkey+\"/\");\n\t\tvar data = {\n\t\t\ttitle: item.find(\".man_link\").html(),\n\t\t\tlink: \"http://\"+site+\"/\"+item.find(\".man_link\").attr(\"href\"),\n\t\t\tdownloadURL: url,\n\t\t\tsize: item.context.cells[5].innerText.replace(\"\\n\",\" \"),\n\t\t\tdate: item.context.cells[4].innerText,\n\t\t\tauthor: item.context.cells[9].innerText,\n\t\t\tsource: site\n\t\t};\n\t\tdatas.push(data);\n\t});\n\n\tsystem.addSearchResult(datas);\n}",
94 | "getTorrentTotalSizeScript": "$(\".torrents_list\").find(\"td:contains('MB'),td:contains('GB'),td:contains('TB')\")",
95 | "name": "HDChina",
96 | "searchPage": "/torrentrss.php?rows=$rows$&ismalldescr=1&search=$key$&search_mode=1&nd=1&passkey=$passkey$",
97 | "searchResultType": "html"
98 | }, {
99 | "name": "TTG",
100 | "searchPage": "/browse.php?search_field=$key$&c=M",
101 | "searchResultType": "html",
102 | "getSearchResultScript": "var items = $(result).find('#torrent_table tr.hover_hr');\nvar datas = [];\n$.each(items, function(index, item) {\n\titem = $(item);\n\tvar id = item.attr(\"id\");\n\tvar url=\"http://\"+site+\"/rssdd.php?par=\"+(new Base64).encode(\"vvv\"+id+\"|||\"+system.getSite(site).passkey+\"zz\");\n\tvar data = {\n\t\ttitle: item.find(\".name_left a\").html(),\n\t\tlink: \"http://\"+site+item.find(\".name_left a\").attr(\"href\"),\n\t\tdownloadURL: url,\n\t\tsize: item.find(\"td:eq(6)\").text().replace(\"\\n\",\" \"),\n\t\tdate: item.find(\"td:eq(4)\").html(),\n\t\tauthor: item.find(\"td:eq(9)\").text(),\n\t\tsource: site\n\t};\n\tdatas.push(data);\n});\n\nsystem.addSearchResult(datas);",
103 | "getTorrentTotalSizeScript": "$(\"#torrent_table\").find(\"td:contains('MB'),td:contains('GB'),td:contains('TB')\")"
104 | }],
105 | "search": {
106 | "rows": "10",
107 | "key": "",
108 | "tags": ["音乐", "电影", "动漫", "图书", "游戏"],
109 | "checkedTags": ["音乐"]
110 | }
111 | }
--------------------------------------------------------------------------------
/src/script/plugin/transmission.js:
--------------------------------------------------------------------------------
1 | // transmission RPC 操作类
2 | // 栽培者
3 | var transmission = {
4 | SessionId:""
5 | ,isInitialized:false
6 | ,host:""
7 | ,port:"9091"
8 | ,path:"/transmission/rpc"
9 | ,rpcpath:"../rpc"
10 | ,fullpath:""
11 | ,on:{
12 | torrentCountChange:null
13 | ,postError:null
14 | }
15 | ,username:""
16 | ,password:""
17 | // 种子状态
18 | ,_status:{
19 | stopped:0
20 | ,checkwait:1
21 | ,check:2
22 | ,downloadwait:3
23 | ,download:4
24 | ,seedwait:5
25 | ,seed:6
26 | // 自定义状态
27 | ,actively:101
28 | }
29 | ,options:{
30 | getFolders:true
31 | ,getTarckers:true
32 | }
33 | ,headers:{}
34 | ,trackers:{}
35 | ,islocal:false
36 | // 当前已存在的目录列表
37 | ,downloadDirs:new Array()
38 | ,getSessionId:function(me,callback)
39 | {
40 | var settings = {
41 | type: "POST"
42 | ,url:this.fullpath
43 | ,error: function(request,event,settings)
44 | {
45 | var SessionId = "";
46 | if (request.status === 409 && (SessionId = request.getResponseHeader('X-Transmission-Session-Id')))
47 | {
48 | me.isInitialized = true;
49 | me.SessionId = SessionId;
50 | me.headers["X-Transmission-Session-Id"] = SessionId;
51 | if (callback)
52 | {
53 | callback();
54 | }
55 | }
56 | else
57 | {
58 | console.log(request);
59 | if (callback)
60 | {
61 | callback({status:"error",msg:"error."});
62 | }
63 | }
64 | }
65 | ,headers:this.headers
66 |
67 | };
68 | jQuery.ajax(settings);
69 | }
70 | ,init:function(config,callback)
71 | {
72 | jQuery.extend(this, config);
73 |
74 | /*
75 | if (this.fullpath=="")
76 | {
77 | this.fullpath = this.host + (this.port?":"+this.port:"") + this.path;
78 | }*/
79 | if (this.username&&this.password)
80 | {
81 | this.headers["Authorization"] = "Basic "+(new Base64()).encode(this.username+":"+this.password);
82 | }
83 |
84 | this.fullpath = this.rpcpath;
85 | this.getSessionId(this,callback);
86 | }
87 | ,exec:function(config,callback,tags)
88 | {
89 | if (!this.isInitialized)
90 | {
91 | return false;
92 | }
93 | var data = {
94 | method:""
95 | ,arguments:{}
96 | ,tag:""
97 | };
98 |
99 | jQuery.extend(data, config);
100 |
101 | var settings = {
102 | type: "POST"
103 | ,url:this.fullpath
104 | ,dataType: 'json'
105 | ,data:JSON.stringify(data)
106 | ,success:function(resultData,textStatus)
107 | {
108 | if (callback)
109 | {
110 | callback(resultData,tags);
111 | }
112 | }
113 | ,error:function(request,event,page)
114 | {
115 | var SessionId = "";
116 | if (request.status === 409 && (SessionId = request.getResponseHeader('X-Transmission-Session-Id')))
117 | {
118 | transmission.SessionId = SessionId;
119 | transmission.headers["X-Transmission-Session-Id"] = SessionId;
120 | jQuery.ajax(settings);
121 | }
122 | else
123 | {
124 | if (transmission.on.postError)
125 | {
126 | transmission.on.postError(request);
127 | }
128 | }
129 | }
130 | ,headers:this.headers
131 | };
132 | jQuery.ajax(settings);
133 | }
134 | ,getStatus:function(callback)
135 | {
136 | this.exec(
137 | {
138 | method:"session-stats"
139 | }
140 | ,function(data)
141 | {
142 | if (data.result=="success")
143 | {
144 | if (callback)
145 | {
146 | callback(data.arguments);
147 | }
148 |
149 | if (transmission.torrents.count!=data.arguments.torrentCount
150 | ||transmission.torrents.activeTorrentCount!=data.arguments.activeTorrentCount
151 | ||transmission.torrents.pausedTorrentCount!=data.arguments.pausedTorrentCount)
152 | {
153 | // 当前种子总数
154 | transmission.torrents.count = data.arguments.torrentCount;
155 | transmission.torrents.activeTorrentCount = data.arguments.activeTorrentCount;
156 | transmission.torrents.pausedTorrentCount = data.arguments.pausedTorrentCount;
157 | transmission._onTorrentCountChange();
158 | }
159 | }
160 | }
161 | );
162 | }
163 | ,getSession:function(callback)
164 | {
165 | this.exec(
166 | {
167 | method:"session-get"
168 | }
169 | ,function(data)
170 | {
171 | if (data.result=="success")
172 | {
173 | if (callback)
174 | {
175 | callback(data.arguments);
176 | }
177 | }
178 | }
179 | );
180 | }
181 | // 添加种子
182 | ,addTorrentFromUrl:function(url,savepath,autostart,callback)
183 | {
184 | // 磁性连接(代码来自原版WEBUI)
185 | if (url.match(/^[0-9a-f]{40}$/i)) {
186 | url = 'magnet:?xt=urn:btih:'+url;
187 | }
188 | var options = {
189 | method:"torrent-add"
190 | ,arguments:{
191 | filename:url
192 | ,paused:(!autostart)
193 | }
194 | };
195 |
196 | if (savepath)
197 | {
198 | options.arguments["download-dir"] = savepath;
199 | }
200 | this.exec(options
201 | ,function(data){
202 | switch (data.result)
203 | {
204 | // 添加成功
205 | case "success":
206 | if (callback)
207 | {
208 | if (data.arguments["torrent-added"])
209 | {
210 | callback(data.arguments["torrent-added"]);
211 | }
212 | // 重复的种子
213 | else if(data.arguments["torrent-duplicate"])
214 | {
215 | callback({
216 | status: "duplicate",
217 | torrent: data.arguments["torrent-duplicate"]
218 | });
219 | }
220 |
221 | }
222 | break;
223 |
224 | // 重复的种子
225 | case "duplicate torrent":
226 | default:
227 | if (callback)
228 | {
229 | callback(data.result);
230 | }
231 | break;
232 |
233 | }
234 | }
235 | );
236 | }
237 | // 从文件内容增加种子
238 | ,addTorrentFromFile:function(file,savePath,paused,callback,filecount)
239 | {
240 | var fileReader = new FileReader();
241 |
242 | fileReader.onload = function(e) {
243 | var contents = e.target.result;
244 | var key = "base64,";
245 | var index = contents.indexOf(key);
246 | if (index==-1)
247 | {
248 | return;
249 | }
250 | var metainfo = contents.substring (index + key.length);
251 |
252 | transmission.exec(
253 | {
254 | method:"torrent-add"
255 | ,arguments:{
256 | metainfo:metainfo
257 | ,"download-dir":savePath
258 | ,paused:paused
259 | }
260 | }
261 | ,function(data){
262 | switch (data.result)
263 | {
264 | // 添加成功
265 | case "success":
266 | if (callback)
267 | {
268 | callback(data.arguments["torrent-added"],filecount);
269 | }
270 | break;
271 | // 重复的种子
272 | case "duplicate torrent":
273 | if (callback)
274 | {
275 | callback("duplicate");
276 | }
277 | break;
278 |
279 | }
280 | }
281 | );
282 | }
283 | fileReader.readAsDataURL (file);
284 |
285 | }
286 | ,_onTorrentCountChange:function()
287 | {
288 | this.torrents.loadSimpleInfo = false;
289 | if (this.on.torrentCountChange)
290 | {
291 | this.on.torrentCountChange();
292 | }
293 | }
294 | // 删除种子
295 | ,removeTorrent:function(ids,removeData,callback)
296 | {
297 | this.exec({
298 | method:"torrent-remove"
299 | ,arguments:{
300 | ids:ids
301 | ,"delete-local-data":removeData
302 | }
303 | }
304 | ,function(data){
305 | if (callback)
306 | callback(data.result);
307 | }
308 | );
309 | }
310 | // 獲取指定目錄的大小
311 | ,getFreeSpace:function(path,callback)
312 | {
313 | this.exec({
314 | method:"free-space"
315 | ,arguments:{
316 | "path":path
317 | }
318 | }
319 | ,function(result){
320 | if (callback)
321 | callback(result);
322 | }
323 | );
324 | }
325 | // 更新黑名單
326 | ,updateBlocklist:function(callback)
327 | {
328 | this.exec({
329 | method:"blocklist-update"
330 | }
331 | ,function(data){
332 | if (callback)
333 | callback(data.result);
334 | }
335 | );
336 | }
337 | };
338 |
339 | /*
340 | (function($){
341 | var items = $("script");
342 | var index = -1;
343 | for (var i=0;i").attr("tag", item).prop("checked", (tags[item] ? true : false)).appendTo(parent);
46 | $("").html(item).appendTo(parent);
47 | });
48 | },
49 | search: function (key) {
50 | $("#tbody-result").empty();
51 | this.setSearchKey(key);
52 | this.sendMessage({
53 | action: "read-config"
54 | }, function (config) {
55 | //alert(config.sites.length);
56 | system.config = config;
57 | system.searchTorrent(key, function (result) {
58 | log(result);
59 | });
60 | });
61 | },
62 | setSearchKey: function (key) {
63 | $("#search-key").val(key);
64 | this.config.search.key = key;
65 | this.config.search.checkedTags = $.map($("#tags input:checked"), function (n) {
66 | return $(n).attr("tag");
67 | });
68 | chrome.extension.sendMessage({
69 | action: "save-config",
70 | config: this.config
71 | });
72 | },
73 | sendMessage: function (options, callback) {
74 | if (callback) {
75 | chrome.extension.sendMessage(options, callback);
76 | } else {
77 | chrome.extension.sendMessage(options);
78 | }
79 | },
80 | requestMessage: function (message, callback) {
81 | switch (message.action.toLowerCase()) {
82 | case "search-torrent":
83 | $("#search-key").val(message.key);
84 | this.search(message.key);
85 | break;
86 |
87 | }
88 | },
89 | getSiteType: function (name) {
90 | var type = "";
91 | $.each(this.config.siteTypes, function (index, item) {
92 | if (item.name == name) {
93 | type = item;
94 | return;
95 | }
96 | });
97 |
98 | return type;
99 | },
100 | getSearchPage: function (name) {
101 | var page = "";
102 | $.each(this.config.siteTypes, function (index, item) {
103 | if (item.name == name) {
104 | page = item.searchPage;
105 | return;
106 | }
107 | });
108 |
109 | return page;
110 | },
111 | getSite: function (name) {
112 | var site = null;
113 | for (var i = 0; i < this.config.sites.length; i++) {
114 | site = this.config.sites[i];
115 | if (site.site == name) {
116 | break;
117 | }
118 | };
119 | return site;
120 | },
121 | checkTag: function (site) {
122 | if (!$.isArray(site.tags)) return false;
123 | if (site.tags.length == 0) return false;
124 |
125 | var tags = {};
126 | var result = false;
127 | if ($.isArray(this.config.search.checkedTags)) {
128 | $.each(this.config.search.checkedTags, function (index, item) {
129 | if ($.inArray(item, site.tags) != -1) {
130 | result = true;
131 | }
132 | });
133 | }
134 |
135 | return result;
136 | },
137 | // 搜索种子
138 | searchTorrent: function (key, callback) {
139 | var rows = this.config.search.rows;
140 | if (isNaN(parseInt(rows))) {
141 | rows = 5;
142 | }
143 | var urls = [];
144 | var scripts = [];
145 | var sites = [];
146 | var errors = [];
147 | $("#status").hide();
148 |
149 | $.each(this.config.sites, function (index, item) {
150 | if (item.allowSearch && system.checkTag(item)) {
151 | var siteType = system.getSiteType(item.type);
152 | var url = system.getSiteHost(item) + siteType.searchPage;
153 | var script = siteType.getSearchResultScript;
154 |
155 | url = system.replaceKeys(url, {
156 | key: key,
157 | rows: rows,
158 | passkey: system.getSite(item.site).passkey
159 | });
160 |
161 | urls.push(url);
162 | scripts.push(script);
163 | sites.push(item.site);
164 | }
165 | });
166 |
167 | doSearch(urls, urls.length, callback);
168 |
169 | function doSearch(items, count, callback) {
170 | var index = count - items.length;
171 | var url = urls.shift();
172 |
173 | if (!url) {
174 | system.showStatusMessage("搜索完成。", 6);
175 | if (errors.length > 0) {
176 | $("#status").html(errors.join("
")).show();
177 | setTimeout(function(){
178 | $("#status").fadeOut();
179 | }, 5000);
180 | }
181 | return;
182 | }
183 | var site = sites[index];
184 | system.showStatusMessage("正在搜索 [" + site + "]..." + (index + 1) + "/" + count + ".", 0);
185 | var settings = {
186 | url: url,
187 | success: function (result, textStatus) {
188 | doSearch(urls, count, callback);
189 | if (result && (typeof result=="string" && result.length > 100) || (typeof result == "object")) {
190 | var script = scripts[index];
191 |
192 | if (script) {
193 | eval(script);
194 | }
195 | } else {
196 | errors.push(site + " 搜索异常。[" + result + "]");
197 | }
198 | },
199 | error: function () {
200 | errors.push(site + " 搜索失败。");
201 | doSearch(urls, count, callback);
202 | }
203 | };
204 |
205 | jQuery.ajax(settings);
206 | }
207 | },
208 | replaceKeys: function (source, keys) {
209 | $.each(keys, function (key, value) {
210 | source = source.replace("\$" + key + "\$", value);
211 | });
212 |
213 | return source;
214 | },
215 | getSiteHost: function (site) {
216 | if (site.host) return site.host;
217 | return ((site.disableHttps===true?"http://":"https://") + site.site);
218 | },
219 | addSearchResult: function (datas) {
220 | $.each(datas, function (index, item) {
221 | if (index < system.config.search.rows)
222 | system.addRow(item);
223 | });
224 | },
225 | addRow: function (data) {
226 | var body = $("#tbody-result");
227 | var index = body[0].rows.length + 1;
228 | var row = $("
").appendTo(body);
229 |
230 | // 序号
231 | $(" | ").css("textAlign", "center").html(index).appendTo(row);
232 | // 标题
233 | $("").attr("href", data.link).html(data.title).attr("target", "_blank").appendTo($(" | ").appendTo(row));
234 | // 操作
235 | var buttons = $(" | ").css("textAlign", "center").appendTo(row);
236 | // 发送到下载服务器
237 | $("").click(function () {
238 | var folder = null;
239 | var url = data.downloadURL;
240 | var site = system.getSite(data.source);
241 | if (site.defaultFolder) {
242 | folder = site.defaultFolder;
243 | } else if (site.folders.length > 0) {
244 | folder = site.folders[0];
245 | }
246 |
247 | system.showStatusMessage("正在发送链接地址 " + url + " 到下载服务器", 0);
248 | chrome.extension.sendMessage({
249 | action: "send-url-to-client",
250 | url: url,
251 | folder: folder
252 | }, function (result) {
253 | system.showStatusMessage(result.msg, 5);
254 | });
255 | }).attr("class", "link sendToDownload").attr("title", "发送到下载服务器").appendTo(buttons);
256 | // log(data.downloadURL);
257 | // 大小
258 | $(" | ").css("textAlign", "right").html(data.size).appendTo(row);
259 | // 发布人
260 | $(" | ").html(data.author).appendTo(row);
261 | // 时间
262 | $(" | ").html(data.date).appendTo(row);
263 | // 来源
264 | $(" | ").html(data.source).appendTo(row);
265 | },
266 | showStatusMessage: function (msg, time) {
267 | if (!this.statusMessageBox) {
268 | this.statusMessageBox = $("").css({
269 | top: -500,
270 | width: "auto"
271 | }).attr("class", "status-messages").html(msg).appendTo($(document.body));
272 | }
273 |
274 | if (time == undefined) {
275 | time = 3000;
276 | } else {
277 | time = time * 1000;
278 | }
279 |
280 | this.statusMessageBox.html(msg);
281 |
282 | var top = jQuery(window).height() - this.statusMessageBox.height() - 30;
283 | var left = jQuery(window).width() - this.statusMessageBox.width() - 50;
284 | this.statusMessageBox.css({
285 | top: top + "px",
286 | left: left + "px"
287 | });
288 |
289 | if (time == 0) {
290 | this.statusMessageBox.stop().show();
291 | } else {
292 | this.statusMessageBox.stop().show().fadeOut(time);
293 | }
294 | },
295 | resize: function () {
296 | $("#search-result").height($(window).height() - $("#search-result").position().top - 10);
297 | }
298 | };
299 |
300 | $(document).ready(function () {
301 | system.init();
302 | });
303 |
304 | $(window).resize(function () {
305 | system.resize();
306 | })
307 |
308 | chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
309 | system.requestMessage(message, sendResponse);
310 | return true;
311 | });
--------------------------------------------------------------------------------
/src/script/plugin/FileSaver.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2011 Eli Grey, http://eligrey.com
3 | This file is based on:
4 | https://github.com/eligrey/FileSaver.js/blob/master/FileSaver.js ,
5 | licensed under X11/MIT.
6 | See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
7 |
8 | This file is part of SwitchySharp.
9 | SwitchySharp is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or
12 | (at your option) any later version.
13 |
14 | SwitchySharp is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with SwitchySharp. If not, see .
21 | */
22 |
23 | var saveAs = saveAs || (function (view) {
24 | "use strict";
25 | var
26 | doc = view.document
27 | // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
28 | , get_URL = function () {
29 | return view.URL || view.webkitURL || view;
30 | }
31 | , URL = view.URL || view.webkitURL || view
32 | , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
33 | , can_use_save_link = "download" in save_link
34 | , click = function (node) {
35 | var event = doc.createEvent("MouseEvents");
36 | event.initMouseEvent(
37 | "click", true, false, view, 0, 0, 0, 0, 0
38 | , false, false, false, false, 0, null
39 | );
40 | return node.dispatchEvent(event); // false if event was cancelled
41 | }
42 | , webkit_req_fs = view.webkitRequestFileSystem
43 | , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
44 | , throw_outside = function (ex) {
45 | (view.setImmediate || view.setTimeout)(function () {
46 | throw ex;
47 | }, 0);
48 | }
49 | , force_saveable_type = "application/octet-stream"
50 | , fs_min_size = 0
51 | , deletion_queue = []
52 | , process_deletion_queue = function () {
53 | var i = deletion_queue.length;
54 | while (i--) {
55 | var file = deletion_queue[i];
56 | if (typeof file === "string") { // file is an object URL
57 | URL.revokeObjectURL(file);
58 | } else { // file is a File
59 | file.remove();
60 | }
61 | }
62 | deletion_queue.length = 0; // clear queue
63 | }
64 | , dispatch = function (filesaver, event_types, event) {
65 | event_types = [].concat(event_types);
66 | var i = event_types.length;
67 | while (i--) {
68 | var listener = filesaver["on" + event_types[i]];
69 | if (typeof listener === "function") {
70 | try {
71 | listener.call(filesaver, event || filesaver);
72 | } catch (ex) {
73 | throw_outside(ex);
74 | }
75 | }
76 | }
77 | }
78 | , FileSaver = function (blob, name) {
79 | // First try a.download, then web filesystem, then object URLs
80 | var
81 | filesaver = this
82 | , type = blob.type
83 | , blob_changed = false
84 | , object_url
85 | , target_view
86 | , get_object_url = function (blob) {
87 | var object_url = get_URL().createObjectURL(blob);
88 | deletion_queue.push(object_url);
89 | return object_url;
90 | }
91 | , dispatch_all = function () {
92 | dispatch(filesaver, "writestart progress write writeend".split(" "));
93 | }
94 | // on any filesys errors revert to saving with object URLs
95 | , fs_error = function () {
96 | // don't create more object URLs than needed
97 | if (blob_changed || !object_url) {
98 | object_url = get_object_url(blob);
99 | }
100 | target_view.location.href = object_url;
101 | filesaver.readyState = filesaver.DONE;
102 | dispatch_all();
103 | }
104 | , abortable = function (func) {
105 | return function () {
106 | if (filesaver.readyState !== filesaver.DONE) {
107 | return func.apply(this, arguments);
108 | }
109 | };
110 | }
111 | , create_if_not_found = {create:true, exclusive:false}
112 | , slice
113 | ;
114 | filesaver.readyState = filesaver.INIT;
115 | if (!name) {
116 | name = "download";
117 | }
118 | if (can_use_save_link) {
119 | object_url = get_object_url(blob);
120 | save_link.href = object_url;
121 | save_link.download = name;
122 | if (click(save_link)) {
123 | filesaver.readyState = filesaver.DONE;
124 | dispatch_all();
125 | return;
126 | }
127 | }
128 | // Object and web filesystem URLs have a problem saving in Google Chrome when
129 | // viewed in a tab, so I force save with application/octet-stream
130 | // http://code.google.com/p/chromium/issues/detail?id=91158
131 | if (view.chrome && type && type !== force_saveable_type) {
132 | slice = blob.slice || blob.webkitSlice;
133 | blob = slice.call(blob, 0, blob.size, force_saveable_type);
134 | blob_changed = true;
135 | }
136 | // Since I can't be sure that the guessed media type will trigger a download
137 | // in WebKit, I append .download to the filename.
138 | // https://bugs.webkit.org/show_bug.cgi?id=65440
139 | //if (webkit_req_fs && name !== "download") {
140 | // name += ".download";
141 | //}
142 | if (type === force_saveable_type || webkit_req_fs) {
143 | target_view = view;
144 | } else {
145 | target_view = view.open();
146 | }
147 | if (!req_fs) {
148 | fs_error();
149 | return;
150 | }
151 | fs_min_size += blob.size;
152 | req_fs(view.TEMPORARY, fs_min_size, abortable(function (fs) {
153 | fs.root.getDirectory("saved", create_if_not_found, abortable(function (dir) {
154 | var save = function () {
155 | dir.getFile(name, create_if_not_found, abortable(function (file) {
156 | file.createWriter(abortable(function (writer) {
157 | writer.onwriteend = function (event) {
158 | target_view.location.href = file.toURL();
159 | deletion_queue.push(file);
160 | filesaver.readyState = filesaver.DONE;
161 | dispatch(filesaver, "writeend", event);
162 | };
163 | writer.onerror = function () {
164 | var error = writer.error;
165 | if (error.code !== error.ABORT_ERR) {
166 | fs_error();
167 | }
168 | };
169 | "writestart progress write abort".split(" ").forEach(function (event) {
170 | writer["on" + event] = filesaver["on" + event];
171 | });
172 | writer.write(blob);
173 | filesaver.abort = function () {
174 | writer.abort();
175 | filesaver.readyState = filesaver.DONE;
176 | };
177 | filesaver.readyState = filesaver.WRITING;
178 | }), fs_error);
179 | }), fs_error);
180 | };
181 | dir.getFile(name, {create:false}, abortable(function (file) {
182 | // delete file if it already exists
183 | file.remove();
184 | save();
185 | }), abortable(function (ex) {
186 | if (ex.code === ex.NOT_FOUND_ERR) {
187 | save();
188 | } else {
189 | fs_error();
190 | }
191 | }));
192 | }), fs_error);
193 | }), fs_error);
194 | }
195 | , FS_proto = FileSaver.prototype
196 | , saveAs = function (blob, name) {
197 | return new FileSaver(blob, name);
198 | }
199 | ;
200 | FS_proto.abort = function () {
201 | var filesaver = this;
202 | filesaver.readyState = filesaver.DONE;
203 | dispatch(filesaver, "abort");
204 | };
205 | FS_proto.readyState = FS_proto.INIT = 0;
206 | FS_proto.WRITING = 1;
207 | FS_proto.DONE = 2;
208 |
209 | FS_proto.error =
210 | FS_proto.onwritestart =
211 | FS_proto.onprogress =
212 | FS_proto.onwrite =
213 | FS_proto.onabort =
214 | FS_proto.onerror =
215 | FS_proto.onwriteend =
216 | null;
217 |
218 | view.addEventListener("unload", process_deletion_queue, false);
219 | return saveAs;
220 | }(self));
221 |
--------------------------------------------------------------------------------
/src/extension/init.js:
--------------------------------------------------------------------------------
1 | var system = {
2 | // 页面操作按钮层
3 | shower: jQuery("").appendTo(jQuery(document.body)),
4 | droper: jQuery(""),
5 | buttonBar: jQuery(""),
6 | buttons: new Array(),
7 | positions: [{
8 | x: 35,
9 | y: 60
10 | }, {
11 | x: 60,
12 | y: 90
13 | }, {
14 | x: 60,
15 | y: 120
16 | }, {
17 | x: 35,
18 | y: 150
19 | }],
20 | status: 0,
21 | config: null,
22 | site: null,
23 | init: function() {
24 | this.shower.click(function() {
25 | if (system.status == 0) {
26 | system.buttonBar.show();
27 | system.status = 1;
28 | } else {
29 | system.buttonBar.hide();
30 | system.status = 0;
31 | }
32 | });
33 | var top = jQuery(window).height() / 2 - this.shower.height() / 2;
34 | var left = jQuery(window).width() - this.shower.width() - 2;
35 | this.shower.css({
36 | top: top + "px",
37 | left: left + "px"
38 | }).show();
39 | this.buttonBar.appendTo(this.shower);
40 | var y = top - 40;
41 | var x = [left - 10, left - 40, left - 40, left - 10];
42 |
43 | jQuery.each(this.positions, function(index, item) {
44 | item.y = y;
45 | item.x = x[index];
46 | y += 30;
47 | });
48 |
49 | this.initButtons();
50 | this.initSiteMenus();
51 | this.initDrop();
52 | },
53 | initButtons: function() {
54 | this.addButton({
55 | key: "copy",
56 | tip: "获取当前页的种子下载链接到剪切板",
57 | action: function() {
58 | //log(system.getSize($(".torrents").find("td:contains('MB'),td:contains('GB')")));
59 |
60 |
61 | var urls = system.getDownloadAddress();
62 | if (urls.length == 0)
63 | return;
64 | // 发送消息
65 | chrome.extension.sendMessage({
66 | action: "toClipboard",
67 | content: urls.join("\n")
68 | }, function() {
69 | system.showStatusMessage(urls.length + "个地址已复制到剪切板");
70 | });
71 | }
72 | });
73 |
74 | this.addButton({
75 | key: "download",
76 | tip: "将当前页的种子下载链接到发送到下载服务器",
77 | action: function() {
78 | var size = system.checkSize();
79 |
80 | if (size!==true)
81 | {
82 | if (!confirm("当前页面种子容量为 "+size+" 已超过 "+system.config.exceedSize+" "+system.config.exceedSizeUnit+",是否发送?"))
83 | {
84 | return;
85 | }
86 | }
87 |
88 | var _urls = system.getDownloadAddress();
89 | if (_urls.length == 0)
90 | return;
91 | var folder = null;
92 | if (system.site.defaultFolder) {
93 | folder = system.site.defaultFolder;
94 | } else if (system.site.folders.length > 0) {
95 | folder = system.site.folders[0];
96 | }
97 | addTorrentsToServer(_urls, _urls.length, folder);
98 |
99 | function addTorrentsToServer(urls, count, savepath, callback) {
100 | var index = count - urls.length;
101 | var url = urls.shift();
102 | if (!url) {
103 | system.showStatusMessage(count + "条链接已发送完成。");
104 | return;
105 | }
106 | system.showStatusMessage("正在发送:" + url + "(" + (count - index) + "/" + count + ")", 0);
107 | chrome.extension.sendMessage({
108 | action: "send-url-to-client",
109 | url: url,
110 | folder: savepath
111 | }, function(data) {
112 | addTorrentsToServer(urls, count, savepath, callback);
113 | });
114 | }
115 | }
116 | });
117 |
118 | this.addButton({
119 | key: "webui",
120 | tip: "打开客户端WEBUI",
121 | action: function() {
122 | chrome.extension.sendMessage({
123 | action: "open-client-webui"
124 | });
125 | }
126 | });
127 |
128 | this.addButton({
129 | key: "config",
130 | tip: "参数设置",
131 | action: function() {
132 | //window.open("chrome-extension://mggjibpagkemifpmbokhekbbdnicjibd/options.html");
133 | chrome.extension.sendMessage({
134 | action: "open-options"
135 | });
136 | }
137 | });
138 | },
139 | getSiteTypeIndex: function(name) {
140 | var resultIndex = -1;
141 | $.each(this.config.siteTypes, function(index, item) {
142 | if (item.name == name) {
143 | resultIndex = index;
144 | return;
145 | }
146 | });
147 |
148 | return resultIndex;
149 | },
150 | checkSize: function() {
151 | if (!this.config.exceedSizeToConfirm) return true;
152 |
153 | var siteType = this.config.siteTypes[this.getSiteTypeIndex(this.site.type)];
154 | if (siteType.getTorrentTotalSizeScript)
155 | {
156 | var result = eval(siteType.getTorrentTotalSizeScript);
157 | var size = this.getSize(result);
158 | var exceedSize = 0;
159 | switch (this.config.exceedSizeUnit)
160 | {
161 | case "MB":
162 | exceedSize = (this.config.exceedSize*1048576);
163 | break;
164 |
165 | case "GB":
166 | exceedSize = (this.config.exceedSize*1073741824);
167 | break;
168 |
169 | case "T":
170 | case "TB":
171 | exceedSize = (this.config.exceedSize*1099511627776);
172 | break;
173 | }
174 |
175 | return (size>=exceedSize?formatSize(size):true);
176 | }
177 | return true;
178 | },
179 | addButton: function(options) {
180 | var def = {
181 | key: "",
182 | text: "",
183 | tip: "",
184 | action: null
185 | };
186 | options = jQuery.extend(true, def, options);
187 |
188 | var button = jQuery("").attr("title", options.tip);
189 | jQuery("")
190 | .html(options.text)
191 | .appendTo(button);
192 |
193 | if (options.action)
194 | button.click(options.action);
195 | button.appendTo(this.buttonBar);
196 | this.buttons.push(button);
197 | this.resetButtonsPosition();
198 | },
199 | // 重新设置按钮位置
200 | resetButtonsPosition: function() {
201 | var positions = this.positions;
202 | jQuery.each(this.buttons, function(index, button) {
203 | button.css({
204 | left: positions[index].x,
205 | top: positions[index].y
206 | });
207 | });
208 | },
209 | // 获取当前页面下载地址
210 | getDownloadAddress: function() {
211 |
212 | if (!this.site) {
213 | //alert("站点信息未设置");
214 | system.showStatusMessage("站点信息未设置,请先设置站点信息。", 6);
215 | return [];
216 | }
217 |
218 | var urls;
219 | if (this.site.listAllTorrentUrlScript)
220 | {
221 | var _script = this.site.listAllTorrentUrlScript;
222 | _script = _script.replace("\$input-host\$",system.site.host);
223 | _script = _script.replace("\$input-passkey\$",system.site.passkey);
224 | urls = eval(_script);
225 | if ($.isArray(urls))
226 | {
227 | var _urls = [];
228 | $.each(urls,function(index,item){
229 | //item = item.replace("\$site\$",system.site.host);
230 | item = item.replace("\$host\$",system.site.host);
231 | item = item.replace("\$passkey\$",system.site.passkey);
232 | _urls.push(item);
233 | });
234 |
235 | urls = _urls;
236 | }
237 | }
238 | else
239 | {
240 | var torrents = jQuery("a[href*='download']").toArray();
241 | urls = jQuery.map(torrents, function(n) {
242 | return system.site.host + jQuery(n).attr("href") + "&passkey=" + system.site.passkey + (system.site.disableHttps?"":"&https=1");
243 | });
244 | }
245 |
246 |
247 | return urls;
248 | },
249 | showStatusMessage: function(msg, time) {
250 | if (!this.statusMessageBox) {
251 | this.statusMessageBox = $("").css({
252 | top: -500,
253 | width: "auto"
254 | }).attr("class", "status-messages").html(msg).appendTo($(document.body));
255 | }
256 |
257 | if (time == undefined) {
258 | time = 3000;
259 | } else {
260 | time = time * 1000;
261 | }
262 |
263 | this.statusMessageBox.html(msg);
264 |
265 | var top = jQuery(window).height() - this.statusMessageBox.height() - 30;
266 | var left = jQuery(window).width() - this.statusMessageBox.width() - 50;
267 | this.statusMessageBox.css({
268 | top: top + "px",
269 | left: left + "px"
270 | });
271 |
272 | if (time == 0) {
273 | this.statusMessageBox.stop().show();
274 | } else {
275 | this.statusMessageBox.stop().show().fadeOut(time);
276 | }
277 | },
278 | // 初始化当前站点菜单
279 | initSiteMenus: function() {
280 | if (!this.site) return;
281 | // 创建当前站点菜单
282 | chrome.extension.sendMessage({
283 | action: "create-site-contextmenu",
284 | site: this.site
285 | });
286 | },
287 | requestMessage: function(message, callback) {
288 | switch (message.action.toLowerCase()) {
289 | case "show-message":
290 | this.showStatusMessage(message.content, message.time);
291 | if (callback) {
292 | callback();
293 | }
294 | break;
295 |
296 | case "get-detail-page-torrent-url":
297 | var _script = message.script;
298 | _script = _script.replace("\$input-host\$",system.site.host);
299 | _script = _script.replace("\$input-passkey\$",system.site.passkey);
300 | var url = eval(_script);
301 | if (callback) {
302 | callback(url);
303 | }
304 | break;
305 |
306 | case "run-script":
307 | var _script = message.script;
308 | _script = _script.replace("\$input-host\$",system.site.host);
309 | _script = _script.replace("\$input-passkey\$",system.site.passkey);
310 | var result = eval(_script);
311 | if (callback) {
312 | callback(result);
313 | }
314 | break;
315 |
316 | }
317 | },
318 | initDrop: function() {
319 | if (!system.config.droptosend) return;
320 |
321 | this.droper.appendTo(this.shower);
322 | this.droper[0].addEventListener("dragover", function(e) {
323 | //console.log(e);
324 | e.stopPropagation();
325 | e.preventDefault();
326 | e.dataTransfer.dropEffect = "copy";
327 | if (e.target.tagName == "A") {
328 | e.dataTransfer.setData('text/plain', e.target.getAttribute('href'));
329 | }
330 |
331 | //console.log(e);
332 | //system.debug("#dropArea.dragover");
333 | }, false);
334 |
335 | this.shower[0].addEventListener("dragover", function(e) {
336 | e.stopPropagation();
337 | e.preventDefault();
338 | system.droper.show();
339 | }, false);
340 |
341 | this.droper[0].addEventListener("drop", function(e) {
342 | //console.log(e);
343 | e.stopPropagation();
344 | e.preventDefault();
345 | system.droper.hide();
346 | if (!system.site)
347 | {
348 | system.showStatusMessage("请先设置站点信息。");
349 | return;
350 | }
351 |
352 | if (!system.site.passkey) {
353 | system.showStatusMessage("请先设置站点密钥(Passkey)。");
354 | return;
355 | }
356 |
357 | var url = e.dataTransfer.getData('text/plain');
358 | if (url) {
359 | if (system.site.dropScript)
360 | {
361 | var _script = system.site.dropScript.replace("\$input-url\$",url);
362 | _script = _script.replace("\$input-host\$",system.site.host);
363 | _script = _script.replace("\$input-passkey\$",system.site.passkey);
364 |
365 | url = eval(_script);
366 | //url = url.replace("\$site\$",system.site.host);
367 | url = url.replace("\$host\$",system.site.host);
368 | url = url.replace("\$passkey\$",system.site.passkey);
369 | }
370 | else
371 | {
372 | id = url.getQueryString("id");
373 | if (id) {
374 | if (system.site && system.config.droptosend) {
375 | // 如果站点没有配置禁用https,则默认添加https链接
376 | url = system.site.host + "download.php?id=" + id + "&passkey=" + system.site.passkey + (system.site.disableHttps?"":"&https=1");
377 | }
378 | }
379 | }
380 | console.log(url);
381 | var folder = null;
382 | if (system.site.defaultFolder) {
383 | folder = system.site.defaultFolder;
384 | } else if (system.site.folders.length > 0) {
385 | folder = system.site.folders[0];
386 | }
387 |
388 | system.showStatusMessage("正在发送链接地址 " + (url.replace(system.site.passkey, "***")) + " 到下载服务器", 0);
389 | chrome.extension.sendMessage({
390 | action: "send-url-to-client",
391 | url: url,
392 | folder: folder
393 | }, function(result) {
394 | system.showStatusMessage(result.msg, 5);
395 | });
396 |
397 | }
398 | //console.log(e.dataTransfer.getData('text/plain'));
399 | //system.debug("drop.e.dataTransfer:",e.dataTransfer);
400 | //system.checkDropFiles(e.dataTransfer.files);
401 | }, false);
402 |
403 | this.droper[0].addEventListener("dragleave", function(e) {
404 | e.stopPropagation();
405 | e.preventDefault();
406 | system.droper.hide();
407 | //system.debug("dragleave");
408 | }, false);
409 | },
410 | getSize: function(source){
411 | var total = 0;
412 |
413 | $.each(source,function(index,item){
414 | var size = parseFloat($(item).text().replace(/[A-Za-z]/g,""));
415 | var unit = $(item).text().replace(/[^A-Za-z]/g,"");
416 | switch (unit)
417 | {
418 | case "MB":
419 | total +=(size*1048576);
420 | break;
421 |
422 | case "GB":
423 | total +=(size*1073741824);
424 | break;
425 |
426 | case "T":
427 | case "TB":
428 | total +=(size*1099511627776);
429 | break;
430 | }
431 | });
432 |
433 | return (total);
434 | },
435 | debug: function(label, msg) {
436 | console.log(label + ":" + msg);
437 | },
438 | test: function() {
439 | var parent = jQuery("a>img.uploading").parent().parent();
440 | var options = {
441 | ids: jQuery.map(parent.find("a[href*='download']").toArray(), function(n) {
442 | return jQuery(n).attr("href").replace("download.php?id=", "");
443 | })
444 | };
445 | }
446 | };
447 |
448 | // 获取参数
449 | chrome.extension.sendMessage({
450 | action: "read-config"
451 | }, function(config) {
452 | system.config = config;
453 | if (config.sites.length) {
454 | $.each(config.sites, function(index, item) {
455 | if (item.site == window.location.hostname) {
456 | system.site = item;
457 | system.site.host = window.location.protocol + "//" + window.location.host + "/";
458 | system.siteType = config.siteTypes[system.getSiteTypeIndex(item.type)];
459 | config.sites[index] = system.site;
460 | return;
461 | }
462 | });
463 | }
464 |
465 | // 优先使用站点类型配置的页面
466 | var pages = system.siteType.pluginIconShowPages || config.pluginIconShowPages;
467 |
468 | // 判断是否显示图标
469 | $.each(pages, function(index, item) {
470 | if (document.location.pathname.indexOf(item) != -1) {
471 | system.init();
472 | return;
473 | }
474 | });
475 | });
476 |
477 |
478 | chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
479 | system.requestMessage(message, sendResponse);
480 | return true;
481 | });
482 |
483 | // jQuery 扩展
484 | // 淡入谈出
485 | (function($) {
486 | $.fn.fadeInAndOut = function(speed, delay, easing, callback) {
487 | var options = null;
488 | if (typeof(speed) == "object") {
489 | options = speed;
490 | } else {
491 | options = {
492 | speed: speed,
493 | easing: easing,
494 | delay: delay,
495 | callback: callback
496 | };
497 | }
498 | options = $.extend($.fn.fadeInAndOut.defaults, options);
499 | return this.fadeIn(options.speed).delay(options.delay).fadeOut(options.speed, options.easing, options.callback);
500 | };
501 |
502 | // 插件的defaults
503 | $.fn.fadeInAndOut.defaults = {
504 | speed: 1000,
505 | easing: "swing",
506 | delay: 1000,
507 | callback: null
508 | };
509 | })(jQuery);
510 |
511 | //alert("sendMessage-begin");
512 | //chrome.extension.sendMessage(options);
513 | //alert("sendMessage-end");
--------------------------------------------------------------------------------
/src/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 参数设置
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
128 |
129 |
130 |
131 |
PT 助手 - 参数设置
132 |
133 |
134 |
135 |
136 |
137 |
138 |
148 |
195 |
196 |
页面规则
197 |
198 |
199 | | 种子列表页面规则: |
200 |
201 |
202 | |
203 |
204 |
205 | | 种子详情页面规则: |
206 |
207 |
208 | |
209 |
210 |
211 | | 种子链接规则: |
212 |
213 |
214 | |
215 |
216 |
217 |
多个规则用回车分隔
218 |
219 |
220 |
当前站点类型列表
221 |
276 |
277 |
278 |
279 |
280 | | 序号 |
281 | 名称 |
282 | 操作 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
343 |
当前站点列表
344 |
345 |
346 |
347 |
348 | | 序号 |
349 | 站点 |
350 | 类型 |
351 | 标签 |
352 | 搜索 |
353 | 不支持HTTPS |
354 | 操作 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
说明:服务器地址需要带上 http:// 或 https:// ,如:http://192.168.1.1;
365 |
370 |
371 |
服务器
372 |
392 |
当前目录对应列表
393 |
402 |
403 | - 站点不需要填写 http:// 或 https:// ,只需要填写域名,如:open.cd ;
404 | - 保存目录为当前站点对应的默认目录,添加新种子时,会自动指定到这个目录;
405 | - 如果站点下不添加任何目录,则以服务器设置的默认目录为准;
406 |
407 |
408 |
409 |
410 |
411 |
412 | | 序号 |
413 | 站点 |
414 | 保存目录 |
415 | 默认 |
416 | 操作 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
服务器
426 |
440 |
441 |
442 | 注:µTorrent 所有参数(如下载目录、是否自动开始等)以服务器上的设置为准。
443 |
444 |
445 |
446 |
服务器
447 |
461 |
462 |
463 | 注:Deluge 所有参数(如下载目录、是否自动开始等)以服务器上的设置为准。
464 |
465 |
466 |
467 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 | 注:备份文件为明文,其中可能包含个人信息,请注意保管。
495 |
496 |
497 |
500 |
501 |
502 |
503 |
504 |
--------------------------------------------------------------------------------
/src/script/background.js:
--------------------------------------------------------------------------------
1 | var system = {
2 | menus: {
3 | transmission: null,
4 | sites: {}
5 | },
6 | clients: {
7 | default: null,
8 | transmission: transmission,
9 | utorrent: utorrent,
10 | deluge: deluge
11 | },
12 | searchTabId: 0,
13 | optionsTabId: 0,
14 | // 配置信息
15 | config: {
16 | name: "zpz-pt-plugin-config",
17 | options: {
18 | droptosend: true,
19 | defaultclient: "transmission",
20 | exceedSizeToConfirm: false,
21 | exceedSize: 100,
22 | exceedSizeUnit: "GB",
23 | sites: [],
24 | transmission: {},
25 | utorrent: {},
26 | deluge: {},
27 | pluginIconShowPages: [
28 | "torrents.php"
29 | ],
30 | contextMenuRules: {
31 | torrentDetailPages: [
32 | "*://*/details.php*",
33 | "*://*/plugin_details.php*"
34 | ],
35 | torrentListPages: [
36 | "*://*/torrents.php*"
37 | ],
38 | torrentLinks: [
39 | "*://*/details.php*",
40 | "*://*/download.php*",
41 | "*://*/plugin_details.php*"
42 | ]
43 | },
44 | siteTypes: [],
45 | search: {
46 | rows: 5,
47 | key: "",
48 | tags: [],
49 | checkedTags: []
50 | },
51 | allowSelectionTextSearch: true
52 | },
53 | read: function(callback) {
54 | chrome.storage.local.get(this.name,
55 | function(result) {
56 | system.config.options = $.extend(true, system.config.options, result[system.config.name]);
57 | if (callback) {
58 | callback(system.config.options);
59 | }
60 | }
61 | );
62 | /*
63 | var local = window.localStorage[this.name];
64 | if (local)
65 | {
66 | var localOptions = JSON.parse(local);
67 | this.options = $.extend(true, this.options, localOptions);
68 | }*/
69 | },
70 | save: function() {
71 | //window.localStorage[this.name] = JSON.stringify(this.options);
72 | chrome.storage.local.set({
73 | "zpz-pt-plugin-config": this.options
74 | });
75 | //chrome.storage.sync.set({"zpz-nexusphp-plugin-config":this.options});
76 | },
77 | syncGet: function(callback) {
78 | chrome.storage.sync.get(this.name,
79 | function(result) {
80 | system.config.options = $.extend(true, system.config.options, result[system.config.name]);
81 | if (callback) {
82 | callback(system.config.options);
83 | }
84 | }
85 | );
86 | },
87 | syncSet: function(callback) {
88 | this.save();
89 | chrome.storage.sync.set({
90 | "zpz-pt-plugin-config": this.options
91 | },function(){
92 | if (callback) {
93 | callback(system.config.options);
94 | }
95 | });
96 | }
97 | },
98 | // 用于接收页面发送过的消息
99 | requestMessage: function(message, sender, callback) {
100 | switch (message.action.toLowerCase()) {
101 | // 复制内容到剪切板
102 | case "toclipboard":
103 | this.copyTextToClipboard(message.content);
104 | if (callback) {
105 | callback();
106 | }
107 | break;
108 |
109 | case "set-options-tabid":
110 | this.optionsTabId = message.id;
111 | break;
112 |
113 | case "open-options":
114 | if (this.optionsTabId==0)
115 | {
116 | chrome.tabs.create({
117 | url: "options.html"
118 | },function(tab){
119 | system.optionsTabId = tab.id;
120 | });
121 | }
122 | else
123 | {
124 | chrome.tabs.get(this.optionsTabId,function(tab){
125 | if (tab)
126 | {
127 | chrome.tabs.update(tab.id, { selected:true });
128 | }
129 | else
130 | {
131 | chrome.tabs.create({
132 | url: "options.html"
133 | },function(tab){
134 | system.optionsTabId = tab.id;
135 | });
136 | }
137 | });
138 | }
139 |
140 | break;
141 |
142 | case "read-config":
143 | this.config.read(function(result) {
144 | system.setDefaulteClient();
145 | if (callback) {
146 | callback(result);
147 | }
148 | });
149 |
150 | break;
151 |
152 | case "save-config":
153 | this.config.options = message.config;
154 | this.setDefaulteClient();
155 | this.config.save();
156 | this.initContextMenus();
157 | break;
158 |
159 | // 从 google 帐户中读取设置信息
160 | case "read-config-from-google":
161 | this.config.syncGet(function(result) {
162 | if (result)
163 | {
164 | system.setDefaulteClient();
165 | if (callback) {
166 | callback(result);
167 | }
168 | }
169 | else
170 | {
171 | if (callback) {
172 | callback(null);
173 | }
174 | }
175 |
176 | });
177 | break;
178 |
179 | // 将当前设置信息同步至 google 帐户
180 | case "save-config-to-google":
181 | this.config.options = message.config;
182 | this.setDefaulteClient();
183 | this.config.syncSet(function(){
184 | if (callback) {
185 | callback();
186 | }
187 | });
188 | this.initContextMenus();
189 | break;
190 |
191 | case "create-site-contextmenu":
192 | this.createSiteFolderContextMenus(message.site);
193 | break;
194 |
195 | case "send-url-to-client":
196 | this.sendUrlToClient(message.url, message.folder, function(data) {
197 | if (callback) {
198 | callback(data);
199 | }
200 | });
201 | break;
202 | case "send-url-to-transmission":
203 | this.sendUrlToTransmission(message.url, message.folder, function(data) {
204 | if (callback) {
205 | callback(data);
206 | }
207 | });
208 |
209 | case "open-client-webui":
210 | if (this.clients.default)
211 | {
212 | chrome.tabs.create({
213 | url: this.clients.default.webui
214 | });
215 | }
216 | break;
217 |
218 | case "set-search-tabid":
219 | this.searchTabId = message.id;
220 | break;
221 |
222 | case "search-torrent":
223 | this.config.options.search.key = message.key;
224 | this.config.save();
225 | if (this.searchTabId==0)
226 | {
227 | chrome.tabs.create({
228 | url: "search.html?key="+message.key
229 | },function(tab){
230 | system.searchTabId = tab.id;
231 | });
232 | }
233 | else
234 | {
235 | chrome.tabs.get(this.searchTabId,function(tab){
236 | if (tab)
237 | {
238 | chrome.tabs.update(tab.id, { selected:true });
239 | chrome.tabs.sendMessage(system.searchTabId, {
240 | action: "search-torrent",
241 | key: message.key
242 | });
243 | }
244 | else
245 | {
246 | chrome.tabs.create({
247 | url: "search.html?key="+message.key
248 | },function(tab){
249 | system.searchTabId = tab.id;
250 | });
251 | }
252 | });
253 |
254 | }
255 | break;
256 |
257 | }
258 | },
259 | setDefaulteClient: function()
260 | {
261 | this.clients.default = this.clients[this.config.options.defaultclient];
262 | this.clients.default.webui = this.config.options[this.config.options.defaultclient].webui;
263 | },
264 | init: function() {
265 | this.config.read(function(){
266 | system.initContextMenus();
267 | });
268 | },
269 | copyTextToClipboard: function(text) {
270 | var copyFrom = $('');
271 | copyFrom.text(text);
272 | $('body').append(copyFrom);
273 | copyFrom.select();
274 | document.execCommand('copy');
275 | copyFrom.remove();
276 | },
277 | initContextMenus: function() {
278 | chrome.contextMenus.removeAll();
279 | // 是否启用选择内容时搜索
280 | if (this.config.options.allowSelectionTextSearch)
281 | {
282 | // 选中内容进行搜索
283 | chrome.contextMenus.create({
284 | title: "搜索 \"%s\" 相关的种子",
285 | contexts: ["selection"],
286 | onclick: function(data, tab) {
287 | system.requestMessage({
288 | action: "search-torrent",
289 | key: data.selectionText
290 | });
291 | }
292 | });
293 | }
294 |
295 | // 复制下载地址
296 | chrome.contextMenus.create({
297 | title: "复制下载地址到剪切板",
298 | documentUrlPatterns: this.config.options.contextMenuRules.torrentListPages,
299 | targetUrlPatterns: this.config.options.contextMenuRules.torrentLinks,
300 | contexts: ["link"],
301 | onclick: function(data, tab) {
302 | //console.log(data.linkUrl);
303 | //console.log(tab.url);
304 | var _indexOf = -1;
305 | $.each(system.config.options.sites, function(index, item) {
306 | if (_indexOf != -1) return;
307 | _indexOf = tab.url.indexOf(item.site);
308 | if (_indexOf != -1) {
309 | if (item.dropScript)
310 | {
311 | var _script = item.dropScript.replace("\$input-url\$",data.linkUrl);
312 |
313 | chrome.tabs.sendMessage(tab.id, {
314 | action: "run-script",
315 | script: _script
316 | },function(address){
317 | address = address.replace("\$host\$",tab.url.substr(0, _indexOf) + item.site+"/");
318 | address = address.replace("\$passkey\$",item.passkey);
319 | system.requestMessage({
320 | action: "toclipboard",
321 | content: address
322 | });
323 | chrome.tabs.sendMessage(tab.id, {
324 | action: "show-message",
325 | content: address.replace(item.passkey, "***") + "已复制到剪切板。"
326 | });
327 | });
328 | }
329 | else
330 | {
331 | var address = tab.url.substr(0, _indexOf) + item.site + "/download.php?id=" + data.linkUrl.getQueryString("id") + "&passkey=" + item.passkey + (item.disableHttps?"":"&https=1");
332 |
333 | system.requestMessage({
334 | action: "toclipboard",
335 | content: address
336 | });
337 | chrome.tabs.sendMessage(tab.id, {
338 | action: "show-message",
339 | content: address.replace(item.passkey, "***") + "已复制到剪切板。"
340 | });
341 | }
342 | //console.log(address);
343 |
344 | return;
345 | }
346 | });
347 | if (_indexOf == -1) {
348 | chrome.tabs.sendMessage(tab.id, {
349 | action: "show-message",
350 | content: "站点信息未设置,请先设置站点信息。"
351 | });
352 | };
353 | }
354 | });
355 |
356 | // 种子详情页面
357 | chrome.contextMenus.create({
358 | title: "发送当前页面种子到下载服务器",
359 | documentUrlPatterns: this.config.options.contextMenuRules.torrentDetailPages,
360 | contexts: ["page"],
361 | onclick: function(data, tab) {
362 | //console.log(data.linkUrl);
363 | //console.log(tab.url);
364 | var _indexOf = -1
365 | $.each(system.config.options.sites, function(index, item) {
366 | if (_indexOf != -1) return;
367 | _indexOf = tab.url.indexOf(item.site);
368 | if (_indexOf != -1) {
369 | var address = "";
370 | var folder = null;
371 | if (item.defaultFolder) {
372 | folder = item.defaultFolder;
373 | } else if (item.folders.length > 0) {
374 | folder = item.folders[0];
375 | }
376 |
377 | if (item.detailScript) {
378 | chrome.tabs.sendMessage(tab.id, {
379 | action: "get-detail-page-torrent-url",
380 | script: item.detailScript
381 | }, function(url) {
382 | if (url) {
383 | url = url.replace("\$passkey\$", item.passkey);
384 | system.execSendUrlToClient(url, folder, tab);
385 | }
386 | });
387 | } else {
388 | // 如果站点没有配置禁用https,则默认添加https链接
389 | address = tab.url.substr(0, _indexOf) + item.site + "/download.php?id=" + tab.url.getQueryString("id") + "&passkey=" + item.passkey + (item.disableHttps?"":"&https=1");
390 | system.execSendUrlToClient(address, folder, tab);
391 | }
392 |
393 | return;
394 | }
395 | });
396 |
397 | if (_indexOf == -1) {
398 | chrome.tabs.sendMessage(tab.id, {
399 | action: "show-message",
400 | content: "站点信息未设置,请先设置站点信息。"
401 | });
402 | };
403 | }
404 | });
405 |
406 |
407 | },
408 | createContextMenus: function(options) {
409 | return chrome.contextMenus.create(options);
410 | },
411 | clearSiteFolderContextMenus: function(site) {
412 | if (this.menus.sites[site.site]) {
413 | $.each(this.menus.sites[site.site], function(index, item) {
414 | chrome.contextMenus.remove(item);
415 | });
416 | }
417 | },
418 | createSiteFolderContextMenus: function(site) {
419 | if (site == null) {
420 | return;
421 | }
422 | //this.clearSiteFolderContextMenus();
423 | if (this.menus.sites[site.site]) {
424 | if (this.menus.sites[site.site].length - 1 != site.folders.length) {
425 | this.clearSiteFolderContextMenus(site);
426 | this.menus.sites[site.site] = new Array();
427 | } else {
428 | return;
429 | }
430 | }
431 |
432 | var documentUrlPatterns = [];
433 | var targetUrlPatterns = [];
434 |
435 | $.each(this.config.options.contextMenuRules.torrentListPages,function(index,item){
436 | documentUrlPatterns.push(item.replace("\*:\/\/\*\/",site.host));
437 | });
438 |
439 | $.each(this.config.options.contextMenuRules.torrentLinks,function(index,item){
440 | targetUrlPatterns.push(item.replace("\*:\/\/\*\/",site.host));
441 | });
442 |
443 | var menus = new Array();
444 | if (site.folders.length <= 1) {
445 | createFolders(undefined, "发送到下载服务器 [%f]");
446 | } else {
447 | var parentId = this.createContextMenus({
448 | title: "发送到 Transmission ...",
449 | documentUrlPatterns: documentUrlPatterns,
450 | targetUrlPatterns: targetUrlPatterns,
451 | contexts: ["link"]
452 | });
453 |
454 | menus.push(parentId);
455 | createFolders(parentId);
456 | }
457 |
458 | this.menus.sites[site.site] = menus;
459 |
460 | function createFolders(parentId, format) {
461 | if (!format)
462 | format = "%f";
463 |
464 | if (site.folders.length == 0) {
465 | menus.push(system.createContextMenus({
466 | title: format.replace("%f", "默认目录"),
467 | documentUrlPatterns: documentUrlPatterns,
468 | targetUrlPatterns: targetUrlPatterns,
469 | contexts: ["link"],
470 | onclick: function(data, tab) {
471 | if (site.dropScript)
472 | {
473 | var _script = site.dropScript.replace("\$input-url\$",data.linkUrl);
474 |
475 | chrome.tabs.sendMessage(tab.id, {
476 | action: "run-script",
477 | script: _script
478 | },function(address){
479 | address = address.replace("\$host\$",site.host);
480 | address = address.replace("\$passkey\$",site.passkey);
481 | system.execSendUrlToClient(address, null, tab);
482 | });
483 | }
484 | else
485 | {
486 | var address = site.host + "download.php?id=" + data.linkUrl.getQueryString("id") + "&passkey=" + site.passkey;
487 | system.execSendUrlToClient(address, null, tab);
488 | }
489 | }
490 | }));
491 | return;
492 | }
493 | $.each(site.folders, function(index, folder) {
494 | menus.push(system.createContextMenus({
495 | parentId: parentId,
496 | title: format.replace("%f", folder),
497 | documentUrlPatterns: documentUrlPatterns,
498 | targetUrlPatterns: targetUrlPatterns,
499 | contexts: ["link"],
500 | onclick: function(data, tab) {
501 | if (site.dropScript)
502 | {
503 | var _script = site.dropScript.replace("\$input-url\$",data.linkUrl);
504 |
505 | chrome.tabs.sendMessage(tab.id, {
506 | action: "run-script",
507 | script: _script
508 | },function(address){
509 | address = address.replace("\$host\$",site.host);
510 | address = address.replace("\$passkey\$",site.passkey);
511 | system.execSendUrlToClient(address, folder, tab);
512 | });
513 | }
514 | else
515 | {
516 | var address = site.host + "download.php?id=" + data.linkUrl.getQueryString("id") + "&passkey=" + site.passkey;
517 | system.execSendUrlToClient(address, folder, tab);
518 | }
519 | }
520 | }));
521 | });
522 | };
523 |
524 | },
525 | execSendUrlToClient: function(address, folder, tab) {
526 | console.log(address);
527 |
528 | chrome.tabs.sendMessage(tab.id, {
529 | action: "show-message",
530 | content: "正在发送链接至下载服务器 ",
531 | time: 0
532 | });
533 |
534 | this.sendUrlToClient(address, folder, function(result) {
535 | chrome.tabs.sendMessage(tab.id, {
536 | action: "show-message",
537 | content: result.msg
538 | });
539 | });
540 | },
541 | sendUrlToClient: function(address, folder, callback) {
542 | var result = {
543 | status: "",
544 | msg: ""
545 | };
546 | switch (this.config.options.defaultclient) {
547 | case "transmission":
548 | this.sendUrlToTransmission(address, folder, function(data) {
549 | if (data) {
550 | if (data.id != undefined) {
551 | msg = data.name + " 已发送至 Transmission,编号:" + data.id;
552 | result.status = "success";
553 | } else if (data.status) {
554 | switch (data.status) {
555 | // 重复的种子
556 | case "duplicate":
557 | msg = data.torrent.name + " 种子已存在!编号:" + data.torrent.id;
558 | break;
559 |
560 | case "error":
561 | msg = "链接发送失败,请检查下载服务器是否可用。";
562 | break;
563 | default:
564 | msg = data.msg;
565 | break;
566 | }
567 | result.status = data.status;
568 | } else {
569 | msg = data;
570 | }
571 | result.msg = msg;
572 | }
573 | if (callback) {
574 | callback(result);
575 | }
576 | });
577 | break;
578 |
579 | case "utorrent":
580 | case "deluge":
581 | this.sendUrlToDefaultClient(address, folder, function(result) {
582 | if (callback) {
583 | callback(result);
584 | }
585 | });
586 | break;
587 |
588 | default:
589 | result.status = "client-undefiend";
590 | result.msg = "默认下载服务器未设置。";
591 | if (callback) {
592 | callback(result);
593 | }
594 | break;
595 | }
596 | },
597 | sendUrlToTransmission: function(address, folder, callback) {
598 | if (!transmission.isInitialized) {
599 | transmission.init({
600 | rpcpath: system.config.options.transmission.rpc,
601 | username: system.config.options.transmission.username,
602 | password: system.config.options.transmission.password
603 | }, function(result) {
604 | if (result) {
605 | if (result.status == "error") {
606 | callback(result);
607 | return;
608 | }
609 | }
610 | transmission.addTorrentFromUrl(address, folder, system.config.options.transmission.autostart, callback);
611 | });
612 | } else {
613 | transmission.addTorrentFromUrl(address, folder, system.config.options.transmission.autostart, callback);
614 | }
615 | },
616 | sendUrlToUTorrent: function(address, folder, callback) {
617 | if (!utorrent.isInitialized) {
618 | utorrent.init({
619 | gui: system.config.options.utorrent.gui,
620 | username: system.config.options.utorrent.username,
621 | password: system.config.options.utorrent.password
622 | }, function() {
623 | utorrent.addTorrentFromUrl(address, callback);
624 | });
625 | } else {
626 | utorrent.addTorrentFromUrl(address, callback);
627 | }
628 | },
629 | sendUrlToDefaultClient: function(address, folder, callback) {
630 | var client = this.clients.default;
631 | if (!client)
632 | return;
633 |
634 | var options = system.config.options[this.config.options.defaultclient];
635 |
636 | if (!client.isInitialized) {
637 | client.init({
638 | gui: options.gui,
639 | username: options.username,
640 | password: options.password
641 | }, function() {
642 | client.addTorrentFromUrl(address, callback);
643 | });
644 | } else {
645 | client.addTorrentFromUrl(address, callback);
646 | }
647 | }
648 | };
649 |
650 | // 监听由活动页面发来的消息事件
651 | chrome.extension.onMessage.addListener(function(message, sender, sendResponse) {
652 | system.requestMessage(message, sender, sendResponse);
653 | return true;
654 | });
655 |
656 |
657 | $(document).ready(function() {
658 | system.init();
659 | });
--------------------------------------------------------------------------------
/src/extension/base.css:
--------------------------------------------------------------------------------
1 | .plugin-body {
2 | position: fixed;
3 | display: block;
4 | left: 5px;
5 | top: 100px;
6 | height: 46px;
7 | width: 46px;
8 | opacity: 0.85;
9 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAC0NJREFUeNrsmXtsm9d1wH8fKYoUX5JISdaDlq1YmR+xF3mUmNBQ7aapval1Wk9JnEyOm6BOswbYEMAd+ufgFd0/LYJkWJGuBbK1jeemqualgFHUVdJYrmfZYmzLjmTLsiz5IVGybFIU39+D390fpGJFohTJdgYU2AEudPGJvOf3HZ57zrnnSkII/hTFwJ+oFMxMJEniXqwvSZIR2AY0A5uAOofDsS4Wi9kAHA5HIhaLDQAjwEWgC+gSQmTuQdcnjAX3+saSJG0C/s7tdj+7bdu2a7t37572er2WyspKm81mQ5IkAIQQJBIJ28TEhOf8+fNlhw4deqqrq2u1JEm/Bn4shOi9JwAhxCdvMTNfbAAb2traAl6vd/D06dPHdV0Pi2WKruvh06dPH/f7/QNtbW0BYNMSdd+dLxUcKAR+sHnz5qFgMBgQD0iCwWDA6/UOAj8ACh8oOFC+c+fOc0ePHj0mhMh8ynqKIlIXLojbP/yhuPnii+Larl3i5je/KW6//rpInTsndE1bCn/m6NGjx3bu3HkOcPUtwLIscGBTXV3dWCgU6p2rTQ0GRfC110Sf0ykumc3iSkmJGCotFYNOp7hoMom+0lIx/t3vCnViYknWD4VCvXV1dWMLuc6SwQGf1+sdVFV1bK4SeXhYXH3iCdFfWCiCGzaIREuL0J55RmRaW4X6la+I2GOPidGaGtFnMIirX/yiUG7cWBK8qqpjOdfxLQYuzTyYGw4lSapfv379+319fQ6DweCavaH1RILRPXtIvv8+nq1bsW/eDEYj3LwJ09OQyYCuQzpN5Pp1gsPD2HftYuXBg0gWy2cGDF3Xwxs3boxdunTpy0KIoXzh0LBAqCv0+/1HAoFAei40wHR7O9EjR6huasK+fj04neBwgMUCySQkEhCPg6JQUlFBRWUl0cOHif7mN0vLigaDKxAIpP1+/xFJkgqXkzm/f+DAgQmbzbZ2njWSSSIdHRR7PDhqayEUgnAYIpHsXFWzQ1EglYJUCldxMVazmamf/xyRWVresdlsaw8cODABfH/RzDnL2g1+v/9rO3bseDjfF5ThYZQrV3DV1CBB1rJTU3dhM5nsUFXQNFAUDLqO3WIh/PHHaOPjmDyeJcHv2LHjC36/v1KSpENzE9U8i+/du/en7e3tsYV+DX16GmIxCkymLOjMmAGdeYE5f02ShB6JkAmHl1VLtbe3x/bu3fvTRV1FkqSGoaEhp8fjaVxwKaMRjEb0dBpk+a5rzAxZ/vQL5YauaWA0IplMy8rsHo+ncWhoyClJUsNiFn/1zTffnFxsIVNVFYbyclLhcBZqxsoz0Dn3mPtrpNJpzNXVmKqqll2W5JheXQi80O12P9vU1LRx0XLS48Hq8zE9OooaidwFnbH+bNdRVchkSCWTJFWVoqe+jqGkZNngTU1NG91u97NAUT5wn8/nuylJUumiVaHRSOlLL5EpLeXW4CB6KpXdjLP9ewY8k0FLpwnFYkQLbPTVPXmvlWipz+e7CXjzgW/ft2/fknaO1e+nfP9+IlNTjA0MIEciiNkbVNPQVZVUIsFodJpEoZnSf/xnzqVqOXv2zj3B59i25wuHDU1NTdalLuTevx9UlfAbb3DtyhVsJhN2axGSJKGpGklVJakoKNUe+jc+Q8PzL/OUCv/d3sfq1U5crsLluosV+GSDzk75/alUymyxWNYsZ8HzP/oVoYO/xHPrAsq1kZw5CihYtYpivx/7y69wfNRO72Qxf//Sak4cH2N4TPDqKzUYjQbk6SCGAjMme9mietLp9NWioiJZCPHIXPCQruvSZ/n4XPmvw9dxlVqoUCY4195Fy9YSLOVlGD0eLBs3gsFAKpXhrbf6qKux8+WvruFXvzjHSv09POZ+UtM3kIxmLO6HqH7sBVzrti904JkyGAxCCOGe6yr2mePWUkXTBLeCMTY8UsnYlBNtmxX3N+Yn3KIiI889V89bPxqhzHaKhsR3QO6nrGEt5odt6Kk0d0aOMXDo91Rv3c+qJ7+DJBnmblDboil/OaLKGlpCprrEzMfdV1hRblokkdj46xbB1Xdfxr8lzsqvfQuDsQDGRyCVxFXhJHItyMUPvofZWUmVb++S2xNxIURiqdDhZIYTl6a5qkj0jCcZC0axrlo8RldZr7C+PkjtE09isDqzp8FkGhJxpGSK0go7a+pLGfvjj/O5SgKI57P4hCzLZovFsqiPxxWdX56N8J9nInw0rqAIG2+338CpGHhxOMkjdQ7KbMY59bUgGEzS/4f3aHz0IaSMAsP92XifiOXifhoyKi6nhZvDF+bplWU5DMj5wIcmJycra2trF4wqkVSG194bp+NCnIfKS2lcVY7RaCQqZ7iVkHnjdJizEzI/e85DVbGJWFRhYCDMQP8UobCg/nYvhUV2SKezBw5FAU0FRc4OTcGUUTAZ5pe+k5OTIWAiH3hvIBDYWltbm9+fM4Lv/X6SI5dknmpczbpVFiJRGL8DxVYoL3Yw6XBwYjTIt9+9wb4aI9cHwpgsZhoeXcFfrXNx490a4pMjOFxlWWBVAVW+W5hpCloyharq8/QHAoEk0JvPxzvffvtt10LWPn0jyb8HojSurqK+yoKzBAqKIJKGaBoSMlgsZmpXVPPbKwof3lRp3bWO557fgMtt5YMPgvRcW8/toWC2htcUUNJZ6yu5uSoTDicQpRvm6c+xdeaz+Jmenp6VQoipfLH86OU4LruNFQ4r1yZgMg6hGKgCFB0UAaoG5kIzRpuTQWOGifEk3UeGuHM7Qd3DFWzb823SH/yRkXOXWV1fhZRRIaOClnWTSDjB0HiS2q/vmxfDe3p6VgJn8oGnQqHQrwOBwHqfz/eFueCXbys4rUUIA0SScCsGmsiCqwJUPTcEWKw2AoPXORaapLGxnEeb1lJSYgYg6vpX+g/uY7r7MlWVdizoaLLCVDTNRLSAiub91PhfnusmfaFQ6BKQypfyARr8fv+7J0+enHfW3P2LG1wMW9lQXca0nLNyJgurCZAzIOuQAcLTEVYWTBJ4rZ6iwvkHqXT4Gtf/8C9Erh5HKBF0TFjK1lDje4EV3r+Z9/ktW7Zc7u7ufh7ozdv0FEL07tmzJzY+Pv5RVVXVp05BD7lN/M9omqSWBVUyWXhNgKJloVUdNECRk6ypMueFBrC4VrP2mTdQE3eQp8cxFJixlj8MeTL36OjoR/X19eLkyZO9szP7vJUPHTr0raefftoBfGprf3WDk0giTjCSRJdyFs9ZXZ7xcSCRSiOnozy9qfgzk5jJVoa9ehPWij/LCw3ou3fvdrzzzjuvfGZ7QgjR293d/buurq4Ts5/7V1n5xl84uBwc49Z0Fj5DztJkfTuRThGbGuUv6y08++fO+27ed3V1neju7v5dvlZ03k5WriF0obOzk9m9lcm4xt92jPLbyynsjlIKzXaQjKS1DOlUHDkZYUutiZ89v5J6d+F9QScSicvbt2+nu7t7sxAiNY9xuS24aFrn306F+Y+eMHdSAiUjKDCAu8hA66Zi/mFb2byUv1xZSgtuQfDcM5/X6z146tQpW0FBQfUndYMmuDCe5qPRJONRDZfVSONKKw3VFuyF93etpGla8PHHH0+cOXPmBSFEz0JXKUtuM4fD4fPic5ZwOHz+gbSZZ/2vsqWl5XxnZ+e8xv4DkkxnZ+exlpaW80Dl53GV8rrX6x38nK5SXn/gVylzXaetrS3Q3Nx88X4vr5qbmy9+7pdXeRbxAj9xu93h1tbWsx0dHR+OjIycisVil+aCxuPxgZGRkVMdHR0ftra2nnW73WHgJ4B3mTrvH3zW94zAl4B/Ag43NzdfBMTs4ff7B4DDuc98CTDeo675Vyn/f5f/fyT/OwAaLn6WzRWFEgAAAABJRU5ErkJggg==);
10 | }
11 | .droper {
12 | height: 46px;
13 | width: 46px;
14 | border: 1px dotted #aaa;
15 | }
16 | .button-bar {
17 | position: fixed;
18 | }
19 |
20 | .button-bar .button {
21 | height: 32px;
22 | width: 32px;
23 | padding: 8.5px 8px;
24 | cursor: pointer;
25 | position: fixed;
26 | background: url(data:image/png;base64,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) no-repeat;
27 | }
28 |
29 | .link-copy {
30 | height: 16px;
31 | width: 16px;
32 | background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAgBJREFUeNqMk79rFEEcxd/M7V2QAzVFEOMFGwNiIGCjEdIEhYODmEawsFf8G4QQSCPYyqUWCdhY2qSQECSpInvFJYT8Ki6dZO8Sb2P29pfvu+4sm+UKv/AYZna/b95ndla9WFyEUmoewG0Mr+9hGB5EYYhypZIseO0fCHa3sP/LhxVFkazd+by0tOIFAQac+3w5imPYto1Pa2tv+VxR+8bRuv8EevIRxn5uQoszpWI2RjSIBgMMLi/hui76/T6+Li+v8Pkz9k0Wo409pFHAJooUCiWqYlk46nTQ2ttD+/gY75pNPKjVmmfd7gf2vKbu5U0sMWBpzWatNcAkv7n789lZ1GdmMqQ3cbxApIUikg58H5S0JgkSE/L/L1JmoNJmMZEDzCNdK5cxwtFxHHxcXcXTqalm27Zf7rRaRKBBhkAhxcgjiYlUo16HfKlqtYpv29u95Az81EClCFLyaQ0SCib/dtNJ6qsGfDmJnRqoXIKiyVUDz8sSSGy5VnI3ikh5k1KplBnog/V19BxnRCZmV15dGCSdO1wziphcS3rrT7d71zk5Ob8+Pf3eMN4aH3/8qtGYM0hp7iyJbO0bBOrMPTz8kl6OpGoTEzEncwapaCLrRNfu6Wli0Etl6mbfdb0MiYrlXsjZyAUTE0qwOxsbo9aQ3/dGEWlYRRcX5xxG/wowAC8cIjzfyA4lAAAAAElFTkSuQmCC) no-repeat;
33 | }
34 |
35 | .link-config {
36 | height: 16px;
37 | width: 16px;
38 | background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAy9JREFUeNp0U21IU2EUft7rdjdtuhFq9KWZJtMfmbrUHxkZ0a/CKOiHFFIGkf0QosysrBViGn1oZBhkQkFRUWIg/RFLQq02rfmxac2cpoZibua+7rZ7e99bVgSdy+V8Puec9z3nJdWXr4ARx3EyD4VC4HkeoihKlEAIYT7C7ItEfb9lGcUCqbGF/s+Y7Pf7EQgEsK+gQOZMZyCaZJbyZhbzb4KW5OR1OxMT1+4SBGGGgiSdVov3fX1gnOk+n09MSkpcui45KV+UxBYJ7AMULJvX61W7XPPIzspCbOyy6Pj4OHg8XkxNTiE3NxeRUZFwOBwkJjoGnW+74fJ858OXRPw8HmvvwvmKI3b7iPODxSIbBwes+DzyWW59fPyLrBPC4T31D3/6OFNtvFhcgE3YPacHxwDGi5V2SRJ1G9LWy5VpNGzDwxi0WmEbGoJf8FG7D8xP248ZqnltDyAoCSQEjt02O2NsbDQW3B7wSiVsNiscoyNPHz96mD9K+ahjDGqVCl6fHyo6IbU+Hi6NBoQjkoKNp6ioSG53emYaSl6JYDAI6+Dg9e6uzrdRWu3cqvjE3WFqDR4/fY6jR4rReL8Rhm/piJ6bhoJNoaGhAQkJCUhbnyaPRqFQYEN6RqEhK3siEEIh4aMQ0bwHZQdrcK3pAXKyc9Da1oq6W9UGQuMzGeh4aZmpgM6dVXe6XOjv70cgRG9ZrcPWqRpk7IgBxkYwpDyI22+CuFplNAwUN5lJ+ZkKeUmEgCDmbc4jq1avlOdLOLqNykiE7m3HxvyVwPgk4PyK+z3Lsb++z1B6+ow5RCRwv7ZwNkWfQvSpenyZnIQqXAPwGgh3NmOjXHkCcE2j0RwHd44RJ06dLedAoJQ4KFh1t9ttofu+pb29HR8sfc4g2nS128xQHTsMfPMAA3Vo6k2AP6ccKskHn9etiwgP/7PKN2/UHjKZTB29PT0vb9Zd29JQd9nwZGAFXnRQMKfF3d41OFBvNtgs75ymN12vbly/enjxLZCTp07LQnVVZRJ7FqXlFfZItxUBMUzihXnsTeWRXNJsKCkzmmsvnWNjWqAY++8E+D9l/iWb/xf0Q4ABALuHnKJqedMoAAAAAElFTkSuQmCC) no-repeat;
39 | }
40 |
41 | .link-download {
42 | height: 16px;
43 | width: 16px;
44 | background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAc9JREFUeNqUUz1IW1EU/u59TxqIRUGKBV2KLupg2slFBxfpolMH7VrQFBrQTVBEtHSrIBh/cOlQB1ct6iA6WWxFooQGpUUdFKdSBE1e3l/POc88IhgxFz7Oz3vfd+8591w1sdz7GUCcYKK8NTvyZilhuo4bf9nQGVFQZbH3/2zypgnTsW2TyUqVJ8A8tqY2DH1wto1yF/HEmrSxHuqege+78ARO4HuF2KXYk5wPtr4QF9YnA4G8lQeXbzsWXI9hE/IkYN/6DEeEPbEuqqP1EB4LWDkLGgYMXUGhX/rMHn3TBA/SL+aJQC6bpQQLmCUFdo+3cHRxGMZN9a/AvFuBHDQJ+Lr0GKRP9zDweiyM59bGwbxA4OaGz0RFUAn6fgH+OX22cScWXuEEdBFQWkl9xSKrO1/wI7Mp/tX1vzCfJXJN7TMkpjuT0gOtNGSOmFwksv1zBYNvP4n/PbMcCvT3jIqd+jocD25BB0OheSINTc024WkXbc1d+Dj/AbFY852Svu3OIpX6Je9Btfc+TVMTWko1MFoZxZNIBE2xF2EukzqBZVl/1+bPa1Rhsh5aXe+eJ/nFNrbW4ffBuey8sXj5Xj6ywGPQ0VeVJPhsi/P/BRgACUr8JeUZnYcAAAAASUVORK5CYII=) no-repeat;
45 | }
46 |
47 | .link-webui {
48 | height: 16px;
49 | width: 16px;
50 | background:url(data:image/png;base64,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) no-repeat;
51 | }
52 |
53 | .status-messages {
54 | padding:10px 10px 10px 25px;
55 | text-align:left;border:2px solid #FF9900;font-size:15px;
56 | margin-bottom: 2px;
57 | color:#555555;
58 | width:auto;
59 | position: fixed;
60 | display: inline-block;
61 | white-space: nowrap;
62 | background: #FFFFCC url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAkRJREFUeNqkU0trE1EUPncmM6YOTdqm04g2mPRBlMZaXfiAFh/gRlO0uFIpdVURFPeKG/EPCLpI3QguBEEUEjftohShWBdCI1i1RqloTGJjiU3GJJN7r+cmM2MVXeXAN9zH+c79zmMI5xyaMQmaNJf4xC/JIGEoAuAlBPbiUQ+iw75HqyG+Iz6g4JeoucAYwOht6jgI26l6/KdChy+MbB0a3eVu1buI5FIBOHBWq5YLuVx6Mf7q49zdZ5Uf2Sfov+QowIjb3B3BMwcuPjivebsCQKv4puFERmVqi+bp7h2Z6N4ycCzyPDbeUsp/iuHVl3oNKIejkdM3o1prWwDMIgDDAMz8C3hmGqB5OwORk9ejguMooAxCnduHwlAtOa9SVoSymYaKmYUaXQfGyo2qS25QdD0sOE6AGgOZM5Ngskg0oFRZRmIGU6O/2yWp1oqBaeaJ4GxU8DnzbiHl7+uJGOU3wLgJLnnzP9tGsE3Z1OuU4DhzQClMLzy8MbuWXc4oShuosue/+Lm6nkkmHs8KjqOAcVgprKbvzdy5RsPDx/cFdx/s09p97bIsK/U2NjoByZlH82/np19UioX7EoGVuiIxymN7JOj3E+jVwYfOh/B8AOFHKLb0yVuJyakr0SkMdDX1DfLxRQ5LX1kjgMjLthOD5I+cOSdS0Ef2h3S4LPaxOXb2fY5bd9yZRGKlozxNclFugU0NcKGidGSHlBjuJ+eQPIj7NUQeYdgKiFVQAdmCa8PavhN+ordiKAzkmqTZ3/mXAAMArODxrCCEdFgAAAAASUVORK5CYII=) no-repeat 5px 10px;
63 | }
--------------------------------------------------------------------------------
/src/jquery/jquery-ui-1.10.3.custom.min.css:
--------------------------------------------------------------------------------
1 | /*! jQuery UI - v1.10.3 - 2013-10-14
2 | * http://jqueryui.com
3 | * Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css, jquery.ui.theme.css
4 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
5 | * Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
6 |
7 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;min-height:0}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:21px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("images/animated-overlay.gif");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-tabs-loading a{cursor:text}.ui-tabs .ui-tabs-nav li a,.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_888888_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_2e83ff_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_cd0a0a_256x240.png)}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px}
--------------------------------------------------------------------------------
/src/script/options.js:
--------------------------------------------------------------------------------
1 | (function ($) {
2 | var system = {
3 | config: {
4 | sites: new Array(),
5 | siteTypes: new Array()
6 | },
7 | toptipsTimer: null,
8 | /**
9 | * 初始化
10 | */
11 | init: function () {
12 | $("#tabs").tabs();
13 | //$("#tabs li").removeClass( "ui-corner-top" ).addClass( "ui-corner-left" );
14 |
15 | $("#tab-clients").tabs();
16 | //$("#tab-clients li").removeClass( "ui-corner-left" ).addClass( "ui-corner-top" );
17 |
18 | chrome.tabs.getCurrent(function (tab) {
19 | system.sendMessage({
20 | action: "set-options-tabid",
21 | id: tab.id
22 | });
23 | });
24 |
25 | // 读取配置信息
26 | this.sendMessage({
27 | action: "read-config"
28 | }, function (config) {
29 | //alert(config.sites.length);
30 | system.config = config;
31 | system.initConfig();
32 | });
33 |
34 | this.initEvents();
35 | },
36 | /**
37 | * 初始化事件
38 | */
39 | initEvents: function () {
40 | $("button").on("click", function (event) {
41 | event.preventDefault();
42 | }).button();
43 |
44 | // 新增站点
45 | $("#button-add-new-site").click(function () {
46 | $("#table-site").show();
47 | system.initSiteTags();
48 | });
49 | $("#button-site-cancel").click(function () {
50 | $("#table-site").hide();
51 | $("#tab-sites").find("*[savedtoclear='1']").val("");
52 | });
53 |
54 | // 导入一个或多个站点信息
55 | $("#button-add-import-site").click(function () {
56 | system.loadFileContent("json", function (content) {
57 | system.importSites(content);
58 | });
59 | });
60 |
61 | // 保存新的站点
62 | $("#button-site-save").click(function () {
63 | var parent = $("#tab-sites");
64 | if (parent.find("#site").val() == "") {
65 | return;
66 | }
67 | var tags = $.map($("#siteTags input:checked"), function (n) {
68 | return $(n).attr("tag");
69 | });
70 |
71 | var site = {
72 | site: parent.find("#site").val(),
73 | passkey: parent.find("#passkey").val(),
74 | detailScript: parent.find("#detailScript").val(),
75 | listAllTorrentUrlScript: parent.find("#listAllTorrentUrlScript").val(),
76 | dropScript: parent.find("#dropScript").val(),
77 | folders: new Array(),
78 | type: parent.find("#type").val(),
79 | allowSearch: parent.find("#allowSearch").prop("checked"),
80 | tags: tags,
81 | disableHttps: parent.find("#disableHttps").prop("checked")
82 | };
83 |
84 | var siteIndex = system.getSiteIndex(site.site);
85 | if (siteIndex == -1) {
86 | system.config.sites.push(site);
87 | system.addSiteToRow(site);
88 | } else {
89 | var _config = system.config.sites[siteIndex];
90 | _config.passkey = site.passkey;
91 | _config.detailScript = site.detailScript;
92 | _config.listAllTorrentUrlScript = site.listAllTorrentUrlScript;
93 | _config.dropScript = site.dropScript;
94 | _config.type = site.type;
95 | _config.allowSearch = site.allowSearch;
96 | _config.tags = site.tags;
97 | _config.disableHttps = site.disableHttps;
98 | system.initSites();
99 | }
100 |
101 | system.saveConfig();
102 | site = null;
103 |
104 | parent.find("*[savedtoclear='1']").val("");
105 | $("#table-site").hide();
106 | });
107 |
108 | // 添加新的站点对应目录
109 | $("#button-add-new-site-folder").click(function () {
110 | var parent = $("#tab-transmission");
111 | if (parent.find("#site").val() == "") {
112 | return;
113 | }
114 | var item = {
115 | site: parent.find("#site").val(),
116 | folder: parent.find("#folder").val(),
117 | siteIndex: -1,
118 | defaultFolder: ""
119 | };
120 |
121 | item.siteIndex = system.getSiteIndex(item.site);
122 | if (item.siteIndex != -1) {
123 | if (system.config.sites[item.siteIndex].folders == undefined) {
124 | system.config.sites[item.siteIndex].folders = new Array();
125 | }
126 | system.config.sites[item.siteIndex].folders.push(item.folder);
127 | system.addSiteFolderToRow(item);
128 | system.saveConfig();
129 | }
130 |
131 | site = null;
132 |
133 | parent.find("*[savedtoclear='1']").val("");
134 | });
135 |
136 | // 保存配置信息
137 | $("#button-save").click(function () {
138 | system.saveConfig();
139 | });
140 |
141 | $("#button-close").click(function () {
142 | chrome.tabs.getSelected(null, function (tab) {
143 | chrome.tabs.remove(tab.id);
144 | });
145 | });
146 |
147 | $("#button-save-and-close").click(function () {
148 | system.saveConfig();
149 | chrome.tabs.getSelected(null, function (tab) {
150 | chrome.tabs.remove(tab.id);
151 | });
152 | });
153 |
154 | // 备份参数设置
155 | $("#button-config-bak").click(function () {
156 | system.saveFileAs("PT-plugin-config.json", JSON.stringify(system.config));
157 | });
158 |
159 | $("#button-config-restore-selectfile").click(function () {
160 | $("#file-restore").click();
161 | });
162 |
163 | // 备份参数设置至google帐户
164 | $("#button-config-sync-save").click(function () {
165 | var button = $(this);
166 | button.prop("disabled", true);
167 | system.sendMessage({
168 | action: "save-config-to-google",
169 | config: system.config
170 | }, function () {
171 | button.prop("disabled", false);
172 | system.showSuccessMsg("参数已备份至Google 帐户");
173 | });
174 | });
175 |
176 | // 从google帐户中恢复设置
177 | $("#button-config-sync-get").click(function () {
178 | var button = $(this);
179 | button.prop("disabled", true);
180 | system.sendMessage({
181 | action: "read-config-from-google"
182 | }, function (result) {
183 | debugger;
184 | if (result) {
185 | system.config = result;
186 | system.initConfig();
187 | system.saveConfig(true);
188 | system.showSuccessMsg("参数已从Google 帐户中恢复");
189 | } else {
190 | alert("加载失败或 Google 帐户中无配置信息。");
191 | }
192 |
193 | button.prop("disabled", false);
194 | });
195 | });
196 |
197 | $("#file-restore").change(function () {
198 | var restoreFile = $("#file-restore")[0];
199 | if (restoreFile.files.length > 0 && restoreFile.files[0].name.length > 0) {
200 | var r = new FileReader();
201 | r.onload = function (e) {
202 | if (confirm("确认要从这个文件中恢复配置吗?这将覆盖当前所有设置信息。")) {
203 | system.config = JSON.parse(e.target.result);
204 | system.initConfig();
205 | system.saveConfig(true);
206 | system.showSuccessMsg("参数已恢复");
207 | }
208 |
209 | };
210 | r.onerror = function () {
211 | system.showErrorMsg("配置信息加载失败");
212 | console.log("配置信息加载失败");
213 | };
214 | r.readAsText(restoreFile.files[0]);
215 | restoreFile.value = "";
216 | }
217 | });
218 |
219 | $("#button-add-new-site-type").click(function () {
220 | $("#table-site-type").show();
221 | });
222 |
223 | // 导入一个或多个站点类型信息
224 | $("#button-add-import-site-type").click(function () {
225 | system.loadFileContent("json", function (content) {
226 | system.importSiteTypes(content);
227 | });
228 | });
229 |
230 | // 保存站点类型
231 | $("#button-site-type-save").click(function () {
232 | var parent = $("#tab-site-types");
233 | if (parent.find("#name").val() == "") {
234 | return;
235 | }
236 |
237 | var fields = ["name", "searchPage", "searchResultType", "getSearchResultScript", "getTorrentTotalSizeScript", "pluginIconShowPages", "torrentListPages", "torrentDetailPages", "torrentLinks"];
238 | var item = {};
239 | $.each(fields, function (index, key) {
240 | var value = parent.find("#" + key).val();
241 | switch (key) {
242 | case "pluginIconShowPages":
243 | case "torrentListPages":
244 | case "torrentDetailPages":
245 | case "torrentLinks":
246 | value = value.split("\n");
247 | break;
248 | }
249 | item[key] = value;
250 | });
251 |
252 | var index = system.getSiteTypeIndex(item.name);
253 | if (index == -1) {
254 | system.config.siteTypes.push(item);
255 | } else {
256 | system.config.siteTypes[index] = item;
257 | }
258 | system.initSiteTypes();
259 | system.saveConfig();
260 | item = null;
261 |
262 | parent.find("*[savedtoclear='1']").val("");
263 | $("#table-site-type").hide();
264 | });
265 |
266 | $("#button-site-type-cancel").click(function () {
267 | $("#table-site-type").hide();
268 | $("#tab-site-types").find("*[savedtoclear='1']").val("");
269 | });
270 |
271 | // 添加分类标签
272 | $("#button-add-search-type-tag").click(function () {
273 | system.addSearchTypeTag($("#tag").val());
274 | $("#tag").val("");
275 | });
276 |
277 | $("#tag").on("keyup", function (e) {
278 | if (e.keyCode == 13) {
279 | system.addSearchTypeTag($("#tag").val());
280 | $("#tag").val("");
281 | }
282 | });
283 | },
284 | /**
285 | * 初始化配置信息
286 | */
287 | initConfig: function () {
288 | this.initBase();
289 | this.initSiteTypes();
290 | this.initSites();
291 | this.initSiteFolders();
292 | this.initTransmissionConfig();
293 | this.initUTorrentConfig();
294 | this.initDelugeConfig();
295 | this.initSearchConfig();
296 | },
297 | initBase: function () {
298 | $("#droptosend").prop("checked", this.config.droptosend);
299 | $("#defaultclient").prop("value", this.config.defaultclient);
300 | $("#allowSelectionTextSearch").prop("checked", this.config.allowSelectionTextSearch);
301 |
302 | $("#exceedSizeToConfirm").prop("checked", this.config.exceedSizeToConfirm);
303 | $("#exceedSize").prop("value", this.config.exceedSize);
304 | $("#exceedSizeUnit").prop("value", this.config.exceedSizeUnit);
305 |
306 | $("#pluginIconShowPages").val(this.config.pluginIconShowPages.join("\n"));
307 | $("#torrentDetailPages").val(this.config.contextMenuRules.torrentDetailPages.join("\n"));
308 | $("#torrentListPages").val(this.config.contextMenuRules.torrentListPages.join("\n"));
309 | $("#torrentLinks").val(this.config.contextMenuRules.torrentLinks.join("\n"));
310 | $("#version").html(chrome.app.getDetails().version);
311 | },
312 | initTransmissionConfig: function () {
313 | var inputs = $("#table-transmission-options").find("input");
314 | $.each(inputs, function (index, item) {
315 | switch (item.type.toLowerCase()) {
316 | case "text":
317 | case "password":
318 | case "textarea":
319 | $(item).val(system.config.transmission[item.id]);
320 | break;
321 | case "checkbox":
322 | $(item).prop("checked", system.config.transmission[item.id]);
323 | break;
324 | }
325 | });
326 | },
327 | initUTorrentConfig: function () {
328 | var inputs = $("#table-utorrent-options").find("input");
329 | $.each(inputs, function (index, item) {
330 | switch (item.type.toLowerCase()) {
331 | case "text":
332 | case "password":
333 | case "textarea":
334 | $(item).val(system.config.utorrent[item.id]);
335 | break;
336 | case "checkbox":
337 | $(item).prop("checked", system.config.utorrent[item.id]);
338 | break;
339 | }
340 | });
341 | },
342 | initDelugeConfig: function () {
343 | var inputs = $("#table-deluge-options").find("input");
344 | $.each(inputs, function (index, item) {
345 | switch (item.type.toLowerCase()) {
346 | case "text":
347 | case "password":
348 | case "textarea":
349 | $(item).val(system.config.deluge[item.id]);
350 | break;
351 | case "checkbox":
352 | $(item).prop("checked", system.config.deluge[item.id]);
353 | break;
354 | }
355 | });
356 | },
357 | // 初始化站点信息
358 | initSites: function () {
359 | $("#tbody-sites").empty();
360 | $.each(this.config.sites, function (index, item) {
361 | system.addSiteToRow(item);
362 | });
363 | },
364 | // 初始化站点类型
365 | initSiteTypes: function () {
366 | $("#tbody-site-types").empty();
367 | if (!this.config.siteTypes)
368 | this.config.siteTypes = new Array();
369 | $.each(this.config.siteTypes, function (index, item) {
370 | system.addSiteTypeToRow(item);
371 | });
372 | var siteType = $("#table-site").find("#type");
373 | siteType.empty();
374 |
375 | $("").val("").text("").appendTo(siteType);
376 | $.each(this.config.siteTypes, function (index, item) {
377 | $("").val(item.name).text(item.name).appendTo(siteType);
378 | });
379 | },
380 | // 初始化站点对应的目录列表
381 | initSiteFolders: function () {
382 | $("#tbody-site-folders").empty();
383 | $.each(this.config.sites, function (i, site) {
384 | if (site.folders && $.isArray(site.folders)) {
385 | $.each(site.folders, function (index, item) {
386 | system.addSiteFolderToRow({
387 | site: site.site,
388 | folder: item,
389 | siteIndex: i
390 | });
391 | });
392 | }
393 | });
394 | },
395 | // 初始化搜索分类标签
396 | initSearchConfig: function () {
397 | $("#search-type-tags").empty();
398 | $.each(this.config.search.tags, function (index, item) {
399 | system.addSearchTypeTag(item, true);
400 | });
401 |
402 | $("#rows").val(this.config.search.rows);
403 | },
404 | // 初始化站点标签
405 | initSiteTags: function (site) {
406 | var tags = {};
407 | if (site) {
408 | if ($.isArray(site.tags)) {
409 | $.each(site.tags, function (index, item) {
410 | tags[item] = true;
411 | });
412 | }
413 | }
414 |
415 | var parent = $("#siteTags");
416 | parent.empty();
417 |
418 | $.each(this.config.search.tags, function (index, item) {
419 | $("").attr("tag", item).prop("checked", (tags[item] ? true : false)).appendTo(parent);
420 | $("").html(item).appendTo(parent);
421 | });
422 | },
423 | /**
424 | * 导入站点类型
425 | */
426 | importSiteTypes: function(data) {
427 | var item = data;
428 | if (typeof (data) === "string") {
429 | try {
430 | item = JSON.parse(data);
431 | } catch (error) {
432 | this.showErrorMsg("JSON文件解析失败!");
433 | return;
434 | }
435 | }
436 |
437 | if ($.isArray(item)) {
438 | this.importSiteTypes(item);
439 | return;
440 | }
441 |
442 | // 验证数据是否正确
443 | if (item.hasOwnProperty("name") && item.hasOwnProperty("searchPage") && item.hasOwnProperty("searchResultType")) {
444 | var index = this.getSiteTypeIndex(item.name);
445 | if (index == -1) {
446 | this.config.siteTypes.push(item);
447 | this.saveConfig(true);
448 | this.addSiteTypeToRow(item);
449 | } else {
450 | this.showErrorMsg("要导入的站点类型:" + item.name + " 已存在。");
451 | }
452 | }
453 | },
454 | /**
455 | * 导入站点
456 | */
457 | importSites: function (data) {
458 | var item = data;
459 | if (typeof (data) === "string") {
460 | try {
461 | item = JSON.parse(data);
462 | } catch (error) {
463 | this.showErrorMsg("JSON文件解析失败!");
464 | return;
465 | }
466 | }
467 |
468 | if ($.isArray(item)) {
469 | this.importSites(item);
470 | return;
471 | }
472 |
473 | // 验证数据是否正确
474 | if (item.hasOwnProperty("site") && item.hasOwnProperty("type")) {
475 | var index = this.getSiteIndex(item.site);
476 | if (index == -1) {
477 | this.config.sites.push(item);
478 | this.saveConfig(true);
479 | this.addSiteToRow(item);
480 | } else {
481 | this.showErrorMsg("要导入的站点:" + item.site + " 已存在。");
482 | }
483 | }
484 | },
485 | // 添加站点类型到列表
486 | addSiteTypeToRow: function (rowData) {
487 | var body = $("#tbody-site-types");
488 | var index = body[0].rows.length + 1;
489 | var row = $("
").appendTo(body);
490 |
491 | // 序号
492 | $(" | ").css("textAlign", "center").html(index).appendTo(row);
493 | $(" | ").html(rowData.name).appendTo(row);
494 | var cell = $(" | ").css("textAlign", "center").appendTo(row);
495 | $("").html("修改")
496 | .data("index", index - 1)
497 | .click(function () {
498 | var parent = $("#tab-site-types");
499 | var fields = ["name", "searchPage", "searchResultType", "getSearchResultScript", "getTorrentTotalSizeScript", "pluginIconShowPages", "torrentListPages", "torrentDetailPages", "torrentLinks"];
500 | var index = $(this).data("index");
501 | var data = system.config.siteTypes[index];
502 | $.each(fields, function (index, key) {
503 | var value = data[key]||"";
504 | if (value) {
505 | switch (key) {
506 | case "pluginIconShowPages":
507 | case "torrentListPages":
508 | case "torrentDetailPages":
509 | case "torrentLinks":
510 | if ($.isArray(value)) {
511 | value = value.join("\n");
512 | }
513 | break;
514 | }
515 | }
516 | parent.find("#" + key).val(value);
517 | });
518 | $("#table-site-type").show();
519 | })
520 | .appendTo(cell);
521 |
522 | $("").html("删除")
523 | .data("index", index - 1)
524 | .click(function () {
525 | var index = $(this).data("index");
526 | system.config.siteTypes = $.grep(system.config.siteTypes, function (n, i) {
527 | return i != index;
528 | });
529 | system.initSiteTypes();
530 | system.saveConfig();
531 | })
532 | .appendTo(cell);
533 |
534 | $("").html("分享")
535 | .data("index", index - 1)
536 | .click(function () {
537 | var index = $(this).data("index");
538 | var item = JSON.parse(JSON.stringify(system.config.siteTypes[index]));
539 |
540 | system.saveFileAs(item.name + ".json", JSON.stringify(item));
541 | })
542 | .appendTo(cell);
543 | },
544 | // 添加站点到列表
545 | addSiteToRow: function (site) {
546 | var body = $("#tbody-sites");
547 | var rowIndex = body[0].rows.length + 1;
548 | var row = $("
").appendTo(body);
549 |
550 | // 序号
551 | $(" | ").css("textAlign", "center").html(rowIndex).appendTo(row);
552 | $(" | ").html(site.site).appendTo(row);
553 | $(" | ").html(site.type).appendTo(row);
554 | //$(" | ").html(site.passkey).appendTo(row);
555 | var tagCell = $(" | ").appendTo(row);
556 |
557 | function initTags() {
558 | var tags = {};
559 | if ($.isArray(site.tags)) {
560 | $.each(site.tags, function (index, item) {
561 | tags[item] = true;
562 | });
563 | }
564 |
565 | $.each(system.config.search.tags, function (index, item) {
566 | $("")
567 | .attr("tag", item)
568 | .prop("checked", (tags[item] ? true : false))
569 | .click(function () {
570 | site.tags = $.map($("#td_site_" + rowIndex + " input:checked"), function (n) {
571 | return $(n).attr("tag");
572 | });
573 | system.saveConfig();
574 | })
575 | .appendTo(tagCell);
576 | $("").html(item).appendTo(tagCell);
577 | });
578 | }
579 | initTags();
580 |
581 | // 允许搜索
582 | $("").prop("checked", site.allowSearch)
583 | .click(function () {
584 | system.config.sites[rowIndex - 1].allowSearch = this.checked;
585 | system.saveConfig();
586 | //system.initSites();
587 | })
588 | .appendTo($(" | ").css("textAlign", "center").appendTo(row));
589 |
590 | // 禁用HTTPS
591 | $("").prop("checked", site.disableHttps)
592 | .click(function () {
593 | system.config.sites[rowIndex - 1].disableHttps = this.checked;
594 | system.saveConfig();
595 | //system.initSites();
596 | })
597 | .appendTo($(" | ").css("textAlign", "center").appendTo(row));
598 |
599 | var cell = $(" | ").css("textAlign", "center").appendTo(row);
600 | $("").html("修改")
601 | .data("index", rowIndex - 1)
602 | .click(function () {
603 | var parent = $("#tab-sites");
604 | var fields = ["site", "passkey", "detailScript", "listAllTorrentUrlScript", "dropScript", "type", "allowSearch", "disableHttps"];
605 | var index = $(this).data("index");
606 | var site = system.config.sites[index];
607 | $.each(fields, function (index, item) {
608 | switch (item) {
609 | case "allowSearch":
610 | parent.find("#" + item).prop("checked", site[item]);
611 | break;
612 |
613 | case "disableHttps":
614 | if (site[item] === undefined) {
615 | site[item] = false;
616 | }
617 | parent.find("#" + item).prop("checked", site[item]);
618 | break;
619 |
620 | default:
621 | parent.find("#" + item).val(site[item]);
622 | break;
623 | }
624 |
625 | });
626 | system.initSiteTags(site);
627 | $("#table-site").show();
628 | })
629 | .appendTo(cell);
630 |
631 | $("").html("删除")
632 | .data("index", rowIndex - 1)
633 | .click(function () {
634 | var index = $(this).data("index");
635 | system.config.sites = $.grep(system.config.sites, function (n, i) {
636 | return i != index;
637 | });
638 | system.initSites();
639 | system.saveConfig();
640 | })
641 | .appendTo(cell);
642 |
643 | $("").html("分享")
644 | .data("index", rowIndex - 1)
645 | .click(function () {
646 | var index = $(this).data("index");
647 | var item = JSON.parse(JSON.stringify(system.config.sites[index]));
648 | delete item.passkey;
649 | delete item.defaultFolder;
650 | delete item.folders;
651 |
652 | system.saveFileAs(item.site + ".json", JSON.stringify(item));
653 | })
654 | .appendTo(cell);
655 | },
656 | // 添加站点目录到列表
657 | addSiteFolderToRow: function (item) {
658 | var body = $("#tbody-site-folders");
659 | var index = body[0].rows.length + 1;
660 | var row = $("
").appendTo(body);
661 | var site = this.config.sites[item.siteIndex];
662 | // 序号
663 | $(" | ").css("textAlign", "center").html(index).appendTo(row);
664 | $(" | ").html(item.site).appendTo(row);
665 | $(" | ").html(item.folder).appendTo(row);
666 | // 默认
667 | $("").prop("checked", (site.defaultFolder == item.folder ? true : false))
668 | .click(function () {
669 | if (this.checked)
670 | system.config.sites[item.siteIndex].defaultFolder = item.folder;
671 | else
672 | system.config.sites[item.siteIndex].defaultFolder = undefined;
673 |
674 | system.saveConfig();
675 | system.initSiteFolders();
676 | })
677 | .appendTo($(" | ").css("textAlign", "center").appendTo(row));
678 |
679 | $("").html("删除")
680 | .data("index", index - 1)
681 | .click(function () {
682 | var index = $(this).data("index");
683 | system.config.sites[item.siteIndex].folders = $.grep(system.config.sites[item.siteIndex].folders, function (n, i) {
684 | return n != item.folder;
685 | });
686 |
687 | system.initSiteFolders();
688 | system.saveConfig();
689 | })
690 | .appendTo($(" | ").css("textAlign", "center").appendTo(row));
691 | },
692 | // 添加搜索分类标签
693 | addSearchTypeTag: function (name, addListOnly) {
694 | if (!name) return;
695 | var parent = $("#search-type-tags");
696 |
697 | if (!addListOnly) {
698 | if ($.inArray(name, this.config.search.tags) != -1)
699 | return;
700 |
701 | this.config.search.tags.push(name);
702 | this.saveConfig();
703 | }
704 |
705 | $("")
706 | .attr("name", name)
707 | .attr("href", "javascript:void(0);")
708 | .attr("title", "点击删除")
709 | .html(name)
710 | .click(function () {
711 | system.removeSearchTypeTag(name);
712 | })
713 | .appendTo(parent);
714 |
715 | this.initSites();
716 | },
717 | // 移除搜索分类标签
718 | removeSearchTypeTag: function (name) {
719 | this.config.search.tags = $.grep(this.config.search.tags, function (n, i) {
720 | return n != name;
721 | });
722 |
723 | $.each(this.config.sites, function (index, item) {
724 | if (!$.isArray(item.tags)) return;
725 | item.tags = $.grep(item.tags, function (n, i) {
726 | return n != name;
727 | });
728 | });
729 | this.saveConfig();
730 | $("#search-type-tags").find("a[name='" + name + "']").remove();
731 | this.initSites();
732 | },
733 | getSiteIndex: function (sitename) {
734 | var siteindex = -1;
735 | $.each(this.config.sites, function (index, item) {
736 | if (item.site == sitename) {
737 | siteindex = index;
738 | return;
739 | }
740 | });
741 |
742 | return siteindex;
743 | },
744 | getSiteTypeIndex: function (name) {
745 | var resultIndex = -1;
746 | $.each(this.config.siteTypes, function (index, item) {
747 | if (item.name == name) {
748 | resultIndex = index;
749 | return;
750 | }
751 | });
752 |
753 | return resultIndex;
754 | },
755 | sendMessage: function (options, callback) {
756 | if (callback) {
757 | chrome.extension.sendMessage(options, callback);
758 | } else {
759 | chrome.extension.sendMessage(options);
760 | }
761 | },
762 | /**
763 | * 保存参数
764 | * @param saveOnly 是否仅保存,默认为 false ,表示配置从当前窗口对应的元素中获取值
765 | */
766 | saveConfig: function (saveOnly) {
767 | if (!saveOnly) {
768 | // 客户端设置
769 | var parent = $("#tab-transmission");
770 |
771 | this.config.transmission = {
772 | server: parent.find("#server").val(),
773 | port: parent.find("#port").val(),
774 | username: parent.find("#username").val(),
775 | password: parent.find("#password").val(),
776 | rpc: parent.find("#server").val() + ":" + parent.find("#port").val() + "/transmission/rpc",
777 | autostart: parent.find("#autostart").prop("checked"),
778 | webui: parent.find("#server").val() + ":" + parent.find("#port").val() + "/transmission/web/"
779 | };
780 |
781 | parent = $("#table-utorrent-options");
782 |
783 | this.config.utorrent = {
784 | server: parent.find("#server").val(),
785 | port: parent.find("#port").val(),
786 | username: parent.find("#username").val(),
787 | password: parent.find("#password").val(),
788 | gui: parent.find("#server").val() + ":" + parent.find("#port").val() + "/gui/",
789 | webui: parent.find("#server").val() + ":" + parent.find("#port").val() + "/gui/"
790 | };
791 |
792 | parent = $("#table-deluge-options");
793 |
794 | this.config.deluge = {
795 | server: parent.find("#server").val(),
796 | port: parent.find("#port").val(),
797 | password: parent.find("#password").val(),
798 | gui: parent.find("#server").val() + ":" + parent.find("#port").val() + "/json",
799 | webui: parent.find("#server").val() + ":" + parent.find("#port").val() + ""
800 | };
801 |
802 | this.config.droptosend = $("#droptosend").prop("checked");
803 | this.config.defaultclient = $("#defaultclient").prop("value");
804 | this.config.allowSelectionTextSearch = $("#allowSelectionTextSearch").prop("checked");
805 |
806 | this.config.exceedSizeToConfirm = $("#exceedSizeToConfirm").prop("checked");
807 | this.config.exceedSize = $("#exceedSize").prop("value");
808 | this.config.exceedSizeUnit = $("#exceedSizeUnit").prop("value");
809 |
810 | this.config.pluginIconShowPages = $("#pluginIconShowPages").val().split("\n");
811 | this.config.contextMenuRules.torrentDetailPages = $("#torrentDetailPages").val().split("\n");
812 | this.config.contextMenuRules.torrentListPages = $("#torrentListPages").val().split("\n");
813 | this.config.contextMenuRules.torrentLinks = $("#torrentLinks").val().split("\n");
814 | this.config.search.rows = $("#rows").val();
815 | }
816 |
817 | this.sendMessage({
818 | action: "save-config",
819 | config: this.config
820 | });
821 | },
822 | /**
823 | * 将指定的内容保存为文件
824 | * @param fileName 文件名
825 | * @param fileData 文件内容
826 | */
827 | saveFileAs: function (fileName, fileData) {
828 | try {
829 | var Blob = window.Blob || window.WebKitBlob;
830 |
831 | // Detect availability of the Blob constructor.
832 | var constructor_supported = false;
833 | if (Blob) {
834 | try {
835 | new Blob([], {
836 | "type": "text/plain"
837 | });
838 | constructor_supported = true;
839 | } catch (_) {}
840 | }
841 |
842 | var b = null;
843 | if (constructor_supported) {
844 | b = new Blob([fileData], {
845 | "type": "text/plain"
846 | });
847 | } else {
848 | // Deprecated BlobBuilder API
849 | var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder;
850 | var bb = new BlobBuilder();
851 | bb.append(fileData);
852 | b = bb.getBlob("text/plain");
853 | }
854 |
855 | saveAs(b, fileName);
856 | } catch (e) {
857 | console.log(e.toString());
858 | }
859 | },
860 | showStatusMessage: function (msg, time, status) {
861 | time = time || 3000;
862 | status = status || "success";
863 | if (!this.toptips) {
864 | this.toptips = $("").appendTo(document.body);
865 | }
866 | clearTimeout(this.toptipsTimer);
867 | this.toptips.html(msg).show();
868 | this.toptipsTimer = setTimeout(function () {
869 | system.toptips.hide()
870 | }, time);
871 | },
872 | showSuccessMsg: function (msg, time) {
873 | this.showStatusMessage(msg, time, "success");
874 | },
875 | showErrorMsg: function (msg, time) {
876 | this.showStatusMessage(msg, time, "warn");
877 | },
878 | /**
879 | * 加载指定的文件内容
880 | */
881 | loadFileContent: function (fileType, callback) {
882 | $("").on("change", function () {
883 | var fileSelector = this;
884 | if (fileSelector.files.length > 0 && fileSelector.files[0].name.length > 0) {
885 | var files = fileSelector.files;
886 | var count = files.length;
887 | var index = 0;
888 | var r = new FileReader();
889 | r.onload = function (e) {
890 | callback && callback.call(system, e.target.result);
891 | readFile();
892 | };
893 | r.onerror = function () {
894 | system.showErrorMsg("文件加载失败");
895 | console.log("文件加载失败");
896 | readFile();
897 | };
898 |
899 | function readFile(file) {
900 |
901 | if (index == count) {
902 | $(fileSelector).remove();
903 | fileSelector.value = "";
904 | return;
905 | }
906 | var file = files[index];
907 | var lastIndex = file.name.lastIndexOf(".");
908 | var fix = file.name.substr(lastIndex + 1);
909 |
910 | index++;
911 |
912 | if (fileType) {
913 | if (fix != fileType) {
914 | system.showErrorMsg("文件类型错误");
915 | return;
916 | }
917 | }
918 |
919 | r.readAsText(file);
920 | }
921 | readFile();
922 | }
923 | }).click();
924 | }
925 | };
926 |
927 | $(document).ready(function () {
928 | system.init();
929 | });
930 | })(jQuery);
--------------------------------------------------------------------------------