aboutsummaryrefslogtreecommitdiff
path: root/background.js
diff options
context:
space:
mode:
Diffstat (limited to 'background.js')
-rw-r--r--background.js602
1 files changed, 602 insertions, 0 deletions
diff --git a/background.js b/background.js
new file mode 100644
index 0000000..af5299d
--- /dev/null
+++ b/background.js
@@ -0,0 +1,602 @@
+/* global chrome axios */
+
+const storage = chrome.storage.local;
+
+const isFirefox = typeof InstallTrigger !== 'undefined';
+
+chrome.runtime.onInstalled.addListener((details) => {
+ if (details.reason == 'update') {
+
+ storage.get((items) => {
+
+ let newItems = {};
+
+ if (items.textDomain) {
+ newItems.domain = items.textDomain;
+ storage.remove('textDomain');
+ }
+
+ if (items.textToken) {
+ newItems.token = items.textToken;
+ storage.remove('textToken');
+ }
+
+ storage.set(newItems);
+
+ });
+
+ }
+});
+
+const contexts = ['image', 'video', 'audio'];
+
+let config = {};
+
+storage.get({
+ domain: '',
+ panelURL: '/dashboard',
+ token: '',
+ lastAlbum: null,
+ autoCopyUrl: false
+}, (items) => {
+ config = items;
+ createContextMenus();
+});
+
+chrome.storage.onChanged.addListener((changes) => {
+ for (const key in changes) {
+ config[key] = changes[key].newValue;
+ if (key === 'token') createContextMenus();
+ }
+});
+
+function createContextMenus() {
+
+ if (!config.domain) return;
+
+ /* == Not the best way to do this but when have I ever done something efficiently? == */
+ chrome.contextMenus.removeAll(() => {
+
+ console.log('Removed old Context Menus');
+
+ /* == Parent Context Menu == */
+ contextMenus.parent = chrome.contextMenus.create({
+ title: 'strelizia',
+ contexts: ['all'],
+ onclick: () => chrome.tabs.create({ url: config.domain + config.panelURL })
+ });
+
+ /* == Upload normally == */
+ chrome.contextMenus.create({
+ title: 'Send to safe',
+ parentId: contextMenus.parent,
+ contexts: contexts,
+ onclick: (info) => upload(info.srcUrl, info.pageUrl)
+ });
+
+ /* == Screenshot page == */
+ chrome.contextMenus.create({
+ title: 'Screenshot page',
+ parentId: contextMenus.parent,
+ contexts: ['page'],
+ onclick: () => {
+ chrome.tabs.captureVisibleTab({ format: 'png' }, (data) => {
+ let blob = b64toBlob(data.replace('data:image/png;base64,', ''), 'image/png');
+ uploadScreenshot(blob);
+ });
+ }
+ });
+
+ /* == Screenshot selection == */
+ chrome.contextMenus.create({
+ title: 'Screenshot selection',
+ parentId: contextMenus.parent,
+ contexts: ['page'],
+ onclick: () => {
+ chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
+ chrome.tabs.sendMessage(tabs[0].id, 'check', (response) => {
+ if (response) {
+ chrome.tabs.sendMessage(tabs[0].id, 'select');
+ } else {
+ chrome.tabs.insertCSS(null, { file: 'content.css' });
+ chrome.tabs.executeScript(null, { file: 'content.js' }, () => {
+ chrome.tabs.sendMessage(tabs[0].id, 'select');
+ });
+ }
+ });
+ });
+ }
+ });
+
+ if (config.token) {
+
+ /* == Separator == */
+ chrome.contextMenus.create({
+ parentId: contextMenus.parent,
+ contexts: contexts,
+ type: 'separator'
+ });
+
+ /* == Refresh Album List == */
+ chrome.contextMenus.create({
+ title: 'Refresh Albums List',
+ parentId: contextMenus.parent,
+ contexts: contexts,
+ onclick: createContextMenus
+ });
+
+ /* == Separator == */
+ chrome.contextMenus.create({
+ parentId: contextMenus.parent,
+ contexts: contexts,
+ type: 'separator'
+ });
+
+ axios.get(config.domain + '/api/albums', {
+ headers: { token: config.token }
+ }).then((list) => {
+
+ if (list.data.albums.length === 0) {
+
+ chrome.contextMenus.create({
+ title: 'No Albums Available',
+ parentId: contextMenus.parent,
+ contexts: contexts,
+ type: 'normal',
+ enabled: false
+ });
+
+ } else {
+
+ const lastAlbum = list.data.albums.find(a => a.id === config.lastAlbum);
+
+ contextMenus.lastAlbum = chrome.contextMenus.create({
+ title: `Upload to: ${lastAlbum ? lastAlbum.name : 'None'}`,
+ parentId: contextMenus.parent,
+ contexts: contexts,
+ enabled: !!lastAlbum,
+ onclick: (info) => upload(info.srcUrl, info.pageUrl, lastAlbum.id, lastAlbum.name)
+ });
+
+ /* == Separator == */
+ chrome.contextMenus.create({
+ parentId: contextMenus.parent,
+ contexts: contexts,
+ type: 'separator'
+ });
+
+ contextMenus.albumsParent = chrome.contextMenus.create({
+ title: 'Upload to:',
+ parentId: contextMenus.parent,
+ contexts: contexts,
+ type: 'normal',
+ enabled: false
+ });
+
+ list.data.albums.forEach((album) => {
+ console.log(album.id, album.name);
+ contextMenus.createAlbumMenu(album.id, album.name);
+ });
+
+ }
+
+ }).catch((err) => {
+
+ console.log(err);
+
+ chrome.contextMenus.create({
+ title: 'Error Getting Albums',
+ parentId: contextMenus.parent,
+ contexts: contexts,
+ type: 'normal',
+ enabled: false
+ });
+
+ });
+
+ }
+
+ });
+
+}
+
+let contextMenus = {
+ parent: null,
+ albumsParent: null,
+ lastAlbum: null,
+ createAlbumMenu: (id, name, enabled = true) => {
+ chrome.contextMenus.create({
+ title: name.replace('&', '&&'),
+ parentId: contextMenus.parent,
+ // parentId: contextMenus.albumsParent,
+ contexts, enabled,
+ onclick: (info) => upload(info.srcUrl, info.pageUrl, id, name)
+ });
+ }
+};
+
+let refererHeader = null;
+let contentURL = '';
+let recentlyUploaded = new Map();
+
+let opt_extraInfoSpec = ['blocking', 'requestHeaders'];
+
+const chromeVersionCheck = navigator.userAgent.match(/Chrome\/(\d+)/);
+
+if (chromeVersionCheck && parseInt(chromeVersionCheck[1]) >= 72)
+ opt_extraInfoSpec.push('extraHeaders');
+
+/* == We need to set this header for image sources that check it for auth or to prevent hotlinking == */
+chrome.webRequest.onBeforeSendHeaders.addListener((details) => {
+
+ if (details.tabId === -1 && details.method === 'GET' && refererHeader !== null) {
+
+ details.requestHeaders.push({
+ name: 'Referer',
+ value: refererHeader
+ });
+
+ details.requestHeaders.push({
+ name: 'Referrer',
+ value: refererHeader
+ });
+
+ }
+
+ return {requestHeaders: details.requestHeaders};
+
+}, { urls: ['<all_urls>'] }, opt_extraInfoSpec);
+
+function upload(url, pageURL, albumID, albumName) {
+
+ if (albumID)
+ storage.set({ lastAlbum: albumID }, () => {
+ chrome.contextMenus.update(contextMenus.lastAlbum, {
+ enabled: true,
+ title: `Upload to: ${albumName}`,
+ onclick: (info) => upload(info.srcUrl, info.pageUrl, albumID, albumName)
+ });
+ });
+
+ let notification = createNotification('basic', 'Retriving file...', null, true);
+
+ refererHeader = pageURL;
+
+ axios.get(url, { responseType: 'blob' }).then((file) => {
+
+ refererHeader = null;
+
+ if (!isFirefox) {
+ chrome.notifications.update(notification, {
+ type: 'progress',
+ message: 'Uploading...',
+ progress: 0
+ });
+ }
+
+ let data = new FormData();
+ data.append('files[]', file.data, 'upload' + fileExt(file.data.type));
+
+ let options = {
+ method: 'POST',
+ url: `${config.domain}/api/upload`,
+ data,
+ headers: {
+ token: config.token
+ },
+ onUploadProgress: (progress) => {
+ if (!isFirefox) {
+ chrome.notifications.update(notification, {
+ progress: Math.round((progress.loaded * 100) / progress.total)
+ });
+ }
+ }
+ };
+
+ if (albumID && config.token)
+ options.url = options.url + '/' + albumID;
+
+ axios.request(options).then((response) => {
+
+ if (response.data.success === true || response.data.files) {
+
+ recentlyUploaded.set(notification, response.data.files[0].name);
+
+ if (!isFirefox) {
+ chrome.notifications.update(notification, {
+ type: 'basic',
+ message: 'Upload Complete!',
+ contextMessage: response.data.files[0].url,
+ buttons: config.autoCopyUrl ? [] : [{ title: 'Copy to clipboard' }, { title: 'Delete Upload' }]
+ });
+ } else {
+ createNotification('basic', 'Upload Complete!');
+ }
+
+ if (config.autoCopyUrl)
+ copyText(response.data.files[0].url);
+
+ contentURL = response.data.files[0].url;
+
+ setTimeout(() => chrome.notifications.clear(notification), 5000);
+
+ } else {
+
+ if (!isFirefox) {
+ chrome.notifications.update(notification, {
+ type: 'basic',
+ message: response.data.description || response.data.message,
+ contextMessage: url,
+ });
+ } else {
+ createNotification('basic', response.data.description || response.data.message);
+ }
+
+ }
+
+ }).catch((err) => {
+
+ console.error(err);
+
+ if (!isFirefox) {
+ chrome.notifications.update(notification, {
+ type: 'basic',
+ message: 'Error!',
+ contextMessage: err.toString(),
+ });
+ } else {
+ createNotification('basic', `Error!\n${err.toString()}`);
+ }
+
+ });
+
+ });
+
+}
+
+function deleteFile(filename) {
+ let headers = {
+ token: config.token
+ };
+ axios.get(`${config.domain}/api/uploads/0`, { headers }).then(response => {
+ let file = response.data.files.find(a => a.name === filename);
+ return axios.post(`${config.domain}/api/upload/delete`, { id: file.id }, { headers }).then(res => {
+ if (res.data.success) {
+ createNotification('basic', `File ${filename} was deleted!`);
+ } else {
+ createNotification('basic', 'Error\nUnable to delete the file.');
+ }
+ });
+ }).catch(() => {
+ createNotification('basic', 'Error\nUnable to delete the file.');
+ });
+}
+
+function uploadScreenshot(blob, albumID) {
+
+ let notification = createNotification('progress', 'Uploading...', null, true, 0);
+
+ let data = new FormData();
+
+ data.append('files[]', blob, 'upload.png');
+
+ let options = {
+ method: 'POST',
+ url: `${config.domain}/api/upload`,
+ data,
+ headers: {
+ token: config.token
+ },
+ onUploadProgress: (progress) => {
+ if (!isFirefox) {
+ chrome.notifications.update(notification, {
+ progress: Math.round((progress.loaded * 100) / progress.total)
+ });
+ }
+ }
+ };
+
+ if (albumID && config.token)
+ options.url = options.url + '/' + albumID;
+
+ axios.request(options).then((response) => {
+
+ if (response.data.success === true || response.data.files) {
+
+ if (!isFirefox) {
+ chrome.notifications.update(notification, {
+ type: 'basic',
+ message: 'Upload Complete!',
+ contextMessage: response.data.files[0].url,
+ buttons: config.autoCopyUrl ? [] : [{ title: 'Copy to clipboard' }]
+ });
+ } else {
+ createNotification('basic', 'Upload Complete!');
+ }
+
+ if (config.autoCopyUrl)
+ copyText(response.data.files[0].url);
+
+ contentURL = response.data.files[0].url;
+
+ setTimeout(() => chrome.notifications.clear(notification), 5000);
+
+ } else {
+
+ if (!isFirefox) {
+ chrome.notifications.update(notification, {
+ type: 'basic',
+ message: response.data.description || response.data.message
+ });
+ } else {
+ createNotification('basic', response.data.description || response.data.message);
+ }
+
+ }
+
+ }).catch((err) => {
+
+ console.error(err);
+
+ if (!isFirefox) {
+ chrome.notifications.update(notification, {
+ type: 'basic',
+ message: 'Error!',
+ contextMessage: err.toString(),
+ });
+ } else {
+ createNotification('basic', `Error!\n${err.toString()}`);
+ }
+
+ });
+
+}
+
+chrome.runtime.onMessage.addListener((request) => {
+
+ if ('coordinates' in request) {
+
+ let pos = request.coordinates;
+
+ chrome.tabs.captureVisibleTab({ format: 'png' }, (data) => {
+
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+
+ const img = new Image();
+
+ img.onload = () => {
+
+ let resHeight = Math.abs(pos[0].y - pos[1].y);
+ let resWidth = Math.abs(pos[0].x - pos[1].x);
+
+ if (resHeight === 0 || resWidth === 0) return;
+
+ let posX = pos[0].x < pos[1].x
+ ? pos[0].x
+ : pos[1].x;
+ let posY = pos[0].y < pos[1].y
+ ? pos[0].y
+ : pos[1].y;
+
+ canvas.height = resHeight;
+ canvas.width = resWidth;
+
+ ctx.drawImage(img, -posX, -posY);
+
+ let imageData = canvas.toDataURL();
+
+ let blob = b64toBlob(imageData.replace('data:image/png;base64,', ''), 'image/png');
+
+ uploadScreenshot(blob);
+
+ };
+
+ img.src = data;
+
+ });
+
+ }
+
+});
+
+function createNotification(type, message, altText, sticky, progress) {
+
+ let notificationContent = {
+ type,
+ title: 'strelizia',
+ message,
+ iconUrl: 'logo-128x128.png'
+ };
+
+ if (typeof InstallTrigger === 'undefined') // Does not work with firefox.
+ notificationContent.requireInteraction = sticky || false;
+
+ if (altText && typeof altText === 'string')
+ notificationContent.contextMessage = altText;
+
+ if (progress && typeof progress === 'number')
+ notificationContent.progress = progress;
+
+ let id = 'notification_' + Date.now();
+
+ chrome.notifications.create(id, notificationContent);
+
+ return id;
+
+}
+
+chrome.notifications.onClicked.addListener((id) => {
+ chrome.notifications.clear(id);
+});
+
+chrome.notifications.onClosed.addListener((id) => {
+ recentlyUploaded.delete(id);
+ contentURL = '';
+});
+
+chrome.notifications.onButtonClicked.addListener((id, index) => {
+ if (!config.autoCopyUrl && index === 0) copyText(contentURL);
+ if (index === 1) deleteFile(recentlyUploaded.get(id));
+ chrome.notifications.clear(id);
+});
+
+const mimetypes = {
+ 'image/png': '.png',
+ 'image/jpeg': '.jpg',
+ 'image/gif': '.gif',
+ 'image/bmp': '.bmp',
+ 'image/x-icon': '.ico',
+ 'video/mp4': '.mp4',
+ 'video/webm': '.webm',
+ 'video/quicktime': '.mov',
+ 'audio/mp4': '.mp4a',
+ 'audio/mpeg': '.mp3',
+ 'audio/ogg': '.ogg',
+ 'audio/x-aac': '.aac',
+ 'audio/x-wav': '.wav'
+};
+
+function fileExt(mimetype) {
+ return mimetypes[mimetype] || '.' + mimetype.split('/')[1];
+}
+
+function copyText(text) {
+ let input = document.createElement('textarea');
+ document.body.appendChild(input);
+ input.value = text;
+ input.focus();
+ input.select();
+ document.execCommand('Copy');
+ input.remove();
+}
+
+// http://stackoverflow.com/a/16245768
+function b64toBlob(b64Data, contentType, sliceSize) {
+
+ contentType = contentType || '';
+ sliceSize = sliceSize || 512;
+
+ let byteCharacters = atob(b64Data);
+ let byteArrays = [];
+
+ for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
+
+ let slice = byteCharacters.slice(offset, offset + sliceSize);
+
+ let byteNumbers = new Array(slice.length);
+
+ for (let i = 0; i < slice.length; i++) {
+ byteNumbers[i] = slice.charCodeAt(i);
+ }
+
+ let byteArray = new Uint8Array(byteNumbers);
+
+ byteArrays.push(byteArray);
+
+ }
+
+ let blob = new Blob(byteArrays, { type: contentType });
+
+ return blob;
+} \ No newline at end of file