PageSourceSearch

https://adventofcomputing.com/rss-render.js

js adventofcomputing.com collected 2026-10-02 15:08:28 UTC 9,149 bytes, 337 lines download raw bytes

1(function(window, $, undefined)
2    {
3        'use strict';
4    
5		var congif = {};
6
7		var post_types = {
8			'text': 'fas fa-sticky-note',
9			'audio/mpeg': 'fas fa-play'
10		};
11        
12		function RSSRender(config){
13			this.config = config;
14			this.params = this.getUrlVars();
15
16			if(this.params.feed_url){
17				this.config.feed_url = this.params.feed_url;
18			}
19
20			this.covers = [];
21			this.timeline = [];
22			this.currentGUID = "";
23
24			this.colors = ['#00429d', '#7ba8c6', '#a8d6c1', '#93c687', '#008000', '#ffaaa2', '#ea6372', '#c32750', '#93003a', '#1eac86', '#e2af39', '#eadac2', '#de3f27'];
25
26			if(config.colors){
27				this.colors = config.colors;
28			}
29
30			return this;
31		}
32
33		RSSRender.prototype.parseFeed = function(callback){
34			var self = this;
35
36			var parser = new RSSParser();
37
38			parser.parseURL(self.config.feed_url, function(err, feed){
39				self.feed = feed;
40				var timeline_id = 0;
41				self.timeline = [];
42
43				feed.items.forEach(function(item){
44					var guid = item.guid;
45
46					var type = "text";
47
48					if(item.enclosure && item.enclosure.type){
49						type = item.enclosure.type;
50					}
51
52					//Parse out timeline data
53					var dates = item.content.match(/([1-2][0-9]{3}: [^<]*)/gm);
54
55					if(dates){
56						dates.forEach(function(d){
57							var p = d.split(": ");
58
59							self.timeline.push({
60								id: timeline_id,
61								episode: item.title,
62								guid: item.guid,
63								className: "ep-" + item.itunes.episode,
64								group: parseInt(item.itunes.episode),
65								style: "background-color:" + self.colors[Math.floor(item.itunes.episode % self.colors.length)],
66								content: "<p class='ep-number'>E" + item.itunes.episode + "</p><p class='event'>" + p[1] + "</p>",
67								start: p[0] + "-01-01",
68								year: p[0]
69							});
70
71							timeline_id++;
72						});
73					}
74				});
75
76				if(callback){
77					callback(self);
78				}
79			});
80		};
81
82		RSSRender.prototype.renderTimeline = function(){
83			var self = this;
84
85			if(!self.config.timeline){
86				return false;
87			}
88
89			self.parseFeed(function(data){
90				var container = document.getElementById(self.config.timeline.target);
91
92		 		// Create a DataSet (allows two way data-binding)
93		 		var items = new vis.DataSet(self.timeline);
94
95		 		var years = self.timeline.map(function(d){
96		 			return d.year;
97		 		});
98
99		  		// Configuration for the Timeline
100		  		var options = {
101					align: "left",
102	  				height: "150%",
103		  			max: (Math.max(...years) + 30) + "-01-01",
104		  			min: (Math.min(...years) - 10) + "-01-01",
105		  			orientation: "top"
106		  		};
107
108		  		if(self.config.timeline.options){
109		  			options = $.extend(options, self.config.timeline.options);
110		  		}
111
112		  		// Create a Timeline
113			 	var timeline = new vis.Timeline(container, items, options);
114			 	
115	 	 		timeline.on('click', function(e){
116	 	 			if(e.item != null){
117						self.renderGUID(self.timeline[e.item].guid, "#" + (self.config.timeline.infobox || "ep-info"));
118					}
119				});
120			});
121		};
122
123		RSSRender.prototype.render = function(callback){
124			var self = this;
125
126			if(self.config.menu_items){
127				self.config.menu_items.forEach(function(item){
128					$("#side-menu").append(
129						'<a href="' + item.href + '" class="menu-item"><div class="row">' +
130							'<div class="col-md-4">' +
131								'<div class="icon">' +
132									'<i class="' + item.icon_class + ' fa-2x"></i>' +
133								'</div>' +
134							'</div>' +
135							'<div class="col-md-8"><div class="vertical-align">' +
136								'<span>' + item.name + '</span>' +
137							'</div></div>' +
138						'</div></a>'
139					);
140				});
141			}
142
143			var parser = new RSSParser();
144
145			parser.parseURL(self.config.feed_url, function(err, feed){
146				self.feed = feed;
147
148				$("#logo").attr("src", feed.image.url);
149
150				if(self.params.guid){
151					feed.items = feed.items.filter(function(item){
152						return item.guid.match(self.params.guid);
153					});
154				}else{
155					$("#header-content").html(feed.description);
156				}
157
158				var timeline_id = 0;
159
160				feed.items.forEach(function(item){
161					var guid = item.guid;
162					var type = "text";
163
164					if(item.enclosure && item.enclosure.type){
165						type = item.enclosure.type;
166					}
167
168					if(self.covers.indexOf(item.itunes.image) < 0){
169						self.covers.push(item.itunes.image);
170					}
171
172					if(self.params.guid){
173						self.renderGUID(self.params.guid);
174					}else{
175						var text =
176							"<div class='row'>" +
177								"<div class='col-md-12 item'>" +
178									"<a href='?guid=" + guid + "'>" +
179										'<h3><span><i class="' + post_types[type] + ' fa-1x"></i></span>' + item.title + "</h3>" +
180									"</a>" +
181									"<div class='item-desc'>" + item.content + "</div>" +
182									"<div class='more'><a href='?guid=" + guid + "'>More...</a></div>" +
183								"</div>" +
184							"</div>";
185
186						$("#feed").append(text);
187					}
188
189					$("#feed iframe:last").remove();
190
191					//Parse out timeline data
192					var dates = item.content.match(/([1-2][0-9]{3}: [^<]*)/gm);
193
194					if(dates){
195						dates.forEach(function(d){
196							var p = d.split(": ");
197
198							self.timeline.push({
199								id: timeline_id,
200								episode: item.title,
201								guid: item.guid,
202								link: "http://adventofcomputing.com/?guid=" + item.guid,
203								className: "ep-" + item.itunes.episode,
204								group: parseInt(item.itunes.episode),
205								style: "background-color:" + self.colors[Math.floor(item.itunes.episode % self.colors.length)],
206								content: "<p class='ep-number'>E" + item.itunes.episode + "</p><p class='event'>" + p[1] + "</p>",
207								start: p[0] + "-01-01"
208							});
209
210							timeline_id++;
211						});
212					}
213				});
214
215				if(callback){
216					callback();
217				}
218			});
219		};
220
221		RSSRender.prototype.renderGUID = function(guid, target = "#feed"){
222			var self = this;
223
224			if(guid != self.currentGUID){
225				self.currentGUID = guid;
226
227				var item = self.feed.items.filter(function(item){
228					return item.guid.match(guid);
229				})[0];
230	
231				$("#logo").attr("src",  item.itunes.image);
232	
233				var text =
234					"<div class='row'>" +
235						"<div class='col-md-12 item'>" +
236							"<h3>" + item.title + "</h3>" +
237							"<div>" + item.content + "</div>" +
238						"</div>" +
239					"</div>";
240				
241				$(target).html(text);
242				
243				item.link = item.link.replace("http://", "https://");
244	
245				$.get(item.link, function(d){
246					var player_source = $(d).find('iframe:last')[0].src;
247					player_source = player_source.replace("http://", "https://");
248					player_source = player_source.replace("file://", "https://");
249					player_source = player_source.replace("yes", "no");
250					$("#header-content").html('<iframe frameborder="0" scrolling="no" src="' + player_source + '"></iframe>');
251					$("#header-content").addClass("player");
252				});
253				
254				//Fetch itunes stuff
255				self.getAppleData(item.title, function(episode){
256					if(episode){
257						$("<a href='" + episode.trackViewUrl + "'>" +
258							"<img src='./img/apple_podcasts.svg'>" +
259						"</a>").appendTo(target);
260						
261						//https://plinkhq.com/i/1459202600/e/1000459702408?to=googlepod
262						$("<a href='https://plinkhq.com/i/" + episode.collectionId + "/e/" + episode.trackId + "?to=googlepod'>" +
263							"<img src='./img/google_podcasts_badge.png'>" +
264						"</a>").appendTo(target);
265					}
266				});
267			}
268		};
269
270		RSSRender.prototype.getAppleData = function(title, cb){
271			var self = this;
272			//Fetch itunes stuff
273			if(!self.itunes_data){
274				$.ajax({
275					url: "https://itunes.apple.com/lookup?id=1459202600&entity=podcastEpisode",
276					dataType: "jsonp",
277					success: function(d){
278						self.itunes_data = d.results;
279						self.getAppleData(title, cb);
280					}
281				});
282			}else{
283				var episode = self.itunes_data.filter(function(e){
284					return e.trackName == title;
285				});
286
287				cb(episode[0] || false);
288			}
289		};
290
291		/**
292		   * This function coverts a DOM Tree into JavaScript Object. 
293		    * @param srcDOM: DOM Tree to be converted. 
294		     */
295		RSSRender.prototype.xml2json = function(srcDOM){
296			let children = [...srcDOM.children];
297	    
298			// base case for recursion. 
299			if (!children.length) {
300		        	return srcDOM.innerHTML
301			}
302         
303	         	// initializing object to be returned. 
304		        let jsonResult = {};
305         
306		        for (let child of children) {
307	  		        // checking is child has siblings of same name. 
308			        let childIsArray = children.filter(eachChild => eachChild.nodeName === child.nodeName).length > 1;
309
310			        // if child is array, save the values as array, else as strings. 
311					if (childIsArray) {
312			             if (jsonResult[child.nodeName] === undefined) {
313			             	jsonResult[child.nodeName] = [xml2json(child)];
314			             } else {
315               				jsonResult[child.nodeName].push(xml2json(child));
316		        	     }
317	        	       } else {
318			            jsonResult[child.nodeName] = xml2json(child);
319			       }
320	         	}
321         
322		        return jsonResult;
323			};
324			   
325		RSSRender.prototype.getUrlVars = function(){
326    		var vars = {};
327    		var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
328        		vars[key] = value;
329    		});
330    		return vars;
331        }
332
333    
334        window.RSSRender = RSSRender;
335        return window;
336    }
337)(window, $, undefined);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.