Mercurial > addons > firefox-addons > feed-preview
annotate js/background.js @ 71:0911daceb718 default tip
Added tag version-14 for changeset e405ff21ab31
author | Guido Berhoerster <guido+feed-preview@berhoerster.name> |
---|---|
date | Sun, 03 Mar 2024 18:12:28 +0100 |
parents | fc5fca9af05f |
children |
rev | line source |
---|---|
0
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
1 /* |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
2 * Copyright (C) 2018 Guido Berhoerster <guido+feed-preview@berhoerster.name> |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
3 * |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
4 * This Source Code Form is subject to the terms of the Mozilla Public |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
7 */ |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
8 |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
9 'use strict'; |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
10 |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
11 import * as feedParser from './feed-parser.js'; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
12 import {renderFeedPreview} from './feed-preview.js'; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
13 |
11
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
14 const FEED_READERS_PRESET = [ |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
15 { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
16 title: 'Feedly', |
68
fc5fca9af05f
Update Feedly URL template
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
54
diff
changeset
|
17 urlTemplate: 'https://feedly.com/i/subscription/feed/%s' |
11
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
18 }, |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
19 { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
20 title: 'FlowReader', |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
21 urlTemplate: 'https://www.flowreader.com/subscribe?url=%s' |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
22 }, |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
23 { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
24 title: 'InoReader', |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
25 urlTemplate: 'https://www.inoreader.com/feed/%s' |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
26 }, |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
27 { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
28 title: 'Kouio', |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
29 urlTemplate: 'https://kouio.com/subscribe?url=%s' |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
30 }, |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
31 { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
32 title: 'My Yahoo', |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
33 urlTemplate: 'https://add.my.yahoo.com/rss?url=%s' |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
34 }, |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
35 { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
36 title: 'Netvibes', |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
37 urlTemplate: 'https://www.netvibes.com/subscribe.php?url=%s' |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
38 }, |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
39 { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
40 title: 'NewsBlur', |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
41 urlTemplate: 'https://www.newsblur.com/?url=%s' |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
42 }, |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
43 { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
44 title: 'The Old Reader', |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
45 urlTemplate: 'https://theoldreader.com/feeds/subscribe?url=%s' |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
46 } |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
47 ]; |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
48 const FEED_MAGIC = [ |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
49 '<rss', |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
50 '<feed', |
14
376a0e415bba
Properly handle non-text content in Atom feed elements
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
11
diff
changeset
|
51 feedParser.XMLNS.ATOM03, |
376a0e415bba
Properly handle non-text content in Atom feed elements
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
11
diff
changeset
|
52 feedParser.XMLNS.ATOM10, |
376a0e415bba
Properly handle non-text content in Atom feed elements
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
11
diff
changeset
|
53 feedParser.XMLNS.RSS09, |
376a0e415bba
Properly handle non-text content in Atom feed elements
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
11
diff
changeset
|
54 feedParser.XMLNS.RSS10 |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
55 ]; |
0
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
56 var tabsFeeds = new Map(); |
10
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
57 var tabsFeedPreviews = new Map(); |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
58 var fetchingFeedPreview = fetch('web_resources/feed-preview.xhtml') |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
59 .then(response => response.text()); |
29
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
60 var feedPreviewOptions = { |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
61 expandEntries: false |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
62 }; |
0
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
63 |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
64 function parseContentType(header) { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
65 let contentType = { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
66 mediaType: '', |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
67 charset: 'utf-8' |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
68 }; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
69 let parts = header.toLowerCase().split(';'); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
70 contentType.mediaType = parts.shift().trim(); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
71 for (let parameter of parts) { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
72 let [, name, value, ] = parameter.trim().split(/([^=]+)="?([^"]*)"?/); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
73 if (name.toLowerCase() === 'charset') { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
74 contentType.charset = value.toLowerCase(); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
75 break; |
0
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
76 } |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
77 } |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
78 |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
79 return contentType; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
80 } |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
81 |
10
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
82 async function handleFeed(inputText, tabId, url) { |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
83 // fast-path: eliminate XML documents which cannot be Atom nor RSS feeds |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
84 let inputTextStart = inputText.substring(0, 512); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
85 if (!FEED_MAGIC.some(element => inputTextStart.includes(element))) { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
86 return inputText; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
87 } |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
88 |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
89 let feed; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
90 try { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
91 feed = (new feedParser.FeedParser).parseFromString(inputText, url); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
92 } catch (e) { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
93 if (e instanceof feedParser.ParserError || |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
94 e instanceof feedParser.UnsupportedFeedTypeError) { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
95 // let the browser deal with non-well formed XML or XML documents |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
96 // which are not supported Atom or RSS feeds |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
97 return inputText; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
98 } |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
99 throw e; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
100 } |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
101 console.log(`parsed feed ${url}:\n`, feed); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
102 |
10
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
103 // mark this feed preview for content script injection |
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
104 tabsFeedPreviews.set(tabId, url); |
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
105 |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
106 // render the preview document |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
107 let feedPreviewDocument = new DOMParser() |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
108 .parseFromString(await fetchingFeedPreview, 'text/html'); |
29
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
109 renderFeedPreview(feedPreviewDocument, feed, |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
110 feedPreviewOptions.expandEntries); |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
111 |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
112 return new XMLSerializer().serializeToString(feedPreviewDocument); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
113 } |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
114 |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
115 browser.webRequest.onHeadersReceived.addListener(details => { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
116 if (details.statusCode !== 200) { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
117 return {}; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
118 } |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
119 |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
120 let contentTypeIndex = details.responseHeaders.findIndex(header => |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
121 header.name.toLowerCase() === 'content-type' && |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
122 typeof header.value !== 'undefined'); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
123 if (contentTypeIndex < 0) { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
124 // no Content-Type header found |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
125 return {}; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
126 } |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
127 let headerValue = details.responseHeaders[contentTypeIndex].value |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
128 let contentType = parseContentType(headerValue); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
129 // until content handlers become available to webextensions |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
130 // (https://bugzilla.mozilla.org/show_bug.cgi?id=1457500) intercept all |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
131 // responses and change the content type from application/atom+xml or |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
132 // application/rss+xml to application/xml which will then be probed for |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
133 // Atom or RSS content |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
134 switch (contentType.mediaType) { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
135 case 'application/atom+xml': |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
136 case 'application/rss+xml': |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
137 case 'application/rdf+xml': |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
138 case 'application/xml': |
16
a59d322e5826
Support feeds served as text/xml
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
14
diff
changeset
|
139 case 'text/xml': |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
140 break; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
141 default: |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
142 // non-XML media type |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
143 return {}; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
144 } |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
145 console.log(`response is an XML document\n`, |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
146 `media type: ${contentType.mediaType}\n`, |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
147 `charset: ${contentType.charset}`); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
148 |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
149 let decoder; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
150 try { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
151 decoder = new TextDecoder(contentType.charset); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
152 } catch (e) { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
153 if (e instanceof RangeError) { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
154 // unsupported charset |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
155 return {}; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
156 } else { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
157 throw e; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
158 } |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
159 } |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
160 let encoder = new TextEncoder(); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
161 let inputText = ''; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
162 let filter = browser.webRequest.filterResponseData(details.requestId); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
163 filter.addEventListener('data', ev => { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
164 inputText += decoder.decode(ev.data, {stream: true}); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
165 }); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
166 filter.addEventListener('stop', async ev => { |
10
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
167 let result = await handleFeed(inputText, details.tabId, details.url); |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
168 filter.write(encoder.encode(result)); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
169 filter.close(); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
170 }); |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
171 |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
172 details.responseHeaders[contentTypeIndex] = { |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
173 name: 'Content-Type', |
37
6bd8a649186d
Fix charset encoding in rewritten Content-Type header
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
29
diff
changeset
|
174 value: 'application/xml;charset=utf-8' |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
175 }; |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
176 |
0
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
177 return {responseHeaders: details.responseHeaders}; |
6
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
178 }, |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
179 {urls: ['http://*/*', 'https://*/*'], types: ['main_frame']}, |
5d7c13e998e9
Create feed previews using a stream filter
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
0
diff
changeset
|
180 ['blocking', 'responseHeaders']); |
0
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
181 |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
182 browser.runtime.onMessage.addListener((request, sender, sendResponse) => { |
54
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
183 // popup querying feeds |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
184 sendResponse(tabsFeeds.get(request)); |
0
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
185 }); |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
186 |
54
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
187 browser.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => { |
46
586eebf8efb7
Work around race condition in feed reader subscription script execution
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
37
diff
changeset
|
188 if (changeInfo.status !== 'complete') { |
54
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
189 // hide the page action when the URL changes since it is no longer |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
190 // valid, it will be shown again if the content script detects a feed |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
191 browser.pageAction.hide(tabId); |
0
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
192 return; |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
193 } |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
194 |
46
586eebf8efb7
Work around race condition in feed reader subscription script execution
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
37
diff
changeset
|
195 if (tabsFeedPreviews.get(tabId) === tab.url) { |
54
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
196 // inject content script once if the requested URL is a feed preview |
10
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
197 browser.tabs.executeScript(tabId, { |
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
198 file: 'content_scripts/feed-readers.js' |
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
199 }); |
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
200 tabsFeedPreviews.delete(tabId); |
54
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
201 } else { |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
202 // query available feeds |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
203 let feeds = await browser.tabs.sendMessage(tabId, {}); |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
204 if (feeds.length > 0) { |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
205 tabsFeeds.set(tabId, feeds); |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
206 browser.pageAction.show(tabId); |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
207 console.log(`detected feeds in tab ${tabId} for ${tab.url}:\n`, |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
208 feeds); |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
209 } else { |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
210 console.log(`no feeds detected in tab ${tabId} for ${tab.url}\n`); |
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
211 } |
10
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
212 } |
46
586eebf8efb7
Work around race condition in feed reader subscription script execution
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
37
diff
changeset
|
213 }, {properties: ["status"]}); |
0
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
214 |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
215 browser.tabs.onRemoved.addListener((tabId, removeInfo) => { |
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
216 tabsFeeds.delete(tabId); |
10
ff5e5e3eba32
Implement feed subscription for web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
6
diff
changeset
|
217 tabsFeedPreviews.delete(tabId); |
0
bc5cc170163c
Initial revision
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
diff
changeset
|
218 }); |
11
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
219 |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
220 browser.runtime.onInstalled.addListener(async details => { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
221 if (details.reason === 'install' || |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
222 (details.reason === 'update' && details.previousVersion < 2)) { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
223 let {feedReaders = []} = await browser.storage.sync.get('feedReaders'); |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
224 let feedReadersSet = |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
225 new Set(feedReaders.map(feedReader => feedReader.urlTemplate)); |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
226 for (let feedReader of FEED_READERS_PRESET) { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
227 if (!feedReadersSet.has(feedReader.urlTemplate)) { |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
228 feedReaders.push(feedReader); |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
229 } |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
230 } |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
231 console.log('set feedReaders to', feedReaders); |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
232 browser.storage.sync.set({feedReaders}); |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
233 } |
a4590add4901
Add preset with common web-based feed readers
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
10
diff
changeset
|
234 }); |
29
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
235 |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
236 browser.storage.sync.get('feedPreview').then(({feedPreview}) => { |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
237 if (typeof feedPreview !== 'undefined' && |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
238 feedPreview === Object(feedPreview)) { |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
239 feedPreviewOptions.expandEntries = !!feedPreview.expandEntries; |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
240 } |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
241 }); |
54
ede87e1004f9
Fix issues with feed detection
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
46
diff
changeset
|
242 |
29
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
243 browser.storage.onChanged.addListener((changes, areaName) => { |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
244 if (areaName !== 'sync' || typeof changes.feedPreview === 'undefined') { |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
245 return; |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
246 } |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
247 |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
248 let newValue = changes.feedPreview.newValue; |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
249 if (typeof newValue !== 'undefined' && newValue === Object(newValue)) { |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
250 feedPreviewOptions.expandEntries = !!newValue.expandEntries; |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
251 } |
688d75e554e0
Add option to expand feed entries by default
Guido Berhoerster <guido+feed-preview@berhoerster.name>
parents:
16
diff
changeset
|
252 }); |