コード例 #1
0
 def delete(self, id):
     from auth import get_profile
     atts = get_profile()
     if atts['superuser']:
         self.bundle = self.model.find_one({'_id': str(id)})
         result = self.delete_obj()
         if not result:
             return result
         else:
             for location in self.bundle['@graph']['ma:locator']:
                 basename = location['@id']
                 duplicates = self.model.find_one({
                     "@graph.ma:locator": {
                         "$elemMatch": {
                             "@id": basename
                         }
                     }
                 })
                 if duplicates is not None:
                     return result
                 extension = location['ma:hasFormat'].split('/')[-1]
                 filename = "{0}.{1}".format(basename, extension)
                 try:
                     remove(config.MEDIA_DIRECTORY + filename)
                 except (IOError, OSError):
                     pass
             return result
     else:
         return action_401()
コード例 #2
0
    def delete_subtitle(self, filename):
        from os import remove
        from helpers import endpoint_404

        query = {
            "@graph.ma:hasRelatedResource": {
                "$elemMatch": {
                    "@id": filename
                }
            }
        }

        bundle = self.model.find_one(query)

        if bundle is None:
            return endpoint_404()

        if not self.acl_write_check(bundle):
            return action_401()

        l = bundle.get("@graph").get("ma:hasRelatedResource")
        l[:] = [d for d in l if d.get('@id') != filename]
        bundle.save()

        remove(config.SUBTITLE_DIRECTORY + filename)

        return mongo_jsonify(bundle)
コード例 #3
0
ファイル: resources.py プロジェクト: mindis/byu-hummedia-api
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"
コード例 #4
0
def videoMembershipBatch():
    status = {}
    packet = request.json

    # ensure the user has write access to the collection
    for up in packet:
        bundle = ags.find_one({'_id': str(up['collection']['id'])})
        group = AssetGroup(request=request)
        if not group.acl_write_check(bundle):
            return action_401()

    for up in packet:
        status[up['collection']['id']] = assets.update(
            {'@graph.pid': {
                '$in': up['videos']
            }}, {
                '$addToSet': {
                    "@graph.ma:isMemberOf": {
                        '@id': up['collection']['id'],
                        'title': up['collection']['id']
                    }
                }
            },
            multi=True)
    return jsonify(status)
コード例 #5
0
ファイル: resources.py プロジェクト: webnard/byu-hummedia-api
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"
コード例 #6
0
ファイル: resources.py プロジェクト: BYU-ODH/byu-hummedia-api
 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()
コード例 #7
0
ファイル: resources.py プロジェクト: BYU-ODH/byu-hummedia-api
    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()
コード例 #8
0
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)
コード例 #9
0
ファイル: resources.py プロジェクト: webnard/byu-hummedia-api
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)
コード例 #10
0
ファイル: resources.py プロジェクト: BYU-ODH/byu-hummedia-api
    def delete(self, id):
        # Verify that a user is logged in.
        from auth import get_profile
        userid = get_profile()['userid']
        if not userid:
            return action_401()

        query = {'_id': id, 'userid': userid}
        result = self.collection.delete_one(query)

        return jsonify({'success': result.deleted_count == 1})
コード例 #11
0
ファイル: resources.py プロジェクト: BYU-ODH/byu-hummedia-api
    def get_list(self):
        # Verify that a user is logged in.
        from auth import get_profile
        userid = get_profile()['userid']
        if not userid:
            return action_401()

        query = {'userid': userid}
        results = self.collection.find(query)

        return mongo_jsonify(list(results))
コード例 #12
0
ファイル: resources.py プロジェクト: webnard/byu-hummedia-api
def videoMembershipBatch():
    status={}
    packet=request.json

    # ensure the user has write access to the collection
    for up in packet:
        bundle = ags.find_one({'_id': str(up['collection']['id'])})
        group = AssetGroup(request=request)
        if not group.acl_write_check(bundle):
            return action_401()

    for up in packet:
        status[up['collection']['id']]=assets.update({'@graph.pid':{'$in':up['videos']}}, {'$addToSet':{"@graph.ma:isMemberOf":{'@id':up['collection']['id'],'title':up['collection']['id']}}},multi=True)
    return jsonify(status)
コード例 #13
0
ファイル: resources.py プロジェクト: BYU-ODH/byu-hummedia-api
    def get(self, id):
        if not id:
            return self.get_list()
        else:
            from auth import get_profile
            userid = get_profile()['userid']
            if not userid:
                return action_401()

            query = {'_id': str(id), 'userid': userid}
            bundle = self.get_bundle(query)

            if bundle:
                return self.serialize_bundle(bundle)
            else:
                return bundle_404()
コード例 #14
0
ファイル: resources.py プロジェクト: BYU-ODH/byu-hummedia-api
    def get_expired(self, limit=0):
        '''Find any expired media and show why they are considered expired.'''
        # Only superusers should be able to review this report.
        from auth import get_profile
        atts = get_profile()
        if not atts['superuser']:
            return action_401()

        current_year = datetime.utcnow().year
        stale_date = datetime.utcnow() - timedelta(days=730)
        stale_str = datetime.strftime(stale_date, '%Y-%m-%d')

        not_hlr_query = {'$or': [{'@graph.dc:hlr': {'$exists': False}}, {'@graph.dc:hlr': False}]}
        exp_date_query = {'$and': [not_hlr_query, {'@graph.dc:expirationdate': {'$lt': current_year}}]}
        stale_query = {'$and': [not_hlr_query, {'@graph.dc:lastviewed': {'$lt': stale_str}}]}
        never_viewed_query = {'$and': [not_hlr_query, {'@graph.dc.lastviewed': {'$exists': False}}]}

        exp_date = [v for v in self.model.find(exp_date_query).limit(limit)]
        stale = [v for v in self.model.find(stale_query).limit(limit)]
        never_viewed = [v for v in self.model.find(never_viewed_query).limit(limit)]

        title = 'Expired Media'

        body = '<h1>%s Media</h1>' % title

        if len(exp_date) > 0:
            exp_date_fields = ['ma:title', 'dc:creator', 'dc:expirationdate', 'ma:isMemberOf']
            exp_date_headings = ['Title', 'Owner', 'Expiration Date', 'Collections']
            exp_date_table = build_html_table(exp_date, exp_date_fields, exp_date_headings)
            body += '<h2>%s</h2>%s' % ('Past Expiration Date', exp_date_table)

        if len(stale) > 0:
            stale_fields = ['ma:title', 'dc:creator', 'dc:date', 'dc:lastviewed', 'ma:isMemberOf']
            stale_headings = ['Title', 'Owner', 'Upload Date', 'Last Viewed', 'Collections']
            stale_table = build_html_table(stale, stale_fields, stale_headings)
            body += '<h2>%s</h2>%s' % ('Not Viewed Recently', stale_table)

        if len(never_viewed) > 0:
            never_viewed_fields = ['ma:title', 'dc:creator', 'dc:date', 'ma:isMemberOf']
            never_viewed_headings = ['Title', 'Owner', 'Upload Date', 'Collections']
            never_viewed_table = build_html_table(never_viewed, never_viewed_fields, never_viewed_headings)
            body += '<h2>%s</h2>%s' % ('Never Viewed', never_viewed_table)

        html = '<html><head><title>%s</title></head><body>%s</body></html>' % (title, body)

        return Response(html, status=200, mimetype="text/html")
コード例 #15
0
ファイル: resources.py プロジェクト: webnard/byu-hummedia-api
 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()
コード例 #16
0
ファイル: resources.py プロジェクト: webnard/byu-hummedia-api
    def update_subtitle(self, filename, new_file):
        from helpers import endpoint_404

        query = {
          "@graph.ma:hasRelatedResource":{"$elemMatch": {"@id":filename}}
        }

        bundle = self.model.find_one(query)

        if bundle is None:
            return endpoint_404() 
        
        if not self.acl_write_check(bundle):
          return action_401()
        
        new_file.save(config.SUBTITLE_DIRECTORY + filename)
        
        return mongo_jsonify(bundle)
コード例 #17
0
    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}))
コード例 #18
0
ファイル: resources.py プロジェクト: webnard/byu-hummedia-api
 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()
コード例 #19
0
    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}))
コード例 #20
0
ファイル: resources.py プロジェクト: BYU-ODH/byu-hummedia-api
    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.')
コード例 #21
0
ファイル: resources.py プロジェクト: webnard/byu-hummedia-api
    def delete_subtitle(self, filename):
        from os import remove
        from helpers import endpoint_404

        query = {
          "@graph.ma:hasRelatedResource":{"$elemMatch": {"@id":filename}}
        }

        bundle = self.model.find_one(query)

        if bundle is None:
            return endpoint_404() 
        
        if not self.acl_write_check(bundle):
            return action_401()

        l = bundle.get("@graph").get("ma:hasRelatedResource")
        l[:] = [d for d in l if d.get('@id') != filename]
        bundle.save()
        
        remove(config.SUBTITLE_DIRECTORY + filename)

        return mongo_jsonify(bundle)
コード例 #22
0
ファイル: resources.py プロジェクト: webnard/byu-hummedia-api
 def delete(self,id):
     from auth import get_profile
     atts=get_profile()
     if atts['superuser']:
         self.bundle=self.model.find_one({'_id': str(id)})
         result = self.delete_obj()
         if not result:
             return result
         else:
             for location in self.bundle['@graph']['ma:locator']:
                 basename = location['@id']
                 duplicates = self.model.find_one({"@graph.ma:locator": {"$elemMatch": {"@id": basename}}})
                 if duplicates is not None:
                     return result
                 extension = location['ma:hasFormat'].split('/')[-1]
                 filename = "{0}.{1}".format(basename, extension)
                 try:
                     remove(config.MEDIA_DIRECTORY + filename)
                 except IOError:
                     pass
             return result
     else:
         return action_401()