This commit is contained in:
Pierre Guillod 2023-08-03 11:41:26 +02:00
parent d81b69a2f1
commit ca5215827e
8 changed files with 1102 additions and 107 deletions

View file

@ -1,6 +1,8 @@
FROM php:8.0-apache FROM php:apache-bookworm AS php-ffmpeg
RUN apt-get update && apt-get -y install ffmpeg
FROM php-ffmpeg
WORKDIR /var/www WORKDIR /var/www
COPY src/ html/ COPY src/ html/
RUN mkdir uploads && chown -R www-data:www-data uploads RUN mkdir uploads && chown -R www-data:www-data uploads
RUN apt-get update && apt-get -y install ffmpeg
EXPOSE 80/tcp EXPOSE 80/tcp

View file

@ -3,6 +3,9 @@
<head> <head>
<link rel="stylesheet" href="css/pico.min.css"> <link rel="stylesheet" href="css/pico.min.css">
<style>
button {all: unset !important; cursor: pointer !important;}
</style>
</head> </head>
<body> <body>
@ -14,31 +17,348 @@
</hgroup> </hgroup>
</header> </header>
<main class="container"> <form action="upload.php" method="post" enctype="multipart/form-data">
<form action="upload.php" method="post" enctype="multipart/form-data">
<main class="container">
<input id="picker" type="file" name="file"> <input id="picker" type="file" name="file">
<div id="buttons" class="grid"></div>
</form> <article id="audfxs" style="display: none;"><details><summary>Filters</summary>
</main>
<details role="list">
<summary aria-haspopup="listbox">Effects</summary>
<ul role="listbox">
<li>
<label>
<input type="checkbox" name="tremolo" value="tremolo">
Add Tremolo
</label>
</li>
<li>
<label>
<input type="checkbox" name="vibrato" value="vibrato">
Add Vibrato
</label>
</li>
<li>
<label>
<input type="checkbox" name="speechnorm" value="speechnorm">
Normalize Speech
</label>
</li>
<li>
<label>
<input type="checkbox" name="loudnorm" value="loudnorm">
Normalize Loudness
</label>
</li>
<li>
<label>
<input type="checkbox" name="extrastereo" value="extrastereo">
Boost stereo
</label>
</li>
<li>
<label>
<input type="checkbox" name="asubboost" value="asubboost">
Boost subwoofer
</label>
</li>
<li>
<label>
<input type="checkbox" name="dialoguenhance" value="dialoguenhance">
Enhance dialogue
</label>
</li>
<li>
<label>
<input type="checkbox" name="earwax" value="earwax">
Enhance headhpones (Earwax)
</label>
</li>
<li>
<label>
<input type="checkbox" name="bs2b" value="bs2b">
Enhance headhpones (Bauer)
</label>
</li>
<li>
<label>
<input type="checkbox" name="flanger" value="flanger">
Flanging effect
</label>
</li>
<li>
<label>
<input type="checkbox" name="aphaser" value="aphaser">
Phaser effect
</label>
</li>
<li>
<label>
<input type="checkbox" name="anlmdn" value="anlmdn">
Denoise
</label>
</li>
<li>
<label>
<input type="checkbox" name="crystalizer" value="crystalizer">
Sharpen Noise
</label>
</li>
</ul>
</details>
<details role="list">
<summary aria-haspopup="listbox">Echo</summary>
<ul role="listbox">
<li>
<label for="echo-none">
<input id="echo-none" type="radio" name="echo" value="none" checked>
None
</label>
</li>
<li>
<label for="echo-two">
<input id="echo-two" type="radio" name="echo" value="two">
Two instruments
</label>
</li>
<li>
<label for="echo-robot">
<input id="echo-robot" type="radio" name="echo" value="robot">
Like a robot
</label>
</li>
<li>
<label for="echo-mountains">
<input id="echo-mountains" type="radio" name="echo" value="mountains">
In the mountains
</label>
</li>
<li>
<label for="echo-more">
<input id="echo-more" type="radio" name="echo" value="more">
More mountains
</label>
</li>
</ul>
</details>
</details></article>
<article id="picfxs" style="display: none;"><details><summary>Filters</summary>
<details role="list">
<summary aria-haspopup="listbox">Rotate & Flip</summary>
<ul role="listbox">
<li>
<label for="transforms-none">
<input id="transforms-none" type="radio" name="transforms" value="none" checked>
None
</label>
</li>
<li>
<label for="transforms-hflip">
<input id="transforms-hflip" type="radio" name="transforms" value="hflip">
Flip horizontally
</label>
</li>
<li>
<label for="transforms-vflip">
<input id="transforms-vflip" type="radio" name="transforms" value="vflip">
Flip vertically
</label>
</li>
<li>
<label for="transforms-clkrot">
<input id="transforms-clkrot" type="radio" name="transforms" value="clkrot">
Rotate 90° clockwise
</label>
</li>
<li>
<label for="transforms-aclkrot">
<input id="transforms-aclkrot" type="radio" name="transforms" value="aclkrot">
Rotate 90° anticlockwise
</label>
</li>
<li>
<label for="transforms-reverse">
<input id="transforms-reverse" type="radio" name="transforms" value="reverse">
Rotate 180°
</label>
</li>
</ul>
</details>
<details role="list">
<summary aria-haspopup="listbox">Effects</summary>
<ul role="listbox">
<li>
<label>
<input type="checkbox" name="blur" value="blur">
Blur
</label>
</li>
<li>
<label>
<input type="checkbox" name="pixelize" value="pixelize">
Pixelize
</label>
</li>
<li>
<label>
<input type="checkbox" name="vignette" value="vignette">
Vignette
</label>
</li>
</ul>
</details>
<details role="list">
<summary aria-haspopup="listbox">Colorization</summary>
<ul role="listbox">
<li>
<label for="colorize-none">
<input id="colorize-none" type="radio" name="colorize" value="none" checked>
None
</label>
</li>
<li>
<label for="colorize-bw">
<input id="colorize-bw" type="radio" name="colorize" value="bw">
Black & White
</label>
</li>
<li>
<label for="colorize-sepia">
<input id="colorize-sepia" type="radio" name="colorize" value="sepia">
Sepia
</label>
</li>
</ul>
</details>
</details></article>
<article id="options" style="display: none;"></article>
</main>
</form>
<script> <script>
document.getElementById('picker').addEventListener('change', function(e) { document.getElementById('picker').addEventListener('change', function(e) {
if (e.target.files[0]) { if (e.target.files[0]) {
fetch('json/conversions.json') const extension = e.target.files[0].name.split('.').pop();
let optionsPath = "";
switch (extension) {
case "flac":
case "ogg":
case "oga":
case "mka":
case "caf":
case "tta":
case "mp1":
case "mp2":
case "mp3":
case "spx":
case "wv":
case "opus":
case "ts":
optionsPath = "json/audio.json";
break;
case "jpg":
case "jpeg":
case "png":
case "qoi":
case "exr":
case "webp":
case "jxl":
case "gif":
case "jp2":
case "j2k":
case "j2c":
case "avif":
optionsPath = "json/picture.json";
break;
}
fetch(optionsPath)
.then((response) => response.json()) .then((response) => response.json())
.then((json) => { .then((json) => {
const fromExt = e.target.files[0].name.split('.').pop(); const elOptions = document.getElementById("options");
const elButtons = document.getElementById("buttons");
while (elButtons.firstChild) { // Empty options area
elButtons.removeChild(elButtons.lastChild); while (elOptions.firstChild) {
} elOptions.removeChild(elOptions.lastChild);
}
for (toExt of json[fromExt]) { for (encoding of json) {
const elButton = document.createElement("input"); const elDetails = document.createElement("details");
elButton.setAttribute("type", "submit"); const elSummary = document.createElement("summary");
elButton.setAttribute("name", "submit"); const txSummary = document.createTextNode(encoding.abbr + (encoding.name ? " (" + encoding.name + ") " : " "));
elButton.setAttribute("value", toExt); elSummary.appendChild(txSummary);
elButtons.appendChild(elButton); elDetails.appendChild(elSummary);
elOptions.appendChild(elDetails);
for (toExt of encoding.containers[0].extensions) {
const txSpace = document.createTextNode(" ");
const elKboard = document.createElement("kbd");
const elButton = document.createElement("button");
const txButton = document.createTextNode(toExt);
elButton.setAttribute("value", encoding.abbr + "/" + toExt);
elButton.setAttribute("name", "submit");
elKboard.appendChild(txButton);
elButton.appendChild(elKboard);
elSummary.appendChild(elButton);
elSummary.appendChild(txSpace);
}
const elPList = document.createElement("p");
const elList = document.createElement("ul");
for (toCont of encoding.containers.slice(1)) {
const elItem = document.createElement("li");
const txSpace = document.createTextNode(" ");
const txCont = document.createTextNode(toCont.name);
elItem.appendChild(txCont);
elItem.appendChild(txSpace);
for (toExt of toCont.extensions) {
const txSpace = document.createTextNode(" ");
const elKboard = document.createElement("kbd");
const elButton = document.createElement("button");
const txButton = document.createTextNode(toExt);
elButton.setAttribute("value", encoding.abbr + "/" + toExt);
elButton.setAttribute("name", "submit");
elKboard.appendChild(txButton);
elButton.appendChild(elKboard);
elItem.appendChild(elButton);
elItem.appendChild(txSpace);
}
elList.appendChild(elItem);
}
elPList.appendChild(elList);
elDetails.appendChild(elPList);
const elDesc = document.createElement("p");
const elUrl = document.createElement("a");
elUrl.setAttribute("href", encoding.url);
const txUrl = document.createTextNode("More information about the codec ↣");
elDesc.appendChild(elUrl);
elUrl.appendChild(txUrl);
elDetails.appendChild(elDesc);
}
document.getElementById("options").style.display = "block";
switch (optionsPath) {
case "json/picture.json":
document.getElementById("picfxs").style.display = "block";
document.getElementById("audfxs").style.display = "none";
break;
case "json/audio.json":
document.getElementById("picfxs").style.display = "none";
document.getElementById("audfxs").style.display = "block";
break;
} }
}); });
} }

192
src/json/audio.json Normal file
View file

@ -0,0 +1,192 @@
[
{
"abbr": "FLAC",
"name": "Free Lossless Audio Codec",
"url": "https://fr.wikipedia.org/wiki/Free_Lossless_Audio_Codec",
"containers": [
{
"name": "Native",
"extensions": [
".flac"
]
},
{
"name": "Ogg",
"extensions": [
".ogg",
".oga"
]
},
{
"name": "Matroska",
"extensions": [
".mka"
]
}
]
},
{
"abbr": "ALAC",
"name": "Apple Lossless Audio Codec",
"url": "https://en.wikipedia.org/wiki/Apple_Lossless_Audio_Codec",
"containers": [
{
"name": "Core Audio Format",
"extensions": [
".caf"
]
}
]
},
{
"abbr": "Vorbis",
"url": "https://en.wikipedia.org/wiki/Vorbis",
"containers": [
{
"name": "Ogg",
"extensions": [
".ogg",
".oga"
]
},
{
"name": "Matroska",
"extensions": [
".mka"
]
},
{
"name": "WebM",
"extensions": [
".webm"
]
}
]
},
{
"abbr": "TTA",
"name": "True Audio",
"url": "https://en.wikipedia.org/wiki/TTA_(codec)",
"containers": [
{
"name": "Native",
"extensions": [
".tta"
]
}
]
},
{
"abbr": "MP1",
"name": "MPEG-1 Audio Layer I",
"url": "https://en.wikipedia.org/wiki/MPEG-1_Audio_Layer_I",
"containers": [
{
"name": "Native",
"extensions": [
".mp1"
]
}
]
},
{
"abbr": "MP2",
"name": "MPEG-1 Audio Layer II",
"url": "https://en.wikipedia.org/wiki/MPEG-1_Audio_Layer_II",
"containers": [
{
"name": "Native",
"extensions": [
".mp2"
]
}
]
},
{
"abbr": "MP3",
"name": "MPEG-1 Audio Layer III",
"url": "https://en.wikipedia.org/wiki/MP3",
"containers": [
{
"name": "Native",
"extensions": [
".mp3"
]
}
]
},
{
"abbr": "Speex",
"url": "https://en.wikipedia.org/wiki/Speex",
"containers": [
{
"name": "Native",
"extensions": [
".spx"
]
},
{
"name": "Ogg",
"extensions": [
".ogg",
".oga"
]
}
]
},
{
"abbr": "WavPack",
"url": "https://en.wikipedia.org/wiki/WavPack",
"containers": [
{
"name": "Ogg",
"extensions": [
".wv"
]
},
{
"name": "Matroska",
"extensions": [
".mka"
]
}
]
},
{
"abbr": "Opus",
"url": "https://en.wikipedia.org/wiki/Opus_(audio_format)",
"containers": [
{
"name": "Native",
"extensions": [
".opus"
]
},
{
"name": "Ogg",
"extensions": [
".ogg",
".oga"
]
},
{
"name": "Matroska",
"extensions": [
".mka"
]
},
{
"name": "WebM",
"extensions": [
".webm"
]
},
{
"name": "MPEG-TS",
"extensions": [
".ts"
]
}
]
}
]

109
src/json/audio.yaml Normal file
View file

@ -0,0 +1,109 @@
- abbr: FLAC
name: Free Lossless Audio Codec
url: https://fr.wikipedia.org/wiki/Free_Lossless_Audio_Codec
containers:
- name: Native
extensions:
- .flac
- name: Ogg
extensions:
- .ogg
- .oga
- name: Matroska
extensions:
- .mka
- abbr: ALAC
name: Apple Lossless Audio Codec
url: https://en.wikipedia.org/wiki/Apple_Lossless_Audio_Codec
containers:
- name: Core Audio Format
extensions:
- .caf
- abbr: Vorbis
url: https://en.wikipedia.org/wiki/Vorbis
containers:
- name: Ogg
extensions:
- .ogg
- .oga
- name: Matroska
extensions:
- .mka
- name: WebM
extensions:
- .webm
- abbr: TTA
name: True Audio
url: https://en.wikipedia.org/wiki/TTA_(codec)
containers:
- name: Native
extensions:
- .tta
- abbr: MP1
name: MPEG-1 Audio Layer I
url: https://en.wikipedia.org/wiki/MPEG-1_Audio_Layer_I
containers:
- name: Native
extensions:
- .mp1
- abbr: MP2
name: MPEG-1 Audio Layer II
url: https://en.wikipedia.org/wiki/MPEG-1_Audio_Layer_II
containers:
- name: Native
extensions:
- .mp2
- abbr: MP3
name: MPEG-1 Audio Layer III
url: https://en.wikipedia.org/wiki/MP3
containers:
- name: Native
extensions:
- .mp3
- abbr: Speex
url: https://en.wikipedia.org/wiki/Speex
containers:
- name: Native
extensions:
- .spx
- name: Ogg
extensions:
- .ogg
- .oga
- abbr: WavPack
url: https://en.wikipedia.org/wiki/WavPack
containers:
- name: Ogg
extensions:
- .wv
- name: Matroska
extensions:
- .mka
- abbr: Opus
url: https://en.wikipedia.org/wiki/Opus_(audio_format)
containers:
- name: Native
extensions:
- .opus
- name: Ogg
extensions:
- .ogg
- .oga
- name: Matroska
extensions:
- .mka
- name: WebM
extensions:
- .webm
- name: MPEG-TS
extensions:
- .ts

View file

@ -1,84 +0,0 @@
{
"jpeg": [
"jp2",
"webp",
"png",
"gif"
],
"jp2": [
"jpeg",
"webp",
"png",
"gif"
],
"webp": [
"jpeg",
"jp2",
"png",
"gif"
],
"png": [
"jpeg",
"jp2",
"webp",
"gif"
],
"gif": [
"jpeg",
"jp2",
"webp",
"png"
],
"av1": [
"mkv",
"webm",
"ogv"
],
"mkv": [
"av1",
"webm",
"ogv"
],
"webm": [
"av1",
"mkv",
"ogv"
],
"ogv": [
"av1",
"mkv",
"webm"
],
"alac": [
"flac",
"mp3",
"ogg",
"wav"
],
"flac": [
"alac",
"mp3",
"ogg",
"wav"
],
"mp3": [
"alac",
"flac",
"ogg",
"wav"
],
"ogg": [
"alac",
"flac",
"mp3",
"wav"
],
"wav": [
"alac",
"flac",
"ogg",
"mp3"
]
}

118
src/json/picture.json Normal file
View file

@ -0,0 +1,118 @@
[
{
"abbr": "JPEG",
"name": "Joint Photographic Experts Group",
"url": "https://en.wikipedia.org/wiki/JPEG",
"containers": [
{
"name": "Native",
"extensions": [
".jpg",
".jpeg"
]
}
]
},
{
"abbr": "PNG",
"name": "Portable Network Graphics",
"url": "https://en.wikipedia.org/wiki/JPEG",
"containers": [
{
"name": "Native",
"extensions": [
".png"
]
}
]
},
{
"abbr": "QOI",
"name": "Quite OK Image Format",
"url": "https://en.wikipedia.org/wiki/QOI_(image_format)",
"containers": [
{
"name": "Native",
"extensions": [
".qoi"
]
}
]
},
{
"abbr": "OpenEXR",
"url": "https://en.wikipedia.org/wiki/OpenEXR",
"containers": [
{
"name": "Native",
"extensions": [
".exr"
]
}
]
},
{
"abbr": "WebP",
"url": "https://en.wikipedia.org/wiki/WebP",
"containers": [
{
"name": "Native",
"extensions": [
".webp"
]
}
]
},
{
"abbr": "JPEG XL",
"url": "https://en.wikipedia.org/wiki/JPEG_XL",
"containers": [
{
"name": "Native",
"extensions": [
".jxl"
]
}
]
},
{
"abbr": "GIF",
"name": "Graphics Interchange Format",
"url": "https://en.wikipedia.org/wiki/GIF",
"containers": [
{
"name": "Native",
"extensions": [
".gif"
]
}
]
},
{
"abbr": "JPEG 2000",
"url": "https://en.wikipedia.org/wiki/JPEG_2000",
"containers": [
{
"name": "Native",
"extensions": [
".jp2",
".j2k",
".j2c"
]
}
]
},
{
"abbr": "AVIF",
"name": "AV1 Image File Format",
"url": "https://en.wikipedia.org/wiki/JPEG_2000",
"containers": [
{
"name": "Native",
"extensions": [
".avif"
]
}
]
}
]

70
src/json/picture.yaml Normal file
View file

@ -0,0 +1,70 @@
- abbr: JPEG
name: Joint Photographic Experts Group
url: https://en.wikipedia.org/wiki/JPEG
containers:
- name: Native
extensions:
- .jpg
- .jpeg
- abbr: PNG
name: Portable Network Graphics
url: https://en.wikipedia.org/wiki/JPEG
containers:
- name: Native
extensions:
- .png
- abbr: QOI
name: Quite OK Image Format
url: https://en.wikipedia.org/wiki/QOI_(image_format)
containers:
- name: Native
extensions:
- .qoi
- abbr: OpenEXR
url: https://en.wikipedia.org/wiki/OpenEXR
containers:
- name: Native
extensions:
- .exr
- abbr: WebP
url: https://en.wikipedia.org/wiki/WebP
containers:
- name: Native
extensions:
- .webp
- abbr: JPEG XL
url: https://en.wikipedia.org/wiki/JPEG_XL
containers:
- name: Native
extensions:
- .jxl
- abbr: GIF
name: Graphics Interchange Format
url: https://en.wikipedia.org/wiki/GIF
containers:
- name: Native
extensions:
- .gif
- abbr: JPEG 2000
url: https://en.wikipedia.org/wiki/JPEG_2000
containers:
- name: Native
extensions:
- .jp2
- .j2k
- .j2c
- abbr: AVIF
name: AV1 Image File Format
url: https://en.wikipedia.org/wiki/JPEG_2000
containers:
- name: Native
extensions:
- .avif

View file

@ -1,7 +1,8 @@
<?php <?php
$fromExt = strtolower(pathinfo($_FILES["file"]["name"])['extension']); $fromExt = strtolower(pathinfo($_FILES["file"]["name"])['extension']);
$toExt = $_POST["submit"]; $toMIME = $_POST["submit"];
$toExt = "";
$jobId = bin2hex(random_bytes(16)); $jobId = bin2hex(random_bytes(16));
chdir('/var/www/uploads/'); chdir('/var/www/uploads/');
@ -9,12 +10,279 @@ mkdir($jobId);
chdir($jobId); chdir($jobId);
move_uploaded_file($_FILES["file"]["tmp_name"], "upload.$fromExt"); move_uploaded_file($_FILES["file"]["tmp_name"], "upload.$fromExt");
exec("ffmpeg -y -i upload.$fromExt output.$toExt"); $filter = array();
$afilter = array();
if (isset($_POST["blur"])) {
array_push($filter,"gblur");
}
if (isset($_POST["pixelize"])) {
array_push($filter,"pixelize");
}
if (isset($_POST["vignette"])) {
array_push($filter,"vignette");
}
if (isset($_POST["tremolo"])) {
array_push($afilter,"tremolo");
}
if (isset($_POST["vibrato"])) {
array_push($afilter,"vibrato");
}
if (isset($_POST["speechnorm"])) {
array_push($afilter,"speechnorm");
}
if (isset($_POST["loudnorm"])) {
array_push($afilter,"loudnorm");
}
if (isset($_POST["extrastereo"])) {
array_push($afilter,"extrastereo");
}
if (isset($_POST["asubboost"])) {
array_push($afilter,"asubboost");
}
if (isset($_POST["dialoguenhance"])) {
array_push($afilter,"dialoguenhance");
}
if (isset($_POST["earwax"])) {
array_push($afilter,"earwax");
}
if (isset($_POST["bs2b"])) {
array_push($afilter,"bs2b");
}
if (isset($_POST["chorus"])) {
array_push($afilter,"aecho=0.8:0.9:1000|1800:0.3|0.25");
}
if (isset($_POST["flanger"])) {
array_push($afilter,"flanger");
}
if (isset($_POST["aphaser"])) {
array_push($afilter,"aphaser");
}
if (isset($_POST["crystalizer"])) {
array_push($afilter,"crystalizer");
}
if (isset($_POST["anlmdn"])) {
array_push($afilter,"anlmdn");
}
switch($_POST["transforms"]) {
case "hflip":
array_push($filter, "hflip");
break;
case "vflip":
array_push($filter, "vflip");
break;
case "clkrot":
array_push($filter, "rotate=PI/2");
break;
case "aclkrot":
array_push($filter, "rotate=-PI/2");
break;
case "reverse":
array_push($filter, "rotate=PI");
break;
}
switch($_POST["colorize"]) {
case "bw":
array_push($filter,"colorchannelmixer=.3:.4:.3:0:.3:.4:.3:0:.3:.4:.3");
break;
case "sepia":
array_push($filter,"colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131");
break;
}
switch($_POST["echo"]) {
case "two":
array_push($afilter,"aecho=0.8:0.88:60:0.4");
break;
case "robot":
array_push($afilter,"aecho=0.8:0.88:6:0.4");
break;
case "mountains":
array_push($afilter,"aecho=0.8:0.9:1000:0.3");
break;
case "more":
array_push($afilter,"aecho=0.8:0.9:1000|1800:0.3|0.25");
break;
}
$filter_str = implode(',',$filter);
$filter_str = empty($filter_str) ? "" : "-vf '$filter_str'";
$afilter_str = implode(',',$afilter);
$afilter_str = empty($afilter_str) ? "" : "-af '$afilter_str'";
switch($toMIME) {
case "FLAC/.flac":
$toExt = "flac";
exec("ffmpeg -y -i upload.$fromExt -acodec flac $afilter_str output.$toExt");
break;
case "FLAC/.ogg":
$toExt = "ogg";
exec("ffmpeg -y -i upload.$fromExt -acodec flac $afilter_str output.$toExt");
break;
case "FLAC/.oga":
$toExt = "oga";
exec("ffmpeg -y -i upload.$fromExt -acodec flac $afilter_str output.$toExt");
break;
case "FLAC/.mka":
$toExt = "mka";
exec("ffmpeg -y -i upload.$fromExt -acodec flac $afilter_str output.$toExt");
break;
case "ALAC/.caf":
$toExt = "caf";
exec("ffmpeg -y -i upload.$fromExt -acodec alac $afilter_str output.$toExt");
break;
case "WavPack/.wv":
$toExt = "wv";
exec("ffmpeg -y -i upload.$fromExt -acodec wavpack $afilter_str output.$toExt");
break;
case "WavPack/.mka":
$toExt = "mka";
exec("ffmpeg -y -i upload.$fromExt -acodec wavpack $afilter_str output.$toExt");
break;
case "Vorbis/.ogg":
$toExt = "ogg";
exec("ffmpeg -y -i upload.$fromExt -acodec vorbis $afilter_str -strict -2 output.$toExt");
break;
case "Vorbis/.oga":
$toExt = "oga";
exec("ffmpeg -y -i upload.$fromExt -acodec vorbis $afilter_str -strict -2 output.$toExt");
break;
case "Vorbis/.mka":
$toExt = "mka";
exec("ffmpeg -y -i upload.$fromExt -acodec vorbis $afilter_str -strict -2 output.$toExt");
break;
case "Vorbis/.webm":
$toExt = "webm";
exec("ffmpeg -y -i upload.$fromExt -acodec vorbis $afilter_str -strict -2 output.$toExt");
break;
case "Speex/.spx":
$toExt = "spx";
exec("ffmpeg -y -i upload.$fromExt -acodec speex $afilter_str output.$toExt");
break;
case "Speex/.ogg":
$toExt = "ogg";
exec("ffmpeg -y -i upload.$fromExt -acodec speex $afilter_str output.$toExt");
break;
case "Speex/.oga":
$toExt = "oga";
exec("ffmpeg -y -i upload.$fromExt -acodec speex $afilter_str output.$toExt");
break;
case "MP1/.mp1":
$toExt = "mp1";
exec("ffmpeg -y -i upload.$fromExt -acodec mp1 $afilter_str output.$toExt");
break;
case "MP2/.mp2":
$toExt = "mp2";
exec("ffmpeg -y -i upload.$fromExt -acodec mp2 $afilter_str output.$toExt");
break;
case "MP3/.mp3":
$toExt = "mp3";
exec("ffmpeg -y -i upload.$fromExt -acodec mp3 $afilter_str output.$toExt");
break;
case "TTA/.tta":
$toExt = "tta";
exec("ffmpeg -y -i upload.$fromExt -acodec tta $afilter_str output.$toExt");
break;
case "Opus/.opus":
$toExt = "opus";
exec("ffmpeg -y -i upload.$fromExt -acodec opus $afilter_str -strict -2 output.$toExt");
break;
case "Opus/.ogg":
$toExt = "ogg";
exec("ffmpeg -y -i upload.$fromExt -acodec opus $afilter_str -strict -2 output.$toExt");
break;
case "Opus/.oga":
$toExt = "oga";
exec("ffmpeg -y -i upload.$fromExt -acodec opus $afilter_str -strict -2 output.$toExt");
break;
case "Opus/.mka":
$toExt = "mka";
exec("ffmpeg -y -i upload.$fromExt -acodec opus $afilter_str -strict -2 output.$toExt");
break;
case "Opus/.webm":
$toExt = "webm";
exec("ffmpeg -y -i upload.$fromExt -acodec opus $afilter_str -strict -2 output.$toExt");
break;
case "Opus/.ts":
$toExt = "ts";
exec("ffmpeg -y -i upload.$fromExt -acodec opus $afilter_str -strict -2 output.$toExt");
break;
case "JPEG/.jpg":
$toExt = "jpg";
exec("ffmpeg -y -i upload.$fromExt -vcodec mjpeg $filter_str output.$toExt");
break;
case "JPEG/.jpeg":
$toExt = "jpeg";
exec("ffmpeg -y -i upload.$fromExt -vcodec mjpeg $filter_str output.$toExt");
break;
case "PNG/.png":
$toExt = "png";
exec("ffmpeg -y -i upload.$fromExt -vcodec png $filter_str output.$toExt");
break;
case "QOI/.qoi":
$toExt = "qoi";
exec("ffmpeg -y -i upload.$fromExt -vcodec qoi $filter_str output.$toExt");
break;
case "OpenEXR/.exr":
$toExt = "exr";
exec("ffmpeg -y -i upload.$fromExt -vcodec exr $filter_str output.$toExt");
break;
case "WebP/.webp":
$toExt = "webp";
exec("ffmpeg -y -i upload.$fromExt -vcodec webp $filter_str output.$toExt");
break;
case "JPEG XL/.jxl":
$toExt = "jxl";
exec("ffmpeg -y -i upload.$fromExt -vcodec jpegxl $filter_str output.$toExt");
break;
case "GIF/.gif":
$toExt = "gif";
exec("ffmpeg -y -i upload.$fromExt -vcodec gif $filter_str output.$toExt");
break;
case "JPEG 2000/.jp2":
$toExt = "jp2";
exec("ffmpeg -y -i upload.$fromExt -vcodec jpeg2000 $filter_str output.$toExt");
break;
case "JPEG 2000/.j2k":
$toExt = "j2k";
exec("ffmpeg -y -i upload.$fromExt -vcodec jpeg2000 $filter_str output.$toExt");
break;
case "JPEG 2000/.j2c":
$toExt = "j2c";
exec("ffmpeg -y -i upload.$fromExt -vcodec jpeg2000 $filter_str output.$toExt");
break;
case "AVIF/.avif":
$toExt = "avif";
exec("ffmpeg -y -i upload.$fromExt -vcodec av1 $filter_str output.$toExt");
break;
}
header("Cache-Control: public"); header("Cache-Control: public");
header("Content-Description: File Transfer"); header("Content-D6escription: File Transfer");
header("Content-Disposition: attachment; filename=output.$toExt"); header("Content-Disposition: attachment; filename=output.$toExt");
header("Content-Type: application/jpeg");
header("Content-Transfer-Encoding: binary"); header("Content-Transfer-Encoding: binary");
readfile("/var/www/uploads/$jobId/output.$toExt"); readfile("/var/www/uploads/$jobId/output.$toExt");