diff --git a/background.js b/background.js new file mode 100644 index 0000000..9b63519 --- /dev/null +++ b/background.js @@ -0,0 +1,81 @@ +function getCurrentTabUrl(callback) { + var queryInfo = { + active: true, + currentWindow: true + }; + + chrome.tabs.query(queryInfo, function(tabs) { + var tab = tabs[0]; + + var url = tab.url; + + callback(url); + }); +} + +chrome.pageAction.onClicked.addListener(function(tab) { + getCurrentTabUrl(function(url) { + var filename = url.substr(url.lastIndexOf("/")); + + chrome.storage.sync.get({url: '', behaviour: ''}, function(items) { + if(items.url == '') { + alert("Please select a Pomf clone."); + chrome.tabs.create({ url: "options.html" }); + return; + } + + var worker = new Worker('worker.js'); + worker.onmessage = function(event) { + var response = JSON.parse(event.data); + + var newUrl = response.files[0].url; + + switch(items.behaviour) + { + case "newtab": + chrome.tabs.create({url: newUrl}); + break; + case "replacetab": + chrome.tabs.update({url: newUrl}); + break; + } + }; + worker.postMessage(JSON.stringify({pomfclone: items.url, url: url, filename: filename})); + }); + }); +}); + +function isCoolUrl(url) { + url = url.toLowerCase(); + + var extensionIndex = url.lastIndexOf('.'); + var extension = url.substr(extensionIndex + 1); + + var validExtensions = ["jpg", "jpeg", "png", "gif", "webm"]; + + var blackList = ["pomf", "mixtape.moe", "catgirlsare.sexy", "cocaine.ninja"]; + + for(black of blackList) { + if(url.indexOf(black) != -1) { + return false; + } + } + + return validExtensions.indexOf(extension) != -1; +} + +chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { + if(isCoolUrl(tab.url) && tab.active) + { + chrome.pageAction.show(tabId); + } +}); + +chrome.tabs.onActivated.addListener(function(activeInfo) { + chrome.tabs.get(activeInfo.tabId, function(tab) { + if(isCoolUrl(tab.url)) + { + chrome.pageAction.show(activeInfo.tabId); + } + }); +}); diff --git a/formdata.js b/formdata.js new file mode 100644 index 0000000..923f24a --- /dev/null +++ b/formdata.js @@ -0,0 +1,98 @@ +/* + * FormData for XMLHttpRequest 2 - Polyfill for Web Worker + * (c) 2014 Rob Wu + * License: MIT + * - append(name, value[, filename]) + * - XMLHttpRequest.prototype.send(object FormData) + * + * Specification: http://www.w3.org/TR/XMLHttpRequest/#formdata + * http://www.w3.org/TR/XMLHttpRequest/#the-send-method + * The .append() implementation also accepts Uint8Array and ArrayBuffer objects + * Web Workers do not natively support FormData: + * http://dev.w3.org/html5/workers/#apis-available-to-workers + * Originally released in 2012 as a part of http://stackoverflow.com/a/10002486. + * Updates since initial release: + * - Forward-compatibility by testing whether FormData exists before defining it. + * - Increased robustness of .append. + * - Allow any typed array in .append. + * - Remove use of String.prototype.toString to work around a Firefox bug. + * - Use typed array in xhr.send instead of arraybuffer to get rid of deprecation + * warnings. + **/ +(function(exports) { + if (exports.FormData) { + // Don't replace FormData if it already exists + //return; + } + // Export variable to the global scope + exports.FormData = FormData; + + var ___send$rw = XMLHttpRequest.prototype.send; + XMLHttpRequest.prototype.send = function(data) { + if (data instanceof FormData) { + if (!data.__endedMultipart) data.__append('--' + data.boundary + '--\r\n'); + data.__endedMultipart = true; + this.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + data.boundary); + data = new Uint8Array(data.data); + } + // Invoke original XHR.send + return ___send$rw.call(this, data); + }; + + function FormData() { + // Force a Constructor + if (!(this instanceof FormData)) return new FormData(); + // Generate a random boundary - This must be unique with respect to the form's contents. + this.boundary = '------RWWorkerFormDataBoundary' + Math.random().toString(36); + var internal_data = this.data = []; + /** + * Internal method. + * @param inp String | ArrayBuffer | Uint8Array Input + */ + this.__append = function(inp) { + var i = 0, len; + if (typeof inp == 'string') { + for (len = inp.length; i < len; ++i) + internal_data.push(inp.charCodeAt(i) & 0xff); + } else if (inp && inp.byteLength) {/*If ArrayBuffer or typed array */ + if (!('byteOffset' in inp)) /* If ArrayBuffer, wrap in view */ + inp = new Uint8Array(inp); + for (len = inp.byteLength; i < len; ++i) + internal_data.push(inp[i] & 0xff); + } + }; + } + /** + * @param name String Key name + * @param value String|Blob|File|typed array|ArrayBuffer Value + * @param filename String Optional File name (when value is not a string). + **/ + FormData.prototype.append = function(name, value, filename) { + if (this.__endedMultipart) { + // Truncate the closing boundary + this.data.length -= this.boundary.length + 6; + this.__endedMultipart = false; + } + if (arguments.length < 2) { + throw new SyntaxError('Not enough arguments'); + } + var part = '--' + this.boundary + '\r\n' + + 'Content-Disposition: form-data; name="' + name + '"'; + + if (value instanceof File || value instanceof Blob) { + return this.append(name, + new Uint8Array(new FileReaderSync().readAsArrayBuffer(value)), + filename || value.name); + } else if (typeof value.byteLength == 'number') { + // Duck-typed typed array or array buffer + part += '; filename="'+ (filename || 'blob').replace(/"/g,'%22') +'"\r\n'; + part += 'Content-Type: application/octet-stream\r\n\r\n'; + this.__append(part); + this.__append(value); + part = '\r\n'; + } else { + part += '\r\n\r\n' + value + '\r\n'; + } + this.__append(part); + }; +})(this || self); diff --git a/icon_128.png b/icon_128.png new file mode 100644 index 0000000..3f9c06b Binary files /dev/null and b/icon_128.png differ diff --git a/icon_19.png b/icon_19.png new file mode 100644 index 0000000..bbbe24c Binary files /dev/null and b/icon_19.png differ diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..40c02ae --- /dev/null +++ b/manifest.json @@ -0,0 +1,28 @@ +{ + "manifest_version": 2, + + "name": "pomf-rehost", + "description": "This extension rehosts an image by uploading it to a Pomf-based file hosting service", + "version": "1.0", + + "icons":{ "128": "icon_128.png"}, + + "options_page": "options.html", + + "background": { + "scripts": ["background.js"], + "presistent": false + }, + + "page_action": { + "default_icon": "icon_19.png" + }, + + "permissions": [ + "activeTab", + "tabs", + "storage", + "http://*/*", + "https://*/*" + ] +} diff --git a/options.html b/options.html new file mode 100644 index 0000000..2348034 --- /dev/null +++ b/options.html @@ -0,0 +1,44 @@ + + + pomf-rehost options + + + Pomf clone: + + +
+ + URL: + + +
+
+ + After upload:
+ Open new tab
+ Replace current tab + +
+
+ + + +
+ +
+ + + + diff --git a/options.js b/options.js new file mode 100644 index 0000000..92520ee --- /dev/null +++ b/options.js @@ -0,0 +1,68 @@ +document.getElementById('status').textContent = 'Loading...'; + +custom = false; + +function setUrlBox() { + var pomfclone = document.getElementById('pomfclone').value; + var urlbox = document.getElementById('urlbox'); + + if(custom) { + customUrl = urlbox.value; + } + + if(pomfclone != "custom") { + urlbox.value = pomfclone; + urlbox.disabled = true; + + custom = false; + } else { + urlbox.value = customUrl; + urlbox.disabled = false; + + custom = true; + } +} + +function saveOptions() { + var pomfclone = document.getElementById('pomfclone').value; + var url = document.getElementById('urlbox').value; + var behaviour = document.querySelector('input[name="behaviour"]:checked').value; + + chrome.storage.sync.set({ + pomfclone: pomfclone, + url: url, + customUrl: customUrl, + behaviour: behaviour + }, function() { + var status = document.getElementById('status'); + status.textContent = 'Options saved.'; + setTimeout(function() { + status.textContent = ''; + }, 750); + }); +} + +function restoreOptions() { + var firstPomfclone = document.getElementById('pomfclone').getElementsByTagName('option')[0]; + + chrome.storage.sync.get({ + pomfclone: firstPomfclone.innerHTML, + url: firstPomfclone.value, + customUrl: '', + behaviour: document.querySelector('input[name="behaviour"]:checked').value + }, function(items) { + document.getElementById('pomfclone').value = items.pomfclone; + document.getElementById('urlbox').value = items.url; + customUrl = items.customUrl; + custom = items.pomfclone == "custom"; + setUrlBox(); + + document.getElementById(items.behaviour).checked = true; + }); + + document.getElementById('status').textContent = ''; +} + +document.addEventListener('DOMContentLoaded', restoreOptions); +document.getElementById('save').addEventListener('click', saveOptions); +document.getElementById('pomfclone').onchange = setUrlBox; diff --git a/worker.js b/worker.js new file mode 100644 index 0000000..24a98eb --- /dev/null +++ b/worker.js @@ -0,0 +1,29 @@ +importScripts('formdata.js') + +self.onmessage = function(event) { + var data = JSON.parse(event.data); + + var request = new XMLHttpRequest(); + request.open('GET', data.url, true); + request.responseType = 'arraybuffer'; + request.onload = function(e) { + if (request.status == 200) { + uploadBuffer(data.pomfclone, request.response, data.filename); + } + }; + request.send(); +}; + +function uploadBuffer(pomfclone, buffer, filename) { + var formData = new FormData(); + formData.append('files[]', buffer, filename); + + var request = new XMLHttpRequest(); + request.open('POST', pomfclone + '/upload.php', true); + request.onload = function(e) { + console.log(request.response); + + postMessage(request.response); + }; + request.send(formData); +};