├── .gitignore
├── AddToTransmission.safariextension
├── Icon.png
├── se.zanmato.addtotransmission.css
├── Info.plist
├── Settings.plist
├── se.zanmato.addtotransmission.js
└── global.html
├── AddToTransmission-Firefox
├── content
│ ├── brand
│ │ ├── icon.png
│ │ └── context-icon.png
│ ├── overlay.xul
│ ├── style.css
│ ├── options.xul
│ ├── overlay.js
│ └── torrentClient.js
├── config_build.sh
├── locale
│ ├── sv-SE
│ │ ├── overlay.properties
│ │ └── overlay.dtd
│ └── en-US
│ │ ├── overlay.properties
│ │ └── overlay.dtd
├── chrome.manifest
├── defaults
│ └── preferences
│ │ └── pref.js
├── install.rdf
├── components
│ └── magnetService.js
└── build_mac.sh
├── Update.plist
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | AddToTransmission.safariextension/.DS_Store
2 |
--------------------------------------------------------------------------------
/AddToTransmission.safariextension/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zanmato/Add-to-Transmission/HEAD/AddToTransmission.safariextension/Icon.png
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/content/brand/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zanmato/Add-to-Transmission/HEAD/AddToTransmission-Firefox/content/brand/icon.png
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/content/brand/context-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zanmato/Add-to-Transmission/HEAD/AddToTransmission-Firefox/content/brand/context-icon.png
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/config_build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Build config for the build script, build.sh. Look there for more info.
4 |
5 | APP_NAME=addtotransmission
6 | CHROME_PROVIDERS="content locale defaults"
7 | CLEAN_UP=1
8 | ROOT_FILES=
9 | ROOT_DIRS=
10 | BEFORE_BUILD=
11 | AFTER_BUILD=
12 |
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/locale/sv-SE/overlay.properties:
--------------------------------------------------------------------------------
1 | downloadingString=Hämtar
2 | failedFetchString=Kunde inte hämta torrenten
3 | sendingString=Skickar
4 | unauthorizedString=Kunde inte logga in
5 | emptyResponseString=Tomt svar
6 | couldNotConnectString=Kunde inte ansluta till Transmission
7 | invalidTorrentString=Fel på torrent-filen
8 | duplicateTorrentString=Redan tillagd
9 | unknownErrorString=Okänt fel
10 | successString=Tillagd
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/chrome.manifest:
--------------------------------------------------------------------------------
1 | content addtotransmission content/
2 | overlay chrome://browser/content/browser.xul chrome://addtotransmission/content/overlay.xul
3 |
4 | locale addtotransmission en-US locale/en-US/
5 | locale addtotransmission sv-SE locale/sv-SE/
6 |
7 | component {e2ad1660-1b52-11e4-8c21-0800200c9a66} components/magnetService.js
8 | contract @mozilla.org/network/protocol;1?name=magnet {e2ad1660-1b52-11e4-8c21-0800200c9a66}
9 |
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/locale/en-US/overlay.properties:
--------------------------------------------------------------------------------
1 | downloadingString=Downloading
2 | failedFetchString=Failed to fetch the torrent
3 | sendingString=Sending
4 | unauthorizedString=Unauthorized
5 | emptyResponseString=Empty response
6 | couldNotConnectString=Couldn't connect to Transmission
7 | invalidTorrentString=Invalid or corrupt torrent
8 | duplicateTorrentString=Duplicate torrent
9 | unknownErrorString=Unknown error
10 | successString=Added
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/defaults/preferences/pref.js:
--------------------------------------------------------------------------------
1 | pref("extensions.addtotransmission.addpaused", true);
2 | pref("extensions.addtotransmission.alllinks", false);
3 | pref("extensions.addtotransmission.username", "");
4 | pref("extensions.addtotransmission.path", "");
5 | pref("extensions.addtotransmission.url", "http://127.0.0.1:9091/transmission/rpc");
6 | pref("extensions.addtotransmission.placement", "t");
7 | pref("extensions.addtotransmission.troubleshooting", false);
8 | pref("extensions.addtotransmission.downloads", false);
9 |
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/locale/en-US/overlay.dtd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/content/overlay.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
15 |
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/locale/sv-SE/overlay.dtd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Update.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Extension Updates
6 |
7 |
8 | CFBundleIdentifier
9 | se.zanmato.addtotransmission
10 | Developer Identifier
11 | C476BSG46Y
12 | CFBundleVersion
13 | 1.3
14 | CFBundleShortVersionString
15 | 1.3
16 | URL
17 | http://downloads.zanmato.se/add-to-transmission/AddToTransmission13.safariextz
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/install.rdf:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | addtotransmission@zanmato.se
6 | Add to Transmission
7 | 2
8 | 1.4
9 | Easily add torrents to Transmission
10 | Andreas Johansson
11 | Patrick Milvi
12 | http://www.zanmato.se/
13 | chrome://addtotransmission/content/brand/icon.png
14 | chrome://addtotransmission/content/options.xul
15 |
16 |
17 |
18 |
19 | {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
20 | 3.6
21 | 31.*
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Easily add torrents to Transmission.
2 |
3 | Just secondary click on any torrent link and select Add to Transmission from the contextual menu to have the torrent downloaded and sent to the daemon of your choice!
4 |
5 | What's new in 1.4?
6 | ------------------
7 | * (Firefox) Handle downloads option. This enables you to directly pass through torrents and magnet links, without using the context menu.
8 | * Download path option, thanks to [amet](https://github.com/zanmato/Add-to-Transmission/pull/6)
9 |
10 | 1.3
11 | ------------------
12 | * Added support for forms without any inputs.
13 | * Made the tooltip placement configurable.
14 | * Added CSS reset for the tooltip.
15 | * (Firefox) New troubleshooting option. This passes through the errors straight from transmission. Useful when you get "Unknown error".
16 | * (Firefox) The extension icon has been added to the context menu.
17 |
18 | 1.2
19 | ------------------
20 | * Added support for magnet links.
21 | * Added a setting to enable the extension for all links, not just links with ".torrent" in them.
22 | * Made the error messages more descriptive.
23 | * Now the extension looks for ".torrent" anywhere in the link, not just at the end of it.
24 | * Increased the display time of the message bubbles.
25 | * Fixed several bugs.
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/content/style.css:
--------------------------------------------------------------------------------
1 | /** Reset */
2 | div.att-bubble {
3 | margin: 0;
4 | padding: 0;
5 | border: 0;
6 | font-size: 100%;
7 | font: inherit;
8 | vertical-align: baseline;
9 | }
10 |
11 | div.att-bubble {
12 | background: #101010 !important;
13 | border: 5px solid #101010 !important;
14 | border-radius: 10px;
15 | color: #fff !important;
16 | font-family: "Lucida Grande", "Lucida", "Helvetica" !important;
17 | font-size: 16px !important;
18 | text-align: center;
19 | min-width: 120px;
20 | opacity: 0;
21 | position: absolute;
22 | padding: 5px !important;
23 | z-index: 100;
24 | transition: opacity 4s linear;
25 | }
26 |
27 | div.att-bubble.arrow:before {
28 | border: 10px solid transparent;
29 | content: "";
30 | display: block;
31 | height: 0;
32 | position: absolute;
33 | width: 0;
34 | z-index: 100;
35 | }
36 |
37 | div.att-bubble.arrow.top:before {
38 | bottom: -22px;
39 | left: 50%;
40 | margin-left: -10px;
41 | border-top-color: #101010 !important;
42 | }
43 |
44 | div.att-bubble.arrow.bottom:before {
45 | top: -22px;
46 | left: 50%;
47 | margin-left: -10px;
48 | border-bottom-color: #101010 !important;
49 | }
50 |
51 | div.att-bubble.arrow.left:before {
52 | top: 50%;
53 | margin-top: -10px;
54 | right: -22px;
55 | border-left-color: #101010 !important;
56 | }
57 |
58 | div.att-bubble.arrow.right:before {
59 | top: 50%;
60 | margin-top: -10px;
61 | left: -22px;
62 | border-right-color: #101010 !important;
63 | }
--------------------------------------------------------------------------------
/AddToTransmission.safariextension/se.zanmato.addtotransmission.css:
--------------------------------------------------------------------------------
1 | /** Reset */
2 | div.att-bubble {
3 | margin: 0;
4 | padding: 0;
5 | border: 0;
6 | font-size: 100%;
7 | font: inherit;
8 | vertical-align: baseline;
9 | }
10 |
11 | div.att-bubble {
12 | background: #101010 !important;
13 | border: 5px solid #101010 !important;
14 | border-radius: 10px;
15 | color: #fff !important;
16 | font-family: "Lucida Grande" !important;
17 | font-size: 16px !important;
18 | text-align: center;
19 | min-width: 120px;
20 | opacity: 0;
21 | position: absolute;
22 | padding: 5px !important;
23 | z-index: 100;
24 | -webkit-transition: opacity 3s linear;
25 | -webkit-transition-delay: 1.5s;
26 | }
27 |
28 | div.att-bubble:before {
29 | border: 10px solid transparent;
30 | content: "";
31 | display: block;
32 | height: 0;
33 | position: absolute;
34 | width: 0;
35 | z-index: 100;
36 | }
37 |
38 | div.att-bubble.top:before {
39 | bottom: -22px;
40 | left: 50%;
41 | margin-left: -10px;
42 | border-top-color: #101010 !important;
43 | }
44 |
45 | div.att-bubble.bottom:before {
46 | top: -22px;
47 | left: 50%;
48 | margin-left: -10px;
49 | border-bottom-color: #101010 !important;
50 | }
51 |
52 | div.att-bubble.left:before {
53 | top: 50%;
54 | margin-top: -10px;
55 | right: -22px;
56 | border-left-color: #101010 !important;
57 | }
58 |
59 | div.att-bubble.right:before {
60 | top: 50%;
61 | margin-top: -10px;
62 | left: -22px;
63 | border-right-color: #101010 !important;
64 | }
--------------------------------------------------------------------------------
/AddToTransmission.safariextension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Author
6 | Andreas Johansson
7 | Builder Version
8 | 8536.26.17
9 | CFBundleDisplayName
10 | Add to Transmission
11 | CFBundleIdentifier
12 | se.zanmato.addtotransmission
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleShortVersionString
16 | 1.3
17 | CFBundleVersion
18 | 1.3
19 | Chrome
20 |
21 | Global Page
22 | global.html
23 |
24 | Content
25 |
26 | Scripts
27 |
28 | Start
29 |
30 | se.zanmato.addtotransmission.js
31 |
32 |
33 | Stylesheets
34 |
35 | se.zanmato.addtotransmission.css
36 |
37 |
38 | Description
39 | Easily add torrents to Transmission
40 | ExtensionInfoDictionaryVersion
41 | 1.0
42 | Permissions
43 |
44 | Website Access
45 |
46 | Include Secure Pages
47 |
48 | Level
49 | All
50 |
51 |
52 | Update Manifest URL
53 | https://github.com/zanmato/Add-to-Transmission/raw/master/Update.plist
54 | Website
55 | http://www.zanmato.se
56 |
57 |
58 |
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/components/magnetService.js:
--------------------------------------------------------------------------------
1 | /** Thanks to mike.kaply for the example code */
2 | const Cc = Components.classes;
3 | const Ci = Components.interfaces;
4 | const Cr = Components.results;
5 |
6 | const nsIProtocolHandler = Ci.nsIProtocolHandler;
7 |
8 | Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
9 | Components.utils.import("chrome://addtotransmission/content/torrentClient.js");
10 |
11 | function MagnetProtocol() {}
12 |
13 | MagnetProtocol.prototype = {
14 | scheme: "magnet",
15 | protocolFlags: nsIProtocolHandler.URI_NORELATIVE |
16 | nsIProtocolHandler.URI_NOAUTH |
17 | nsIProtocolHandler.URI_LOADABLE_BY_ANYONE,
18 |
19 | newURI: function(aSpec, aOriginCharset, aBaseURI) {
20 | var uri = Cc["@mozilla.org/network/simple-uri;1"].createInstance(Ci.nsIURI);
21 | uri.spec = aSpec;
22 | return uri;
23 | },
24 |
25 | newChannel: function(aURI) {
26 | var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
27 |
28 | var torrentInfo = {'href': aURI.spec, 'id': null, 'magnet': true};
29 | var newTorrent = new TorrentClient(torrentInfo, null);
30 | newTorrent.add();
31 |
32 | return false;
33 | },
34 |
35 | classDescription: "Magnet Protocol Handler",
36 | contractID: "@mozilla.org/network/protocol;1?name=" + "magnet",
37 | classID: Components.ID('{e2ad1660-1b52-11e4-8c21-0800200c9a66}'),
38 | QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler])
39 | };
40 |
41 | var prefManager = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
42 | if (prefManager.getBoolPref("extensions.addtotransmission.downloads")) {
43 | if (XPCOMUtils.generateNSGetFactory) {
44 | var NSGetFactory = XPCOMUtils.generateNSGetFactory([MagnetProtocol]);
45 | } else {
46 | var NSGetModule = XPCOMUtils.generateNSGetModule([MagnetProtocol]);
47 | }
48 | }
--------------------------------------------------------------------------------
/AddToTransmission.safariextension/Settings.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | DefaultValue
7 | http://127.0.0.1:9091/transmission/rpc
8 | Key
9 | url
10 | Title
11 | URL
12 | Type
13 | TextField
14 |
15 |
16 | DefaultValue
17 |
18 | Key
19 | path
20 | Title
21 | Download Path
22 | Type
23 | TextField
24 |
25 |
26 | DefaultValue
27 | admin
28 | Key
29 | username
30 | Title
31 | Username
32 | Type
33 | TextField
34 |
35 |
36 | DefaultValue
37 | admin
38 | Key
39 | password
40 | Password
41 |
42 | Secure
43 |
44 | Title
45 | Password
46 | Type
47 | TextField
48 |
49 |
50 | DefaultValue
51 |
52 | Key
53 | addpaused
54 | Title
55 | Add paused?
56 | Type
57 | CheckBox
58 |
59 |
60 | DefaultValue
61 |
62 | Key
63 | alllinks
64 | Title
65 | Enable for all links?
66 | Type
67 | CheckBox
68 |
69 |
70 | DefaultValue
71 | t
72 | Key
73 | placement
74 | Title
75 | Tooltip placement
76 | Titles
77 |
78 | Top
79 | Bottom
80 | Left
81 | Right
82 |
83 | Type
84 | ListBox
85 | Values
86 |
87 | t
88 | b
89 | l
90 | r
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/AddToTransmission.safariextension/se.zanmato.addtotransmission.js:
--------------------------------------------------------------------------------
1 | var settings = {};
2 |
3 | document.addEventListener("contextmenu", handleContextMenu, false);
4 | safari.self.addEventListener("message", getMessage, false);
5 | safari.self.tab.dispatchMessage("getSettings");
6 |
7 | function getMessage(theMessageEvent) {
8 | if (theMessageEvent.name === "att-progress") {
9 | var info = theMessageEvent.message.info;
10 | var status = theMessageEvent.message.message;
11 | var close = theMessageEvent.message.close;
12 |
13 | var bubble = document.getElementById(info.id);
14 | if (bubble != null) {
15 | bubble.innerHTML = status;
16 | bubble.style.display = 'block';
17 | bubble.style.opacity = 0.9;
18 | if (close) {
19 | // Fade out, set timeout to remove it
20 | bubble.style.opacity = 0;
21 | setTimeout('document.body.removeChild(document.getElementById(\''+info.id+'\'))', 5000);
22 | }
23 | }
24 | } else if (theMessageEvent.name === "setSettings") {
25 | settings = theMessageEvent.message;
26 | }
27 | }
28 |
29 | function findParentNode(parentName, childObj) {
30 | var testObj = childObj.parentNode;
31 | var count = 1;
32 | while (testObj.nodeName != parentName && count < 50) {
33 | testObj = testObj.parentNode;
34 | if (testObj == null) {
35 | return false;
36 | }
37 | count++;
38 | }
39 |
40 | if (testObj.nodeName == "A") {
41 | return testObj.href;
42 | } else if (testObj.nodeName == "FORM") {
43 | return testObj.action;
44 | } else {
45 | return false;
46 | }
47 | }
48 |
49 | function handleContextMenu(event) {
50 | var href = false;
51 | if (event.target.nodeName == "A") {
52 | href = event.target.href;
53 | } else if (event.target.nodeName == "INPUT" || event.target.nodeName == "BUTTON") {
54 | href = findParentNode("FORM", event.target);
55 | } else {
56 | href = findParentNode("A", event.target);
57 | }
58 |
59 | if (href != false && (href.toLowerCase().indexOf('.torrent') != -1 || href.toLowerCase().indexOf('magnet:?') != -1 || settings.allLinks)) {
60 | var magnet = (href.toLowerCase().indexOf('magnet:?') != -1 ? true : false);
61 | var d = new Date();
62 | var id = d.getTime();
63 | var bubble = document.createElement("div");
64 | bubble.id = id;
65 | bubble.className = "att-bubble";
66 | bubble.style.display = 'none';
67 |
68 | var pos = {};
69 | switch (settings.placement) {
70 | case 'b':
71 | pos = {top: event.pageY + 30, left: event.pageX - 70};
72 | bubble.className += " bottom";
73 | break
74 | case 't':
75 | pos = {top: event.pageY - 70, left: event.pageX - 70};
76 | bubble.className += " top";
77 | break
78 | case 'l':
79 | pos = {top: event.pageY - 22, right: (document.body.offsetWidth-event.pageX) + 70};
80 | bubble.className += " left";
81 | break
82 | case 'r':
83 | pos = {top: event.pageY - 22, left: event.pageX + 70};
84 | bubble.className += " right";
85 | break
86 | }
87 |
88 | if (pos.left) {
89 | bubble.style.left = pos.left+"px";
90 | } else {
91 | bubble.style.right = pos.right+"px";
92 | }
93 | bubble.style.top = pos.top+"px";
94 |
95 | document.body.appendChild(bubble);
96 | safari.self.tab.setContextMenuEventUserInfo(event, {'href':href,'magnet':magnet,'id':id});
97 | return;
98 | }
99 | safari.self.tab.setContextMenuEventUserInfo(event, false);
100 | }
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/build_mac.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # build.sh -- builds JAR and XPI files for mozilla extensions
3 | # by Nickolay Ponomarev
4 | # (original version based on Nathan Yergler's build script)
5 | # Most recent version is at
6 |
7 | # This script assumes the following directory structure:
8 | # ./
9 | # chrome.manifest (optional - for newer extensions)
10 | # install.rdf
11 | # (other files listed in $ROOT_FILES)
12 | #
13 | # content/ |
14 | # locale/ |} these can be named arbitrary and listed in $CHROME_PROVIDERS
15 | # skin/ |
16 | #
17 | # defaults/ |
18 | # components/ |} these must be listed in $ROOT_DIRS in order to be packaged
19 | # ... |
20 | #
21 | # It uses a temporary directory ./build when building; don't use that!
22 | # Script's output is:
23 | # ./$APP_NAME.xpi
24 | # ./$APP_NAME.jar (only if $KEEP_JAR=1)
25 | # ./files -- the list of packaged files
26 | #
27 | # Note: It modifies chrome.manifest when packaging so that it points to
28 | # chrome/$APP_NAME.jar!/*
29 |
30 | #
31 | # default configuration file is ./config_build.sh, unless another file is
32 | # specified in command-line. Available config variables:
33 | APP_NAME= # short-name, jar and xpi files name. Must be lowercase with no spaces
34 | CHROME_PROVIDERS= # which chrome providers we have (space-separated list)
35 | CLEAN_UP= # delete the jar / "files" when done? (1/0)
36 | ROOT_FILES= # put these files in root of xpi (space separated list of leaf filenames)
37 | ROOT_DIRS= # ...and these directories (space separated list)
38 | BEFORE_BUILD= # run this before building (bash command)
39 | AFTER_BUILD= # ...and this after the build (bash command)
40 |
41 | # is "cpio" available? If not, fall back to GNU-only "cp --parents"
42 | HAVE_CPIO=0
43 | which cpio 2>&1 > /dev/null && HAVE_CPIO=1
44 | echo "have cpio: $HAVE_CPIO"
45 |
46 | function cp_parents {
47 | if [ $HAVE_CPIO = 1 ]; then
48 | echo $1 | cpio -pduv $TMP_DIR
49 | else
50 | cp --verbose --parents $1 $TMP_DIR
51 | fi
52 | }
53 |
54 | function cp_parents_chr {
55 | if [ $HAVE_CPIO = 1 ]; then
56 | echo $1 | cpio -pduv $TMP_DIR/chrome
57 | else
58 | cp --verbose --parents $1 $TMP_DIR/chrome
59 | fi
60 | }
61 |
62 |
63 | if [ -z $1 ]; then
64 | . ./config_build.sh
65 | else
66 | . $1
67 | fi
68 |
69 | if [ -z $APP_NAME ]; then
70 | echo "You need to create build config file first!"
71 | echo "Read comments at the beginning of this script for more info."
72 | exit;
73 | fi
74 |
75 | ROOT_DIR=`pwd`
76 | TMP_DIR=build
77 |
78 | #uncomment to debug
79 | set -x
80 |
81 | # remove any left-over files from previous build
82 | rm -f $APP_NAME.jar $APP_NAME.xpi files
83 | rm -rf $TMP_DIR
84 |
85 | $BEFORE_BUILD
86 |
87 | # verbose, create each non-existent directorys
88 | mkdir -v -p $TMP_DIR/chrome
89 |
90 | # generate the JAR file, excluding CVS, SVN, and temporary files
91 | JAR_FILE=$TMP_DIR/chrome/$APP_NAME.jar
92 | echo "Generating $JAR_FILE..."
93 | for CHROME_SUBDIR in $CHROME_PROVIDERS; do
94 | find $CHROME_SUBDIR \( -path '*CVS*' -o -path '*.svn*' \) -prune -o -type f -print | grep -v \~ >> files
95 | done
96 |
97 | #zip -0 -r $JAR_FILE -@ < files
98 | # The following statement should be used instead if you don't wish to use the JAR file
99 | FLS=`cat files`
100 | LL=""
101 | for F in $FLS; do
102 | cp_parents $F
103 | done
104 |
105 | # prepare components and defaults
106 | echo "Copying various files to $TMP_DIR folder..."
107 | for DIR in $ROOT_DIRS; do
108 | mkdir $TMP_DIR/$DIR
109 | FILES="`find $DIR \( -path '*CVS*' -o -path '*.svn*' \) -prune -o -type f -print | grep -v \~`"
110 | echo $FILES >> files
111 | cp_parents $FILES
112 | done
113 |
114 | # Copy other files to the root of future XPI.
115 | for ROOT_FILE in $ROOT_FILES install.rdf chrome.manifest; do
116 | cp_parents $ROOT_FILE
117 | if [ -f $ROOT_FILE ]; then
118 | echo $ROOT_FILE >> files
119 | fi
120 | done
121 |
122 | cd $TMP_DIR
123 |
124 | if [ -f "chrome.manifest" ]; then
125 | echo "Preprocessing chrome.manifest..."
126 | # You think this is scary?
127 | #s/^(content\s+\S*\s+)(\S*\/)$/\1jar:chrome\/$APP_NAME\.jar!\/\2/
128 | #s/^(skin|locale)(\s+\S*\s+\S*\s+)(.*\/)$/\1\2jar:chrome\/$APP_NAME\.jar!\/\3/
129 | #
130 | # Then try this! (Same, but with characters escaped for bash :)
131 | #sed -i -r s/^\(content\\s+\\S*\\s+\)\(\\S*\\/\)$/\\1jar:chrome\\/$APP_NAME\\.jar!\\/\\2/ chrome.manifest
132 | #sed -i -r s/^\(skin\|locale\)\(\\s+\\S*\\s+\\S*\\s+\)\(.*\\/\)$/\\1\\2jar:chrome\\/$APP_NAME\\.jar!\\/\\3/ chrome.manifest
133 |
134 | # (it simply adds jar:chrome/whatever.jar!/ at appropriate positions of chrome.manifest)
135 | fi
136 |
137 | # generate the XPI file
138 | echo "Generating $APP_NAME.xpi..."
139 | zip -r ../$APP_NAME.xpi *
140 |
141 | cd "$ROOT_DIR"
142 |
143 | echo "Cleanup..."
144 | if [ $CLEAN_UP = 0 ]; then
145 | # save the jar file
146 | mv $TMP_DIR/chrome/$APP_NAME.jar .
147 | else
148 | rm ./files
149 | fi
150 |
151 | # remove the working files
152 | rm -rf $TMP_DIR
153 | echo "Done!"
154 |
155 | $AFTER_BUILD
156 |
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/content/options.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/AddToTransmission.safariextension/global.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
177 |
178 |
179 |
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/content/overlay.js:
--------------------------------------------------------------------------------
1 | Components.utils.import("chrome://addtotransmission/content/torrentClient.js");
2 |
3 | var uriContentListener = {
4 | QueryInterface: function(aIID) {
5 | if (aIID.equals(Components.interfaces.nsISupports)
6 | || aIID.equals(Components.interfaces.nsIURIContentListener)
7 | || aIID.equals(Components.interfaces.nsISupportsWeakReference)
8 | ) {
9 | return this;
10 | }
11 | return false;
12 | },
13 | canHandleContent: function(contentType, isContentPreferred, desiredContentType) {
14 | return false;
15 | },
16 | doContent: function(contentType, isContentPreferred, request, contentHandler) {
17 | var torrentInfo = {'href': request.URI.spec, 'id': null, 'magnet': false};
18 | var newTorrent = new TorrentClient(torrentInfo, null);
19 | newTorrent.add();
20 | return true;
21 | },
22 | isPreferred: function(contentType, desiredContentType) {
23 | if (contentType == "application/x-bittorrent") {
24 | return true;
25 | }
26 |
27 | return false;
28 | },
29 | onStartURIOpen: function(URI) {
30 | return true;
31 | }
32 | };
33 |
34 | function TorrentClientDelegate() {
35 | this.showText = function(str, id, close) {
36 | var bubble = content.document.getElementById(id);
37 | if (bubble != null) {
38 | var bundles = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService);
39 | var strings = bundles.createBundle("chrome://addtotransmission/locale/overlay.properties");
40 | bubble.textContent = strings.GetStringFromName(str);
41 | bubble.style.display = 'block';
42 | bubble.style.opacity = 0.9;
43 | if (close) {
44 | // Fade out, set timeout to remove it
45 | setTimeout(function() {
46 | if (typeof(content.document.body) !== 'undefined') {
47 | try {
48 | content.document.getElementById(id).style.opacity = 0;
49 | } catch (e) {
50 | /*Do nothing*/
51 | }
52 | }
53 | }, 1000);
54 | setTimeout(function() {
55 | if (typeof(content.document.body) !== 'undefined') {
56 | try {
57 | content.document.body.removeChild(content.document.getElementById(id));
58 | } catch (e) {
59 | /*Do nothing*/
60 | }
61 | }
62 | }, 5000);
63 | }
64 | }
65 | };
66 | }
67 |
68 | var AddToTransmission = {
69 | session_id: false,
70 | userInfo: false,
71 | prefManager: Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch),
72 | lastClickEvent: null,
73 | launchListener: function() {
74 | if (this.prefManager.getBoolPref("extensions.addtotransmission.downloads")) {
75 | var uriLoader = Components.classes["@mozilla.org/uriloader;1"].getService(Components.interfaces.nsIURILoader);
76 | uriLoader.registerContentListener(uriContentListener);
77 | }
78 | },
79 | onLoad: function(e) {
80 | var that = this;
81 | var contextMenu = document.getElementById("contentAreaContextMenu");
82 |
83 | if (contextMenu) {
84 | window.addEventListener("contextmenu", function (e) { that.handleContextMenu(e); }, false);
85 | this.loadCSS();
86 | }
87 |
88 | var anchors = content.document.getElementsByName("a");
89 | console.log("brooo");
90 | for (var i = 0; i < anchors.length; i++) {
91 | console.log("iaiia");
92 | anchors[i].addEventListener("click", function(event) {
93 | console.log("douchebag");
94 | that.lastClickEvent = event;
95 | });
96 | }
97 | },
98 | loadCSS: function() {
99 | var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService);
100 | var ios = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
101 | var uri = ios.newURI("chrome://addtotransmission/content/style.css", null, null);
102 |
103 | if (!sss.sheetRegistered(uri, sss.USER_SHEET)) {
104 | sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
105 | }
106 | },
107 | findParentNode: function(parentName, childObj) {
108 | var testObj = childObj.parentNode;
109 | var count = 1;
110 | while (testObj.nodeName != parentName && count < 50) {
111 | testObj = testObj.parentNode;
112 | if (testObj == null) {
113 | return false;
114 | }
115 | count++;
116 | }
117 |
118 | if (testObj.nodeName == "A") {
119 | return testObj.href;
120 | } else if (testObj.nodeName == "FORM") {
121 | return testObj.action;
122 | } else {
123 | return false;
124 | }
125 | },
126 | handleContextMenu: function(event) {
127 | var menu = document.getElementById('addtotransmission-ctx');
128 |
129 | var href = false;
130 | if (event.target.nodeName == "A") {
131 | href = event.target.href;
132 | } else if (event.target.nodeName == "INPUT" || event.target.nodeName == "BUTTON") {
133 | href = this.findParentNode("FORM", event.target);
134 | } else {
135 | href = this.findParentNode("A", event.target);
136 | }
137 |
138 | var allLinks = this.prefManager.getBoolPref("extensions.addtotransmission.alllinks");
139 |
140 | if (href != false && (href.toLowerCase().indexOf('.torrent') != -1 || href.toLowerCase().indexOf('magnet:?') != -1 || allLinks)) {
141 | var magnet = (href.toLowerCase().indexOf('magnet:?') != -1 ? true : false);
142 | var d = new Date();
143 | var id = d.getTime();
144 |
145 | var placement = this.prefManager.getCharPref("extensions.addtotransmission.placement");
146 |
147 | var bubble = content.document.createElement("div");
148 | bubble.id = id;
149 | bubble.className = "att-bubble arrow";
150 | bubble.style.display = 'none';
151 |
152 | var pos = {};
153 | switch (placement) {
154 | case 'b':
155 | pos = {top: event.pageY + 30, left: event.pageX - 70};
156 | bubble.className += " bottom";
157 | break
158 | case 't':
159 | pos = {top: event.pageY - 70, left: event.pageX - 70};
160 | bubble.className += " top";
161 | break
162 | case 'l':
163 | pos = {top: event.pageY - 22, right: (content.document.body.offsetWidth-event.pageX) + 70};
164 | bubble.className += " left";
165 | break
166 | case 'r':
167 | pos = {top: event.pageY - 22, left: event.pageX + 70};
168 | bubble.className += " right";
169 | break
170 | }
171 |
172 | if (pos.left) {
173 | bubble.style.left = pos.left+"px";
174 | } else {
175 | bubble.style.right = pos.right+"px";
176 | }
177 | bubble.style.top = pos.top+"px";
178 |
179 | content.document.body.appendChild(bubble);
180 |
181 | menu.hidden = false;
182 | this.userInfo = {'href':href,'id':id,'magnet':magnet};
183 | return;
184 | }
185 | menu.hidden = true;
186 | this.userInfo = false;
187 | },
188 | contextMenuItemClicked: function(event) {
189 | if (typeof this.userInfo == 'boolean') {
190 | return;
191 | }
192 |
193 | var delegate = new TorrentClientDelegate();
194 | var newTorrent = new TorrentClient(this.userInfo, delegate);
195 | newTorrent.add();
196 | }
197 | };
198 |
199 | window.addEventListener("load", function(e) {
200 | AddToTransmission.onLoad(e);
201 | }, false);
--------------------------------------------------------------------------------
/AddToTransmission-Firefox/content/torrentClient.js:
--------------------------------------------------------------------------------
1 | var EXPORTED_SYMBOLS = ["TorrentClient"];
2 |
3 | const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1", "nsIXMLHttpRequest");
4 |
5 | /**
6 | * Transmission torrent client
7 | * @param info Torrent info
8 | * @param delegate Delegate for showing fancy text stuff
9 | * @constructor
10 | */
11 | function TorrentClient(info, delegate) {
12 | this.info = info;
13 | this.delegate = delegate;
14 | this.prefManager = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
15 | this.loginManager = Components.classes["@mozilla.org/login-manager;1"].getService(Components.interfaces.nsILoginManager);
16 | this.keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/l";
17 | this.session_id = null;
18 | this.add = function() {
19 | var that = this;
20 | // Add paused? defaults to YES!
21 | var addPaused = that.prefManager.getBoolPref("extensions.addtotransmission.addpaused");
22 | var downloadDir = that.prefManager.getCharPref("extensions.addtotransmission.path");
23 |
24 | if (that.info.magnet) {
25 | // Send the magnet link
26 | that.upload(JSON.stringify({method: "torrent-add", arguments: {filename: that.info.href, paused: addPaused, "download-dir": downloadDir}}));
27 | } else {
28 | // Try to download the torrent file
29 | that.showText('downloadingString');
30 | try {
31 | var request = new XMLHttpRequest();
32 | request.open("GET", that.info.href, true);
33 | request.overrideMimeType('text/plain; charset=x-user-defined');
34 | request.onreadystatechange = function() {
35 | if (request.readyState == 4) {
36 | // Base64 encode the metadata
37 | var metainfo = that.encodeBinary(request.responseText);
38 |
39 | that.upload(JSON.stringify({method: "torrent-add", arguments: {metainfo: metainfo, paused: addPaused, "download-dir": downloadDir}}));
40 | }
41 | }
42 |
43 | request.send(null);
44 | } catch (e) {
45 | that.showText('failedFetchString', true);
46 | }
47 | }
48 | };
49 |
50 | this.upload = function(data) {
51 | var that = this;
52 |
53 | that.showText('sendingString');
54 | var troubleshooting = this.prefManager.getBoolPref("extensions.addtotransmission.troubleshooting");
55 | var request = new XMLHttpRequest();
56 | var username = that.prefManager.getCharPref("extensions.addtotransmission.username");
57 | var url = that.prefManager.getCharPref("extensions.addtotransmission.url");
58 | var password = false;
59 | var logins = that.loginManager.findLogins({}, "chrome://addtotransmission", url, null);
60 | for (var i=0; i< logins.length; i++) {
61 | if (logins[i].username == username) {
62 | password = logins[i].password;
63 | break;
64 | }
65 | }
66 |
67 | if (username.length > 0 && password != false) {
68 | request.open("POST", that.prefManager.getCharPref("extensions.addtotransmission.url"), true, username, password);
69 | } else {
70 | request.open("POST", that.prefManager.getCharPref("extensions.addtotransmission.url"), true);
71 | }
72 |
73 | if (that.session_id) {
74 | request.setRequestHeader("X-Transmission-Session-Id", that.session_id);
75 | }
76 |
77 | request.onreadystatechange = function() {
78 | if (request.readyState == 4) {
79 | var response = request.responseText;
80 | try {
81 | if (response.length > 0) {
82 | if (response.search(/invalid session-id/i) != -1) {
83 | var matches = response.match(/X-Transmission-Session-Id: (.*)<\/code>/);
84 | that.session_id = matches[1];
85 | that.upload(data);
86 | } else if (response.search(/unauthorized/i) != -1) {
87 | that.showText('unauthorizedString', true);
88 | } else {
89 | var json_response = JSON.parse(response);
90 | if (json_response.result == 'success') {
91 | that.showText('successString', true);
92 | } else {
93 | if (!troubleshooting) {
94 | if (json_response.result == 'duplicate torrent') {
95 | that.showText('duplicateTorrentString', true);
96 | } else if (json_response.result == 'invalid or corrupt torrent file') {
97 | that.showText('invalidTorrentString', true);
98 | } else {
99 | that.showText('unknownErrorString', true);
100 | }
101 | } else {
102 | that.showText(json_response.result.charAt(0).toUpperCase() + json_response.result.slice(1), true);
103 | }
104 | }
105 | }
106 | } else {
107 | that.showText('couldNotConnectString', true);
108 | }
109 | } catch (e) {
110 | that.showText('unknownErrorString', true);
111 | }
112 | }
113 | };
114 |
115 | request.send(data);
116 | };
117 | this.showText = function(str, close) {
118 | if (!close) {
119 | close = false;
120 | }
121 |
122 | if (delegate == null) {
123 | return;
124 | }
125 |
126 | this.delegate.showText(str, this.info.id, close);
127 | };
128 |
129 | // From http://emilsblog.lerch.org/2009/07/javascript-hacks-using-xhr-to-load.html
130 | this.encodeBinary = function(input) {
131 | var output = "";
132 | var bytebuffer;
133 | var encodedCharIndexes = new Array(4);
134 | var inx = 0;
135 | var paddingBytes = 0;
136 |
137 | while(inx < input.length){
138 | // Fill byte buffer array
139 | bytebuffer = new Array(3);
140 | for(var jnx = 0; jnx < bytebuffer.length; jnx++)
141 | if(inx < input.length)
142 | bytebuffer[jnx] = input.charCodeAt(inx++) & 0xff; // throw away high-order byte, as documented at: https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data
143 | else
144 | bytebuffer[jnx] = 0;
145 |
146 | // Get each encoded character, 6 bits at a time
147 | // index 1: first 6 bits
148 | encodedCharIndexes[0] = bytebuffer[0] >> 2;
149 | // index 2: second 6 bits (2 least significant bits from input byte 1 + 4 most significant bits from byte 2)
150 | encodedCharIndexes[1] = ((bytebuffer[0] & 0x3) << 4) | (bytebuffer[1] >> 4);
151 | // index 3: third 6 bits (4 least significant bits from input byte 2 + 2 most significant bits from byte 3)
152 | encodedCharIndexes[2] = ((bytebuffer[1] & 0x0f) << 2) | (bytebuffer[2] >> 6);
153 | // index 3: forth 6 bits (6 least significant bits from input byte 3)
154 | encodedCharIndexes[3] = bytebuffer[2] & 0x3f;
155 |
156 | // Determine whether padding happened, and adjust accordingly
157 | paddingBytes = inx - (input.length - 1);
158 | switch(paddingBytes){
159 | case 2:
160 | // Set last 2 characters to padding char
161 | encodedCharIndexes[3] = 64;
162 | encodedCharIndexes[2] = 64;
163 | break;
164 | case 1:
165 | // Set last character to padding char
166 | encodedCharIndexes[3] = 64;
167 | break;
168 | default:
169 | break; // No padding - proceed
170 | }
171 | // Now we will grab each appropriate character out of our keystring
172 | // based on our index array and append it to the output string
173 | for(var jnx = 0; jnx < encodedCharIndexes.length; jnx++)
174 | output += this.keyStr.charAt(encodedCharIndexes[jnx]);
175 | }
176 | return output;
177 | };
178 | }
--------------------------------------------------------------------------------