Makes IPFS video chain

This commit is contained in:
fred 2022-04-07 02:14:21 +02:00
parent aa99769de5
commit 5da57550d2
16 changed files with 2580 additions and 3 deletions

View File

@ -1,6 +1,29 @@
# bunkerbox
Chaine video IPFS.
Source: https://crowdbunker.com
PUBLICATION : https://tube.copylaradio.com/ipns/k51qzi5uqu5djt17zonkpg1cb8hrxhahpesybusz8q57j4ocqm0qlc6s99z60x
Sauvegarde de Chaine video dans IPFS / IPNS.
- Source : https://crowdbunker.com
En suivant le même principe, on peut facilement créer des chaines de vidéos depuis d'autres sources (webcam, etc...)
```
# INSTALL
mkdir ~/workspace && cd ~/workspace
git clone https://git.p2p.legal/qo-op/bunkerbox.git
# RUN
cd ~/workspace/bunkerbox
./crowdbunker.sh
```
# Explications
crowdbunker.sh est une boucle qui inscrit les denrières vidéos dans une liste publiée au travers d'une chaine de vidéos.
- PUBLICATION qo-op DEV : https://tube.copylaradio.com/ipns/k51qzi5uqu5djt17zonkpg1cb8hrxhahpesybusz8q57j4ocqm0qlc6s99z60x
1. Récupère la liste des 30 dernières video publiées sur https://crowdbunker.com
2. Télécharge les fichiers video et audio (360p de préférence) et leurs fichiers m3u8
3. Ajoute le lecteur videojs dans index.html et met à jour history.json
4. Publie localement ou sur la clef IPFS qo-op ou au travers du TestNet astrXbian
Pour revenir en mode "debug", effacez le fichier ~/.zen/bunkerbox/choice

244
crowdbunker.sh Executable file
View File

@ -0,0 +1,244 @@
#!/bin/bash
################################################################################
# Author: Fred (support@qo-op.com)
# Version: 0.1
# License: AGPL-3.0 (https://choosealicense.com/licenses/agpl-3.0/)
################################################################################
mkdir -p ~/.zen/bunkerbox # BunkerBOX temp directory
# Fred MadeInZion, [20/03/2022 23:03]
# Script qui capture et transfert dans IPFS le flux des nouvelles vidéos de https://crowdbunker.com/
# le resultat est inscrit dans une chaine video accessible localement ou publiée au travers de qo-op
# ou du TestNET astrXbian, videoclub entre amis d'amis...
MY_PATH="`dirname \"$0\"`" # relative
MY_PATH="`( cd \"$MY_PATH\" && pwd )`" # absolutized and normalized
ME="${0##*/}"
TS=$(date -u +%s%N | cut -b1-13)
[[ ! $(which ipfs) ]] && echo "EXIT. Vous devez avoir installé ipfs CLI sur votre ordinateur" && echo "RDV sur https://dist.ipfs.io/#go-ipfs" && exit 1
YOU=$(ps auxf --sort=+utime | grep -w ipfs | grep -v -E 'color=auto|grep' | tail -n 1 | cut -d " " -f 1) || echo " warning ipfs daemon not running"
isLAN=$(hostname -I | awk '{print $1}' | head -n 1 | cut -f3 -d '/' | grep -E "(^127\.)|(^192\.168\.)|(^fd42\:)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^::1$)|(^[fF][cCdD])/")
IPFSNGW="https://tube.copylaradio.com"
IPFSNGW="http://127.0.0.1:8080"
[[ ! $isLAN ]] && IPFSNGW="https://$(hostname)"
echo "IPFS GATEWAY $IPFSNGW"
## GET LATEST VIDEOS
VWALLURL="https://api.crowdbunker.com/post/all"
curl -s $VWALLURL -H "Accept: application/json" > ~/.zen/bunkerbox/crowd.json
## LOOP THROUGH
for VUID in $(cat ~/.zen/bunkerbox/crowd.json | jq -r '.posts | .[] | .video.id'); do
[[ "$VUID" == "null" ]] && echo "MESSAGE... Bypassing..." && echo && continue
echo "Bunker BOX : Adding $VUID"
mkdir -p ~/.zen/bunkerbox/$VUID/media
URL="https://api.crowdbunker.com/post/$VUID/details"
# echo "WISHING TO EXPLORE $URL ?"; read TEST; [[ "$TEST" != "" ]] && echo && continue
curl -s $URL -H "Accept: application/json" -o ~/.zen/bunkerbox/$VUID/$VUID.json
# STREAMING LIVE ?
echo ">>> Extracting video caracteristics from ~/.zen/bunkerbox/$VUID/$VUID.json"
ISLIVE=$(cat ~/.zen/bunkerbox/$VUID/$VUID.json | jq -r .video.isLiveType)&& [[ "$ISLIVE" == "true" ]] && echo "LIVE... "
LIVE=$(cat ~/.zen/bunkerbox/$VUID/$VUID.json | jq -r .video.isLiveActive) && [[ "$LIVE" == "true" ]] && echo "STREAMING... Bypassing..." && echo && continue
DURATION=$(cat ~/.zen/bunkerbox/$VUID/$VUID.json | jq -r .video.duration) && [[ $DURATION == 0 ]] && echo "NOT STARTED YET" && echo && continue
TITLE=$(cat ~/.zen/bunkerbox/$VUID/$VUID.json | jq -r .video.title | sed "s/'/ /g" | sed 's/"/ /g') # Remove quote
CHANNEL=$(cat ~/.zen/bunkerbox/$VUID/$VUID.json | jq -r .channel.name)
ORGUID=$(cat ~/.zen/bunkerbox/$VUID/$VUID.json | jq -r .organization.uid)
ORGNAME=$(cat ~/.zen/bunkerbox/$VUID/$VUID.json | jq -r .organization.name)
ORGBANNER=$(cat ~/.zen/bunkerbox/$VUID/$VUID.json | jq -r .organization.banner.url)
HLS=$(cat ~/.zen/bunkerbox/$VUID/$VUID.json | jq -r .video.hlsManifest.url)
MEDIASOURCE=$(echo $HLS | rev | cut -d '/' -f 2- | rev)
echo "$TITLE ($DURATION s)"
## CHECK PUBLISH MODE
[[ ! -f ~/.zen/bunkerbox/choice ]] && echo "READY TO PROCESS ? ENTER. Any character sent means next." && read TEST && [[ "$TEST" != "" ]] && echo && continue ## NO CHOICE MADE
start=`date +%s`
echo "$HLS"
curl -s $HLS -o ~/.zen/bunkerbox/$VUID/$VUID.m3u8
# cat ~/.zen/bunkerbox/$VUID/$VUID.m3u8
echo ">>>>>>>>>>>>>>>> Downloading VIDEO"
# Choose 360p or 480p or 240p
VSIZE=360 && VIDEOHEAD=$(cat ~/.zen/bunkerbox/$VUID/$VUID.m3u8 | grep -B1 ${VSIZE}p | head -n 1) && VIDEOSRC=$(cat ~/.zen/bunkerbox/$VUID/$VUID.m3u8 | grep ${VSIZE}p | tail -n 1 | cut -f 1 -d '.')
[[ "$VIDEOSRC" == "" ]] && VSIZE=480 && VIDEOHEAD=$(cat ~/.zen/bunkerbox/$VUID/$VUID.m3u8 | grep -B1 ${VSIZE}p | head -n 1) && VIDEOSRC=$(cat ~/.zen/bunkerbox/$VUID/$VUID.m3u8 | grep ${VSIZE}p | tail -n 1 | cut -f 1 -d '.')
[[ "$VIDEOSRC" == "" ]] && VSIZE=240 &&VIDEOHEAD=$(cat ~/.zen/bunkerbox/$VUID/$VUID.m3u8 | grep -B1 ${VSIZE}p | head -n 1) && VIDEOSRC=$(cat ~/.zen/bunkerbox/$VUID/$VUID.m3u8 | grep ${VSIZE}p | tail -n 1 | cut -f 1 -d '.')
VTHUMB="$(cat ~/.zen/bunkerbox/$VUID/$VUID.json | jq -r --arg VSIZE "$VSIZE" '.video.thumbnails[] | select(.height == $VSIZE) | .url')"
echo ">>>>>>>>>>>>>>>> Downloading Video $VSIZE Thumbnail"
curl -s $VTHUMB -o ~/.zen/bunkerbox/$VUID/media/$VUID.jpg
[[ ! -f ~/.zen/bunkerbox/$VUID/media/$VUID.jpg ]] && cp ${MY_PATH}/images/astroport.jpg ~/.zen/bunkerbox/$VUID/media/$VUID.jpg # CORRECT MISSING THUMB
echo "VIDEOSRC=$MEDIASOURCE/$VIDEOSRC"
# Downloading Video m3u8 and Video
[[ ! -f ~/.zen/bunkerbox/$VUID/media/$VIDEOSRC.m3u8 ]] && curl -s $MEDIASOURCE/$VIDEOSRC.m3u8 -o ~/.zen/bunkerbox/$VUID/media/$VIDEOSRC.m3u8
[[ ! -f ~/.zen/bunkerbox/$VUID/media/$VIDEOSRC ]] && curl $MEDIASOURCE/$VIDEOSRC -o ~/.zen/bunkerbox/$VUID/media/$VIDEOSRC
echo ">>>>>>>>>>>>>>>> Downloading AUDIO"
AUDIOLINE=$(cat ~/.zen/bunkerbox/$VUID/$VUID.m3u8 | grep '=AUDIO')
AUDIOFILE=$(echo $AUDIOLINE | rev | cut -d '.' -f 2- | cut -d '"' -f 1 | rev)
echo "AUDIO=$MEDIASOURCE/$AUDIOFILE"
# Downloading Audio m3u8 and Audio
[[ ! -f ~/.zen/bunkerbox/$VUID/media/$AUDIOFILE.m3u8 ]] && curl -s $MEDIASOURCE/$AUDIOFILE.m3u8 -o ~/.zen/bunkerbox/$VUID/media/$AUDIOFILE.m3u8
[[ ! -f ~/.zen/bunkerbox/$VUID/media/$AUDIOFILE ]] && curl $MEDIASOURCE/$AUDIOFILE -o ~/.zen/bunkerbox/$VUID/media/$AUDIOFILE
echo ">>>>>>>>>>>>>>>> CREATING $VSIZE M3U8"
echo "#EXTM3U
#EXT-X-VERSION:6
#EXT-X-INDEPENDENT-SEGMENTS
$AUDIOLINE
$VIDEOHEAD
$VIDEOSRC.m3u8
" > ~/.zen/bunkerbox/$VUID/media/$VUID.m3u8
ls ~/.zen/bunkerbox/$VUID/media/
##########################################################################
echo "##########################################################################"
echo ">>>>>>>>>>>>>>>> ADDING index.html"
# COPY index, style, js AND data
cp -R ${MY_PATH}/templates/styles ~/.zen/bunkerbox/$VUID/media/
cp -R ${MY_PATH}/templates/js ~/.zen/bunkerbox/$VUID/media/
cp ${MY_PATH}/templates/videojs.html ~/.zen/bunkerbox/$VUID/media/index.html
cp ${MY_PATH}/images/astroport.jpg ~/.zen/bunkerbox/$VUID/media/
# Add current/latest common history reversed
if [[ -f ~/.zen/bunkerbox/history.json ]]; then
# qo-op get latest history.json
[[ "$(cat ~/.zen/bunkerbox/choice)"=="qo-op" ]] && ipfs get -o ~/.zen/bunkerbox/history.qo-op.json /ipns/$(cat ~/.zen/bunkerbox/qo-op)/history.json
# FUSION/REPLACEMENT WHAT TODO ?
##
echo '{
"Videos":' > ~/.zen/bunkerbox/$VUID/media/history.json
cat ~/.zen/bunkerbox/history.json | jq '.[] | reverse' >> ~/.zen/bunkerbox/$VUID/media/history.json
echo '}' >> ~/.zen/bunkerbox/$VUID/media/history.json
else
## NEW history
[[ ! $(cat ~/.zen/bunkerbox/history.json | grep Videos) ]] && cp ${MY_PATH}/templates/data/history.json ~/.zen/bunkerbox/history.json
cp ~/.zen/bunkerbox/history.json ~/.zen/bunkerbox/$VUID/media/history.json
fi
# Using relative links
sed "s/_IPFSROOT_/./g" ${MY_PATH}/templates/videojs.html > ~/.zen/bunkerbox/$VUID/media/index.html
sed -i "s/_VUID_/$VUID/g" ~/.zen/bunkerbox/$VUID/media/index.html
# sed -i s/_DATE_/$(date -u "+%Y-%m-%d#%H:%M:%S")/g ~/.zen/bunkerbox/$VUID/media/index.html # Different Copy Makes Different Chains !
sed -i "s~_TITLE_~$TITLE~g" ~/.zen/bunkerbox/$VUID/media/index.html
sed -i "s~_CHANNEL_~$CHANNEL~g" ~/.zen/bunkerbox/$VUID/media/index.html
echo ">>>>> ADDING TO IPFS : ipfs add -rwH ~/.zen/bunkerbox/$VUID/media/* "
echo
IPFSROOT=$(ipfs add -rwHq ~/.zen/bunkerbox/$VUID/media/* | tail -n 1)
INDEX="/ipfs/$IPFSROOT"
VMAIN="/ipfs/$IPFSROOT/$VUID.m3u8"
# UPDATING original JSON
cat ~/.zen/bunkerbox/$VUID/$VUID.json | jq ".video.hlsManifest.url = \"$VMAIN\"" > ~/.zen/bunkerbox/$VUID/media/$VUID.json
echo "M3U8 : $IPFSNGW$VMAIN"
## UPDATE GLOCAL HISTORY ?
IsThere=$(cat ~/.zen/bunkerbox/history.json | jq .Videos[].link | grep $VUID)
if [[ ! $IsThere ]]; then
echo "Add $INDEX to ~/.zen/bunkerbox/$VUID/media/history.json"
cat ~/.zen/bunkerbox/history.json | jq '.Videos += [{"link": "<a href='"'_INDEX_'"'><img src='"'_INDEX_/_VUID_.jpg'"' height=80 ></a><br>'"'_TITLE_'"'"}]' > ~/.zen/bunkerbox/$VUID/media/history.json
echo $INDEX
sed -i "s~_INDEX_~$INDEX~g" ~/.zen/bunkerbox/$VUID/media/history.json
echo $VUID
sed -i "s~_VUID_~$VUID~g" ~/.zen/bunkerbox/$VUID/media/history.json
echo $TITLE
sed -i "s~_TITLE_~$TITLE~g" ~/.zen/bunkerbox/$VUID/media/history.json
# COULD BE DONE LIKE THAT
# cat ~/.zen/bunkerbox/$VUID/media/history.json | jq --arg INDEX "$INDEX" --arg TITLE "$TITLE" '.Videos += [{"link": "<a href='''$INDEX''' >'''$TITLE'''</a>"}]' > ~/.zen/bunkerbox/history.json
echo "Mise à jour ~/.zen/bunkerbox/history.json"
[[ "$(cat ~/.zen/bunkerbox/$VUID/media/history.json)" == "" ]] && echo "FATAL ERROR MAJ" && exit 1
[[ -f ~/.zen/bunkerbox/$VUID/media/history.json ]] && cp -f ~/.zen/bunkerbox/$VUID/media/history.json ~/.zen/bunkerbox/history.json
fi
echo "<meta http-equiv=\"refresh\" content=\"0;URL=$INDEX\">" > ~/.zen/bunkerbox/index.html
echo "ACTUEL INDEX $IPFSNGW/ipfs/$IPFSROOT"
echo "OLD JSON : $IPFSNGW/ipfs/$IPFSROOT/history.json"
PS3="Comment voulez-vous continuer et publier la collecte ? "
choices=("debug" "local" "qo-op" "astrXbian")
fav=$(cat ~/.zen/bunkerbox/choice)
[[ ! $fav ]] && select fav in "${choices[@]}"; do [[ $fav ]] && break; done
case $fav in
"local")
echo 'local' > ~/.zen/bunkerbox/choice
echo "Historique LOCAL = ~/.zen/bunkerbox/history.json"
continue
;;
"astrXbian")
[[ ! -d ~/.zen/astrXbian ]] && echo "DEV ZONE - Installez astrXbian SVP ... P2P VideoClub DEMO - DEV ZONE !" && exit 1
[[ ! $IPFSNODEID ]] && echo "Missing IPFSNODEID. Exit" && exit 1
echo 'astrXbian' > ~/.zen/bunkerbox/choice
mkdir -p ~/.zen/ipfs/.$IPFSNODEID/astroport/bunkerbox
echo "<meta http-equiv=\"refresh\" content=\"0;URL=$INDEX\">" > ~/.zen/ipfs/.$IPFSNODEID/astroport/bunkerbox/index.html
cp ~/.zen/bunkerbox/history.json ~/.zen/ipfs/.$IPFSNODEID/astroport/bunkerbox/
echo "BALISE Station $IPFSNGW/ipns/$IPFSNODEID/.$IPFSNODEID/astroport/bunkerbox/ propagation au prochain cycle astrXbian"
continue
;;
"qo-op")
if [[ ! $(ipfs key list | grep 'qo-op') ]]; then
echo "MIssing qo-op key! Clef qo-op manquante!"
echo "get it from your best friend and do not break confidence ring!"
echo "récupérez la auprès de votre meilleur ami. Et ne brisez pas la chaine de confiance!"
echo "Contact support@qo-op.com for help! Envoyez un email pour obtenir assistance."
echo "Utiliser la clef de DEV ? ENTRER pour OUI. Répondez qqch pour NON."
read KDEV
[[ "$KDEV" != "" ]] && echo "BRAVO! Confidence is in the KEY. La confiance est dans la CLEF." && break ## NO CHOICE MADE
## USE DEV KEY
echo "k51qzi5uqu5djt17zonkpg1cb8hrxhahpesybusz8q57j4ocqm0qlc6s99z60x" > ~/.zen/bunkerbox/qo-op
cp ${MY_PATH}/key_ofxs233q ~/.ipfs/keystore/
mkdir -p /tmp/$VUID
echo "<meta http-equiv=\"refresh\" content=\"0;URL=$INDEX\">" > /tmp/$VUID/index.html
cp ~/.zen/bunkerbox/history.json > /tmp/$VUID/history.json
echo "$TS" > /tmp/$VUID/ts # TimeStamping
VROOT=$(ipfs add -wHq /tmp/$VUID/* | tail -n 1)
ipfs name publish --key=qo-op /ipfs/$VROOT
echo "qo-op : $IPFSNGW/ipns/$IPNS/history.json /ipfs/$VROOT"
else
## WRITE qo-op IPNS key
ipfs key list -l | grep 'qo-op' | cut -f 1 -d ' ' > ~/.zen/bunkerbox/qo-op
fi
echo 'qo-op' > ~/.zen/bunkerbox/choice
IPNS=$(cat ~/.zen/bunkerbox/qo-op)
echo "Votre chaine vidéo qo-op /ipns/$IPNS"
echo
InHere=$(cat ~/.zen/bunkerbox/history.qo-op.json | jq .Videos[].link | grep $VUID)
if [[ ! $InHere ]]; then
echo "NOUVELLE VIDEO."
mkdir -p /tmp/$VUID
echo "<meta http-equiv=\"refresh\" content=\"0;URL=$INDEX\">" > /tmp/$VUID/index.html
cp ~/.zen/bunkerbox/history.json /tmp/$VUID/history.json
echo "$TS" > /tmp/$VUID/ts # TimeStamping
VROOT=$(ipfs add -wHq /tmp/$VUID/* | tail -n 1)
ipfs name publish --key=qo-op /ipfs/$VROOT
echo "qo-op : $IPFSNGW/ipns/$IPNS/"
echo "qo-op : $IPFSNGW/ipns/$IPNS/history.json"
fi
#[[ $VUID != "" ]] && rm -Rf /tmp/$VUID # Cleaning
continue
;;
"debug")
echo "debug"
> ~/.zen/bunkerbox/choice
break
;;
esac
##########################################################################
# cat ~/.zen/bunkerbox/$VUID/media/$VUID.json | jq -r .video.hlsManifest.url
end=`date +%s`; echo Duration `expr $end - $start` seconds.
done

BIN
images/astroport.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

1
key_ofxs233q Normal file
View File

@ -0,0 +1 @@
@^‡’@ƒrÈEkã¿ù¬ˆ¢Ügá]Ì)ÄTÙá 1šU…a¨ƒŽfGíO+Ÿ~"ÎÇ=ûZI5ê£*¶A

View File

@ -0,0 +1,6 @@
{
"Videos": [
]
}

2
templates/js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

11
templates/js/pagination.min.js vendored Normal file

File diff suppressed because one or more lines are too long

26
templates/js/video.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,192 @@
:root {
--rouge: hsl(0, 98.8%, 33.5%);
--rouge-fonce: hsl(0, 75%, 33.5%);
--noir-complet: black;
--noir-fonce: hsl(0, 30%, 2.1%);
--noir-moyen: hsl(0, 15%, 3.1%);
--noir-clair: hsl(0, 5%, 7.1%);
--blanc: hsla(0, 0%, 100%, 1);
--blanc-fort: hsla(0, 0%, 100%, 0.75);
--blanc-semi-transparent: hsla(0, 0%, 100%, 0.25);
}
body {
background: var(--noir-fonce);
color: white;
font-family: Roboto,sans-serif;
}
header {
background: var(--noir-clair);
}
header * {
color: var(--rouge);
text-decoration: none;
}
header span {
color: white;
}
#pinFilter ul li a {
background-color: var(--blanc);
}
#pinFilter ul li.selected a {
background-color: var(--rouge);
}
ul#tagsList,
ul#narrowingTags {
list-style: none;
margin-left: 0;
padding-left: 0;
}
ul#tagsList li,
ul#narrowingTags li {
display: inline-block;
}
ul#tagsList a,
ul#tagsList a:visited {
text-decoration: none;
color: var(--rouge-fonce);
}
#narrowingTags a,
#narrowingTags a:visited {
text-decoration: none;
color: inherit;
}
#narrowingTags li {
border-radius: 1rem;
}
#narrowingTags li.selected {
background-color: var(--rouge-fonce);
color: var(--blanc);
border: 0.125rem solid var(--noir-clair);
}
#tagsList,
#narrowingTags {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
#tagsList li.station,
#narrowingTags li.station {
order: 1;
}
#tagsList li.station,
#narrowingTags li.station {
background-image: url("logo.png");
background-repeat: no-repeat;
background-position: left middle;
background-size: contain;
padding-left: 2em;
order: 1;
}
#narrowingTags li.selectable {
background-color: var(--noir-fonce);
color: var(--rouge-fonce);
border: 0.125rem solid var(--noir-clair);
}
#videosList > li {
background: var(--noir-clair);
border-color: var(--rouge);
border-style: solid;
}
.video-title,
.video-title a,
.video-title a:visited {
color: white;
font-weight: bold;
text-decoration: none;
word-break: break-all;
}
#videosList .thumbnail {
background-color: var(--noir-complet);
}
#videosList > li ul.tags li a,
#videosList > li ul.tags li a:visited {
text-decoration: none;
}
#videosList > li ul.tags li.selectable a,
#videosList > li ul.tags li.selectable a:visited {
color: var(--blanc-semi-transparent);
}
#videosList > li ul.tags li.selectable a:hover {
color: var(--blanc-fort);
}
#videosList > li ul.tags li.selected a,
#videosList > li ul.tags li.selected a:visited {
color: var(--blanc-fort);
}
article {
background: var(--noir-clair);
}
article video {
background: black;
}
article .video-title {
font-weight: bold;
}
#successMsg {
opacity: 0;
transition: opacity 1s;
}

View File

@ -0,0 +1 @@
.vjs-theme-forest{--vjs-theme-forest--primary:#6fb04e;--vjs-theme-forest--secondary:#fff}.vjs-theme-forest.vjs-big-play-button:focus,.vjs-theme-forest:hover .vjs-big-play-button{background-color:transparent;background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='88' height='88' fill='%236fb04e'%3E%3Cpath fill-rule='evenodd' d='M44 88C19.738 88 0 68.262 0 44S19.738 0 44 0s44 19.738 44 44-19.738 44-44 44zm0-85C21.393 3 3 21.393 3 44c0 22.608 18.393 41 41 41s41-18.392 41-41C85 21.393 66.607 3 44 3zm16.063 43.898L39.629 60.741a3.496 3.496 0 01-3.604.194 3.492 3.492 0 01-1.859-3.092V30.158c0-1.299.712-2.483 1.859-3.092a3.487 3.487 0 013.604.194l20.433 13.843a3.497 3.497 0 01.001 5.795zm-1.683-3.311L37.946 29.744a.49.49 0 00-.276-.09.51.51 0 00-.239.062.483.483 0 00-.265.442v27.685c0 .262.166.389.265.442.1.053.299.118.515-.028L58.38 44.414A.489.489 0 0058.6 44a.49.49 0 00-.22-.413z'/%3E%3C/svg%3E")}.vjs-theme-forest .vjs-big-play-button{width:88px;height:88px;background:none;background-repeat:no-repeat;background-position:50%;background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='88' height='88' fill='%23fff'%3E%3Cpath fill-rule='evenodd' d='M44 88C19.738 88 0 68.262 0 44S19.738 0 44 0s44 19.738 44 44-19.738 44-44 44zm0-85C21.393 3 3 21.393 3 44c0 22.608 18.393 41 41 41s41-18.392 41-41C85 21.393 66.607 3 44 3zm16.063 43.898L39.629 60.741a3.496 3.496 0 01-3.604.194 3.492 3.492 0 01-1.859-3.092V30.158c0-1.299.712-2.483 1.859-3.092a3.487 3.487 0 013.604.194l20.433 13.843a3.497 3.497 0 01.001 5.795zm-1.683-3.311L37.946 29.744a.49.49 0 00-.276-.09.51.51 0 00-.239.062.483.483 0 00-.265.442v27.685c0 .262.166.389.265.442.1.053.299.118.515-.028L58.38 44.414A.489.489 0 0058.6 44a.49.49 0 00-.22-.413z'/%3E%3C/svg%3E");border:none;top:50%;left:50%;margin-top:-44px;margin-left:-44px;color:purple}.vjs-theme-forest .vjs-big-play-button .vjs-icon-placeholder{display:none}.vjs-theme-forest .vjs-button>.vjs-icon-placeholder:before{line-height:1.55}.vjs-theme-forest .vjs-control:not(.vjs-disabled):not(.vjs-time-control):hover{color:var(--vjs-theme-forest--primary);text-shadow:var(--vjs-theme-forest--secondary) 1px 0 10px}.vjs-theme-forest .vjs-control-bar{background:none;margin-bottom:1em;padding-left:1em;padding-right:1em}.vjs-theme-forest .vjs-play-control{font-size:.8em}.vjs-theme-forest .vjs-play-control .vjs-icon-placeholder:before{background-color:var(--vjs-theme-forest--secondary);height:1.5em;width:1.5em;margin-top:.2em;border-radius:1em;color:var(--vjs-theme-forest--primary)}.vjs-theme-forest .vjs-play-control:hover .vjs-icon-placeholder:before{background-color:var(--vjs-theme-forest--primary);color:var(--vjs-theme-forest--secondary)}.vjs-theme-forest .vjs-mute-control{display:none}.vjs-theme-forest .vjs-volume-panel{margin-left:.5em;margin-right:.5em;padding-top:.3em}.vjs-theme-forest .vjs-volume-bar.vjs-slider-horizontal,.vjs-theme-forest .vjs-volume-panel,.vjs-theme-forest .vjs-volume-panel.vjs-volume-panel-horizontal.vjs-slider-active,.vjs-theme-forest .vjs-volume-panel.vjs-volume-panel-horizontal:hover,.vjs-theme-forest .vjs-volume-panel:active .vjs-volume-control.vjs-volume-horizontal,.vjs-theme-forest .vjs-volume-panel:hover,.vjs-theme-forest .vjs-volume-panel:hover .vjs-volume-control.vjs-volume-horizontal{width:3em}.vjs-theme-forest .vjs-volume-level:before{font-size:1em}.vjs-theme-forest .vjs-volume-panel .vjs-volume-control{opacity:1;width:100%;height:100%}.vjs-theme-forest .vjs-volume-bar{background-color:transparent;margin:0}.vjs-theme-forest .vjs-slider-horizontal .vjs-volume-level{height:100%}.vjs-theme-forest .vjs-volume-bar.vjs-slider-horizontal{margin-top:0;margin-bottom:0;height:100%}.vjs-theme-forest .vjs-volume-bar:before{content:"";z-index:0;width:0;height:0;position:absolute;top:0;left:0;border-left:3em solid transparent;border-bottom:2em solid var(--vjs-theme-forest--primary);border-right:0 solid transparent;border-top:0 solid transparent}.vjs-theme-forest .vjs-volume-level{overflow:hidden;background-color:transparent}.vjs-theme-forest .vjs-volume-level:before{content:"";z-index:1;width:0;height:0;position:absolute;top:0;left:0;border-left:3em solid transparent;border-bottom:2em solid var(--vjs-theme-forest--secondary);border-right:0 solid transparent;border-top:0 solid transparent}.vjs-theme-forest .vjs-progress-control:hover .vjs-progress-holder{font-size:1em}.vjs-theme-forest .vjs-play-progress:before{display:none}.vjs-theme-forest .vjs-progress-holder{border-radius:.2em;height:.5em;margin:0}.vjs-theme-forest .vjs-load-progress,.vjs-theme-forest .vjs-load-progress div,.vjs-theme-forest .vjs-play-progress{border-radius:.2em}

250
templates/styles/layout.css Normal file
View File

@ -0,0 +1,250 @@
body {
margin: 0;
padding: 0;
}
header {
overflow: hidden;
padding: 1rem 0.666rem 1.333rem;
margin-bottom: 2rem;
}
header > * {
font-size: 1.5rem;
margin: 0;
padding: 0;
}
header > .sitetitle {
margin-bottom: 0.25rem;
}
header > .sitetitle span {
border-bottom-style: solid;
border-bottom-color: var(--pink);
}
header .usp {
font-size: 0.95rem;
}
main {
width: 95%;
margin: auto;
}
body.home main {
display: grid;
grid-gap: 1rem 1rem;
grid-auto-flow: row;
grid-template-columns: 998px auto;
grid-template-areas: "c m";
}
body.home main > #menu {
grid-area: m;
}
body.home main > ul#videosList {
grid-area: c;
}
aside#menu > div {
position: sticky;
top: 2rem;
}
#pinFilter ul {
margin: 0;
padding: 0;
list-style: none;
font-size: 3rem;
display: flex;
}
#pinFilter ul li a span {
display: none;
}
#pinFilter ul li a {
display: inline-block;
height: 3rem;
width: 3rem;
border: 1px solid red;
background-repeat: no-repeat;
}
#pinFilter ul li#filter_pinned a {
background-image: url("font-awesome/hdd.svg");
background-position: center center;
background-size: 2.5rem;
}
#pinFilter ul li#filter_notpinned a {
background-image: url("font-awesome/cloud.svg");
background-position: center center;
background-size: 2.5rem;
}
#pinFilter ul li#filter_both a {
background-image: url("font-awesome/hdd.svg"),
url("font-awesome/cloud.svg");
background-position: bottom 0.25rem left 0.25rem,
top 0.25rem right 0.25rem;
background-size: 1.75rem,
1.75rem;
}
#tagsList li,
#narrowingTags li {
padding: 0.125rem 0.5rem;
margin: 0.25rem 0.25rem;
}
#videosList {
display: grid;
grid-gap: 1rem 1rem;
grid-auto-flow: row;
grid-template-columns: 322px 322px 322px;
list-style: none;
margin: 0;
padding: 0;
justify-content: center;
align-content: start
}
#videosList > li {
border-radius: 0.25rem;
border-width: 1px;
overflow: hidden;
}
#videosList .thumbnail {
text-align: center;
height: 180px;
margin-top: 0;
display: flex;
justify-content: center;
align-items: center;
}
#videosList .thumbnail img {
max-height: 180px;
width: auto;
}
#videosList .video-title {
padding: 0.5rem 1rem;
}
#videosList > li ul.tags {
padding: 0;
margin: 0;
list-style: none;
}
#videosList > li ul.tags li {
display: inline-block;
}
#videosList > li ul.tags li:after {
content: ", ";
}
#videosList > li ul.tags li:last-of-type:after {
content: "";
}
article {
border-radius: 0.25rem;
width: 58.3%;
margin: auto;
overflow: hidden;
}
article video {
width: 100%;
max-height: calc(100vh - 14rem);
}
article .video-title {
padding: 1rem 1rem;
font-size: 1.25rem;
margin: 0;
}
form.add-video {
position: absolute;
top: 0.50rem;
right: 0.50rem;
}
form.add-video input {
height: 2rem;
padding: 0.25rem 0.5rem;
box-sizing: border-box;
border-width: 0.125rem;
border-radius: 0.5rem;
}
form label {
display: none;
}
form label input {
width: 50%;
}
form.add-video .confirmation {
margin: 0.5rem 0;
font-size: 0.85rem;
text-align: center;
}
footer {
display: none;
}

BIN
templates/styles/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

82
templates/videojs.html Normal file
View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>_CHANNEL_ : _TITLE_ [BunkerBOX]</title>
<link rel="icon" type="image/png" href="_IPFSROOT_/styles/logo.png" />
<link rel="stylesheet" href="_IPFSROOT_/styles/video-js.css" type="text/css" />
<link rel="stylesheet" href="_IPFSROOT_/styles/forest.css" type="text/css" />
<link rel="stylesheet" href="_IPFSROOT_/styles/decoration.css" type="text/css" />
<link rel="stylesheet" href="_IPFSROOT_/styles/layout.css" type="text/css" />
</head>
<body>
<header>
<h6>
<a href="https://crowdbunker.com/v/_VUID_" target="bunker"> "<span>BunkerBOX</span>"</a> /ipfs/
</h6>
</header>
<main>
<center>
<div class="row justify-center">
<video
id="vbunk"
class="video-js vjs-theme-forest"
controls
preload="auto"
width="auto" height="auto"
poster="_IPFSROOT_/_VUID_.jpg"
>
<source src="_IPFSROOT_/_VUID_.m3u8" type="application/x-mpegURL" />
<p class="vjs-no-js">
Activer JavaScript SVP
</p>
</video>
</div>
</center>
<article>
<h1 class="video-title">
_CHANNEL_ : _TITLE_
</h1>
</article>
<center>
<div id="videosList"><div class="wrapper"></div></div>
</center>
<h6>
powered by <a href="https://astroport.com"><span>"</span>Astroport<span>"</span></a>
</h6>
</main>
</body>
<script src="_IPFSROOT_/js/video.min.js"></script>
<script src="_IPFSROOT_/js/jquery.min.js"></script>
<script src="_IPFSROOT_/js/pagination.min.js"></script>
<link rel="stylesheet" href="_IPFSROOT_/styles/pagination.css" />
<script>
var player = videojs('vbunk', {
autoplay: 'muted'
});
</script>
<script>
$.getJSON('./history.json', function (json) {
$('#videosList').pagination({
dataSource: json.Videos,
pageSize: 1,
callback: function(data, pagination) {
var wrapper = $('#videosList .wrapper').empty();
$.each(data, function (i, f) {
$('#videosList .wrapper').append('<ul><li>' + f.link + '</li></ul>');
});
}
});
});
</script>
</html>