diff --git a/README.md b/README.md index 11f544e..6eb56b6 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,88 @@ -# KittyPlayer -Video player library for web pages with modern design in css and javaScript +# KittyPlayer-lib +KittyPlayer-lib is a library of components for creating modern and customizable video players. + +## Installation +You can install KittyPlayer-lib via npm: + +```bash +npm i kittyplayer +``` + +To use KittyPlayer-lib, first ensure you include the library in your project. Then, you can create a KittyPlayer instance and add it to your page: + +```html + + + +``` + +These two files must always be imported so that the library works 100% and does not fail. + +# Components + +KittyPlayer-lib includes a variety of components for customizing and enhancing the video playback experience, such as customizable controls, play buttons, progress bars, and more: + +## Warning ⚠ + +adding this is very important to be able to use the library + +```html +
+ +
+
❚❚
+
+ + +
00:00 / 00:00
+
+ +
+ +
+
+ +
+
+``` + +# Video Player Components + +- `.video-container` (`div`) - Main container of the video player. + - `.video` (`video`) - Video element. + - `.seek-icon` (`div`) - Seek icon. + - `.pause-icon` (`div`) - Pause icon. + - `.controls` (`div`) - Player controls. + - `#playPause` (`button`) - Play/pause button. + - Play/pause icon (`i` with class `fas fa-play`). + - `#progress` (`input[type="range"]`) - Progress bar. + - `#time` (`div`) - Elapsed time/duration of the video. + - `#volumeContainer` (`div`) - Volume container. + - `#volume` (`input[type="range"]`) - Volume control. + - `#volumeIcon` (`div`) - Volume icon (`i` with class `fas fa-volume-up`). + - `#fullscreen` (`button`) - Fullscreen button (`i` with class `fas fa-expand`). + +## Images + +
+ Preview 1 + + ![Image 1](path_to_image_1) + ![Image 2](path_to_image_2) +
+ +
+ Preview 2 + + ![Image 3](path_to_image_3) + ![Image 4](path_to_image_4) +
+ +# Contribution + +Feel free to contribute to KittyPlayer-lib! You can submit suggestions, report bugs, or add new components through pull requests. + + + \ No newline at end of file diff --git a/package.json b/package.json index 04af01d..036ac7c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kittyplayer", - "version": "0.0.1", + "version": "0.0.2", "description": "📦 Browser video player library", "main": "src/scripts/js/PlayVideo-Script.js", "repository": { diff --git a/src/components/video/playVideo.css b/src/components/video/playVideo.css index e02f959..b9bd10d 100644 --- a/src/components/video/playVideo.css +++ b/src/components/video/playVideo.css @@ -121,4 +121,51 @@ body { display: flex; justify-content: center; align-items: center; -} \ No newline at end of file +} + +.seek-icon { + display: none; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 3em; + color: white; + background-color: rgba(0, 0, 0, 0.5); + padding: 10px 20px; + border-radius: 10px; + z-index: 1000; +} + +@keyframes slideIn { + from { + transform: translateY(-100%); + } + to { + transform: translateY(0); + } +} + +@keyframes slideOut { + from { + transform: translateY(0); + } + to { + transform: translateY(-100%); + } +} + +.alert { + position: fixed; + top: 2rem; + left: 50%; + transform: translateX(-50%); + padding: 1rem 2rem; + background-color: #f56565; + color: #fff; + border-radius: 0.25rem; + animation: slideIn 0.5s forwards, slideOut 0.5s forwards 2.5s; + opacity: 0; + display: none; +} + diff --git a/src/html/example.html b/src/html/example.html index f54815e..a53860f 100644 --- a/src/html/example.html +++ b/src/html/example.html @@ -1,11 +1,12 @@ - + KittyPlayer +
@@ -15,19 +16,23 @@
+
❚❚
- +
00:00 / 00:00
- - 🔊 - +
+ +
+ +
+
-
+
4k nature video (Test video)
diff --git a/src/icons/fullscreen-icon.svg b/src/icons/fullscreen-icon.svg deleted file mode 100644 index dcc2c62..0000000 --- a/src/icons/fullscreen-icon.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/scripts/js/PlayVideo-Script.js b/src/scripts/js/PlayVideo-Script.js index c7a65b6..dcdf3fb 100644 --- a/src/scripts/js/PlayVideo-Script.js +++ b/src/scripts/js/PlayVideo-Script.js @@ -6,9 +6,9 @@ const pauseIcon = document.getElementById('pauseIcon'); const fullscreenBtn = document.getElementById('fullscreen'); const videoContainer = document.getElementById('videoContainer'); const controls = document.getElementById('controls'); -const volumeUpBtn = document.getElementById('volumeUp'); -const volumeDownBtn = document.getElementById('volumeDown'); +const volumeSlider = document.getElementById('volume'); const volumeIcon = document.getElementById('volumeIcon'); +const volumeContainer = document.getElementById('volumeContainer'); playPauseBtn.addEventListener('click', togglePlayPause); video.addEventListener('click', togglePlayPause); @@ -16,21 +16,65 @@ video.addEventListener('timeupdate', updateProgress); progress.addEventListener('input', setVideoProgress); fullscreenBtn.addEventListener('click', toggleFullscreen); videoContainer.addEventListener('mousemove', showControls); -volumeUpBtn.addEventListener('click', increaseVolume); -volumeDownBtn.addEventListener('click', decreaseVolume); +volumeSlider.addEventListener('input', setVolume); +volumeContainer.addEventListener('mouseenter', showVolumeSlider); +volumeContainer.addEventListener('mouseleave', hideVolumeSlider); let hideControlsTimeout; +let customAlert; + +video.addEventListener('contextmenu', function(event) { + event.preventDefault(); // Prevenir el menú contextual + + const alertElement = document.createElement('div'); + alertElement.className = 'alert'; + alertElement.textContent = 'Right click not allowed'; + + document.body.appendChild(alertElement); + + // Mostrar la alerta con la animación de entrada + alertElement.style.opacity = '1'; + alertElement.style.display = 'block'; + alertElement.style.animation = 'slideIn 0.5s forwards'; + + // Programar la ocultación de la alerta después de 2 segundos + setTimeout(() => { + alertElement.style.animation = 'slideOut 0.5s forwards'; + setTimeout(() => { + document.body.removeChild(alertElement); + }, 500); // Eliminar la alerta después de la animación de salida + }, 2000); // Ocultar la alerta después de 2 segundos +}); + + +function showVolumeSlider() { + volumeSlider.style.display = 'block'; +} + +function hideVolumeSlider() { + volumeSlider.style.display = 'none'; +} + +let lastToggleTime = 0; +const toggleDelay = 500; function togglePlayPause() { + const now = Date.now(); + if (now - lastToggleTime < toggleDelay) { + return; + } + if (video.paused || video.ended) { video.play(); - playPauseBtn.textContent = 'Pause'; + playPauseBtn.innerHTML = ''; pauseIcon.classList.remove('active'); } else { video.pause(); - playPauseBtn.textContent = 'Play'; + playPauseBtn.innerHTML = ''; pauseIcon.classList.add('active'); } + + lastToggleTime = now; } function updateProgress() { @@ -78,32 +122,26 @@ hideControlsTimeout = setTimeout(() => { controls.classList.add('hidden'); }, 2000); -function increaseVolume() { - if (video.volume < 1) { - video.volume = Math.min(1, video.volume + 0.1); - updateVolumeIcon(); - } -} - -function decreaseVolume() { - if (video.volume > 0) { - video.volume = Math.max(0, video.volume - 0.1); - updateVolumeIcon(); - } +function setVolume() { + video.volume = volumeSlider.value; + updateVolumeIcon(); } function updateVolumeIcon() { if (video.volume === 0) { - volumeIcon.innerHTML = '🔇'; // Mute icon + volumeIcon.innerHTML = ''; } else if (video.volume < 0.5) { - volumeIcon.innerHTML = '🔉'; // Volume down icon + volumeIcon.innerHTML = ''; } else { - volumeIcon.innerHTML = '🔊'; // Volume up icon + volumeIcon.innerHTML = ''; } } document.addEventListener('keydown', handleKeyPress); +let lastSeekTime = 0; +const seekDelay = 500; + function handleKeyPress(event) { const arrowLeftKeyCode = 37; const arrowRightKeyCode = 39; @@ -125,19 +163,39 @@ function handleKeyPress(event) { } function animateSeek(targetTime) { + const now = Date.now(); + if (now - lastSeekTime < seekDelay) { + return; + } + + lastSeekTime = now; + const start = video.currentTime; const end = targetTime; const duration = Math.abs(end - start); const startTime = performance.now(); + const seekIconClass = end > start ? 'forward' : 'backward'; + const seekIcon = document.getElementById('seekIcon'); + seekIcon.innerHTML = `${end > start ? '>>' : '<<'} ${Math.abs(end - start)}s`; + seekIcon.classList.add(seekIconClass); + seekIcon.style.display = 'block'; + function update() { const elapsed = performance.now() - startTime; const progress = Math.min(elapsed / duration, 1); const easedProgress = easeOutQuart(progress); video.currentTime = start + (end - start) * easedProgress; + seekIcon.innerHTML = end > start ? '>>' : '<<'; + if (progress < 1) { requestAnimationFrame(update); + } else { + setTimeout(() => { + seekIcon.style.display = 'none'; + seekIcon.classList.remove(seekIconClass); + }, 500); } } @@ -146,75 +204,4 @@ function animateSeek(targetTime) { function easeOutQuart(x) { return 1 - Math.pow(1 - x, 4); -} - - -const videoInfo = document.createElement('div'); -videoInfo.id = 'videoInfo'; -videoInfo.classList.add('hidden'); -document.body.appendChild(videoInfo); - -const style = document.createElement('style'); -style.innerHTML = ` - #videoInfo { - position: absolute; - background: rgba(0, 0, 0, 0.8); - color: white; - padding: 15px; - border-radius: 8px; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); - z-index: 1000; - max-width: 300px; - font-family: Arial, sans-serif; - } - #videoInfo.hidden { - display: none; - } - #videoInfo strong { - display: block; - margin-bottom: 10px; - font-size: 16px; - } - #videoInfo p { - margin: 5px 0; - } - #videoInfo .section-title { - margin-top: 10px; - font-size: 14px; - text-decoration: underline; - } -`; -document.head.appendChild(style); - -function showVideoInfo(event) { - event.preventDefault(); - - const libraryName = "KittyPlayer Lib"; - const developerName = "Developer: Sstudiosdev"; - - const currentTime = formatTime(video.currentTime); - const duration = formatTime(video.duration); - const volume = Math.round(video.volume * 100); - const isPaused = video.paused ? 'Yes' : 'No'; - - videoInfo.innerHTML = ` - Video Player information -

${libraryName}

-

${developerName}

-
Video Information
-

Current Time: ${currentTime}

-

Duration: ${duration}

-

Volume: ${volume}%

-

Paused: ${isPaused}

- `; - - videoInfo.style.top = `${event.clientY}px`; - videoInfo.style.left = `${event.clientX}px`; - videoInfo.classList.remove('hidden'); -} - -video.addEventListener('contextmenu', showVideoInfo); - -document.addEventListener('click', () => { - videoInfo.classList.add('hidden'); -}); \ No newline at end of file +} \ No newline at end of file