diff options
| author | 8cy <[email protected]> | 2020-05-23 02:25:46 -0700 |
|---|---|---|
| committer | 8cy <[email protected]> | 2020-05-23 02:25:46 -0700 |
| commit | 7565a48b941c0d2237b0c90a4e0e906b5581e161 (patch) | |
| tree | beb54a16e8009eb1782bb9577fd6c59573ed7bfe | |
| download | strelizia-extension-7565a48b941c0d2237b0c90a4e0e906b5581e161.tar.xz strelizia-extension-7565a48b941c0d2237b0c90a4e0e906b5581e161.zip | |
| -rw-r--r-- | .gitattributes | 2 | ||||
| -rw-r--r-- | .vscode/settings.json | 5 | ||||
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | axios.min.js | 3 | ||||
| -rw-r--r-- | background.js | 602 | ||||
| -rw-r--r-- | backup/logo-128x128.png | bin | 0 -> 35419 bytes | |||
| -rw-r--r-- | backup/logo-48x48.png | bin | 0 -> 24050 bytes | |||
| -rw-r--r-- | backup/logo.png | bin | 0 -> 59261 bytes | |||
| -rw-r--r-- | content.css | 21 | ||||
| -rw-r--r-- | content.js | 111 | ||||
| -rw-r--r-- | logo-128x128.png | bin | 0 -> 17342 bytes | |||
| -rw-r--r-- | logo-48x48.png | bin | 0 -> 3857 bytes | |||
| -rw-r--r-- | logo.png | bin | 0 -> 43010 bytes | |||
| -rw-r--r-- | manifest.json | 36 | ||||
| -rw-r--r-- | settings.html | 103 | ||||
| -rw-r--r-- | settings.js | 42 |
16 files changed, 926 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..da0a6e6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "strelizia" + ] +}
\ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3a6bc5d --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# strelizia-extension
\ No newline at end of file diff --git a/axios.min.js b/axios.min.js new file mode 100644 index 0000000..6dfa1da --- /dev/null +++ b/axios.min.js @@ -0,0 +1,3 @@ +/* axios v0.15.3 | (c) 2016 by Matt Zabriskie */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(4),a=n(5),u=r(a);u.Axios=i,u.create=function(e){return r(o.merge(a,e))},u.Cancel=n(22),u.CancelToken=n(23),u.isCancel=n(19),u.all=function(e){return Promise.all(e)},u.spread=n(24),e.exports=u,e.exports.default=u},function(e,t,n){"use strict";function r(e){return"[object Array]"===C.call(e)}function o(e){return"[object ArrayBuffer]"===C.call(e)}function s(e){return"undefined"!=typeof FormData&&e instanceof FormData}function i(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function a(e){return"string"==typeof e}function u(e){return"number"==typeof e}function c(e){return"undefined"==typeof e}function f(e){return null!==e&&"object"==typeof e}function p(e){return"[object Date]"===C.call(e)}function d(e){return"[object File]"===C.call(e)}function l(e){return"[object Blob]"===C.call(e)}function h(e){return"[object Function]"===C.call(e)}function m(e){return f(e)&&h(e.pipe)}function y(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function w(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function g(){return"undefined"!=typeof window&&"undefined"!=typeof document&&"function"==typeof document.createElement}function v(e,t){if(null!==e&&"undefined"!=typeof e)if("object"==typeof e||r(e)||(e=[e]),r(e))for(var n=0,o=e.length;n<o;n++)t.call(null,e[n],n,e);else for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.call(null,e[s],s,e)}function x(){function e(e,n){"object"==typeof t[n]&&"object"==typeof e?t[n]=x(t[n],e):t[n]=e}for(var t={},n=0,r=arguments.length;n<r;n++)v(arguments[n],e);return t}function b(e,t,n){return v(t,function(t,r){n&&"function"==typeof t?e[r]=E(t,n):e[r]=t}),e}var E=n(3),C=Object.prototype.toString;e.exports={isArray:r,isArrayBuffer:o,isFormData:s,isArrayBufferView:i,isString:a,isNumber:u,isObject:f,isUndefined:c,isDate:p,isFile:d,isBlob:l,isFunction:h,isStream:m,isURLSearchParams:y,isStandardBrowserEnv:g,forEach:v,merge:x,extend:b,trim:w}},function(e,t){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(5),s=n(2),i=n(16),a=n(17),u=n(20),c=n(21);r.prototype.request=function(e){"string"==typeof e&&(e=s.merge({url:arguments[0]},arguments[1])),e=s.merge(o,this.defaults,{method:"get"},e),e.baseURL&&!u(e.url)&&(e.url=c(e.baseURL,e.url));var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},s.forEach(["delete","get","head"],function(e){r.prototype[e]=function(t,n){return this.request(s.merge(n||{},{method:e,url:t}))}}),s.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(s.merge(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e,t){!s.isUndefined(e)&&s.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}function o(){var e;return"undefined"!=typeof XMLHttpRequest?e=n(7):"undefined"!=typeof process&&(e=n(7)),e}var s=n(2),i=n(6),a=/^\)\]\}',?\n/,u={"Content-Type":"application/x-www-form-urlencoded"},c={adapter:o(),transformRequest:[function(e,t){return i(t,"Content-Type"),s.isFormData(e)||s.isArrayBuffer(e)||s.isStream(e)||s.isFile(e)||s.isBlob(e)?e:s.isArrayBufferView(e)?e.buffer:s.isURLSearchParams(e)?(r(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):s.isObject(e)?(r(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"==typeof e){e=e.replace(a,"");try{e=JSON.parse(e)}catch(e){}}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(e){return e>=200&&e<300}};c.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){c.headers[e]={}}),s.forEach(["post","put","patch"],function(e){c.headers[e]=s.merge(u)}),e.exports=c},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(8),s=n(11),i=n(12),a=n(13),u=n(9),c="undefined"!=typeof window&&window.btoa&&window.btoa.bind(window)||n(14);e.exports=function(e){return new Promise(function(t,f){var p=e.data,d=e.headers;r.isFormData(p)&&delete d["Content-Type"];var l=new XMLHttpRequest,h="onreadystatechange",m=!1;if("undefined"==typeof window||!window.XDomainRequest||"withCredentials"in l||a(e.url)||(l=new window.XDomainRequest,h="onload",m=!0,l.onprogress=function(){},l.ontimeout=function(){}),e.auth){var y=e.auth.username||"",w=e.auth.password||"";d.Authorization="Basic "+c(y+":"+w)}if(l.open(e.method.toUpperCase(),s(e.url,e.params,e.paramsSerializer),!0),l.timeout=e.timeout,l[h]=function(){if(l&&(4===l.readyState||m)&&(0!==l.status||l.responseURL&&0===l.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in l?i(l.getAllResponseHeaders()):null,r=e.responseType&&"text"!==e.responseType?l.response:l.responseText,s={data:r,status:1223===l.status?204:l.status,statusText:1223===l.status?"No Content":l.statusText,headers:n,config:e,request:l};o(t,f,s),l=null}},l.onerror=function(){f(u("Network Error",e)),l=null},l.ontimeout=function(){f(u("timeout of "+e.timeout+"ms exceeded",e,"ECONNABORTED")),l=null},r.isStandardBrowserEnv()){var g=n(15),v=(e.withCredentials||a(e.url))&&e.xsrfCookieName?g.read(e.xsrfCookieName):void 0;v&&(d[e.xsrfHeaderName]=v)}if("setRequestHeader"in l&&r.forEach(d,function(e,t){"undefined"==typeof p&&"content-type"===t.toLowerCase()?delete d[t]:l.setRequestHeader(t,e)}),e.withCredentials&&(l.withCredentials=!0),e.responseType)try{l.responseType=e.responseType}catch(e){if("json"!==l.responseType)throw e}"function"==typeof e.onDownloadProgress&&l.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&l.upload&&l.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){l&&(l.abort(),f(e),l=null)}),void 0===p&&(p=null),l.send(p)})}},function(e,t,n){"use strict";var r=n(9);e.exports=function(e,t,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?t(r("Request failed with status code "+n.status,n.config,null,n)):e(n)}},function(e,t,n){"use strict";var r=n(10);e.exports=function(e,t,n,o){var s=new Error(e);return r(s,t,n,o)}},function(e,t){"use strict";e.exports=function(e,t,n,r){return e.config=t,n&&(e.code=n),e.response=r,e}},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)&&(t+="[]"),o.isArray(e)||(e=[e]),o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}return s&&(e+=(e.indexOf("?")===-1?"?":"&")+s),e}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e){var t,n,o,s={};return e?(r.forEach(e.split("\n"),function(e){o=e.indexOf(":"),t=r.trim(e.substr(0,o)).toLowerCase(),n=r.trim(e.substr(o+1)),t&&(s[t]=s[t]?s[t]+", "+n:n)}),s):s}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){function e(e){var t=e;return n&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(n){var o=r.isString(n)?e(n):n;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t){"use strict";function n(){this.message="String contains an invalid character"}function r(e){for(var t,r,s=String(e),i="",a=0,u=o;s.charAt(0|a)||(u="=",a%1);i+=u.charAt(63&t>>8-a%1*8)){if(r=s.charCodeAt(a+=.75),r>255)throw new n;t=t<<8|r}return i}var o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";n.prototype=new Error,n.prototype.code=5,n.prototype.name="InvalidCharacterError",e.exports=r},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){return{write:function(e,t,n,o,s,i){var a=[];a.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(s)&&a.push("domain="+s),i===!0&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(2);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(2),s=n(18),i=n(19),a=n(5);e.exports=function(e){r(e),e.headers=e.headers||{},e.data=s(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]});var t=e.adapter||a.adapter;return t(e).then(function(t){return r(e),t.data=s(t.data,t.headers,e.transformResponse),t},function(t){return i(t)||(r(e),t&&t.response&&(t.response.data=s(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t){"use strict";e.exports=function(e,t){return e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,"")}},function(e,t){"use strict";function n(e){this.message=e}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,e.exports=n},function(e,t,n){"use strict";function r(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new o(e),t(n.reason))})}var o=n(22);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var e,t=new r(function(t){e=t});return{token:t,cancel:e}},e.exports=r},function(e,t){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}}])}); +//# sourceMappingURL=axios.min.map
\ No newline at end of file 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 diff --git a/backup/logo-128x128.png b/backup/logo-128x128.png Binary files differnew file mode 100644 index 0000000..29c1a5b --- /dev/null +++ b/backup/logo-128x128.png diff --git a/backup/logo-48x48.png b/backup/logo-48x48.png Binary files differnew file mode 100644 index 0000000..4f21545 --- /dev/null +++ b/backup/logo-48x48.png diff --git a/backup/logo.png b/backup/logo.png Binary files differnew file mode 100644 index 0000000..94b6797 --- /dev/null +++ b/backup/logo.png diff --git a/content.css b/content.css new file mode 100644 index 0000000..7f070b1 --- /dev/null +++ b/content.css @@ -0,0 +1,21 @@ +#loli-lasso { + position: fixed; + border: 1px dotted; + background: rgba(255, 255, 255, 0.1); + display: none; + left: 0; + right: 0; + width: 0; + height: 0; + z-index: 999; +} + +body.loli-filter:after { + content: ''; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 998; +}
\ No newline at end of file diff --git a/content.js b/content.js new file mode 100644 index 0000000..25e3de3 --- /dev/null +++ b/content.js @@ -0,0 +1,111 @@ +let loliLasso = document.createElement('div'); +loliLasso.setAttribute('id', 'loli-lasso'); +document.body.appendChild(loliLasso); + +let firstPos; +let secondPos; + +const captureFunctions = { + mousedown: (event) => { + + if (event.buttons !== 1) return; + + setStyles('#loli-lasso', { + display: 'block', + top: event.clientY + 'px', + left: event.clientX + 'px' + }); + + firstPos = { x: event.clientX, y: event.clientY }; + + }, + mousemove: (event) => { + + if (event.buttons !== 1) return + + const originalTop = $('#loli-lasso').style.top; + const originalLeft = $('#loli-lasso').style.left; + + const height = event.clientY - firstPos.y; + const width = event.clientX - firstPos.x; + + setStyles('#loli-lasso', { + top: (height > 0) + ? originalTop + : event.clientY + 'px', + height: (height > 0) + ? height + 'px' + : (firstPos.y - event.clientY) + 'px', + left: (width > 0) + ? originalLeft + : event.clientX + 'px', + width: (width > 0) + ? width + 'px' + : (firstPos.x - event.clientX) + 'px' + }); + }, + mouseup: (event) => { + + if (event.which !== 1) return; + + document.body.classList.remove('loli-filter'); + + setStyles('body', { + cursor: 'initial', + userSelect: 'initial' + }); + + setStyles('#loli-lasso', { + display: 'none', + top: 0, left: 0, + height: 0, width: 0 + }); + + secondPos = { + x: (event.clientX < window.innerWidth) + ? event.clientX + : window.innerWidth, + y: (event.clientY < window.innerHeight) + ? event.clientY + : window.innerHeight + }; + + document.removeEventListener('mousedown', captureFunctions.mousedown); + document.removeEventListener('mousemove', captureFunctions.mousemove); + document.removeEventListener('mouseup', captureFunctions.mouseup); + + setTimeout(() => chrome.runtime.sendMessage({ coordinates: [firstPos, secondPos] }), 100); + + } +}; + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + + if (request === 'select') { + + setStyles('body', { + cursor: 'crosshair', + userSelect: 'none' + }); + + document.body.classList.add('loli-filter'); + + document.addEventListener('mousedown', captureFunctions.mousedown); + document.addEventListener('mousemove', captureFunctions.mousemove); + document.addEventListener('mouseup', captureFunctions.mouseup); + + } else if (request === 'check') { + + sendResponse(true); + + } + +}); + +const $ = (el) => document.querySelector(el); + +function setStyles(element, styles) { + let el = document.querySelector(element); + for (let style in styles) + el.style[style] = styles[style]; +}
\ No newline at end of file diff --git a/logo-128x128.png b/logo-128x128.png Binary files differnew file mode 100644 index 0000000..c13dd29 --- /dev/null +++ b/logo-128x128.png diff --git a/logo-48x48.png b/logo-48x48.png Binary files differnew file mode 100644 index 0000000..3fed93d --- /dev/null +++ b/logo-48x48.png diff --git a/logo.png b/logo.png Binary files differnew file mode 100644 index 0000000..0ca96d2 --- /dev/null +++ b/logo.png diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..be28db0 --- /dev/null +++ b/manifest.json @@ -0,0 +1,36 @@ + { + "manifest_version": 2, + "name": "strelizia Uploader", + "description": "Uploader for strelizia", + "version": "2019.1.24.1", + "version_name": "Biribiri", + "options_ui": { + "page": "settings.html", + "chrome_style": false, + "open_in_tab": true + }, + "icons": { + "48": "logo-48x48.png", + "128": "logo-128x128.png" + }, + "permissions": [ + "contextMenus", + "storage", + "notifications", + "tabs", + "webRequest", + "webRequestBlocking", + "<all_urls>" + ], + "background": { + "scripts": [ + "axios.min.js", + "background.js" + ], + "persistent": true + }, + "web_accessible_resources": [ + "content.js", + "content.css" + ] + } diff --git a/settings.html b/settings.html new file mode 100644 index 0000000..50e753f --- /dev/null +++ b/settings.html @@ -0,0 +1,103 @@ +<!DOCTYPE html> +<html> +<head> + <title>strelizia Settings</title> + <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro" rel="stylesheet"> + <style type="text/css"> + + * { + font-family: 'Source Sans Pro', sans-serif; + color: #3c3c3c; + } + + p#b { + border-radius: 24px; + display: inline-block; + height: 240px; + margin-bottom: 40px; + position: relative; + vertical-align: top; + width: 240px; + box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2); + } + + p#b img.logo { + height: 200px; + margin-top: 20px; + } + + div.container { + text-align: center; + width: 870px; + margin: 0 auto; + } + + h2 { + text-decoration: underline; + text-align: center; + } + + input[type="text"] { + border: 0px; + border-bottom: 1px solid #adadad; + font-size: 16px; + width: 400px; + padding: 10px; + outline: none; + text-align: center; + } + + input[type="text"]:focus { + border-bottom: 1px solid #00d1b2 + } + + button { + background: rgba(0, 0, 0, 0); + border: 1px solid #00d1b2; + width: 200px; + height: 40px; + font-size: 14px; + border-radius: 5px; + margin-top: 20px; + } + + button:hover { + background: #00d1b2; + color: white; + } + #autoCopyUrl { + vertical-align: sub; + } + </style> +</head> +<body> + <div class="container"> + + <p id="b"> + <img class="logo" src="logo.png"> + </p> + + <p> + This page will help you setup your strelizia extension so you can rehost images/audio/videos by right clicking on them. For this to work you need to provide the domain were strelizia is running. If you want to keep track of your uploads and be able to create albums to store them, you should create an account on the website and paste the token here, so that every upload gets tied to your account, enabling you to go back to the site and see all of your uploaded files. + </p> + + <p>Domain on which strelizia is running:</p> + <input type="text" id="domain" placeholder="https://strelizia.cc"> + + <p>Your strelizia token (optional):</p> + <input type="text" id="token" placeholder="your-super-secret-token"> + + <p> + <label>Automatically copy URL to clipboard after upload <input type="checkbox" id="autoCopyUrl"></label> + </p> + + + <p></p> + + <button id="save">Save</button> + + <script src="settings.js"></script> + + </div> +</body> +</html> diff --git a/settings.js b/settings.js new file mode 100644 index 0000000..4b8535d --- /dev/null +++ b/settings.js @@ -0,0 +1,42 @@ +const storage = chrome.storage.local; +const background = chrome.extension.getBackgroundPage(); + +document.addEventListener('DOMContentLoaded', () => { + storage.get({ domain: '', token: '', autoCopyUrl: false }, (items) => { + for (key in items) { + let el = document.getElementById(key); + if (el) { + if (el.type === 'checkbox') + el.checked = items[key]; + else + el.value = items[key]; + } + } + }); +}); + +document.getElementById('save').addEventListener('click', () => { + + const textDomain = document.getElementById('domain').value; + const textToken = document.getElementById('token').value; + const autoCopyUrl = document.getElementById('autoCopyUrl').checked; + + if (!textDomain) + return alert('strelizia domain is required!'); + + storage.set({ + domain: textDomain, + token: textToken, + autoCopyUrl: autoCopyUrl + }, () => { + background.createContextMenus(); + let notification = background.createNotification('basic', 'Settings Saved!'); + setTimeout(() => chrome.notifications.clear(notification), 5000); + }); + +}); + +document.getElementById('domain').addEventListener('blur', function() { + if (this.value.slice(-1) === '/') + this.value = this.value.slice(0, -1); +});
\ No newline at end of file |