{% extends 'base.html.twig' %}
{% block title %}
{{ video.influencer.name|title }}
Nude Video #{{ video.id }} - Share-Nude
{% endblock %}
{% block description %}Nude video #{{ video.id }} of {{ video.influencer.name|title }} MYM posted {% if video.user.username != 'Admin' %}by {{ video.user.username }} {% endif %}on {{ video.createdAt|date('Y-m-d') }}. More leaks of {{ video.influencer.name|title }} Onlyfans on Share-Nude{% endblock %}
{% block meta %}
<meta content="{{ video.influencer.name|title }} Nude Video #{{ video.id }}" property="og:title"/>
<meta content="Nude video #{{ video.id }} of {{ video.influencer.name|title }}{% if video.user.username != 'Admin' %} posted by {{ video.user.username }}{% endif %} on Share-Nude. More videos of {{ video.influencer.name|title }} on Share-Nude" property="og:description"/>
<meta content="Share-Nude" property="og:site_name"/>
<meta content="en_EN" property="og:locale"/>
<meta content="video.other" property="og:type"/>
<meta content="{{ video.embed }}" property="og:video:url"/>
<meta content="{{ video.embed }}" property="og:video:secure_url"/>
<meta content="https://share-nude.com{{ app.request.requestUri }}" property="og:url"/>
{% if video.webp is not null %}
<meta content="https://share-nude.com{{ asset('images/influencer/' ~ video.influencer.slug ~ '/306/' ~ video.webp) }}" property="og:image"/>
{% else %}
<meta content="https://share-nude.com{{ asset('images/influencer/' ~ video.influencer.slug ~ '/306/' ~ video.slug) }}" property="og:image"/>
{% endif %}
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:title" content="{{ video.influencer.name|title }} Nude Video #{{ video.id }}"/>
<meta name="twitter:description" content="Nude video #{{ video.id }} of {{ video.influencer.name|title }} on Share-Nude"/>
<meta name="twitter:image" content="https://share-nude.com{{ asset('images/influencer/' ~ video.influencer.slug ~ '/306/' ~ (video.webp ?? video.slug)) }}"/>
<link rel="canonical" href="{{sharenude|raw}}/v/{{ video.influencer.slug }}/{{ video.id }}"/>
{# Schema.org JSON-LD - VideoObject #}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "{{ video.influencer.name|title }} Nude Video #{{ video.id }}",
"description": "Nude video of {{ video.influencer.name|title }}{% if video.influencer.onlyfans|length > 0 %} ({{ video.influencer.onlyfans }} OnlyFans){% endif %}{% if video.influencer.mym|length > 0 %} ({{ video.influencer.mym }} MYM){% endif %} posted on Share-Nude",
"thumbnailUrl": "{{sharenude|raw}}{{ asset('images/influencer/' ~ video.influencer.slug ~ '/306/' ~ (video.webp ?? video.slug)) }}",
"uploadDate": "{{ video.createdAt|date('c') }}",
"url": "{{sharenude|raw}}/v/{{ video.influencer.slug }}/{{ video.id }}",
"embedUrl": "{{ video.embed }}",
"author": {
"@type": "Person",
"name": "{{ video.influencer.name|title }}",
"url": "{{sharenude|raw}}/i/{{ video.influencer.slug }}"
},
"publisher": {
"@type": "Organization",
"name": "Share-Nude",
"url": "{{sharenude|raw}}",
"logo": {
"@type": "ImageObject",
"url": "{{sharenude|raw}}{{ asset('sharenude.png') }}"
}
},
"interactionStatistic": {
"@type": "InteractionCounter",
"interactionType": "https://schema.org/ViewAction",
"userInteractionCount": {{ video.views }}
},
"commentCount": {{ comments|length }},
"comment": [
{% for c in comments|slice(0, 10) %}
{
"@type": "Comment",
"author": {"@type": "Person", "name": "{{ c.user.username|e('js') }}"},
"dateCreated": "{{ c.createdAt|date('c') }}",
"text": "{{ c.comment|e('js') }}"
}{% if not loop.last %},{% endif %}
{% endfor %}
]
}
</script>
{# BreadcrumbList for navigation #}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "{{sharenude|raw}}"
},
{
"@type": "ListItem",
"position": 2,
"name": "{{ video.influencer.name|title }}",
"item": "{{sharenude|raw}}/i/{{ video.influencer.slug }}"
},
{
"@type": "ListItem",
"position": 3,
"name": "Video #{{ video.id }}",
"item": "{{sharenude|raw}}/v/{{ video.influencer.slug }}/{{ video.id }}"
}
]
}
</script>
{% endblock %}
{% block body %}
<div class="container">
{% set breadcrumbs = [
{'label': video.influencer.name|title, 'url': path('app_influencer', {'slug': video.influencer.slug})},
{'label': 'Video #' ~ video.id, 'url': path('user_video', {'slug': video.influencer.slug, 'id': video.id})}
] %}
{{ include('partials/breadcrumb.html.twig') }}
<div class="row">
<div class="col-lg-12 mx-auto my-3 text-center white">
<h1>{{ video.influencer.name|title }} Nude Video #{{ video.id }}</h1>
{{ include ('flash.html.twig') }}
<!-- VIP Promo Banner -->
<div class="vip-promo-alert">
<a href="https://share-nude-vip.com" target="_blank" rel="noopener nofollow" class="vip-promo-link">
<span class="vip-icon">🌟</span>
<span class="vip-text">Share-Nude VIP - Toutes les vidéos exclusives sans pub pour seulement 1€</span>
<span class="vip-arrow">→</span>
</a>
</div>
<div class="ratio ratio-16x9 my-3 position-relative" id="video-player-container">
<!-- Preroll Overlay -->
<div id="preroll-overlay" class="preroll-overlay">
<div id="preroll-loader" class="preroll-loader">
<div class="preroll-spinner"></div>
<p>Loading ad...</p>
</div>
<video id="preroll-video" class="preroll-video" playsinline preload="auto">
<!-- Video source will be set dynamically by JavaScript -->
</video>
<button id="preroll-play-pause" class="preroll-play-pause" style="display: none;">
<i class="fas fa-pause"></i>
</button>
<div id="preroll-timer" class="preroll-timer" style="display: none;">
Skip ad in <span id="timer-seconds">10</span>s
</div>
<button id="skip-preroll-btn" class="skip-preroll-btn" style="display: none;">
Skip Ad
</button>
<div id="preroll-clickable" class="preroll-clickable"></div>
</div>
<!-- Real Video (hidden initially) -->
<iframe id="real-video" width="600" height="480" src="{{ video.embed }}" scrolling="no" frameborder="0" allowfullscreen="true" style="display: none;"></iframe>
</div>
{{ include('ads.html.twig') }}
{% if video.description|length > 0 %}
<p>{{ video.description }}</p>
{% endif %}
{% if app.user %}
<p>
{% if is_granted('ROLE_ADMIN') %}
<a href="{{ path('user_edit_video', {id:video.id}) }}" class="btn btn-secondary">Edit</a>
{% endif %}
{% if app.user == video.user or is_granted('ROLE_ADMIN') %}
<a href="{{ path('user_remove_video', {id:video.id}) }}" onclick="return confirm('Are you sure you want to delete this video ?');" class="btn btn-danger">Delete</a>
{% endif %}
</p>
{% endif %}
<p class="text-muted">Posted
{{ video.createdAt|ago }}
{% if video.user.username != 'Admin' and video.user.ip is not null %}by
<a href="{{ path('user_user', {username: video.user.username}) }}">{{ video.user.username }}</a>{% endif %}<br>{{ video.views|number_format }}
<i class="fa-solid fa-eye"></i>
</p>
<a href="{{path('app_influencer', {slug:video.influencer.slug})}}" title="More {{ video.influencer.name|title }} photos and videos">
{{ video.influencer.name }}{% if video.influencer.onlyfans|length > 0 %} / {{ video.influencer.onlyfans }} Onlyfans{% endif %}{% if video.influencer.mym|length > 0 %} / {{ video.influencer.mym }} MyM{% endif %}
<br>
{% if video.influencer.mainPhoto is not null %}
<picture>
{% if video.influencer.mainPhoto.webp is not null %}<source srcset="{{sharenude|raw}}{{ asset('images/influencer/' ~ video.influencer.slug ~ '/196/' ~ video.influencer.mainPhoto.webp ~ '') }}" type="image/webp">{% endif %}
<img loading="lazy" src="{{sharenude|raw}}{{ asset('images/influencer/' ~ video.influencer.slug ~ '/196/' ~ video.influencer.mainPhoto.slug ~ '') }}" class="rounded-circle" title="{{ video.influencer.name|title }} photo" alt="{{ video.influencer.name|title }} photo"/>
</picture>
{% endif %}
</a>
<br>
{% if video.influencer.videos|length > 1 %}
<h2 id="more-videos-title">{{ video.influencer.videos|length -1 }} More {{ video.influencer.name|title }} videos</h2>
{% endif %}
<div id="more-videos-container" class="row mt-4" data-influencer-id="{{ video.influencer.id }}" data-video-id="{{ video.id }}" data-influencer-name="{{ video.influencer.name|title }}"></div>
<div id="load-more-videos-button-container" class="text-center mt-4">
<button id="load-more-videos-btn" class="btn btn-primary">
Show more {{ video.influencer.name|title }} videos
</button>
</div>
{{ include('comments.html.twig') }}
<p class="text-muted mt-4">
Is this "{{ video.influencer.name|title }}" video yours and was shared without your consent?
<a href="mailto:[email protected]?subject=[DMCA on Share-Nude] Unauthorized Content Removal Request - {{ video.influencer.name|title }} &body=Url : {{sharenude|raw}} /v/{{ video.influencer.slug }}/{{ video.id }}%0D%0APlease provide details about the content in question">
<br>
<button class="btn btn-sm btn-outline-danger"> Click here to reach out to us for removal.</button>
</a>
<br>
Video will be deleted within fews days.
</p>
</div>
</div>
</div>
{% endblock %}
{% block javascripts %}
<script>
// Preroll Ad System
function initPreroll() {
const prerollOverlay = document.getElementById('preroll-overlay');
const prerollVideo = document.getElementById('preroll-video');
const skipBtn = document.getElementById('skip-preroll-btn');
const realVideo = document.getElementById('real-video');
const prerollClickable = document.getElementById('preroll-clickable');
const timerElement = document.getElementById('preroll-timer');
const timerSeconds = document.getElementById('timer-seconds');
const playPauseBtn = document.getElementById('preroll-play-pause');
const prerollLoader = document.getElementById('preroll-loader');
if (!prerollOverlay || !prerollVideo || !skipBtn || !realVideo || !timerElement || !timerSeconds || !playPauseBtn || !prerollLoader) return;
// Array of preroll videos with tracking names
const prerollVideos = [
{ file: 'julie.MOV', name: 'julie' },
{ file: '004_fr.mp4', name: '004_fr' },
{ file: '006_fr.mp4', name: '006_fr' },
{ file: 'Afroditee-fr.mp4', name: 'Afroditee-fr' },
{ file: 'sn-vip.mp4', name: 'sn-vip' }
];
// Randomly select a video (rand 4)
const selectedVideo = prerollVideos[Math.floor(Math.random() * prerollVideos.length)];
// Set video source dynamically
prerollVideo.src = '{{ asset('') }}' + selectedVideo.file;
// Build tracking URL - julie uses direct Telegram link, sn-vip uses VIP access, others use tracking
let trackingUrl;
if (selectedVideo.name === 'julie') {
trackingUrl = 'https://t.me/m/I74uPFutOTY1';
} else if (selectedVideo.name === 'sn-vip') {
trackingUrl = 'https://acces.share-nude-vip.com';
} else {
trackingUrl = 'https://go.mavrtracktor.com?sourceId=sharenude&creativeId=preroll&campaignId=' + selectedVideo.name + '&userId=ff9cd0158a2d244c452cbcbc061440b1763a55f068539e459404ba4934dae07b';
}
let countdown = 10;
let isPlaying = true;
let loaderHidden = false;
// Function to hide loader and show controls
function showControls() {
if (loaderHidden) return; // Already hidden
loaderHidden = true;
prerollLoader.style.display = 'none';
playPauseBtn.style.display = 'flex';
timerElement.style.display = 'block';
}
// Update play/pause button icon
function updatePlayPauseIcon() {
const icon = playPauseBtn.querySelector('i');
if (isPlaying) {
icon.className = 'fas fa-pause';
} else {
icon.className = 'fas fa-play';
}
}
// Start countdown timer
function startCountdown() {
currentCountdownInterval = setInterval(() => {
countdown--;
timerSeconds.textContent = countdown;
if (countdown <= 0) {
clearInterval(currentCountdownInterval);
timerElement.style.display = 'none';
skipBtn.style.display = 'block';
}
}, 1000);
}
// Function to start video playback
async function startVideo() {
try {
// Try to play with sound first
prerollVideo.muted = false;
await prerollVideo.play();
showControls();
clearTimeout(currentPrerollTimeout);
isPlaying = true;
updatePlayPauseIcon();
startCountdown();
} catch (error) {
// If autoplay with sound fails (Chrome policy), try muted
try {
prerollVideo.muted = true;
await prerollVideo.play();
showControls();
clearTimeout(currentPrerollTimeout);
isPlaying = true;
updatePlayPauseIcon();
startCountdown();
} catch (mutedError) {
clearTimeout(currentPrerollTimeout);
hidePreroll();
}
}
}
// Wait for video to be ready before playing
let videoStarted = false;
function onVideoReady() {
if (videoStarted) return; // Prevent double start
videoStarted = true;
startVideo();
}
// Try to play immediately, with retries
let playAttempts = 0;
const maxAttempts = 20;
async function tryPlay() {
if (videoStarted) return;
playAttempts++;
try {
// Check if video has any data
if (prerollVideo.readyState >= 1) {
onVideoReady();
return;
}
} catch (e) {}
// Retry after delay if not started
if (playAttempts < maxAttempts && !videoStarted) {
setTimeout(tryPlay, 250);
}
}
// Event listeners as backup
prerollVideo.addEventListener('canplay', onVideoReady, { once: true });
prerollVideo.addEventListener('loadedmetadata', onVideoReady, { once: true });
// Force reload and start trying to play
prerollVideo.load();
setTimeout(tryPlay, 100);
// Safety timeout: skip preroll after 5 seconds if video doesn't start
currentPrerollTimeout = setTimeout(() => {
if (!videoStarted) {
hidePreroll();
}
}, 5000);
// Play/Pause button handler
playPauseBtn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
if (isPlaying) {
// Pause video and timer
prerollVideo.pause();
clearInterval(currentCountdownInterval);
isPlaying = false;
} else {
// Resume video and timer
prerollVideo.play();
startCountdown();
isPlaying = true;
}
updatePlayPauseIcon();
});
// Function to hide preroll and show real video
function hidePreroll() {
prerollOverlay.style.display = 'none';
realVideo.style.display = 'block';
prerollVideo.pause();
clearInterval(currentCountdownInterval);
clearInterval(currentPollInterval);
clearTimeout(currentPrerollTimeout);
}
// Skip button click handler
skipBtn.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
hidePreroll();
});
// Clickable area handler - open tracking link and hide preroll
prerollClickable.addEventListener('click', (e) => {
e.preventDefault();
window.open(trackingUrl, '_blank', 'noopener,noreferrer');
hidePreroll();
});
// When preroll ends, show real video automatically
prerollVideo.addEventListener('ended', hidePreroll);
// Handle video errors - skip preroll if video fails to load
prerollVideo.addEventListener('error', hidePreroll);
}
// Variables globales pour stocker les handlers et permettre le nettoyage
let currentScrollHandler = null;
let currentTouchMoveHandler = null;
let currentPrerollTimeout = null;
let currentCountdownInterval = null;
let currentPollInterval = null;
// Fonction pour nettoyer les event listeners et timeouts
function cleanupEventListeners() {
if (currentScrollHandler) {
window.removeEventListener('scroll', currentScrollHandler);
currentScrollHandler = null;
}
if (currentTouchMoveHandler) {
window.removeEventListener('touchmove', currentTouchMoveHandler);
currentTouchMoveHandler = null;
}
// Nettoyer les timeouts et intervals du preroll
if (currentPrerollTimeout) {
clearTimeout(currentPrerollTimeout);
currentPrerollTimeout = null;
}
if (currentCountdownInterval) {
clearInterval(currentCountdownInterval);
currentCountdownInterval = null;
}
if (currentPollInterval) {
clearInterval(currentPollInterval);
currentPollInterval = null;
}
// Mettre en pause la vidéo preroll si elle existe
const prerollVideo = document.getElementById('preroll-video');
if (prerollVideo) {
prerollVideo.pause();
}
}
function initVideoPage() {
// Nettoyer les listeners de la page précédente
cleanupEventListeners();
// Récupérer les éléments à chaque fois car ils peuvent changer avec Swup
function getElements() {
return {
container: document.getElementById('more-videos-container'),
loadMoreBtn: document.getElementById('load-more-videos-btn'),
loadMoreBtnContainer: document.getElementById('load-more-videos-button-container')
};
}
const elements = getElements();
if (!elements.container) return;
// Récupérer dynamiquement les IDs et le nom depuis les attributs data (pour éviter les conflits avec Swup)
const influencerId = elements.container.getAttribute('data-influencer-id');
const videoId = elements.container.getAttribute('data-video-id');
const influencerName = elements.container.getAttribute('data-influencer-name');
if (!influencerId || !videoId || !influencerName) {
console.error('Missing influencer ID, video ID or influencer name');
return;
}
// Réinitialiser TOUTES les variables à chaque appel pour éviter les conflits entre pages
let nextPage = 1;
let isLoading = false;
let hasMoreVideos = true;
const loadedVideoIds = new Set();
const basePath = '/load-more-influencer-videos';
// Vider le conteneur pour éviter d'afficher les vidéos de la page précédente
elements.container.innerHTML = '';
// Supprimer les anciens event listeners en clonant le bouton
if (elements.loadMoreBtn) {
const newBtn = elements.loadMoreBtn.cloneNode(true);
elements.loadMoreBtn.parentNode.replaceChild(newBtn, elements.loadMoreBtn);
}
// Supprimer l'ancien listener de scroll s'il existe
if (window._videoScrollHandler) {
window.removeEventListener('scroll', window._videoScrollHandler);
window.removeEventListener('touchmove', window._videoScrollHandler);
}
function updateButtonVisibility() {
const elements = getElements();
// Récupérer le nom de l'influenceur depuis les attributs data
const currentInfluencerName = elements.container.getAttribute('data-influencer-name');
if (elements.loadMoreBtnContainer) {
if (!hasMoreVideos) {
elements.loadMoreBtnContainer.style.display = 'none';
} else {
elements.loadMoreBtnContainer.style.display = 'block';
}
}
if (elements.loadMoreBtn) {
elements.loadMoreBtn.disabled = isLoading || !hasMoreVideos;
if (isLoading) {
elements.loadMoreBtn.textContent = 'Loading...';
} else {
elements.loadMoreBtn.textContent = 'Show more ' + currentInfluencerName + ' videos';
}
}
}
function buildUrl(page) {
return basePath + '/' + page + '?influencer=' + influencerId + '&video=' + videoId;
}
function handleScroll() {
if (isLoading || !hasMoreVideos) return;
const footer = document.getElementById('footer') ? document.getElementById('footer').offsetHeight : 0;
const scrollPosition = window.innerHeight + window.scrollY;
const documentHeight = document.body.offsetHeight;
if (scrollPosition >= documentHeight - 600 - footer) {
loadMoreVideos();
}
}
// Stocker le handler pour pouvoir le supprimer plus tard
window._videoScrollHandler = handleScroll;
function getVideoIdFromElement(element) {
const link = element.querySelector('a[href*="/v/"]');
if (link) {
const href = link.getAttribute('href');
const match = href.match(/\/v\/[^\/]+\/(\d+)/);
if (match) {
return match[1];
}
}
return null;
}
function loadMoreVideos() {
if (isLoading || !hasMoreVideos) return;
isLoading = true;
updateButtonVisibility();
const url = buildUrl(nextPage);
fetch(url)
.then(response => response.text())
.then(data => {
const elements = getElements();
if (data.trim() === '') {
hasMoreVideos = false;
isLoading = false;
updateButtonVisibility();
return;
}
const tempDiv = document.createElement('div');
tempDiv.innerHTML = data;
const newElements = Array.from(tempDiv.querySelectorAll('.col-lg-3'));
if (elements.container && newElements.length > 0) {
let addedCount = 0;
newElements.forEach(element => {
const vidId = getVideoIdFromElement(element);
if (!vidId || !loadedVideoIds.has(vidId)) {
elements.container.appendChild(element);
if (vidId) {
loadedVideoIds.add(vidId);
}
addedCount++;
}
});
if (newElements.length < 4) {
hasMoreVideos = false;
} else if (addedCount === 0) {
hasMoreVideos = false;
} else {
nextPage += 1;
}
} else {
hasMoreVideos = false;
}
isLoading = false;
updateButtonVisibility();
})
.catch(error => {
console.error('Error loading videos:', error);
isLoading = false;
hasMoreVideos = false;
updateButtonVisibility();
});
}
// Gérer le clic sur le bouton avec plusieurs types d'événements pour iOS
const elementsAfterClone = getElements();
if (elementsAfterClone.loadMoreBtn) {
elementsAfterClone.loadMoreBtn.addEventListener('click', loadMoreVideos);
elementsAfterClone.loadMoreBtn.addEventListener('touchend', function(e) {
e.preventDefault();
loadMoreVideos();
});
}
// Stocker et attacher l'événement de scroll avec plusieurs types pour iOS
currentScrollHandler = handleScroll;
currentTouchMoveHandler = handleScroll;
window.addEventListener('scroll', currentScrollHandler, { passive: true });
window.addEventListener('touchmove', currentTouchMoveHandler, { passive: true });
// Initialiser la visibilité du bouton
updateButtonVisibility();
}
// Variable pour éviter les doubles initialisations
let isInitializing = false;
// Fonction wrapper pour initialiser avec vérification
function safeInit() {
// Éviter les doubles initialisations simultanées
if (isInitializing) return;
isInitializing = true;
// Vérifier que nous sommes sur une page vidéo avant d'initialiser le preroll
const prerollOverlay = document.getElementById('preroll-overlay');
if (prerollOverlay) {
initPreroll();
}
initVideoPage();
// Reset après un délai
setTimeout(() => {
isInitializing = false;
}, 500);
}
// Initialiser au chargement de la page
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', safeInit);
} else {
safeInit();
}
// Réinitialiser après chaque changement de page Swup
if (typeof Swup !== 'undefined') {
// Nettoyer avant le changement de page
document.addEventListener('swup:willReplaceContent', function() {
cleanupEventListeners();
});
// Utiliser uniquement animationInDone pour éviter les doubles appels
document.addEventListener('swup:animationInDone', function() {
setTimeout(safeInit, 250);
});
}
</script>
{% endblock %}