@@ -100,6 +100,27 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
100100 return true ;
101101 }
102102
103+ if ( message . type === 'ds-abort' ) {
104+ // 获取当前请求的 chatId 和 messageId,发送 stop_stream 到 DeepSeek 标签页
105+ const processorIds = Object . keys ( dsSseProcessors ) ;
106+ if ( processorIds . length > 0 ) {
107+ const processor = dsSseProcessors [ processorIds [ 0 ] ] ;
108+ const chatId = processor . getChatId ( ) ;
109+ const messageId = processor . getMessageId ( ) ;
110+ chrome . tabs . query ( { url : '*://chat.deepseek.com/*' } , ( tabs ) => {
111+ if ( tabs [ 0 ] ?. id ) {
112+ chrome . tabs . sendMessage ( tabs [ 0 ] . id , {
113+ type : 'ds-abort-stop' ,
114+ chatId,
115+ messageId,
116+ } ) . catch ( ( ) => { } ) ;
117+ }
118+ } ) ;
119+ }
120+ dsSseProcessors = { } ;
121+ return false ;
122+ }
123+
103124 if ( message . type === 'ds-send' ) {
104125 const requestId = message . requestId || crypto . randomUUID ( ) ;
105126 dsHandleSend ( message . markdown , message . prompt , requestId ) ;
@@ -118,6 +139,21 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
118139 return false ;
119140 }
120141
142+ if ( message . type === 'ds-open-chat' ) {
143+ const url = message . url || 'https://chat.deepseek.com' ;
144+ const isStreaming = Object . keys ( dsSseProcessors ) . length > 0 ;
145+ chrome . tabs . query ( { url : '*://chat.deepseek.com/*' } , ( tabs ) => {
146+ if ( isStreaming || tabs . length === 0 ) {
147+ // 流式处理中或无标签页:新建标签页,避免中断正在运行的脚本
148+ chrome . tabs . create ( { url } ) ;
149+ } else {
150+ // 空闲:复用已有标签页
151+ chrome . tabs . update ( tabs [ 0 ] . id , { url, active : true } ) ;
152+ }
153+ } ) ;
154+ return false ;
155+ }
156+
121157 // DeepSeek bridge → bilibili tab 转发
122158 if ( message . type === 'DEEPSEEK_CHUNK' ) {
123159 const rid = message . requestId ;
@@ -395,6 +431,27 @@ function formatDate(timestamp) {
395431// ── DeepSeek 文档整理 ──
396432
397433const DS_URL = 'https://chat.deepseek.com' ;
434+
435+ const DS_DEFAULT_PROMPT = `你是一个视频笔记整理助手,将视频导出的 Markdown 文档整理为简洁、高质量、适合长期保存的 Markdown 学习笔记。
436+
437+ 要求:
438+
439+ 1. 删除口语化内容、重复内容、无意义过渡语句,例如:好的、然后、这里呢、兄弟、就是说等。
440+ 2. 删除所有字幕时间戳,例如 \`00:12\`、\`05:30\`。
441+ 3. 不要逐句输出字幕,将连续字幕整理为简洁、连贯、易阅读的知识内容。
442+ 4. 字幕可能由 AI 识别生成,存在错别字、同音字、术语错误、英文大小写错误,请结合上下文修正,并统一技术术语写法。
443+ 5. 若文档存在章节结构,严格按原始章节整理;若无章节,则按内容自然分段。
444+ 6. 不要新增原文不存在的标题、章节或目录层级,不要改变原始内容顺序。
445+ 7. 文档中形如  的 Markdown 标记属于特殊文本块,() 内为相对资源路径且默认与前一句字幕内容关联;必须保留全部此类标记,禁止修改语法、alt 文本、路径或文件名,不得遗漏,可根据整理后的内容适当调整其在当前语义块中的位置。
446+ 8. 保留所有技术名词、工具名、框架名、产品名,不要删除、替换或省略。
447+ 9. 若存在 Frontmatter(文档开头 YAML),必须完整原样保留,禁止修改字段、字段值和字段顺序。
448+ 10. 仅整理原文,禁止总结、解释、扩展原文不存在的信息或补充额外知识。
449+
450+ 待整理文档:
451+
452+ {markdown}
453+
454+ 直接输出整理后的 Markdown 文档,不要输出任何额外内容。` ;
398455let dsInjectedTabs = new Set ( ) ;
399456let dsChatId = null ;
400457let dsSseProcessors = { } ;
@@ -441,10 +498,11 @@ chrome.tabs.onRemoved.addListener((tabId) => { dsInjectedTabs.delete(tabId); });
441498
442499async function dsCheckLogin ( ) {
443500 try {
444- const tabs = await chrome . tabs . query ( { url : '*://chat.deepseek.com/*' } ) ;
445- const tab = tabs . length > 0 ? tabs [ 0 ] : null ;
501+ // 自动获取或创建 DeepSeek 标签页
502+ const tab = await dsEnsureTab ( ) ;
446503 if ( ! tab ?. id ) return { loggedIn : false } ;
447504
505+ // 主要方式:通过 localStorage token 验证
448506 try {
449507 const results = await chrome . scripting . executeScript ( {
450508 target : { tabId : tab . id } ,
@@ -483,6 +541,12 @@ async function dsCheckLogin() {
483541 if ( r && typeof r . loggedIn === 'boolean' ) return r ;
484542 } catch { }
485543
544+ // 降级:cookie 检测
545+ const cookies = await chrome . cookies . getAll ( { domain : '.deepseek.com' } ) ;
546+ const cookieMap = Object . fromEntries ( cookies . map ( c => [ c . name , c . value ] ) ) ;
547+ const hasSession = [ 'ds_session_id' , 'HWSID' ] . some ( name => ! ! cookieMap [ name ] ) ;
548+ if ( hasSession ) return { loggedIn : true , key : 'cookie' } ;
549+
486550 return { loggedIn : false } ;
487551 } catch ( e ) {
488552 return { loggedIn : false , reason : String ( e ) } ;
@@ -519,16 +583,14 @@ async function dsHandleSend(markdown, prompt, requestId) {
519583 let fullPrompt = prompt ;
520584 try {
521585 const stored = await chrome . storage . local . get ( 'deepseekPrompt' ) ;
522- const sysPrompt = stored . deepseekPrompt || '' ;
523- if ( sysPrompt && sysPrompt . includes ( '{markdown}' ) ) {
586+ const sysPrompt = stored . deepseekPrompt || DS_DEFAULT_PROMPT ;
587+ if ( sysPrompt . includes ( '{markdown}' ) ) {
524588 fullPrompt = sysPrompt . replace ( '{markdown}' , markdown ) ;
525- } else if ( sysPrompt ) {
526- fullPrompt = sysPrompt + '\n\n' + markdown ;
527589 } else {
528- fullPrompt = markdown ;
590+ fullPrompt = sysPrompt + '\n\n' + markdown ;
529591 }
530592 } catch {
531- fullPrompt = markdown ;
593+ fullPrompt = DS_DEFAULT_PROMPT . replace ( '{ markdown}' , markdown ) ;
532594 }
533595
534596 chrome . tabs . sendMessage ( tab . id , {
@@ -552,25 +614,48 @@ async function dsHandleSend(markdown, prompt, requestId) {
552614function dsCreateSSEProcessor ( ) {
553615 let inThink = false ;
554616 let chatId = null ;
617+ let messageId = null ;
618+ let dataLineBuf = '' ;
555619
556620 function processChunk ( chunk ) {
557621 let text = '' ;
558- for ( const line of chunk . split ( '\n' ) ) {
559- if ( ! line . startsWith ( 'data: ' ) ) continue ;
560- const jsonStr = line . slice ( 6 ) . trim ( ) ;
561- if ( ! jsonStr || jsonStr === '[DONE]' ) continue ;
562- try {
563- const data = JSON . parse ( jsonStr ) ;
564- if ( data . type === 'deepseek:chat_session_id' ) { chatId = data . chat_session_id ; continue ; }
565- const result = processEvent ( data ) ;
566- if ( result ) text += result ;
567- } catch { }
568- }
622+ try {
623+ for ( const line of chunk . split ( '\n' ) ) {
624+ if ( line . startsWith ( 'data: ' ) ) {
625+ const jsonStr = line . slice ( 6 ) . trim ( ) ;
626+ if ( ! jsonStr || jsonStr === '[DONE]' ) { dataLineBuf = '' ; continue ; }
627+ try {
628+ const data = JSON . parse ( jsonStr ) ;
629+ dataLineBuf = '' ;
630+ if ( data . type === 'deepseek:chat_session_id' ) { chatId = data . chat_session_id ; continue ; }
631+ if ( data . response_message_id != null ) messageId = data . response_message_id ;
632+ const result = processEvent ( data ) ;
633+ if ( result ) text += result ;
634+ } catch {
635+ dataLineBuf = line ;
636+ }
637+ } else {
638+ if ( dataLineBuf ) {
639+ dataLineBuf += '\n' + line ;
640+ try {
641+ const jsonStr = dataLineBuf . slice ( 6 ) . trim ( ) ;
642+ const data = JSON . parse ( jsonStr ) ;
643+ dataLineBuf = '' ;
644+ if ( data . type === 'deepseek:chat_session_id' ) { chatId = data . chat_session_id ; continue ; }
645+ if ( data . response_message_id != null ) messageId = data . response_message_id ;
646+ const result = processEvent ( data ) ;
647+ if ( result ) text += result ;
648+ } catch { }
649+ }
650+ }
651+ }
652+ } catch { }
569653 return text ;
570654 }
571655
572656 function processEvent ( data ) {
573657 if ( data . o === 'SET' || data . o === 'BATCH' ) return null ;
658+ const path = Array . isArray ( data . p ) ? data . p . join ( '/' ) : data . p ;
574659 const resp = data . v ?. response ;
575660
576661 if ( resp ?. fragments && Array . isArray ( resp . fragments ) ) {
@@ -606,7 +691,22 @@ function dsCreateSSEProcessor() {
606691 return parts . length > 0 ? parts . join ( '' ) : null ;
607692 }
608693
609- if ( data . o === 'APPEND' && typeof data . v === 'string' ) return data . v || null ;
694+ if ( data . o === 'APPEND' && typeof data . v === 'string' ) {
695+ return data . v || null ;
696+ }
697+
698+ if ( path ?. includes ( 'reasoning' ) && typeof data . v === 'string' ) {
699+ if ( ! data . v ) return null ;
700+ if ( ! inThink ) { inThink = true ; return `<think>${ data . v } ` ; }
701+ return data . v ;
702+ }
703+
704+ if ( data . type === 'thinking' ) {
705+ const content = typeof data . v === 'string' ? data . v : data . content || '' ;
706+ if ( ! content ) return null ;
707+ if ( ! inThink ) { inThink = true ; return `<think>${ content } ` ; }
708+ return content ;
709+ }
610710
611711 const delta = data . choices ?. [ 0 ] ?. delta ;
612712 if ( delta ) {
@@ -624,10 +724,18 @@ function dsCreateSSEProcessor() {
624724
625725 if ( typeof data . v === 'string' ) {
626726 if ( ! data . v ) return null ;
727+ if ( ! path && inThink ) return data . v ;
627728 if ( inThink ) { inThink = false ; return `</think>${ data . v } ` ; }
628729 return data . v ;
629730 }
630731
732+ if ( data . type === 'text' && typeof data . content === 'string' ) {
733+ const content = data . content . trim ( ) ;
734+ if ( ! content ) return null ;
735+ if ( inThink ) { inThink = false ; return `</think>${ content } ` ; }
736+ return content ;
737+ }
738+
631739 return null ;
632740 }
633741
@@ -636,6 +744,6 @@ function dsCreateSSEProcessor() {
636744 return '' ;
637745 }
638746
639- return { processChunk, flush, getChatId : ( ) => chatId } ;
747+ return { processChunk, flush, getChatId : ( ) => chatId , getMessageId : ( ) => messageId } ;
640748}
641749
0 commit comments