Source code for youtube

#!/usr/bin/python
# -*- coding: utf-8 -*-



################################
##
##  Transmogrifier: YouTube
##  A Final Cut Server import/export tool 
##
##  Written by: Beau Hunter beau@318.com
##  318 Inc 05/2009
##  
##
##  This class is a decedent of TransmogrifierObject, and pretty mimics the 
##  interface and functionality of it's parent, with one key addition function. 
##  Once uploaded, YouTube processes the media and XML, and then generates it's 
##  own XML report as to the status of the import. In order to ensure a successful
##  upload, we need to check this file to ensure that if it failed we properly 
##  report the status. To do so, YouTubeObject provides two additional methods, 
##  batchStatusCheck() and checkYouTubeXMLStatusFile(). The former method 
##  actually utilizes the latter, so it will rarely be need to be called directly. 
##
##  Copyright © 2009-2011 Beau Hunter, 318 Inc.
##
##  This file is part of Transmogrifier.
##
##  Transmogrifier is free software: you can redistribute it and/or modify
##  it under the terms of version 3 the GNU General Public License as published
##  by the Free Software Foundation, either version 3 of the License, or
##  (at your option) any later version.
##
##  Transmogrifier is distributed in the hope that it will be useful,
##  but WITHOUT ANY WARRANTY; without even the implied warranty of
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##  GNU General Public License for more details.
##
##  You should have received a copy of the GNU General Public License
##  along with Transmogrifier. If not, see <http://www.gnu.org/licenses/>.
##
#############################################################

import os, os.path, re, glob, shutil, sys, datetime, time
from ftplib import FTP
from fcsxml import FCSXMLField, FCSXMLObject
from transmogrifierTarget import TransmogrifierTargetObject, MediaFile

from xml.dom import minidom

version = ".91beta"
build = "2010040101"

[docs]class YouTubeObject(TransmogrifierTargetObject): ''' This provides an interface for uploading assets and XML to YouTube. Asside from basic delivery, once uploaded, YouTube will processes the media and XML, and then generates it's own XML report as to the status of the import. In order to ensure a successful upload, we need to check this file to ensure that if it failed we properly report the status. To do so, YouTubeObject provides two additional methods, :func:`YouTubeObject.batchStatusCheck()` and :func:`YouTubeObject.checkYouTubeXMLStatusFile()`. The former method actually utilizes the latter, so `checkYouTubeXMLStatusFile` will rarely be need to be called directly. ''' ytUsername = "" ytPassword = "" ytOwnerName = "" ytSFTPServer = "" ytXML = "" ytXMLFilePath = "" ytCustomID = "" retryCount = "" validActions = ['upload','batchStatusCheck'] debug = False def __init__(self,entityID=0): TransmogrifierTargetObject.__init__(self,entityID) self.ytUsername = "" self.ytPassword = "" self.multipleBitRate = False self.ytSFTPServer = "" self.ytOwnerName = "" self.files = {} self.log = [] self.serviceName = "YouTube" self.supportSubDirs = ["xmlin", "xmlout", "media","upload","inprogress"] self.neededAttributes = ["entityID", "approver", "title", "description", "ytOwnerName", "ytUsername", "ytSFTPServer"] self.reqFCSFields = ["YouTube Publish History","Publish to YouTube", "Published to YouTube","YouTube GeneratedID", "Publishing Approver"] self.retryCount = int (5) self.validActions = ['upload','batchStatusCheck']
[docs] def batchStatusCheck(self): """Checks on the status of any inprogress batches, as indicated by the presence of *.xml files in the inprogress folder.""" ## Iterate through our files: for theFilePath in glob.glob( os.path.join(self.supportPath,"inprogress", "*.xml")): processingSuccessfull = False entityID = re.sub(' ','_',re.sub(r'^(.*?)\.xml$',r'\1',os.path.basename(theFilePath))) self.logger("Checking batch status for job: %s" % entityID, "detailed") print "/usr/bin/sftp %s@%s:%s/status-%s.xml '%s/status-%s.xml'" % (self.ytUsername,self.ytSFTPServer,entityID,entityID,os.path.join(self.supportPath, "xmlin"),entityID) if not os.system("/usr/bin/sftp %s@%s:%s/status-%s.xml \'%s/status-%s.xml\'" % (self.ytUsername,self.ytSFTPServer,entityID,entityID,os.path.join(self.supportPath, "xmlin"),entityID)): ## at this point we have sftp'd the status file locally to the xmlin ## directory. Check the file for any reported problems: ytXMLInPath = os.path.join(self.supportPath, "xmlin", "status-%s.xml" % entityID) fcsXMLInPath = theFilePath if not self.checkYouTubeXMLStatusFile(ytXMLInPath): histString = "%s" % self.lastError else: histString = "YouTube reports that media successfully published!" processingSuccessfull = True ## Read our FCS XML. This will be stale, don't know a great ## way around that. Mb we could script something with fcsvr_client ## For now we just assume our YT history hasn't changed for this ## Asset (any changes will be over-ridden) fcsXMLIn = FCSXMLObject() fcsXMLIn.setFile(fcsXMLInPath) entityID = fcsXMLIn.entityID ## Date/time string used for reporting currentTime = datetime.datetime.fromtimestamp(time.mktime(datetime.datetime.now().timetuple())) historyField = "%s Publish History" % self.serviceName publishHistory = fcsXMLIn.valueForField(historyField) if publishHistory: publishHistory = "%s\n%s: %s" % (publishHistory,currentTime,histString) else: publishHistory = "%s: %s" % (currentTime,histString) ## Create our XML object and set vars fcsXMLOut = FCSXMLObject(entityID) fcsXMLOut.overwriteExistingFiles = True xmlOutPath = os.path.join(os.path.dirname(self.supportPath),"fcsvr_xmlin","%s_%s.xml" % (self.serviceName,entityID)) ## Report our history. fcsXMLOut.setField(FCSXMLField("%s Publish History" % self.serviceName, publishHistory)) fcsXMLOut.setField(FCSXMLField("Publish to %s" % self.serviceName, "false", "bool")) if processingSuccessfull: fcsXMLOut.setField(FCSXMLField("Published to %s" % self.serviceName, "true", "bool")) ## We may want to do this, but if other targets were specified, it may be premature ##fcsXMLOut.setField(FCSXMLField("Status", "Published", "string")) if self.ytCustomID: fcsXMLOut.setField(FCSXMLField("YouTube Generated ID", self.ytCustomID)) print "Hist String :%s" % histString if not fcsXMLOut.xmlOut(xmlOutPath): print "Failed to output FCS XML to: '%s' Error:\n%s" % (xmlOutPath, fcsXMLOut.lastError) ## Get rid of our local YT xmlin file (xmlin/status-123.xml), ## if processing failed or isn't finished, we will simply ## redownload this file at next check if os.path.exists(ytXMLInPath): os.remove(ytXMLInPath) ## At this point we have transferred our YT status file and ## it reported failure. Get Rid of our inprogress watcher os.remove(fcsXMLInPath)
[docs] def checkYouTubeXMLStatusFile(self, filePath): """import YouTube XML status file, verify that our publishing worked""" errorCode = "" self.logger("ytCheck hit", "detailed") if os.path.exists(filePath): ytXML = minidom.parse(filePath).documentElement self.logger("Loading XML from File: %s" % filePath, "info") else: self.logger("File does not exist at path: %s, exiting!" % filePath, "error") return False for item in ytXML.getElementsByTagName('item_status'): self.logger("iterating through YT item", "detailed") actionElement = item.getElementsByTagName('action')[0] commandTxt = self.getXMLNodeText(actionElement.getElementsByTagName('command')[0].childNodes) try: if self.getXMLNodeText(item.getElementsByTagName('id')[0].childNodes): self.ytCustomID = self.getXMLNodeText(item.getElementsByTagName('id')[0].childNodes) except: self.ytCustomID = "" statusTxt = self.getXMLNodeText(actionElement.getElementsByTagName('status')[0].childNodes) statusDetailTxt = self.getXMLNodeText(actionElement.getElementsByTagName('status_detail')[0].childNodes) test = self.getXMLNodeText(actionElement.getElementsByTagName('command')[0].childNodes) self.logger("StatusTxt: '%s' for command: '%s'" % (statusTxt, commandTxt), "detailed") if statusTxt == "Failure": self.logger("Youtube reports an error with command: '%s'\n\tError: '%s'" % (commandTxt, statusDetailTxt),"error") errorCode = 1 elif not statusTxt == "Success": errorCode = 3 if not errorCode: self.logger("Youtube reports upload successful!", "detailed") return True else: self.logger("Youtube reports upload failed! ErrorCode: %s" % errorCode, "detailed") return False
[docs] def deleteSupportFiles(self): """Delete Registered support files (media and xml)""" ## Call our parent, which removes any loaded media or xml files if not TransmogrifierTargetObject.deleteSupportFiles(self): errorCode = 1 ## Delete our youtube batch upload file if self.supportPath: batchFilePath = os.path.join(self.supportPath, "upload", "%s.batch" % self.entityID) if os.path.exists(batchFilePath): self.logger("Removing file at path: '%s'" % batchFilePath, "detailed") os.remove(batchFilePath) if errorCode: return False else: return True
[docs] def loadConfiguration(self, parser): """Load from configuration file, expects a ConfigParser type object. If you subclass, you should call this function. If we return false then you should abort. or do your own sanity checks""" if not TransmogrifierTargetObject.loadConfiguration(self, parser): return False; try: self.ytSFTPServer = parser.get("YouTube","host") self.ytUsername = parser.get("YouTube","username") self.ytOwnerName = parser.get("YouTube","ownername") except: self.logger("loadConfiguration() Problem loading configuration records, please double check your configuration") try: self.retryCount = int (parser.get("YouTube","retryCount")) except: try: self.retryCount = int (parser.get("GLOBAL","retryCount")) except: self.retryCount = int (5); return True
[docs] def setFCSXMLFile(self,filePath): """import FCS XML file, and set applicable local values""" TransmogrifierTargetObject.setFCSXMLFile(self, filePath) self.ytCustomID = self.fcsXMLObject.valueForField("Youtube Generated ID")
[docs] def runFunction(self, function): """Perform action based on passed function""" if function == "batchStatusCheck": return self.batchStatusCheck() else: return TransmogrifierTargetObject.runFunction(self,function)
[docs] def upload(self, dirPath=""): '''Uploads all relative assets to the configured ftpHost, also calls xmlOut and uploads the resulting file''' theError = "" retryCount = self.retryCount currentRetryNum = 1 ## Sanity checks if not dirPath: dirPath = self.supportPath if not os.path.isdir(dirPath): self.logger("upload() Directory does not exist:'%s'" % dirPath, "error") return False ## generate our xml xmlOutPath = os.path.join(dirPath, "xmlout", "%s.xml" % self.entityID) if not self.xmlOut(xmlOutPath): self.logger("upload() could not write XML, exiting", "error") return False ## Create/open our batch file (used for sftp batch uploads) uploadDirPath = os.path.join(dirPath,"upload") batchFilePath = os.path.join(uploadDirPath, "%s.batch" % self.entityID) if not os.path.isdir(uploadDirPath): os.mkdir(uploadDirPath) ## If our batch file exists and we are not allowed to overwrite it, bail if not self.overwriteExistingFiles and os.path.exists(batchFilePath): self.logger("upload() Batch file already exists at path: '%s' and we are not allowed to overwrite, exiting!" % batchFilePath, "error") return False batchFile = open(batchFilePath, "w") batchFile.write("-mkdir '%s'\n" % self.entityID) batchFile.write("chdir '%s'\n" % self.entityID) ## Iterate through our files and append their paths to our batchfile if len(self.files) > 0: for file in self.files.itervalues(): if os.path.exists(file.path): self.logger("upload() adding file to batch upload: '%s'" % (file.fileName), "normal") batchFile.write("put '%s'\n" % file.path) else: theError = file.path,sys.exc_info()[0] self.logger("upload() could not uplod file: '%s' Error:\n%s" % (theError), "error") ## Add our XML file if os.path.exists(xmlOutPath): self.logger("upload() adding file to batch upload: '%s'" % os.path.basename(xmlOutPath), "detailed") batchFile.write("put '%s'\n" % xmlOutPath) else: theError = xmlOutPath,sys.exc_info()[0] self.logger("upload() could not upload file: '%s' Error:\n%s" % (theError), "error") ## Build our FCS object for reporting if not self.fcsXMLOutObject: self.fcsXMLOutObject = FCSXMLObject(self.entityID) fcsXMLOut = self.fcsXMLOutObject batchFile.close() ## If no errors so far, generate our delivery.complete file and do our ## uploads if not theError: if not os.path.exists(uploadDirPath): currentTime = datetime.datetime.fromtimestamp(time.mktime(datetime.datetime.now().timetuple())) self.logger("upload() failed: directory: '%s' does not exist" % uploadDirPath, "error") self.appendFCSField("%s Publish History" % self.serviceName, "%s: Failed to publish to %s. Please try again. Error:\n\t%s\n" % (currentTime,self.serviceName,self.lastError)) return False else: didFinishUpload = False; while ((currentRetryNum <= retryCount) and (not didFinishUpload)): ## Upload our files based on our batch process list if not os.system("/usr/bin/sftp -b '%s' %s@%s" % (batchFilePath, self.ytUsername,self.ytSFTPServer)): currentTime = datetime.datetime.fromtimestamp(time.mktime(datetime.datetime.now().timetuple())) didFinishUpload = True; self.logger("upload() successfully uploaded files!", "detailed") self.appendFCSField("%s Publish History" % self.serviceName, "%s: Successfully published to %s after %s attempt(s).\n" % (currentTime,self.serviceName,currentRetryNum)) fcsXMLOut.setField(FCSXMLField("Published to %s" % self.serviceName, "true", "bool")) fcsXMLOut.setField(FCSXMLField("Status", "Verify Publishing", "string")) ## remove our batch file os.remove(batchFilePath) else: print "currentRetryNum: %i, retryCount: %i\n" % (currentRetryNum, retryCount) currentTime = datetime.datetime.fromtimestamp(time.mktime(datetime.datetime.now().timetuple())) if (currentRetryNum < retryCount): self.logger("upload() failed: error uploading files via sftp on attempt %s of %s, will retry!" % (currentRetryNum,retryCount), "error") self.appendFCSField("%s Publish History" % self.serviceName, "%s: Failed to upload files to %s on attempt %s of %s, will retry.\n" % (currentTime,self.serviceName,currentRetryNum,retryCount)) currentRetryNum = currentRetryNum + 1 else: self.logger("upload() failed: error uploading media files via sftp after %s attempts!" % retryCount, "error") self.appendFCSField("%s Publish History" % self.serviceName, "%s: Failed to publish to %s. Please try again. Error:\n\t%s\n" % (currentTime,self.serviceName,self.lastError)) return False delFilePath = os.path.join(uploadDirPath,"delivery.complete") delFile = open(delFilePath, "w") delFile.close() batchFile = open(batchFilePath, "w") batchFile.write("-mkdir '%s'\n" % self.entityID) batchFile.write("chdir '%s'\n" % self.entityID) batchFile.write("put '%s'\n" % delFilePath) batchFile.close() currentRetryNum = 1; while(currentRetryNum <= retryCount): if not os.system("/usr/bin/sftp -b '%s' %s@%s" % (batchFilePath, self.ytUsername,self.ytSFTPServer)): ## Generate our shell file in our 'inprogress' directory ## so that we can keep track of existing is-progress uploads ## A SQLlite db is probably better suited here. inprogressDirPath = os.path.join(dirPath,"inprogress") inprogressFilePath = os.path.join(inprogressDirPath, "%s.xml" % self.entityID) if not os.path.isdir(inprogressDirPath): os.mkdir(inprogressDirPath) shutil.copyfile(self.fcsXMLObject.path,inprogressFilePath) os.remove(batchFilePath) return True; else: currentRetryNum += 1; self.logger("upload() failed: Failed uploading delivery.complete file after %s attempts!" % retryCount, "error") self.appendFCSField("%s Publish History" % self.serviceName, "%s: Failed to publish to %s. Please try again. Error:\n\t%s\n" % (currentTime,self.serviceName,self.lastError)) return False; else: self.appendFCSField("%s Publish History" % self.serviceName, "%s: An error occured publishing to %s. Please try again. Error: %s\n" % (currentTime,self.serviceName, self.lastError)) return False
[docs] def xmlOut(self, filePath=""): '''Output our YouTube compliant XML. If passed a filepath for the second Parameter, we write to that file, otherwise we print to stdout''' ## Sanity checks and variable initialization theThumbFile = "" if not len(self.files) > 0: self.readMediaFiles() if not len(self.files) > 0: self.logger("No media files were found to upload!", "error") return False if not self.approver: self.logger("No Approver specified!", "error") return False if not self.description: self.logger("No Description Provided!", "error") return False if not self.emailToNotify: self.logger("No notification email address specified!", "error") return False else: ## Youtube wants space delimited addresses in their xml self.emailToNotify = self.emailToNotify.replace(","," ") if not self.entityID: self.logger("Entity ID could not be determined!", "error") if not self.title: self.logger("No title specified!", "error") return False if not self.ytUsername: self.logger("Youtube username or password not specified!", "error") return False if not self.ytOwnerName: self.logger("Youtube ownername not specified!", "error") return False ## Make sure either that our xml out file doesn't already exist, or ## that we're allowed to overwrite existing files. Then Generate our XML if (filePath and (not os.path.exists(filePath) \ or (os.path.exists(filePath) and self.overwriteExistingFiles)) and os.path.isdir(os.path.dirname(filePath))) \ or not filePath : ## create our new xml doc, add our root FCS elements: ## <?xml version="1.0" encoding="UTF-8"?> ## <rss version="2.0" ## xmlns:media="http://search.yahoo.com/mrss" ## xmlns:yt="http://www.youtube.com/schemas/yt/0.2"> ## <channel> ## <yt:notification_email>sandy@example.com, ## ben@example.com</yt:notification_email> ## <yt:account> ## <yt:username>happypartner</yt:username> ## <yt:password>thec0wg0esm00</yt:password> ## </yt:account> ## <yt:owner_name>Example.com TV</yt:owner_name> self.xmlObject = minidom.Document() xmlDoc = self.xmlObject rssElement = xmlDoc.createElement("rss") rssElement.setAttribute("xmlns:media", "http://search.yahoo.com/mrss") rssElement.setAttribute("xmlns:yt", "http://www.youtube.com/schemas/yt/0.2") xmlDoc.appendChild(rssElement) channelElement = xmlDoc.createElement("channel") rssElement.appendChild(channelElement) notifyElement = xmlDoc.createElement("yt:notification_email") notifyElement.appendChild(xmlDoc.createTextNode("%s"% self.emailToNotify)) channelElement.appendChild(notifyElement) accountElement = xmlDoc.createElement("yt:account") channelElement.appendChild(accountElement) userElement = xmlDoc.createElement("yt:username") userElement.appendChild(xmlDoc.createTextNode(self.ytUsername)) passElement = xmlDoc.createElement("yt:password") passElement.appendChild(xmlDoc.createTextNode(self.ytPassword)) accountElement.appendChild(userElement) accountElement.appendChild(passElement) ownerElement = xmlDoc.createElement("yt:owner_name") passElement.appendChild(xmlDoc.createTextNode(self.ytOwnerName)) channelElement.appendChild(ownerElement) ## And then our individual files. for file in self.files.itervalues(): if file.fileType == "video": ## <item> ## <yt:action>Insert</yt:action> ## <media:title>Covert Operations II</media:title> ## <media:content url="file://co2_file.mov" fileSize="12216320"> ## <media:description type="plain"> Ms. World reveals world domination plans. </media:description> ## <media:keywords>covert, operations, spy, pagent</media:keywords> ## <media:category>Entertainment</media:category> ## <media:rating scheme="urn:simple">nonadult</media:rating> ## </media:content> itemElement = xmlDoc.createElement("item") channelElement.appendChild(itemElement) actionElement = xmlDoc.createElement("yt:action") actionElement.appendChild(xmlDoc.createTextNode("insert")) itemElement.appendChild(actionElement) titleElement = xmlDoc.createElement("media:title") titleElement.appendChild(xmlDoc.createTextNode(file.title)) itemElement.appendChild(titleElement) contentElement = xmlDoc.createElement("media:content") contentElement.setAttribute("url", "file://%s" % file.fileName) contentElement.setAttribute("fileSize", "%s" % file.size) itemElement.appendChild(contentElement) if self.description: mediaDescElement = xmlDoc.createElement("media:description") mediaDescElement.appendChild(xmlDoc.createTextNode(self.description)) contentElement.appendChild(mediaDescElement) if self.keywordString: keywordElement = xmlDoc.createElement("media:keywords") keywordElement.appendChild(xmlDoc.createTextNode(self.keywordString)) contentElement.appendChild(keywordElement) categoryElement = xmlDoc.createElement("media:category") categoryElement.appendChild(xmlDoc.createTextNode("Entertainment")) contentElement.appendChild(categoryElement) ratingElement = xmlDoc.createElement("media:rating") ratingElement.setAttribute("scheme", "urn:simple") ratingElement.appendChild(xmlDoc.createTextNode("nonadult")) contentElement.appendChild(ratingElement) ## <yt:language>en</yt:language> ## <yt:date_recorded>2005-08-01</yt:date_recorded> ## <yt:location> ## <yt:country>US</yt:country> ## <yt:location_text>Beverly Hills, CA</yt:location_text> ## </yt:location> ## <yt:start_time>2007-07-07T07:07:07</yt:start_time> ## <yt:end_time>2007-12-31T00:00:00</yt:end_time> languageElement = xmlDoc.createElement("yt:language") languageElement.appendChild(xmlDoc.createTextNode("en")) itemElement.appendChild(languageElement) locationElement = xmlDoc.createElement("yt:location") countryElement = xmlDoc.createElement("yt:country") countryElement.appendChild(xmlDoc.createTextNode("US")) locationElement.appendChild(countryElement) locTextElement = xmlDoc.createElement("yt:location_text") locTextElement.appendChild(xmlDoc.createTextNode("%s" % self.eventLocation)) locationElement.appendChild(locTextElement) dateRecordedElement = xmlDoc.createElement("yt:date_recorded") dateRecordedElement.appendChild(xmlDoc.createTextNode("%s" % self.eventYear)) locationElement.appendChild(dateRecordedElement) itemElement.appendChild(locationElement) ## <yt:community> ## <yt:allow_comments>Always</yt:allow_comments> ## <yt:allow_responses>Never</yt:allow_responses> ## <yt:allow_ratings>true</yt:allow_ratings> ## <yt:allow_embedding>true</yt:allow_embedding> ## </yt:community> ## <yt:policy> ## <yt:commercial>share</yt:commercial> ## <yt:ugc>share</yt:ugc> ## </yt:policy> communityElement = xmlDoc.createElement("yt:community") itemElement.appendChild(communityElement) commentsElement = xmlDoc.createElement("yt:allow_comments") commentsElement.appendChild(xmlDoc.createTextNode("Always")) communityElement.appendChild(commentsElement) responseElement = xmlDoc.createElement("yt:allow_responces") responseElement.appendChild(xmlDoc.createTextNode("Always")) communityElement.appendChild(responseElement) ratingsElement = xmlDoc.createElement("yt:allow_ratings") ratingsElement.appendChild(xmlDoc.createTextNode("true")) communityElement.appendChild(ratingsElement) embedElement = xmlDoc.createElement("yt:allow_embedding") embedElement.appendChild(xmlDoc.createTextNode("true")) communityElement.appendChild(embedElement) policyElement = xmlDoc.createElement("yt:policy") itemElement.appendChild(policyElement) commercialElement = xmlDoc.createElement("yt:commercial") commercialElement.appendChild(xmlDoc.createTextNode("share")) policyElement.appendChild(commercialElement) ugcElement = xmlDoc.createElement("yt:ugc") ugcElement.appendChild(xmlDoc.createTextNode("share")) policyElement.appendChild(ugcElement) ## <yt:movie_metadata> ## <yt:custom_id>000ABC123XYZ</yt:custom_id> ## <yt:title>Covert Operations II (Deluxe extended ## director's cut)</yt:title> ## </yt:movie_metadata> ## <yt:distribution_restriction> ## <yt:distribution_rule>Deny</yt:distribution_rule> ## <yt:adsense_syndication>Deny</yt:adsense_syndication> ## </yt:distribution_restriction> ## <yt:advertising> ## <yt:invideo>Allow</yt:invideo> ## </yt:advertising> ## <yt:target>upload,claim,fingerprint</yt:target> ## <yt:keep_fingerprint>no</yt:keep_fingerprint> ## </item> movieElement = xmlDoc.createElement("yt:movie_metadata") itemElement.appendChild(movieElement) customidElement = xmlDoc.createElement("yt:custom_id") customidElement.appendChild(xmlDoc.createTextNode(self.entityID)) movieElement.appendChild(customidElement) titleElement = xmlDoc.createElement("yt:title") titleElement.appendChild(xmlDoc.createTextNode(file.title)) movieElement.appendChild(titleElement) #movieElement.appendChild( #xmlDoc.createElement("yt:custom_id").appendChild(xmlDoc.createTextNode(self.entityID))) distributionElement = xmlDoc.createElement("yt:distribution_restriction") itemElement.appendChild(distributionElement) distributionRuleElement = xmlDoc.createElement("yt:distribution_rule") distributionRuleElement.appendChild(xmlDoc.createTextNode("Deny")) distributionElement.appendChild(distributionRuleElement) adsenseElement = xmlDoc.createElement("yt:adsense_syndication") adsenseElement.appendChild(xmlDoc.createTextNode("Deny")) distributionElement.appendChild(adsenseElement) advertisingElement = xmlDoc.createElement("yt:advertising") invideoElement = xmlDoc.createElement("yt:invideo") invideoElement.appendChild(xmlDoc.createTextNode("Allow")) advertisingElement.appendChild(invideoElement) itemElement.appendChild(advertisingElement) targetElement = xmlDoc.createElement("yt:target") targetElement.appendChild(xmlDoc.createTextNode("upload,claim,fingerprint")) itemElement.appendChild(targetElement) else: self.logger("Unknown media type: '%s' for file: '%s'" % (file.fileType, file.path)) return False; ## Write our XML to file if provided, otherwise echo it if filePath: theFile = open(filePath, "w") xmlDoc.writexml(theFile) theFile.close() else: print xmlDoc.toprettyxml() elif os.path.exists(filePath) and not self.overwriteExistingFiles: self.logger("File already exists at path: %s, exiting!" % filePath, "error") return False elif not os.path.exists(os.path.dirname(filePath)): self.logger("Directory does not exist at path: %s, exiting!" % os.path.dirname(filePath), "error") return false else: self.logger("Uncaught Exception: Error writing XML", "error") return False xmlDoc.unlink() return True