1+ /*
2+ * uget-chrome-wrapper is an extension to integrate uGet Download manager
3+ * with Google Chrome, Chromium, Vivaldi and Opera in Linux and Windows.
4+ *
5+ * Copyright (C) 2016 Gobinath
6+ *
7+ * This program is free software: you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation, either version 3 of the License, or
10+ * (at your option) any later version.
11+ *
12+ * This program is distributed in the hope that it will be useful,
13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+ * GNU General Public License for more details.
16+ *
17+ * You should have received a copy of the GNU General Public License
18+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
19+ */
20+
21+ var interruptDownloads = true ;
22+ var ugetWrapperNotFound = true ;
23+ var interruptDownload = false ;
24+ var disposition = '' ;
25+ var hostName = 'com.javahelps.ugetchromewrapper' ;
26+ var ugetChromeWrapperVersion ;
27+ var ugetVersion ;
28+ var chromeVersion ;
29+ var filter = [ ] ;
30+ var keywords = [ ] ;
31+ var requestList = [ {
32+ cookies : '' ,
33+ postdata : '' ,
34+ id : ''
35+ } , {
36+ cookies : '' ,
37+ postdata : '' ,
38+ id : ''
39+ } , {
40+ cookies : '' ,
41+ postdata : '' ,
42+ id : ''
43+ } ] ;
44+ var currRequest = 0 ;
45+ try {
46+ chromeVersion = / C h r o m e \/ ( [ 0 - 9 ] + ) / . exec ( navigator . userAgent ) [ 1 ] ;
47+ } catch ( ex ) {
48+ chromeVersion = 33 ;
49+ }
50+ chromeVersion = parseInt ( chromeVersion ) ;
51+ sendMessageToHost ( { version : "2.0.0" } ) ;
52+
53+ if ( localStorage [ "uget-keywords" ] ) {
54+ keywords = localStorage [ "uget-keywords" ] . split ( / [ \s , ] + / ) ;
55+ } else {
56+ localStorage [ "uget-keywords" ] = '' ;
57+ }
58+
59+
60+ if ( ! localStorage [ "uget-interrupt" ] ) {
61+ localStorage [ "uget-interrupt" ] = 'true' ;
62+ } else {
63+ var interrupt = ( localStorage [ "uget-interrupt" ] == "true" ) ;
64+ setInterruptDownload ( interrupt ) ;
65+ }
66+ // Message format to send the download information to the uget-chrome-wrapper
67+ var message = {
68+ url : '' ,
69+ cookies : '' ,
70+ useragent : '' ,
71+ filename : '' ,
72+ filesize : '' ,
73+ referrer : '' ,
74+ postdata : ''
75+ } ;
76+
77+ // Listen to the key press
78+ chrome . extension . onRequest . addListener ( function ( request , sender , sendResponse ) {
79+ var msg = request . message ;
80+ if ( msg === 'enable' ) {
81+ // Temporarily enable
82+ setInterruptDownload ( true ) ;
83+ } else if ( msg == 'disable' ) {
84+ // Temporarily disable
85+ setInterruptDownload ( false ) ;
86+ } else {
87+ // Toggle
88+ setInterruptDownload ( ! interruptDownloads , true ) ;
89+ }
90+ } ) ;
91+
92+ // Send message to the uget-chrome-wrapper
93+ function sendMessageToHost ( message ) {
94+ chrome . runtime . sendNativeMessage ( hostName , message , function ( response ) {
95+ ugetWrapperNotFound = ( response == null ) ;
96+ if ( ! ugetWrapperNotFound ) {
97+ ugetChromeWrapperVersion = response . version ;
98+ ugetVersion = response . uget ;
99+ }
100+ } ) ;
101+ }
102+
103+ function getInfo ( ) {
104+ if ( ugetWrapperNotFound ) {
105+ return "<font color='red'>Error: Unable to connect to the uget-chrome-wrapper</font>" ;
106+ } else if ( ! ugetChromeWrapperVersion . startsWith ( "2." ) ) {
107+ return "<font color='orange'>Warning: Please update the uget-chrome-wrapper to the latest version</font>" ;
108+ } else {
109+ return "<font color='green'>Info: Found uGet: " + ugetVersion + " and uget-chrome-wrapper: " + ugetChromeWrapperVersion + "</font>" ;
110+ }
111+ }
112+ function clearMessage ( ) {
113+ message . url = '' ;
114+ message . cookies = '' ;
115+ message . filename = '' ;
116+ message . filesize = '' ;
117+ message . referrer = '' ;
118+ message . useragent = '' ;
119+ }
120+
121+ function postParams ( source ) {
122+ var array = [ ] ;
123+ for ( var key in source ) {
124+ array . push ( encodeURIComponent ( key ) + '=' + encodeURIComponent ( source [ key ] ) ) ;
125+ }
126+ return array . join ( '&' ) ;
127+ }
128+
129+ // Add to Chrome context menu
130+ chrome . contextMenus . create ( {
131+ title : 'Download with uGet' ,
132+ id : "download_with_uget" ,
133+ contexts : [ 'link' ]
134+ } ) ;
135+
136+ chrome . contextMenus . onClicked . addListener ( function ( info , tab ) {
137+ "use strict" ;
138+ if ( info . menuItemId === "download_with_uget" ) {
139+ clearMessage ( ) ;
140+ message . url = info [ 'linkUrl' ] ;
141+ message . referrer = info [ 'pageUrl' ] ;
142+ sendMessageToHost ( message ) ;
143+ clearMessage ( ) ;
144+ }
145+ } ) ;
146+
147+ // Interrupt Google Chrome download
148+ chrome . downloads . onCreated . addListener ( function ( downloadItem ) {
149+
150+ if ( ugetWrapperNotFound || ! interruptDownloads ) { // uget-chrome-wrapper not installed
151+ return ;
152+ }
153+
154+ var fileSize = downloadItem [ 'fileSize' ] ;
155+
156+ if ( fileSize != - 1 && fileSize < 300000 ) { // 300 kb
157+ return ;
158+ }
159+
160+ var url = '' ;
161+ if ( chromeVersion >= 54 ) {
162+ url = downloadItem [ 'finalUrl' ] ;
163+ } else {
164+ url = downloadItem [ 'url' ] ;
165+ }
166+
167+ if ( ! url ) {
168+ return ;
169+ }
170+
171+ if ( isBlackListed ( url ) ) {
172+ return ;
173+ }
174+
175+ chrome . downloads . cancel ( downloadItem . id ) ; // Cancel the download
176+ chrome . downloads . erase ( { id : downloadItem . id } ) ; // Erase the download from list
177+
178+ clearMessage ( ) ;
179+ message . url = url ;
180+ message . filename = downloadItem [ 'filename' ] ;
181+ message . filesize = fileSize ;
182+ message . referrer = downloadItem [ 'referrer' ] ;
183+ sendMessageToHost ( message ) ;
184+ } ) ;
185+
186+ chrome . webRequest . onBeforeRequest . addListener ( function ( details ) {
187+ if ( details . method == 'POST' ) {
188+ message . postdata = postParams ( details . requestBody . formData ) ;
189+ }
190+ return {
191+ requestHeaders : details . requestHeaders
192+ } ;
193+ } , {
194+ urls : [
195+ '<all_urls>'
196+ ] ,
197+ types : [
198+ 'main_frame' ,
199+ 'sub_frame'
200+ ]
201+ } , [
202+ 'blocking' ,
203+ 'requestBody'
204+ ] ) ;
205+ chrome . webRequest . onBeforeSendHeaders . addListener ( function ( details ) {
206+ clearMessage ( ) ;
207+ currRequest ++ ;
208+ if ( currRequest > 2 )
209+ currRequest = 2 ;
210+ requestList [ currRequest ] . id = details . requestId ;
211+ for ( var i = 0 ; i < details . requestHeaders . length ; ++ i ) {
212+ if ( details . requestHeaders [ i ] . name . toLowerCase ( ) === 'user-agent' ) {
213+ message . useragent = details . requestHeaders [ i ] . value ;
214+ } else if ( details . requestHeaders [ i ] . name . toLowerCase ( ) === 'referer' ) {
215+ requestList [ currRequest ] . referrer = details . requestHeaders [ i ] . value ;
216+ } else if ( details . requestHeaders [ i ] . name . toLowerCase ( ) === 'cookie' ) {
217+ requestList [ currRequest ] . cookies = details . requestHeaders [ i ] . value ;
218+ }
219+ }
220+ return {
221+ requestHeaders : details . requestHeaders
222+ } ;
223+ } , {
224+ urls : [
225+ '<all_urls>'
226+ ] ,
227+ types : [
228+ 'main_frame' ,
229+ 'sub_frame' ,
230+ 'xmlhttprequest'
231+ ]
232+ } , [
233+ 'blocking' ,
234+ 'requestHeaders'
235+ ] ) ;
236+ chrome . webRequest . onHeadersReceived . addListener ( function ( details ) {
237+
238+ if ( ugetWrapperNotFound ) { // uget-chrome-wrapper not installed
239+ return {
240+ responseHeaders : details . responseHeaders
241+ } ;
242+ }
243+
244+ if ( ! details . statusLine . includes ( "200" ) ) { // HTTP response is not OK
245+ return {
246+ responseHeaders : details . responseHeaders
247+ } ;
248+ }
249+
250+ if ( isBlackListed ( details . url ) ) {
251+ return {
252+ responseHeaders : details . responseHeaders
253+ } ;
254+ }
255+
256+ interruptDownload = false ;
257+ message . url = details . url ;
258+ var contentType = "" ;
259+
260+ for ( var i = 0 ; i < details . responseHeaders . length ; ++ i ) {
261+ if ( details . responseHeaders [ i ] . name . toLowerCase ( ) == 'content-length' ) {
262+ message . filesize = details . responseHeaders [ i ] . value ;
263+ var fileSize = parseInt ( message . filesize ) ;
264+ if ( fileSize < 300000 ) { // 300 kb
265+ return {
266+ responseHeaders : details . responseHeaders
267+ } ;
268+ }
269+ } else if ( details . responseHeaders [ i ] . name . toLowerCase ( ) == 'content-disposition' ) {
270+ disposition = details . responseHeaders [ i ] . value ;
271+ if ( disposition . lastIndexOf ( 'filename' ) != - 1 ) {
272+ message . filename = disposition . match ( / f i l e n a m e [ ^ ; = \n ] * = ( ( [ ' " ] ) .* ?\2| [ ^ ; \n ] * ) / ) [ 1 ] ;
273+ message . filename = message . filename . replace ( / [ " ' ] / g, "" ) ;
274+ interruptDownload = true ;
275+ }
276+ } else if ( details . responseHeaders [ i ] . name . toLowerCase ( ) == 'content-type' ) {
277+ contentType = details . responseHeaders [ i ] . value ;
278+ if ( / \b (?: x m l | r s s | j a v a s c r i p t | j s o n | h t m l | t e x t ) \b / . test ( contentType ) ) {
279+ interruptDownload = false ;
280+ return {
281+ responseHeaders : details . responseHeaders
282+ } ;
283+ } else if ( / \b (?: a p p l i c a t i o n \/ | v i d e o \/ | a u d i o \/ ) \b / . test ( contentType ) == true ) {
284+ interruptDownload = true ;
285+ } else {
286+ return {
287+ responseHeaders : details . responseHeaders
288+ } ;
289+ }
290+ }
291+ }
292+ if ( interruptDownload == true && interruptDownloads == true ) {
293+ for ( var i = 0 ; i < filter . length ; i ++ ) {
294+ if ( filter [ i ] != "" && contentType . lastIndexOf ( filter [ i ] ) != - 1 ) {
295+ return {
296+ responseHeaders : details . responseHeaders
297+ } ;
298+ }
299+ }
300+ for ( var j = 0 ; j < 3 ; j ++ ) {
301+ if ( details . requestId == requestList [ j ] . id && requestList [ j ] . id != "" ) {
302+ message . referrer = requestList [ j ] . referrer ;
303+ message . cookies = requestList [ j ] . cookies ;
304+ break ;
305+ }
306+ }
307+ if ( details . method != "POST" ) {
308+ message . postdata = '' ;
309+ }
310+ sendMessageToHost ( message ) ;
311+ message . postdata = '' ;
312+ var scheme = / ^ h t t p s / . test ( details . url ) ? 'https' : 'http' ;
313+ if ( chromeVersion >= 35 ) {
314+ return { redirectUrl : "javascript:" } ;
315+ } else if ( details . frameId === 0 ) {
316+ chrome . tabs . update ( details . tabId , {
317+ url : "javascript:"
318+ } ) ;
319+ var responseHeaders = details . responseHeaders . filter ( function ( header ) {
320+ var name = header . name . toLowerCase ( ) ;
321+ return name !== 'content-type' &&
322+ name !== 'x-content-type-options' &&
323+ name !== 'content-disposition' ;
324+ } ) . concat ( [ {
325+ name : 'Content-Type' ,
326+ value : 'text/plain'
327+ } , {
328+ name : 'X-Content-Type-Options' ,
329+ value : 'nosniff'
330+ } ] ) ;
331+ return {
332+ responseHeaders : responseHeaders
333+ } ;
334+ }
335+ return {
336+ cancel : true
337+ } ;
338+ }
339+ interruptDownloads == true ;
340+ clearMessage ( ) ;
341+ return {
342+ responseHeaders : details . responseHeaders
343+ } ;
344+ } , {
345+ urls : [
346+ '<all_urls>'
347+ ] ,
348+ types : [
349+ 'main_frame' ,
350+ 'sub_frame'
351+ ]
352+ } , [
353+ 'responseHeaders' ,
354+ 'blocking'
355+ ] ) ;
356+
357+ function updateKeywords ( data ) {
358+ keywords = data . split ( / [ \s , ] + / ) ;
359+ } ;
360+
361+ function isBlackListed ( url ) {
362+ if ( url . includes ( "//docs.google.com/" ) || url . includes ( "googleusercontent.com/docs" ) ) { // Cannot download from Google Docs
363+ return true ;
364+ }
365+ for ( keyword of keywords ) {
366+ if ( url . includes ( keyword ) ) {
367+ return true ;
368+ }
369+ }
370+ return false ;
371+ }
372+
373+
374+ function setInterruptDownload ( interrupt , writeToStorage ) {
375+ interruptDownloads = interrupt ;
376+ if ( interrupt ) {
377+ chrome . browserAction . setIcon ( { path : "./icon_32.png" } ) ;
378+ } else {
379+ chrome . browserAction . setIcon ( { path : "./icon_disabled_32.png" } ) ;
380+ }
381+ if ( writeToStorage ) {
382+ localStorage [ "uget-interrupt" ] = interrupt . toString ( ) ;
383+ }
384+ }
0 commit comments