Bug 303645. Add support for media feeds and objects (enclosures). Patch by Will Guaraldi <will.guaraldi@pculture.org>. r=sayrer/gavin, ui-r=beltzner, a=beltzner
|
@ -24,6 +24,7 @@
|
|||
# Asaf Romano <mano@mozilla.com>
|
||||
# Robert Sayre <sayrer@gmail.com>
|
||||
# Michael Ventnor <m.ventnor@gmail.com>
|
||||
# Will Guaraldi <will.guaraldi@pculture.org>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -91,8 +92,35 @@ const PREF_SHOW_FIRST_RUN_UI = "browser.feeds.showFirstRunUI";
|
|||
const TITLE_ID = "feedTitleText";
|
||||
const SUBTITLE_ID = "feedSubtitleText";
|
||||
|
||||
/**
|
||||
* Converts a number of bytes to the appropriate unit that results in a
|
||||
* number that needs fewer than 4 digits
|
||||
*
|
||||
* @return a pair: [new value with 3 sig. figs., its unit]
|
||||
*/
|
||||
function convertByteUnits(aBytes) {
|
||||
var units = ["bytes", "kilobyte", "megabyte", "gigabyte"];
|
||||
let unitIndex = 0;
|
||||
|
||||
// convert to next unit if it needs 4 digits (after rounding), but only if
|
||||
// we know the name of the next unit
|
||||
while ((aBytes >= 999.5) && (unitIndex < units.length - 1)) {
|
||||
aBytes /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
|
||||
// Get rid of insignificant bits by truncating to 1 or 0 decimal points
|
||||
// 0 -> 0; 1.2 -> 1.2; 12.3 -> 12.3; 123.4 -> 123; 234.5 -> 235
|
||||
aBytes = aBytes.toFixed((aBytes > 0) && (aBytes < 100) ? 1 : 0);
|
||||
|
||||
return [aBytes, units[unitIndex]];
|
||||
}
|
||||
|
||||
function FeedWriter() {}
|
||||
FeedWriter.prototype = {
|
||||
_mimeSvc : Cc["@mozilla.org/mime;1"].
|
||||
getService(Ci.nsIMIMEService),
|
||||
|
||||
_getPropertyAsBag: function FW__getPropertyAsBag(container, property) {
|
||||
return container.fields.getProperty(property).
|
||||
QueryInterface(Ci.nsIPropertyBag2);
|
||||
|
@ -357,6 +385,12 @@ FeedWriter.prototype = {
|
|||
}
|
||||
body.className = "feedEntryContent";
|
||||
entryContainer.appendChild(body);
|
||||
|
||||
if (entry.enclosures && entry.enclosures.length > 0) {
|
||||
var enclosuresDiv = this._buildEnclosureDiv(entry);
|
||||
entryContainer.appendChild(enclosuresDiv);
|
||||
}
|
||||
|
||||
feedContent.appendChild(entryContainer);
|
||||
var clearDiv = this._document.createElementNS(HTML_NS, "div");
|
||||
clearDiv.style.clear = "both";
|
||||
|
@ -364,6 +398,105 @@ FeedWriter.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Takes a url to a media item and returns the best name it can come up with.
|
||||
* Frequently this is the filename portion (e.g. passing in
|
||||
* http://example.com/foo.mpeg would return "foo.mpeg"), but in more complex
|
||||
* cases, this will return the entire url (e.g. passing in
|
||||
* http://example.com/somedirectory/ would return
|
||||
* http://example.com/somedirectory/).
|
||||
* @param aURL
|
||||
* The URL string from which to create a display name
|
||||
* @returns a string
|
||||
*/
|
||||
_getURLDisplayName: function FW__getURLDisplayName(aURL) {
|
||||
var url = makeURI(aURL);
|
||||
url.QueryInterface(Ci.nsIURL);
|
||||
if (url == null || url.fileName.length == 0)
|
||||
return aURL;
|
||||
|
||||
return decodeURI(url.fileName);
|
||||
},
|
||||
|
||||
/**
|
||||
* Takes a FeedEntry with enclosures, generates the HTML code to represent
|
||||
* them, and returns that.
|
||||
* @param entry
|
||||
* FeedEntry with enclosures
|
||||
* @returns element
|
||||
*/
|
||||
_buildEnclosureDiv: function FW__buildEnclosureDiv(entry) {
|
||||
var enclosuresDiv = this._document.createElementNS(HTML_NS, "div");
|
||||
enclosuresDiv.setAttribute("class", "enclosures");
|
||||
|
||||
enclosuresDiv.appendChild(this._document.createTextNode(this._getString("mediaLabel")));
|
||||
|
||||
var roundme = function(n) {
|
||||
return (Math.round(n * 100) / 100).toLocaleString();
|
||||
}
|
||||
|
||||
for (var i_enc = 0; i_enc < entry.enclosures.length; ++i_enc) {
|
||||
var enc = entry.enclosures.queryElementAt(i_enc, Ci.nsIWritablePropertyBag2);
|
||||
|
||||
if (!(enc.hasKey("url")))
|
||||
continue;
|
||||
|
||||
var enclosureDiv = this._document.createElementNS(HTML_NS, "div");
|
||||
enclosureDiv.setAttribute("class", "enclosure");
|
||||
|
||||
var mozicon = "moz-icon://.txt?size=16";
|
||||
var type_text = null;
|
||||
var size_text = null;
|
||||
|
||||
if (enc.hasKey("type")) {
|
||||
type_text = enc.get("type");
|
||||
try {
|
||||
var handlerInfoWrapper = this._mimeSvc.getFromTypeAndExtension(enc.get("type"), null);
|
||||
|
||||
if (handlerInfoWrapper)
|
||||
type_text = handlerInfoWrapper.description;
|
||||
|
||||
if (type_text && type_text.length > 0)
|
||||
mozicon = "moz-icon://goat?size=16&contentType=" + enc.get("type");
|
||||
|
||||
} catch (ex) { }
|
||||
|
||||
}
|
||||
|
||||
if (enc.hasKey("length") && /^[0-9]+$/.test(enc.get("length"))) {
|
||||
var enc_size = convertByteUnits(parseInt(enc.get("length")));
|
||||
|
||||
var size_text = this._getFormattedString("enclosureSizeText",
|
||||
[enc_size[0], this._getString(enc_size[1])]);
|
||||
}
|
||||
|
||||
var iconimg = this._document.createElementNS(HTML_NS, "img");
|
||||
iconimg.setAttribute("src", mozicon);
|
||||
iconimg.setAttribute("class", "type-icon");
|
||||
enclosureDiv.appendChild(iconimg);
|
||||
|
||||
enclosureDiv.appendChild(this._document.createTextNode( " " ));
|
||||
|
||||
var enc_href = this._document.createElementNS(HTML_NS, "a");
|
||||
enc_href.appendChild(this._document.createTextNode(this._getURLDisplayName(enc.get("url"))));
|
||||
this._safeSetURIAttribute(enc_href, "href", enc.get("url"));
|
||||
enclosureDiv.appendChild(enc_href);
|
||||
|
||||
if (type_text && size_text)
|
||||
enclosureDiv.appendChild(this._document.createTextNode( " (" + type_text + ", " + size_text + ")"));
|
||||
|
||||
else if (type_text)
|
||||
enclosureDiv.appendChild(this._document.createTextNode( " (" + type_text + ")"))
|
||||
|
||||
else if (size_text)
|
||||
enclosureDiv.appendChild(this._document.createTextNode( " (" + size_text + ")"))
|
||||
|
||||
enclosuresDiv.appendChild(enclosureDiv);
|
||||
}
|
||||
|
||||
return enclosuresDiv;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a valid nsIFeedContainer object from the parsed nsIFeedResult.
|
||||
* Displays error information if there was one.
|
||||
|
|
После Ширина: | Высота: | Размер: 1.8 KiB |
После Ширина: | Высота: | Размер: 830 B |
|
@ -152,3 +152,21 @@ a[href] img {
|
|||
font-size: 85%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.type-icon {
|
||||
vertical-align: bottom;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.enclosures {
|
||||
border: 1px solid THreeDShadow;
|
||||
padding: 1em;
|
||||
margin: 1em auto;
|
||||
background: -moz-Dialog;
|
||||
}
|
||||
|
||||
.enclosure {
|
||||
vertical-align: middle;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
|
После Ширина: | Высота: | Размер: 1.8 KiB |
После Ширина: | Высота: | Размер: 830 B |
|
@ -26,6 +26,10 @@ classic.jar:
|
|||
skin/classic/browser/Toolbar-small.png
|
||||
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/videoFeedIcon.png (feeds/videoFeedIcon.png)
|
||||
skin/classic/browser/feeds/videoFeedIcon16.png (feeds/videoFeedIcon16.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon.png (feeds/audioFeedIcon.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/audioFeedIcon16.png)
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
* skin/classic/browser/places/bookmarkProperties.css (places/bookmarkProperties.css)
|
||||
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
|
||||
|
|
После Ширина: | Высота: | Размер: 1.7 KiB |
После Ширина: | Высота: | Размер: 3.5 KiB |
|
@ -126,3 +126,21 @@ a[href] img {
|
|||
font-size: 85%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.type-icon {
|
||||
vertical-align: bottom;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.enclosures {
|
||||
border: 1px solid THreeDShadow;
|
||||
padding: 1em;
|
||||
margin: 1em auto;
|
||||
background: -moz-Dialog;
|
||||
}
|
||||
|
||||
.enclosure {
|
||||
vertical-align: middle;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
|
После Ширина: | Высота: | Размер: 1.7 KiB |
После Ширина: | Высота: | Размер: 3.5 KiB |
|
@ -32,6 +32,10 @@ classic.jar:
|
|||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/videoFeedIcon.png (feeds/videoFeedIcon.png)
|
||||
skin/classic/browser/feeds/videoFeedIcon16.png (feeds/videoFeedIcon16.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon.png (feeds/audioFeedIcon.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/audioFeedIcon16.png)
|
||||
skin/classic/browser/radio-selected-bg.gif
|
||||
skin/classic/browser/setDesktopBackground.css
|
||||
skin/classic/browser/monitor.png
|
||||
|
|
После Ширина: | Высота: | Размер: 1.7 KiB |
После Ширина: | Высота: | Размер: 3.5 KiB |
|
@ -152,3 +152,21 @@ a[href] img {
|
|||
font-size: 85%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.type-icon {
|
||||
vertical-align: bottom;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.enclosures {
|
||||
border: 1px solid THreeDShadow;
|
||||
padding: 1em;
|
||||
margin: 1em auto;
|
||||
background: -moz-Dialog;
|
||||
}
|
||||
|
||||
.enclosure {
|
||||
vertical-align: middle;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
|
После Ширина: | Высота: | Размер: 1.7 KiB |
После Ширина: | Высота: | Размер: 3.5 KiB |
|
@ -31,6 +31,10 @@ classic.jar:
|
|||
skin/classic/browser/wrench.png
|
||||
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/videoFeedIcon.png (feeds/videoFeedIcon.png)
|
||||
skin/classic/browser/feeds/videoFeedIcon16.png (feeds/videoFeedIcon16.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon.png (feeds/audioFeedIcon.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/audioFeedIcon16.png)
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/places/places.css (places/places.css)
|
||||
skin/classic/browser/places/organizer.css (places/organizer.css)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Ben Goodger <beng@google.com>
|
||||
* Myk Melez <myk@mozilla.org>
|
||||
* Michael Ventnor <m.ventnor@gmail.com>
|
||||
* Will Guaraldi <will.guaraldi@pculture.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -220,7 +221,9 @@ var gNamespaces = {
|
|||
"http://my.netscape.com/rdf/simple/0.9/":"rss1",
|
||||
"http://wellformedweb.org/CommentAPI/":"wfw",
|
||||
"http://purl.org/rss/1.0/modules/wiki/":"wiki",
|
||||
"http://www.w3.org/XML/1998/namespace":"xml"
|
||||
"http://www.w3.org/XML/1998/namespace":"xml",
|
||||
"http://search.yahoo.com/mrss/":"media",
|
||||
"http://search.yahoo.com/mrss":"media"
|
||||
}
|
||||
|
||||
// We allow a very small set of namespaces in XHTML content,
|
||||
|
@ -264,6 +267,8 @@ function Feed() {
|
|||
this.authors = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray);
|
||||
this.contributors = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray);
|
||||
this.baseURI = null;
|
||||
this.enclosureCount = 0;
|
||||
this.type = Ci.nsIFeed.TYPE_FEED;
|
||||
}
|
||||
|
||||
Feed.prototype = {
|
||||
|
@ -303,6 +308,8 @@ Feed.prototype = {
|
|||
if (bagHasKey(this.fields, "links"))
|
||||
this._atomLinksToURI();
|
||||
|
||||
this._calcEnclosureCountAndFeedType();
|
||||
|
||||
// Resolve relative image links
|
||||
if (this.image && bagHasKey(this.image, "url"))
|
||||
this._resolveImageLink();
|
||||
|
@ -311,6 +318,67 @@ Feed.prototype = {
|
|||
this.searchLists.title]);
|
||||
},
|
||||
|
||||
_calcEnclosureCountAndFeedType: function Feed_calcEnclosureCountAndFeedType() {
|
||||
var entries_with_enclosures = 0;
|
||||
var audio_count = 0;
|
||||
var image_count = 0;
|
||||
var video_count = 0;
|
||||
var other_count = 0;
|
||||
|
||||
for (var i = 0; i < this.items.length; ++i) {
|
||||
var entry = this.items.queryElementAt(i, Ci.nsIFeedEntry);
|
||||
entry.QueryInterface(Ci.nsIFeedContainer);
|
||||
|
||||
if (entry.enclosures && entry.enclosures.length > 0) {
|
||||
++entries_with_enclosures;
|
||||
|
||||
for (var e = 0; e < entry.enclosures.length; ++e) {
|
||||
var enc = entry.enclosures.queryElementAt(e, Ci.nsIWritablePropertyBag2);
|
||||
if (enc.hasKey("type")) {
|
||||
var enctype = enc.get("type");
|
||||
|
||||
if (/^audio/.test(enctype)) {
|
||||
++audio_count;
|
||||
} else if (/^image/.test(enctype)) {
|
||||
++image_count;
|
||||
} else if (/^video/.test(enctype)) {
|
||||
++video_count;
|
||||
} else {
|
||||
++other_count;
|
||||
}
|
||||
} else {
|
||||
++other_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var feedtype = Ci.nsIFeed.TYPE_FEED;
|
||||
|
||||
// For a feed to be marked as TYPE_VIDEO, TYPE_AUDIO and TYPE_IMAGE,
|
||||
// we enforce two things:
|
||||
//
|
||||
// 1. all entries must have at least one enclosure
|
||||
// 2. all enclosures must be video for TYPE_VIDEO, audio for TYPE_AUDIO or image
|
||||
// for TYPE_IMAGE
|
||||
//
|
||||
// Otherwise it's a TYPE_FEED.
|
||||
if (entries_with_enclosures == this.items.length && other_count == 0) {
|
||||
if (audio_count > 0 && !video_count && !image_count) {
|
||||
feedtype = Ci.nsIFeed.TYPE_AUDIO;
|
||||
|
||||
} else if (image_count > 0 && !audio_count && !video_count) {
|
||||
feedtype = Ci.nsIFeed.TYPE_IMAGE;
|
||||
|
||||
} else if (video_count > 0 && !audio_count && !image_count) {
|
||||
feedtype = Ci.nsIFeed.TYPE_VIDEO;
|
||||
}
|
||||
}
|
||||
|
||||
this.type = feedtype;
|
||||
this.enclosureCount = other_count + video_count + audio_count + image_count;
|
||||
},
|
||||
|
||||
_atomLinksToURI: function Feed_linkToURI() {
|
||||
var links = this.fields.getPropertyAsInterface("links", Ci.nsIArray);
|
||||
var alternates = findAtomLinks("alternate", links);
|
||||
|
@ -407,7 +475,10 @@ Entry.prototype = {
|
|||
// Assign Atom link if needed
|
||||
if (bagHasKey(this.fields, "links"))
|
||||
this._atomLinksToURI();
|
||||
|
||||
|
||||
// Populate enclosures array
|
||||
this._populateEnclosures();
|
||||
|
||||
// The link might be a guid w/ permalink=true
|
||||
if (!this.link && bagHasKey(this.fields, "guid")) {
|
||||
var guid = this.fields.getProperty("guid");
|
||||
|
@ -430,6 +501,133 @@ Entry.prototype = {
|
|||
this.searchLists.title]);
|
||||
},
|
||||
|
||||
_populateEnclosures: function Entry_populateEnclosures() {
|
||||
if (bagHasKey(this.fields, "links"))
|
||||
this._atomLinksToEnclosures();
|
||||
|
||||
// Add RSS2 enclosure to enclosures
|
||||
if (bagHasKey(this.fields, "enclosure"))
|
||||
this._enclosureToEnclosures();
|
||||
|
||||
// Add media:content to enclosures
|
||||
if (bagHasKey(this.fields, "mediacontent"))
|
||||
this._mediacontentToEnclosures();
|
||||
|
||||
// Add media:content in media:group to enclosures
|
||||
if (bagHasKey(this.fields, "mediagroup"))
|
||||
this._mediagroupToEnclosures();
|
||||
},
|
||||
|
||||
__enclosure_map: null,
|
||||
|
||||
_addToEnclosures: function Entry_addToEnclosures(new_enc) {
|
||||
if (!bagHasKey(new_enc, "url"))
|
||||
return;
|
||||
|
||||
if (this.__enclosure_map == null)
|
||||
this.__enclosure_map = {};
|
||||
|
||||
var previous_enc = this.__enclosure_map[new_enc.getPropertyAsAString("url")];
|
||||
|
||||
if (previous_enc != undefined) {
|
||||
previous_enc.QueryInterface(Ci.nsIWritablePropertyBag2);
|
||||
|
||||
if (!bagHasKey(previous_enc, "type") && bagHasKey(new_enc, "type"))
|
||||
previous_enc.setPropertyAsAString("type", new_enc.getPropertyAsAString("type"));
|
||||
|
||||
if (!bagHasKey(previous_enc, "length") && bagHasKey(new_enc, "length"))
|
||||
previous_enc.setPropertyAsAString("length", new_enc.getPropertyAsAString("length"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.enclosures == null) {
|
||||
this.enclosures = Cc[ARRAY_CONTRACTID].createInstance(Ci.nsIMutableArray);
|
||||
this.enclosures.QueryInterface(Ci.nsIMutableArray);
|
||||
}
|
||||
|
||||
this.enclosures.appendElement(new_enc, false);
|
||||
this.__enclosure_map[new_enc.getPropertyAsAString("url")] = new_enc;
|
||||
},
|
||||
|
||||
_atomLinksToEnclosures: function Entry_linkToEnclosure() {
|
||||
var links = this.fields.getPropertyAsInterface("links", Ci.nsIArray);
|
||||
var enc_links = findAtomLinks("enclosure", links);
|
||||
if (enc_links.length == 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < enc_links.length; ++i) {
|
||||
var link = enc_links[i];
|
||||
|
||||
// an enclosure must have an href
|
||||
if (!(link.getProperty("href")))
|
||||
return;
|
||||
|
||||
var enc = Cc[BAG_CONTRACTID].createInstance(Ci.nsIWritablePropertyBag2);
|
||||
|
||||
// copy Atom bits over to equivalent enclosure bits
|
||||
enc.setPropertyAsAString("url", link.getPropertyAsAString("href"));
|
||||
if (bagHasKey(link, "type"))
|
||||
enc.setPropertyAsAString("type", link.getPropertyAsAString("type"));
|
||||
if (bagHasKey(link, "length"))
|
||||
enc.setPropertyAsAString("length", link.getPropertyAsAString("length"));
|
||||
|
||||
this._addToEnclosures(enc);
|
||||
}
|
||||
},
|
||||
|
||||
_enclosureToEnclosures: function Entry_enclosureToEnclosures() {
|
||||
var enc = this.fields.getPropertyAsInterface("enclosure", Ci.nsIPropertyBag2);
|
||||
|
||||
if (!(enc.getProperty("url")))
|
||||
return;
|
||||
|
||||
this._addToEnclosures(enc);
|
||||
},
|
||||
|
||||
_mediacontentToEnclosures: function Entry_mediacontentToEnclosures() {
|
||||
var mc = this.fields.getPropertyAsInterface("mediacontent", Ci.nsIPropertyBag2);
|
||||
|
||||
if (!(mc.getProperty("url")))
|
||||
return;
|
||||
|
||||
var enc = Cc[BAG_CONTRACTID].createInstance(Ci.nsIWritablePropertyBag2);
|
||||
|
||||
enc.setPropertyAsAString("url", mc.getPropertyAsAString("url"));
|
||||
if (bagHasKey(mc, "fileSize"))
|
||||
enc.setPropertyAsAString("length", mc.getPropertyAsAString("fileSize"));
|
||||
if (bagHasKey(mc, "type"))
|
||||
enc.setPropertyAsAString("type", mc.getPropertyAsAString("type"));
|
||||
|
||||
this._addToEnclosures(enc);
|
||||
},
|
||||
|
||||
_mediagroupToEnclosures: function Entry_mediagroupToEnclosures() {
|
||||
var group = this.fields.getPropertyAsInterface("mediagroup", Ci.nsIPropertyBag2);
|
||||
|
||||
var content = group.getPropertyAsInterface("mediacontent", Ci.nsIArray);
|
||||
for (var i = 0; i < content.length; ++i) {
|
||||
var contentElement = content.queryElementAt(i, Ci.nsIWritablePropertyBag2);
|
||||
// media:content don't require url, but if it's not there, we should
|
||||
// skip it.
|
||||
if (!bagHasKey(contentElement, "url"))
|
||||
continue;
|
||||
|
||||
var enc = Cc[BAG_CONTRACTID].createInstance(Ci.nsIWritablePropertyBag2);
|
||||
|
||||
// copy media:content bits over to equivalent enclosure bits
|
||||
enc.setPropertyAsAString("url", contentElement.getPropertyAsAString("url"));
|
||||
if (bagHasKey(contentElement, "type")) {
|
||||
enc.setPropertyAsAString("type", contentElement.getPropertyAsAString("type"));
|
||||
}
|
||||
if (bagHasKey(contentElement, "fileSize")) {
|
||||
enc.setPropertyAsAString("length", contentElement.getPropertyAsAString("fileSize"));
|
||||
}
|
||||
|
||||
this._addToEnclosures(enc);
|
||||
}
|
||||
},
|
||||
|
||||
// XPCOM stuff
|
||||
classDescription: ENTRY_CLASSNAME,
|
||||
classID: ENTRY_CLASSID,
|
||||
|
@ -1063,7 +1261,9 @@ function FeedProcessor() {
|
|||
"dc:contributor": new ElementInfo("contributors", Cc[PERSON_CONTRACTID],
|
||||
rssAuthor, true),
|
||||
"category": new ElementInfo("categories", null, rssCatTerm, true),
|
||||
"enclosure": new ElementInfo("enclosure", null, null, true),
|
||||
"enclosure": new ElementInfo("enclosure", null, null, false),
|
||||
"media:content": new ElementInfo("mediacontent", null, null, false),
|
||||
"media:group": new ElementInfo("mediagroup", null, null, false),
|
||||
"guid": new ElementInfo("guid", null, rssGuid, false)
|
||||
},
|
||||
|
||||
|
@ -1075,6 +1275,10 @@ function FeedProcessor() {
|
|||
"hour": new ElementInfo("hours", null, rssArrayElement, true)
|
||||
},
|
||||
|
||||
"IN_MEDIAGROUP": {
|
||||
"media:content": new ElementInfo("mediacontent", null, null, true)
|
||||
},
|
||||
|
||||
/********* RSS1 **********/
|
||||
"IN_RDF": {
|
||||
// If we hit a rss1:channel, we can verify that we have RSS1
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
|
||||
Description: item enclosure works
|
||||
Expect: var links = feed.items.queryElementAt(0, Components.interfaces.nsIFeedEntry).fields.getProperty('links'); links.QueryInterface(Components.interfaces.nsIArray); var link = links.queryElementAt(0, Components.interfaces.nsIPropertyBag2); ((link.getProperty('length') == '24986239') && (link.getProperty('type') == 'audio/mpeg') && (link.getProperty('href') == 'http://dallas.example.com/joebob_050689.mp3') && (feed.type == 1) && (feed.enclosureCount == 1));
|
||||
|
||||
-->
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<id>tag:snellspace.com,2006:/atom/conformance/linktest/</id>
|
||||
<title>Atom Link Tests</title>
|
||||
<updated>2005-01-18T15:10:00Z</updated>
|
||||
<author><name>James Snell</name></author>
|
||||
<link href="http://www.intertwingly.net/wiki/pie/LinkConformanceTests" />
|
||||
<link rel="self" href="http://www.snellspace.com/public/linktests.xml" />
|
||||
|
||||
|
||||
|
||||
<entry>
|
||||
|
||||
<id>tag:snellspace.com,2006:/atom/conformance/linktest/4</id>
|
||||
<title>One of each core link rel type + An additional alternate link</title>
|
||||
<updated>2005-01-18T15:00:04Z</updated>
|
||||
<summary>The aggregator should pick either the first or last links as the alternate. First link is likely better.</summary>
|
||||
<link rel="enclosure" length="24986239" type="audio/mpeg" href="http://dallas.example.com/joebob_050689.mp3" />
|
||||
</entry>
|
||||
|
||||
</feed>
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
|
||||
Description: item enclosure added to enclosures
|
||||
Expect: var encs = feed.items.queryElementAt(0, Components.interfaces.nsIFeedEntry).enclosures; encs.QueryInterface(Components.interfaces.nsIArray); var enc = encs.queryElementAt(0, Components.interfaces.nsIPropertyBag2); ((enc.getProperty('length') == '24986239') && (enc.getProperty('type') == 'audio/mpeg') && (enc.getProperty('url') == 'http://dallas.example.com/joebob_050689.mp3'));
|
||||
|
||||
-->
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<id>tag:snellspace.com,2006:/atom/conformance/linktest/</id>
|
||||
<title>Atom Link Tests</title>
|
||||
<updated>2005-01-18T15:10:00Z</updated>
|
||||
<author><name>James Snell</name></author>
|
||||
<link href="http://www.intertwingly.net/wiki/pie/LinkConformanceTests" />
|
||||
<link rel="self" href="http://www.snellspace.com/public/linktests.xml" />
|
||||
|
||||
|
||||
|
||||
<entry>
|
||||
|
||||
<id>tag:snellspace.com,2006:/atom/conformance/linktest/4</id>
|
||||
<title>One of each core link rel type + An additional alternate link</title>
|
||||
<updated>2005-01-18T15:00:04Z</updated>
|
||||
<summary>The aggregator should pick either the first or last links as the alternate. First link is likely better.</summary>
|
||||
<link rel="enclosure" length="24986239" type="audio/mpeg" href="http://dallas.example.com/joebob_050689.mp3" />
|
||||
</entry>
|
||||
|
||||
</feed>
|
|
@ -2,7 +2,7 @@
|
|||
<!--
|
||||
|
||||
Description: item enclosure works
|
||||
Expect: var encs = feed.items.queryElementAt(0, Components.interfaces.nsIFeedEntry).fields.getProperty('enclosure'); encs.QueryInterface(Components.interfaces.nsIArray); var enc = encs.queryElementAt(0, Components.interfaces.nsIPropertyBag); ((enc.getProperty('length') == '24986239') && (enc.getProperty('type') == 'audio/mpeg') && (enc.getProperty('url') == 'http://dallas.example.com/joebob_050689.mp3'));
|
||||
Expect: var enc = feed.items.queryElementAt(0, Components.interfaces.nsIFeedEntry).fields.getProperty('enclosure'); enc.QueryInterface(Components.interfaces.nsIPropertyBag); ((enc.getProperty('length') == '24986239') && (enc.getProperty('type') == 'audio/mpeg') && (enc.getProperty('url') == 'http://dallas.example.com/joebob_050689.mp3') && (feed.type == 1) && (feed.enclosureCount == 1));
|
||||
|
||||
-->
|
||||
<rss version="2.0" >
|
||||
|
@ -18,4 +18,4 @@ Expect: var encs = feed.items.queryElementAt(0, Components.interfaces.nsIFeedEnt
|
|||
|
||||
<description>I'm headed for France. I wasn't gonna go this year, but then last week <a href="http://www.imdb.com/title/tt0086525/">Valley Girl</a> came out and I said to myself, Joe Bob, you gotta get out of the country for a while.</description></item>
|
||||
</channel>
|
||||
</rss>
|
||||
</rss>
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
|
||||
Description: feed with duplicate enclosures on a single item
|
||||
Expect: ((feed.type == 4) && (feed.enclosureCount == 1));
|
||||
|
||||
-->
|
||||
<rss xmlns:media="http://search.yahoo.com/mrss" version="2.0" >
|
||||
<channel>
|
||||
|
||||
<item>
|
||||
<enclosure length="24986239" type="video/mpeg" url="http://dallas.example.com/joebob_050689.mpeg" />
|
||||
<media:content fileSize="24986239" type="video/mpeg" url="http://dallas.example.com/joebob_050689.mpeg" />
|
||||
<author>jbb@dallas.example.com (Joe Bob Briggs)</author>
|
||||
<comments>http://example.org</comments>
|
||||
<title>test audio</title>
|
||||
|
||||
<category domain="foo">bar</category>
|
||||
|
||||
<description>Listen to the words that are coming out of my mouth.</description>
|
||||
</item>
|
||||
|
||||
</channel>
|
||||
</rss>
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
|
||||
Description: feed with duplicate enclosures on a single item with different data available
|
||||
Expect: var enc = feed.items.queryElementAt(0, Components.interfaces.nsIFeedEntry).fields.getProperty('enclosure'); enc.QueryInterface(Components.interfaces.nsIPropertyBag); ((enc.getProperty('length') == '24986239') && (enc.getProperty('type') == 'video/mpeg') && (feed.type == 4) && (feed.enclosureCount == 1) );
|
||||
|
||||
-->
|
||||
<rss xmlns:media="http://search.yahoo.com/mrss" version="2.0" >
|
||||
<channel>
|
||||
|
||||
<item>
|
||||
<enclosure url="http://dallas.example.com/joebob_050689.mpeg" />
|
||||
<media:content fileSize="24986239" type="video/mpeg" url="http://dallas.example.com/joebob_050689.mpeg" />
|
||||
<author>jbb@dallas.example.com (Joe Bob Briggs)</author>
|
||||
<comments>http://example.org</comments>
|
||||
<title>test audio</title>
|
||||
|
||||
<category domain="foo">bar</category>
|
||||
|
||||
<description>Listen to the words that are coming out of my mouth.</description>
|
||||
</item>
|
||||
|
||||
</channel>
|
||||
</rss>
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
|
||||
Description: feed with different kinds of enclosures that should be TYPE_FEED (0)
|
||||
Expect: ((feed.type == 0) && (feed.enclosureCount == 2));
|
||||
|
||||
-->
|
||||
<rss version="2.0" >
|
||||
<channel>
|
||||
|
||||
<item>
|
||||
<enclosure length="24986239" type="audio/mpeg" url="http://dallas.example.com/joebob_050689.mp3" />
|
||||
<author>jbb@dallas.example.com (Joe Bob Briggs)</author>
|
||||
<comments>http://example.org</comments>
|
||||
<title>test audio</title>
|
||||
|
||||
<category domain="foo">bar</category>
|
||||
|
||||
<description>Listen to the words that are coming out of my mouth.</description>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<enclosure length="3000000" type="video/mpeg" url="http://dallas.example.com/joebob_pants.mpeg" />
|
||||
<author>jbb@dallas.example.com (Joe Bob Briggs)</author>
|
||||
<comments>http://example.org</comments>
|
||||
<title>test video</title>
|
||||
|
||||
<category domain="foo">bar</category>
|
||||
|
||||
<description>Look into my eyes....</description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
|
||||
Description: feed that doesn't have at least one enclosure per entry should be TYPE_FEED (0)
|
||||
Expect: ((feed.type == 0) && (feed.enclosureCount == 1));
|
||||
|
||||
-->
|
||||
<rss version="2.0" >
|
||||
<channel>
|
||||
|
||||
<item>
|
||||
<author>jbb@dallas.example.com (Joe Bob Briggs)</author>
|
||||
<comments>http://example.org</comments>
|
||||
<title>no video this week!</title>
|
||||
|
||||
<category domain="foo">bar</category>
|
||||
|
||||
<description>I'm on a trip to the moon this week for this year's Spaceshot Vlogger
|
||||
conference. No video this week!</description>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<enclosure length="3000000" type="video/mpeg" url="http://dallas.example.com/joebob_pants.mpeg" />
|
||||
<author>jbb@dallas.example.com (Joe Bob Briggs)</author>
|
||||
<comments>http://example.org</comments>
|
||||
<title>orange keyboard</title>
|
||||
|
||||
<category domain="foo">bar</category>
|
||||
|
||||
<description>Crazy things happen when you paint your keyboard orange.</description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
|
||||
Description: item enclosure is added to enclosures array
|
||||
Expect: var encs = feed.items.queryElementAt(0, Components.interfaces.nsIFeedEntry).enclosures; encs.QueryInterface(Components.interfaces.nsIArray); var enc = encs.queryElementAt(0, Components.interfaces.nsIPropertyBag2); ((enc.getProperty('length') == '24986239') && (enc.getProperty('type') == 'audio/mpeg') && (enc.getProperty('url') == 'http://dallas.example.com/joebob_050689.mp3'));
|
||||
|
||||
-->
|
||||
<rss version="2.0" >
|
||||
<channel>
|
||||
<item>
|
||||
|
||||
<enclosure length="24986239" type="audio/mpeg" url="http://dallas.example.com/joebob_050689.mp3" />
|
||||
<author>jbb@dallas.example.com (Joe Bob Briggs)</author>
|
||||
<comments>http://example.org</comments>
|
||||
<title>test</title>
|
||||
|
||||
<category domain="foo">bar</category>
|
||||
|
||||
<description>I'm headed for France. I wasn't gonna go this year, but then last week <a href="http://www.imdb.com/title/tt0086525/">Valley Girl</a> came out and I said to myself, Joe Bob, you gotta get out of the country for a while.</description></item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
|
||||
Description: mrss content works
|
||||
Expect: var enc = feed.items.queryElementAt(0, Components.interfaces.nsIFeedEntry).fields.getProperty('mediacontent'); enc.QueryInterface(Components.interfaces.nsIPropertyBag); ((enc.getProperty('fileSize') == '24986239') && (enc.getProperty('type') == 'video/mpeg') && (enc.getProperty('url') == 'http://dallas.example.com/joebob_050689.mpeg') && (feed.type == 4) && (feed.enclosureCount == 1));
|
||||
|
||||
-->
|
||||
<rss xmlns:media="http://search.yahoo.com/mrss" version="2.0" >
|
||||
<channel>
|
||||
<item>
|
||||
|
||||
<media:content fileSize="24986239" type="video/mpeg" url="http://dallas.example.com/joebob_050689.mpeg" />
|
||||
<author>jbb@dallas.example.com (Joe Bob Briggs)</author>
|
||||
<comments>http://example.org</comments>
|
||||
<title>test</title>
|
||||
|
||||
<category domain="foo">bar</category>
|
||||
|
||||
<description>I'm headed for France. I wasn't gonna go this year, but then last week <a href="http://www.imdb.com/title/tt0086525/">Valley Girl</a> came out and I said to myself, Joe Bob, you gotta get out of the country for a while.</description></item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
|
||||
Description: mrss content added to enclosures array
|
||||
Expect: var encs = feed.items.queryElementAt(0, Components.interfaces.nsIFeedEntry).enclosures; encs.QueryInterface(Components.interfaces.nsIArray); var enc = encs.queryElementAt(0, Components.interfaces.nsIPropertyBag); ((enc.getProperty('length') == '24986239') && (enc.getProperty('type') == 'audio/mpeg') && (enc.getProperty('url') == 'http://dallas.example.com/joebob_050689.mp3') && (feed.type == 1) && (feed.enclosureCount == 1));
|
||||
|
||||
-->
|
||||
<rss xmlns:media="http://search.yahoo.com/mrss" version="2.0" >
|
||||
<channel>
|
||||
<item>
|
||||
|
||||
<media:content fileSize="24986239" type="audio/mpeg" url="http://dallas.example.com/joebob_050689.mp3" />
|
||||
<author>jbb@dallas.example.com (Joe Bob Briggs)</author>
|
||||
<comments>http://example.org</comments>
|
||||
<title>test</title>
|
||||
|
||||
<category domain="foo">bar</category>
|
||||
|
||||
<description>I'm headed for France. I wasn't gonna go this year, but then last week <a href="http://www.imdb.com/title/tt0086525/">Valley Girl</a> came out and I said to myself, Joe Bob, you gotta get out of the country for a while.</description></item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
|
||||
Description: mrss group content works
|
||||
Expect: var mg = feed.items.queryElementAt(0, Components.interfaces.nsIFeedEntry).fields.getProperty('mediagroup'); mg.QueryInterface(Components.interfaces.nsIPropertyBag); var mcs = mg.getProperty("mediacontent"); mcs.QueryInterface(Components.interfaces.nsIArray); var mc1 = mcs.queryElementAt(0, Components.interfaces.nsIPropertyBag); var mc2 = mcs.queryElementAt(1, Components.interfaces.nsIPropertyBag); ((mc1.getProperty('fileSize') == '400') && (mc1.getProperty('type') == 'audio/mpeg') && (mc1.getProperty('url') == 'http://dallas.example.com/joebob_050689_2.mp3') && (mc2.getProperty('fileSize') == '200') && (mc2.getProperty('type') == 'audio/mpeg') && (mc2.getProperty('url') == 'http://dallas.example.com/joebob_050689_1.mp3'));
|
||||
|
||||
|
||||
-->
|
||||
<rss xmlns:media="http://search.yahoo.com/mrss" version="2.0" >
|
||||
<channel>
|
||||
<item>
|
||||
|
||||
<media:group>
|
||||
<media:content fileSize="400" type="audio/mpeg" url="http://dallas.example.com/joebob_050689_2.mp3" />
|
||||
<media:content fileSize="200" type="audio/mpeg" url="http://dallas.example.com/joebob_050689_1.mp3" />
|
||||
</media:group>
|
||||
|
||||
<author>jbb@dallas.example.com (Joe Bob Briggs)</author>
|
||||
<comments>http://example.org</comments>
|
||||
<title>test</title>
|
||||
|
||||
<category domain="foo">bar</category>
|
||||
|
||||
<description>I'm headed for France. I wasn't gonna go this year, but then last week <a href="http://www.imdb.com/title/tt0086525/">Valley Girl</a> came out and I said to myself, Joe Bob, you gotta get out of the country for a while.</description></item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
|
||||
Description: mrss group content works
|
||||
Expect: var encs = feed.items.queryElementAt(0, Components.interfaces.nsIFeedEntry).enclosures; encs.QueryInterface(Components.interfaces.nsIArray); var enc1 = encs.queryElementAt(0, Components.interfaces.nsIPropertyBag); var enc2 = encs.queryElementAt(1, Components.interfaces.nsIPropertyBag); ((enc1.getProperty('length') == '400') && (enc1.getProperty('type') == 'audio/mpeg') && (enc1.getProperty('url') == 'http://dallas.example.com/joebob_050689_2.mp3') && (enc2.getProperty('length') == '200') && (enc2.getProperty('type') == 'audio/mpeg') && (enc2.getProperty('url') == 'http://dallas.example.com/joebob_050689_1.mp3'));
|
||||
|
||||
|
||||
-->
|
||||
<rss xmlns:media="http://search.yahoo.com/mrss" version="2.0" >
|
||||
<channel>
|
||||
<item>
|
||||
|
||||
<media:group>
|
||||
<media:content fileSize="400" type="audio/mpeg" url="http://dallas.example.com/joebob_050689_2.mp3" />
|
||||
<media:content fileSize="200" type="audio/mpeg" url="http://dallas.example.com/joebob_050689_1.mp3" />
|
||||
</media:group>
|
||||
|
||||
<author>jbb@dallas.example.com (Joe Bob Briggs)</author>
|
||||
<comments>http://example.org</comments>
|
||||
<title>test</title>
|
||||
|
||||
<category domain="foo">bar</category>
|
||||
|
||||
<description>I'm headed for France. I wasn't gonna go this year, but then last week <a href="http://www.imdb.com/title/tt0086525/">Valley Girl</a> came out and I said to myself, Joe Bob, you gotta get out of the country for a while.</description></item>
|
||||
</channel>
|
||||
</rss>
|