@@ -8,6 +8,7 @@ const extConfigDefaults = {
88 interceptAllDownloads : false ,
99 silentDownload : false ,
1010 skipFileExtensions : [ ] ,
11+ minFileSize : 0 ,
1112 shiftToggleEnabled : false ,
1213 videoSnifferEnabled : true ,
1314 videoSnifferFormats : [ 'm4s' , 'mp4' , 'flv' , 'm3u8' , 'ts' ] ,
@@ -316,8 +317,11 @@ const syncExtConfigFromClient = async () => {
316317 const interceptAllDownloads = ! ! data . interceptAllDownloads
317318 const silentDownload = ! ! data . silentDownload
318319 const shiftToggleEnabled = ! ! data . shiftToggleEnabled
320+ const minFileSize = Number ( data . minFileSize ) || 0
319321 const rawList = Array . isArray ( data . skipFileExtensions ) ? data . skipFileExtensions : [ ]
320322 const skipFileExtensions = rawList . map ( x => `${ x } ` . trim ( ) . toLowerCase ( ) ) . filter ( Boolean )
323+ const rawDomainList = Array . isArray ( data . excludeDomains ) ? data . excludeDomains : [ ]
324+ const excludeDomains = rawDomainList . map ( x => `${ x } ` . trim ( ) ) . filter ( Boolean )
321325
322326 // 视频嗅探器配置
323327 const videoSnifferEnabled = data . videoSnifferEnabled !== undefined ? ! ! data . videoSnifferEnabled : true
@@ -340,6 +344,8 @@ const syncExtConfigFromClient = async () => {
340344 interceptAllDownloads,
341345 silentDownload,
342346 skipFileExtensions,
347+ excludeDomains,
348+ minFileSize,
343349 shiftToggleEnabled,
344350 videoSnifferEnabled,
345351 videoSnifferFormats,
@@ -837,6 +843,164 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
837843 handleAddFromContent ( )
838844 return true
839845 }
846+
847+ if ( msg && msg . type === 'addExcludeDomain' && msg . domain ) {
848+ const handleAddExcludeDomain = async ( ) => {
849+ try {
850+ // 先获取当前配置
851+ const currentConfig = await tryChannel ( '/linkcore/ext-config' , {
852+ method : 'GET'
853+ } , 3000 )
854+
855+ let excludeDomains = [ ]
856+ if ( currentConfig && currentConfig . resp ) {
857+ const data = await currentConfig . resp . json ( )
858+ if ( Array . isArray ( data . excludeDomains ) ) {
859+ excludeDomains = data . excludeDomains
860+ }
861+ }
862+
863+ const domain = msg . domain . toLowerCase ( ) . trim ( )
864+ const existingIndex = excludeDomains . findIndex ( d => d . toLowerCase ( ) . trim ( ) === domain )
865+
866+ if ( existingIndex !== - 1 ) {
867+ // 域名已存在,移除它
868+ excludeDomains . splice ( existingIndex , 1 )
869+ const result = await tryChannel ( '/linkcore/ext-config' , {
870+ method : 'POST' ,
871+ headers : { 'Content-Type' : 'application/json' } ,
872+ body : JSON . stringify ( { excludeDomains } )
873+ } , 3000 )
874+
875+ if ( result && result . resp && result . resp . ok ) {
876+ sendResponse ( { ok : true , removed : true } )
877+ } else {
878+ sendResponse ( { ok : false } )
879+ }
880+ } else {
881+ // 域名不存在,添加它
882+ excludeDomains . push ( domain )
883+ const result = await tryChannel ( '/linkcore/ext-config' , {
884+ method : 'POST' ,
885+ headers : { 'Content-Type' : 'application/json' } ,
886+ body : JSON . stringify ( { excludeDomains } )
887+ } , 3000 )
888+
889+ if ( result && result . resp && result . resp . ok ) {
890+ sendResponse ( { ok : true , added : true } )
891+ } else {
892+ sendResponse ( { ok : false } )
893+ }
894+ }
895+ } catch ( e ) {
896+ console . error ( '[Background] Failed to add/remove exclude domain:' , e )
897+ sendResponse ( { ok : false } )
898+ }
899+ }
900+ handleAddExcludeDomain ( )
901+ return true
902+ }
903+
904+ if ( msg && msg . type === 'getExcludeDomains' ) {
905+ const handleGetExcludeDomains = async ( ) => {
906+ try {
907+ const result = await tryChannel ( '/linkcore/ext-config' , {
908+ method : 'GET'
909+ } , 3000 )
910+
911+ if ( result && result . resp ) {
912+ const data = await result . resp . json ( )
913+ sendResponse ( { excludeDomains : data . excludeDomains || [ ] } )
914+ } else {
915+ sendResponse ( { excludeDomains : [ ] } )
916+ }
917+ } catch ( e ) {
918+ console . error ( '[Background] Failed to get exclude domains:' , e )
919+ sendResponse ( { excludeDomains : [ ] } )
920+ }
921+ }
922+ handleGetExcludeDomains ( )
923+ return true
924+ }
925+
926+ if ( msg && msg . type === 'addSkipFileType' && msg . fileType ) {
927+ const handleAddSkipFileType = async ( ) => {
928+ try {
929+ const result = await tryChannel ( '/linkcore/ext-config' , {
930+ method : 'POST' ,
931+ headers : { 'Content-Type' : 'application/json' } ,
932+ body : JSON . stringify ( { skipFileExtensions : [ msg . fileType ] } )
933+ } , 3000 )
934+
935+ if ( result && result . resp && result . resp . ok ) {
936+ sendResponse ( { ok : true } )
937+ } else {
938+ sendResponse ( { ok : false } )
939+ }
940+ } catch ( e ) {
941+ console . error ( '[Background] Failed to add skip file type:' , e )
942+ sendResponse ( { ok : false } )
943+ }
944+ }
945+ handleAddSkipFileType ( )
946+ return true
947+ }
948+
949+ if ( msg && msg . type === 'addSkipFileTypes' && Array . isArray ( msg . fileTypes ) ) {
950+ const handleAddSkipFileTypes = async ( ) => {
951+ let response = { ok : false , error : 'unknown' }
952+ try {
953+ console . log ( '[Background] Adding skip file types:' , msg . fileTypes )
954+
955+ // 先获取当前配置
956+ const currentConfig = await tryChannel ( '/linkcore/ext-config' , {
957+ method : 'GET'
958+ } , 5000 )
959+
960+ let skipFileExtensions = [ ]
961+ if ( currentConfig && currentConfig . resp ) {
962+ const data = await currentConfig . resp . json ( )
963+ console . log ( '[Background] Current config data:' , data )
964+ if ( Array . isArray ( data . skipFileExtensions ) ) {
965+ skipFileExtensions = data . skipFileExtensions
966+ }
967+ }
968+
969+ // 合并并去重(与程序逻辑一致)
970+ const allExtensions = [ ...skipFileExtensions , ...msg . fileTypes ]
971+ const uniqueExtensions = Array . from ( new Set ( allExtensions ) )
972+
973+ console . log ( '[Background] Sending skipFileExtensions:' , uniqueExtensions )
974+
975+ const result = await tryChannel ( '/linkcore/ext-config' , {
976+ method : 'POST' ,
977+ headers : { 'Content-Type' : 'application/json' } ,
978+ body : JSON . stringify ( { skipFileExtensions : uniqueExtensions } )
979+ } , 5000 )
980+
981+ console . log ( '[Background] POST result:' , result )
982+
983+ if ( result && result . resp && result . resp . ok ) {
984+ response = { ok : true , added : msg . fileTypes . length }
985+ } else {
986+ console . error ( '[Background] POST failed, result:' , result )
987+ response = { ok : false , error : 'POST failed' }
988+ }
989+ } catch ( e ) {
990+ console . error ( '[Background] Failed to add skip file types:' , e )
991+ response = { ok : false , error : e . message }
992+ }
993+
994+ // 确保总是发送响应
995+ try {
996+ sendResponse ( response )
997+ } catch ( e ) {
998+ console . error ( '[Background] Failed to send response:' , e )
999+ }
1000+ }
1001+ handleAddSkipFileTypes ( )
1002+ return true
1003+ }
8401004} )
8411005chrome . contextMenus . onClicked . addListener ( async ( info , tab ) => {
8421006 let url = info . linkUrl || info . srcUrl || info . pageUrl
@@ -870,6 +1034,39 @@ chrome.downloads.onCreated.addListener((item) => {
8701034 if ( ! effectiveAutoHijack ) return
8711035 const url = item && item . url ? item . url : ''
8721036 if ( ! url || ! / ^ h t t p s ? : / i. test ( url ) ) return
1037+
1038+ // 检查是否在排除域名列表中
1039+ try {
1040+ const downloadUrl = new URL ( url )
1041+ const downloadDomain = downloadUrl . hostname
1042+
1043+ // 检查 referer 域名
1044+ let refererDomain = ''
1045+ if ( item . referrer ) {
1046+ try {
1047+ const refererUrl = new URL ( item . referrer )
1048+ refererDomain = refererUrl . hostname
1049+ } catch ( e ) { }
1050+ }
1051+
1052+ // 获取排除域名列表
1053+ const excludeDomains = Array . isArray ( extConfig . excludeDomains ) ? extConfig . excludeDomains : [ ]
1054+
1055+ // 检查下载域名或 referer 域名是否在排除列表中
1056+ const isDomainExcluded = excludeDomains . some ( domain => {
1057+ const normalizedDomain = domain . toLowerCase ( ) . trim ( )
1058+ return downloadDomain . toLowerCase ( ) . includes ( normalizedDomain ) ||
1059+ ( refererDomain && refererDomain . toLowerCase ( ) . includes ( normalizedDomain ) )
1060+ } )
1061+
1062+ if ( isDomainExcluded ) {
1063+ console . log ( '[LinkCore] Domain excluded, skipping download:' , downloadDomain )
1064+ return
1065+ }
1066+ } catch ( e ) {
1067+ console . error ( '[LinkCore] Error checking excluded domain:' , e )
1068+ }
1069+
8731070 try {
8741071 let name = ''
8751072 if ( item && item . filename ) {
@@ -886,6 +1083,26 @@ chrome.downloads.onCreated.addListener((item) => {
8861083 if ( ext && Array . isArray ( extConfig . skipFileExtensions ) && extConfig . skipFileExtensions . includes ( ext ) ) {
8871084 return
8881085 }
1086+
1087+ // 检查文件大小限制(minFileSize 单位为 MB)
1088+ const minFileSizeMB = Number ( extConfig . minFileSize ) || 0
1089+ if ( minFileSizeMB > 0 ) {
1090+ // 获取文件大小(字节)
1091+ // totalBytes 是文件总大小,如果未知则为 -1
1092+ const totalBytes = item . totalBytes || 0
1093+ const fileSizeMB = totalBytes / ( 1024 * 1024 )
1094+
1095+ // 如果已知文件大小且小于最小限制,跳过拦截
1096+ if ( totalBytes > 0 && fileSizeMB < minFileSizeMB ) {
1097+ console . log ( '[LinkCore] File size (' + fileSizeMB . toFixed ( 2 ) + 'MB) below minimum (' + minFileSizeMB + 'MB), skipping:' , url )
1098+ return
1099+ }
1100+
1101+ // 如果文件大小未知(totalBytes 为 0 或 -1),继续拦截
1102+ if ( totalBytes <= 0 ) {
1103+ console . log ( '[LinkCore] File size unknown, will intercept anyway:' , url )
1104+ }
1105+ }
8891106 } catch ( e ) {
8901107 }
8911108 try {
0 commit comments