{
	const parseRSSItemByIndex = function(rss, index) {
		return parseRSSItem(rss, rss.find('item').eq(index))
	}
	
	const parseRSSItemByGUID = function(rss, guid) {
		return parseRSSItem(rss, rss.find('item > guid:contains("'+guid+'")').eq(0).parent())
	}
	
	const parseRSSItem = function(rss, item) {
		let channel = rss.find('channel')
		let guid = item.find('guid').text()
		let link = item.find('link').text()
		let imgSrc, desc
		
		// resolve main image
		imgSrc = item.find('enclosure').attr('url')
		if (!imgSrc) imgSrc = item.find('media\\:content').attr('url')
		if (!imgSrc) imgSrc = item.find('description').children('img').eq(0).attr('src')
		
		// resolve description
		desc = item.find('content\\:encoded').text()
		if (!desc) desc = item.find('description').clone().children().remove().end().text()
		
		return {
			type: "rss",
			title: item.find('title').text(),
			id: guid,
			link: link,
			descHtml: desc,
			hasImage: !!imgSrc,
			imgSrc: imgSrc,
			pubDate: item.find('pubDate').text(),
			feed: {
				title: channel.children('title').text(),
				copyright: channel.children('copyright').text(),
				lastBuildDate: channel.children('lastBuildDate').text(),
				category: channel.children('category').text(),
			}
		}
	}
	
	const parseYouTubeEntryByIndex = function(feed, index) {
		return parseYouTubeEntry(feed, feed.find('entry').eq(index))
	}
	
	const parseYouTubeEntryById = function(feed, id) {
		return parseYouTubeEntry(feed, feed.find('entry > id:contains("'+id+'")').eq(0).parent())
	}
	
	const parseYouTubeEntry = function(feed, item) {
		let id = item.find('id').text()
		let link = item.find('link').attr('href')
		let imgSrc, desc
		
		// resolve main image
		imgSrc = item.find('media\\:thumbnail').attr('url')
		videoId = item.children('yt\\:videoId').text()
		embededFrameSrc = "https://www.youtube.com/embed/" + videoId
		
		// resolve description
		desc = item.find('medua\\:description').clone().children().remove().end().text()
		
		return {
			type: "youtube",
			title: item.find('title').text(),
			id: id,
			link: link,
			descHtml: desc,
			hasImage: !!imgSrc,
			imgSrc: imgSrc,
			hasEmbededFrame: !!embededFrameSrc,
			embededFrameSrc: embededFrameSrc,
			pubDate: item.find('published').text(),
			feed: {
				title: feed.children('title').text(),
				copyright: "",
				lastBuildDate: feed.children('published').text(),
				category: "",
			}
		}
	}
	
	// expose to global
	var FeedParser = {
		parseItemByIndex: function(xml$, idx) {
			let root = xml$.children().first()
			let rootTag = root.prop('tagName')
		
			if (rootTag == "rss") return parseRSSItemByIndex(xml$, idx)
			if (rootTag == "feed" && root.attr("xmlns:yt") == "http://www.youtube.com/xml/schemas/2015") return parseYouTubeEntryByIndex(xml$, idx)
		},
		
		parseItemById: function(xml$, id) {
			let root = xml$.children().first()
			let rootTag = root.prop('tagName')
		
			if (rootTag == "rss") return parseRSSItemByGUID(xml$, id)
			if (rootTag == "feed" && root.attr("xmlns:yt") == "http://www.youtube.com/xml/schemas/2015") return parseYouTubeEntryById(xml$, id)
		},
		
		countItem: function(xml$) {
			let root = xml$.children().first()
			let rootTag = root.prop('tagName')
		
			if (rootTag == "rss") return xml$.find('item').length
			if (rootTag == "feed" && root.attr("xmlns:yt") == "http://www.youtube.com/xml/schemas/2015") return xml$.find('entry').length
		},
	}
}
