diff options
| author | ilotterytea <iltsu@alright.party> | 2025-03-24 14:07:21 +0500 |
|---|---|---|
| committer | ilotterytea <iltsu@alright.party> | 2025-03-24 14:07:21 +0500 |
| commit | 52fea7284ff009a6afddbc6e64bdf49c24f2a038 (patch) | |
| tree | af334cf32499e121937db12aae83b6d23f72e521 | |
| parent | 83db2ca649ee7d4068b070a032800037caf2e116 (diff) | |
feat: download external files
| -rw-r--r-- | public/index.php | 76 | ||||
| -rw-r--r-- | public/static/style.css | 12 | ||||
| -rw-r--r-- | public/upload.php | 113 |
3 files changed, 153 insertions, 48 deletions
diff --git a/public/index.php b/public/index.php index 7d07c5b..e08a67a 100644 --- a/public/index.php +++ b/public/index.php @@ -26,9 +26,28 @@ include_once $_SERVER['DOCUMENT_ROOT'] . '/../lib/partials.php'; accept="<?= implode(', ', array_unique(array_values(FILE_ACCEPTED_MIME_TYPES))) ?>" id="form-file"> - <button type="button" id="form-upload-wrapper" style="display: none"> - <h1>Click here to start upload</h1> - </button> + <div class="column gap-8" id="form-upload-wrapper"> + <button type="button"> + <h1>Click here to start upload</h1> + </button> + <?php if (FILEEXT_ENABLED): ?> + <div class="row gap-8"> + <p>URL:</p> + <div class="column grow"> + <input type="url" name="url" id="form-url" + placeholder="Instagram, YouTube and other links"> + <ul class="row gap-8 font-small" style="list-style:none"> + <li> + <p>Max duration: <b><?= FILEEXT_MAX_DURATION / 60 ?> minutes</b></p> + </li> + <li><a href="https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md" + target="_blank">Supported + platforms</a></li> + </ul> + </div> + </div> + <?php endif; ?> + </div> <button type="submit">Upload</button> </form> @@ -49,15 +68,30 @@ include_once $_SERVER['DOCUMENT_ROOT'] . '/../lib/partials.php'; <script> const uploadedFiles = document.getElementById('uploaded-files'); + <?php if (FILEEXT_ENABLED): ?> + const fileURL = document.getElementById('form-url'); + <?php endif; ?> const formUpload = document.getElementById('form-upload'); formUpload.addEventListener('submit', (event) => { event.preventDefault(); - fileUpload(); + <?php if (FILEEXT_ENABLED): ?> + fileUpload(fileURL.value.length != 0); + <?php else: ?> + fileUpload(false); + <?php endif; ?> }); - const formUploadWrapper = document.getElementById('form-upload-wrapper'); - formUploadWrapper.style.display = 'block'; + const fileUploadWrapper = document.querySelector('#form-upload-wrapper>button'); + fileUploadWrapper.style.display = 'block'; + + <?php if (FILEEXT_ENABLED): ?> + const fileURLWrapper = document.querySelector('#form-upload-wrapper>div'); + fileURL.addEventListener('change', () => { + fileUploadWrapper.style.display = fileURL.value.length == 0 ? 'block' : 'none'; + formSubmitButton.style.display = fileURL.value.length == 0 ? 'none' : 'block'; + }); + <?php endif; ?> const formSubmitButton = document.querySelector('#form-upload button[type=submit]'); @@ -66,21 +100,31 @@ include_once $_SERVER['DOCUMENT_ROOT'] . '/../lib/partials.php'; formFile.addEventListener("change", (e) => { const file = e.target.files[0]; if (file) { - formUploadWrapper.innerHTML = `<h1>File: ${file.name}</h1>`; + fileUploadWrapper.innerHTML = `<h1>File: ${file.name}</h1>`; formSubmitButton.style.display = 'block'; + <?php if (FILEEXT_ENABLED): ?> + fileURLWrapper.style.display = 'none'; + <?php endif; ?> } }); - formUploadWrapper.addEventListener("click", () => formFile.click()); + fileUploadWrapper.addEventListener("click", () => formFile.click()); formSubmitButton.style.display = 'none'; - function fileUpload() { - formUploadWrapper.innerHTML = `<h1>Uploading ${formFile.files[0].name}...</h1><p>This might take a while...</p>`; + function fileUpload(is_url) { + const form = new FormData(formUpload); + + fileUploadWrapper.innerHTML = is_url ? `<h1>Uploading ${fileURL.value}</h1><p>This might take a while...</p>` : `<h1>Uploading ${formFile.files[0].name}...</h1><p>This might take a while...</p>`; + fileUploadWrapper.style.display = 'block'; + <?php if (FILEEXT_ENABLED): ?> + fileURLWrapper.style.display = 'none'; + fileURL.value = ''; + <?php endif; ?> formSubmitButton.style.display = 'none'; fetch(formUpload.getAttribute('action'), { - 'body': new FormData(formUpload), + 'body': form, 'method': 'POST', 'headers': { 'Accept': 'application/json' @@ -89,10 +133,18 @@ include_once $_SERVER['DOCUMENT_ROOT'] . '/../lib/partials.php'; .catch((err) => { console.error(err); alert('Failed to send a file. More info in the console...'); + <?php if (FILEEXT_ENABLED): ?> + fileURLWrapper.style.display = 'flex'; + <?php endif; ?> + fileUploadWrapper.style.display = 'block'; }) .then((r) => r.json()) .then((json) => { - formUploadWrapper.innerHTML = '<h1>Click here to start upload</h1>'; + fileUploadWrapper.innerHTML = '<h1>Click here to start upload</h1>'; + <?php if (FILEEXT_ENABLED): ?> + fileURLWrapper.style.display = 'flex'; + <?php endif; ?> + fileUploadWrapper.style.display = 'block'; if (json.status_code != 201) { alert(`${json.message} (${json.status_code})`); diff --git a/public/static/style.css b/public/static/style.css index 69332ca..9762b38 100644 --- a/public/static/style.css +++ b/public/static/style.css @@ -52,14 +52,14 @@ button[type=submit]:hover { cursor: pointer; } -#form-upload-wrapper { +#form-upload-wrapper>button { background: var(--background-2); padding: 32px 0; color: var(--foreground); border: 4px dashed var(--box-border); } -#form-upload-wrapper:hover { +#form-upload-wrapper>button:hover { background: var(--background); cursor: pointer; } @@ -116,10 +116,18 @@ button[type=submit]:hover { padding: 4px; } +.gap-16 { + gap: 16px; +} + .gap-8 { gap: 8px; } .gap-4 { gap: 4px; +} + +.font-small { + font-size: 10px; }
\ No newline at end of file diff --git a/public/upload.php b/public/upload.php index 5c4e3cb..2fd7c67 100644 --- a/public/upload.php +++ b/public/upload.php @@ -7,57 +7,102 @@ if ($_SERVER['REQUEST_METHOD'] != 'POST') { exit; } -if (!isset($_FILES['file'])) { - json_response(null, "No 'file' specified!", 400); - exit(); -} - if (!is_dir(FILE_DIRECTORY) && !mkdir(FILE_DIRECTORY, 0777, true)) { json_response(null, 'Failed to create a directory for user files', 500); exit(); } try { - $file = $_FILES['file']; + $url = $_POST['url'] ?? null; + $file = $_FILES['file'] ?? null; + $file_data = null; - if ( - !isset($file['error']) || - is_array($file['error']) - ) { - throw new RuntimeException('Invalid parameters.'); - } + if (FILEEXT_ENABLED && isset($url) && !empty($url)) { + $output = []; + exec('yt-dlp --get-filename -o "%(filesize_approx)s %(ext)s %(duration)s" ' . escapeshellarg($url) . '', $output); + if (empty($output)) { + throw new RuntimeException('Bad URL'); + } + + $output = explode(' ', $output[0]); + + // TODO: some videos don't have duration + $duration = intval($output[2]); + if ($duration > FILEEXT_MAX_DURATION) { + throw new RuntimeException(sprintf("File must be under %d minutes", FILEEXT_MAX_DURATION / 60)); + } - // checking file size - switch ($file['error']) { - case UPLOAD_ERR_OK: - break; - case UPLOAD_ERR_NO_FILE: - throw new RuntimeException('No file sent.'); - case UPLOAD_ERR_INI_SIZE: - case UPLOAD_ERR_FORM_SIZE: - throw new RuntimeException('Exceeded filesize limit.'); - default: - throw new RuntimeException('Unknown errors.'); + if (!array_key_exists($output[1], FILE_ACCEPTED_MIME_TYPES)) { + throw new RuntimeException("Unsupported extension: {$output[1]}"); + } + + $file_data = [ + 'size' => intval($output[0]), + 'mime' => FILE_ACCEPTED_MIME_TYPES[$output[1]], + 'extension' => $output[1] + ]; + } else if (isset($file)) { + if ( + !isset($file['error']) || + is_array($file['error']) + ) { + throw new RuntimeException('Invalid parameters.'); + } + + // checking file error + switch ($file['error']) { + case UPLOAD_ERR_OK: + break; + case UPLOAD_ERR_NO_FILE: + throw new RuntimeException('No file sent.'); + case UPLOAD_ERR_INI_SIZE: + case UPLOAD_ERR_FORM_SIZE: + throw new RuntimeException('Exceeded filesize limit.'); + default: + throw new RuntimeException('Unknown errors.'); + } + + // checking file mimetype + $finfo = new finfo(FILEINFO_MIME_TYPE); + if (false === $file_ext = array_search($finfo->file($file['tmp_name']), FILE_ACCEPTED_MIME_TYPES, true)) { + throw new RuntimeException("Invalid file format."); + } + + $file_data = [ + 'size' => $file['size'], + 'mime' => FILE_ACCEPTED_MIME_TYPES[$file_ext], + 'extension' => $file_ext + ]; } - // checking file mimetype - $finfo = new finfo(FILEINFO_MIME_TYPE); - if (false === $file_ext = array_search($finfo->file($file['tmp_name']), FILE_ACCEPTED_MIME_TYPES, true)) { - throw new RuntimeException("Invalid file format."); + if (!$file_data) { + throw new RuntimeException('No URL or file specified'); } $file_id = generate_random_char_sequence(FILE_ID_CHARACTERS, FILE_ID_LENGTH); + $file_data['id'] = $file_id; + + if (isset($url)) { + $result = 0; + $output = []; + + exec(sprintf( + 'yt-dlp -o "%s/%s.%s" %s 2>&1', + FILE_DIRECTORY, + $file_id, + $file_data['extension'], + escapeshellarg($url) + ), $output, $result); - if (!move_uploaded_file($file['tmp_name'], FILE_DIRECTORY . sprintf('/%s.%s', $file_id, $file_ext))) { + if ($result != 0) { + error_log(sprintf("Failed to download a file (URL: %s): %s", $url, implode('\n', $output))); + throw new RuntimeException('Failed to download a file! Try again later.'); + } + } else if (!move_uploaded_file($file['tmp_name'], FILE_DIRECTORY . sprintf('/%s.%s', $file_id, $file_ext))) { throw new RuntimeException("Failed to save the file. Try again later."); } - json_response([ - 'id' => $file_id, - 'extension' => $file_ext, - 'mime' => FILE_ACCEPTED_MIME_TYPES[$file_ext], - 'size' => $file['size'] - ], null, 201); + json_response($file_data, null, 201); } catch (RuntimeException $e) { json_response(null, $e->getMessage(), 400); }
\ No newline at end of file |
