Skip to content

Instantly share code, notes, and snippets.

@timrosskamp
Last active November 9, 2023 18:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timrosskamp/c22b67d979b5032a6a5cc644f7b3b324 to your computer and use it in GitHub Desktop.
Save timrosskamp/c22b67d979b5032a6a5cc644f7b3b324 to your computer and use it in GitHub Desktop.
Python server
from flask import Flask, send_from_directory, jsonify, request, Response
from functools import wraps
import os
app = Flask(__name__)
def check_auth(username, password):
"""This function is called to check if a username /
password combination is valid."""
return username == 'tim' and password == 'üöäüöä'
def authenticate():
"""Sends a 401 response that enables basic auth"""
return Response(
'Could not verify your access level for that URL.\n'
'You have to login with proper credentials', 401,
{'WWW-Authenticate': 'Basic realm="Login Required"'}
)
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
return authenticate()
return f(*args, **kwargs)
return decorated
# Serve the index.html file at the root.
@app.route('/')
@requires_auth
def index():
return app.send_static_file('index.html')
# Serve files from the 'static' subdirectory.
@app.route('/static/<path:path>')
def serve_static(path):
return send_from_directory('static', path)
# Endpoint that returns a JSON list of file names in the static directory.
@app.route('/api/files')
def list_files():
dir = 'static/videos'
files = os.listdir(dir)
files = [os.path.join('/', dir, f) for f in files if os.path.isfile(os.path.join(dir, f))]
return jsonify(files)
# Assuming this script is being run directly, start the Flask app.
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8888, debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: sans-serif;
background-color: rgb(46, 46, 46);
}
.item {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
}
video {
width: 100%;
height: 100%;
object-fit: contain;
}
</style>
</head>
<body>
<div class="scroller"></div>
<script type="module">
const $scroller = document.querySelector('.scroller')
let playingVideo = null
/** @param {HTMLVideoElement} $video */
function play($video) {
if( playingVideo && playingVideo != $video ) {
playingVideo.pause()
}
$video.play()
playingVideo = $video
}
/** @param {HTMLVideoElement} $video */
function pause($video) {
$video.pause()
playingVideo = null
}
// const observer = new IntersectionObserver(entries => {
// for( const entry of entries ) {
// if( entry.isIntersecting ) {
// const $item = entry.target
// const $video = $item.querySelector('video')
// if( $video && $video.paused && $video != playingVideo ) {
// if( playingVideo ) {
// playingVideo.pause()
// }
// playingVideo = $video
// $video.play()
// }
// const $nextVideo = $item.nextElementSibling.querySelector('video')
// if( $nextVideo ){
// $nextVideo.load()
// }
// }
// }
// }, {
// rootMargin: '0px',
// threshold: 0.75
// })
fetch('api/files').then(res => res.json()).then(files => {
for( const file of files ) {
const $item = document.createElement('div')
$item.classList.add('item')
if( file.endsWith('.mp4') ){
const $video = document.createElement('video')
$video.loop = true
$video.playsInline = true
$video.preload = 'none'
$video.innerHTML = `<source src="${file}" type="video/mp4">`
$item.addEventListener('click', e => {
if( $video.paused ){
play($video)
}else{
pause($video)
}
})
$item.appendChild($video)
}
$scroller.appendChild($item)
}
const firstVideo = document.querySelector('.item video')
if( firstVideo ){
firstVideo.load()
}
})
function scrollToNext() {
const $items = document.querySelectorAll('.item')
let next = null
let top = -1
$items.forEach((item, index) => {
let rect = item.getBoundingClientRect()
if( rect.top > 0 ) {
if( top == -1 || rect.top < top ) {
top = rect.top
next = item
}
}
})
if( next != null && top < window.innerHeight ){
next.scrollIntoView({ behavior: 'smooth' })
const video = next.querySelector('video')
if( video ){
play(video)
}
if( next.nextElementSibling ){
const nextVideo = next.nextElementSibling.querySelector('video')
if( nextVideo ){
nextVideo.load()
}
}
}
}
function scrollToPrev() {
const $items = document.querySelectorAll('.item')
let prev = null
let bottom = -1
$items.forEach((item, index) => {
let rect = item.getBoundingClientRect()
if( rect.bottom < window.innerHeight ) {
if( bottom == -1 || rect.bottom > bottom ) {
bottom = rect.bottom
prev = item
}
}
})
if( prev != null && bottom > 0 ){
prev.scrollIntoView({ behavior: 'smooth' })
const video = prev.querySelector('video')
if( video ){
play(video)
}
}
}
function scrollToCurrent() {
const $items = document.querySelectorAll('.item')
let current = null
let top = -1
$items.forEach((item, index) => {
let rect = item.getBoundingClientRect()
if( top == -1 || Math.abs(rect.top) < top ) {
top = Math.abs(rect.top)
current = item
}
})
if( current != null && top < window.innerHeight ){
current.scrollIntoView({ behavior: 'smooth' })
const video = current.querySelector('video')
if( video ){
play(video)
}
}
}
let moved = false
let startY = 0
let dY = 0
document.body.addEventListener('touchstart', e => {
startY = e.touches[0].clientY
moved = false
})
document.body.addEventListener('touchmove', e => {
dY = e.touches[0].clientY - startY
moved = true
})
document.body.addEventListener('touchend', e => {
if( !moved ){
return;
}
const threshold = window.innerHeight / 5
if( dY < -threshold ){
scrollToNext()
}
else if( dY > threshold ){
scrollToPrev()
}
else{
scrollToCurrent()
}
});
// document.body.addEventListener('keydown', e => {
// if( e.keyCode == 40 ){
// e.preventDefault()
// scrollToNext()
// }
// else if( e.keyCode == 38 ){
// e.preventDefault()
// scrollToPrev()
// }
// })
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment