LoopTube 2016 - Infinite Video Looper & Repeater
About this app
The ultimate YouTube video looper. Define start and end times to repeat your favorite sequences infinitely. Simple, colorful, and powerful video repeater.
LoopTube 2016 - Infinite Video Looper & Repeater LOOPTUBE 2016 Repeat any part of any video, forever. LOAD 00:00:00 LOOP ACTIVE START POINT 00:00:00 SET START AT CURRENT TIME END POINT 00:00:00 SET END AT CURRENT TIME TOGGLE LOOP SAVE LOOP SAVED LOOPS No saved sequences yet. Quick Tip Use the sliders or the 'Set At Current' buttons to define your perfect sequence. Great for learning guitar solos, choreography, or focused study! © 2016-2024 LoopTube Sequence Engine. All Video Content © YouTube.
Put this on your site
Source
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<title>LoopTube 2016 - Infinite Video Looper & Repeater</title>
<meta name="description" content="The ultimate YouTube video looper. Define start and end times to repeat your favorite sequences infinitely. Simple, colorful, and powerful video repeater.">
<meta name="keywords" content="YouTube looper, video repeater, repeat sequence, youtube loop, study loop, music looper, video clipper">
<!-- Libraries -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" crossorigin="anonymous">
<script type="text/javascript">
// Global variables for YouTube API
let player;
let loopTimer;
let startTime = 0;
let endTime = 0;
let duration = 0;
let isLooping = true;
let savedLoops = JSON.parse(localStorage.getItem('looptube_saves') || '[]');
try {
// Load YouTube IFrame API
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
window.onYouTubeIframeAPIReady = function() {
initPlayer('qMtcWqzZ8Mg'); // Default video: Lo-fi or similar
};
function initPlayer(videoId) {
if (player) {
player.loadVideoById(videoId);
return;
}
player = new YT.Player('player', {
height: '100%',
width: '100%',
videoId: videoId,
playerVars: {
'playsinline': 1,
'modestbranding': 1,
'rel': 0
},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(event) {
duration = player.getDuration();
endTime = duration;
updateSliderRange();
startLoopCheck();
updateUI();
}
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING) {
duration = player.getDuration();
if (endTime === 0 || endTime > duration) endTime = duration;
updateSliderRange();
}
}
function startLoopCheck() {
if (loopTimer) clearInterval(loopTimer);
loopTimer = setInterval(() => {
if (player && player.getCurrentTime && isLooping) {
let curr = player.getCurrentTime();
updateProgressIndicator(curr);
if (curr >= endTime) {
player.seekTo(startTime);
}
if (curr < startTime) {
player.seekTo(startTime);
}
}
}, 200);
}
function formatTime(seconds) {
let date = new Date(0);
date.setSeconds(seconds);
return date.toISOString().substr(11, 8);
}
function updateSliderRange() {
$('#start-slider').attr('max', duration).val(startTime);
$('#end-slider').attr('max', duration).val(endTime);
}
function updateUI() {
$('#start-val').text(formatTime(startTime));
$('#end-val').text(formatTime(endTime));
$('#loop-status').toggleClass('text-success', isLooping).toggleClass('text-muted', !isLooping);
$('#loop-status-icon').toggleClass('fa-sync-alt fa-spin', isLooping).toggleClass('fa-stop-circle', !isLooping);
renderSavedLoops();
}
function updateProgressIndicator(curr) {
let percent = (curr / duration) * 100;
$('#progress-bar-inner').css('width', percent + '%');
$('#current-time-display').text(formatTime(curr));
}
function extractVideoId(url) {
const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
const match = url.match(regExp);
return (match && match[2].length == 11) ? match[2] : null;
}
function renderSavedLoops() {
const container = $('#saved-loops-list');
container.empty();
savedLoops.forEach((item, index) => {
container.append(`
<div class="saved-item p-2 mb-2 d-flex justify-content-between align-items-center">
<div class="text-truncate flex-grow-1" style="cursor:pointer;" onclick="loadSavedLoop(${index})">
<small class="d-block fw-bold">${item.id}</small>
<small class="text-muted">${formatTime(item.start)} - ${formatTime(item.end)}</small>
</div>
<button class="btn btn-sm btn-outline-danger ms-2" onclick="deleteLoop(${index})">
<i class="fas fa-trash"></i>
</button>
</div>
`);
});
}
window.loadSavedLoop = function(index) {
let item = savedLoops[index];
initPlayer(item.id);
startTime = item.start;
endTime = item.end;
setTimeout(() => {
player.seekTo(startTime);
updateSliderRange();
updateUI();
}, 1000);
};
window.deleteLoop = function(index) {
savedLoops.splice(index, 1);
localStorage.setItem('looptube_saves', JSON.stringify(savedLoops));
renderSavedLoops();
};
document.addEventListener("DOMContentLoaded", function() {
$('#load-btn').click(() => {
let url = $('#video-url').val();
let id = extractVideoId(url);
if (id) {
initPlayer(id);
startTime = 0;
endTime = 0;
} else {
alert("Invalid YouTube URL");
}
});
$('#start-slider').on('input', function() {
startTime = parseFloat($(this).val());
if (startTime >= endTime) {
endTime = startTime + 1;
$('#end-slider').val(endTime);
}
updateUI();
});
$('#end-slider').on('input', function() {
endTime = parseFloat($(this).val());
if (endTime <= startTime) {
startTime = endTime - 1;
if (startTime < 0) startTime = 0;
$('#start-slider').val(startTime);
}
updateUI();
});
$('#set-start-now').click(() => {
startTime = player.getCurrentTime();
$('#start-slider').val(startTime);
updateUI();
});
$('#set-end-now').click(() => {
endTime = player.getCurrentTime();
$('#end-slider').val(endTime);
updateUI();
});
$('#toggle-loop').click(() => {
isLooping = !isLooping;
updateUI();
});
$('#save-loop').click(() => {
let videoId = player.getVideoData().video_id;
savedLoops.push({ id: videoId, start: startTime, end: endTime });
localStorage.setItem('looptube_saves', JSON.stringify(savedLoops));
renderSavedLoops();
});
renderSavedLoops();
});
} catch (error) {
console.error("App Error:", error);
}
</script>
<style>
:root {
--primary: #FF0000;
--secondary: #282828;
--accent: #00d2ff;
--bg-gradient: linear-gradient(135deg, #1e1e2f 0%, #2a2a40 100%);
}
body {
background: var(--bg-gradient);
color: #ffffff;
font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
min-height: 100vh;
}
#main-container {
padding: 1.5rem;
max-width: 1200px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 2rem;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
.header h1 {
font-weight: 800;
letter-spacing: -1px;
background: linear-gradient(to right, #ff0000, #ff8a00);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.card-glass {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
padding: 20px;
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3);
}
.video-wrapper {
position: relative;
width: 100%;
padding-top: 56.25%; /* 16:9 Aspect Ratio */
border-radius: 12px;
overflow: hidden;
background: #000;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
.video-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.controls-panel {
margin-top: 1.5rem;
}
.range-container {
padding: 15px 0;
}
input[type=range] {
width: 100%;
accent-color: var(--primary);
height: 8px;
border-radius: 5px;
background: #444;
outline: none;
}
.time-display {
font-family: 'Courier New', Courier, monospace;
font-size: 1.2rem;
color: var(--accent);
font-weight: bold;
}
.btn-action {
border-radius: 50px;
padding: 10px 20px;
font-weight: 600;
transition: all 0.3s ease;
border: none;
}
.btn-loop {
background: #FF0000;
color: white;
}
.btn-loop:hover {
background: #cc0000;
transform: scale(1.05);
}
.btn-outline-custom {
background: transparent;
border: 2px solid rgba(255,255,255,0.2);
color: white;
}
.btn-outline-custom:hover {
background: rgba(255,255,255,0.1);
border-color: white;
}
.saved-item {
background: rgba(255,255,255,0.08);
border-radius: 10px;
transition: background 0.2s;
}
.saved-item:hover {
background: rgba(255,255,255,0.15);
}
#progress-bar {
height: 6px;
background: #333;
width: 100%;
border-radius: 3px;
margin-top: 10px;
overflow: hidden;
}
#progress-bar-inner {
height: 100%;
background: var(--accent);
width: 0%;
transition: width 0.1s linear;
}
/* Animations */
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.6; }
100% { opacity: 1; }
}
.pulse {
animation: pulse 2s infinite;
}
@media (max-width: 768px) {
#main-container {
padding: 0.75rem;
}
.header h1 {
font-size: 1.8rem;
}
.btn-action {
padding: 8px 15px;
font-size: 0.9rem;
}
}
</style>
</head>
<body>
<div id="main-container">
<header class="header">
<h1><i class="fab fa-youtube"></i> LOOPTUBE 2016</h1>
<p class="text-secondary">Repeat any part of any video, forever.</p>
</header>
<div class="row g-4">
<!-- Main Player Area -->
<div class="col-lg-8">
<div class="card-glass h-100">
<div class="input-group mb-4">
<input type="text" id="video-url" class="form-control bg-dark text-white border-secondary" placeholder="Paste YouTube Link (e.g., https://www.youtube.com/watch?v=...)">
<button class="btn btn-danger px-4" id="load-btn">LOAD</button>
</div>
<div class="video-wrapper">
<div id="player"></div>
</div>
<div id="progress-bar">
<div id="progress-bar-inner"></div>
</div>
<div class="d-flex justify-content-between mt-1">
<small id="current-time-display" class="text-info">00:00:00</small>
<small id="loop-status" class="text-success fw-bold">
<i id="loop-status-icon" class="fas fa-sync-alt fa-spin"></i> LOOP ACTIVE
</small>
</div>
<div class="controls-panel mt-4">
<div class="row align-items-center">
<div class="col-md-6 range-container">
<div class="d-flex justify-content-between mb-1">
<label class="fw-bold"><i class="fas fa-step-backward text-danger"></i> START POINT</label>
<span class="time-display" id="start-val">00:00:00</span>
</div>
<input type="range" id="start-slider" step="0.1" value="0">
<button class="btn btn-sm btn-outline-custom mt-2 w-100" id="set-start-now">SET START AT CURRENT TIME</button>
</div>
<div class="col-md-6 range-container">
<div class="d-flex justify-content-between mb-1">
<label class="fw-bold"><i class="fas fa-step-forward text-warning"></i> END POINT</label>
<span class="time-display" id="end-val">00:00:00</span>
</div>
<input type="range" id="end-slider" step="0.1" value="0">
<button class="btn btn-sm btn-outline-custom mt-2 w-100" id="set-end-now">SET END AT CURRENT TIME</button>
</div>
</div>
<div class="d-flex flex-wrap gap-2 justify-content-center mt-4">
<button class="btn btn-action btn-loop px-5" id="toggle-loop">
<i class="fas fa-power-off me-2"></i> TOGGLE LOOP
</button>
<button class="btn btn-action btn-outline-custom" id="save-loop">
<i class="fas fa-bookmark me-2 text-warning"></i> SAVE LOOP
</button>
</div>
</div>
</div>
</div>
<!-- Sidebar Area -->
<div class="col-lg-4">
<div class="card-glass h-100">
<h4 class="mb-3"><i class="fas fa-history me-2 text-info"></i> SAVED LOOPS</h4>
<hr class="border-secondary">
<div id="saved-loops-list" style="max-height: 500px; overflow-y: auto; padding-right: 5px;">
<!-- Items populated via JS -->
<div class="text-center text-muted py-5">
<i class="fas fa-folder-open fa-3x mb-3 opacity-25"></i>
<p>No saved sequences yet.</p>
</div>
</div>
<div class="mt-4 p-3 rounded bg-dark border border-secondary">
<h6><i class="fas fa-lightbulb me-2 text-warning"></i> Quick Tip</h6>
<small class="text-secondary d-block">Use the sliders or the 'Set At Current' buttons to define your perfect sequence. Great for learning guitar solos, choreography, or focused study!</small>
</div>
</div>
</div>
</div>
<footer class="mt-5 text-center text-secondary py-3">
<small>© 2016-2024 LoopTube Sequence Engine. All Video Content © YouTube.</small>
</footer>
</div>
<script>
// Extra safety to ensure sliders update when user interacts with them directly
$('#start-slider, #end-slider').on('change', function() {
if (player && player.seekTo) {
player.seekTo($(this).val());
}
});
</script>
</body>
</html>
NEW APPS
These are apps made by the community!