mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-25 08:13:44 +03:00
added audio, video previews, fixed image previews
This commit is contained in:
parent
8a995a8ca5
commit
e7d78d59ec
|
@ -1,3 +1,20 @@
|
|||
from . import image, video
|
||||
from . import audio, image, video
|
||||
|
||||
previews = {"video": {"mp4": video.mp4.view}, "image": {"jpeg": image.jpeg.view}}
|
||||
previews = {
|
||||
"audio": {
|
||||
"aac": audio.basic.view,
|
||||
"mpeg": audio.basic.view,
|
||||
"ogg": audio.basic.view,
|
||||
"opus": audio.basic.view,
|
||||
"wav": audio.basic.view,
|
||||
"webm": audio.basic.view,
|
||||
},
|
||||
"video": {"mp4": video.mp4.view},
|
||||
"image": {
|
||||
"jpeg": image.basic.view,
|
||||
"png": image.basic.view,
|
||||
"avif": image.basic.view,
|
||||
},
|
||||
}
|
||||
|
||||
extensions = {"mp4": video.mp4.view, "mp3": audio.basic.view, "avif": image.basic.view}
|
||||
|
|
1
akarpov/files/previews/audio/__init__.py
Normal file
1
akarpov/files/previews/audio/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
from . import basic # noqa
|
61
akarpov/files/previews/audio/basic.py
Normal file
61
akarpov/files/previews/audio/basic.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
from akarpov.files.models import File
|
||||
|
||||
|
||||
def view(file: File) -> (str, str):
|
||||
static = """
|
||||
"""
|
||||
content = (
|
||||
"""
|
||||
<div id="waveform">
|
||||
</div>
|
||||
<div id="wave-timeline"> </div>
|
||||
|
||||
<div class="controls mt-4 d-flex align-items-center justify-content-center text-center">
|
||||
<button class="btn btn-primary" data-action="play">
|
||||
<i class="glyphicon glyphicon-play"></i>
|
||||
Play
|
||||
/
|
||||
<i class="glyphicon glyphicon-pause"></i>
|
||||
Pause
|
||||
</button>
|
||||
</div>
|
||||
<script src="https://unpkg.com/wavesurfer.js@6.6.3/dist/wavesurfer.js"></script>
|
||||
<script src="https://unpkg.com/wavesurfer.js@6.6.3/dist/plugin/wavesurfer.timeline.min.js"></script>
|
||||
<script src="https://unpkg.com/wavesurfer.js@6.6.3/dist/plugin/wavesurfer.regions.min.js"></script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
wavesurfer = WaveSurfer.create({
|
||||
container: document.querySelector('#waveform'),
|
||||
waveColor: '#D9DCFF',
|
||||
progressColor: '#4353FF',
|
||||
cursorColor: '#4353FF',
|
||||
barWidth: 3,
|
||||
barRadius: 3,
|
||||
cursorWidth: 1,
|
||||
height: 200,
|
||||
barGap: 3,
|
||||
plugins: [
|
||||
WaveSurfer.regions.create({}),
|
||||
WaveSurfer.timeline.create({
|
||||
container: "#wave-timeline"
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
wavesurfer.on('error', function(e) {
|
||||
console.warn(e);
|
||||
});
|
||||
"""
|
||||
+ f"""
|
||||
wavesurfer.load('{file.file.url}');
|
||||
"""
|
||||
+ """
|
||||
document
|
||||
.querySelector('[data-action="play"]')
|
||||
.addEventListener('click', wavesurfer.playPause.bind(wavesurfer));
|
||||
}
|
||||
</script>
|
||||
"""
|
||||
)
|
||||
|
||||
return static, content
|
102
akarpov/files/previews/audio/waves.py
Normal file
102
akarpov/files/previews/audio/waves.py
Normal file
|
@ -0,0 +1,102 @@
|
|||
from akarpov.files.models import File
|
||||
|
||||
|
||||
def view(file: File) -> (str, str):
|
||||
static = """
|
||||
<style>
|
||||
#canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
"""
|
||||
content = (
|
||||
"""
|
||||
<div id="container">
|
||||
<canvas id="canvas"></canvas>
|
||||
<audio id="audio"></audio>
|
||||
</div>
|
||||
"""
|
||||
+ """
|
||||
<script>
|
||||
const container = document.getElementById("container");
|
||||
container.addEventListener("click", function () {
|
||||
let audio1 = new Audio();
|
||||
"""
|
||||
+ f"""
|
||||
audio1.src = "{file.file.url}";
|
||||
"""
|
||||
+ """
|
||||
audio1.crossOrigin = "anonymous";
|
||||
const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); // for safari browser
|
||||
|
||||
const container = document.getElementById("container");
|
||||
const canvas = document.getElementById("canvas");
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
let audioSource = null;
|
||||
let analyser = null;
|
||||
|
||||
audio1.play();
|
||||
audioSource = audioCtx.createMediaElementSource(audio1);
|
||||
analyser = audioCtx.createAnalyser();
|
||||
audioSource.connect(analyser);
|
||||
analyser.connect(audioCtx.destination);
|
||||
analyser.fftSize = 128;
|
||||
const bufferLength = analyser.frequencyBinCount;
|
||||
const dataArray = new Uint8Array(bufferLength);
|
||||
|
||||
const barWidth = canvas.width / 2 / bufferLength;
|
||||
|
||||
let x = 0;
|
||||
|
||||
function animate() {
|
||||
x = 0;
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height); // clears the canvas
|
||||
analyser.getByteFrequencyData(dataArray);
|
||||
drawVisualizer({ bufferLength, dataArray, barWidth });
|
||||
requestAnimationFrame(animate); // calls the animate function again. This method is built in
|
||||
}
|
||||
|
||||
const drawVisualizer = ({ bufferLength, dataArray, barWidth }) => {
|
||||
let barHeight;
|
||||
for (let i = 0; i < bufferLength; i++) {
|
||||
barHeight = dataArray[i];
|
||||
const red = (i * barHeight) / 10;
|
||||
const green = i * 4;
|
||||
const blue = barHeight / 4 - 12;
|
||||
ctx.fillStyle = `rgb(${red}, ${green}, ${blue})`;
|
||||
ctx.fillRect(
|
||||
canvas.width / 2 - x, // this will start the bars at the center of the canvas and move from right to left
|
||||
canvas.height - barHeight,
|
||||
barWidth,
|
||||
barHeight
|
||||
);
|
||||
x += barWidth; // increases the x value by the width of the bar
|
||||
}
|
||||
|
||||
for (let i = 0; i < bufferLength; i++) {
|
||||
barHeight = dataArray[i];
|
||||
const red = (i * barHeight) / 10;
|
||||
const green = i * 4;
|
||||
const blue = barHeight / 4 - 12;
|
||||
ctx.fillStyle = `rgb(${red}, ${green}, ${blue})`;
|
||||
ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
|
||||
x += barWidth; // increases the x value by the width of the bar
|
||||
}
|
||||
};
|
||||
|
||||
animate();
|
||||
});
|
||||
|
||||
</script>
|
||||
"""
|
||||
)
|
||||
|
||||
return static, content
|
|
@ -1 +1 @@
|
|||
from . import jpeg # noqa
|
||||
from . import basic # noqa
|
||||
|
|
|
@ -10,6 +10,8 @@ def view(file: File) -> (str, str):
|
|||
<div>
|
||||
<img id="image" class="img-fluid" src="{file.file.url}" alt="Picture">
|
||||
</div>
|
||||
<div id="images">
|
||||
</div
|
||||
<script src="/static/js/jquery.js"></script>
|
||||
"""
|
||||
+ """
|
||||
|
@ -23,10 +25,7 @@ def view(file: File) -> (str, str):
|
|||
}
|
||||
});
|
||||
|
||||
// Get the Viewer.js instance after initialized
|
||||
var viewer = $image.data('viewer');
|
||||
|
||||
// View a list of images
|
||||
$('#images').viewer();
|
||||
</script>
|
||||
"""
|
|
@ -9,7 +9,7 @@ def view(file: File) -> (str, str):
|
|||
content = f"""
|
||||
|
||||
<video id="my_video_1" class="video-js vjs-default-skin" height="500px"
|
||||
controls poster='{file.preview.url}'
|
||||
controls poster='{file.preview.url if file.preview else ''}'
|
||||
data-setup='{data}'>
|
||||
<source src="{file.file.url}" type='video/mp4' />
|
||||
</video>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
ChunkedUploadView,
|
||||
)
|
||||
from akarpov.files.models import File, Folder
|
||||
from akarpov.files.previews import previews
|
||||
from akarpov.files.previews import extensions, previews
|
||||
|
||||
|
||||
class TopFolderView(LoginRequiredMixin, ListView):
|
||||
|
@ -41,10 +41,15 @@ def get_context_data(self, **kwargs):
|
|||
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)
|
||||
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)
|
||||
context["preview_static"] = static
|
||||
context["preview_content"] = content
|
||||
return context
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
{% block content %}
|
||||
<div class="row m-2">
|
||||
<div class="col-auto">
|
||||
<div class="col-md-4 col-sm-6">
|
||||
<h1 class="fs-1">{{ file.name }}</h1>
|
||||
{% if not has_perm %}
|
||||
<p>Uploaded by: <a href="{% url 'users:detail' file.user.username %}">
|
||||
|
@ -24,7 +24,7 @@
|
|||
<p>{{ file.description }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="col-md-8 col-sm-10">
|
||||
{% autoescape off %}
|
||||
{{ preview_content }}
|
||||
{% endautoescape %}
|
||||
|
|
|
@ -7,4 +7,4 @@ dpkg -i draw.io-amd64-13.0.3.deb
|
|||
rm draw.io-amd64-13.0.3.deb
|
||||
apt-get purge -y --auto-remove -o APT:AutoRemove:RecommendsImportant=false && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
preview --check-dependencies``
|
||||
preview --check-dependencies
|
||||
|
|
Loading…
Reference in New Issue
Block a user