def testAGetChannel(self): _log.info("Get channel metadata and content ------------") if not TestContentSource.run_test: _log.debug("Test avoided.") return feeds = ["http://www.rtvslo.si/podcasts/zapisi_iz_mocvirja.xml", "http://downloads.bbc.co.uk/podcasts/radio4/today/rss.xml"] for f in feeds: channel = Channel.getContentSource(f) feed = feedparser.parse(f) self.assertTrue(channel.metadata != None) self.assertTrue(channel.cstype == settings.CS_TYPE_CHANNEL) self.assertTrue(channel.sourceMeta == None) self.assertTrue(channel.name != None) self.assertTrue(channel.identifier != None) self.assertTrue(channel.location == f) self.assertTrue(os.path.isdir(channel.storage)) self.assertTrue(os.path.exists(os.path.join(channel.storage, channel.metaFile))) self.assertTrue(os.path.exists(os.path.join(channel.storage, settings.CONTENT_SOURCE_PROPERTIES))) self.assertTrue(len(channel.items) == len(feed.entries)) for i, v in channel.items.items(): self.assertTrue(v.name != None) self.assertTrue(v.cutype == settings.CONTENT_VOD) self.assertTrue(v.identifier != None and v.identifier == i) self.assertTrue(v.metadata != None) self.assertTrue(channel.storage == v.feedStore) self.assertTrue(v.stored) self.assertTrue(v.acquire == channel.acquire) self.assertTrue(os.path.exists(os.path.join(channel.storage, v.contentFile))) self.assertTrue(os.path.exists(os.path.join(channel.storage, v.metaFile))) restored = channel.restore(channel.storage) self.assertTrue(restored == channel) new = Channel.getContentSource(f) self.assertTrue(new == channel) channel.remove()
def testDCheckUpdate(self): _log.info("Check update from source ------------") if not TestContentSource.run_test: _log.debug("Test avoided.") return feeds = ["http://www.rtvslo.si/podcasts/zapisi_iz_mocvirja.xml", "http://downloads.bbc.co.uk/podcasts/radio4/today/rss.xml"] for f in feeds: channel = Channel.getContentSource(f) for i, v in channel.items.items(): self.assertTrue(os.path.exists(os.path.join(channel.storage, v.contentFile))) self.assertTrue(os.path.exists(os.path.join(channel.storage, v.metaFile))) random.random() r = random.randint(1, len(channel.items)) n = 0 meta = None cont = None for i, v in channel.items.items(): n += 1 if n == r: meta = os.path.join(channel.storage, v.contentFile) cont = os.path.join(channel.storage, v.metaFile) os.remove(meta) os.remove(cont) self.assertTrue(not os.path.exists(meta)) self.assertTrue(not os.path.exists(cont)) # update channel = Channel.getContentSource(f) self.assertTrue(os.path.exists(meta)) self.assertTrue(os.path.exists(cont))
def testHRestoreStoredProperties(self): _log.info("Restore stored properties -----------") if not TestContentSource.run_test: _log.debug("Test avoided.") return feed = "http://www.rtvslo.si/podcasts/zapisi_iz_mocvirja.xml" publish = "http://stream.e5.ijs.si/vod" feedLink = "http://stream.e5.ijs.si/feeds/zapisi_iz_mocvirja.xml" cuci = "RTVVoDContent" exportLink = "http://web.server.of.your.choice/relative" guid = "xyz" image = "http://stream.e5.ijs.si/image/kuku.jpg" didfile = "did-base-test.xml" rmg = RichMetadataGenerator.getInstance() meta = rmg.getRichMetadata(None, metadata.MPEG_21_BASE) meta.setRelatedIdentifier("urn:rtv-slo:slo1-xyz") meta.setPaymentReference("URI to additional MPEG_21 data (payment)") meta.setAdvertisementReference("URI to additional MPEG_21 data (advertising)") meta.setScalabilityReference("URI to additional MPEG_21 data (scalability)") meta.setLimoReference("URI to additional MPEG_21 data (limo)") f = open(didfile, 'w') f.write(rmg.build(meta)) f.close() channel = Channel.getContentSource(feed, publish, RTVVoDContent(), feedLink, didfile) feed1_xml = channel.exportFeed(guid, image) test = ContentSource.getContentSource(feed) test.storage = channel.storage test.restoreAttributes() self.assertTrue(channel.storage == test.storage) self.assertTrue(channel.cstype == test.cstype) self.assertTrue(channel.location == test.location) self.assertTrue(channel.publish == test.publish) self.assertTrue(channel.image == test.image) self.assertTrue(channel.contentUnitClassInstance == test.contentUnitClassInstance) self.assertTrue(channel.exportFeedLink == test.exportFeedLink) self.assertTrue(channel.didbaseFile == test.didbaseFile) self.assertTrue(channel.guid == test.guid) channel = Channel.getContentSource(feed) feed2_xml = channel.exportFeed() # Cannot compare directly xmls since the updated can change feed1_meta = Feed.getMetadata(StringIO(feed1_xml), False) feed2_meta = Feed.getMetadata(StringIO(feed2_xml), False) self.assertTrue(feed1_meta.id == feed2_meta.id) self.assertTrue(feed1_meta.p2pnext_img_src == feed2_meta.p2pnext_img_src) self.assertTrue(feed1_meta.links_href == feed2_meta.links_href) count = 0 for i in feed1_meta._items: self.assertTrue(i.links_href == feed2_meta._items[count].links_href) self.assertTrue(i.id == feed2_meta._items[count].id) self.assertTrue(i.p2pnext_image_src == feed2_meta._items[count].p2pnext_image_src) count += 1
def testEDefaultsExportFeed(self): _log.info("Defaults export feed ------------") if not TestContentSource.run_test: _log.debug("Test avoided.") return feeds = ["http://www.rtvslo.si/podcasts/zapisi_iz_mocvirja.xml", "http://downloads.bbc.co.uk/podcasts/radio4/today/rss.xml"] rmg = RichMetadataGenerator.getInstance() publish = "http://web.server.of.your.choice/relative" for f in feeds: channel = Channel.getContentSource(f, publish) _log.debug(rmg.prettyPrint(channel.exportFeed(), 'utf-8')) # Get meta, don't identify media, since we can't (yet?) meta = Feed.getMetadata(StringIO(channel.exportFeed()), False) self.assertTrue(meta.title == channel.name) self.assertTrue(meta.links_href == publish + "/" + textify(channel.name) + settings.METADATA_EXT) self.assertTrue(meta.language == channel.metadata.getLanguage()) self.assertTrue(meta.author == channel.metadata.getPublisher()) self.assertTrue(meta.id == channel.getExportFeedLink()) self.assertTrue(meta.p2pnext_image_src == channel.image) for i, v in channel.items.items(): # Find according to link rmi = None for i in meta._items: if i.links_href == publish + "/" + v.publish: rmi = i self.assertTrue(rmi != None) self.assertTrue(rmi.title == v.name) self.assertTrue(rmi.links_type == "application/x-bittorrent") # Id not tested self.assertTrue(rmi.p2pnext_image_src == channel.image) self.assertTrue(rmi.title == v.metadata.getTitleEpisodeTitle())
def run(self): """ Runs the feed tool and creates a feed according to specified options """ if not options.title: options.title = self.default_title if not options.exporturl: self.exitOnInputError("Export url must be defined") if not options.publisher: options.publisher = self.default_publisher if not options.id: options.id = options.exporturl if not options.image: options.image = self.default_image df = P2PNextAtomFeed(title=options.title, feed_url=options.exporturl, author_name=options.publisher, feed_guid=options.id, image=options.image) storage = settings.MEDIA_ROOT if options.mediaroot: if os.path.isdir(options.mediaroot): storage = options.mediaroot else: self.exitOnInputError("Specified media root is not a directory") for e in os.listdir(storage): fdir = os.path.join(storage, e) _log.debug(fdir) if os.path.isdir(fdir): if os.path.exists(os.path.join(fdir, settings.CONTENT_SOURCE_PROPERTIES)): _log.debug(fdir) # Will need to adapt when live streams are supported cs = Channel.getContentSource(fdir) _log.debug(cs.toString()) image = options.image if cs.image: image = cs.image fid = settings.URN + settings.P2P_NEXT + settings.COLON + cs.identifier if cs.guid: fid = cs.guid video = False for i, v in cs.items.items(): if v.metadata: if v.metadata.getVideoCoding(): video = True break if video: cat = [(settings.CATEGORY_TV, settings.CATEGORY_SCHEME_ST)] else: cat = [(settings.CATEGORY_RADIO, settings.CATEGORY_SCHEME_ST)] df.add_item(title=cs.name, link=cs.exportFeedLink, link_type="application/atom+xml", unique_id=fid, description=cs.metadata.getTitleSeriesTitle(), image=image, categories=cat) print self.rmg.prettyPrint(df.writeString(), 'utf-8')
def testJLoadFromDir(self): _log.info("Loading from directory -----------") if not TestContentSource.run_test: _log.debug("Test avoided.") return feeds = ["http://www.rtvslo.si/podcasts/zapisi_iz_mocvirja.xml", "http://downloads.bbc.co.uk/podcasts/radio4/today/rss.xml"] netch = [] for f in feeds: netch.append(Channel.getContentSource(f)) dirch = [] for c in netch: dirch.append(Channel.getContentSource(c.storage)) i = 0 for c in netch: self.assertTrue(c == dirch[i]) i += 1
def testFCostumizedExportFeed(self): _log.info("Customized export feed -----------") if not TestContentSource.run_test: _log.debug("Test avoided.") return feeds = ["http://www.rtvslo.si/podcasts/zapisi_iz_mocvirja.xml", "http://downloads.bbc.co.uk/podcasts/radio4/today/rss.xml"] rmg = RichMetadataGenerator.getInstance() publish = "http://stream.e5.ijs.si/vod" for f in feeds: url = urlparse.urlparse(f) if url.netloc == "www.rtvslo.si": channel = Channel.getContentSource(f, publish, RTVVoDContent()) for i, v in channel.items.items(): self.assertTrue(type(v) == type(RTVVoDContent())) else: channel = Channel.getContentSource(f, publish) for i, v in channel.items.items(): self.assertTrue(type(v) == type(ContentUnit())) _log.debug(rmg.prettyPrint(channel.exportFeed(), 'utf-8'))
def testIWindow(self): _log.info("Window test -----------") if not TestContentSource.run_test: _log.debug("Test avoided.") return feed = "http://downloads.bbc.co.uk/podcasts/radio4/today/rss.xml" channel = Channel.getContentSource(feed) fp = feedparser.parse(feed) osw = len(fp.entries) channel = Channel.getContentSource(feed, None, None, None, None, osw) self.assertTrue(len(channel.items) == osw) channel = Channel.getContentSource(feed, None, None, None, None, osw-1) self.assertTrue(len(channel.items) == osw-1) channel.window = 10 channel.checkWindow() self.assertTrue(len(channel.items) == 10) channel.store(True) channel = Channel.getContentSource(feed) self.assertTrue(len(channel.items) == 10) # Negative value for window restores default - None channel = Channel.getContentSource(feed, None, None, None, None, -1) self.assertTrue(len(channel.items) == osw)
def testGExportFeedLink(self): _log.info("Export feed link -----------") if not TestContentSource.run_test: _log.debug("Test avoided.") return feeds = ["http://www.rtvslo.si/podcasts/zapisi_iz_mocvirja.xml"] rmg = RichMetadataGenerator.getInstance() publish = "http://stream.e5.ijs.si/vod" feedLink = "http://stream.e5.ijs.si/feeds/zapisi_iz_mocvirja.xml" for f in feeds: channel = Channel.getContentSource(f, publish, RTVVoDContent(), feedLink) meta = Feed.getMetadata(StringIO(channel.exportFeed()), False) self.assertTrue(meta.links_href == feedLink)
def run(self): """ Runs the getfeed tool, fetches the content, generate torrents and provides P2P-Next compliant feed on std out """ if options.location != None: template = None if options.template: if self.mapper.get(options.template): template = self.mapper[options.template] channel = Channel.getContentSource(options.location, options.publish, template, options.feedexport, options.didbaseFile, options.window) _log.info("Feed is stored in path: %s", channel.storage) _log.info("Resulting torrent files reside in path: %s", settings.EXPORT_TORRENT_DIR) _log.info("DID Base used path: %s", options.didbaseFile) _log.info("Resulting feed should be published at location: %s", channel.getExportFeedLink()) print self.rmg.prettyPrint(channel.exportFeed(options.guid, options.image), 'utf-8') elif options.directory != None: if os.path.isdir(options.directory): if os.path.exists(os.path.join(options.directory, settings.CONTENT_SOURCE_PROPERTIES)): channel = Channel.getContentSource(options.directory) if channel.location.startswith("file"): _log.debug("Mannually created feed in the directory %s, won't update", options.directory) else: channel.update() print self.rmg.prettyPrint(channel.exportFeed(), 'utf-8') else: self.exitOnInputError("Directory " + options.directory + " specified but does not hold a feed.") else: self.exitOnInputError("Specified path '" + options.directory + "' is not a directory") else: self.exitOnInputError("Neither location (-l) nor update directory (-u)\n were specified.")
def testBExportTorrents(self): _log.info("Export torrents ------------") if not TestContentSource.run_test: _log.debug("Test avoided.") return channel = Channel.getContentSource("http://www.rtvslo.si/podcasts/zapisi_iz_mocvirja.xml") channel.exportTorrent() for i, v in channel.items.items(): (b, e) = os.path.splitext(v.contentFile) tp = os.path.join(settings.EXPORT_TORRENT_DIR, b + '.tstream') self.assertTrue(os.path.exists(tp)) channel.update() for i, v in channel.items.items(): self.assertTrue(not v.fresh) channel.remove() shutil.rmtree(settings.EXPORT_TORRENT_DIR)
def run(self): """ Runs the managefeed tool and creates a feed according to specified options or modifies feed content (items) """ core = None rmg = RichMetadataGenerator.getInstance() if options.coremetafile: core = rmg.getRichMetadata(options.coremetafile) if core: if core.metadataType != metadata.METADATA_CORE: self.exitOnInputError("Core metadata of wrong type: " + core.metadataType) else: self.exitOnInputError("Cannot read core metadata from supplied file: " + options.coremetafile) # Creates a feed if options.feedmod: if not options.title and not options.coremetafile: self.exitOnInputError("Feed title or core metadata must be defined") channel = Channel() if core: if not core.getTitleMain(): self.exitOnInputError("Feed title or core metadata title mainmust be defined") channel.name = core.getTitleMain() channel.metadata = core else: channel.name = options.title channel.storage = settings.MEDIA_ROOT + os.path.sep + textify(channel.name) channel.location = "file://" + channel.storage channel.identifier = channel.identify(channel.location) if options.cuci: cuci = classImport(classpath, options.cuci) if cuci: channel.contentUnitClassInstance = cuci.__class.__name__ channel.cuci = cuci if os.path.isdir(channel.storage): channel = channel.restore(channel.storage, channel) if core: # core metadata supplied on command line, prevail channel.metadata = core if options.publish: channel.publish = options.publish if options.exporturl: channel.exportFeedLink = options.exporturl if options.didbase: channel.setDIDBaseFile(options.didbase) if options.image: channel.image = options.image if not core: core = rmg.getRichMetadata() old = core if options.language: core.setLanguage(options.language) if options.description: core.setTitleSeriesTitle(options.description) if options.publisher: core.setPublisher(options.publisher) if options.originator: core.setOriginator(options.originator) if options.title: core.setTitleMain(options.title) if core != old or not channel.metadata: channel.metadata = core channel.store(True) # Adds an item to the feed elif options.additem: if not options.feeddir: self.exitOnInputError("For adding the feed item feed directory needs\n to be specified! (-d option)") if not os.path.exists(os.path.join(options.feeddir, settings.CONTENT_SOURCE_PROPERTIES)): self.exitOnInputError("Feed directory specified seems not to be populated.\n Feed properties file is missing in path: " + options.feeddir) c = Channel() channel = c.restore(options.feeddir) cu = channel.getContentUnitInstance() cu.acquire = channel.acquire if options.content: if os.path.exists(options.content) and os.path.isfile(options.content): cu.contentFile = os.path.basename(options.content) else: self.exitOnInputError("Content file is missing in path or is not a file:\n " + options.content) else: self.exitOnInputError("Content file should be specified while adding an item") item = Item() item._items.append(Media.getMetadata(options.content)) if not core: core = rmg.getRichMetadata() if options.title: core.setTitleEpisodeTitle(options.title) if options.synopsis: core.setSynopsis(options.synopsis) # Problem turned round. From RM set the item attributes for k, v in settings.MMM_ITEM.items(): if v: m = "get" + v.lstrip("set") f = getattr(core, m) setattr(item, k, f()) if options.coremetafile: cu.metadata = item.getRichMetadata(core) else: cu.metadata = item.getRichMetadata(channel.metadata) cu.name = cu.metadata.getTitleEpisodeTitle() cu.identifier = cu.identify() if cu.identifier in channel.items: self.exitOnInputError("You are trying to add the content " + options.content + " with metadata that seems already added to the feed with name " + channel.name) cu.feedStore = channel.storage (b, e) = os.path.splitext(cu.contentFile) cu.storeMeta(os.path.join(channel.storage, b)) if channel.storage != os.path.basename(options.content): if os.path.exists(os.path.join(channel.storage, cu.contentFile)): self.exitOnInputError("You are trying to add the content " + cu.contentFile + "\n to the feed with name '" + channel.name + "' that already\n exists in the feed.") os.symlink(options.content, os.path.join(channel.storage, cu.contentFile)) cu.fresh = True channel.items[cu.identifier] = cu channel.exportTorrent() # Removes the item elif options.removeitem: if not options.feeddir: self.exitOnInputError("For removing the feed item feed directory needs to be\n specified (-d option)!") if os.path.exists(options.feeddir) and os.path.isdir(options.feeddir): c = Channel() channel = c.restore(options.feeddir) if channel.items.has_key(options.removeitem): channel.removeContentUnit(options.removeitem) else: self.exitOnInputError("Cannot remove nonexistent content unit, identifier " + options.removeitem + " not registred") else: self.exitOnInputError("Feed directory is missing in path or is not a directory:\n " + options.feeddir) # List the feed elif options.list: if os.path.exists(options.list) and os.path.isdir(options.list): c = Channel() channel = c.getCSFromDir(options.list) if options.listlong: print channel.toString() else: print "'" + channel.name + "', stored in " + channel.storage print "Location: " + channel.location i = 1 sitems = channel.timesort.sort() sitems.reverse() for k in sitems: if channel.items.get(k): v = channel.items[k] print '{0:>3}'.format(i) + ") " + v.name print " Identifier: " + v.identifier print " Content: " + v.contentFile print " Metadata: " + v.metaFile print " Torrent: " + str(v.findTorrentFile()) i += 1 else: _log.warn("Programmable error: identifier in sorter that does not exists in source") else: self.exitOnInputError("Feed directory is missing in path or is not a directory:\n " + options.list) else: self.exitOnInputError("None of the main options -c, -a, -r or -l specified!")