diff --git a/.gitignore b/.gitignore index 4bfa312..75fbd9c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ *.swp lutim.conf -lutim.db +*.db +*.db-shm +*.db-wal script/hypnotoad.pid local/* files/* @@ -10,5 +12,6 @@ themes/* !themes/default/* themes/default/templates/data.html.ep themes/default/templates/raw.html.ep +themes/default/templates/stats.json.ep themes/default/public/packed/* -tmp/ +tmp/* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..4d0d8f7 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,120 @@ +image: hatsoftwares/test-ci:latest +stages: + - sqlite + - postgresql +before_script: + - carton install + - rm -f *db +sqlite1: + stage: sqlite + cache: + key: "$CI_BUILD_REF_NAME" + untracked: true + paths: + - local + script: + - make podcheck + - MOJO_CONFIG=t/sqlite1.conf make test-sqlite + - MOJO_CONFIG=t/sqlite1.conf make watch + - MOJO_CONFIG=t/sqlite1.conf make cleanbdd + - MOJO_CONFIG=t/sqlite1.conf make cleanfiles + - MOJO_CONFIG=t/sqlite1.conf make stats +sqlite2: + stage: sqlite + cache: + key: "$CI_BUILD_REF_NAME" + untracked: true + paths: + - local + script: + - make podcheck + - MOJO_CONFIG=t/sqlite2.conf make minion & + - MOJO_CONFIG=t/sqlite2.conf make test-sqlite + - MOJO_CONFIG=t/sqlite2.conf make watch + - MOJO_CONFIG=t/sqlite2.conf make cleanbdd + - MOJO_CONFIG=t/sqlite2.conf make cleanfiles + - MOJO_CONFIG=t/sqlite2.conf make stats +sqlite3: + stage: sqlite + cache: + key: "$CI_BUILD_REF_NAME" + untracked: true + paths: + - local + script: + - make podcheck + - service postgresql restart + - sleep 10 + - service postgresql status + - make create-pg-test-db + - MOJO_CONFIG=t/sqlite3.conf make minion & + - sleep 3 + - MOJO_CONFIG=t/sqlite3.conf make test-sqlite + - MOJO_CONFIG=t/sqlite3.conf make watch + - MOJO_CONFIG=t/sqlite3.conf make cleanbdd + - MOJO_CONFIG=t/sqlite3.conf make cleanfiles + - MOJO_CONFIG=t/sqlite3.conf make stats + tags: + - Debian + - Jessie +postgresql1: + stage: postgresql + cache: + key: "$CI_BUILD_REF_NAME" + untracked: true + paths: + - local + script: + - make podcheck + - service postgresql restart + - sleep 10 + - service postgresql status + - make create-pg-test-db + - MOJO_CONFIG=t/postgresql1.conf make test-pg + - MOJO_CONFIG=t/postgresql1.conf make watch + - MOJO_CONFIG=t/postgresql1.conf make cleanbdd + - MOJO_CONFIG=t/postgresql1.conf make cleanfiles + - MOJO_CONFIG=t/postgresql1.conf make stats +postgresql2: + stage: postgresql + cache: + key: "$CI_BUILD_REF_NAME" + untracked: true + paths: + - local + script: + - make podcheck + - service postgresql restart + - sleep 10 + - service postgresql status + - make create-pg-test-db + - MOJO_CONFIG=t/postgresql2.conf make minion & + - sleep 3 + - MOJO_CONFIG=t/postgresql2.conf make test-pg + - MOJO_CONFIG=t/postgresql2.conf make watch + - MOJO_CONFIG=t/postgresql2.conf make cleanbdd + - MOJO_CONFIG=t/postgresql2.conf make cleanfiles + - MOJO_CONFIG=t/postgresql2.conf make stats +postgresql3: + stage: postgresql + cache: + key: "$CI_BUILD_REF_NAME" + untracked: true + paths: + - local + script: + - make podcheck + - service postgresql restart + - sleep 10 + - service postgresql status + - make create-pg-test-db + - MOJO_CONFIG=t/postgresql3.conf make minion & + - sleep 3 + - MOJO_CONFIG=t/postgresql3.conf make test-pg + - MOJO_CONFIG=t/postgresql3.conf make watch + - MOJO_CONFIG=t/postgresql3.conf make cleanbdd + - MOJO_CONFIG=t/postgresql3.conf make cleanfiles + - MOJO_CONFIG=t/postgresql3.conf make stats + tags: + - Debian + - Jessie diff --git a/AUTHORS.md b/AUTHORS.md index 61d58ff..15803cf 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -14,3 +14,4 @@ * Laura Arjona Reina (), spanish translation * Thor77 (), german translation, among other things * Quentin Pagès, occitan translation +* Alexis Clairet (), paste image to upload ability diff --git a/CHANGELOG b/CHANGELOG index f2ce7c6..6a1b96e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,22 @@ Revision history for Lutim 0.8 2017-? - Improve statistics page + - Add database abstraction layer (#42) + - Add PostgreSQL support (#42) + - Asks for Mojolicious 7.31 minimum (to install it: `carton update`) + - Add Liberapay and Tipeee buttons + - Remove Flattr button + - Handle MOJO_CONFIG env variable (#44) + - Fix bug #39 + - Add gallery constructor to "my files" list (#33) + - Handle too much images in zip download URL (#27) + - LocalStorage is now updated if an image's delay is modified + - Allow user to paste image from clipboard to upload images (#14 and !5) + - Fix #40 + - Add stats in JSON format (GET /stats.json) + - Add Cache-control headers for static files + - Put almost all js/css stuff outside templates + - Allow to use Minion to increment counter (#43) 0.7.1 2016-06-21 - Fix dependency bug diff --git a/Makefile b/Makefile index 4b5c2aa..ea2bf9e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -EXTRACTFILES=utilities/locales_files.txt +EXTRACTDIR=-D lib -D themes/default/templates EN=themes/default/lib/Lutim/I18N/en.po FR=themes/default/lib/Lutim/I18N/fr.po DE=themes/default/lib/Lutim/I18N/de.po @@ -7,19 +7,58 @@ OC=themes/default/lib/Lutim/I18N/oc.po XGETTEXT=carton exec local/bin/xgettext.pl CARTON=carton exec LUTIM=script/lutim +REAL_LUTIM=script/application locales: - $(XGETTEXT) -W -f $(EXTRACTFILES) -o $(EN) 2>/dev/null - $(XGETTEXT) -W -f $(EXTRACTFILES) -o $(FR) 2>/dev/null - $(XGETTEXT) -W -f $(EXTRACTFILES) -o $(DE) 2>/dev/null - $(XGETTEXT) -W -f $(EXTRACTFILES) -o $(ES) 2>/dev/null - $(XGETTEXT) -W -f $(EXTRACTFILES) -o $(OC) 2>/dev/null + $(XGETTEXT) $(EXTRACTDIR) -o $(EN) 2>/dev/null + $(XGETTEXT) $(EXTRACTDIR) -o $(FR) 2>/dev/null + $(XGETTEXT) $(EXTRACTDIR) -o $(DE) 2>/dev/null + $(XGETTEXT) $(EXTRACTDIR) -o $(ES) 2>/dev/null + $(XGETTEXT) $(EXTRACTDIR) -o $(OC) 2>/dev/null + +podcheck: + podchecker lib/Lutim/DB/Image.pm + +test-sqlite: + $(CARTON) $(REAL_LUTIM) test + +test-pg: + $(CARTON) $(REAL_LUTIM) test + +test: podcheck test-sqlite test-pg clean: rm -rf lutim.db files/ -dev: + +rmassets: rm -rf themes/default/public/packed/* + +dev: rmassets $(CARTON) morbo $(LUTIM) --listen http://0.0.0.0:3000 --watch lib/ --watch script/ --watch themes/ --watch lutim.conf devlog: multitail log/development.log + +prod: rmassets + $(CARTON) hypnotoad -f $(LUTIM) + +prodlog: + multitail log/production.log + +minion: + $(CARTON) $(REAL_LUTIM) minion worker + +create-pg-test-db: + sudo -u postgres psql -f t/create-pg-testdb.sql + +stats: + $(CARTON) $(LUTIM) cron stats -m production + +watch: + $(CARTON) $(LUTIM) cron watch -m production + +cleanfiles: + $(CARTON) $(LUTIM) cron cleanfiles -m production + +cleanbdd: + $(CARTON) $(LUTIM) cron cleanbdd -m production diff --git a/cpanfile b/cpanfile index 4b930b9..91e27ad 100644 --- a/cpanfile +++ b/cpanfile @@ -1,13 +1,17 @@ -requires 'Mojolicious'; +requires 'Mojolicious', '>= 7.31'; requires 'EV'; requires 'IO::Socket::SSL'; requires 'Data::Validate::URI'; requires 'Net::Domain::TLD', '>= 1.73'; # Must have the last version to handle (at least) .xyz and .link +requires 'Mojo::Pg'; requires 'Mojolicious::Plugin::I18N'; requires 'Mojolicious::Plugin::AssetPack'; +requires 'Mojolicious::Plugin::DebugDumperHelper'; +requires 'Mojolicious::Plugin::PgURLHelper'; +requires "Minion", "== 4.06"; +requires 'Minion::Backend::SQLite', "== 0.009"; requires 'CSS::Minifier::XS'; requires 'JavaScript::Minifier::XS'; -requires 'Mojolicious::Plugin::DebugDumperHelper'; requires 'ORLite'; requires 'Text::Unidecode'; requires 'DateTime'; diff --git a/cpanfile.snapshot b/cpanfile.snapshot index 7ee27fe..ebb1cf3 100644 --- a/cpanfile.snapshot +++ b/cpanfile.snapshot @@ -1,20 +1,20 @@ # carton snapshot format: version 1.0 DISTRIBUTIONS - Archive-Zip-1.57 - pathname: P/PH/PHRED/Archive-Zip-1.57.tar.gz + Archive-Zip-1.59 + pathname: P/PH/PHRED/Archive-Zip-1.59.tar.gz provides: - Archive::Zip 1.57 - Archive::Zip::Archive 1.57 - Archive::Zip::BufferedFileHandle 1.57 - Archive::Zip::DirectoryMember 1.57 - Archive::Zip::FileMember 1.57 - Archive::Zip::Member 1.57 - Archive::Zip::MemberRead 1.57 - Archive::Zip::MockFileHandle 1.57 - Archive::Zip::NewFileMember 1.57 - Archive::Zip::StringMember 1.57 - Archive::Zip::Tree 1.57 - Archive::Zip::ZipFileMember 1.57 + Archive::Zip 1.59 + Archive::Zip::Archive 1.59 + Archive::Zip::BufferedFileHandle 1.59 + Archive::Zip::DirectoryMember 1.59 + Archive::Zip::FileMember 1.59 + Archive::Zip::Member 1.59 + Archive::Zip::MemberRead 1.59 + Archive::Zip::MockFileHandle 1.59 + Archive::Zip::NewFileMember 1.59 + Archive::Zip::StringMember 1.59 + Archive::Zip::Tree 1.59 + Archive::Zip::ZipFileMember 1.59 requirements: Compress::Raw::Zlib 2.017 ExtUtils::MakeMaker 0 @@ -27,10 +27,49 @@ DISTRIBUTIONS IO::File 0 IO::Handle 0 IO::Seekable 0 - Test::MockModule 0 - Test::More 0.88 Time::Local 0 perl 5.006 + B-Hooks-EndOfScope-0.21 + pathname: E/ET/ETHER/B-Hooks-EndOfScope-0.21.tar.gz + provides: + B::Hooks::EndOfScope 0.21 + B::Hooks::EndOfScope::PP 0.21 + B::Hooks::EndOfScope::XS 0.21 + requirements: + ExtUtils::MakeMaker 0 + Module::Implementation 0.05 + Sub::Exporter::Progressive 0.001006 + Text::ParseWords 0 + Variable::Magic 0.48 + perl 5.008001 + strict 0 + warnings 0 + CPAN-Meta-2.150010 + pathname: D/DA/DAGOLDEN/CPAN-Meta-2.150010.tar.gz + provides: + CPAN::Meta 2.150010 + CPAN::Meta::Converter 2.150010 + CPAN::Meta::Feature 2.150010 + CPAN::Meta::History 2.150010 + CPAN::Meta::Merge 2.150010 + CPAN::Meta::Prereqs 2.150010 + CPAN::Meta::Spec 2.150010 + CPAN::Meta::Validator 2.150010 + Parse::CPAN::Meta 2.150010 + requirements: + CPAN::Meta::Requirements 2.121 + CPAN::Meta::YAML 0.011 + Carp 0 + Encode 0 + Exporter 0 + ExtUtils::MakeMaker 6.17 + File::Spec 0.80 + JSON::PP 2.27300 + Scalar::Util 0 + perl 5.008001 + strict 0 + version 0.88 + warnings 0 CSS-Minifier-XS-0.09 pathname: G/GT/GTERMARS/CSS-Minifier-XS-0.09.tar.gz provides: @@ -38,18 +77,53 @@ DISTRIBUTIONS requirements: ExtUtils::CBuilder 0 Test::More 0 - Canary-Stability-2006 - pathname: M/ML/MLEHMANN/Canary-Stability-2006.tar.gz + Canary-Stability-2012 + pathname: M/ML/MLEHMANN/Canary-Stability-2012.tar.gz provides: - Canary::Stability 2006 + Canary::Stability 2012 requirements: ExtUtils::MakeMaker 0 - Class-Singleton-1.4 - pathname: A/AB/ABW/Class-Singleton-1.4.tar.gz + Class-Data-Inheritable-0.08 + pathname: T/TM/TMTM/Class-Data-Inheritable-0.08.tar.gz provides: - Class::Singleton 1.4 + Class::Data::Inheritable 0.08 requirements: ExtUtils::MakeMaker 0 + Class-Inspector-1.31 + pathname: P/PL/PLICEASE/Class-Inspector-1.31.tar.gz + provides: + Class::Inspector 1.31 + Class::Inspector::Functions 1.31 + requirements: + ExtUtils::MakeMaker 0 + File::Spec 0.80 + perl 5.006 + Class-Method-Modifiers-2.12 + pathname: E/ET/ETHER/Class-Method-Modifiers-2.12.tar.gz + provides: + Class::Method::Modifiers 2.12 + requirements: + B 0 + Carp 0 + Exporter 0 + ExtUtils::MakeMaker 0 + base 0 + perl 5.006 + strict 0 + warnings 0 + Class-Singleton-1.5 + pathname: S/SH/SHAY/Class-Singleton-1.5.tar.gz + provides: + Class::Singleton 1.5 + requirements: + ExtUtils::MakeMaker 0 + Clone-0.39 + pathname: G/GA/GARU/Clone-0.39.tar.gz + provides: + Clone 0.39 + requirements: + ExtUtils::MakeMaker 0 + Test::More 0 Crypt-Blowfish-2.14 pathname: D/DP/DPARIS/Crypt-Blowfish-2.14.tar.gz provides: @@ -70,13 +144,28 @@ DISTRIBUTIONS requirements: ExtUtils::MakeMaker 0 perl 5.006 - DBD-SQLite-1.40 - pathname: I/IS/ISHIGAKI/DBD-SQLite-1.40.tar.gz + DBD-Pg-3.6.2 + pathname: T/TU/TURNSTEP/DBD-Pg-3.6.2.tar.gz provides: - DBD::SQLite 1.40 - DBD::SQLite::_WriteOnceHash 1.40 - DBD::SQLite::db 1.40 - DBD::SQLite::dr 1.40 + Bundle::DBD::Pg v3.6.2 + DBD::Pg v3.6.2 + requirements: + DBI 1.614 + ExtUtils::MakeMaker 6.11 + Test::More 0.88 + Time::HiRes 0 + version 0 + DBD-SQLite-1.54 + pathname: I/IS/ISHIGAKI/DBD-SQLite-1.54.tar.gz + provides: + DBD::SQLite 1.54 + DBD::SQLite::Constants undef + DBD::SQLite::VirtualTable 1.54 + DBD::SQLite::VirtualTable::Cursor 1.54 + DBD::SQLite::VirtualTable::FileContent undef + DBD::SQLite::VirtualTable::FileContent::Cursor undef + DBD::SQLite::VirtualTable::PerlData undef + DBD::SQLite::VirtualTable::PerlData::Cursor undef requirements: DBI 1.57 ExtUtils::MakeMaker 0 @@ -85,8 +174,8 @@ DISTRIBUTIONS Test::More 0.47 Tie::Hash 0 perl 5.006 - DBI-1.631 - pathname: T/TI/TIMB/DBI-1.631.tar.gz + DBI-1.636 + pathname: T/TI/TIMB/DBI-1.636.tar.gz provides: Bundle::DBI 12.008696 DBD::DBM 0.08 @@ -99,15 +188,15 @@ DISTRIBUTIONS DBD::ExampleP::db 12.014311 DBD::ExampleP::dr 12.014311 DBD::ExampleP::st 12.014311 - DBD::File 0.42 - DBD::File::DataSource::File 0.42 - DBD::File::DataSource::Stream 0.42 - DBD::File::Statement 0.42 - DBD::File::Table 0.42 - DBD::File::TableSource::FileSystem 0.42 - DBD::File::db 0.42 - DBD::File::dr 0.42 - DBD::File::st 0.42 + DBD::File 0.44 + DBD::File::DataSource::File 0.44 + DBD::File::DataSource::Stream 0.44 + DBD::File::Statement 0.44 + DBD::File::Table 0.44 + DBD::File::TableSource::FileSystem 0.44 + DBD::File::db 0.44 + DBD::File::dr 0.44 + DBD::File::st 0.44 DBD::Gofer 0.015327 DBD::Gofer::Policy::Base 0.010088 DBD::Gofer::Policy::classic 0.010088 @@ -135,7 +224,7 @@ DISTRIBUTIONS DBD::Sponge::dr 12.010003 DBD::Sponge::st 12.010003 DBDI 12.015129 - DBI 1.631 + DBI 1.636 DBI::Const::GetInfo::ANSI 2.008697 DBI::Const::GetInfo::ODBC 2.011374 DBI::Const::GetInfoReturn 2.008697 @@ -152,7 +241,6 @@ DISTRIBUTIONS DBI::DBD::SqlEngine::db 0.06 DBI::DBD::SqlEngine::dr 0.06 DBI::DBD::SqlEngine::st 0.06 - DBI::FAQ 1.014935 DBI::Gofer::Execute 0.014283 DBI::Gofer::Request 0.012537 DBI::Gofer::Response 0.011566 @@ -176,7 +264,7 @@ DISTRIBUTIONS DBI::SQL::Nano::Table_ 1.015544 DBI::Util::CacheMemory 0.010315 DBI::Util::_accessor 0.009479 - DBI::common 1.631 + DBI::common 1.636 requirements: ExtUtils::MakeMaker 6.48 Test::Simple 0.90 @@ -223,23 +311,27 @@ DISTRIBUTIONS perl 5.006 strict 0 warnings 0 - Data-Validate-Domain-0.10 - pathname: N/NE/NEELY/Data-Validate-Domain-0.10.tar.gz + Data-Validate-Domain-0.14 + pathname: D/DR/DROLSKY/Data-Validate-Domain-0.14.tar.gz provides: - Data::Validate::Domain 0.10 - requirements: - ExtUtils::MakeMaker 0 - Net::Domain::TLD 1.62 - Test::More 0 - Data-Validate-IP-0.22 - pathname: D/DR/DROLSKY/Data-Validate-IP-0.22.tar.gz - provides: - Data::Validate::IP 0.22 + Data::Validate::Domain 0.14 requirements: Exporter 0 - ExtUtils::MakeMaker 6.30 + ExtUtils::MakeMaker 0 + Net::Domain::TLD 1.74 + strict 0 + warnings 0 + Data-Validate-IP-0.27 + pathname: D/DR/DROLSKY/Data-Validate-IP-0.27.tar.gz + provides: + Data::Validate::IP 0.27 + requirements: + Exporter 0 + ExtUtils::MakeMaker 0 NetAddr::IP 4 Scalar::Util 0 + base 0 + perl 5.008 strict 0 warnings 0 Data-Validate-URI-0.07 @@ -250,878 +342,442 @@ DISTRIBUTIONS Data::Validate::Domain 0 Data::Validate::IP 0 ExtUtils::MakeMaker 0 - DateTime-1.28 - pathname: D/DR/DROLSKY/DateTime-1.28.tar.gz + DateTime-1.43 + pathname: D/DR/DROLSKY/DateTime-1.43.tar.gz provides: - DateTime 1.28 - DateTime::Duration 1.28 - DateTime::Helpers 1.28 - DateTime::Infinite 1.28 - DateTime::Infinite::Future 1.28 - DateTime::Infinite::Past 1.28 - DateTime::LeapSecond 1.28 - DateTime::PP 1.28 - DateTime::PPExtra 1.28 + DateTime 1.43 + DateTime::Duration 1.43 + DateTime::Helpers 1.43 + DateTime::Infinite 1.43 + DateTime::Infinite::Future 1.43 + DateTime::Infinite::Past 1.43 + DateTime::LeapSecond 1.43 + DateTime::PP 1.43 + DateTime::PPExtra 1.43 + DateTime::Types 1.43 requirements: Carp 0 - DateTime::Locale 0.41 - DateTime::TimeZone 1.74 + DateTime::Locale 1.06 + DateTime::TimeZone 2.02 + Dist::CheckConflicts 0.02 ExtUtils::MakeMaker 0 POSIX 0 - Params::Validate 1.03 + Params::ValidationCompiler 0.13 Scalar::Util 0 + Specio 0.18 + Specio::Declare 0 + Specio::Exporter 0 + Specio::Library::Builtins 0 + Specio::Library::Numeric 0 + Specio::Library::String 0 Try::Tiny 0 XSLoader 0 base 0 - constant 0 integer 0 + namespace::autoclean 0.19 overload 0 - perl 5.008001 + parent 0 + perl 5.008004 strict 0 - vars 0 warnings 0 warnings::register 0 - DateTime-Locale-0.45 - pathname: D/DR/DROLSKY/DateTime-Locale-0.45.tar.gz + DateTime-Locale-1.16 + pathname: D/DR/DROLSKY/DateTime-Locale-1.16.tar.gz provides: - DateTime::Locale 0.45 - DateTime::Locale::Base undef - DateTime::Locale::Catalog undef - DateTime::Locale::aa undef - DateTime::Locale::aa_DJ undef - DateTime::Locale::aa_ER undef - DateTime::Locale::aa_ER_SAAHO undef - DateTime::Locale::aa_ET undef - DateTime::Locale::af undef - DateTime::Locale::af_NA undef - DateTime::Locale::af_ZA undef - DateTime::Locale::ak undef - DateTime::Locale::ak_GH undef - DateTime::Locale::am undef - DateTime::Locale::am_ET undef - DateTime::Locale::ar undef - DateTime::Locale::ar_AE undef - DateTime::Locale::ar_BH undef - DateTime::Locale::ar_DZ undef - DateTime::Locale::ar_EG undef - DateTime::Locale::ar_IQ undef - DateTime::Locale::ar_JO undef - DateTime::Locale::ar_KW undef - DateTime::Locale::ar_LB undef - DateTime::Locale::ar_LY undef - DateTime::Locale::ar_MA undef - DateTime::Locale::ar_OM undef - DateTime::Locale::ar_QA undef - DateTime::Locale::ar_SA undef - DateTime::Locale::ar_SD undef - DateTime::Locale::ar_SY undef - DateTime::Locale::ar_TN undef - DateTime::Locale::ar_YE undef - DateTime::Locale::as undef - DateTime::Locale::as_IN undef - DateTime::Locale::az undef - DateTime::Locale::az_AZ undef - DateTime::Locale::az_Cyrl undef - DateTime::Locale::az_Cyrl_AZ undef - DateTime::Locale::az_Latn undef - DateTime::Locale::az_Latn_AZ undef - DateTime::Locale::be undef - DateTime::Locale::be_BY undef - DateTime::Locale::bg undef - DateTime::Locale::bg_BG undef - DateTime::Locale::bn undef - DateTime::Locale::bn_BD undef - DateTime::Locale::bn_IN undef - DateTime::Locale::bo undef - DateTime::Locale::bo_CN undef - DateTime::Locale::bo_IN undef - DateTime::Locale::bs undef - DateTime::Locale::bs_BA undef - DateTime::Locale::byn undef - DateTime::Locale::byn_ER undef - DateTime::Locale::ca undef - DateTime::Locale::ca_ES undef - DateTime::Locale::cch undef - DateTime::Locale::cch_NG undef - DateTime::Locale::cop undef - DateTime::Locale::cs undef - DateTime::Locale::cs_CZ undef - DateTime::Locale::cy undef - DateTime::Locale::cy_GB undef - DateTime::Locale::da undef - DateTime::Locale::da_DK undef - DateTime::Locale::de undef - DateTime::Locale::de_AT undef - DateTime::Locale::de_BE undef - DateTime::Locale::de_CH undef - DateTime::Locale::de_DE undef - DateTime::Locale::de_LI undef - DateTime::Locale::de_LU undef - DateTime::Locale::dv undef - DateTime::Locale::dv_MV undef - DateTime::Locale::dz undef - DateTime::Locale::dz_BT undef - DateTime::Locale::ee undef - DateTime::Locale::ee_GH undef - DateTime::Locale::ee_TG undef - DateTime::Locale::el undef - DateTime::Locale::el_CY undef - DateTime::Locale::el_GR undef - DateTime::Locale::el_POLYTON undef - DateTime::Locale::en undef - DateTime::Locale::en_AS undef - DateTime::Locale::en_AU undef - DateTime::Locale::en_BE undef - DateTime::Locale::en_BW undef - DateTime::Locale::en_BZ undef - DateTime::Locale::en_CA undef - DateTime::Locale::en_Dsrt undef - DateTime::Locale::en_Dsrt_US undef - DateTime::Locale::en_GB undef - DateTime::Locale::en_GU undef - DateTime::Locale::en_HK undef - DateTime::Locale::en_IE undef - DateTime::Locale::en_IN undef - DateTime::Locale::en_JM undef - DateTime::Locale::en_MH undef - DateTime::Locale::en_MP undef - DateTime::Locale::en_MT undef - DateTime::Locale::en_NA undef - DateTime::Locale::en_NZ undef - DateTime::Locale::en_PH undef - DateTime::Locale::en_PK undef - DateTime::Locale::en_SG undef - DateTime::Locale::en_Shaw undef - DateTime::Locale::en_TT undef - DateTime::Locale::en_UM undef - DateTime::Locale::en_US undef - DateTime::Locale::en_US_POSIX undef - DateTime::Locale::en_VI undef - DateTime::Locale::en_ZA undef - DateTime::Locale::en_ZW undef - DateTime::Locale::eo undef - DateTime::Locale::es undef - DateTime::Locale::es_AR undef - DateTime::Locale::es_BO undef - DateTime::Locale::es_CL undef - DateTime::Locale::es_CO undef - DateTime::Locale::es_CR undef - DateTime::Locale::es_DO undef - DateTime::Locale::es_EC undef - DateTime::Locale::es_ES undef - DateTime::Locale::es_GT undef - DateTime::Locale::es_HN undef - DateTime::Locale::es_MX undef - DateTime::Locale::es_NI undef - DateTime::Locale::es_PA undef - DateTime::Locale::es_PE undef - DateTime::Locale::es_PR undef - DateTime::Locale::es_PY undef - DateTime::Locale::es_SV undef - DateTime::Locale::es_US undef - DateTime::Locale::es_UY undef - DateTime::Locale::es_VE undef - DateTime::Locale::et undef - DateTime::Locale::et_EE undef - DateTime::Locale::eu undef - DateTime::Locale::eu_ES undef - DateTime::Locale::fa undef - DateTime::Locale::fa_AF undef - DateTime::Locale::fa_IR undef - DateTime::Locale::fi undef - DateTime::Locale::fi_FI undef - DateTime::Locale::fil undef - DateTime::Locale::fil_PH undef - DateTime::Locale::fo undef - DateTime::Locale::fo_FO undef - DateTime::Locale::fr undef - DateTime::Locale::fr_BE undef - DateTime::Locale::fr_CA undef - DateTime::Locale::fr_CH undef - DateTime::Locale::fr_FR undef - DateTime::Locale::fr_LU undef - DateTime::Locale::fr_MC undef - DateTime::Locale::fr_SN undef - DateTime::Locale::fur undef - DateTime::Locale::fur_IT undef - DateTime::Locale::ga undef - DateTime::Locale::ga_IE undef - DateTime::Locale::gaa undef - DateTime::Locale::gaa_GH undef - DateTime::Locale::gez undef - DateTime::Locale::gez_ER undef - DateTime::Locale::gez_ET undef - DateTime::Locale::gl undef - DateTime::Locale::gl_ES undef - DateTime::Locale::gsw undef - DateTime::Locale::gsw_CH undef - DateTime::Locale::gu undef - DateTime::Locale::gu_IN undef - DateTime::Locale::gv undef - DateTime::Locale::gv_GB undef - DateTime::Locale::ha undef - DateTime::Locale::ha_Arab undef - DateTime::Locale::ha_Arab_NG undef - DateTime::Locale::ha_Arab_SD undef - DateTime::Locale::ha_GH undef - DateTime::Locale::ha_Latn undef - DateTime::Locale::ha_Latn_GH undef - DateTime::Locale::ha_Latn_NE undef - DateTime::Locale::ha_Latn_NG undef - DateTime::Locale::ha_NE undef - DateTime::Locale::ha_NG undef - DateTime::Locale::ha_SD undef - DateTime::Locale::haw undef - DateTime::Locale::haw_US undef - DateTime::Locale::he undef - DateTime::Locale::he_IL undef - DateTime::Locale::hi undef - DateTime::Locale::hi_IN undef - DateTime::Locale::hr undef - DateTime::Locale::hr_HR undef - DateTime::Locale::hu undef - DateTime::Locale::hu_HU undef - DateTime::Locale::hy undef - DateTime::Locale::hy_AM undef - DateTime::Locale::hy_AM_REVISED undef - DateTime::Locale::ia undef - DateTime::Locale::id undef - DateTime::Locale::id_ID undef - DateTime::Locale::ig undef - DateTime::Locale::ig_NG undef - DateTime::Locale::ii undef - DateTime::Locale::ii_CN undef - DateTime::Locale::is undef - DateTime::Locale::is_IS undef - DateTime::Locale::it undef - DateTime::Locale::it_CH undef - DateTime::Locale::it_IT undef - DateTime::Locale::iu undef - DateTime::Locale::ja undef - DateTime::Locale::ja_JP undef - DateTime::Locale::ka undef - DateTime::Locale::ka_GE undef - DateTime::Locale::kaj undef - DateTime::Locale::kaj_NG undef - DateTime::Locale::kam undef - DateTime::Locale::kam_KE undef - DateTime::Locale::kcg undef - DateTime::Locale::kcg_NG undef - DateTime::Locale::kfo undef - DateTime::Locale::kfo_CI undef - DateTime::Locale::kk undef - DateTime::Locale::kk_Cyrl undef - DateTime::Locale::kk_Cyrl_KZ undef - DateTime::Locale::kk_KZ undef - DateTime::Locale::kl undef - DateTime::Locale::kl_GL undef - DateTime::Locale::km undef - DateTime::Locale::km_KH undef - DateTime::Locale::kn undef - DateTime::Locale::kn_IN undef - DateTime::Locale::ko undef - DateTime::Locale::ko_KR undef - DateTime::Locale::kok undef - DateTime::Locale::kok_IN undef - DateTime::Locale::kpe undef - DateTime::Locale::kpe_GN undef - DateTime::Locale::kpe_LR undef - DateTime::Locale::ku undef - DateTime::Locale::ku_Arab undef - DateTime::Locale::ku_Arab_IQ undef - DateTime::Locale::ku_Arab_IR undef - DateTime::Locale::ku_Arab_SY undef - DateTime::Locale::ku_IQ undef - DateTime::Locale::ku_IR undef - DateTime::Locale::ku_Latn undef - DateTime::Locale::ku_Latn_TR undef - DateTime::Locale::ku_SY undef - DateTime::Locale::ku_TR undef - DateTime::Locale::kw undef - DateTime::Locale::kw_GB undef - DateTime::Locale::ky undef - DateTime::Locale::ky_KG undef - DateTime::Locale::ln undef - DateTime::Locale::ln_CD undef - DateTime::Locale::ln_CG undef - DateTime::Locale::lo undef - DateTime::Locale::lo_LA undef - DateTime::Locale::lt undef - DateTime::Locale::lt_LT undef - DateTime::Locale::lv undef - DateTime::Locale::lv_LV undef - DateTime::Locale::mk undef - DateTime::Locale::mk_MK undef - DateTime::Locale::ml undef - DateTime::Locale::ml_IN undef - DateTime::Locale::mn undef - DateTime::Locale::mn_CN undef - DateTime::Locale::mn_Cyrl undef - DateTime::Locale::mn_Cyrl_MN undef - DateTime::Locale::mn_MN undef - DateTime::Locale::mn_Mong undef - DateTime::Locale::mn_Mong_CN undef - DateTime::Locale::mo undef - DateTime::Locale::mr undef - DateTime::Locale::mr_IN undef - DateTime::Locale::ms undef - DateTime::Locale::ms_BN undef - DateTime::Locale::ms_MY undef - DateTime::Locale::mt undef - DateTime::Locale::mt_MT undef - DateTime::Locale::my undef - DateTime::Locale::my_MM undef - DateTime::Locale::nb undef - DateTime::Locale::nb_NO undef - DateTime::Locale::nds undef - DateTime::Locale::nds_DE undef - DateTime::Locale::ne undef - DateTime::Locale::ne_IN undef - DateTime::Locale::ne_NP undef - DateTime::Locale::nl undef - DateTime::Locale::nl_BE undef - DateTime::Locale::nl_NL undef - DateTime::Locale::nn undef - DateTime::Locale::nn_NO undef - DateTime::Locale::no undef - DateTime::Locale::nr undef - DateTime::Locale::nr_ZA undef - DateTime::Locale::nso undef - DateTime::Locale::nso_ZA undef - DateTime::Locale::ny undef - DateTime::Locale::ny_MW undef - DateTime::Locale::oc undef - DateTime::Locale::oc_FR undef - DateTime::Locale::om undef - DateTime::Locale::om_ET undef - DateTime::Locale::om_KE undef - DateTime::Locale::or undef - DateTime::Locale::or_IN undef - DateTime::Locale::pa undef - DateTime::Locale::pa_Arab undef - DateTime::Locale::pa_Arab_PK undef - DateTime::Locale::pa_Guru undef - DateTime::Locale::pa_Guru_IN undef - DateTime::Locale::pa_IN undef - DateTime::Locale::pa_PK undef - DateTime::Locale::pl undef - DateTime::Locale::pl_PL undef - DateTime::Locale::ps undef - DateTime::Locale::ps_AF undef - DateTime::Locale::pt undef - DateTime::Locale::pt_BR undef - DateTime::Locale::pt_PT undef - DateTime::Locale::ro undef - DateTime::Locale::ro_MD undef - DateTime::Locale::ro_RO undef - DateTime::Locale::root undef - DateTime::Locale::ru undef - DateTime::Locale::ru_RU undef - DateTime::Locale::ru_UA undef - DateTime::Locale::rw undef - DateTime::Locale::rw_RW undef - DateTime::Locale::sa undef - DateTime::Locale::sa_IN undef - DateTime::Locale::se undef - DateTime::Locale::se_FI undef - DateTime::Locale::se_NO undef - DateTime::Locale::sh undef - DateTime::Locale::sh_BA undef - DateTime::Locale::sh_CS undef - DateTime::Locale::sh_YU undef - DateTime::Locale::si undef - DateTime::Locale::si_LK undef - DateTime::Locale::sid undef - DateTime::Locale::sid_ET undef - DateTime::Locale::sk undef - DateTime::Locale::sk_SK undef - DateTime::Locale::sl undef - DateTime::Locale::sl_SI undef - DateTime::Locale::so undef - DateTime::Locale::so_DJ undef - DateTime::Locale::so_ET undef - DateTime::Locale::so_KE undef - DateTime::Locale::so_SO undef - DateTime::Locale::sq undef - DateTime::Locale::sq_AL undef - DateTime::Locale::sr undef - DateTime::Locale::sr_BA undef - DateTime::Locale::sr_CS undef - DateTime::Locale::sr_Cyrl undef - DateTime::Locale::sr_Cyrl_BA undef - DateTime::Locale::sr_Cyrl_CS undef - DateTime::Locale::sr_Cyrl_ME undef - DateTime::Locale::sr_Cyrl_RS undef - DateTime::Locale::sr_Cyrl_YU undef - DateTime::Locale::sr_Latn undef - DateTime::Locale::sr_Latn_BA undef - DateTime::Locale::sr_Latn_CS undef - DateTime::Locale::sr_Latn_ME undef - DateTime::Locale::sr_Latn_RS undef - DateTime::Locale::sr_Latn_YU undef - DateTime::Locale::sr_ME undef - DateTime::Locale::sr_RS undef - DateTime::Locale::sr_YU undef - DateTime::Locale::ss undef - DateTime::Locale::ss_SZ undef - DateTime::Locale::ss_ZA undef - DateTime::Locale::st undef - DateTime::Locale::st_LS undef - DateTime::Locale::st_ZA undef - DateTime::Locale::sv undef - DateTime::Locale::sv_FI undef - DateTime::Locale::sv_SE undef - DateTime::Locale::sw undef - DateTime::Locale::sw_KE undef - DateTime::Locale::sw_TZ undef - DateTime::Locale::syr undef - DateTime::Locale::syr_SY undef - DateTime::Locale::ta undef - DateTime::Locale::ta_IN undef - DateTime::Locale::te undef - DateTime::Locale::te_IN undef - DateTime::Locale::tg undef - DateTime::Locale::tg_Cyrl undef - DateTime::Locale::tg_Cyrl_TJ undef - DateTime::Locale::tg_TJ undef - DateTime::Locale::th undef - DateTime::Locale::th_TH undef - DateTime::Locale::ti undef - DateTime::Locale::ti_ER undef - DateTime::Locale::ti_ET undef - DateTime::Locale::tig undef - DateTime::Locale::tig_ER undef - DateTime::Locale::tl undef - DateTime::Locale::tn undef - DateTime::Locale::tn_ZA undef - DateTime::Locale::to undef - DateTime::Locale::to_TO undef - DateTime::Locale::tr undef - DateTime::Locale::tr_TR undef - DateTime::Locale::trv undef - DateTime::Locale::trv_TW undef - DateTime::Locale::ts undef - DateTime::Locale::ts_ZA undef - DateTime::Locale::tt undef - DateTime::Locale::tt_RU undef - DateTime::Locale::ug undef - DateTime::Locale::ug_Arab undef - DateTime::Locale::ug_Arab_CN undef - DateTime::Locale::ug_CN undef - DateTime::Locale::uk undef - DateTime::Locale::uk_UA undef - DateTime::Locale::ur undef - DateTime::Locale::ur_IN undef - DateTime::Locale::ur_PK undef - DateTime::Locale::uz undef - DateTime::Locale::uz_AF undef - DateTime::Locale::uz_Arab undef - DateTime::Locale::uz_Arab_AF undef - DateTime::Locale::uz_Cyrl undef - DateTime::Locale::uz_Cyrl_UZ undef - DateTime::Locale::uz_Latn undef - DateTime::Locale::uz_Latn_UZ undef - DateTime::Locale::uz_UZ undef - DateTime::Locale::ve undef - DateTime::Locale::ve_ZA undef - DateTime::Locale::vi undef - DateTime::Locale::vi_VN undef - DateTime::Locale::wal undef - DateTime::Locale::wal_ET undef - DateTime::Locale::wo undef - DateTime::Locale::wo_Latn undef - DateTime::Locale::wo_Latn_SN undef - DateTime::Locale::wo_SN undef - DateTime::Locale::xh undef - DateTime::Locale::xh_ZA undef - DateTime::Locale::yo undef - DateTime::Locale::yo_NG undef - DateTime::Locale::zh undef - DateTime::Locale::zh_CN undef - DateTime::Locale::zh_HK undef - DateTime::Locale::zh_Hans undef - DateTime::Locale::zh_Hans_CN undef - DateTime::Locale::zh_Hans_HK undef - DateTime::Locale::zh_Hans_MO undef - DateTime::Locale::zh_Hans_SG undef - DateTime::Locale::zh_Hant undef - DateTime::Locale::zh_Hant_HK undef - DateTime::Locale::zh_Hant_MO undef - DateTime::Locale::zh_Hant_TW undef - DateTime::Locale::zh_MO undef - DateTime::Locale::zh_SG undef - DateTime::Locale::zh_TW undef - DateTime::Locale::zu undef - DateTime::Locale::zu_ZA undef + DateTime::Locale 1.16 + DateTime::Locale::Base 1.16 + DateTime::Locale::Catalog 1.16 + DateTime::Locale::Data 1.16 + DateTime::Locale::FromData 1.16 + DateTime::Locale::Util 1.16 requirements: - List::MoreUtils 0 - Module::Build 0 - Params::Validate 0.91 - perl 5.006 - DateTime-TimeZone-1.90 - pathname: D/DR/DROLSKY/DateTime-TimeZone-1.90.tar.gz + Carp 0 + Dist::CheckConflicts 0.02 + Exporter 0 + ExtUtils::MakeMaker 0 + File::ShareDir 0 + File::ShareDir::Install 0.06 + List::Util 1.45 + Params::ValidationCompiler 0.13 + Specio::Declare 0 + Specio::Library::String 0 + namespace::autoclean 0.19 + perl 5.008004 + strict 0 + warnings 0 + DateTime-TimeZone-2.13 + pathname: D/DR/DROLSKY/DateTime-TimeZone-2.13.tar.gz provides: - DateTime::TimeZone 1.90 - DateTime::TimeZone::Africa::Abidjan 1.90 - DateTime::TimeZone::Africa::Accra 1.90 - DateTime::TimeZone::Africa::Algiers 1.90 - DateTime::TimeZone::Africa::Bissau 1.90 - DateTime::TimeZone::Africa::Cairo 1.90 - DateTime::TimeZone::Africa::Casablanca 1.90 - DateTime::TimeZone::Africa::Ceuta 1.90 - DateTime::TimeZone::Africa::El_Aaiun 1.90 - DateTime::TimeZone::Africa::Johannesburg 1.90 - DateTime::TimeZone::Africa::Khartoum 1.90 - DateTime::TimeZone::Africa::Lagos 1.90 - DateTime::TimeZone::Africa::Maputo 1.90 - DateTime::TimeZone::Africa::Monrovia 1.90 - DateTime::TimeZone::Africa::Nairobi 1.90 - DateTime::TimeZone::Africa::Ndjamena 1.90 - DateTime::TimeZone::Africa::Tripoli 1.90 - DateTime::TimeZone::Africa::Tunis 1.90 - DateTime::TimeZone::Africa::Windhoek 1.90 - DateTime::TimeZone::America::Adak 1.90 - DateTime::TimeZone::America::Anchorage 1.90 - DateTime::TimeZone::America::Araguaina 1.90 - DateTime::TimeZone::America::Argentina::Buenos_Aires 1.90 - DateTime::TimeZone::America::Argentina::Catamarca 1.90 - DateTime::TimeZone::America::Argentina::Cordoba 1.90 - DateTime::TimeZone::America::Argentina::Jujuy 1.90 - DateTime::TimeZone::America::Argentina::La_Rioja 1.90 - DateTime::TimeZone::America::Argentina::Mendoza 1.90 - DateTime::TimeZone::America::Argentina::Rio_Gallegos 1.90 - DateTime::TimeZone::America::Argentina::Salta 1.90 - DateTime::TimeZone::America::Argentina::San_Juan 1.90 - DateTime::TimeZone::America::Argentina::San_Luis 1.90 - DateTime::TimeZone::America::Argentina::Tucuman 1.90 - DateTime::TimeZone::America::Argentina::Ushuaia 1.90 - DateTime::TimeZone::America::Asuncion 1.90 - DateTime::TimeZone::America::Atikokan 1.90 - DateTime::TimeZone::America::Bahia 1.90 - DateTime::TimeZone::America::Bahia_Banderas 1.90 - DateTime::TimeZone::America::Barbados 1.90 - DateTime::TimeZone::America::Belem 1.90 - DateTime::TimeZone::America::Belize 1.90 - DateTime::TimeZone::America::Blanc_Sablon 1.90 - DateTime::TimeZone::America::Boa_Vista 1.90 - DateTime::TimeZone::America::Bogota 1.90 - DateTime::TimeZone::America::Boise 1.90 - DateTime::TimeZone::America::Cambridge_Bay 1.90 - DateTime::TimeZone::America::Campo_Grande 1.90 - DateTime::TimeZone::America::Cancun 1.90 - DateTime::TimeZone::America::Caracas 1.90 - DateTime::TimeZone::America::Cayenne 1.90 - DateTime::TimeZone::America::Chicago 1.90 - DateTime::TimeZone::America::Chihuahua 1.90 - DateTime::TimeZone::America::Costa_Rica 1.90 - DateTime::TimeZone::America::Creston 1.90 - DateTime::TimeZone::America::Cuiaba 1.90 - DateTime::TimeZone::America::Curacao 1.90 - DateTime::TimeZone::America::Danmarkshavn 1.90 - DateTime::TimeZone::America::Dawson 1.90 - DateTime::TimeZone::America::Dawson_Creek 1.90 - DateTime::TimeZone::America::Denver 1.90 - DateTime::TimeZone::America::Detroit 1.90 - DateTime::TimeZone::America::Edmonton 1.90 - DateTime::TimeZone::America::Eirunepe 1.90 - DateTime::TimeZone::America::El_Salvador 1.90 - DateTime::TimeZone::America::Fortaleza 1.90 - DateTime::TimeZone::America::Glace_Bay 1.90 - DateTime::TimeZone::America::Godthab 1.90 - DateTime::TimeZone::America::Goose_Bay 1.90 - DateTime::TimeZone::America::Grand_Turk 1.90 - DateTime::TimeZone::America::Guatemala 1.90 - DateTime::TimeZone::America::Guayaquil 1.90 - DateTime::TimeZone::America::Guyana 1.90 - DateTime::TimeZone::America::Halifax 1.90 - DateTime::TimeZone::America::Havana 1.90 - DateTime::TimeZone::America::Hermosillo 1.90 - DateTime::TimeZone::America::Indiana::Indianapolis 1.90 - DateTime::TimeZone::America::Indiana::Knox 1.90 - DateTime::TimeZone::America::Indiana::Marengo 1.90 - DateTime::TimeZone::America::Indiana::Petersburg 1.90 - DateTime::TimeZone::America::Indiana::Tell_City 1.90 - DateTime::TimeZone::America::Indiana::Vevay 1.90 - DateTime::TimeZone::America::Indiana::Vincennes 1.90 - DateTime::TimeZone::America::Indiana::Winamac 1.90 - DateTime::TimeZone::America::Inuvik 1.90 - DateTime::TimeZone::America::Iqaluit 1.90 - DateTime::TimeZone::America::Jamaica 1.90 - DateTime::TimeZone::America::Juneau 1.90 - DateTime::TimeZone::America::Kentucky::Louisville 1.90 - DateTime::TimeZone::America::Kentucky::Monticello 1.90 - DateTime::TimeZone::America::La_Paz 1.90 - DateTime::TimeZone::America::Lima 1.90 - DateTime::TimeZone::America::Los_Angeles 1.90 - DateTime::TimeZone::America::Maceio 1.90 - DateTime::TimeZone::America::Managua 1.90 - DateTime::TimeZone::America::Manaus 1.90 - DateTime::TimeZone::America::Martinique 1.90 - DateTime::TimeZone::America::Matamoros 1.90 - DateTime::TimeZone::America::Mazatlan 1.90 - DateTime::TimeZone::America::Menominee 1.90 - DateTime::TimeZone::America::Merida 1.90 - DateTime::TimeZone::America::Metlakatla 1.90 - DateTime::TimeZone::America::Mexico_City 1.90 - DateTime::TimeZone::America::Miquelon 1.90 - DateTime::TimeZone::America::Moncton 1.90 - DateTime::TimeZone::America::Monterrey 1.90 - DateTime::TimeZone::America::Montevideo 1.90 - DateTime::TimeZone::America::Nassau 1.90 - DateTime::TimeZone::America::New_York 1.90 - DateTime::TimeZone::America::Nipigon 1.90 - DateTime::TimeZone::America::Nome 1.90 - DateTime::TimeZone::America::Noronha 1.90 - DateTime::TimeZone::America::North_Dakota::Beulah 1.90 - DateTime::TimeZone::America::North_Dakota::Center 1.90 - DateTime::TimeZone::America::North_Dakota::New_Salem 1.90 - DateTime::TimeZone::America::Ojinaga 1.90 - DateTime::TimeZone::America::Panama 1.90 - DateTime::TimeZone::America::Pangnirtung 1.90 - DateTime::TimeZone::America::Paramaribo 1.90 - DateTime::TimeZone::America::Phoenix 1.90 - DateTime::TimeZone::America::Port_au_Prince 1.90 - DateTime::TimeZone::America::Port_of_Spain 1.90 - DateTime::TimeZone::America::Porto_Velho 1.90 - DateTime::TimeZone::America::Puerto_Rico 1.90 - DateTime::TimeZone::America::Rainy_River 1.90 - DateTime::TimeZone::America::Rankin_Inlet 1.90 - DateTime::TimeZone::America::Recife 1.90 - DateTime::TimeZone::America::Regina 1.90 - DateTime::TimeZone::America::Resolute 1.90 - DateTime::TimeZone::America::Rio_Branco 1.90 - DateTime::TimeZone::America::Santa_Isabel 1.90 - DateTime::TimeZone::America::Santarem 1.90 - DateTime::TimeZone::America::Santiago 1.90 - DateTime::TimeZone::America::Santo_Domingo 1.90 - DateTime::TimeZone::America::Sao_Paulo 1.90 - DateTime::TimeZone::America::Scoresbysund 1.90 - DateTime::TimeZone::America::Sitka 1.90 - DateTime::TimeZone::America::St_Johns 1.90 - DateTime::TimeZone::America::Swift_Current 1.90 - DateTime::TimeZone::America::Tegucigalpa 1.90 - DateTime::TimeZone::America::Thule 1.90 - DateTime::TimeZone::America::Thunder_Bay 1.90 - DateTime::TimeZone::America::Tijuana 1.90 - DateTime::TimeZone::America::Toronto 1.90 - DateTime::TimeZone::America::Vancouver 1.90 - DateTime::TimeZone::America::Whitehorse 1.90 - DateTime::TimeZone::America::Winnipeg 1.90 - DateTime::TimeZone::America::Yakutat 1.90 - DateTime::TimeZone::America::Yellowknife 1.90 - DateTime::TimeZone::Antarctica::Casey 1.90 - DateTime::TimeZone::Antarctica::Davis 1.90 - DateTime::TimeZone::Antarctica::DumontDUrville 1.90 - DateTime::TimeZone::Antarctica::Macquarie 1.90 - DateTime::TimeZone::Antarctica::Mawson 1.90 - DateTime::TimeZone::Antarctica::Palmer 1.90 - DateTime::TimeZone::Antarctica::Rothera 1.90 - DateTime::TimeZone::Antarctica::Syowa 1.90 - DateTime::TimeZone::Antarctica::Troll 1.90 - DateTime::TimeZone::Antarctica::Vostok 1.90 - DateTime::TimeZone::Asia::Almaty 1.90 - DateTime::TimeZone::Asia::Amman 1.90 - DateTime::TimeZone::Asia::Anadyr 1.90 - DateTime::TimeZone::Asia::Aqtau 1.90 - DateTime::TimeZone::Asia::Aqtobe 1.90 - DateTime::TimeZone::Asia::Ashgabat 1.90 - DateTime::TimeZone::Asia::Baghdad 1.90 - DateTime::TimeZone::Asia::Baku 1.90 - DateTime::TimeZone::Asia::Bangkok 1.90 - DateTime::TimeZone::Asia::Beirut 1.90 - DateTime::TimeZone::Asia::Bishkek 1.90 - DateTime::TimeZone::Asia::Brunei 1.90 - DateTime::TimeZone::Asia::Chita 1.90 - DateTime::TimeZone::Asia::Choibalsan 1.90 - DateTime::TimeZone::Asia::Colombo 1.90 - DateTime::TimeZone::Asia::Damascus 1.90 - DateTime::TimeZone::Asia::Dhaka 1.90 - DateTime::TimeZone::Asia::Dili 1.90 - DateTime::TimeZone::Asia::Dubai 1.90 - DateTime::TimeZone::Asia::Dushanbe 1.90 - DateTime::TimeZone::Asia::Gaza 1.90 - DateTime::TimeZone::Asia::Hebron 1.90 - DateTime::TimeZone::Asia::Ho_Chi_Minh 1.90 - DateTime::TimeZone::Asia::Hong_Kong 1.90 - DateTime::TimeZone::Asia::Hovd 1.90 - DateTime::TimeZone::Asia::Irkutsk 1.90 - DateTime::TimeZone::Asia::Jakarta 1.90 - DateTime::TimeZone::Asia::Jayapura 1.90 - DateTime::TimeZone::Asia::Jerusalem 1.90 - DateTime::TimeZone::Asia::Kabul 1.90 - DateTime::TimeZone::Asia::Kamchatka 1.90 - DateTime::TimeZone::Asia::Karachi 1.90 - DateTime::TimeZone::Asia::Kathmandu 1.90 - DateTime::TimeZone::Asia::Khandyga 1.90 - DateTime::TimeZone::Asia::Kolkata 1.90 - DateTime::TimeZone::Asia::Krasnoyarsk 1.90 - DateTime::TimeZone::Asia::Kuala_Lumpur 1.90 - DateTime::TimeZone::Asia::Kuching 1.90 - DateTime::TimeZone::Asia::Macau 1.90 - DateTime::TimeZone::Asia::Magadan 1.90 - DateTime::TimeZone::Asia::Makassar 1.90 - DateTime::TimeZone::Asia::Manila 1.90 - DateTime::TimeZone::Asia::Nicosia 1.90 - DateTime::TimeZone::Asia::Novokuznetsk 1.90 - DateTime::TimeZone::Asia::Novosibirsk 1.90 - DateTime::TimeZone::Asia::Omsk 1.90 - DateTime::TimeZone::Asia::Oral 1.90 - DateTime::TimeZone::Asia::Pontianak 1.90 - DateTime::TimeZone::Asia::Pyongyang 1.90 - DateTime::TimeZone::Asia::Qatar 1.90 - DateTime::TimeZone::Asia::Qyzylorda 1.90 - DateTime::TimeZone::Asia::Rangoon 1.90 - DateTime::TimeZone::Asia::Riyadh 1.90 - DateTime::TimeZone::Asia::Sakhalin 1.90 - DateTime::TimeZone::Asia::Samarkand 1.90 - DateTime::TimeZone::Asia::Seoul 1.90 - DateTime::TimeZone::Asia::Shanghai 1.90 - DateTime::TimeZone::Asia::Singapore 1.90 - DateTime::TimeZone::Asia::Srednekolymsk 1.90 - DateTime::TimeZone::Asia::Taipei 1.90 - DateTime::TimeZone::Asia::Tashkent 1.90 - DateTime::TimeZone::Asia::Tbilisi 1.90 - DateTime::TimeZone::Asia::Tehran 1.90 - DateTime::TimeZone::Asia::Thimphu 1.90 - DateTime::TimeZone::Asia::Tokyo 1.90 - DateTime::TimeZone::Asia::Ulaanbaatar 1.90 - DateTime::TimeZone::Asia::Urumqi 1.90 - DateTime::TimeZone::Asia::Ust_Nera 1.90 - DateTime::TimeZone::Asia::Vladivostok 1.90 - DateTime::TimeZone::Asia::Yakutsk 1.90 - DateTime::TimeZone::Asia::Yekaterinburg 1.90 - DateTime::TimeZone::Asia::Yerevan 1.90 - DateTime::TimeZone::Atlantic::Azores 1.90 - DateTime::TimeZone::Atlantic::Bermuda 1.90 - DateTime::TimeZone::Atlantic::Canary 1.90 - DateTime::TimeZone::Atlantic::Cape_Verde 1.90 - DateTime::TimeZone::Atlantic::Faroe 1.90 - DateTime::TimeZone::Atlantic::Madeira 1.90 - DateTime::TimeZone::Atlantic::Reykjavik 1.90 - DateTime::TimeZone::Atlantic::South_Georgia 1.90 - DateTime::TimeZone::Atlantic::Stanley 1.90 - DateTime::TimeZone::Australia::Adelaide 1.90 - DateTime::TimeZone::Australia::Brisbane 1.90 - DateTime::TimeZone::Australia::Broken_Hill 1.90 - DateTime::TimeZone::Australia::Currie 1.90 - DateTime::TimeZone::Australia::Darwin 1.90 - DateTime::TimeZone::Australia::Eucla 1.90 - DateTime::TimeZone::Australia::Hobart 1.90 - DateTime::TimeZone::Australia::Lindeman 1.90 - DateTime::TimeZone::Australia::Lord_Howe 1.90 - DateTime::TimeZone::Australia::Melbourne 1.90 - DateTime::TimeZone::Australia::Perth 1.90 - DateTime::TimeZone::Australia::Sydney 1.90 - DateTime::TimeZone::CET 1.90 - DateTime::TimeZone::CST6CDT 1.90 - DateTime::TimeZone::Catalog 1.90 - DateTime::TimeZone::EET 1.90 - DateTime::TimeZone::EST 1.90 - DateTime::TimeZone::EST5EDT 1.90 - DateTime::TimeZone::Europe::Amsterdam 1.90 - DateTime::TimeZone::Europe::Andorra 1.90 - DateTime::TimeZone::Europe::Athens 1.90 - DateTime::TimeZone::Europe::Belgrade 1.90 - DateTime::TimeZone::Europe::Berlin 1.90 - DateTime::TimeZone::Europe::Brussels 1.90 - DateTime::TimeZone::Europe::Bucharest 1.90 - DateTime::TimeZone::Europe::Budapest 1.90 - DateTime::TimeZone::Europe::Chisinau 1.90 - DateTime::TimeZone::Europe::Copenhagen 1.90 - DateTime::TimeZone::Europe::Dublin 1.90 - DateTime::TimeZone::Europe::Gibraltar 1.90 - DateTime::TimeZone::Europe::Helsinki 1.90 - DateTime::TimeZone::Europe::Istanbul 1.90 - DateTime::TimeZone::Europe::Kaliningrad 1.90 - DateTime::TimeZone::Europe::Kiev 1.90 - DateTime::TimeZone::Europe::Lisbon 1.90 - DateTime::TimeZone::Europe::London 1.90 - DateTime::TimeZone::Europe::Luxembourg 1.90 - DateTime::TimeZone::Europe::Madrid 1.90 - DateTime::TimeZone::Europe::Malta 1.90 - DateTime::TimeZone::Europe::Minsk 1.90 - DateTime::TimeZone::Europe::Monaco 1.90 - DateTime::TimeZone::Europe::Moscow 1.90 - DateTime::TimeZone::Europe::Oslo 1.90 - DateTime::TimeZone::Europe::Paris 1.90 - DateTime::TimeZone::Europe::Prague 1.90 - DateTime::TimeZone::Europe::Riga 1.90 - DateTime::TimeZone::Europe::Rome 1.90 - DateTime::TimeZone::Europe::Samara 1.90 - DateTime::TimeZone::Europe::Simferopol 1.90 - DateTime::TimeZone::Europe::Sofia 1.90 - DateTime::TimeZone::Europe::Stockholm 1.90 - DateTime::TimeZone::Europe::Tallinn 1.90 - DateTime::TimeZone::Europe::Tirane 1.90 - DateTime::TimeZone::Europe::Uzhgorod 1.90 - DateTime::TimeZone::Europe::Vienna 1.90 - DateTime::TimeZone::Europe::Vilnius 1.90 - DateTime::TimeZone::Europe::Volgograd 1.90 - DateTime::TimeZone::Europe::Warsaw 1.90 - DateTime::TimeZone::Europe::Zaporozhye 1.90 - DateTime::TimeZone::Europe::Zurich 1.90 - DateTime::TimeZone::Floating 1.90 - DateTime::TimeZone::HST 1.90 - DateTime::TimeZone::Indian::Chagos 1.90 - DateTime::TimeZone::Indian::Christmas 1.90 - DateTime::TimeZone::Indian::Cocos 1.90 - DateTime::TimeZone::Indian::Kerguelen 1.90 - DateTime::TimeZone::Indian::Mahe 1.90 - DateTime::TimeZone::Indian::Maldives 1.90 - DateTime::TimeZone::Indian::Mauritius 1.90 - DateTime::TimeZone::Indian::Reunion 1.90 - DateTime::TimeZone::Local 1.90 - DateTime::TimeZone::Local::Android 1.90 - DateTime::TimeZone::Local::Unix 1.90 - DateTime::TimeZone::Local::VMS 1.90 - DateTime::TimeZone::MET 1.90 - DateTime::TimeZone::MST 1.90 - DateTime::TimeZone::MST7MDT 1.90 - DateTime::TimeZone::OffsetOnly 1.90 - DateTime::TimeZone::OlsonDB 1.90 - DateTime::TimeZone::OlsonDB::Change 1.90 - DateTime::TimeZone::OlsonDB::Observance 1.90 - DateTime::TimeZone::OlsonDB::Rule 1.90 - DateTime::TimeZone::OlsonDB::Zone 1.90 - DateTime::TimeZone::PST8PDT 1.90 - DateTime::TimeZone::Pacific::Apia 1.90 - DateTime::TimeZone::Pacific::Auckland 1.90 - DateTime::TimeZone::Pacific::Bougainville 1.90 - DateTime::TimeZone::Pacific::Chatham 1.90 - DateTime::TimeZone::Pacific::Chuuk 1.90 - DateTime::TimeZone::Pacific::Easter 1.90 - DateTime::TimeZone::Pacific::Efate 1.90 - DateTime::TimeZone::Pacific::Enderbury 1.90 - DateTime::TimeZone::Pacific::Fakaofo 1.90 - DateTime::TimeZone::Pacific::Fiji 1.90 - DateTime::TimeZone::Pacific::Funafuti 1.90 - DateTime::TimeZone::Pacific::Galapagos 1.90 - DateTime::TimeZone::Pacific::Gambier 1.90 - DateTime::TimeZone::Pacific::Guadalcanal 1.90 - DateTime::TimeZone::Pacific::Guam 1.90 - DateTime::TimeZone::Pacific::Honolulu 1.90 - DateTime::TimeZone::Pacific::Kiritimati 1.90 - DateTime::TimeZone::Pacific::Kosrae 1.90 - DateTime::TimeZone::Pacific::Kwajalein 1.90 - DateTime::TimeZone::Pacific::Majuro 1.90 - DateTime::TimeZone::Pacific::Marquesas 1.90 - DateTime::TimeZone::Pacific::Nauru 1.90 - DateTime::TimeZone::Pacific::Niue 1.90 - DateTime::TimeZone::Pacific::Norfolk 1.90 - DateTime::TimeZone::Pacific::Noumea 1.90 - DateTime::TimeZone::Pacific::Pago_Pago 1.90 - DateTime::TimeZone::Pacific::Palau 1.90 - DateTime::TimeZone::Pacific::Pitcairn 1.90 - DateTime::TimeZone::Pacific::Pohnpei 1.90 - DateTime::TimeZone::Pacific::Port_Moresby 1.90 - DateTime::TimeZone::Pacific::Rarotonga 1.90 - DateTime::TimeZone::Pacific::Tahiti 1.90 - DateTime::TimeZone::Pacific::Tarawa 1.90 - DateTime::TimeZone::Pacific::Tongatapu 1.90 - DateTime::TimeZone::Pacific::Wake 1.90 - DateTime::TimeZone::Pacific::Wallis 1.90 - DateTime::TimeZone::UTC 1.90 - DateTime::TimeZone::WET 1.90 + DateTime::TimeZone 2.13 + DateTime::TimeZone::Africa::Abidjan 2.13 + DateTime::TimeZone::Africa::Accra 2.13 + DateTime::TimeZone::Africa::Algiers 2.13 + DateTime::TimeZone::Africa::Bissau 2.13 + DateTime::TimeZone::Africa::Cairo 2.13 + DateTime::TimeZone::Africa::Casablanca 2.13 + DateTime::TimeZone::Africa::Ceuta 2.13 + DateTime::TimeZone::Africa::El_Aaiun 2.13 + DateTime::TimeZone::Africa::Johannesburg 2.13 + DateTime::TimeZone::Africa::Khartoum 2.13 + DateTime::TimeZone::Africa::Lagos 2.13 + DateTime::TimeZone::Africa::Maputo 2.13 + DateTime::TimeZone::Africa::Monrovia 2.13 + DateTime::TimeZone::Africa::Nairobi 2.13 + DateTime::TimeZone::Africa::Ndjamena 2.13 + DateTime::TimeZone::Africa::Tripoli 2.13 + DateTime::TimeZone::Africa::Tunis 2.13 + DateTime::TimeZone::Africa::Windhoek 2.13 + DateTime::TimeZone::America::Adak 2.13 + DateTime::TimeZone::America::Anchorage 2.13 + DateTime::TimeZone::America::Araguaina 2.13 + DateTime::TimeZone::America::Argentina::Buenos_Aires 2.13 + DateTime::TimeZone::America::Argentina::Catamarca 2.13 + DateTime::TimeZone::America::Argentina::Cordoba 2.13 + DateTime::TimeZone::America::Argentina::Jujuy 2.13 + DateTime::TimeZone::America::Argentina::La_Rioja 2.13 + DateTime::TimeZone::America::Argentina::Mendoza 2.13 + DateTime::TimeZone::America::Argentina::Rio_Gallegos 2.13 + DateTime::TimeZone::America::Argentina::Salta 2.13 + DateTime::TimeZone::America::Argentina::San_Juan 2.13 + DateTime::TimeZone::America::Argentina::San_Luis 2.13 + DateTime::TimeZone::America::Argentina::Tucuman 2.13 + DateTime::TimeZone::America::Argentina::Ushuaia 2.13 + DateTime::TimeZone::America::Asuncion 2.13 + DateTime::TimeZone::America::Atikokan 2.13 + DateTime::TimeZone::America::Bahia 2.13 + DateTime::TimeZone::America::Bahia_Banderas 2.13 + DateTime::TimeZone::America::Barbados 2.13 + DateTime::TimeZone::America::Belem 2.13 + DateTime::TimeZone::America::Belize 2.13 + DateTime::TimeZone::America::Blanc_Sablon 2.13 + DateTime::TimeZone::America::Boa_Vista 2.13 + DateTime::TimeZone::America::Bogota 2.13 + DateTime::TimeZone::America::Boise 2.13 + DateTime::TimeZone::America::Cambridge_Bay 2.13 + DateTime::TimeZone::America::Campo_Grande 2.13 + DateTime::TimeZone::America::Cancun 2.13 + DateTime::TimeZone::America::Caracas 2.13 + DateTime::TimeZone::America::Cayenne 2.13 + DateTime::TimeZone::America::Chicago 2.13 + DateTime::TimeZone::America::Chihuahua 2.13 + DateTime::TimeZone::America::Costa_Rica 2.13 + DateTime::TimeZone::America::Creston 2.13 + DateTime::TimeZone::America::Cuiaba 2.13 + DateTime::TimeZone::America::Curacao 2.13 + DateTime::TimeZone::America::Danmarkshavn 2.13 + DateTime::TimeZone::America::Dawson 2.13 + DateTime::TimeZone::America::Dawson_Creek 2.13 + DateTime::TimeZone::America::Denver 2.13 + DateTime::TimeZone::America::Detroit 2.13 + DateTime::TimeZone::America::Edmonton 2.13 + DateTime::TimeZone::America::Eirunepe 2.13 + DateTime::TimeZone::America::El_Salvador 2.13 + DateTime::TimeZone::America::Fort_Nelson 2.13 + DateTime::TimeZone::America::Fortaleza 2.13 + DateTime::TimeZone::America::Glace_Bay 2.13 + DateTime::TimeZone::America::Godthab 2.13 + DateTime::TimeZone::America::Goose_Bay 2.13 + DateTime::TimeZone::America::Grand_Turk 2.13 + DateTime::TimeZone::America::Guatemala 2.13 + DateTime::TimeZone::America::Guayaquil 2.13 + DateTime::TimeZone::America::Guyana 2.13 + DateTime::TimeZone::America::Halifax 2.13 + DateTime::TimeZone::America::Havana 2.13 + DateTime::TimeZone::America::Hermosillo 2.13 + DateTime::TimeZone::America::Indiana::Indianapolis 2.13 + DateTime::TimeZone::America::Indiana::Knox 2.13 + DateTime::TimeZone::America::Indiana::Marengo 2.13 + DateTime::TimeZone::America::Indiana::Petersburg 2.13 + DateTime::TimeZone::America::Indiana::Tell_City 2.13 + DateTime::TimeZone::America::Indiana::Vevay 2.13 + DateTime::TimeZone::America::Indiana::Vincennes 2.13 + DateTime::TimeZone::America::Indiana::Winamac 2.13 + DateTime::TimeZone::America::Inuvik 2.13 + DateTime::TimeZone::America::Iqaluit 2.13 + DateTime::TimeZone::America::Jamaica 2.13 + DateTime::TimeZone::America::Juneau 2.13 + DateTime::TimeZone::America::Kentucky::Louisville 2.13 + DateTime::TimeZone::America::Kentucky::Monticello 2.13 + DateTime::TimeZone::America::La_Paz 2.13 + DateTime::TimeZone::America::Lima 2.13 + DateTime::TimeZone::America::Los_Angeles 2.13 + DateTime::TimeZone::America::Maceio 2.13 + DateTime::TimeZone::America::Managua 2.13 + DateTime::TimeZone::America::Manaus 2.13 + DateTime::TimeZone::America::Martinique 2.13 + DateTime::TimeZone::America::Matamoros 2.13 + DateTime::TimeZone::America::Mazatlan 2.13 + DateTime::TimeZone::America::Menominee 2.13 + DateTime::TimeZone::America::Merida 2.13 + DateTime::TimeZone::America::Metlakatla 2.13 + DateTime::TimeZone::America::Mexico_City 2.13 + DateTime::TimeZone::America::Miquelon 2.13 + DateTime::TimeZone::America::Moncton 2.13 + DateTime::TimeZone::America::Monterrey 2.13 + DateTime::TimeZone::America::Montevideo 2.13 + DateTime::TimeZone::America::Nassau 2.13 + DateTime::TimeZone::America::New_York 2.13 + DateTime::TimeZone::America::Nipigon 2.13 + DateTime::TimeZone::America::Nome 2.13 + DateTime::TimeZone::America::Noronha 2.13 + DateTime::TimeZone::America::North_Dakota::Beulah 2.13 + DateTime::TimeZone::America::North_Dakota::Center 2.13 + DateTime::TimeZone::America::North_Dakota::New_Salem 2.13 + DateTime::TimeZone::America::Ojinaga 2.13 + DateTime::TimeZone::America::Panama 2.13 + DateTime::TimeZone::America::Pangnirtung 2.13 + DateTime::TimeZone::America::Paramaribo 2.13 + DateTime::TimeZone::America::Phoenix 2.13 + DateTime::TimeZone::America::Port_au_Prince 2.13 + DateTime::TimeZone::America::Port_of_Spain 2.13 + DateTime::TimeZone::America::Porto_Velho 2.13 + DateTime::TimeZone::America::Puerto_Rico 2.13 + DateTime::TimeZone::America::Punta_Arenas 2.13 + DateTime::TimeZone::America::Rainy_River 2.13 + DateTime::TimeZone::America::Rankin_Inlet 2.13 + DateTime::TimeZone::America::Recife 2.13 + DateTime::TimeZone::America::Regina 2.13 + DateTime::TimeZone::America::Resolute 2.13 + DateTime::TimeZone::America::Rio_Branco 2.13 + DateTime::TimeZone::America::Santarem 2.13 + DateTime::TimeZone::America::Santiago 2.13 + DateTime::TimeZone::America::Santo_Domingo 2.13 + DateTime::TimeZone::America::Sao_Paulo 2.13 + DateTime::TimeZone::America::Scoresbysund 2.13 + DateTime::TimeZone::America::Sitka 2.13 + DateTime::TimeZone::America::St_Johns 2.13 + DateTime::TimeZone::America::Swift_Current 2.13 + DateTime::TimeZone::America::Tegucigalpa 2.13 + DateTime::TimeZone::America::Thule 2.13 + DateTime::TimeZone::America::Thunder_Bay 2.13 + DateTime::TimeZone::America::Tijuana 2.13 + DateTime::TimeZone::America::Toronto 2.13 + DateTime::TimeZone::America::Vancouver 2.13 + DateTime::TimeZone::America::Whitehorse 2.13 + DateTime::TimeZone::America::Winnipeg 2.13 + DateTime::TimeZone::America::Yakutat 2.13 + DateTime::TimeZone::America::Yellowknife 2.13 + DateTime::TimeZone::Antarctica::Casey 2.13 + DateTime::TimeZone::Antarctica::Davis 2.13 + DateTime::TimeZone::Antarctica::DumontDUrville 2.13 + DateTime::TimeZone::Antarctica::Macquarie 2.13 + DateTime::TimeZone::Antarctica::Mawson 2.13 + DateTime::TimeZone::Antarctica::Palmer 2.13 + DateTime::TimeZone::Antarctica::Rothera 2.13 + DateTime::TimeZone::Antarctica::Syowa 2.13 + DateTime::TimeZone::Antarctica::Troll 2.13 + DateTime::TimeZone::Antarctica::Vostok 2.13 + DateTime::TimeZone::Asia::Almaty 2.13 + DateTime::TimeZone::Asia::Amman 2.13 + DateTime::TimeZone::Asia::Anadyr 2.13 + DateTime::TimeZone::Asia::Aqtau 2.13 + DateTime::TimeZone::Asia::Aqtobe 2.13 + DateTime::TimeZone::Asia::Ashgabat 2.13 + DateTime::TimeZone::Asia::Atyrau 2.13 + DateTime::TimeZone::Asia::Baghdad 2.13 + DateTime::TimeZone::Asia::Baku 2.13 + DateTime::TimeZone::Asia::Bangkok 2.13 + DateTime::TimeZone::Asia::Barnaul 2.13 + DateTime::TimeZone::Asia::Beirut 2.13 + DateTime::TimeZone::Asia::Bishkek 2.13 + DateTime::TimeZone::Asia::Brunei 2.13 + DateTime::TimeZone::Asia::Chita 2.13 + DateTime::TimeZone::Asia::Choibalsan 2.13 + DateTime::TimeZone::Asia::Colombo 2.13 + DateTime::TimeZone::Asia::Damascus 2.13 + DateTime::TimeZone::Asia::Dhaka 2.13 + DateTime::TimeZone::Asia::Dili 2.13 + DateTime::TimeZone::Asia::Dubai 2.13 + DateTime::TimeZone::Asia::Dushanbe 2.13 + DateTime::TimeZone::Asia::Famagusta 2.13 + DateTime::TimeZone::Asia::Gaza 2.13 + DateTime::TimeZone::Asia::Hebron 2.13 + DateTime::TimeZone::Asia::Ho_Chi_Minh 2.13 + DateTime::TimeZone::Asia::Hong_Kong 2.13 + DateTime::TimeZone::Asia::Hovd 2.13 + DateTime::TimeZone::Asia::Irkutsk 2.13 + DateTime::TimeZone::Asia::Jakarta 2.13 + DateTime::TimeZone::Asia::Jayapura 2.13 + DateTime::TimeZone::Asia::Jerusalem 2.13 + DateTime::TimeZone::Asia::Kabul 2.13 + DateTime::TimeZone::Asia::Kamchatka 2.13 + DateTime::TimeZone::Asia::Karachi 2.13 + DateTime::TimeZone::Asia::Kathmandu 2.13 + DateTime::TimeZone::Asia::Khandyga 2.13 + DateTime::TimeZone::Asia::Kolkata 2.13 + DateTime::TimeZone::Asia::Krasnoyarsk 2.13 + DateTime::TimeZone::Asia::Kuala_Lumpur 2.13 + DateTime::TimeZone::Asia::Kuching 2.13 + DateTime::TimeZone::Asia::Macau 2.13 + DateTime::TimeZone::Asia::Magadan 2.13 + DateTime::TimeZone::Asia::Makassar 2.13 + DateTime::TimeZone::Asia::Manila 2.13 + DateTime::TimeZone::Asia::Nicosia 2.13 + DateTime::TimeZone::Asia::Novokuznetsk 2.13 + DateTime::TimeZone::Asia::Novosibirsk 2.13 + DateTime::TimeZone::Asia::Omsk 2.13 + DateTime::TimeZone::Asia::Oral 2.13 + DateTime::TimeZone::Asia::Pontianak 2.13 + DateTime::TimeZone::Asia::Pyongyang 2.13 + DateTime::TimeZone::Asia::Qatar 2.13 + DateTime::TimeZone::Asia::Qyzylorda 2.13 + DateTime::TimeZone::Asia::Riyadh 2.13 + DateTime::TimeZone::Asia::Sakhalin 2.13 + DateTime::TimeZone::Asia::Samarkand 2.13 + DateTime::TimeZone::Asia::Seoul 2.13 + DateTime::TimeZone::Asia::Shanghai 2.13 + DateTime::TimeZone::Asia::Singapore 2.13 + DateTime::TimeZone::Asia::Srednekolymsk 2.13 + DateTime::TimeZone::Asia::Taipei 2.13 + DateTime::TimeZone::Asia::Tashkent 2.13 + DateTime::TimeZone::Asia::Tbilisi 2.13 + DateTime::TimeZone::Asia::Tehran 2.13 + DateTime::TimeZone::Asia::Thimphu 2.13 + DateTime::TimeZone::Asia::Tokyo 2.13 + DateTime::TimeZone::Asia::Tomsk 2.13 + DateTime::TimeZone::Asia::Ulaanbaatar 2.13 + DateTime::TimeZone::Asia::Urumqi 2.13 + DateTime::TimeZone::Asia::Ust_Nera 2.13 + DateTime::TimeZone::Asia::Vladivostok 2.13 + DateTime::TimeZone::Asia::Yakutsk 2.13 + DateTime::TimeZone::Asia::Yangon 2.13 + DateTime::TimeZone::Asia::Yekaterinburg 2.13 + DateTime::TimeZone::Asia::Yerevan 2.13 + DateTime::TimeZone::Atlantic::Azores 2.13 + DateTime::TimeZone::Atlantic::Bermuda 2.13 + DateTime::TimeZone::Atlantic::Canary 2.13 + DateTime::TimeZone::Atlantic::Cape_Verde 2.13 + DateTime::TimeZone::Atlantic::Faroe 2.13 + DateTime::TimeZone::Atlantic::Madeira 2.13 + DateTime::TimeZone::Atlantic::Reykjavik 2.13 + DateTime::TimeZone::Atlantic::South_Georgia 2.13 + DateTime::TimeZone::Atlantic::Stanley 2.13 + DateTime::TimeZone::Australia::Adelaide 2.13 + DateTime::TimeZone::Australia::Brisbane 2.13 + DateTime::TimeZone::Australia::Broken_Hill 2.13 + DateTime::TimeZone::Australia::Currie 2.13 + DateTime::TimeZone::Australia::Darwin 2.13 + DateTime::TimeZone::Australia::Eucla 2.13 + DateTime::TimeZone::Australia::Hobart 2.13 + DateTime::TimeZone::Australia::Lindeman 2.13 + DateTime::TimeZone::Australia::Lord_Howe 2.13 + DateTime::TimeZone::Australia::Melbourne 2.13 + DateTime::TimeZone::Australia::Perth 2.13 + DateTime::TimeZone::Australia::Sydney 2.13 + DateTime::TimeZone::CET 2.13 + DateTime::TimeZone::CST6CDT 2.13 + DateTime::TimeZone::Catalog 2.13 + DateTime::TimeZone::EET 2.13 + DateTime::TimeZone::EST 2.13 + DateTime::TimeZone::EST5EDT 2.13 + DateTime::TimeZone::Europe::Amsterdam 2.13 + DateTime::TimeZone::Europe::Andorra 2.13 + DateTime::TimeZone::Europe::Astrakhan 2.13 + DateTime::TimeZone::Europe::Athens 2.13 + DateTime::TimeZone::Europe::Belgrade 2.13 + DateTime::TimeZone::Europe::Berlin 2.13 + DateTime::TimeZone::Europe::Brussels 2.13 + DateTime::TimeZone::Europe::Bucharest 2.13 + DateTime::TimeZone::Europe::Budapest 2.13 + DateTime::TimeZone::Europe::Chisinau 2.13 + DateTime::TimeZone::Europe::Copenhagen 2.13 + DateTime::TimeZone::Europe::Dublin 2.13 + DateTime::TimeZone::Europe::Gibraltar 2.13 + DateTime::TimeZone::Europe::Helsinki 2.13 + DateTime::TimeZone::Europe::Istanbul 2.13 + DateTime::TimeZone::Europe::Kaliningrad 2.13 + DateTime::TimeZone::Europe::Kiev 2.13 + DateTime::TimeZone::Europe::Kirov 2.13 + DateTime::TimeZone::Europe::Lisbon 2.13 + DateTime::TimeZone::Europe::London 2.13 + DateTime::TimeZone::Europe::Luxembourg 2.13 + DateTime::TimeZone::Europe::Madrid 2.13 + DateTime::TimeZone::Europe::Malta 2.13 + DateTime::TimeZone::Europe::Minsk 2.13 + DateTime::TimeZone::Europe::Monaco 2.13 + DateTime::TimeZone::Europe::Moscow 2.13 + DateTime::TimeZone::Europe::Oslo 2.13 + DateTime::TimeZone::Europe::Paris 2.13 + DateTime::TimeZone::Europe::Prague 2.13 + DateTime::TimeZone::Europe::Riga 2.13 + DateTime::TimeZone::Europe::Rome 2.13 + DateTime::TimeZone::Europe::Samara 2.13 + DateTime::TimeZone::Europe::Saratov 2.13 + DateTime::TimeZone::Europe::Simferopol 2.13 + DateTime::TimeZone::Europe::Sofia 2.13 + DateTime::TimeZone::Europe::Stockholm 2.13 + DateTime::TimeZone::Europe::Tallinn 2.13 + DateTime::TimeZone::Europe::Tirane 2.13 + DateTime::TimeZone::Europe::Ulyanovsk 2.13 + DateTime::TimeZone::Europe::Uzhgorod 2.13 + DateTime::TimeZone::Europe::Vienna 2.13 + DateTime::TimeZone::Europe::Vilnius 2.13 + DateTime::TimeZone::Europe::Volgograd 2.13 + DateTime::TimeZone::Europe::Warsaw 2.13 + DateTime::TimeZone::Europe::Zaporozhye 2.13 + DateTime::TimeZone::Europe::Zurich 2.13 + DateTime::TimeZone::Floating 2.13 + DateTime::TimeZone::HST 2.13 + DateTime::TimeZone::Indian::Chagos 2.13 + DateTime::TimeZone::Indian::Christmas 2.13 + DateTime::TimeZone::Indian::Cocos 2.13 + DateTime::TimeZone::Indian::Kerguelen 2.13 + DateTime::TimeZone::Indian::Mahe 2.13 + DateTime::TimeZone::Indian::Maldives 2.13 + DateTime::TimeZone::Indian::Mauritius 2.13 + DateTime::TimeZone::Indian::Reunion 2.13 + DateTime::TimeZone::Local 2.13 + DateTime::TimeZone::Local::Android 2.13 + DateTime::TimeZone::Local::Unix 2.13 + DateTime::TimeZone::Local::VMS 2.13 + DateTime::TimeZone::MET 2.13 + DateTime::TimeZone::MST 2.13 + DateTime::TimeZone::MST7MDT 2.13 + DateTime::TimeZone::OffsetOnly 2.13 + DateTime::TimeZone::OlsonDB 2.13 + DateTime::TimeZone::OlsonDB::Change 2.13 + DateTime::TimeZone::OlsonDB::Observance 2.13 + DateTime::TimeZone::OlsonDB::Rule 2.13 + DateTime::TimeZone::OlsonDB::Zone 2.13 + DateTime::TimeZone::PST8PDT 2.13 + DateTime::TimeZone::Pacific::Apia 2.13 + DateTime::TimeZone::Pacific::Auckland 2.13 + DateTime::TimeZone::Pacific::Bougainville 2.13 + DateTime::TimeZone::Pacific::Chatham 2.13 + DateTime::TimeZone::Pacific::Chuuk 2.13 + DateTime::TimeZone::Pacific::Easter 2.13 + DateTime::TimeZone::Pacific::Efate 2.13 + DateTime::TimeZone::Pacific::Enderbury 2.13 + DateTime::TimeZone::Pacific::Fakaofo 2.13 + DateTime::TimeZone::Pacific::Fiji 2.13 + DateTime::TimeZone::Pacific::Funafuti 2.13 + DateTime::TimeZone::Pacific::Galapagos 2.13 + DateTime::TimeZone::Pacific::Gambier 2.13 + DateTime::TimeZone::Pacific::Guadalcanal 2.13 + DateTime::TimeZone::Pacific::Guam 2.13 + DateTime::TimeZone::Pacific::Honolulu 2.13 + DateTime::TimeZone::Pacific::Kiritimati 2.13 + DateTime::TimeZone::Pacific::Kosrae 2.13 + DateTime::TimeZone::Pacific::Kwajalein 2.13 + DateTime::TimeZone::Pacific::Majuro 2.13 + DateTime::TimeZone::Pacific::Marquesas 2.13 + DateTime::TimeZone::Pacific::Nauru 2.13 + DateTime::TimeZone::Pacific::Niue 2.13 + DateTime::TimeZone::Pacific::Norfolk 2.13 + DateTime::TimeZone::Pacific::Noumea 2.13 + DateTime::TimeZone::Pacific::Pago_Pago 2.13 + DateTime::TimeZone::Pacific::Palau 2.13 + DateTime::TimeZone::Pacific::Pitcairn 2.13 + DateTime::TimeZone::Pacific::Pohnpei 2.13 + DateTime::TimeZone::Pacific::Port_Moresby 2.13 + DateTime::TimeZone::Pacific::Rarotonga 2.13 + DateTime::TimeZone::Pacific::Tahiti 2.13 + DateTime::TimeZone::Pacific::Tarawa 2.13 + DateTime::TimeZone::Pacific::Tongatapu 2.13 + DateTime::TimeZone::Pacific::Wake 2.13 + DateTime::TimeZone::Pacific::Wallis 2.13 + DateTime::TimeZone::UTC 2.13 + DateTime::TimeZone::WET 2.13 requirements: Class::Singleton 1.03 Cwd 3 @@ -1130,16 +786,50 @@ DISTRIBUTIONS File::Compare 0 File::Find 0 File::Spec 0 - List::AllUtils 0 - List::Util 0 + List::Util 1.33 Module::Runtime 0 - Params::Validate 0.72 + Params::ValidationCompiler 0.13 + Specio::Library::Builtins 0 + Specio::Library::String 0 Try::Tiny 0 constant 0 + namespace::autoclean 0 parent 0 + perl 5.008004 + strict 0 + warnings 0 + Devel-GlobalDestruction-0.14 + pathname: H/HA/HAARG/Devel-GlobalDestruction-0.14.tar.gz + provides: + Devel::GlobalDestruction 0.14 + requirements: + ExtUtils::MakeMaker 0 + Sub::Exporter::Progressive 0.001011 + perl 5.006 + Devel-StackTrace-2.02 + pathname: D/DR/DROLSKY/Devel-StackTrace-2.02.tar.gz + provides: + Devel::StackTrace 2.02 + Devel::StackTrace::Frame 2.02 + requirements: + ExtUtils::MakeMaker 0 + File::Spec 0 + Scalar::Util 0 + overload 0 perl 5.006 strict 0 - vars 0 + warnings 0 + Dist-CheckConflicts-0.11 + pathname: D/DO/DOY/Dist-CheckConflicts-0.11.tar.gz + provides: + Dist::CheckConflicts 0.11 + requirements: + Carp 0 + Exporter 0 + ExtUtils::MakeMaker 6.30 + Module::Runtime 0.009 + base 0 + strict 0 warnings 0 EV-4.22 pathname: M/ML/MLEHMANN/EV-4.22.tar.gz @@ -1150,14 +840,81 @@ DISTRIBUTIONS Canary::Stability 0 ExtUtils::MakeMaker 6.52 common::sense 0 - Exporter-Tiny-0.042 - pathname: T/TO/TOBYINK/Exporter-Tiny-0.042.tar.gz + Eval-Closure-0.14 + pathname: D/DO/DOY/Eval-Closure-0.14.tar.gz provides: - Exporter::Shiny 0.042 - Exporter::Tiny 0.042 + Eval::Closure 0.14 + requirements: + Carp 0 + Exporter 0 + ExtUtils::MakeMaker 0 + Scalar::Util 0 + constant 0 + overload 0 + strict 0 + warnings 0 + Exception-Class-1.42 + pathname: D/DR/DROLSKY/Exception-Class-1.42.tar.gz + provides: + Exception::Class 1.42 + Exception::Class::Base 1.42 + requirements: + Class::Data::Inheritable 0.02 + Devel::StackTrace 2.00 + ExtUtils::MakeMaker 0 + Scalar::Util 0 + base 0 + overload 0 + perl 5.008001 + strict 0 + warnings 0 + Exporter-Tiny-1.000000 + pathname: T/TO/TOBYINK/Exporter-Tiny-1.000000.tar.gz + provides: + Exporter::Shiny 1.000000 + Exporter::Tiny 1.000000 requirements: ExtUtils::MakeMaker 6.17 perl 5.006001 + ExtUtils-Config-0.008 + pathname: L/LE/LEONT/ExtUtils-Config-0.008.tar.gz + provides: + ExtUtils::Config 0.008 + requirements: + Data::Dumper 0 + ExtUtils::MakeMaker 6.30 + strict 0 + warnings 0 + ExtUtils-Helpers-0.026 + pathname: L/LE/LEONT/ExtUtils-Helpers-0.026.tar.gz + provides: + ExtUtils::Helpers 0.026 + ExtUtils::Helpers::Unix 0.026 + ExtUtils::Helpers::VMS 0.026 + ExtUtils::Helpers::Windows 0.026 + requirements: + Carp 0 + Exporter 5.57 + ExtUtils::MakeMaker 0 + File::Basename 0 + File::Copy 0 + File::Spec::Functions 0 + Text::ParseWords 3.24 + perl 5.006 + strict 0 + warnings 0 + ExtUtils-InstallPaths-0.011 + pathname: L/LE/LEONT/ExtUtils-InstallPaths-0.011.tar.gz + provides: + ExtUtils::InstallPaths 0.011 + requirements: + Carp 0 + ExtUtils::Config 0.002 + ExtUtils::MakeMaker 0 + File::Spec 0 + perl 5.006 + strict 0 + warnings 0 File-BaseDir-0.07 pathname: K/KI/KIMRYAN/File-BaseDir-0.07.tar.gz provides: @@ -1173,24 +930,26 @@ DISTRIBUTIONS IPC::System::Simple 0 Module::Build 0.24 Test::More 0 - File-DesktopEntry-0.12 - pathname: M/MI/MICHIELB/File-DesktopEntry-0.12.tar.gz + File-DesktopEntry-0.22 + pathname: M/MI/MICHIELB/File-DesktopEntry-0.22.tar.gz provides: - File::DesktopEntry 0.12 + File::DesktopEntry 0.22 requirements: Carp 0 + Encode 0 ExtUtils::MakeMaker 6.30 File::BaseDir 0.03 File::Path 0 File::Spec 0 + URI::Escape 0 perl 5.008006 - File-MimeInfo-0.27 - pathname: M/MI/MICHIELB/File-MimeInfo-0.27.tar.gz + File-MimeInfo-0.28 + pathname: M/MI/MICHIELB/File-MimeInfo-0.28.tar.gz provides: - File::MimeInfo 0.27 - File::MimeInfo::Applications 0.27 - File::MimeInfo::Magic 0.27 - File::MimeInfo::Rox 0.27 + File::MimeInfo 0.28 + File::MimeInfo::Applications 0.28 + File::MimeInfo::Magic 0.28 + File::MimeInfo::Rox 0.28 requirements: Carp 0 Exporter 0 @@ -1200,16 +959,46 @@ DISTRIBUTIONS File::DesktopEntry 0.04 Pod::Usage 0 perl 5.006001 - File-Remove-1.52 - pathname: A/AD/ADAMK/File-Remove-1.52.tar.gz + File-Remove-1.57 + pathname: S/SH/SHLOMIF/File-Remove-1.57.tar.gz provides: - File::Remove 1.52 + File::Remove 1.57 requirements: Cwd 3.29 - ExtUtils::MakeMaker 6.36 + ExtUtils::MakeMaker 0 + File::Glob 0 + File::Path 0 File::Spec 3.29 - Test::More 0.42 - perl 5.00503 + constant 0 + perl 5.006 + strict 0 + vars 0 + warnings 0 + File-ShareDir-1.102 + pathname: R/RE/REHSACK/File-ShareDir-1.102.tar.gz + provides: + File::ShareDir 1.102 + requirements: + Carp 0 + Class::Inspector 1.12 + ExtUtils::MakeMaker 0 + File::ShareDir::Install 0.03 + File::Spec 0.80 + perl 5.008001 + warnings 0 + File-ShareDir-Install-0.11 + pathname: E/ET/ETHER/File-ShareDir-Install-0.11.tar.gz + provides: + File::ShareDir::Install 0.11 + requirements: + Carp 0 + Exporter 0 + File::Spec 0 + IO::Dir 0 + Module::Build::Tiny 0.034 + perl 5.008 + strict 0 + warnings 0 File-Which-1.21 pathname: P/PL/PLICEASE/File-Which-1.21.tar.gz provides: @@ -1217,10 +1006,10 @@ DISTRIBUTIONS requirements: ExtUtils::MakeMaker 0 perl 5.006 - Filesys-DiskUsage-0.08 - pathname: S/SZ/SZABGAB/Filesys-DiskUsage-0.08.tar.gz + Filesys-DiskUsage-0.10 + pathname: M/MA/MANWAR/Filesys-DiskUsage-0.10.tar.gz provides: - Filesys::DiskUsage 0.08 + Filesys::DiskUsage 0.10 requirements: ExtUtils::MakeMaker 0 File::Basename 0 @@ -1228,6 +1017,7 @@ DISTRIBUTIONS File::Temp 0 Test::More 0 Test::Warn 0 + perl 5.006 HTTP-Lite-2.44 pathname: N/NE/NEILB/HTTP-Lite-2.44.tar.gz provides: @@ -1239,25 +1029,33 @@ DISTRIBUTIONS perl 5.005 strict 0 warnings 0 - IO-Socket-IP-0.37 - pathname: P/PE/PEVANS/IO-Socket-IP-0.37.tar.gz + Hash-Merge-0.200 + pathname: R/RE/REHSACK/Hash-Merge-0.200.tar.gz provides: - IO::Socket::IP 0.37 + Hash::Merge 0.200 + requirements: + Clone 0 + ExtUtils::MakeMaker 0 + perl 5.008001 + IO-Socket-IP-0.39 + pathname: P/PE/PEVANS/IO-Socket-IP-0.39.tar.gz + provides: + IO::Socket::IP 0.39 requirements: IO::Socket 0 Socket 1.97 Test::More 0.88 - IO-Socket-SSL-2.027 - pathname: S/SU/SULLR/IO-Socket-SSL-2.027.tar.gz + IO-Socket-SSL-2.048 + pathname: S/SU/SULLR/IO-Socket-SSL-2.048.tar.gz provides: - IO::Socket::SSL 2.027 + IO::Socket::SSL 2.048 IO::Socket::SSL::Intercept 2.014 - IO::Socket::SSL::OCSP_Cache 2.027 - IO::Socket::SSL::OCSP_Resolver 2.027 + IO::Socket::SSL::OCSP_Cache 2.048 + IO::Socket::SSL::OCSP_Resolver 2.048 IO::Socket::SSL::PublicSuffix undef - IO::Socket::SSL::SSL_Context 2.027 - IO::Socket::SSL::SSL_HANDLE 2.027 - IO::Socket::SSL::Session_Cache 2.027 + IO::Socket::SSL::SSL_Context 2.048 + IO::Socket::SSL::SSL_HANDLE 2.048 + IO::Socket::SSL::Session_Cache 2.048 IO::Socket::SSL::Utils 2.014 requirements: ExtUtils::MakeMaker 0 @@ -1302,79 +1100,83 @@ DISTRIBUTIONS re 0 strict 0 warnings 0 - Image-ExifTool-10.15 - pathname: E/EX/EXIFTOOL/Image-ExifTool-10.15.tar.gz + Image-ExifTool-10.55 + pathname: E/EX/EXIFTOOL/Image-ExifTool-10.55.tar.gz provides: File::RandomAccess 1.10 - Image::ExifTool 10.15 + Image::ExifTool 10.55 Image::ExifTool::AES 1.01 Image::ExifTool::AFCP 1.07 Image::ExifTool::AIFF 1.07 Image::ExifTool::APE 1.05 Image::ExifTool::APP12 1.13 Image::ExifTool::ASF 1.23 - Image::ExifTool::Apple 1.02 + Image::ExifTool::Apple 1.03 Image::ExifTool::Audible 1.02 - Image::ExifTool::BMP 1.08 + Image::ExifTool::BMP 1.09 + Image::ExifTool::BPG 1.00 Image::ExifTool::BZZ 1.00 Image::ExifTool::BigTIFF 1.06 - Image::ExifTool::BuildTagLookup 2.95 - Image::ExifTool::Canon 3.61 - Image::ExifTool::CanonCustom 1.53 + Image::ExifTool::BuildTagLookup 3.08 + Image::ExifTool::Canon 3.75 + Image::ExifTool::CanonCustom 1.54 Image::ExifTool::CanonRaw 1.58 Image::ExifTool::CanonVRD 1.28 Image::ExifTool::CaptureOne 1.04 - Image::ExifTool::Casio 1.37 - Image::ExifTool::Charset 1.09 + Image::ExifTool::Casio 1.38 + Image::ExifTool::Charset 1.10 Image::ExifTool::DICOM 1.19 + Image::ExifTool::DJI 1.00 Image::ExifTool::DNG 1.22 - Image::ExifTool::DPX 1.02 + Image::ExifTool::DPX 1.03 Image::ExifTool::DV 1.01 Image::ExifTool::DarwinCore 1.01 Image::ExifTool::DjVu 1.05 Image::ExifTool::EXE 1.13 - Image::ExifTool::Exif 3.79 + Image::ExifTool::Exif 3.92 Image::ExifTool::FLAC 1.07 - Image::ExifTool::FLIR 1.14 + Image::ExifTool::FLIF 1.02 + Image::ExifTool::FLIR 1.15 Image::ExifTool::Fixup 1.05 Image::ExifTool::Flash 1.12 - Image::ExifTool::FlashPix 1.26 + Image::ExifTool::FlashPix 1.29 Image::ExifTool::Font 1.08 Image::ExifTool::FotoStation 1.04 - Image::ExifTool::FujiFilm 1.53 + Image::ExifTool::FujiFilm 1.58 Image::ExifTool::GE 1.00 - Image::ExifTool::GIF 1.12 + Image::ExifTool::GIF 1.13 Image::ExifTool::GIMP 1.02 - Image::ExifTool::GPS 1.44 + Image::ExifTool::GPS 1.46 Image::ExifTool::GeoTiff 1.11 - Image::ExifTool::Geotag 1.48 + Image::ExifTool::Geotag 1.51 Image::ExifTool::H264 1.14 Image::ExifTool::HP 1.04 Image::ExifTool::HTML 1.15 - Image::ExifTool::HtmlDump 1.33 + Image::ExifTool::HtmlDump 1.34 Image::ExifTool::ICC_Profile 1.30 Image::ExifTool::ID3 1.47 - Image::ExifTool::IPTC 1.53 + Image::ExifTool::IPTC 1.54 Image::ExifTool::ISO 1.01 Image::ExifTool::ITC 1.02 - Image::ExifTool::Import 1.05 + Image::ExifTool::Import 1.06 Image::ExifTool::InDesign 1.04 Image::ExifTool::JPEG 1.25 - Image::ExifTool::JPEGDigest 1.05 + Image::ExifTool::JPEGDigest 1.06 + Image::ExifTool::JSON 1.00 Image::ExifTool::JVC 1.03 - Image::ExifTool::Jpeg2000 1.25 + Image::ExifTool::Jpeg2000 1.26 Image::ExifTool::Kodak 1.41 Image::ExifTool::KyoceraRaw 1.03 Image::ExifTool::LNK 1.07 Image::ExifTool::Lang::cs 1.07 - Image::ExifTool::Lang::de 1.30 - Image::ExifTool::Lang::en_ca 1.10 - Image::ExifTool::Lang::en_gb 1.11 + Image::ExifTool::Lang::de 1.32 + Image::ExifTool::Lang::en_ca 1.11 + Image::ExifTool::Lang::en_gb 1.12 Image::ExifTool::Lang::es 1.14 Image::ExifTool::Lang::fi 1.02 - Image::ExifTool::Lang::fr 1.30 - Image::ExifTool::Lang::it 1.12 - Image::ExifTool::Lang::ja 1.22 + Image::ExifTool::Lang::fr 1.31 + Image::ExifTool::Lang::it 1.13 + Image::ExifTool::Lang::ja 1.23 Image::ExifTool::Lang::ko 1.06 Image::ExifTool::Lang::nl 1.11 Image::ExifTool::Lang::pl 1.10 @@ -1383,81 +1185,95 @@ DISTRIBUTIONS Image::ExifTool::Lang::tr 1.04 Image::ExifTool::Lang::zh_cn 1.08 Image::ExifTool::Lang::zh_tw 1.06 - Image::ExifTool::Leaf 1.06 + Image::ExifTool::Leaf 1.07 Image::ExifTool::Lytro 1.02 - Image::ExifTool::M2TS 1.12 - Image::ExifTool::MIE 1.45 + Image::ExifTool::M2TS 1.13 + Image::ExifTool::MIE 1.46 Image::ExifTool::MIFF 1.07 Image::ExifTool::MNG 1.00 Image::ExifTool::MOI 1.02 Image::ExifTool::MPC 1.01 Image::ExifTool::MPEG 1.15 - Image::ExifTool::MPF 1.12 - Image::ExifTool::MWG 1.16 + Image::ExifTool::MPF 1.13 + Image::ExifTool::MWG 1.19 Image::ExifTool::MXF 1.08 - Image::ExifTool::MakerNotes 1.97 - Image::ExifTool::Matroska 1.07 - Image::ExifTool::Microsoft 1.17 - Image::ExifTool::Minolta 2.32 - Image::ExifTool::MinoltaRaw 1.14 + Image::ExifTool::MacOS 1.01 + Image::ExifTool::MakerNotes 1.99 + Image::ExifTool::Matroska 1.08 + Image::ExifTool::Microsoft 1.18 + Image::ExifTool::Minolta 2.50 + Image::ExifTool::MinoltaRaw 1.15 Image::ExifTool::Motorola 1.00 - Image::ExifTool::Nikon 3.17 + Image::ExifTool::Nikon 3.34 Image::ExifTool::NikonCapture 1.14 - Image::ExifTool::NikonCustom 1.12 + Image::ExifTool::NikonCustom 1.15 Image::ExifTool::Nintendo 1.00 Image::ExifTool::OOXML 1.07 - Image::ExifTool::Ogg 1.01 - Image::ExifTool::Olympus 2.40 + Image::ExifTool::Ogg 1.02 + Image::ExifTool::Olympus 2.49 Image::ExifTool::OpenEXR 1.02 - Image::ExifTool::PDF 1.41 + Image::ExifTool::Opus 1.00 + Image::ExifTool::PDF 1.43 Image::ExifTool::PGF 1.02 Image::ExifTool::PICT 1.05 - Image::ExifTool::PLIST 1.06 - Image::ExifTool::PNG 1.36 + Image::ExifTool::PLIST 1.07 + Image::ExifTool::PLUS 1.00 + Image::ExifTool::PNG 1.41 Image::ExifTool::PPM 1.08 Image::ExifTool::PSP 1.05 Image::ExifTool::Palm 1.00 - Image::ExifTool::Panasonic 1.91 - Image::ExifTool::PanasonicRaw 1.09 - Image::ExifTool::Pentax 3.02 - Image::ExifTool::PhaseOne 1.03 + Image::ExifTool::Panasonic 1.92 + Image::ExifTool::PanasonicRaw 1.10 + Image::ExifTool::Pentax 3.16 + Image::ExifTool::PhaseOne 1.04 Image::ExifTool::PhotoCD 1.01 - Image::ExifTool::PhotoMechanic 1.04 - Image::ExifTool::Photoshop 1.49 + Image::ExifTool::PhotoMechanic 1.05 + Image::ExifTool::Photoshop 1.55 Image::ExifTool::PostScript 1.41 Image::ExifTool::PrintIM 1.07 Image::ExifTool::Qualcomm 1.01 - Image::ExifTool::QuickTime 1.96 - Image::ExifTool::RIFF 1.41 + Image::ExifTool::QuickTime 2.02 + Image::ExifTool::RIFF 1.43 Image::ExifTool::RSRC 1.08 Image::ExifTool::RTF 1.02 Image::ExifTool::Radiance 1.01 Image::ExifTool::Rawzor 1.04 Image::ExifTool::Real 1.06 Image::ExifTool::Reconyx 1.04 - Image::ExifTool::Ricoh 1.31 - Image::ExifTool::Samsung 1.32 + Image::ExifTool::Ricoh 1.32 + Image::ExifTool::Samsung 1.38 Image::ExifTool::Sanyo 1.16 Image::ExifTool::Scalado 1.01 Image::ExifTool::Shortcuts 1.57 - Image::ExifTool::Sigma 1.17 - Image::ExifTool::SigmaRaw 1.24 - Image::ExifTool::Sony 2.34 - Image::ExifTool::SonyIDC 1.05 + Image::ExifTool::Sigma 1.23 + Image::ExifTool::SigmaRaw 1.25 + Image::ExifTool::Sony 2.61 + Image::ExifTool::SonyIDC 1.06 Image::ExifTool::Stim 1.01 - Image::ExifTool::TagInfoXML 1.28 - Image::ExifTool::TagLookup 1.13 + Image::ExifTool::TagInfoXML 1.30 + Image::ExifTool::TagLookup 1.16 Image::ExifTool::Theora 1.00 Image::ExifTool::Torrent 1.03 Image::ExifTool::Unknown 1.13 Image::ExifTool::VCard 1.04 + Image::ExifTool::Validate 1.02 Image::ExifTool::Vorbis 1.08 - Image::ExifTool::XMP 2.91 + Image::ExifTool::XMP 3.03 Image::ExifTool::ZIP 1.18 Image::ExifTool::iWork 1.04 requirements: ExtUtils::MakeMaker 0 perl 5.004 + JSON-PP-2.94 + pathname: I/IS/ISHIGAKI/JSON-PP-2.94.tar.gz + provides: + JSON::PP 2.94 + JSON::PP::Boolean 2.94 + JSON::PP::IncrParser 2.94 + requirements: + ExtUtils::MakeMaker 0 + Scalar::Util 1.08 + Test::More 0 JavaScript-Minifier-XS-0.11 pathname: G/GT/GTERMARS/JavaScript-Minifier-XS-0.11.tar.gz provides: @@ -1466,35 +1282,14 @@ DISTRIBUTIONS ExtUtils::CBuilder 0 Test::More 0 perl v5.6.0 - List-AllUtils-0.09 - pathname: D/DR/DROLSKY/List-AllUtils-0.09.tar.gz + List-MoreUtils-0.419 + pathname: R/RE/REHSACK/List-MoreUtils-0.419.tar.gz provides: - List::AllUtils 0.09 + List::MoreUtils 0.419 + List::MoreUtils::PP 0.419 requirements: - Exporter 0 - ExtUtils::MakeMaker 0 - List::MoreUtils 0.28 - List::Util 1.31 - base 0 - strict 0 - warnings 0 - List-MoreUtils-0.415 - pathname: R/RE/REHSACK/List-MoreUtils-0.415.tar.gz - provides: - List::MoreUtils 0.415 - List::MoreUtils::PP 0.415 - List::MoreUtils::XS 0.415 - requirements: - Carp 0 Exporter::Tiny 0.038 ExtUtils::MakeMaker 0 - File::Basename 0 - File::Copy 0 - File::Path 0 - File::Spec 0 - IPC::Cmd 0 - XSLoader 0 - base 0 Locale-Maketext-Lexicon-1.00 pathname: D/DR/DRTECH/Locale-Maketext-Lexicon-1.00.tar.gz provides: @@ -1523,35 +1318,64 @@ DISTRIBUTIONS requirements: ExtUtils::MakeMaker 6.30 Locale::Maketext 1.17 - Module-Build-0.4205 - pathname: L/LE/LEONT/Module-Build-0.4205.tar.gz + MRO-Compat-0.13 + pathname: H/HA/HAARG/MRO-Compat-0.13.tar.gz provides: - Module::Build 0.4205 - Module::Build::Base 0.4205 - Module::Build::Compat 0.4205 - Module::Build::Config 0.4205 - Module::Build::Cookbook 0.4205 - Module::Build::Dumper 0.4205 - Module::Build::ModuleInfo 0.4205 - Module::Build::Notes 0.4205 - Module::Build::PPMMaker 0.4205 - Module::Build::Platform::Default 0.4205 - Module::Build::Platform::MacOS 0.4205 - Module::Build::Platform::Unix 0.4205 - Module::Build::Platform::VMS 0.4205 - Module::Build::Platform::VOS 0.4205 - Module::Build::Platform::Windows 0.4205 - Module::Build::Platform::aix 0.4205 - Module::Build::Platform::cygwin 0.4205 - Module::Build::Platform::darwin 0.4205 - Module::Build::Platform::os2 0.4205 - Module::Build::PodParser 0.4205 - Module::Build::Version 0.87 - Module::Build::YAML 1.41 - inc::latest 0.4205 - inc::latest::private 0.4205 + MRO::Compat 0.13 requirements: - CPAN::Meta 2.110420 + ExtUtils::MakeMaker 0 + perl 5.006 + Minion-4.06 + pathname: S/SR/SRI/Minion-4.06.tar.gz + provides: + Minion 4.06 + Minion::Backend undef + Minion::Backend::Pg undef + Minion::Command::minion undef + Minion::Command::minion::job undef + Minion::Command::minion::worker undef + Minion::Job undef + Minion::Worker undef + Mojolicious::Plugin::Minion undef + requirements: + ExtUtils::MakeMaker 0 + Mojolicious 6.0 + Minion-Backend-SQLite-0.009 + pathname: D/DB/DBOOK/Minion-Backend-SQLite-0.009.tar.gz + provides: + Minion::Backend::SQLite 0.009 + requirements: + Minion 4.0 + Module::Build::Tiny 0.034 + Mojo::SQLite 1.002 + Mojolicious 6.0 + Sys::Hostname 0 + Time::HiRes 0 + perl 5.010001 + Module-Build-0.4224 + pathname: L/LE/LEONT/Module-Build-0.4224.tar.gz + provides: + Module::Build 0.4224 + Module::Build::Base 0.4224 + Module::Build::Compat 0.4224 + Module::Build::Config 0.4224 + Module::Build::Cookbook 0.4224 + Module::Build::Dumper 0.4224 + Module::Build::Notes 0.4224 + Module::Build::PPMMaker 0.4224 + Module::Build::Platform::Default 0.4224 + Module::Build::Platform::MacOS 0.4224 + Module::Build::Platform::Unix 0.4224 + Module::Build::Platform::VMS 0.4224 + Module::Build::Platform::VOS 0.4224 + Module::Build::Platform::Windows 0.4224 + Module::Build::Platform::aix 0.4224 + Module::Build::Platform::cygwin 0.4224 + Module::Build::Platform::darwin 0.4224 + Module::Build::Platform::os2 0.4224 + Module::Build::PodParser 0.4224 + requirements: + CPAN::Meta 2.142060 CPAN::Meta::YAML 0.003 Cwd 0 Data::Dumper 0 @@ -1572,19 +1396,44 @@ DISTRIBUTIONS Parse::CPAN::Meta 1.4401 Perl::OSType 1 Pod::Man 2.17 - Test::Harness 3.16 + TAP::Harness 3.29 Test::More 0.49 Text::Abbrev 0 Text::ParseWords 0 perl 5.006001 version 0.87 - Module-Implementation-0.07 - pathname: D/DR/DROLSKY/Module-Implementation-0.07.tar.gz + Module-Build-Tiny-0.039 + pathname: L/LE/LEONT/Module-Build-Tiny-0.039.tar.gz provides: - Module::Implementation 0.07 + Module::Build::Tiny 0.039 + requirements: + CPAN::Meta 0 + DynaLoader 0 + Exporter 5.57 + ExtUtils::CBuilder 0 + ExtUtils::Config 0.003 + ExtUtils::Helpers 0.020 + ExtUtils::Install 0 + ExtUtils::InstallPaths 0.002 + ExtUtils::ParseXS 0 + File::Basename 0 + File::Find 0 + File::Path 0 + File::Spec::Functions 0 + Getopt::Long 2.36 + JSON::PP 2 + Pod::Man 0 + TAP::Harness::Env 0 + perl 5.006 + strict 0 + warnings 0 + Module-Implementation-0.09 + pathname: D/DR/DROLSKY/Module-Implementation-0.09.tar.gz + provides: + Module::Implementation 0.09 requirements: Carp 0 - ExtUtils::MakeMaker 6.30 + ExtUtils::MakeMaker 0 Module::Runtime 0.012 Try::Tiny 0 strict 0 @@ -1599,8 +1448,45 @@ DISTRIBUTIONS perl 5.006 strict 0 warnings 0 - Mojolicious-6.63 - pathname: S/SR/SRI/Mojolicious-6.63.tar.gz + Mojo-Pg-3.06 + pathname: S/SR/SRI/Mojo-Pg-3.06.tar.gz + provides: + Mojo::Pg 3.06 + Mojo::Pg::Database undef + Mojo::Pg::Migrations undef + Mojo::Pg::PubSub undef + Mojo::Pg::Results undef + Mojo::Pg::Transaction undef + requirements: + DBD::Pg 3.005001 + ExtUtils::MakeMaker 0 + Mojolicious 7.32 + SQL::Abstract 1.81 + Mojo-SQLite-2.002 + pathname: D/DB/DBOOK/Mojo-SQLite-2.002.tar.gz + provides: + Mojo::SQLite 2.002 + Mojo::SQLite::Database 2.002 + Mojo::SQLite::Migrations 2.002 + Mojo::SQLite::PubSub 2.002 + Mojo::SQLite::Results 2.002 + Mojo::SQLite::Transaction 2.002 + requirements: + Carp 0 + DBD::SQLite 1.50 + DBI 1.627 + File::Spec::Functions 0 + File::Temp 0 + Module::Build::Tiny 0.034 + Mojolicious 7.15 + SQL::Abstract 1.81 + Scalar::Util 0 + URI 1.69 + URI::db 0.15 + URI::file 4.21 + perl 5.010001 + Mojolicious-7.33 + pathname: S/SR/SRI/Mojolicious-7.33.tar.gz provides: Mojo undef Mojo::Asset undef @@ -1622,6 +1508,7 @@ DISTRIBUTIONS Mojo::Date undef Mojo::EventEmitter undef Mojo::Exception undef + Mojo::File undef Mojo::Headers undef Mojo::HelloWorld undef Mojo::Home undef @@ -1630,6 +1517,8 @@ DISTRIBUTIONS Mojo::IOLoop::Delay undef Mojo::IOLoop::Server undef Mojo::IOLoop::Stream undef + Mojo::IOLoop::Subprocess undef + Mojo::IOLoop::TLS undef Mojo::JSON undef Mojo::JSON::Pointer undef Mojo::Loader undef @@ -1647,6 +1536,8 @@ DISTRIBUTIONS Mojo::Server::Daemon undef Mojo::Server::Hypnotoad undef Mojo::Server::Morbo undef + Mojo::Server::Morbo::Backend undef + Mojo::Server::Morbo::Backend::Poll undef Mojo::Server::PSGI undef Mojo::Server::PSGI::_IO undef Mojo::Server::Prefork undef @@ -1663,7 +1554,7 @@ DISTRIBUTIONS Mojo::UserAgent::Transactor undef Mojo::Util undef Mojo::WebSocket undef - Mojolicious 6.63 + Mojolicious 7.33 Mojolicious::Command undef Mojolicious::Command::cgi undef Mojolicious::Command::cpanify undef @@ -1685,7 +1576,6 @@ DISTRIBUTIONS Mojolicious::Controller undef Mojolicious::Lite undef Mojolicious::Plugin undef - Mojolicious::Plugin::Charset undef Mojolicious::Plugin::Config undef Mojolicious::Plugin::Config::Sandbox undef Mojolicious::Plugin::DefaultHelpers undef @@ -1715,21 +1605,17 @@ DISTRIBUTIONS JSON::PP 2.27103 Pod::Simple 3.09 Time::Local 1.2 - Mojolicious-Plugin-AssetPack-1.13 - pathname: J/JH/JHTHORSEN/Mojolicious-Plugin-AssetPack-1.13.tar.gz + Mojolicious-Plugin-AssetPack-1.44 + pathname: J/JH/JHTHORSEN/Mojolicious-Plugin-AssetPack-1.44.tar.gz provides: - Mojolicious::Plugin::AssetPack 1.13 + Mojolicious::Plugin::AssetPack 1.44 Mojolicious::Plugin::AssetPack::Asset undef Mojolicious::Plugin::AssetPack::Asset::Null undef - Mojolicious::Plugin::AssetPack::Backcompat undef - Mojolicious::Plugin::AssetPack::Backcompat::Asset undef - Mojolicious::Plugin::AssetPack::Handler::Http undef - Mojolicious::Plugin::AssetPack::Handler::Https undef - Mojolicious::Plugin::AssetPack::Handler::Sprites undef Mojolicious::Plugin::AssetPack::Pipe undef Mojolicious::Plugin::AssetPack::Pipe::CoffeeScript undef Mojolicious::Plugin::AssetPack::Pipe::Combine undef Mojolicious::Plugin::AssetPack::Pipe::Css undef + Mojolicious::Plugin::AssetPack::Pipe::Favicon undef Mojolicious::Plugin::AssetPack::Pipe::Fetch undef Mojolicious::Plugin::AssetPack::Pipe::JavaScript undef Mojolicious::Plugin::AssetPack::Pipe::Jpeg undef @@ -1738,17 +1624,8 @@ DISTRIBUTIONS Mojolicious::Plugin::AssetPack::Pipe::Reloader undef Mojolicious::Plugin::AssetPack::Pipe::Riotjs undef Mojolicious::Plugin::AssetPack::Pipe::Sass undef - Mojolicious::Plugin::AssetPack::Preprocessor undef - Mojolicious::Plugin::AssetPack::Preprocessor::CoffeeScript undef - Mojolicious::Plugin::AssetPack::Preprocessor::Css undef - Mojolicious::Plugin::AssetPack::Preprocessor::Fallback undef - Mojolicious::Plugin::AssetPack::Preprocessor::JavaScript undef - Mojolicious::Plugin::AssetPack::Preprocessor::Jsx undef - Mojolicious::Plugin::AssetPack::Preprocessor::Less undef - Mojolicious::Plugin::AssetPack::Preprocessor::Sass undef - Mojolicious::Plugin::AssetPack::Preprocessor::Scss undef - Mojolicious::Plugin::AssetPack::Preprocessors 0.01 - Mojolicious::Plugin::AssetPack::Preprocessors::CWD 0.01 + Mojolicious::Plugin::AssetPack::Pipe::TypeScript undef + Mojolicious::Plugin::AssetPack::Pipe::Vuejs undef Mojolicious::Plugin::AssetPack::Store undef Mojolicious::Plugin::AssetPack::Util undef Mojolicious::Plugin::AssetPack::Util::_chdir undef @@ -1756,7 +1633,7 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 File::Which 1.21 IPC::Run3 0.048 - Mojolicious 6.50 + Mojolicious 7.17 Test::More 0.88 Mojolicious-Plugin-DebugDumperHelper-0.03 pathname: L/LD/LDIDRY/Mojolicious-Plugin-DebugDumperHelper-0.03.tar.gz @@ -1775,33 +1652,70 @@ DISTRIBUTIONS Mojolicious 5 Test::More 0 perl 5.010001 - Net-Domain-TLD-1.74 - pathname: A/AL/ALEXP/Net-Domain-TLD-1.74.tar.gz + Mojolicious-Plugin-PgURLHelper-0.03 + pathname: L/LD/LDIDRY/Mojolicious-Plugin-PgURLHelper-0.03.tar.gz provides: - Net::Domain::TLD 1.74 + Mojolicious::Plugin::PgURLHelper 0.03 + requirements: + ExtUtils::MakeMaker 0 + Mojolicious 7.23 + Moo-2.003002 + pathname: H/HA/HAARG/Moo-2.003002.tar.gz + provides: + Method::Generate::Accessor undef + Method::Generate::BuildAll undef + Method::Generate::Constructor undef + Method::Generate::DemolishAll undef + Moo 2.003002 + Moo::HandleMoose undef + Moo::HandleMoose::FakeConstructor undef + Moo::HandleMoose::FakeMetaClass undef + Moo::HandleMoose::_TypeMap undef + Moo::Object undef + Moo::Role 2.003002 + Moo::_Utils undef + Moo::_mro undef + Moo::_strictures undef + Moo::sification undef + oo undef + requirements: + Class::Method::Modifiers 1.1 + Devel::GlobalDestruction 0.11 + Exporter 5.57 + ExtUtils::MakeMaker 0 + Module::Runtime 0.014 + Role::Tiny 2.000004 + Scalar::Util 0 + Sub::Defer 2.003001 + Sub::Quote 2.003001 + perl 5.006 + Net-Domain-TLD-1.75 + pathname: A/AL/ALEXP/Net-Domain-TLD-1.75.tar.gz + provides: + Net::Domain::TLD 1.75 requirements: Carp 0 ExtUtils::MakeMaker 0 Storable 0 - Net-SSLeay-1.58 - pathname: M/MI/MIKEM/Net-SSLeay-1.58.tar.gz + Net-SSLeay-1.81 + pathname: M/MI/MIKEM/Net-SSLeay-1.81.tar.gz provides: - Net::SSLeay 1.58 + Net::SSLeay 1.81 Net::SSLeay::Handle 0.61 requirements: ExtUtils::MakeMaker 6.36 MIME::Base64 0 Test::More 0.60_01 perl 5.005 - NetAddr-IP-4.072 - pathname: M/MI/MIKER/NetAddr-IP-4.072.tar.gz + NetAddr-IP-4.079 + pathname: M/MI/MIKER/NetAddr-IP-4.079.tar.gz provides: - NetAddr::IP 4.072 + NetAddr::IP 4.079 NetAddr::IP::InetBase 0.08 - NetAddr::IP::Lite 1.52 - NetAddr::IP::Util 1.51 + NetAddr::IP::Lite 1.57 + NetAddr::IP::Util 1.53 NetAddr::IP::UtilPP 1.09 - NetAddr::IP::UtilPolluted 1.51 + NetAddr::IP::UtilPolluted 1.53 NetAddr::IP::Util_IS 1 requirements: ExtUtils::MakeMaker 0 @@ -1822,6 +1736,36 @@ DISTRIBUTIONS Test::More 0.47 Test::Script 1.06 perl 5.006 + Package-Stash-0.37 + pathname: D/DO/DOY/Package-Stash-0.37.tar.gz + provides: + Package::Stash 0.37 + Package::Stash::PP 0.37 + requirements: + B 0 + Carp 0 + Config 0 + Dist::CheckConflicts 0.02 + ExtUtils::MakeMaker 0 + File::Spec 0 + Getopt::Long 0 + Module::Implementation 0.06 + Package::Stash::XS 0.26 + Scalar::Util 0 + Symbol 0 + Text::ParseWords 0 + constant 0 + strict 0 + warnings 0 + Package-Stash-XS-0.28 + pathname: D/DO/DOY/Package-Stash-XS-0.28.tar.gz + provides: + Package::Stash::XS 0.28 + requirements: + ExtUtils::MakeMaker 6.30 + XSLoader 0 + strict 0 + warnings 0 Params-Classify-0.013 pathname: Z/ZE/ZEFRAM/Params-Classify-0.013.tar.gz provides: @@ -1847,27 +1791,23 @@ DISTRIBUTIONS Scalar::Util 1.18 Test::More 0.42 perl 5.00503 - Params-Validate-1.08 - pathname: D/DR/DROLSKY/Params-Validate-1.08.tar.gz + Params-ValidationCompiler-0.24 + pathname: D/DR/DROLSKY/Params-ValidationCompiler-0.24.tar.gz provides: - Attribute::Params::Validate 1.08 - Params::Validate 1.08 - Params::Validate::Constants 1.08 - Params::Validate::PP 1.08 - Params::Validate::XS 1.08 + Params::ValidationCompiler 0.24 + Params::ValidationCompiler::Compiler 0.24 + Params::ValidationCompiler::Exceptions 0.24 requirements: - Attribute::Handlers 0.79 + B 0 Carp 0 + Eval::Closure 0 + Exception::Class 0 Exporter 0 - ExtUtils::CBuilder 0 - Module::Build 0.3601 - Module::Implementation 0 - Scalar::Util 1.10 - XSLoader 0 - attributes 0 - perl 5.008001 + ExtUtils::MakeMaker 0 + List::Util 1.29 + Scalar::Util 0 + overload 0 strict 0 - vars 0 warnings 0 Probe-Perl-0.03 pathname: K/KW/KWILLIAMS/Probe-Perl-0.03.tar.gz @@ -1878,34 +1818,139 @@ DISTRIBUTIONS ExtUtils::MakeMaker 6.30 File::Spec 0 strict 0 - SUPER-1.20141117 - pathname: C/CH/CHROMATIC/SUPER-1.20141117.tar.gz + Role-Tiny-2.000005 + pathname: H/HA/HAARG/Role-Tiny-2.000005.tar.gz provides: - SUPER 1.20141117 + Role::Tiny 2.000005 + Role::Tiny::With 2.000005 requirements: - Scalar::Util 1.20 - Sub::Identify 0.03 - Test::Simple 0.61 - perl v5.6.2 - Sub-Identify-0.12 - pathname: R/RG/RGARCIA/Sub-Identify-0.12.tar.gz + Exporter 5.57 + perl 5.006 + SQL-Abstract-1.84 + pathname: I/IL/ILMARI/SQL-Abstract-1.84.tar.gz provides: - Sub::Identify 0.12 + SQL::Abstract 1.84 + SQL::Abstract::Test undef + SQL::Abstract::Tree undef + requirements: + Exporter 5.57 + ExtUtils::MakeMaker 0 + Hash::Merge 0.12 + List::Util 0 + MRO::Compat 0.12 + Moo 2.000001 + Scalar::Util 0 + Sub::Quote 2.000001 + Text::Balanced 2.00 + Scalar-List-Utils-1.47 + pathname: P/PE/PEVANS/Scalar-List-Utils-1.47.tar.gz + provides: + List::Util 1.47 + List::Util::XS 1.47 + Scalar::Util 1.47 + Sub::Util 1.47 requirements: ExtUtils::MakeMaker 0 Test::More 0 - Sub-Uplevel-0.24 - pathname: D/DA/DAGOLDEN/Sub-Uplevel-0.24.tar.gz + perl 5.006 + Specio-0.37 + pathname: D/DR/DROLSKY/Specio-0.37.tar.gz provides: - Sub::Uplevel 0.24 + Specio 0.37 + Specio::Coercion 0.37 + Specio::Constraint::AnyCan 0.37 + Specio::Constraint::AnyDoes 0.37 + Specio::Constraint::AnyIsa 0.37 + Specio::Constraint::Enum 0.37 + Specio::Constraint::Intersection 0.37 + Specio::Constraint::ObjectCan 0.37 + Specio::Constraint::ObjectDoes 0.37 + Specio::Constraint::ObjectIsa 0.37 + Specio::Constraint::Parameterizable 0.37 + Specio::Constraint::Parameterized 0.37 + Specio::Constraint::Role::CanType 0.37 + Specio::Constraint::Role::DoesType 0.37 + Specio::Constraint::Role::Interface 0.37 + Specio::Constraint::Role::IsaType 0.37 + Specio::Constraint::Simple 0.37 + Specio::Constraint::Structurable 0.37 + Specio::Constraint::Structured 0.37 + Specio::Constraint::Union 0.37 + Specio::Declare 0.37 + Specio::DeclaredAt 0.37 + Specio::Exception 0.37 + Specio::Exporter 0.37 + Specio::Helpers 0.37 + Specio::Library::Builtins 0.37 + Specio::Library::Numeric 0.37 + Specio::Library::Perl 0.37 + Specio::Library::String 0.37 + Specio::Library::Structured 0.37 + Specio::Library::Structured::Dict 0.37 + Specio::Library::Structured::Map 0.37 + Specio::Library::Structured::Tuple 0.37 + Specio::OO 0.37 + Specio::PartialDump 0.37 + Specio::Registry 0.37 + Specio::Role::Inlinable 0.37 + Specio::Subs 0.37 + Specio::TypeChecks 0.37 + Test::Specio 0.37 + requirements: + B 0 + Carp 0 + Devel::StackTrace 0 + Eval::Closure 0 + Exporter 0 + ExtUtils::MakeMaker 0 + IO::File 0 + List::Util 1.33 + MRO::Compat 0 + Module::Runtime 0 + Role::Tiny 1.003003 + Role::Tiny::With 0 + Scalar::Util 0 + Storable 0 + Test::Fatal 0 + Test::More 0.96 + overload 0 + parent 0 + perl 5.008 + re 0 + strict 0 + version 0.83 + warnings 0 + Sub-Exporter-Progressive-0.001013 + pathname: F/FR/FREW/Sub-Exporter-Progressive-0.001013.tar.gz + provides: + Sub::Exporter::Progressive 0.001013 + requirements: + ExtUtils::MakeMaker 0 + Sub-Identify-0.14 + pathname: R/RG/RGARCIA/Sub-Identify-0.14.tar.gz + provides: + Sub::Identify 0.14 + requirements: + ExtUtils::MakeMaker 0 + Test::More 0 + Sub-Quote-2.004000 + pathname: H/HA/HAARG/Sub-Quote-2.004000.tar.gz + provides: + Sub::Defer 2.004000 + Sub::Quote 2.004000 + requirements: + ExtUtils::MakeMaker 0 + Scalar::Util 0 + perl 5.006 + Sub-Uplevel-0.2800 + pathname: D/DA/DAGOLDEN/Sub-Uplevel-0.2800.tar.gz + provides: + Sub::Uplevel 0.2800 requirements: Carp 0 - Exporter 0 - ExtUtils::MakeMaker 6.30 - File::Find 0 - File::Temp 0 - Test::More 0 + ExtUtils::MakeMaker 6.17 constant 0 + perl 5.006 strict 0 warnings 0 Switch-2.17 @@ -1918,65 +1963,225 @@ DISTRIBUTIONS Text::Balanced 2 if 0 perl 5.005 - Test-MockModule-0.11 - pathname: G/GF/GFRANKS/Test-MockModule-0.11.tar.gz + Test-Fatal-0.014 + pathname: R/RJ/RJBS/Test-Fatal-0.014.tar.gz provides: - Test::MockModule 0.11 + Test::Fatal 0.014 requirements: Carp 0 - Module::Build 0.38 - SUPER 0 - Scalar::Util 0 - Test::More 0.45 - perl 5.006 - Test-Script-1.07 - pathname: A/AD/ADAMK/Test-Script-1.07.tar.gz + Exporter 5.57 + ExtUtils::MakeMaker 0 + Test::Builder 0 + Try::Tiny 0.07 + strict 0 + warnings 0 + Test-Script-1.18 + pathname: P/PL/PLICEASE/Test-Script-1.18.tar.gz provides: - Test::Script 1.07 + Test::Script 1.18 requirements: - ExtUtils::MakeMaker 6.42 + ExtUtils::MakeMaker 0 File::Spec 0.80 IPC::Run3 0.034 Probe::Perl 0.01 Test::Builder 0.32 - Test::Builder::Tester 1.02 - Test::More 0.62 - blib 0 - Test-Warn-0.30 - pathname: C/CH/CHORNY/Test-Warn-0.30.tar.gz + Test::More 0.96 + perl 5.006 + Test-Warn-0.32 + pathname: B/BI/BIGJ/Test-Warn-0.32.tar.gz provides: - Test::Warn 0.30 - Test::Warn::Categorization 0.30 + Test::Warn 0.32 + Test::Warn::Categorization 0.32 requirements: Carp 1.22 ExtUtils::MakeMaker 0 - File::Spec 0 Sub::Uplevel 0.12 Test::Builder 0.13 Test::Builder::Tester 1.02 - Test::More 0 perl 5.006 - Text-Unidecode-1.27 - pathname: S/SB/SBURKE/Text-Unidecode-1.27.tar.gz + Text-Unidecode-1.30 + pathname: S/SB/SBURKE/Text-Unidecode-1.30.tar.gz provides: - Text::Unidecode 1.27 + Text::Unidecode 1.30 requirements: ExtUtils::MakeMaker 0 perl 5.008 - Try-Tiny-0.19 - pathname: D/DO/DOY/Try-Tiny-0.19.tar.gz + Try-Tiny-0.28 + pathname: E/ET/ETHER/Try-Tiny-0.28.tar.gz provides: - Try::Tiny 0.19 + Try::Tiny 0.28 requirements: Carp 0 Exporter 5.57 - ExtUtils::MakeMaker 6.30 + ExtUtils::MakeMaker 0 constant 0 + perl 5.006 strict 0 warnings 0 - common-sense-3.73 - pathname: M/ML/MLEHMANN/common-sense-3.73.tar.gz + URI-1.71 + pathname: E/ET/ETHER/URI-1.71.tar.gz provides: - common::sense 3.73 + URI 1.71 + URI::Escape 3.31 + URI::Heuristic 4.20 + URI::IRI 1.71 + URI::QueryParam 1.71 + URI::Split 1.71 + URI::URL 5.04 + URI::WithBase 2.20 + URI::_foreign 1.71 + URI::_generic 1.71 + URI::_idna 1.71 + URI::_ldap 1.71 + URI::_login 1.71 + URI::_punycode 1.71 + URI::_query 1.71 + URI::_segment 1.71 + URI::_server 1.71 + URI::_userpass 1.71 + URI::data 1.71 + URI::file 4.21 + URI::file::Base 1.71 + URI::file::FAT 1.71 + URI::file::Mac 1.71 + URI::file::OS2 1.71 + URI::file::QNX 1.71 + URI::file::Unix 1.71 + URI::file::Win32 1.71 + URI::ftp 1.71 + URI::gopher 1.71 + URI::http 1.71 + URI::https 1.71 + URI::ldap 1.71 + URI::ldapi 1.71 + URI::ldaps 1.71 + URI::mailto 1.71 + URI::mms 1.71 + URI::news 1.71 + URI::nntp 1.71 + URI::pop 1.71 + URI::rlogin 1.71 + URI::rsync 1.71 + URI::rtsp 1.71 + URI::rtspu 1.71 + URI::sftp 1.71 + URI::sip 1.71 + URI::sips 1.71 + URI::snews 1.71 + URI::ssh 1.71 + URI::telnet 1.71 + URI::tn3270 1.71 + URI::urn 1.71 + URI::urn::isbn undef + URI::urn::oid 1.71 + requirements: + Exporter 5.57 + ExtUtils::MakeMaker 0 + MIME::Base64 2 + Scalar::Util 0 + parent 0 + perl 5.008001 + utf8 0 + URI-Nested-0.10 + pathname: D/DW/DWHEELER/URI-Nested-0.10.tar.gz + provides: + URI::Nested 0.10 + requirements: + Module::Build 0.30 + Test::More 0.88 + URI 1.40 + perl 5.008001 + URI-db-0.17 + pathname: D/DW/DWHEELER/URI-db-0.17.tar.gz + provides: + URI::cassandra 0.17 + URI::couch 0.17 + URI::couchdb 0.17 + URI::cubrid 0.17 + URI::db 0.17 + URI::db2 0.17 + URI::derby 0.17 + URI::firebird 0.17 + URI::hive 0.17 + URI::impala 0.17 + URI::informix 0.17 + URI::ingres 0.17 + URI::interbase 0.17 + URI::ldapdb 0.17 + URI::maria 0.17 + URI::mariadb 0.17 + URI::max 0.17 + URI::maxdb 0.17 + URI::monet 0.17 + URI::monetdb 0.17 + URI::mongo 0.17 + URI::mongodb 0.17 + URI::mssql 0.17 + URI::mysql 0.17 + URI::oracle 0.17 + URI::pg 0.17 + URI::pgsql 0.17 + URI::pgxc 0.17 + URI::postgres 0.17 + URI::postgresql 0.17 + URI::postgresxc 0.17 + URI::sqlite 0.17 + URI::sqlite3 0.17 + URI::sqlserver 0.17 + URI::sybase 0.17 + URI::teradata 0.17 + URI::unify 0.17 + URI::vertica 0.17 + requirements: + Module::Build 0.30 + Test::More 0.88 + URI 1.40 + URI::Nested 0.10 + perl 5.008001 + Variable-Magic-0.61 + pathname: V/VP/VPIT/Variable-Magic-0.61.tar.gz + provides: + Variable::Magic 0.61 + requirements: + Carp 0 + Config 0 + Exporter 0 + ExtUtils::MakeMaker 0 + IO::Handle 0 + IO::Select 0 + IPC::Open3 0 + POSIX 0 + Socket 0 + Test::More 0 + XSLoader 0 + base 0 + lib 0 + perl 5.008 + common-sense-3.74 + pathname: M/ML/MLEHMANN/common-sense-3.74.tar.gz + provides: + common::sense 3.74 requirements: ExtUtils::MakeMaker 0 + namespace-autoclean-0.28 + pathname: E/ET/ETHER/namespace-autoclean-0.28.tar.gz + provides: + namespace::autoclean 0.28 + requirements: + B::Hooks::EndOfScope 0.12 + ExtUtils::MakeMaker 0 + List::Util 0 + Sub::Identify 0 + namespace::clean 0.20 + perl 5.006 + strict 0 + warnings 0 + namespace-clean-0.27 + pathname: R/RI/RIBASUSHI/namespace-clean-0.27.tar.gz + provides: + namespace::clean 0.27 + requirements: + B::Hooks::EndOfScope 0.12 + ExtUtils::MakeMaker 0 + Package::Stash 0.23 + perl 5.008001 diff --git a/lib/Lutim.pm b/lib/Lutim.pm index 53f2fa8..e30b070 100644 --- a/lib/Lutim.pm +++ b/lib/Lutim.pm @@ -1,9 +1,7 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: package Lutim; use Mojo::Base 'Mojolicious'; -use Mojo::Util qw(quote); -use LutimModel; -use Crypt::CBC; -use Data::Entropy qw(entropy_source); +use Lutim::DB::Image; use vars qw($im_loaded); BEGIN { @@ -25,6 +23,7 @@ sub startup { $self->{wait_for_it} = {}; $self->plugin('DebugDumperHelper'); + $self->plugin('PgURLHelper'); my $config = $self->plugin('Config', { default => { @@ -42,6 +41,13 @@ sub startup { crypto_key_length => 8, thumbnail_size => 100, theme => 'default', + dbtype => 'sqlite', + max_files_in_zip => 15, + minion => { + enabled => 0, + dbtype => 'sqlite', + db_path => 'minion.db' + }, } }); @@ -70,228 +76,30 @@ sub startup { $self->plugin('AssetPack' => { pipes => [qw(Combine)] }); # Helpers - $self->helper( - render_file => sub { - my $c = shift; - my ($filename, $path, $mediatype, $dl, $expires, $nocache, $key, $thumb) = @_; + $self->plugin('Lutim::Plugin::Helpers'); - $dl = 'attachment' if ($mediatype =~ m/svg/); - $filename = quote($filename); + # Minion + if ($config->{minion}->{enabled}) { + $self->config->{minion}->{dbtype} = 'sqlite' unless defined $config->{minion}->{dbtype}; + if ($config->{minion}->{dbtype} eq 'sqlite') { + $self->config('minion')->{db_path} = 'minion.db' unless defined $config->{minion}->{db_path}; + $self->plugin('Minion' => { SQLite => 'sqlite:'.$config->{minion}->{db_path} }); + } elsif ($config->{minion}->{dbtype} eq 'postgresql') { + $self->plugin('Minion' => { Pg => $self->pg_url($config->{minion}->{'pgdb'}) }); + } + $self->app->minion->add_task( + accessed => sub { + my $job = shift; + my $short = $job->args->[0]; + my $time = $job->args->[1]; - my $asset; - unless (-f $path && -r $path) { - $c->app->log->error("Cannot read file [$path]. error [$!]"); - $c->flash( - msg => $c->l('Unable to find the image: it has been deleted.') - ); - return 500; + my $img = Lutim::DB::Image->new(app => $job->app, short => $short); + $img->accessed($time) if $img->path; } + ); + } - $mediatype =~ s/x-//; - - my $headers = Mojo::Headers->new(); - if ($nocache) { - $headers->add('Cache-Control' => 'no-cache, no-store, max-age=0, must-revalidate'); - } else { - $headers->add('Expires' => $expires); - } - $headers->add('Content-Type' => $mediatype.';name='.$filename); - $headers->add('Content-Disposition' => $dl.';filename='.$filename); - $c->res->content->headers($headers); - - if ($key) { - $asset = $c->decrypt($key, $path); - } else { - $asset = Mojo::Asset::File->new(path => $path); - } - - if (defined $thumb && $im_loaded && $mediatype ne 'image/svg+xml' && $mediatype !~ m#image/(x-)?xcf# && $mediatype ne 'image/webp') { # ImageMagick don't work in Debian with svg (for now?) - my $im = Image::Magick->new; - $im->BlobToImage($asset->slurp); - - # Create the thumbnail - $im->Resize(geometry=>'x'.$c->config('thumbnail_size')); - - # Replace the asset with the thumbnail - $asset = Mojo::Asset::Memory->new->add_chunk($im->ImageToBlob()); - } - - $c->res->content->asset($asset); - $headers->add('Content-Length' => $asset->size); - - return $c->rendered(200); - } - ); - - $self->helper( - ip => sub { - my $c = shift; - my $ip_only = shift || 0; - - my $proxy = $c->req->headers->header('X-Forwarded-For'); - - my $ip = ($proxy) ? $proxy : $c->tx->remote_address; - - my $remote_port = (defined($c->req->headers->header('X-Remote-Port'))) ? $c->req->headers->header('X-Remote-Port') : $c->tx->remote_port; - - return ($ip_only) ? $ip : "$ip remote port:$remote_port"; - } - ); - - $self->helper( - provisioning => sub { - my $c = shift; - - # Create some short patterns for provisioning - if (LutimModel::Lutim->count('WHERE path IS NULL') < $c->config->{provisioning}) { - for (my $i = 0; $i < $c->config->{provis_step}; $i++) { - if (LutimModel->begin) { - my $short; - do { - $short= $c->shortener($c->config->{length}); - } while (LutimModel::Lutim->count('WHERE short = ?', $short) || $short eq 'about' || $short eq 'stats' || $short eq 'd' || $short eq 'm' || $short eq 'gallery' || $short eq 'zip' || $short eq 'infos'); - - LutimModel::Lutim->create( - short => $short, - counter => 0, - enabled => 1, - delete_at_first_view => 0, - delete_at_day => 0, - mod_token => $c->shortener($c->config->{token_length}) - ); - LutimModel->commit; - } - } - } - } - ); - - $self->helper( - shortener => sub { - my $c = shift; - my $length = shift; - - my @chars = ('a'..'z','A'..'Z','0'..'9'); - my $result = ''; - foreach (1..$length) { - $result .= $chars[entropy_source->get_int(scalar(@chars))]; - } - return $result; - } - ); - - $self->helper( - stop_upload => sub { - my $c = shift; - - if (-f 'stop-upload' || -f 'stop-upload.manual') { - $c->stash( - stop_upload => $c->l('Uploading is currently disabled, please try later or contact the administrator (%1).', $config->{contact}) - ); - return 1; - } - return 0; - } - ); - - $self->helper( - max_delay => sub { - my $c = shift; - - return $c->config->{max_delay} if ($c->config->{max_delay} >= 0); - - warn "max_delay set to a negative value. Default to 0."; - return 0; - } - ); - - $self->helper( - default_delay => sub { - my $c = shift; - - return $c->config->{default_delay} if ($c->config->{default_delay} >= 0); - - warn "default_delay set to a negative value. Default to 0."; - return 0; - } - ); - - $self->helper( - is_selected => sub { - my $c = shift; - my $num = shift; - - return ($num == $c->default_delay) ? 'selected="selected"' : ''; - } - ); - - $self->helper( - crypt => sub { - my $c = shift; - my $upload = shift; - my $filename = shift; - - my $key = $c->shortener($c->config('crypto_key_length')); - - my $cipher = Crypt::CBC->new( - -key => $key, - -cipher => 'Blowfish', - -header => 'none', - -iv => 'dupajasi' - ); - - $cipher->start('encrypting'); - - my $crypt_asset = Mojo::Asset::File->new; - - $crypt_asset->add_chunk($cipher->crypt($upload->slurp)); - $crypt_asset->add_chunk($cipher->finish); - - my $crypt_upload = Mojo::Upload->new; - $crypt_upload->filename($filename); - $crypt_upload->asset($crypt_asset); - - return ($crypt_upload, $key); - } - ); - - $self->helper( - decrypt => sub { - my $c = shift; - my $key = shift; - my $file = shift; - - my $cipher = Crypt::CBC->new( - -key => $key, - -cipher => 'Blowfish', - -header => 'none', - -iv => 'dupajasi' - ); - - $cipher->start('decrypting'); - - my $decrypt_asset = Mojo::Asset::File->new; - - open(my $f, "<",$file) or die "Unable to read encrypted file: $!"; - binmode $f; - while (read($f, my $buffer,1024)) { - $decrypt_asset->add_chunk($cipher->crypt($buffer)); - } - $decrypt_asset->add_chunk($cipher->finish) ; - - return $decrypt_asset; - } - ); - - $self->helper( - delete_image => sub { - my $c = shift; - my $image = shift; - unlink $image->path(); - $image->update(enabled => 0); - } - ); - + # Hooks $self->hook( before_dispatch => sub { my $c = shift; @@ -328,15 +136,20 @@ sub startup { delete @{$wait_for_it}{grep { time - $wait_for_it->{$_} > $c->config->{anti_flood_delay} } keys %{$wait_for_it}} if (defined($wait_for_it)); } ); + $self->hook(after_static => sub { + my $c = shift; + $c->res->headers->cache_control('max-age=2592000, must-revalidate'); + }); $self->asset->store->paths($self->static->paths); - $self->asset->process('index.css' => ('css/bootstrap.min.css', 'css/fontello-embedded.css', 'css/animation.css', 'css/uploader.css', 'css/hennypenny.css', 'css/lutim.css', 'css/markdown.css')); - $self->asset->process('stats.css' => ('css/bootstrap.min.css', 'css/fontello-embedded.css', 'css/morris-0.4.3.min.css', 'css/hennypenny.css', 'css/lutim.css')); - $self->asset->process('about.css' => ('css/bootstrap.min.css', 'css/fontello-embedded.css', 'css/hennypenny.css', 'css/lutim.css')); + $self->asset->process('index.css' => ('css/bootstrap.min.css', 'css/fontello-embedded.css', 'css/animation.css', 'css/uploader.css', 'css/hennypenny.css', 'css/lutim.css', 'css/markdown.css')); + $self->asset->process('stats.css' => ('css/bootstrap.min.css', 'css/fontello-embedded.css', 'css/morris-0.4.3.min.css', 'css/hennypenny.css', 'css/lutim.css')); + $self->asset->process('about.css' => ('css/bootstrap.min.css', 'css/fontello-embedded.css', 'css/hennypenny.css', 'css/lutim.css')); + $self->asset->process('gallery.css' => ('/gallery/css/unite-gallery.css', '/gallery/themes/default/ug-theme-default.css')); - $self->asset->process('index.js' => ('js/jquery-2.1.0.min.js', 'js/bootstrap.min.js', 'js/lutim.js', 'js/dmuploader.min.js')); - $self->asset->process('stats.js' => ('js/jquery-2.1.0.min.js', 'js/bootstrap.min.js', 'js/lutim.js', 'js/raphael-min.js', 'js/morris-0.4.3.min.js', 'js/stats.js')); - $self->asset->process('freeze.js' => ('js/jquery-2.1.0.min.js', 'js/freezeframe.min.js')); + $self->asset->process('index.js' => ('js/bootstrap.min.js', 'js/lutim.js', 'js/dmuploader.min.js')); + $self->asset->process('stats.js' => ('js/bootstrap.min.js', 'js/lutim.js', 'js/raphael-min.js', 'js/morris-0.4.3.min.js', 'js/stats.js')); + $self->asset->process('freeze.js' => ('js/jquery-2.1.0.min.js', 'js/freezeframe.min.js')); $self->defaults(layout => 'default'); @@ -367,6 +180,20 @@ sub startup { to('Controller#stats')-> name('stats'); + $r->get('/partial/:file' => sub { + my $c = shift; + $c->render( + template => 'partial/'.$c->param('file'), + format => 'js', + layout => undef, + d => { + delay_0 => $c->l('no time limit'), + delay_1 => $c->l('24 hours'), + delay_365 => $c->l('1 year') + } + ); + })->name('partial'); + $r->get('/gallery' => sub { shift->render( template => 'gallery', diff --git a/lib/Lutim/Command/cron.pm b/lib/Lutim/Command/cron.pm index 163620c..a4d10c9 100644 --- a/lib/Lutim/Command/cron.pm +++ b/lib/Lutim/Command/cron.pm @@ -1,3 +1,4 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: package Lutim::Command::cron; use Mojo::Base 'Mojolicious::Commands'; diff --git a/lib/Lutim/Command/cron/cleanbdd.pm b/lib/Lutim/Command/cron/cleanbdd.pm index 4257755..b65589b 100644 --- a/lib/Lutim/Command/cron/cleanbdd.pm +++ b/lib/Lutim/Command/cron/cleanbdd.pm @@ -1,7 +1,8 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: package Lutim::Command::cron::cleanbdd; use Mojo::Base 'Mojolicious::Command'; -use LutimModel; -use Mojo::Util qw(slurp decode); +use Mojo::File; +use Lutim::DB::Image; use FindBin qw($Bin); use File::Spec qw(catfile); @@ -11,20 +12,26 @@ has usage => sub { shift->extract_usage }; sub run { my $c = shift; + my $cfile = Mojo::File->new($Bin, '..' , 'lutim.conf'); + if (defined $ENV{MOJO_CONFIG}) { + $cfile = Mojo::File->new($ENV{MOJO_CONFIG}); + unless (-e $cfile->to_abs) { + $cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG}); + } + } my $config = $c->app->plugin('Config', { - file => File::Spec->catfile($Bin, '..' ,'lutim.conf'), + file => $cfile, default => { keep_ip_during => 365, + dbtype => 'sqlite', } }); my $separation = time() - $config->{keep_ip_during} * 86400; - LutimModel->do( - 'UPDATE lutim SET created_by = "" WHERE path IS NOT NULL AND created_at < ?', - {}, - $separation - ); + my $dbi = Lutim::DB::Image->new(app => $c->app); + + $dbi->clean_ips_until($separation); } =encoding utf8 diff --git a/lib/Lutim/Command/cron/cleanfiles.pm b/lib/Lutim/Command/cron/cleanfiles.pm index 008ece6..1293213 100644 --- a/lib/Lutim/Command/cron/cleanfiles.pm +++ b/lib/Lutim/Command/cron/cleanfiles.pm @@ -1,8 +1,9 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: package Lutim::Command::cron::cleanfiles; use Mojo::Base 'Mojolicious::Command'; -use LutimModel; +use Mojo::File; +use Lutim::DB::Image; use Lutim; -use Mojo::Util qw(slurp decode); use FindBin qw($Bin); use File::Spec qw(catfile); @@ -11,26 +12,40 @@ has usage => sub { shift->extract_usage }; sub run { my $c = shift; - my $l = Lutim->new; - my $time = time(); - my @images = LutimModel::Lutim->select('WHERE enabled = 1 AND (delete_at_day * 86400) < (? - created_at) AND delete_at_day != 0', $time); - - for my $image (@images) { - $l->app->delete_image($image); + my $cfile = Mojo::File->new($Bin, '..' , 'lutim.conf'); + if (defined $ENV{MOJO_CONFIG}) { + $cfile = Mojo::File->new($ENV{MOJO_CONFIG}); + unless (-e $cfile->to_abs) { + $cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG}); + } } - my $config = $c->app->plugin('Config', { - file => File::Spec->catfile($Bin, '..' ,'lutim.conf'), + file => $cfile, + default => { + dbtype => 'sqlite', + } }); - if (defined($config->{delete_no_longer_viewed_files}) && $config->{delete_no_longer_viewed_files} > 0) { - $time = time() - $config->{delete_no_longer_viewed_files} * 86400; - @images = LutimModel::Lutim->select('WHERE enabled = 1 AND last_access_at < ?', $time); + my $l = Lutim->new; - for my $image (@images) { - $l->app->delete_image($image); + my $dbi = Lutim::DB::Image->new(app => $c->app); + + $dbi->get_images_to_clean()->each( + sub { + my ($img, $num) = @_; + $l->app->delete_image($img); } + ); + + if (defined($config->{delete_no_longer_viewed_files}) && $config->{delete_no_longer_viewed_files} > 0) { + my $time = time() - $config->{delete_no_longer_viewed_files} * 86400; + $dbi->get_no_longer_viewed_files($time)->each( + sub { + my ($img, $num) = @_; + $l->app->delete_image($img); + } + ); } } diff --git a/lib/Lutim/Command/cron/stats.pm b/lib/Lutim/Command/cron/stats.pm index c82d6fa..ca4f85e 100644 --- a/lib/Lutim/Command/cron/stats.pm +++ b/lib/Lutim/Command/cron/stats.pm @@ -1,11 +1,15 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: package Lutim::Command::cron::stats; use Mojo::Base 'Mojolicious::Command'; -use LutimModel; use Mojo::DOM; -use Mojo::Util qw(slurp spurt encode); +use Mojo::Util qw(encode); +use Mojo::File; +use Mojo::JSON qw(encode_json); +use Lutim::DB::Image; use DateTime; use FindBin qw($Bin); use File::Spec qw(catfile); +use POSIX; has description => 'Generate statistics about Lutim.'; has usage => sub { shift->extract_usage }; @@ -13,11 +17,19 @@ has usage => sub { shift->extract_usage }; sub run { my $c = shift; + my $cfile = Mojo::File->new($Bin, '..' , 'lutim.conf'); + if (defined $ENV{MOJO_CONFIG}) { + $cfile = Mojo::File->new($ENV{MOJO_CONFIG}); + unless (-e $cfile->to_abs) { + $cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG}); + } + } my $config = $c->app->plugin('Config', { - file => File::Spec->catfile($Bin, '..' ,'lutim.conf'), - theme => 'default', + file => $cfile, default => { - stats_day_num => 365 + theme => 'default', + stats_day_num => 365, + dbtype => 'sqlite' } }); @@ -26,7 +38,10 @@ sub run { $config->{theme} = 'default'; $template = 'themes/'.$config->{theme}.'/templates/data.html.ep.template'; } - my $text = slurp($template); + + my $stats = {}; + + my $text = Mojo::File->new($template)->slurp; my $dom = Mojo::DOM->new($text); my $thead_tr = $dom->at('table thead tr'); my $tbody_tr = $dom->at('table tbody tr'); @@ -35,18 +50,28 @@ sub run { my $separation = time() - $config->{stats_day_num} * 86400; my %data; - for my $img (LutimModel::Lutim->select('WHERE path IS NOT NULL AND created_at >= ?', $separation)) { - my $time = DateTime->from_epoch(epoch => $img->created_at); - my ($year, $month, $day) = ($time->year(), $time->month(), $time->day()); + my $img = Lutim::DB::Image->new(app => $c->app); + my $sca = $img->select_created_after($separation); - if (defined($data{$year}->{$month}->{$day})) { - $data{$year}->{$month}->{$day} += 1; - } else { - $data{$year}->{$month}->{$day} = 1; + $stats->{total} = $img->count_not_empty; + $stats->{average} = floor($sca->size / $config->{stats_day_num}) if $config->{stats_day_num}; + $stats->{for_days} = $config->{stats_day_num}; + + $sca->each( + sub { + my ($e, $num) = @_; + my $time = DateTime->from_epoch(epoch => $e->created_at); + my ($year, $month, $day) = ($time->year(), $time->month(), $time->day()); + + if (defined($data{$year}->{$month}->{$day})) { + $data{$year}->{$month}->{$day} += 1; + } else { + $data{$year}->{$month}->{$day} = 1; + } } - } + ); - my $total = LutimModel::Lutim->count('WHERE path IS NOT NULL AND created_at < ?', $separation); + my $total = $img->count_created_before($separation); for my $year (sort {$a <=> $b} keys %data) { for my $month (sort {$a <=> $b} keys %{$data{$year}}) { for my $day (sort {$a <=> $b} keys %{$data{$year}->{$month}}) { @@ -58,33 +83,58 @@ sub run { } } + my $moy = $total / $config->{stats_day_num}; + # Raw datas my $template2 = 'themes/'.$config->{theme}.'/templates/raw.html.ep.template'; unless (-e $template2) { $config->{theme} = 'default'; $template = 'themes/'.$config->{theme}.'/templates/raw.html.ep.template'; } - my $text2 = slurp($template2); + my $text2 = Mojo::File->new($template2)->slurp; my $dom2 = Mojo::DOM->new($text2); my $raw = $dom2->at('table tbody'); my $raw_foot = $dom2->at('table tfoot'); - my $unlimited_enabled = LutimModel::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = 0 AND enabled = 1'); - my $unlimited_disabled = LutimModel::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = 0 AND enabled = 0'); - my $day_enabled = LutimModel::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = 1 AND enabled = 1'); - my $day_disabled = LutimModel::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = 1 AND enabled = 0'); - my $week_enabled = LutimModel::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = 7 AND enabled = 1'); - my $week_disabled = LutimModel::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = 7 AND enabled = 0'); - my $month_enabled = LutimModel::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = 30 AND enabled = 1'); - my $month_disabled = LutimModel::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = 30 AND enabled = 0'); - my $year_enabled = LutimModel::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = 365 AND enabled = 1'); - my $year_disabled = LutimModel::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = 365 AND enabled = 0'); - my $year_disabled_in_month = LutimModel::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = 365 AND enabled = 0 AND created_at < ?', time - 30 * 86400); + my $unlimited_enabled = $img->count_delete_at_day_endis(0, 1); + my $unlimited_disabled = $img->count_delete_at_day_endis(0, 0); + my $day_enabled = $img->count_delete_at_day_endis(1, 1); + my $day_disabled = $img->count_delete_at_day_endis(1, 0); + my $week_enabled = $img->count_delete_at_day_endis(7, 1); + my $week_disabled = $img->count_delete_at_day_endis(7, 0); + my $month_enabled = $img->count_delete_at_day_endis(30, 1); + my $month_disabled = $img->count_delete_at_day_endis(30, 0); + my $year_enabled = $img->count_delete_at_day_endis(365, 1); + my $year_disabled = $img->count_delete_at_day_endis(365, 0); + my $year_disabled_in_month = $img->count_delete_at_day_endis(365, 1, time - 335 * 86400); + + $stats->{unlimited} = { + enabled => $unlimited_enabled, + disabled => $unlimited_disabled + }; + $stats->{day} = { + enabled => $day_enabled, + disabled => $day_disabled + }; + $stats->{week} = { + enabled => $week_enabled, + disabled => $week_disabled + }; + $stats->{month} = { + enabled => $month_enabled, + disabled => $month_disabled + }; + $stats->{year} = { + enabled => $year_enabled, + disabled => $year_disabled + }; + + my $year_disabled_in_month_pct = ($year_enabled != 0) ? " (".sprintf('%.2f', $year_disabled_in_month/$year_enabled)."%)" : ''; $raw->append_content("\n<%= \$raw[4] %>".$unlimited_enabled."".$unlimited_disabled."ø\n"); $raw->append_content("<%= \$raw[5] %>".$day_enabled."".$day_disabled."".$day_enabled." (100%)\n"); $raw->append_content("<%= \$raw[6] %>".$week_enabled."".$week_disabled."".$week_enabled." (100%)\n"); $raw->append_content("<%= \$raw[7] %>".$month_enabled."".$month_disabled."".$month_enabled." (100%)\n"); - $raw->append_content("<%= \$raw[8] %>".$year_enabled."".$year_disabled."".$year_disabled_in_month." (".sprintf('%.2f', $year_disabled_in_month/$year_enabled)."%)\n"); + $raw->append_content("<%= \$raw[8] %>".$year_enabled."".$year_disabled."".$year_disabled_in_month.$year_disabled_in_month_pct."\n"); $raw_foot->append_content("\n<%= \$raw[9] %>".($unlimited_enabled + $day_enabled + $week_enabled + $month_enabled + $year_enabled)."".($unlimited_disabled + $day_disabled + $week_disabled + $month_disabled + $year_disabled)."".($day_enabled + $week_enabled + $month_enabled + $year_disabled_in_month)."\n"); @@ -140,8 +190,9 @@ Morris.Donut({ $dom2 EOF - spurt $dom, 'themes/'.$config->{theme}.'/templates/data.html.ep'; - spurt encode('UTF-8', $dom2), 'themes/'.$config->{theme}.'/templates/raw.html.ep'; + Mojo::File->new('themes/'.$config->{theme}.'/templates/stats.json.ep')->spurt(encode_json($stats)); + Mojo::File->new('themes/'.$config->{theme}.'/templates/data.html.ep')->spurt($dom); + Mojo::File->new('themes/'.$config->{theme}.'/templates/raw.html.ep')->spurt(encode('UTF-8', $dom2)); } =encoding utf8 diff --git a/lib/Lutim/Command/cron/watch.pm b/lib/Lutim/Command/cron/watch.pm index 7ae7cad..31eda39 100644 --- a/lib/Lutim/Command/cron/watch.pm +++ b/lib/Lutim/Command/cron/watch.pm @@ -1,8 +1,10 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: package Lutim::Command::cron::watch; use Mojo::Base 'Mojolicious::Command'; -use Mojo::Util qw(slurp decode); use Filesys::DiskUsage qw/du/; -use LutimModel; +use Lutim::DB::Image; +use Lutim; +use Mojo::File; use Switch; use FindBin qw($Bin); use File::Spec qw(catfile); @@ -13,10 +15,18 @@ has usage => sub { shift->extract_usage }; sub run { my $c = shift; + my $cfile = Mojo::File->new($Bin, '..' , 'lutim.conf'); + if (defined $ENV{MOJO_CONFIG}) { + $cfile = Mojo::File->new($ENV{MOJO_CONFIG}); + unless (-e $cfile->to_abs) { + $cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG}); + } + } my $config = $c->app->plugin('Config', { - file => File::Spec->catfile($Bin, '..' ,'lutim.conf'), + file => $cfile, default => { - policy_when_full => 'warn' + policy_when_full => 'warn', + dbtype => 'sqlite', } }); @@ -36,11 +46,15 @@ sub run { } case 'delete' { say '[Lutim cron job watch] Older files are being deleted'; + my $dbi = Lutim::DB::Image->new(app => $c->app); + my $l = Lutim->new; do { - for my $img (LutimModel::Lutim->select('WHERE path IS NOT NULL AND enabled = 1 ORDER BY created_at ASC LIMIT 50')) { - unlink $img->path() or warn "Could not unlink ".$img->path.": $!"; - $img->update(enabled => 0); - } + $dbi->get_50_oldest()->each( + sub { + my ($img, $num) = @_; + $l->app->delete_image($img); + } + ); } while (du(qw/files/) > $config->{max_total_size}); } else { diff --git a/lib/Lutim/Controller.pm b/lib/Lutim/Controller.pm index d9229b8..48e289f 100644 --- a/lib/Lutim/Controller.pm +++ b/lib/Lutim/Controller.pm @@ -1,9 +1,10 @@ # vim:set sw=4 ts=4 sts=4 expandtab: package Lutim::Controller; use Mojo::Base 'Mojolicious::Controller'; -use Mojo::Util qw(url_unescape b64_encode); +use Mojo::Util qw(url_escape url_unescape b64_encode); use Mojo::Asset::Memory; use Mojo::JSON qw(true false); +use Lutim::DB::Image; use DateTime; use Digest::file qw(digest_file_hex); use Text::Unidecode; @@ -45,9 +46,12 @@ sub about { } sub stats { - shift->render( + my $c = shift; + + my $img = Lutim::DB::Image->new(app => $c); + $c->render( template => 'stats', - total => LutimModel::Lutim->count('WHERE path IS NOT NULL') + total => $img->count_not_empty ); } @@ -85,13 +89,13 @@ sub get_counter { my $short = $c->param('short'); my $token = $c->param('token'); - my @images = LutimModel::Lutim->select('WHERE short = ? AND path IS NOT NULL AND mod_token = ?', ($short, $token)); - if (scalar(@images)) { + my $img = Lutim::DB::Image->new(app => $c->app, short => $short); + if (defined($img->mod_token) && $img->mod_token eq $token) { return $c->render( json => { success => true, - counter => $images[0]->counter, - enabled => ($images[0]->enabled) ? true : false + counter => $img->counter, + enabled => ($img->enabled) ? true : false } ); } @@ -109,19 +113,18 @@ sub modify { my $token = $c->param('token'); my $url = $c->param('url'); - my @images = LutimModel::Lutim->select('WHERE short = ? AND path IS NOT NULL', $short); - if (scalar(@images)) { - my $image = $images[0]; + my $image = Lutim::DB::Image->new(app => $c->app, short => $short); + if ($image->path) { my $msg; - if ($image->mod_token() ne $token || $token eq '') { + if ($image->mod_token ne $token || $token eq '') { $msg = $c->l('The delete token is invalid.'); } else { $c->app->log->info('[MODIFICATION] someone modify '.$image->filename.' with token method (path: '.$image->path.')'); - $image->update( - delete_at_day => ($c->param('delete-day') && ($c->param('delete-day') <= $c->max_delay || $c->max_delay == 0)) ? $c->param('delete-day') : $c->max_delay, - delete_at_first_view => ($c->param('first-view')) ? 1 : 0, - ); + $image->delete_at_day(($c->param('delete-day') && ($c->param('delete-day') <= $c->max_delay || $c->max_delay == 0)) ? $c->param('delete-day') : $c->max_delay); + $image->delete_at_first_view(($c->param('first-view')) ? 1 : 0); + $image->write; + $msg = $c->l('The image\'s delay has been successfully modified'); if (defined($c->param('format')) && $c->param('format') eq 'json') { return $c->render( @@ -178,11 +181,10 @@ sub delete { my $short = $c->param('short'); my $token = $c->param('token'); - my @images = LutimModel::Lutim->select('WHERE short = ? AND path IS NOT NULL', $short); - if (scalar(@images)) { - my $image = $images[0]; + my $image = Lutim::DB::Image->new(app => $c->app, short => $short); + if ($image->path) { my $msg; - if ($image->mod_token() ne $token || $token eq '') { + if ($image->mod_token ne $token || $token eq '') { $msg = $c->l('The delete token is invalid.'); } elsif ($image->enabled() == 0) { $msg = $c->l('The image %1 has already been deleted.', $image->filename); @@ -349,102 +351,96 @@ sub add { return $c->redirect_to('/'); } } - if(LutimModel->begin) { - my @records = LutimModel::Lutim->select('WHERE path IS NULL LIMIT 1'); - if (scalar(@records)) { - # Save file and create record - my $filename = unidecode($upload->filename); - my $ext = ($filename =~ m/([^.]+)$/)[0]; - my $path = 'files/'.$records[0]->short.'.'.$ext; + my $record = Lutim::DB::Image->new(app => $c->app)->select_empty; + if ($record->short) { + # Save file and create record + my $filename = unidecode($upload->filename); + my $ext = ($filename =~ m/([^.]+)$/)[0]; + my $path = 'files/'.$record->short.'.'.$ext; - my ($width, $height); - if ($im_loaded && $mediatype ne 'image/svg+xml' && $mediatype !~ m#image/(x-)?xcf# && $mediatype ne 'image/webp') { # ImageMagick don't work in Debian with svg (for now?) - my $im = Image::Magick->new; - $im->BlobToImage($upload->slurp); + my ($width, $height); + if ($im_loaded && $mediatype ne 'image/svg+xml' && $mediatype !~ m#image/(x-)?xcf# && $mediatype ne 'image/webp') { # ImageMagick don't work in Debian with svg (for now?) + my $im = Image::Magick->new; + $im->BlobToImage($upload->slurp); - # Automatic rotation from EXIF tag - $im->AutoOrient(); + # Automatic rotation from EXIF tag + $im->AutoOrient(); - # Update the uploaded file with it's auto-rotated clone - my $asset = Mojo::Asset::Memory->new->add_chunk($im->ImageToBlob()); - $upload->asset($asset); + # Update the uploaded file with it's auto-rotated clone + my $asset = Mojo::Asset::Memory->new->add_chunk($im->ImageToBlob()); + $upload->asset($asset); - # Create the thumbnail - $width = $im->Get('width'); - $height = $im->Get('height'); - $im->Resize(geometry=>'x85'); - - $thumb = 'data:'.$mediatype.';base64,'; - if ($mediatype eq 'image/gif') { - $thumb .= b64_encode $im->[0]->ImageToBlob(); - } else { - $thumb .= b64_encode $im->ImageToBlob(); - } + # Create the thumbnail + $width = $im->Get('width'); + $height = $im->Get('height'); + $im->Resize(geometry=>'x85'); + $thumb = 'data:'.$mediatype.';base64,'; + if ($mediatype eq 'image/gif') { + $thumb .= b64_encode $im->[0]->ImageToBlob(); + } else { + $thumb .= b64_encode $im->ImageToBlob(); } - unless ((defined($keep_exif) && $keep_exif) || $mediatype eq 'image/svg+xml' || $mediatype !~ m#image/(x-)?xcf# || $mediatype ne 'image/webp') { - # Remove the EXIF tags - my $data = new IO::Scalar \$upload->slurp(); - my $et = new Image::ExifTool; - - # Use $data in Image::ExifTool object - $et->ExtractInfo($data); - # Remove all metadata - $et->SetNewValue('*', undef); - - # Create a temporary IO::Scalar to write into - my $temp; - my $a = new IO::Scalar \$temp; - $et->WriteInfo($data, $a); - - # Update the uploaded file with it's no-tags clone - $data = Mojo::Asset::Memory->new->add_chunk($temp); - $upload->asset($data); - } - - my $key; - if ($c->param('crypt') || $c->config->{always_encrypt}) { - ($upload, $key) = $c->crypt($upload, $filename); - } - $upload->move_to($path); - - $records[0]->update( - path => $path, - filename => $filename, - mediatype => $mediatype, - footprint => digest_file_hex($path, 'SHA-512'), - enabled => 1, - delete_at_day => ($c->param('delete-day') && ($c->param('delete-day') <= $c->max_delay || $c->max_delay == 0)) ? $c->param('delete-day') : $c->max_delay, - delete_at_first_view => ($c->param('first-view')) ? 1 : 0, - created_at => time(), - created_by => $ip, - width => $width, - height => $height - ); - - # Log image creation - $c->app->log->info('[CREATION] '.$ip.' pushed '.$filename.' (path: '.$path.')'); - - # Give url to user - $short = $records[0]->short; - $real_short = $short; - if (!defined($records[0]->mod_token)) { - $records[0]->update( - mod_token => $c->shortener($c->config->{token_length}) - ); - } - $token = $records[0]->mod_token; - $short .= '/'.$key if (defined($key)); - - $limit = $records[0]->delete_at_day; - $created = $records[0]->created_at; - } else { - # Houston, we have a problem - $msg = $c->l('There is no more available URL. Retry or contact the administrator. %1', $c->config->{contact}); } + + unless ((defined($keep_exif) && $keep_exif) || $mediatype eq 'image/svg+xml' || $mediatype !~ m#image/(x-)?xcf# || $mediatype ne 'image/webp') { + # Remove the EXIF tags + my $data = new IO::Scalar \$upload->slurp(); + my $et = new Image::ExifTool; + + # Use $data in Image::ExifTool object + $et->ExtractInfo($data); + # Remove all metadata + $et->SetNewValue('*', undef); + + # Create a temporary IO::Scalar to write into + my $temp; + my $a = new IO::Scalar \$temp; + $et->WriteInfo($data, $a); + + # Update the uploaded file with it's no-tags clone + $data = Mojo::Asset::Memory->new->add_chunk($temp); + $upload->asset($data); + } + + my $key; + if ($c->param('crypt') || $c->config('always_encrypt')) { + ($upload, $key) = $c->crypt($upload, $filename); + } + $upload->move_to($path); + + $record->path($path) + ->filename($filename) + ->mediatype($mediatype) + ->footprint(digest_file_hex($path, 'SHA-512')) + ->enabled(1) + ->delete_at_day(($c->param('delete-day') && ($c->param('delete-day') <= $c->max_delay || $c->max_delay == 0)) ? $c->param('delete-day') : $c->max_delay) + ->delete_at_first_view(($c->param('first-view'))? 1 : 0) + ->created_at(time()) + ->created_by($ip) + ->width($width) + ->height($height) + ->write; + + # Log image creation + $c->app->log->info('[CREATION] '.$ip.' pushed '.$filename.' (path: '.$path.')'); + + # Give url to user + $short = $record->short; + $real_short = $short; + if (!defined($record->mod_token)) { + $record->mod_token($c->shortener($c->config->{token_length}))->write; + } + $token = $record->mod_token; + $short .= '/'.$key if (defined($key)); + + $limit = $record->delete_at_day; + $created = $record->created_at; + } else { + # Houston, we have a problem + $msg = $c->l('There is no more available URL. Retry or contact the administrator. %1', $c->config->{contact}); } - LutimModel->commit; } else { $msg = $c->l('The file %1 is not an image.', $upload->filename); } @@ -519,15 +515,14 @@ sub short { my $thumb = $c->param('thumb'); my $dl = (defined($c->param('dl'))) ? 'attachment' : 'inline'; - my @images = LutimModel::Lutim->select('WHERE short = ? AND ENABLED = 1 AND path IS NOT NULL', $short); - - if (scalar(@images)) { - if($images[0]->delete_at_day && $images[0]->created_at + $images[0]->delete_at_day * 86400 <= time()) { + my $image = Lutim::DB::Image->new(app => $c->app, short => $short); + if ($image->enabled && $image->path) { + if($image->delete_at_day && $image->created_at + $image->delete_at_day * 86400 <= time()) { # Log deletion - $c->app->log->info('[DELETION] someone tried to view '.$images[0]->filename.' but it has been removed by expiration (path: '.$images[0]->path.')'); + $c->app->log->info('[DELETION] someone tried to view '.$image->filename.' but it has been removed by expiration (path: '.$image->path.')'); # Delete image - $c->delete_image($images[0]); + $c->delete_image($image); # Warn user $c->flash( @@ -539,54 +534,53 @@ sub short { my $test; if (defined($touit)) { $test = 1; - my $short = $images[0]->short; + my $short = $image->short; $short .= '/'.$key if (defined($key)); my ($width, $height) = (340,340); - if ($images[0]->mediatype eq 'image/gif') { - if (defined($images[0]->width) && defined($images[0]->height)) { - ($width, $height) = ($images[0]->width, $images[0]->height); + if ($image->mediatype eq 'image/gif') { + if (defined($image->width) && defined($image->height)) { + ($width, $height) = ($image->width, $image->height); } elsif ($im_loaded) { - my $upload = $c->decrypt($key, $images[0]->path); + my $upload = $c->decrypt($key, $image->path); my $im = Image::Magick->new; $im->BlobToImage($upload->slurp); $width = $im->Get('width'); $height = $im->Get('height'); - $images[0]->update( - width => $width, - height => $height - ); + $image->width($width) + ->height($height) + ->write; } } return $c->render( template => 'twitter', layout => undef, short => $short, - filename => $images[0]->filename, - mimetype => ($c->req->url->to_abs()->scheme eq 'https') ? $images[0]->mediatype : '', + filename => $image->filename, + mimetype => ($c->req->url->to_abs()->scheme eq 'https') ? $image->mediatype : '', width => $width, height => $height ); } else { # Delete image if needed - if ($images[0]->delete_at_first_view && $images[0]->counter >= 1) { + if ($image->delete_at_first_view && $image->counter >= 1) { # Log deletion - $c->app->log->info('[DELETION] someone made '.$images[0]->filename.' removed (path: '.$images[0]->path.')'); + $c->app->log->info('[DELETION] someone made '.$image->filename.' removed (path: '.$image->path.')'); # Delete image - $c->delete_image($images[0]); + $c->delete_image($image); $c->flash( msg => $c->l('Unable to find the image: it has been deleted.') ); return $c->redirect_to('/'); } else { - my $expires = ($images[0]->delete_at_day) ? $images[0]->delete_at_day : 360; - my $dt = DateTime->from_epoch( epoch => $expires * 86400 + $images[0]->created_at); + my $expires = ($image->delete_at_day) ? $image->delete_at_day : 360; + my $dt = DateTime->from_epoch( epoch => $expires * 86400 + $image->created_at); $dt->set_time_zone('GMT'); $expires = $dt->strftime("%a, %d %b %Y %H:%M:%S GMT"); - $test = $c->render_file($images[0]->filename, $images[0]->path, $images[0]->mediatype, $dl, $expires, $images[0]->delete_at_first_view, $key, $thumb); + $test = $c->render_file($im_loaded, $image->filename, $image->path, $image->mediatype, $dl, $expires, $image->delete_at_first_view, $key, $thumb); } } @@ -594,40 +588,37 @@ sub short { # Update counter $c->on(finish => sub { # Log access - $c->app->log->info('[VIEW] someone viewed '.$images[0]->filename.' (path: '.$images[0]->path.')'); + $c->app->log->info('[VIEW] someone viewed '.$image->filename.' (path: '.$image->path.')'); # Update record - my $counter = $images[0]->counter + 1; - $images[0]->update(counter => $counter); - - $images[0]->update(last_access_at => time()); + if ($c->config('minion')->{enabled}) { + $c->app->minion->enqueue(accessed => [$image->short, time]); + } else { + $image->accessed(time); + } # Delete image if needed - if ($images[0]->delete_at_first_view) { + if ($image->delete_at_first_view) { # Log deletion - $c->app->log->info('[DELETION] someone made '.$images[0]->filename.' removed (path: '.$images[0]->path.')'); + $c->app->log->info('[DELETION] someone made '.$image->filename.' removed (path: '.$image->path.')'); # Delete image - $c->delete_image($images[0]); + $c->delete_image($image); } }); } + } elsif ($image->path && !$image->enabled) { + # Log access try + $c->app->log->info('[NOT FOUND] someone tried to view '.$short.' but it does\'nt exist anymore.'); + + # Warn user + $c->flash( + msg => $c->l('Unable to find the image: it has been deleted.') + ); + return $c->redirect_to('/'); } else { - @images = LutimModel::Lutim->select('WHERE short = ? AND ENABLED = 0 AND path IS NOT NULL', $short); - - if (scalar(@images)) { - # Log access try - $c->app->log->info('[NOT FOUND] someone tried to view '.$short.' but it does\'nt exist anymore.'); - - # Warn user - $c->flash( - msg => $c->l('Unable to find the image: it has been deleted.') - ); - return $c->redirect_to('/'); - } else { - # Image never existed - $c->render_not_found; - } + # Image never existed + $c->render_not_found; } } @@ -635,105 +626,122 @@ sub zip { my $c = shift; my $imgs = $c->every_param('i'); - my $zip = Archive::Zip->new(); + my $img_nb = scalar(@{$imgs}); + my $max_zip = $c->config('max_files_in_zip'); - # We HAVE to add a png file at the beginning, otherwise the $zip - # could use the mimetype of an SVG file if it's the first file asked. - $zip->addFile('themes/default/public/img/favicon.png', 'hosted_with_lutim.png'); + if ($img_nb <= $max_zip) { + my $zip = Archive::Zip->new(); - $zip->addDirectory('images/'); - for my $img (@{$imgs}) { - my ($short, $key) = split('/', $img); - if (defined $key) { - $key =~ s/\.[^.]*//; - } else { - $short =~ s/\.[^.]*//; - } - my @images = LutimModel::Lutim->select('WHERE short = ? AND ENABLED = 1 AND path IS NOT NULL', $short); + # We HAVE to add a png file at the beginning, otherwise the $zip + # could use the mimetype of an SVG file if it's the first file asked. + $zip->addFile('themes/default/public/img/favicon.png', 'hosted_with_lutim.png'); - if (scalar(@images)) { - my $filename = $images[0]->filename; - if($images[0]->delete_at_day && $images[0]->created_at + $images[0]->delete_at_day * 86400 <= time()) { - # Log deletion - $c->app->log->info('[DELETION] someone tried to view '.$images[0]->filename.' but it has been removed by expiration (path: '.$images[0]->path.')'); - - # Delete image - $c->delete_image($images[0]); - - # Warn user - $zip->addString($c->l('Unable to find the image: it has been deleted.'), 'images/'.$filename.'.txt'); - next; - } - - # Delete image if needed - if ($images[0]->delete_at_first_view && $images[0]->counter >= 1) { - # Log deletion - $c->app->log->info('[DELETION] someone made '.$images[0]->filename.' removed (path: '.$images[0]->path.')'); - - # Delete image - $c->delete_image($images[0]); - - $zip->addString($c->l('Unable to find the image: it has been deleted.'), 'images/'.$filename.'.txt'); - next; + $zip->addDirectory('images/'); + for my $img (@{$imgs}) { + my ($short, $key) = split('/', $img); + if (defined $key) { + $key =~ s/\.[^.]*//; } else { - my $expires = ($images[0]->delete_at_day) ? $images[0]->delete_at_day : 360; - my $dt = DateTime->from_epoch( epoch => $expires * 86400 + $images[0]->created_at); - $dt->set_time_zone('GMT'); - $expires = $dt->strftime("%a, %d %b %Y %H:%M:%S GMT"); + $short =~ s/\.[^.]*//; + } + my $image = Lutim::DB::Image->new(app => $c->app, short => $short); - my $path = $images[0]->path; - unless ( -f $path && -r $path ) { - $c->app->log->error("Cannot read file [$path]. error [$!]"); + if ($image->enabled && $image->path) { + my $filename = $image->filename; + if($image->delete_at_day && $image->created_at + $image->delete_at_day * 86400 <= time()) { + # Log deletion + $c->app->log->info('[DELETION] someone tried to view '.$image->filename.' but it has been removed by expiration (path: '.$image->path.')'); + + # Delete image + $c->delete_image($image); + + # Warn user $zip->addString($c->l('Unable to find the image: it has been deleted.'), 'images/'.$filename.'.txt'); next; } - if ($key) { - $zip->addString($c->decrypt($key, $path)->slurp, "images/$filename"); + # Delete image if needed + if ($image->delete_at_first_view && $image->counter >= 1) { + # Log deletion + $c->app->log->info('[DELETION] someone made '.$image->filename.' removed (path: '.$image->path.')'); + + # Delete image + $c->delete_image($image); + + $zip->addString($c->l('Unable to find the image: it has been deleted.'), 'images/'.$filename.'.txt'); + next; } else { - $zip->addFile($path, "images/$filename"); + my $expires = ($image->delete_at_day) ? $image->delete_at_day : 360; + my $dt = DateTime->from_epoch( epoch => $expires * 86400 + $image->created_at); + $dt->set_time_zone('GMT'); + $expires = $dt->strftime("%a, %d %b %Y %H:%M:%S GMT"); + + my $path = $image->path; + unless ( -f $path && -r $path ) { + $c->app->log->error("Cannot read file [$path]. error [$!]"); + $zip->addString($c->l('Unable to find the image: it has been deleted.'), 'images/'.$filename.'.txt'); + next; + } + + if ($key) { + $zip->addString($c->decrypt($key, $path)->slurp, "images/$filename"); + } else { + $zip->addFile($path, "images/$filename"); + } + + # Log access + $c->app->log->info('[VIEW] someone viewed '.$image->filename.' (path: '.$image->path.')'); + + # Update counter and record + if ($c->config('minion')->{enabled}) { + $c->app->minion->enqueue(accessed => [$image->short, time]); + } else { + $image->accessed(time); + } } - - # Log access - $c->app->log->info('[VIEW] someone viewed '.$images[0]->filename.' (path: '.$images[0]->path.')'); - # Update counter - $images[0]->update(counter => $images[0]->counter + 1); - # Update record - $images[0]->update(last_access_at => time()); - } - } else { - @images = LutimModel::Lutim->select('WHERE short = ? AND ENABLED = 0 AND path IS NOT NULL', $short); - - if (scalar(@images)) { + } elsif ($image->path && !$image->enabled) { # Log access try $c->app->log->info('[NOT FOUND] someone tried to view '.$short.' but it does\'nt exist anymore.'); # Warn user - $zip->addString($c->l('Unable to find the image: it has been deleted.'), 'images/'.$images[0]->filename.'.txt'); + $zip->addString($c->l('Unable to find the image: it has been deleted.'), 'images/'.$image->filename.'.txt'); next; } else { $zip->addString($c->l('Image not found.'), 'images/'.$short.'.txt'); next; } } - } - my ($fh, $zipfile) = Archive::Zip::tempFile(); - unless ($zip->writeToFileNamed($zipfile) == AZ_OK) { - $c->flash( - msg => $c->l('Something went wrong when creating the zip file. Try again later or contact the administrator (%1).', $c->config('contact')) + my ($fh, $zipfile) = Archive::Zip::tempFile(); + unless ($zip->writeToFileNamed($zipfile) == AZ_OK) { + $c->flash( + msg => $c->l('Something went wrong when creating the zip file. Try again later or contact the administrator (%1).', $c->config('contact')) + ); + return $c->redirect_to('/'); + } + $c->res->content->headers->content_type('application/zip;name=images.zip'); + $c->res->content->headers->content_disposition('attachment;filename=images.zip');; + + my $asset = Mojo::Asset::File->new(path => $zipfile); + $c->res->content->asset($asset); + $c->res->content->headers->content_length($asset->size); + + unlink $zipfile; + + return $c->rendered(200); + } else { + my $i = -1; + my @urls = (); + my @esc_imgs = map { my $e = $_; $e = url_escape($e); $e =~ s#%2F#/#g; $e } @{$imgs}; + while (++$i < $img_nb) { + my $stop = ($i + $max_zip - 1 < $img_nb) ? $i + $max_zip - 1 : $img_nb - 1; + push @urls, $c->url_for('/zip')->to_abs->to_string.'?i='.join('&i=', @esc_imgs[$i..$stop]); + $i = $stop; + } + $c->render( + template => 'zip', + urls => \@urls ); - return $c->redirect_to('/'); } - $c->res->content->headers->content_type('application/zip;name=images.zip'); - $c->res->content->headers->content_disposition('attachment;filename=images.zip');; - - my $asset = Mojo::Asset::File->new(path => $zipfile); - $c->res->content->asset($asset); - $c->res->content->headers->content_length($asset->size); - - unlink $zipfile; - - return $c->rendered(200); } 1; diff --git a/lib/Lutim/DB/Image.pm b/lib/Lutim/DB/Image.pm new file mode 100644 index 0000000..b458c48 --- /dev/null +++ b/lib/Lutim/DB/Image.pm @@ -0,0 +1,332 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +package Lutim::DB::Image; +use Mojo::Base -base; + +has 'short'; +has 'path'; +has 'footprint'; +has 'enabled'; +has 'mediatype'; +has 'filename'; +has 'counter' => 0; +has 'delete_at_first_view'; +has 'delete_at_day'; +has 'created_at'; +has 'created_by'; +has 'last_access_at'; +has 'mod_token'; +has 'width'; +has 'height'; +has 'app'; + +=head1 NAME + +Lutim::DB::Image - DB abstraction layer for Lutim images + +=head1 Contributing + +When creating a new database accessor, make sure that it provides the following subroutines. +After that, modify this file and modify the C subroutine to allow to use your accessor. + +Have a look at Lutim::DB::Image::SQLite's code: it's simple and may be more understandable that this doc. + +=head1 Attributes + +=over 1 + +=item B : random string + +=item B : string, path to the image, relative to lutim's installation directory + +=item B : string, sha512 checksum of the image + +=item B : boolean, is the image accessible? + +=item B : string, mimetype of the image + +=item B : string + +=item B : integer + +=item B : boolean + +=item B : integer, number of days from image upload to deletion + +=item B : unix timestamp + +=item B : unix timestamp + +=item B : unix timestamp + +=item B : random string + +=item B : integer + +=item B : integer + +=item B : a mojolicious object + +=back + +=head1 Sub routines + +=head2 new + +=over 1 + +=item B : C<$c = Lutim::DB::Image-Enew(app =E $self);> + +=item B : any of the attribute above + +=item B : construct a new db accessor object. If the C attribute is provided, it have to load the informations from the database. + +=item B : the db accessor object + +=item B : the app argument is used by Lutim::DB::Image to choose which db accessor will be used, you don't need to use it in new(), but you can use it to access helpers or configuration settings in the other subroutines + +=back + +=cut + +sub new { + my $c = shift; + + $c = $c->SUPER::new(@_); + + if (ref($c) eq 'Lutim::DB::Image') { + my $dbtype = $c->app->config('dbtype'); + if ($dbtype eq 'sqlite') { + use Lutim::DB::Image::SQLite; + $c = Lutim::DB::Image::SQLite->new(@_); + } elsif ($dbtype eq 'postgresql') { + use Lutim::DB::Image::Pg; + $c = Lutim::DB::Image::Pg->new(@_); + } + } + + return $c; +} + +sub to_hash { + my $c = shift; + + return { + short => $c->short, + path => $c->path, + footprint => $c->footprint, + enabled => $c->enabled, + mediatype => $c->mediatype, + filename => $c->filename, + counter => $c->counter, + delete_at_first_view => $c->delete_at_first_view, + delete_at_day => $c->delete_at_day, + created_at => $c->created_at, + created_by => $c->created_by, + last_access_at => $c->last_access_at, + mod_token => $c->mod_token, + width => $c->width, + height => $c->height + }; +} + +=head2 accessed + +=over 1 + +=item B : C<$c-Eaccessed($time)> + +=item B : an unix timestamp + +=item B : increments the counter attribute by one, set the last_access_at attribute to $time and update the database + +=item B : the db accessor object + +=back + +=head2 count_delete_at_day_endis + +=over 1 + +=item B : C<$c-Ecount_delete_at_day_endis($delete_at_day, $enabled[, $time])> + +=item B : two mandatory parameters: one integer, the delete_at_day attribute, a boolean (0 or 1), the enabled attribute + an optional parameter: an unix timestamp + +=item B : count how many images there is with the given delete_at_day attribute, and enabled or disabled, depending on the given enabled attribute + if the optional parameter is given, count only images according to the given mandatory parameters that were created before the timestamp + +=item B : integer + +=back + +=head2 count_created_before + +=over 1 + +=item B : C<$c-Ecount_created_before($time)> + +=item B : an unix timestamp + +=item B : count how many images have been created before the given timestamp + +=item B : integer + +=back + +=head2 select_created_after + +=over 1 + +=item B : C<$c-Eselect_created_after($time)> + +=item B : an unix timestamp + +=item B : select images created after the given timestamp + +=item B : a Mojo::Collection object containing the images created after the given timestamp + +=back + +=head2 select_empty + +=over 1 + +=item B : C<$c-Eselect_empty> + +=item B : none + +=item B : select a ready-to-use empty record + +=item B : a db accessor object + +=back + +=head2 write + +=over 1 + +=item B : C<$c-Ewrite> + +=item B : none + +=item B : create or update a record in the database, with the values of the object's attributes + +=item B : the db accessor object + +=back + +=head2 count_short + +=over 1 + +=item B : C<$c-Ecount_short($short)> + +=item B : a random string, unique image identifier in the database + +=item B : checks that an identifier isn't already used + +=item B : integer, number of records having this identifier (should be 0 or 1) + +=back + +=head2 count_empty + +=over 1 + +=item B : C<$c-Ecount_empty> + +=item B : none + +=item B : counts the number of record which path is null + +=item B : integer + +=back + +=head2 count_not_empty + +=over 1 + +=item B : C<$c-Ecount_not_empty> + +=item B : none + +=item B : counts the number of record which path is not null + +=item B : integer + +=back + +=head2 clean_ips_until + +=over 1 + +=item B : C<$c-Eclean_ips_until($time)> + +=item B : unix timestamp + +=item B : remove the image's sender information on images created before the given timestamp + +=item B : the db accessor object + +=back + +=head2 get_no_longer_viewed_files + +=over 1 + +=item B : C<$c-Eget_no_longer_viewed_files($time)> + +=item B : unix timestamp + +=item B : get images no longer viewed after the given timestamp + +=item B : a Mojo::Collection object containing the no longer viewed images as Lutim::DB::Image objects + +=back + +=head2 get_images_to_clean + +=over 1 + +=item B : C<$c-Eget_images_to_clean> + +=item B : none + +=item B : get images that are expired but not marked as it + +=item B : a Mojo::Collection object containing the images to clean as Lutim::DB::Image objects + +=back + +=head2 get_50_oldest + +=over 1 + +=item B : C<$c-Eget_50_oldest> + +=item B : none + +=item B : get the 50 oldest enabled images + +=item B : a Mojo::Collection object containing the 50 oldest enabled images as Lutim::DB::Image objects + +=back + +=head2 disable + +=over 1 + +=item B : C<$c-Edisable> + +=item B : none + +=item B : change the attribute C to false and update the database record + +=item B : the db accessor object + +=back + +=cut + +1; diff --git a/lib/Lutim/DB/Image/Pg.pm b/lib/Lutim/DB/Image/Pg.pm new file mode 100644 index 0000000..97dc4d0 --- /dev/null +++ b/lib/Lutim/DB/Image/Pg.pm @@ -0,0 +1,229 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +package Lutim::DB::Image::Pg; +use Mojo::Base 'Lutim::DB::Image'; +use Mojo::Collection 'c'; + +has 'record' => 0; + +sub new { + my $c = shift; + + $c = $c->SUPER::new(@_); + $c = $c->_slurp if ($c->short); + + return $c; +} + +sub accessed { + my $c = shift; + my $time = shift; + + my $h = $c->app->pg->db->query('UPDATE lutim SET counter = counter + 1, last_access_at = ? WHERE short = ? RETURNING counter, last_access_at', $time, $c->short)->hashes->first; + $c->counter($h->{counter}); + $c->last_access_at($h->{last_access_at}); + + return $c; +} + +sub count_delete_at_day_endis { + my $c = shift; + my $day = shift; + my $enabled = shift; + my $created = shift; + + if (defined $created) { + return $c->app->pg->db->query('SELECT count(short) FROM lutim WHERE path IS NOT NULL AND delete_at_day = ? AND enabled = ? AND created_at < ?', $day, $enabled, $created)->hashes->first->{count}; + } else { + return $c->app->pg->db->query('SELECT count(short) FROM lutim WHERE path IS NOT NULL AND delete_at_day = ? AND enabled = ?', $day, $enabled)->hashes->first->{count}; + } +} + +sub count_created_before { + my $c = shift; + my $time = shift; + + return $c->app->pg->db->query('SELECT count(short) FROM lutim WHERE path IS NOT NULL AND created_at < ?', $time)->hashes->first->{count}; +} + +sub select_created_after { + my $c = shift; + my $time = shift; + + my @images; + + my $records = $c->app->pg->db->query('SELECT * FROM lutim WHERE path IS NOT NULL AND created_at >= ?', $time)->hashes; + + $records->each( + sub { + my ($e, $num) = @_; + my $i = Lutim::DB::Image->new(app => $c->app); + $i->_slurp($e); + + push @images, $i; + } + ); + + return c(@images); +} + +sub select_empty { + my $c = shift; + + my $record = $c->app->pg->db->query('SELECT * FROM lutim WHERE path IS NULL LIMIT 1')->hashes->first; + + $c = $c->_slurp($record); + + return $c; +} + +sub write { + my $c = shift; + + if ($c->record) { + $c->app->pg->db->query('UPDATE lutim SET counter = ?, created_at = ?, created_by = ?, delete_at_day = ?, delete_at_first_view = ?, enabled = ?, filename = ?, footprint = ?, height = ?, last_access_at = ?, mediatype = ?, mod_token = ?, path = ?, short = ?, width = ? WHERE short = ?', $c->counter, $c->created_at, $c->created_by, $c->delete_at_day, $c->delete_at_first_view, $c->enabled, $c->filename, $c->footprint, $c->height, $c->last_access_at, $c->mediatype, $c->mod_token, $c->path, $c->short, $c->width, $c->short); + } else { + $c->app->pg->db->query('INSERT INTO lutim (counter, created_at, created_by, delete_at_day, delete_at_first_view, enabled, filename, footprint, height, last_access_at, mediatype, mod_token, path, short, width) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', $c->counter, $c->created_at, $c->created_by, $c->delete_at_day, $c->delete_at_first_view, $c->enabled, $c->filename, $c->footprint, $c->height, $c->last_access_at, $c->mediatype, $c->mod_token, $c->path, $c->short, $c->width); + $c->record(1); + } + + return $c; +} + +sub count_short { + my $c = shift; + my $short = shift; + + return $c->app->pg->db->query('SELECT count(short) FROM lutim WHERE short = ?', $short)->hashes->first->{count}; +} + +sub count_empty { + my $c = shift; + + return $c->app->pg->db->query('SELECT count(short) FROM lutim WHERE path IS NULL')->hashes->first->{count}; +} + +sub count_not_empty { + my $c = shift; + + return $c->app->pg->db->query('SELECT count(short) FROM lutim WHERE path IS NOT NULL')->hashes->first->{count}; +} + +sub clean_ips_until { + my $c = shift; + my $time = shift; + + $c->app->pg->db->query('UPDATE lutim SET created_by = NULL WHERE path IS NOT NULL AND created_at < ?', $time); + + return $c; +} + +sub get_no_longer_viewed_files { + my $c = shift; + my $time = shift; + + my @images; + + my $records = $c->app->pg->db->query('SELECT * FROM lutim WHERE enabled = 1 AND last_access_at < ?', $time)->{hashes}; + + $records->each( + sub { + my ($e, $num) = @_; + my $i = Lutim::DB::Image->new(app => $c->app); + $i->record(1); + $i->_slurp($e); + + push @images, $i; + } + ); + + return c(@images); +} + +sub get_images_to_clean { + my $c = shift; + + my @images; + + my $records = $c->app->pg->db->query('SELECT * FROM lutim WHERE enabled = 1 AND (delete_at_day * 86400) < (? - created_at) AND delete_at_day != 0', time())->hashes; + + $records->each( + sub { + my ($e, $num) = @_; + my $i = Lutim::DB::Image->new(app => $c->app); + $i->_slurp($e); + + push @images, $i; + } + ); + + return c(@images); +} + +sub get_50_oldest { + my $c = shift; + + my @images; + + my $records = $c->app->pg->db->query('SELECT * FROM lutim WHERE path IS NOT NULL AND enabled = 1 ORDER BY created_at ASC LIMIT 50')->hashes; + + $records->each( + sub { + my ($e, $num) = @_; + my $i = Lutim::DB::Image->new(app => $c->app); + $i->_slurp($e); + + push @images, $i; + } + ); + + return c(@images); +} + +sub disable { + my $c = shift; + + $c->app->pg->db->query('UPDATE lutim SET enabled = 0 WHERE short = ?', $c->short); + $c->enabled(0); + + return $c; +} + +sub _slurp { + my $c = shift; + my $r = shift; + + my $image; + if (defined $r) { + $image = $r; + } else { + my $images = $c->app->pg->db->query('SELECT * FROM lutim WHERE short = ?', $c->short)->hashes; + + if ($images->size) { + $image = $images->first; + } + } + + if ($image) { + $c->short($image->{short}); + $c->path($image->{path}); + $c->footprint($image->{footprint}); + $c->enabled($image->{enabled}); + $c->mediatype($image->{mediatype}); + $c->filename($image->{filename}); + $c->counter($image->{counter}); + $c->delete_at_first_view($image->{delete_at_first_view}); + $c->delete_at_day($image->{delete_at_day}); + $c->created_at($image->{created_at}); + $c->created_by($image->{created_by}); + $c->last_access_at($image->{last_access_at}); + $c->mod_token($image->{mod_token}); + $c->width($image->{width}); + $c->height($image->{height}); + + $c->record(1); + } + + return $c; +} + +1; diff --git a/lib/Lutim/DB/Image/SQLite.pm b/lib/Lutim/DB/Image/SQLite.pm new file mode 100644 index 0000000..c9d604d --- /dev/null +++ b/lib/Lutim/DB/Image/SQLite.pm @@ -0,0 +1,259 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +package Lutim::DB::Image::SQLite; +use Mojo::Base 'Lutim::DB::Image'; +use Lutim::DB::SQLite; +use Mojo::Collection 'c'; + +has 'record'; + +sub new { + my $c = shift; + + $c = $c->SUPER::new(@_); + $c = $c->_slurp if ($c->short); + + return $c; +} + +sub accessed { + my $c = shift; + my $time = shift; + + $c->record->update( + counter => $c->counter + 1, + last_access_at => $time + ); + + $c->counter($c->record->counter); + $c->last_access_at($c->record->last_access_at); + + return $c; +} + +sub count_delete_at_day_endis { + my $c = shift; + my $day = shift; + my $enabled = shift; + my $created = shift; + + if (defined $created) { + return Lutim::DB::SQLite::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = ? AND enabled = ? AND created_at < ?', $day, $enabled, $created); + } else { + return Lutim::DB::SQLite::Lutim->count('WHERE path IS NOT NULL AND delete_at_day = ? AND enabled = ?', $day, $enabled); + } +} + +sub count_created_before { + my $c = shift; + my $time = shift; + + return Lutim::DB::SQLite::Lutim->count('WHERE path IS NOT NULL AND created_at < ?', $time); +} + +sub select_created_after { + my $c = shift; + my $time = shift; + + my @images; + + my @records = Lutim::DB::SQLite::Lutim->select('WHERE path IS NOT NULL AND created_at >= ?', $time); + + for my $e (@records) { + my $i = Lutim::DB::Image->new(app => $c->app); + $i->record($e); + $i->_slurp; + + push @images, $i; + } + + return c(@images); +} + +sub select_empty { + my $c = shift; + + my @records = Lutim::DB::SQLite::Lutim->select('WHERE path IS NULL LIMIT 1'); + + $c->record($records[0]); + $c = $c->_slurp; + + return $c; +} + +sub write { + my $c = shift; + + if ($c->record) { + $c->record->update( + counter => $c->counter, + created_at => $c->created_at, + created_by => $c->created_by, + delete_at_day => $c->delete_at_day, + delete_at_first_view => $c->delete_at_first_view, + enabled => $c->enabled, + filename => $c->filename, + footprint => $c->footprint, + height => $c->height, + last_access_at => $c->last_access_at, + mediatype => $c->mediatype, + mod_token => $c->mod_token, + path => $c->path, + short => $c->short, + width => $c->width + ); + } else { + my $record = Lutim::DB::SQLite::Lutim->create( + counter => $c->counter, + created_at => $c->created_at, + created_by => $c->created_by, + delete_at_day => $c->delete_at_day, + delete_at_first_view => $c->delete_at_first_view, + enabled => $c->enabled, + filename => $c->filename, + footprint => $c->footprint, + height => $c->height, + last_access_at => $c->last_access_at, + mediatype => $c->mediatype, + mod_token => $c->mod_token, + path => $c->path, + short => $c->short, + width => $c->width + ); + $c->record($record); + } + + return $c; +} + +sub count_short { + my $c = shift; + my $short = shift; + + return Lutim::DB::SQLite::Lutim->count('WHERE short IS ?', $short); +} + +sub count_empty { + my $c = shift; + + return Lutim::DB::SQLite::Lutim->count('WHERE path IS NULL'); +} + +sub count_not_empty { + my $c = shift; + + return Lutim::DB::SQLite::Lutim->count('WHERE path IS NOT NULL'); +} + +sub clean_ips_until { + my $c = shift; + my $time = shift; + + Lutim::DB::SQLite->do( + 'UPDATE lutim SET created_by = "" WHERE path IS NOT NULL AND created_at < ?', + {}, + $time + ); + + return $c; +} + +sub get_no_longer_viewed_files { + my $c = shift; + my $time = shift; + + my @images; + + my @records = Lutim::DB::SQLite::Lutim->select('WHERE enabled = 1 AND last_access_at < ?', $time); + + for my $e (@records) { + my $i = Lutim::DB::Image->new(app => $c->app); + $i->record($e); + $i->_slurp; + + push @images, $i; + } + + return c(@images); +} + +sub get_images_to_clean { + my $c = shift; + + my @images; + + my @records = Lutim::DB::SQLite::Lutim->select('WHERE enabled = 1 AND (delete_at_day * 86400) < (? - created_at) AND delete_at_day != 0', time()); + + for my $e (@records) { + my $i = Lutim::DB::Image->new(app => $c->app); + $i->record($e); + $i->_slurp; + + push @images, $i; + } + + return c(@images); +} + +sub get_50_oldest { + my $c = shift; + + my @images; + + my @records = Lutim::DB::SQLite::Lutim->select('WHERE path IS NOT NULL AND enabled = 1 ORDER BY created_at ASC LIMIT 50'); + + for my $e (@records) { + my $i = Lutim::DB::Image->new(app => $c->app); + $i->record($e); + $i->_slurp; + + push @images, $i; + } + + return c(@images); +} + +sub disable { + my $c = shift; + + $c->record->update(enabled => 0); + $c->enabled(0); + + return $c; +} + +sub _slurp { + my $c = shift; + + my @images; + if ($c->record) { + @images = ($c->record); + } elsif ($c->short) { + @images = Lutim::DB::SQLite::Lutim->select('WHERE short = ?', $c->short); + } + + if (scalar @images) { + my $image = $images[0]; + + $c->short($image->short); + $c->path($image->path); + $c->footprint($image->footprint); + $c->enabled($image->enabled); + $c->mediatype($image->mediatype); + $c->filename($image->filename); + $c->counter($image->counter); + $c->delete_at_first_view($image->delete_at_first_view); + $c->delete_at_day($image->delete_at_day); + $c->created_at($image->created_at); + $c->created_by($image->created_by); + $c->last_access_at($image->last_access_at); + $c->mod_token($image->mod_token); + $c->width($image->width); + $c->height($image->height); + + $c->record($image) unless $c->record; + } + + return $c; +} + +1; diff --git a/lib/LutimModel.pm b/lib/Lutim/DB/SQLite.pm similarity index 73% rename from lib/LutimModel.pm rename to lib/Lutim/DB/SQLite.pm index 7456baa..83bc9c2 100644 --- a/lib/LutimModel.pm +++ b/lib/Lutim/DB/SQLite.pm @@ -1,13 +1,21 @@ -package LutimModel; +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +package Lutim::DB::SQLite; use Mojolicious; +use Mojo::File; use FindBin qw($Bin); -use File::Spec qw(catfile); BEGIN { my $m = Mojolicious->new; + my $cfile = Mojo::File->new($Bin, '..' , 'lutim.conf'); + if (defined $ENV{MOJO_CONFIG}) { + $cfile = Mojo::File->new($ENV{MOJO_CONFIG}); + unless (-e $cfile->to_abs) { + $cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG}); + } + } our $config = $m->plugin('Config' => { - file => File::Spec->catfile($Bin, '..' ,'lutim.conf'), + file => $cfile->to_abs->to_string, default => { db_path => 'lutim.db' } diff --git a/lib/Lutim/Plugin/Helpers.pm b/lib/Lutim/Plugin/Helpers.pm new file mode 100644 index 0000000..a102f1b --- /dev/null +++ b/lib/Lutim/Plugin/Helpers.pm @@ -0,0 +1,245 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +package Lutim::Plugin::Helpers; +use Mojo::Base 'Mojolicious::Plugin'; +use Mojo::Util qw(quote); +use Crypt::CBC; +use Data::Entropy qw(entropy_source); + +sub register { + my ($self, $app) = @_; + + $app->plugin('PgURLHelper'); + + if ($app->config('dbtype') eq 'postgresql') { + use Mojo::Pg; + $app->helper(pg => \&_pg); + + # Database migration + my $migrations = Mojo::Pg::Migrations->new(pg => $app->pg); + if ($app->mode eq 'development') { + $migrations->from_file('utilities/migrations.sql')->migrate(0)->migrate(1); + } else { + $migrations->from_file('utilities/migrations.sql')->migrate(1); + } + } + + $app->helper(render_file => \&_render_file); + $app->helper(ip => \&_ip); + $app->helper(provisioning => \&_provisioning); + $app->helper(shortener => \&_shortener); + $app->helper(stop_upload => \&_stop_upload); + $app->helper(max_delay => \&_max_delay); + $app->helper(default_delay => \&_default_delay); + $app->helper(is_selected => \&_is_selected); + $app->helper(crypt => \&_crypt); + $app->helper(decrypt => \&_decrypt); + $app->helper(delete_image => \&_delete_image); +} + +sub _pg { + my $c = shift; + + state $pg = Mojo::Pg->new($c->app->pg_url($c->app->config('pgdb'))); + return $pg; +} + +sub _render_file { + my $c = shift; + my ($im_loaded, $filename, $path, $mediatype, $dl, $expires, $nocache, $key, $thumb) = @_; + + $dl = 'attachment' if ($mediatype =~ m/svg/); + $filename = quote($filename); + + my $asset; + unless (-f $path && -r $path) { + $c->app->log->error("Cannot read file [$path]. error [$!]"); + $c->flash( + msg => $c->l('Unable to find the image: it has been deleted.') + ); + return 500; + } + + $mediatype =~ s/x-//; + + my $headers = Mojo::Headers->new(); + if ($nocache) { + $headers->add('Cache-Control' => 'no-cache, no-store, max-age=0, must-revalidate'); + } else { + $headers->add('Expires' => $expires); + } + $headers->add('Content-Type' => $mediatype.';name='.$filename); + $headers->add('Content-Disposition' => $dl.';filename='.$filename); + $c->res->content->headers($headers); + + if ($key) { + $asset = $c->decrypt($key, $path); + } else { + $asset = Mojo::Asset::File->new(path => $path); + } + + if (defined $thumb && $im_loaded && $mediatype ne 'image/svg+xml' && $mediatype !~ m#image/(x-)?xcf# && $mediatype ne 'image/webp') { # ImageMagick don't work in Debian with svg (for now?) + my $im = Image::Magick->new; + $im->BlobToImage($asset->slurp); + + # Create the thumbnail + $im->Resize(geometry=>'x'.$c->config('thumbnail_size')); + + # Replace the asset with the thumbnail + $asset = Mojo::Asset::Memory->new->add_chunk($im->ImageToBlob()); + } + + $c->res->content->asset($asset); + $headers->add('Content-Length' => $asset->size); + + return $c->rendered(200); +} + +sub _ip { + my $c = shift; + my $ip_only = shift || 0; + + my $proxy = $c->req->headers->header('X-Forwarded-For'); + + my $ip = ($proxy) ? $proxy : $c->tx->remote_address; + + my $remote_port = (defined($c->req->headers->header('X-Remote-Port'))) ? $c->req->headers->header('X-Remote-Port') : $c->tx->remote_port; + + return ($ip_only) ? $ip : "$ip remote port:$remote_port"; +} + +sub _provisioning { + my $c = shift; + + # Create some short patterns for provisioning + my $img = Lutim::DB::Image->new(app => $c->app); + if ($img->count_empty < $c->app->config('provisioning')) { + for (my $i = 0; $i < $c->app->config('provis_step'); $i++) { + my $short; + do { + $short = $c->shortener($c->app->config('length')); + } while ($img->count_short($short) || $short eq 'about' || $short eq 'stats' || $short eq 'd' || $short eq 'm' || $short eq 'gallery' || $short eq 'zip' || $short eq 'infos'); + + $img->short($short) + ->counter(0) + ->enabled(1) + ->delete_at_first_view(0) + ->delete_at_day(0) + ->mod_token($c->shortener($c->app->config('token_length'))) + ->write; + + $img = Lutim::DB::Image->new(app => $c->app); + } + } +} + +sub _shortener { + my $c = shift; + my $length = shift; + + my @chars = ('a'..'z','A'..'Z','0'..'9'); + my $result = ''; + foreach (1..$length) { + $result .= $chars[entropy_source->get_int(scalar(@chars))]; + } + return $result; +} + +sub _stop_upload { + my $c = shift; + + if (-f 'stop-upload' || -f 'stop-upload.manual') { + $c->stash( + stop_upload => $c->l('Uploading is currently disabled, please try later or contact the administrator (%1).', $c->app->config('contact')) + ); + return 1; + } + return 0; +} + +sub _max_delay { + my $c = shift; + + return $c->app->config('max_delay') if ($c->app->config('max_delay') >= 0); + + warn "max_delay set to a negative value. Default to 0."; + return 0; +} + +sub _default_delay { + my $c = shift; + + return $c->app->config('default_delay') if ($c->app->config('default_delay') >= 0); + + warn "default_delay set to a negative value. Default to 0."; + return 0; +} + +sub _is_selected { + my $c = shift; + my $num = shift; + + return ($num == $c->default_delay) ? 'selected="selected"' : ''; +} + +sub _crypt { + my $c = shift; + my $upload = shift; + my $filename = shift; + + my $key = $c->shortener($c->config('crypto_key_length')); + + my $cipher = Crypt::CBC->new( + -key => $key, + -cipher => 'Blowfish', + -header => 'none', + -iv => 'dupajasi' + ); + + $cipher->start('encrypting'); + + my $crypt_asset = Mojo::Asset::File->new; + + $crypt_asset->add_chunk($cipher->crypt($upload->slurp)); + $crypt_asset->add_chunk($cipher->finish); + + my $crypt_upload = Mojo::Upload->new; + $crypt_upload->filename($filename); + $crypt_upload->asset($crypt_asset); + + return ($crypt_upload, $key); +} + +sub _decrypt { + my $c = shift; + my $key = shift; + my $file = shift; + + my $cipher = Crypt::CBC->new( + -key => $key, + -cipher => 'Blowfish', + -header => 'none', + -iv => 'dupajasi' + ); + + $cipher->start('decrypting'); + + my $decrypt_asset = Mojo::Asset::File->new; + + open(my $f, "<",$file) or die "Unable to read encrypted file: $!"; + binmode $f; + while (read($f, my $buffer,1024)) { + $decrypt_asset->add_chunk($cipher->crypt($buffer)); + } + $decrypt_asset->add_chunk($cipher->finish) ; + + return $decrypt_asset; +} + +sub _delete_image { + my $c = shift; + my $img = shift; + unlink $img->path or warn "Could not unlink ".$img->path.": $!"; + $img->disable(); +} + +1; diff --git a/lib/Mounter.pm b/lib/Mounter.pm index f40d2c8..e8c44fa 100644 --- a/lib/Mounter.pm +++ b/lib/Mounter.pm @@ -1,5 +1,7 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: package Mounter; use Mojo::Base 'Mojolicious'; +use Mojo::File; use FindBin qw($Bin); use File::Spec qw(catfile); @@ -9,9 +11,16 @@ sub startup { push @{$self->commands->namespaces}, 'Lutim::Command'; + my $cfile = Mojo::File->new($Bin, '..' , 'lutim.conf'); + if (defined $ENV{MOJO_CONFIG}) { + $cfile = Mojo::File->new($ENV{MOJO_CONFIG}); + unless (-e $cfile->to_abs) { + $cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG}); + } + } my $config = $self->plugin('Config' => { - file => File::Spec->catfile($Bin, '..' ,'lutim.conf'), + file => $cfile, default => { prefix => '/', theme => 'default', @@ -19,6 +28,8 @@ sub startup { } ); + $self->plugin('Lutim::Plugin::Helpers'); + $config->{prefix} = $config->{url_sub_dir} if (defined($config->{url_sub_dir}) && $config->{prefix} eq '/'); $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})); @@ -31,6 +42,10 @@ sub startup { } push @{$self->static->paths}, $self->home->rel_file('themes/default/public'); + $self->hook(after_static => sub { + my $c = shift; + $c->res->headers->cache_control('max-age=2592000, must-revalidate'); + }); $self->plugin('Mount' => {$config->{prefix} => File::Spec->catfile($Bin, '..', 'script', 'application')}); } diff --git a/lutim.conf.template b/lutim.conf.template index 3d4fc47..be72e9b 100644 --- a/lutim.conf.template +++ b/lutim.conf.template @@ -108,12 +108,53 @@ # optional, defaut is / #prefix => '/', + # choose what database you want to use + # valid choices are sqlite and postgresql (all lowercase) + # optional, default is sqlite + #dbtype => 'sqlite', + + # SQLite ONLY - only used if dbtype is set to sqlite # define a path to the SQLite database # you can define it relative to lutim directory or set an absolute path # remember that it has to be in a directory writable by Lutim user # optional, default is lutim.db #db_path => 'lutim.db', + # PostgreSQL ONLY - only used if dbtype is set to postgresql + # these are the credentials to access the PostgreSQL database + # mandatory if you choosed postgresql as dbtype + #pgdb => { + # database => 'lutim', + # host => 'localhost', + # #user => 'DBUSER', + # #pwd => 'DBPASSWORD' + #}, + + # use Minion instead of directly increase counters + # need to launch a minion worker service if enabled + # optional, Minion is disabled by default + #minion => { + # enabled => 0, + # # Which Minion backend to use? + # # valid values are sqlite and postgresql (all lowercase) + # # mandatory if Minion is enabled, default is sqlite + # dbtype => 'sqlite', + # # SQLite ONLY - only used if if you choose sqlite as Minion backend, define the path to the minion database + # # you can define it relative to lutim directory or set an absolute path + # # remember that it has to be in a directory writable by Lutim user + # # optional, default is minion.db + # db_path => 'minion.db', + # # PostgreSQL ONLY - only used if you choose postgresql as Minion backend + # # these are the credentials to access the Minion's PostgreSQL database + # # mandatory if you choosed postgresql as Minion backend, no default + # pgdb => { + # database => 'lutim_minion', + # host => 'localhost', + # #user => 'DBUSER', + # #pwd => 'DBPASSWORD' + # } + #}, + # define the height of the thumbnails generated at users' will # this is not the height of the thumbnails send after upload, # we're talking about thumbnails generated when someone asked for @@ -122,6 +163,14 @@ # optional, default is 100 (pixels) #thumbnail_size => 100, + # maximum number of files that can be downloaded as a single zip archive + # if too many files are asked, it results a timeout, so Lutim split the zip URL + # in multiple URLs, each with max_file_size images. + # timeout behavior depends heavily on your server ressources (CPU) and if images + # are encrypted + # optional, default is 15 + #max_files_in_zip => 15, + ########################## # Lutim cron jobs settings ########################## diff --git a/t/basic.t b/t/basic.t deleted file mode 100644 index 5f257e5..0000000 --- a/t/basic.t +++ /dev/null @@ -1,9 +0,0 @@ -use Mojo::Base -strict; - -use Test::More; -use Test::Mojo; - -my $t = Test::Mojo->new('Lutim'); -$t->get_ok('/')->status_is(200)->content_like(qr/Mojolicious/i); - -done_testing(); diff --git a/t/create-pg-testdb.sql b/t/create-pg-testdb.sql new file mode 100644 index 0000000..323f934 --- /dev/null +++ b/t/create-pg-testdb.sql @@ -0,0 +1,4 @@ +CREATE USER lutim WITH PASSWORD 'lutim'; +CREATE DATABASE lutimtest OWNER lutim; +CREATE DATABASE lutim_miniontest OWNER lutim; + diff --git a/t/postgresql1.conf b/t/postgresql1.conf new file mode 100644 index 0000000..9d7fe63 --- /dev/null +++ b/t/postgresql1.conf @@ -0,0 +1,202 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +{ + #################### + # Hypnotoad settings + #################### + # see http://mojolicio.us/perldoc/Mojo/Server/Hypnotoad for a full list of settings + hypnotoad => { + # array of IP addresses and ports you want to listen to + listen => ['http://127.0.0.1:8080'], + # if you use Lutim behind a reverse proxy like Nginx, you want to set proxy to 1 + # if you use Lutim directly, let it commented + #proxy => 1, + }, + + ################ + # Lutim settings + ################ + + # put a way to contact you here and uncomment it + # mandatory + contact => 'John Doe, admin[at]example.com', + + # random string used to encrypt cookies + # mandatory + secrets => ['fdjsofjoihrei'], + + # choose a theme. See the available themes in `themes` directory + # optional, default is 'default' + #theme => 'default', + + # length of the images random URL + # optional, default is 8 + #length => 8, + + # length of the encryption key + # optional, default is 8 + #crypto_key_length => 8, + + # how many URLs will be provisioned in a batch ? + # optional, default is 5 + #provis_step => 5, + + # max number of URLs to be provisioned + # optional, default is 100 + #provisioning => 100, + + # anti-flood protection delay, in seconds + # users won't be able to ask Lutim to download images more than one per anti_flood_delay seconds + # optional, default is 5 + #anti_flood_delay => 5, + + # twitter account which will appear on twitter cards + # see https://dev.twitter.com/docs/cards/validation/validator to register your Lutim instance on twitter + # optional, default is @framasky + #tweet_card_via => '@framasky', + + # max image size, in octets + # you can write it 10*1024*1024 + # optional, default is 10485760 + max_file_size => 1048576, + + # if you want to have piwik statistics, provide a piwik image tracker + # only the image tracker is allowed, no javascript + # optional, no default + #piwik_img => 'https://piwik.example.org/piwik.php?idsite=1&rec=1', + + # if you want to include something in the right of the screen, put it here + # here's an example to put the logo of your hoster + # optional, no default + #hosted_by => 'My super hoster Hoster logo', + + # DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + # Lutim now checks if the X-Forwarded-Proto header is present and equal to https. + # set to 1 if you use Lutim behind a secure web server + # optional, default is 0 + #https => 0, + + # broadcast_message which will displayed on all pages of Lutim (but no in json response) + # optional, no default + broadcast_message => 'test broadcast message', + + # array of authorized domains for API calls. + # if you want to authorize everyone to use the API: ['*'] + # optional, no domains allowed by default + #allowed_domains => ['http://1.example.com', 'http://2.example.com'], + + # default time limit for files + # valid values are 0, 1, 7, 30 and 365 + # optional, default is 0 (no limit) + default_delay => 30, + + # number of days after which the images will be deleted, even if they were uploaded with "no delay" (or value superior to max_delay) + # a warning message will be displayed on homepage + # optional, default is 0 (no limit) + max_delay => 200, + + # if set to 1, all the images will be encrypted and the encryption option will no be displayed + # optional, default is 0 + #always_encrypt => 0, + + # length of the image's delete token + # optional, default is 24 + #token_length => 24, + + # URL sub-directory in which you want Lutim to be accessible + # example: you want to have Lutim under https://example.org/lutim/ + # => set prefix to '/lutim' or to '/lutim/', it doesn't matter + # optional, defaut is / + #prefix => '/', + + # choose what database you want to use + # valid choices are sqlite and postgresql (all lowercase) + # optional, default is sqlite + dbtype => 'postgresql', + + # SQLite ONLY - only used if dbtype is set to sqlite + # define a path to the SQLite database + # you can define it relative to lutim directory or set an absolute path + # remember that it has to be in a directory writable by Lutim user + # optional, default is lutim.db + #db_path => 'lutim.db', + + # PostgreSQL ONLY - only used if dbtype is set to postgresql + # these are the credentials to access the PostgreSQL database + # mandatory if you choosed postgresql as dbtype + pgdb => { + database => 'lutimtest', + host => 'localhost', + user => 'lutim', + pwd => 'lutim' + }, + + # use Minion instead of directly increase counters + # need to launch a minion worker service if enabled + # optional, Minion is disabled by default + #minion => { + # enabled => 0, + # # Which Minion backend to use? + # # valid values are sqlite and postgresql (all lowercase) + # # mandatory if Minion is enabled, default is sqlite + # dbtype => 'sqlite', + # # SQLite ONLY - only used if if you choose sqlite as Minion backend, define the path to the minion database + # # you can define it relative to lutim directory or set an absolute path + # # remember that it has to be in a directory writable by Lutim user + # # optional, default is minion.db + # db_path => 'minion.db', + # # PostgreSQL ONLY - only used if you choose postgresql as Minion backend + # # these are the credentials to access the Minion's PostgreSQL database + # # mandatory if you choosed postgresql as Minion backend, no default + # pgdb => { + # database => 'lutim_minion', + # host => 'localhost', + # #user => 'DBUSER', + # #pwd => 'DBPASSWORD' + # } + #}, + + # define the height of the thumbnails generated at users' will + # this is not the height of the thumbnails send after upload, + # we're talking about thumbnails generated when someone asked for + # https://example.org/lutim/tesrinp?thumb + # this works only if you have ImageMagick + # optional, default is 100 (pixels) + #thumbnail_size => 100, + + # maximum number of files that can be downloaded as a single zip archive + # if too many files are asked, it results a timeout, so Lutim split the zip URL + # in multiple URLs, each with max_file_size images. + # timeout behavior depends heavily on your server ressources (CPU) and if images + # are encrypted + # optional, default is 15 + #max_files_in_zip => 15, + + ########################## + # Lutim cron jobs settings + ########################## + + # number of days shown in /stats page (used with script/lutim cron stats) + # optional, default is 365 + #stats_day_num => 365, + + # number of days senders' IP addresses are kept in database + # after that delay, they will be deleted from database (used with script/lutim cron cleanbdd) + # optional, default is 365 + #keep_ip_during => 365, + + # max size of the files directory, in octets + # used by script/lutim cron watch to trigger an action + # optional, no default + max_total_size => 10*1024*1024*1024, + + # default action when files directory is over max_total_size (used with script/lutim cron watch) + # valid values are 'warn', 'stop-upload' and 'delete' + # please, see readme + # optional, default is 'warn' + #policy_when_full => 'warn', + + # images which are not viewed since delete_no_longer_viewed_files days will be deleted by the cron cleanfiles task + # if delete_no_longer_viewed_files is not set, the no longer viewed files will NOT be deleted + # optional, no default + #delete_no_longer_viewed_files => 90 +}; diff --git a/t/postgresql2.conf b/t/postgresql2.conf new file mode 100644 index 0000000..452e6ca --- /dev/null +++ b/t/postgresql2.conf @@ -0,0 +1,202 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +{ + #################### + # Hypnotoad settings + #################### + # see http://mojolicio.us/perldoc/Mojo/Server/Hypnotoad for a full list of settings + hypnotoad => { + # array of IP addresses and ports you want to listen to + listen => ['http://127.0.0.1:8080'], + # if you use Lutim behind a reverse proxy like Nginx, you want to set proxy to 1 + # if you use Lutim directly, let it commented + #proxy => 1, + }, + + ################ + # Lutim settings + ################ + + # put a way to contact you here and uncomment it + # mandatory + contact => 'John Doe, admin[at]example.com', + + # random string used to encrypt cookies + # mandatory + secrets => ['fdjsofjoihrei'], + + # choose a theme. See the available themes in `themes` directory + # optional, default is 'default' + #theme => 'default', + + # length of the images random URL + # optional, default is 8 + #length => 8, + + # length of the encryption key + # optional, default is 8 + #crypto_key_length => 8, + + # how many URLs will be provisioned in a batch ? + # optional, default is 5 + #provis_step => 5, + + # max number of URLs to be provisioned + # optional, default is 100 + #provisioning => 100, + + # anti-flood protection delay, in seconds + # users won't be able to ask Lutim to download images more than one per anti_flood_delay seconds + # optional, default is 5 + #anti_flood_delay => 5, + + # twitter account which will appear on twitter cards + # see https://dev.twitter.com/docs/cards/validation/validator to register your Lutim instance on twitter + # optional, default is @framasky + #tweet_card_via => '@framasky', + + # max image size, in octets + # you can write it 10*1024*1024 + # optional, default is 10485760 + max_file_size => 1048576, + + # if you want to have piwik statistics, provide a piwik image tracker + # only the image tracker is allowed, no javascript + # optional, no default + #piwik_img => 'https://piwik.example.org/piwik.php?idsite=1&rec=1', + + # if you want to include something in the right of the screen, put it here + # here's an example to put the logo of your hoster + # optional, no default + #hosted_by => 'My super hoster Hoster logo', + + # DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + # Lutim now checks if the X-Forwarded-Proto header is present and equal to https. + # set to 1 if you use Lutim behind a secure web server + # optional, default is 0 + #https => 0, + + # broadcast_message which will displayed on all pages of Lutim (but no in json response) + # optional, no default + broadcast_message => 'test broadcast message', + + # array of authorized domains for API calls. + # if you want to authorize everyone to use the API: ['*'] + # optional, no domains allowed by default + #allowed_domains => ['http://1.example.com', 'http://2.example.com'], + + # default time limit for files + # valid values are 0, 1, 7, 30 and 365 + # optional, default is 0 (no limit) + default_delay => 30, + + # number of days after which the images will be deleted, even if they were uploaded with "no delay" (or value superior to max_delay) + # a warning message will be displayed on homepage + # optional, default is 0 (no limit) + max_delay => 200, + + # if set to 1, all the images will be encrypted and the encryption option will no be displayed + # optional, default is 0 + #always_encrypt => 0, + + # length of the image's delete token + # optional, default is 24 + #token_length => 24, + + # URL sub-directory in which you want Lutim to be accessible + # example: you want to have Lutim under https://example.org/lutim/ + # => set prefix to '/lutim' or to '/lutim/', it doesn't matter + # optional, defaut is / + #prefix => '/', + + # choose what database you want to use + # valid choices are sqlite and postgresql (all lowercase) + # optional, default is sqlite + dbtype => 'postgresql', + + # SQLite ONLY - only used if dbtype is set to sqlite + # define a path to the SQLite database + # you can define it relative to lutim directory or set an absolute path + # remember that it has to be in a directory writable by Lutim user + # optional, default is lutim.db + db_path => 'testpg2.db', + + # PostgreSQL ONLY - only used if dbtype is set to postgresql + # these are the credentials to access the PostgreSQL database + # mandatory if you choosed postgresql as dbtype + pgdb => { + database => 'lutimtest', + host => 'localhost', + user => 'lutim', + pwd => 'lutim' + }, + + # use Minion instead of directly increase counters + # need to launch a minion worker service if enabled + # optional, Minion is disabled by default + minion => { + enabled => 1, + # # Which Minion backend to use? + # # valid values are sqlite and postgresql (all lowercase) + # # mandatory if Minion is enabled, default is sqlite + # dbtype => 'sqlite', + # # SQLite ONLY - only used if if you choose sqlite as Minion backend, define the path to the minion database + # # you can define it relative to lutim directory or set an absolute path + # # remember that it has to be in a directory writable by Lutim user + # # optional, default is minion.db + # db_path => 'minion.db', + # # PostgreSQL ONLY - only used if you choose postgresql as Minion backend + # # these are the credentials to access the Minion's PostgreSQL database + # # mandatory if you choosed postgresql as Minion backend, no default + # pgdb => { + # database => 'lutim_minion', + # host => 'localhost', + # #user => 'DBUSER', + # #pwd => 'DBPASSWORD' + # } + }, + + # define the height of the thumbnails generated at users' will + # this is not the height of the thumbnails send after upload, + # we're talking about thumbnails generated when someone asked for + # https://example.org/lutim/tesrinp?thumb + # this works only if you have ImageMagick + # optional, default is 100 (pixels) + #thumbnail_size => 100, + + # maximum number of files that can be downloaded as a single zip archive + # if too many files are asked, it results a timeout, so Lutim split the zip URL + # in multiple URLs, each with max_file_size images. + # timeout behavior depends heavily on your server ressources (CPU) and if images + # are encrypted + # optional, default is 15 + #max_files_in_zip => 15, + + ########################## + # Lutim cron jobs settings + ########################## + + # number of days shown in /stats page (used with script/lutim cron stats) + # optional, default is 365 + #stats_day_num => 365, + + # number of days senders' IP addresses are kept in database + # after that delay, they will be deleted from database (used with script/lutim cron cleanbdd) + # optional, default is 365 + #keep_ip_during => 365, + + # max size of the files directory, in octets + # used by script/lutim cron watch to trigger an action + # optional, no default + max_total_size => 10*1024*1024*1024, + + # default action when files directory is over max_total_size (used with script/lutim cron watch) + # valid values are 'warn', 'stop-upload' and 'delete' + # please, see readme + # optional, default is 'warn' + #policy_when_full => 'warn', + + # images which are not viewed since delete_no_longer_viewed_files days will be deleted by the cron cleanfiles task + # if delete_no_longer_viewed_files is not set, the no longer viewed files will NOT be deleted + # optional, no default + #delete_no_longer_viewed_files => 90 +}; diff --git a/t/postgresql3.conf b/t/postgresql3.conf new file mode 100644 index 0000000..a8a5810 --- /dev/null +++ b/t/postgresql3.conf @@ -0,0 +1,202 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +{ + #################### + # Hypnotoad settings + #################### + # see http://mojolicio.us/perldoc/Mojo/Server/Hypnotoad for a full list of settings + hypnotoad => { + # array of IP addresses and ports you want to listen to + listen => ['http://127.0.0.1:8080'], + # if you use Lutim behind a reverse proxy like Nginx, you want to set proxy to 1 + # if you use Lutim directly, let it commented + #proxy => 1, + }, + + ################ + # Lutim settings + ################ + + # put a way to contact you here and uncomment it + # mandatory + contact => 'John Doe, admin[at]example.com', + + # random string used to encrypt cookies + # mandatory + secrets => ['fdjsofjoihrei'], + + # choose a theme. See the available themes in `themes` directory + # optional, default is 'default' + #theme => 'default', + + # length of the images random URL + # optional, default is 8 + #length => 8, + + # length of the encryption key + # optional, default is 8 + #crypto_key_length => 8, + + # how many URLs will be provisioned in a batch ? + # optional, default is 5 + #provis_step => 5, + + # max number of URLs to be provisioned + # optional, default is 100 + #provisioning => 100, + + # anti-flood protection delay, in seconds + # users won't be able to ask Lutim to download images more than one per anti_flood_delay seconds + # optional, default is 5 + #anti_flood_delay => 5, + + # twitter account which will appear on twitter cards + # see https://dev.twitter.com/docs/cards/validation/validator to register your Lutim instance on twitter + # optional, default is @framasky + #tweet_card_via => '@framasky', + + # max image size, in octets + # you can write it 10*1024*1024 + # optional, default is 10485760 + max_file_size => 1048576, + + # if you want to have piwik statistics, provide a piwik image tracker + # only the image tracker is allowed, no javascript + # optional, no default + #piwik_img => 'https://piwik.example.org/piwik.php?idsite=1&rec=1', + + # if you want to include something in the right of the screen, put it here + # here's an example to put the logo of your hoster + # optional, no default + #hosted_by => 'My super hoster Hoster logo', + + # DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + # Lutim now checks if the X-Forwarded-Proto header is present and equal to https. + # set to 1 if you use Lutim behind a secure web server + # optional, default is 0 + #https => 0, + + # broadcast_message which will displayed on all pages of Lutim (but no in json response) + # optional, no default + broadcast_message => 'test broadcast message', + + # array of authorized domains for API calls. + # if you want to authorize everyone to use the API: ['*'] + # optional, no domains allowed by default + #allowed_domains => ['http://1.example.com', 'http://2.example.com'], + + # default time limit for files + # valid values are 0, 1, 7, 30 and 365 + # optional, default is 0 (no limit) + default_delay => 30, + + # number of days after which the images will be deleted, even if they were uploaded with "no delay" (or value superior to max_delay) + # a warning message will be displayed on homepage + # optional, default is 0 (no limit) + max_delay => 200, + + # if set to 1, all the images will be encrypted and the encryption option will no be displayed + # optional, default is 0 + #always_encrypt => 0, + + # length of the image's delete token + # optional, default is 24 + #token_length => 24, + + # URL sub-directory in which you want Lutim to be accessible + # example: you want to have Lutim under https://example.org/lutim/ + # => set prefix to '/lutim' or to '/lutim/', it doesn't matter + # optional, defaut is / + #prefix => '/', + + # choose what database you want to use + # valid choices are sqlite and postgresql (all lowercase) + # optional, default is sqlite + dbtype => 'postgresql', + + # SQLite ONLY - only used if dbtype is set to sqlite + # define a path to the SQLite database + # you can define it relative to lutim directory or set an absolute path + # remember that it has to be in a directory writable by Lutim user + # optional, default is lutim.db + db_path => 'testpg3.db', + + # PostgreSQL ONLY - only used if dbtype is set to postgresql + # these are the credentials to access the PostgreSQL database + # mandatory if you choosed postgresql as dbtype + pgdb => { + database => 'lutimtest', + host => 'localhost', + user => 'lutim', + pwd => 'lutim' + }, + + # use Minion instead of directly increase counters + # need to launch a minion worker service if enabled + # optional, Minion is disabled by default + minion => { + enabled => 1, + # Which Minion backend to use? + # valid values are sqlite and postgresql (all lowercase) + # mandatory if Minion is enabled, default is sqlite + dbtype => 'postgresql', + # SQLite ONLY - only used if if you choose sqlite as Minion backend, define the path to the minion database + # you can define it relative to lutim directory or set an absolute path + # remember that it has to be in a directory writable by Lutim user + # optional, default is minion.db + db_path => 'minion.db', + # PostgreSQL ONLY - only used if you choose postgresql as Minion backend + # these are the credentials to access the Minion's PostgreSQL database + # mandatory if you choosed postgresql as Minion backend, no default + pgdb => { + database => 'lutim_miniontest', + host => 'localhost', + user => 'lutim', + pwd => 'lutim' + } + }, + + # define the height of the thumbnails generated at users' will + # this is not the height of the thumbnails send after upload, + # we're talking about thumbnails generated when someone asked for + # https://example.org/lutim/tesrinp?thumb + # this works only if you have ImageMagick + # optional, default is 100 (pixels) + #thumbnail_size => 100, + + # maximum number of files that can be downloaded as a single zip archive + # if too many files are asked, it results a timeout, so Lutim split the zip URL + # in multiple URLs, each with max_file_size images. + # timeout behavior depends heavily on your server ressources (CPU) and if images + # are encrypted + # optional, default is 15 + #max_files_in_zip => 15, + + ########################## + # Lutim cron jobs settings + ########################## + + # number of days shown in /stats page (used with script/lutim cron stats) + # optional, default is 365 + #stats_day_num => 365, + + # number of days senders' IP addresses are kept in database + # after that delay, they will be deleted from database (used with script/lutim cron cleanbdd) + # optional, default is 365 + #keep_ip_during => 365, + + # max size of the files directory, in octets + # used by script/lutim cron watch to trigger an action + # optional, no default + max_total_size => 10*1024*1024*1024, + + # default action when files directory is over max_total_size (used with script/lutim cron watch) + # valid values are 'warn', 'stop-upload' and 'delete' + # please, see readme + # optional, default is 'warn' + #policy_when_full => 'warn', + + # images which are not viewed since delete_no_longer_viewed_files days will be deleted by the cron cleanfiles task + # if delete_no_longer_viewed_files is not set, the no longer viewed files will NOT be deleted + # optional, no default + #delete_no_longer_viewed_files => 90 +}; diff --git a/t/sqlite1.conf b/t/sqlite1.conf new file mode 100644 index 0000000..c4cae54 --- /dev/null +++ b/t/sqlite1.conf @@ -0,0 +1,202 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +{ + #################### + # Hypnotoad settings + #################### + # see http://mojolicio.us/perldoc/Mojo/Server/Hypnotoad for a full list of settings + hypnotoad => { + # array of IP addresses and ports you want to listen to + listen => ['http://127.0.0.1:8080'], + # if you use Lutim behind a reverse proxy like Nginx, you want to set proxy to 1 + # if you use Lutim directly, let it commented + #proxy => 1, + }, + + ################ + # Lutim settings + ################ + + # put a way to contact you here and uncomment it + # mandatory + contact => 'John Doe, admin[at]example.com', + + # random string used to encrypt cookies + # mandatory + secrets => ['fdjsofjoihrei'], + + # choose a theme. See the available themes in `themes` directory + # optional, default is 'default' + #theme => 'default', + + # length of the images random URL + # optional, default is 8 + #length => 8, + + # length of the encryption key + # optional, default is 8 + #crypto_key_length => 8, + + # how many URLs will be provisioned in a batch ? + # optional, default is 5 + #provis_step => 5, + + # max number of URLs to be provisioned + # optional, default is 100 + #provisioning => 100, + + # anti-flood protection delay, in seconds + # users won't be able to ask Lutim to download images more than one per anti_flood_delay seconds + # optional, default is 5 + #anti_flood_delay => 5, + + # twitter account which will appear on twitter cards + # see https://dev.twitter.com/docs/cards/validation/validator to register your Lutim instance on twitter + # optional, default is @framasky + #tweet_card_via => '@framasky', + + # max image size, in octets + # you can write it 10*1024*1024 + # optional, default is 10485760 + max_file_size => 1048576, + + # if you want to have piwik statistics, provide a piwik image tracker + # only the image tracker is allowed, no javascript + # optional, no default + #piwik_img => 'https://piwik.example.org/piwik.php?idsite=1&rec=1', + + # if you want to include something in the right of the screen, put it here + # here's an example to put the logo of your hoster + # optional, no default + #hosted_by => 'My super hoster Hoster logo', + + # DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + # Lutim now checks if the X-Forwarded-Proto header is present and equal to https. + # set to 1 if you use Lutim behind a secure web server + # optional, default is 0 + #https => 0, + + # broadcast_message which will displayed on all pages of Lutim (but no in json response) + # optional, no default + broadcast_message => 'test broadcast message', + + # array of authorized domains for API calls. + # if you want to authorize everyone to use the API: ['*'] + # optional, no domains allowed by default + #allowed_domains => ['http://1.example.com', 'http://2.example.com'], + + # default time limit for files + # valid values are 0, 1, 7, 30 and 365 + # optional, default is 0 (no limit) + default_delay => 30, + + # number of days after which the images will be deleted, even if they were uploaded with "no delay" (or value superior to max_delay) + # a warning message will be displayed on homepage + # optional, default is 0 (no limit) + max_delay => 200, + + # if set to 1, all the images will be encrypted and the encryption option will no be displayed + # optional, default is 0 + #always_encrypt => 0, + + # length of the image's delete token + # optional, default is 24 + #token_length => 24, + + # URL sub-directory in which you want Lutim to be accessible + # example: you want to have Lutim under https://example.org/lutim/ + # => set prefix to '/lutim' or to '/lutim/', it doesn't matter + # optional, defaut is / + #prefix => '/', + + # choose what database you want to use + # valid choices are sqlite and postgresql (all lowercase) + # optional, default is sqlite + dbtype => 'sqlite', + + # SQLite ONLY - only used if dbtype is set to sqlite + # define a path to the SQLite database + # you can define it relative to lutim directory or set an absolute path + # remember that it has to be in a directory writable by Lutim user + # optional, default is lutim.db + db_path => 'testdqlite1.db', + + # PostgreSQL ONLY - only used if dbtype is set to postgresql + # these are the credentials to access the PostgreSQL database + # mandatory if you choosed postgresql as dbtype + #pgdb => { + # database => 'lutim', + # host => 'localhost', + # #user => 'DBUSER', + # #pwd => 'DBPASSWORD' + #}, + + # use Minion instead of directly increase counters + # need to launch a minion worker service if enabled + # optional, Minion is disabled by default + #minion => { + # enabled => 0, + # # Which Minion backend to use? + # # valid values are sqlite and postgresql (all lowercase) + # # mandatory if Minion is enabled, default is sqlite + # dbtype => 'sqlite', + # # SQLite ONLY - only used if if you choose sqlite as Minion backend, define the path to the minion database + # # you can define it relative to lutim directory or set an absolute path + # # remember that it has to be in a directory writable by Lutim user + # # optional, default is minion.db + # db_path => 'minion.db', + # # PostgreSQL ONLY - only used if you choose postgresql as Minion backend + # # these are the credentials to access the Minion's PostgreSQL database + # # mandatory if you choosed postgresql as Minion backend, no default + # pgdb => { + # database => 'lutim_minion', + # host => 'localhost', + # #user => 'DBUSER', + # #pwd => 'DBPASSWORD' + # } + #}, + + # define the height of the thumbnails generated at users' will + # this is not the height of the thumbnails send after upload, + # we're talking about thumbnails generated when someone asked for + # https://example.org/lutim/tesrinp?thumb + # this works only if you have ImageMagick + # optional, default is 100 (pixels) + #thumbnail_size => 100, + + # maximum number of files that can be downloaded as a single zip archive + # if too many files are asked, it results a timeout, so Lutim split the zip URL + # in multiple URLs, each with max_file_size images. + # timeout behavior depends heavily on your server ressources (CPU) and if images + # are encrypted + # optional, default is 15 + #max_files_in_zip => 15, + + ########################## + # Lutim cron jobs settings + ########################## + + # number of days shown in /stats page (used with script/lutim cron stats) + # optional, default is 365 + #stats_day_num => 365, + + # number of days senders' IP addresses are kept in database + # after that delay, they will be deleted from database (used with script/lutim cron cleanbdd) + # optional, default is 365 + #keep_ip_during => 365, + + # max size of the files directory, in octets + # used by script/lutim cron watch to trigger an action + # optional, no default + max_total_size => 10*1024*1024*1024, + + # default action when files directory is over max_total_size (used with script/lutim cron watch) + # valid values are 'warn', 'stop-upload' and 'delete' + # please, see readme + # optional, default is 'warn' + #policy_when_full => 'warn', + + # images which are not viewed since delete_no_longer_viewed_files days will be deleted by the cron cleanfiles task + # if delete_no_longer_viewed_files is not set, the no longer viewed files will NOT be deleted + # optional, no default + #delete_no_longer_viewed_files => 90 +}; diff --git a/t/sqlite2.conf b/t/sqlite2.conf new file mode 100644 index 0000000..e4c6a12 --- /dev/null +++ b/t/sqlite2.conf @@ -0,0 +1,202 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +{ + #################### + # Hypnotoad settings + #################### + # see http://mojolicio.us/perldoc/Mojo/Server/Hypnotoad for a full list of settings + hypnotoad => { + # array of IP addresses and ports you want to listen to + listen => ['http://127.0.0.1:8080'], + # if you use Lutim behind a reverse proxy like Nginx, you want to set proxy to 1 + # if you use Lutim directly, let it commented + #proxy => 1, + }, + + ################ + # Lutim settings + ################ + + # put a way to contact you here and uncomment it + # mandatory + contact => 'John Doe, admin[at]example.com', + + # random string used to encrypt cookies + # mandatory + secrets => ['fdjsofjoihrei'], + + # choose a theme. See the available themes in `themes` directory + # optional, default is 'default' + #theme => 'default', + + # length of the images random URL + # optional, default is 8 + #length => 8, + + # length of the encryption key + # optional, default is 8 + #crypto_key_length => 8, + + # how many URLs will be provisioned in a batch ? + # optional, default is 5 + #provis_step => 5, + + # max number of URLs to be provisioned + # optional, default is 100 + #provisioning => 100, + + # anti-flood protection delay, in seconds + # users won't be able to ask Lutim to download images more than one per anti_flood_delay seconds + # optional, default is 5 + #anti_flood_delay => 5, + + # twitter account which will appear on twitter cards + # see https://dev.twitter.com/docs/cards/validation/validator to register your Lutim instance on twitter + # optional, default is @framasky + #tweet_card_via => '@framasky', + + # max image size, in octets + # you can write it 10*1024*1024 + # optional, default is 10485760 + max_file_size => 1048576, + + # if you want to have piwik statistics, provide a piwik image tracker + # only the image tracker is allowed, no javascript + # optional, no default + #piwik_img => 'https://piwik.example.org/piwik.php?idsite=1&rec=1', + + # if you want to include something in the right of the screen, put it here + # here's an example to put the logo of your hoster + # optional, no default + #hosted_by => 'My super hoster Hoster logo', + + # DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + # Lutim now checks if the X-Forwarded-Proto header is present and equal to https. + # set to 1 if you use Lutim behind a secure web server + # optional, default is 0 + #https => 0, + + # broadcast_message which will displayed on all pages of Lutim (but no in json response) + # optional, no default + broadcast_message => 'test broadcast message', + + # array of authorized domains for API calls. + # if you want to authorize everyone to use the API: ['*'] + # optional, no domains allowed by default + #allowed_domains => ['http://1.example.com', 'http://2.example.com'], + + # default time limit for files + # valid values are 0, 1, 7, 30 and 365 + # optional, default is 0 (no limit) + default_delay => 30, + + # number of days after which the images will be deleted, even if they were uploaded with "no delay" (or value superior to max_delay) + # a warning message will be displayed on homepage + # optional, default is 0 (no limit) + max_delay => 200, + + # if set to 1, all the images will be encrypted and the encryption option will no be displayed + # optional, default is 0 + #always_encrypt => 0, + + # length of the image's delete token + # optional, default is 24 + #token_length => 24, + + # URL sub-directory in which you want Lutim to be accessible + # example: you want to have Lutim under https://example.org/lutim/ + # => set prefix to '/lutim' or to '/lutim/', it doesn't matter + # optional, defaut is / + #prefix => '/', + + # choose what database you want to use + # valid choices are sqlite and postgresql (all lowercase) + # optional, default is sqlite + dbtype => 'sqlite', + + # SQLite ONLY - only used if dbtype is set to sqlite + # define a path to the SQLite database + # you can define it relative to lutim directory or set an absolute path + # remember that it has to be in a directory writable by Lutim user + # optional, default is lutim.db + db_path => 'testsqlite2.db', + + # PostgreSQL ONLY - only used if dbtype is set to postgresql + # these are the credentials to access the PostgreSQL database + # mandatory if you choosed postgresql as dbtype + #pgdb => { + # database => 'lutim', + # host => 'localhost', + # #user => 'DBUSER', + # #pwd => 'DBPASSWORD' + #}, + + # use Minion instead of directly increase counters + # need to launch a minion worker service if enabled + # optional, Minion is disabled by default + minion => { + enabled => 1, + # # Which Minion backend to use? + # # valid values are sqlite and postgresql (all lowercase) + # # mandatory if Minion is enabled, default is sqlite + # dbtype => 'sqlite', + # # SQLite ONLY - only used if if you choose sqlite as Minion backend, define the path to the minion database + # # you can define it relative to lutim directory or set an absolute path + # # remember that it has to be in a directory writable by Lutim user + # # optional, default is minion.db + # db_path => 'minion.db', + # # PostgreSQL ONLY - only used if you choose postgresql as Minion backend + # # these are the credentials to access the Minion's PostgreSQL database + # # mandatory if you choosed postgresql as Minion backend, no default + # pgdb => { + # database => 'lutim_minion', + # host => 'localhost', + # #user => 'DBUSER', + # #pwd => 'DBPASSWORD' + # } + }, + + # define the height of the thumbnails generated at users' will + # this is not the height of the thumbnails send after upload, + # we're talking about thumbnails generated when someone asked for + # https://example.org/lutim/tesrinp?thumb + # this works only if you have ImageMagick + # optional, default is 100 (pixels) + #thumbnail_size => 100, + + # maximum number of files that can be downloaded as a single zip archive + # if too many files are asked, it results a timeout, so Lutim split the zip URL + # in multiple URLs, each with max_file_size images. + # timeout behavior depends heavily on your server ressources (CPU) and if images + # are encrypted + # optional, default is 15 + #max_files_in_zip => 15, + + ########################## + # Lutim cron jobs settings + ########################## + + # number of days shown in /stats page (used with script/lutim cron stats) + # optional, default is 365 + #stats_day_num => 365, + + # number of days senders' IP addresses are kept in database + # after that delay, they will be deleted from database (used with script/lutim cron cleanbdd) + # optional, default is 365 + #keep_ip_during => 365, + + # max size of the files directory, in octets + # used by script/lutim cron watch to trigger an action + # optional, no default + max_total_size => 10*1024*1024*1024, + + # default action when files directory is over max_total_size (used with script/lutim cron watch) + # valid values are 'warn', 'stop-upload' and 'delete' + # please, see readme + # optional, default is 'warn' + #policy_when_full => 'warn', + + # images which are not viewed since delete_no_longer_viewed_files days will be deleted by the cron cleanfiles task + # if delete_no_longer_viewed_files is not set, the no longer viewed files will NOT be deleted + # optional, no default + #delete_no_longer_viewed_files => 90 +}; diff --git a/t/sqlite3.conf b/t/sqlite3.conf new file mode 100644 index 0000000..dea2e0b --- /dev/null +++ b/t/sqlite3.conf @@ -0,0 +1,202 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +{ + #################### + # Hypnotoad settings + #################### + # see http://mojolicio.us/perldoc/Mojo/Server/Hypnotoad for a full list of settings + hypnotoad => { + # array of IP addresses and ports you want to listen to + listen => ['http://127.0.0.1:8080'], + # if you use Lutim behind a reverse proxy like Nginx, you want to set proxy to 1 + # if you use Lutim directly, let it commented + #proxy => 1, + }, + + ################ + # Lutim settings + ################ + + # put a way to contact you here and uncomment it + # mandatory + contact => 'John Doe, admin[at]example.com', + + # random string used to encrypt cookies + # mandatory + secrets => ['fdjsofjoihrei'], + + # choose a theme. See the available themes in `themes` directory + # optional, default is 'default' + #theme => 'default', + + # length of the images random URL + # optional, default is 8 + #length => 8, + + # length of the encryption key + # optional, default is 8 + #crypto_key_length => 8, + + # how many URLs will be provisioned in a batch ? + # optional, default is 5 + #provis_step => 5, + + # max number of URLs to be provisioned + # optional, default is 100 + #provisioning => 100, + + # anti-flood protection delay, in seconds + # users won't be able to ask Lutim to download images more than one per anti_flood_delay seconds + # optional, default is 5 + #anti_flood_delay => 5, + + # twitter account which will appear on twitter cards + # see https://dev.twitter.com/docs/cards/validation/validator to register your Lutim instance on twitter + # optional, default is @framasky + #tweet_card_via => '@framasky', + + # max image size, in octets + # you can write it 10*1024*1024 + # optional, default is 10485760 + max_file_size => 1048576, + + # if you want to have piwik statistics, provide a piwik image tracker + # only the image tracker is allowed, no javascript + # optional, no default + #piwik_img => 'https://piwik.example.org/piwik.php?idsite=1&rec=1', + + # if you want to include something in the right of the screen, put it here + # here's an example to put the logo of your hoster + # optional, no default + #hosted_by => 'My super hoster Hoster logo', + + # DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + # Lutim now checks if the X-Forwarded-Proto header is present and equal to https. + # set to 1 if you use Lutim behind a secure web server + # optional, default is 0 + #https => 0, + + # broadcast_message which will displayed on all pages of Lutim (but no in json response) + # optional, no default + broadcast_message => 'test broadcast message', + + # array of authorized domains for API calls. + # if you want to authorize everyone to use the API: ['*'] + # optional, no domains allowed by default + #allowed_domains => ['http://1.example.com', 'http://2.example.com'], + + # default time limit for files + # valid values are 0, 1, 7, 30 and 365 + # optional, default is 0 (no limit) + default_delay => 30, + + # number of days after which the images will be deleted, even if they were uploaded with "no delay" (or value superior to max_delay) + # a warning message will be displayed on homepage + # optional, default is 0 (no limit) + max_delay => 200, + + # if set to 1, all the images will be encrypted and the encryption option will no be displayed + # optional, default is 0 + #always_encrypt => 0, + + # length of the image's delete token + # optional, default is 24 + #token_length => 24, + + # URL sub-directory in which you want Lutim to be accessible + # example: you want to have Lutim under https://example.org/lutim/ + # => set prefix to '/lutim' or to '/lutim/', it doesn't matter + # optional, defaut is / + #prefix => '/', + + # choose what database you want to use + # valid choices are sqlite and postgresql (all lowercase) + # optional, default is sqlite + dbtype => 'sqlite', + + # SQLite ONLY - only used if dbtype is set to sqlite + # define a path to the SQLite database + # you can define it relative to lutim directory or set an absolute path + # remember that it has to be in a directory writable by Lutim user + # optional, default is lutim.db + db_path => 'testsqlite3.db', + + # PostgreSQL ONLY - only used if dbtype is set to postgresql + # these are the credentials to access the PostgreSQL database + # mandatory if you choosed postgresql as dbtype + #pgdb => { + # database => 'lutim', + # host => 'localhost', + # #user => 'DBUSER', + # #pwd => 'DBPASSWORD' + #}, + + # use Minion instead of directly increase counters + # need to launch a minion worker service if enabled + # optional, Minion is disabled by default + minion => { + enabled => 1, + # Which Minion backend to use? + # valid values are sqlite and postgresql (all lowercase) + # mandatory if Minion is enabled, default is sqlite + dbtype => 'postgresql', + # SQLite ONLY - only used if if you choose sqlite as Minion backend, define the path to the minion database + # you can define it relative to lutim directory or set an absolute path + # remember that it has to be in a directory writable by Lutim user + # optional, default is minion.db + db_path => 'minion.db', + # PostgreSQL ONLY - only used if you choose postgresql as Minion backend + # these are the credentials to access the Minion's PostgreSQL database + # mandatory if you choosed postgresql as Minion backend, no default + pgdb => { + database => 'lutim_miniontest', + host => 'localhost', + user => 'lutim', + pwd => 'lutim' + } + }, + + # define the height of the thumbnails generated at users' will + # this is not the height of the thumbnails send after upload, + # we're talking about thumbnails generated when someone asked for + # https://example.org/lutim/tesrinp?thumb + # this works only if you have ImageMagick + # optional, default is 100 (pixels) + #thumbnail_size => 100, + + # maximum number of files that can be downloaded as a single zip archive + # if too many files are asked, it results a timeout, so Lutim split the zip URL + # in multiple URLs, each with max_file_size images. + # timeout behavior depends heavily on your server ressources (CPU) and if images + # are encrypted + # optional, default is 15 + #max_files_in_zip => 15, + + ########################## + # Lutim cron jobs settings + ########################## + + # number of days shown in /stats page (used with script/lutim cron stats) + # optional, default is 365 + #stats_day_num => 365, + + # number of days senders' IP addresses are kept in database + # after that delay, they will be deleted from database (used with script/lutim cron cleanbdd) + # optional, default is 365 + #keep_ip_during => 365, + + # max size of the files directory, in octets + # used by script/lutim cron watch to trigger an action + # optional, no default + max_total_size => 10*1024*1024*1024, + + # default action when files directory is over max_total_size (used with script/lutim cron watch) + # valid values are 'warn', 'stop-upload' and 'delete' + # please, see readme + # optional, default is 'warn' + #policy_when_full => 'warn', + + # images which are not viewed since delete_no_longer_viewed_files days will be deleted by the cron cleanfiles task + # if delete_no_longer_viewed_files is not set, the no longer viewed files will NOT be deleted + # optional, no default + #delete_no_longer_viewed_files => 90 +}; diff --git a/t/test.t b/t/test.t new file mode 100644 index 0000000..83aee73 --- /dev/null +++ b/t/test.t @@ -0,0 +1,108 @@ +# vim:set sw=4 ts=4 sts=4 ft=perl expandtab: +use Mojo::Base -strict; +use Mojo::File; +use Mojo::JSON qw(true false); +use Mojolicious; + +use Test::More; +use Test::Mojo; + +use FindBin qw($Bin); +use Digest::file qw(digest_file_hex); + +my ($m, $cfile); + +BEGIN { + use lib 'lib'; + $m = Mojolicious->new; + $cfile = Mojo::File->new($Bin, '..' , 'lutim.conf'); + if (defined $ENV{MOJO_CONFIG}) { + $cfile = Mojo::File->new($ENV{MOJO_CONFIG}); + unless (-e $cfile->to_abs) { + $cfile = Mojo::File->new($Bin, '..', $ENV{MOJO_CONFIG}); + } + } + my $config = $m->plugin('Config' => + { + file => $cfile->to_abs->to_string, + default => { + dbtype => 'sqlite' + } + } + ); + $m->plugin('Lutim::Plugin::Helpers'); + $m->plugin('DebugDumperHelper'); +} + +# Home page +my $t = Test::Mojo->new('Lutim'); +$t->get_ok('/') + ->status_is(200) + ->content_like(qr/Let's Upload That IMage/i); + +# Instance settings informations +$t->get_ok('/infos') + ->status_is(200) + ->json_has('image_magick') + ->json_is( + '/always_encrypt' => false, + '/broadcast_message' => 'test broadcast message', + '/contact' => 'John Doe, admin[at]example.com', + '/default_delay' => 30, + '/max_delay' => 200, + '/max_file_size' => 1048576 + ); + +# Post image +my $image = Mojo::File->new($Bin, '..', 'themes', 'default', 'public', 'img', 'Lutim.png')->to_string; +$t->post_ok('/' => form => { file => { file => $image }, format => 'json' }) + ->status_is(200) + ->json_has('msg', 'success') + ->json_is('/success' => true, '/msg/filename' => 'Lutim.png') + ->json_like('/msg/short' => qr#[-_a-zA-Z0-9]{8}#, '/msg/real_short' => qr#[-_a-zA-Z0-9]{8}#, '/msg/token' => qr#[-_a-zA-Z0-9]{24}#); + +# Post delete-at-first-view image +my $raw = $t->ua->post('/' => form => { file => { file => $image }, 'first-view' => 1, format => 'json' })->res; +my $short = $raw->json('/msg/short'); + +$t->get_ok('/'.$short) + ->status_is(200); + +$t->get_ok('/'.$short) + ->status_is(302); + +# Delete image with token +$raw = $t->ua->post('/' => form => { file => { file => $image }, format => 'json' })->res; +my $rshort = $raw->json('/msg/real_short'); +my $token = $raw->json('/msg/token'); + +$t->get_ok('/'.$rshort) + ->status_is(200); + +$t->get_ok('/d/'.$rshort.'/'.$token, form => { format => 'json' }) + ->status_is('200') + ->json_is( + { + success => true, + msg => 'The image Lutim.png has been successfully deleted' + } + ); + +$t->get_ok('/'.$rshort) + ->status_is(302); + +# Needed if we use Minion with sqlite for increasing counters +sleep 8; + +# Get image counter +$t->post_ok('/c', form => { short => $rshort, token => $token }) + ->status_is(200) + ->json_is( + { + success => true, + counter => 1, + enabled => false + } + ); + +done_testing(); diff --git a/themes/default/lib/Lutim/I18N/de.po b/themes/default/lib/Lutim/I18N/de.po index 660d645..485d213 100644 --- a/themes/default/lib/Lutim/I18N/de.po +++ b/themes/default/lib/Lutim/I18N/de.po @@ -18,19 +18,11 @@ msgstr "" "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#. ($delay) -#. (config('max_delay') #. (7) #. (30) -#: lib/Lutim/Command/cron/stats.pm:100 -#: lib/Lutim/Command/cron/stats.pm:110 -#: lib/Lutim/Command/cron/stats.pm:111 -#: lib/Lutim/Command/cron/stats.pm:127 -#: lib/Lutim/Command/cron/stats.pm:128 -#: lib/Lutim/Command/cron/stats.pm:99 -#: themes/default/templates/partial/lutim.js.ep:235 -#: themes/default/templates/partial/lutim.js.ep:244 -#: themes/default/templates/partial/lutim.js.ep:245 +#. ($delay) +#. (config('max_delay') +#: lib/Lutim/Command/cron/stats.pm:149 lib/Lutim/Command/cron/stats.pm:150 lib/Lutim/Command/cron/stats.pm:160 lib/Lutim/Command/cron/stats.pm:161 lib/Lutim/Command/cron/stats.pm:177 lib/Lutim/Command/cron/stats.pm:178 themes/default/templates/partial/for_my_delay.html.ep:12 themes/default/templates/partial/for_my_delay.html.ep:13 themes/default/templates/partial/for_my_delay.html.ep:3 themes/default/templates/partial/lutim.js.ep:138 themes/default/templates/partial/lutim.js.ep:147 themes/default/templates/partial/lutim.js.ep:148 themes/default/templates/raw.html.ep:19 themes/default/templates/raw.html.ep:20 themes/default/templates/raw.html.ep:36 themes/default/templates/raw.html.ep:37 themes/default/templates/raw.html.ep:8 themes/default/templates/raw.html.ep:9 msgid "%1 days" msgstr "%1 Tage" @@ -43,41 +35,35 @@ msgstr "%1 Bilder wurden bisher über diese Instanz versendet." msgid "-or-" msgstr "-oder-" -#: lib/Lutim/Command/cron/stats.pm:101 -#: lib/Lutim/Command/cron/stats.pm:112 -#: lib/Lutim/Command/cron/stats.pm:129 -#: themes/default/templates/index.html.ep:5 +#: lib/Lutim.pm:192 lib/Lutim/Command/cron/stats.pm:151 lib/Lutim/Command/cron/stats.pm:162 lib/Lutim/Command/cron/stats.pm:179 themes/default/templates/index.html.ep:5 themes/default/templates/raw.html.ep:10 themes/default/templates/raw.html.ep:21 themes/default/templates/raw.html.ep:38 msgid "1 year" msgstr "1 Jahr" -#: lib/Lutim/Command/cron/stats.pm:109 -#: lib/Lutim/Command/cron/stats.pm:126 -#: lib/Lutim/Command/cron/stats.pm:98 -#: themes/default/templates/index.html.ep:4 -#: themes/default/templates/partial/lutim.js.ep:244 +#: lib/Lutim.pm:191 lib/Lutim/Command/cron/stats.pm:148 lib/Lutim/Command/cron/stats.pm:159 lib/Lutim/Command/cron/stats.pm:176 themes/default/templates/index.html.ep:4 themes/default/templates/partial/for_my_delay.html.ep:12 themes/default/templates/partial/lutim.js.ep:147 themes/default/templates/raw.html.ep:18 themes/default/templates/raw.html.ep:35 themes/default/templates/raw.html.ep:7 msgid "24 hours" msgstr "24 Stunden" -#: themes/default/templates/myfiles.html.ep:79 +#: themes/default/templates/partial/myfiles.js.ep:57 msgid ": Error while trying to get the counter." msgstr ":Fehler beim Abrufen des Zählers." -#: lib/Lutim/Command/cron/stats.pm:94 +#: lib/Lutim/Command/cron/stats.pm:144 themes/default/templates/raw.html.ep:3 msgid "Active images" msgstr "" -#: lib/Lutim/Controller.pm:286 +#: lib/Lutim/Controller.pm:288 msgid "An error occured while downloading the image." msgstr "Beim Herunterladen des Bildes ist ein Fehler aufgetreten." -#: themes/default/templates/about.html.ep:41 -#: themes/default/templates/myfiles.html.ep:27 -#: themes/default/templates/stats.html.ep:25 +#: themes/default/templates/zip.html.ep:2 +msgid "Archives download" +msgstr "" + +#: themes/default/templates/about.html.ep:41 themes/default/templates/myfiles.html.ep:64 themes/default/templates/stats.html.ep:25 msgid "Back to homepage" msgstr "Zurück zur Hauptseite" -#: themes/default/templates/index.html.ep:193 -#: themes/default/templates/index.html.ep:194 +#: themes/default/templates/index.html.ep:193 themes/default/templates/index.html.ep:194 msgid "Click to open the file browser" msgstr "Klicken um den Dateibrowser zu öffnen" @@ -85,27 +71,15 @@ msgstr "Klicken um den Dateibrowser zu öffnen" msgid "Contributors" msgstr "Mitwirkende" -#: themes/default/templates/partial/lutim.js.ep:310 -#: themes/default/templates/partial/lutim.js.ep:359 -#: themes/default/templates/partial/lutim.js.ep:437 +#: themes/default/templates/partial/lutim.js.ep:214 themes/default/templates/partial/lutim.js.ep:268 themes/default/templates/partial/lutim.js.ep:346 msgid "Copy all view links to clipboard" msgstr "Alle Links zum Anschauen in die Zwischenablage kopieren" -#: themes/default/templates/index.html.ep:18 -#: themes/default/templates/index.html.ep:36 -#: themes/default/templates/index.html.ep:69 -#: themes/default/templates/index.html.ep:77 -#: themes/default/templates/index.html.ep:85 -#: themes/default/templates/index.html.ep:93 -#: themes/default/templates/partial/common.js.ep:45 -#: themes/default/templates/partial/lutim.js.ep:176 -#: themes/default/templates/partial/lutim.js.ep:188 -#: themes/default/templates/partial/lutim.js.ep:202 -#: themes/default/templates/partial/lutim.js.ep:217 +#: themes/default/templates/index.html.ep:18 themes/default/templates/index.html.ep:36 themes/default/templates/index.html.ep:69 themes/default/templates/index.html.ep:77 themes/default/templates/index.html.ep:85 themes/default/templates/index.html.ep:93 themes/default/templates/myfiles.html.ep:20 themes/default/templates/myfiles.html.ep:38 themes/default/templates/partial/common.js.ep:150 themes/default/templates/partial/lutim.js.ep:105 themes/default/templates/partial/lutim.js.ep:120 themes/default/templates/partial/lutim.js.ep:79 themes/default/templates/partial/lutim.js.ep:91 msgid "Copy to clipboard" msgstr "In die Zwischenablage kopieren" -#: themes/default/templates/myfiles.html.ep:15 +#: themes/default/templates/myfiles.html.ep:52 msgid "Counter" msgstr "Zähler" @@ -117,26 +91,19 @@ msgstr "" msgid "Delay repartition chart for enabled images" msgstr "" -#: themes/default/templates/index.html.ep:115 -#: themes/default/templates/index.html.ep:147 -#: themes/default/templates/index.html.ep:178 -#: themes/default/templates/myfiles.html.ep:16 -#: themes/default/templates/partial/lutim.js.ep:256 +#: themes/default/templates/index.html.ep:115 themes/default/templates/index.html.ep:147 themes/default/templates/index.html.ep:178 themes/default/templates/myfiles.html.ep:53 themes/default/templates/partial/lutim.js.ep:159 msgid "Delete at first view?" msgstr "Nach erstem Aufruf löschen?" -#: lib/Lutim/Command/cron/stats.pm:95 +#: lib/Lutim/Command/cron/stats.pm:145 themes/default/templates/raw.html.ep:4 msgid "Deleted images" msgstr "" -#: lib/Lutim/Command/cron/stats.pm:96 +#: lib/Lutim/Command/cron/stats.pm:146 themes/default/templates/raw.html.ep:5 msgid "Deleted images in 30 days" msgstr "" -#: themes/default/templates/index.html.ep:98 -#: themes/default/templates/myfiles.html.ep:19 -#: themes/default/templates/partial/common.js.ep:37 -#: themes/default/templates/partial/common.js.ep:40 +#: themes/default/templates/index.html.ep:98 themes/default/templates/myfiles.html.ep:56 themes/default/templates/partial/common.js.ep:142 themes/default/templates/partial/common.js.ep:145 msgid "Deletion link" msgstr "Link zum Löschen" @@ -144,15 +111,11 @@ msgstr "Link zum Löschen" msgid "Download all images" msgstr "Laden Sie alle Bilder" -#: themes/default/templates/index.html.ep:81 -#: themes/default/templates/index.html.ep:83 -#: themes/default/templates/partial/lutim.js.ep:194 -#: themes/default/templates/partial/lutim.js.ep:198 +#: themes/default/templates/index.html.ep:81 themes/default/templates/index.html.ep:83 themes/default/templates/partial/lutim.js.ep:101 themes/default/templates/partial/lutim.js.ep:97 msgid "Download link" msgstr "Link zum Herunterladen" -#: themes/default/templates/index.html.ep:28 -#: themes/default/templates/index.html.ep:31 +#: themes/default/templates/index.html.ep:28 themes/default/templates/index.html.ep:31 themes/default/templates/myfiles.html.ep:30 themes/default/templates/myfiles.html.ep:33 msgid "Download zip link" msgstr "Link zum Archivbilder" @@ -164,12 +127,11 @@ msgstr "Bilder hierher ziehen" msgid "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." msgstr "Ziehe Bilder in den dafür vorgesehenen Bereich und Lutim wird vier URLs generieren. Eine zum Anschauen, eine zum direkten Herunterladen, eine zum Nutzen in sozialen Netzwerken und eine letzte um das Bild zu löschen." -#: themes/default/templates/index.html.ep:150 -#: themes/default/templates/index.html.ep:181 +#: themes/default/templates/index.html.ep:150 themes/default/templates/index.html.ep:181 msgid "Encrypt the image (Lutim does not keep the key)." msgstr "Verschlüssle das Bild (Lutim behält den Key nicht)" -#: themes/default/templates/partial/lutim.js.ep:72 +#: themes/default/templates/partial/lutim.js.ep:44 msgid "Error while trying to modify the image." msgstr "Beim bearbeiten des Bildes ist ein Fehler aufgetreten." @@ -177,11 +139,11 @@ msgstr "Beim bearbeiten des Bildes ist ein Fehler aufgetreten." msgid "Evolution of total files" msgstr "Entwicklung der Anzahl an Dateien" -#: themes/default/templates/myfiles.html.ep:18 +#: themes/default/templates/myfiles.html.ep:55 msgid "Expires at" msgstr "Läuft ab am" -#: themes/default/templates/myfiles.html.ep:13 +#: themes/default/templates/myfiles.html.ep:50 msgid "File name" msgstr "Dateiname" @@ -189,21 +151,19 @@ msgstr "Dateiname" msgid "For more details, see the homepage of the project." msgstr "Besuche für mehr Details die Homepage des Projekts." -#: themes/default/templates/layouts/default.html.ep:50 +#: themes/default/templates/layouts/default.html.ep:55 msgid "Fork me!" msgstr "Fork me!" -#: themes/default/templates/index.html.ep:10 -#: themes/default/templates/index.html.ep:13 +#: themes/default/templates/index.html.ep:10 themes/default/templates/index.html.ep:13 themes/default/templates/myfiles.html.ep:12 themes/default/templates/myfiles.html.ep:15 msgid "Gallery link" msgstr "Link zur Galerie" -#: themes/default/templates/partial/lutim.js.ep:125 -#: themes/default/templates/partial/lutim.js.ep:142 +#: themes/default/templates/partial/common.js.ep:104 themes/default/templates/partial/common.js.ep:87 msgid "Hit Ctrl+C, then Enter to copy the short link" msgstr "Drücke STRG+C und dann Enter um den Kurz-Link zu kopieren." -#: themes/default/templates/layouts/default.html.ep:45 +#: themes/default/templates/layouts/default.html.ep:50 msgid "Homepage" msgstr "Webseite" @@ -223,27 +183,30 @@ msgstr "Wie kann ich ein Bild melden?" msgid "If the files are deleted if you ask it while posting it, their SHA512 footprint are retained." msgstr "Wenn du versuchst, ein Bild während dem Hochladen zu löschen, wird die SHA512-Summe des Bildes behalten." -#: themes/default/templates/index.html.ep:163 -#: themes/default/templates/index.html.ep:203 +#: themes/default/templates/index.html.ep:163 themes/default/templates/index.html.ep:203 msgid "Image URL" msgstr "Bild-URL" -#: lib/Lutim/Command/cron/stats.pm:93 +#: lib/Lutim/Command/cron/stats.pm:143 themes/default/templates/raw.html.ep:2 msgid "Image delay" msgstr "" -#: lib/Lutim/Controller.pm:715 +#: lib/Lutim/Controller.pm:710 msgid "Image not found." msgstr "Bild nicht gefunden" -#: themes/default/templates/layouts/default.html.ep:49 +#: themes/default/templates/layouts/default.html.ep:54 msgid "Informations" msgstr "Informationen" -#: themes/default/templates/layouts/default.html.ep:55 +#: themes/default/templates/layouts/default.html.ep:62 msgid "Install webapp" msgstr "Installiere die Webapp" +#: themes/default/templates/layouts/default.html.ep:61 +msgid "Instance's statistics" +msgstr "" + #: themes/default/templates/about.html.ep:11 msgid "Is it really anonymous?" msgstr "Ist es wirklich anonym?" @@ -256,29 +219,30 @@ msgstr "Is es wirklich kostenlos?" msgid "Juste like you pronounce the French word lutin (/ly.tɛ̃/)." msgstr "Genauso wie das französische Wort lutin (/ly.tɛ̃/)." -#: themes/default/templates/index.html.ep:153 -#: themes/default/templates/index.html.ep:184 +#: themes/default/templates/index.html.ep:153 themes/default/templates/index.html.ep:184 msgid "Keep EXIF tags" msgstr "Behalte EXIF-Daten" -#: themes/default/templates/index.html.ep:118 -#: themes/default/templates/index.html.ep:166 -#: themes/default/templates/index.html.ep:206 -#: themes/default/templates/partial/lutim.js.ep:260 +#: themes/default/templates/index.html.ep:118 themes/default/templates/index.html.ep:166 themes/default/templates/index.html.ep:206 themes/default/templates/partial/lutim.js.ep:163 msgid "Let's go!" msgstr "Los gehts!" -#: themes/default/templates/layouts/default.html.ep:48 +#: themes/default/templates/layouts/default.html.ep:58 +msgid "Liberapay button" +msgstr "" + +#: themes/default/templates/layouts/default.html.ep:53 msgid "License:" msgstr "Lizenz:" -#: themes/default/templates/index.html.ep:89 -#: themes/default/templates/index.html.ep:91 -#: themes/default/templates/partial/lutim.js.ep:208 -#: themes/default/templates/partial/lutim.js.ep:212 +#: themes/default/templates/index.html.ep:89 themes/default/templates/index.html.ep:91 themes/default/templates/partial/lutim.js.ep:111 themes/default/templates/partial/lutim.js.ep:115 msgid "Link for share on social networks" msgstr "Links zum teilen auf sozialen Netzwerken" +#: themes/default/templates/zip.html.ep:7 +msgid "Lutim can't zip so many images at once, so it splitted your demand in multiple URLs." +msgstr "" + #: themes/default/templates/about.html.ep:4 msgid "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." msgstr "" @@ -289,24 +253,19 @@ msgstr "" msgid "Main developers" msgstr "Haupt-Entwickler" -#: themes/default/templates/index.html.ep:73 -#: themes/default/templates/index.html.ep:75 -#: themes/default/templates/partial/lutim.js.ep:182 -#: themes/default/templates/partial/lutim.js.ep:185 +#: themes/default/templates/index.html.ep:73 themes/default/templates/index.html.ep:75 themes/default/templates/partial/lutim.js.ep:85 themes/default/templates/partial/lutim.js.ep:88 msgid "Markdown syntax" msgstr "Markdown Syntax" -#: themes/default/templates/layouts/default.html.ep:54 -#: themes/default/templates/myfiles.html.ep:2 +#: themes/default/templates/layouts/default.html.ep:60 themes/default/templates/myfiles.html.ep:2 msgid "My images" msgstr "Meine Bilder" -#: themes/default/templates/myfiles.html.ep:39 +#: themes/default/templates/partial/myfiles.js.ep:19 msgid "No limit" msgstr "Keine Begrenzung" -#: themes/default/templates/index.html.ep:165 -#: themes/default/templates/index.html.ep:198 +#: themes/default/templates/index.html.ep:165 themes/default/templates/index.html.ep:198 msgid "Only images are allowed" msgstr "Es sind nur Bilder erlaubt" @@ -318,6 +277,10 @@ msgstr "Nur die Bilder, die über diesen Browser versendet wurden, werden hier a msgid "Only the uploader! (well, only if he's the only owner of the images' rights before the upload)" msgstr "Nur der Hochladende (natürlich nur, wenn er vorher auch Rechteinhaber des Bildes war)" +#: themes/default/templates/zip.html.ep:12 +msgid "Please click on each URL to download the different zip files." +msgstr "" + #. (config('contact') #: themes/default/templates/about.html.ep:19 msgid "Please contact the administrator: %1" @@ -331,24 +294,31 @@ msgstr "" msgid "Send an image" msgstr "Sende ein Bild" -#: themes/default/templates/partial/lutim.js.ep:51 +#: themes/default/templates/partial/lutim.js.ep:20 msgid "Share it!" msgstr "Teile es!" -#: themes/default/templates/layouts/default.html.ep:51 +#: themes/default/templates/layouts/default.html.ep:56 msgid "Share on Twitter" msgstr "Teile es auf Twitter" -#: themes/default/templates/index.html.ep:133 -#: themes/default/templates/partial/lutim.js.ep:271 +#: themes/default/templates/index.html.ep:133 themes/default/templates/partial/lutim.js.ep:174 msgid "Something bad happened" msgstr "Es ist ein Fehler aufgetreten" #. ($c->config('contact') -#: lib/Lutim/Controller.pm:723 +#: lib/Lutim/Controller.pm:717 msgid "Something went wrong when creating the zip file. Try again later or contact the administrator (%1)." msgstr "Es ist ein Fehler aufgetreten. Versuche es erneut oder kontaktiere den Administrator (%1)." +#: themes/default/templates/layouts/default.html.ep:58 +msgid "Support the author on Liberapay" +msgstr "" + +#: themes/default/templates/layouts/default.html.ep:57 +msgid "Support the author on Tipeee" +msgstr "" + #: themes/default/templates/about.html.ep:13 msgid "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)." msgstr "Die IP-Adresse des Nutzers wird für eine bestimmte Zeit gespeichert. Diese kann der Administrator frei wählen (für die offizielle Instanz, die in Frankreich gehostet ist, liegt diese Zeit bei einem Jahr)" @@ -357,26 +327,27 @@ msgstr "Die IP-Adresse des Nutzers wird für eine bestimmte Zeit gespeichert. Di msgid "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." msgstr "Lutim ist freie Software, was dir erlaubt sie herunterzuladen und sie auf deinem eigenem Server zu installieren. Schau dir die AGPL an um deine Recht zu sehen." -#: lib/Lutim/Controller.pm:305 +#: lib/Lutim/Controller.pm:307 msgid "The URL is not valid." msgstr "Die URL ist nicht gültig." -#: lib/Lutim/Controller.pm:117 -#: lib/Lutim/Controller.pm:186 +#: themes/default/templates/zip.html.ep:16 +msgid "The automatic download process will open a tab in your browser for each link. You need to allow popups for Lutim." +msgstr "" + +#: lib/Lutim/Controller.pm:120 lib/Lutim/Controller.pm:188 msgid "The delete token is invalid." msgstr "Das Token zum Löschen ist ungültig." #. ($upload->filename) -#: lib/Lutim/Controller.pm:449 +#: lib/Lutim/Controller.pm:445 msgid "The file %1 is not an image." msgstr "Die Datei %1 ist kein Bild." -#. ($max_file_size) #. ($tx->res->max_message_size) #. ($c->req->max_message_size) -#: lib/Lutim/Controller.pm:269 -#: lib/Lutim/Controller.pm:338 -#: themes/default/templates/partial/lutim.js.ep:332 +#. (config('max_file_size') +#: lib/Lutim/Controller.pm:271 lib/Lutim/Controller.pm:340 themes/default/templates/partial/lutim.js.ep:240 msgid "The file exceed the size limit (%1)" msgstr "Die Datei überschreitet die Größenbeschränkung (%1)" @@ -385,17 +356,16 @@ msgid "The graph's datas are not updated in real-time." msgstr "Die Daten des Graphs werden nicht in Echtzeit aktualisiert." #. ($image->filename) -#: lib/Lutim/Controller.pm:188 +#: lib/Lutim/Controller.pm:190 msgid "The image %1 has already been deleted." msgstr "Das Bild %1 wurde schon gelöscht." #. ($image->filename) -#: lib/Lutim/Controller.pm:197 -#: lib/Lutim/Controller.pm:202 +#: lib/Lutim/Controller.pm:199 lib/Lutim/Controller.pm:204 msgid "The image %1 has been successfully deleted" msgstr "Das Bild %1 wurde erfolgreich gelöscht." -#: lib/Lutim/Controller.pm:125 +#: lib/Lutim/Controller.pm:128 msgid "The image's delay has been successfully modified" msgstr "Die Zeit bis zum Löschen des Bildes wurde erfolgreich geändert." @@ -408,37 +378,32 @@ msgid "The images you post on Lutim can be stored indefinitely or be deleted at msgstr "Die Bilder, die du auf Lutim hochlädst, können entweder nie, nach dem ersten Aufruf oder nach einer bestimmten Zeit gelöscht werden." #. ($c->config->{contact}) -#: lib/Lutim/Controller.pm:444 +#: lib/Lutim/Controller.pm:442 msgid "There is no more available URL. Retry or contact the administrator. %1" msgstr "Es sind keine URLs mehr verfügbar. Versuche es erneut oder kontaktiere den Administrator. %1" -#: lib/Lutim/Command/cron/stats.pm:102 +#: themes/default/templates/layouts/default.html.ep:57 +msgid "Tipeee button" +msgstr "" + +#: lib/Lutim/Command/cron/stats.pm:152 themes/default/templates/raw.html.ep:11 msgid "Total" msgstr "" -#: themes/default/templates/index.html.ep:60 -#: themes/default/templates/partial/lutim.js.ep:45 +#: themes/default/templates/index.html.ep:60 themes/default/templates/partial/lutim.js.ep:14 msgid "Tweet it!" msgstr "Twittere es!" #. ($short) -#: lib/Lutim/Controller.pm:159 -#: lib/Lutim/Controller.pm:231 +#: lib/Lutim/Controller.pm:162 lib/Lutim/Controller.pm:233 msgid "Unable to find the image %1." msgstr "Konnte das Bild %1 nicht finden." -#: lib/Lutim.pm:85 -#: lib/Lutim/Controller.pm:534 -#: lib/Lutim/Controller.pm:580 -#: lib/Lutim/Controller.pm:624 -#: lib/Lutim/Controller.pm:664 -#: lib/Lutim/Controller.pm:676 -#: lib/Lutim/Controller.pm:687 -#: lib/Lutim/Controller.pm:712 +#: lib/Lutim/Controller.pm:529 lib/Lutim/Controller.pm:574 lib/Lutim/Controller.pm:616 lib/Lutim/Controller.pm:659 lib/Lutim/Controller.pm:671 lib/Lutim/Controller.pm:682 lib/Lutim/Controller.pm:707 lib/Lutim/Plugin/Helpers.pm:57 msgid "Unable to find the image: it has been deleted." msgstr "Dieses Bild wurde gelöscht." -#: lib/Lutim/Controller.pm:101 +#: lib/Lutim/Controller.pm:105 msgid "Unable to get counter" msgstr "Konnte den Zähler nicht abrufen" @@ -446,12 +411,11 @@ msgstr "Konnte den Zähler nicht abrufen" msgid "Unlike many image sharing services, you don't give us rights on uploaded images." msgstr "Im Gegensatz zu anderen Bild-Hosting-Diensten, überträgst du uns nicht die Rechte an hochgeladenen Bildern." -#: themes/default/templates/index.html.ep:162 -#: themes/default/templates/index.html.ep:201 +#: themes/default/templates/index.html.ep:162 themes/default/templates/index.html.ep:201 msgid "Upload an image with its URL" msgstr "Lade ein Bild über seine URL hoch" -#: themes/default/templates/myfiles.html.ep:17 +#: themes/default/templates/myfiles.html.ep:54 msgid "Uploaded at" msgstr "Hochgeladen am" @@ -459,16 +423,12 @@ msgstr "Hochgeladen am" msgid "Uploaded files by days" msgstr "Hochgeladene Bilder pro Tag" -#. ($config->{contact}) -#: lib/Lutim.pm:189 +#. ($c->app->config('contact') +#: lib/Lutim/Plugin/Helpers.pm:152 msgid "Uploading is currently disabled, please try later or contact the administrator (%1)." msgstr "Hochladen ist momentan deaktiviert. Versuche es später erneut oder kontaktiere den Administrator (%1)." -#: themes/default/templates/index.html.ep:65 -#: themes/default/templates/index.html.ep:67 -#: themes/default/templates/myfiles.html.ep:14 -#: themes/default/templates/partial/lutim.js.ep:168 -#: themes/default/templates/partial/lutim.js.ep:172 +#: themes/default/templates/index.html.ep:65 themes/default/templates/index.html.ep:67 themes/default/templates/myfiles.html.ep:51 themes/default/templates/partial/lutim.js.ep:71 themes/default/templates/partial/lutim.js.ep:75 msgid "View link" msgstr "Link ansehen" @@ -492,6 +452,10 @@ msgstr "Ja, ist es! Auf der anderen Seite wird deine IP-Adresse, wegen rechtlich msgid "Yes, it is! On the other side, if you want to support the developer, you can do it via Tipeee or via Liberapay." msgstr "Ja, ist es! Auf der anderen Seite kannst du den Entwickler via Tipeee oder Liberapay unterstützen." +#: themes/default/templates/zip.html.ep:6 +msgid "You asked to download a zip archive for too much files." +msgstr "" + #: themes/default/templates/about.html.ep:8 msgid "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." msgstr "Du kannst Bilder, die du auf Lutim hochlädst, entweder nach dem ernsten Ansehen (oder Herunterladen) oder nach einem der vorgeschlagenen Zeiten löschen lassen." @@ -504,10 +468,7 @@ msgstr "und auf" msgid "core developer" msgstr "Haupt-Entwickler" -#: lib/Lutim/Command/cron/stats.pm:108 -#: lib/Lutim/Command/cron/stats.pm:125 -#: lib/Lutim/Command/cron/stats.pm:97 -#: themes/default/templates/index.html.ep:3 +#: lib/Lutim.pm:190 lib/Lutim/Command/cron/stats.pm:147 lib/Lutim/Command/cron/stats.pm:158 lib/Lutim/Command/cron/stats.pm:175 themes/default/templates/index.html.ep:3 themes/default/templates/raw.html.ep:17 themes/default/templates/raw.html.ep:34 themes/default/templates/raw.html.ep:6 msgid "no time limit" msgstr "keine Zeit-Begrenzung" diff --git a/themes/default/lib/Lutim/I18N/en.po b/themes/default/lib/Lutim/I18N/en.po index 979e9c6..0f21ee8 100644 --- a/themes/default/lib/Lutim/I18N/en.po +++ b/themes/default/lib/Lutim/I18N/en.po @@ -16,19 +16,11 @@ msgstr "" "Language: en\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#. ($delay) -#. (config('max_delay') #. (7) #. (30) -#: lib/Lutim/Command/cron/stats.pm:100 -#: lib/Lutim/Command/cron/stats.pm:110 -#: lib/Lutim/Command/cron/stats.pm:111 -#: lib/Lutim/Command/cron/stats.pm:127 -#: lib/Lutim/Command/cron/stats.pm:128 -#: lib/Lutim/Command/cron/stats.pm:99 -#: themes/default/templates/partial/lutim.js.ep:235 -#: themes/default/templates/partial/lutim.js.ep:244 -#: themes/default/templates/partial/lutim.js.ep:245 +#. ($delay) +#. (config('max_delay') +#: lib/Lutim/Command/cron/stats.pm:149 lib/Lutim/Command/cron/stats.pm:150 lib/Lutim/Command/cron/stats.pm:160 lib/Lutim/Command/cron/stats.pm:161 lib/Lutim/Command/cron/stats.pm:177 lib/Lutim/Command/cron/stats.pm:178 themes/default/templates/partial/for_my_delay.html.ep:12 themes/default/templates/partial/for_my_delay.html.ep:13 themes/default/templates/partial/for_my_delay.html.ep:3 themes/default/templates/partial/lutim.js.ep:138 themes/default/templates/partial/lutim.js.ep:147 themes/default/templates/partial/lutim.js.ep:148 themes/default/templates/raw.html.ep:19 themes/default/templates/raw.html.ep:20 themes/default/templates/raw.html.ep:36 themes/default/templates/raw.html.ep:37 themes/default/templates/raw.html.ep:8 themes/default/templates/raw.html.ep:9 msgid "%1 days" msgstr "" @@ -41,41 +33,35 @@ msgstr "%1 sent images on this instance from beginning." msgid "-or-" msgstr "-or-" -#: lib/Lutim/Command/cron/stats.pm:101 -#: lib/Lutim/Command/cron/stats.pm:112 -#: lib/Lutim/Command/cron/stats.pm:129 -#: themes/default/templates/index.html.ep:5 +#: lib/Lutim.pm:192 lib/Lutim/Command/cron/stats.pm:151 lib/Lutim/Command/cron/stats.pm:162 lib/Lutim/Command/cron/stats.pm:179 themes/default/templates/index.html.ep:5 themes/default/templates/raw.html.ep:10 themes/default/templates/raw.html.ep:21 themes/default/templates/raw.html.ep:38 msgid "1 year" msgstr "1 year" -#: lib/Lutim/Command/cron/stats.pm:109 -#: lib/Lutim/Command/cron/stats.pm:126 -#: lib/Lutim/Command/cron/stats.pm:98 -#: themes/default/templates/index.html.ep:4 -#: themes/default/templates/partial/lutim.js.ep:244 +#: lib/Lutim.pm:191 lib/Lutim/Command/cron/stats.pm:148 lib/Lutim/Command/cron/stats.pm:159 lib/Lutim/Command/cron/stats.pm:176 themes/default/templates/index.html.ep:4 themes/default/templates/partial/for_my_delay.html.ep:12 themes/default/templates/partial/lutim.js.ep:147 themes/default/templates/raw.html.ep:18 themes/default/templates/raw.html.ep:35 themes/default/templates/raw.html.ep:7 msgid "24 hours" msgstr "24 hours" -#: themes/default/templates/myfiles.html.ep:79 +#: themes/default/templates/partial/myfiles.js.ep:57 msgid ": Error while trying to get the counter." msgstr "" -#: lib/Lutim/Command/cron/stats.pm:94 +#: lib/Lutim/Command/cron/stats.pm:144 themes/default/templates/raw.html.ep:3 msgid "Active images" msgstr "" -#: lib/Lutim/Controller.pm:286 +#: lib/Lutim/Controller.pm:288 msgid "An error occured while downloading the image." msgstr "An error occured while downloading the image." -#: themes/default/templates/about.html.ep:41 -#: themes/default/templates/myfiles.html.ep:27 -#: themes/default/templates/stats.html.ep:25 +#: themes/default/templates/zip.html.ep:2 +msgid "Archives download" +msgstr "" + +#: themes/default/templates/about.html.ep:41 themes/default/templates/myfiles.html.ep:64 themes/default/templates/stats.html.ep:25 msgid "Back to homepage" msgstr "Back to homepage" -#: themes/default/templates/index.html.ep:193 -#: themes/default/templates/index.html.ep:194 +#: themes/default/templates/index.html.ep:193 themes/default/templates/index.html.ep:194 msgid "Click to open the file browser" msgstr "Click to open the file browser" @@ -83,27 +69,15 @@ msgstr "Click to open the file browser" msgid "Contributors" msgstr "Contributors" -#: themes/default/templates/partial/lutim.js.ep:310 -#: themes/default/templates/partial/lutim.js.ep:359 -#: themes/default/templates/partial/lutim.js.ep:437 +#: themes/default/templates/partial/lutim.js.ep:214 themes/default/templates/partial/lutim.js.ep:268 themes/default/templates/partial/lutim.js.ep:346 msgid "Copy all view links to clipboard" msgstr "" -#: themes/default/templates/index.html.ep:18 -#: themes/default/templates/index.html.ep:36 -#: themes/default/templates/index.html.ep:69 -#: themes/default/templates/index.html.ep:77 -#: themes/default/templates/index.html.ep:85 -#: themes/default/templates/index.html.ep:93 -#: themes/default/templates/partial/common.js.ep:45 -#: themes/default/templates/partial/lutim.js.ep:176 -#: themes/default/templates/partial/lutim.js.ep:188 -#: themes/default/templates/partial/lutim.js.ep:202 -#: themes/default/templates/partial/lutim.js.ep:217 +#: themes/default/templates/index.html.ep:18 themes/default/templates/index.html.ep:36 themes/default/templates/index.html.ep:69 themes/default/templates/index.html.ep:77 themes/default/templates/index.html.ep:85 themes/default/templates/index.html.ep:93 themes/default/templates/myfiles.html.ep:20 themes/default/templates/myfiles.html.ep:38 themes/default/templates/partial/common.js.ep:150 themes/default/templates/partial/lutim.js.ep:105 themes/default/templates/partial/lutim.js.ep:120 themes/default/templates/partial/lutim.js.ep:79 themes/default/templates/partial/lutim.js.ep:91 msgid "Copy to clipboard" msgstr "Copy to clipboard" -#: themes/default/templates/myfiles.html.ep:15 +#: themes/default/templates/myfiles.html.ep:52 msgid "Counter" msgstr "" @@ -115,26 +89,19 @@ msgstr "" msgid "Delay repartition chart for enabled images" msgstr "" -#: themes/default/templates/index.html.ep:115 -#: themes/default/templates/index.html.ep:147 -#: themes/default/templates/index.html.ep:178 -#: themes/default/templates/myfiles.html.ep:16 -#: themes/default/templates/partial/lutim.js.ep:256 +#: themes/default/templates/index.html.ep:115 themes/default/templates/index.html.ep:147 themes/default/templates/index.html.ep:178 themes/default/templates/myfiles.html.ep:53 themes/default/templates/partial/lutim.js.ep:159 msgid "Delete at first view?" msgstr "Delete at first view?" -#: lib/Lutim/Command/cron/stats.pm:95 +#: lib/Lutim/Command/cron/stats.pm:145 themes/default/templates/raw.html.ep:4 msgid "Deleted images" msgstr "" -#: lib/Lutim/Command/cron/stats.pm:96 +#: lib/Lutim/Command/cron/stats.pm:146 themes/default/templates/raw.html.ep:5 msgid "Deleted images in 30 days" msgstr "" -#: themes/default/templates/index.html.ep:98 -#: themes/default/templates/myfiles.html.ep:19 -#: themes/default/templates/partial/common.js.ep:37 -#: themes/default/templates/partial/common.js.ep:40 +#: themes/default/templates/index.html.ep:98 themes/default/templates/myfiles.html.ep:56 themes/default/templates/partial/common.js.ep:142 themes/default/templates/partial/common.js.ep:145 msgid "Deletion link" msgstr "Deletion link" @@ -142,15 +109,11 @@ msgstr "Deletion link" msgid "Download all images" msgstr "" -#: themes/default/templates/index.html.ep:81 -#: themes/default/templates/index.html.ep:83 -#: themes/default/templates/partial/lutim.js.ep:194 -#: themes/default/templates/partial/lutim.js.ep:198 +#: themes/default/templates/index.html.ep:81 themes/default/templates/index.html.ep:83 themes/default/templates/partial/lutim.js.ep:101 themes/default/templates/partial/lutim.js.ep:97 msgid "Download link" msgstr "Download link" -#: themes/default/templates/index.html.ep:28 -#: themes/default/templates/index.html.ep:31 +#: themes/default/templates/index.html.ep:28 themes/default/templates/index.html.ep:31 themes/default/templates/myfiles.html.ep:30 themes/default/templates/myfiles.html.ep:33 msgid "Download zip link" msgstr "" @@ -162,12 +125,11 @@ msgstr "Drag & drop images here" msgid "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." msgstr "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." -#: themes/default/templates/index.html.ep:150 -#: themes/default/templates/index.html.ep:181 +#: themes/default/templates/index.html.ep:150 themes/default/templates/index.html.ep:181 msgid "Encrypt the image (Lutim does not keep the key)." msgstr "Encrypt the image (Lutim does not keep the key)." -#: themes/default/templates/partial/lutim.js.ep:72 +#: themes/default/templates/partial/lutim.js.ep:44 msgid "Error while trying to modify the image." msgstr "" @@ -175,11 +137,11 @@ msgstr "" msgid "Evolution of total files" msgstr "Evolution of total files" -#: themes/default/templates/myfiles.html.ep:18 +#: themes/default/templates/myfiles.html.ep:55 msgid "Expires at" msgstr "" -#: themes/default/templates/myfiles.html.ep:13 +#: themes/default/templates/myfiles.html.ep:50 msgid "File name" msgstr "" @@ -187,21 +149,19 @@ msgstr "" msgid "For more details, see the homepage of the project." msgstr "For more details, see the homepage of the project." -#: themes/default/templates/layouts/default.html.ep:50 +#: themes/default/templates/layouts/default.html.ep:55 msgid "Fork me!" msgstr "Fork me!" -#: themes/default/templates/index.html.ep:10 -#: themes/default/templates/index.html.ep:13 +#: themes/default/templates/index.html.ep:10 themes/default/templates/index.html.ep:13 themes/default/templates/myfiles.html.ep:12 themes/default/templates/myfiles.html.ep:15 msgid "Gallery link" msgstr "" -#: themes/default/templates/partial/lutim.js.ep:125 -#: themes/default/templates/partial/lutim.js.ep:142 +#: themes/default/templates/partial/common.js.ep:104 themes/default/templates/partial/common.js.ep:87 msgid "Hit Ctrl+C, then Enter to copy the short link" msgstr "" -#: themes/default/templates/layouts/default.html.ep:45 +#: themes/default/templates/layouts/default.html.ep:50 msgid "Homepage" msgstr "Homepage" @@ -221,27 +181,30 @@ msgstr "How to report an image?" msgid "If the files are deleted if you ask it while posting it, their SHA512 footprint are retained." msgstr "If the files are deleted if you ask it while posting it, their SHA512 footprint are retained." -#: themes/default/templates/index.html.ep:163 -#: themes/default/templates/index.html.ep:203 +#: themes/default/templates/index.html.ep:163 themes/default/templates/index.html.ep:203 msgid "Image URL" msgstr "Image URL" -#: lib/Lutim/Command/cron/stats.pm:93 +#: lib/Lutim/Command/cron/stats.pm:143 themes/default/templates/raw.html.ep:2 msgid "Image delay" msgstr "" -#: lib/Lutim/Controller.pm:715 +#: lib/Lutim/Controller.pm:710 msgid "Image not found." msgstr "" -#: themes/default/templates/layouts/default.html.ep:49 +#: themes/default/templates/layouts/default.html.ep:54 msgid "Informations" msgstr "Informations" -#: themes/default/templates/layouts/default.html.ep:55 +#: themes/default/templates/layouts/default.html.ep:62 msgid "Install webapp" msgstr "Install webapp" +#: themes/default/templates/layouts/default.html.ep:61 +msgid "Instance's statistics" +msgstr "" + #: themes/default/templates/about.html.ep:11 msgid "Is it really anonymous?" msgstr "Is it really anonymous?" @@ -254,29 +217,30 @@ msgstr "Is it really free (as in free beer)?" msgid "Juste like you pronounce the French word lutin (/ly.tɛ̃/)." msgstr "Juste like you pronounce the French word lutin (/ly.tɛ̃/)." -#: themes/default/templates/index.html.ep:153 -#: themes/default/templates/index.html.ep:184 +#: themes/default/templates/index.html.ep:153 themes/default/templates/index.html.ep:184 msgid "Keep EXIF tags" msgstr "Keep EXIF tags" -#: themes/default/templates/index.html.ep:118 -#: themes/default/templates/index.html.ep:166 -#: themes/default/templates/index.html.ep:206 -#: themes/default/templates/partial/lutim.js.ep:260 +#: themes/default/templates/index.html.ep:118 themes/default/templates/index.html.ep:166 themes/default/templates/index.html.ep:206 themes/default/templates/partial/lutim.js.ep:163 msgid "Let's go!" msgstr "Let's go!" -#: themes/default/templates/layouts/default.html.ep:48 +#: themes/default/templates/layouts/default.html.ep:58 +msgid "Liberapay button" +msgstr "" + +#: themes/default/templates/layouts/default.html.ep:53 msgid "License:" msgstr "License:" -#: themes/default/templates/index.html.ep:89 -#: themes/default/templates/index.html.ep:91 -#: themes/default/templates/partial/lutim.js.ep:208 -#: themes/default/templates/partial/lutim.js.ep:212 +#: themes/default/templates/index.html.ep:89 themes/default/templates/index.html.ep:91 themes/default/templates/partial/lutim.js.ep:111 themes/default/templates/partial/lutim.js.ep:115 msgid "Link for share on social networks" msgstr "Link for share on social networks" +#: themes/default/templates/zip.html.ep:7 +msgid "Lutim can't zip so many images at once, so it splitted your demand in multiple URLs." +msgstr "" + #: themes/default/templates/about.html.ep:4 msgid "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." msgstr "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." @@ -285,24 +249,19 @@ msgstr "Lutim is a free (as in free beer) and anonymous image hosting service. I msgid "Main developers" msgstr "Main developers" -#: themes/default/templates/index.html.ep:73 -#: themes/default/templates/index.html.ep:75 -#: themes/default/templates/partial/lutim.js.ep:182 -#: themes/default/templates/partial/lutim.js.ep:185 +#: themes/default/templates/index.html.ep:73 themes/default/templates/index.html.ep:75 themes/default/templates/partial/lutim.js.ep:85 themes/default/templates/partial/lutim.js.ep:88 msgid "Markdown syntax" msgstr "Markdown syntax" -#: themes/default/templates/layouts/default.html.ep:54 -#: themes/default/templates/myfiles.html.ep:2 +#: themes/default/templates/layouts/default.html.ep:60 themes/default/templates/myfiles.html.ep:2 msgid "My images" msgstr "" -#: themes/default/templates/myfiles.html.ep:39 +#: themes/default/templates/partial/myfiles.js.ep:19 msgid "No limit" msgstr "" -#: themes/default/templates/index.html.ep:165 -#: themes/default/templates/index.html.ep:198 +#: themes/default/templates/index.html.ep:165 themes/default/templates/index.html.ep:198 msgid "Only images are allowed" msgstr "Only images are allowed" @@ -314,6 +273,10 @@ msgstr "" msgid "Only the uploader! (well, only if he's the only owner of the images' rights before the upload)" msgstr "Only the uploader! (well, only if he's the only owner of the images' rights before the upload)" +#: themes/default/templates/zip.html.ep:12 +msgid "Please click on each URL to download the different zip files." +msgstr "" + #. (config('contact') #: themes/default/templates/about.html.ep:19 msgid "Please contact the administrator: %1" @@ -327,24 +290,31 @@ msgstr "" msgid "Send an image" msgstr "Send an image" -#: themes/default/templates/partial/lutim.js.ep:51 +#: themes/default/templates/partial/lutim.js.ep:20 msgid "Share it!" msgstr "" -#: themes/default/templates/layouts/default.html.ep:51 +#: themes/default/templates/layouts/default.html.ep:56 msgid "Share on Twitter" msgstr "Share on Twitter" -#: themes/default/templates/index.html.ep:133 -#: themes/default/templates/partial/lutim.js.ep:271 +#: themes/default/templates/index.html.ep:133 themes/default/templates/partial/lutim.js.ep:174 msgid "Something bad happened" msgstr "Something bad happened" #. ($c->config('contact') -#: lib/Lutim/Controller.pm:723 +#: lib/Lutim/Controller.pm:717 msgid "Something went wrong when creating the zip file. Try again later or contact the administrator (%1)." msgstr "" +#: themes/default/templates/layouts/default.html.ep:58 +msgid "Support the author on Liberapay" +msgstr "" + +#: themes/default/templates/layouts/default.html.ep:57 +msgid "Support the author on Tipeee" +msgstr "" + #: themes/default/templates/about.html.ep:13 msgid "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)." msgstr "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)." @@ -353,26 +323,27 @@ msgstr "The IP address of the image's sender is retained for a delay which depen msgid "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." msgstr "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." -#: lib/Lutim/Controller.pm:305 +#: lib/Lutim/Controller.pm:307 msgid "The URL is not valid." msgstr "The URL is not valid." -#: lib/Lutim/Controller.pm:117 -#: lib/Lutim/Controller.pm:186 +#: themes/default/templates/zip.html.ep:16 +msgid "The automatic download process will open a tab in your browser for each link. You need to allow popups for Lutim." +msgstr "" + +#: lib/Lutim/Controller.pm:120 lib/Lutim/Controller.pm:188 msgid "The delete token is invalid." msgstr "The delete token is invalid." #. ($upload->filename) -#: lib/Lutim/Controller.pm:449 +#: lib/Lutim/Controller.pm:445 msgid "The file %1 is not an image." msgstr "The file %1 is not an image." -#. ($max_file_size) #. ($tx->res->max_message_size) #. ($c->req->max_message_size) -#: lib/Lutim/Controller.pm:269 -#: lib/Lutim/Controller.pm:338 -#: themes/default/templates/partial/lutim.js.ep:332 +#. (config('max_file_size') +#: lib/Lutim/Controller.pm:271 lib/Lutim/Controller.pm:340 themes/default/templates/partial/lutim.js.ep:240 msgid "The file exceed the size limit (%1)" msgstr "The file exceed the size limit (%1)" @@ -381,17 +352,16 @@ msgid "The graph's datas are not updated in real-time." msgstr "The graph's datas are not updated in real-time." #. ($image->filename) -#: lib/Lutim/Controller.pm:188 +#: lib/Lutim/Controller.pm:190 msgid "The image %1 has already been deleted." msgstr "The image %1 has already been deleted." #. ($image->filename) -#: lib/Lutim/Controller.pm:197 -#: lib/Lutim/Controller.pm:202 +#: lib/Lutim/Controller.pm:199 lib/Lutim/Controller.pm:204 msgid "The image %1 has been successfully deleted" msgstr "The image %1 has been successfully deleted" -#: lib/Lutim/Controller.pm:125 +#: lib/Lutim/Controller.pm:128 msgid "The image's delay has been successfully modified" msgstr "The image's delay has been successfully modified" @@ -404,37 +374,32 @@ msgid "The images you post on Lutim can be stored indefinitely or be deleted at msgstr "The images you post on Lutim can be stored indefinitely or be deleted at first view or after a delay selected from those proposed." #. ($c->config->{contact}) -#: lib/Lutim/Controller.pm:444 +#: lib/Lutim/Controller.pm:442 msgid "There is no more available URL. Retry or contact the administrator. %1" msgstr "There is no more available URL. Retry or contact the administrator. %1" -#: lib/Lutim/Command/cron/stats.pm:102 +#: themes/default/templates/layouts/default.html.ep:57 +msgid "Tipeee button" +msgstr "" + +#: lib/Lutim/Command/cron/stats.pm:152 themes/default/templates/raw.html.ep:11 msgid "Total" msgstr "" -#: themes/default/templates/index.html.ep:60 -#: themes/default/templates/partial/lutim.js.ep:45 +#: themes/default/templates/index.html.ep:60 themes/default/templates/partial/lutim.js.ep:14 msgid "Tweet it!" msgstr "Tweet it!" #. ($short) -#: lib/Lutim/Controller.pm:159 -#: lib/Lutim/Controller.pm:231 +#: lib/Lutim/Controller.pm:162 lib/Lutim/Controller.pm:233 msgid "Unable to find the image %1." msgstr "Unable to find the image %1." -#: lib/Lutim.pm:85 -#: lib/Lutim/Controller.pm:534 -#: lib/Lutim/Controller.pm:580 -#: lib/Lutim/Controller.pm:624 -#: lib/Lutim/Controller.pm:664 -#: lib/Lutim/Controller.pm:676 -#: lib/Lutim/Controller.pm:687 -#: lib/Lutim/Controller.pm:712 +#: lib/Lutim/Controller.pm:529 lib/Lutim/Controller.pm:574 lib/Lutim/Controller.pm:616 lib/Lutim/Controller.pm:659 lib/Lutim/Controller.pm:671 lib/Lutim/Controller.pm:682 lib/Lutim/Controller.pm:707 lib/Lutim/Plugin/Helpers.pm:57 msgid "Unable to find the image: it has been deleted." msgstr "Unable to find the image: it has been deleted." -#: lib/Lutim/Controller.pm:101 +#: lib/Lutim/Controller.pm:105 msgid "Unable to get counter" msgstr "" @@ -442,12 +407,11 @@ msgstr "" msgid "Unlike many image sharing services, you don't give us rights on uploaded images." msgstr "Unlike many image sharing services, you don't give us rights on uploaded images." -#: themes/default/templates/index.html.ep:162 -#: themes/default/templates/index.html.ep:201 +#: themes/default/templates/index.html.ep:162 themes/default/templates/index.html.ep:201 msgid "Upload an image with its URL" msgstr "Upload an image with its URL" -#: themes/default/templates/myfiles.html.ep:17 +#: themes/default/templates/myfiles.html.ep:54 msgid "Uploaded at" msgstr "" @@ -455,16 +419,12 @@ msgstr "" msgid "Uploaded files by days" msgstr "Uploaded files by days" -#. ($config->{contact}) -#: lib/Lutim.pm:189 +#. ($c->app->config('contact') +#: lib/Lutim/Plugin/Helpers.pm:152 msgid "Uploading is currently disabled, please try later or contact the administrator (%1)." msgstr "Uploading is currently disabled, please try later or contact the administrator (%1)." -#: themes/default/templates/index.html.ep:65 -#: themes/default/templates/index.html.ep:67 -#: themes/default/templates/myfiles.html.ep:14 -#: themes/default/templates/partial/lutim.js.ep:168 -#: themes/default/templates/partial/lutim.js.ep:172 +#: themes/default/templates/index.html.ep:65 themes/default/templates/index.html.ep:67 themes/default/templates/myfiles.html.ep:51 themes/default/templates/partial/lutim.js.ep:71 themes/default/templates/partial/lutim.js.ep:75 msgid "View link" msgstr "View link" @@ -484,6 +444,7 @@ msgstr "Who owns rights on images uploaded on Lutim?" msgid "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!" msgstr "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!" +#: msgid "Yes, it is! On the other side, if you want to support the developer, you can do it via Flattr or with BitCoin." msgstr "Yes, it is! On the other side, if you want to support the developer, you can do it via Flattr or with BitCoin." @@ -491,6 +452,10 @@ msgstr "Yes, it is! On the other side, if you want to support the developer, you msgid "Yes, it is! On the other side, if you want to support the developer, you can do it via Tipeee or via Liberapay." msgstr "" +#: themes/default/templates/zip.html.ep:6 +msgid "You asked to download a zip archive for too much files." +msgstr "" + #: themes/default/templates/about.html.ep:8 msgid "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." msgstr "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." @@ -503,10 +468,7 @@ msgstr "and on" msgid "core developer" msgstr "core developer" -#: lib/Lutim/Command/cron/stats.pm:108 -#: lib/Lutim/Command/cron/stats.pm:125 -#: lib/Lutim/Command/cron/stats.pm:97 -#: themes/default/templates/index.html.ep:3 +#: lib/Lutim.pm:190 lib/Lutim/Command/cron/stats.pm:147 lib/Lutim/Command/cron/stats.pm:158 lib/Lutim/Command/cron/stats.pm:175 themes/default/templates/index.html.ep:3 themes/default/templates/raw.html.ep:17 themes/default/templates/raw.html.ep:34 themes/default/templates/raw.html.ep:6 msgid "no time limit" msgstr "no time limit" diff --git a/themes/default/lib/Lutim/I18N/es.po b/themes/default/lib/Lutim/I18N/es.po index 576d5ae..e67ace7 100644 --- a/themes/default/lib/Lutim/I18N/es.po +++ b/themes/default/lib/Lutim/I18N/es.po @@ -18,19 +18,11 @@ msgstr "" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#. ($delay) -#. (config('max_delay') #. (7) #. (30) -#: lib/Lutim/Command/cron/stats.pm:100 -#: lib/Lutim/Command/cron/stats.pm:110 -#: lib/Lutim/Command/cron/stats.pm:111 -#: lib/Lutim/Command/cron/stats.pm:127 -#: lib/Lutim/Command/cron/stats.pm:128 -#: lib/Lutim/Command/cron/stats.pm:99 -#: themes/default/templates/partial/lutim.js.ep:235 -#: themes/default/templates/partial/lutim.js.ep:244 -#: themes/default/templates/partial/lutim.js.ep:245 +#. ($delay) +#. (config('max_delay') +#: lib/Lutim/Command/cron/stats.pm:149 lib/Lutim/Command/cron/stats.pm:150 lib/Lutim/Command/cron/stats.pm:160 lib/Lutim/Command/cron/stats.pm:161 lib/Lutim/Command/cron/stats.pm:177 lib/Lutim/Command/cron/stats.pm:178 themes/default/templates/partial/for_my_delay.html.ep:12 themes/default/templates/partial/for_my_delay.html.ep:13 themes/default/templates/partial/for_my_delay.html.ep:3 themes/default/templates/partial/lutim.js.ep:138 themes/default/templates/partial/lutim.js.ep:147 themes/default/templates/partial/lutim.js.ep:148 themes/default/templates/raw.html.ep:19 themes/default/templates/raw.html.ep:20 themes/default/templates/raw.html.ep:36 themes/default/templates/raw.html.ep:37 themes/default/templates/raw.html.ep:8 themes/default/templates/raw.html.ep:9 msgid "%1 days" msgstr "%1 días" @@ -43,41 +35,35 @@ msgstr "%1 imágenes enviadas a esta instancia desde el inicio." msgid "-or-" msgstr "-o-" -#: lib/Lutim/Command/cron/stats.pm:101 -#: lib/Lutim/Command/cron/stats.pm:112 -#: lib/Lutim/Command/cron/stats.pm:129 -#: themes/default/templates/index.html.ep:5 +#: lib/Lutim.pm:192 lib/Lutim/Command/cron/stats.pm:151 lib/Lutim/Command/cron/stats.pm:162 lib/Lutim/Command/cron/stats.pm:179 themes/default/templates/index.html.ep:5 themes/default/templates/raw.html.ep:10 themes/default/templates/raw.html.ep:21 themes/default/templates/raw.html.ep:38 msgid "1 year" msgstr "1 año" -#: lib/Lutim/Command/cron/stats.pm:109 -#: lib/Lutim/Command/cron/stats.pm:126 -#: lib/Lutim/Command/cron/stats.pm:98 -#: themes/default/templates/index.html.ep:4 -#: themes/default/templates/partial/lutim.js.ep:244 +#: lib/Lutim.pm:191 lib/Lutim/Command/cron/stats.pm:148 lib/Lutim/Command/cron/stats.pm:159 lib/Lutim/Command/cron/stats.pm:176 themes/default/templates/index.html.ep:4 themes/default/templates/partial/for_my_delay.html.ep:12 themes/default/templates/partial/lutim.js.ep:147 themes/default/templates/raw.html.ep:18 themes/default/templates/raw.html.ep:35 themes/default/templates/raw.html.ep:7 msgid "24 hours" msgstr "24 horas" -#: themes/default/templates/myfiles.html.ep:79 +#: themes/default/templates/partial/myfiles.js.ep:57 msgid ": Error while trying to get the counter." msgstr ": Error al intentar obtener el contador." -#: lib/Lutim/Command/cron/stats.pm:94 +#: lib/Lutim/Command/cron/stats.pm:144 themes/default/templates/raw.html.ep:3 msgid "Active images" msgstr "" -#: lib/Lutim/Controller.pm:286 +#: lib/Lutim/Controller.pm:288 msgid "An error occured while downloading the image." msgstr "Error al intentar modificar la imagen." -#: themes/default/templates/about.html.ep:41 -#: themes/default/templates/myfiles.html.ep:27 -#: themes/default/templates/stats.html.ep:25 +#: themes/default/templates/zip.html.ep:2 +msgid "Archives download" +msgstr "" + +#: themes/default/templates/about.html.ep:41 themes/default/templates/myfiles.html.ep:64 themes/default/templates/stats.html.ep:25 msgid "Back to homepage" msgstr "Volver a la página inicial" -#: themes/default/templates/index.html.ep:193 -#: themes/default/templates/index.html.ep:194 +#: themes/default/templates/index.html.ep:193 themes/default/templates/index.html.ep:194 msgid "Click to open the file browser" msgstr "Clic para abrir el explorador de archivos" @@ -85,27 +71,15 @@ msgstr "Clic para abrir el explorador de archivos" msgid "Contributors" msgstr "Contribuidores" -#: themes/default/templates/partial/lutim.js.ep:310 -#: themes/default/templates/partial/lutim.js.ep:359 -#: themes/default/templates/partial/lutim.js.ep:437 +#: themes/default/templates/partial/lutim.js.ep:214 themes/default/templates/partial/lutim.js.ep:268 themes/default/templates/partial/lutim.js.ep:346 msgid "Copy all view links to clipboard" msgstr "Copiar todos los enlaces de visualización al portapapeles" -#: themes/default/templates/index.html.ep:18 -#: themes/default/templates/index.html.ep:36 -#: themes/default/templates/index.html.ep:69 -#: themes/default/templates/index.html.ep:77 -#: themes/default/templates/index.html.ep:85 -#: themes/default/templates/index.html.ep:93 -#: themes/default/templates/partial/common.js.ep:45 -#: themes/default/templates/partial/lutim.js.ep:176 -#: themes/default/templates/partial/lutim.js.ep:188 -#: themes/default/templates/partial/lutim.js.ep:202 -#: themes/default/templates/partial/lutim.js.ep:217 +#: themes/default/templates/index.html.ep:18 themes/default/templates/index.html.ep:36 themes/default/templates/index.html.ep:69 themes/default/templates/index.html.ep:77 themes/default/templates/index.html.ep:85 themes/default/templates/index.html.ep:93 themes/default/templates/myfiles.html.ep:20 themes/default/templates/myfiles.html.ep:38 themes/default/templates/partial/common.js.ep:150 themes/default/templates/partial/lutim.js.ep:105 themes/default/templates/partial/lutim.js.ep:120 themes/default/templates/partial/lutim.js.ep:79 themes/default/templates/partial/lutim.js.ep:91 msgid "Copy to clipboard" msgstr "Copiar al portapapeles" -#: themes/default/templates/myfiles.html.ep:15 +#: themes/default/templates/myfiles.html.ep:52 msgid "Counter" msgstr "Contador" @@ -117,26 +91,19 @@ msgstr "" msgid "Delay repartition chart for enabled images" msgstr "" -#: themes/default/templates/index.html.ep:115 -#: themes/default/templates/index.html.ep:147 -#: themes/default/templates/index.html.ep:178 -#: themes/default/templates/myfiles.html.ep:16 -#: themes/default/templates/partial/lutim.js.ep:256 +#: themes/default/templates/index.html.ep:115 themes/default/templates/index.html.ep:147 themes/default/templates/index.html.ep:178 themes/default/templates/myfiles.html.ep:53 themes/default/templates/partial/lutim.js.ep:159 msgid "Delete at first view?" msgstr "¿Borrar en la primera vista?" -#: lib/Lutim/Command/cron/stats.pm:95 +#: lib/Lutim/Command/cron/stats.pm:145 themes/default/templates/raw.html.ep:4 msgid "Deleted images" msgstr "" -#: lib/Lutim/Command/cron/stats.pm:96 +#: lib/Lutim/Command/cron/stats.pm:146 themes/default/templates/raw.html.ep:5 msgid "Deleted images in 30 days" msgstr "" -#: themes/default/templates/index.html.ep:98 -#: themes/default/templates/myfiles.html.ep:19 -#: themes/default/templates/partial/common.js.ep:37 -#: themes/default/templates/partial/common.js.ep:40 +#: themes/default/templates/index.html.ep:98 themes/default/templates/myfiles.html.ep:56 themes/default/templates/partial/common.js.ep:142 themes/default/templates/partial/common.js.ep:145 msgid "Deletion link" msgstr "Enlace para borrar" @@ -144,15 +111,11 @@ msgstr "Enlace para borrar" msgid "Download all images" msgstr "Descargar todas las imágenes" -#: themes/default/templates/index.html.ep:81 -#: themes/default/templates/index.html.ep:83 -#: themes/default/templates/partial/lutim.js.ep:194 -#: themes/default/templates/partial/lutim.js.ep:198 +#: themes/default/templates/index.html.ep:81 themes/default/templates/index.html.ep:83 themes/default/templates/partial/lutim.js.ep:101 themes/default/templates/partial/lutim.js.ep:97 msgid "Download link" msgstr "Enlace de descarga" -#: themes/default/templates/index.html.ep:28 -#: themes/default/templates/index.html.ep:31 +#: themes/default/templates/index.html.ep:28 themes/default/templates/index.html.ep:31 themes/default/templates/myfiles.html.ep:30 themes/default/templates/myfiles.html.ep:33 msgid "Download zip link" msgstr "Enlace de descarga del archivo de las imágenes" @@ -164,12 +127,11 @@ msgstr "Arrastre y suelte imágenes aquí" msgid "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." msgstr "Arrastre y suelte una imagen en el área apropiada, o use el método tradicional para enviar ficheros, y Lutim proporcionará cuatro URLs. Una para ver la imagen, otra para descargarla directamente, una que upede usar en redes sociales, y una última para borrar la imagen cuando lo desee." -#: themes/default/templates/index.html.ep:150 -#: themes/default/templates/index.html.ep:181 +#: themes/default/templates/index.html.ep:150 themes/default/templates/index.html.ep:181 msgid "Encrypt the image (Lutim does not keep the key)." msgstr "Las imágenes se cifran en el servidor (Lutim no guarda la clave)." -#: themes/default/templates/partial/lutim.js.ep:72 +#: themes/default/templates/partial/lutim.js.ep:44 msgid "Error while trying to modify the image." msgstr "Error al intentar modificar la imagen." @@ -177,11 +139,11 @@ msgstr "Error al intentar modificar la imagen." msgid "Evolution of total files" msgstr "Evolución de archivos en total" -#: themes/default/templates/myfiles.html.ep:18 +#: themes/default/templates/myfiles.html.ep:55 msgid "Expires at" msgstr "Expira" -#: themes/default/templates/myfiles.html.ep:13 +#: themes/default/templates/myfiles.html.ep:50 msgid "File name" msgstr "Nombre de archivo" @@ -189,21 +151,19 @@ msgstr "Nombre de archivo" msgid "For more details, see the homepage of the project." msgstr "Para más detalles, vea la página del proyecto." -#: themes/default/templates/layouts/default.html.ep:50 +#: themes/default/templates/layouts/default.html.ep:55 msgid "Fork me!" msgstr "¡Clóname!" -#: themes/default/templates/index.html.ep:10 -#: themes/default/templates/index.html.ep:13 +#: themes/default/templates/index.html.ep:10 themes/default/templates/index.html.ep:13 themes/default/templates/myfiles.html.ep:12 themes/default/templates/myfiles.html.ep:15 msgid "Gallery link" msgstr "Enlace a la galería" -#: themes/default/templates/partial/lutim.js.ep:125 -#: themes/default/templates/partial/lutim.js.ep:142 +#: themes/default/templates/partial/common.js.ep:104 themes/default/templates/partial/common.js.ep:87 msgid "Hit Ctrl+C, then Enter to copy the short link" msgstr "Presione Ctrl + C, entonces Ingresar para copiar el enlace" -#: themes/default/templates/layouts/default.html.ep:45 +#: themes/default/templates/layouts/default.html.ep:50 msgid "Homepage" msgstr "Página inicial" @@ -223,27 +183,30 @@ msgstr "¿Cómo informar sobre una imagen?" msgid "If the files are deleted if you ask it while posting it, their SHA512 footprint are retained." msgstr "Si los ficheros se borran por haberlo solicitado al enviarlos, se retiene su huella digital SHA512." -#: themes/default/templates/index.html.ep:163 -#: themes/default/templates/index.html.ep:203 +#: themes/default/templates/index.html.ep:163 themes/default/templates/index.html.ep:203 msgid "Image URL" msgstr "URL de la imagen" -#: lib/Lutim/Command/cron/stats.pm:93 +#: lib/Lutim/Command/cron/stats.pm:143 themes/default/templates/raw.html.ep:2 msgid "Image delay" msgstr "" -#: lib/Lutim/Controller.pm:715 +#: lib/Lutim/Controller.pm:710 msgid "Image not found." msgstr "Imagen no encontrada." -#: themes/default/templates/layouts/default.html.ep:49 +#: themes/default/templates/layouts/default.html.ep:54 msgid "Informations" msgstr "Informaciones" -#: themes/default/templates/layouts/default.html.ep:55 +#: themes/default/templates/layouts/default.html.ep:62 msgid "Install webapp" msgstr "Instalar webapp" +#: themes/default/templates/layouts/default.html.ep:61 +msgid "Instance's statistics" +msgstr "" + #: themes/default/templates/about.html.ep:11 msgid "Is it really anonymous?" msgstr "¿Es realmente anónimo?" @@ -256,29 +219,30 @@ msgstr "¿Es realmente gratis?" msgid "Juste like you pronounce the French word lutin (/ly.tɛ̃/)." msgstr "Tal y como se pronuncia la palabra francesa lutin (/ly.tɛ̃/)." -#: themes/default/templates/index.html.ep:153 -#: themes/default/templates/index.html.ep:184 +#: themes/default/templates/index.html.ep:153 themes/default/templates/index.html.ep:184 msgid "Keep EXIF tags" msgstr "Mantener las etiquetas EXIF" -#: themes/default/templates/index.html.ep:118 -#: themes/default/templates/index.html.ep:166 -#: themes/default/templates/index.html.ep:206 -#: themes/default/templates/partial/lutim.js.ep:260 +#: themes/default/templates/index.html.ep:118 themes/default/templates/index.html.ep:166 themes/default/templates/index.html.ep:206 themes/default/templates/partial/lutim.js.ep:163 msgid "Let's go!" msgstr "¡Vamos allá!" -#: themes/default/templates/layouts/default.html.ep:48 +#: themes/default/templates/layouts/default.html.ep:58 +msgid "Liberapay button" +msgstr "" + +#: themes/default/templates/layouts/default.html.ep:53 msgid "License:" msgstr "Licencia:" -#: themes/default/templates/index.html.ep:89 -#: themes/default/templates/index.html.ep:91 -#: themes/default/templates/partial/lutim.js.ep:208 -#: themes/default/templates/partial/lutim.js.ep:212 +#: themes/default/templates/index.html.ep:89 themes/default/templates/index.html.ep:91 themes/default/templates/partial/lutim.js.ep:111 themes/default/templates/partial/lutim.js.ep:115 msgid "Link for share on social networks" msgstr "Enlace para compartir en redes sociales" +#: themes/default/templates/zip.html.ep:7 +msgid "Lutim can't zip so many images at once, so it splitted your demand in multiple URLs." +msgstr "" + #: themes/default/templates/about.html.ep:4 msgid "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." msgstr "Lutim es un servicio de alojamiento de imágenes anónimo y gratuito. También es el nombre del software libre que proporciona este servicio." @@ -287,24 +251,19 @@ msgstr "Lutim es un servicio de alojamiento de imágenes anónimo y gratuito. Ta msgid "Main developers" msgstr "Desarrolladores principales" -#: themes/default/templates/index.html.ep:73 -#: themes/default/templates/index.html.ep:75 -#: themes/default/templates/partial/lutim.js.ep:182 -#: themes/default/templates/partial/lutim.js.ep:185 +#: themes/default/templates/index.html.ep:73 themes/default/templates/index.html.ep:75 themes/default/templates/partial/lutim.js.ep:85 themes/default/templates/partial/lutim.js.ep:88 msgid "Markdown syntax" msgstr "Sintaxis de Markdown" -#: themes/default/templates/layouts/default.html.ep:54 -#: themes/default/templates/myfiles.html.ep:2 +#: themes/default/templates/layouts/default.html.ep:60 themes/default/templates/myfiles.html.ep:2 msgid "My images" msgstr "Mis Imágenes" -#: themes/default/templates/myfiles.html.ep:39 +#: themes/default/templates/partial/myfiles.js.ep:19 msgid "No limit" msgstr "Sin fecha de caducidad" -#: themes/default/templates/index.html.ep:165 -#: themes/default/templates/index.html.ep:198 +#: themes/default/templates/index.html.ep:165 themes/default/templates/index.html.ep:198 msgid "Only images are allowed" msgstr "Sólo se admiten imágenes" @@ -316,6 +275,10 @@ msgstr "Sólo se enumeran aquí las imágenes enviadas con este navegador. Las i msgid "Only the uploader! (well, only if he's the only owner of the images' rights before the upload)" msgstr "¡Sólo el usuario! (bueno, sólo si él/ela es el único titular de los derechos de las imágenes antes de subirlas)" +#: themes/default/templates/zip.html.ep:12 +msgid "Please click on each URL to download the different zip files." +msgstr "" + #. (config('contact') #: themes/default/templates/about.html.ep:19 msgid "Please contact the administrator: %1" @@ -329,24 +292,31 @@ msgstr "" msgid "Send an image" msgstr "Enviar una imagen" -#: themes/default/templates/partial/lutim.js.ep:51 +#: themes/default/templates/partial/lutim.js.ep:20 msgid "Share it!" msgstr "¡Compártelo!" -#: themes/default/templates/layouts/default.html.ep:51 +#: themes/default/templates/layouts/default.html.ep:56 msgid "Share on Twitter" msgstr "Compartir en Twitter" -#: themes/default/templates/index.html.ep:133 -#: themes/default/templates/partial/lutim.js.ep:271 +#: themes/default/templates/index.html.ep:133 themes/default/templates/partial/lutim.js.ep:174 msgid "Something bad happened" msgstr "Algo malo ha pasado" #. ($c->config('contact') -#: lib/Lutim/Controller.pm:723 +#: lib/Lutim/Controller.pm:717 msgid "Something went wrong when creating the zip file. Try again later or contact the administrator (%1)." msgstr "Algo malo ha pasado. Inténtelo de nuevo más tarde o contacte con el administrador (%1)." +#: themes/default/templates/layouts/default.html.ep:58 +msgid "Support the author on Liberapay" +msgstr "" + +#: themes/default/templates/layouts/default.html.ep:57 +msgid "Support the author on Tipeee" +msgstr "" + #: themes/default/templates/about.html.ep:13 msgid "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)." msgstr "La dirección IP del remitente de la imagen se retiene durante un tiempo, que depende de lo que elija el administrador (para la instancia oficial, que está localizada en Francia, es un año)." @@ -355,26 +325,27 @@ msgstr "La dirección IP del remitente de la imagen se retiene durante un tiempo msgid "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." msgstr "El software Lutim es software libre, lo que le permite descargarlo e instalarlo en su propio servidor. Eche un vistazo a la licencia AGPL para ver qué puede hacer." -#: lib/Lutim/Controller.pm:305 +#: lib/Lutim/Controller.pm:307 msgid "The URL is not valid." msgstr "La URL no es válida." -#: lib/Lutim/Controller.pm:117 -#: lib/Lutim/Controller.pm:186 +#: themes/default/templates/zip.html.ep:16 +msgid "The automatic download process will open a tab in your browser for each link. You need to allow popups for Lutim." +msgstr "" + +#: lib/Lutim/Controller.pm:120 lib/Lutim/Controller.pm:188 msgid "The delete token is invalid." msgstr "El código de borrado no es válido." #. ($upload->filename) -#: lib/Lutim/Controller.pm:449 +#: lib/Lutim/Controller.pm:445 msgid "The file %1 is not an image." msgstr "El archivo %1 no es una imagen." -#. ($max_file_size) #. ($tx->res->max_message_size) #. ($c->req->max_message_size) -#: lib/Lutim/Controller.pm:269 -#: lib/Lutim/Controller.pm:338 -#: themes/default/templates/partial/lutim.js.ep:332 +#. (config('max_file_size') +#: lib/Lutim/Controller.pm:271 lib/Lutim/Controller.pm:340 themes/default/templates/partial/lutim.js.ep:240 msgid "The file exceed the size limit (%1)" msgstr "El archivo supera el límite de tamaño (%1)" @@ -383,17 +354,16 @@ msgid "The graph's datas are not updated in real-time." msgstr "Los datos del gráfico no se actualizan en tiempo real." #. ($image->filename) -#: lib/Lutim/Controller.pm:188 +#: lib/Lutim/Controller.pm:190 msgid "The image %1 has already been deleted." msgstr "La imagen %1 ya se ha borrado." #. ($image->filename) -#: lib/Lutim/Controller.pm:197 -#: lib/Lutim/Controller.pm:202 +#: lib/Lutim/Controller.pm:199 lib/Lutim/Controller.pm:204 msgid "The image %1 has been successfully deleted" msgstr "La imagen %1 se ha borrado correctamente" -#: lib/Lutim/Controller.pm:125 +#: lib/Lutim/Controller.pm:128 msgid "The image's delay has been successfully modified" msgstr "Se ha modificado correctamente el tiempo de la imagen" @@ -406,37 +376,32 @@ msgid "The images you post on Lutim can be stored indefinitely or be deleted at msgstr "Puede, opcionalmente, solicitar que la imagen publicada en Lutim se elimine con la primera vista (o descarga) o tras un tiempo seleccionado de entre varios propuestos." #. ($c->config->{contact}) -#: lib/Lutim/Controller.pm:444 +#: lib/Lutim/Controller.pm:442 msgid "There is no more available URL. Retry or contact the administrator. %1" msgstr "No más URL disponibles. Inténtelo de nuevo o contacte con el administrador. %1" -#: lib/Lutim/Command/cron/stats.pm:102 +#: themes/default/templates/layouts/default.html.ep:57 +msgid "Tipeee button" +msgstr "" + +#: lib/Lutim/Command/cron/stats.pm:152 themes/default/templates/raw.html.ep:11 msgid "Total" msgstr "" -#: themes/default/templates/index.html.ep:60 -#: themes/default/templates/partial/lutim.js.ep:45 +#: themes/default/templates/index.html.ep:60 themes/default/templates/partial/lutim.js.ep:14 msgid "Tweet it!" msgstr "¡Tuitéalo!" #. ($short) -#: lib/Lutim/Controller.pm:159 -#: lib/Lutim/Controller.pm:231 +#: lib/Lutim/Controller.pm:162 lib/Lutim/Controller.pm:233 msgid "Unable to find the image %1." msgstr "No se ha podido encontrar la imagen %1." -#: lib/Lutim.pm:85 -#: lib/Lutim/Controller.pm:534 -#: lib/Lutim/Controller.pm:580 -#: lib/Lutim/Controller.pm:624 -#: lib/Lutim/Controller.pm:664 -#: lib/Lutim/Controller.pm:676 -#: lib/Lutim/Controller.pm:687 -#: lib/Lutim/Controller.pm:712 +#: lib/Lutim/Controller.pm:529 lib/Lutim/Controller.pm:574 lib/Lutim/Controller.pm:616 lib/Lutim/Controller.pm:659 lib/Lutim/Controller.pm:671 lib/Lutim/Controller.pm:682 lib/Lutim/Controller.pm:707 lib/Lutim/Plugin/Helpers.pm:57 msgid "Unable to find the image: it has been deleted." msgstr "No se ha podido encontrar la imagen: ha sido borrada." -#: lib/Lutim/Controller.pm:101 +#: lib/Lutim/Controller.pm:105 msgid "Unable to get counter" msgstr "Imposible recuperar el contador" @@ -444,12 +409,11 @@ msgstr "Imposible recuperar el contador" msgid "Unlike many image sharing services, you don't give us rights on uploaded images." msgstr "A diferencia de muchos servicios de compartición de imágenes, usted no cede los derechos de las imágenes que sube." -#: themes/default/templates/index.html.ep:162 -#: themes/default/templates/index.html.ep:201 +#: themes/default/templates/index.html.ep:162 themes/default/templates/index.html.ep:201 msgid "Upload an image with its URL" msgstr "Subir una imagen con la URL" -#: themes/default/templates/myfiles.html.ep:17 +#: themes/default/templates/myfiles.html.ep:54 msgid "Uploaded at" msgstr "Enviado el" @@ -457,16 +421,12 @@ msgstr "Enviado el" msgid "Uploaded files by days" msgstr "Archivos enviados por día" -#. ($config->{contact}) -#: lib/Lutim.pm:189 +#. ($c->app->config('contact') +#: lib/Lutim/Plugin/Helpers.pm:152 msgid "Uploading is currently disabled, please try later or contact the administrator (%1)." msgstr "La carga está deshabilitada en estos momentos, por favor inténtelo más tarde o contacte con el administrador (%1)." -#: themes/default/templates/index.html.ep:65 -#: themes/default/templates/index.html.ep:67 -#: themes/default/templates/myfiles.html.ep:14 -#: themes/default/templates/partial/lutim.js.ep:168 -#: themes/default/templates/partial/lutim.js.ep:172 +#: themes/default/templates/index.html.ep:65 themes/default/templates/index.html.ep:67 themes/default/templates/myfiles.html.ep:51 themes/default/templates/partial/lutim.js.ep:71 themes/default/templates/partial/lutim.js.ep:75 msgid "View link" msgstr "Enlace de visualización" @@ -490,6 +450,10 @@ msgstr "¡Sí, lo es! Por otro lado, por razones legales, se almacena la direcci msgid "Yes, it is! On the other side, if you want to support the developer, you can do it via Tipeee or via Liberapay." msgstr "¡Sí, lo es! Por otro lado, si quiere ayudar a apoyar al desarrollador, puede hacerlo vía Tipeee o con Liberapay." +#: themes/default/templates/zip.html.ep:6 +msgid "You asked to download a zip archive for too much files." +msgstr "" + #: themes/default/templates/about.html.ep:8 msgid "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." msgstr "Puede, opcionalmente, solicitar que la imagen publicada en Lutim se elimine con la primera vista (o descarga) o tras un tiempo seleccionado de entre varios propuestos." @@ -502,10 +466,7 @@ msgstr "y en" msgid "core developer" msgstr "desarrollador principal" -#: lib/Lutim/Command/cron/stats.pm:108 -#: lib/Lutim/Command/cron/stats.pm:125 -#: lib/Lutim/Command/cron/stats.pm:97 -#: themes/default/templates/index.html.ep:3 +#: lib/Lutim.pm:190 lib/Lutim/Command/cron/stats.pm:147 lib/Lutim/Command/cron/stats.pm:158 lib/Lutim/Command/cron/stats.pm:175 themes/default/templates/index.html.ep:3 themes/default/templates/raw.html.ep:17 themes/default/templates/raw.html.ep:34 themes/default/templates/raw.html.ep:6 msgid "no time limit" msgstr "Sin tiempo límite" diff --git a/themes/default/lib/Lutim/I18N/fr.po b/themes/default/lib/Lutim/I18N/fr.po index b3b2108..d48b123 100644 --- a/themes/default/lib/Lutim/I18N/fr.po +++ b/themes/default/lib/Lutim/I18N/fr.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Lutim\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" -"PO-Revision-Date: 2015-09-17 22:02+0000\n" +"PO-Revision-Date: 2017-06-05 15:54+0000\n" "Last-Translator: Luc Didry \n" "Language-Team: French (http://www.transifex.com/fiat-tux/lutim/language/fr/)\n" "MIME-Version: 1.0\n" @@ -18,19 +18,11 @@ msgstr "" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#. ($delay) -#. (config('max_delay') #. (7) #. (30) -#: lib/Lutim/Command/cron/stats.pm:100 -#: lib/Lutim/Command/cron/stats.pm:110 -#: lib/Lutim/Command/cron/stats.pm:111 -#: lib/Lutim/Command/cron/stats.pm:127 -#: lib/Lutim/Command/cron/stats.pm:128 -#: lib/Lutim/Command/cron/stats.pm:99 -#: themes/default/templates/partial/lutim.js.ep:235 -#: themes/default/templates/partial/lutim.js.ep:244 -#: themes/default/templates/partial/lutim.js.ep:245 +#. ($delay) +#. (config('max_delay') +#: lib/Lutim/Command/cron/stats.pm:149 lib/Lutim/Command/cron/stats.pm:150 lib/Lutim/Command/cron/stats.pm:160 lib/Lutim/Command/cron/stats.pm:161 lib/Lutim/Command/cron/stats.pm:177 lib/Lutim/Command/cron/stats.pm:178 themes/default/templates/partial/for_my_delay.html.ep:12 themes/default/templates/partial/for_my_delay.html.ep:13 themes/default/templates/partial/for_my_delay.html.ep:3 themes/default/templates/partial/lutim.js.ep:138 themes/default/templates/partial/lutim.js.ep:147 themes/default/templates/partial/lutim.js.ep:148 themes/default/templates/raw.html.ep:19 themes/default/templates/raw.html.ep:20 themes/default/templates/raw.html.ep:36 themes/default/templates/raw.html.ep:37 themes/default/templates/raw.html.ep:8 themes/default/templates/raw.html.ep:9 msgid "%1 days" msgstr "%1 jours" @@ -43,41 +35,35 @@ msgstr "%1 images envoyées sur cette instance depuis le début." msgid "-or-" msgstr "-ou-" -#: lib/Lutim/Command/cron/stats.pm:101 -#: lib/Lutim/Command/cron/stats.pm:112 -#: lib/Lutim/Command/cron/stats.pm:129 -#: themes/default/templates/index.html.ep:5 +#: lib/Lutim.pm:192 lib/Lutim/Command/cron/stats.pm:151 lib/Lutim/Command/cron/stats.pm:162 lib/Lutim/Command/cron/stats.pm:179 themes/default/templates/index.html.ep:5 themes/default/templates/raw.html.ep:10 themes/default/templates/raw.html.ep:21 themes/default/templates/raw.html.ep:38 msgid "1 year" msgstr "1 an" -#: lib/Lutim/Command/cron/stats.pm:109 -#: lib/Lutim/Command/cron/stats.pm:126 -#: lib/Lutim/Command/cron/stats.pm:98 -#: themes/default/templates/index.html.ep:4 -#: themes/default/templates/partial/lutim.js.ep:244 +#: lib/Lutim.pm:191 lib/Lutim/Command/cron/stats.pm:148 lib/Lutim/Command/cron/stats.pm:159 lib/Lutim/Command/cron/stats.pm:176 themes/default/templates/index.html.ep:4 themes/default/templates/partial/for_my_delay.html.ep:12 themes/default/templates/partial/lutim.js.ep:147 themes/default/templates/raw.html.ep:18 themes/default/templates/raw.html.ep:35 themes/default/templates/raw.html.ep:7 msgid "24 hours" msgstr "24 heures" -#: themes/default/templates/myfiles.html.ep:79 +#: themes/default/templates/partial/myfiles.js.ep:57 msgid ": Error while trying to get the counter." msgstr " : Erreur en essayant de récupérer le compteur." -#: lib/Lutim/Command/cron/stats.pm:94 +#: lib/Lutim/Command/cron/stats.pm:144 themes/default/templates/raw.html.ep:3 msgid "Active images" msgstr "Images actives" -#: lib/Lutim/Controller.pm:286 +#: lib/Lutim/Controller.pm:288 msgid "An error occured while downloading the image." msgstr "Une erreur est survenue lors du téléchargement de l’image." -#: themes/default/templates/about.html.ep:41 -#: themes/default/templates/myfiles.html.ep:27 -#: themes/default/templates/stats.html.ep:25 +#: themes/default/templates/zip.html.ep:2 +msgid "Archives download" +msgstr "Téléchargement d’archives" + +#: themes/default/templates/about.html.ep:41 themes/default/templates/myfiles.html.ep:64 themes/default/templates/stats.html.ep:25 msgid "Back to homepage" msgstr "Retour à la page d’accueil" -#: themes/default/templates/index.html.ep:193 -#: themes/default/templates/index.html.ep:194 +#: themes/default/templates/index.html.ep:193 themes/default/templates/index.html.ep:194 msgid "Click to open the file browser" msgstr "Cliquez pour utiliser le navigateur de fichier" @@ -85,27 +71,15 @@ msgstr "Cliquez pour utiliser le navigateur de fichier" msgid "Contributors" msgstr "Contributeurs" -#: themes/default/templates/partial/lutim.js.ep:310 -#: themes/default/templates/partial/lutim.js.ep:359 -#: themes/default/templates/partial/lutim.js.ep:437 +#: themes/default/templates/partial/lutim.js.ep:214 themes/default/templates/partial/lutim.js.ep:268 themes/default/templates/partial/lutim.js.ep:346 msgid "Copy all view links to clipboard" msgstr "Copier tous les liens de visualisation dans le presse-papier" -#: themes/default/templates/index.html.ep:18 -#: themes/default/templates/index.html.ep:36 -#: themes/default/templates/index.html.ep:69 -#: themes/default/templates/index.html.ep:77 -#: themes/default/templates/index.html.ep:85 -#: themes/default/templates/index.html.ep:93 -#: themes/default/templates/partial/common.js.ep:45 -#: themes/default/templates/partial/lutim.js.ep:176 -#: themes/default/templates/partial/lutim.js.ep:188 -#: themes/default/templates/partial/lutim.js.ep:202 -#: themes/default/templates/partial/lutim.js.ep:217 +#: themes/default/templates/index.html.ep:18 themes/default/templates/index.html.ep:36 themes/default/templates/index.html.ep:69 themes/default/templates/index.html.ep:77 themes/default/templates/index.html.ep:85 themes/default/templates/index.html.ep:93 themes/default/templates/myfiles.html.ep:20 themes/default/templates/myfiles.html.ep:38 themes/default/templates/partial/common.js.ep:150 themes/default/templates/partial/lutim.js.ep:105 themes/default/templates/partial/lutim.js.ep:120 themes/default/templates/partial/lutim.js.ep:79 themes/default/templates/partial/lutim.js.ep:91 msgid "Copy to clipboard" msgstr "Copier dans le presse-papier" -#: themes/default/templates/myfiles.html.ep:15 +#: themes/default/templates/myfiles.html.ep:52 msgid "Counter" msgstr "Compteur" @@ -117,26 +91,19 @@ msgstr "Graphe de répartition des délais pour les images supprimées" msgid "Delay repartition chart for enabled images" msgstr "Graphe de répartition des délais pour les images actives" -#: themes/default/templates/index.html.ep:115 -#: themes/default/templates/index.html.ep:147 -#: themes/default/templates/index.html.ep:178 -#: themes/default/templates/myfiles.html.ep:16 -#: themes/default/templates/partial/lutim.js.ep:256 +#: themes/default/templates/index.html.ep:115 themes/default/templates/index.html.ep:147 themes/default/templates/index.html.ep:178 themes/default/templates/myfiles.html.ep:53 themes/default/templates/partial/lutim.js.ep:159 msgid "Delete at first view?" msgstr "Supprimer au premier accès ?" -#: lib/Lutim/Command/cron/stats.pm:95 +#: lib/Lutim/Command/cron/stats.pm:145 themes/default/templates/raw.html.ep:4 msgid "Deleted images" msgstr "Images supprimées" -#: lib/Lutim/Command/cron/stats.pm:96 +#: lib/Lutim/Command/cron/stats.pm:146 themes/default/templates/raw.html.ep:5 msgid "Deleted images in 30 days" msgstr "Images supprimées dans 30 jours" -#: themes/default/templates/index.html.ep:98 -#: themes/default/templates/myfiles.html.ep:19 -#: themes/default/templates/partial/common.js.ep:37 -#: themes/default/templates/partial/common.js.ep:40 +#: themes/default/templates/index.html.ep:98 themes/default/templates/myfiles.html.ep:56 themes/default/templates/partial/common.js.ep:142 themes/default/templates/partial/common.js.ep:145 msgid "Deletion link" msgstr "Lien de suppression" @@ -144,15 +111,11 @@ msgstr "Lien de suppression" msgid "Download all images" msgstr "Télécharger toutes les images" -#: themes/default/templates/index.html.ep:81 -#: themes/default/templates/index.html.ep:83 -#: themes/default/templates/partial/lutim.js.ep:194 -#: themes/default/templates/partial/lutim.js.ep:198 +#: themes/default/templates/index.html.ep:81 themes/default/templates/index.html.ep:83 themes/default/templates/partial/lutim.js.ep:101 themes/default/templates/partial/lutim.js.ep:97 msgid "Download link" msgstr "Lien de téléchargement" -#: themes/default/templates/index.html.ep:28 -#: themes/default/templates/index.html.ep:31 +#: themes/default/templates/index.html.ep:28 themes/default/templates/index.html.ep:31 themes/default/templates/myfiles.html.ep:30 themes/default/templates/myfiles.html.ep:33 msgid "Download zip link" msgstr "Lien de téléchargement de l’archive des images" @@ -164,12 +127,11 @@ msgstr "Déposez vos images ici" msgid "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." msgstr "Faites glisser des images dans la zone prévue à cet effet ou sélectionnez un fichier de façon classique et Lutim vous fournira quatre URLs en retour. Une pour afficher l’image, une autre pour la télécharger directement, une pour l’utiliser sur les réseaux sociaux et une dernière pour supprimer votre image quand vous le souhaitez" -#: themes/default/templates/index.html.ep:150 -#: themes/default/templates/index.html.ep:181 +#: themes/default/templates/index.html.ep:150 themes/default/templates/index.html.ep:181 msgid "Encrypt the image (Lutim does not keep the key)." msgstr "Chiffrer l’image (Lutim ne stocke pas la clé)." -#: themes/default/templates/partial/lutim.js.ep:72 +#: themes/default/templates/partial/lutim.js.ep:44 msgid "Error while trying to modify the image." msgstr "Une erreur est survenue en essayant de modifier l’image." @@ -177,11 +139,11 @@ msgstr "Une erreur est survenue en essayant de modifier l’image." msgid "Evolution of total files" msgstr "Évolution du nombre total de fichiers" -#: themes/default/templates/myfiles.html.ep:18 +#: themes/default/templates/myfiles.html.ep:55 msgid "Expires at" msgstr "Expire le" -#: themes/default/templates/myfiles.html.ep:13 +#: themes/default/templates/myfiles.html.ep:50 msgid "File name" msgstr "Nom du fichier" @@ -189,21 +151,19 @@ msgstr "Nom du fichier" msgid "For more details, see the homepage of the project." msgstr "Pour plus de détails, consultez la page Github du projet." -#: themes/default/templates/layouts/default.html.ep:50 +#: themes/default/templates/layouts/default.html.ep:55 msgid "Fork me!" msgstr "Créez un fork !" -#: themes/default/templates/index.html.ep:10 -#: themes/default/templates/index.html.ep:13 +#: themes/default/templates/index.html.ep:10 themes/default/templates/index.html.ep:13 themes/default/templates/myfiles.html.ep:12 themes/default/templates/myfiles.html.ep:15 msgid "Gallery link" msgstr "Lien vers la galerie" -#: themes/default/templates/partial/lutim.js.ep:125 -#: themes/default/templates/partial/lutim.js.ep:142 +#: themes/default/templates/partial/common.js.ep:104 themes/default/templates/partial/common.js.ep:87 msgid "Hit Ctrl+C, then Enter to copy the short link" msgstr "Faites Ctrl+C puis appuyez sur la touche Entrée pour copier le lien" -#: themes/default/templates/layouts/default.html.ep:45 +#: themes/default/templates/layouts/default.html.ep:50 msgid "Homepage" msgstr "Accueil" @@ -223,27 +183,30 @@ msgstr "Comment peut-on faire pour signaler une image ?" msgid "If the files are deleted if you ask it while posting it, their SHA512 footprint are retained." msgstr "Si les fichiers sont bien supprimés si vous en avez exprimé le choix, leur empreinte SHA512 est toutefois conservée." -#: themes/default/templates/index.html.ep:163 -#: themes/default/templates/index.html.ep:203 +#: themes/default/templates/index.html.ep:163 themes/default/templates/index.html.ep:203 msgid "Image URL" msgstr "URL de l’image" -#: lib/Lutim/Command/cron/stats.pm:93 +#: lib/Lutim/Command/cron/stats.pm:143 themes/default/templates/raw.html.ep:2 msgid "Image delay" msgstr "Durée de rétention de l’image" -#: lib/Lutim/Controller.pm:715 +#: lib/Lutim/Controller.pm:710 msgid "Image not found." msgstr "Image non trouvée." -#: themes/default/templates/layouts/default.html.ep:49 +#: themes/default/templates/layouts/default.html.ep:54 msgid "Informations" msgstr "Informations" -#: themes/default/templates/layouts/default.html.ep:55 +#: themes/default/templates/layouts/default.html.ep:62 msgid "Install webapp" msgstr "Installer la webapp" +#: themes/default/templates/layouts/default.html.ep:61 +msgid "Instance's statistics" +msgstr "Statistiques de l’instance" + #: themes/default/templates/about.html.ep:11 msgid "Is it really anonymous?" msgstr "C’est vraiment anonyme ?" @@ -256,29 +219,30 @@ msgstr "C’est vraiment gratuit ?" msgid "Juste like you pronounce the French word lutin (/ly.tɛ̃/)." msgstr "Comme on prononce lutin (/ly.tɛ̃/)." -#: themes/default/templates/index.html.ep:153 -#: themes/default/templates/index.html.ep:184 +#: themes/default/templates/index.html.ep:153 themes/default/templates/index.html.ep:184 msgid "Keep EXIF tags" msgstr "Conserver les données EXIF" -#: themes/default/templates/index.html.ep:118 -#: themes/default/templates/index.html.ep:166 -#: themes/default/templates/index.html.ep:206 -#: themes/default/templates/partial/lutim.js.ep:260 +#: themes/default/templates/index.html.ep:118 themes/default/templates/index.html.ep:166 themes/default/templates/index.html.ep:206 themes/default/templates/partial/lutim.js.ep:163 msgid "Let's go!" msgstr "Allons-y !" -#: themes/default/templates/layouts/default.html.ep:48 +#: themes/default/templates/layouts/default.html.ep:58 +msgid "Liberapay button" +msgstr "Bouton Liberapay" + +#: themes/default/templates/layouts/default.html.ep:53 msgid "License:" msgstr "Licence :" -#: themes/default/templates/index.html.ep:89 -#: themes/default/templates/index.html.ep:91 -#: themes/default/templates/partial/lutim.js.ep:208 -#: themes/default/templates/partial/lutim.js.ep:212 +#: themes/default/templates/index.html.ep:89 themes/default/templates/index.html.ep:91 themes/default/templates/partial/lutim.js.ep:111 themes/default/templates/partial/lutim.js.ep:115 msgid "Link for share on social networks" msgstr "Lien pour partager sur les réseaux sociaux" +#: themes/default/templates/zip.html.ep:7 +msgid "Lutim can't zip so many images at once, so it splitted your demand in multiple URLs." +msgstr "Lutim ne peut zipper autant d’images à la fois, votre demande a donc été découpée en plusieurs URL." + #: themes/default/templates/about.html.ep:4 msgid "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." msgstr "Lutim est un service gratuit et anonyme d’hébergement d’images. Il s’agit aussi du nom du logiciel (libre) qui fournit ce service." @@ -287,24 +251,19 @@ msgstr "Lutim est un service gratuit et anonyme d’hébergement d’images. Il msgid "Main developers" msgstr "Développeurs de l’application" -#: themes/default/templates/index.html.ep:73 -#: themes/default/templates/index.html.ep:75 -#: themes/default/templates/partial/lutim.js.ep:182 -#: themes/default/templates/partial/lutim.js.ep:185 +#: themes/default/templates/index.html.ep:73 themes/default/templates/index.html.ep:75 themes/default/templates/partial/lutim.js.ep:85 themes/default/templates/partial/lutim.js.ep:88 msgid "Markdown syntax" msgstr "Syntaxe Markdown" -#: themes/default/templates/layouts/default.html.ep:54 -#: themes/default/templates/myfiles.html.ep:2 +#: themes/default/templates/layouts/default.html.ep:60 themes/default/templates/myfiles.html.ep:2 msgid "My images" msgstr "Mes images" -#: themes/default/templates/myfiles.html.ep:39 +#: themes/default/templates/partial/myfiles.js.ep:19 msgid "No limit" msgstr "Pas de date d’expiration" -#: themes/default/templates/index.html.ep:165 -#: themes/default/templates/index.html.ep:198 +#: themes/default/templates/index.html.ep:165 themes/default/templates/index.html.ep:198 msgid "Only images are allowed" msgstr "Seules les images sont acceptées" @@ -316,6 +275,10 @@ msgstr "Seules les images envoyées avec ce navigateur seront listées ici. Les msgid "Only the uploader! (well, only if he's the only owner of the images' rights before the upload)" msgstr "Seulement l’envoyeur ! (enfin, seulement s’il possède des droits exclusifs sur les images avant de les envoyer)" +#: themes/default/templates/zip.html.ep:12 +msgid "Please click on each URL to download the different zip files." +msgstr "Veuillez cliquer sur chaque URL pour télécharger les différents fichiers zip." + #. (config('contact') #: themes/default/templates/about.html.ep:19 msgid "Please contact the administrator: %1" @@ -329,24 +292,31 @@ msgstr "Statistiques brutes" msgid "Send an image" msgstr "Envoyer une image" -#: themes/default/templates/partial/lutim.js.ep:51 +#: themes/default/templates/partial/lutim.js.ep:20 msgid "Share it!" msgstr "Partagez !" -#: themes/default/templates/layouts/default.html.ep:51 +#: themes/default/templates/layouts/default.html.ep:56 msgid "Share on Twitter" msgstr "Partager sur Twitter" -#: themes/default/templates/index.html.ep:133 -#: themes/default/templates/partial/lutim.js.ep:271 +#: themes/default/templates/index.html.ep:133 themes/default/templates/partial/lutim.js.ep:174 msgid "Something bad happened" msgstr "Un problème est survenu" #. ($c->config('contact') -#: lib/Lutim/Controller.pm:723 +#: lib/Lutim/Controller.pm:717 msgid "Something went wrong when creating the zip file. Try again later or contact the administrator (%1)." msgstr "Quelque chose s’est mal passé lors de la création de l’archive. Veuillez réessayer plus tard ou contactez l’administrateur (%1)." +#: themes/default/templates/layouts/default.html.ep:58 +msgid "Support the author on Liberapay" +msgstr "Supporter l’auteur sur Liberapay" + +#: themes/default/templates/layouts/default.html.ep:57 +msgid "Support the author on Tipeee" +msgstr "Supporter l’auteur sur Tipeee" + #: themes/default/templates/about.html.ep:13 msgid "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)." msgstr "" @@ -357,26 +327,27 @@ msgstr "" msgid "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." msgstr "Le logiciel Lutim est un logiciel libre, ce qui vous permet de le télécharger et de l’installer sur votre propre serveur. Jetez un coup d’œil à l’AGPL pour voir quels sont vos droits" -#: lib/Lutim/Controller.pm:305 +#: lib/Lutim/Controller.pm:307 msgid "The URL is not valid." msgstr "L’URL n’est pas valide." -#: lib/Lutim/Controller.pm:117 -#: lib/Lutim/Controller.pm:186 +#: themes/default/templates/zip.html.ep:16 +msgid "The automatic download process will open a tab in your browser for each link. You need to allow popups for Lutim." +msgstr "Le processus de téléchargement automatique va ouvrir un onglet dans votre navigateur pour chaque lien. Vous devez autoriser les fenêtres popup pour Lutim." + +#: lib/Lutim/Controller.pm:120 lib/Lutim/Controller.pm:188 msgid "The delete token is invalid." msgstr "Le jeton de suppression est invalide." #. ($upload->filename) -#: lib/Lutim/Controller.pm:449 +#: lib/Lutim/Controller.pm:445 msgid "The file %1 is not an image." msgstr "Le fichier %1 n’est pas une image." -#. ($max_file_size) #. ($tx->res->max_message_size) #. ($c->req->max_message_size) -#: lib/Lutim/Controller.pm:269 -#: lib/Lutim/Controller.pm:338 -#: themes/default/templates/partial/lutim.js.ep:332 +#. (config('max_file_size') +#: lib/Lutim/Controller.pm:271 lib/Lutim/Controller.pm:340 themes/default/templates/partial/lutim.js.ep:240 msgid "The file exceed the size limit (%1)" msgstr "Le fichier dépasse la limite de taille (%1)" @@ -385,17 +356,16 @@ msgid "The graph's datas are not updated in real-time." msgstr "Les données du graphique ne sont pas mises à jour en temps réél." #. ($image->filename) -#: lib/Lutim/Controller.pm:188 +#: lib/Lutim/Controller.pm:190 msgid "The image %1 has already been deleted." msgstr "L’image %1 a déjà été supprimée." #. ($image->filename) -#: lib/Lutim/Controller.pm:197 -#: lib/Lutim/Controller.pm:202 +#: lib/Lutim/Controller.pm:199 lib/Lutim/Controller.pm:204 msgid "The image %1 has been successfully deleted" msgstr "L’image %1 a été supprimée avec succès." -#: lib/Lutim/Controller.pm:125 +#: lib/Lutim/Controller.pm:128 msgid "The image's delay has been successfully modified" msgstr "Le délai de l’image a été modifié avec succès." @@ -408,37 +378,32 @@ msgid "The images you post on Lutim can be stored indefinitely or be deleted at msgstr "Les images déposées sur Lutim peuvent être stockées indéfiniment, ou s’effacer dès le premier affichage ou au bout du délai choisi parmi ceux proposés." #. ($c->config->{contact}) -#: lib/Lutim/Controller.pm:444 +#: lib/Lutim/Controller.pm:442 msgid "There is no more available URL. Retry or contact the administrator. %1" msgstr "Il n’y a plus d’URL disponible. Veuillez réessayer ou contacter l’administrateur. %1." -#: lib/Lutim/Command/cron/stats.pm:102 +#: themes/default/templates/layouts/default.html.ep:57 +msgid "Tipeee button" +msgstr "Bouton Tipeee" + +#: lib/Lutim/Command/cron/stats.pm:152 themes/default/templates/raw.html.ep:11 msgid "Total" msgstr "Total" -#: themes/default/templates/index.html.ep:60 -#: themes/default/templates/partial/lutim.js.ep:45 +#: themes/default/templates/index.html.ep:60 themes/default/templates/partial/lutim.js.ep:14 msgid "Tweet it!" msgstr "Tweetez !" #. ($short) -#: lib/Lutim/Controller.pm:159 -#: lib/Lutim/Controller.pm:231 +#: lib/Lutim/Controller.pm:162 lib/Lutim/Controller.pm:233 msgid "Unable to find the image %1." msgstr "Impossible de trouver l’image %1." -#: lib/Lutim.pm:85 -#: lib/Lutim/Controller.pm:534 -#: lib/Lutim/Controller.pm:580 -#: lib/Lutim/Controller.pm:624 -#: lib/Lutim/Controller.pm:664 -#: lib/Lutim/Controller.pm:676 -#: lib/Lutim/Controller.pm:687 -#: lib/Lutim/Controller.pm:712 +#: lib/Lutim/Controller.pm:529 lib/Lutim/Controller.pm:574 lib/Lutim/Controller.pm:616 lib/Lutim/Controller.pm:659 lib/Lutim/Controller.pm:671 lib/Lutim/Controller.pm:682 lib/Lutim/Controller.pm:707 lib/Lutim/Plugin/Helpers.pm:57 msgid "Unable to find the image: it has been deleted." msgstr "Impossible de trouver l’image : elle a été supprimée." -#: lib/Lutim/Controller.pm:101 +#: lib/Lutim/Controller.pm:105 msgid "Unable to get counter" msgstr "Impossible de récupérer le compteur" @@ -446,12 +411,11 @@ msgstr "Impossible de récupérer le compteur" msgid "Unlike many image sharing services, you don't give us rights on uploaded images." msgstr "Au contraire de la majorité des services de partages d’image, vous ne nous cédez aucun droit sur les images envoyées." -#: themes/default/templates/index.html.ep:162 -#: themes/default/templates/index.html.ep:201 +#: themes/default/templates/index.html.ep:162 themes/default/templates/index.html.ep:201 msgid "Upload an image with its URL" msgstr "Déposer une image par son URL" -#: themes/default/templates/myfiles.html.ep:17 +#: themes/default/templates/myfiles.html.ep:54 msgid "Uploaded at" msgstr "Envoyé le" @@ -459,16 +423,12 @@ msgstr "Envoyé le" msgid "Uploaded files by days" msgstr "Fichiers envoyés, par jour" -#. ($config->{contact}) -#: lib/Lutim.pm:189 +#. ($c->app->config('contact') +#: lib/Lutim/Plugin/Helpers.pm:152 msgid "Uploading is currently disabled, please try later or contact the administrator (%1)." msgstr "L’envoi d’images est actuellement désactivé, veuillez réessayer plus tard ou contacter l’administrateur (%1)." -#: themes/default/templates/index.html.ep:65 -#: themes/default/templates/index.html.ep:67 -#: themes/default/templates/myfiles.html.ep:14 -#: themes/default/templates/partial/lutim.js.ep:168 -#: themes/default/templates/partial/lutim.js.ep:172 +#: themes/default/templates/index.html.ep:65 themes/default/templates/index.html.ep:67 themes/default/templates/myfiles.html.ep:51 themes/default/templates/partial/lutim.js.ep:71 themes/default/templates/partial/lutim.js.ep:75 msgid "View link" msgstr "Lien d’affichage" @@ -492,6 +452,10 @@ msgstr "Oui, ça l’est ! Par contre, pour des raisons légales, votre adresse msgid "Yes, it is! On the other side, if you want to support the developer, you can do it via Tipeee or via Liberapay." msgstr "Oui, ça l’est ! Par contre, si vous avez envie de soutenir le développeur, vous pouvez faire un microdon avec Tipeee ou via Liberapay." +#: themes/default/templates/zip.html.ep:6 +msgid "You asked to download a zip archive for too much files." +msgstr "Vous avez demandé de télécharger une archive zip pour trop de fichiers." + #: themes/default/templates/about.html.ep:8 msgid "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." msgstr "Vous pouvez, de façon facultative, demander à ce que la ou les images déposées sur Lutim soient supprimées après leur premier affichage (ou téléchargement) ou au bout d’un délai choisi parmi ceux proposés." @@ -504,10 +468,7 @@ msgstr "et sur" msgid "core developer" msgstr "développeur principal" -#: lib/Lutim/Command/cron/stats.pm:108 -#: lib/Lutim/Command/cron/stats.pm:125 -#: lib/Lutim/Command/cron/stats.pm:97 -#: themes/default/templates/index.html.ep:3 +#: lib/Lutim.pm:190 lib/Lutim/Command/cron/stats.pm:147 lib/Lutim/Command/cron/stats.pm:158 lib/Lutim/Command/cron/stats.pm:175 themes/default/templates/index.html.ep:3 themes/default/templates/raw.html.ep:17 themes/default/templates/raw.html.ep:34 themes/default/templates/raw.html.ep:6 msgid "no time limit" msgstr "Pas de limitation de durée" diff --git a/themes/default/lib/Lutim/I18N/oc.po b/themes/default/lib/Lutim/I18N/oc.po index f18e05e..eec5543 100644 --- a/themes/default/lib/Lutim/I18N/oc.po +++ b/themes/default/lib/Lutim/I18N/oc.po @@ -17,19 +17,11 @@ msgstr "" "Language: oc\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#. ($delay) -#. (config('max_delay') #. (7) #. (30) -#: lib/Lutim/Command/cron/stats.pm:100 -#: lib/Lutim/Command/cron/stats.pm:110 -#: lib/Lutim/Command/cron/stats.pm:111 -#: lib/Lutim/Command/cron/stats.pm:127 -#: lib/Lutim/Command/cron/stats.pm:128 -#: lib/Lutim/Command/cron/stats.pm:99 -#: themes/default/templates/partial/lutim.js.ep:235 -#: themes/default/templates/partial/lutim.js.ep:244 -#: themes/default/templates/partial/lutim.js.ep:245 +#. ($delay) +#. (config('max_delay') +#: lib/Lutim/Command/cron/stats.pm:149 lib/Lutim/Command/cron/stats.pm:150 lib/Lutim/Command/cron/stats.pm:160 lib/Lutim/Command/cron/stats.pm:161 lib/Lutim/Command/cron/stats.pm:177 lib/Lutim/Command/cron/stats.pm:178 themes/default/templates/partial/for_my_delay.html.ep:12 themes/default/templates/partial/for_my_delay.html.ep:13 themes/default/templates/partial/for_my_delay.html.ep:3 themes/default/templates/partial/lutim.js.ep:138 themes/default/templates/partial/lutim.js.ep:147 themes/default/templates/partial/lutim.js.ep:148 themes/default/templates/raw.html.ep:19 themes/default/templates/raw.html.ep:20 themes/default/templates/raw.html.ep:36 themes/default/templates/raw.html.ep:37 themes/default/templates/raw.html.ep:8 themes/default/templates/raw.html.ep:9 msgid "%1 days" msgstr "%1 jorns" @@ -42,69 +34,51 @@ msgstr "%1 imatges mandats sus aquesta instància dempuèi lo començament." msgid "-or-" msgstr "-o-" -#: lib/Lutim/Command/cron/stats.pm:101 -#: lib/Lutim/Command/cron/stats.pm:112 -#: lib/Lutim/Command/cron/stats.pm:129 -#: themes/default/templates/index.html.ep:5 +#: lib/Lutim.pm:192 lib/Lutim/Command/cron/stats.pm:151 lib/Lutim/Command/cron/stats.pm:162 lib/Lutim/Command/cron/stats.pm:179 themes/default/templates/index.html.ep:5 themes/default/templates/raw.html.ep:10 themes/default/templates/raw.html.ep:21 themes/default/templates/raw.html.ep:38 msgid "1 year" msgstr "1 an" -#: lib/Lutim/Command/cron/stats.pm:109 -#: lib/Lutim/Command/cron/stats.pm:126 -#: lib/Lutim/Command/cron/stats.pm:98 -#: themes/default/templates/index.html.ep:4 -#: themes/default/templates/partial/lutim.js.ep:244 +#: lib/Lutim.pm:191 lib/Lutim/Command/cron/stats.pm:148 lib/Lutim/Command/cron/stats.pm:159 lib/Lutim/Command/cron/stats.pm:176 themes/default/templates/index.html.ep:4 themes/default/templates/partial/for_my_delay.html.ep:12 themes/default/templates/partial/lutim.js.ep:147 themes/default/templates/raw.html.ep:18 themes/default/templates/raw.html.ep:35 themes/default/templates/raw.html.ep:7 msgid "24 hours" msgstr "24 oras" -#: themes/default/templates/myfiles.html.ep:79 +#: themes/default/templates/partial/myfiles.js.ep:57 msgid ": Error while trying to get the counter." msgstr " : Error al moment de recuperar lo comptador." -#: lib/Lutim/Command/cron/stats.pm:94 +#: lib/Lutim/Command/cron/stats.pm:144 themes/default/templates/raw.html.ep:3 msgid "Active images" msgstr "Imatges actius" -#: lib/Lutim/Controller.pm:286 +#: lib/Lutim/Controller.pm:288 msgid "An error occured while downloading the image." msgstr "Una error es apareguda pendent lo telecargament de l'imatge." -#: themes/default/templates/about.html.ep:41 -#: themes/default/templates/myfiles.html.ep:27 -#: themes/default/templates/stats.html.ep:25 +#: themes/default/templates/zip.html.ep:2 +msgid "Archives download" +msgstr "Telecargar los archius" + +#: themes/default/templates/about.html.ep:41 themes/default/templates/myfiles.html.ep:64 themes/default/templates/stats.html.ep:25 msgid "Back to homepage" msgstr "Tornar a la pagina d'acuèlh" -#: themes/default/templates/index.html.ep:193 -#: themes/default/templates/index.html.ep:194 +#: themes/default/templates/index.html.ep:193 themes/default/templates/index.html.ep:194 msgid "Click to open the file browser" -msgstr "Clicatz per utilizar lo navigador de fichièr" +msgstr "Clicatz per utilizar lo navigator de fichièr" #: themes/default/templates/about.html.ep:30 msgid "Contributors" -msgstr "Contributors" +msgstr "Contribudors" -#: themes/default/templates/partial/lutim.js.ep:310 -#: themes/default/templates/partial/lutim.js.ep:359 -#: themes/default/templates/partial/lutim.js.ep:437 +#: themes/default/templates/partial/lutim.js.ep:214 themes/default/templates/partial/lutim.js.ep:268 themes/default/templates/partial/lutim.js.ep:346 msgid "Copy all view links to clipboard" msgstr "Copiar totes los ligams de visualizacion dins lo quichapapièrs" -#: themes/default/templates/index.html.ep:18 -#: themes/default/templates/index.html.ep:36 -#: themes/default/templates/index.html.ep:69 -#: themes/default/templates/index.html.ep:77 -#: themes/default/templates/index.html.ep:85 -#: themes/default/templates/index.html.ep:93 -#: themes/default/templates/partial/common.js.ep:45 -#: themes/default/templates/partial/lutim.js.ep:176 -#: themes/default/templates/partial/lutim.js.ep:188 -#: themes/default/templates/partial/lutim.js.ep:202 -#: themes/default/templates/partial/lutim.js.ep:217 +#: themes/default/templates/index.html.ep:18 themes/default/templates/index.html.ep:36 themes/default/templates/index.html.ep:69 themes/default/templates/index.html.ep:77 themes/default/templates/index.html.ep:85 themes/default/templates/index.html.ep:93 themes/default/templates/myfiles.html.ep:20 themes/default/templates/myfiles.html.ep:38 themes/default/templates/partial/common.js.ep:150 themes/default/templates/partial/lutim.js.ep:105 themes/default/templates/partial/lutim.js.ep:120 themes/default/templates/partial/lutim.js.ep:79 themes/default/templates/partial/lutim.js.ep:91 msgid "Copy to clipboard" msgstr "Copiar dins lo quichapapièrs" -#: themes/default/templates/myfiles.html.ep:15 +#: themes/default/templates/myfiles.html.ep:52 msgid "Counter" msgstr "Comptador" @@ -116,26 +90,19 @@ msgstr "Grafic de despartiment dels delais pels imatges desactivats" msgid "Delay repartition chart for enabled images" msgstr "Grafic de despartiment dels delais pels imatges activats" -#: themes/default/templates/index.html.ep:115 -#: themes/default/templates/index.html.ep:147 -#: themes/default/templates/index.html.ep:178 -#: themes/default/templates/myfiles.html.ep:16 -#: themes/default/templates/partial/lutim.js.ep:256 +#: themes/default/templates/index.html.ep:115 themes/default/templates/index.html.ep:147 themes/default/templates/index.html.ep:178 themes/default/templates/myfiles.html.ep:53 themes/default/templates/partial/lutim.js.ep:159 msgid "Delete at first view?" msgstr "Suprimir al primièr accès ?" -#: lib/Lutim/Command/cron/stats.pm:95 +#: lib/Lutim/Command/cron/stats.pm:145 themes/default/templates/raw.html.ep:4 msgid "Deleted images" msgstr "Imatges suprimits" -#: lib/Lutim/Command/cron/stats.pm:96 +#: lib/Lutim/Command/cron/stats.pm:146 themes/default/templates/raw.html.ep:5 msgid "Deleted images in 30 days" msgstr "Imatges per èsser suprimits dins 30 jorns" -#: themes/default/templates/index.html.ep:98 -#: themes/default/templates/myfiles.html.ep:19 -#: themes/default/templates/partial/common.js.ep:37 -#: themes/default/templates/partial/common.js.ep:40 +#: themes/default/templates/index.html.ep:98 themes/default/templates/myfiles.html.ep:56 themes/default/templates/partial/common.js.ep:142 themes/default/templates/partial/common.js.ep:145 msgid "Deletion link" msgstr "Ligam de supression" @@ -143,15 +110,11 @@ msgstr "Ligam de supression" msgid "Download all images" msgstr "Telecargar totes los imatges" -#: themes/default/templates/index.html.ep:81 -#: themes/default/templates/index.html.ep:83 -#: themes/default/templates/partial/lutim.js.ep:194 -#: themes/default/templates/partial/lutim.js.ep:198 +#: themes/default/templates/index.html.ep:81 themes/default/templates/index.html.ep:83 themes/default/templates/partial/lutim.js.ep:101 themes/default/templates/partial/lutim.js.ep:97 msgid "Download link" msgstr "Ligam de telecargament" -#: themes/default/templates/index.html.ep:28 -#: themes/default/templates/index.html.ep:31 +#: themes/default/templates/index.html.ep:28 themes/default/templates/index.html.ep:31 themes/default/templates/myfiles.html.ep:30 themes/default/templates/myfiles.html.ep:33 msgid "Download zip link" msgstr "Ligam de telecargament de l'archiu dels imatges" @@ -163,12 +126,11 @@ msgstr "Lisatz e depausatz vòstres imatges aquí" msgid "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." msgstr "Depausatz vòstres imatges dins la zòna prevista per aquò o seleccionatz un fichièr d'un biais classic e Lutim vos donarà quatre URLs en torna. Una per afichar l'imatge, una mai per lo telecargar dirèctament, una per l'utilizar suls malhums socials e una darrièra per suprimir vòstre imatge quand volguèssetz." -#: themes/default/templates/index.html.ep:150 -#: themes/default/templates/index.html.ep:181 +#: themes/default/templates/index.html.ep:150 themes/default/templates/index.html.ep:181 msgid "Encrypt the image (Lutim does not keep the key)." msgstr "Chifrar l'imatge (Lutim garda pas la clau)." -#: themes/default/templates/partial/lutim.js.ep:72 +#: themes/default/templates/partial/lutim.js.ep:44 msgid "Error while trying to modify the image." msgstr "Una error es apareguda al moment de modificar l'imatge." @@ -176,11 +138,11 @@ msgstr "Una error es apareguda al moment de modificar l'imatge." msgid "Evolution of total files" msgstr "Evolucion del nombre total de fichièrs" -#: themes/default/templates/myfiles.html.ep:18 +#: themes/default/templates/myfiles.html.ep:55 msgid "Expires at" -msgstr "Expira lo" +msgstr "S'acaba lo" -#: themes/default/templates/myfiles.html.ep:13 +#: themes/default/templates/myfiles.html.ep:50 msgid "File name" msgstr "Nom del fichièr" @@ -188,21 +150,19 @@ msgstr "Nom del fichièr" msgid "For more details, see the homepage of the project." msgstr "Per mai de detalhs, consultatz la pagina Github del projècte." -#: themes/default/templates/layouts/default.html.ep:50 +#: themes/default/templates/layouts/default.html.ep:55 msgid "Fork me!" -msgstr "Creatz un fork !" +msgstr "Tustatz-me !" -#: themes/default/templates/index.html.ep:10 -#: themes/default/templates/index.html.ep:13 +#: themes/default/templates/index.html.ep:10 themes/default/templates/index.html.ep:13 themes/default/templates/myfiles.html.ep:12 themes/default/templates/myfiles.html.ep:15 msgid "Gallery link" msgstr "Ligam cap a la galariá" -#: themes/default/templates/partial/lutim.js.ep:125 -#: themes/default/templates/partial/lutim.js.ep:142 +#: themes/default/templates/partial/common.js.ep:104 themes/default/templates/partial/common.js.ep:87 msgid "Hit Ctrl+C, then Enter to copy the short link" msgstr "Fasètz Ctrl+C puèi picatz Entrada per copiar lo ligam" -#: themes/default/templates/layouts/default.html.ep:45 +#: themes/default/templates/layouts/default.html.ep:50 msgid "Homepage" msgstr "Acuèlh" @@ -222,27 +182,30 @@ msgstr "Qué far per senhalar un imatge ?" msgid "If the files are deleted if you ask it while posting it, their SHA512 footprint are retained." msgstr "Se los fichièrs son ben estats suprimits se o avètz demandat, lors signaturas SHA512 son gardadas." -#: themes/default/templates/index.html.ep:163 -#: themes/default/templates/index.html.ep:203 +#: themes/default/templates/index.html.ep:163 themes/default/templates/index.html.ep:203 msgid "Image URL" msgstr "URL de l'imatge" -#: lib/Lutim/Command/cron/stats.pm:93 +#: lib/Lutim/Command/cron/stats.pm:143 themes/default/templates/raw.html.ep:2 msgid "Image delay" msgstr "Delai de l'imatge" -#: lib/Lutim/Controller.pm:715 +#: lib/Lutim/Controller.pm:710 msgid "Image not found." msgstr "Imatge pas trobat." -#: themes/default/templates/layouts/default.html.ep:49 +#: themes/default/templates/layouts/default.html.ep:54 msgid "Informations" msgstr "Informacions" -#: themes/default/templates/layouts/default.html.ep:55 +#: themes/default/templates/layouts/default.html.ep:62 msgid "Install webapp" msgstr "Installar la webapp" +#: themes/default/templates/layouts/default.html.ep:61 +msgid "Instance's statistics" +msgstr "Estatisticas de l'instància" + #: themes/default/templates/about.html.ep:11 msgid "Is it really anonymous?" msgstr "Es vertadièrament anonim ?" @@ -255,29 +218,30 @@ msgstr "Es vertadièrament gratuit ?" msgid "Juste like you pronounce the French word lutin (/ly.tɛ̃/)." msgstr "Òm pronóncia coma en occitan lengadocian, LU-TI-N, amb una M finala que sona N, o coma la paraula francesa lutin (/ly.tɛ̃/)." -#: themes/default/templates/index.html.ep:153 -#: themes/default/templates/index.html.ep:184 +#: themes/default/templates/index.html.ep:153 themes/default/templates/index.html.ep:184 msgid "Keep EXIF tags" msgstr "Conservar las donadas EXIF" -#: themes/default/templates/index.html.ep:118 -#: themes/default/templates/index.html.ep:166 -#: themes/default/templates/index.html.ep:206 -#: themes/default/templates/partial/lutim.js.ep:260 +#: themes/default/templates/index.html.ep:118 themes/default/templates/index.html.ep:166 themes/default/templates/index.html.ep:206 themes/default/templates/partial/lutim.js.ep:163 msgid "Let's go!" msgstr "Zo !" -#: themes/default/templates/layouts/default.html.ep:48 +#: themes/default/templates/layouts/default.html.ep:58 +msgid "Liberapay button" +msgstr "Boton Liberapay" + +#: themes/default/templates/layouts/default.html.ep:53 msgid "License:" msgstr "Licéncia :" -#: themes/default/templates/index.html.ep:89 -#: themes/default/templates/index.html.ep:91 -#: themes/default/templates/partial/lutim.js.ep:208 -#: themes/default/templates/partial/lutim.js.ep:212 +#: themes/default/templates/index.html.ep:89 themes/default/templates/index.html.ep:91 themes/default/templates/partial/lutim.js.ep:111 themes/default/templates/partial/lutim.js.ep:115 msgid "Link for share on social networks" msgstr "Ligam per partejar suls malhums socials" +#: themes/default/templates/zip.html.ep:7 +msgid "Lutim can't zip so many images at once, so it splitted your demand in multiple URLs." +msgstr "Lutim pòt pas comprimir tan d'imatge d'un còp, a doncas trocejat vòstra demanda en multiplas URLs" + #: themes/default/templates/about.html.ep:4 msgid "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." msgstr "Lutim es un servici gratuit e anonim d’albergament d’imatges. S’agís tanben del nom del logicial (liure) que fornís aqueste servici." @@ -286,24 +250,19 @@ msgstr "Lutim es un servici gratuit e anonim d’albergament d’imatges. S’ag msgid "Main developers" msgstr "Desvolopaires de l'aplicacion" -#: themes/default/templates/index.html.ep:73 -#: themes/default/templates/index.html.ep:75 -#: themes/default/templates/partial/lutim.js.ep:182 -#: themes/default/templates/partial/lutim.js.ep:185 +#: themes/default/templates/index.html.ep:73 themes/default/templates/index.html.ep:75 themes/default/templates/partial/lutim.js.ep:85 themes/default/templates/partial/lutim.js.ep:88 msgid "Markdown syntax" msgstr "Sintaxi Markdown" -#: themes/default/templates/layouts/default.html.ep:54 -#: themes/default/templates/myfiles.html.ep:2 +#: themes/default/templates/layouts/default.html.ep:60 themes/default/templates/myfiles.html.ep:2 msgid "My images" msgstr "Mos imatges" -#: themes/default/templates/myfiles.html.ep:39 +#: themes/default/templates/partial/myfiles.js.ep:19 msgid "No limit" msgstr "Pas cap de data d'expiracion" -#: themes/default/templates/index.html.ep:165 -#: themes/default/templates/index.html.ep:198 +#: themes/default/templates/index.html.ep:165 themes/default/templates/index.html.ep:198 msgid "Only images are allowed" msgstr "Solament son acceptats los imatges" @@ -315,6 +274,10 @@ msgstr "Solament los imatges mandats amb aqueste navigador seràn listats aquí. msgid "Only the uploader! (well, only if he's the only owner of the images' rights before the upload)" msgstr "Solament lo qu'a mandat ! (ben, solament se ten los dreits exclusius dels imatges abans de los mandar)" +#: themes/default/templates/zip.html.ep:12 +msgid "Please click on each URL to download the different zip files." +msgstr "Mercés de clicar sus cada URL per telecargar los diferents archius ZIP." + #. (config('contact') #: themes/default/templates/about.html.ep:19 msgid "Please contact the administrator: %1" @@ -322,30 +285,37 @@ msgstr "Mercés de contactar l'administrator : %1" #: themes/default/templates/stats.html.ep:22 msgid "Raw stats" -msgstr "Estatisticas bruts" +msgstr "Estatisticas brutas" #: themes/default/templates/index.html.ep:158 msgid "Send an image" msgstr "Mandar un imatge" -#: themes/default/templates/partial/lutim.js.ep:51 +#: themes/default/templates/partial/lutim.js.ep:20 msgid "Share it!" -msgstr "Partejatz !" +msgstr "Partejatz-lo !" -#: themes/default/templates/layouts/default.html.ep:51 +#: themes/default/templates/layouts/default.html.ep:56 msgid "Share on Twitter" msgstr "Partejar sus Twitter" -#: themes/default/templates/index.html.ep:133 -#: themes/default/templates/partial/lutim.js.ep:271 +#: themes/default/templates/index.html.ep:133 themes/default/templates/partial/lutim.js.ep:174 msgid "Something bad happened" msgstr "Un problèma es aparegut" #. ($c->config('contact') -#: lib/Lutim/Controller.pm:723 +#: lib/Lutim/Controller.pm:717 msgid "Something went wrong when creating the zip file. Try again later or contact the administrator (%1)." msgstr "Quicòm a trucat pendent la creacion de l'archiu. Mercés de tornar ensajar pus tard o de contactar l'administrator (%1)." +#: themes/default/templates/layouts/default.html.ep:58 +msgid "Support the author on Liberapay" +msgstr "Sostenir l'autor sus Liberapay" + +#: themes/default/templates/layouts/default.html.ep:57 +msgid "Support the author on Tipeee" +msgstr "Sostenir l'autor sus Tipeee" + #: themes/default/templates/about.html.ep:13 msgid "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)." msgstr "L’IP de la persona que mandèt l'imatge es gardada pendent un delai que depend de l'administrator de l'instància (per l'instància oficiala que lo servidor es en França, es un delai d'un an)." @@ -354,26 +324,27 @@ msgstr "L’IP de la persona que mandèt l'imatge es gardada pendent un delai qu msgid "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." msgstr "Lo logicial Lutim es un logicial liure, que permet de lo telecargar e de l’installar sus vòstre pròpri servidor. Gaitatz l’AGPL per veire que son vòstres dreits" -#: lib/Lutim/Controller.pm:305 +#: lib/Lutim/Controller.pm:307 msgid "The URL is not valid." msgstr "L'URL n'es pas valida." -#: lib/Lutim/Controller.pm:117 -#: lib/Lutim/Controller.pm:186 +#: themes/default/templates/zip.html.ep:16 +msgid "The automatic download process will open a tab in your browser for each link. You need to allow popups for Lutim." +msgstr "Lo processús automatic de telecargament obrirà un onglet dins lo navigato per cada ligam. Vos cal autorizar las popups per Lutim." + +#: lib/Lutim/Controller.pm:120 lib/Lutim/Controller.pm:188 msgid "The delete token is invalid." msgstr "Lo geton de supression es invalida." #. ($upload->filename) -#: lib/Lutim/Controller.pm:449 +#: lib/Lutim/Controller.pm:445 msgid "The file %1 is not an image." msgstr "Lo fichièr %1 es pas un imatge." -#. ($max_file_size) #. ($tx->res->max_message_size) #. ($c->req->max_message_size) -#: lib/Lutim/Controller.pm:269 -#: lib/Lutim/Controller.pm:338 -#: themes/default/templates/partial/lutim.js.ep:332 +#. (config('max_file_size') +#: lib/Lutim/Controller.pm:271 lib/Lutim/Controller.pm:340 themes/default/templates/partial/lutim.js.ep:240 msgid "The file exceed the size limit (%1)" msgstr "Lo fichièr depassa lo limit de talha (%1)" @@ -382,17 +353,16 @@ msgid "The graph's datas are not updated in real-time." msgstr "Las donadas del grafic son pas mesas a jorn en temps real." #. ($image->filename) -#: lib/Lutim/Controller.pm:188 +#: lib/Lutim/Controller.pm:190 msgid "The image %1 has already been deleted." msgstr "L'imatge %1 es ja estat suprimit." #. ($image->filename) -#: lib/Lutim/Controller.pm:197 -#: lib/Lutim/Controller.pm:202 +#: lib/Lutim/Controller.pm:199 lib/Lutim/Controller.pm:204 msgid "The image %1 has been successfully deleted" msgstr "L'imatge %1 es estat suprimit amb succès." -#: lib/Lutim/Controller.pm:125 +#: lib/Lutim/Controller.pm:128 msgid "The image's delay has been successfully modified" msgstr "Lo delai de l'imatge es plan estat modificat." @@ -405,37 +375,32 @@ msgid "The images you post on Lutim can be stored indefinitely or be deleted at msgstr "Los imatges depausats sus Lutim pòdon èsser gardats sens fin, o s’escafar tre lo primièr afichatge o al cap d'un delai causit entre los prepausats." #. ($c->config->{contact}) -#: lib/Lutim/Controller.pm:444 +#: lib/Lutim/Controller.pm:442 msgid "There is no more available URL. Retry or contact the administrator. %1" msgstr "I a pas mai d'URL disponibla. Mercés de tornar ensajar o de contactar l'administrator. %1." -#: lib/Lutim/Command/cron/stats.pm:102 +#: themes/default/templates/layouts/default.html.ep:57 +msgid "Tipeee button" +msgstr "Boton Tipeee" + +#: lib/Lutim/Command/cron/stats.pm:152 themes/default/templates/raw.html.ep:11 msgid "Total" msgstr "Total" -#: themes/default/templates/index.html.ep:60 -#: themes/default/templates/partial/lutim.js.ep:45 +#: themes/default/templates/index.html.ep:60 themes/default/templates/partial/lutim.js.ep:14 msgid "Tweet it!" -msgstr "Tweetejatz !" +msgstr "Tweetejatz-lo !" #. ($short) -#: lib/Lutim/Controller.pm:159 -#: lib/Lutim/Controller.pm:231 +#: lib/Lutim/Controller.pm:162 lib/Lutim/Controller.pm:233 msgid "Unable to find the image %1." msgstr "Impossible de trobar l'imatge %1." -#: lib/Lutim.pm:85 -#: lib/Lutim/Controller.pm:534 -#: lib/Lutim/Controller.pm:580 -#: lib/Lutim/Controller.pm:624 -#: lib/Lutim/Controller.pm:664 -#: lib/Lutim/Controller.pm:676 -#: lib/Lutim/Controller.pm:687 -#: lib/Lutim/Controller.pm:712 +#: lib/Lutim/Controller.pm:529 lib/Lutim/Controller.pm:574 lib/Lutim/Controller.pm:616 lib/Lutim/Controller.pm:659 lib/Lutim/Controller.pm:671 lib/Lutim/Controller.pm:682 lib/Lutim/Controller.pm:707 lib/Lutim/Plugin/Helpers.pm:57 msgid "Unable to find the image: it has been deleted." msgstr "Impossible de trobar l'imatge : es estat suprimit." -#: lib/Lutim/Controller.pm:101 +#: lib/Lutim/Controller.pm:105 msgid "Unable to get counter" msgstr "Impossible de recuperar lo comptador" @@ -443,12 +408,11 @@ msgstr "Impossible de recuperar lo comptador" msgid "Unlike many image sharing services, you don't give us rights on uploaded images." msgstr "A l'invèrse de la màger part dels servicis de partiment d'imatge, daissatz pas cap de dreit suls imatges que mandatz." -#: themes/default/templates/index.html.ep:162 -#: themes/default/templates/index.html.ep:201 +#: themes/default/templates/index.html.ep:162 themes/default/templates/index.html.ep:201 msgid "Upload an image with its URL" msgstr "Depausar un imatge per son URL" -#: themes/default/templates/myfiles.html.ep:17 +#: themes/default/templates/myfiles.html.ep:54 msgid "Uploaded at" msgstr "Mandat lo" @@ -456,16 +420,12 @@ msgstr "Mandat lo" msgid "Uploaded files by days" msgstr "Fichièrs mandats per jorn" -#. ($config->{contact}) -#: lib/Lutim.pm:189 +#. ($c->app->config('contact') +#: lib/Lutim/Plugin/Helpers.pm:152 msgid "Uploading is currently disabled, please try later or contact the administrator (%1)." msgstr "La mesa en linha es desactivada pel moment, mercés de tornar ensajar mai tard o de contactar l'administrator (%1)." -#: themes/default/templates/index.html.ep:65 -#: themes/default/templates/index.html.ep:67 -#: themes/default/templates/myfiles.html.ep:14 -#: themes/default/templates/partial/lutim.js.ep:168 -#: themes/default/templates/partial/lutim.js.ep:172 +#: themes/default/templates/index.html.ep:65 themes/default/templates/index.html.ep:67 themes/default/templates/myfiles.html.ep:51 themes/default/templates/partial/lutim.js.ep:71 themes/default/templates/partial/lutim.js.ep:75 msgid "View link" msgstr "Ligam d'afichatge" @@ -489,6 +449,10 @@ msgstr "Òc, es aquò ! Al contrari, per de rasons legalas, vòstra adreça IP s msgid "Yes, it is! On the other side, if you want to support the developer, you can do it via Tipeee or via Liberapay." msgstr "Òc, o es ! Al contrari, s'avètz enveja de sosténer lo desvolopaire, podètz far un microdon amb Tipeee o via Liberapay." +#: themes/default/templates/zip.html.ep:6 +msgid "You asked to download a zip archive for too much files." +msgstr "Avètz demandat de telecargar tròp d'imatges d'un còp dins un archiu ZIP." + #: themes/default/templates/about.html.ep:8 msgid "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." msgstr "Podètz, d'un biais facultatiu, demandar que l'imatge o los imatges depausats sus Lutim sián suprimits aprèp lor primièr afichatge (o telecargament) o al cap d'un delai causit entre las prepausadas." @@ -501,10 +465,7 @@ msgstr "e sus" msgid "core developer" msgstr "desvolopaire màger" -#: lib/Lutim/Command/cron/stats.pm:108 -#: lib/Lutim/Command/cron/stats.pm:125 -#: lib/Lutim/Command/cron/stats.pm:97 -#: themes/default/templates/index.html.ep:3 +#: lib/Lutim.pm:190 lib/Lutim/Command/cron/stats.pm:147 lib/Lutim/Command/cron/stats.pm:158 lib/Lutim/Command/cron/stats.pm:175 themes/default/templates/index.html.ep:3 themes/default/templates/raw.html.ep:17 themes/default/templates/raw.html.ep:34 themes/default/templates/raw.html.ep:6 msgid "no time limit" msgstr "Pas cap de limitacion de durada" diff --git a/themes/default/public/css/lutim.css b/themes/default/public/css/lutim.css index e1e58ca..37da882 100644 --- a/themes/default/public/css/lutim.css +++ b/themes/default/public/css/lutim.css @@ -66,3 +66,20 @@ label.always-encrypt { .adjust-addon .btn { width: 43px; } +#tipeee-img { + margin-top: -4px; +} +#liberapay-img { + height: 21px; + line-height: 21px; + margin-top: -5.33333px; +} +.pasteZone { + position: absolute; + top: 0; + left: -100px; + z-index: -999; + height: 10000vh; + width: 0; + display: hidden; +} diff --git a/themes/default/public/css/markdown.css b/themes/default/public/css/markdown.css index f77f739..83f2411 100644 --- a/themes/default/public/css/markdown.css +++ b/themes/default/public/css/markdown.css @@ -1,10 +1,10 @@ @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'); + 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: normal; font-style: normal; } diff --git a/themes/default/public/gallery/css/unite-gallery.css b/themes/default/public/gallery/css/unite-gallery.css index caf2ca2..8e4cc84 100644 --- a/themes/default/public/gallery/css/unite-gallery.css +++ b/themes/default/public/gallery/css/unite-gallery.css @@ -95,7 +95,7 @@ height:35px; width:32px; height:32px; - background-image:url('../images/loader_skype_trans.gif'); + background-image:url('../../gallery/images/loader_skype_trans.gif'); background-repeat:no-repeat; } @@ -151,78 +151,78 @@ .ug-slider-preloader.ug-loader1{ width:30px; height:30px; - background-image:url('../images/loader-white1.gif'); + background-image:url('../../gallery/images/loader-white1.gif'); } .ug-slider-preloader.ug-loader1.ug-loader-black{ - background-image:url('../images/loader-black1.gif'); + background-image:url('../../gallery/images/loader-black1.gif'); } .ug-slider-preloader.ug-loader2{ width:32px; height:32px; - background-image:url('../images/loader-white2.gif'); + background-image:url('../../gallery/images/loader-white2.gif'); } .ug-slider-preloader.ug-loader2.ug-loader-black{ - background-image:url('../images/loader-black2.gif'); + background-image:url('../../gallery/images/loader-black2.gif'); } .ug-slider-preloader.ug-loader3{ width:38px; height:38px; - background-image:url('../images/loader-white3.gif'); + background-image:url('../../gallery/images/loader-white3.gif'); } .ug-slider-preloader.ug-loader3.ug-loader-black{ - background-image:url('../images/loader-black3.gif'); + background-image:url('../../gallery/images/loader-black3.gif'); } .ug-slider-preloader.ug-loader4{ width:32px; height:32px; - background-image:url('../images/loader-white4.gif'); + background-image:url('../../gallery/images/loader-white4.gif'); background-color:white; } .ug-slider-preloader.ug-loader4.ug-loader-black{ - background-image:url('../images/loader-black4.gif'); + background-image:url('../../gallery/images/loader-black4.gif'); } .ug-slider-preloader.ug-loader5{ width:60px; height:8px; - background-image:url('../images/loader-white5.gif'); + background-image:url('../../gallery/images/loader-white5.gif'); background-color:white; border:none; border-radius:0px; } .ug-slider-preloader.ug-loader5.ug-loader-black{ - background-image:url('../images/loader-black5.gif'); + background-image:url('../../gallery/images/loader-black5.gif'); border:2px solid #000000; } .ug-slider-preloader.ug-loader6{ width:32px; height:32px; - background-image:url('../images/loader-white6.gif'); + background-image:url('../../gallery/images/loader-white6.gif'); } .ug-slider-preloader.ug-loader6.ug-loader-black{ - background-image:url('../images/loader-black6.gif'); + background-image:url('../../gallery/images/loader-black6.gif'); } .ug-slider-preloader.ug-loader7{ width:32px; height:10px; - background-image:url('../images/loader-white7.gif'); + background-image:url('../../gallery/images/loader-white7.gif'); border-width:3px; border-radius:3px; } .ug-slider-preloader.ug-loader7.ug-loader-black{ - background-image:url('../images/loader-black7.gif'); + background-image:url('../../gallery/images/loader-black7.gif'); } .ug-slider-preloader.ug-loader-black{ @@ -243,7 +243,7 @@ .ug-slider-wrapper .ug-button-videoplay.ug-type-square{ width:86px; height:66px; - background-image:url('../images/play-button-square.png'); + background-image:url('../../gallery/images/play-button-square.png'); background-position:0px -66px; } @@ -255,7 +255,7 @@ .ug-slider-wrapper .ug-button-videoplay.ug-type-round{ width:76px; height:76px; - background-image:url('../images/play-button-round.png'); + background-image:url('../../gallery/images/play-button-round.png'); opacity:0.9; filter: alpha(opacity = 90); transition: all 0.3s ease 0s !important; @@ -275,7 +275,7 @@ position:absolute; z-index:100; background-color:#000000; - background-image:url('../images/loader-black1.gif'); + background-image:url('../../gallery/images/loader-black1.gif'); background-repeat:no-repeat; background-position:center center; box-sizing:border-box; @@ -286,7 +286,7 @@ width:100%; height:100%; background-color:#000000; - background-image:url('../images/loader-black1.gif'); + background-image:url('../../gallery/images/loader-black1.gif'); background-repeat:no-repeat; background-position:center center; } @@ -296,7 +296,7 @@ position:absolute; height:64px; width:64px; - background-image:url('../images/button-close.png'); + background-image:url('../../gallery/images/button-close.png'); cursor:pointer; z-index:1000; } @@ -372,15 +372,15 @@ } .ug-thumb-wrapper.ug-thumb-generated .ug-thumb-loader-dark{ - background-image:url('../images/loader.gif'); + background-image:url('../../gallery/images/loader.gif'); } .ug-thumb-wrapper.ug-thumb-generated .ug-thumb-loader-bright{ - background-image:url('../images/loader_bright.gif'); + background-image:url('../../gallery/images/loader_bright.gif'); } .ug-thumb-wrapper.ug-thumb-generated .ug-thumb-error{ - background-image:url('../images/not_loaded.png'); + background-image:url('../../gallery/images/not_loaded.png'); } .ug-thumb-wrapper.ug-thumb-generated img{ @@ -572,7 +572,7 @@ img.ug-sepia-effect{ background-color:#000000; opacity: 0.3; filter: alpha(opacity=30); - background-image:url('../images/cover-grid.png'); + background-image:url('../../gallery/images/cover-grid.png'); } @@ -695,15 +695,15 @@ img.ug-sepia-effect{ } .ug-thumb-wrapper.ug-tile .ug-tile-icon.ug-icon-link{ - background-image:url('../images/icon-link32.png'); + background-image:url('../../gallery/images/icon-link32.png'); } .ug-thumb-wrapper.ug-tile .ug-tile-icon.ug-icon-zoom{ - background-image:url('../images/icon-zoom32.png'); + background-image:url('../../gallery/images/icon-zoom32.png'); } .ug-thumb-wrapper.ug-tile .ug-tile-icon.ug-icon-play{ - background-image:url('../images/icon-play32.png'); + background-image:url('../../gallery/images/icon-play32.png'); } .ug-thumb-wrapper.ug-tile .ug-tile-icon:hover{ @@ -805,14 +805,14 @@ img.ug-sepia-effect{ width:50px; height:55px; background-repeat:no-repeat; - background-image:url('../images/lightbox-arrow-left.png'); + background-image:url('../../gallery/images/lightbox-arrow-left.png'); background-position:0px 0px; z-index:3; cursor:pointer; } .ug-lightbox .ug-lightbox-arrow-right{ - background-image:url('../images/lightbox-arrow-right.png'); + background-image:url('../../gallery/images/lightbox-arrow-right.png'); } .ug-lightbox .ug-lightbox-button-close{ @@ -820,7 +820,7 @@ img.ug-sepia-effect{ width:36px; height:36px; background-repeat:no-repeat; - background-image:url('../images/lightbox-icon-close.png'); + background-image:url('../../gallery/images/lightbox-icon-close.png'); background-position:0px 0px; z-index:4; cursor:pointer; @@ -830,7 +830,7 @@ img.ug-sepia-effect{ .ug-lightbox-compact .ug-lightbox-button-close{ width:45px; height:41px; - background-image:url('../images/lightbox-icon-close-compact2.png'); + background-image:url('../../gallery/images/lightbox-icon-close-compact2.png'); } diff --git a/themes/default/public/gallery/themes/default/ug-theme-default.css b/themes/default/public/gallery/themes/default/ug-theme-default.css index fe3e48b..a22ccca 100644 --- a/themes/default/public/gallery/themes/default/ug-theme-default.css +++ b/themes/default/public/gallery/themes/default/ug-theme-default.css @@ -14,7 +14,7 @@ .ug-theme-default .ug-default-button-fullscreen{ position:absolute; - background-image:url('images/button_fullscreen.png'); + background-image:url('../../gallery/themes/default/images/button_fullscreen.png'); width:53px; height:50px; cursor:pointer; @@ -39,7 +39,7 @@ .ug-theme-default .ug-default-button-fullscreen-single{ position:absolute; - background-image:url('images/button_fullscreen_single.png'); + background-image:url('../../gallery/themes/default/images/button_fullscreen_single.png'); width:52px; height:50px; cursor:pointer; @@ -64,7 +64,7 @@ .ug-theme-default .ug-default-button-play{ position:absolute; - background-image:url('images/button_playpause.png'); + background-image:url('../../gallery/themes/default/images/button_playpause.png'); width:51px; height:50px; cursor:pointer; @@ -88,7 +88,7 @@ .ug-theme-default .ug-default-button-play-single{ position:absolute; - background-image:url('images/button_playpause_single.png'); + background-image:url('../../gallery/themes/default/images/button_playpause_single.png'); width:50px; height:50px; cursor:pointer; @@ -136,7 +136,7 @@ width:7px; height:7px; background-repeat:no-repeat; - background-image:url('images/arrow_down_up.png'); + background-image:url('../../gallery/themes/default/images/arrow_down_up.png'); background-position: 0px 0px; z-index:2; } diff --git a/themes/default/public/img/liberapay.svg b/themes/default/public/img/liberapay.svg new file mode 100644 index 0000000..1537ec9 --- /dev/null +++ b/themes/default/public/img/liberapay.svg @@ -0,0 +1,63 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/themes/default/public/img/tipeee-tip-btn.png b/themes/default/public/img/tipeee-tip-btn.png new file mode 100644 index 0000000..221237a Binary files /dev/null and b/themes/default/public/img/tipeee-tip-btn.png differ diff --git a/themes/default/public/js/lutim.js b/themes/default/public/js/lutim.js index c20621f..47affec 100644 --- a/themes/default/public/js/lutim.js +++ b/themes/default/public/js/lutim.js @@ -24,6 +24,22 @@ function delItem(short) { }); localStorage.setItem('images', JSON.stringify(files)); } +function updateItem(short, limit, del_at_view) { + var files = localStorage.getItem('images'); + if (files === null) { + files = new Array(); + } else { + files = JSON.parse(files); + } + $(files).each(function(index) { + if (files[index].real_short === short) { + files[index].del_at_view = del_at_view;; + files[index].limit = limit; + return false; + } + }); + localStorage.setItem('images', JSON.stringify(files)); +} function share(url) { new MozActivity({ name: 'share', @@ -84,6 +100,7 @@ $('document').ready(function() { var deleteday = ($('#delete-day').prop('checked')) ? 1 : 0; bindddz(firstview, deleteday); + initPaste(); $('#file-url-button').on('click', upload_url); $('#lutim-file-url').keydown( function(e) { diff --git a/themes/default/templates/gallery.html.ep b/themes/default/templates/gallery.html.ep index 3aac928..308f282 100644 --- a/themes/default/templates/gallery.html.ep +++ b/themes/default/templates/gallery.html.ep @@ -12,40 +12,3 @@ -%= stylesheet '/gallery/css/unite-gallery.css' -%= stylesheet '/gallery/themes/default/ug-theme-default.css' -%= javascript '/gallery/js/unitegallery.js' -%= javascript '/gallery/themes/tiles/ug-theme-tiles.js' -%= javascript '/js/jszip.min.js' -%= javascript '/js/FileSaver.min.js' -%= javascript begin -$(document).ready(function() { - var absUrl = '<%= url_for('/') %>'; - - var key = window.location.hash.substring(1); // Get key - // First, strip everything after the equal sign (=) which signals end of base64 string. - i = key.indexOf('='); if (i>-1) { key = key.substring(0,i+1); } - // If the equal sign was not present, some parameters may remain: - i = key.indexOf('&'); if (i>-1) { key = key.substring(0,i); } - - var keys = key.split(','); - - $('#download-all').attr('href', $('#download-all').attr('href')+keys.join('&i=')); - - var items = []; - keys.forEach(function(element, index, array) { - if (!element.match('xcf')) { - $('#gallery').append( - [ - '' - ].join('') - ); - } - }); - var api = $("#gallery").unitegallery({ - gallery_theme: "tiles", - tiles_max_columns: 4, - lightbox_overlay_color: "#DDD" - }); -}); -% end diff --git a/themes/default/templates/index.html.ep b/themes/default/templates/index.html.ep index 17f72ef..8d41c1e 100644 --- a/themes/default/templates/index.html.ep +++ b/themes/default/templates/index.html.ep @@ -207,6 +207,3 @@ - -%= include 'partial/common', format => 'js' -%= include 'partial/lutim', format => 'js', d => \%d diff --git a/themes/default/templates/layouts/default.html.ep b/themes/default/templates/layouts/default.html.ep index b88acec..34a604c 100644 --- a/themes/default/templates/layouts/default.html.ep +++ b/themes/default/templates/layouts/default.html.ep @@ -3,7 +3,6 @@ % my $twitter_url = 'https://twitter.com/share'; % my $url = url_for('/')->to_abs(); % $twitter_url .= '?url='.url_escape("$url") -% .'&via=framasky' % .'&text=Check out this %23Lutim instance! '; @@ -28,6 +27,12 @@ %= asset 'about.css' % } else { %= asset 'index.css' +% } +% if (current_route 'gallery') { + %= asset 'gallery.css' +% } +% if (!(current_route 'about')) { + %= javascript '/js/jquery-2.1.0.min.js' % } @@ -48,10 +53,12 @@ <%= l('License:') %> <%= link_to 'https://www.gnu.org/licenses/agpl-3.0.html' => begin %>AGPL<% end %> —  <%= link_to url_for('about') => begin %><%= l('Informations') %><% end %> —  <%= link_to 'https://framagit.org/luc/lutim' => (title => l('Fork me!')) => begin %><% end %>  - <%= link_to $twitter_url => (title => l('Share on Twitter')) => begin %><% end %>  - <%= link_to 'https://flattr.com/submit/auto?user_id=_SKy_&url='.$url.'&title=Lutim&category=software' => (title => 'Flattr this') => begin %><% end %>  + <%= link_to $twitter_url => (title => l('Share on Twitter')) => begin %><% end %>  + <%= link_to 'https://tipeee.com/fiat-tux' => (title => l('Support the author on Tipeee')) => begin %><%= l('Tipeee button') %><% end %>  + <%= link_to 'https://liberapay.com/sky' => (title => l('Support the author on Liberapay')) => begin %><%= l('Liberapay button') %><% end %>  <%= link_to 'bitcoin:1JCEtmx9pyzWfitMQj2pKAk8GNgyix7RmA?label=lutim' => (title => 'Give Bitcoins') => begin %><% end %> —  <%= link_to url_for('myfiles') => begin %><%= l('My images') %><% end %> —  + <%= link_to url_for('stats') => begin %><%= l('Instance\'s statistics') %><% end %> —  mozilla rocket logo <%= l('Install webapp') %>

@@ -66,18 +73,34 @@ <%= stash('stop_upload') %> % } + <%= content %> + %= javascript begin var manifestUrl = '<%== url_for('manifest.webapp')->to_abs() %>'; % end +% if (defined(config('piwik_img'))) { + +% } % if (current_route 'stats') { %= asset 'stats.js' % } elsif (!(current_route 'about')) { %= asset 'index.js' % } - <%= content %> - -% if (defined(config('piwik_img'))) { - +% if (current_route 'index') { + %= javascript '/partial/common.js' + %= javascript '/partial/lutim.js' +% } +% if (current_route 'gallery') { + %= javascript '/gallery/js/unitegallery.js' + %= javascript '/gallery/themes/tiles/ug-theme-tiles.js' + %= javascript '/js/jszip.min.js' + %= javascript '/js/FileSaver.min.js' + %= javascript '/partial/gallery.js' +% } +% if (current_route 'myfiles') { + %= javascript '/partial/common.js' + %= javascript '/js/moment-with-locales.min.js' + %= javascript '/partial/myfiles.js' % } diff --git a/themes/default/templates/myfiles.html.ep b/themes/default/templates/myfiles.html.ep index e9d2dda..bd8467b 100644 --- a/themes/default/templates/myfiles.html.ep +++ b/themes/default/templates/myfiles.html.ep @@ -6,10 +6,47 @@ <%= l('Only the images sent with this browser will be listed here. The informations are stored in localStorage: if you delete your localStorage data, you\'ll loose this informations.') %>

+ +
+ @@ -25,61 +62,3 @@ <%= link_to url_for('/') => ( class => "btn btn-primary btn-lg" ) => begin %><%= l('Back to homepage') %><% end%> - -%= include 'partial/common', format => 'js' -%= javascript begin - function populateFilesTable() { - var files = JSON.parse(localStorage.getItem('images')); - files.reverse(); - files.forEach(function(element, index, array) { - var real_short = element.real_short; - var vlink = link(element.short+'.'+element.ext, ''); - var del_view = (element.del_at_view) ? '' : ''; - var dlink = link(real_short, 'dl', element.token, false, true); - var limit = (element.limit === 0) ? '<%= l('No limit') %>' : moment.unix(element.limit * 86400 + element.created_at).locale(window.navigator.language).format('LLLL'); - var created_at = moment.unix(element.created_at).locale(window.navigator.language).format('LLLL'); - - var tr = ''; - $('#myfiles').append(tr); - $('#del-'+real_short).on('click', delImage); - - $.ajax({ - url : '<%== url_for('counter') %>', - type : 'POST', - data : { - 'short': real_short, - 'token': element.token - }, - success: function(data) { - if (data.success) { - if (data.enabled) { - $('#count-'+real_short).text(data.counter); - } else { - delItem(real_short); - $('#alert-'+real_short).remove(); - } - } else { - alert(data.msg); - } - }, - error: function() { - alert(element.filename+'<%= l(': Error while trying to get the counter.') %>'); - } - }); - }); - } -% end -%= javascript '/js/moment-with-locales.min.js' diff --git a/themes/default/templates/partial/common.js.ep b/themes/default/templates/partial/common.js.ep index 60c6788..2ec073d 100644 --- a/themes/default/templates/partial/common.js.ep +++ b/themes/default/templates/partial/common.js.ep @@ -1,55 +1,159 @@ % # vim:set sw=4 ts=4 sts=4 ft=javascript expandtab: -%= javascript begin - function delImage() { - var short = $(this).attr('data-short'); - var token = $(this).attr('data-token'); - $.ajax({ - url: '<%= url_for('/') %>d/'+short+'/'+token, - method: 'GET', - data: { - format: 'json' - }, - success: function(data) { - if (data.success) { - $('#alert-'+short).remove(); - evaluateCopyAll(); - delItem(short); - } else { - alert(data.msg); - } - }, - error: function() { - }, - complete: function() { - } - }); +window.gallery_url = '<%= url_for('gallery')->to_abs %>#'; +window.zip_url = '<%= url_for('zip')->to_abs %>?i='; +window.short_hash = {}; +window.zip_hash = {}; +function addToShortHash(short) { + window.short_hash[short] = 1; + console.debug(window.short_hash); + if (Object.keys(window.short_hash).length > 0) { + $('#gallery-url').removeClass('hidden'); + $('#gallery-url-input').val(window.gallery_url+Object.keys(window.short_hash).join(',')); + $('#gallery-url-link').attr('href', window.gallery_url+Object.keys(window.short_hash).join(',')); } - function link(url, dl, token, modify, only_url) { - if (token !== undefined) { - if (modify !== undefined && modify === true) { - return '<%== url_for('/m/')->to_abs() %>'+url+'/'+token; - } - var link = '<%== url_for('/')->to_abs() %>d/'+url+'/'+token; - if (only_url !== undefined && only_url === true) { - return link; - } - return [ - '', - '
', - '
', - '', - ' ', - '', - '
', - '', - '', - '', - '', - '
' - ].join(''); - } else if (dl !== '') { - url = url+'?'+dl; +} +function rmFromShortHash(short) { + delete window.short_hash[short]; + $('#gallery-url-input').val(window.gallery_url+Object.keys(window.short_hash).join(',')); + $('#gallery-url-link').attr('href', window.gallery_url+Object.keys(window.short_hash).join(',')); + if (Object.keys(window.short_hash).length === 0) { + $('#gallery-url').addClass('hidden'); + } +} +function addToZipHash(short) { + window.zip_hash[short] = 1; + if (Object.keys(window.zip_hash).length > 0) { + $('#zip-url').removeClass('hidden'); + $('#zip-url-input').val(window.zip_url+Object.keys(window.zip_hash).join('&i=')); + $('#zip-url-link').attr('href', window.zip_url+Object.keys(window.zip_hash).join('&i=')); + } +} +function rmFromZipHash(short) { + delete window.zip_hash[short]; + $('#zip-url-input').val(window.zip_url+Object.keys(window.zip_hash).join('&i=')); + $('#zip-url-link').attr('href', window.zip_url+Object.keys(window.zip_hash).join('&i=')); + if (Object.keys(window.zip_hash).length === 0) { + $('#zip-url').addClass('hidden'); + } +} +/* Stolen from https://github.com/mozilla-services/push-dev-dashboard/blob/3ad4de737380d0842f40c82301d1f748c1b20f2b/push/static/js/validation.js */ +function createNode(text) { + var node = document.createElement('pre'); + node.style.width = '1px'; + node.style.height = '1px'; + node.style.position = 'fixed'; + node.style.top = '5px'; + node.textContent = text; + return node; +} + +function copyNode(node) { + var selection = getSelection(); + selection.removeAllRanges(); + + var range = document.createRange(); + range.selectNodeContents(node); + selection.addRange(range); + + var success = document.execCommand('copy'); + selection.removeAllRanges(); + return success; +} + +function copyText(text) { + var node = createNode(text); + document.body.appendChild(node); + var success = copyNode(node); + document.body.removeChild(node); + return success; +} + +function copyInput(node) { + node.select(); + var success = document.execCommand('copy'); + getSelection().removeAllRanges(); + return success; +} +function copyToClipboard(el) { + el = el.siblings('input'); + try { + var successful = copyInput(el); + var msg = successful ? 'successful' : 'unsuccessful'; + console.debug('Copying text command was ' + msg); + if (!successful) { + throw new Error('Copying text command was ' + msg); } - return '<%== url_for('/')->to_abs() %>'+url; + } catch (err) { + prompt('<%= l('Hit Ctrl+C, then Enter to copy the short link') %>', el.val()); } -% end +} +function copyAllToClipboard() { + var text = new Array(); + $('.view-link-input').each(function(index) { + text.push($(this).val()); + }); + + try { + var successful = copyText(text.join("\n")); + var msg = successful ? 'successful' : 'unsuccessful'; + console.debug('Copying text command was ' + msg); + if (!successful) { + throw new Error('Copying text command was ' + msg); + } + } catch (err) { + prompt('<%= l('Hit Ctrl+C, then Enter to copy the short link') %>', text.join(" ")); + } + +} +function delImage() { + var short = $(this).attr('data-short'); + var token = $(this).attr('data-token'); + $.ajax({ + url: '<%= url_for('/') %>d/'+short+'/'+token, + method: 'GET', + data: { + format: 'json' + }, + success: function(data) { + if (data.success) { + $('#alert-'+short).remove(); + evaluateCopyAll(); + delItem(short); + } else { + alert(data.msg); + } + }, + error: function() { + }, + complete: function() { + } + }); +} +function link(url, dl, token, modify, only_url) { + if (token !== undefined) { + if (modify !== undefined && modify === true) { + return '<%== url_for('/m/')->to_abs() %>'+url+'/'+token; + } + var link = '<%== url_for('/')->to_abs() %>d/'+url+'/'+token; + if (only_url !== undefined && only_url === true) { + return link; + } + return [ + '', + '
', + '
', + '', + ' ', + '', + '
', + '', + '', + '', + '', + '
' + ].join(''); + } else if (dl !== '') { + url = url+'?'+dl; + } + return '<%== url_for('/')->to_abs() %>'+url; +} diff --git a/themes/default/templates/partial/gallery.js.ep b/themes/default/templates/partial/gallery.js.ep new file mode 100644 index 0000000..d83b3d0 --- /dev/null +++ b/themes/default/templates/partial/gallery.js.ep @@ -0,0 +1,30 @@ +% # vim:set sw=4 ts=4 sts=4 ft=javascript expandtab: +$(document).ready(function() { + var absUrl = '<%= url_for('/') %>'; + + var key = window.location.hash.substring(1); // Get key + // First, strip everything after the equal sign (=) which signals end of base64 string. + i = key.indexOf('='); if (i>-1) { key = key.substring(0,i+1); } + // If the equal sign was not present, some parameters may remain: + i = key.indexOf('&'); if (i>-1) { key = key.substring(0,i); } + + var keys = key.split(','); + + $('#download-all').attr('href', $('#download-all').attr('href')+keys.join('&i=')); + + var items = []; + keys.forEach(function(element, index, array) { + if (!element.match('xcf')) { + $('#gallery').append( + [ + '' + ].join('') + ); + } + }); + var api = $("#gallery").unitegallery({ + gallery_theme: "tiles", + tiles_max_columns: 4, + lightbox_overlay_color: "#DDD" + }); +}); diff --git a/themes/default/templates/partial/lutim.js.ep b/themes/default/templates/partial/lutim.js.ep index 73f1522..752a623 100644 --- a/themes/default/templates/partial/lutim.js.ep +++ b/themes/default/templates/partial/lutim.js.ep @@ -1,454 +1,468 @@ % # vim:set sw=4 ts=4 sts=4 ft=javascript expandtab: -%= javascript begin - window.gallery_url = '<%= url_for('gallery')->to_abs %>#'; - window.zip_url = '<%= url_for('zip')->to_abs %>?i='; - window.short_hash = {}; - window.zip_hash = {}; - function addToShortHash(short) { - window.short_hash[short] = 1; - console.debug(window.short_hash); - if (Object.keys(window.short_hash).length > 0) { - $('#gallery-url').removeClass('hidden'); - $('#gallery-url-input').val(window.gallery_url+Object.keys(window.short_hash).join(',')); - $('#gallery-url-link').attr('href', window.gallery_url+Object.keys(window.short_hash).join(',')); - } +function selectInput() { + $(this).select(); +} +function cleanName(name, empty) { + if (empty !== undefined && empty !== null && empty) { + return name.replace(/&(l|g)t;/g, '').replace(/"/g, '\''); + } else { + return name.replace(//g, '>'); } - function rmFromShortHash(short) { - delete window.short_hash[short]; - $('#gallery-url-input').val(window.gallery_url+Object.keys(window.short_hash).join(',')); - $('#gallery-url-link').attr('href', window.gallery_url+Object.keys(window.short_hash).join(',')); - if (Object.keys(window.short_hash).length === 0) { - $('#gallery-url').addClass('hidden'); - } - } - function addToZipHash(short) { - window.zip_hash[short] = 1; - if (Object.keys(window.zip_hash).length > 0) { - $('#zip-url').removeClass('hidden'); - $('#zip-url-input').val(window.zip_url+Object.keys(window.zip_hash).join('&i=')); - $('#zip-url-link').attr('href', window.zip_url+Object.keys(window.zip_hash).join('&i=')); - } - } - function rmFromZipHash(short) { - delete window.zip_hash[short]; - $('#zip-url-input').val(window.zip_url+Object.keys(window.zip_hash).join('&i=')); - $('#zip-url-link').attr('href', window.zip_url+Object.keys(window.zip_hash).join('&i=')); - if (Object.keys(window.zip_hash).length === 0) { - $('#zip-url').addClass('hidden'); - } - } - function selectInput() { - $(this).select(); - } - function tw_url(url) { - var btn = [ - '', - '', +} +function tw_url(url) { + var btn = [ + '', + '', + '' + ].join(''); + if (navigator.mozSetMessageHandler !== undefined) { + btn = btn+[ + '', + '', '' ].join(''); - if (navigator.mozSetMessageHandler !== undefined) { - btn = btn+[ - '', - '', - '' - ].join(''); + } + return btn +} +function modify(url, short) { + var limit = $('#day-'+short).val(); + var del_at_view = ($('#first-view-'+short).prop('checked')) ? 1 : 0; + $.ajax({ + url : url, + type : 'POST', + data : { + 'image_url' : '<%== url_for('/')->to_abs() %>'+short, + 'format' : 'json', + 'delete-day' : limit, + 'first-view' : del_at_view + }, + success: function(data) { + updateItem(short, limit, del_at_view); + alert(data.msg); + }, + error: function() { + alert('<%= l('Error while trying to modify the image.') %>'); } - return btn - } - function modify(url, short) { - $.ajax({ - url : url, - type : 'POST', - data : { - 'image_url' : '<%== url_for('/')->to_abs() %>'+short, - 'format' : 'json', - 'first-view' : ($('#first-view-'+short).prop('checked')) ? 1 : 0, - 'delete-day' : $('#day-'+short).val() - }, - success: function(data) { - alert(data.msg); - }, - error: function() { - alert('<%= l('Error while trying to modify the image.') %>'); - } - }); - } + }); +} - /* Stolen from https://github.com/mozilla-services/push-dev-dashboard/blob/3ad4de737380d0842f40c82301d1f748c1b20f2b/push/static/js/validation.js */ - function createNode(text) { - var node = document.createElement('pre'); - node.style.width = '1px'; - node.style.height = '1px'; - node.style.position = 'fixed'; - node.style.top = '5px'; - node.textContent = text; - return node; - } - - function copyNode(node) { - var selection = getSelection(); - selection.removeAllRanges(); - - var range = document.createRange(); - range.selectNodeContents(node); - selection.addRange(range); - - var success = document.execCommand('copy'); - selection.removeAllRanges(); - return success; - } - - function copyText(text) { - var node = createNode(text); - document.body.appendChild(node); - var success = copyNode(node); - document.body.removeChild(node); - return success; - } - - function copyInput(node) { - node.select(); - var success = document.execCommand('copy'); - getSelection().removeAllRanges(); - return success; - } - function copyToClipboard(el) { - el = el.siblings('input'); - try { - var successful = copyInput(el); - var msg = successful ? 'successful' : 'unsuccessful'; - console.debug('Copying text command was ' + msg); - if (!successful) { - throw new Error('Copying text command was ' + msg); - } - } catch (err) { - prompt('<%= l('Hit Ctrl+C, then Enter to copy the short link') %>', el.val()); - } - } - function copyAllToClipboard() { - var text = new Array(); - $('.view-link-input').each(function(index) { - text.push($(this).val()); - }); - - try { - var successful = copyText(text.join("\n")); - var msg = successful ? 'successful' : 'unsuccessful'; - console.debug('Copying text command was ' + msg); - if (!successful) { - throw new Error('Copying text command was ' + msg); - } - } catch (err) { - prompt('<%= l('Hit Ctrl+C, then Enter to copy the short link') %>', text.join(" ")); - } - - } - function buildMessage(success, msg) { - if(success) { - var s_url = link([msg.short, '.', msg.ext].join(''), ''); - var thumb = (msg.thumb !== null) ? [ - '
', - '', - '', msg.filename, ' thumbnail', - '', - '
' - ].join('') : '' - return [ - '
', - '', - '
', thumb, - '
', - '

', - '', - msg.filename, - '', - '

', - '
', - '
', - '', - '
', - '
', - '', - '', - '', - '
', - '', - '', - '', +function buildMessage(success, msg) { + if(success) { + var s_url = link([msg.short, '.', msg.ext].join(''), ''); + var thumb = (msg.thumb !== null) ? [ + '' + ].join('') : '' + return [ + '
', + '', + '
', thumb, + '
', + '

', + '', + msg.filename, + '', + '

', + '', + '
', + '', + '
', + '
', + '', + '', '', '
', + '', + '', + '', + '', '
', - '
', - '', - '
', - '
', - '', - '
', - '', - '', - '', + '
', + '', + '
', + '', + '
', + '
', + '', + '', '', '
', + '', + '', + '', + '', '
', - '
', - '', - '
', - '
', - '', - '', - '', - '
', - '', - '', - '', + '
', + '
', + '', + '
', + '
', + '', + '', '', + tw_url(msg.short), '
', + '', + '', + '', + '', '
', - '
', - '', - '
', - '
', - '', - '', - '', - tw_url(msg.short), - '
', - '', - '', - '', - '', - '
', + '
', + '
', + '
', + '', link(msg.real_short, '', msg.token), '', '
', - '
', - '
', - '', link(msg.real_short, '', msg.token), '', - '
', - '
', - '', - '
', + '
', + '', '
', - '
', - '
', - '
', - '', % for my $delay (qw/0 1 7 30 365/) { % my $text = ($delay == 7 || $delay == 30) ? l('%1 days', $delay) : $d->{'delay_'.$delay}; % if (config('max_delay')) { % if ($delay) { % if ($delay < config('max_delay')) { - '', + '', % } elsif ($delay == config('max_delay')) { - '', + '', % last; % } else { % my $text = ($delay == 1) ? l('24 hours') : l('%1 days', $delay); - '', + '', % last; % } % } % } else { - '', + '', % } % } - ' ', - '
', - '', - '
 ', - '', - '<%= l('Let\'s go!') %>', - '', - '
', - '', - '
', - '
' - ].join(''); - } else { - return [ - '
', - '', - '<%= l('Something bad happened') %>
', - msg.filename, - '
', - msg.msg, - '
' - ].join(''); - } - } - function bindddz(firstview, deleteday) { - $('#drag-and-drop-zone').dmUploader({ - url: '<%== url_for('/') %>', - dataType: 'json', - allowedTypes: 'image/*', - maxFileSize: <%= $max_file_size %>, - onNewFile: function(id, file){ - $('.messages').append([ - '
', - file.name, '
', - '
', - '
', - ' 0%', - '
', + ' ', + '
', + '', + '
 ', + '', + '<%= l('Let\'s go!') %>', + '', '
', - '
' - ].join('')); - }, - onUploadProgress: function(id, percent){ - var percentStr = ' '+percent+'%'; - $('#'+id).prop('aria-valuenow', percent); - $('#'+id).prop('style', 'width: '+percent+'%;'); - $('#'+id+'-text').html(percentStr); - }, - onUploadSuccess: function(id, data){ - $('#'+id+'-div').remove(); - if ($('#copy-all').length === 0 && data.success) { - $('.messages').prepend( - [ - '' - ].join('') - ); - } - $('.messages').append(buildMessage(data.success, data.msg)); - $('#del-'+data.msg.real_short).on('click', delImage); - if (data.success) { - addToShortHash(data.msg.short+'.'+data.msg.ext); - addToZipHash(data.msg.short); - $('.close').unbind('click', evaluateCopyAll); - $('.close').on('click', evaluateCopyAll); - $('input[type=\'text\']').unbind("click", selectInput); - $('input[type=\'text\']').on("click", selectInput); - addItem(data.msg); - } - }, - onUploadError: function(id, message){ - $('.messages').append(buildMessage(false, '')); - }, - onFileSizeError: function(file){ - $('.messages').append(buildMessage(false, { filename: file.name, msg: '<%= l('The file exceed the size limit (%1)', $max_file_size) %>'})); - } - }); - } - - function upload_url() { - var val = $('#lutim-file-url').val(); - if (val !== undefined && val !== '') { - $('#lutim-file-url').prop('disabled', 'disabled'); - $('.hidden-spin').css('display', 'block'); - $.ajax({ - url : '<%== url_for('/') %>', - type : 'POST', - data : { - 'lutim-file-url' : val, - 'format' : 'json', - 'first-view' : ($('#first-view').prop('checked')) ? 1 : 0, - 'crypt' : ($('#crypt').prop('checked')) ? 1 : 0, - 'delete-day' : $('#delete-day').val() - }, - success: function(data) { - $('.messages').append(buildMessage(data.success, data.msg)); - if (data.success) { - if ($('#copy-all').length === 0) { - $('.messages').prepend([ - '' - ].join('')); - } - $('#lutim-file-url').val(''); - addToShortHash(data.msg.short+'.'+data.msg.ext); - addToZipHash(data.msg.short); - $('.close').unbind('click', evaluateCopyAll); - $('.close').on('click', evaluateCopyAll); - addItem(data.msg); - } - }, - error: function() { - $('.messages').append(buildMessage(false, '')); - }, - complete: function() { - $('#lutim-file-url').prop('disabled', ''); - $('.hidden-spin').css('display', 'none'); - } - }); - } - } - - function fileUpload(file) { - var fd = new FormData(); - fd.append('file', file); - - fd.append('format', 'json'); - fd.append('first-view', ($('#first-view').prop('checked')) ? 1 : 0); - fd.append('crypt', ($('#crypt').prop('checked')) ? 1 : 0); - fd.append('delete-day', ($('#delete-day').val())); - - $('.messages').append([ - '
', file.name, '
', - '
', - '
', - ' 0%', - '
', + '', '
', '
' - ].join('')); - // Ajax Submit - $.ajax({ - url: '<%== url_for('/') %>', - type: 'POST', - dataType: 'json', - data: fd, - cache: false, - contentType: false, - processData: false, - forceSync: false, - xhr: function(){ - var xhrobj = $.ajaxSettings.xhr(); - if(xhrobj.upload){ - xhrobj.upload.addEventListener('progress', function(event) { - var percent = 0; - var position = event.loaded || event.position; - var total = event.total || e.totalSize; - if(event.lengthComputable){ - percent = Math.ceil(position / total * 100); - } - - var percentStr = ' '+percent+'%'; - $('#1').prop('aria-valuenow', percent); - $('#1').prop('style', 'width: '+percent+'%;'); - $('#1-text').html(percentStr); - }, false); - } - - return xhrobj; - }, - success: function (data, message, xhr){ - $('#1-div').remove(); - if ($('#copy-all').length === 0 && data.success) { - $('.messages').prepend([ + ].join(''); + } else { + return [ + '
', + '', + '<%= l('Something bad happened') %>
', + msg.filename, + '
', + msg.msg, + '
' + ].join(''); + } +} +function bindddz(firstview, deleteday) { + $('#drag-and-drop-zone').dmUploader({ + url: '<%== url_for('/') %>', + dataType: 'json', + allowedTypes: 'image/*', + maxFileSize: <%= config('max_file_size') %>, + onNewFile: function(id, file){ + $('.messages').append([ + '
', + cleanName(file.name), '
', + '
', + '
', + ' 0%', + '
', + '
', + '
' + ].join('')); + }, + onUploadProgress: function(id, percent){ + var percentStr = ' '+percent+'%'; + $('#'+id).prop('aria-valuenow', percent); + $('#'+id).prop('style', 'width: '+percent+'%;'); + $('#'+id+'-text').html(percentStr); + }, + onUploadSuccess: function(id, data){ + data.msg.filename = cleanName(data.msg.filename); + $('#'+id+'-div').remove(); + if ($('#copy-all').length === 0 && data.success) { + $('.messages').prepend( + [ '' - ].join('')); - } + ].join('') + ); + } + $('.messages').append(buildMessage(data.success, data.msg)); + $('#del-'+data.msg.real_short).on('click', function() { + rmFromShortHash(data.msg.short+'.'+data.msg.ext) + rmFromZipHash(data.msg.short); + }); + $('#del-'+data.msg.real_short).on('click', delImage); + if (data.success) { + addToShortHash(data.msg.short+'.'+data.msg.ext); + addToZipHash(data.msg.short); + $('.close').unbind('click', evaluateCopyAll); + $('.close').on('click', evaluateCopyAll); + $('input[type=\'text\']').unbind("click", selectInput); + $('input[type=\'text\']').on("click", selectInput); + addItem(data.msg); + } + }, + onUploadError: function(id, message){ + $('.messages').append(buildMessage(false, '')); + }, + onFileSizeError: function(file){ + $('.messages').append(buildMessage(false, { filename: file.name, msg: '<%= l('The file exceed the size limit (%1)', config('max_file_size')) %>'})); + } + }); +} + +function upload_url() { + var val = $('#lutim-file-url').val(); + if (val !== undefined && val !== '') { + $('#lutim-file-url').prop('disabled', 'disabled'); + $('.hidden-spin').css('display', 'block'); + $.ajax({ + url : '<%== url_for('/') %>', + type : 'POST', + data : { + 'lutim-file-url' : val, + 'format' : 'json', + 'first-view' : ($('#first-view').prop('checked')) ? 1 : 0, + 'crypt' : ($('#crypt').prop('checked')) ? 1 : 0, + 'delete-day' : $('#delete-day').val() + }, + success: function(data) { + data.msg.filename = cleanName(data.msg.filename); $('.messages').append(buildMessage(data.success, data.msg)); if (data.success) { + if ($('#copy-all').length === 0) { + $('.messages').prepend([ + '' + ].join('')); + } + $('#lutim-file-url').val(''); + addToShortHash(data.msg.short+'.'+data.msg.ext); + addToZipHash(data.msg.short); $('.close').unbind('click', evaluateCopyAll); $('.close').on('click', evaluateCopyAll); addItem(data.msg); } }, - error: function (xhr, status, errMsg){ + error: function() { $('.messages').append(buildMessage(false, '')); }, + complete: function() { + $('#lutim-file-url').prop('disabled', ''); + $('.hidden-spin').css('display', 'none'); + } }); } -% end +} + +function fileUpload(file) { + var fd = new FormData(); + fd.append('file', file); + + fd.append('format', 'json'); + fd.append('first-view', ($('#first-view').prop('checked')) ? 1 : 0); + fd.append('crypt', ($('#crypt').prop('checked')) ? 1 : 0); + fd.append('delete-day', ($('#delete-day').val())); + + $('.messages').append([ + '
', cleanName(file.name), '
', + '
', + '
', + ' 0%', + '
', + '
', + '
' + ].join('')); + // Ajax Submit + $.ajax({ + url: '<%== url_for('/') %>', + type: 'POST', + dataType: 'json', + data: fd, + cache: false, + contentType: false, + processData: false, + forceSync: false, + xhr: function(){ + var xhrobj = $.ajaxSettings.xhr(); + if(xhrobj.upload){ + xhrobj.upload.addEventListener('progress', function(event) { + var percent = 0; + var position = event.loaded || event.position; + var total = event.total || e.totalSize; + if(event.lengthComputable){ + percent = Math.ceil(position / total * 100); + } + + var percentStr = ' '+percent+'%'; + $('#1').prop('aria-valuenow', percent); + $('#1').prop('style', 'width: '+percent+'%;'); + $('#1-text').html(percentStr); + }, false); + } + + return xhrobj; + }, + success: function (data, message, xhr){ + $('#1-div').remove(); + if ($('#copy-all').length === 0 && data.success) { + $('.messages').prepend([ + '' + ].join('')); + } + data.msg.filename = cleanName(data.msg.filename); + $('.messages').append(buildMessage(data.success, data.msg)); + if (data.success) { + $('.close').unbind('click', evaluateCopyAll); + $('.close').on('click', evaluateCopyAll); + addItem(data.msg); + } + }, + error: function (xhr, status, errMsg){ + $('.messages').append(buildMessage(false, '')); + }, + }); +} + +function initPaste() { + /* + actually FF and Chrome doesn't handle paste events the same way... + for ff we need to create a editable div and register an event to it. + When user paste, the image is "really" pasted in the div. Then, we need to iterate throught + the div childs to get images. Previsouly FF didn't have the paste event so it was esay to figure on wich browser we were. + But firefox now have a paste event so I test it... + + on Chrome the file object is directlyt in the clipboard. + */ + var b = 'FF'; + try { + //FF + var cbe = new ClipboardEvent('hop'); + } catch(hop) { + //under webkkit Clipboard doesn't have arguments... + b = 'WK' + } + if (b === 'FF') { + var pasteDiv = document.createElement('div'); + pasteDiv.addEventListener('paste', onPasteFF); + pasteDiv.setAttribute('class', 'pasteZone'); + pasteDiv.setAttribute('contenteditable', true); + + document.getElementsByTagName('body')[0].appendChild(pasteDiv); + pasteDiv.focus(); + + document.addEventListener('click', function(event) { + var t = $(event.target); + + switch (t[0].nodeName.toUpperCase()) { + case 'A': + case 'BUTTON': + case 'INPUT': + case 'SELECT': + case 'SPAN': + case 'LABEL': + break; + default: + if (t[0].parentNode.nodeName.toUpperCase() !== 'SELECT') { + pasteDiv.focus(); + } + } + }); + } else { + document.addEventListener('paste', onPaste); + } +} + +function waitforpastedata(elem, savedcontent) { + if (elem.childNodes && elem.childNodes.length > 0) { + processpaste(elem, savedcontent); + } else { + var that = { + e: elem, + s: savedcontent + }; + that.callself = function () { + waitforpastedata(that.e, that.s); + } + setTimeout(that.callself, 20); + } +} + +function processpaste(elem, savedcontent) { + var pasteZone = document.getElementsByClassName('pasteZone')[0]; + var f = new Image(); + + f.onload = function(){ + var canvas = document.createElement('canvas'); + canvas.width = f.width; + canvas.height = f.height; + + var ctx = canvas.getContext('2d'); + ctx.drawImage(f, 0, 0, canvas.width, canvas.height); + + canvas.toBlob(function(blob) { + var url = window.URL.createObjectURL(blob); + fileUpload(blob); + }); + } + + f.src = pasteZone.childNodes[0].src; + + pasteZone.innerHTML = ''; +} + +function onPasteFF(e) { + var pasteZone = document.getElementsByClassName('pasteZone')[0]; + waitforpastedata(pasteZone, 'savedcontent'); +} + +function onPaste(e) { + var items = e.clipboardData.items; + for(var i = 0; i < items.length; i++) { + var item = items[i]; + if (/image/.test(item.type)) { + var file = item.getAsFile(); + fileUpload(file); + } else { + //not image.. + } + } +} diff --git a/themes/default/templates/partial/myfiles.js.ep b/themes/default/templates/partial/myfiles.js.ep new file mode 100644 index 0000000..f3e3050 --- /dev/null +++ b/themes/default/templates/partial/myfiles.js.ep @@ -0,0 +1,61 @@ +% # vim:set sw=4 ts=4 sts=4 ft=javascript expandtab: +function onCheck(e, short, ext) { + if (e.is(':checked')) { + addToShortHash(short+'.'+ext); + addToZipHash(short); + } else { + rmFromShortHash(short+'.'+ext); + rmFromZipHash(short); + } +} +function populateFilesTable() { + var files = JSON.parse(localStorage.getItem('images')); + files.reverse(); + files.forEach(function(element, index, array) { + var real_short = element.real_short; + var vlink = link(element.short+'.'+element.ext, ''); + var del_view = (element.del_at_view) ? '' : ''; + var dlink = link(real_short, 'dl', element.token, false, true); + var limit = (element.limit === 0) ? '<%= l('No limit') %>' : moment.unix(element.limit * 86400 + element.created_at).locale(window.navigator.language).format('LLLL'); + var created_at = moment.unix(element.created_at).locale(window.navigator.language).format('LLLL'); + + var tr = [ + '
', + '', + '', + '', + '', + '', + '', + '', + '', + '' + ].join(''); + $('#myfiles').append(tr); + $('#del-'+real_short).on('click', delImage); + + $.ajax({ + url : '<%== url_for('counter') %>', + type : 'POST', + data : { + 'short': real_short, + 'token': element.token + }, + success: function(data) { + if (data.success) { + if (data.enabled) { + $('#count-'+real_short).text(data.counter); + } else { + delItem(real_short); + $('#alert-'+real_short).remove(); + } + } else { + alert(data.msg); + } + }, + error: function() { + alert(element.filename+'<%= l(': Error while trying to get the counter.') %>'); + } + }); + }); +} diff --git a/themes/default/templates/zip.html.ep b/themes/default/templates/zip.html.ep new file mode 100644 index 0000000..6c6e1c5 --- /dev/null +++ b/themes/default/templates/zip.html.ep @@ -0,0 +1,31 @@ +% # vim:set sts=4 sw=4 ts=4 ft=html.epl expandtab: +

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

+
+
+

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

+
+ +
+

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

+
+ +
    +% for my $i (@{$urls}) { +
  • <%= $i %>
  • +% } +
+%= javascript begin +$(document).ready(function() { + $('.jsononly').show(); + $('.dl-zip').each(function(index) { + this.click(); + }); +}); +% end diff --git a/utilities/locales_files.txt b/utilities/locales_files.txt deleted file mode 100644 index d2491d4..0000000 --- a/utilities/locales_files.txt +++ /dev/null @@ -1,11 +0,0 @@ -themes/default/templates/about.html.ep -themes/default/templates/index.html.ep -themes/default/templates/stats.html.ep -themes/default/templates/myfiles.html.ep -themes/default/templates/gallery.html.ep -themes/default/templates/layouts/default.html.ep -themes/default/templates/partial/common.js.ep -themes/default/templates/partial/lutim.js.ep -lib/Lutim.pm -lib/Lutim/Controller.pm -lib/Lutim/Command/cron/stats.pm diff --git a/utilities/lutim-minion@.service b/utilities/lutim-minion@.service new file mode 100644 index 0000000..ddb75e3 --- /dev/null +++ b/utilities/lutim-minion@.service @@ -0,0 +1,13 @@ +[Unit] +Description=Image hosting and sharing service job queue +Documentation=https://framagit.org/luc/lutim +After=lutim.service + +[Service] +Type=simple +User=www-data +WorkingDirectory=/var/www/lutim/ +ExecStart=/usr/local/bin/carton exec script/application minion worker -m production + +[Install] +WantedBy=multi-user.target diff --git a/utilities/lutim.service b/utilities/lutim.service index 13a1560..4460f53 100644 --- a/utilities/lutim.service +++ b/utilities/lutim.service @@ -3,6 +3,8 @@ Description=Image hosting and sharing service Documentation=https://framagit.org/luc/lutim Requires=network.target After=network.target +#Requires=postgresql.service +#After=postgresql.service [Service] Type=forking diff --git a/utilities/migrations.sql b/utilities/migrations.sql new file mode 100644 index 0000000..7663d03 --- /dev/null +++ b/utilities/migrations.sql @@ -0,0 +1,20 @@ +-- 1 up +CREATE TABLE IF NOT EXISTS lutim ( + short text PRIMARY KEY, + path text default null, + footprint text default null, + enabled integer, + mediatype text default null, + filename text default null, + counter integer default 0, + delete_at_first_view integer default null, + delete_at_day integer default null, + created_at integer default null, + created_by text default null, + last_access_at integer default null, + mod_token text default null, + width integer default null, + height integer default null +); +-- 1 down +DROP TABLE lutim;
<%= l('File name') %> <%= l('View link') %> <%= l('Counter') %>
' - +element.filename - +'' - +''+vlink+'' - +'' - +'' - +del_view - +'' - +created_at - +'' - +limit - +'' - +''+dlink+'' - +'
', element.filename.replace(//g, '>'), '',vlink,'', del_view, '', created_at, '', limit, '',dlink,'