added text previews, bug fixes

This commit is contained in:
Alexander Karpov 2023-04-13 14:41:04 +03:00
parent d4f68935a1
commit 4966884646
13 changed files with 302 additions and 16 deletions

View File

@ -1,6 +1,9 @@
from . import audio, image, video
from . import application, audio, image, text, video
previews = {
"application": {
"zip": application.zip.view,
},
"audio": {
"aac": audio.basic.view,
"mpeg": audio.basic.view,
@ -14,12 +17,19 @@
"jpeg": image.basic.view,
"png": image.basic.view,
"avif": image.basic.view,
"bmp": image.basic.view,
},
"text": {"css": text.common.view, "plain": text.plain.view},
}
source_code = {}
for ext in text.common.language_previews.keys():
source_code[ext] = text.common.view
extensions = {
"mp4": video.mp4.view,
"mp3": audio.basic.view,
"avif": image.basic.view,
"bmp": image.basic.view,
"mov": video.basic.view,
}
} | source_code

View File

@ -0,0 +1 @@
from . import zip # noqa

View File

@ -0,0 +1,141 @@
import zipfile
from collections import defaultdict
from akarpov.files.models import File
FILE_MARKER = "<files>"
def attach(branch, trunk):
"""
Insert a branch of directories on its trunk.
"""
parts = branch.split("/", 1)
if len(parts) == 1: # branch is a file
trunk[FILE_MARKER].append(parts[0])
else:
node, others = parts
if node not in trunk:
trunk[node] = defaultdict(dict, ((FILE_MARKER, []),))
attach(others, trunk[node])
def to_li(d, indent=0):
"""
Convert tree like structure to html ul li
"""
res = ""
for key, value in d.items():
if key != FILE_MARKER:
if indent >= 2 or str(key).startswith("."):
in_res = (
"""
<li data-jstree='{ "opened" : false }'>
"""
+ str(key)
+ "<ul>"
)
else:
in_res = (
"""
<li data-jstree='{ "opened" : true }'>
"""
+ str(key)
+ "<ul>"
)
r_res = ""
c_res = """</ul></li>"""
if isinstance(value, dict):
r_res += to_li(value, indent + 1)
else:
if value is not str and isinstance(value, list):
for v in value:
if v:
r_res += (
"""<li data-jstree='{ "opened" : true, "type" : "file" }'>"""
+ str(v)
+ "</li>"
)
else:
if value:
r_res += (
"""<li data-jstree='{ "opened" : true, "type" : "file" }'>"""
+ str(value)
+ "</li>"
)
res += in_res + r_res + c_res
else:
if value is not str and isinstance(value, list):
for v in value:
if v:
res += (
"""<li data-jstree='{ "opened" : true, "type" : "file" }'>"""
+ str(v)
+ "</li>"
)
else:
if value:
res += (
"""<li data-jstree='{ "opened" : true, "type" : "file" }'>"""
+ str(value)
+ "</li>"
)
return res
def view(file: File) -> (str, str):
zip = zipfile.ZipFile(file.file.path)
root = defaultdict(dict, ((FILE_MARKER, []),))
for line in zip.namelist():
attach(line, root)
r = str(to_li(root))
static = """
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />
"""
content = (
"""
<div id="jstree_demo_div">
<ul data-jstree='{ "opened" : true }>"""
+ f"""
{file.file.path.split("/")[-1]}
"""
+ """
<li data-jstree='{ "opened" : true }>
"""
+ f"""
{r}
</li>
</ul>
</div> """
+ """
<script src="/static/js/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
<script>
$(function () {
$('#jstree_demo_div').jstree({
"core" : {
"themes" : {
"responsive": false
}
},
"types" : {
"default" : {
"icon" : "bi bi-folder"
},
"file" : {
"icon" : "bi bi-file-earmark-fill"
}
},
"plugins": ["types"]
});
});
</script>
"""
)
return static, content

View File

@ -13,7 +13,7 @@ def view(file: File) -> (str, str):
</div>
<div id="images">
</div
<script src="/static/js/jquery.js"></script>
<script src="/static/js/jquery.min.js"></script>
"""
+ """
<script src="https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.3/viewer.min.js">

View File

@ -0,0 +1 @@
from . import common, plain # noqa

View File

@ -0,0 +1,64 @@
import html
from akarpov.files.models import File
language_previews = {
"jsx": "javascript",
"js": "javascript",
"tsx": "typescript",
"ts": "typescript",
"css": "css",
"py": "python",
"go": "go",
"java": "java",
"php": "php",
"cs": "csharp",
"swift": "swift",
"r": "r",
"rb": "ruby",
"c": "c",
"cpp": "cpp",
"mlx": "matlab",
"scala": "scala",
"sc": "scala",
"sql": "sql",
"html": "html",
"rs": "rust",
"pl": "perl",
"PL": "perl",
}
def view(file: File) -> (str, str):
extension = file.file.path.split(".")[-1]
if extension in language_previews:
extension = language_previews[extension]
static = f"""
<meta property="og:title" content="{file.name}" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-light.min.css">
"""
content = "<pre>"
with file.file.open("r") as f:
lines = f.readlines()
for line in lines:
content += (
f"""<div class='code language-{extension}'>{html.escape(line)}</div>"""
)
content += (
"""</pre>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
"""
+ f"""
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/{extension}.min.js"></script>
"""
+ """
<script>
hljs.configure({ ignoreUnescapedHTML: true })
document.querySelectorAll('div.code').forEach(el => {
hljs.highlightElement(el);
});
</script>
"""
)
return static, content

View File

@ -0,0 +1,23 @@
import html
from akarpov.files.models import File
from akarpov.files.previews import text
from akarpov.files.previews.text.common import language_previews
def view(file: File) -> (str, str):
extension = file.file.path.split(".")[-1]
if hasattr(text, extension):
return getattr(text, extension).view(file)
elif extension in language_previews:
return text.common.view(file)
static = f"""
<meta property="og:title" content="{file.name}" />
"""
content = "<pre>"
with file.file.open("r") as f:
lines = f.readlines()
for line in lines:
content += f"""<div class='code language-plaintext'>{html.escape(line)}</div>"""
content += "</pre>"
return static, content

View File

@ -5,7 +5,7 @@ def view(file: File) -> (str, str):
static = f"""
<meta property="og:title" content="{file.name}" />
<meta property="og:type" content="video.movie" />
<meta property="og:video" content="dev2.akarpov.ru/{file.file.url}" />
<meta property="og:video" content="{file.file.url}" />
<meta property="og:video:type" content="{file.file_type}" />
<meta property="og:video:width" content="720" />
<meta property="og:video:height" content="480" />

View File

@ -43,15 +43,15 @@ def get_context_data(self, **kwargs):
static = ""
content = ""
if self.object.file_type:
if self.object.file_type == "application/octet-stream":
extension = self.object.file.path.split(".")[-1]
if extension in extensions:
static, content = extensions[extension](self.object)
else:
t1, t2 = self.object.file_type.split("/")
if t1 in previews:
if t2 in previews[t1]:
static, content = previews[t1][t2](self.object)
t1, t2 = self.object.file_type.split("/")
extension = self.object.file.path.split(".")[-1]
loaded = False
if t1 in previews:
if t2 in previews[t1]:
static, content = previews[t1][t2](self.object)
loaded = True
if not loaded and extension in extensions:
static, content = extensions[extension](self.object)
context["preview_static"] = static
context["preview_content"] = content
return context

View File

@ -0,0 +1,44 @@
/* Tomorrow Night Eighties Theme */
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
/* https://jmblog.github.io/color-themes-for-google-code-highlightjs */
.tomorrow-comment, pre .comment, pre .title {
color: #999999;
}
.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo {
color: #f2777a;
}
.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant {
color: #f99157;
}
.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute {
color: #ffcc66;
}
.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata {
color: #99cc99;
}
.tomorrow-aqua, pre .css .hexcolor {
color: #66cccc;
}
.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title {
color: #6699cc;
}
.tomorrow-purple, pre .keyword, pre .javascript .function {
color: #cc99cc;
}
pre code {
display: block;
background: #2d2d2d;
color: #cccccc;
font-family: Menlo, Monaco, Consolas, monospace;
line-height: 1.5;
border: 1px solid #ccc;
padding: 10px;
}

2
akarpov/static/js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@
{% load humanize static %}
{% block javascript %}
<script src="{% static 'js/jquery.js' %}"></script>
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/jquery.ui.widget.js' %}"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="{% static 'js/jquery.iframe-transport.js' %}"></script>
@ -36,7 +36,7 @@
{% for folder in folders %}
{{ folder.name }}
{% endfor %}
<div class="row">
<div class="row justify-content-center">
<div class="col-lg-2 col-xxl-2 col-md-4 col-sm-6 col-xs-12 mb-3 m-3 d-flex align-items-stretch card">
<div class="card-body d-flex flex-column justify-content-center align-items-center">
{% csrf_token %}

View File

@ -2,7 +2,7 @@
{% load static %}
{% block javascript %}
<script src="{% static 'js/jquery.js' %}"></script>
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/jquery.ui.widget.js' %}"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="{% static 'js/jquery.iframe-transport.js' %}"></script>