├── log └── .gitignore ├── .gitattributes ├── themes ├── korrigan │ ├── .gitignore │ ├── preview.png │ ├── lib │ │ └── Lutim │ │ │ └── I18N.pm │ ├── Readme.md │ ├── Makefile │ ├── public │ │ └── css │ │ │ └── korrigan.css │ └── templates │ │ └── layouts │ │ └── default.html.ep └── default │ ├── public │ ├── img │ │ ├── Lutim.png │ │ ├── Lutim.xcf │ │ ├── favicon.png │ │ ├── lutim32.png │ │ ├── lutim60.png │ │ ├── lutim76.png │ │ ├── lutim90.png │ │ ├── rocket.png │ │ ├── Lutim_flou.xcf │ │ ├── lutim120.png │ │ ├── lutim128.png │ │ ├── lutim152.png │ │ ├── lutim196.png │ │ ├── lutim256.png │ │ ├── Lutim_small.png │ │ ├── Lutim_sticker.png │ │ ├── Lutim_sticker.xcf │ │ ├── tipeee-tip-btn.png │ │ └── liberapay.svg │ ├── font │ │ ├── fontello.eot │ │ ├── fontello.ttf │ │ ├── fontello.woff │ │ ├── markdown.eot │ │ ├── markdown.ttf │ │ ├── markdown.woff │ │ ├── fontello.woff2 │ │ ├── hennypenny.ttf │ │ ├── hennypenny.woff2 │ │ ├── LICENSE.txt │ │ └── markdown.svg │ ├── gallery │ │ ├── images │ │ │ ├── loader.gif │ │ │ ├── cover-grid.png │ │ │ ├── icon-link32.png │ │ │ ├── icon-play32.png │ │ │ ├── icon-zoom32.png │ │ │ ├── not_loaded.png │ │ │ ├── transparent.png │ │ │ ├── button-close.png │ │ │ ├── loader-black1.gif │ │ │ ├── loader-black2.gif │ │ │ ├── loader-black3.gif │ │ │ ├── loader-black4.gif │ │ │ ├── loader-black5.gif │ │ │ ├── loader-black6.gif │ │ │ ├── loader-black7.gif │ │ │ ├── loader-white1.gif │ │ │ ├── loader-white2.gif │ │ │ ├── loader-white3.gif │ │ │ ├── loader-white4.gif │ │ │ ├── loader-white5.gif │ │ │ ├── loader-white6.gif │ │ │ ├── loader-white7.gif │ │ │ ├── loader_bright.gif │ │ │ ├── lightbox-arrow-left.png │ │ │ ├── lightbox-icon-close.png │ │ │ ├── loader_skype_trans.gif │ │ │ ├── play-button-round.png │ │ │ ├── play-button-square.png │ │ │ ├── lightbox-arrow-right.png │ │ │ ├── lightbox-icon-close-compact.png │ │ │ └── lightbox-icon-close-compact2.png │ │ ├── skins │ │ │ ├── default │ │ │ │ ├── arrow_grid_up.png │ │ │ │ ├── icon_zoom_back.png │ │ │ │ ├── icon_zoom_plus.png │ │ │ │ ├── slider_bullets.png │ │ │ │ ├── arrow_grid_down.png │ │ │ │ ├── arrows_strip_down.png │ │ │ │ ├── arrows_strip_left.png │ │ │ │ ├── arrows_strip_up.png │ │ │ │ ├── button_fullscreen.png │ │ │ │ ├── button_playpause.png │ │ │ │ ├── grid_arrow_left.png │ │ │ │ ├── grid_arrow_right.png │ │ │ │ ├── icon_zoom_minus.png │ │ │ │ ├── slider_arrow_left.png │ │ │ │ ├── tile_bullets_blue.png │ │ │ │ ├── tile_bullets_gray.png │ │ │ │ ├── tile_bullets_red.png │ │ │ │ ├── tile_button_left.png │ │ │ │ ├── tile_button_right.png │ │ │ │ ├── arrows_strip_right.png │ │ │ │ ├── slider_arrow_right.png │ │ │ │ ├── tile_bullets_brown.png │ │ │ │ ├── tile_bullets_green.png │ │ │ │ ├── grid_handle_black_left.png │ │ │ │ ├── grid_handle_black_top.png │ │ │ │ ├── tile_button_play_pause.png │ │ │ │ ├── grid_handle_black_bottom.png │ │ │ │ └── grid_handle_black_right.png │ │ │ └── alexis │ │ │ │ └── images │ │ │ │ ├── grid_arrow_up.png │ │ │ │ ├── button_playpause.png │ │ │ │ ├── button_zoom_back.png │ │ │ │ ├── button_zoom_plus.png │ │ │ │ ├── grid_arrow_down.png │ │ │ │ ├── grid_arrow_left.png │ │ │ │ ├── grid_arrow_right.png │ │ │ │ ├── grid_handle_down.png │ │ │ │ ├── grid_handle_left.png │ │ │ │ ├── grid_handle_up.png │ │ │ │ ├── slider_bullets.png │ │ │ │ ├── arrows_strip_left.png │ │ │ │ ├── arrows_strip_right.png │ │ │ │ ├── button_fullscreen.png │ │ │ │ ├── button_zoom_minus.png │ │ │ │ ├── grid_handle_right.png │ │ │ │ ├── slider_arrow_left.png │ │ │ │ ├── slider_arrow_right.png │ │ │ │ ├── grid_arrow_left_hortype.png │ │ │ │ └── grid_arrow_right_hortype.png │ │ └── themes │ │ │ ├── video │ │ │ ├── images │ │ │ │ ├── arrow_left.png │ │ │ │ └── arrow_right.png │ │ │ ├── skin-right-thumb.css │ │ │ ├── skin-right-title-only.css │ │ │ └── skin-right-no-thumb.css │ │ │ ├── default │ │ │ ├── images │ │ │ │ ├── arrow_down_up.png │ │ │ │ ├── button_playpause.png │ │ │ │ ├── arrows_strip_left.png │ │ │ │ ├── arrows_strip_right.png │ │ │ │ ├── button_fullscreen.png │ │ │ │ ├── button_fullscreen_single.png │ │ │ │ └── button_playpause_single.png │ │ │ └── ug-theme-default.css │ │ │ └── slider │ │ │ └── ug-theme-slider.js │ ├── css │ │ ├── default-skin │ │ │ ├── preloader.gif │ │ │ ├── default-skin.png │ │ │ └── default-skin.svg │ │ ├── hennypenny.css │ │ ├── morris-0.5.1.min.css │ │ ├── fontello-codes.css │ │ ├── markdown.css │ │ ├── toastify.css │ │ ├── uploader.css │ │ ├── fontello-ie7-codes.css │ │ ├── fontello-ie7.css │ │ ├── animation.css │ │ ├── fontello.css │ │ ├── not_stats.min.css │ │ ├── lutim.css │ │ └── photoswipe.css │ └── js │ │ ├── FileSaver.min.js │ │ ├── raphael.path.methods.js │ │ ├── stats.js │ │ ├── dmuploader.min.js │ │ └── lutim.js │ ├── templates │ ├── partial │ │ ├── manifest.js.ep │ │ ├── for_my_delay.html.ep │ │ └── navbar.html.ep │ ├── logout.html.ep │ ├── data.html.ep.template │ ├── raw.html.ep.template │ ├── login.html.ep │ ├── stats.html.ep │ ├── share.html.ep │ ├── zip.html.ep │ ├── manifest.webapp.ep │ ├── gallery.html.ep │ ├── layouts │ │ └── default.html.ep │ └── about.html.ep │ └── lib │ └── Lutim │ └── I18N.pm ├── .weblate ├── .dockerignore ├── CONTRIBUTING.md ├── t └── create-pg-testdb.sql ├── .provision ├── ansible-role-lutim │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ ├── main.yml │ │ ├── gitclone.yaml │ │ ├── dependencies.yaml │ │ ├── cronjob.yaml │ │ └── apprun.yaml │ ├── files │ │ └── cronjob │ ├── vars │ │ └── main.yml │ ├── templates │ │ └── app.conf │ └── README.md ├── terraform-aws-lutim │ ├── output.tf │ ├── provider.tf │ ├── vars.tf │ ├── lutim_startup.sh │ ├── main.tf │ └── README.md └── README.md ├── utilities ├── lutim.default ├── lutim-minion@.service ├── lutim.service ├── lutim_upstart.conf ├── migrations │ ├── sqlite.sql │ └── postgresql.sql ├── read_conf.pl ├── fontello-config.json └── Shutter.pm ├── script ├── lutim └── application ├── .gitignore ├── docker-compose.dev.yml ├── lib ├── Lutim │ ├── Command │ │ ├── cron.pm │ │ ├── cron │ │ │ ├── cleanbdd.pm │ │ │ ├── cleanfiles.pm │ │ │ └── watch.pm │ │ └── theme.pm │ ├── Plugin │ │ ├── Lang.pm │ │ └── Headers.pm │ ├── DefaultConfig.pm │ └── Controller │ │ └── Authent.pm └── Mounter.pm ├── docker-compose.yml ├── docker-stack.yml ├── AUTHORS.md ├── docker └── entrypoint.sh ├── Dockerfile ├── cpanfile ├── Makefile ├── README.md └── .gitlab-ci.yml /log/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | zanata.xml merge=ours 2 | -------------------------------------------------------------------------------- /themes/korrigan/.gitignore: -------------------------------------------------------------------------------- 1 | public/packed/ 2 | templates/data.html.ep -------------------------------------------------------------------------------- /.weblate: -------------------------------------------------------------------------------- 1 | [weblate] 2 | url = https://weblate.framasoft.org/api/ 3 | translation = lutim/development 4 | -------------------------------------------------------------------------------- /themes/korrigan/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/korrigan/preview.png -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .ash_history 2 | .git 3 | .cpan 4 | .cpanm 5 | /files/ 6 | /local/ 7 | /lutim.conf 8 | /lutim.db -------------------------------------------------------------------------------- /themes/default/public/img/Lutim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/Lutim.png -------------------------------------------------------------------------------- /themes/default/public/img/Lutim.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/Lutim.xcf -------------------------------------------------------------------------------- /themes/default/public/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/favicon.png -------------------------------------------------------------------------------- /themes/default/public/img/lutim32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/lutim32.png -------------------------------------------------------------------------------- /themes/default/public/img/lutim60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/lutim60.png -------------------------------------------------------------------------------- /themes/default/public/img/lutim76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/lutim76.png -------------------------------------------------------------------------------- /themes/default/public/img/lutim90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/lutim90.png -------------------------------------------------------------------------------- /themes/default/public/img/rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/rocket.png -------------------------------------------------------------------------------- /themes/default/public/font/fontello.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/font/fontello.eot -------------------------------------------------------------------------------- /themes/default/public/font/fontello.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/font/fontello.ttf -------------------------------------------------------------------------------- /themes/default/public/font/fontello.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/font/fontello.woff -------------------------------------------------------------------------------- /themes/default/public/font/markdown.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/font/markdown.eot -------------------------------------------------------------------------------- /themes/default/public/font/markdown.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/font/markdown.ttf -------------------------------------------------------------------------------- /themes/default/public/font/markdown.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/font/markdown.woff -------------------------------------------------------------------------------- /themes/default/public/img/Lutim_flou.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/Lutim_flou.xcf -------------------------------------------------------------------------------- /themes/default/public/img/lutim120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/lutim120.png -------------------------------------------------------------------------------- /themes/default/public/img/lutim128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/lutim128.png -------------------------------------------------------------------------------- /themes/default/public/img/lutim152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/lutim152.png -------------------------------------------------------------------------------- /themes/default/public/img/lutim196.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/lutim196.png -------------------------------------------------------------------------------- /themes/default/public/img/lutim256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/lutim256.png -------------------------------------------------------------------------------- /themes/default/public/font/fontello.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/font/fontello.woff2 -------------------------------------------------------------------------------- /themes/default/public/font/hennypenny.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/font/hennypenny.ttf -------------------------------------------------------------------------------- /themes/default/public/img/Lutim_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/Lutim_small.png -------------------------------------------------------------------------------- /themes/default/public/font/hennypenny.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/font/hennypenny.woff2 -------------------------------------------------------------------------------- /themes/default/public/img/Lutim_sticker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/Lutim_sticker.png -------------------------------------------------------------------------------- /themes/default/public/img/Lutim_sticker.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/Lutim_sticker.xcf -------------------------------------------------------------------------------- /themes/default/public/img/tipeee-tip-btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/img/tipeee-tip-btn.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader.gif -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | See how to contribute on the [wiki](https://framagit.org/fiat-tux/hat-softwares/lutim/-/wikis/contribute). 4 | -------------------------------------------------------------------------------- /themes/default/public/css/default-skin/preloader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/css/default-skin/preloader.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/cover-grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/cover-grid.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/icon-link32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/icon-link32.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/icon-play32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/icon-play32.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/icon-zoom32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/icon-zoom32.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/not_loaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/not_loaded.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/transparent.png -------------------------------------------------------------------------------- /themes/default/public/css/default-skin/default-skin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/css/default-skin/default-skin.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/button-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/button-close.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-black1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-black1.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-black2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-black2.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-black3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-black3.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-black4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-black4.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-black5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-black5.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-black6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-black6.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-black7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-black7.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-white1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-white1.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-white2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-white2.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-white3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-white3.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-white4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-white4.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-white5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-white5.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-white6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-white6.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader-white7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader-white7.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader_bright.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader_bright.gif -------------------------------------------------------------------------------- /t/create-pg-testdb.sql: -------------------------------------------------------------------------------- 1 | CREATE USER lutim WITH PASSWORD 'lutim'; 2 | CREATE DATABASE lutimtest OWNER lutim; 3 | CREATE DATABASE lutim_miniontest OWNER lutim; 4 | 5 | -------------------------------------------------------------------------------- /themes/default/public/gallery/images/lightbox-arrow-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/lightbox-arrow-left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/lightbox-icon-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/lightbox-icon-close.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/loader_skype_trans.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/loader_skype_trans.gif -------------------------------------------------------------------------------- /themes/default/public/gallery/images/play-button-round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/play-button-round.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/play-button-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/play-button-square.png -------------------------------------------------------------------------------- /.provision/ansible-role-lutim/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for ansible-role-lutim 3 | 4 | - name: restart nginx 5 | service: name=nginx state=restarted 6 | -------------------------------------------------------------------------------- /themes/default/public/gallery/images/lightbox-arrow-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/lightbox-arrow-right.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/arrow_grid_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/arrow_grid_up.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/icon_zoom_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/icon_zoom_back.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/icon_zoom_plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/icon_zoom_plus.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/slider_bullets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/slider_bullets.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/arrow_grid_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/arrow_grid_down.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/arrows_strip_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/arrows_strip_down.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/arrows_strip_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/arrows_strip_left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/arrows_strip_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/arrows_strip_up.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/button_fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/button_fullscreen.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/button_playpause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/button_playpause.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/grid_arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/grid_arrow_left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/grid_arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/grid_arrow_right.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/icon_zoom_minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/icon_zoom_minus.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/slider_arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/slider_arrow_left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/tile_bullets_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/tile_bullets_blue.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/tile_bullets_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/tile_bullets_gray.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/tile_bullets_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/tile_bullets_red.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/tile_button_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/tile_button_left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/tile_button_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/tile_button_right.png -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/video/images/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/themes/video/images/arrow_left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/video/images/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/themes/video/images/arrow_right.png -------------------------------------------------------------------------------- /themes/default/templates/partial/manifest.js.ep: -------------------------------------------------------------------------------- 1 | % # vim:set sw=4 ts=4 sts=4 ft=javascript expandtab: 2 | var manifestUrl = '<%== url_for('manifest.webapp')->to_abs() %>'; 3 | -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/grid_arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/grid_arrow_up.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/arrows_strip_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/arrows_strip_right.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/slider_arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/slider_arrow_right.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/tile_bullets_brown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/tile_bullets_brown.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/tile_bullets_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/tile_bullets_green.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/lightbox-icon-close-compact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/lightbox-icon-close-compact.png -------------------------------------------------------------------------------- /themes/default/public/gallery/images/lightbox-icon-close-compact2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/images/lightbox-icon-close-compact2.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/button_playpause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/button_playpause.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/button_zoom_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/button_zoom_back.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/button_zoom_plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/button_zoom_plus.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/grid_arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/grid_arrow_down.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/grid_arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/grid_arrow_left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/grid_arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/grid_arrow_right.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/grid_handle_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/grid_handle_down.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/grid_handle_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/grid_handle_left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/grid_handle_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/grid_handle_up.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/slider_bullets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/slider_bullets.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/grid_handle_black_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/grid_handle_black_left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/grid_handle_black_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/grid_handle_black_top.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/tile_button_play_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/tile_button_play_pause.png -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/default/images/arrow_down_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/themes/default/images/arrow_down_up.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/arrows_strip_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/arrows_strip_left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/arrows_strip_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/arrows_strip_right.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/button_fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/button_fullscreen.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/button_zoom_minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/button_zoom_minus.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/grid_handle_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/grid_handle_right.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/slider_arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/slider_arrow_left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/slider_arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/slider_arrow_right.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/grid_handle_black_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/grid_handle_black_bottom.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/default/grid_handle_black_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/default/grid_handle_black_right.png -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/default/images/button_playpause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/themes/default/images/button_playpause.png -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/default/images/arrows_strip_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/themes/default/images/arrows_strip_left.png -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/default/images/arrows_strip_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/themes/default/images/arrows_strip_right.png -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/default/images/button_fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/themes/default/images/button_fullscreen.png -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/grid_arrow_left_hortype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/grid_arrow_left_hortype.png -------------------------------------------------------------------------------- /utilities/lutim.default: -------------------------------------------------------------------------------- 1 | # LDIR is the path where you installed Lutim 2 | # It has to end with a final / 3 | LDIR=/var/www/lutim/ 4 | 5 | # USER is the user who will launch Lutim 6 | USER=www-data 7 | -------------------------------------------------------------------------------- /themes/default/public/gallery/skins/alexis/images/grid_arrow_right_hortype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/skins/alexis/images/grid_arrow_right_hortype.png -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/default/images/button_fullscreen_single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/themes/default/images/button_fullscreen_single.png -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/default/images/button_playpause_single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldidry/lutim/HEAD/themes/default/public/gallery/themes/default/images/button_playpause_single.png -------------------------------------------------------------------------------- /.provision/ansible-role-lutim/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for ansible-role-lutim 3 | 4 | - include: dependencies.yaml 5 | - include: gitclone.yaml 6 | - include: apprun.yaml 7 | - include: cronjob.yaml -------------------------------------------------------------------------------- /.provision/terraform-aws-lutim/output.tf: -------------------------------------------------------------------------------- 1 | output "public_ip" { 2 | value = "${aws_instance.ec2_instance.public_ip}" 3 | } 4 | 5 | output "App_running_at" { 6 | value = "http://${aws_instance.ec2_instance.public_ip}:8080" 7 | } 8 | -------------------------------------------------------------------------------- /.provision/ansible-role-lutim/files/cronjob: -------------------------------------------------------------------------------- 1 | #Path of the script 2 | PATH=/var/www/lutim 3 | 4 | carton exec script/lutim cron cleanbdd --mode production 5 | carton exec script/lutim cron cleanfiles --mode production 6 | carton exec script/lutim cron watch --mode production 7 | -------------------------------------------------------------------------------- /.provision/ansible-role-lutim/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for ansible-role-lutim 3 | 4 | lutim_owner: "www-data" 5 | 6 | lutim_group: "www-data" 7 | 8 | app_dir: "/var/www/lutim" 9 | 10 | _contact: "" 11 | 12 | _secrets: "" 13 | 14 | _project_version: "" 15 | 16 | _servername: "" -------------------------------------------------------------------------------- /script/lutim: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use FindBin; 7 | BEGIN { unshift @INC, "$FindBin::Bin/../lib" } 8 | 9 | # Start command line interface for application 10 | require Mojolicious::Commands; 11 | Mojolicious::Commands->start_app('Mounter'); 12 | -------------------------------------------------------------------------------- /themes/default/templates/logout.html.ep: -------------------------------------------------------------------------------- 1 | % # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab: 2 | % title 'Lutim logout'; 3 |

<%= l('You have been successfully logged out.') %>

4 |

5 | <%= l('Signin') %> 6 |

start_app('Lutim'); 12 | -------------------------------------------------------------------------------- /themes/default/lib/Lutim/I18N.pm: -------------------------------------------------------------------------------- 1 | package Lutim::I18N; 2 | 3 | use base 'Locale::Maketext'; 4 | use File::Basename qw/dirname/; 5 | use Locale::Maketext::Lexicon { 6 | _auto => 1, 7 | _decode => 1, 8 | _style => 'gettext', 9 | '*' => [Gettext => dirname(__FILE__) . '/I18N/*.po'] 10 | }; 11 | 12 | 1; 13 | -------------------------------------------------------------------------------- /.provision/terraform-aws-lutim/provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 3.0" 6 | } 7 | } 8 | } 9 | 10 | provider "aws" { 11 | access_key = "${var.aws_access_key}" 12 | secret_key = "${var.aws_secret_key}" 13 | region = "${var.aws_region}" 14 | } -------------------------------------------------------------------------------- /themes/default/templates/data.html.ep.template: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | -------------------------------------------------------------------------------- /.provision/README.md: -------------------------------------------------------------------------------- 1 | ## ansible-role-lutim 2 | 3 | An ansible role deploy the application on host machine(Ubuntu 20.04) 4 | 5 | ## terraform-aws-lutim 6 | 7 | A terraform plan creates necessary AWS infrastructure and deploy the lutim. This terraform plan uses the `lutim_startup.sh` script to deploy lufi on AWS and also uses above ansible role `ansible-role-lutim` to configure the application on AWS. -------------------------------------------------------------------------------- /themes/default/templates/raw.html.ep.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
<%= $raw[0] %><%= $raw[1] %><%= $raw[2] %><%= $raw[3] %>
15 | -------------------------------------------------------------------------------- /themes/default/public/css/hennypenny.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Henny_Penny'; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: local('Henny Penny'), local('HennyPenny-Regular'), url(../font/hennypenny.woff2) format('woff2'); 6 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 7 | } 8 | -------------------------------------------------------------------------------- /utilities/lutim-minion@.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Image hosting and sharing service job queue 3 | Documentation=https://framagit.org/fiat-tux/hat-softwares/lutim 4 | After=lutim.service 5 | 6 | [Service] 7 | Type=simple 8 | User=www-data 9 | WorkingDirectory=/var/www/lutim/ 10 | ExecStart=/usr/local/bin/carton exec script/application minion worker -m production 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /themes/default/public/css/morris-0.5.1.min.css: -------------------------------------------------------------------------------- 1 | .morris-hover{position:absolute;z-index:1000}.morris-hover.morris-default-style{border-radius:10px;padding:6px;color:#666;background:rgba(255,255,255,0.8);border:solid 2px rgba(230,230,230,0.8);font-family:sans-serif;font-size:12px;text-align:center}.morris-hover.morris-default-style .morris-hover-row-label{font-weight:bold;margin:0.25em 0} 2 | .morris-hover.morris-default-style .morris-hover-point{white-space:nowrap;margin:0.1em 0} 3 | -------------------------------------------------------------------------------- /.provision/ansible-role-lutim/tasks/gitclone.yaml: -------------------------------------------------------------------------------- 1 | #gitclone 2 | --- 3 | 4 | - name: clone the repository 5 | ansible.builtin.git: 6 | repo: 'https://framagit.org/fiat-tux/hat-softwares/lutim.git' 7 | dest: "{{ app_dir }}" 8 | clone: yes 9 | update: yes 10 | version: "{{ project_version }}" 11 | 12 | - name: Change the owner 13 | ansible.builtin.file: 14 | path: "{{ app_dir }}" 15 | owner: "{{ lutim_owner }}" 16 | group: "{{ lutim_group }}" 17 | state: directory 18 | recurse: yes -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | lutim.conf 3 | *.db 4 | *.db-shm 5 | *.db-wal 6 | script/hypnotoad.pid 7 | local/* 8 | files/* 9 | stop-upload 10 | tap.xml 11 | themes/* 12 | !themes/default 13 | !themes/default/* 14 | themes/default/templates/data.html.ep 15 | themes/default/templates/raw.html.ep 16 | themes/default/templates/stats.json.ep 17 | themes/default/templates/partial/raw.js.ep 18 | !themes/korrigan 19 | !themes/korrigan/* 20 | tmp/* 21 | .zanata-cache/* 22 | cover_db/* 23 | *.passwd 24 | .ash_history 25 | .vscode/ 26 | .DS_Store 27 | .cpanm/ 28 | -------------------------------------------------------------------------------- /themes/korrigan/lib/Lutim/I18N.pm: -------------------------------------------------------------------------------- 1 | # vim:set sw=4 ts=4 sts=4 ft=perl expandtab: 2 | package Lutim::I18N; 3 | 4 | use base 'Locale::Maketext'; 5 | use File::Basename qw/dirname/; 6 | use Locale::Maketext::Lexicon { 7 | _auto => 1, 8 | _decode => 1, 9 | _style => 'gettext', 10 | '*' => [ 11 | Gettext => dirname(__FILE__) . '/I18N/*.po', 12 | Gettext => $app_dir . 'themes/default/lib/Lutim/I18N/*.po', 13 | ] 14 | }; 15 | 16 | use vars qw($app_dir); 17 | BEGIN { 18 | use Cwd; 19 | my $app_dir = getcwd; 20 | } 21 | 22 | 1; 23 | -------------------------------------------------------------------------------- /docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | 3 | services: 4 | app_dev: 5 | build: . 6 | ports: 7 | - 8080:8080 8 | volumes: 9 | - .:/home/lutim 10 | command: dev 11 | postgres_dev: 12 | image: postgres:11.2-alpine 13 | environment: 14 | POSTGRES_PASSWORD: password 15 | POSTGRES_USER: lutim 16 | POSTGRES_DB: lutim 17 | memcached: 18 | image: memcached:1.5-alpine 19 | adminer: 20 | image: dehy/adminer 21 | ports: 22 | - 8081:80 -------------------------------------------------------------------------------- /.provision/ansible-role-lutim/tasks/dependencies.yaml: -------------------------------------------------------------------------------- 1 | # dependencies.yaml 2 | --- 3 | - name: Lutim | Update apt cache 4 | ansible.builtin.apt: update_cache=yes 5 | changed_when: no 6 | - name: Install Dependencies 7 | ansible.builtin.apt: 8 | name: 9 | - nginx 10 | - carton 11 | - build-essential 12 | - libssl-dev 13 | - libpq-dev 14 | - libio-socket-ssl-perl 15 | - zlib1g-dev 16 | - libmojo-sqlite-perl 17 | - shared-mime-info 18 | - perlmagick 19 | state: present 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /themes/korrigan/Readme.md: -------------------------------------------------------------------------------- 1 | I know there is a lot to work on but this fits my needs for now and don't have much time to rework the theme from beginning. 2 | 3 | Feel free to open a merge request for improvements. 4 | 5 | ![preview of the theme](./preview.png) 6 | 7 | # Credits: 8 | 9 | * Triskel image comes from https://upload.wikimedia.org/wikipedia/commons/0/07/Triskele-Symbol-spiral-five-thirds-turns.svg 10 | 11 | # License: 12 | 13 | [MIT](https://opensource.org/licenses/MIT) 14 | 15 | # Author: 16 | 17 | [nicofrand](https://nicofrand.eu) ([Twitter](https://twitter.com/@nicofrand), [Mastodon](https://mastodon.social/@nicofrand)) 18 | -------------------------------------------------------------------------------- /utilities/lutim.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Image hosting and sharing service 3 | Documentation=https://framagit.org/fiat-tux/hat-softwares/lutim 4 | Requires=network.target 5 | After=network.target 6 | #Requires=postgresql.service 7 | #After=postgresql.service 8 | 9 | [Service] 10 | Type=forking 11 | User=www-data 12 | RemainAfterExit=yes 13 | WorkingDirectory=/var/www/lutim/ 14 | PIDFile=/var/www/lutim/script/hypnotoad.pid 15 | ExecStart=/usr/local/bin/carton exec hypnotoad script/lutim 16 | ExecStop=/usr/local/bin/carton exec hypnotoad -s script/lutim 17 | ExecReload=/usr/local/bin/carton exec hypnotoad script/lutim 18 | 19 | [Install] 20 | WantedBy=multi-user.target 21 | -------------------------------------------------------------------------------- /lib/Lutim/Command/cron.pm: -------------------------------------------------------------------------------- 1 | # vim:set sw=4 ts=4 sts=4 ft=perl expandtab: 2 | package Lutim::Command::cron; 3 | use Mojo::Base 'Mojolicious::Commands'; 4 | 5 | has description => 'Execute tasks.'; 6 | has hint => < sub { shift->extract_usage . "\nCron tasks:\n" }; 11 | has namespaces => sub { ['Lutim::Command::cron'] }; 12 | 13 | sub help { shift->run(@_) } 14 | 15 | 1; 16 | 17 | =encoding utf8 18 | 19 | =head1 NAME 20 | 21 | Lutim::Command::cron - Cron commands 22 | 23 | =head1 SYNOPSIS 24 | 25 | Usage: script/lutim cron TASK [OPTIONS] 26 | 27 | =cut 28 | -------------------------------------------------------------------------------- /.provision/ansible-role-lutim/tasks/cronjob.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Copy the cronjob file 3 | ansible.builtin.copy: 4 | src: ../files/cronjob 5 | dest: /etc/cron.d/lutim 6 | owner: www-data 7 | group: www-data 8 | 9 | - name: "example cronjob" 10 | ansible.builtin.cron: 11 | name: "cronjob" 12 | state: present 13 | user: www-data 14 | minute: "0" 15 | hour: "0" 16 | day: "*" 17 | month: "*" 18 | weekday: "*" 19 | job: | 20 | carton exec script/lutim cron cleanbdd --mode production; carton exec script/lutim cron cleanfiles --mode production; carton exec script/lutim cron watch --mode production 21 | -------------------------------------------------------------------------------- /utilities/lutim_upstart.conf: -------------------------------------------------------------------------------- 1 | # -*- upstart -*- 2 | description "lutim" 3 | author "Thor77 5 | % } 6 |
7 |
8 | 9 | 10 |
11 |
12 | 13 | 14 |
15 | 18 |
19 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | 3 | services: 4 | app: 5 | build: . 6 | ports: 7 | - 8080:8080 8 | volumes: 9 | - ./lutim.conf:/home/lutim/lutim.conf:ro 10 | db: 11 | image: postgres:11.2-alpine 12 | environment: 13 | POSTGRES_PASSWORD: password 14 | POSTGRES_USER: lutim 15 | POSTGRES_DB: lutim 16 | cache: 17 | image: memcached:1.5-alpine 18 | minion: 19 | build: . 20 | command: minion 21 | volumes: 22 | - ./lutim.conf:/home/lutim/lutim.conf:ro 23 | minion_db: 24 | image: postgres:11.2-alpine 25 | environment: 26 | POSTGRES_PASSWORD: password 27 | POSTGRES_USER: lutim_minion 28 | POSTGRES_DB: lutim_minion -------------------------------------------------------------------------------- /.provision/ansible-role-lutim/tasks/apprun.yaml: -------------------------------------------------------------------------------- 1 | #apprun.yml 2 | --- 3 | - name: This command will install the postgress module 4 | ansible.builtin.shell: 5 | cmd: carton install --deployment --without=test --without=sqlite 6 | chdir: "{{ app_dir }}" 7 | 8 | - name: Upload application config file 9 | ansible.builtin.template: 10 | src: ../templates/lutim.conf.j2 11 | dest: "{{ app_dir }}/lutim.conf" 12 | 13 | - name: App executes 14 | ansible.builtin.shell: 15 | cmd: carton exec hypnotoad script/lutim 16 | chdir: "{{ app_dir }}" 17 | 18 | - name: Nginx configuration file add 19 | ansible.builtin.template: 20 | src: ../templates/app.conf 21 | dest: /etc/nginx/conf.d/ 22 | mode: '0644' 23 | notify: restart nginx -------------------------------------------------------------------------------- /themes/default/templates/stats.html.ep: -------------------------------------------------------------------------------- 1 | % # vim:set sts=4 sw=4 ts=4 ft=html.epl expandtab: 2 |

<%= l('%1 sent images on this instance from beginning.', $total) %>

3 |
4 | 5 | %= include 'data' 6 |

<%= l('Uploaded files by days') %>

7 |
8 |
9 | 10 |

<%= l('Evolution of total files') %>

11 |
12 |

<%= l('The graph\'s datas are not updated in real-time.') %>

13 |
14 | 15 |

<%= l('Delay repartition chart for enabled images') %>

16 |
17 | 18 |

<%= l('Delay repartition chart for disabled images') %>

19 |
20 |
21 | 22 |

<%= l('Raw stats') %>

23 | %= include 'raw' 24 | 25 | <%= link_to url_for('/') => ( class => "btn btn-primary btn-lg" ) => begin %><%= l('Back to homepage') %><% end%> 26 | -------------------------------------------------------------------------------- /utilities/migrations/sqlite.sql: -------------------------------------------------------------------------------- 1 | -- 1 up 2 | CREATE TABLE IF NOT EXISTS lutim ( 3 | short TEXT PRIMARY KEY, 4 | path TEXT, 5 | footprint TEXT, 6 | enabled INTEGER, 7 | mediatype TEXT, 8 | filename TEXT, 9 | counter INTEGER, 10 | delete_at_first_view INTEGER, 11 | delete_at_day INTEGER, 12 | created_at INTEGER, 13 | created_by TEXT, 14 | last_access_at INTEGER, 15 | mod_token TEXT, 16 | width INTEGER, 17 | height INTEGER 18 | ); 19 | -- 1 down 20 | DROP TABLE lutim; 21 | -- 2 up 22 | ALTER TABLE lutim ADD COLUMN iv TEXT; 23 | -- 2 down 24 | -- 3 up 25 | CREATE INDEX IF NOT EXISTS empty_short_idx ON lutim (short) WHERE path IS NULL; 26 | -- 3 down 27 | DROP INDEX empty_short_idx; 28 | -------------------------------------------------------------------------------- /themes/default/public/css/fontello-codes.css: -------------------------------------------------------------------------------- 1 | 2 | .icon-ok:before { content: '\e800'; } /* '' */ 3 | .icon-eye:before { content: '\e801'; } /* '' */ 4 | .icon-download:before { content: '\e802'; } /* '' */ 5 | .icon-share:before { content: '\e803'; } /* '' */ 6 | .icon-trash:before { content: '\e804'; } /* '' */ 7 | .icon-bitcoin:before { content: '\e805'; } /* '' */ 8 | .icon-git:before { content: '\e806'; } /* '' */ 9 | .icon-twitter:before { content: '\e807'; } /* '' */ 10 | .icon-clipboard:before { content: '\e808'; } /* '' */ 11 | .icon-spinner:before { content: '\e809'; } /* '' */ 12 | .icon-shuffle:before { content: '\e80a'; } /* '' */ 13 | .icon-cancel:before { content: '\e80b'; } /* '' */ 14 | .icon-picture:before { content: '\e80c'; } /* '' */ 15 | .icon-file-archive:before { content: '\e80d'; } /* '' */ 16 | .icon-language:before { content: '\e80e'; } /* '' */ 17 | .icon-edit:before { content: '\e80f'; } /* '' */ -------------------------------------------------------------------------------- /utilities/migrations/postgresql.sql: -------------------------------------------------------------------------------- 1 | -- 1 up 2 | CREATE TABLE IF NOT EXISTS lutim ( 3 | short text PRIMARY KEY, 4 | path text default null, 5 | footprint text default null, 6 | enabled integer, 7 | mediatype text default null, 8 | filename text default null, 9 | counter integer default 0, 10 | delete_at_first_view integer default null, 11 | delete_at_day integer default null, 12 | created_at integer default null, 13 | created_by text default null, 14 | last_access_at integer default null, 15 | mod_token text default null, 16 | width integer default null, 17 | height integer default null 18 | ); 19 | -- 1 down 20 | DROP TABLE lutim; 21 | -- 2 up 22 | ALTER TABLE lutim ADD COLUMN iv text; 23 | -- 2 down 24 | ALTER TABLE lutim DROP COLUMN iv; 25 | -- 3 up 26 | CREATE INDEX IF NOT EXISTS empty_short_idx ON lutim (short) WHERE path IS NULL; 27 | -- 3 down 28 | DROP INDEX empty_short_idx; 29 | -------------------------------------------------------------------------------- /themes/default/public/css/markdown.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'markdown'; 3 | src:url('../../font/markdown.eot?-6fnbp5'); 4 | src:url('../../font/markdown.eot?#iefix-6fnbp5') format('embedded-opentype'), 5 | url('../../font/markdown.woff?-6fnbp5') format('woff'), 6 | url('../../font/markdown.ttf?-6fnbp5') format('truetype'), 7 | url('../../font/markdown.svg?-6fnbp5#markdown') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | } 11 | 12 | [class^="markdown-"], [class*=" markdown-"] { 13 | font-family: 'markdown'; 14 | speak: none; 15 | font-style: normal; 16 | font-weight: normal; 17 | font-variant: normal; 18 | text-transform: none; 19 | line-height: 1; 20 | 21 | /* Better Font Rendering =========== */ 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | } 25 | 26 | .markdown-mark:before { 27 | content: "\e600"; 28 | } 29 | .markdown-mark-solid:before { 30 | content: "\e601"; 31 | } 32 | -------------------------------------------------------------------------------- /themes/default/templates/share.html.ep: -------------------------------------------------------------------------------- 1 | % # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab: 2 | % my $abs = url_for('/'.$short)->to_abs(); 3 | 4 | 5 | 6 | Lutim 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /themes/default/templates/zip.html.ep: -------------------------------------------------------------------------------- 1 | % # vim:set sts=4 sw=4 ts=4 ft=html.epl expandtab: 2 |

<%= l('Archives download') %>

3 |
4 |
5 |

6 | <%= l('You asked to download a zip archive for too much files.') %> 7 | <%= l('Lutim can\'t zip so many images at once, so it splitted your demand in multiple URLs.') %> 8 |

9 |
10 | 15 |
16 |

<%= l('The automatic download process will open a tab in your browser for each link. You need to allow popups for Lutim.') %>

17 |
18 | 19 | 24 | %= javascript begin 25 | $(document).ready(function() { 26 | $('.jsononly').show(); 27 | $('.dl-zip').each(function(index) { 28 | this.click(); 29 | }); 30 | }); 31 | % end 32 | -------------------------------------------------------------------------------- /lib/Lutim/Plugin/Lang.pm: -------------------------------------------------------------------------------- 1 | # vim:set sw=4 ts=4 sts=4 ft=perl expandtab: 2 | package Lutim::Plugin::Lang; 3 | use Mojo::Base 'Mojolicious::Plugin'; 4 | use Mojo::Collection; 5 | use Mojo::File; 6 | 7 | sub register { 8 | my ($self, $app) = @_; 9 | 10 | $app->helper(available_langs => \&_available_langs); 11 | 12 | $app->hook( 13 | before_dispatch => sub { 14 | my $c = shift; 15 | $c->languages($c->cookie('lutim_lang')) if $c->cookie('lutim_lang'); 16 | } 17 | ); 18 | } 19 | 20 | sub _available_langs { 21 | my $c = shift; 22 | 23 | state $langs = Mojo::Collection->new( 24 | glob($c->app->home->rel_file('themes/'.$c->config('theme').'/lib/Lutim/I18N/*po')), 25 | glob($c->app->home->rel_file('themes/default/lib/Lutim/I18N/*po')) 26 | )->map( 27 | sub { 28 | Mojo::File->new($_)->basename('.po'); 29 | } 30 | )->uniq->sort( 31 | sub { 32 | $c->l($a) cmp $c->l($b) 33 | } 34 | )->to_array; 35 | } 36 | 37 | 1; 38 | 39 | -------------------------------------------------------------------------------- /docker-stack.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | 3 | services: 4 | app: 5 | image: aquinum/lutim 6 | configs: 7 | - source: lutim.conf 8 | target: /home/lutim/lutim.conf 9 | uid: '1000' 10 | gid: '1000' 11 | mode: 0440 12 | deploy: 13 | replicas: 1 14 | db: 15 | image: postgres:11.2-alpine 16 | environment: 17 | POSTGRES_PASSWORD: 18 | POSTGRES_USER: lutim 19 | POSTGRES_DB: lutim 20 | cache: 21 | image: memcached:1.5-alpine 22 | minion: 23 | image: aquinum/lutim 24 | command: minion 25 | configs: 26 | - source: lutim.conf 27 | target: /home/lutim/lutim.conf 28 | uid: '1000' 29 | gid: '1000' 30 | mode: 0440 31 | minion_db: 32 | image: mariadb:10.3 33 | environment: 34 | MYSQL_ROOT_PASSWORD: 35 | MYSQL_DATABASE: lutim_minion 36 | 37 | configs: 38 | lutim.conf: 39 | file: ./lutim.conf -------------------------------------------------------------------------------- /themes/default/templates/partial/for_my_delay.html.ep: -------------------------------------------------------------------------------- 1 | % # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab: 2 | % my @delays = split(',', $self->config('proposed_delays')); 3 | % for my $delay (@delays) { 4 | % my $text = (defined($d->{'delay_'.$delay})) ? $d->{'delay_'.$delay} : l('%1 days', $delay); 5 | % if (config('max_delay')) { 6 | % if ($delay) { 7 | % if ($delay < config('max_delay')) { 8 | 9 | % } elsif ($delay == config('max_delay')) { 10 | 11 | % last; 12 | % } else { 13 | % my $text = ($delay == 1) ? l('24 hours') : l('%1 days', $delay); 14 | 15 | % last; 16 | % } 17 | % } 18 | % } else { 19 | 20 | % } 21 | % } 22 | -------------------------------------------------------------------------------- /.provision/terraform-aws-lutim/vars.tf: -------------------------------------------------------------------------------- 1 | variable "aws_region" { 2 | default = "aws_region" 3 | } 4 | variable "vpc_cidr" { 5 | default = "cidr_value" 6 | } 7 | variable "public_subnet_cidr" { 8 | default = "cidr_value" 9 | } 10 | variable "public_subnet1_cidr" { 11 | default = "cidr_value" 12 | } 13 | 14 | variable "user" { 15 | default = "user_of_instance" 16 | } 17 | 18 | variable "public_key" { 19 | default = "$PWD_publickey" 20 | } 21 | variable "private_key" { 22 | default = "$PWD_privatekey" 23 | } 24 | variable "aws_access_key" { 25 | default = "aws_access_key" 26 | } 27 | 28 | variable "aws_secret_key" { 29 | default = "aws_secrete_key" 30 | } 31 | 32 | variable "instance_name" { 33 | default = "instance_name" 34 | } 35 | 36 | variable "lutim_owner" { 37 | default = "" 38 | } 39 | 40 | variable "lutim_group" { 41 | default = "" 42 | } 43 | 44 | variable "app_dir" { 45 | default = "" 46 | } 47 | 48 | variable "contact_user" { 49 | default = "" 50 | } 51 | 52 | variable "contact" { 53 | default = "" 54 | } 55 | 56 | variable "secret" { 57 | default = "" 58 | } 59 | 60 | 61 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # Lutim's authors 2 | 3 | ## Main developers 4 | 5 | * Luc Didry, aka Sky (), core developer, @framasky on [Mastodon](https://framapiaf.org/@framasky) and on [Diaspora*](https://framasphere.org/public/framasky) 6 | * Dattaz (), webapp developer, [@dat_taz](https://twitter.com/dat_taz) 7 | 8 | ## Contributors 9 | 10 | * Jean-Bernard Marcon, aka Goofy () 11 | * Jean-Christophe Bach () 12 | * Florian Bigard, aka Chocobozzz () 13 | * Sandro Cazzaniga, aka Kharec (), [@Kharec](https://twitter.com/Kharec) 14 | * Laura Arjona Reina (), spanish translation 15 | * Thor77 (), german translation, among other things 16 | * Quentin Pagès, occitan translation 17 | * Alexis Clairet (), paste image to upload ability 18 | * ButterflyOfFire (), arabic translation 19 | * Alexander Sapozhnikov (), russian translation 20 | * Arnaud de Mouhy, Docker support 21 | * Armando Lüscher () 22 | -------------------------------------------------------------------------------- /docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | cd ~lutim 6 | 7 | if [ "${1:-}" == "dev" ] 8 | then 9 | echo "" 10 | echo "" 11 | echo "Container started in dev mode. Connect to the container with the following command:" 12 | echo " docker-compose -f docker-compose.dev.yml exec -u root app_dev sh" 13 | echo "" 14 | echo "" 15 | echo "You can then install the build dependencies with this command" 16 | echo " sh ~lutim/docker/install-dev-env.sh" 17 | 18 | tail -f /dev/null 19 | exit 0 20 | fi 21 | 22 | # If MySQL/PostgreSQL, wait for database to be up 23 | DB_TYPE=$(perl utilities/read_conf.pl dbtype sqlite) 24 | DB_HOST= 25 | DB_PORT= 26 | if [ "$DB_TYPE" == "postgresql" ] 27 | then 28 | DB_HOST=$(perl utilities/read_conf.pl pgdb/host db) 29 | DB_PORT=$(perl utilities/read_conf.pl pgdb/port 5432) 30 | fi 31 | if [ -n "$DB_HOST" ] && [ -n "$DB_PORT" ] 32 | then 33 | while ! nc -vz "${DB_HOST}" "${DB_PORT}"; do 34 | echo "Waiting for database..." 35 | sleep 1; 36 | done 37 | fi 38 | 39 | if [ "${1:-}" == "minion" ] 40 | then 41 | exec carton exec script/application minion worker 42 | fi 43 | 44 | exec carton exec hypnotoad -f script/lutim -------------------------------------------------------------------------------- /lib/Lutim/Command/cron/cleanbdd.pm: -------------------------------------------------------------------------------- 1 | # vim:set sw=4 ts=4 sts=4 ft=perl expandtab: 2 | package Lutim::Command::cron::cleanbdd; 3 | use Mojo::Base 'Mojolicious::Command'; 4 | use Mojo::File; 5 | use Lutim::DB::Image; 6 | use Lutim::DefaultConfig qw($default_config); 7 | use FindBin qw($Bin); 8 | use File::Spec qw(catfile); 9 | 10 | has description => 'Delete IP addresses from database after configured delay.'; 11 | has usage => sub { shift->extract_usage }; 12 | 13 | sub run { 14 | my $c = shift; 15 | 16 | my $cfile = Mojo::File->new($Bin, '..' , 'lutim.conf'); 17 | if (defined $ENV{MOJO_CONFIG}) { 18 | $cfile = Mojo::File->new($ENV{MOJO_CONFIG}); 19 | unless (-e $cfile->to_abs) { 20 | $cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG}); 21 | } 22 | } 23 | my $config = $c->app->plugin('Config', { 24 | file => $cfile, 25 | default => $default_config 26 | }); 27 | 28 | my $separation = time() - $config->{keep_ip_during} * 86400; 29 | 30 | my $dbi = Lutim::DB::Image->new(app => $c->app); 31 | 32 | $dbi->clean_ips_until($separation); 33 | } 34 | 35 | =encoding utf8 36 | 37 | =head1 NAME 38 | 39 | Lutim::Command::cron::cleanbdd - Delete IP addresses from database after configured delay 40 | 41 | =head1 SYNOPSIS 42 | 43 | Usage: script/lutim cron cleanbdd 44 | 45 | =cut 46 | 47 | 1; 48 | -------------------------------------------------------------------------------- /utilities/read_conf.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | # read_conf.pl - Outputs lutim's config value for given keypath 4 | 5 | use strict; 6 | use warnings; 7 | 8 | use FindBin; 9 | use Cwd qw(realpath); 10 | use Config::FromHash; 11 | 12 | sub print_help { 13 | print <new(filename => $filename); 42 | my $value = $config->get($ARGV[0]); 43 | 44 | if (defined $value) { 45 | print $value; 46 | exit 0; 47 | } 48 | if (not defined $value and defined $ARGV[1]) { 49 | print $ARGV[1]; 50 | exit 0; 51 | } 52 | print STDERR "Error: keypath \"$ARGV[0]\" not found in config, and no default value provided.\n"; 53 | exit 1; -------------------------------------------------------------------------------- /themes/korrigan/Makefile: -------------------------------------------------------------------------------- 1 | EN=lib/Lutim/I18N/en.po 2 | FR=lib/Lutim/I18N/fr.po 3 | DE=lib/Lutim/I18N/de.po 4 | ES=lib/Lutim/I18N/es.po 5 | OC=lib/Lutim/I18N/oc.po 6 | AR=lib/Lutim/I18N/ar.po 7 | SEDOPTS=-e "s@SOME DESCRIPTIVE TITLE@Lutim language file@" \ 8 | -e "s@YEAR THE PACKAGE'S COPYRIGHT HOLDER@2015 Luc Didry@" \ 9 | -e "s@CHARSET@utf8@" \ 10 | -e "s@the PACKAGE package@the Lutim package@" \ 11 | -e '/^\#\. (/{N;/\n\#\. (/{N;/\n.*\.\.\/default\//{s/\#\..*\n.*\#\./\#. (/g}}}' \ 12 | -e '/^\#\. (/{N;/\n.*\.\.\/default\//{s/\n/ /}}' 13 | SEDOPTS2=-e '/^\#.*\.\.\/default\//,+3d' 14 | XGETTEXT=carton exec ../../local/bin/xgettext.pl 15 | CARTON=carton exec 16 | 17 | locales: 18 | $(XGETTEXT) -D templates -D ../default/templates -o $(EN) 2>/dev/null 19 | $(XGETTEXT) -D templates -D ../default/templates -o $(FR) 2>/dev/null 20 | $(XGETTEXT) -D templates -D ../default/templates -o $(DE) 2>/dev/null 21 | $(XGETTEXT) -D templates -D ../default/templates -o $(ES) 2>/dev/null 22 | $(XGETTEXT) -D templates -D ../default/templates -o $(OC) 2>/dev/null 23 | $(XGETTEXT) -D templates -D ../default/templates -o $(AR) 2>/dev/null 24 | sed $(SEDOPTS) -i $(EN) 25 | sed $(SEDOPTS2) -i $(EN) 26 | sed $(SEDOPTS) -i $(FR) 27 | sed $(SEDOPTS2) -i $(FR) 28 | sed $(SEDOPTS) -i $(DE) 29 | sed $(SEDOPTS2) -i $(DE) 30 | sed $(SEDOPTS) -i $(ES) 31 | sed $(SEDOPTS2) -i $(ES) 32 | sed $(SEDOPTS) -i $(OC) 33 | sed $(SEDOPTS) -i $(OC) 34 | sed $(SEDOPTS2) -i $(AR) 35 | sed $(SEDOPTS2) -i $(AR) 36 | -------------------------------------------------------------------------------- /themes/default/public/css/default-skin/default-skin.svg: -------------------------------------------------------------------------------- 1 | default-skin 2 -------------------------------------------------------------------------------- /themes/default/public/font/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Font license info 2 | 3 | 4 | ## Font Awesome 5 | 6 | Copyright (C) 2016 by Dave Gandy 7 | 8 | Author: Dave Gandy 9 | License: SIL () 10 | Homepage: http://fortawesome.github.com/Font-Awesome/ 11 | 12 | 13 | ## Typicons 14 | 15 | (c) Stephen Hutchings 2012 16 | 17 | Author: Stephen Hutchings 18 | License: SIL (http://scripts.sil.org/OFL) 19 | Homepage: http://typicons.com/ 20 | 21 | 22 | ## MFG Labs 23 | 24 | Copyright (C) 2012 by Daniel Bruce 25 | 26 | Author: MFG Labs 27 | License: SIL (http://scripts.sil.org/OFL) 28 | Homepage: http://www.mfglabs.com/ 29 | 30 | 31 | ## Zocial 32 | 33 | Copyright (C) 2012 by Sam Collins 34 | 35 | Author: Sam Collins 36 | License: MIT (http://opensource.org/licenses/mit-license.php) 37 | Homepage: http://zocial.smcllns.com/ 38 | 39 | 40 | ## Elusive 41 | 42 | Copyright (C) 2013 by Aristeides Stathopoulos 43 | 44 | Author: Aristeides Stathopoulos 45 | License: SIL (http://scripts.sil.org/OFL) 46 | Homepage: http://aristeides.com/ 47 | 48 | 49 | ## Web Symbols 50 | 51 | Copyright (c) 2011 by Just Be Nice studio. All rights reserved. 52 | 53 | Author: Just Be Nice studio 54 | License: SIL (http://scripts.sil.org/OFL) 55 | Homepage: http://www.justbenicestudio.com/ 56 | 57 | 58 | ## Entypo 59 | 60 | Copyright (C) 2012 by Daniel Bruce 61 | 62 | Author: Daniel Bruce 63 | License: SIL (http://scripts.sil.org/OFL) 64 | Homepage: http://www.entypo.com 65 | 66 | 67 | -------------------------------------------------------------------------------- /themes/default/public/css/toastify.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Toastify js 1.4.0 3 | * https://github.com/apvarun/toastify-js 4 | * @license MIT licensed 5 | * 6 | * Copyright (C) 2018 Varun A P 7 | */ 8 | 9 | .toastify { 10 | padding: 12px 20px; 11 | color: #ffffff; 12 | display: inline-block; 13 | box-shadow: 0 3px 6px -1px rgba(0, 0, 0, 0.12), 0 10px 36px -4px rgba(77, 96, 232, 0.3); 14 | background: -webkit-linear-gradient(315deg, #73a5ff, #5477f5); 15 | background: linear-gradient(135deg, #73a5ff, #5477f5); 16 | position: fixed; 17 | opacity: 0; 18 | transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1); 19 | border-radius: 2px; 20 | cursor: pointer; 21 | text-decoration: none; 22 | max-width: calc(50% - 20px); 23 | z-index: 2147483647; 24 | } 25 | 26 | .toastify.on { 27 | opacity: 1; 28 | } 29 | 30 | .toast-close { 31 | opacity: 0.4; 32 | padding: 0 5px; 33 | } 34 | 35 | .toastify-right { 36 | right: 15px; 37 | } 38 | 39 | .toastify-left { 40 | left: 15px; 41 | } 42 | 43 | .toastify-top { 44 | top: -150px; 45 | } 46 | 47 | .toastify-bottom { 48 | bottom: -150px; 49 | } 50 | 51 | .toastify-rounded { 52 | border-radius: 25px; 53 | } 54 | 55 | .toastify-avatar { 56 | width: 1.5em; 57 | height: 1.5em; 58 | margin: 0 5px; 59 | border-radius: 2px; 60 | } 61 | 62 | @media only screen and (max-width: 360px) { 63 | .toastify-right, .toastify-left { 64 | margin-left: auto; 65 | margin-right: auto; 66 | left: 0; 67 | right: 0; 68 | max-width: fit-content; 69 | } 70 | } -------------------------------------------------------------------------------- /.provision/ansible-role-lutim/templates/app.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | # No need to have a `root` parameter. 4 | server_name {{ _server_name }}; 5 | # This is important for user's privacy ! 6 | access_log off; 7 | error_log /var/log/nginx/lutim.error.log; 8 | # This is important ! Make it OK with your Lutim configuration 9 | client_max_body_size 40M; 10 | 11 | location ~* ^/(img|css|font|js)/ { 12 | try_files $uri @lutim; 13 | add_header Expires "Thu, 31 Dec 2037 23:55:55 GMT"; 14 | add_header Cache-Control "public, max-age=315360000"; 15 | 16 | # HTTPS only header, improves security 17 | #add_header Strict-Transport-Security "max-age=15768000"; 18 | } 19 | 20 | location / { 21 | try_files $uri @lutim; 22 | 23 | # HTTPS only header, improves security 24 | #add_header Strict-Transport-Security "max-age=15768000"; 25 | } 26 | 27 | location @lutim { 28 | # Adapt this to your configuration 29 | proxy_pass http://127.0.0.1:8080; 30 | 31 | proxy_set_header Host $host; 32 | proxy_set_header X-Real-IP $remote_addr; 33 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 34 | 35 | # If you want to log the remote port of the image senders, you'll need that 36 | proxy_set_header X-Remote-Port $remote_port; 37 | 38 | proxy_set_header X-Forwarded-Proto $scheme; 39 | 40 | # We expect the downsteam servers to redirect to the right hostname, so don't do any rewrites here. 41 | proxy_redirect off; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/Lutim/DefaultConfig.pm: -------------------------------------------------------------------------------- 1 | # vim:set sw=4 ts=4 sts=4 ft=perl expandtab: 2 | package Lutim::DefaultConfig; 3 | require Exporter; 4 | @ISA = qw(Exporter); 5 | @EXPORT_OK = qw($default_config); 6 | our $default_config = { 7 | provisioning => 100, 8 | provis_step => 5, 9 | length => 8, 10 | always_encrypt => 0, 11 | anti_flood_delay => 5, 12 | max_file_size => 10*1024*1024, 13 | https => 0, 14 | proposed_delays => '0,1,7,30,365', 15 | default_delay => 0, 16 | max_delay => 0, 17 | token_length => 24, 18 | crypto_key_length => 8, 19 | thumbnail_size => 100, 20 | watermark_path => '', 21 | watermark_placement => 'SouthEast', 22 | watermark_default => 'none', 23 | watermark_enforce => 'none', 24 | theme => 'default', 25 | disable_api => 0, 26 | upload_dir => 'files', 27 | dbtype => 'sqlite', 28 | db_path => 'lutim.db', 29 | max_files_in_zip => 15, 30 | prefix => '/', 31 | minion => { 32 | enabled => 0, 33 | dbtype => 'sqlite', 34 | db_path => 'minion.db' 35 | }, 36 | session_duration => 3600, 37 | cache_max_size => 0, 38 | memcached_servers => [], 39 | quiet_logs => 0, 40 | disable_img_stats => 0, 41 | x_frame_options => 'DENY', 42 | x_content_type_options => 'nosniff', 43 | x_xss_protection => '1; mode=block', 44 | stats_day_num => 365, 45 | keep_ip_during => 365, 46 | policy_when_full => 'warn', 47 | }; 48 | 49 | 1; 50 | -------------------------------------------------------------------------------- /themes/default/public/css/uploader.css: -------------------------------------------------------------------------------- 1 | .uploader 2 | { 3 | border: 2px dotted #A5A5C7; 4 | width: 100%; 5 | color: #777; 6 | text-align: center; 7 | vertical-align: middle; 8 | padding: 30px 0px; 9 | margin-bottom: 10px; 10 | font-size: 200%; 11 | 12 | cursor: default; 13 | 14 | -webkit-touch-callout: none; 15 | -webkit-user-select: none; 16 | -khtml-user-select: none; 17 | -moz-user-select: none; 18 | -ms-user-select: none; 19 | user-select: none; 20 | } 21 | 22 | .uploader div.or { 23 | font-size: 50%; 24 | font-weight: bold; 25 | color: #677; 26 | padding: 10px; 27 | } 28 | 29 | @media (max-width:768px){ 30 | .uploader div.browser label { 31 | max-width:95%; 32 | } 33 | } 34 | 35 | @media (min-width:768px){ 36 | .uploader div.browser label { 37 | width:300px; 38 | } 39 | } 40 | 41 | .uploader div.browser label { 42 | background-color: #416bc4; 43 | padding: 5px 15px; 44 | color: white; 45 | padding: 6px 0px; 46 | font-size: 40%; 47 | font-weight: bold; 48 | cursor: pointer; 49 | border-radius: 2px; 50 | position: relative; 51 | overflow: hidden; 52 | display: block; 53 | margin: 20px auto 0px auto; 54 | 55 | box-shadow: 2px 2px 2px #888888; 56 | } 57 | 58 | .uploader div.browser span { 59 | cursor: pointer; 60 | } 61 | 62 | 63 | .uploader div.browser input { 64 | position: absolute; 65 | top: 0; 66 | right: 0; 67 | margin: 0; 68 | border: solid transparent; 69 | border-width: 0 0 100px 200px; 70 | opacity: .0; 71 | filter: alpha(opacity= 0); 72 | -o-transform: translate(250px,-50px) scale(1); 73 | -moz-transform: translate(-300px,0) scale(4); 74 | direction: ltr; 75 | cursor: pointer; 76 | } 77 | 78 | .uploader div.browser label:hover { 79 | background-color: #427fed; 80 | } 81 | -------------------------------------------------------------------------------- /.provision/ansible-role-lutim/README.md: -------------------------------------------------------------------------------- 1 | Ansible-Role-lutim 2 | ========= 3 | This role installs the and configures lutim on Debian/Ubuntu servers with nginx web server configuration. 4 | 5 | Role Variables 6 | -------------- 7 | | Variable name | Value | Description | 8 | | ------------- | ----- | ----------- | 9 | | `app_dir` | /var/www/lutim | Set the application directory for the best practice | 10 | | `lutim_owner` | www-data | Set the application user for the best practice | 11 | | `lutim_group` | www-data | Set the application group for the best practice | 12 | | `_contact` | contact.example.com | Contact option (mandatory), where you have to put some way for the users to contact you. | 13 | | `_secrets` | ffyg7kbkjba | Secrets option (mandotory), which is array of random string. Used by Mojolicious for encrypting session cookies | 14 | | `_project_version` | master | We can chose the project version either Master branch, Dev branch or tag based | 15 | | `_server_name` | IP address (or) CNAME/FQDN | Mention the Server Name for the Nginx configurations | 16 | 17 | Sample example of use in a playbook 18 | -------------- 19 | 20 | The following code has been tested with Ubuntu 20.04 21 | 22 | ```yaml 23 | 24 | - name: "install lutim" 25 | hosts: enter your hosts file 26 | become: yes 27 | role: 28 | - ansible-role-lutim 29 | vars: 30 | lutim_owner: "www-data" 31 | lutim_group: "www-data" 32 | contact: "contact.example.com" 33 | secrets: "yigavlvlivwe" 34 | app_dir: "/var/www/lutim" 35 | project_version: "master" 36 | servername: "IP address (or) CNAME/FQDN" 37 | ``` 38 | 39 | Contributing 40 | ------------ 41 | Don’t hesitate to create a pull request 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /themes/default/public/css/fontello-ie7-codes.css: -------------------------------------------------------------------------------- 1 | 2 | .icon-ok { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 3 | .icon-eye { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 4 | .icon-download { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 5 | .icon-share { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 6 | .icon-trash { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 7 | .icon-bitcoin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 8 | .icon-git { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 9 | .icon-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 10 | .icon-clipboard { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 11 | .icon-spinner { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 12 | .icon-shuffle { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 13 | .icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 14 | .icon-picture { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 15 | .icon-file-archive { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 16 | .icon-language { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 17 | .icon-edit { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -------------------------------------------------------------------------------- /lib/Lutim/Command/cron/cleanfiles.pm: -------------------------------------------------------------------------------- 1 | # vim:set sw=4 ts=4 sts=4 ft=perl expandtab: 2 | package Lutim::Command::cron::cleanfiles; 3 | use Mojo::Base 'Mojolicious::Command'; 4 | use Mojo::File; 5 | use Lutim::DB::Image; 6 | use Lutim::DefaultConfig qw($default_config); 7 | use Lutim; 8 | use FindBin qw($Bin); 9 | use File::Spec qw(catfile); 10 | 11 | has description => 'Delete expired files.'; 12 | has usage => sub { shift->extract_usage }; 13 | 14 | sub run { 15 | my $c = shift; 16 | 17 | my $cfile = Mojo::File->new($Bin, '..' , 'lutim.conf'); 18 | if (defined $ENV{MOJO_CONFIG}) { 19 | $cfile = Mojo::File->new($ENV{MOJO_CONFIG}); 20 | unless (-e $cfile->to_abs) { 21 | $cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG}); 22 | } 23 | } 24 | my $config = $c->app->plugin('Config', { 25 | file => $cfile, 26 | default => $default_config 27 | }); 28 | 29 | my $l = Lutim->new; 30 | 31 | my $dbi = Lutim::DB::Image->new(app => $c->app); 32 | 33 | $dbi->get_images_to_clean()->each( 34 | sub { 35 | my ($img, $num) = @_; 36 | $l->app->delete_image($img); 37 | } 38 | ); 39 | 40 | if (defined($config->{delete_no_longer_viewed_files}) && $config->{delete_no_longer_viewed_files} > 0) { 41 | my $time = time() - $config->{delete_no_longer_viewed_files} * 86400; 42 | $dbi->get_no_longer_viewed_files($time)->each( 43 | sub { 44 | my ($img, $num) = @_; 45 | $l->app->delete_image($img); 46 | } 47 | ); 48 | } 49 | } 50 | 51 | =encoding utf8 52 | 53 | =head1 NAME 54 | 55 | Lutim::Command::cron::cleanfiles - Delete expired files 56 | 57 | =head1 SYNOPSIS 58 | 59 | Usage: script/lutim cron cleanfiles 60 | 61 | =cut 62 | 63 | 1; 64 | -------------------------------------------------------------------------------- /lib/Mounter.pm: -------------------------------------------------------------------------------- 1 | # vim:set sw=4 ts=4 sts=4 ft=perl expandtab: 2 | package Mounter; 3 | use Mojo::Base 'Mojolicious'; 4 | use Mojo::File; 5 | use FindBin qw($Bin); 6 | use File::Spec qw(catfile); 7 | use Lutim::DefaultConfig qw($default_config); 8 | 9 | # This method will run once at server start 10 | sub startup { 11 | my $self = shift; 12 | 13 | push @{$self->commands->namespaces}, 'Lutim::Command'; 14 | 15 | my $cfile = Mojo::File->new($Bin, '..' , 'lutim.conf'); 16 | if (defined $ENV{MOJO_CONFIG}) { 17 | $cfile = Mojo::File->new($ENV{MOJO_CONFIG}); 18 | unless (-e $cfile->to_abs) { 19 | $cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG}); 20 | } 21 | } 22 | my $config = $self->plugin('Config', { 23 | file => $cfile, 24 | default => $default_config 25 | }); 26 | 27 | $config->{prefix} = $config->{url_sub_dir} if (defined($config->{url_sub_dir}) && $config->{prefix} eq '/'); 28 | 29 | $self->app->log->warn('"url_sub_dir" configuration option is deprecated. Use "prefix" instead. "url_sub_dir" will be removed in the future') if (defined($config->{url_sub_dir})); 30 | 31 | # Themes handling 32 | shift @{$self->static->paths}; 33 | if ($config->{theme} ne 'default') { 34 | my $theme = $self->home->rel_file('themes/'.$config->{theme}); 35 | push @{$self->static->paths}, $theme.'/public' if -d $theme.'/public'; 36 | } 37 | push @{$self->static->paths}, $self->home->rel_file('themes/default/public'); 38 | 39 | # Static assets gzipping 40 | $self->plugin('GzipStatic'); 41 | 42 | # Headers 43 | $self->plugin('Lutim::Plugin::Headers'); 44 | 45 | # Helpers 46 | $self->plugin('Lutim::Plugin::Helpers'); 47 | 48 | $self->plugin('Mount' => {$config->{prefix} => File::Spec->catfile($Bin, '..', 'script', 'application')}); 49 | } 50 | 51 | 1; 52 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.22 2 | 3 | ARG BUILD_DATE 4 | ARG VCS_REF 5 | ARG VERSION 6 | LABEL org.label-schema.build-date=$BUILD_DATE \ 7 | org.label-schema.name="Lets Upload That Image" \ 8 | org.label-schema.url="https://lutim.fiat-tux.fr/" \ 9 | org.label-schema.vcs-ref=$VCS_REF \ 10 | org.label-schema.vcs-url="https://framagit.org/fiat-tux/hat-softwares/lutim" \ 11 | org.label-schema.vendor="Luc Didry" \ 12 | org.label-schema.version=$VERSION \ 13 | org.label-schema.schema-version="1.0" 14 | 15 | RUN adduser -D lutim \ 16 | && addgroup lutim root 17 | 18 | COPY . /home/lutim 19 | RUN chmod -R g+rwX /home/lutim 20 | 21 | WORKDIR /home/lutim 22 | RUN apk --no-cache add perl~=5 \ 23 | libpq~=17 \ 24 | perl-crypt-rijndael~=1 \ 25 | perl-io-socket-ssl~=2 \ 26 | perl-net-ssleay~=1 \ 27 | su-exec~=0.2 \ 28 | shared-mime-info~=2 \ 29 | libretls~=3 \ 30 | imagemagick~=7 \ 31 | imagemagick-perlmagick~=7 \ 32 | bash~=~5 \ 33 | && apk --no-cache add --virtual .build-deps build-base~=0.5 \ 34 | perl-utils~=5 \ 35 | perl-dev~=5 \ 36 | postgresql17-dev~=17 \ 37 | vim~=9 \ 38 | wget~=1 \ 39 | zlib-dev~=1 \ 40 | && cpan notest Carton Config::FromHash \ 41 | && carton install --without test \ 42 | && apk del .build-deps \ 43 | && rm -rf /var/cache/apk/* /root/.cpan* 44 | 45 | USER lutim 46 | EXPOSE 8080 47 | 48 | ENTRYPOINT ["/bin/sh", "/home/lutim/docker/entrypoint.sh"] 49 | -------------------------------------------------------------------------------- /themes/default/public/font/markdown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | { 7 | "fontFamily": "markdown", 8 | "majorVersion": 1, 9 | "minorVersion": 0, 10 | "fontURL": "https://github.com/dcurtis/markdown-mark", 11 | "designer": "Dustin Curtis", 12 | "designerURL": "http://twitter.com/dcurtis", 13 | "license": "CC0 UNIVERSAL PUBLIC DOMAIN DEDICATION LICENSE", 14 | "licenseURL": "https://raw.githubusercontent.com/dcurtis/markdown-mark/master/LICENSE", 15 | "version": "Version 1.0", 16 | "fontId": "markdown", 17 | "psName": "markdown", 18 | "subFamily": "Regular", 19 | "fullName": "markdown", 20 | "description": "Generated by IcoMoon" 21 | } 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /themes/default/public/css/fontello-ie7.css: -------------------------------------------------------------------------------- 1 | [class^="icon-"], [class*=" icon-"] { 2 | font-family: 'fontello'; 3 | font-style: normal; 4 | font-weight: normal; 5 | 6 | /* fix buttons height */ 7 | line-height: 1em; 8 | 9 | /* you can be more comfortable with increased icons size */ 10 | /* font-size: 120%; */ 11 | } 12 | 13 | .icon-ok { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 14 | .icon-eye { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 15 | .icon-download { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 16 | .icon-share { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 17 | .icon-trash { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 18 | .icon-bitcoin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 19 | .icon-git { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 20 | .icon-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 21 | .icon-clipboard { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 22 | .icon-spinner { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 23 | .icon-shuffle { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 24 | .icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 25 | .icon-picture { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 26 | .icon-file-archive { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 27 | .icon-language { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } 28 | .icon-edit { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -------------------------------------------------------------------------------- /lib/Lutim/Plugin/Headers.pm: -------------------------------------------------------------------------------- 1 | package Lutim::Plugin::Headers; 2 | use Mojo::Base 'Mojolicious::Plugin'; 3 | 4 | sub register { 5 | my ($self, $app) = @_; 6 | 7 | # Assets Cache headers 8 | $app->plugin('StaticCache' => { even_in_dev => 1 }); 9 | 10 | # Add CSP Header 11 | if (!defined($app->config('csp')) || (defined($app->config('csp')) && $app->config('csp') ne '')) { 12 | my $directives = { 13 | 'default-src' => "'none'", 14 | 'script-src' => "'self' 'unsafe-eval'", 15 | 'style-src' => "'self' 'unsafe-inline'", 16 | 'connect-src' => "'self'", 17 | 'img-src' => "'self' data:", 18 | 'font-src' => "'self'", 19 | 'form-action' => "'self'", 20 | 'base-uri' => "'self'", 21 | }; 22 | 23 | my $frame_ancestors = ''; 24 | $frame_ancestors = "'none'" if $app->config('x_frame_options') eq 'DENY'; 25 | $frame_ancestors = "'self'" if $app->config('x_frame_options') eq 'SAMEORIGIN'; 26 | if ($app->config('x_frame_options') =~ m#^ALLOW-FROM#) { 27 | $frame_ancestors = $app->config('x_frame_options'); 28 | $frame_ancestors =~ s#ALLOW-FROM +##; 29 | } 30 | $directives->{'frame-ancestors'} = $frame_ancestors if $frame_ancestors; 31 | 32 | $app->plugin('CSPHeader', 33 | csp => $app->config('csp'), 34 | directives => $directives 35 | ); 36 | } 37 | 38 | # Add other headers 39 | $app->hook( 40 | before_dispatch => sub { 41 | my $c = shift; 42 | 43 | $c->res->headers->header('X-Frame-Options' => $app->config('x_frame_options')) if $app->config('x_frame_options'); 44 | $c->res->headers->header('X-Content-Type-Options' => $app->config('x_content_type_options')) if $app->config('x_content_type_options'); 45 | $c->res->headers->header('X-XSS-Protection' => $app->config('x_xss_protection')) if $app->config('x_xss_protection'); 46 | } 47 | ); 48 | } 49 | 50 | 1; 51 | -------------------------------------------------------------------------------- /cpanfile: -------------------------------------------------------------------------------- 1 | requires 'Mojolicious', '>= 7.31'; 2 | requires 'EV'; 3 | requires 'IO::Socket::SSL'; 4 | requires 'Net::SSLeay', '>= 1.81'; 5 | requires 'Data::Validate::URI'; 6 | requires 'Net::Domain::TLD', '>= 1.75'; # Must have the last version to handle (at least) .xyz and .link 7 | requires 'Mojolicious::Plugin::I18N'; 8 | requires 'Mojolicious::Plugin::DebugDumperHelper'; 9 | requires 'Mojolicious::Plugin::StaticCache'; 10 | requires 'Mojolicious::Plugin::GzipStatic'; 11 | requires 'Mojolicious::Plugin::CSPHeader'; 12 | requires 'Text::Unidecode'; 13 | requires 'DateTime'; 14 | requires 'Filesys::DiskUsage'; 15 | requires 'Switch'; 16 | requires 'Crypt::CBC'; 17 | requires 'Crypt::Blowfish'; 18 | requires 'Digest::MD5'; 19 | requires 'Locale::Maketext'; 20 | requires 'Locale::Maketext::Extract'; 21 | requires 'File::MimeInfo'; 22 | requires 'IO::Scalar'; 23 | requires 'Image::ExifTool'; 24 | requires 'Data::Entropy'; 25 | requires 'List::MoreUtils', '> 0.33'; 26 | requires 'Archive::Zip'; 27 | requires 'ISO::639_1'; 28 | 29 | feature 'postgresql', 'PostgreSQL support' => sub { 30 | requires 'Mojo::Pg'; 31 | requires 'Mojolicious::Plugin::PgURLHelper'; 32 | }; 33 | feature 'sqlite', 'SQLite support' => sub { 34 | requires 'Mojo::SQLite', '>= 3.000'; 35 | requires 'Minion::Backend::SQLite', '>= 4.001'; 36 | requires 'DBD::SQLite', '>= 1.66'; 37 | }; 38 | feature 'minion', 'Minion support' => sub { 39 | requires 'Minion'; 40 | }; 41 | feature 'cache', 'Cache system' => sub { 42 | requires 'Mojolicious::Plugin::CHI'; 43 | requires 'Data::Serializer'; 44 | }; 45 | feature 'memcached', 'Cache system using Memcached' => sub { 46 | requires 'Mojolicious::Plugin::CHI'; 47 | requires 'CHI::Driver::Memcached'; 48 | requires 'Cache::Memcached'; 49 | }; 50 | feature 'ldap', 'LDAP authentication support' => sub { 51 | requires 'Net::LDAP'; 52 | requires 'Mojolicious::Plugin::Authentication'; 53 | }; 54 | feature 'htpasswd', 'Htpasswd authentication support' => sub { 55 | requires 'Apache::Htpasswd'; 56 | requires 'Mojolicious::Plugin::Authentication'; 57 | }; 58 | feature 'test' => sub { 59 | requires 'Devel::Cover'; 60 | }; 61 | -------------------------------------------------------------------------------- /themes/default/public/css/animation.css: -------------------------------------------------------------------------------- 1 | /* 2 | Animation example, for spinners 3 | */ 4 | .animate-spin { 5 | -moz-animation: spin 2s infinite linear; 6 | -o-animation: spin 2s infinite linear; 7 | -webkit-animation: spin 2s infinite linear; 8 | animation: spin 2s infinite linear; 9 | display: inline-block; 10 | } 11 | @-moz-keyframes spin { 12 | 0% { 13 | -moz-transform: rotate(0deg); 14 | -o-transform: rotate(0deg); 15 | -webkit-transform: rotate(0deg); 16 | transform: rotate(0deg); 17 | } 18 | 19 | 100% { 20 | -moz-transform: rotate(359deg); 21 | -o-transform: rotate(359deg); 22 | -webkit-transform: rotate(359deg); 23 | transform: rotate(359deg); 24 | } 25 | } 26 | @-webkit-keyframes spin { 27 | 0% { 28 | -moz-transform: rotate(0deg); 29 | -o-transform: rotate(0deg); 30 | -webkit-transform: rotate(0deg); 31 | transform: rotate(0deg); 32 | } 33 | 34 | 100% { 35 | -moz-transform: rotate(359deg); 36 | -o-transform: rotate(359deg); 37 | -webkit-transform: rotate(359deg); 38 | transform: rotate(359deg); 39 | } 40 | } 41 | @-o-keyframes spin { 42 | 0% { 43 | -moz-transform: rotate(0deg); 44 | -o-transform: rotate(0deg); 45 | -webkit-transform: rotate(0deg); 46 | transform: rotate(0deg); 47 | } 48 | 49 | 100% { 50 | -moz-transform: rotate(359deg); 51 | -o-transform: rotate(359deg); 52 | -webkit-transform: rotate(359deg); 53 | transform: rotate(359deg); 54 | } 55 | } 56 | @-ms-keyframes spin { 57 | 0% { 58 | -moz-transform: rotate(0deg); 59 | -o-transform: rotate(0deg); 60 | -webkit-transform: rotate(0deg); 61 | transform: rotate(0deg); 62 | } 63 | 64 | 100% { 65 | -moz-transform: rotate(359deg); 66 | -o-transform: rotate(359deg); 67 | -webkit-transform: rotate(359deg); 68 | transform: rotate(359deg); 69 | } 70 | } 71 | @keyframes spin { 72 | 0% { 73 | -moz-transform: rotate(0deg); 74 | -o-transform: rotate(0deg); 75 | -webkit-transform: rotate(0deg); 76 | transform: rotate(0deg); 77 | } 78 | 79 | 100% { 80 | -moz-transform: rotate(359deg); 81 | -o-transform: rotate(359deg); 82 | -webkit-transform: rotate(359deg); 83 | transform: rotate(359deg); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/Lutim/Controller/Authent.pm: -------------------------------------------------------------------------------- 1 | # vim:set sw=4 ts=4 sts=4 ft=perl expandtab: 2 | package Lutim::Controller::Authent; 3 | use Mojo::Base 'Mojolicious::Controller'; 4 | 5 | sub index { 6 | my $c = shift; 7 | if ($c->is_user_authenticated) { 8 | $c->redirect_to('index'); 9 | } else { 10 | $c->render(template => 'login'); 11 | } 12 | } 13 | 14 | sub login { 15 | my $c = shift; 16 | my $login = $c->param('login'); 17 | my $pwd = $c->param('password'); 18 | my $ref = $c->req->headers->referrer; 19 | 20 | if($c->authenticate($login, $pwd)) { 21 | $c->respond_to( 22 | json => sub { 23 | my $c = shift; 24 | $c->render( 25 | json => { 26 | success => Mojo::JSON->true, 27 | msg => $c->l('You have been successfully logged in.') 28 | } 29 | ); 30 | }, 31 | any => sub { 32 | $c->redirect_to($ref); 33 | } 34 | ); 35 | } else { 36 | my $msg = $c->l('Please, check your credentials: unable to authenticate.'); 37 | $c->respond_to( 38 | json => sub { 39 | my $c = shift; 40 | $c->render( 41 | json => { 42 | success => Mojo::JSON->false, 43 | msg => $msg 44 | } 45 | ); 46 | }, 47 | any => sub { 48 | $c->stash(msg => $msg); 49 | $c->render(template => 'login') 50 | } 51 | ); 52 | } 53 | } 54 | 55 | sub log_out { 56 | my $c = shift; 57 | if ($c->is_user_authenticated) { 58 | $c->logout; 59 | } 60 | $c->respond_to( 61 | json => sub { 62 | my $c = shift; 63 | $c->render( 64 | json => { 65 | success => Mojo::JSON->true, 66 | msg => $c->l('You have been successfully logged out.') 67 | } 68 | ); 69 | }, 70 | any => sub { 71 | $c->render(template => 'logout'); 72 | } 73 | ); 74 | } 75 | 76 | 1; 77 | -------------------------------------------------------------------------------- /themes/default/public/js/FileSaver.min.js: -------------------------------------------------------------------------------- 1 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 2 | var saveAs=saveAs||function(e){"use strict";if(typeof e==="undefined"||typeof navigator!=="undefined"&&/MSIE [1-9]\./.test(navigator.userAgent)){return}var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=t.createElementNS("http://www.w3.org/1999/xhtml","a"),o="download"in r,i=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},a=/constructor/i.test(e.HTMLElement),f=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},u="application/octet-stream",s=1e3*40,d=function(e){var t=function(){if(typeof e==="string"){n().revokeObjectURL(e)}else{e.remove()}};setTimeout(t,s)},c=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var o=e["on"+t[r]];if(typeof o==="function"){try{o.call(e,n||e)}catch(i){f(i)}}}},l=function(e){if(/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)){return new Blob([String.fromCharCode(65279),e],{type:e.type})}return e},p=function(t,f,s){if(!s){t=l(t)}var p=this,v=t.type,w=v===u,m,y=function(){c(p,"writestart progress write writeend".split(" "))},h=function(){if(w&&a&&e.FileReader){var r=new FileReader;r.onloadend=function(){var t=r.result;e.location.href="data:attachment/file"+t.slice(t.search(/[,;]/));p.readyState=p.DONE;y()};r.readAsDataURL(t);p.readyState=p.INIT;return}if(!m){m=n().createObjectURL(t)}if(w){e.location.href=m}else{var o=e.open(m,"_blank");if(!o){e.location.href=m}}p.readyState=p.DONE;y();d(m)};p.readyState=p.INIT;if(o){m=n().createObjectURL(t);setTimeout(function(){r.href=m;r.download=f;i(r);y();d(m);p.readyState=p.DONE});return}h()},v=p.prototype,w=function(e,t,n){return new p(e,t||e.name||"download",n)};if(typeof navigator!=="undefined"&&navigator.msSaveOrOpenBlob){return function(e,t,n){t=t||e.name||"download";if(!n){e=l(e)}return navigator.msSaveOrOpenBlob(e,t)}}v.abort=function(){};v.readyState=v.INIT=0;v.WRITING=1;v.DONE=2;v.error=v.onwritestart=v.onprogress=v.onwrite=v.onabort=v.onerror=v.onwriteend=null;return w}(typeof self!=="undefined"&&self||typeof window!=="undefined"&&window||this.content);if(typeof module!=="undefined"&&module.exports){module.exports.saveAs=saveAs}else if(typeof define!=="undefined"&&define!==null&&define.amd!==null){define([],function(){return saveAs})} 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | EXTRACTDIR=-D lib -D themes/default/templates 2 | POT=themes/default/lib/Lutim/I18N/lutim.pot 3 | ENPO=themes/default/lib/Lutim/I18N/en.po 4 | XGETTEXT=carton exec local/bin/xgettext.pl -u 5 | CARTON=carton exec 6 | LUTIM=script/lutim 7 | REAL_LUTIM=script/application 8 | HARNESS_PERL_SWITCHES=-MDevel::Cover=+ignore,local 9 | HEAD := $(shell git rev-parse --abbrev-ref HEAD) 10 | 11 | minify: 12 | @echo "CSS concatenation" 13 | @cd ./themes/default/public/css/ && cat bootstrap.min.css fontello.css hennypenny.css lutim.css toastify.css | csso > common.min.css 14 | @cd ./themes/default/public/css/ && cat animation.css uploader.css markdown.css | csso > not_stats.min.css 15 | @cd ./themes/default/public/css/ && cat photoswipe.css default-skin/default-skin.css | csso > gallery.min.css 16 | 17 | locales: 18 | $(XGETTEXT) $(EXTRACTDIR) -o $(POT) 2>/dev/null 19 | $(XGETTEXT) $(EXTRACTDIR) -o $(ENPO) 2>/dev/null 20 | 21 | podcheck: 22 | podchecker lib/Lutim/DB/Image.pm 23 | 24 | check-syntax: 25 | find lib/ themes/ -name \*.pm -exec $(CARTON) perl -Ilib -c {} \; 26 | find t/ -name \*.t -exec $(CARTON) perl -Ilib -c {} \; 27 | 28 | cover: 29 | PERL5OPT='-Ilib' $(CARTON) cover --ignore_re '^local' 30 | 31 | test: 32 | @PERL5OPT='-Ilib/' HARNESS_PERL_SWITCHES='$(HARNESS_PERL_SWITCHES)' $(CARTON) -- prove -l --failures 33 | 34 | test-junit-output: 35 | @PERL5OPT='-Ilib/' HARNESS_PERL_SWITCHES='$(HARNESS_PERL_SWITCHES)' $(CARTON) -- prove -l --failures --formatter TAP::Formatter::JUnit > tap.xml 36 | 37 | full-test: podcheck just-test 38 | 39 | clean: 40 | rm -rf lutim.db files/ 41 | 42 | dev: minify 43 | $(CARTON) morbo $(LUTIM) --listen http://0.0.0.0:3000 --watch lib/ --watch script/ --watch themes/ --watch lutim.conf 44 | 45 | devlog: 46 | multitail log/development.log 47 | 48 | prod: 49 | $(CARTON) hypnotoad -f $(LUTIM) 50 | 51 | prodlog: 52 | multitail log/production.log 53 | 54 | minion: 55 | $(CARTON) $(REAL_LUTIM) minion worker 56 | 57 | create-pg-test-db: 58 | sudo -u postgres psql -f t/create-pg-testdb.sql 59 | 60 | stats: 61 | $(CARTON) $(LUTIM) cron stats -m production 62 | 63 | watch: 64 | $(CARTON) $(LUTIM) cron watch -m production 65 | 66 | cleanfiles: 67 | $(CARTON) $(LUTIM) cron cleanfiles -m production 68 | 69 | cleanbdd: 70 | $(CARTON) $(LUTIM) cron cleanbdd -m production 71 | -------------------------------------------------------------------------------- /themes/default/public/js/raphael.path.methods.js: -------------------------------------------------------------------------------- 1 | Raphael.el.isAbsolute = true; 2 | Raphael.el.absolutely = function () { 3 | this.isAbsolute = 1; 4 | return this; 5 | }; 6 | Raphael.el.relatively = function () { 7 | this.isAbsolute = 0; 8 | return this; 9 | }; 10 | Raphael.el.moveTo = function (x, y) { 11 | this._last = {x: x, y: y}; 12 | return this.attr({path: this.attrs.path + ["m", "M"][+this.isAbsolute] + parseFloat(x) + " " + parseFloat(y)}); 13 | }; 14 | Raphael.el.lineTo = function (x, y) { 15 | this._last = {x: x, y: y}; 16 | return this.attr({path: this.attrs.path + ["l", "L"][+this.isAbsolute] + parseFloat(x) + " " + parseFloat(y)}); 17 | }; 18 | Raphael.el.arcTo = function (rx, ry, large_arc_flag, sweep_flag, x, y, angle) { 19 | this._last = {x: x, y: y}; 20 | return this.attr({path: this.attrs.path + ["a", "A"][+this.isAbsolute] + [parseFloat(rx), parseFloat(ry), +angle, large_arc_flag, sweep_flag, parseFloat(x), parseFloat(y)].join(" ")}); 21 | }; 22 | Raphael.el.curveTo = function () { 23 | var args = Array.prototype.splice.call(arguments, 0, arguments.length), 24 | d = [0, 0, 0, 0, "s", 0, "c"][args.length] || ""; 25 | this.isAbsolute && (d = d.toUpperCase()); 26 | this._last = {x: args[args.length - 2], y: args[args.length - 1]}; 27 | return this.attr({path: this.attrs.path + d + args}); 28 | }; 29 | Raphael.el.cplineTo = function (x, y, w) { 30 | this.attr({path: this.attrs.path + ["C", this._last.x + w, this._last.y, x - w, y, x, y]}); 31 | this._last = {x: x, y: y}; 32 | return this; 33 | }; 34 | Raphael.el.qcurveTo = function () { 35 | var d = [0, 1, "t", 3, "q"][arguments.length], 36 | args = Array.prototype.splice.call(arguments, 0, arguments.length); 37 | if (this.isAbsolute) { 38 | d = d.toUpperCase(); 39 | } 40 | this._last = {x: args[args.length - 2], y: args[args.length - 1]}; 41 | return this.attr({path: this.attrs.path + d + args}); 42 | }; 43 | Raphael.el.addRoundedCorner = function (r, dir) { 44 | var rollback = this.isAbsolute; 45 | rollback && this.relatively(); 46 | this._last = {x: r * (!!(dir.indexOf("r") + 1) * 2 - 1), y: r * (!!(dir.indexOf("d") + 1) * 2 - 1)}; 47 | this.arcTo(r, r, 0, {"lu": 1, "rd": 1, "ur": 1, "dl": 1}[dir] || 0, this._last.x, this._last.y); 48 | rollback && this.absolutely(); 49 | return this; 50 | }; 51 | Raphael.el.andClose = function () { 52 | return this.attr({path: this.attrs.path + "z"}); 53 | }; 54 | -------------------------------------------------------------------------------- /themes/default/templates/manifest.webapp.ep: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Lutim", 3 | "description": "Let's Upload That Image!\n\nThis is a simple image sharing app which use <%= url_for('/')->to_abs %> for storing the images. Once you have uploaded an image, you'll be provided differents links:\n a view link, which points directly to the image\n a download link, which force the download of the image\n a social link, which you can share on social networks\n a delete link, which allows you to delete the image anytime you want\n\nThe image is stored on <%= url_for('/')->to_abs %> for a delay which you can define.\n\nThe particularity of Lutim is that the image is encrypted and its usage is as most anonymous as possible. See the information page (<%= url_for('about')->to_abs %>) for more details.\nLicense: AGPLv3 (https://www.gnu.org/licenses/agpl-3.0.html)", 4 | "launch_path": "<%= url_for('/') %>", 5 | "icons": { 6 | "32": "<%= url_for('/img/lutim32.png') %>", 7 | "60": "<%= url_for('/img/lutim60.png') %>", 8 | "90": "<%= url_for('/img/lutim90.png') %>", 9 | "120": "<%= url_for('/img/lutim120.png') %>", 10 | "128": "<%= url_for('/img/lutim128.png') %>", 11 | "256": "<%= url_for('/img/lutim256.png') %>" 12 | }, 13 | "developer": { 14 | "name": "Lutim team!", 15 | "url": "https://framagit.org/fiat-tux/hat-softwares/lutim" 16 | }, 17 | "default_locale": "en", 18 | "locales": { 19 | "fr": { 20 | "description": "Envoyons cette image !\n\nCeci est une application de partage simple d'images qui utilise <%= url_for('/')->to_abs %> pour enregistrer les images. Une fois que vous avez envoyé une image, vous obtiendrez différents liens :\n un lien de visualisation, qui pointe directement sur l'image\n un lien de téléchargement, qui force le téléchargement de l'image\n un lien de partage, que vous pouvez partager sur les réseaux sociaux\n un lien de suppression, qui vous permet de supprimer l'image quand vous le souhaitez\n\nL'image est conservée sur <%= url_for('/')->to_abs %> pour un délai que vous pouvez définir.\n\nLa particularité de Lutim est que l'image est chiffrée et que son usage est aussi anonyme que possible. Voir la page d'information (<%= url_for('about')->to_abs %>) pour plus de détails.\nLicence : AGPLv3 (https://www.gnu.org/licenses/agpl-3.0.html)" 21 | } 22 | }, 23 | "activities": { 24 | "share": { 25 | "filters": { 26 | "type": [ "image/*"] 27 | }, 28 | "href": "<%= url_for('/') %>", 29 | "disposition": "window" 30 | } 31 | }, 32 | "version": "0.1", 33 | "chrome": { "navigation": true } 34 | } 35 | -------------------------------------------------------------------------------- /themes/default/templates/gallery.html.ep: -------------------------------------------------------------------------------- 1 | % # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab: 2 |
3 |
4 |
5 |
6 |
7 | 14 |
15 | 17 | 18 | 53 |
54 |
55 | -------------------------------------------------------------------------------- /utilities/fontello-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fontello", 3 | "css_prefix_text": "icon-", 4 | "css_use_suffix": false, 5 | "hinting": true, 6 | "units_per_em": 1000, 7 | "ascent": 850, 8 | "glyphs": [ 9 | { 10 | "uid": "12f4ece88e46abd864e40b35e05b11cd", 11 | "css": "ok", 12 | "code": 59392, 13 | "src": "fontawesome" 14 | }, 15 | { 16 | "uid": "c5fd349cbd3d23e4ade333789c29c729", 17 | "css": "eye", 18 | "code": 59393, 19 | "src": "fontawesome" 20 | }, 21 | { 22 | "uid": "9a76bc135eac17d2c8b8ad4a5774fc87", 23 | "css": "download", 24 | "code": 59394, 25 | "src": "fontawesome" 26 | }, 27 | { 28 | "uid": "4aad6bb50b02c18508aae9cbe14e784e", 29 | "css": "share", 30 | "code": 59395, 31 | "src": "fontawesome" 32 | }, 33 | { 34 | "uid": "f48ae54adfb27d8ada53d0fd9e34ee10", 35 | "css": "trash", 36 | "code": 59396, 37 | "src": "fontawesome" 38 | }, 39 | { 40 | "uid": "2cb15eb2b295ee3c33fab1530e18a924", 41 | "css": "bitcoin", 42 | "code": 59397, 43 | "src": "fontawesome" 44 | }, 45 | { 46 | "uid": "e7cb72a17f3b21e3576f35c3f0a7639b", 47 | "css": "git", 48 | "code": 59398, 49 | "src": "fontawesome" 50 | }, 51 | { 52 | "uid": "627abcdb627cb1789e009c08e2678ef9", 53 | "css": "twitter", 54 | "code": 59399, 55 | "src": "fontawesome" 56 | }, 57 | { 58 | "uid": "1a27e6346cdf0480c9c22351378bebbb", 59 | "css": "clipboard", 60 | "code": 59400, 61 | "src": "typicons" 62 | }, 63 | { 64 | "uid": "fccd3ea0efb711b849045bee686b1ceb", 65 | "css": "spinner", 66 | "code": 59401, 67 | "src": "mfglabs" 68 | }, 69 | { 70 | "uid": "499b745a2e2485bdd059c3a53d048e5f", 71 | "css": "cancel", 72 | "code": 59403, 73 | "src": "elusive" 74 | }, 75 | { 76 | "uid": "baa375529925294ea0a2bc889c93ba2d", 77 | "css": "picture", 78 | "code": 59404, 79 | "src": "websymbols" 80 | }, 81 | { 82 | "uid": "e80ae555c1413a4ec18b33fb348b4049", 83 | "css": "file-archive", 84 | "code": 59405, 85 | "src": "fontawesome" 86 | }, 87 | { 88 | "uid": "ddecf5ad7935e3fb1b70dac6ed00d06a", 89 | "css": "language", 90 | "code": 59406, 91 | "src": "entypo" 92 | }, 93 | { 94 | "uid": "3d349daaea304032a7669b4f24931b6c", 95 | "css": "shuffle", 96 | "code": 59402, 97 | "src": "entypo" 98 | }, 99 | { 100 | "uid": "41087bc74d4b20b55059c60a33bf4008", 101 | "css": "edit", 102 | "code": 59407, 103 | "src": "fontawesome" 104 | } 105 | ] 106 | } -------------------------------------------------------------------------------- /themes/default/public/css/fontello.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'fontello'; 3 | src: url('../font/fontello.eot?74275093'); 4 | src: url('../font/fontello.eot?74275093#iefix') format('embedded-opentype'), 5 | url('../font/fontello.woff2?74275093') format('woff2'), 6 | url('../font/fontello.woff?74275093') format('woff'), 7 | url('../font/fontello.ttf?74275093') format('truetype'), 8 | url('../font/fontello.svg?74275093#fontello') format('svg'); 9 | font-weight: normal; 10 | font-style: normal; 11 | } 12 | /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ 13 | /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ 14 | /* 15 | @media screen and (-webkit-min-device-pixel-ratio:0) { 16 | @font-face { 17 | font-family: 'fontello'; 18 | src: url('../font/fontello.svg?74275093#fontello') format('svg'); 19 | } 20 | } 21 | */ 22 | 23 | [class^="icon-"]:before, [class*=" icon-"]:before { 24 | font-family: "fontello"; 25 | font-style: normal; 26 | font-weight: normal; 27 | speak: none; 28 | 29 | display: inline-block; 30 | text-decoration: inherit; 31 | width: 1em; 32 | margin-right: .2em; 33 | text-align: center; 34 | /* opacity: .8; */ 35 | 36 | /* For safety - reset parent styles, that can break glyph codes*/ 37 | font-variant: normal; 38 | text-transform: none; 39 | 40 | /* fix buttons height, for twitter bootstrap */ 41 | line-height: 1em; 42 | 43 | /* Animation center compensation - margins should be symmetric */ 44 | /* remove if not needed */ 45 | margin-left: .2em; 46 | 47 | /* you can be more comfortable with increased icons size */ 48 | /* font-size: 120%; */ 49 | 50 | /* Font smoothing. That was taken from TWBS */ 51 | -webkit-font-smoothing: antialiased; 52 | -moz-osx-font-smoothing: grayscale; 53 | 54 | /* Uncomment for 3D effect */ 55 | /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ 56 | } 57 | 58 | .icon-ok:before { content: '\e800'; } /* '' */ 59 | .icon-eye:before { content: '\e801'; } /* '' */ 60 | .icon-download:before { content: '\e802'; } /* '' */ 61 | .icon-share:before { content: '\e803'; } /* '' */ 62 | .icon-trash:before { content: '\e804'; } /* '' */ 63 | .icon-bitcoin:before { content: '\e805'; } /* '' */ 64 | .icon-git:before { content: '\e806'; } /* '' */ 65 | .icon-twitter:before { content: '\e807'; } /* '' */ 66 | .icon-clipboard:before { content: '\e808'; } /* '' */ 67 | .icon-spinner:before { content: '\e809'; } /* '' */ 68 | .icon-shuffle:before { content: '\e80a'; } /* '' */ 69 | .icon-cancel:before { content: '\e80b'; } /* '' */ 70 | .icon-picture:before { content: '\e80c'; } /* '' */ 71 | .icon-file-archive:before { content: '\e80d'; } /* '' */ 72 | .icon-language:before { content: '\e80e'; } /* '' */ 73 | .icon-edit:before { content: '\e80f'; } /* '' */ -------------------------------------------------------------------------------- /themes/default/public/js/stats.js: -------------------------------------------------------------------------------- 1 | function graph(stats_labels, stats_data, stats_total) { 2 | Morris.Line({ 3 | // ID of the element in which to draw the chart. 4 | element: 'evol-holder', 5 | // Chart data records -- each entry in this array corresponds to a point on 6 | // the chart. 7 | data: stats_data, 8 | // The name of the data record attribute that contains x-values. 9 | xkey: 'day', 10 | // A list of names of data record attributes that contain y-values. 11 | ykeys: ['value'], 12 | // Labels for the ykeys -- will be displayed when you hover over the 13 | // chart. 14 | labels: ['Uploaded files'], 15 | xLabels: 'day', 16 | dateFormat: function(x) { return new Date(x).toLocaleDateString(); }, 17 | xLabelFormat: function(x) { return x.toLocaleDateString(); } 18 | }); 19 | Morris.Line({ 20 | // ID of the element in which to draw the chart. 21 | element: 'total-holder', 22 | // Chart data records -- each entry in this array corresponds to a point on 23 | // the chart. 24 | data: stats_total, 25 | // The name of the data record attribute that contains x-values. 26 | xkey: 'day', 27 | // A list of names of data record attributes that contain y-values. 28 | ykeys: ['value'], 29 | // Labels for the ykeys -- will be displayed when you hover over the 30 | // chart. 31 | labels: ['Uploaded files'], 32 | xLabels: 'day', 33 | lineColors: ['red'], 34 | dateFormat: function(x) { return new Date(x).toLocaleDateString(); }, 35 | xLabelFormat: function(x) { return x.toLocaleDateString(); } 36 | }); 37 | } 38 | $(document).ready(function() { 39 | // Get the data 40 | var stats_labels = [], stats_data = [], stats_total = []; 41 | $("#stats-data thead th").each(function () { 42 | stats_labels.push($(this).html()); 43 | }); 44 | var i = 0; 45 | $("#stats-data tbody tr:first-child td").each(function () { 46 | var s = stats_labels[i++]; 47 | s = s.replace(/([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{4})/, "$3-$2-$1"); 48 | stats_data.push({ day: s, value: $(this).html()}); 49 | }); 50 | i = 0; 51 | $("#stats-data tbody tr:nth-child(2) td").each(function () { 52 | var s = stats_labels[i++]; 53 | s = s.replace(/([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{4})/, "$3-$2-$1"); 54 | stats_total.push({ day: s, value: $(this).html()}); 55 | }); 56 | 57 | // Hide the data 58 | $("#stats-data").hide(); 59 | 60 | graph(stats_labels, stats_data, stats_total); 61 | 62 | $(window).resize(function() { 63 | $("#evol-holder").empty(); 64 | $("#total-holder").empty(); 65 | graph(stats_labels, stats_data, stats_total); 66 | }); 67 | Morris.Donut(enabled_donut); 68 | Morris.Donut(disabled_donut); 69 | }); 70 | -------------------------------------------------------------------------------- /themes/default/public/img/liberapay.svg: -------------------------------------------------------------------------------- 1 | 2 | 15 | 17 | 18 | 20 | image/svg+xml 21 | 23 | 24 | 25 | 26 | 28 | 49 | 54 | 58 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /.provision/terraform-aws-lutim/lutim_startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "**********************************************************************" 4 | echo " *" 5 | echo "Install dependencies *" 6 | echo " *" 7 | echo "**********************************************************************" 8 | 9 | SUDO=sudo 10 | $SUDO apt update 11 | $SUDO apt install jq -y 12 | $SUDO apt install wget -y 13 | $SUDO apt install unzip 14 | $SUDO apt install carton -y 15 | $SUDO apt install build-essential -y 16 | $SUDO apt install nginx -y 17 | $SUDO apt install libssl-dev -y 18 | $SUDO apt install libio-socket-ssl-perl -y 19 | $SUDO apt install liblwp-protocol-https-perl -y 20 | $SUDO apt install zlib1g-dev -y 21 | $SUDO apt install libmojo-sqlite-perl -y 22 | $SUDO apt install libpq-dev -y 23 | 24 | echo "**********************************************************************" 25 | echo " *" 26 | echo "Configuring the Application *" 27 | echo " *" 28 | echo "**********************************************************************" 29 | 30 | sleep 10; 31 | version=$(curl -s https://framagit.org/api/v4/projects/1/releases | jq '.[]' | jq -r '.name' | head -1) 32 | echo $version 33 | pushd ${directory} 34 | $SUDO wget https://framagit.org/fiat-tux/hat-softwares/lutim/-/archive/$version/lutim-$version.zip 35 | $SUDO unzip lutim-$version.zip 36 | $SUDO chown ${user} lutim-$version 37 | $SUDO chgrp ${group} lutim-$version 38 | pushd lutim-$version 39 | 40 | echo "**********************************************************************" 41 | echo " *" 42 | echo "Install Carton Packages *" 43 | echo " *" 44 | echo "**********************************************************************" 45 | 46 | $SUDO carton install --deployment --without=test --without=sqlite --without=mysql 47 | 48 | sleep 10; 49 | 50 | $SUDO cp lutim.conf.template lutim.conf 51 | 52 | sed -i 's/127.0.0.1/0.0.0.0/' lutim.conf 53 | sed -i 's/#contact/contact/g' lutim.conf 54 | sed -i "s/John Doe/${contact_user}/g" lutim.conf 55 | sed -i "s/admin[at]example.com/${contact_lutim}/g" lutim.conf 56 | sed -i "s/fdjsofjoihrei/${secret_lutim}/g" lutim.conf 57 | sed -i '153 , 158 s/#/ /g' lutim.conf 58 | 59 | echo "**********************************************************************" 60 | echo " *" 61 | echo "Run the Application *" 62 | echo " *" 63 | echo "**********************************************************************" 64 | 65 | $SUDO carton exec hypnotoad script/lutim 66 | 67 | -------------------------------------------------------------------------------- /lib/Lutim/Command/cron/watch.pm: -------------------------------------------------------------------------------- 1 | # vim:set sw=4 ts=4 sts=4 ft=perl expandtab: 2 | package Lutim::Command::cron::watch; 3 | use Mojo::Base 'Mojolicious::Command'; 4 | use Filesys::DiskUsage qw/du/; 5 | use Lutim::DB::Image; 6 | use Lutim::DefaultConfig qw($default_config); 7 | use Lutim; 8 | use Mojo::File; 9 | use Switch; 10 | use FindBin qw($Bin); 11 | use File::Spec qw(catfile); 12 | 13 | has description => 'Watch the files directory and take action when over quota'; 14 | has usage => sub { shift->extract_usage }; 15 | 16 | sub run { 17 | my $c = shift; 18 | 19 | my $cfile = Mojo::File->new($Bin, '..' , 'lutim.conf'); 20 | if (defined $ENV{MOJO_CONFIG}) { 21 | $cfile = Mojo::File->new($ENV{MOJO_CONFIG}); 22 | unless (-e $cfile->to_abs) { 23 | $cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG}); 24 | } 25 | } 26 | my $config = $c->app->plugin('Config', { 27 | file => $cfile, 28 | default => $default_config 29 | }); 30 | 31 | if (defined($config->{max_total_size})) { 32 | my $total = du(qw/files/); 33 | 34 | if ($total > $config->{max_total_size}) { 35 | say "[Lutim cron job watch] Files directory is over quota ($total > ".$config->{max_total_size}.")"; 36 | switch ($config->{policy_when_full}) { 37 | case 'warn' { 38 | say "[Lutim cron job watch] Please, delete some files or increase quota (".$config->{max_total_size}.")"; 39 | } 40 | case 'stop-upload' { 41 | open (my $fh, '>', 'stop-upload') or die ("Couldn't open stop-upload: $!"); 42 | close($fh); 43 | say '[Lutim cron job watch] Uploads are stopped. Delete some images and the stop-upload file to reallow uploads.'; 44 | } 45 | case 'delete' { 46 | say '[Lutim cron job watch] Older files are being deleted'; 47 | my $dbi = Lutim::DB::Image->new(app => $c->app); 48 | my $l = Lutim->new; 49 | do { 50 | $dbi->get_50_oldest()->each( 51 | sub { 52 | my ($img, $num) = @_; 53 | $l->app->delete_image($img); 54 | } 55 | ); 56 | } while (du(qw/files/) > $config->{max_total_size}); 57 | } 58 | else { 59 | say '[Lutim cron job watch] Unrecognized policy_when_full option: '.$config->{policy_when_full}.'. Aborting.'; 60 | } 61 | } 62 | } else { 63 | unlink 'stop-upload' if (-f 'stop-upload'); 64 | } 65 | } else { 66 | say "[Lutim cron job watch] No max_total_size found in the configuration file. Aborting."; 67 | } 68 | } 69 | 70 | =encoding utf8 71 | 72 | =head1 NAME 73 | 74 | Lutim::Command::cron::watch - Watch the files directory and take action when over quota 75 | 76 | =head1 SYNOPSIS 77 | 78 | Usage: script/lutim cron watch 79 | 80 | =cut 81 | 82 | 1; 83 | -------------------------------------------------------------------------------- /themes/default/public/css/not_stats.min.css: -------------------------------------------------------------------------------- 1 | @-moz-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.animate-spin{-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear;display:inline-block}.uploader{border:2px dotted #a5a5c7;width:100%;color:#777;text-align:center;vertical-align:middle;padding:30px 0;margin-bottom:10px;font-size:200%;cursor:default;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.uploader div.or{font-size:50%;font-weight:700;color:#677;padding:10px}@media (max-width:768px){.uploader div.browser label{max-width:95%}}@media (min-width:768px){.uploader div.browser label{width:300px}}.uploader div.browser label{background-color:#416bc4;color:#fff;padding:6px 0;font-size:40%;font-weight:700;cursor:pointer;border-radius:2px;position:relative;overflow:hidden;display:block;margin:20px auto 0;box-shadow:2px 2px 2px #888}.uploader div.browser span{cursor:pointer}.uploader div.browser input{position:absolute;top:0;right:0;margin:0;border:solid transparent;border-width:0 0 100px 200px;opacity:0;filter:alpha(opacity= 0);-o-transform:translate(250px,-50px) scale(1);-moz-transform:translate(-300px,0) scale(4);direction:ltr;cursor:pointer}.uploader div.browser label:hover{background-color:#427fed}@font-face{font-family:"markdown";src:url(../../font/markdown.eot?-6fnbp5);src:url(../../font/markdown.eot?#iefix-6fnbp5)format("embedded-opentype"),url(../../font/markdown.woff?-6fnbp5)format("woff"),url(../../font/markdown.ttf?-6fnbp5)format("truetype"),url(../../font/markdown.svg?-6fnbp5#markdown)format("svg");font-weight:400;font-style:normal}[class*=" markdown-"],[class^=markdown-]{font-family:"markdown";speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.markdown-mark:before{content:""}.markdown-mark-solid:before{content:""} 2 | -------------------------------------------------------------------------------- /themes/default/public/css/lutim.css: -------------------------------------------------------------------------------- 1 | /* vim:set sw=4 ts=4 sts=4 ft=css expandtab: */ 2 | @media (max-width: 767px) { 3 | body { 4 | padding-top: 5px; 5 | padding-bottom: 5px; 6 | } 7 | } 8 | 9 | @media (min-width: 768px) { 10 | body { 11 | padding-bottom: 40px; 12 | } 13 | } 14 | 15 | .container { 16 | padding: 15px; 17 | margin: 0 auto; 18 | } 19 | 20 | nav .container { 21 | padding: 0; 22 | } 23 | 24 | .jsonly { 25 | display: none; 26 | } 27 | 28 | .thumbnail { 29 | margin-right: 8px; 30 | } 31 | 32 | .hennypenny { 33 | font-family: 'Henny_Penny', cursive; 34 | font-size: 42px; 35 | } 36 | 37 | .logo { 38 | margin-right: 10px; 39 | } 40 | label.always-encrypt { 41 | display: none; 42 | } 43 | .link_nocol, 44 | .link_nocol:hover{ 45 | color: #000000; 46 | text-decoration: none; 47 | } 48 | 49 | #install-app img { 50 | height: 22px; 51 | } 52 | #install-app { 53 | display: none; 54 | } 55 | .form-control[readonly] { 56 | background-color: #FFFFFF; 57 | } 58 | .alert .form-group { 59 | margin-bottom: 5px; 60 | } 61 | #copy-all { 62 | margin-bottom: 8px; 63 | } 64 | #gallery-url { 65 | margin-bottom: 10px; 66 | } 67 | .adjust-addon { 68 | width: 42px; 69 | } 70 | .adjust-addon .btn { 71 | width: 43px; 72 | } 73 | #tipeee-img { 74 | margin-top: -4px; 75 | } 76 | #liberapay-img { 77 | height: 21px; 78 | line-height: 21px; 79 | margin-top: -5.33333px; 80 | } 81 | .pasteZone { 82 | position: absolute; 83 | top: 0; 84 | left: -100px; 85 | z-index: -999; 86 | height: 10000vh; 87 | width: 0; 88 | display: hidden; 89 | } 90 | .gallery figure { 91 | margin-right: auto; 92 | margin-left: auto; 93 | margin-bottom: 5px; 94 | } 95 | @media (min-width: 1200px) { 96 | .gallery { column-count: 4 } 97 | } 98 | @media (min-width: 991px) and (max-width: 1199px) { 99 | .gallery { column-count: 3 } 100 | } 101 | @media (min-width: 676px) and (max-width: 990px) { 102 | .gallery { column-count: 2 } 103 | } 104 | @media (max-width: 675px) { 105 | .gallery { column-count: 1 } 106 | } 107 | .border-zero { 108 | border: 0; 109 | } 110 | .copy-node { 111 | width: 1px; 112 | height: 1px; 113 | position: 'fixed'; 114 | top: 5px; 115 | } 116 | .width-zero { 117 | width: 0%; 118 | } 119 | .pdg-left-10 { 120 | padding-left: 10px; 121 | } 122 | .spin { 123 | font-size: 200%; 124 | display: none; 125 | } 126 | #myfiles td.ellips { 127 | max-width: 300px; 128 | white-space: nowrap; 129 | overflow: hidden; 130 | text-overflow: ellipsis; 131 | } 132 | h1.ellips { 133 | white-space: nowrap; 134 | overflow: hidden; 135 | text-overflow: ellipsis; 136 | } 137 | 138 | /* 139 | * a11y 140 | */ 141 | .navbar-default .navbar-brand, 142 | .navbar-default .navbar-nav > li > a, 143 | .navbar-default .navbar-text { 144 | color: #555; 145 | } 146 | 147 | .navbar-default .navbar-nav > li > a:focus 148 | .navbar-default .navbar-nav > li > a:hover { 149 | color: #111; 150 | } 151 | 152 | .btn-primary { 153 | background-color: #3c74c8; 154 | } 155 | -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/slider/ug-theme-slider.js: -------------------------------------------------------------------------------- 1 | 2 | if(typeof g_ugFunctions != "undefined") 3 | g_ugFunctions.registerTheme("slider"); 4 | else 5 | jQuery(document).ready(function(){g_ugFunctions.registerTheme("slider")}); 6 | 7 | 8 | /** 9 | * Slider gallery theme 10 | */ 11 | function UGTheme_slider(){ 12 | 13 | var t = this; 14 | var g_gallery = new UniteGalleryMain(), g_objGallery, g_objects, g_objWrapper; 15 | var g_objThumbs, g_objSlider; 16 | var g_functions = new UGFunctions(); 17 | 18 | 19 | //theme options 20 | var g_options = { 21 | 22 | }; 23 | 24 | 25 | var g_defaults = { 26 | gallery_autoplay: true, 27 | 28 | slider_scale_mode:"fill", 29 | slider_controls_always_on:true, 30 | slider_enable_text_panel:false, 31 | slider_controls_appear_ontap: true, //appear controls on tap event on touch devices 32 | slider_enable_bullets: true, 33 | slider_enable_arrows: true, 34 | slider_enable_play_button: false, 35 | slider_enable_fullscreen_button:false, 36 | slider_enable_zoom_panel: false, 37 | slider_vertical_scroll_ondrag: true 38 | }; 39 | 40 | 41 | /** 42 | * init 43 | */ 44 | this.init = function(gallery, customOptions){ 45 | 46 | g_gallery = gallery; 47 | 48 | g_options = jQuery.extend(g_options, g_defaults); 49 | g_options = jQuery.extend(g_options, customOptions); 50 | 51 | //set gallery options 52 | g_gallery.setOptions(g_options); 53 | 54 | g_gallery.initSlider(g_options); 55 | 56 | g_objects = gallery.getObjects(); 57 | 58 | //get some objects for local use 59 | g_objGallery = jQuery(gallery); 60 | g_objWrapper = g_objects.g_objWrapper; 61 | g_objSlider = g_objects.g_objSlider; 62 | } 63 | 64 | 65 | /** 66 | * set gallery html elements 67 | */ 68 | function setHtml(){ 69 | 70 | //add html elements 71 | g_objWrapper.addClass("ug-theme-slider"); 72 | 73 | //set slider html 74 | if(g_objSlider) 75 | g_objSlider.setHtml(); 76 | } 77 | 78 | 79 | /** 80 | * place the slider according the thumbs panel size and position 81 | */ 82 | function placeSlider(){ 83 | 84 | var sliderHeight = g_gallery.getHeight(); 85 | var sliderWidth = g_gallery.getWidth(); 86 | 87 | g_objSlider.setSize(sliderWidth, sliderHeight); 88 | g_objSlider.setPosition(0, 0); 89 | } 90 | 91 | 92 | 93 | /** 94 | * on gallery size change - resize the theme. 95 | */ 96 | function onSizeChange(){ 97 | 98 | placeSlider(); 99 | 100 | } 101 | 102 | 103 | /** 104 | * init buttons functionality and events 105 | */ 106 | function initEvents(){ 107 | 108 | g_objGallery.on(g_gallery.events.SIZE_CHANGE,onSizeChange); 109 | //g_objGallery.on(g_gallery.events.ITEM_CHANGE,onItemChange); 110 | } 111 | 112 | /** 113 | * init all the theme's elements and set them to their places 114 | * according gallery's dimentions. 115 | * this function should work on resize too. 116 | */ 117 | function initAndPlaceElements(){ 118 | placeSlider(); 119 | g_objSlider.run(); 120 | 121 | } 122 | 123 | /** 124 | * run the theme setting 125 | */ 126 | this.run = function(){ 127 | 128 | setHtml(); 129 | 130 | initAndPlaceElements(); 131 | 132 | initEvents(); 133 | } 134 | 135 | 136 | } 137 | -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/video/skin-right-thumb.css: -------------------------------------------------------------------------------- 1 | @CHARSET "ISO-8859-1"; 2 | 3 | /* ----- Strip Panel ------- */ 4 | 5 | .ug-videoskin-right-thumb .ug-strip-panel{ 6 | background-color:#232323; 7 | } 8 | 9 | /* ----- Thumb Wrapper ------- */ 10 | 11 | .ug-videoskin-right-thumb .ug-thumb-wrapper{ 12 | background-color:#232323; 13 | border-bottom:1px solid #393939; 14 | width:420px; 15 | height:61px; 16 | cursor:pointer; 17 | text-align:left; 18 | } 19 | 20 | .ug-videoskin-right-thumb .ug-thumb-wrapper:last-child{ 21 | border-bottom:none; 22 | } 23 | 24 | /* - thumb selected and over - */ 25 | 26 | .ug-videoskin-right-thumb .ug-thumb-wrapper.ug-thumb-over{ 27 | cursor:pointer; 28 | background-color:#1A1A1A; 29 | } 30 | 31 | .ug-videoskin-right-thumb .ug-thumb-wrapper.ug-thumb-selected{ 32 | cursor:default; 33 | background-color:#525252; 34 | } 35 | 36 | /* ----- Thumb Inner data ------- */ 37 | 38 | 39 | .ug-videoskin-right-thumb .ug-thumb-icon{ 40 | width:72px; 41 | height:40px; 42 | float:left; 43 | background-position:center center; 44 | background-size:cover; 45 | } 46 | 47 | .ug-videoskin-right-thumb .ug-thumb-selected .ug-thumb-icon{ 48 | border:2px solid red; 49 | box-sizing: border-box; 50 | } 51 | 52 | .ug-videoskin-right-thumb .ug-thumb-right{ 53 | float:left; 54 | padding-left:15px; 55 | } 56 | 57 | 58 | .ug-videoskin-right-thumb .ug-thumb-inner{ 59 | padding-top:12px; 60 | padding-left:13px; 61 | padding-right:5px; 62 | } 63 | 64 | .ug-videoskin-right-thumb .ug-thumb-title{ 65 | color:white; 66 | font-size:16px; 67 | overflow:hidden; 68 | width:300px; 69 | height:20px; 70 | line-height:normal; 71 | } 72 | 73 | .ug-videoskin-right-thumb .ug-thumb-desc{ 74 | color:#999999; 75 | font-size:11px; 76 | width:300px; 77 | line-height:normal; 78 | } 79 | 80 | /* ----- Under 960 ------- */ 81 | .ug-under-960.ug-videoskin-right-thumb .ug-thumb-wrapper 82 | { 83 | width:320px; 84 | } 85 | 86 | .ug-under-960.ug-videoskin-right-thumb .ug-thumb-title { 87 | width: 206px; 88 | height:18px; 89 | font-size:14px; 90 | } 91 | .ug-under-960.ug-videoskin-right-thumb .ug-thumb-desc 92 | { 93 | width:167px; 94 | padding-top:0px; 95 | line-height:normal; 96 | } 97 | 98 | 99 | /* ----- Under 780 ------- */ 100 | 101 | .ug-under-780.ug-videoskin-right-thumb .ug-thumb-wrapper 102 | { 103 | width:240px; 104 | } 105 | 106 | .ug-under-780.ug-videoskin-right-thumb .ug-thumb-icon 107 | { 108 | width:40px; 109 | } 110 | 111 | .ug-under-780.ug-videoskin-right-thumb .ug-thumb-title { 112 | width: 167px; 113 | height:18px; 114 | font-size:14px; 115 | } 116 | 117 | .ug-under-780.ug-videoskin-right-thumb .ug-thumb-desc 118 | { 119 | width:167px; 120 | padding-top:0px; 121 | line-height:normal; 122 | } 123 | 124 | 125 | /* ----- Under 480 ------- */ 126 | 127 | .ug-under-480.ug-videoskin-right-thumb .ug-thumb-wrapper 128 | { 129 | width:56px; 130 | } 131 | 132 | .ug-under-480.ug-videoskin-right-thumb .ug-thumb-title { 133 | display:none; 134 | } 135 | 136 | .ug-under-480.ug-videoskin-right-thumb .ug-thumb-desc 137 | { 138 | display:none; 139 | } 140 | 141 | .ug-under-480.ug-videoskin-right-thumb .ug-thumb-inner { 142 | padding-left: 8px; 143 | padding-right: 5px; 144 | padding-top: 12px; 145 | } 146 | 147 | .ug-under-480.ug-videoskin-right-thumb .ug-thumb-icon 148 | { 149 | width:40px; 150 | } -------------------------------------------------------------------------------- /.provision/terraform-aws-lutim/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | user_data_vars = { 3 | user = var.lutim_owner 4 | group = var.lutim_group 5 | directory = var.app_dir 6 | contact_user = var.contact_user 7 | contact_lutim = var.contact 8 | secret_lutim = var.secret 9 | } 10 | } 11 | 12 | #Create the VPC 13 | resource "aws_vpc" "vpc" { 14 | cidr_block = "${var.vpc_cidr}" 15 | enable_dns_hostnames = true 16 | enable_dns_support = true 17 | instance_tenancy = "default" 18 | tags = { 19 | Name = "lutim-master-vpc" 20 | } 21 | } 22 | 23 | # Create InternetGateWay and attach to VPC 24 | 25 | resource "aws_internet_gateway" "IGW" { 26 | vpc_id = "${aws_vpc.vpc.id}" 27 | tags = { 28 | "Name" = "lutim-master-igw" 29 | } 30 | } 31 | 32 | # Create a public subnet 33 | 34 | resource "aws_subnet" "publicsubnet" { 35 | vpc_id = "${aws_vpc.vpc.id}" 36 | cidr_block = "${var.public_subnet_cidr}" 37 | map_public_ip_on_launch = true 38 | tags = { 39 | Name = "lutim-master-us-east-1-public" 40 | } 41 | } 42 | 43 | # Create routeTable 44 | resource "aws_route_table" "publicroute" { 45 | vpc_id = "${aws_vpc.vpc.id}" 46 | route { 47 | cidr_block = "0.0.0.0/0" 48 | gateway_id = "${aws_internet_gateway.IGW.id}" 49 | } 50 | 51 | tags = { 52 | Name = "lutim-master-us-east-1-public-rt" 53 | } 54 | } 55 | 56 | resource "aws_main_route_table_association" "mainRTB" { 57 | vpc_id = "${aws_vpc.vpc.id}" 58 | route_table_id = "${aws_route_table.publicroute.id}" 59 | } 60 | ## Create security group 61 | resource "aws_security_group" "security" { 62 | name = "lutim-master-sg" 63 | description = "allow all traffic" 64 | vpc_id = "${aws_vpc.vpc.id}" 65 | 66 | ingress { 67 | description = "allow all traffic" 68 | from_port = "0" 69 | to_port = "65535" 70 | protocol = "tcp" 71 | cidr_blocks = ["0.0.0.0/0"] 72 | } 73 | ingress { 74 | description = "allow port SSH" 75 | from_port = "22" 76 | to_port = "22" 77 | protocol = "tcp" 78 | cidr_blocks = ["0.0.0.0/0"] 79 | } 80 | egress { 81 | from_port = 0 82 | to_port = 0 83 | protocol = "-1" 84 | cidr_blocks = ["0.0.0.0/0"] 85 | } 86 | 87 | } 88 | 89 | # Add ubuntu AMI 90 | data "aws_ami" "ubuntu" { 91 | most_recent = true 92 | owners = ["099720109477"] 93 | 94 | filter { 95 | name = "name" 96 | values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] 97 | } 98 | } 99 | 100 | #Create key_pair for the instance 101 | 102 | resource "aws_key_pair" "genkey" { 103 | key_name = "lutim.webapp" 104 | public_key = "${file(var.public_key)}" 105 | } 106 | 107 | # Craete ec2 instance 108 | resource "aws_instance" "ec2_instance" { 109 | ami = "${data.aws_ami.ubuntu.id}" 110 | instance_type = "t2.medium" 111 | associate_public_ip_address = "true" 112 | subnet_id = "${aws_subnet.publicsubnet.id}" 113 | vpc_security_group_ids = ["${aws_security_group.security.id}"] 114 | user_data = templatefile("${path.module}/lutim_startup.sh", local.user_data_vars) 115 | key_name = "lutim.webapp" 116 | 117 | tags = { 118 | Name = "${var.instance_name}" 119 | } 120 | } 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lutim 2 | 3 | ## What Lutim means? 4 | It means Let's Upload That Image. 5 | 6 | ## What does it do? 7 | It stores images and allows you to see them, download them or share them on social networks. 8 | 9 | Images are indefinitely stored unless you request that they will be deleted at first view or after 24 hours / one week / one month / one year. 10 | 11 | ## License 12 | Lutim is licensed under the terms of the AGPL. See the LICENSE file. 13 | 14 | ## Logo 15 | Lutim's logo is an adaptation of [Lutin](http://commons.wikimedia.org/wiki/File:Lutin_by_godo.jpg) by [Godo](http://godoillustrateur.wordpress.com/), licensed under the terms of the CC-BY-SA 3.0 license. 16 | 17 | ![Lutim's logo](https://lutim.fiat-tux.fr/img/Lutim_small.png) 18 | 19 | ## Wiki 20 | 21 | The official wiki contains all you need to know about Lutim (installation, API, etc.). Go to or clone it: 22 | 23 | ``` 24 | git clone https://framagit.org/fiat-tux/hat-softwares/lutim.wiki.git 25 | ``` 26 | 27 | ## Encryption 28 | 29 | Lutim does encryption on the server if asked to, but does not store the key. 30 | 31 | The encryption is done on the server since Lutim is made to be usable even without javascript. If you want to add client-side encryption for javascript-enabled browsers, patches are welcome. 32 | 33 | ## Internationalization 34 | 35 | Lutim comes with English, French and Spanish languages. It will choose the language to display from the browser's settings. 36 | 37 | ## Authors 38 | 39 | See [AUTHORS.md](AUTHORS.md) file. 40 | 41 | ## Contribute! 42 | 43 | Please consider contributing, either by [reporting issues](https://framagit.org/fiat-tux/hat-softwares/lutim/issues) or by helping the [internationalization](https://weblate.framasoft.org/projects/lutim/). And of course, code contribution are welcome! 44 | 45 | The details on how to contribute are on the [wiki](https://framagit.org/fiat-tux/hat-softwares/lutim/wikis/contribute). 46 | 47 | ## Make a donation 48 | 49 | You can make a donation to the author on [Tipeee](https://www.tipeee.com/fiat-tux) or on [Liberapay](https://liberapay.com/sky/). 50 | 51 | ## Others projects dependencies 52 | 53 | Lutim is written in Perl with the [Mojolicious](http://mojolicio.us) framework. 54 | 55 | It uses: 56 | 57 | * [Twitter bootstrap](http://getbootstrap.com) framework to look not too ugly 58 | * [JQuery](http://jquery.com) and [JQuery File Uploader](https://github.com/danielm/uploader/) (slightly modified) to add some modernity 59 | * [Raphaël](http://raphaeljs.com/) and [morris.js](https://morrisjs.github.io/morris.js/) for stats graphs 60 | * [freezeframe.js](http://freezeframe.chrisantonellis.com/) (slightly modified) to be able to freeze animated gifs in twitter card 61 | * [Moment.js](http://momentjs.com/) for displaying real dates instead of unix timestamps. 62 | * [Fontello](http://fontello.com/) and the [markdown font](https://github.com/dcurtis/markdown-mark/) for the icons, licenses for the fontello icons fonts are in `public/font/LICENSE.txt` 63 | * [Henny Penny](https://www.google.com/fonts/specimen/Henny+Penny) font designed by Olga Umpeleva for [Brownfox](http://brownfox.org) 64 | * [PhotoSwipe](http://photoswipe.com/) for the gallery 65 | * [JSZip](https://stuk.github.io/jszip/) for generating a zip containing all the images in the gallery 66 | * [FileSaver.js](https://github.com/eligrey/FileSaver.js/) for saving the zip 67 | * [Toastify JS](https://apvarun.github.io/toastify-js/) for notifications 68 | 69 | ## Deploy lutim 70 | 71 | An ansible role and a terraform plan reside under the `.provision` directory. An user could utilize the terraform plan if they chose to deploy lutim on AWS, if that's not the goal, they could simply execute the ansible role in part. Usage docs for both are present in their respective directories. 72 | -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/video/skin-right-title-only.css: -------------------------------------------------------------------------------- 1 | @CHARSET "ISO-8859-1"; 2 | 3 | /* ----- Strip Panel ------- */ 4 | 5 | .ug-videoskin-right-title-only .ug-strip-panel{ 6 | background-color:#232323; 7 | } 8 | 9 | /* ----- Thumb Wrapper ------- */ 10 | 11 | .ug-videoskin-right-title-only .ug-thumb-wrapper{ 12 | background-color:#232323; 13 | border-bottom:1px solid #393939; 14 | width:360px; 15 | height:60px; 16 | cursor:pointer; 17 | text-align:left; 18 | } 19 | 20 | 21 | .ug-videoskin-right-title-only .ug-thumb-wrapper:last-child{ 22 | border-bottom:none; 23 | } 24 | 25 | /* - thumb selected and over - */ 26 | 27 | .ug-videoskin-right-title-only .ug-thumb-wrapper.ug-thumb-over{ 28 | cursor:pointer; 29 | background-color:#1A1A1A; 30 | } 31 | 32 | .ug-videoskin-right-title-only .ug-thumb-wrapper.ug-thumb-selected{ 33 | cursor:default; 34 | background-color:#176DB3; 35 | } 36 | 37 | /* ----- Thumb Inner data ------- */ 38 | 39 | .ug-videoskin-right-title-only .ug-thumb-inner{ 40 | padding-top:18px; 41 | padding-left:20px; 42 | padding-right:10px; 43 | } 44 | 45 | .ug-videoskin-right-title-only .ug-thumb-title{ 46 | color:white; 47 | font-size:14px; 48 | line-height:normal; 49 | } 50 | 51 | 52 | /* ----- Buttons Panel ------- */ 53 | 54 | .ug-videoskin-right-title-only .ug-video-buttons-panel{ 55 | height:42px; 56 | background-color:#000; 57 | position:absolute; 58 | display:none; 59 | } 60 | 61 | .ug-videoskin-right-title-only .ug-button-prev-video{ 62 | width:50%; 63 | height:42px; 64 | float:left; 65 | background-image:url('images/arrow_left.png'); 66 | cursor:pointer; 67 | background-repeat:no-repeat; 68 | background-position:center; 69 | box-sizing:border-box; 70 | border-right:1px solid #444; 71 | } 72 | 73 | .ug-videoskin-right-title-only .ug-button-prev-video:hover, .ug-videoskin-right-title-only .ug-button-next-video:hover 74 | { 75 | background-color:#444; 76 | } 77 | 78 | .ug-videoskin-right-title-only .ug-button-next-video{ 79 | width:50%; 80 | height:42px; 81 | float:right; 82 | background-image:url('images/arrow_right.png'); 83 | cursor:pointer; 84 | background-repeat:no-repeat; 85 | background-position:center; 86 | } 87 | 88 | 89 | 90 | /* ----- Under 960 ------- */ 91 | .ug-under-960.ug-videoskin-right-title-only .ug-thumb-wrapper 92 | { 93 | width:300px; 94 | } 95 | 96 | .ug-under-960.ug-videoskin-right-title-only .ug-thumb-title { 97 | width: 289px; 98 | height:18px; 99 | font-size:14px; 100 | line-height:normal; 101 | } 102 | 103 | 104 | .ug-under-960.ug-videoskin-right-title-only .ug-video-buttons-panel{ 105 | display:none; 106 | } 107 | 108 | /* ----- Under 780 ------- */ 109 | 110 | .ug-under-780.ug-videoskin-right-title-only .ug-thumb-wrapper 111 | { 112 | width:240px; 113 | } 114 | 115 | .ug-under-780.ug-videoskin-right-title-only .ug-thumb-icon 116 | { 117 | width:40px; 118 | } 119 | 120 | .ug-under-780.ug-videoskin-right-title-only .ug-thumb-title { 121 | width: 167px; 122 | height:18px; 123 | font-size:14px; 124 | } 125 | 126 | 127 | .ug-under-780.ug-videoskin-right-title-only .ug-video-buttons-panel{ 128 | display:none; 129 | } 130 | 131 | 132 | /* ----- Under 480 ------- */ 133 | 134 | .ug-under-480.ug-videoskin-right-title-only .ug-thumb-wrapper 135 | { 136 | width:0px; 137 | } 138 | 139 | .ug-under-480.ug-videoskin-right-title-only .ug-thumb-title { 140 | display:none; 141 | } 142 | 143 | 144 | .ug-under-480.ug-videoskin-right-title-only .ug-thumb-inner { 145 | padding-left: 8px; 146 | padding-right: 5px; 147 | padding-top: 12px; 148 | } 149 | 150 | .ug-under-480.ug-videoskin-right-title-only .ug-thumb-icon 151 | { 152 | width:40px; 153 | } 154 | 155 | .ug-under-480.ug-videoskin-right-title-only .ug-video-buttons-panel{ 156 | display:block; 157 | } 158 | -------------------------------------------------------------------------------- /.provision/terraform-aws-lutim/README.md: -------------------------------------------------------------------------------- 1 | # Terraform-AWS-Deploy 2 | 3 | This terraform plan create the resourcess of EC2 instance 4 | 5 | ## Terraform Variables 6 | Edit the `vars.tf` file to add the variables as per your need. 7 | 8 | | Variable name | Value | Description | 9 | | ------------- | ----- | ----------- | 10 | | `aws_region` | us-east-1 | Set the region | 11 | | `vpc_cidr` | 10.0.0.0/16 | Set the cidr value for the vpc | 12 | | `public_subnet_cidr` | 10.0.2.0/24 | Set the cidr value for the public subnet | 13 | | `user` | ubuntu | Set the EC2 instance user name | 14 | | `public_key` | /home/user_name/.ssh/id_rsa_pub | Set the publickey value for the ec2 instance from the host machine | 15 | | `private_key` | /home/user_name/.ssh/id_rsa | Set the private key value for the ec2 instance from the hostmachine | 16 | | `aws_access_key` | AWSACCESSKEY | Enter your aws access key | 17 | | `aws_secrete_key` | AWSSECRETEKEY | Enter your aws secrete key | 18 | | `instance_name` | lutim_app_instance | Set the name for instance | 19 | | `app_dir` | /var/www/lutim | Set the application directory for the best practice | 20 | | `lutim_owner` | www-data | Set the application user for the best practice | 21 | | `lutim_group` | www-data | Set the application group for the best practice | 22 | | `contact` | contact.example.com | Contact option (mandatory), where you have to put some way for the users to contact you. | 23 | | `contact_user` | name | Name of the user | 24 | | `secrets` | ffyg7kbkjba | Secrets option (mandotory), which is array of random string. Used by Mojolicious for encrypting session cookies | 25 | | `app_dir` | /var/www/lutim | Set the application directory for the best practice | 26 | | `lutim_owner` | www-data | Set the application user for the best practice | 27 | | `lutim_group` | www-data | Set the application group for the best practice | 28 | | `contact` | contact.example.com | Contact option (mandatory), where you have to put some way for the users to contact you. | 29 | | `contact_user` | name | Name of the user | 30 | | `secrets` | ffyg7kbkjba | Secrets option (mandotory), which is array of random string. Used by Mojolicious for encrypting session cookies | 31 | 32 | ## Usage of terraform plan with lufi deploy script 33 | 34 | ```sh 35 | git clone https://framagit.org/fiat-tux/hat-softwares/lutim.git 36 | 37 | cd lutim/.provision/terraform-aws-lutim 38 | 39 | terraform init 40 | terraform plan 41 | terraform apply 42 | ``` 43 | ## Usage of terraform plan with ansible role 44 | 45 | - Comment out the below `locals` and `user_data` source in __main.tf__ file 46 | 47 | ```hcl 48 | locals { 49 | user_data_vars = { 50 | user = var.lutim_owner 51 | group = var.lutim_group 52 | directory = var.app_dir 53 | contact_user = var.contact_user 54 | contact_lutim = var.contact 55 | secret_lutim = var.secret 56 | } 57 | } 58 | ``` 59 | 60 | ```hcl 61 | user_data = templatefile("${path.module}/lutim_startup.sh", local.user_data_vars) 62 | ``` 63 | 64 | - Add the below provisioner data in __main.tf__ file at the `aws_instance` resource 65 | 66 | ```sh 67 | connection { 68 | agent = false 69 | type = "ssh" 70 | host = aws_instance.ec2_instance.public_dns 71 | private_key = "${file(var.private_key)}" 72 | user = "${var.user}" 73 | } 74 | 75 | provisioner "remote-exec" { 76 | inline = [ 77 | "sudo apt update -y", 78 | "sudo apt install python3.9 -y", 79 | ] 80 | } 81 | 82 | provisioner "local-exec" { 83 | command = < hosts && \ 86 | echo "[Lutim]" | tee -a hosts && \ 87 | echo "${aws_instance.ec2_instance.public_ip} ansible_user=${var.user} ansible_ssh_private_key_file=${var.private_key}" | tee -a hosts && \ 88 | export ANSIBLE_HOST_KEY_CHECKING=False && \ 89 | ansible-playbook -u ${var.user} --private-key ${var.private_key} -i hosts site.yml 90 | EOT 91 | } 92 | ``` 93 | -------------------------------------------------------------------------------- /themes/default/templates/partial/navbar.html.ep: -------------------------------------------------------------------------------- 1 | % # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab: 2 | % my $lang = $self->languages; 3 | % $lang =~ s/-(.*)/_\U$1/; 4 | 76 | -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/video/skin-right-no-thumb.css: -------------------------------------------------------------------------------- 1 | @CHARSET "ISO-8859-1"; 2 | 3 | 4 | 5 | /* ----- Strip Panel ------- */ 6 | 7 | .ug-videoskin-right-no-thumb .ug-strip-panel{ 8 | background-color:#232323; 9 | } 10 | 11 | /* ----- Thumb Wrapper ------- */ 12 | 13 | .ug-videoskin-right-no-thumb .ug-thumb-wrapper{ 14 | background-color:#232323; 15 | border-bottom:1px solid #393939; 16 | width:380px; 17 | height:70px; 18 | cursor:pointer; 19 | text-align:left; 20 | } 21 | 22 | 23 | .ug-videoskin-right-no-thumb .ug-thumb-wrapper:last-child{ 24 | border-bottom:none; 25 | } 26 | 27 | /* - thumb selected and over - */ 28 | 29 | .ug-videoskin-right-no-thumb .ug-thumb-wrapper.ug-thumb-over{ 30 | cursor:pointer; 31 | background-color:#1A1A1A; 32 | } 33 | 34 | .ug-videoskin-right-no-thumb .ug-thumb-wrapper.ug-thumb-selected{ 35 | cursor:default; 36 | background-color:#176DB3; 37 | } 38 | 39 | /* ----- Thumb Inner data ------- */ 40 | 41 | .ug-videoskin-right-no-thumb .ug-thumb-inner{ 42 | padding-top:15px; 43 | padding-left:15px; 44 | padding-right:5px; 45 | } 46 | 47 | .ug-videoskin-right-no-thumb .ug-thumb-title{ 48 | color:white; 49 | font-size:14px; 50 | height:18px; 51 | overflow:hidden; 52 | line-height:normal; 53 | } 54 | 55 | .ug-videoskin-right-no-thumb .ug-thumb-desc{ 56 | color:#dddddd; 57 | font-size:11px; 58 | line-height:normal; 59 | } 60 | 61 | /* ----- Buttons Panel ------- */ 62 | 63 | .ug-videoskin-right-no-thumb .ug-video-buttons-panel{ 64 | height:42px; 65 | background-color:#000; 66 | position:absolute; 67 | display:none; 68 | } 69 | 70 | .ug-videoskin-right-no-thumb .ug-button-prev-video{ 71 | width:50%; 72 | height:42px; 73 | float:left; 74 | background-image:url('images/arrow_left.png'); 75 | cursor:pointer; 76 | background-repeat:no-repeat; 77 | background-position:center; 78 | box-sizing:border-box; 79 | border-right:1px solid #444; 80 | } 81 | 82 | .ug-videoskin-right-no-thumb .ug-button-prev-video:hover, .ug-videoskin-right-no-thumb .ug-button-next-video:hover 83 | { 84 | background-color:#444; 85 | } 86 | 87 | .ug-videoskin-right-no-thumb .ug-button-next-video{ 88 | width:50%; 89 | height:42px; 90 | float:right; 91 | background-image:url('images/arrow_right.png'); 92 | cursor:pointer; 93 | background-repeat:no-repeat; 94 | background-position:center; 95 | } 96 | 97 | 98 | /* ----- Under 960 ------- */ 99 | .ug-under-960.ug-videoskin-right-no-thumb .ug-thumb-wrapper 100 | { 101 | width:320px; 102 | } 103 | 104 | .ug-under-960.ug-videoskin-right-no-thumb .ug-thumb-title { 105 | width: 289px; 106 | height:18px; 107 | font-size:14px; 108 | } 109 | .ug-under-960.ug-videoskin-right-no-thumb .ug-thumb-desc 110 | { 111 | width:289px; 112 | padding-top:0px; 113 | } 114 | 115 | .ug-under-960.ug-videoskin-right-no-thumb .ug-video-buttons-panel{ 116 | display:none; 117 | } 118 | 119 | /* ----- Under 780 ------- */ 120 | 121 | .ug-under-780.ug-videoskin-right-no-thumb .ug-thumb-wrapper 122 | { 123 | width:240px; 124 | } 125 | 126 | .ug-under-780.ug-videoskin-right-no-thumb .ug-thumb-title { 127 | width: 167px; 128 | height:18px; 129 | font-size:14px; 130 | } 131 | 132 | .ug-under-780.ug-videoskin-right-no-thumb .ug-thumb-desc 133 | { 134 | width:167px; 135 | padding-top:0px; 136 | } 137 | 138 | .ug-under-780.ug-videoskin-right-no-thumb .ug-video-buttons-panel{ 139 | display:none; 140 | } 141 | 142 | 143 | /* ----- Under 480 ------- */ 144 | 145 | .ug-under-480.ug-videoskin-right-no-thumb .ug-thumb-wrapper 146 | { 147 | width:0px; 148 | } 149 | 150 | .ug-under-480.ug-videoskin-right-no-thumb .ug-thumb-title { 151 | display:none; 152 | } 153 | 154 | .ug-under-480.ug-videoskin-right-no-thumb .ug-thumb-desc 155 | { 156 | display:none; 157 | } 158 | 159 | .ug-under-480.ug-videoskin-right-no-thumb .ug-thumb-inner { 160 | padding-left: 8px; 161 | padding-right: 5px; 162 | padding-top: 12px; 163 | } 164 | 165 | 166 | .ug-under-480.ug-videoskin-right-no-thumb .ug-video-buttons-panel{ 167 | display:block; 168 | } 169 | 170 | -------------------------------------------------------------------------------- /themes/default/templates/layouts/default.html.ep: -------------------------------------------------------------------------------- 1 | % # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab: 2 | % use Mojo::Util qw(url_escape); 3 | % my $url = url_for('/')->to_abs(); 4 | % my $lang = $self->languages; 5 | % $lang =~ s/-(.*)/_\U$1/; 6 | 7 | 8 | 9 | Lutim 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | %= stylesheet '/css/common.min.css' 24 | % if (current_route 'stats') { 25 | %= stylesheet '/css/morris-0.5.1.min.css' 26 | % } else { 27 | %= stylesheet '/css/not_stats.min.css' 28 | % } 29 | % if (current_route 'gallery') { 30 | %= stylesheet '/css/gallery.min.css' 31 | % } 32 | 33 | 34 | %= include 'partial/navbar' 35 |
36 |
37 | % if (defined(config('hosted_by'))) { 38 |
39 | <%== config('hosted_by') %> 40 |
41 | % } 42 |
43 | 46 |

Let's Upload That Image!

47 |
48 |
49 | % if (defined(config('broadcast_message'))) { 50 |
51 | <%== config('broadcast_message') %> 52 |
53 | % } 54 | % if (defined(stash('stop_upload'))) { 55 |
56 | <%= stash('stop_upload') %> 57 |
58 | % } 59 | <%= content %> 60 |
61 | % if (defined(config('piwik_img'))) { 62 | 63 | % } 64 | %= javascript '/js/jquery-3.7.1.min.js' 65 | %= javascript '/partial/manifest.js' 66 | %= javascript '/js/toastify.js' 67 | %= javascript '/js/bootstrap.min.js' 68 | %= javascript '/partial/common.js' 69 | % if (current_route 'stats') { 70 | %= javascript '/js/lutim.js' 71 | %= javascript '/js/raphael-min.js' 72 | %= javascript '/js/morris-0.5.1.min.js' 73 | %= javascript '/js/stats.js' 74 | %= javascript '/partial/raw.js' 75 | % } elsif (!(current_route 'about')) { 76 | %= javascript '/js/lutim.js' 77 | %= javascript '/js/dmuploader.min.js' 78 | % } 79 | % if (current_route 'index') { 80 | %= javascript '/partial/lutim.js' 81 | % } 82 | % if (current_route 'gallery') { 83 | %= javascript '/js/photoswipe.min.js' 84 | %= javascript '/js/photoswipe-ui-default.min.js' 85 | %= javascript '/js/jszip.min.js' 86 | %= javascript '/js/FileSaver.min.js' 87 | %= javascript '/partial/gallery.js' 88 | %= javascript '/partial/lutim.js' 89 | % } 90 | % if (current_route 'myfiles') { 91 | %= javascript '/partial/myfiles.js' 92 | % } 93 | 94 | 95 | -------------------------------------------------------------------------------- /themes/default/public/js/dmuploader.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * dmuploader.js - Jquery File Uploader - 0.1 3 | * http://www.daniel.com.uy/projects/jquery-file-uploader/ 4 | * 5 | * Copyright (c) 2013 Daniel Morales 6 | * Dual licensed under the MIT and GPL licenses. 7 | * http://www.daniel.com.uy/doc/license/ 8 | */ 9 | (function(c){var b="dmUploader";var d={url:document.URL,method:"POST",extraData:{},maxFileSize:0,allowedTypes:"*",dataType:null,fileName:"file",onInit:function(){},onFallbackMode:function(){message},onNewFile:function(g,f){},onBeforeUpload:function(f){},onComplete:function(){},onUploadProgress:function(g,f){},onUploadSuccess:function(g,f){},onUploadError:function(g,f){},onFileTypeError:function(f){},onFileSizeError:function(f){}};var a=function(g,f){this.element=c(g);this.settings=c.extend({},d,f);if(!this.checkBrowser()){return false}this.init();return true};a.prototype.checkBrowser=function(){if(window.FormData===undefined){this.settings.onFallbackMode.call(this.element,"Browser doesn't support From API");return false}if(this.element.find("input[type=file]").length>0){return true}if(!this.checkEvent("drop",this.element)||!this.checkEvent("dragstart",this.element)){this.settings.onFallbackMode.call(this.element,"Browser doesn't support Ajax Drag and Drop");return false}return true};a.prototype.checkEvent=function(f,h){var h=h||document.createElement("div");var f="on"+f;var g=f in h;if(!g){if(!h.setAttribute){h=document.createElement("div")}if(h.setAttribute&&h.removeAttribute){h.setAttribute(f,"");g=typeof h[f]=="function";if(typeof h[f]!="undefined"){h[f]=undefined}h.removeAttribute(f)}}h=null;return g};a.prototype.init=function(){var f=this;f.queue=new Array();f.queuePos=-1;f.queueRunning=false;f.element.on("drop",function(g){g.preventDefault();var h=g.originalEvent.dataTransfer.files;f.queueFiles(h)});f.element.find("input[type=file]").on("change",function(g){var h=g.target.files;f.queueFiles(h);c(this).val("")});this.settings.onInit.call(this.element)};a.prototype.queueFiles=function(l){var g=this.queue.length;for(var k=0;k0)&&(h.size>this.settings.maxFileSize)){this.settings.onFileSizeError.call(this.element,h);continue}if((this.settings.allowedTypes!="*")&&!h.type.match(this.settings.allowedTypes)){this.settings.onFileTypeError.call(this.element,h);continue}this.queue.push(h);var f=this.queue.length-1;this.settings.onNewFile.call(this.element,f,h)}if(this.queueRunning){return false}if(this.queue.length==g){return false}this.processQueue();return true};a.prototype.processQueue=function(){var h=this;h.queuePos++;if(h.queuePos>=h.queue.length){h.settings.onComplete.call(h.element);h.queuePos=(h.queue.length-1);h.queueRunning=false;return}var g=h.queue[h.queuePos];var f=new FormData();f.append(h.settings.fileName,g); 10 | // c.each(h.settings.extraData,function(i,j){f.append(i,j)}); 11 | f.append('format', 'json'); 12 | f.append('first-view', ($("#first-view").prop('checked')) ? 1 : 0); 13 | f.append('delete-day', ($("#delete-day").val())); 14 | f.append('watermark', ($("#watermark").val())); 15 | f.append('crypt', ($("#crypt").prop('checked')) ? 1 : 0); 16 | f.append('keep-exif', ($("#keep-exif").prop('checked')) ? 1 : 0); 17 | h.settings.onBeforeUpload.call(h.element,h.queuePos);h.queueRunning=true;c.ajax({url:h.settings.url,type:h.settings.method,dataType:h.settings.dataType,data:f,cache:false,contentType:false,processData:false,forceSync:false,xhr:function(){var i=c.ajaxSettings.xhr();if(i.upload){i.upload.addEventListener("progress",function(m){var l=0;var j=m.loaded||m.position;var k=m.total||e.totalSize;if(m.lengthComputable){l=Math.ceil(j/k*100)}h.settings.onUploadProgress.call(h.element,h.queuePos,l)},false)}return i},success:function(j,i,k){h.settings.onUploadSuccess.call(h.element,h.queuePos,j)},error:function(k,i,j){h.settings.onUploadError.call(h.element,h.queuePos,j)},complete:function(i,j){h.processQueue()}})};c.fn.dmUploader=function(f){return this.each(function(){if(!c.data(this,b)){c.data(this,b,new a(this,f))}})};c(document).on("dragenter",function(f){f.stopPropagation();f.preventDefault()});c(document).on("dragover",function(f){f.stopPropagation();f.preventDefault()});c(document).on("drop",function(f){f.stopPropagation();f.preventDefault()})})(jQuery); 18 | -------------------------------------------------------------------------------- /lib/Lutim/Command/theme.pm: -------------------------------------------------------------------------------- 1 | # vim:set sw=4 ts=4 sts=4 ft=perl expandtab: 2 | package Lutim::Command::theme; 3 | use Mojo::Base 'Mojolicious::Commands'; 4 | use FindBin qw($Bin); 5 | use File::Spec qw(catfile cat dir); 6 | use File::Path qw(make_path); 7 | 8 | has description => 'Create new theme skeleton.'; 9 | has usage => sub { shift->extract_usage }; 10 | has message => sub { shift->extract_usage . "\nCreate new theme skeleton:\n" }; 11 | has namespaces => sub { ['Lutim::Command::theme'] }; 12 | 13 | sub run { 14 | my $c = shift; 15 | my $name = shift; 16 | 17 | unless (defined $name) { 18 | say $c->extract_usage; 19 | exit 1; 20 | } 21 | 22 | my $home = File::Spec->catdir($Bin, '..', 'themes', $name); 23 | 24 | unless (-d $home) { 25 | 26 | # Create skeleton 27 | mkdir $home; 28 | mkdir File::Spec->catdir($home, 'public'); 29 | make_path(File::Spec->catdir($home, 'templates', 'layouts')); 30 | make_path(File::Spec->catdir($home, 'lib', 'Lutim', 'I18N')); 31 | 32 | my $i18n = < 1, 40 | _decode => 1, 41 | _style => 'gettext', 42 | '*' => [ 43 | Gettext => dirname(__FILE__) . '/I18N/*.po', 44 | Gettext => \$app_dir . 'themes/default/lib/Lutim/I18N/*.po', 45 | ] 46 | }; 47 | 48 | use vars qw(\$app_dir); 49 | BEGIN { 50 | use Cwd; 51 | my \$app_dir = getcwd; 52 | } 53 | 54 | 1; 55 | EOF 56 | 57 | open my $f, '>', File::Spec->catfile($home, 'lib', 'Lutim', 'I18N.pm') or die "Unable to open $home/lib/Lutim/I18N.pm: $!"; 58 | print $f $i18n; 59 | close $f; 60 | 61 | my $makefile = </dev/null 80 | \$(XGETTEXT) -D templates -D ../default/templates -o \$(FR) 2>/dev/null 81 | \$(XGETTEXT) -D templates -D ../default/templates -o \$(DE) 2>/dev/null 82 | \$(XGETTEXT) -D templates -D ../default/templates -o \$(ES) 2>/dev/null 83 | \$(XGETTEXT) -D templates -D ../default/templates -o \$(OC) 2>/dev/null 84 | \$(XGETTEXT) -D templates -D ../default/templates -o \$(AR) 2>/dev/null 85 | sed \$(SEDOPTS) -i \$(EN) 86 | sed \$(SEDOPTS2) -i \$(EN) 87 | sed \$(SEDOPTS) -i \$(FR) 88 | sed \$(SEDOPTS2) -i \$(FR) 89 | sed \$(SEDOPTS) -i \$(DE) 90 | sed \$(SEDOPTS2) -i \$(DE) 91 | sed \$(SEDOPTS) -i \$(ES) 92 | sed \$(SEDOPTS2) -i \$(ES) 93 | sed \$(SEDOPTS) -i \$(OC) 94 | sed \$(SEDOPTS) -i \$(OC) 95 | sed \$(SEDOPTS2) -i \$(AR) 96 | sed \$(SEDOPTS2) -i \$(AR) 97 | EOF 98 | 99 | open $f, '>', File::Spec->catfile($home, 'Makefile') or die "Unable to open $home/Makefile: $!"; 100 | print $f $makefile; 101 | close $f; 102 | open $f, '>', File::Spec->catfile($home, '.gitignore') or die "Unable to open $home/.gitignore: $!"; 103 | print $f "public/packed/\ntemplates/data.html.ep"; 104 | close $f; 105 | } else { 106 | say "$name theme already exists. Aborting."; 107 | exit 1; 108 | } 109 | } 110 | 111 | =encoding utf8 112 | 113 | =head1 NAME 114 | 115 | Lutim::Command::theme - Create new theme skeleton. 116 | 117 | =head1 SYNOPSIS 118 | 119 | Usage: script/lutim theme THEME_NAME 120 | 121 | Your new theme will be available in the themes directory. 122 | =cut 123 | 124 | 1; 125 | -------------------------------------------------------------------------------- /themes/korrigan/public/css/korrigan.css: -------------------------------------------------------------------------------- 1 | 2 | /* Yeched'mad CSS */ 3 | :root { 4 | --theme-blue: #0060DF; 5 | --theme-blue-hover: #45A1FF; 6 | } 7 | 8 | body { 9 | position: relative; 10 | background-color: #EEEEEE; 11 | 12 | background-size: cover; 13 | 14 | min-height: 100vh; 15 | display: flex; 16 | flex-direction: column; 17 | } 18 | 19 | body::before, 20 | body::after { 21 | content: ""; 22 | position: absolute; 23 | top: 0; 24 | left: 0; 25 | bottom: 0; 26 | right: 0; 27 | z-index: -1; 28 | } 29 | 30 | body::before { 31 | background-size: cover; 32 | background-image: url("../img/background.svg"); 33 | } 34 | 35 | body::after { 36 | background: linear-gradient(to bottom, rgba(255, 255, 255, 0.75) 4em, transparent 4em); 37 | } 38 | 39 | body .navbar-default { 40 | background-color: transparent; 41 | border-color: transparent; 42 | } 43 | 44 | body .navbar-default .open > a, 45 | body .navbar-default .open > a:focus, 46 | body .navbar-default .open > a:hover, 47 | body .navbar-default .open > a:active { 48 | background-color: rgba(11, 103, 183, 0.5); 49 | } 50 | 51 | body > .container { 52 | flex-grow: 1; 53 | background-color: #FFFFFF; 54 | padding: 3em; 55 | border-radius: 5px; 56 | box-shadow: 1px 1px 5px #333333; 57 | display: flex; 58 | justify-content: space-between; 59 | font-size: 1.15em; 60 | 61 | /* SVG coming from https://upload.wikimedia.org/wikipedia/commons/0/07/Triskele-Symbol-spiral-five-thirds-turns.svg */ 62 | background-image: url('../img/triskel.svg'); 63 | background-size: 500px; 64 | background-repeat: no-repeat; 65 | background-position: -125px calc(100% + 150px); 66 | } 67 | 68 | body > .container .upload-info { 69 | width: 100%; 70 | } 71 | 72 | body > .container::before, 73 | body > .container::after { 74 | display: none; 75 | } 76 | 77 | body.index > .container > * { 78 | background-color: rgba(255, 255, 255, 0.8); 79 | width: calc(50% - 2em); 80 | border-bottom-left-radius: inherit; 81 | border-bottom-right-radius: inherit; 82 | } 83 | 84 | body .logo { 85 | display: none; 86 | } 87 | 88 | body .header { 89 | margin-bottom: 2em; 90 | } 91 | 92 | body .hennypenny { 93 | color: var(--theme-blue); 94 | margin-top: 0; 95 | font-family: sans-serif; 96 | } 97 | 98 | body label { 99 | font-weight: normal; 100 | display: block; 101 | margin: 1em 0; 102 | } 103 | 104 | body input[type='checkbox'] { 105 | -moz-appearance: none; 106 | -webkit-appearance: none; 107 | appearance: none; 108 | 109 | position: static; 110 | margin: 0; 111 | cursor: pointer; 112 | vertical-align: middle; 113 | display: inline-flex; 114 | justify-content: flex-start; 115 | align-items: center; 116 | 117 | background-color: #555555; 118 | width: 3rem; 119 | height: 1.5rem; 120 | margin-top: 0.25em; 121 | margin-bottom: 0.25em; 122 | border: none; 123 | border-radius: 1em; 124 | } 125 | 126 | body input[type='checkbox']:checked { 127 | color: #FFFFFF; 128 | background-color: var(--theme-blue); 129 | justify-content: flex-end; 130 | } 131 | 132 | body input[type='checkbox']::after { 133 | content: ''; 134 | margin: 0 0.15rem; 135 | width: 1.2rem; 136 | height: 1.2rem; 137 | border-radius: 50%; 138 | background-color: white; 139 | } 140 | 141 | body .uploader-container { 142 | display: flex; 143 | flex-direction: column; 144 | } 145 | 146 | body .uploader { 147 | display: flex; 148 | flex-direction: column; 149 | justify-content: center; 150 | flex-grow: 1; 151 | border: 2px dashed #DDDDDD; 152 | border-radius: 5px; 153 | color: #6F7986; 154 | } 155 | 156 | body .uploader:hover { 157 | background-color: #FDFEFF; 158 | } 159 | 160 | body .uploader div.browser label { 161 | background-color: var(--theme-blue); 162 | } 163 | 164 | body .uploader-container form .label { 165 | display: block; 166 | } 167 | 168 | body .btn { 169 | background-color: var(--theme-blue); 170 | color: white; 171 | padding: 0.5em; 172 | } 173 | 174 | body .btn:hover, 175 | body .btn:focus, 176 | body .btn:active { 177 | background-color: var(--theme-blue-hover); 178 | } 179 | -------------------------------------------------------------------------------- /themes/korrigan/templates/layouts/default.html.ep: -------------------------------------------------------------------------------- 1 | % # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab: 2 | % use Mojo::Util qw(url_escape); 3 | % my $url = url_for('/')->to_abs(); 4 | 5 | 6 | 7 | Lutim 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | %= stylesheet '/css/common.min.css' 22 | % if (current_route 'stats') { 23 | %= stylesheet '/css/morris-0.5.1.min.css' 24 | % } else { 25 | %= stylesheet '/css/not_stats.min.css' 26 | % } 27 | % if (current_route 'gallery') { 28 | %= stylesheet '/css/gallery.min.css' 29 | % } 30 | %= stylesheet '/css/korrigan.css' 31 | 32 | 33 | %= include 'partial/navbar' 34 |
35 |
36 |
37 | % if (defined(config('hosted_by'))) { 38 |
39 | <%== config('hosted_by') %> 40 |
41 | % } 42 |
43 | 46 |

Let's Upload That Image!

47 |
48 |
49 | % if (defined(config('broadcast_message'))) { 50 |
51 | <%== config('broadcast_message') %> 52 |
53 | % } 54 | % if (defined(stash('stop_upload'))) { 55 |
56 | <%= stash('stop_upload') %> 57 |
58 | % } 59 | <%= content %> 60 |
61 | % if (defined(config('piwik_img'))) { 62 | 63 | % } 64 | %= javascript '/js/jquery-3.7.1.min.js' 65 | %= javascript '/partial/manifest.js' 66 | %= javascript '/js/toastify.js' 67 | %= javascript '/js/bootstrap.min.js' 68 | %= javascript '/partial/common.js' 69 | % if (current_route 'stats') { 70 | %= javascript '/js/lutim.js' 71 | %= javascript '/js/raphael-min.js' 72 | %= javascript '/js/morris-0.5.1.min.js' 73 | %= javascript '/js/stats.js' 74 | %= javascript '/partial/raw.js' 75 | % } elsif (!(current_route 'about')) { 76 | %= javascript '/js/lutim.js' 77 | %= javascript '/js/dmuploader.min.js' 78 | % } 79 | % if (current_route 'index') { 80 | %= javascript '/partial/lutim.js' 81 | %= javascript '/partial/korrigan.js' 82 | % } 83 | % if (current_route 'gallery') { 84 | %= javascript '/js/photoswipe.min.js' 85 | %= javascript '/js/photoswipe-ui-default.min.js' 86 | %= javascript '/js/jszip.min.js' 87 | %= javascript '/js/FileSaver.min.js' 88 | %= javascript '/partial/gallery.js' 89 | %= javascript '/partial/lutim.js' 90 | %= javascript '/partial/korrigan.js' 91 | % } 92 | % if (current_route 'myfiles') { 93 | %= javascript '/partial/myfiles.js' 94 | % } 95 | 96 | 97 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: hatsoftwares/lutim-test-ci:latest 2 | stages: 3 | - create_release 4 | - pouet_it 5 | - podcheck 6 | - carton 7 | - carton_bdd 8 | - tests 9 | - cover 10 | before_script: 11 | - rm -f *.db 12 | variables: 13 | POSTGRES_DB: lutim_db 14 | POSTGRES_USER: lutim 15 | POSTGRES_PASSWORD: lutim_pwd 16 | 17 | ### Jobs templates 18 | ## 19 | # 20 | .retry: &retry 21 | retry: 2 22 | except: 23 | - tags 24 | 25 | .carton_bdd_template: &carton_bdd_definition 26 | <<: *retry 27 | stage: carton_bdd 28 | artifacts: 29 | paths: 30 | - local/ 31 | needs: 32 | - carton 33 | 34 | .test_template: &test_definition 35 | <<: *retry 36 | stage: tests 37 | script: 38 | - MOJO_CONFIG=t/$CI_JOB_NAME.conf make test 39 | - MOJO_CONFIG=t/$CI_JOB_NAME.conf make watch 40 | - MOJO_CONFIG=t/$CI_JOB_NAME.conf make cleanbdd 41 | - MOJO_CONFIG=t/$CI_JOB_NAME.conf make cleanfiles 42 | - MOJO_CONFIG=t/$CI_JOB_NAME.conf make stats 43 | - MOJO_CONFIG=t/$CI_JOB_NAME.conf make test-junit-output 44 | artifacts: 45 | paths: 46 | - tap.xml 47 | - cover_db/ 48 | 49 | .sqlite_template: &sqlite_definition 50 | <<: *test_definition 51 | needs: 52 | - carton_sqlite 53 | 54 | .pg_template: &pg_definition 55 | <<: *test_definition 56 | needs: 57 | - carton_postgresql 58 | services: 59 | - name: postgres:9.6 60 | alias: postgres 61 | 62 | ### Publish tag changelog and create a toot 63 | ## 64 | # 65 | include: 66 | - 'https://framagit.org/fiat-tux/gitlabci-snippets/-/raw/2aac6c1f3dd725d9aed57549da67a92759f9f9ec/create-release-from-ci.gitlab-ci.yml' 67 | - 'https://framagit.org/fiat-tux/gitlabci-snippets/-/raw/41345a919d3c927991782f5fd17e0c7b338a3f3a/pouet-it-from-ci.gitlab-ci.yml' 68 | 69 | ### Podcheck 70 | ## 71 | # 72 | podcheck: 73 | <<: *retry 74 | stage: podcheck 75 | script: 76 | - make podcheck 77 | 78 | ### Install common dependencies 79 | ## 80 | # 81 | carton: 82 | <<: *retry 83 | stage: carton 84 | artifacts: 85 | paths: 86 | - local/ 87 | dependencies: [] 88 | script: 89 | - cpanm -l local Devel::Cover~1.29 90 | - carton install --deployment --without=sqlite --without=postgresql --without=minion --without=cache --without=memcached 91 | when: always 92 | 93 | ### Install DB related dependencies 94 | ## 95 | # 96 | carton_sqlite: 97 | <<: *carton_bdd_definition 98 | script: 99 | - carton install --deployment --without=postgresql --without=minion --without=cache --without=memcached 100 | carton_postgresql: 101 | <<: *carton_bdd_definition 102 | script: 103 | - carton install --deployment --without=sqlite --without=minion --without=cache --without=memcached 104 | 105 | ### SQLite tests 106 | ## 107 | # 108 | sqlite1: 109 | <<: *sqlite_definition 110 | before_script: 111 | - carton install --deployment --without=postgresql --without=minion --without=cache --without=memcached 112 | sqlite2: 113 | <<: *sqlite_definition 114 | before_script: 115 | - carton install --deployment --without=postgresql --without=cache --without=memcached 116 | sqlite3: 117 | <<: *sqlite_definition 118 | services: 119 | - name: postgres:9.6 120 | alias: postgres 121 | before_script: 122 | - carton install --deployment --without=cache --without=memcached 123 | - export PGPASSWORD=lutim_pwd; echo 'CREATE DATABASE lutim_minion WITH OWNER lutim;' | psql -h postgres -U lutim lutim_db 124 | 125 | ### PostgreSQL tests 126 | ## 127 | # 128 | postgresql1: 129 | <<: *pg_definition 130 | before_script: 131 | - carton install --deployment --without=sqlite --without=minion --without=cache --without=memcached 132 | postgresql2: 133 | <<: *pg_definition 134 | before_script: 135 | - carton install --deployment --without=cache --without=memcached 136 | postgresql3: 137 | <<: *pg_definition 138 | before_script: 139 | - carton install --deployment --without=sqlite --without=cache --without=memcached 140 | - export PGPASSWORD=lutim_pwd; echo 'CREATE DATABASE lutim_minion WITH OWNER lutim;' | psql -h postgres -U lutim lutim_db 141 | 142 | ### Code coverage 143 | ## 144 | # 145 | cover: 146 | stage: cover 147 | script: 148 | - make cover 149 | coverage: '/Total.* (\d+\.\d+)$/' 150 | artifacts: 151 | reports: 152 | junit: tap.xml 153 | except: 154 | - tags 155 | -------------------------------------------------------------------------------- /themes/default/public/gallery/themes/default/ug-theme-default.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | .ug-gallery-wrapper .ug-theme-panel{ 4 | position:absolute; 5 | xbackground-color:red; 6 | z-index:11; 7 | } 8 | 9 | .ug-theme-panel .ug-strip-panel{ 10 | z-index:6; 11 | } 12 | 13 | /* --- fullscreen button -- */ 14 | 15 | .ug-theme-default .ug-default-button-fullscreen{ 16 | position:absolute; 17 | background-image:url('../../gallery/themes/default/images/button_fullscreen.png'); 18 | width:53px; 19 | height:50px; 20 | cursor:pointer; 21 | background-position:0px 0px; 22 | z-index:3; 23 | } 24 | 25 | .ug-theme-default .ug-default-button-fullscreen.ug-button-hover{ 26 | background-position:0px -50px; 27 | } 28 | 29 | .ug-theme-default .ug-default-button-fullscreen.ug-fullscreenmode{ 30 | background-position:0px -100px; 31 | } 32 | 33 | .ug-theme-default .ug-default-button-fullscreen.ug-fullscreenmode.ug-button-hover{ 34 | background-position:0px -150px; 35 | } 36 | 37 | 38 | /* --- fullscreen button single mode-- */ 39 | 40 | .ug-theme-default .ug-default-button-fullscreen-single{ 41 | position:absolute; 42 | background-image:url('../../gallery/themes/default/images/button_fullscreen_single.png'); 43 | width:52px; 44 | height:50px; 45 | cursor:pointer; 46 | background-position:0px 0px; 47 | z-index:3; 48 | } 49 | 50 | .ug-theme-default .ug-default-button-fullscreen-single.ug-button-hover{ 51 | background-position:0px -50px; 52 | } 53 | 54 | .ug-theme-default .ug-default-button-fullscreen-single.ug-fullscreenmode{ 55 | background-position:0px -100px; 56 | } 57 | 58 | .ug-theme-default .ug-default-button-fullscreen-single.ug-fullscreenmode.ug-button-hover{ 59 | background-position:0px -150px; 60 | } 61 | 62 | 63 | /* --- play button -- */ 64 | 65 | .ug-theme-default .ug-default-button-play{ 66 | position:absolute; 67 | background-image:url('../../gallery/themes/default/images/button_playpause.png'); 68 | width:51px; 69 | height:50px; 70 | cursor:pointer; 71 | background-position:0px 0px; 72 | z-index:4; 73 | } 74 | 75 | .ug-theme-default .ug-default-button-play.ug-button-hover{ 76 | background-position:0px -50px; 77 | } 78 | 79 | .ug-theme-default .ug-default-button-play.ug-stop-mode{ 80 | background-position:0px -100px; 81 | } 82 | 83 | .ug-theme-default .ug-default-button-play.ug-stop-mode.ug-button-hover{ 84 | background-position:0px -150px; 85 | } 86 | 87 | /* --- play button single mode-- */ 88 | 89 | .ug-theme-default .ug-default-button-play-single{ 90 | position:absolute; 91 | background-image:url('../../gallery/themes/default/images/button_playpause_single.png'); 92 | width:50px; 93 | height:50px; 94 | cursor:pointer; 95 | background-position:0px 0px; 96 | z-index:4; 97 | } 98 | 99 | .ug-theme-default .ug-default-button-play-single.ug-button-hover{ 100 | background-position:0px -50px; 101 | } 102 | 103 | .ug-theme-default .ug-default-button-play-single.ug-stop-mode{ 104 | background-position:0px -100px; 105 | } 106 | 107 | .ug-theme-default .ug-default-button-play-single.ug-stop-mode.ug-button-hover{ 108 | background-position:0px -150px; 109 | } 110 | 111 | 112 | /* --- hide panel button -- */ 113 | 114 | .ug-default-button-hidepanel{ 115 | position:absolute; 116 | width:23px; 117 | height:23px; 118 | z-index:5; 119 | cursor:pointer; 120 | } 121 | 122 | .ug-default-button-hidepanel .ug-default-button-hidepanel-bg{ 123 | background-color:#000000; 124 | width:23px; 125 | height:23px; 126 | position:absolute; 127 | top:0px; 128 | left:0px; 129 | opacity:0.4; 130 | filter: alpha(opacity = 40); 131 | z-index:1; 132 | } 133 | 134 | .ug-default-button-hidepanel .ug-default-button-hidepanel-tip{ 135 | position:absolute; 136 | width:7px; 137 | height:7px; 138 | background-repeat:no-repeat; 139 | background-image:url('../../gallery/themes/default/images/arrow_down_up.png'); 140 | background-position: 0px 0px; 141 | z-index:2; 142 | } 143 | 144 | .ug-default-button-hidepanel.ug-button-hover .ug-default-button-hidepanel-tip{ 145 | background-position: 0px -7px; 146 | } 147 | 148 | .ug-default-button-hidepanel.ug-button-hidden-mode .ug-default-button-hidepanel-tip{ 149 | background-position: 0px -14px; 150 | } 151 | 152 | .ug-default-button-hidepanel.ug-button-hidden-mode.ug-button-hover .ug-default-button-hidepanel-tip{ 153 | background-position: 0px -21px; 154 | } 155 | 156 | -------------------------------------------------------------------------------- /themes/default/public/js/lutim.js: -------------------------------------------------------------------------------- 1 | function addItem(item) { 2 | var files = localStorage.getItem('images'); 3 | if (files === null) { 4 | files = new Array(); 5 | } else { 6 | files = JSON.parse(files); 7 | } 8 | delete item['thumb']; 9 | files.push(item); 10 | localStorage.setItem('images', JSON.stringify(files)); 11 | } 12 | function delItem(short) { 13 | var files = localStorage.getItem('images'); 14 | if (files === null) { 15 | files = new Array(); 16 | } else { 17 | files = JSON.parse(files); 18 | } 19 | $(files).each(function(index) { 20 | if (files[index].real_short === short) { 21 | files.splice(index, 1); 22 | return false; 23 | } 24 | }); 25 | localStorage.setItem('images', JSON.stringify(files)); 26 | } 27 | function updateItem(short, limit, del_at_view) { 28 | var files = localStorage.getItem('images'); 29 | if (files === null) { 30 | files = new Array(); 31 | } else { 32 | files = JSON.parse(files); 33 | } 34 | $(files).each(function(index) { 35 | if (files[index].real_short === short) { 36 | files[index].del_at_view = del_at_view;; 37 | files[index].limit = limit; 38 | return false; 39 | } 40 | }); 41 | localStorage.setItem('images', JSON.stringify(files)); 42 | } 43 | function evaluateCopyAll(e) { 44 | if (e) { 45 | e.preventDefault(); 46 | } 47 | setTimeout(function() { 48 | if ($('.view-link-input').length === 0) { 49 | $('#copy-all').parent().remove(); 50 | } 51 | }, 5); 52 | } 53 | window.onload = function() { 54 | if (navigator.mozSetMessageHandler !== undefined) { 55 | navigator.mozSetMessageHandler('activity', function handler(activityRequest) { 56 | var activityName = activityRequest.source.name; 57 | if (activityName == 'share') { 58 | activity = activityRequest; 59 | blob = activity.source.data.blobs[0]; 60 | fileUpload(blob); 61 | } 62 | }); 63 | } 64 | }; 65 | $('document').ready(function() { 66 | $('.jsonly').show(); 67 | $('.input-group-addon.jsonly').css('display', 'table-cell'); 68 | // Are we in a mozilla navigator? (well, are we in a navigator which can handle webapps?) 69 | if (navigator.mozApps !== undefined) { 70 | var installCheck = navigator.mozApps.checkInstalled(manifestUrl); 71 | installCheck.onsuccess = function() { 72 | if(installCheck.result === null) { 73 | var button = $('#install-app'); 74 | // Show app install button when app is not installed 75 | button.css('display','inline-block'); 76 | button.click(function() { 77 | var request = window.navigator.mozApps.install(manifestUrl); 78 | request.onsuccess = function () { 79 | // Save the App object that is returned 80 | var appRecord = this.result; 81 | button.css('display','none'); 82 | }; 83 | request.onerror = function () { 84 | // Display the error information from the DOMError object 85 | alert('Install failed, error: ' + this.error.name); 86 | }; 87 | }); 88 | } 89 | } 90 | } 91 | if ($('#first-view').length !== 0) { 92 | var firstview = ($('#first-view').prop('checked')) ? 1 : 0; 93 | var deleteday = ($('#delete-day').prop('checked')) ? 1 : 0; 94 | 95 | bindddz(firstview, deleteday); 96 | initPaste(); 97 | 98 | $('#file-url-button').on('click', upload_url); 99 | $('#lutim-file-url').keydown( function(e) { 100 | var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0; 101 | if(key == 13) { 102 | e.preventDefault(); 103 | upload_url(); 104 | } 105 | }); 106 | } else if ($('#myfiles').length !== 0) { 107 | populateFilesTable(); 108 | $('#json-export').on('click', function() { exportStorage(); }); 109 | $('#json-import').on('click', function() { $('#import').click(); }); 110 | $('#import').on('change', function() { importStorage(this.files); }) 111 | $('#mod-delay').on('click', modifyDelay); 112 | $('#check-all').on('click', checkAll) 113 | $('#mass-delete').on('click', massDelete); 114 | } 115 | $('.copy-to-clipboard-link').on('click', clickOnCopyLink); 116 | $('.copy-all-to-clipboard-link').on('click', copyAllToClipboard); 117 | }); 118 | -------------------------------------------------------------------------------- /themes/default/templates/about.html.ep: -------------------------------------------------------------------------------- 1 | % # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab: 2 |
3 |

<%= l('What is Lutim?')%>

4 |

<%= l('Lutim is a free (as in free beer) and anonymous image hosting service. It\'s also the name of the free (as in free speech) software which provides this service.') %>

5 |

<%= l('The images you post on Lutim can be stored indefinitely or be deleted at first view or after a delay selected from those proposed.') %>

6 |

<%= l('How does it work?') %>

7 |

<%= l('Drag and drop an image in the appropriate area or use the traditional way to send files and Lutim will provide you four URLs. One to view the image, an other to directly download it, one you can use on social networks and a last to delete the image when you want.') %>

8 |

<%= l('You can, optionally, request that the image(s) posted on Lutim to be deleted at first view (or download) or after the delay selected from those proposed.') %>

9 |

<%= l('Is it really free (as in free beer)?') %>

10 |

<%== l('Yes, it is! On the other side, if you want to support the developer, you can do it via Tipeee or via Liberapay.') %>

11 |

<%= l('Is it really anonymous?') %>

12 |

<%= l('Yes, it is! On the other side, for legal reasons, your IP address will be stored when you send an image. Don\'t panic, it is normally the case of all sites on which you send files!') %>

13 |

<%= l('The IP address of the image\'s sender is retained for a delay which depends of the administrator\'s choice (for the official instance, which is located in France, it\'s one year).') %>

14 |

<%= l('If the files are deleted if you ask it while posting it, their SHA512 footprint are retained.') %>

15 |

<%= l('Who owns rights on images uploaded on Lutim?') %>

16 |

<%= l('Only the uploader! (well, only if he\'s the only owner of the images\' rights before the upload)') %>

17 |

<%= l('Unlike many image sharing services, you don\'t give us rights on uploaded images.') %>

18 |

<%= l('How to report an image?') %>

19 |

<%= l('Please contact the administrator: %1', config('contact')) %>

20 |

<%= l('How do you pronounce Lutim?') %>

21 |

<%== l('The way you pronounce the French word lutin (/ly.tɛ̃/).', 'https://fr.wikipedia.org/wiki/Lutin') %>

22 |

<%= l('What about the software which provides the service?') %>

23 |

<%== l('The Lutim software is a free software, which allows you to download and install it on you own server. Have a look at the AGPL to see what you can do.') %>

24 |

<%== l('For more details, see the homepage of the project.') %>

25 |

<%= l('Main developers') %>

26 | 30 |

<%= l('Contributors') %>

31 | 43 | 44 | <%= link_to url_for('/') => ( class => "btn btn-primary btn-lg" ) => begin %><%= l('Back to homepage') %><% end%> 45 |
46 | -------------------------------------------------------------------------------- /utilities/Shutter.pm: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env perl 2 | ################################################### 3 | # 4 | # Copyright (C) 2010-2011 Vadim Rutkovsky , Mario Kemper and Shutter Team 5 | # 6 | # This file is part of Shutter. 7 | # 8 | # Shutter is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Shutter is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Shutter; if not, write to the Free Software 20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 | # 22 | ################################################### 23 | 24 | package Lutim; 25 | 26 | use lib $ENV{'SHUTTER_ROOT'}.'/share/shutter/resources/modules'; 27 | 28 | use utf8; 29 | use strict; 30 | use POSIX qw/setlocale/; 31 | use Locale::gettext; 32 | use Glib qw/TRUE FALSE/; 33 | 34 | use Shutter::Upload::Shared; 35 | our @ISA = qw(Shutter::Upload::Shared); 36 | 37 | my $d = Locale::gettext->domain("shutter-upload-plugins"); 38 | $d->dir( $ENV{'SHUTTER_INTL'} ); 39 | 40 | my %upload_plugin_info = ( 41 | 'module' => "Lutim", 42 | 'url' => "https://lutim.fiat-tux.fr/", 43 | 'registration' => "-", 44 | 'name' => "Lutim", 45 | 'description' => "Upload screenshots to Lutim", 46 | 'supports_anonymous_upload' => TRUE, 47 | 'supports_authorized_upload' => FALSE, 48 | 'supports_oauth_upload' => FALSE, 49 | ); 50 | 51 | binmode( STDOUT, ":utf8" ); 52 | if ( exists $upload_plugin_info{$ARGV[ 0 ]} ) { 53 | print $upload_plugin_info{$ARGV[ 0 ]}; 54 | exit; 55 | } 56 | 57 | 58 | #don't touch this 59 | sub new { 60 | my $class = shift; 61 | 62 | #call constructor of super class (host, debug_cparam, shutter_root, gettext_object, main_gtk_window, ua) 63 | my $self = $class->SUPER::new( shift, shift, shift, shift, shift, shift ); 64 | 65 | bless $self, $class; 66 | return $self; 67 | } 68 | 69 | #load some custom modules here (or do other custom stuff) 70 | sub init { 71 | my $self = shift; 72 | 73 | use JSON; 74 | use LWP::UserAgent; 75 | use HTTP::Request::Common; 76 | 77 | return TRUE; 78 | } 79 | 80 | #handle 81 | sub upload { 82 | my ( $self, $upload_filename, $username, $password ) = @_; 83 | 84 | #store as object vars 85 | $self->{_filename} = $upload_filename; 86 | $self->{_username} = $username; 87 | $self->{_password} = $password; 88 | 89 | utf8::encode $upload_filename; 90 | utf8::encode $password; 91 | utf8::encode $username; 92 | 93 | my $json = JSON->new(); 94 | 95 | my $browser = LWP::UserAgent->new( 96 | 'timeout' => 20, 97 | 'keep_alive' => 10, 98 | 'env_proxy' => 1, 99 | ); 100 | 101 | 102 | #upload the file 103 | eval{ 104 | 105 | my $url = 'https://lutim.fiat-tux.fr/'; 106 | my $request = HTTP::Request::Common::POST( 107 | $url, 108 | Content_Type => 'multipart/form-data', 109 | Content => [ 110 | file => [$upload_filename], 111 | format => 'json' 112 | ] 113 | ); 114 | 115 | my $response = $browser->request($request); 116 | 117 | if ($response->is_success) { 118 | my $hash = $json->decode($response->decoded_content); 119 | 120 | if ($hash->{success}) { 121 | my $link = $url.$hash->{msg}->{short}; 122 | $self->{_links}->{'view_image'} = $link; 123 | $self->{_links}->{'download_link'} = $link.'?dl'; 124 | $self->{_links}->{'twitter_link'} = $link.'?t'; 125 | $self->{_links}->{'delete_link'} = $url.'d/'.$hash->{msg}->{real_short}.'/'.$hash->{msg}->{token}; 126 | 127 | #set success code (200) 128 | $self->{_links}{'status'} = 200; 129 | } else { 130 | $self->{_links}{'status'} = $hash->{msg}->{msg}; 131 | 132 | } 133 | } else { 134 | $self->{_links}{'status'} = $response->status_line; 135 | } 136 | }; 137 | if($@){ 138 | $self->{_links}{'status'} = $@; 139 | } 140 | 141 | #and return links 142 | return %{ $self->{_links} }; 143 | } 144 | 145 | 1; 146 | -------------------------------------------------------------------------------- /themes/default/public/css/photoswipe.css: -------------------------------------------------------------------------------- 1 | /*! PhotoSwipe main CSS by Dmitry Semenov | photoswipe.com | MIT license */ 2 | /* 3 | Styles for basic PhotoSwipe functionality (sliding area, open/close transitions) 4 | */ 5 | /* pswp = photoswipe */ 6 | .pswp { 7 | display: none; 8 | position: absolute; 9 | width: 100%; 10 | height: 100%; 11 | left: 0; 12 | top: 0; 13 | overflow: hidden; 14 | -ms-touch-action: none; 15 | touch-action: none; 16 | z-index: 1500; 17 | -webkit-text-size-adjust: 100%; 18 | /* create separate layer, to avoid paint on window.onscroll in webkit/blink */ 19 | -webkit-backface-visibility: hidden; 20 | outline: none; } 21 | .pswp * { 22 | -webkit-box-sizing: border-box; 23 | box-sizing: border-box; } 24 | .pswp img { 25 | max-width: none; } 26 | 27 | /* style is added when JS option showHideOpacity is set to true */ 28 | .pswp--animate_opacity { 29 | /* 0.001, because opacity:0 doesn't trigger Paint action, which causes lag at start of transition */ 30 | opacity: 0.001; 31 | will-change: opacity; 32 | /* for open/close transition */ 33 | -webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); 34 | transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); } 35 | 36 | .pswp--open { 37 | display: block; } 38 | 39 | .pswp--zoom-allowed .pswp__img { 40 | /* autoprefixer: off */ 41 | cursor: -webkit-zoom-in; 42 | cursor: -moz-zoom-in; 43 | cursor: zoom-in; } 44 | 45 | .pswp--zoomed-in .pswp__img { 46 | /* autoprefixer: off */ 47 | cursor: -webkit-grab; 48 | cursor: -moz-grab; 49 | cursor: grab; } 50 | 51 | .pswp--dragging .pswp__img { 52 | /* autoprefixer: off */ 53 | cursor: -webkit-grabbing; 54 | cursor: -moz-grabbing; 55 | cursor: grabbing; } 56 | 57 | /* 58 | Background is added as a separate element. 59 | As animating opacity is much faster than animating rgba() background-color. 60 | */ 61 | .pswp__bg { 62 | position: absolute; 63 | left: 0; 64 | top: 0; 65 | width: 100%; 66 | height: 100%; 67 | background: #000; 68 | opacity: 0; 69 | -webkit-transform: translateZ(0); 70 | transform: translateZ(0); 71 | -webkit-backface-visibility: hidden; 72 | will-change: opacity; } 73 | 74 | .pswp__scroll-wrap { 75 | position: absolute; 76 | left: 0; 77 | top: 0; 78 | width: 100%; 79 | height: 100%; 80 | overflow: hidden; } 81 | 82 | .pswp__container, 83 | .pswp__zoom-wrap { 84 | -ms-touch-action: none; 85 | touch-action: none; 86 | position: absolute; 87 | left: 0; 88 | right: 0; 89 | top: 0; 90 | bottom: 0; } 91 | 92 | /* Prevent selection and tap highlights */ 93 | .pswp__container, 94 | .pswp__img { 95 | -webkit-user-select: none; 96 | -moz-user-select: none; 97 | -ms-user-select: none; 98 | user-select: none; 99 | -webkit-tap-highlight-color: transparent; 100 | -webkit-touch-callout: none; } 101 | 102 | .pswp__zoom-wrap { 103 | position: absolute; 104 | width: 100%; 105 | -webkit-transform-origin: left top; 106 | -ms-transform-origin: left top; 107 | transform-origin: left top; 108 | /* for open/close transition */ 109 | -webkit-transition: -webkit-transform 333ms cubic-bezier(0.4, 0, 0.22, 1); 110 | transition: transform 333ms cubic-bezier(0.4, 0, 0.22, 1); } 111 | 112 | .pswp__bg { 113 | will-change: opacity; 114 | /* for open/close transition */ 115 | -webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); 116 | transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); } 117 | 118 | .pswp--animated-in .pswp__bg, 119 | .pswp--animated-in .pswp__zoom-wrap { 120 | -webkit-transition: none; 121 | transition: none; } 122 | 123 | .pswp__container, 124 | .pswp__zoom-wrap { 125 | -webkit-backface-visibility: hidden; } 126 | 127 | .pswp__item { 128 | position: absolute; 129 | left: 0; 130 | right: 0; 131 | top: 0; 132 | bottom: 0; 133 | overflow: hidden; } 134 | 135 | .pswp__img { 136 | position: absolute; 137 | width: auto; 138 | height: auto; 139 | top: 0; 140 | left: 0; } 141 | 142 | /* 143 | stretched thumbnail or div placeholder element (see below) 144 | style is added to avoid flickering in webkit/blink when layers overlap 145 | */ 146 | .pswp__img--placeholder { 147 | -webkit-backface-visibility: hidden; } 148 | 149 | /* 150 | div element that matches size of large image 151 | large image loads on top of it 152 | */ 153 | .pswp__img--placeholder--blank { 154 | background: #222; } 155 | 156 | .pswp--ie .pswp__img { 157 | width: 100% !important; 158 | height: auto !important; 159 | left: 0; 160 | top: 0; } 161 | 162 | /* 163 | Error message appears when image is not loaded 164 | (JS option errorMsg controls markup) 165 | */ 166 | .pswp__error-msg { 167 | position: absolute; 168 | left: 0; 169 | top: 50%; 170 | width: 100%; 171 | text-align: center; 172 | font-size: 14px; 173 | line-height: 16px; 174 | margin-top: -8px; 175 | color: #CCC; } 176 | 177 | .pswp__error-msg a { 178 | color: #CCC; 179 | text-decoration: underline; } 180 | --------------------------------------------------------------------------------