UP | HOME

How to stream into Freenet / Hyphanet

With version 1489 Freenet / Hyphanet gained a filter for m3u files — playlists — which enables its use as streaming platform.

Update 2021-07: I now created a streaming-website generation tool which automates the process of streaming video-on-demand. It’s called Guile Media Site. You can clone it from sourcehut or get it directly from Freenet:

For streaming audio, use the multi-node version below.


PDF (drucken)

In this article I want to show you how you can forward an arbitrary stream into Hyphanet. To listen to a stream by its USK-key, download and run your own Freenet / Hyphanet node.

2024-01-restream-into-hyphanet.png

TLDR: For audio, just use re-stream to Hyphanet:

cd /tmp && \
git clone https://github.com/hyphanet/re-stream-into-freenet && \
cd re-stream-into-freenet && \
echo -e "\n1\n" | ./re-stream-to-freenet.sh theradiocc \
  "http://ogg.theradio.cc/" $(((3 * 24 * 60 * 60))) \
  "The Radio.cc: theradio.cc"

Requirements: pyFreenet3 (pip3 install --user pyFreenet3) and openjdk.

It directly creates a freesite where people can listen to the audio. Watch for output like this:

Creating minimal streaming site:
http://127.0.0.1:8888/freenet:USK@fLh9vDtv4yliMDD6tJSb~GMLdC2EQuf~Wpc1PxyFMXo,30P5T9rvQ4UGDJs2hZ7cdzhKYixBgds296gKbfK2XjI,AQACAAE/theradiocc/0/

To embed such a stream on your Freesite, you can use an audio-tag with the /SSK@.../stream.m3u in src. You can simply copy a working tag from the minimal site.

1. Requirements

Watching this stream requires a Freenet / Hyphanet node running at least build 1492. For uploading the stream you need pyFreenet. And GNU Linux, but you guessed that, right?

  • Install Freenet / Hyphanet: install-freenet-linux.html
    (as of build 1492, Freenet supports at most openjdk 15. Version 16 and 17 still need module system fixes)
  • Install pyFreenet: Get Python3, then: pip3 install --user pyFreenet3

The stream has around 15 minute delay, if your node is fast enough. Given that a practical streaming setup for semi-professional free streaming uses around 20s delay, that’s not too shabby over a confidential decentralized network. With a stronger internet connection, you might be able to push this further down. I’m limited to 40Mbps in theory, the nodes for this use much less.

As source I use theradio.cc, a radio station that streams creativecommons licensed media.

To get gap-less playback for mp3, almost without artefacts, use mpv --ytdl=no --prefetch-playlist.

For ogg, use a site in Freenet with an audio-tag, because there’s some issue with our file splitting that trips up mpv playlist playing with ogg.

2. Restreaming theradio.cc with a fully automated script

To use this script, either download it, inspect it, then run it as a bash script, or, if you’re reckless, run it directly:

sudo apt install openjdk-17-jdk wget
pip3 install --user pyFreenet3
wget -O stream-radiocc-into-freenet.sh \
  https://www.draketo.de/software/stream-the-radio-cc-into-freenet.txt
bash stream-radiocc-into-freenet.sh
# stream the radio cc (without transcoding)
# Select the source: (64k ogg)
SOURCE=http://stream.theradio.cc:8000/trcc-stream-lq.ogg
# Set the streamtime: 3 days (the maximum time this setup can do is 4 days)
STREAMTIME=$(((3 * 24 * 60 * 60)))
# Choose a prefix to use for the audio-files in Freenet
FILEPREFIX="theradiocc-"
FREENET_NODES_BASEFOLDER=$(mktemp -d "${FILEPREFIX}"XXXXXXXX)
mkdir "${FREENET_NODES_BASEFOLDER}"
cd "${FREENET_NODES_BASEFOLDER}"
# following https://www.draketo.de/software/install-freenet-linux.html
# use the Lysator mirror, because github throttles us
wget http://ftp.lysator.liu.se/pub/freenet/fred-releases/build01494/new_installer_offline_1494.jar \
  -O freenet-installer.jar
mkdir node1
cd node1
echo === 
echo follow the prompts
echo ===
java -jar ../freenet-installer.jar -console
./run.sh stop
# setting up default settings and restarting
cat > freenet.ini <<EOF
security-levels.networkThreatLevel=LOW
security-levels.physicalThreatLevel=NORMAL
fproxy.enableCachingForChkAndSskKeys=true
fproxy.hasCompletedWizard=true
fproxy.ssl=false
fproxy.enabled=true
fproxy.port=8180
logger.maxZippedLogsSize=1048
logger.priority=ERROR
pluginmanager.loadplugin=Sharesite
pluginmanager.enabled=true
node.slashdotCacheSize=53687091
node.minDiskFreeShortTerm=536870912
node.uploadAllowedDirs=all
node.outputBandwidthLimit=131072
node.storeSize=429496730
node.storeType=ram
node.assumeNATed=true
node.clientCacheType=ram
node.l10n=English
node.inputBandwidthLimit=131072
fcp.port=9180
node.opennet.enabled=true
node.load.subMaxPingTime=7000
node.load.maxPingTime=15000
End
EOF
./run.sh restart
echo giving Freenet some time to start
sleep 10
echo stop the node to replicate it
./run.sh stop
cd "${FREENET_NODES_BASEFOLDER}"
# Next just copy the folder:
for i in {2..5}; do cp -r node1 node$i; done
# Then remove the listen-port lines in freenet.ini. This causes
# Freenet to create unique listen ports on the next run.
# Also adjust the fcpport, fred port, and the bandwidth
for i in {1..5}; do
    sed -i s/fproxy.port=.*/fproxy.port=8${i}80/  node$i/freenet.ini
    sed -i s/fcp.port=.*/fcp.port=9${i}80/  node$i/freenet.ini
    sed -i s/node.listenPort=.*// node$i/freenet.ini
    sed -i s/node.opennet.listenPort=.*// node$i/freenet.ini
    sed -i s/node.inputBandwidthLimit=.*/node.inputBandwidthLimit=70k/ node$i/freenet.ini
    sed -i s/node.outputBandwidthLimit=.*/node.outputBandwidthLimit=70k/ node$i/freenet.ini
done
# And start them:
for i in {1..5}; do cd node$i; ./run.sh start; cd -; done
# check the settings.
grep -i \\.port node*/*ini
# expected:
# node1/freenet.ini:fproxy.port=8180
# node1/freenet.ini:fcp.port=9180
# node2/freenet.ini:fproxy.port=8280
# node2/freenet.ini:fcp.port=9280
# node3/freenet.ini:fproxy.port=8380
# node3/freenet.ini:fcp.port=9380
# node4/freenet.ini:fproxy.port=8480
# node4/freenet.ini:fcp.port=9480
# node5/freenet.ini:fproxy.port=8580
# node5/freenet.ini:fcp.port=9580
# Now we have 5 running nodes on FCP ports 9180 to 9580. We‘ll use them to insert

# copy ogg data from theradio.cc
# first do 10 short segments so people can get in, then create larger segments in the background
echo creating the first 10 segments, 5 minutes, before starting to upload.
echo Please give them enough time.
rm -rf "${FREENET_NODES_BASEFOLDER}"/FREESTREAM-split/
mkdir "${FREENET_NODES_BASEFOLDER}"/FREESTREAM-split/
cd "${FREENET_NODES_BASEFOLDER}"/FREESTREAM-split/
# 30 seconds are 200-300kiB, the ideal size for long-lived files in Freenet
timeout 300 nohup ffmpeg -i ${SOURCE}  \
        -c copy -map 0 \
        -segment_time 00:00:30 \
        -f segment \
        -reset_timestamps 1 "${FILEPREFIX}--%01d.ogg"
echo First 10 segments done. Later segments are created in the background.
echo This setup can live-stream radio for more than 4 days.
# 6 minutes segments are about 2.5MiB each, ensured below 4MiB, 
# the maximum size for single-container files in Freenet.
# This reduces the audible stops in the audio during streaming,
# and 6 minute segments are easy to track for humans,
# because 10 segments are one hour. This way we can create streams
# that you can step in at any hour of the day.
timeout ${STREAMTIME} nohup ffmpeg -i ${SOURCE}  \
        -c copy -map 0 \
        -segment_time 00:06:00 \
        -f segment \
        -reset_timestamps 1 "${FILEPREFIX}%03d.ogg" &

KEY=$(fcpgenkey -P 9180 | tail -n 1)
PUBKEY=$(fcpinvertkey -P 9180 $KEY)
for i in {0..9}; do
    echo "${FILEPREFIX}--${i}.ogg" >> stream.m3u;
done
for i in {000..999}; do
    echo "${FILEPREFIX}${i}.ogg" >> stream.m3u;
done
# insert stream.m3u with compression because it is large and very
# repetitive, and with high priority to ensure that it does not get
# drowned by later mp3 inserts
# use the last node for the streaming file
fcpupload -P 9580 -p 2 ${KEY}stream.m3u stream.m3u
# provide the link to the playlist
echo Streaming radio to $(fcpinvertkey -P 9180 $KEY)stream.m3u

# show how to actually provide the stream as a freesite

echo ===
echo To create a streaming site, open the Sharesite plugin site
echo http://localhost:8180/Sharesite/ 
echo in your browser, click "create a new freesite"
echo open your freesite and enter the following:
echo 'Stream: <audio src="/'$(fcpinvertkey -P 9180 $KEY)stream.m3u'" controls="controls" style="height: 40px" ></audio>'
echo Then change the Insert Hour to -1 to insert at once.
echo Save it, go back to the freesite menu, then tick its checkbox and click insert.
echo Once a link appears next to your site, your streaming page is ready. You can use that link to share it.
echo ===
echo mpv --ytdl=no --prefetch-playlist http://127.0.0.1:8888/freenet:$(fcpinvertkey -P 9180 $KEY)stream.m3u
for i in -- {00..99}; do
    # upload 9 files in parallel, because Freenet does some checking
    # for availability, that does not consume much bandwidth but takes
    # time
    PRE="${FILEPREFIX}${i}"
    # wait until the next file is available, to ensure that the current file is ready
    while test ! -e "${PRE}1.ogg"; do sleep 10; done
    date # for statistics
    # upload the first 5 files, one file per insertion-node
    # the first 5 get higher priority
    fcpupload -P 9180 -p 2 "${KEY}${PRE}0.ogg" "${PRE}0.ogg"
    while test ! -e "${PRE}2.ogg"; do sleep 10; done
    fcpupload -P 9280 -p 2 "${KEY}${PRE}1.ogg" "${PRE}1.ogg"
    while test ! -e "${PRE}3.ogg"; do sleep 10; done
    fcpupload -P 9380 -p 2 "${KEY}${PRE}2.ogg" "${PRE}2.ogg"
    while test ! -e "${PRE}4.ogg"; do sleep 10; done
    fcpupload -P 9480 -p 2 "${KEY}${PRE}3.ogg" "${PRE}3.ogg"
    while test ! -e "${PRE}5.ogg"; do sleep 10; done
    fcpupload -P 9580 -p 2 "${KEY}${PRE}4.ogg" "${PRE}4.ogg"
    # the next 5 get lower priority so the first finish earlier, 
    # but they run in parallel to catch up on time lost at the end
    while test ! -e "${PRE}6.ogg"; do sleep 10; done
    fcpupload -P 9180 "${KEY}${PRE}5.ogg" "${PRE}5.ogg" &
    while test ! -e "${PRE}7.ogg"; do sleep 10; done
    fcpupload -P 9280 "${KEY}${PRE}6.ogg" "${PRE}6.ogg" &
    while test ! -e "${PRE}8.ogg"; do sleep 10; done
    fcpupload -P 9380 "${KEY}${PRE}7.ogg" "${PRE}7.ogg" &
    while test ! -e "${PRE}9.ogg"; do sleep 10; done
    # wait for completion of the upload before the last upload 
    # as a primitive way to limit parallelism; 
    # no use clogging the node if it cannot keep up
    fcpupload -w -P 9480 "${KEY}${PRE}8.ogg" "${PRE}8.ogg"
    # wait a full segment to ensure that the last file actually is ready
    # (because we do not have the next key yet, so we cannot do nice checking)
    sleep 360
    fcpupload -P 9580 "${KEY}${PRE}9.ogg" "${PRE}9.ogg"
done
sleep 300
echo All the files are uploading. Stopping the streaming nodes.
for i in "${FREENET_NODES_BASEFOLDER}"/node*; do cd $i; ./run.sh stop; cd -; done

3. Background: Stream audio with a single node

To stream live, you need a sufficiently fast connection to upload 350KiB to Freenet in 30s.

On my node this is not real-time yet: It takes around 11 minutes to insert 3 minutes of music.

The following code uses some optimizations: The uploaded segments fit into a single SSK splitfile (around 300KiB) and multiple files are inserted in parallel to reduce the impact of wait times for detecting successful uploads (the first with higher priority to reduce the time until the stream can start). It still has room for improvement, though. It could, for example, use multiple insert-nodes, one per file in a batch, and reducing the batch-size to 5. That might allow pushing the delay down to 2 minutes.

HOST=127.0.0.1
FREDPORT=8888
FCPPORT=9481
KEY=$(fcpgenkey -H $HOST -P $FCPPORT | tail -n 1)
PUBKEY=$(fcpinvertkey -H $HOST -P $FCPPORT $KEY)
FILEPREFIX="theradiocc-"
rm -rf /tmp/FREESTREAM-split/
mkdir /tmp/FREESTREAM-split/
cd /tmp/FREESTREAM-split/
for i in {000..999}; do
    echo "${FILEPREFIX}${i}.mp3" >> stream.m3u;
done
# insert stream.m3u with compression because it is large and very
# repetitive, and with high priority to ensure that it does not get
# drowned by later mp3 inserts
fcpupload -H $HOST -P $FCPPORT -p 2 ${KEY}stream.m3u stream.m3u
# provide the link to the playlist
echo Streaming radio to $(fcpinvertkey -H $HOST -P $FCPPORT $KEY)stream.m3u
# run mp3 encoding asynchronously for one hour, re-encode to quality 0
# (lowest quality) so this can work with an OK connection.
timeout 60000 nohup ffmpeg -i http://mp3.theradio.cc/  \
        -c copy -map 0 \
        -segment_time 00:00:20 \
        -f segment \
        -reset_timestamps 1 "${FILEPREFIX}%03d.mp3" &
# show a command how to actually start the stream
echo you can listen to the stream with
echo mpv --ytdl=no --prefetch-playlist http://$HOST:$FREDPORT/freenet:$(fcpinvertkey -H $HOST -P $FCPPORT $KEY)stream.m3u
for i in {00..99}; do
    # upload 9 files in parallel, because Freenet does some checking
    # for availability, that does not consume much bandwidth but takes
    # time
    # wait until all the next 10 files are available
    while test ! -e "${FILEPREFIX}${i}9.mp3"; do sleep 10; done
    # wait for one more file to avoid partial files
    sleep 30
    date
    # upload the first of the batch with higher priority
    j=0
    fcpupload -H $HOST -P $FCPPORT -p 2 "${KEY}${FILEPREFIX}${i}${j}.mp3" "${FILEPREFIX}${i}${j}.mp3"
    # upload 8 more files
    for j in {1..8}; do
        # insert segments in parallel to reduce the impact of wait times
        fcpupload -H $HOST -P $FCPPORT "${KEY}${FILEPREFIX}${i}${j}.mp3" "${FILEPREFIX}${i}${j}.mp3"
    done
    # wait for the upload of the last one of the batch as primitive limitation for the parallel uploads :-)
    j=9
    fcpupload -w -H $HOST -P $FCPPORT "${KEY}${FILEPREFIX}${i}${j}.mp3" "${FILEPREFIX}${i}${j}.mp3"
done

If you have Freenet 1489-pre1 running at port 8888, you can listen in on a test-stream with mpv:

mpv --ytdl=no --prefetch-playlist http://127.0.0.1:8888/freenet:SSK@d8lB5dqTaAt~39aFk6KyMU4cb5y3BEkNWgneouaVq0g,P~pzGxzDr08D7NfzKkKOvRHGf3jXUAr7lavnZfszflc,AQACAAE/stream.m3u

(also works in vlc, but with small gaps between the segments)

We have Freenet Radio!

It’s imperfect and you’ll hit some gotchas, but it works, and that’s seriously cool!

4. Background: Multi-node version

To speed this up more, you can install multiple nodes. This recipe can livestream audio over Freenet with 5-10 minutes delay if you have at least 400kiB/s upload speed.

First install a template node:

FREENET_NODES_BASEFOLDER=/tmp/freenet-streaming-nodes
mkdir "${FREENET_NODES_BASEFOLDER}"
cd "${FREENET_NODES_BASEFOLDER}"
mkdir node1
cd node1
# following https://www.draketo.de/software/install-freenet-linux.html
wget 'https://github.com/freenet/fred/releases/download/build01492/new_installer_offline_1492.jar'
java -jar new_installer_offline_1492.jar -console

follow the prompts, then open the Freenet web interface:

lynx 127.0.0.1:8888
# follow the wizard

Now stop the node:

cd "${FREENET_NODES_BASEFOLDER}"/node1; ./run.sh stop; cd "${FREENET_NODES_BASEFOLDER}"

Next just copy the folder:

for i in {2..5}; do cp -r node1 node$i; done

Then remove the listen-port lines in freenet.ini. This causes Freenet to create unique listen ports on the next run.

Also adjust the fcpport, fred port, and optionally the bandwidth:

for i in {1..5}; do
    sed -i s/fproxy.port=.*/fproxy.port=8${i}80/  node$i/freenet.ini
    sed -i s/fcp.port=.*/fcp.port=9${i}80/  node$i/freenet.ini
    sed -i s/node.listenPort=.*// node$i/freenet.ini
    sed -i s/node.opennet.listenPort=.*// node$i/freenet.ini
    sed -i s/node.inputBandwidthLimit=.*/node.inputBandwidthLimit=70k/ node$i/freenet.ini
    sed -i s/node.outputBandwidthLimit=.*/node.outputBandwidthLimit=70k/ node$i/freenet.ini
done

And start them:

for i in {1..5}; do cd node$i; ./run.sh start; cd -; done
$ grep -i \\.port node*/*ini
node1/freenet.ini:fproxy.port=8180
node1/freenet.ini:fcp.port=9180
node2/freenet.ini:fproxy.port=8280
node2/freenet.ini:fcp.port=9280
node3/freenet.ini:fproxy.port=8380
node3/freenet.ini:fcp.port=9380
node4/freenet.ini:fproxy.port=8480
node4/freenet.ini:fcp.port=9480
node5/freenet.ini:fproxy.port=8580
node5/freenet.ini:fcp.port=9580

Now we have 5 running nodes on FCP ports 9180 to 9580. We‘ll use them to insert:

# stream the radio cc without transcoding
# SOURCE=http://mp3.theradio.cc/
# stream rc3 (remote chaos experience)
# SOURCE=https://cdn.c3voc.de/hls/chaoszone/native_sd.m3u8
# stream the radio CC with transcoding 
# (using ogg instead of opus, because with opus ffmpeg stopped transcoding randomly)
SOURCE=http://stream.theradio.cc:8000/trcc-stream-lq.ogg
KEY=$(fcpgenkey -P 9180 | tail -n 1)
PUBKEY=$(fcpinvertkey -P 9180 $KEY)
FILEPREFIX="theradiocc-"
rm -rf /tmp/FREESTREAM-split/
mkdir /tmp/FREESTREAM-split/
cd /tmp/FREESTREAM-split/
for i in {000..999}; do
    echo "${FILEPREFIX}${i}.mp3" >> stream.m3u;
done
# insert stream.m3u with compression because it is large and very
# repetitive, and with high priority to ensure that it does not get
# drowned by later mp3 inserts
# use the last node for the streaming file
fcpupload -P 9580 -p 2 ${KEY}stream.m3u stream.m3u
# provide the link to the playlist
echo Streaming radio to $(fcpinvertkey -P 9180 $KEY)stream.m3u

# run mp3 encoding asynchronously for one hour, re-encode to quality 8
# (second to lowest quality) so this can work with an OK connection.
# copy mp3 data from theradio.cc
# timeout 60000 nohup ffmpeg -i ${SOURCE}  \
#         -c copy -map 0 \
#         -segment_time 00:00:20 \
#         -f segment \
#         -reset_timestamps 1 "${FILEPREFIX}%03d.mp3" &
# re-encode for 50000 seconds, for 1000 segments, each 50s
timeout 50000 nohup ffmpeg -i ${SOURCE}  \
        -c:a libmp3lame -vn  -map 0:a:0 \
        -abr 1 -b:a 50k \
        -segment_time 00:00:50 \
        -f segment \
        -reset_timestamps 1 "${FILEPREFIX}%03d.mp3" &
# show a command how to actually start the stream
echo you can listen to the stream with
echo mpv --ytdl=no --prefetch-playlist http://127.0.0.1:8888/freenet:$(fcpinvertkey -P 9180 $KEY)stream.m3u
for i in {00..99}; do
    # upload 9 files in parallel, because Freenet does some checking
    # for availability, that does not consume much bandwidth but takes
    # time
    PRE="${FILEPREFIX}${i}"
    # wait until the next file is available, to ensure that the current file is ready
    while test ! -e "${PRE}1.mp3"; do sleep 10; done
    date # for statistics
    # upload the first 5 files, one file per insertion-node
    # the first 5 get higher priority
    fcpupload -P 9180 -p 2 "${KEY}${PRE}0.mp3" "${PRE}0.mp3"
    while test ! -e "${PRE}2.mp3"; do sleep 10; done
    fcpupload -P 9280 -p 2 "${KEY}${PRE}1.mp3" "${PRE}1.mp3"
    while test ! -e "${PRE}3.mp3"; do sleep 10; done
    fcpupload -P 9380 -p 2 "${KEY}${PRE}2.mp3" "${PRE}2.mp3"
    while test ! -e "${PRE}4.mp3"; do sleep 10; done
    fcpupload -P 9480 -p 2 "${KEY}${PRE}3.mp3" "${PRE}3.mp3"
    while test ! -e "${PRE}5.mp3"; do sleep 10; done
    fcpupload -P 9580 -p 2 "${KEY}${PRE}4.mp3" "${PRE}4.mp3"
    # the next 5 get lower priority so the first finish earlier, 
    # but they run in parallel to catch up on time lost at the end
    while test ! -e "${PRE}6.mp3"; do sleep 10; done
    fcpupload -P 9180 "${KEY}${PRE}5.mp3" "${PRE}5.mp3" &
    while test ! -e "${PRE}7.mp3"; do sleep 10; done
    fcpupload -P 9280 "${KEY}${PRE}6.mp3" "${PRE}6.mp3" &
    while test ! -e "${PRE}8.mp3"; do sleep 10; done
    fcpupload -P 9380 "${KEY}${PRE}7.mp3" "${PRE}7.mp3" &
    while test ! -e "${PRE}9.mp3"; do sleep 10; done
    # wait for completion of the upload before the last upload 
    # as a primitive way to limit parallelism; 
    # no use clogging the node if it cannot keep up
    fcpupload -w -P 9480 "${KEY}${PRE}8.mp3" "${PRE}8.mp3"
    # wait a full segment to ensure that the last file actually is ready
    # (because we do not have the next key yet, so we cannot do nice checking)
    sleep 50
    fcpupload -P 9580 "${KEY}${PRE}9.mp3" "${PRE}9.mp3"
done

5. Video-Streaming

Wouldn’t it be great to replace youtube with fully decentralized streaming? Can Freenet do it? Are you up for the test? :-)

You won’t be live-streaming yet, bandwidth does not suffice with the currently supported codecs, but you can provide video that starts playing right-away.

We’ll prepare the nodes just like before, and choose a video file to stream.

SOURCE=/tmp/36C3_-_Climate_Modelling-Q_ysS7C8IBw.mkv
KEY=$(fcpgenkey -P 9180 | tail -n 1)
PUBKEY=$(fcpinvertkey -P 9180 $KEY)
FILEPREFIX="36c3-climate-"
rm -rf /tmp/FREESTREAM-split/
mkdir /tmp/FREESTREAM-split/
cd /tmp/FREESTREAM-split/
for i in {000..999}; do
    echo "${FILEPREFIX}${i}.ogv" >> stream.m3u;
done
# insert stream.m3u with compression because it is large and very
# repetitive, and with high priority to ensure that it does not get
# drowned by later ogv inserts
# use the last node for the streaming file
fcpupload -P 9580 -p 2 ${KEY}stream.m3u stream.m3u
# provide the link to the playlist
echo Streaming radio to $(fcpinvertkey -P 9180 $KEY)stream.m3u
# run ogv encoding asynchronously for one hour, re-encode to quality 0
# (lowest quality) so this can work with an OK connection.
timeout 60000 nohup ffmpeg -i ${SOURCE}  \
        -c:v libtheora -c:a libvorbis -map 0 \
        -q:v 1 -q:a 1 \
        -vf scale=640:480 \
        -segment_time 00:00:15 \
        -f segment \
        -reset_timestamps 1 "${FILEPREFIX}%03d.ogv" &
# show a command how to actually start the stream
echo you can listen to the stream with
echo mpv --ytdl=no --prefetch-playlist http://127.0.0.1:8888/freenet:$(fcpinvertkey -P 9180 $KEY)stream.m3u
for i in {00..99}; do
    # upload 9 files in parallel, because Freenet does some checking
    # for availability, that does not consume much bandwidth but takes
    # time
    PRE="${FILEPREFIX}${i}"
    # wait until the first 5 files are available
    while test ! -e "${PRE}5.ogv"; do sleep 10; done
    date # for statistics
    # upload the first 5 files, one file per insertion-node
    # the first 5 get higher priority
    fcpupload -P 9180 -p 2 "${KEY}${PRE}0.ogv" "${PRE}0.ogv"
    fcpupload -P 9280 -p 2 "${KEY}${PRE}1.ogv" "${PRE}1.ogv"
    fcpupload -P 9380 -p 2 "${KEY}${PRE}2.ogv" "${PRE}2.ogv"
    fcpupload -P 9480 -p 2 "${KEY}${PRE}3.ogv" "${PRE}3.ogv"
    fcpupload -P 9580 -p 2 "${KEY}${PRE}4.ogv" "${PRE}4.ogv"
    # wait until the next 5 files are available
    while test ! -e "${PRE}9.ogv"; do sleep 10; done
    # wait some more to avoid partial files
    sleep 60
    fcpupload -P 9180 "${KEY}${PRE}5.ogv" "${PRE}5.ogv"
    fcpupload -P 9280 "${KEY}${PRE}6.ogv" "${PRE}6.ogv"
    fcpupload -P 9380 "${KEY}${PRE}7.ogv" "${PRE}7.ogv"
    fcpupload -P 9480 "${KEY}${PRE}8.ogv" "${PRE}8.ogv"
    # wait for completion of the last upload as a primitive way to limit parallelism
    fcpupload -w -P 9580 "${KEY}${PRE}9.ogv" "${PRE}9.ogv"
done

This has some glitches at the beginning, but you can already watch it:

mpv --ytdl=no --prefetch-playlist http://127.0.0.1:8888/freenet:SSK@I3yBAkjMtFmZPQS088ch7JkIVQzXiwGSEDHy7ge-pds,ahgVpCwvDfOPYB9tTNFS~nSQUS4SjrXaXfEHn999cs4,AQACAAE/stream.m3u

And with that we have video-streaming over Freenet!

6. Background: Split a video file by silence

Depending on your player, playback might not be completely gapless. You can lessen this problem by splitting the video file by silence. While this will likely fail catastrophically for music, it should work pretty well for recorded talks.

Here’s a one-line example from Vi at Stackoverflow, adapted to prouce scaled down ogg theora for Freenet, splitting at places with at least 0.3 seconds of -40dB signal:

ffmpeg -i infile.mkv -filter_complex "[0:a]silencedetect=n=-40dB:d=0.3[outa]" -map [outa] -f s16le -y /dev/null |& F='-q:v 0 -q:a 0 -vf scale=320:240' perl -ne 'INIT { $ss=0; $se=0; } if (/silence_start: (\S+)/) { $ss=$1; $ctr+=1; printf "ffmpeg -nostdin -i infile.mkv -ss %f -t %f $ENV{F} -y ssf-%03d.ogv\n", $se, ($ss-$se), $ctr; }  if (/silence_end: (\S+)/) { $se=$1; } END { printf "ffmpeg -nostdin -i infile.mkv -ss %f $ENV{F} -y ssf-%03d.ogv\n", $se, $ctr+1; }' | bash -x

ArneBab 2020-11-30 Mo 00:00 - Impressum - GPLv3 or later (code), cc by-sa (rest)