added viewnext and viewprev routes and plumbed these in to the file viewer code. Viewer code now works has a prev/next button, and handles videos
This commit is contained in:
6
TODO
6
TODO
@@ -1,8 +1,9 @@
|
||||
## GENERAL
|
||||
|
||||
* allow rotate of image (permanently on FS, so its right everywhere)
|
||||
* file browser:
|
||||
- maybe back feature/button?
|
||||
|
||||
* improve photo browser -> view file, rather than just allowing browser to show image
|
||||
* allow rotate of image (permanently on FS, so its right everywhere)
|
||||
|
||||
* face locations:
|
||||
START FORM SCRATCH so all images have face_locn data
|
||||
@@ -16,6 +17,7 @@
|
||||
* refimg
|
||||
- remove AI menu from top-level -> make a sub-of Person, and just have Match or AI
|
||||
|
||||
* remove dirs after the duplicate cleanup removes all its content
|
||||
* fix up logging in general
|
||||
* comment your code
|
||||
* more OO goodness :)
|
||||
|
||||
31
files.py
31
files.py
@@ -450,6 +450,37 @@ def move_files():
|
||||
st.SetMessage( f"Created <a href=/job/{job.id}>Job #{job.id}</a> to move selected file(s)")
|
||||
return render_template("base.html")
|
||||
|
||||
@app.route("/viewnext", methods=["GET","POST"])
|
||||
@login_required
|
||||
def viewnext():
|
||||
if request.method=="POST":
|
||||
id = request.form['current']
|
||||
eids=request.form['eids']
|
||||
lst = eids.split(',')
|
||||
new_id = lst[lst.index(id)+1]
|
||||
obj = Entry.query.join(File).filter(Entry.id==new_id).first()
|
||||
return render_template("viewer.html", obj=obj, eids=eids)
|
||||
|
||||
@app.route("/viewprev", methods=["GET","POST"])
|
||||
@login_required
|
||||
def viewprev():
|
||||
if request.method=="POST":
|
||||
id = request.form['current']
|
||||
eids=request.form['eids']
|
||||
lst = eids.split(',')
|
||||
new_id = lst[lst.index(id)-1]
|
||||
obj = Entry.query.join(File).filter(Entry.id==new_id).first()
|
||||
return render_template("viewer.html", obj=obj, eids=eids)
|
||||
|
||||
@app.route("/view/<id>", methods=["GET","POST"])
|
||||
@login_required
|
||||
def view_img(id):
|
||||
obj = Entry.query.join(File).filter(Entry.id==id).first()
|
||||
if request.method=="POST":
|
||||
eids=request.form['eids']
|
||||
else:
|
||||
eids=''
|
||||
return render_template("viewer.html", obj=obj, eids=eids)
|
||||
|
||||
################################################################################
|
||||
# /static -> returns the contents of any file referenced inside /static.
|
||||
|
||||
@@ -111,6 +111,14 @@
|
||||
<input id="offset" type="hidden" name="offset" value="{{offset}}">
|
||||
<input id="size" type="hidden" name="size" value="{{size}}">
|
||||
</div class="form-row">
|
||||
{% set eids=namespace( str="" ) %}
|
||||
{# gather all the file eids and collect them in case we go gallery mode #}
|
||||
{% for obj in entry_data %}
|
||||
{% if obj.type.name != "Directory" %}
|
||||
{% set eids.str = eids.str + obj.id|string +"," %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<input name="eids" id="eids" type="hidden" value="{{eids.str}}">
|
||||
</form>
|
||||
|
||||
{% set last = namespace(printed=0) %}
|
||||
@@ -122,7 +130,7 @@
|
||||
{% if folders and entry_data|length == 0 %}
|
||||
{% if cwd != root %}
|
||||
<figure class="px-1 dir entry" ecnt="1" dir="{{cwd|ParentPath}}">
|
||||
<span style="font-size:{{(size|int-22)/2}}" class="fa-stack">
|
||||
<span style="font-size:{{(size|int-22)/2}}px" class="fa-stack">
|
||||
<i style="color:grey" class="fas fa-folder fa-stack-2x"></i>
|
||||
<i class="fas fa-level-up-alt fa-flip-horizontal fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
@@ -130,7 +138,7 @@
|
||||
</figure class="figure">
|
||||
{% else %}
|
||||
{# create an even lighter-grey, unclickable back button - so folders dont jump around when you go into them #}
|
||||
<span style="font-size:{{(size|int-22)/2}}" class="mx-1 fa-stack">
|
||||
<span style="font-size:{{(size|int-22)/2}}px" class="mx-1 fa-stack">
|
||||
<i style="color:lightgrey" class="fas fa-folder fa-stack-2x"></i>
|
||||
<i class="fas fa-level-up-alt fa-flip-horizontal fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
@@ -140,7 +148,7 @@
|
||||
{% if loop.index==1 and folders %}
|
||||
{% if cwd != root %}
|
||||
<figure class="px-1 dir entry" ecnt="{{loop.index}}" dir="{{cwd|ParentPath}}">
|
||||
<span style="font-size:{{(size|int-22)/2}}" class="fa-stack">
|
||||
<span style="font-size:{{(size|int-22)/2}}px" class="fa-stack">
|
||||
<i style="color:grey" class="fas fa-folder fa-stack-2x"></i>
|
||||
<i class="fas fa-level-up-alt fa-flip-horizontal fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
@@ -148,7 +156,7 @@
|
||||
</figure class="figure">
|
||||
{% else %}
|
||||
{# create an even lighter-grey, unclickable back button - so folders dont jump around when you go into them #}
|
||||
<span style="font-size:{{(size|int-22)/2}}" class="mx-1 fa-stack">
|
||||
<span style="font-size:{{(size|int-22)/2}}px" class="mx-1 fa-stack">
|
||||
<i style="color:lightgrey" class="fas fa-folder fa-stack-2x"></i>
|
||||
<i class="fas fa-level-up-alt fa-flip-horizontal fa-stack-1x fa-inverse"></i>
|
||||
</span>
|
||||
@@ -193,7 +201,7 @@
|
||||
<a href="{{obj.in_dir.in_path.path_prefix}}/{{obj.in_dir.rel_path}}/{{obj.name}}"><img class="thumb" height="{{size}}" src="data:image/jpeg;base64,{{obj.file_details.thumbnail}}"></img></a>
|
||||
{% if search_term is defined %}
|
||||
<div style="position:absolute; bottom: 2; left: 2;">
|
||||
<i style="font-size:16;background-color:black;color:white" class="fas {{LocationIcon(obj)}}"></i>
|
||||
<i style="font-size:16px;background-color:black;color:white" class="fas {{LocationIcon(obj)}}"></i>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -201,11 +209,11 @@
|
||||
<div style="position:relative; width:100%">
|
||||
<a href="{{obj.in_dir.in_path.path_prefix}}/{{obj.in_dir.rel_path}}/{{obj.name}}"><img class="thumb" style="display:block" height="{{size}}" src="data:image/jpeg;base64,{{obj.file_details.thumbnail}}"></img></a>
|
||||
<div style="position:absolute; top: 2; left: 2;">
|
||||
<i style="font-size:32;background-color:black;color:white" class="fas fa-film"></i>
|
||||
<i style="font-size:32px;background-color:black;color:white" class="fas fa-film"></i>
|
||||
</div>
|
||||
{% if search_term is defined %}
|
||||
<div style="position:absolute; bottom: 2; left: 2;">
|
||||
<i style="font-size:16;background-color:black;color:white" class="fas {{LocationIcon(obj)}}"></i>
|
||||
<i style="font-size:16px;background-color:black;color:white" class="fas {{LocationIcon(obj)}}"></i>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -223,7 +231,7 @@
|
||||
{# if this dir is the toplevel of the cwd, show the folder icon #}
|
||||
{% if dirname| TopLevelFolderOf(cwd) %}
|
||||
<figure class="px-1 dir entry" id={{obj.id}} ecnt={{loop.index}} dir="{{dirname}}">
|
||||
<i style="font-size:{{size|int-22}};" class="fas fa-folder"></i>
|
||||
<i style="font-size:{{size|int-22}}px" class="fas fa-folder"></i>
|
||||
<figcaption class="figure-caption text-center text-wrap text-break">{{obj.name}}</figcaption>
|
||||
</figure class="figure">
|
||||
{% endif %}
|
||||
@@ -382,12 +390,12 @@ function ChangeSize(clicked_button,sz)
|
||||
{
|
||||
$('.sz-but.btn-info').removeClass('btn-info').addClass('btn-outline-info')
|
||||
$(clicked_button).addClass('btn-info').removeClass('btn-outline-info')
|
||||
$('.thumb').attr( {height: sz, style: 'font-size:'+sz } )
|
||||
$('.thumb').attr( {height: sz, style: 'font-size:'+sz+'px' } )
|
||||
$('#size').val(sz)
|
||||
sz=sz-22
|
||||
$('.fa-folder').attr( {style: 'font-size:'+sz } )
|
||||
$('.fa-folder').attr( {style: 'font-size:'+sz+'px' } )
|
||||
sz=sz/2
|
||||
$('.fa-stack').attr( {style: 'color:grey;font-size:'+sz} )
|
||||
$('.fa-stack').attr( {style: 'color:grey;font-size:'+sz+'px'} )
|
||||
}
|
||||
|
||||
// e == event (can see if shift/ctrl held down while left-clicking
|
||||
@@ -488,6 +496,13 @@ function NoSel() {
|
||||
$('.figure').click( function(e) { DoSel(e, this ); SetButtonState(); return false; });
|
||||
$(document).on('click', function(e) { $('.highlight').removeClass('highlight') ; SetButtonState() });
|
||||
|
||||
$('.figure').dblclick(
|
||||
function() {
|
||||
s='<form id="_fm" method="POST" action="/view/' + $(this).attr("id");
|
||||
s+='"><input type="hidden" name="eids" value="'+$("#eids").val() + '"></form>'
|
||||
$(s).appendTo('body').submit(); }
|
||||
);
|
||||
|
||||
|
||||
// different context menu on files
|
||||
$.contextMenu({
|
||||
@@ -529,7 +544,11 @@ $.contextMenu({
|
||||
return {
|
||||
callback: function( key, options) {
|
||||
if( key == "details" ) { DetailsDBox() }
|
||||
if( key == "view" ) { document.location.href = $(this).find('a').attr('href'); }
|
||||
if( key == "view" ) {
|
||||
s='<form id="_fm" method="POST" action="/view/' + $(this).attr("id");
|
||||
s+='"><input type="hidden" name="eids" value="'+$("#eids").val() + '"></form>'
|
||||
$(s).appendTo('body').submit();
|
||||
}
|
||||
if( key == "move" ) { MoveDBox() }
|
||||
if( key == "del" ) { DelDBox('Delete') }
|
||||
if( key == "undel" ) { DelDBox('Restore') }
|
||||
|
||||
108
templates/viewer.html
Normal file
108
templates/viewer.html
Normal file
@@ -0,0 +1,108 @@
|
||||
{% extends "base.html" %} {% block main_content %}
|
||||
<script>
|
||||
var gap=0.8
|
||||
|
||||
function NewWidth()
|
||||
{
|
||||
w_r=im.width/(window.innerWidth*gap)
|
||||
h_r=im.height/(window.innerHeight*gap)
|
||||
if( w_r > h_r )
|
||||
return window.innerWidth*gap
|
||||
else
|
||||
return im.width*gap / (im.height/window.innerHeight)
|
||||
}
|
||||
|
||||
function NewHeight()
|
||||
{
|
||||
w_r=im.width/(window.innerWidth*gap)
|
||||
h_r=im.height/(window.innerHeight*gap)
|
||||
if( h_r > w_r )
|
||||
return window.innerHeight*gap
|
||||
else
|
||||
return im.height*gap / (im.width/window.innerWidth)
|
||||
}
|
||||
|
||||
// Define this once and before it will be called, hence at the top of this file
|
||||
function DrawImg()
|
||||
{
|
||||
// another call to this func will occur on load, so skip this one
|
||||
if( im.width == 0 )
|
||||
return
|
||||
|
||||
canvas.width=NewWidth(im)
|
||||
canvas.height=NewHeight(im)
|
||||
|
||||
// actually draw the pixel images to the canvas at the right size
|
||||
context.drawImage(im, 0, 0, canvas.width, canvas.height )
|
||||
|
||||
/* need a for loop
|
||||
context.beginPath();
|
||||
new_x=(orig_face.x/orig_face.orig_w)*img.width/(img.height/canvas.height)
|
||||
new_y=(orig_face.y/orig_face.orig_h)*thumbsize/(img.height/canvas.height)
|
||||
new_w=(orig_face.w/orig_face.orig_w)*img.width/(img.height/canvas.height)
|
||||
new_h=(orig_face.h/orig_face.orig_h)*thumbsize/(img.height/canvas.height)
|
||||
context.rect(new_x, new_y, new_w, new_h)
|
||||
context.lineWidth = 2;
|
||||
context.strokeStyle = 'green';
|
||||
context.stroke();
|
||||
*/
|
||||
}
|
||||
|
||||
function ResizeVideo()
|
||||
{
|
||||
$('#_v').height(window.innerHeight*gap)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="container-fluid">
|
||||
{% set max=eids.split(',')|length %}
|
||||
<br>
|
||||
<center>
|
||||
<input type="hidden" name="eids" value={{eids}}>
|
||||
<div class="form-row col-lg-12">
|
||||
{% if eids.find(obj.id|string) > 0 %}
|
||||
<form id="prev" class="form form-inline" action="/viewprev" method="POST">
|
||||
<input type="hidden" name="current" value="{{obj.id}}">
|
||||
<input type="hidden" name="eids" value="{{eids}}">
|
||||
<button class="btn btn-outline-info h-75" id="la"><i class="fas fa-angle-double-left"></i></button>
|
||||
</form id="prev">
|
||||
{% endif %}
|
||||
{% if obj.type.name == "Image" %}
|
||||
<figure style="border: 1px solid #5bc0de; border-radius: 3px;">
|
||||
<canvas id="canvas"></canvas>
|
||||
<script>
|
||||
var im=new Image();
|
||||
im.onload=DrawImg
|
||||
im.src="/{{obj.in_dir.in_path.path_prefix}}/{{obj.in_dir.rel_path}}/{{obj.name}}"
|
||||
var context = canvas.getContext('2d')
|
||||
window.addEventListener('resize', DrawImg, false);
|
||||
</script>
|
||||
<figcaption class="figure-caption text-center text-wrap text-break">{{obj.name}}</figcaption>
|
||||
</figure>
|
||||
{% elif obj.type.name == "Video" %}
|
||||
<video id="_v" controls>
|
||||
<source src="/{{obj.in_dir.in_path.path_prefix}}/{{obj.in_dir.rel_path}}/{{obj.name}}" type="video/mp4">
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
<script>
|
||||
window.addEventListener('resize', ResizeVideo, false);
|
||||
ResizeVideo()
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% for eid in eids.split(',') %}
|
||||
{% if loop.index == max-1 %}
|
||||
{% if eid|int != obj.id %}
|
||||
<form id="next" class="form form-inline" action="/viewnext" method="POST">
|
||||
<input type="hidden" name="current" value="{{obj.id}}">
|
||||
<input type="hidden" name="eids" value="{{eids}}">
|
||||
<button class="btn btn-outline-info h-75" id="ra"><i class="fas fa-angle-double-right"></i></button>
|
||||
</form id="next">
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div id="/form-row">
|
||||
</div class="form-row col-lg-12">
|
||||
</center>
|
||||
</div class="container">
|
||||
{% endblock main_content %}
|
||||
Reference in New Issue
Block a user