I wanted to have a widget on dashboard that I could use to play G&G casts. I was working on one, its almost there but there are some error in it somewhere. It add the G&G feed link it doesnt the widget wont play. I'm using this link http://feeds.feedburner.com/ge...
When I add the feed for our church podcast it plays fine. It's also a feedburner url http://feeds.feedburner.com/bt...
I'm not sure what could be the issue.
FYI: Here is a screenshot of the widget.







sweet
That's sweet that you are making a widget for that. I dunno what else to call it.
What error are you getting? Is it a parse error? Something else?
Matt Farina
Geeks and God Co-Host
www.innovatingtomorrow.net
www.mattfarina.com
When trying to run it theres
When trying to run it theres a error that reads "Value undefined (result of expression track.GetPluginStatus) is not object"
There error is at line 430 of the PodcastSupport.JS
This is going to be a long list here, here it goes.
// This file was generated by Dashcode from Apple Inc.
// You may edit this file to customize your Dashboard widget.
// The podcast feed, as obtained from attributes.js
var feed = attributes.podcastURL.replace(/^(itpc|pcast|feed):/i, "http:");
// How often the feed should refresh, from attributes.js
var refreshInterval = attributes.refreshInterval;
var lastUpdated = 0; // Keeps track of the last update, so that the widget knows when to update
var xmlRequest = null; // The current XMLHttpRequest
var loadingAnimationTimer = null; // Tracks the "Loading..." animation
var trackStatusInterval = null; // Tracks whether the episode is playing
var trackLoadingInterval = null; // Tracks whether the episode is loading
var results = new Array; // The saved, parsed results of the request, used to store the episodes
var podcastDescription = null; // The podcast description, used on the widget's back
var isPlaying = false; // Tracks whether the widget is currently playing
//
// Function: podcastLoad()
// Called when the widget loads. Clears out placeholder text on the widget.
// Adds an invisible <select> used to populate the episode name menu.
//
function podcastLoad()
{
document.getElementById("playButton").addEventListener("click", playpause, false);
var episodeName = document.getElementById("episodeName");
if (episodeName) {
episodeName.object.button.textElement.style.textOverflow = "ellipsis";
episodeName.object.setOptions([""]);
}
if (document.getElementById("episodeDate")) {
document.getElementById("episodeDate").innerText = "";
}
if (document.getElementById("episodeDescription")) {
document.getElementById("episodeDescription").innerText = "";
}
if (document.getElementById("episodeInformation")) {
document.getElementById("episodeInformation").innerText = "";
}
}
//
// Function: podcastShow()
// Posts a request for the podcast RSS feed when the widget is shown.
// Requests are spaced out by the requestInterval to ease server load
// and prevent unnecessary load time.
//
function podcastShow()
{
var episodeName = document.getElementById("episodeName");
if (attributes.podcastURL == "") {
if (episodeName) {
episodeName.object.setOptions([getLocalizedString("No Podcast specified")]);
}
}
else {
var now = (new Date).getTime();
// only check if refresh interval has passed
// Interval in minutes; 60000 is one minute
if (((now - lastUpdated) > (refreshInterval * 60000)) && (!isPlaying)) {
if(xmlRequest) {
xmlRequest.abort();
xmlRequest = null;
}
xmlRequest = new XMLHttpRequest();
xmlRequest.onload = function(e) {
if (xmlRequest.status == 200) {
processFeed(e, xmlRequest);
}
else {
stopLoadingAnimation();
var playButton = document.getElementById("playButton");
playButton.src = "Images/reload.png";
playButton.addEventListener("click", podcastReload, false);
playButton.removeEventListener("click", playpause, false);
episodeName.object.setOptions([getLocalizedString("No Podcast Available")]);
}
};
xmlRequest.overrideMimeType("text/xml");
xmlRequest.open("GET", feed);
xmlRequest.setRequestHeader("Cache-Control", "no-cache");
xmlRequest.send(null);
if (episodeName) {
startLoadingAnimation(); // Begins the "Loading..." animation
}
}
}
}
//
// Function: podcastReload()
// Called by the reload button to try again if the feed failed to load
//
function podcastReload()
{
var playButton = document.getElementById("playButton");
playButton.src = "Images/play.png";
playButton.removeEventListener("click", podcastReload, false);
playButton.addEventListener("click", playpause, false);
podcastShow();
}
//
// Function: findChild(element, nodeName)
// Scans the children of a given DOM element for a node matching nodeName.
//
// element: The DOM element to search.
// nodeName: The node name to search for.
//
function findChild(element, nodeName)
{
var child;
for (child = element.firstChild; child != null; child = child.nextSibling) {
if (child.nodeName == nodeName) {
return child;
}
}
return null;
}
//
// Function: processFeed(e, request)
// Extract the content of the podcast RSS feed and store the data in a results array.
//
// e: onLoad event from XMLHttpRequest
// request: xmlHttpRequest containing the feed
//
function processFeed(e, request)
{
xmlRequest = null;
if (request.responseXML) {
// Clear the results array
while(results.length > 0) {
results.pop();
}
// Get the top level <rss> element
var rss = findChild(request.responseXML, 'rss');
if (!rss) return;
// Get single subordinate channel element
var channel = findChild(rss, 'channel');
if (!channel) return;
// Store the podcast description for use on the widget back
podcastDescription = findChild(channel, 'description');
if (!podcastDescription || !podcastDescription.firstChild) {
podcastDescription = findChild(channel, 'itunes:summary');
if (!podcastDescription || !podcastDescription.firstChild) {
podcastDescription = getLocalizedString("No Podcast description provided");
}
else {
podcastDescription = podcastDescription.firstChild.data;
}
}
else {
podcastDescription = podcastDescription.firstChild.data;
}
// Get all item elements subordinate to the channel element.
// For each element, get title, pubDate, subtitle, description, and episode URL.
for (var item = channel.firstChild; item != null; item = item.nextSibling) {
if (item.nodeName == 'item') {
var title = findChild (item, 'title');
// we have to have the title to include the item in the list
if (title) {
var title = findChild(item, 'title');
if (!title || !title.firstChild) {
title = getLocalizedString("No episode title provided");
}
else {
title = title.firstChild.data;
}
var date = findChild(item, 'pubDate');
var dateString = null;
if (!date || !date.firstChild) {
dateString = null;
date = null;
}
else {
dateString = date.firstChild.data;
date = new Date(Date.parse(date.firstChild.data));
}
var description = findChild(item, 'description');
if (!description || !description.firstChild) {
description = getLocalizedString("No episode description provided");
}
else {
description = description.firstChild.data;
}
var subtitle = findChild(item, 'itunes:subtitle');
if (!subtitle || !subtitle.firstChild) {
subtitle = description;
}
else {
subtitle = subtitle.firstChild.data;
}
var link = findChild (item, 'link');
if (!link) {
link = null;
}
else {
link = link.firstChild.data;
}
var enclosure = findChild(item, 'enclosure');
if (!enclosure) {
// if there's no enclosure, there's no episode to play; ignore the entry and move on.
continue;
}
else {
enclosure = enclosure.getAttribute('url');
}
results[results.length] = {
title: title,
date: date,
dateString: dateString,
subtitle: subtitle,
description: description,
link: link,
track: enclosure
};
}
}
}
// Sort by date
results.sort(function (a, b) { return b.date - a.date; });
// Since we have results, pause the loading animation
stopLoadingAnimation();
// Copy titles into the pop-up menu
populateMenu(results);
// Place the most recent episode's information on the widget
updateEpisode(results[0]);
// Reset the last updated value track how often the widget refreshes
lastUpdated = (new Date).getTime();
}
}
//
// Function: createDateStr(date)
// Creates a readable date string from the provided Date object.
//
// date: JavaScript Date object to format
//
function createDateStr(date)
{
if (!date) {
return getLocalizedString("No or improper date provided");
}
var day;
switch (date.getDay()) {
case 0: day = getLocalizedString("Sunday"); break;
case 1: day = getLocalizedString("Monday"); break;
case 2: day = getLocalizedString("Tuesday"); break;
case 3: day = getLocalizedString("Wednesday"); break;
case 4: day = getLocalizedString("Thursday"); break;
case 5: day = getLocalizedString("Friday"); break;
case 6: day = getLocalizedString("Saturday"); break;
default: day = "";
}
var month;
switch (date.getMonth()) {
case 0: month = getLocalizedString("January"); break;
case 1: month = getLocalizedString("February"); break;
case 2: month = getLocalizedString("March"); break;
case 3: month = getLocalizedString("April"); break;
case 4: month = getLocalizedString("May"); break;
case 5: month = getLocalizedString("June"); break;
case 6: month = getLocalizedString("July"); break;
case 7: month = getLocalizedString("August"); break;
case 8: month = getLocalizedString("September"); break;
case 9: month = getLocalizedString("October"); break;
case 10: month = getLocalizedString("November"); break;
case 11: month = getLocalizedString("December"); break;
default: month = "";
}
if (day == "" && month == "") {
return null;
}
else {
return day + ", " + month + " " + date.getDate() + ", " + date.getFullYear();
}
}
//
// Function: populateMenu(results)
// Called whenever there's a need to change the elements shown in the
// episode popup menu. It empties the menu and replaces its items
// with the titles found in a results-structured array.
//
// results: Episodes to show in the menu
//
function populateMenu(results)
{
var episodeNames = [];
for (var i = 0; i < results.length; i++) {
var item = results[i];
var episodeName = [item.title];
episodeNames[i] = episodeName;
}
document.getElementById("episodeName").object.setOptions(episodeNames);
}
//
// Function: changeEpisode(elem)
// Called when a new item is selected in the menu; swaps out the
// episode info and track with the selected episode's.
//
// elem: episode menu element
//
function changeEpisode(elem)
{
var chosen = document.getElementById("episodeName").object.getSelectedIndex();
updateEpisode(results[chosen]);
}
//
// Function: updateEpisode(elem)
// Updates all of the various strings on the widget with the supplied
// episode's information. Also preps the episode track to play and
// pauses it
//
// elem: chosen episode from results array
//
function updateEpisode(elem)
{
if (isPlaying) {
playpause();
}
var episodeDate = document.getElementById("episodeDate");
var date = createDateStr(elem.date);
if (!date) {
if (elem.dateString) {
if (episodeDate) {
episodeDate.innerText = elem.dateString;
}
}
}
else {
if (episodeDate) {
episodeDate.innerText = date;
}
}
if (document.getElementById("episodeDescription")) {
document.getElementById("episodeDescription").innerText = stripTags(elem.subtitle);
}
var episodeInformation = document.getElementById("episodeInformation");
if (episodeInformation) {
episodeInformation.innerHTML = (elem.title + "<br>" + elem.description + "<br><br>" + getLocalizedString("About this Podcast:") + "<br>" + podcastDescription).replace(/\r?\n/g,"<br>");
// Remove any embedded content
var embeddedElements = episodeInformation.getElementsByTagName("embed");
for (var i = 0; i < embeddedElements.length; i++) {
(embeddedElements[i].parentNode).removeChild(embeddedElements[i]);
}
// Change all links into onclick calls, so that the link opens in a browser
var anchors = episodeInformation.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++) {
anchors[i].setAttribute("onclick", "widget.openURL('" + (anchors[i].href).replace(/([\\\'])/g, '\\$1') + "');"); //"
anchors[i].removeAttribute("href");
}
}
// Load the podcast's track
var episodeTrack = document.getElementById("episodeTrack");
if (episodeTrack) {
episodeTrack.SetResetPropertiesOnReload(false);
episodeTrack.SetURL(elem.track);
}
else {
var episode = document.createElement("embed");
episode.setAttribute("id", "episodeTrack");
episode.setAttribute("controller", "false");
episode.setAttribute("autoplay", "false");
episode.setAttribute("enablejavascript", "true");
episode.setAttribute("type", "audio/quicktime");
episode.setAttribute("style", "visibility: hidden;");
episode.setAttribute("src", elem.track);
document.getElementById("body").appendChild(episode);
}
// Load a spinner, so that people know the audio is loading
if (!(document.getElementById("_spinner"))) {
document.getElementById("playButton").src = "Images/loading.png";
var spinner = document.createElement("img");
spinner.setAttribute("id", "_spinner");
spinner.setAttribute("src", "Images/progress.gif");
var playPauseStyle = document.defaultView.getComputedStyle(document.getElementById("playButton"), null);
spinner.setAttribute("style", "position: absolute; width:" + playPauseStyle.getPropertyValue("width") +
"; height:" + playPauseStyle.getPropertyValue("height") +
"; top:" + playPauseStyle.getPropertyValue("top") +
"; right:" + playPauseStyle.getPropertyValue("right") +
"; bottom:" + playPauseStyle.getPropertyValue("bottom") +
"; left:" + playPauseStyle.getPropertyValue("left") +
"; z-index: 8000;");
document.getElementById("front").appendChild(spinner);
}
// Check in to see if things have loaded
var checkTrackLoad = function ()
{
var track = document.getElementById("episodeTrack");
var status = track.GetPluginStatus();
if ((status.match("Playable")) || (status.match("Complete"))) {
if (document.getElementById("_spinner")) {
document.getElementById("front").removeChild(document.getElementById("_spinner"));
}
document.getElementById("playButton").src = "Images/play.png";
clearInterval(trackLoadingInterval);
}
else {
if ((status.match("Error"))) {
if (document.getElementById("_spinner")) {
document.getElementById("front").removeChild(document.getElementById("_spinner"));
}
document.getElementById("playButton").src = "Images/error.png";
clearInterval(trackLoadingInterval);
}
}
};
if (trackLoadingInterval) {
clearInterval(trackLoadingInterval);
}
trackLoadingInterval = setInterval(checkTrackLoad, 1000);
}
//
// Function: stripTags(aString)
// Removes any extra HTML tags that may be strewn about the response XML.
//
// aString: string to strip the tags from
//
function stripTags(aString)
{
return aString.replace(/<[^>]*>/g, "");
}
//
// Function: subscribe(event)
// Called when the subscribe button is clicked on the widget's back;
// hands off the podcast URL to iTunes.
//
// event: onClick event from the button
//
function subscribe(event)
{
widget.openURL(feed.replace(/^http:/, "itpc:"));
}
//
// Function: startLoadingAnimation()
// Places animated "Loading..." text on the widget while the feed loads.
//
function startLoadingAnimation()
{
var dots = 0;
var animateLoadingDots = function ()
{
var loading = getLocalizedString("Loading");
for (var i = 0; i < dots; i++) {
loading = loading + ".";
}
document.getElementById("episodeName").object.setOptions([loading]);
if (++dots > 3) {
dots = 0;
}
};
loadingAnimationTimer = setInterval(animateLoadingDots, 500);
}
//
// Function: stopLoadingAnimation()
//
// Stops the "Loading..." animation when the feed finishes loading.
//
function stopLoadingAnimation()
{
if (loadingAnimationTimer != null) {
clearInterval(loadingAnimationTimer);
loadingAnimationTimer = null;
}
}
//
// Function: playpause(event)
// Toggles whether the widget is playing or not
//
// event: onClick event from the button.
//
function playpause(event)
{
var track = document.getElementById("episodeTrack");
if (!track) return;
var status = track.GetPluginStatus();
if ((status.match("Waiting")) || (status.match("Loading")) || (status.match("Error"))) return;
if (!isPlaying) {
document.getElementById("playButton").src = "Images/pause.png";
track.Play();
var checkTrackStatus = function ()
{
var track = document.getElementById("episodeTrack");
if (track.GetTime() >= track.GetDuration()) {
playpause();
}
};
trackStatusInterval = setInterval(checkTrackStatus, 1000);
}
else {
document.getElementById("playButton").src = "Images/play.png";
track.Stop();
if (track.GetTime() >= track.GetDuration()) {
// If done, set to beginning
track.SetTime(0);
}
clearInterval(trackStatusInterval);
}
isPlaying = !isPlaying;
}
This is what's strange. I
This is what's strange. I created another one for the PC/Mac Smackdown podcast and works fine. I change the url in dashcode to the G&G url it no longer works either. Go figure huh.
Here's the LINK for that widget.
There's something wrong with
There's something wrong with your feed. It contains entries like this:
<media:content url="http://feeds.feedburner.com/~r/geeksandgod/~5/208723538/" fi
leSize="38112256" type="audio/mpeg" />
For some reason, the URL isn't pointing to an audio file, and that causes the widget to crash when it tries to play it. It's an interesting challenge to try to avoid the crash.. probably better to fix your feed. :-)
you're right
You are right. I was running an early version of the podtrac module and it was causing broken feeds. It should all be fixed now. Let me know if that gets it going.
Matt Farina
Geeks and God Co-Host
www.innovatingtomorrow.net
www.mattfarina.com
Still seems to be something feedburner is doing
Looking at my own churches widget I realized that it was not pulling the feedburner url but the direct link to the xml file in which feedburner was pulling from.
I inserted the feedburner address into it and was having the same issues as with the G&G one.
Matt, if you can email me the direct url to the feed I can use that just to verify whether it works or not and post back. I won't give it up at all. You can get my email addy in my account profile here.
strange
What's the error this time? I'm curious what part of the feed is acting up.
Matt Farina
Geeks and God Co-Host
www.innovatingtomorrow.net
www.mattfarina.com
It's working now
I decided just to start from scratch. This time around it's working with the original feedburner address.
Cool, now I can listen to G&G from my dashboard instead of iTunes.
Here is a Link to download it if anyone wants it.
Nice find
Nice find. At this moment it's still not working. Feed is probably cached or something. I'll try again later and see how it goes.
Widget for XP/Vista
I was just wondering if there is anyway to have this kind of widget for a PC user using XP or Vista. Thanks.
Yes
You can make widgets for Vista. That is built right into the operating system. In XP you would need to sue something like Yahoo Widgets.
Matt Farina
Geeks and God Co-Host
www.innovatingtomorrow.net
www.mattfarina.com
You could try converting it
This may be able to do it, but I havent used it myself.
http://www.amnestywidgets.com/...