/* You can override the default CBC feed by specifying the RSS feed you would prefer to use through the parameters field in the widget. Available CBC RSS feed are available here: https://www.cbc.ca/rss/ */ function unescapeHTML(str) {//modified from underscore.string and string.js return str.replace(/\&([^;]+);/g, function(entity, entityCode) { var escapeChars = { lt: '<', gt: '>', quot: '"', apos: "'", amp: '&' }; var match; if ( entityCode in escapeChars) { return escapeChars[entityCode]; } else if ( match = entityCode.match(/^#x([\da-fA-F]+)$/)) { return String.fromCharCode(parseInt(match[1], 16)); } else if ( match = entityCode.match(/^#(\d+)$/)) { return String.fromCharCode(~~match[1]); } else { return entity; } }); } let params = args.widgetParameter; var url = "https://rss.cbc.ca/lineup/canada.xml"; if(params != null) { url = params; } let items = []; let request = new Request(url); let s = await request.loadString(request); let xmlParser = new XMLParser(s); let elementName = ""; let currentValue = null; let currentItem = null; let currentAttributes = null; xmlParser.didStartElement = (name, attributes) => { currentValue = ""; if(name == "item") { currentItem = {}; } } xmlParser.didEndElement = name => { const hasItem = currentItem != null; if(hasItem) { switch(name) { case "title": currentItem["title"] = currentValue; break; case "description": currentItem["description"] = currentValue; break; case "link": currentItem["link"] = currentValue; break; case "pubDate": currentItem["date"] = new Date(currentValue); break; case "author": currentItem["author"] = currentValue; break; default: break; } } if(name == "item") { items.push(currentItem); currentItem = {}; } } xmlParser.foundCharacters = (string) => { currentValue += string; } xmlParser.parseErrorOccurred = (string) => { console.log("failed on: " + string); } xmlParser.parse(); let widget = await createWidget(items); if(!config.runsInWidget) { await widget.presentMedium(); } Script.setWidget(widget) Script.complete() async function createWidget(items) { let info = items[0]; let imageURL = extractImageURL(info.description); let df = new DateFormatter(); df.dateFormat = "MMMM dd, yyyy h:mm a"; let publishDate = df.string(info.date); let w = new ListWidget(); w.url = info.link; let title = w.addText(info.title); title.font = Font.boldSystemFont(16); w.addSpacer(1); let storyDate = "@ " + w.addText(publishDate); storyDate.font = Font.caption1(); let g = new LinearGradient(); g.locations = [0, 1]; g.colors = [ new Color("#ff0000af"), new Color("#0000007f") ] let imageRequest = new Request(imageURL); let image = await imageRequest.loadImage(); if(image != null) { w.backgroundImage = image; } w.backgroundColor = Color.red(); w.backgroundGradient = g; w.addSpacer(8); var story = w.addText(extractStoryText(info.description)); story.font = Font.mediumSystemFont(12); return w; } function extractImageURL(item) { let regex = /<img src='(.*)' alt='/; let matches = item.match(regex); if (matches && matches.length >= 2) { return matches[1]; } else { return null; } } function extractStoryText(item) { let regex = /<p>(.*)<\/p>/; let matches = item.match(regex); if(matches && matches.length >= 2) { return matches[1]; } else { return null; } }