thumbnail generation and primitive search
git-svn-id: http://yolanda.mister-muffin.de/svn@405 7eef14d0-6ed0-489d-bf55-20463b2d70db
This commit is contained in:
parent
2003134084
commit
76ad4c8710
9 changed files with 78 additions and 47 deletions
|
@ -19,9 +19,13 @@ port = 5000
|
||||||
use = egg:Yolanda
|
use = egg:Yolanda
|
||||||
full_stack = true
|
full_stack = true
|
||||||
cache_dir = /tmp/yolanda/data
|
cache_dir = /tmp/yolanda/data
|
||||||
beaker.session.key = yolanda
|
beaker.session.key = yolandav
|
||||||
beaker.session.secret = somesecret
|
beaker.session.secret = somesecret
|
||||||
|
|
||||||
|
directory_videos = videos
|
||||||
|
directory_video-stills = video-stills
|
||||||
|
directory_video-thumbnails = thumbnails
|
||||||
|
|
||||||
# If you'd like to fine-tune the individual locations of the cache data dirs
|
# If you'd like to fine-tune the individual locations of the cache data dirs
|
||||||
# for the Cache data, or the Session saves, un-comment the desired settings
|
# for the Cache data, or the Session saves, un-comment the desired settings
|
||||||
# here:
|
# here:
|
||||||
|
@ -33,7 +37,6 @@ beaker.session.secret = somesecret
|
||||||
# execute malicious code after an exception is raised.
|
# execute malicious code after an exception is raised.
|
||||||
#set debug = false
|
#set debug = false
|
||||||
|
|
||||||
|
|
||||||
# Logging configuration
|
# Logging configuration
|
||||||
[loggers]
|
[loggers]
|
||||||
keys = root, yolanda
|
keys = root, yolanda
|
||||||
|
|
|
@ -32,14 +32,14 @@ def make_map():
|
||||||
|
|
||||||
video = kargs.pop('video')
|
video = kargs.pop('video')
|
||||||
kargs['id'] = video['id']
|
kargs['id'] = video['id']
|
||||||
kargs['title'] = video['title']
|
kargs['dc_title'] = video['dc_title']
|
||||||
|
|
||||||
return kargs
|
return kargs
|
||||||
|
|
||||||
map.connect('video_page', 'video/:id/:title', controller='video', _filter=video_expand)
|
map.connect('video_page', 'video/:id/:dc_title', controller='video', _filter=video_expand)
|
||||||
# map.connect('video_file', 'video/:id.ogv', controller='video', action='file' _filter=video_expand)
|
# map.connect('video_file', 'video/:id.ogv', controller='video', action='file' _filter=video_expand)
|
||||||
|
|
||||||
map.connect('download_page', 'download/:id/:title', controller='download', action="download")
|
map.connect('download_page', 'download/:id/:dc_title', controller='download', action="download")
|
||||||
|
|
||||||
# everything else
|
# everything else
|
||||||
map.connect(':controller/:action/:id')
|
map.connect(':controller/:action/:id')
|
||||||
|
|
|
@ -1,4 +1,21 @@
|
||||||
|
## Yolanda, a video CMS for the web
|
||||||
|
## Copyright (C) 2007, 2008 Nils Dagsson Moskopp, Johannes Schauer
|
||||||
|
|
||||||
|
## This program is free software: you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU Affero General Public License as
|
||||||
|
## published by the Free Software Foundation, either version 3 of the
|
||||||
|
## License, or (at your option) any later version.
|
||||||
|
|
||||||
|
## This program 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
## You should have received a copy of the GNU Affero General Public License
|
||||||
|
## along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
from yolanda.lib.base import *
|
from yolanda.lib.base import *
|
||||||
|
|
||||||
|
@ -10,21 +27,27 @@ class SearchController(BaseController):
|
||||||
|
|
||||||
c.query = request.params['query']
|
c.query = request.params['query']
|
||||||
|
|
||||||
# c.results dummy
|
raw_results = model.Video.query.filter_by(dc_title=c.query).all()
|
||||||
c.results = [
|
|
||||||
{'title': 'foobar', 'id': '23' },
|
if not raw_results:
|
||||||
{'title': 'blablupp', 'id': '42'},
|
c.message = {
|
||||||
{'title': 'uiae nrdt', 'id': '555'},
|
'type': 'warning'
|
||||||
{'title': 'uiaenrtd uiaenrtd uiaenrdt', 'id': '666666666'},
|
}
|
||||||
{'title': 'foobar', 'id': '23'},
|
c.message['text']='No results for query "%s".' % c.query
|
||||||
{'title': 'blablupp', 'id': '42'},
|
return render('/xhtml/results.mako')
|
||||||
{'title': 'James Bond drives a bulletproof Aston Martin !!!', 'id': '555'},
|
|
||||||
{'title': 'uiaenrtd uiaenrtd uiaenrdt uiaenrtd uiaenrtd', 'id': '666666666'},
|
c.results = []
|
||||||
{'title': 'foobar', 'id': '123'},
|
|
||||||
{'title': 'blablupp', 'id': '42'},
|
for result in raw_results:
|
||||||
{'title': 'lolwtf hax !!!11', 'id': '9001'}
|
c.results.append(
|
||||||
]
|
{
|
||||||
|
'dc_title': result.dc_title,
|
||||||
|
'id': result.id,
|
||||||
|
'snapshot': os.path.join(config['directory_video-stills'],str(result.id)),
|
||||||
|
'thumbnail': os.path.join(config['directory_video-thumbnails'],str(result.id))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return render('/xhtml/results.mako')
|
return render('/xhtml/results.mako')
|
||||||
# return request.params['query']
|
# return request.params['query']
|
||||||
# return h.form(h.url(action='search'), method='get')
|
# return h.form(h.url(action='search'), method='get'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
## <one line to give the program's name and a brief idea of what it does.>
|
## Yolanda, a video CMS for the web
|
||||||
## Copyright (C) 2007, 2008 Nils Dagsson Moskopp, Johannes Schauer
|
## Copyright (C) 2007, 2008 Nils Dagsson Moskopp, Johannes Schauer
|
||||||
|
|
||||||
## This program is free software: you can redistribute it and/or modify
|
## This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -70,23 +70,25 @@ class UploadController(BaseController):
|
||||||
# TODO: enable several contributors
|
# TODO: enable several contributors
|
||||||
dc_contributor = '',
|
dc_contributor = '',
|
||||||
|
|
||||||
dc_created = '',
|
# TODO: insert real data
|
||||||
dc_valid = '',
|
dc_created = datetime(9999,9,9).strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
dc_available = '',
|
dc_valid = datetime(9999,9,9).strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
dc_issued = '',
|
dc_available = datetime(9999,9,9).strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
dc_modified = '',
|
dc_issued = datetime(9999,9,9).strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
dc_dateAccepted = '',
|
dc_modified = datetime(9999,9,9).strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
dc_dateCopyrighted = '',
|
dc_dateAccepted = datetime(9999,9,9).strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
dc_dateSubmitted = datetime.today().isoformat(),
|
dc_dateCopyrighted = datetime(9999,9,9).strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
dc_dateSubmitted = datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
|
||||||
dc_identifier = '',
|
dc_identifier = '',
|
||||||
dc_source = '',
|
dc_source = '',
|
||||||
dc_language = request.params['language'],
|
dc_language = request.params['language'],
|
||||||
|
|
||||||
dc_extent = timedelta(0), # TODO: insert videolength
|
# TODO: insert videolength
|
||||||
|
dc_extent = timedelta(0),
|
||||||
|
|
||||||
dc_spatial = request.params['spatial'],
|
dc_spatial = request.params['spatial'],
|
||||||
dc_temporal = request.params['temporal'],
|
dc_temporal = datetime(9999,9,9).strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
|
||||||
dc_rightsHolder = '',
|
dc_rightsHolder = '',
|
||||||
|
|
||||||
|
@ -108,11 +110,12 @@ class UploadController(BaseController):
|
||||||
|
|
||||||
# define stuff
|
# define stuff
|
||||||
videosource=os.path.join(config['cache.dir'], str(video.id))
|
videosource=os.path.join(config['cache.dir'], str(video.id))
|
||||||
videodestination=os.path.join(config['pylons.paths']['static_files'], "videos", str(video.id))
|
videodestination=os.path.join(config['pylons.paths']['static_files'], config['directory_videos'], str(video.id))
|
||||||
imagedestination=os.path.join(config['pylons.paths']['static_files'], "video-stills", str(video.id))
|
snapshotdestination=os.path.join(config['pylons.paths']['static_files'], config['directory_video-stills'], str(video.id))
|
||||||
|
thumbnaildestination=os.path.join(config['pylons.paths']['static_files'], config['directory_video-thumbnails'], str(video.id))
|
||||||
|
|
||||||
# start encoding thread in background
|
# start encoding thread in background
|
||||||
threading.Thread(target=self.bgencode, args=(videosource, videodestination, imagedestination)).start()
|
threading.Thread(target=self.bgencode, args=(videosource, videodestination, snapshotdestination, thumbnaildestination)).start()
|
||||||
|
|
||||||
# return 'Successfully uploaded: %s'%video.query.all()
|
# return 'Successfully uploaded: %s'%video.query.all()
|
||||||
c.message = {
|
c.message = {
|
||||||
|
@ -122,9 +125,11 @@ class UploadController(BaseController):
|
||||||
c.message['text']='Your file was successfully uploaded to "%s".'%videodestination
|
c.message['text']='Your file was successfully uploaded to "%s".'%videodestination
|
||||||
return render('/xhtml/index.mako')
|
return render('/xhtml/index.mako')
|
||||||
|
|
||||||
def bgencode(self, source, destination, snapshotdestination):
|
def bgencode(self, source, destination, snapshotdestination, thumbnaildestination):
|
||||||
videosnapshot = snapshot.Snapshot(source).get_snapshot()
|
videosnapshot = snapshot.Snapshot(source).get_snapshot()
|
||||||
videosnapshot.save(snapshotdestination, "JPEG")
|
videosnapshot.save(snapshotdestination, 'JPEG')
|
||||||
|
videosnapshot.thumbnail((300,150))
|
||||||
|
videosnapshot.save(thumbnaildestination, 'JPEG')
|
||||||
videoencode = encode.Encode(source,destination)
|
videoencode = encode.Encode(source,destination)
|
||||||
videoencode.run()
|
videoencode.run()
|
||||||
os.unlink(source)
|
os.unlink(source)
|
||||||
|
|
|
@ -55,10 +55,9 @@ class Snapshot:
|
||||||
#get current buffer's capabilities
|
#get current buffer's capabilities
|
||||||
caps = buffer.get_caps ()
|
caps = buffer.get_caps ()
|
||||||
#we are interested in it's dimension
|
#we are interested in it's dimension
|
||||||
h, w = caps[0]['height'], caps[0]['width']
|
height, width = caps[0]['height'], caps[0]['width']
|
||||||
#using PIL we grab the image in raw RGB mode from the buffer data
|
#using PIL we grab the image in raw RGB mode from the buffer data
|
||||||
im = Image.frombuffer('RGB', (w, h), buffer.data,
|
im = Image.frombuffer('RGB', (width, height), buffer.data,'raw', 'RGB', 0, 1)
|
||||||
'raw', 'RGB', 0, 1)
|
|
||||||
#here we check the standard variance of a grayscale version of the
|
#here we check the standard variance of a grayscale version of the
|
||||||
#current frame against the BORING_IMAGE_VARIANCE
|
#current frame against the BORING_IMAGE_VARIANCE
|
||||||
if ImageStat.Stat(ImageOps.grayscale(im)).var[0] > \
|
if ImageStat.Stat(ImageOps.grayscale(im)).var[0] > \
|
||||||
|
|
|
@ -6,4 +6,4 @@ available to Controllers. This module is available to both as 'h'.
|
||||||
from webhelpers import *
|
from webhelpers import *
|
||||||
|
|
||||||
# between 0.9.6 and 0.9.7, some things are no longer imported by default
|
# between 0.9.6 and 0.9.7, some things are no longer imported by default
|
||||||
from routes import url_for
|
from pylons.controllers.util import url_for
|
||||||
|
|
|
@ -23,8 +23,8 @@ class Video(Entity):
|
||||||
dc_dateCopyrighted = Field(DateTime)
|
dc_dateCopyrighted = Field(DateTime)
|
||||||
dc_dateSubmitted = Field(DateTime)
|
dc_dateSubmitted = Field(DateTime)
|
||||||
|
|
||||||
dc_identifier = Field(Unicode(255))
|
dc_identifier = Field(Unicode(255)) # URI
|
||||||
dc_source = Field(Unicode(255))
|
dc_source = Field(Unicode(255)) # URI
|
||||||
dc_language = Field(Unicode(3)) # see ISO 639-3
|
dc_language = Field(Unicode(3)) # see ISO 639-3
|
||||||
|
|
||||||
dc_extent = Field(Interval)
|
dc_extent = Field(Interval)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
<h1>Search</h1>
|
<h1>Search</h1>
|
||||||
|
|
||||||
<form action="(h.url_for('search_results'))}" method="get">
|
<form action="${h.url_for('search_results')}" method="get">
|
||||||
|
|
||||||
<input id="query" name="query" type="text"/>
|
<input id="query" name="query" type="text"/>
|
||||||
<input type="submit" value="Search"/>
|
<input type="submit" value="Search"/>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="heading()">
|
<%def name="heading()">
|
||||||
There are over 9000 videos matching "${c.query}".
|
There are ${len(c.results)} videos matching "${c.query}".
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="results_listing(results)">
|
<%def name="results_listing(results)">
|
||||||
|
@ -13,11 +13,12 @@
|
||||||
% for result in c.results:
|
% for result in c.results:
|
||||||
<li>
|
<li>
|
||||||
<a href="${h.url_for('video_page', video=result)}">
|
<a href="${h.url_for('video_page', video=result)}">
|
||||||
<img src="${h.url_for('/images/404.png')}" alt='thumbnail for "${result['title']}"'/>
|
|
||||||
|
<img src="${result['thumbnail']}" alt='thumbnail for "${result['dc_title']}"'/>
|
||||||
</a>
|
</a>
|
||||||
<br />
|
<br />
|
||||||
<a href="${h.url_for('video_page', video=result)}" class="title">
|
<a href="${h.url_for('video_page', video=result)}" class="title">
|
||||||
${result['title']}
|
${result['dc_title']}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
% endfor
|
% endfor
|
||||||
|
|
Loading…
Reference in a new issue