@@ -4,7 +4,10 @@ import {Md5} from "ts-md5";
4
4
5
5
/**
6
6
* parser for .rss files, build from scratch
7
- * because I could not find a parser that works on mobile and is up to date.
7
+ * because I could not find a parser that
8
+ * - works on mobile
9
+ * - is up-to-date
10
+ * - works for multiple different interpretations of the rss spec
8
11
*/
9
12
10
13
export interface RssFeedContent {
@@ -44,58 +47,72 @@ export interface RssFeedItem {
44
47
}
45
48
46
49
/**
50
+ * return the node with the specified name
47
51
* : to get namespaced element
48
52
* . to get nested element
49
53
* @param element
50
54
* @param name
51
55
*/
52
56
function getElementByName ( element : Element | Document , name : string ) : ChildNode {
53
57
let value : ChildNode ;
54
- if ( typeof element . getElementsByTagName !== 'function' ) {
58
+ if ( typeof element . getElementsByTagName !== 'function' && typeof element . getElementsByTagNameNS !== 'function' ) {
59
+ //the required methods do not exist on element, aborting
55
60
return ;
56
61
}
57
62
58
63
if ( name . contains ( ":" ) ) {
59
64
const [ namespace , tag ] = name . split ( ":" ) ;
60
65
const namespaceUri = element . lookupNamespaceURI ( namespace ) ;
61
- if ( element . getElementsByTagNameNS ( namespaceUri , tag ) . length > 0 ) {
62
- value = element . getElementsByTagNameNS ( namespaceUri , tag ) [ 0 ] . childNodes [ 0 ] ;
66
+ const byNamespace = element . getElementsByTagNameNS ( namespaceUri , tag ) ;
67
+ if ( byNamespace . length > 0 ) {
68
+ value = byNamespace [ 0 ] . childNodes [ 0 ] ;
69
+ } else {
70
+ //there is no element in that namespace, probably because no namespace has been defined
71
+ const tmp = element . getElementsByTagName ( name ) ;
72
+ if ( tmp . length > 0 ) {
73
+ if ( tmp [ 0 ] . childNodes . length === 0 ) {
74
+ value = tmp [ 0 ] ;
75
+ } else {
76
+ const node = tmp [ 0 ] . childNodes [ 0 ] ;
77
+ if ( node !== undefined ) {
78
+ value = node ;
79
+ }
80
+ }
81
+ }
63
82
}
64
83
65
84
} else if ( name . contains ( "." ) ) {
66
85
const [ prefix , tag ] = name . split ( "." ) ;
67
86
if ( element . getElementsByTagName ( prefix ) . length > 0 ) {
68
87
const nodes = Array . from ( element . getElementsByTagName ( prefix ) [ 0 ] . childNodes ) ;
69
-
70
88
nodes . forEach ( ( node ) => {
71
89
if ( node . nodeName == tag ) {
72
90
value = node ;
73
91
}
74
92
} ) ;
75
93
}
76
94
77
- } else {
78
- if ( element . getElementsByTagName ( name ) . length > 0 ) {
79
- if ( element . getElementsByTagName ( name ) [ 0 ] . childNodes . length == 0 ) {
80
- value = element . getElementsByTagName ( name ) [ 0 ] ;
81
- } else {
82
- const node = element . getElementsByTagName ( name ) [ 0 ] . childNodes [ 0 ] ;
83
- if ( node !== undefined )
84
- value = node ;
85
- }
95
+ } else if ( element . getElementsByTagName ( name ) . length > 0 ) {
96
+ if ( element . getElementsByTagName ( name ) [ 0 ] . childNodes . length == 0 ) {
97
+ value = element . getElementsByTagName ( name ) [ 0 ] ;
98
+ } else {
99
+ const node = element . getElementsByTagName ( name ) [ 0 ] . childNodes [ 0 ] ;
100
+ if ( node !== undefined )
101
+ value = node ;
86
102
}
87
103
}
88
104
return value ;
89
105
}
90
106
91
107
/**
92
108
* # to get attribute
109
+ * Always returns the last found value for names
93
110
* @param element
94
111
* @param names possible names
95
112
*/
96
113
function getContent ( element : Element | Document , names : string [ ] ) : string {
97
114
let value : string ;
98
- names . forEach ( ( name ) => {
115
+ for ( let name of names ) {
99
116
if ( name . contains ( "#" ) ) {
100
117
const [ elementName , attr ] = name . split ( "#" ) ;
101
118
const data = getElementByName ( element , elementName ) ;
@@ -108,21 +125,21 @@ function getContent(element: Element | Document, names: string[]): string {
108
125
}
109
126
}
110
127
}
111
- } else {
128
+ } else {
112
129
const data = getElementByName ( element , name ) ;
113
130
if ( data ) {
114
131
//@ts -ignore
115
132
if ( data . nodeValue && data . nodeValue . length > 0 ) {
116
133
value = data . nodeValue ;
117
134
}
118
135
//@ts -ignore
119
- if ( data . innerHTML && data . innerHTML . length > 0 ) {
136
+ else if ( data . innerHTML && data . innerHTML . length > 0 ) {
120
137
//@ts -ignore
121
138
value = data . innerHTML ;
122
139
}
123
140
}
124
141
}
125
- } ) ;
142
+ }
126
143
if ( value === undefined ) {
127
144
return "" ;
128
145
}
@@ -133,7 +150,7 @@ function buildItem(element: Element): RssFeedItem {
133
150
return {
134
151
title : getContent ( element , [ "title" ] ) ,
135
152
description : getContent ( element , [ "content" , "content:encoded" , "itunes:summary" , "description" , "summary" , "media:description" ] ) ,
136
- content : getContent ( element , [ "itunes:summary" , "description" , "summary" , "media:description" , "content" , "content:encoded" ] ) ,
153
+ content : getContent ( element , [ "itunes:summary" , "description" , "summary" , "media:description" , "content" , "content:encoded" , "ns0:encoded" ] ) ,
137
154
category : getContent ( element , [ "category" ] ) ,
138
155
link : getContent ( element , [ "link" , "link#href" ] ) ,
139
156
creator : getContent ( element , [ "creator" , "dc:creator" , "author" , "author.name" ] ) ,
@@ -178,7 +195,7 @@ export async function getFeedItems(feed: RssFeed): Promise<RssFeedContent> {
178
195
try {
179
196
const rawData = await request ( { url : feed . url } ) ;
180
197
data = new window . DOMParser ( ) . parseFromString ( rawData , "text/xml" ) ;
181
- } catch ( e ) {
198
+ } catch ( e ) {
182
199
console . error ( e ) ;
183
200
return Promise . resolve ( undefined ) ;
184
201
}
@@ -200,14 +217,13 @@ export async function getFeedItems(feed: RssFeed): Promise<RssFeedContent> {
200
217
item . language = language ;
201
218
item . hash = < string > new Md5 ( ) . appendStr ( item . title ) . appendStr ( item . folder ) . appendStr ( item . link ) . end ( ) ;
202
219
203
- if ( ! item . image && feed . url . contains ( "youtube.com/feeds" ) ) {
220
+ if ( ! item . image && feed . url . contains ( "youtube.com/feeds" ) ) {
204
221
item . image = "https://i3.ytimg.com/vi/" + item . id . split ( ":" ) [ 2 ] + "/hqdefault.jpg" ;
205
222
}
206
223
207
224
items . push ( item ) ;
208
225
}
209
226
} )
210
-
211
227
const image = getContent ( data , [ "image" , "image.url" , "icon" ] ) ;
212
228
213
229
const content : RssFeedContent = {
0 commit comments