mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-25 17:33:44 +03:00
added file previews, file page
This commit is contained in:
parent
a30f402f18
commit
8a995a8ca5
3
akarpov/files/previews/__init__.py
Normal file
3
akarpov/files/previews/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from . import image, video
|
||||||
|
|
||||||
|
previews = {"video": {"mp4": video.mp4.view}, "image": {"jpeg": image.jpeg.view}}
|
1
akarpov/files/previews/image/__init__.py
Normal file
1
akarpov/files/previews/image/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from . import jpeg # noqa
|
35
akarpov/files/previews/image/jpeg.py
Normal file
35
akarpov/files/previews/image/jpeg.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
from akarpov.files.models import File
|
||||||
|
|
||||||
|
|
||||||
|
def view(file: File) -> (str, str):
|
||||||
|
static = """
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.css" rel="stylesheet">
|
||||||
|
"""
|
||||||
|
content = (
|
||||||
|
f"""
|
||||||
|
<div>
|
||||||
|
<img id="image" class="img-fluid" src="{file.file.url}" alt="Picture">
|
||||||
|
</div>
|
||||||
|
<script src="/static/js/jquery.js"></script>
|
||||||
|
"""
|
||||||
|
+ """
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js">
|
||||||
|
var $image = $('#image');
|
||||||
|
|
||||||
|
$image.viewer({
|
||||||
|
inline: true,
|
||||||
|
viewed: function() {
|
||||||
|
$image.viewer('zoomTo', 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get the Viewer.js instance after initialized
|
||||||
|
var viewer = $image.data('viewer');
|
||||||
|
|
||||||
|
// View a list of images
|
||||||
|
$('#images').viewer();
|
||||||
|
</script>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
return static, content
|
1
akarpov/files/previews/video/__init__.py
Normal file
1
akarpov/files/previews/video/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from . import mp4 # noqa
|
20
akarpov/files/previews/video/mp4.py
Normal file
20
akarpov/files/previews/video/mp4.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
from akarpov.files.models import File
|
||||||
|
|
||||||
|
|
||||||
|
def view(file: File) -> (str, str):
|
||||||
|
static = """
|
||||||
|
<link href="https://vjs.zencdn.net/8.0.4/video-js.css" rel="stylesheet" />
|
||||||
|
"""
|
||||||
|
data = """"playbackRates": [0.5, 1, 1.5, 2], "responsive": true }"""
|
||||||
|
content = f"""
|
||||||
|
|
||||||
|
<video id="my_video_1" class="video-js vjs-default-skin" height="500px"
|
||||||
|
controls poster='{file.preview.url}'
|
||||||
|
data-setup='{data}'>
|
||||||
|
<source src="{file.file.url}" type='video/mp4' />
|
||||||
|
</video>
|
||||||
|
|
||||||
|
<script src="https://vjs.zencdn.net/8.0.4/video.min.js"></script>
|
||||||
|
"""
|
||||||
|
|
||||||
|
return static, content
|
|
@ -84,7 +84,8 @@ def create_preview(file_path: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
def get_file_mimetype(file_path: str) -> str:
|
def get_file_mimetype(file_path: str) -> str:
|
||||||
return magic.from_file(file_path)
|
mime = magic.Magic(mime=True)
|
||||||
|
return mime.from_file(file_path)
|
||||||
|
|
||||||
|
|
||||||
def get_description(file_path: str) -> str:
|
def get_description(file_path: str) -> str:
|
||||||
|
|
|
@ -31,7 +31,7 @@ def process_file(pk: int):
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
file.type = get_file_mimetype(file.file.path)
|
file.file_type = get_file_mimetype(file.file.path)
|
||||||
descr = None
|
descr = None
|
||||||
try:
|
try:
|
||||||
descr = get_description(file.file.path)
|
descr = get_description(file.file.path)
|
||||||
|
|
|
@ -11,10 +11,12 @@
|
||||||
ChunkedUploadView,
|
ChunkedUploadView,
|
||||||
)
|
)
|
||||||
from akarpov.files.models import File, Folder
|
from akarpov.files.models import File, Folder
|
||||||
|
from akarpov.files.previews import previews
|
||||||
|
|
||||||
|
|
||||||
class TopFolderView(LoginRequiredMixin, ListView):
|
class TopFolderView(LoginRequiredMixin, ListView):
|
||||||
template_name = "files/list.html"
|
template_name = "files/list.html"
|
||||||
|
paginate_by = 20
|
||||||
model = File
|
model = File
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
@ -33,6 +35,20 @@ class FileView(DetailView):
|
||||||
model = File
|
model = File
|
||||||
slug_field = "slug"
|
slug_field = "slug"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context["has_perm"] = self.object.user == self.request.user
|
||||||
|
static = ""
|
||||||
|
content = ""
|
||||||
|
if self.object.file_type:
|
||||||
|
t1, t2 = self.object.file_type.split("/")
|
||||||
|
if t1 in previews:
|
||||||
|
if t2 in previews[t1]:
|
||||||
|
static, content = previews[t1][t2](self.object)
|
||||||
|
context["preview_static"] = static
|
||||||
|
context["preview_content"] = content
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
files_view = FileView.as_view()
|
files_view = FileView.as_view()
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
</li>
|
</li>
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'files:main' %}" class="{% active_link 'files' %} text-muted nav-link px-sm-0 px-2">
|
<a href="{% url 'files:main' %}" class="{% active_link 'files:main' %} text-muted nav-link px-sm-0 px-2">
|
||||||
<i class="fs-5 bi-folder-fill"></i><span class="ms-1 d-none d-sm-inline">Files</span></a>
|
<i class="fs-5 bi-folder-fill"></i><span class="ms-1 d-none d-sm-inline">Files</span></a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -57,8 +57,8 @@
|
||||||
</symbol>
|
</symbol>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
<p class="text-break" id="progress-message"></p>
|
||||||
<div id="progress" class="progress w-100" style="display: none" role="progressbar" aria-label="Warning example" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
|
<div id="progress" class="progress w-100" style="display: none" role="progressbar" aria-label="Warning example" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
|
||||||
<h1 id="progress-message"></h1>
|
|
||||||
<div id="progress-bar" class="progress-bar text-bg-warning" style="width: 0%">0%</div>
|
<div id="progress-bar" class="progress-bar text-bg-warning" style="width: 0%">0%</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="messages"></div>
|
<div id="messages"></div>
|
||||||
|
@ -72,11 +72,36 @@
|
||||||
<div class="align-self-stretch align-items-center justify-content-center d-flex flex-column fill-height controlsdiv">
|
<div class="align-self-stretch align-items-center justify-content-center d-flex flex-column fill-height controlsdiv">
|
||||||
<img src="{{ file.file_image_url }}" class="img-fluid" alt="">
|
<img src="{{ file.file_image_url }}" class="img-fluid" alt="">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<a href="{% url 'files:view' file.slug %}" class="stretched-link"></a>
|
||||||
<p class="card-text mb-4 mt-2 ms-3"><small class="text-muted">{{ file.modified | naturaltime }}</small></p>
|
<p class="card-text mb-4 mt-2 ms-3"><small class="text-muted">{{ file.modified | naturaltime }}</small></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
{% if page_obj.has_other_pages %}
|
||||||
|
<div class="btn-group" role="group" aria-label="Item pagination">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<a href="?page={{ page_obj.previous_page_number }}" class="btn btn-outline-warning">«</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for page_number in page_obj.paginator.page_range %}
|
||||||
|
{% if page_obj.number == page_number %}
|
||||||
|
<button class="btn btn-outline-warning active">
|
||||||
|
<span>{{ page_number }} <span class="sr-only">(current)</span></span>
|
||||||
|
</button>
|
||||||
|
{% else %}
|
||||||
|
<a href="?page={{ page_number }}" class="btn btn-outline-warning">
|
||||||
|
{{ page_number }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<a href="?page={{ page_obj.next_page_number }}" class="btn btn-outline-warning">»</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block inline_javascript %}
|
{% block inline_javascript %}
|
||||||
|
@ -157,15 +182,14 @@
|
||||||
add: function(e, data) { // Called before starting upload
|
add: function(e, data) { // Called before starting upload
|
||||||
if (cur !== true){
|
if (cur !== true){
|
||||||
cur = true
|
cur = true
|
||||||
console.log("add", data.files[0])
|
|
||||||
form_data.splice(1);
|
form_data.splice(1);
|
||||||
calculate_md5(data.files[0], 1000000);
|
calculate_md5(data.files[0], 1000000);
|
||||||
data.submit();
|
data.submit();
|
||||||
$("#progress").css("display", "flex");
|
$("#progress").css("display", "flex");
|
||||||
|
$("#progress-message").text("loading file: " + data.files[0].name);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
chunkdone: function (e, data) { // Called after uploading each chunk
|
chunkdone: function (e, data) { // Called after uploading each chunk
|
||||||
console.log("chunkdone", data.files[0])
|
|
||||||
if (form_data.length < 2) {
|
if (form_data.length < 2) {
|
||||||
form_data.push(
|
form_data.push(
|
||||||
{"name": "upload_id", "value": data.result.upload_id}
|
{"name": "upload_id", "value": data.result.upload_id}
|
||||||
|
@ -177,7 +201,10 @@
|
||||||
sel.text(progress + "%");
|
sel.text(progress + "%");
|
||||||
},
|
},
|
||||||
done: function (e, data) { // Called when the file has completely uploaded
|
done: function (e, data) { // Called when the file has completely uploaded
|
||||||
console.log("done", data.files[0])
|
var progress = 100;
|
||||||
|
let sel = $("#progress-bar");
|
||||||
|
sel.css("width", progress + "%");
|
||||||
|
sel.text(progress + "%");
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
url: "{% url 'files:api_chunked_upload_complete' %}",
|
url: "{% url 'files:api_chunked_upload_complete' %}",
|
||||||
|
|
33
akarpov/templates/files/view.html
Normal file
33
akarpov/templates/files/view.html
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block javascript %}
|
||||||
|
{% autoescape off %}
|
||||||
|
{{ preview_static }}
|
||||||
|
{% endautoescape %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row m-2">
|
||||||
|
<div class="col-auto">
|
||||||
|
<h1 class="fs-1">{{ file.name }}</h1>
|
||||||
|
{% if not has_perm %}
|
||||||
|
<p>Uploaded by: <a href="{% url 'users:detail' file.user.username %}">
|
||||||
|
{% if file.user.image_cropped %}<img class="rounded" width="20" src="{{ file.user.image_cropped.url }}" alt=""> {% endif %}
|
||||||
|
{{ file.user.username }}</a></p>
|
||||||
|
{% endif %}
|
||||||
|
<p class="mt-2">Last updated: {{ file.modified|date:"d.m.Y" }} {{ file.modified|time:"H:i" }}</p>
|
||||||
|
<p>File size: {{ file.file_size | filesizeformat }}</p>
|
||||||
|
{% if file.file_type %}
|
||||||
|
<p>File type: {{ file.file_type }}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% if file.description %}
|
||||||
|
<p>{{ file.description }}</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
{% autoescape off %}
|
||||||
|
{{ preview_content }}
|
||||||
|
{% endautoescape %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user