Skip to content

Instantly share code, notes, and snippets.

@joeybaumgartner
Last active November 26, 2020 20:22
Show Gist options
  • Save joeybaumgartner/d659ced958ccc194c449f634fcbabb08 to your computer and use it in GitHub Desktop.
Save joeybaumgartner/d659ced958ccc194c449f634fcbabb08 to your computer and use it in GitHub Desktop.
CBC Scriptable Widget
/*
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;
}
}
@joeybaumgartner
Copy link
Author

Added unescapeHTML function that was missing from original file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment