first commit
This commit is contained in:
@@ -0,0 +1,254 @@
|
||||
<!DOCTYPE html>
|
||||
{% trans_default_domain 'history' %}
|
||||
<html lang="{{ app.request.locale }}" dir="{{ app.request.locale == 'ar' ? 'rtl' : 'ltr' }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes">
|
||||
<title>{{ 'title_history'|trans }} — {{ 'title_home'|trans }}</title>
|
||||
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/font-awesome@6.7.2/css/all.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/frontend.css') }}">
|
||||
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/bootstrap@5.3.8/css/bootstrap.min.css') }}">
|
||||
{% if app.request.locale == 'ar' %}
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/bootstrap@5.3.8/css/bootstrap.rtl.min.css') }}">
|
||||
{% endif %}
|
||||
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/history.css') }}">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- ── TOP HEADER BAR ── -->
|
||||
<header class="top-header-bar">
|
||||
<div class="top-bar-container">
|
||||
<div class="static-lang">
|
||||
<a href="/change-language?lang=ar">🇸🇦</a>
|
||||
<a href="/change-language?lang=fr">🇫🇷</a>
|
||||
<a href="/change-language?lang=en">🇬🇧</a>
|
||||
</div>
|
||||
|
||||
{% if is_granted('ROLE_USER') %}
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
|
||||
<a href="{{ path('app_frontend_home') }}">
|
||||
<button class="btn btn-light border menu-btn">
|
||||
<i class="fa-solid fa-house"></i>
|
||||
{{ "btn_home"|trans }}
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<a href="{{ path('security_logout') }}">
|
||||
<button class="btn btn-danger menu-btn">
|
||||
<i class="fa-solid fa-arrow-right-to-bracket"></i>
|
||||
{{ "btn_decnx"|trans }}
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="username">{{ app.user.pseudo|e }}</span>
|
||||
<i class="fa-solid fa-circle-user fa-2xl"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% else %}
|
||||
<a href="{{ path('security_login') }}">
|
||||
<button class="btn btn-success menu-btn">
|
||||
<i class="fa-solid fa-right-to-bracket"></i>
|
||||
{{ "btn_cnx"|trans }}
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- ── MAIN CONTENT ── -->
|
||||
<main class="main-container">
|
||||
|
||||
<!-- Page header -->
|
||||
<div class="history-page-header">
|
||||
<h1 class="history-page-title">
|
||||
<i class="fa-solid fa-clock-rotate-left"></i>
|
||||
{{ "history_title"|trans }}
|
||||
<span class="history-badge">{{ videos|length }}</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{% if videos|length > 0 %}
|
||||
|
||||
<!-- Toolbar -->
|
||||
<div class="history-toolbar">
|
||||
<div class="history-search">
|
||||
<i class="fa-solid fa-magnifying-glass search-icon"></i>
|
||||
<input
|
||||
type="text"
|
||||
id="searchInput"
|
||||
placeholder="{{ 'history_search_placeholder'|trans }}"
|
||||
autocomplete="off"
|
||||
>
|
||||
</div>
|
||||
<select class="history-sort-select" id="sortSelect">
|
||||
<option value="date_desc">{{ "sort_date_desc"|trans }}</option>
|
||||
<option value="date_asc">{{ "sort_date_asc"|trans }}</option>
|
||||
<option value="name_asc">{{ "sort_name_asc"|trans }}</option>
|
||||
<option value="size_desc">{{ "sort_size_desc"|trans }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Table -->
|
||||
<div class="history-table-wrapper">
|
||||
<table class="history-table" id="historyTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ "col_name"|trans }}</th>
|
||||
<th>{{ "col_date"|trans }}</th>
|
||||
<th>{{ "col_size"|trans }}</th>
|
||||
<th>{{ "col_actions"|trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="historyTbody">
|
||||
{% for video in videos %}
|
||||
<tr
|
||||
data-id="{{ video.getId() }}"
|
||||
data-name="{{ video.getName()|lower }}"
|
||||
data-date="{{ video.getDateAdd()|date('U') }}"
|
||||
{#data-size="{{ video.filesize }}"#}
|
||||
>
|
||||
<!-- Name -->
|
||||
<td>
|
||||
<div class="video-name-cell">
|
||||
<div class="video-thumb-icon">
|
||||
<i class="fa-solid fa-film"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="video-title-text" title="{{ video.getName()|e }}">
|
||||
{{ video.getName()|e }}
|
||||
</div>
|
||||
<span class="video-ext-badge">{{ video.getName()|split('.')|last }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Date -->
|
||||
<td class="date-cell">
|
||||
{{ video.getDateAdd()|date("d/m/Y") }}
|
||||
<span class="time-sub">
|
||||
{{ video.getDateAdd()|date("H:i") }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<!-- Size -->
|
||||
<td class="size-cell">
|
||||
{% set sizeMb = video.getSizeFile() %}
|
||||
{% if sizeMb >= 1024 %}
|
||||
{{ (sizeMb / 1024)|round(2) }} <span class="size-unit">GB</span>
|
||||
{% else %}
|
||||
{{ sizeMb }} <span class="size-unit">MB</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<!-- Actions -->
|
||||
<td class="actions-cell">
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<a
|
||||
href="{{ path('app_frontend_download_user', {id: video.getId()}) }}"
|
||||
class="btn-action-dl"
|
||||
title="{{ 'action_download'|trans }}"
|
||||
>
|
||||
<i class="fa-solid fa-download"></i>
|
||||
<span>{{ "action_download"|trans }}</span>
|
||||
</a>
|
||||
<button
|
||||
class="btn-action-del"
|
||||
title="{{ 'action_delete'|trans }}"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#deleteModal"
|
||||
data-video-id="{{ video.getId() }}"
|
||||
data-video-name="{{ video.getName()|e }}"
|
||||
>
|
||||
<i class="fa-solid fa-trash-can"></i>
|
||||
<span>{{ "action_delete"|trans }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination info -->
|
||||
<div class="history-pagination">
|
||||
<span class="pagination-info" id="paginationInfo">
|
||||
{{ "pagination_showing"|trans({
|
||||
'%count%': videos|length,
|
||||
'%total%': videos|length
|
||||
}) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
|
||||
<!-- Empty state -->
|
||||
<div class="history-empty">
|
||||
<i class="fa-solid fa-photo-film"></i>
|
||||
<p>{{ "history_empty_title"|trans }}</p>
|
||||
<span>{{ "history_empty_subtitle"|trans }}</span>
|
||||
<div class="mt-3">
|
||||
<a href="{{ path('app_frontend_home') }}" class="btn-action-dl text-decoration-none d-inline-flex">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
<span>{{ "btn_new_download"|trans }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
</main>
|
||||
|
||||
<!-- ── DELETE CONFIRM MODAL ── -->
|
||||
<div
|
||||
class="modal fade modal-confirm"
|
||||
id="deleteModal"
|
||||
tabindex="-1"
|
||||
aria-labelledby="deleteModalLabel"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="deleteModalLabel">
|
||||
<i class="fa-solid fa-triangle-exclamation me-2"></i>
|
||||
{{ "modal_delete_title"|trans }}
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body py-3">
|
||||
<p class="mb-1 text-secondary" id="deleteModalBody">
|
||||
{{ "modal_delete_body"|trans }}
|
||||
</p>
|
||||
<p class="fw-bold text-danger mb-0" id="deleteModalFileName"></p>
|
||||
</div>
|
||||
<div class="modal-footer border-0 pt-0">
|
||||
<button type="button" class="btn btn-light rounded-pill px-4" data-bs-dismiss="modal">
|
||||
{{ "modal_cancel"|trans }}
|
||||
</button>
|
||||
<form id="deleteForm" method="POST" action="" class="d-inline">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token('delete_video') }}">
|
||||
<button type="submit" class="btn btn-danger rounded-pill px-4 fw-bold">
|
||||
<i class="fa-solid fa-trash-can me-1"></i>
|
||||
{{ "modal_confirm_delete"|trans }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="{{ asset('assets/vendor/jquery@4.0.0/jquery.min.js') }}"></script>
|
||||
<script src="{{ asset('assets/vendor/bootstrap@5.3.8/js/bootstrap.min.js') }}"></script>
|
||||
<script src="{{ asset('assets/js/history.js') }}"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,148 @@
|
||||
<!DOCTYPE html>
|
||||
{% trans_default_domain 'home' %}
|
||||
<html lang="{{ app.request.locale }}" dir="{{ app.request.locale == 'ar' ? 'rtl' : 'ltr' }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes">
|
||||
|
||||
|
||||
<meta name="description"
|
||||
content="Téléchargez des vidéos depuis n'importe quel site
|
||||
en quelques secondes avec VideoPowerPME. Gratuit,
|
||||
sans inscription, compatible YouTube, Instagram,
|
||||
TikTok, Facebook et plus encore.">
|
||||
|
||||
<meta name="keywords" content="télécharger vidéo en ligne, téléchargeur vidéo gratuit,
|
||||
download vidéo YouTube, convertir YouTube MP4,
|
||||
downloader vidéo sans logiciel, VideoPowerPME">
|
||||
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="author" content="VideoPowerPME">
|
||||
<link rel="canonical" href="https://videopowerpme.com/fr/">
|
||||
<link rel="alternate" hreflang="en" href="{{ url('change_language', {'lang': 'en'}) }}">
|
||||
<link rel="alternate" hreflang="ar" href="{{ url('change_language', {'lang': 'ar'}) }}">
|
||||
<link rel="alternate" hreflang="fr" href="{{ url('change_language', {'lang': 'fr'}) }}">
|
||||
<link rel="alternate" hreflang="x-default" href="{{ url('change_language', {'lang': 'fr'}) }}">
|
||||
|
||||
|
||||
<title>{{ 'title_home'|trans}}</title>
|
||||
<!-- Font Awesome pour les icônes -->
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/font-awesome@6.7.2/css/all.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/frontend.css') }}">
|
||||
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/bootstrap@5.3.8/css/bootstrap.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/bootstrap@5.3.8/css/bootstrap.rtl.min.css') }}">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<!-- BARRE HORIZONTALE TOUT EN HAUT DE LA PAGE -->
|
||||
<header class="top-header-bar">
|
||||
<div class="top-bar-container">
|
||||
<!-- Section langue fixe (pas de JS, simple affichage) -->
|
||||
<div class="static-lang">
|
||||
<a href="{{ path('change_language', {'lang': 'ar'}) }}">🇸🇦</a>
|
||||
<a href="{{ path('change_language', {'lang': 'fr'}) }}">🇫🇷</a>
|
||||
<a href="{{ path('change_language', {'lang': 'en'}) }}">🇬🇧</a>
|
||||
</div>
|
||||
|
||||
<!-- Badge démontrant l'absence de connexion obligatoire -->
|
||||
|
||||
{% if is_granted('ROLE_USER') %}
|
||||
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
|
||||
<!-- History Button -->
|
||||
<a href="{{ path('app_frontend_history') }}" class="btn btn-light border menu-btn">
|
||||
<i class="fa-solid fa-clock-rotate-left"></i>
|
||||
{{ "btn_history"|trans }}
|
||||
</a>
|
||||
|
||||
<!-- Logout Button -->
|
||||
<a href="{{ path('security_logout') }}">
|
||||
<button class="btn btn-danger menu-btn">
|
||||
<i class="fa-solid fa-arrow-right-to-bracket"></i>
|
||||
{{ "btn_decnx"|trans }}
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<!-- User Info -->
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="username">{{ app.user.pseudo|e }}</span>
|
||||
<i class="fa-solid fa-circle-user fa-2xl"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
<a href="{{ path('security_login') }}">
|
||||
<button class="btn btn-success menu-btn">
|
||||
<i class="fa-solid fa-right-to-bracket"></i>
|
||||
{{ "btn_cnx"|trans }}
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="main-alert">
|
||||
{% if not is_granted('ROLE_USER') %}
|
||||
<div class="alert alert-primary" role="alert">
|
||||
<i class="fa-solid fa-bell"></i>
|
||||
{{ "alert_defaut"|trans }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Contenu principal (centré) -->
|
||||
<div class="main-container">
|
||||
|
||||
<!-- Logo et titre -->
|
||||
<div class="logo-area">
|
||||
<i class="fab fa-youtube logo-icon"></i>
|
||||
<span class="logo-text">VideoPowerPME</span>
|
||||
</div>
|
||||
<!-- Zone de saisie des URLs -->
|
||||
<div class="url-section">
|
||||
<div class="url-input-area">
|
||||
<textarea id="youtubeUrls" placeholder="{{ 'placeholder_url'|trans }}"></textarea>
|
||||
<div class="format-row">
|
||||
{#<select id="formatSelect">
|
||||
<option value="mp4-1080p">MP4 - 1080p</option>
|
||||
<option value="mp4-720p" selected>MP4 - 720p</option>
|
||||
<option value="mp4-480p">MP4 - 480p</option>
|
||||
<option value="webm-1080p">WebM - 1080p</option>
|
||||
<option value="webm-720p">WebM - 720p</option>
|
||||
</select>#}
|
||||
<button id="processBtn" class="process-btn"><i class="fas fa-download"></i> <span class="btn-text">{{ 'btn_start'|trans }}</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Liste des vidéos avec progression et statut -->
|
||||
<div class="video-list" id="videoListContainer">
|
||||
<!-- Les éléments dynamiques sont insérés ici -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{{ asset('assets/vendor/jquery@4.0.0/jquery.min.js') }}"></script>
|
||||
<script src="{{ asset('assets/vendor/bootstrap@5.3.8/js/bootstrap.min.js') }}"></script>
|
||||
<script>
|
||||
const ENDPOINTS = {
|
||||
getInfo: "{{ path('app_frontend_size_movie') }}", // retourne { name: "...", sizeMB: 180 } ou erreur
|
||||
streamDownload: "{{ path('app_streamed_download') }}", // téléchargement direct
|
||||
backgroundDownload: "{{ path('app_background_download') }}", // lance tâche de fond
|
||||
urlAuth: "{{ path('security_login') }}" // retourne { authenticated: true/false }
|
||||
// téléchargement le vidéo anonyme
|
||||
};
|
||||
function checkAuth() {
|
||||
{% if is_granted('ROLE_USER') %}
|
||||
return true;
|
||||
{% else %}
|
||||
return false;
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
</script>
|
||||
<script src="{{ asset('assets/js/frontend.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,75 @@
|
||||
<!DOCTYPE html>
|
||||
{% trans_default_domain 'sign-in' %}
|
||||
|
||||
<html lang="{{ app.request.locale }}" dir="{{ app.request.locale == 'ar' ? 'rtl' : 'ltr' }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes">
|
||||
<title>Téléchargeur de vidéos YouTube</title>
|
||||
<!-- jQuery -->
|
||||
<script src="{{ asset('assets/vendor/jquery@4.0.0/jquery.min.js') }}"></script>
|
||||
<!-- Font Awesome pour les icônes -->
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/frontend.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/bootstrap@5.3.8/css/bootstrap.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/bootstrap@5.3.8/css/bootstrap.rtl.min.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-container">
|
||||
<div class="row mb-4">
|
||||
<div class="col-3"></div>
|
||||
<div class="col-2">
|
||||
<a href="{{ path('change_language', {'lang':'fr'}) }}">🇫🇷 Français</a>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<a href="{{ path('change_language', {'lang':'en'}) }}">🇬🇧 English (UK)</a>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<a href="{{ path('change_language', {'lang':'ar'}) }}"> 🇸🇦 العربية</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="mb-4">
|
||||
<h3>{{ 'sign_in'|trans }}</h3>
|
||||
<p class="mt-4">{{ 'account'|trans }} <a href="{{ path('security_registration') }}">{{ 'sign_up'|trans }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<form action="{{ path('security_login') }}" method="post">
|
||||
{% if error %}
|
||||
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
|
||||
{% endif %}
|
||||
<input type="hidden" name="_csrf_token" data-controller="csrf-protection" value="{{ csrf_token('authenticate') }}">
|
||||
<div class="row gy-3 overflow-hidden">
|
||||
<div class="col-12">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="email" class="form-control" name="email" id="email" placeholder="{{ 'placeholder_email'|trans }}" required>
|
||||
<label for="email" class="form-label">{{ 'label_email'|trans }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="password" class="form-control" name="password" id="password" value="" placeholder="{{ 'password'|trans }}" required>
|
||||
<label for="password" class="form-label">{{ 'password'|trans }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="form-group">
|
||||
<input class="form-check-input" type="checkbox" value="" name="remember_me" id="remember_me">
|
||||
<label class="form-check-label text-secondary" for="remember_me">
|
||||
{{ 'remember'|trans }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3 offset-4">
|
||||
<div class="d-grid">
|
||||
<button class="btn btn-success btn-lg" type="submit">{{ 'sign_in'|trans }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
</div>
|
||||
<script src="{{ asset('assets/vendor/bootstrap@5.3.8/js/bootstrap.min.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,211 @@
|
||||
<!DOCTYPE html>
|
||||
{% trans_default_domain 'sign-up' %}
|
||||
|
||||
<html lang="{{ app.request.locale }}" dir="{{ app.request.locale == 'ar' ? 'rtl' : 'ltr' }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes">
|
||||
<title>Téléchargeur de vidéos YouTube</title>
|
||||
<!-- jQuery -->
|
||||
<script src="{{ asset('assets/vendor/jquery@4.0.0/jquery.min.js') }}"></script>
|
||||
<!-- Font Awesome pour les icônes -->
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/font-awesome@6.7.2/css/all.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/frontend.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/bootstrap@5.3.8/css/bootstrap.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/country-select-js@2.1.0/build/css/countrySelect.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/intl-tel-input@28.1.0/dist/css/intlTelInput.min.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="main-container">
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-sm-2 offset-sm-3">
|
||||
<a href="{{ path('change_language', {'lang':'fr'}) }}">🇫🇷 Français</a>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<a href="{{ path('change_language', {'lang':'en'}) }}">🇬🇧 English (UK)</a>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<a href="{{ path('change_language', {'lang':'ar'}) }}"> 🇸🇦 العربية</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- create a new account -->
|
||||
|
||||
{{ form_start(form, {'attr': {'class': 'register-form outer-top-xs'}}) }}
|
||||
|
||||
{% set formErrors = form.vars.errors.form.getErrors(true) %}
|
||||
|
||||
{% if formErrors|length %}
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
{% for key,error in formErrors %}
|
||||
<li><strong>{{ error.message }}</strong></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h3 class="checkout-subtitle">{{ 'your_personal_information'|trans }}</h3>
|
||||
<div class="row mt-3">
|
||||
<div class="col-md-4 col-sm-4">
|
||||
<div class="form-group">
|
||||
<label class="info-title">{{ form_label(form.gender) }} <span>*</span></label>
|
||||
{{ form_widget(form.gender, {'attr': {'class': 'form-control'}}) }}
|
||||
<span class="help-block">{{ form_errors(form.gender) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-4">
|
||||
<div class="form-group">
|
||||
<label class="info-title">{{ form_label(form.pseudo) }}</label>
|
||||
{{ form_widget(form.pseudo, {'attr': {'class': 'form-control'}}) }}
|
||||
<span class="help-block">{{ form_errors(form.pseudo) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-4">
|
||||
<div class="form-group">
|
||||
<label class="info-title">{{ form_label(form.birthdate) }} <span>*</span></label>
|
||||
{{ form_widget(form.birthdate, {'attr': {'placeholder': 'dd/mm/yyyy'}}) }}
|
||||
<span class="help-block">{{ form_errors(form.birthdate) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-sm-4">
|
||||
<div class="form-group">
|
||||
<label class="info-title">{{ form_label(form.phoneNumber) }} <span>*</span></label>
|
||||
{{ form_widget(form.phoneNumber, {'attr': {'class': 'form-control'}}) }}
|
||||
<span class="help-block">{{ form_errors(form.phoneNumber) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-3">
|
||||
<div class="form-group">
|
||||
<label class="info-title">{{ form_label(form.country) }}<span>*</span></label>
|
||||
<span class="help-block">{{ form_errors(form.country) }}</span>
|
||||
</div>
|
||||
{{ form_widget(form.country, {'attr': {'class': 'form-control'}}) }}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<h3 class="checkout-subtitle mt-5">{{ 'your_login_information'|trans }}</h3>
|
||||
|
||||
<div class="form-group mt-3">
|
||||
<label class="info-title">{{ form_label(form.email) }} <span>*</span></label>
|
||||
{{ form_widget(form.email, {'attr': {'class': 'form-control'}}) }}
|
||||
<span class="help-block">{{ form_errors(form.email) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-md-6 col-sm-6">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="info-title">{{ form_label(form.password.first) }} <span>*</span></label>
|
||||
{{ form_widget(form.password.first, {'attr': {'class': 'form-control'}}) }}
|
||||
<span class="help-block">{{ form_errors(form.password.first) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-6">
|
||||
<div class="form-group">
|
||||
<label class="info-title">{{ form_label(form.password.second) }} <span>*</span></label>
|
||||
{{ form_widget(form.password.second, {'attr': {'class': 'form-control'}}) }}
|
||||
<span class="help-block">{{ form_errors(form.password.second) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="form-group">
|
||||
{{ form_widget(form.cgu, {'attr': {'class': 'form-check-input'}}) }}
|
||||
<label class="form-check-label">{{ form_label(form.cgu) }}</label>
|
||||
</div>
|
||||
|
||||
{{ form_row(form.save) }}
|
||||
|
||||
{{ form_end(form) }}
|
||||
|
||||
|
||||
</div><!-- /.row -->
|
||||
</div>
|
||||
|
||||
<script src="{{ asset('assets/vendor/bootstrap@5.3.8/js/bootstrap.min.js') }}"></script>
|
||||
<script src="{{ asset('assets/vendor/country-select-js@2.1.0/build/js/countrySelect.js') }}"></script>
|
||||
<script src="{{ asset('assets/vendor/intl-tel-input@28.1.0/dist/js/intlTelInput.min.js') }}"></script>
|
||||
|
||||
<script>
|
||||
|
||||
// 1. Récupérer la locale du navigateur (ex: "fr-FR", "en-US")
|
||||
let browserLocale = navigator.language || navigator.userLanguage;
|
||||
|
||||
// 2. Extraire le code pays (les 2 dernières lettres après le tiret)
|
||||
// On passe en minuscule car country-select-js attend du minuscule (ex: "fr")
|
||||
let defaultCountryCode = "tn"; // Une valeur de secours (fallback) au cas où
|
||||
|
||||
if (browserLocale && browserLocale.includes('-')) {
|
||||
defaultCountryCode = browserLocale.split('-')[1].toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
$("#user_registration_country").countrySelect({
|
||||
defaultCountry: defaultCountryCode,
|
||||
preferredCountries: ['tn','fr'],
|
||||
excludeCountries: ["il"],
|
||||
nationalMode: false,
|
||||
formatOnDisplay: true,
|
||||
separateDialCode: true,
|
||||
autoHideDialCode: true,
|
||||
});
|
||||
|
||||
var phoneInputID = document.querySelector("#user_registration_phoneNumber");
|
||||
|
||||
// 1. Initialisation
|
||||
var iti = intlTelInput(phoneInputID, {
|
||||
nationalMode: false,
|
||||
formatOnDisplay: true,
|
||||
separateDialCode: true, // L'indicatif est masqué du champ de saisie
|
||||
autoHideDialCode: true,
|
||||
autoPlaceholder: "aggressive",
|
||||
initialCountry: defaultCountryCode,
|
||||
placeholderNumberType: "MOBILE",
|
||||
preferredCountries: ['tn', 'fr'],
|
||||
excludeCountries: ["il"],
|
||||
loadUtils: () =>
|
||||
import("{{ asset('assets/vendor/intl-tel-input@28.1.0/dist/js/utils.js') }}")
|
||||
.then((module) => {
|
||||
|
||||
window.intlTelInputUtils = module;
|
||||
|
||||
return module;
|
||||
}),
|
||||
});
|
||||
|
||||
// attendre le chargement
|
||||
iti.promise.then(() => {
|
||||
$(phoneInputID).on("countrychange", function(event) {
|
||||
|
||||
// Get the selected country data to know which country is selected.
|
||||
var selectedCountryData = iti.getSelectedCountryData();
|
||||
|
||||
// Get an example number for the selected country to use as placeholder.
|
||||
var newPlaceholder = intlTelInputUtils.getExampleNumber(selectedCountryData.iso2, true, intlTelInputUtils.numberFormat.INTERNATIONAL);
|
||||
|
||||
// Reset the phone number input.
|
||||
iti.setNumber("");
|
||||
|
||||
// Convert placeholder as exploitable mask by replacing all 1-9 numbers with 0s
|
||||
var mask = newPlaceholder.replace(/[1-9]/g, "0");
|
||||
|
||||
// Apply the new mask for the input
|
||||
$(this).mask(mask);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
{% trans_default_domain 'sign-up' %}
|
||||
|
||||
<html lang="{{ app.request.locale }}" dir="{{ app.request.locale == 'ar' ? 'rtl' : 'ltr' }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes">
|
||||
<title>Téléchargeur de vidéos YouTube</title>
|
||||
<!-- jQuery -->
|
||||
<script src="{{ asset('assets/vendor/jquery@4.0.0/jquery.min.js') }}"></script>
|
||||
<!-- Font Awesome pour les icônes -->
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/font-awesome@6.7.2/css/all.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/frontend.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/bootstrap@5.3.8/css/bootstrap.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/country-select-js@2.1.0/build/css/countrySelect.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/vendor/intl-tel-input@28.1.0/dist/css/intlTelInput.min.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div class="container mt-5">
|
||||
<h3>Téléchargement de la vidéo</h3>
|
||||
<button id="start-download" class="btn btn-primary mb-3">Lancer le téléchargement</button>
|
||||
|
||||
<div class="progress" style="height: 30px;">
|
||||
<div id="progress-bar" class="progress-bar progress-bar-striped progress-bar-animated"
|
||||
role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
|
||||
0%
|
||||
</div>
|
||||
</div>
|
||||
<div id="status" class="mt-2 text-muted">Prêt.</div>
|
||||
</div>
|
||||
|
||||
<script src="{{ asset('assets/vendor/bootstrap@5.3.8/js/bootstrap.min.js') }}"></script>
|
||||
<script src="{{ asset('assets/vendor/country-select-js@2.1.0/build/js/countrySelect.js') }}"></script>
|
||||
<script src="{{ asset('assets/vendor/intl-tel-input@28.1.0/dist/js/intlTelInput.min.js') }}"></script>
|
||||
|
||||
<script>
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#start-download').on('click', function() {
|
||||
const $progressBar = $('#progress-bar');
|
||||
const $status = $('#status');
|
||||
|
||||
$status.text('Téléchargement en cours...');
|
||||
$progressBar.css('width', '0%').attr('aria-valuenow', 0).text('0%');
|
||||
$(this).prop('disabled', true); // Désactive le bouton pendant le téléchargement
|
||||
|
||||
// On ouvre la connexion SSE vers notre route Symfony
|
||||
const eventSource = new EventSource("{{ path('app_streamed_download') }}");
|
||||
|
||||
eventSource.onmessage = function(event) {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
if (data.progress) {
|
||||
// Mise à jour de la barre avec jQuery
|
||||
$progressBar.css('width', data.progress + '%')
|
||||
.attr('aria-valuenow', data.progress)
|
||||
.text(data.progress + '%');
|
||||
}
|
||||
|
||||
// Si le script PHP a terminé
|
||||
if (data.done) {
|
||||
$status.text('Téléchargement terminé avec succès !');
|
||||
$progressBar.removeClass('progress-bar-animated').addClass('bg-success');
|
||||
eventSource.close(); // On ferme la connexion
|
||||
$('#start-download').prop('disabled', false);
|
||||
}
|
||||
};
|
||||
|
||||
eventSource.onerror = function(err) {
|
||||
console.error("Erreur SSE:", err);
|
||||
$status.text('Une erreur est survenue lors du téléchargement.');
|
||||
eventSource.close();
|
||||
$('#start-download').prop('disabled', false);
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user