def videoCreationBatch(): from auth import get_user, is_superuser if not is_superuser(): return action_401() if request.method=="GET": chdir(config.INGEST_DIRECTORY) files=[f for f in listdir(getcwd()) if f[0] != '.'] return json.dumps(files) else: packet=request.json ids = [up.get('id') for up in packet] if len(set(ids)) is not len(ids): return bundle_400("Duplicate IDs found. Cannot update." % s) # test everything before we start ingesting, otherwise half the batch # might get completed before we get an error. easier to just reject everything # than half of everything for up in packet: i = up['id'] dupe = assets.find_one({'@graph.ma:locator': {'$elemMatch': {'@id': i}}}) mp4 = (unicode(config.MEDIA_DIRECTORY) + i + '.mp4').encode('utf-8') webm = (unicode(config.MEDIA_DIRECTORY) + i + '.webm').encode('utf-8') if path.isfile(mp4) or path.isfile(webm) or dupe is not None: return bundle_400("That file (%s) already exists; try another unique ID." %i) for up in packet: result = MediaAsset.set_new_file(up['pid'], up['id'], up['filepath']) if not result[0]: return bundle_400(result[1]) return "Success"
def audioCreationBatch(): import mutagen import uuid import os from werkzeug.utils import secure_filename from auth import is_superuser if not is_superuser(): return action_401() files = request.files.getlist('audio[]') if not len(files): return bundle_400("Missing form field 'audio[]'") incompatible = filter(lambda x: not x.filename.endswith('mp3'), files) if len(incompatible): return bundle_400("Only MP3 files are supported.") results = [] for f in files: ext = f.filename.split('.')[-1] filename = secure_filename(f.filename.split('.', 1)[0]) \ + str(uuid.uuid4()) + '.' + ext path = os.path.join(config.MEDIA_DIRECTORY, filename) f.save(path) id3 = mutagen.File(path, easy=True) # metadata _id = str(ObjectId()) audio = assets.Video() audio['_id'] = _id audio['@graph']['dc:type'] = 'hummedia:type/humaudio' audio['@graph']['pid'] = _id audio['@graph']['ma:title'] = id3.get('title', [f.filename])[0] audio['@graph']['ma:hasContributor'] = [{ '@id': '', 'name': x } for x in id3.get('artist', [])] try: audio['@graph']["ma:date"] = int(id3.get('date')[0]) except: audio['@graph'][ 'ma:date'] = 1970 # TODO: this requires a number, but I don't have one for it audio['@graph']["ma:locator"] = [{ "@id": '.'.join(filename.split('.')[0:-1]), "ma:hasFormat": "audio/" + ext, "ma:hasCompression": {} }] audio.save() audio['@graph']['ma:locator'][0]['@id'] += '.mp3' results.append(audio['@graph']) return mongo_jsonify(results)
def post(self, id=None): # Verify that a user is logged in. from auth import get_profile userid = get_profile()['userid'] if not userid: return action_401() data = self.request.get_json() # Require clips to have a start time. # End time is optional. if 'start' not in data: return bundle_400('clips must have a start time!') # Validate media id. if 'mediaid' in data: query = {'_id': data['mediaid']} if not assets.find_one(query): return bundle_400('invalid media id!') else: return bundle_400('clips must have a valid media id!') # Populate the new object with all our data. self.bundle = self.model() self.set_attrs() self.bundle['userid'] = userid self.bundle['_id'] = str(ObjectId()) return self.save_bundle()
def audioCreationBatch(): import mutagen import uuid import os from werkzeug.utils import secure_filename from auth import is_superuser if not is_superuser(): return action_401() files = request.files.getlist('audio[]') if not len(files): return bundle_400("Missing form field 'audio[]'") incompatible = filter(lambda x: not x.filename.endswith('mp3'), files) if len(incompatible): return bundle_400("Only MP3 files are supported.") results = [] for f in files: ext = f.filename.split('.')[-1] filename = secure_filename(f.filename.split('.', 1)[0]) \ + str(uuid.uuid4()) + '.' + ext path = os.path.join(config.MEDIA_DIRECTORY, filename) f.save(path) id3 = mutagen.File(path, easy=True) # metadata _id = str(ObjectId()) audio = assets.Video() audio['_id'] = _id audio['@graph']['dc:type'] = 'hummedia:type/humaudio' audio['@graph']['pid'] = _id audio['@graph']['ma:title'] = id3.get('title',[f.filename])[0] audio['@graph']['ma:hasContributor'] = [{'@id': '', 'name': x} for x in id3.get('artist',[])] try: audio['@graph']["ma:date"] = int(id3.get('date')[0]) except: audio['@graph']['ma:date'] = 1970 # TODO: this requires a number, but I don't have one for it audio['@graph']["ma:locator"] = [ { "@id": '.'.join(filename.split('.')[0:-1]), "ma:hasFormat": "audio/" + ext, "ma:hasCompression": {} } ] audio.save() audio['@graph']['ma:locator'][0]['@id'] += '.mp3' results.append(audio['@graph']) return mongo_jsonify(results)
def client_process(self,bundle=None,list=False,client=None): if not bundle: bundle=self.bundle if not client: client = self.request.args.get("client") c=clients.lookup[client]() m=assets.find_one(bundle["@graph"]["dc:relation"]) m["@graph"]["resource"]=uri_pattern(m["@graph"]["pid"],config.APIHOST+"/video") m["@graph"]["type"]=resolve_type(m["@graph"]["dc:type"]) m["@graph"]["url"]=[] for url in m["@graph"]["ma:locator"]: if m["@graph"]["type"]=="humvideo": host=config.HOST+"/video" ext="."+url["ma:hasFormat"].replace("video/","") elif m["@graph"]["type"]=="humaudio": host=config.HOST+"/video" ext="."+url["ma:hasFormat"].replace("audio/","") elif m["@graph"]["type"]=="yt": host="http://youtu.be" ext="" m["@graph"]["url"].append(uri_pattern(url["@id"]+ext,host)) resp_context=True if not list else False try: required = True if bundle["@graph"]["pid"] in m["@graph"].get("ma:hasPolicy") else False except TypeError: return bundle_400("That annotation list isn't currently associated with any media.") return c.serialize(bundle["@graph"],m["@graph"],resp_context,required)
def videoCreationBatch(): from auth import get_user, is_superuser if not is_superuser(): return action_401() if request.method=="GET": chdir(config.INGEST_DIRECTORY) files=[f for f in listdir(getcwd()) if f[0] != '.'] return json.dumps(files) else: from PIL import Image from shutil import move from helpers import getVideoInfo packet=request.json for up in packet: filepath=unicode(config.INGEST_DIRECTORY + up['filepath']) new_file=unicode(config.MEDIA_DIRECTORY + up['id'] + ".mp4") if path.isfile(new_file): return bundle_400("That file already exists; try another unique ID.") if path.isfile(filepath.encode('utf-8')): md=getVideoInfo(filepath.encode('utf-8')) poster = config.POSTERS_DIRECTORY + "%s.jpg" % (up["id"]) thumb = config.POSTERS_DIRECTORY + "%s_thumb.jpg" % (up["id"]) move(filepath.encode('utf-8'), new_file.encode('utf-8')) assets.update({"_id":up["pid"]},{"$set":{ "@graph.ma:frameRate":float(md["framerate"]), "@graph.ma:averageBitRate":int(float(md["bitrate"])), "@graph.ma:frameWidth":int(md["width"]), "@graph.ma:frameHeight":int(md["height"]), "@graph.ma:duration":int( round(float(md["duration"])) )/60, "@graph.ma:locator": [ { "@id": up["id"], "ma:hasFormat": "video/mp4", "ma:hasCompression": {"@id":"http://www.freebase.com/view/en/h_264_mpeg_4_avc","name": "avc.42E01E"} }, { "@id": up["id"], "ma:hasFormat": "video/webm", "ma:hasCompression": {"@id":"http://www.freebase.com/m/0c02yk5","name":"vp8.0"} } ] }}) imgcmd = "avconv -i '%s' -q:v 1 -r 1 -t 00:00:01 -ss 00:00:30 -f image2 '%s'" % (new_file,poster) system(imgcmd.encode('utf-8')) chmod(poster,0775) im=Image.open(poster) im.thumbnail((160,90)) im.save(thumb) chmod(thumb,0775) if not app.config.get('TESTING'): from gearman import GearmanClient client = GearmanClient(config.GEARMAN_SERVERS) client.submit_job("generate_webm", str(up["id"])) else: from ingest import generate_webm result = generate_webm(file_id=up['id']) if result == "ERROR": raise Exception("Could not convert media file.") return "Success"
def get(self,id,limit=0): q=self.set_query() if id: try: q['_id']=ObjectId(str(id)) except Exception as e: return bundle_400("The ID you submitted is malformed.") if "enrollments" in self.request.args: info = self.get_bundle(q) en = self.get_enrollments(info['username'], info['userid']) en.update({"username": info['username'], '_id': q['_id']}) self.bundle = en else: self.bundle=self.get_bundle(q) if self.bundle: self.bundle=self.auth_filter(self.bundle) if not self.bundle: return action_401() self.set_resource() return self.serialize_bundle(self.bundle) else: return bundle_404() else: self.bundle=self.collection.find(q).limit(limit) return self.get_list()
def post(self,pid=None): if self.acl_write_check(): self.bundle=self.model() if not pid: if "username" in self.request.json: self.bundle["_id"]=str(self.request.json.username) else: return bundle_400() else: self.bundle["_id"]=str(ObjectId(pid)) self.preprocess_bundle() setattrs=self.set_attrs() if setattrs.get("resp")==200: return self.save_bundle() else: return bundle_400(setattrs.get("msg")) else: return action_401()
def patch(self, id): from auth import get_profile atts = get_profile() if self.request.json is None or 'replacement_file' not in self.request.json: return super(MediaAsset, self).patch(id) if not atts['superuser']: return action_401() found = assets.find_one({'_id': id}) if not found: return bundle_404() file_id = None to_delete = [] # find existing filenames for f in found['@graph']['ma:locator']: if file_id is not None and f['@id'] != file_id: raise Exception( "Cannot replace file; multiple files with different IDs") file_id = f['@id'] extension = f['ma:hasFormat'].split('/')[-1] fpath = config.MEDIA_DIRECTORY + f['@id'] + '.' + extension to_delete.append(fpath) from os import remove for f in to_delete: try: remove(f) except OSError: pass assets.update({'_id': id}, {'$set': {'@graph.ma:locator': []}}) result = self.set_new_file(id, file_id, self.request.json['replacement_file']) if not result[0]: return bundle_400(result[1]) return self.serialize_bundle(assets.find_one({'_id': id}))
def get(self,id,limit=0): q=self.set_query() if id: try: q['_id']=ObjectId(str(id)) except Exception as e: return bundle_400("The ID you submitted is malformed.") self.bundle=self.get_bundle(q) if self.bundle: self.bundle=self.auth_filter(self.bundle) if not self.bundle: return action_401() self.set_resource() return self.serialize_bundle(self.bundle) else: return bundle_404() else: self.bundle=self.collection.find(q).limit(limit) return self.get_list()
def patch(self, id): from auth import get_profile atts=get_profile() if self.request.json is None or 'replacement_file' not in self.request.json: return super(MediaAsset, self).patch(id) if not atts['superuser']: return action_401() found = assets.find_one({'_id': id}) if not found: return bundle_404() file_id = None to_delete = [] # find existing filenames for f in found['@graph']['ma:locator']: if file_id is not None and f['@id'] != file_id: raise Exception("Cannot replace file; multiple files with different IDs") file_id = f['@id'] extension = f['ma:hasFormat'].split('/')[-1] fpath = config.MEDIA_DIRECTORY + f['@id'] + '.' + extension to_delete.append(fpath) from os import remove for f in to_delete: try: remove(f) except OSError: pass assets.update({'_id': id}, {'$set': {'@graph.ma:locator': []}}) result = self.set_new_file(id, file_id, self.request.json['replacement_file']) if not result[0]: return bundle_400(result[1]) return self.serialize_bundle(assets.find_one({'_id': id}))
def update_lastview(self, id, limit=0): '''Update the last view time if the 'view' url parameter is used.''' self.bundle = self.model.find_one({'$or': [{'_id': str(id)}, {'_id': ObjectId(id)}]}) if self.bundle: self.bundle = self.auth_filter(self.bundle) if not self.bundle: return action_401() self.bundle[u'@graph'][u'dc:lastviewed'] = datetime.utcnow() self.set_attrs() # Sometimes in the development testing database the ma:duration filed is missing. # This causes an error when the lastview field is updated. # This eats the error, which is probably not a best practice but makes the user # experience better. from mongokit.schema_document import RequireFieldError try: self.bundle.save() except RequireFieldError: return mongo_jsonify({"resp":200}) return mongo_jsonify({"resp":200}) else: return bundle_400('The ID you submitted is malformed.')