From: Dmitry Shalnoff Date: Wed, 8 Jul 2020 23:25:57 +0000 (+0200) Subject: Initial commit X-Git-Url: https://git.shalnoff.com/BABOOSHKA.TV/commitdiff_plain/0b1b5e8500d533b59121e6d3e62254d4224232f2?ds=sidebyside Initial commit --- 0b1b5e8500d533b59121e6d3e62254d4224232f2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2c3fa5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +playlist +currentpos +currenttrack +VIDEO/ +YOUTUBE/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..1ebec86 --- /dev/null +++ b/README.md @@ -0,0 +1,379 @@ +# [babooshka.tv](https://babooshka.tv) old-school tv-box video player + +This simple and lightweight package could turn your RPi into a video player. The package is designed primarily for your grandparents, for whom the use of a computer is a difficult task. You can upload your home kittens-kids videos or add videos from Youtube/Vimeo that you like. + +The package is fully written in bash. + +![babooshka.tv RPi based prototype](https://repository.interplaymedium.org/babooshka.tv/babooshka.tv.rpi.jpeg) + +## Wiring + +[Pi Zero IO Pinout](https://pinout.xyz/pinout/io_pi_zero) + +The yellow LED connected to +3,3v via 470R + + GPIO 0 BCM17 LED green, booting + GPIO 2 BCM27 LED red, video status + +Lowering resistors are required for all diodes (Red LEDs normally brighter, so I would recommend ~470R for yellow and green and about 1K for red) + +### Infrared interface + + GPIO 3 BCM22 IR TX + GPIO 4 BCM23 IR RX + + 38kHz -- most popular + + +-----------------------+ 3 + | data -> +---------------------o +3.3V + | ______________ | + | / | + | ( | 2 + | \______________ + +---------------------o GND + | | + | | 1 + | - +---------------------o GPIO 4 (BCM23) + +-----------------------+ + + + 950nm emitting diode (e.g. TSUS5400) + + +5V + o + | + | | 51 Ohm (depending on MOSFET maybe not required) + |_| + | + _|_ + \ / + --- --> IR LED + | + MOSFET | + ___ |---' + o-----|___|-----| + 10K |->-- + GPIO 3 (BCM22) | + | + ----- GND + --- + - + +### Analog Audio + + GPIO 1 BCM18 R AUDIO + GPIO 23 BCM13 L AUDIO + +![RPi Zero Audio](https://repository.interplaymedium.org/babooshka.tv/pi-zero-audio_bb.jpg) +Picture taken [from here](https://shallowsky.com/blog/hardware/pi-zero-audio.html), thanks :) + +### Analog video pin + +![RPi TV out](https://repository.interplaymedium.org/babooshka.tv/RPi_TV_out.jpeg) +Picture taken [from here](https://magpi.raspberrypi.org/articles/rca-pi-zero), thanks :) + +## Setup + +Download, copy to microSD and install oficial [Raspberry Pi OS Lite image](https://www.raspberrypi.org/downloads/raspberry-pi-os/) + +The procedure of adding a login and password for your access point, as well as the ssh configuration is omitted. It is assumed that you know how to do so :) +If you not sure, [ddg it](https://duckduckgo.com/?q=RPi+headless+how+setup+and+ssh). + +Further operations are performed on device. + + ssh + +Update repository list and install dependencies + + apt update + apt install mc fbi omxplayer sox + +Try to install freefonts (required by omxplayer) + + apt install freefonts + +By some reason recently *freefonts* package has been removed from official RPi repository. So in case of unsuccess just copy included freefonts to /usr/share/fonts/truetype/... +do it with *sudo* + + cp -r freefont /usr/share/fonts/truetype/freefont + chown root:root /usr/share/fonts/truetype/freefont + chown root:root /usr/share/fonts/truetype/freefont/* + +### IR interface setup + + apt install lirc + +edit /etc/lirc/hardware.conf + + # Run "lircd --driver=help" for a list of supported drivers. + DRIVER="default" + + # usually /dev/lirc0 is the correct setting for systems using udev + DEVICE="/dev/lirc1" + MODULES="gpio_ir_recv" + +edit /etc/lirc/lirc_options.conf +NOTE! add new line in the end of the file !!!! [known bug](https://forum.odroid.com/viewtopic.php?t=32181) + + driver = default + device = /dev/lirc1 + +First try to find you device using + + irdb-get find YOUR_DEVICE + +In case of unsiccess try to find and copy YOUR_DEVICE.conf for your remote controller to */etc/lirc/lircd.conf.d/* +Here is a [list of devices](http://lirc-remotes.sourceforge.net/remotes-table.html) supported by Lirc 'from the box'. However, you always can record your own, see below... + +Copy template lircd.conf + + cp /etc/lirc/lircd.conf.dist /etc/lirc/lircd.conf + +Make changes in */boot/config.txt* to set up PAL video output and run appropriate kernel overlays for IR interface: + + disable_splash=1 + + # disable_overscan=1 + + framebuffer_width=720 + framebuffer_height=576 + + # enable PWM audio (add this line) + dtoverlay=pwm-2chan,pin=18,func=2,pin2=13,func2=4 + + # uncomment for composite PAL + sdtv_mode=2 + + # uncomment if hdmi display is not detected and composite is being output + # hdmi_force_hotplug=1 + + # Uncomment this to enable the gpio-ir module + dtoverlay=gpio-ir,gpio_pin=23,gpio_pull=up + dtoverlay=gpio-ir-tx,gpio_pin=22 + +### Make IR works as TX and RX simultanoiously + +This part taken from [this GitHub comment](https://github.com/raspberrypi/linux/issues/2993#issuecomment-497420228) thank you [@elmicha](https://github.com/elmicha) :) + +Add these rules in */etc/udev/rules.d/71-lirc.rules* to get stable */dev/lirc-rx* and */dev/lirc-tx* device names: + + ACTION=="add", SUBSYSTEM=="lirc", DRIVERS=="gpio_ir_recv", SYMLINK+="lirc-rx" + ACTION=="add", SUBSYSTEM=="lirc", DRIVERS=="gpio-ir-tx", SYMLINK+="lirc-tx" + ACTION=="add", SUBSYSTEM=="lirc", DRIVERS=="pwm-ir-tx", SYMLINK+="lirc-tx" + +Change the device and listening address in /etc/lirc/lirc_options.conf: + + device = /dev/lirc-rx + listen = 0.0.0.0:8766 + +Copy lirc_options.conf to lirc_tx_options.conf and edit these lines: + + device = /dev/lirc-tx + output = /var/run/lirc/lircd-tx + pidfile = /var/run/lirc/lircd-tx.pid + listen = 0.0.0.0:8765 + connect = 127.0.0.1:8766 + +Create */etc/systemd/system/lircd-tx.service* (from the output of *systemctl cat lircd*) and edit it like this: + + [Unit] + Documentation=man:lircd(8) + Documentation=http://lirc.org/html/configure.html + Description=Second lircd, the transmitter + Wants=lircd-setup.service + After=network.target lircd-setup.service lircd.service + + [Service] + Type=simple + ExecStart=/usr/sbin/lircd --nodaemon --options-file /etc/lirc/lirc_tx_options.conf + + [Install] + WantedBy=multi-user.target + Create /etc/systemd/system/lircd-tx.socket (from the output of systemctl cat lircd.socket) and edit it: + + [Socket] + ListenStream=/run/lirc/lircd-tx + + [Install] + WantedBy=sockets.target + Also=lircd-tx.service + + +Create /usr/local/bin/irsend and make it executable + + #! /bin/sh + exec /usr/bin/irsend --device=/var/run/lirc/lircd-tx "$@" + +Start lircd-tx (with *sudo*) + + systemctl daemon-reload + systemctl start lircd-tx + systemctl enable lircd-tx + +Enable RX (with *sudo*) + systemctl enable lircd.service + systemctl enable lircd.socket + + systemctl restart lircd + +NOTE: there maybe the Warning of duplication of "begin remote .. end remote", it is fine. Ignore it. + +Reboot and check status :) + + systemctl reboot + + systemctl status lircd.service + systemctl status lircd.socket + +### Test IR + +Send some command. replace vendor and command with your + + irsend SEND_ONCE SONY-TV KEY_1 + +Read RX + irw + +Record your own (if you have no compatible remote control or incomplete config) + + systemctl stop lircd.socket + systemctl stop lircd.service + + record with own key names + irrecord --disable-namespace + + systemctl start lircd.socket + systemctl start lircd.service + +Force raw record mode (normally not required) + + irrecord -f -d /dev/lirc0 ~/lirc.conf + +## Main package installation + + cd /home/pi/ + git clone (see above) + cd BABOOSHKA.TV/ + +Make sure that all .sh files inside are executable (have x flag) + + ls --all + +if required make them *chmod +x *.sh* + +### Early stage systemd service (launching led driver and creating splash image) + +Create */etc/systemd/system/splash.service* file and add there + + [Unit] + DefaultDependencies=no + After=local-fs.target + + [Service] + StandardInput=tty + StandardOutput=tty + ExecStart=/home/pi/BABOOSHKA.TV/early_init.sh + + [Install] + WantedBy=sysinit.target + +Activate the service + + sudo systemctl enable splash.service + +### On boot launcher + +Add this line to */etc/rc.local* + + sudo -H -u pi /home/pi/babooshka.tv/start.babooshka.sh > /dev/null & + +reboot and test :) + + systemctl reboot + +if everything has been done properly, you will see the splash babooshka.tv logo + +- add testing video in *~/BABOOSHKA.TV/VIDEO/* directory +- check playlist (that the video link has been added) +- click PLAY on your remote +- if something went wrong, see Debug section below + +## Cosmetic polishing + +Edit */boot/cmdline.txt*. Make sure that you have *console=tty3 quiet consoleblank=0* and *logo.nologo*, this is my cmdline: + + console=serial0,115200 console=tty3 quiet consoleblank=0 loglevel=1 root=PARTUUID=6c586e13-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait logo.nologo + +Disable blinking cursor (probably not required) + + vt.global_cursor_default=0 + +Remove tty login service to eliminate blinking cursor + + sudo systemctl disable getty@tty1 + +## Additional software + +If' you're going to watch videos from YouTube, Vimeo and so on, this packages would be required. Most porbably probably would beed to install youtube-dl globally. So do that with *sudo -H ...*. It would be recommended wor futher compatibility. + + apt install mkvtoolnix python-pip + pip install -U youtube-dl + +## Usage + +converting video (note -level 3.0 option! it is required for RPi HW codec) + + ffmpeg -i FILEIN -vcodec libx264 -preset slow -level 3.0 -b 700k -s 720x404 FILEOUT + +upload new video from local PC + + scp :BABOOSHKA.TV/VIDEO/ + +download new video from youtube (on device) + + youtube-dl -f 'bestvideo[vcodec=avc1][height<=720]+bestaudio/best[abr<=120]' --merge-output-format mp4 -o '%(playlist_index)s - %(title)s.%(ext)s' + +click PLAY button and enjoy :) + +## Debug + + tail -F /tmp/babooshka.log + +## Known bugs + +- Not changing the state on finish (WATCHED) if video has been resumed (time of resuming is disregarded) + +## Todo + +- WiFi auto-reconnect, probably *sudo iw dev wlan0 set power_save off* would be helpful +- youtube-dl, autoupdate +- youtube-dl download from downloadlist +- check free storage space +- auto removing of old videos + commenting in playlist +- splash info, Nth video from COUNT videos +- Make a single package + +## Extras + +Download this nice babooshka.tv [sticker and logo](https://repository.interplaymedium.org/babooshka.tv/babooshka_sticker.svg) + +![babooshka.tv found enclosure and cool sticker](https://repository.interplaymedium.org/babooshka.tv/babooshka.tv.enclosure_front.jpeg) + +## License + +Copyright © 2020 Dmitry Shalnov [interplaymedium.org] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this files except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + + + diff --git a/dbuscontrol.sh b/dbuscontrol.sh new file mode 100755 index 0000000..48d792a --- /dev/null +++ b/dbuscontrol.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +#set -x + +OMXPLAYER_DBUS_ADDR="/tmp/omxplayerdbus.${USER:-root}" +OMXPLAYER_DBUS_PID="/tmp/omxplayerdbus.${USER:-root}.pid" + +# OMXPLAYER_DBUS_ADDR="/tmp/omxplayerdbus.pi" +# OMXPLAYER_DBUS_PID="/tmp/omxplayerdbus.pi.pid" + +export DBUS_SESSION_BUS_ADDRESS=`cat $OMXPLAYER_DBUS_ADDR` +export DBUS_SESSION_BUS_PID=`cat $OMXPLAYER_DBUS_PID` + +[ -z "$DBUS_SESSION_BUS_ADDRESS" ] && { echo "Must have DBUS_SESSION_BUS_ADDRESS" >&2; exit 1; } + +case $1 in + status) + duration=`dbus-send --print-reply=literal --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:"org.mpris.MediaPlayer2.Player" string:"Duration"` + [ $? -ne 0 ] && exit 1 + duration="$(awk '{print $2}' <<< "$duration")" + + position=`dbus-send --print-reply=literal --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:"org.mpris.MediaPlayer2.Player" string:"Position"` + [ $? -ne 0 ] && exit 1 + position="$(awk '{print $2}' <<< "$position")" + + playstatus=`dbus-send --print-reply=literal --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:"org.mpris.MediaPlayer2.Player" string:"PlaybackStatus"` + [ $? -ne 0 ] && exit 1 + playstatus="$(sed 's/^ *//;s/ *$//;' <<< "$playstatus")" + + paused="true" + [ "$playstatus" == "Playing" ] && paused="false" + echo "Duration: $duration" + echo "Position: $position" + echo "Paused: $paused" + ;; + + volume) + volume=`dbus-send --print-reply=double --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Set string:"org.mpris.MediaPlayer2.Player" string:"Volume" ${2:+double:}$2` + [ $? -ne 0 ] && exit 1 + volume="$(awk '{print $2}' <<< "$volume")" + echo "Volume: $volume" + ;; + + list) # list dbus interfaces + + dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ListNames +# dbus-send --print-reply=literal --type=method_call --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.freedesktop.DBus.Introspectable.Introspect + ;; + + pause) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:16 >/dev/null + ;; + + info) # doesn't work IMHO + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:5 + ;; + + action) # universal + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:$2 >/dev/null + ;; + +# ----------------------------------------------- + + subslist) + subslist=`dbus-send --print-reply --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.ListSubtitles` +# [ $? -ne 0 ] && exit 1 + echo "$subslist" | grep string + ;; + + togglesubtitles) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:12 >/dev/null + ;; + + hidesubtitles) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:30 >/dev/null + ;; + + showsubtitles) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:31 >/dev/null + ;; + subsnext) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:11 >/dev/null + ;; + subsprev) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:10 >/dev/null + ;; + +# ----------------------------------------------- + + audiolist) + audiolist=`dbus-send --print-reply --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.ListAudio` +# [ $? -ne 0 ] && exit 1 + echo "$audiolist" | grep string + ;; + + audiom) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:6 >/dev/null + ;; + + audiop) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:7 >/dev/null + ;; + +# ----------------------------------------------- + + seekfl) # seek forward large step + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:22 >/dev/null + ;; + + seekbl) # seek backward large step + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:21 >/dev/null + ;; + + seekf) # seek forward large step + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:20 >/dev/null + ;; + + seekb) # seek backward large step + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:19 >/dev/null + ;; + +# ----------------------------------------------- + + stop) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:15 >/dev/null + ;; + + seek) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Seek int64:$2 >/dev/null + ;; + + setposition) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.SetPosition objpath:/not/used int64:$2 >/dev/null + ;; + + setalpha) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.SetAlpha objpath:/not/used int64:$2 >/dev/null + ;; + + setvideopos) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.VideoPos objpath:/not/used string:"$2 $3 $4 $5" >/dev/null + ;; + + setvideocroppos) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.SetVideoCropPos objpath:/not/used string:"$2 $3 $4 $5" >/dev/null + ;; + + setaspectmode) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.SetAspectMode objpath:/not/used string:"$2" >/dev/null + ;; + + hidevideo) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:28 >/dev/null + ;; + + unhidevideo) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:29 >/dev/null + ;; + + volumeup) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:18 >/dev/null + ;; + + volumedown) + dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:17 >/dev/null + ;; + + getsource) + source=$(dbus-send --print-reply=literal --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.GetSource) + echo "$source" | sed 's/^ *//' + ;; + *) + echo "usage: $0 status|pause|stop|seek|volumeup|volumedown|setposition [position in microseconds]|hidevideo|unhidevideo|togglesubtitles|hidesubtitles|showsubtitles|setvideopos [x1 y1 x2 y2]|setvideocroppos [x1 y1 x2 y2]|setaspectmode [letterbox,fill,stretch,default]|setalpha [alpha (0..255)]|getsource" >&2 + exit 1 + ;; +esac diff --git a/early_init.sh b/early_init.sh new file mode 100755 index 0000000..56e186b --- /dev/null +++ b/early_init.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +export BABOOSHKA_HOME=/home/pi/BABOOSHKA.TV/ + +# run booting led and led daemon +$BABOOSHKA_HOME/leds.sh 2>&1 >/dev/null & + +# show splash image +/usr/bin/fbi -d /dev/fb0 --once --noverbose --autozoom $BABOOSHKA_HOME/splash.png + +exit 0 diff --git a/freefont/FreeMono.ttf b/freefont/FreeMono.ttf new file mode 100644 index 0000000..61d8263 Binary files /dev/null and b/freefont/FreeMono.ttf differ diff --git a/freefont/FreeMonoBold.ttf b/freefont/FreeMonoBold.ttf new file mode 100644 index 0000000..2212613 Binary files /dev/null and b/freefont/FreeMonoBold.ttf differ diff --git a/freefont/FreeMonoBoldOblique.ttf b/freefont/FreeMonoBoldOblique.ttf new file mode 100644 index 0000000..16d9cd7 Binary files /dev/null and b/freefont/FreeMonoBoldOblique.ttf differ diff --git a/freefont/FreeMonoOblique.ttf b/freefont/FreeMonoOblique.ttf new file mode 100644 index 0000000..7a11773 Binary files /dev/null and b/freefont/FreeMonoOblique.ttf differ diff --git a/freefont/FreeSans.ttf b/freefont/FreeSans.ttf new file mode 100644 index 0000000..81b0509 Binary files /dev/null and b/freefont/FreeSans.ttf differ diff --git a/freefont/FreeSansBold.ttf b/freefont/FreeSansBold.ttf new file mode 100644 index 0000000..a1ec0a3 Binary files /dev/null and b/freefont/FreeSansBold.ttf differ diff --git a/freefont/FreeSansBoldOblique.ttf b/freefont/FreeSansBoldOblique.ttf new file mode 100644 index 0000000..5d2acfe Binary files /dev/null and b/freefont/FreeSansBoldOblique.ttf differ diff --git a/freefont/FreeSansOblique.ttf b/freefont/FreeSansOblique.ttf new file mode 100644 index 0000000..f5521bc Binary files /dev/null and b/freefont/FreeSansOblique.ttf differ diff --git a/freefont/FreeSerif.ttf b/freefont/FreeSerif.ttf new file mode 100644 index 0000000..21609e1 Binary files /dev/null and b/freefont/FreeSerif.ttf differ diff --git a/freefont/FreeSerifBold.ttf b/freefont/FreeSerifBold.ttf new file mode 100644 index 0000000..c3254c8 Binary files /dev/null and b/freefont/FreeSerifBold.ttf differ diff --git a/freefont/FreeSerifBoldItalic.ttf b/freefont/FreeSerifBoldItalic.ttf new file mode 100644 index 0000000..49669fd Binary files /dev/null and b/freefont/FreeSerifBoldItalic.ttf differ diff --git a/freefont/FreeSerifItalic.ttf b/freefont/FreeSerifItalic.ttf new file mode 100644 index 0000000..fd06aab Binary files /dev/null and b/freefont/FreeSerifItalic.ttf differ diff --git a/leds.sh b/leds.sh new file mode 100755 index 0000000..8783eca --- /dev/null +++ b/leds.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +echo "leds on" + +LEDS_CONTROL=/tmp/bbshk_leds +LED_BOOT=2 +LED_VIDEO=0 + +# touch $LEDS_CONTROL +# gpio write $LED_BOOT 1 + +gpio mode 0 out # II green +gpio mode 2 out # III red + +while [ 1 ]; do + + LEDS_STATE=$(cat $LEDS_CONTROL) + + case "$LEDS_STATE" in + "BOOTCOMPLETE") + gpio write $LED_BOOT 1 + ;; + + "NEWVIDEO") + if [ -z $ONOFF ]; then + gpio write $LED_VIDEO 0 + ONOFF=1 + else + gpio write $LED_VIDEO 1 + ONOFF='' + fi + ;; + + "VIDEOSTARTED") + gpio write $LED_VIDEO 1 + ;; + + "VIDEOCOMPLETE") + gpio write $LED_VIDEO 0 + ;; + + *) # booting + echo $LEDS_STATE + if [ -z $ONOFF ]; then + gpio write $LED_BOOT 0 + ONOFF=1 + else + gpio write $LED_BOOT 1 + ONOFF='' + fi + ;; + esac + + sleep 0.5s +done diff --git a/playlist.sh b/playlist.sh new file mode 100755 index 0000000..b7c5643 --- /dev/null +++ b/playlist.sh @@ -0,0 +1,365 @@ +#!/bin/bash + +if [ $# -lt 1 ]; then + + echo "IM Playlist Player. Created for BABOOSHKA.TV™ project (https://babooshka.tv)" + echo "Copyright © 2020 Dmitry Shalnov [interplaymedium.org]" + echo "Licensed under the Apache License, Version 2.0" + + echo "Usage: $0 -p [options]" + echo "-v volume amp in dB>" + echo "-f play from Nth file in the playlist" + echo "-a set audio track" + echo "-m video mode in WxH format" + echo "-t subtitle track number" + echo "-s stop after" + echo "-o play list once (make sence if you're not using -s option)" + echo "Dependences: omxplayer, ttf-freefont" + echo "Playlist format (using TAB delimiter): [comment] [additional options] [position] [state]" + echo "Use ';' symbol to comment playlist lines if needed" + exit 1 +fi + +# BABOOSHKA_HOME=/home/pi # assigned in start.babooshka.sh + +SAVE_PATH=$BABOOSHKA_HOME +DBUS_CTRL_FILE=/tmp/dbuscontrol_command +VOLUME=0 +LEDS_CONTROL=/tmp/bbshk_leds +CNT=1 + +# ------------------- parse commandline ---------------------- + +parserCnt=0 + +while [ "$#" -gt 0 ] && [ "$parserCnt" -lt 20 ] ; do + case "$1" in +# -i) MEDIAPATH="$2"; shift 2;; # media file + -p) PLAYLIST="$2"; shift 2;; # media file + -v) VOLUME="$2"; shift 2;; # volume amp + -f) START_FROM="$2"; shift 2;; # from Nth file, 0 is random order + -a) PREF_LANG="$2"; shift 2;; # audio track prefered language pattern, e.g. ":ру|:ru" + -m) VIDEOMODE="$2"; shift 2;; # video mode + -t) SUBTITLES="$2"; shift 2;; # volume amp + -s) PLAYSINGLE=1; shift 1;; # play file by file with stops (no parameter required) + -o) PLAYLISTONCE=1; shift 1;; # play list once (no parameter required) + + -*) echo "unknown option: $1" >&2; exit 1;; +# *) handle_argument "$1"; shift 1;; + *) sleep 0; shift 1;; + esac + parserCnt=$(( $parserCnt + 1 )) +done + +if [ "$SUBTITLES" != "" ]; then SUBTITLES_SET="-t $SUBTITLES"; fi + +if [ -z "$PLAYLIST" ]; then + echo "Playlist is not assigned. Please use -p option." + exit 0 +fi + +# ------------------------------------------------------------------- + +killCCONTROL() { # function called by trap (Ctrl-C handler) + + kill -9 $WAIT1_PID 2>/dev/null + kill -9 $WAIT2_PID 2>/dev/null + kill -9 $WAIT3_PID 2>/dev/null + kill -9 $PLAYLIST_CHANGE_PID 2>/dev/null + echo "Have a nice day..." + exit 0 +} + +trap 'killCCONTROL' 2 + +waiting_for_press_play() { + echo "waiting for PLAY button press... "; + while [ "$DBUS_COMMAND" != "PLAY" ]; do + DBUS_COMMAND=$(cat $DBUS_CTRL_FILE) +# echo -n "." + sleep 1 + done +# echo '' +} + +waiting_for_player_start() { + echo "waiting for playback starting... "; + while ! ./dbuscontrol.sh status 1>/dev/null 2>/dev/null ; do +# echo -n "+" + sleep 1 + done +# echo '' +} + +# check for unwatched / not completed video and turn RED LED on + +check_video_complete(){ + + if grep -v -P "\tPLAY|\tWATCHED" "$1" | grep "^[^#;]" >/dev/null ; then + + lastLedState=$(cat $LEDS_CONTROL) + currentPos=$(cat $SAVE_PATH/currentpos) + + # make new video current (if previous one has not been paused and all videos has been watched) + + if [ "$lastLedState" == "VIDEOCOMPLETE" ] && [ "$currentPos" == '' ]; then + newVideo=$(grep -v -P "\tPLAY|\tWATCHED" "$1" | grep "^[^#;]" | head -1 | awk '{split($0,a,"\t"); print a[1]}') + echo $newVideo > $SAVE_PATH/currenttrack + echo "Playlist changed: $newVideo" + fi + +# echo 'NEWVIDEO' + echo "NEWVIDEO" > "$LEDS_CONTROL" + else + if grep -P "\tPLAY" "$1" | grep "^[^#;]" >/dev/null ; then +# echo 'VIDEOSTARTED' + echo "VIDEOSTARTED" > "$LEDS_CONTROL" + else +# echo 'VIDEOCOMPLETE' + echo "VIDEOCOMPLETE" > "$LEDS_CONTROL" + fi + fi +} + +# check_video_complete "$PLAYLIST" + +# background checking for external playlist changes + +{ + while [ 1 ]; do + check_video_complete "$PLAYLIST" + sleep 10 + done +} & +PLAYLIST_CHANGE_PID=$! + +# ----------------------- crash / reboot handler -------------------- + +touch "$DBUS_CTRL_FILE" +touch $SAVE_PATH/currenttrack +touch $SAVE_PATH/currentpos + +currentTrack=$(cat $SAVE_PATH/currenttrack) +currentPos=$(cat $SAVE_PATH/currentpos) + +echo "Saved track: $currentPos, $currentTrack" + +if [ "$START_FROM" == '' ]; then + + if [ "$currentTrack" != '' ]; then + + currentTrackNum=$( cat $PLAYLIST | grep "^[^#;]" | grep -Fn "$currentTrack" | cut -f1 -d: ) # looking for current track in playlist and return number of it + + if [ "$currentTrackNum" != "" ]; then # playlist has been updated + CNT=$currentTrackNum; + echo "Current track number: $CNT" + fi + + if [ "$currentTrackNum" != '' ] && [ "$currentPos" != '' ]; then + + currentPos=$(( $currentPos / 60 )) + echo "restarting from $currentPos min : $CNT : $currentTrack" + POSITION_SET="-s $currentPos" + + { + echo "waiting for player start.." + waiting_for_player_start + + # trick to make still picture visible + + ./dbuscontrol.sh pause + echo "paused" + sleep 10 + ./dbuscontrol.sh pause + sleep 0.1 + ./dbuscontrol.sh pause + + } & + WAIT1_PID=$! + else + waiting_for_press_play + fi + else + waiting_for_press_play + fi +else + CNT=$START_FROM + waiting_for_press_play +fi + +# --------------------- main loop start ----------------------------- + +while [ 1 ]; do + + totalLines=$(cat $PLAYLIST | grep "^[^#;]" | wc -l) + playlistLine=$(cat $PLAYLIST | grep "^[^#;]" | head -$CNT | tail -1) + + echo "playlistLine: $CNT, $playlistLine" + + if echo $playlistLine | grep "^[^#;]" >/dev/null; then + + fileState=$(echo "$playlistLine" | awk '{split($0,a,"\t"); print a[5]}') + + # show splash + + case "$fileState" in + "PLAY") + sudo fbi -T 3 -d /dev/fb0 --once -noverbose splash_loading_pause.png &>/dev/null + ;; + '') + sudo fbi -T 3 -d /dev/fb0 --once -noverbose splash_loading_new.png &>/dev/null + ;; + *) + sudo fbi -T 3 -d /dev/fb0 --once -noverbose splash_loading.png &>/dev/null + ;; + esac + + file=$(echo "$playlistLine" | awk '{split($0,a,"\t"); print a[1]}') + fileComment=$(echo "$playlistLine" | awk '{split($0,a,"\t"); print a[2]}') + fileOptions=$(echo "$playlistLine" | awk '{split($0,a,"\t"); print a[3]}') + + echo "Loading: $CNT/$totalLines : $file" + echo "Commentary: $fileComment" + echo "Additional options: $POSITION_SET $fileOptions" + + echo $file > $SAVE_PATH/currenttrack + + if [ "$PREF_LANG" != "" ]; then + { + echo "prefered language (pattern): $PREF_LANG" + waiting_for_player_start + audioTracks=$( $BABOOSHKA_HOME/dbuscontrol.sh audiolist 2>/dev/null ) + prefAudioTrackNum=$( echo "$audioTracks" | awk -v var=$PREF_LANG 'tolower($0) ~ var {print NR; exit }' ) + + if [ "$prefAudioTrackNum" != "" ]; then + i=1 + while [ "$i" -lt "$prefAudioTrackNum" ] ; do + i=$(( $i + 1 )) + $BABOOSHKA_HOME/dbuscontrol.sh audiop + done + targetTrackName=$(echo "$audioTracks" | head -$prefAudioTrackNum | tail -1 ) + echo "audio track $prefAudioTrackNum : $targetTrackName" + else + echo "probably single audiotrack detected:" + echo "$audioTracks" + fi + } & + WAIT2_PID=$! + fi + + { + waiting_for_player_start + sudo fbi -T 3 -d /dev/fb0 --once -noverbose splash.png &>/dev/null + } & + WAIT3_PID=$! + + # set playlist marker before playing + + if cat "$PLAYLIST" | grep "^[^#;]" | grep "$file" | grep -v -P "\tWATCHED" >/dev/null; then + + sed -i "s|\tPLAY||g" "$PLAYLIST" + newPlaylistLine=$(cat "$PLAYLIST" | grep "^[^#;]" | grep "$file" | awk -F"\t" -v pbState="PLAY" '{print $1"\t"$2"\t"$3"\t"$4"\t"pbState}') + sed -i "s|^$file.*|${newPlaylistLine}|g" "$PLAYLIST" + fi + + # playing + + echo "VIDEOSTARTED" > "$LEDS_CONTROL" + echo 'playing...' + + playerOutput=$(./playmovie.sh -i "$file" -v $VOLUME -a 1 -m "$VIDEOMODE" $POSITION_SET $SUBTITLES_SET -r letterbox $fileOptions) + + # set playlist markers after playing + + if cat "$PLAYLIST" | grep "^[^#;]" | grep "$file" | grep -v -P "\tWATCHED" >/dev/null; then + + playbackPos=$(echo "$playerOutput" | grep "Playback duration" | awk -F: '{print $2}' | xargs) # whether it was stopped and what time + + ct=$(echo $playbackPos | awk -F'/' '{print $1}') + tt=$(echo $playbackPos | awk -F'/' '{print $2}') + + if [ "$ct" -ge "$tt" ]; then watched='WATCHED'; else watched=''; fi + + newPlaylistLine=$(cat "$PLAYLIST" | grep "^[^#;]" | grep "$file" | awk -v pbPos="$playbackPos" -v pbState="$watched" -F"\t" '{print $1"\t"$2"\t"$3"\t"pbPos"\t"pbState}') + sed -i "s|^$file.*|${newPlaylistLine}|g" "$PLAYLIST" + + echo "playlist line updated: $newPlaylistLine" + fi + + # check for unwatched / not completed video and turn RED LED on + + check_video_complete "$PLAYLIST" + + : > $SAVE_PATH/currentpos + POSITION_SET='' + + DBUS_COMMAND=$(cat "$DBUS_CTRL_FILE") + + if [ "$PLAYSINGLE" != "" ] && [ "$DBUS_COMMAND" != "NEXT" ]; then + echo "play single STOP" + echo "STOP" > "$DBUS_CTRL_FILE"; + DBUS_COMMAND="STOP" + CNT=$(( $CNT + 1 )); + fi + + else +# if [ "$DBUS_COMMAND" == "PLAY" ]; then CNT=$(( $CNT + 1 )); fi + DBUS_COMMAND="NEXT" + fi + + # check playlist for finishing + + echo "DBus command: $DBUS_COMMAND" + + totalLines=$(cat $PLAYLIST | grep "^[^#;]" | wc -l) + + if [ "$PLAYLISTONCE" != '' ] && [ "$CNT" -ge "$totalLines" ] && [ "$DBUS_COMMAND" != "PREV" ]; then + echo "play once STOP" + echo "STOP" > "$DBUS_CTRL_FILE" + DBUS_COMMAND="STOP" + CNT=$(( $CNT + 1 )); + fi + + # handle and pass dbus command (original or assigned forcibly) + + echo "DBus command: $DBUS_COMMAND" + + if [ "$DBUS_COMMAND" != "" ]; then + case "$DBUS_COMMAND" in + "NEXT") + CNT=$(( $CNT + 1 )); + ;; + "STOP") + waiting_for_press_play + + # check for possibly new video in playlist + + currentLEDState=$(cat $LEDS_CONTROL) + + if [ "$currentLEDState" == "NEWVIDEO" ]; then + newVideo=$(grep -v -P "\tPLAY|\tWATCHED" "$PLAYLIST" | grep "^[^#;]" | head -1 | awk '{split($0,a,"\t"); print a[1]}') + echo $newVideo > $SAVE_PATH/currenttrack + + CNT=$( cat "$PLAYLIST" | grep "^[^#;]" | grep -Fn "$newVideo" | cut -f1 -d: ) + totalLines=$(cat "$PLAYLIST" | grep "^[^#;]" | wc -l) + echo "New track detected: $CNT, $newVideo" + fi + + ;; + "PREV") + CNT=$(( $CNT - 1 )); + ;; + esac + : > "$DBUS_CTRL_FILE" + else + CNT=$(( $CNT + 1 )) + fi + + # playlist next line counter + + if [ "$CNT" -gt "$totalLines" ]; then CNT=1; fi + if [ "$CNT" -lt "1" ]; then CNT=$totalLines; fi +done + +exit 0 + diff --git a/playmovie.sh b/playmovie.sh new file mode 100755 index 0000000..b879614 --- /dev/null +++ b/playmovie.sh @@ -0,0 +1,338 @@ +#!/bin/bash + +if [ $# -lt 1 ]; then + echo "IM Media Player. Created for Interplaymedium™ project (https://interplaymedium.org)" + echo "Copyright © 2013 Dmitry Shalnov [interplaymedium.org]" + echo "Licensed under the Apache License, Version 2.0" + + echo "Usage: $0 -i [-m