media gallery and comic reader to handle easily huge device and online collections
Go to file
John Doe 512c71dc03 update links 2023-11-14 20:10:54 +01:00
.idea improve collections 2023-10-23 20:34:00 +02:00
app metadata rotation 2023-11-09 21:17:27 +01:00
fastlane/metadata/android/en-US metadata rotation 2023-11-09 21:17:27 +01:00
gradle/wrapper random slideshow 2023-05-01 23:14:39 +02:00
.gitignore filmstrips with libextractor, add diaporama/slideshow 2022-02-05 21:19:09 +01:00
0001-no-eof-mimetype-format.patch improve collections 2023-09-29 23:09:49 +02:00
0001-tor-fdsan-double-close-crash.patch improve collections 2023-10-02 22:03:01 +02:00
LICENSE Add LICENSE 2019-07-18 15:43:18 +00:00 update links 2023-11-14 20:10:54 +01:00
build.gradle metadata rotation 2023-11-09 21:17:27 +01:00 improve collections 2023-10-02 22:03:01 +02:00 improve thumbs 2023-10-29 23:26:39 +01:00 metadata rotation 2023-11-09 21:17:27 +01:00
gplv3-with-text-136x68.png important fixes 2023-03-26 21:51:04 +02:00 random slideshow 2023-05-01 23:14:39 +02:00
gradlew random slideshow 2023-05-01 23:14:39 +02:00
lockedhashes.txt metadata rotation 2023-11-09 21:17:27 +01:00
settings.gradle initial commit. 2019-07-18 15:06:20 +02:00
torbootstrap.txt Update file torbootstrap.txt 2022-12-24 21:48:11 +00:00
torlockedhashes.txt metadata rotation 2023-11-09 21:17:27 +01:00

icon PhotoChiotte GPLv3


Get it on F-Droid (direct download link)

Set up your own secure online media server in 5 minutes. Tutorial below.


  • browse and display media at the same time
  • instant jump to any media even in huge collections (graphical representation of your directory structure)
  • split screen to compare pictures, draw, play videos or minigames, read comics... all at the same time
  • integrated multiple video player (mpv, optional)
  • create collections
  • display and manage your apache/nginx online media server, upload selections directly from app
  • resize, crop & filter pictures and videos (using ffmpeg filters)
  • minigames using your pictures (puzzle, swap tiles, tilt device, ...)
  • draw, on top of pictures, cut/edit/comment them, with stylus support
  • slideshow
  • zapping mode
  • animated wallpaper/lockscreen with your own selection
  • comic reading mode
  • automatic background music player
  • seamlessly browse forums pictures bypassing ads and crap
  • display pictures directly from inside archives
  • root screenshot and screenrecord commands
  • howto and online readme buttons (direct link to codeberg) for issues/suggestions
  • minimal power consumption (no useless redraws)
  • AndroidTV support

how to

  • pinch 2 fingers : zoom picture or thumbnails (depends on position)
  • click left/right of media or bottom left/right corners of the screen : previous/next media
  • click center of media : zoom switch between full size and fit screen
  • 3 fingers or top left corner of the screen : show/hide menu
  • if the menu is shown : graphical representation of the whole gallery on the left, click wherever you want to jump to
  • 4 fingers : show current file name and info
  • 5 fingers : only show the main picture
  • back button : you need to click it 3 times to exit app and free resources
play video
  • 3 fingers : show/hide menu
  • click top of video : zapping mode
  • click center : play/pause
  • click right/left : jump forward/backward in time (time delta depends on menu setting)
  • click bottom : show timebar and current position, click where you want to jump to
  • pinch 2 fingers : zoom video
  • move 2 fingers around : move video around (inside its surface)
androidTV : browse
  • ok : switch between fit picture / default zoom mode
  • menu : currently selected menu item is underlined in yellow, use pad left/right and top/down to navigate
  • back : click 3 times to quit
  • numeric / media keys : control the background music player
  • keys 1/2/3 : zoom in/out/switch mode
  • keys 4/5/6 : music player previous/next/playpause
  • keys 7/8/9 : music player stop/random/linear playback
  • key 0 : navigate to next media
androidTV : play video
  • ok : play/pause video
  • menu : again, navigate with pad
  • pad top : zapping mode
  • pad bottom : show timebar and current position
  • pad left/right : jump backward/forward in time (time delta depends on menu setting)


playing videos smoothly

Depending on your device you will find better to use software or hardware acceleration (menu -> tweaks -> gpu-next hardware copy to ram). Software decoding always works. If the playback isn't smooth try hardware copy to ram (mediacodec-copy) or hw+ (mediacodec). If it still doesn't render properly use hardware direct rendering (mediacodec-embed). This is the default mode on AndroidTV, and you'll benefit from your TV/device's motion interpolation. Subtitles are rendered on an overlay.

picture quality

You can enable dithering to try to improve picture quality in menu -> modify -> dither off -> dither on.

hardware acceleration

Hardware acceleration is enabled by default on non-AndroidTV devices. If browsing media is laggy on your device you can try to switch it off : menu -> tweaks -> browser hw -> browser sw.

in depth : additional details

music player

The music player will autoplay/autostop whenever you quit/launch a video. You can control it with the standard android media action buttons, through the notification, the menu, or with the homescreen widget. On AndroidTV the music player will autostart at boot if enabled when shut down.

menu buttons

Only the more opaque part of the menu text is clickable.


This will remove all thumbnails created from this app in its own cache directory. Note that when accessing online collections, thumbnails and media are directly read from the online server and kept in cache in RAM (thus nothing is copied/stored on the disk, not even the thumbnails since this is the server's role.)

TV mode

For TV AOSP firmwares or for big video collections you may want to force PhotoChiotte to behave as with an androidTV device. menu->tweaks->tv mode on.


online media server

access and browse your own huge collection of media from anywhere in the world, and on all your android devices

Connect your old laptop to your wifi, connect your external hard drive containing your collections of media/movies/photos/comics and install an apache server to be able to access them.

  1. find out your laptop LAN IP
ip address show
  1. install and start apache
sudo apt-get install apache2
sudo systemctl start httpd

Now you are able to access your server from your android device in a browser using e.g.

  1. mount your external hard drive and link it to your apache root folder
sudo mount /dev/sdb1 /mnt/usb
ln -s /mnt/usb /srv/http/media

Now you are able to browse your media collection in PhotoChiotte using

  1. optional but recommended for an expanded view (instead of 3. the dynamic one) : create a folder index
cd /mnt/usb/
find . -type f -printf "%h/\n" | uniq | sort -f | uniq > folderlist.txt

Now open the menu in PhotoChiotte, click online media, and then add online media source. Type in and... done !

upload photos from app

It's the same as you would manage medias on your device : menu->share/copy->copy will upload your selection if the destination path is on your web server. Similarly you can move, delete and create new folders on your server from app. Thumbnails will also automatically be uploaded or deleted alongside.

For this enable webDav in apache : edit /etc/httpd/conf/httpd.conf

  • uncomment Dav modules
LoadModule dav_module modules/
LoadModule dav_fs_module modules/
LoadModule dav_lock_module modules/
  • append
DAVLockDB /srv/http/DAVLock
Alias /media "/srv/http/media/"
<Directory "/srv/http/media/">
  DAV On
  AllowOverride None
  Options Indexes FollowSymLinks
  Require all granted
  • give apache permission to write to your external hard drive
<IfModule unixd_module>
  User http
  Group users
  • here we make it writable by any member of our group users
sudo chown http:users /srv/http
sudo chmod g+w -R /mnt/usb

Finally restart the service sudo systemctl restart httpd.


Optional but recommended : it's a good idea to generate thumbnails on the server side since PhotoChiotte won't store anything on your device. The "apache online" method tries to grab the folder/subfolder/file.ext.thmb thumbnail that is expected to correspond to the folder/subfolder/file.ext file. If this fails it will generate a thumbnail from the big files, which makes it optional but heavier for both the device and the server.

  • build the thumbnail creator (based on GNU libextractor)
sudo apt-get install ffmpeg
gcc -lavcodec -lpostproc -lswresample -lavutil -lavformat -lswscale -lavfilter -lavdevice thumb.cpp -o thumb.o
  • create thumbnails

./thumb.o source file destination thumbnails width height
maximum number of filmstrip pictures (for videos)
maximum percentage of the video

while read f
  if [ ! -f "${f}.thmb" ]
    nice -n 19 ./thumb.o "${f}" "${f}.thmb" 256 256 15 100
done < <(find /mnt/usb/ -type f -size +40k | grep -vP '\.thmb([._]\d+)?$')

Update v1.45 02/11/2023 : full decode if fast seeking methods fail

Update v1.46 09/11/2023 : metadata : handle rotation, grab creation_time

internet access

To access your collections from anywhere in the world install openvpn on your media server.

  • Replace with your server's own public ip address, to be able to access it from the internet.
export PUBLIC_IP_WWW=""
  • Install openvpn.
apt-get install -y openvpn openssl easy-rsa
  • Generate openvpn keys for secure communication with your server.
cd /etc/openvpn/server
mkdir -p sample-ca
touch sample-ca/index.txt
echo "01" > sample-ca/serial
cp /etc/easy-rsa/openssl-easyrsa.cnf openssl.cnf
openvpn --genkey secret ta.key
openssl req -new -newkey rsa:4096 -days 20000 -nodes -x509 -extensions easyrsa_ca -keyout sample-ca/ca.key -out sample-ca/ca.crt -subj "/C=FR/ST=IDF/L=Paris/ openVPN/" -config openssl.cnf
openssl req -new -nodes -config openssl.cnf -extensions server -subj "/C=FR/ST=IDF/ openVPN/CN=VPNserver/" -keyout sample-ca/server.key -out sample-ca/server.csr
openssl ca -batch -config openssl.cnf -extensions server -out sample-ca/server.crt -in sample-ca/server.csr
openssl req -new -nodes -config openssl.cnf -subj "/C=FR/ST=IDF/ openVPN/CN=VPNclient/" -keyout sample-ca/client.key -out sample-ca/client.csr
openssl ca -batch -config openssl.cnf -out sample-ca/client.crt -in sample-ca/client.csr
openssl dhparam -out dh2048.pem 2048
cp -vf sample-ca/server.key sample-ca/server.crt sample-ca/client.key sample-ca/client.crt sample-ca/ca.crt .
  • Create the openvpn client configuration file client.ovpn. You can share it with all your devices. Import it in your openvpn app.
cat >client.ovpn<<EOF
dev tun
proto udp
remote ${PUBLIC_IP_WWW} 443
resolv-retry infinite
remote-cert-tls server
cipher AES-256-GCM
verb 3
auth SHA512
echo "<ca>" >> client.ovpn
cat ca.crt >> client.ovpn
echo "</ca>" >> client.ovpn
echo "key-direction 1" >> client.ovpn
echo "<tls-crypt>" >> client.ovpn
cat ta.key >> client.ovpn
echo "</tls-crypt>" >> client.ovpn
echo "<cert>" >> client.ovpn
cat client.crt >> client.ovpn
echo "</cert>" >> client.ovpn
echo "<key>" >> client.ovpn
cat client.key >> client.ovpn
echo "</key>" >> client.ovpn

ln -s /etc/openvpn/server/client.ovpn /srv/http/client.ovpn
  • Create the server configuration file.
cat >server.conf<<EOF
local ${PUBLIC_IP_WWW}
port 443
proto udp
dev crypt
dev-type tun
ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/server.crt
key /etc/openvpn/server/server.key
dh /etc/openvpn/server/dh2048.pem
topology subnet
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS"
keepalive 20 120
tls-crypt /etc/openvpn/server/ta.key
cipher AES-256-GCM
auth SHA512
status /var/log/openvpn/openvpn-status.log
log /var/log/openvpn/openvpn.log
verb 3
explicit-exit-notify 1
script-security 2
plugin /usr/lib/openvpn/plugins/ login

chown -R openvpn:network /etc/openvpn/server
mkdir /var/log/openvpn
chown openvpn:network /var/log/openvpn
  • Create new users or use your current user credentials. This will be your login/password for the openvpn client app.
useradd -m -p $(echo "crappypassword" | openssl passwd -1 -stdin) "openvpnuser"
  • Start your secure internet media server.
systemctl start openvpn-server@server
  • Open your media server's port 443 on your router to be able to access it from the internet.
  • Install the Free/Libre Open Source openVPN app on your android devices.
  • Import in openVPN and connect to your server with your login/password.

This way the online media source you added before is still valid, so no change is needed in the PhotoChiotte app. Just connect to your openVPN server et voilà !

more flexibility

The live wallpaper and the background music player also work with your online media server. Generate a folderlist.txt for your music and another one for your pictures, you will then be able to create custom collections with whatever source you want. This is the prefered way for homogeneous media collections (music, personal pictures and videos, comics...).

However you can also directly populate PhotoChiotte medias and folders by specifying the address to a .sel collection in the online media menu. All of PhotoChiotte variables are accessible with this more flexible method. This collection.sel consists of a text file with sequential operations on its elements, followed by variable=value lines.

  1. start with an operation (+ add, - remove, / modify) on an element e.g. element=+element_media
  2. continue with wanted variable=value lines until the next element=+element_media operation

An element can be either a collection, an ordner, or a media. See their respective java files for an exhaustive list. All variables above the /** generated **/ comment are exposed.

  1. start with an element_collection element
$ cat > /mnt/usb/testcoll.sel <<EOF

printName=a test collection

address=/dummy/cherry picked !


Its printName will be the one shown in the app when the is loaded.

Ordners always need an address= for identification, be it a dummy one. If we set a printName=cherry for this ordner the app will show cherry instead of /dummy/cherry picked ! for the folder name.

  1. add a picture to this empty /dummy/cherry picked ! container
$ cat >> /mnt/usb/testcoll.sel <<EOF

ordnerAddress=/dummy/cherry picked !


The address= can also be local, but if it needs to be retrieved online (http://.*), you need to set the isOnline=online_apache variable.

If there were a thumbnail it would also be retrieved automatically when needed thanks to the online_apache value. To override this set the addressToGetThumbnail= variable addressToGetThumbnail= (and optionally addressToGetPreviewFullSize= for video previews).

The ordnerAddress= will populate the /dummy/cherry picked ! folder with this picture. If not set the media will be placed in the last element_ordner of its collection (here also /dummy/cherry picked !).

  1. add a video
$ cat >> /mnt/usb/testcoll.sel <<EOF

addressEncode= vidéos/Ne ne doesn't exist.mkv
printName=This video is a broken link.
printDetails=Additionnal text.
printFooter=2 audio 3 subs
ordnerAddress=/dummy/cherry picked !


Important : if you list files from your apache server you will have to do URL encoding (here a valid link would be address='t%20exist.mkv).

You can append Encode to any string variable (here address, but also ordnerAddress, etc...) to ask the app to URL encode your value.

  1. add another ordner
$ cat >> /mnt/usb/testcoll.sel <<EOF

addressEncode=ée 2023/
printName=Randonnée 2023


Whenever the user reaches this folder the app will populate this ordner with the content of /mnt/usb/Randonnée 2023/* through your apache server.

Collections can also load subcollections to avoid loading everything at startup.

  • this collection will load the testcoll.sel above when browsed
$ cat > /mnt/usb/master.sel <<EOF

printName=Parent collection.



Whenever the user reaches this ordner the linked collection will be loaded.

  • or load testcoll.sel only when clicked
$ cat > /mnt/usb/master.sel <<EOF

printName=Parent collection.

address=/dummy/test coll
printName=Click the media underneath to load the testcoll collection.

ordnerAddress=/dummy/test coll
printName=Click to load testcoll.sel.


This is merely triggered by the variable isALinkThatCreatesAnOrdner=true.

Other useful variables :

  • setting the updateDeltaTime=n ordner variable will update its whole content every n seconds
  • setting the byDefaultShowMediaNumber=n ordner variable will show media number n by default. Negative values will start counting from the end (e.g. antepenultimate will be -3).
  • set the playInSequence=true media variable to play videos that are pieces of a single stream in sequence
  • the playStartAtPosition=n media variable adds the menu button : start track at position n seconds
  • the subtitleAddress=subtitleAddress media variable adds the external subtitle subtitleAddress. Repeat for multiple external subs, one variable=value per line, as always.

Notes :

You can append Encode to any string variable (address=http -> adressEncode=http, ordnerAdressEncode=, subtitleAddressEncode=, etc...) to ask the app to URL encode your value.

Any line that is not starting with a known variable= is ignored. Variables are case insensitive. Values are read till the end of the line.

nginx alternative

By default apache enables Options Indexes FollowSymLinks which displays directory listings when you try to access any folder from a browser (e.g. For nginx you might need to enable it though :

autoindex on;
try_files $uri $uri/ =404;
sendfile on;
tcp_nopush on;

Also there are some performance tweaks that may be useful e.g. worker_processes, worker_rlimit_nofile, worker_connections, multi_accept, sendfile_max_chunk, ....

To enable uploads from app comment out the try_files $uri $uri/ =404; line above and append

client_max_body_size 0;
create_full_put_path on;
dav_access  group:rw all:r;
client_body_buffer_size 10M;

Also give nginx permission to write to your hard drive

user http users;

browse forums

browse directly pictures scraped from forums, as a spider

This will display forum pictures as if part of your collection by scraping the forum, bypassing ads and flood, in an expanded view. Any forum can be browsed this way through the PhotoChiotte app.

Here are a few examples :

  • (18+ adult forum) CmFkZHJlc3M9aHR0cDovL3d3dy5wb3JuYmIub3JnL2ZvcnVtCmhvc3Q9aHR0cDovL3d3dy5wb3JuYmIub3JnCjBmb3J1bXM9PGEgaHJlZj0uKFteXCJcJ10rKVwuaHRtbC4gY2xhc3M9LmZvcnVtbGluay4+CjFwYWdpbmF0aW9uPS0wLmh0bWwKMXBhZ2luYXRpb25kZWx0YT01MAoxcGFnaW5hdGlvbnN0YXJ0PTAKMWZvcnVtc3BhZ2VzPTxhIGNsYXNzPS5idG4gYnRuLWRlZmF1bHQuIGhyZWY9LlteXCdcIl0rLShcZCspXC5odG1sCjF0aHJlYWRzK3BhZ2U9PGEgaHJlZj0uKFteXCJcJ10rPykoLShcZCspKT9cLmh0bWxbXj5dKz48aSBjbGFzcz0uaWNvIGktbGFzdC1yZXBseS4+CjJwYWdpbmF0aW9uPS0wLmh0bWwKMnBhZ2luYXRpb25kZWx0YT0xNQoycGFnaW5hdGlvbnN0YXJ0PTAKMmltYWdlcyttaW5pPTxhIGhyZWY9LihodHRwW15cJ1wiXSspLiB0YXJnZXQ9Ll9ibGFuay4gY2xhc3M9LnBvc3RsaW5rLiByZWw9Lm5vZm9sbG93Lj48aW1nIHNyYz0uaHR0cFteXCdcIl0rLiBjbGFzcz0uaW1nLXJlc3BvbnNpdmUuIGFsdD0uc2NyZWVuc2hvdC4KMm1pbmlpbmltYWdlcz1zcmM9LihodHRwW15cIlwnXSspCg==
  • (18+ adult forum) CmFkZHJlc3M9aHR0cHM6Ly92aXBlcmdpcmxzLnRvL2ZvcnVtLnBocApob3N0PWh0dHBzOi8vdmlwZXJnaXJscy50bwowZm9ydW1zPTxoMiBjbGFzcz0uZm9ydW10aXRsZS4qP2hyZWY9Lihmb3J1bXMvW15cIlwnP10rKQoxcGFnaW5hdGlvbj0vcGFnZTAKMXBhZ2luYXRpb25kZWx0YT0xCjFwYWdpbmF0aW9uc3RhcnQ9MQoxZm9ydW1zcGFnZXM9PGEgaHJlZj0uamF2YXNjcmlwdDovLy4gY2xhc3M9LnBvcHVwY3RybC5bXj5dKj5QYWdlIFxkKyBvZiAoXGQrKTwvYT4KMXRocmVhZHMrcGFnZT0gaHJlZj0uKHRocmVhZHMvW15cJ1wiLz9dKykoL3BhZ2UoXGQrKSk/CjJwYWdpbmF0aW9uPS9wYWdlMAoycGFnaW5hdGlvbmRlbHRhPTEKMnBhZ2luYXRpb25zdGFydD0xCjJpbWFnZXMrbWluaT08YSBbXj5dKmhyZWY9LihodHRwW15cIlwnXSspW14+XSs+W14+PF0qPGltZyBbXj5dKnNyYz0uaHR0cFteXCJcJ10qCjJtaW5paW5pbWFnZXM9c3JjPS4oaHR0cFteXCJcJ10rKQo=

These are just base64 encoded strings.

  1. long press the base64 string and copy it
  2. open the PhotoChiotte menu (3 fingers or top left corner)
  3. click online media
  4. click add online media source
  5. long press the text input field and paste your base64 string

Done !

build PhotoChiotte

git clone
cd PhotoChiotte

The first time you need to build mpv and tor libraries. Dependencies are pretty basic, just have a look at F-Droid's build metadata.

curl -s | tail -n 23
  - apt-get install -y autoconf automake libtool make nasm pkg-config meson ninja-build autopoint cmake

Specify the path to your Android NDK.

export ANDROID_NDK="/path/to/android/sdk/ndk/26.1.10909125"

Only move if you want to build the latest versions of the libraries :

mv -vi lockedhashes.txt lastworkingmpvhashes.txt
mv -vi torlockedhashes.txt lastworkingtorhashes.txt

Build the libraries.

bash all

Uncomment //ndkVersion in app/build.gradle.

sed -i -e 's/\/\/ *ndkVersion .*/ndkVersion "26.1.10909125"/' app/build.gradle

Build the apk either by importing the project in AndroidStudio, or headless with

export ANDROID_HOME="/path/to/android/sdk"
./gradlew build assembleDebug

Android 7+ : NDK r26b ABI 24

Android 5+ : NDK r25c ABI 21