├── background.js ├── bg.html ├── css └── offcloud.css ├── icon32.png ├── icon64.png ├── lib ├── css │ └── notie.min.css ├── fonts │ └── OpenSans-Regular.ttf └── js │ ├── jquery-2.0.3.min.js │ └── notie.min.js ├── logo.png ├── main.js ├── manifest.json ├── options.html └── options.js /background.js: -------------------------------------------------------------------------------- 1 | var cm = chrome.contextMenus; 2 | var om = chrome.runtime.onMessage; 3 | var t = chrome.tabs; 4 | var remoteOptionId; 5 | var s = chrome.storage.local; 6 | var cn = chrome.notifications; 7 | var apiKey; 8 | 9 | var APIURLS = { 10 | instantDld: 'https://offcloud.com/api/instant/download', 11 | cloudDld: 'https://offcloud.com/api/cloud/download', 12 | remoteDld: 'https://offcloud.com/api/remote/download', 13 | login: 'https://offcloud.com/login', 14 | checkLogin: 'https://offcloud.com/api/login/check', 15 | getRemoteId: 'https://offcloud.com/api/remote-account/list', 16 | remoteSet: 'https://www.offcloud.com/#/remote' 17 | }; 18 | 19 | restoreOptions(); 20 | 21 | initMenus(); 22 | 23 | function restoreOptions(){ 24 | chrome.storage.local.get(['apiKey', 'remoteOptionId'], function(object){ 25 | if (object.apiKey != null) 26 | apiKey = object.apiKey; 27 | 28 | if (object.remoteOptionId != null) 29 | remoteOptionId = object.remoteOptionId; 30 | }); 31 | } 32 | 33 | function getApiKey(callback) { 34 | s.get('apiKey', function(result) { 35 | apiKey = result.apiKey; 36 | if (apiKey == null) { 37 | $.post('https://offcloud.com/api/account/get', function(data) { 38 | if (data.error) { 39 | notifyNotLoggedIn(); 40 | } else { 41 | apiKey = data.apiKey; 42 | s.set({ 43 | apiKey: apiKey 44 | }, function() { 45 | setDefaultRemoteAccount(function(){ 46 | callback(); 47 | }); 48 | }); 49 | } 50 | }); 51 | } else { 52 | callback(); 53 | } 54 | }); 55 | } 56 | 57 | function setApiKey(newApiKey){ 58 | s.set({ 59 | apiKey: newApiKey 60 | }, function(){ 61 | apiKey = newApiKey; 62 | setDefaultRemoteAccount(()=>{}); 63 | }); 64 | } 65 | 66 | function initMenus() { 67 | cm.removeAll(); 68 | 69 | cm.create({ 70 | type: "normal", 71 | title: "Instant download selected links", 72 | contexts: ["link", "selection"], 73 | onclick: function(clickData, tab) { 74 | downloadAction(clickData, tab, APIURLS.instantDld, false, 0); 75 | } 76 | }); 77 | cm.create({ 78 | type: "normal", 79 | title: "Cloud download selected links", 80 | contexts: ["link", "selection"], 81 | onclick: function(clickData, tab) { 82 | downloadAction(clickData, tab, APIURLS.cloudDld, false, 1); 83 | } 84 | }); 85 | cm.create({ 86 | type: "normal", 87 | title: "Remote download selected links", 88 | contexts: ["link", "selection"], 89 | onclick: function(clickData, tab) { 90 | downloadAction(clickData, tab, APIURLS.remoteDld, true, 2); 91 | } 92 | }); 93 | 94 | cm.create({ 95 | type: "normal", 96 | title: "Instant download custom links", 97 | contexts: ["page_action"], 98 | onclick: function(clickData, tab) { 99 | customDownload(tab, 0); 100 | } 101 | }); 102 | cm.create({ 103 | type: "normal", 104 | title: "Cloud download custom links", 105 | contexts: ["page_action"], 106 | onclick: function(clickData, tab) { 107 | customDownload(tab, 1); 108 | } 109 | }); 110 | cm.create({ 111 | type: "normal", 112 | title: "Remote download custom links", 113 | contexts: ["page_action"], 114 | onclick: function(clickData, tab) { 115 | customDownload(tab, 2); 116 | } 117 | }); 118 | } 119 | 120 | function customDownload(tab, type) { 121 | if (apiKey == null) { 122 | checkLogin(function(){ 123 | getApiKey(function() { 124 | t.sendMessage(tab.id, { 125 | cmd: "showModal", 126 | type: type 127 | }); 128 | }); 129 | }); 130 | } else { 131 | t.sendMessage(tab.id, { 132 | cmd: "showModal", 133 | type: type 134 | }); 135 | } 136 | } 137 | 138 | function downloadAction(clickData, tab, apiLink, remote, type) { 139 | if (apiKey == null) { 140 | checkLogin(function(){ 141 | getApiKey(function() { 142 | startAction(); 143 | }); 144 | }); 145 | } else { 146 | startAction(); 147 | } 148 | 149 | function startAction() { 150 | apiLink += "?apiKey=" + apiKey; 151 | 152 | t.sendMessage(tab.id, { 153 | cmd: "appendLoader" 154 | }); 155 | 156 | if (clickData.linkUrl) { 157 | processCall(apiLink, clickData.linkUrl, remote, tab, type); 158 | } else if (clickData.selectionText) { 159 | t.sendMessage(tab.id, { 160 | cmd: "getSelectedHtml" 161 | }, function(resp) { 162 | if (resp && resp.html) { 163 | processMultipleLink(resp.html, true, remote, tab, apiLink, resp.href, type); 164 | } 165 | }); 166 | } 167 | } 168 | } 169 | function processMultipleLink(html, needReg, remote, tab, api, href, type) { 170 | var result = []; 171 | if (needReg) { 172 | result = findLinkByRegex(html); 173 | } else { 174 | result = findLinkByText(html); 175 | } 176 | 177 | result = result.map(function(link) { 178 | if (link.startsWith('http')) { 179 | return link; 180 | } else { 181 | return href + link; 182 | } 183 | }); 184 | 185 | if (result && result.length > 1) { 186 | var requestList = []; 187 | for (var i = 0; i < result.length; i++) { 188 | var dataBody = { 189 | url: result[i] 190 | }; 191 | if (remote) { 192 | if (remoteOptionId) 193 | dataBody.remoteOptionId = remoteOptionId; 194 | else 195 | dataBody.remoteOptionId = ""; 196 | } 197 | requestList.push($.ajax(api, { 198 | method: 'POST', 199 | data: dataBody 200 | })); 201 | } 202 | var multiRequest = $.when.apply($, requestList); 203 | multiRequest.done(function(data) { 204 | var finalData = []; 205 | $.each(arguments, function(index, responseData) { 206 | if (responseData[1] == "success") { 207 | if (responseData[0].not_available) { 208 | t.sendMessage(tab.id, { 209 | cmd: "errorNotification" 210 | }); 211 | 212 | return false; 213 | } else { 214 | if (remote) { 215 | t.sendMessage(tab.id, { 216 | cmd: "remoteInProcessNotification" 217 | }); 218 | return false; 219 | } else { 220 | if (!responseData[0].error) 221 | finalData.push(responseData[0].url); 222 | } 223 | } 224 | } else { 225 | t.sendMessage(tab.id, { 226 | cmd: "errorNotification" 227 | }); 228 | } 229 | }); 230 | 231 | if (finalData.length != 0) { 232 | //copying the result to the clipboard 233 | var text = finalData.join("\n"); 234 | copyTextToClipboard(text); 235 | t.sendMessage(tab.id, { 236 | cmd: "successNotification", 237 | type: type 238 | }, function(res) { 239 | if (res){ 240 | finalData.forEach(function(url) { 241 | t.create({ 242 | url: url 243 | }); 244 | }); 245 | } 246 | }); 247 | } 248 | }); 249 | } else if (result && result.length == 1) { 250 | processCall(api, result[0], remote, tab, type); 251 | } 252 | } 253 | 254 | function processCall(api, link, remote, tab, type) { 255 | var dataBody = { 256 | url: link 257 | }; 258 | if (remote) { 259 | if (remoteOptionId) 260 | dataBody.remoteOptionId = remoteOptionId; 261 | else 262 | dataBody.remoteOptionId = ""; 263 | 264 | processAjax(api, link, true, tab, dataBody, type); 265 | 266 | } else { 267 | processAjax(api, link, false, tab, dataBody, type); 268 | } 269 | } 270 | 271 | function findLinkByRegex(html) { 272 | var linkReg = /href=[\'"]?([^\'" >]+)/g; 273 | var result = html.match(linkReg); 274 | for (var i = 0; i < result.length; i++) { 275 | result[i] = result[i].replace('href="', ''); 276 | } 277 | return result; 278 | } 279 | 280 | function findLinkByText(text) { 281 | var urlReg = /[a-zA-z]+:\/\/[^\s]*/g; 282 | return text.match(urlReg); 283 | } 284 | 285 | function processAjax(api, link, remote, tab, dataBody, type) { 286 | $.ajax(api, { 287 | method: 'POST', 288 | data: dataBody 289 | // 'contentType': 'multipart/form-data' 290 | }).success(function(data) { 291 | if (!data.not_available && remote) { 292 | t.sendMessage(tab.id, { 293 | cmd: "remoteInProcessNotification" 294 | }); 295 | } else if (!data.not_available) { 296 | //copying the result to the clipboard 297 | var url = data.url; 298 | copyTextToClipboard(url); 299 | 300 | t.sendMessage(tab.id, { 301 | cmd: "successNotification", 302 | type: type 303 | }, function(res) { 304 | if (res){ 305 | t.create({ 306 | url: url 307 | }); 308 | } 309 | }); 310 | } else { 311 | t.sendMessage(tab.id, { 312 | cmd: "errorNotification" 313 | }); 314 | } 315 | }).fail(function() { 316 | t.sendMessage(tab.id, { 317 | cmd: "errorNotification" 318 | }); 319 | }); 320 | } 321 | 322 | function checkLogin(callback) { 323 | $.get(APIURLS.checkLogin, function(response){ 324 | var loggedIn = response.loggedIn; 325 | 326 | if (loggedIn){ 327 | callback(); 328 | } 329 | else 330 | notifyNotLoggedIn(); 331 | 332 | }).fail(function() { 333 | showErrorMessage(); 334 | }); 335 | } 336 | 337 | function setDefaultRemoteAccount(callback){ 338 | $.get(APIURLS.getRemoteId + "?apikey=" + apiKey, function(data){ 339 | if (!data.error){ 340 | var remoteOptionsArray = data.data; 341 | if (remoteOptionsArray.length > 0) 342 | remoteOptionId = remoteOptionsArray[0].remoteOptionId; 343 | callback(); 344 | } 345 | }); 346 | } 347 | 348 | om.addListener(function(req, sender, sendResponse) { 349 | if (req.action == "setApiKey") 350 | setApiKey(req.newApiKey); 351 | 352 | if (req.action == "setRemoteOptionId") 353 | remoteOptionId = req.newRemoteOptionId; 354 | 355 | if (req.action == "removeRemoteOptionId") 356 | remoteOptionId = null; 357 | 358 | if (req.cmd == "custom") { 359 | var currentApi; 360 | if (req.type == 0) { 361 | currentApi = APIURLS.instantDld; 362 | } else if (req.type == 1) { 363 | currentApi = APIURLS.cloudDld; 364 | } else { 365 | currentApi = APIURLS.remoteDld; 366 | } 367 | currentApi += "?apiKey=" + apiKey; 368 | 369 | t.sendMessage(sender.tab.id, { 370 | cmd: "appendLoader" 371 | }); 372 | 373 | processMultipleLink(req.html, false, req.type == 2, sender.tab, currentApi, null, req.type); 374 | } 375 | }); 376 | 377 | function showErrorMessage() { 378 | showNotification("errorMsg", { 379 | type: "basic", 380 | title: ' Offcloud.com is offline', 381 | message: 'Sorry, Offcloud.com is offline, please try again later' 382 | }); 383 | } 384 | 385 | function notifyNotLoggedIn() { 386 | showNotification("notlogin", { 387 | type: "basic", 388 | title: 'You are currently not logged in', 389 | message: 'You are currently not logged into Offcloud. Please log into your account...' 390 | }, 391 | true, 392 | APIURLS.login); 393 | } 394 | 395 | function showNotification(name, options, redirect, redirectUrl) { 396 | cn.clear(name, function() { 397 | cn.create(name, { 398 | type: options.type, 399 | iconUrl: 'icon64.png', 400 | title: options.title, 401 | message: options.message 402 | }, function() { 403 | if (redirect) { 404 | t.create({ 405 | active: true, 406 | url: redirectUrl 407 | }); 408 | } 409 | 410 | }); 411 | }); 412 | } 413 | 414 | function copyTextToClipboard(text) { 415 | var copyFrom = $('