From 028d463547e862f9fe132c3a732d799e45424a65 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 24 May 2012 14:58:39 +0200 Subject: [PATCH] initial commit 'music', 'art' are usable 'index', 'webpage', 'litterature' are not yet implemented or dummies works with (slightly modified) starter-package by Piratenpartei Bremen (see www.kulturtankstelle.net) --- README.txt | 75 ++++ cgi-bin/kt | 35 ++ kulturtankstelle/config.xml | 71 ++++ kulturtankstelle/header.jpg | Bin 0 -> 10837 bytes kulturtankstelle/licenses/cc-by-nc-nd.png | Bin 0 -> 688 bytes kulturtankstelle/licenses/cc-by-nc-sa.png | Bin 0 -> 697 bytes kulturtankstelle/licenses/cc-by-nc.png | Bin 0 -> 672 bytes kulturtankstelle/licenses/cc-by-nd.png | Bin 0 -> 665 bytes kulturtankstelle/licenses/cc-by-sa.png | Bin 0 -> 672 bytes kulturtankstelle/licenses/cc-by.png | Bin 0 -> 640 bytes kulturtankstelle/modules/KTart.pm | 311 ++++++++++++++ kulturtankstelle/modules/KTmain.pm | 400 ++++++++++++++++++ kulturtankstelle/modules/KTmusic.pm | 321 ++++++++++++++ kulturtankstelle/style.css | 168 ++++++++ .../templates/kt_art_details.tmpl | 40 ++ .../templates/kt_art_overview.tmpl | 27 ++ kulturtankstelle/templates/kt_footer.tmpl | 2 + kulturtankstelle/templates/kt_header.tmpl | 7 + kulturtankstelle/templates/kt_index.tmpl | 7 + .../templates/kt_language_selector.tmpl | 3 + kulturtankstelle/templates/kt_menu.tmpl | 7 + .../templates/kt_music_details.tmpl | 50 +++ .../templates/kt_music_overview.tmpl | 27 ++ 23 files changed, 1551 insertions(+) create mode 100644 README.txt create mode 100755 cgi-bin/kt create mode 100644 kulturtankstelle/config.xml create mode 100644 kulturtankstelle/header.jpg create mode 100644 kulturtankstelle/licenses/cc-by-nc-nd.png create mode 100644 kulturtankstelle/licenses/cc-by-nc-sa.png create mode 100644 kulturtankstelle/licenses/cc-by-nc.png create mode 100644 kulturtankstelle/licenses/cc-by-nd.png create mode 100644 kulturtankstelle/licenses/cc-by-sa.png create mode 100644 kulturtankstelle/licenses/cc-by.png create mode 100644 kulturtankstelle/modules/KTart.pm create mode 100644 kulturtankstelle/modules/KTmain.pm create mode 100644 kulturtankstelle/modules/KTmusic.pm create mode 100644 kulturtankstelle/style.css create mode 100644 kulturtankstelle/templates/kt_art_details.tmpl create mode 100644 kulturtankstelle/templates/kt_art_overview.tmpl create mode 100644 kulturtankstelle/templates/kt_footer.tmpl create mode 100644 kulturtankstelle/templates/kt_header.tmpl create mode 100644 kulturtankstelle/templates/kt_index.tmpl create mode 100644 kulturtankstelle/templates/kt_language_selector.tmpl create mode 100644 kulturtankstelle/templates/kt_menu.tmpl create mode 100644 kulturtankstelle/templates/kt_music_details.tmpl create mode 100644 kulturtankstelle/templates/kt_music_overview.tmpl diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..cddc9da --- /dev/null +++ b/README.txt @@ -0,0 +1,75 @@ +Kulturtankstelle +================ + +Kontakt: oder Mailingliste unter + + +Inhalte: getestet mit leicht verändertem Starter-Paket der Bremer Piraten + +- cgi-bin/kt: +--- Hauptprogramm der Kulturtankstelle +--- Perl, CGI-Script +--- verwendet HTML::Template, XML::Simple, (optional) CGI::Carp +--- Anpassungen nötig: +----- 'use lib' muss auf Modulpfad zeigen +----- $configfile muss auf config.xml zeigen + +- kulturtankstelle/config.xml: +--- zentrale Konfigurationsdatei der Kulturtankstelle + +--- enthält Pfade: +----- root: Programmdateien im Dateisystem +----- webroot: Programmdateien im HTTP-Server +----- content: Inhalte im Dateisystem +----- webcontent: Inhalte im HTTP-Server + +--- enthält Menüeinträge: +----- 'id' ist ein frei wählbarer Eintrag im Menü +----- 'type' ist ein vorgefertigter Seitentyp: +------- "index": Standardeintrag, derzeit nicht implementiert +------- "music": Albenübersicht und Albumdetails +------- "art": Übersicht aller Kollektionen und Details einer Kollektion +------- "litterature": eBooks, derzeit nicht implementiert +------- "webpage": lokal vorhandene Webseite, derzeit nicht implementiert +----- 'folder' enthält den Pfad relativ zum Ordner für die Inhalte + +--- enthält Übersetzungen aller im Programm verwendeten Strings + +- kulturtankstelle/style.css: +--- zentrales Stylesheet + +- kulturtankstelle/licenses/*: +--- Bilder und HTML-Lizenztexte der CC-Lizenzen +--- jeder Content-Teil darf aber auch eigene Lizenzen besitzen + +- kulturtankstelle/templates/*: +--- Templates aller Seiten +--- siehe Dokumentation zu HTML::Template für Aufbau + +- kulturtankstelle/modules/* +--- enthält die "Intelligenz" der Kulturtankstelle + +--- KTmain.pm: +----- read_config() => liest und parst config.xml +----- read_templates() => liest alle Templates ein +----- print_header() => zeigt kt_header.tmpl an +----- print_footer() => zeigt kt_footer.tmpl +----- print_menu() => zeigt kt_menu.tmpl an +----- print_language_selector() => zeigt kt_language_selector.tmpl an +----- print_content() => verweist auf print_content() im entsprechenden Modul +----- get_language() => wählt Sprache aus (URL, Browser-Settings oder 'de') +----- get_string() => übersetzt String +----- get_license() => erkennt bekannte Lizenzen und gibt Bild/URL zurück + +--- KTmusic.pm: +----- init() => initialisiert Musik-Teil +----- print_content() => verweist auf print_overview oder print_albumdetails +----- print_overview() => zeigt Albumliste +----- print_albumdetails() => zeigt Albumdetails +----- get_time() => zerlegt Sekundenanzahl in lesbaren String + +--- KTart.pm: +----- init() => initialisiert Kunst-Teil +----- print_content() => verweist auf print_overview oder print_details +----- print_overview() => zeigt Liste aller Kollektionen +----- print_details() => zeigt Details einer Kollektion diff --git a/cgi-bin/kt b/cgi-bin/kt new file mode 100755 index 0000000..f0d135e --- /dev/null +++ b/cgi-bin/kt @@ -0,0 +1,35 @@ +#!/usr/bin/perl -w +use strict; +use 5.010; + +# Standard perl modules +use CGI::Carp 'fatalsToBrowser'; # no more HTTP 500 errors :-) +use HTML::Template; +use XML::Simple; +use Data::Dumper; + +# Kulturtankstelle modules +use lib '/srv/www/kulturtankstelle/modules'; +use KTmain; +use KTmusic; +use KTart; + +# Global variables +my $configfile = '/srv/www/kulturtankstelle/config.xml'; +my $config; # XML configuration file +my $templates; # HTML templates + +# Initialization +print "Content-Type: text/html\r\n\r\n"; +$config = &KTmain::read_config($configfile) or die "Error reading config"; +$templates = &KTmain::read_templates($config) or die "Error reading templates"; + +&KTmusic::init($config); +&KTart::init($config); + +# Send out document +&KTmain::print_header($config, $templates->{header}); +&KTmain::print_menu($config, $templates->{menu}); +&KTmain::print_language_selector($config, $templates->{language_selector}); +&KTmain::print_content($config, $templates); +&KTmain::print_footer($config, $templates->{footer}); diff --git a/kulturtankstelle/config.xml b/kulturtankstelle/config.xml new file mode 100644 index 0000000..b2a6f90 --- /dev/null +++ b/kulturtankstelle/config.xml @@ -0,0 +1,71 @@ + + + + /srv/www/kulturtankstelle/ + /kulturtankstelle/ + /srv/www/data/ + /data/ + + + + + + + + + + + + + Startseite + Musik + Kunst + E-Books + Informationen + Lizenz + Stücke + Artist + Musik: Übersicht + Musik: Details + Track + Titel + Länge + [ Album herunterladen ] + Download + [ laden ] + Kunst: Übersicht + Kunst: Details + Künster + Stücke + Entstehungsjahr + Beschreibung + [ Kollection herunterladen ] + + + + start page + music + art + e-books + information + license + tracks + artist + music: overview + music: album details + track + title + length + download + [ get ] + [ fetch album ] + art: overview + art: collection details + artist + pieces + year + description + [ fetch collection ] + + + diff --git a/kulturtankstelle/header.jpg b/kulturtankstelle/header.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1414c3306be9a39c01127fbf54383fe39d11a7a5 GIT binary patch literal 10837 zcmbVyby(a#v+v>##ogVDOQ94fUfi|CS=?QU7K(d|EiQ${U5gYg?u&bIce_j9-+Saf z_m6XKc=BYv$z+mGGRb6Sd7gV-1-z1%mXij+zyJU+&_BTQ8ulM4PoM<=AScHHKn4Jy z83zXCrRi@b`G=N;ev|$en&}@J7Fy2*0}H@}miExh4W;p*r7tw&!v3cm;1~G6^5UTN z%g}78VdZ9LLdDI&#mm73;C{`;E&Q5Wm|K8~n@5<7N0>(dfCvD@Apzi_ysx>rxnSb| zMZ>_t0RY+m)N{Rl4U_$!W5E7Hr$GC_{X>UA>6e5EfP;biI|Ha(!2bjl4D7#V%m!Tw z*njBSSAT^8p8sDfxd4y^AR{6oAtE3nAt9llAfuw=VW6X-p%dfaV&RdKP*RYSkdaZ* zaWGQRu+fr{F$plUz2@TO<)vg45*6eY;o#xreufHxK|w)5M?)vVz#!tLCZp#5U#I7v z0BmG{GvG5E3=IGl8wL&==D7zz3EfZxn7`>?AfVr{aPSC-NXRItXi$c_R{&TTI5=2% zI0OWE=(@xBy(~67HUbVcmpCG>sxcCc6CQV9d=4_LL{%rg+V}|_kBM^-3Mv615itop z10xeN3ojqPfS{1D@bQ!{f5ODmwYi>sTvho_f!a7bv_m+*+M z35iL`DXHJSr{(757Zes1m;9)%sjaJTXl!ck>hAf~+t)uZI59ajJu^Eu4_RB^*xcIQ z`LnxsdUk$sd3Akrd-sA12D-KXPX9vof8oN0;(~>Thl59Y!36{B@d6wh9)X$*5l37V z$=C^(hC2`$Pa;02suP8lN9_dP#CaT*fR1;K{`3XfUu6F?U_t+1$o>P^f8v4w(BWX9 zn+Jyt5CdFAzwH{n_(OiUPM1xWT;e}a@C+Db4d_<|J_D#^JN9EQigUtfVR1UeKnm;Q*G1_L1y$K3i`NYjeR)Bc*P+wuttj!oQqK$v&$#V8O4n@j!yhK(f~REVmLmvo{6X_x=UjbcAY=t^N;C@&wwmPe~H8c zh{MBq@I_f0r|$S=aYzbJH)mz9%$nZY4}Yh=*jbqQ?HN!5Tsa@Xf=(9V@xonr%M~!n z_fXRQ!X(B5FZNG;@v$wKpx08C7M_|aP%(|EM>%}5eTiE%O zBesNB4?2U7d}@3K$lHqT;XaPP!^&sG!~NQqavO5!!b1dJ`%@IXe97%TZVyySFFuHH zbMn~SqJJeGo7t!LbFx*laNdwViw=u=lS^ozxDJbG-lo1m*ssP!0=1HnGQ5JcpF>gwwi`S#AbjsTy4vb+8Xx z>O~m?TXfb$L~$2w^t=i7JSc=$wPIr}arT&PD3GJf+w1;RS^1NOiL+_T#3G82KBJ)wdUn(yIn_^zCJH*JMPR1SbL+;!hM(I+{&06=g8WA za{WtR&W*azx*Wfz&ORUnBx%qW?uN{}#6r$72K!4$aMwUFCD^HCah;EbUW_LzISUJy ze=GdQAw}dRzJYLYM!ug?Of{A3r$K3Pq+kUj;OYu~U(oPyYd-D()U4b>pDesIQW1Kl0!&V#uKNqNSMy9X1) zrF8LS>6^oA?~r%0$Xx(0fOh1v(Td~`k%EGtcS|?;>+37^c4H+#+PSW^oFU>8>t>9s z1(k6(sbyjYjO4@`ZDo;^W%`NVftq}8oH8?)vx9r$jl{1EP3Gjkt?Ts4UjIlXF|K|F zC{C99j{|NKbe`^fURQA2t0!EQrr21H-v;~?wiLLkwIp6IEiGoJtzABSci7sa?EmFf z+h@&Zm-iU}57b7ppQW};`lelqQMV)faBkG^z~LcB?fy>Jk^ibf@5YAUP@vmN+xhzz z9c6Y!N!Ksw%=p!H(xhWrkON^We^dgnIh(SZIttxCdG1DA-B6}muRJ$iM7&?6Vm2`9 zRJ+y9$*z4HIm1{bDBGi~0=*|?1&hPCOO--0@$i?X+}T71$bv=wl6Egfep0S^wvO?L z=exNmp0`$c0a*8syIs+4d|7pIr-OHiM=7Z4@r&YcD>;nn`M|NN&W+yQwwUm4Xf4se zvcE+|VwzfQ73R3U%)>LF|N6F~?CMO=r^$h_m5}YgazxwVB<+spXWAlUHq37MkI5ca zwX%B5<#y`v+9AWxP-yaYpNaqpXssi1`a$(E!<3b5HI#8myCUe!GAbi{wDP=&!+q*linLhRqeUn=qpu$Wl3-z7Mn zD1$(m2*mC-9$7LMCG2Q)273Qg-KizYap#@V{w{B)S{65srQwHn9X1K*GB);2ceu#B zZ%*DxYjaw?2c{agCHcM4q+NaFn8W3$SAmO>-Tz2$wePu1~x~`r109nWzfJxEEZ^g~3H#045~&ni zbT85JdWdA}m^U@x8de{%*5U1w#QZ6a0!0<4luWt6M!SVmfLGEouL* z5h6o@rT{A5lY{AUo^}?ql(i@?Gdm5=o<|%+>T!zLMbn}D;@q=w?@7aVR@c~=cld)DNmG`r0~dOn-?Wr98Qon3 zX4c6mmdua7dJ;D3adT>3p4z?O{0@ zyihl%>ArTYSh`_mTUw2;_0{>FitY$kn`1(NQ;RmaUi7NDkm$;)H$Jd8i&>gwK>8Wr z7b7;6NbAa*XSrrjE*SbU?c`p#(hQ#w&Mx|T!OgJ{w6 zP4h7LR(1>XwaeIcrLRKwNQ>>hw{5s|jNubJwRl4k<9zud-#i4PRkByTa= zCMuDVKDDeG2t>oWQdEHI4CqB?zJ9z^zTl&SY7E+6jad|No^E&u%=@b`-?8pOo&m1v z;Eqjn5Y#}aQ$GV#Ku2EzJHAe9`KJP33L5}^If#EEo=y&pF!DX^H}?=pFJ80Rg{e=? zP8K%CQh1u!Nh+sYE4<^3_dizbey~X-RLbA&FmIX->k;&+uyBNAHJIn=vd4T2wCGb^ z*w+=7PPu!iW^G}E$K?fuI;$4!TU*R%IPo7Z+mn60KwDB;kUZ&{UvT2>28!P9*>sgk zt*I3$=nfp;Wi{~H4Ux|eEwhR{_k(-eT6V1$MD5{?g;g6WOHSjPG)9pVQ^ZnR4d*<4X}J7 zyR<`HC%Sx7=oK$0QUkNx6hO%{>d48yC}*#nWT+%jxvOJDKW6JX=eoObF6IwvMHm?9 z)0;e*id(sHKbLb?t=!@<;Nu$C5p1^JRrsjT(f=pOQh4;$#l(s;u3{F}tKE+I>(8Y9 zVN;1y+LXn=-0}>$Ke)>lZMq$?2uv|d@Zp>`>E_z{*%(GG^I>S^zF;rG@ig4Q+u?#O^l zoAqt6d5R@n!hsy$CBkx~jSq2*9~ZHH@U=~P>YB%w0+W?_wkDxlGs+Ev+7sV8M%AN{ zVpFxYQO;A2N_$sQHx;bp;6y0AFPEe%hwLe*{k^KebuLB^z8LvL@0AN2#OE`#qGJNh z3t_Gl8JJ>=(bCe05KuXi;yH;6VyQlc={1CN<~4tdv`Rlt-H$EsP7M>GF1*p39IT0T zElN#pKLsBs3F|jJUNDPIi0v$O9OoF;masUfE^cM&DkudP7y3T~p8OV|c)vm4@*wwT zKzpdQ8E(LjfSkXZq5pR?RGJsLxgRsmxUNGL9Z`47i;AP30W5&dn02>M*kLN7gWk+5 zsF$_V3c8-p{R((HDfV!k_;k_|LGcyr)KJd1Y!KAN9=!TQ2G3J zTZi=AcsaA;Gv%Uzk?G105r;jfCvMJ z42uGF^W|Rwpuq_kICwO46et^%>&43lAYdaR;ZWmpiMt@<;nS#U8apLab<%P};}B}< zf$`N{;{{Ca0wzAQO59=zQGK-0#hsm?ZHr4Z^aQntIYcbQcxWK(x~M?(0hTv0hMD& zI)=wT(IPjV7FtlwHULf{V-nm5rknwfndue=LK<*(X$3#j;l|cC^Ls9y{akZwYDOXb z!aryOl|cx_YTD=?@KW-;CccxSyu!boO+?7JzopdQf7q|y%(})LUH=1xOG*y?Km3vKwoQp8?0b=v61CAZ{`i;aZ`-c8Eti)$veQIzZEL7t z0Vcv*TnRj-=7!D)MB&_Db_Ilv@@g=>Sg0C1R@tPswx`z)T|kvk;6w+*svF9s`Wx-e z)Y&)J!@~crPM=$z)-Q*T-Pd*5i|^)Szj@NUWBIfz zX@=VQ$#t|Lm4k!7NRC>T4AzRYE;2f+vm{@}uC}-_^J2Sr23)d4GOak^w1wYn2j77vb zg~c6<->22+e>QfI)wlAiRC9gh(pg(#^AU8PGHJF)$om{0vUzLueml8^V}pV%oCArj z41q1`v)sCi+C(8ueXf@y%&)tc{b1(qqw6UBAFplIZH1%xAFMx>oLpBf~i zywO98e8HN$TqK z;9y)Jfe%vfO$(f2oK|F)xir5V@jF+#fCea(-tFP;6>8Od8{E&h-wt6kyJg|NMKvE3 zuSiz|?m@?Wu#s3+`m4z*fFWx2QWr znB{oI!2hwYDd}|JY)tOnaQ&CJf;vv)#CIX!R1^Y8lwMOy-R6LuF-ZD=pDMQ5F^p*l z&d%~$nXfl3(X6$cl1`E%p-`jT7{snqE^zPq7`4c*9l>O6z(xQ;aPM>Y+DV@he^HbvQLL7CCeH>$zV1EwW2dVM1#qGkmJL(^n45 zOEOjSY853mz##)aNy_68l>?df%!QgnN$Dkr5G@?_w&)4&oUOc~-4cbv>U133L28a# zyfd7F9D_a&a=~(o10$42;u+GxCD^G|K{BsjdJY_R#sf|nma_UsarAZd;SjccuqVm}*ZyEeb6mU8OfRMPt9`5F7ZAZ}(N}UwnJJ69Ee@vC({n?owwoUN>d~@1ZzqWImh9`2 zV`g>wpRG)vI?7QQPbqGruo#JqN#U<}+lyqT9X;_o!=DuS*d2a&W|H2|MN(4vO*iF7 zY>$vJHZJ_hJ%#}H-&mLt`;9eha)|WruvlF<;GO0uRVH%mETj_03?^)POoR`5&@)S8 zp1@zYsEW^}6)6g9Ov%vl*BR?vYiVDq++E${t{cFP(o&7~F^KLeAxUvroykrpWKjmj zw^dBJ>f*1Y0i2NDJT#X&m^!=UUzUD;m4_gAZf?@Ne#}ANVO}3dKUH}iPl^$}ih2^C z#rL}{nhTqOp{Aj>lSP3=TtdkuG{$<@XL_V-J1G#>V0#1HI3Q`>V~M&1*cn!;wjgLc zz!@{mIGc$~9wDi#wQRhR3S83-rW z7!5Q_B4APWe2wNCcHsRyrkmZ>R~aKi-Qkln1hmWsZ>+7aXM7vizLqZ^UlW_lH-04Z2@~S)#SxjyPm$E_94c~P z&bk%r`<*mRN!rGKfkpLkRMRh|4XY50YF<}0STu-NZDq7Q-jZ5OD+UwF#Cv0OOSG27 zm)BHN)TkF~lS~!gs-fnjB9KX6{7#`z2pUx26Wq$uW-T)j|bimqXaBs?#aoM_f?Ym&aJtIDT!LXl9?I*U9{Ov9K{>g)C2_ zeX4gwVi=;mS8X}J=jjKR3FC0tvwc5Og0Dz4>Yf2VX=B&#F<8=qs&@kt$Gns7N-}F0 zxWAkl+;3+A0}?B}L+(nF%d%#)1bu2izT@pm{mna>WxyqIP9uY@pT?N{+kfCoiFR_L zmf*l-DO!;>tYn*KL6P@1v+TfVivvPau(=%)Zq(^W01L4Jf18&&vQ+)zkPXXmQne>m zeLNp(wAt_NK2lGIAg7RHakgH9u#fhEypc7JR-QllyQ+l^$$;l?-b^V943djs=L&r_ zLZKb_pk0e$%r{*!RHFh>bA+=ZKb~<>G#P1LTtw$_ZdoGC2;p9%eQO9AU7IGq8!?sn zLb8WH13gMBAn&)4y;s6KIO5vURyf=06IFl^%GiE z-j&H$4ZC00JF-J#eJyhq(F=t|$2dqV*<7nD+qpB-S)Xb!#n@t0nBN!qgp)DJ%mryJ zKB}DgTnl7~Ai+xPZPo7^ft+zjV;Ghka6h%`VlQc_+>#%8`29iZR>lY8jD^PtR{F9T za+oR_SppIkKMN;G%&$X)osxLhHS!ZQ;=F3aqni}!S#^aY2I8tAY5<^5E7x$wNlDDF zdrWZU0)3v^Z-sL3R0?EEG7{KIc8opT=aE&qpc2mo*5y`@`{s|DqJ9M4V(HwaO{={8 zF37~Zj(GL6pRiI-BQ>Gk%g&z4(b3sHhrPyi$kNm52%;T2fTCSrNHUXB>f@V8g2^hU zJd8Xn#q~z^EkxaIvYHC!_XFdMntxeZ0Iuw=&4N8CL5&xycANP$RT7AcIA5=L7tuQH z8gzw(Qd_>GnJ`ij01A_F@Nn> zw%TsWA~U1JRmGNnwf&b}8LO$X7^fMp_Ou(Yt=~9e?*bueSmpQiaorV(0xNRg^>Q=R zrPB?9rri=n{Z5D;9V#aZD*WMIj*sTNqn07pnLC!+i}iURm%M?#(Uf^d2mXl4`)Lf$ zp18S{`<+X`?i>wevI^UlY91|-HI^}_I*tF9sSknpST>}`pcg^DMxCxD8peYUOPYbZ zY}m;m$Fw7?QJ2!=McvIE4nYuzzP!3MtI})nf@qs3@rkqD&sC&XA0URNx8l)nOb6RB zaPwSy7`B$pu7>hr{VUAh8(cyXKCrW6x7do9CNFh`pN!252sP+hd8?27PN)gVqyP9R zmp^qJ&569Dc!u_u64|ClRoi5+e2r?KEPV1AG5NyEe4AEn99Pisz=4=^j$z$m1^<5Z zFlTe)>Ac?ZcdAt~^ff*lg@iJ#Xi=MYwsKwMq8u&>zSAa=f1I z&|*foQ0;>OXUKsEH=&Tq1PSG9A<&+H@`7Gcp|*O28No1Qd9G9R{+Ej5?6#SCCX&Q=@a7$%sG79WK`5*@R>1qm zl2Tmi*c(bip?#SzG94e4{P)F9COOOMICd=3h8x*1)8olNEL;-G!6Q?%Q z>RNF@JzwxD7xKIsuqQ8P#bvZ@b~TtX;H5@W)0!Sr*FQ20OkRI!P$*STxjz4eB-HDB z`Q@fKeC;#AQa0&Ek<*b_-RuYYkt_+$y{ePiu1W~sdwQ{=9rw@yMlZ*#>#uL|ZdpJ9 zwFc~JUpZ6=$w!yG%8nlE+V2TAippWQaSptqSTSU!rDbFUqzqhV#x@Ly2*4jE@VjBG zWxSOWl85$ypVKIZBO6piV^t68H`c?E&}$!&k|j)a_s}#<7WH#iY;rirCN*pdjE;Xx zr&2og86uOmdM19&f@r1Iq(m)@&WN<4?CSvAzP*eGzDjfe;3pZE z-Z!y&9q2djdT$v2Fl0uaZZRRvX63WY%WI6?>je4bgp_dNr+#?I3K9$Y*U2!n0r^f2 za|cYGG(!zca?R@AKGeR1FtTj?JlAHqQaZ@8nqr=sK@8ALs+dVYdg6OHE^jW*`s%>X zgGbm^ls06K9iA#?2dcY|DyQhgldvs!e0NK502w_2D)neRP9fVH+R6qHZ#E z*RK>qyx7hq>FF7eP~by%VR)_h0f+rJySt3DLbOZ0%Wo+ZS8s|I!}PDPEt-r=__3UP zbTv|2{du#MJ{F8F6tapg2^kd@Gh33qWLJNXsX$!sdeaxBJitCkzp> z(8;vCwOlPE!#}dwouy~emo%IhHM5XYTOoNZQh=c;a4T#XFqpvB-j8{yUZ!!ZfUi!#J-$X(iT#VB(5x>J%0*W!c zRCwU4Nvq>J{q0{85LW(!xxDoT-5=_3sLckzn7+K2sC9W~2W|{s?)SL>ZEd}s72b2j zSG*4tASY$4A9;r(RIe+w;=C+{1GcRsJQcn8Hk)TB@+Qg%_3qw#Yd8c&UFg|6ni%8= zVY<3+zFu9@BghC6nIf9BN+nw(TK8ix^?8s6lmHo)0T$! zF$~qJzom7r$hwyn_y+kt!=al0It6nbE`o}Zsg$DE{0Cj%(GfZmMh}jYVR8xYO!^ep zkbsY`F0~}F3h}*l+*5CDqAI~K*g7m3#}N;?3@oGIlz-zHhDp%PrvVWcFM z0LLk|)UTaZKIxA4>yrx~W|kM<_^{ef6Pdz=8^hGm4;OOOK!0zLBdemqGBn_IFZFj% zmuevGBoD%Vl~s)EA+@hZJp?E`JkF zg4|!FSvWPf4dXNKT$gI*-L1YyUxNr2)#bR^zV4wCZ>U@~oCK*w08>>o*rO8b50N3o z({{dRcyICQ)hyj-L1V!RgVF$5P<`E65k?f>Ew$OO&aG54r;&0+D6J71_~F8@E@(eM zHnzU(M-jvRvW+?=8P_!D$&3QD>9MX{c%pO&hDGk0{+#mBN@Bb`c8|@iy<5JjJp7OV zOK{68_S-}b8h@rfCjE~$XkYJ|_`96B`X~*Jy%T!t@PCZSsSeO153^`cn_h(dS`RqQ zjh`am#C--tlDQTS@bI|`^h$xWH zCX=ha>YCLNxTo-Ef^ylAFIR!CVhTQ@ij=*; vHJb0xn^)E6Ux!ph6);1m7}BS1l($IB57BiaEqB0i>I*E8Pe%UuJpX?HN)c~j literal 0 HcmV?d00001 diff --git a/kulturtankstelle/licenses/cc-by-nc-nd.png b/kulturtankstelle/licenses/cc-by-nc-nd.png new file mode 100644 index 0000000000000000000000000000000000000000..072f8cda0ab220f98162dec5c705c44298d9aeee GIT binary patch literal 688 zcmV;h0#E&kP)IS55s3f)|36ZE%gD$AVXfJ;8d+k`uDvs-&g|&uC@(L^)aL5ydg|1vw(eGO32`7- zURJ@?$@SxhkAvK|ka%Unlz92#A;p2zGg2JH^$yhwR ze8~!7VPRapg#ci1+`Msf!`h8N_Qy{jJbXO7eY}UNhc8{cl%AdrWSl*FR#{mYnC^jT z`2G9$KoZCXiU7rpjg4JgT&`Wc1~r9=3CKlDKM;VNoG{r~1(9{(DPJ(Ppjk?khc8{c z{Q1*opnrhuu&^*71E?QJc6N3G{rT?QJ7CP;yLS&L3lzL_`wl!+0~0xB2>}EU>){L_ z31k!W09++pBQaXgEG5drU%z|-l7fPQz$gWJ4B~TO0tT{`l$3ztX=!Ppp`oxM9_sX; zKYuW?Fk-p}*?SOoz`2;Qfy<#}Xdxknxp{biB+$1&zX5#+j8#an4CDg+3>2@ZsF*ct z7Fqzavvd6aLt0=n!T_2erh2#t@mfgmu%5myFE1~|pTLOSvu6*`M4-=sY+!5)2?+s3 zAldcInKO#YiV$4_`~tv=3V#d}UsWRegcuW$6%f<{ZFnHp!+l--&!0ZOfB!xnJAff# zVqy{<7ab7n59G>9%QZJNZ{4zWkk`Y&fWT5pN5@6IeftI&rFb-#m6fTeDnoqB&nK{B z%Z@?rTYS|Lu>F*pnOa#{+1}ocRgaUi)Aj4u3rY&$>A8PG|7cr!khY~qT4#v?Aiw}` W?NiqbQ>df>0000IS55s3f)|36ZE3j`1kui3O3Sz^zwy)&oI?C9tyFE7W`=IZKt>eQ*W?pARLaUfS- zR>9TD_2Y++gWR`3Zvy?xgemdz#mnW3m*es+5bWN)+sw>ta{m+v_ru2zg$0E}C6cjt zc=?hQ!otG1d8z{RS#dfcqu(S9mqI)_N=n9GB6nc z)A0NE?|~$c4HN;28yg$DxVT)qdJSp{6BCe&mVO`r&PA5On%*$k$R^-QrD(PgERUEl ze0%xxr_VtD0NG(-VL%4Z2q4+n*$MRLyLaz^F@NvgJ)kU5@XqZ!@Kg;<? z1Gzvy1H~&UDrU`^g%&65>>U69{Kpf+*lP$_Fe_H@*|00^!fe!_wi^0hKPxYNpxIvK(IfMD=RJ6+|ayr%hn-T4@bvEy?y%z7^QeLmz9;N zs47Ez%g-mUW6O>~?pu7-60rT0nweTzS=rv+j#ZD7v(xqK*9%Gt;OV)4LjP!6dXToI fM_Olz0U*EtDwt)|Le?|v00000NkvXXu0mjf&ay*> literal 0 HcmV?d00001 diff --git a/kulturtankstelle/licenses/cc-by-nc.png b/kulturtankstelle/licenses/cc-by-nc.png new file mode 100644 index 0000000000000000000000000000000000000000..54ebdfbd8b88229b0cb6da644bde68c83181d87e GIT binary patch literal 672 zcmV;R0$=@!P)1RCwBA zU>IS55s3f)|36ZE3j`1kui3O3Sz^zwy)&oI?C9tyFE7W`=IZKt>eQ*W?pARLaUfS- zR>9TD_2Y++gWR`3Zvy?xgemdz#mnW3m*es+5bWN)+sw>ta{m+v_ru2zg$0E}C6cjt zc=?hQ!otG1d8z{RS#dfcqu(S9mqI)_N=n9GB6nc z)A0NE?|~$c4HN;28yg$DxVT)qdJSp{6BCe&mVO`r&PA5On%*$k$R^Or!F!maPkrB-^Sk==uhV}Gyd3kvu{sczso;`bjjsW@`$Ogu?kdP2i1d?6PoH?VY ztO(I1z%Kx-sPM-y@l_?V=gBaEsD=k}J>1vT|NQCm`}gnT(FP0=6BCo@xafdje;`*@ zTCTaFdFz&~L$V%@j*EKx_6;yf@n|k9D^pQbhWM7BPhiKE9fRDr_^Ksf`zbXuwX(9Z zy}cc)9w%p~>({RrloY_zbN__?(YEv;ZA*`|&JqJafB^uooh;+!k6K6o0000IS55s3f)|36ZE%gD$AVXfJ;8d+k`uDvs-&g|&uC@(L^)aL5ydg|1vw(eGO32`7- zURJ@?$@SxhkAvK|ka%Unlz92#A;p2zGg2JH^$yhwR ze8~!7VPRapg#ci1+`Msf!`h8N_Qy{jJbXO7eY}UNhc8{cl%AdrWSl*FR#{mYnC^jT z`2G9$KoZCXiU7rpjg4JgT&`Wc1~r9=3CKlDKM;VNoG{r~1tDxS6KLh(OBXMH{`48> zA0Rs{EDXp1S_vdOJ3E2?eE04hFy`;wy9bm73f{SW2cD{di5#ANT|MREM@87?VM;kCiOiWCoFBtqw{PD7qZE(kva&K2Rb_~8`S}EPY}ql$eT%PJ0=A!0GgB)oE8E-KvFdSh zcDjE3dO=A6JU#bM=pSuM57M^uNb4*y00bBS5>6)L^o3Ai00000NkvXXu0mjfhO#Q? literal 0 HcmV?d00001 diff --git a/kulturtankstelle/licenses/cc-by-sa.png b/kulturtankstelle/licenses/cc-by-sa.png new file mode 100644 index 0000000000000000000000000000000000000000..c67509f1264e4b845b643e340cb39970e432c711 GIT binary patch literal 672 zcmV;R0$=@!P)1RCwBA zU>IS55s3f)|36ZE%gD$AVXfJ;8d+k`uDvs-&g|&uC@(L^)aL5ydg|1vw(eGO32`7- zURJ@?$@SxhkAvK|ka%Unlz92#A;p2zGg2JH^$yhwR ze8~!7VPRapg#ci1+`Msf!`h8N_Qy{jJbXO7eY}UNhc8{cl%AdrWSl*FR#{mYnC^jT z`2G9$KoZCXiU7rpjg4JgT&`Wc1~r9=3CKlDKM;VNoG{t=wa}t)VZ!k3<bHjPBvDU%miIK|w)alma~l@i{O71KCPSN;c*e^f{0XjBOzyA)p8(yPi37Mp0Q2 zqDz2Z09aAsk70s!21)8EZFnHp!+l--&!0ZOfB!xnZNLyQF)@jbiw+3(2XbYl<(eCs zw{F=w$m?NXXksa)qvN99zI_9XQaqZ=%F0w!l_9?6=M&hmWyc`*Exu|A*nUdQOs%Y} zY;SMJs>jLM>H78S1tkUW^xQw8f3z(IS55s3f)|36ZE%gD$AVXfJ;8d+k`uDvs-&g|&uC@(L^)aL5ydg|1vw(eGO32`7- zURJ@?$@SxhkAvK|ka%Unlz92#A;p2zGg2JH^$yhwR ze8~!7VPRapg#ci1+`Msf!`h8N_Qy{jJbXO7eY}UNhc8{cl%AdrWSl*FR#{mYnC^jT z`2G9$KoZCXiU7rpjg4JgT&`Wc1~r9=3CKlDKM;VNoG{q~@8L@qFMs~@8R#D%J1i^= z$N;(zNOpF10{!{!-8*2+-@A7YC<_$4bNdcFRRa?_W(ffV5bwbmKoZCvL>~V7mWB>su@y=H}r6 zl0e@A{RZ?QFjgVOGLQ@OGf=#uqGHypS!juqot@+VpZ|Dbc<|<7J$+qXUS5blff2iB z&mN$ofj$Safw3(lBm@+JWY;ri&L}D?LUal63jixB{4qSZ8Xm~?a9>yd^QX`6-@lJX z8!$vnOiZHVq632cfm~T>x#ouEty{JZ@_HB;`dCWo=(wo2Z{Gl;6p!YzvN9D_Wr%P2 z`2==s*)hm{i?3P&wx3cnQ!6Vg+uPf*>Tz;*x_nt$< a1Q-Bx&HUr%A;kRv0000{$id}->{titles} is array of collection titles +# $art->{$id}->{collections} is hash of collection information hashes +my $art; + +# initialize KTart module (fill $art) +# in: $config +# out: true or undef +sub init +{ + my $c; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + # include every menu entry with type='art' + foreach my $entry (@{$c->{menu}->{entry}}) { + next unless ($entry->{id} eq 'art'); + + # fetch all collection folders + my $basepath = $c->{dirs}->{content} . $entry->{folder}; + unless(opendir(COLLECTIONS, $basepath)) { + say "Error: ".(caller 0)[3]. + ": can't open $basepath: $!"; + return; + } + my @folders = readdir(COLLECTIONS); + closedir(COLLECTIONS); + + # read and parse $folder/info.xml + foreach my $folder(sort @folders) { + next if $folder =~ /^\.+$/; + + # parse collection information file + my $infofile = "$basepath/$folder/info.xml"; + my $collection = eval { XML::Simple::XMLin( + $infofile, KeyAttr => []) }; + if($@) { + say "Error: ".(caller 0)[3].": $infofile: $@"; + next; + } + + # TODO: check data structures more thorough + unless($collection->{collectionname}) { + say "Error: ".(caller 0)[3]. + "$infofile contains no collectionname"; + next; + } + + # fill in collection title, folder and all other data + my $title = $collection->{collectionname}; + push (@{$art->{$entry->{id}}->{titles}}, $title); + $art->{$entry->{id}}->{collections}->{$title} = + $collection; + $art->{$entry->{id}}->{collections}->{$title}->{path} = + $folder; + } + } +} + +# check for art area overview or collection detail page +# in: $config, $entry (menu entry from $config), $templates +# out: nothing +sub print_content +{ + my $c; + my $entry; + my $templates; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($entry = shift) { + say "Error: ".(caller 0)[3].": no entry"; + return; + } + + unless($templates = shift) { + say "Error: ".(caller 0)[3].": no templates"; + return; + } + + # check for 'collection' parameter in QUERY_STRING + if($ENV{QUERY_STRING}) { + foreach(split(/;/, $ENV{QUERY_STRING})) { + (my $param, my $val) = split(/=/, $_); + next unless ($param =~ /^collection$/); + + # found -> print collection detail page + &KTart::print_details( + $c, + $entry, + $templates, + $val, + ); + return; + } + } + + # not found -> print collection overview + &KTart::print_overview( + $c, + $entry, + $templates, + ); +} + +# print collection overview +# in: $config, $entry (menu entry from $config), $templates +# out: nothing +sub print_overview +{ + my $c; + my $entry; + my $templates; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($entry = shift) { + say "Error: ".(caller 0)[3].": no entry"; + return; + } + + unless($templates = shift) { + say "Error: ".(caller 0)[3].": no templates"; + return; + } + + # set global variables + $templates->{art_overview}->param( + PAGETITLE => &KTmain::get_string($c, 'art_contents'), + SCRIPT => $ENV{SCRIPT_NAME}, + LANGUAGE => &KTmain::get_language($c), + MENUID => $entry->{id}, + MENUTITLE => &KTmain::get_string($c, $entry->{id}), + PIECES => &KTmain::get_string($c, 'art_pieces'), + ARTIST => &KTmain::get_string($c, 'art_artist'), + LICENSE => &KTmain::get_string($c, 'license'), + ); + + # set per-collection variables + my @collections = @{$art->{$entry->{id}}->{titles}}; + my @loopdata; + for my $index (0 .. $#collections) { + my %data; + my $info = $art->{$entry->{id}}->{collections}->{$collections[$index]}; + + $data{COLLECTIONID} = $index; + $data{COLLECTIONTITLE} = $collections[$index]; + $data{COLLECTIONCOVER} = $c->{dirs}->{webcontent} . + $entry->{folder} . + $info->{path} . + "/cover.jpg"; + $data{PIECESCOUNT} = $info->{collectionimagecount}; + $data{ARTISTNAME} = $info->{collectionartist}; + + # fill in license data + (my $url, my $img) = + &KTmain::get_license($c, $info->{collectionlicense}); + if(($url) && ($img)) { + $data{LICENSEURL} = $url; + $data{LICENSETEXT} = ""; + } else { + $data{LICENSEURL} = $c->{dirs}->{webcontent} . + $entry->{folder} . + $info->{path} . "/" . + $info->{collectionlicense}; + $data{LICENSETEXT} = + &KTmain::get_string($c, 'license'); + } + + push(@loopdata, \%data); + } + $templates->{art_overview}->param(COLLECTIONLOOP => \@loopdata); + + print $templates->{art_overview}->output; +} + +# print collection details +# in: $config, $entry, $templates, $collectionid +# ($collectionid: index in $art->{id]->{titles} array) +# out: nothing +sub print_details +{ + my $c; + my $entry; + my $templates; + my $collectionid; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($entry = shift) { + say "Error: ".(caller 0)[3].": no entry"; + return; + } + + unless($templates = shift) { + say "Error: ".(caller 0)[3].": no templates"; + return; + } + + unless(defined($collectionid = shift)) { + say "Error: ".(caller 0)[3].": no albumid"; + return; + } + + my $title = $art->{$entry->{id}}->{titles}->[$collectionid]; + my $info = $art->{$entry->{id}}->{collections}->{$title}; + + # set global variables + $templates->{art_details}->param( + # general + PAGETITLE => &KTmain::get_string($c, 'art_details'), + SCRIPT => $ENV{SCRIPT_NAME}, + LANGUAGE => &KTmain::get_language($c), + MENUID => $entry->{id}, + + # translations + MENUTITLE => &KTmain::get_string($c, $entry->{id}), + PIECES => &KTmain::get_string($c, 'art_pieces'), + ARTIST => &KTmain::get_string($c, 'art_artist'), + LICENSE => &KTmain::get_string($c, 'license'), +# TITLE => &KTmain::get_string($c, 'art_title'), +# LENGTH => &KTmain::get_string($c, 'art_length'), + DESCRIPTION => &KTmain::get_string($c, 'art_description'), + YEAR => &KTmain::get_string($c, 'art_year'), + FETCHCOLLECTION => &KTmain::get_string($c, 'art_fetchcollection'), +# DOWNLOAD => &KTmain::get_string($c, 'art_download'), +# DOWNLOADTEXT => &KTmain::get_string($c, 'art_downloadtext'), + + # collection specific + COLLECTIONID => $collectionid, + COLLECTIONTITLE => $title, + PIECESCOUNT => $info->{collectionimagecount}, + ARTISTNAME => $info->{collectionartist}, + LICENSETEXT => $info->{collectionlicense}, + COLLECTIONCOVER => $c->{dirs}->{webcontent} . + $entry->{folder} . + $info->{path} . + "/cover.jpg", + # TODO: dynamically create zipfile + FETCHCOLLECTIONLINK => "javascript:alert(\'not implemented\')", + ); + + # fill in license data + (my $url, my $img) = + &KTmain::get_license($c, $info->{albumlicense}); + if(($url) && ($img)) { + $templates->{art_details}->param( + LICENSEURL => $url, + LICENSETEXT => "", + ); + } else { + $templates->{art_details}->param( + LICENSEURL => $c->{dirs}->{webcontent} . + $entry->{folder} . + $info->{path} . "/" . + $info->{collectionlicense}, + LICENSETEXT => + &KTmain::get_string($c, 'license'), + ); + } + + # set collection-specific variables + my @loopdata; + foreach my $image (@{$info->{image}}) { + my %imagedata; + + $imagedata{IMAGETITLE} = $image->{title}; + $imagedata{IMAGEFILE} = $c->{dirs}->{webcontent} . + $entry->{folder} . + $info->{path} . "/" . + $image->{filename}; + + $imagedata{IMAGEFILE_THUMB} = $c->{dirs}->{webcontent} . + $entry->{folder} . + $info->{path} . "/" . + # FIXME: thumbnail filename! + substr($image->{filename}, 0, -4). + "_tn.jpg"; + + $imagedata{IMAGE_THUMBWIDTH} = $image->{thumbnailsizex}; + $imagedata{IMAGE_THUMBHEIGHT} = $image->{thumbnailsizey}; + $imagedata{ARTISTNAME} = $image->{artist}; + $imagedata{CREATIONYEAR} = $image->{year}; + $imagedata{DESCRIPTIONTEXT} = $image->{description}; + + push(@loopdata, \%imagedata); + } + $templates->{art_details}->param(IMAGELOOP => \@loopdata); + + print $templates->{art_details}->output; +} + +1; diff --git a/kulturtankstelle/modules/KTmain.pm b/kulturtankstelle/modules/KTmain.pm new file mode 100644 index 0000000..fa4ed5e --- /dev/null +++ b/kulturtankstelle/modules/KTmain.pm @@ -0,0 +1,400 @@ +#!/usr/bin/perl -w +use strict; +use 5.010; + +package KTmain; + +# read and parse xml configuration file +# in: $filename - filename of XML file +# out: $config - hash reference with parsed contents +sub read_config +{ + my $filename; + my $config; + + unless($filename = shift) { + say "Error: ".(caller 0)[3].": no configuration file"; + return; + } + + $config = eval { main::XMLin("$filename", KeyAttr => [ ] ); }; + if($@) { + say "Error: ".(caller 0)[3].": parsing failed: $@"; + return; + } + + return $config; +} + +# read all template files from template directory ($c->{dirs}->{templates}) +# in: $config - global configuration +# out: $templates - hash reference with template objects +sub read_templates +{ + my $c; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no configuration"; + return; + } + + unless($c->{dirs}->{root}) { + say "Error: ".(caller 0)[3].": no template directory"; + return; + } + + my $dir = "$c->{dirs}->{root}/templates"; + unless(opendir(TEMPLATES, $dir)) { + say "Error: ".(caller 0)[3].": $!"; + return; + } + + my %t; + while(readdir(TEMPLATES)) { + next unless /^kt_([0-9a-zA-Z_]+)\.tmpl$/; + $t{$1} = HTML::Template->new( + filename => "$dir/$_", + loop_context_vars => 1, + global_vars => 1, + ); + } + closedir(TEMPLATES); + + return \%t; +} + +# print header from template +# in: $config, $template +# out: nothing +sub print_header +{ + my $c; + my $t; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($t = shift) { + say "Error: ".(caller 0)[3].": no template"; + return; + } + + $t->param(WEBROOT => "$c->{dirs}->{webroot}"); + print $t->output; +} + +# print footer from template +# in: $config, $template +# out: nothing +sub print_footer +{ + my $c; + my $t; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($t = shift) { + say "Error: ".(caller 0)[3].": no template"; + return; + } + + print $t->output; +} + +# print menu from template +# in: $config, $template +# out: nothing +sub print_menu +{ + my $c; + my $t; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($t = shift) { + say "Error: ".(caller 0)[3].": no template"; + return; + } + + my @entries; + foreach(@{$c->{menu}->{entry}}) { + push (@entries, { + TEXT => &KTmain::get_string($c, $_->{id}), + URL => "$ENV{SCRIPT_NAME}?". + "lang=".&KTmain::get_language($c).";". + "id=$_->{id}", + }); + } + + $t->param(MENU_ENTRIES => [ @entries ]); + print $t->output; +} + +# print language selector +# in: $config, $template +# out: nothing +sub print_language_selector +{ + my $c; + my $t; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($t = shift) { + say "Error: ".(caller 0)[3].": no template"; + return; + } + + # fetch all request parameters, filter "lang" parameter + my @newparams; + if($ENV{REQUEST_URI}) { + (undef, my $params) = split(/\?/, $ENV{REQUEST_URI}); + foreach(split(/;/, $params)) { + (my $param, my $val) = split(/=/, $_); + next if $param =~ /^lang$/; + $val = "" unless $val; + push(@newparams, "$param=$val"); + } + } + + # find all languages + my $script = $ENV{SCRIPT_NAME}; + my @languages; + foreach my $lang (sort keys $c->{translation}) { + push (@languages, { + LANG => $lang, + URI => "$script?lang=$lang;".join(";", @newparams), + }); + + my $uri = "$script?lang=$lang;".join(";", @newparams); + } + $t->param(LANGUAGES => [ @languages ]); + print $t->output; +} + +# select content printing function based on 'id' +# in: $config and $templates (all of them) +# out: nothing +sub print_content +{ + my $c; + my $templates; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no configuration"; + return; + } + + unless($templates = shift) { + say "Error: ".(caller 0)[3].": no templates"; + return; + } + + # get page id + my $id; + if($ENV{QUERY_STRING}) { + foreach(split(/;/, $ENV{QUERY_STRING})) { + (my $param, my $val) = split(/=/, $_); + next unless ($param =~ /^id$/); + $id = $val; + } + } + + # get page type + my $entry; + foreach(@{$c->{menu}->{entry}}) { + if($id eq $_->{id}) { + $entry = $_; + } + } + + # switch/case depending on page type + given($entry->{type}) { + when ('music') { + # music area + &KTmusic::print_content( + $c, + $entry, + $templates); + } + + when ('art') { + # art area + &KTart::print_content( + $c, + $entry, + $templates); + } + + when ('litterature') { + # litterature area + &KTlitterature::print_content( + $c, + $entry, + $templates); + } + + when ('webpage') { + # webpage area + say "WEBPAGE at $entry->{folder}"; + } + + default { + # fallback: index page from template + print $templates->{index}->output; + } + } +} + +sub get_language +{ + my $c; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + # check QUERY_STRING for "lang=" + if($ENV{QUERY_STRING}) { + foreach(split(/;/, $ENV{QUERY_STRING})) { + (my $param, my $val) = split(/=/); + next unless ($param =~ /^lang$/); + + if($c->{translation}->{$val}) { + return $val; + } + } + } + + # check HTTP_ACCEPT_LANGUAGE + if($ENV{HTTP_ACCEPT_LANGUAGE}) { + my %ll; + foreach(split(/,/, $ENV{HTTP_ACCEPT_LANGUAGE})) { + (my $l, my $q) = split(/;q=/); + $q = 1 unless $q; + $ll{$l} = $q; + } + + # sort languages by q values, descending + foreach( sort { $ll{$b} <=> $ll{$a} } (keys %ll) ) { + if($c->{translation}->{$_}) { + return $_; + } + } + } + + # fallback + return "de"; +} + +# get translated string +# in: $config, $string +# out: string or undef +sub get_string +{ + my $c; + my $s; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($s = shift) { + say "Error: ".(caller 0)[3].": no string"; + return; + } + + my $lang = &KTmain::get_language($c); + + if($c->{translation}->{$lang}->{$s}) { + return $c->{translation}->{$lang}->{$s}; + } else { + return "!$s"; + } +} + +# return license and image file url for known licenses +# in: $config, license text (i.e. 'cc__by_nc_sa') +# out: [url, imageurl] if known license, [undef, undef] else +sub get_license +{ + my $config; + my $license; + + unless($config = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($license = shift) { + return (undef, undef); + } + + given($license) { + # CC license: see http://creativecommons.org/licenses/ + when('cc__by') { # CC: Attribution + return ( + $config->{dirs}->{webroot}. + "/licenses/cc-by.html", + $config->{dirs}->{webroot}. + "/licenses/cc-by.png", + ); + } + + when('cc__by_nc') { # CC: Attribution, NonCommercial + return ( + $config->{dirs}->{webroot}. + "/licenses/cc-by-nc.html", + $config->{dirs}->{webroot}. + "/licenses/cc-by-nc.png", + ); + } + + when('cc__by_nd') { # CC: Attribution, NoDerivs + $config->{dirs}->{webroot}. + "/licenses/cc-by-nd.html", + $config->{dirs}->{webroot}. + "/licenses/cc-by-nd.png", + } + + when('cc__by_sa') { # CC: Attribution, ShareAlike + $config->{dirs}->{webroot}. + "/licenses/cc-by-sa.html", + $config->{dirs}->{webroot}. + "/licenses/cc-by-sa.png", + } + + when('cc__by_nc_nd') { # CC: Attrib, NonCommercial, NoDerivs + $config->{dirs}->{webroot}. + "/licenses/cc-by-nc-nd.html", + $config->{dirs}->{webroot}. + "/licenses/cc-by-nc-nd.png", + } + + when('cc__by_nc_sa') { # CC: Attrib, NonCommercial, ShareAlike + $config->{dirs}->{webroot}. + "/licenses/cc-by-nc-sa.html", + $config->{dirs}->{webroot}. + "/licenses/cc-by-nc-sa.png", + } + + default { # anything else + return [undef, undef]; + } + } +} + +1; diff --git a/kulturtankstelle/modules/KTmusic.pm b/kulturtankstelle/modules/KTmusic.pm new file mode 100644 index 0000000..0704624 --- /dev/null +++ b/kulturtankstelle/modules/KTmusic.pm @@ -0,0 +1,321 @@ +#!/usr/bin/perl -w +use strict; +use 5.010; + +package KTmusic; + +# package global music data +# $music->{$id}->{titles} is array of album titles +# $music->{$id}->{albums} is hash of album information hashes +my $music; + +# initialize KTmusic module (create $music) +# in: $config +# out: true or undef +sub init +{ + my $c; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + # include every menu entry with type='music' + foreach my $entry (@{$c->{menu}->{entry}}) { + next unless ($entry->{id} eq 'music'); + + # fetch all album folders + my $basepath = $c->{dirs}->{content} . $entry->{folder}; + unless(opendir(ALBUMS, $basepath)) { + say "Error: ".(caller 0)[3]. + ": can't open $basepath: $!"; + return; + } + my @folders = readdir(ALBUMS); + closedir(ALBUMS); + + # read and parse $folder/info.xml + foreach my $folder(sort @folders) { + next if $folder =~ /^\.+$/; + + # parse album information file + my $infofile = "$basepath/$folder/info.xml"; + my $album = eval { XML::Simple::XMLin( + $infofile, KeyAttr => []) }; + if($@) { + say "Error: ".(caller 0)[3].": $infofile: $@"; + next; + } + + # TODO: check data structures more thorough + unless($album->{albumtitle}) { + say "Error: ".(caller 0)[3]. + "$infofile contains no album title"; + next; + } + + # fill in album title, folder and all other data + my $title = $album->{albumtitle}; + push (@{$music->{$entry->{id}}->{titles}}, $title); + $music->{$entry->{id}}->{albums}->{$title} = $album; + $music->{$entry->{id}}->{albums}->{$title}->{path} = + $folder; + } + } +} + +# check for music area overview or album detail page +# in: $config, $entry (menu entry from $config), $templates +# out: nothing +sub print_content +{ + my $c; + my $entry; + my $templates; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($entry = shift) { + say "Error: ".(caller 0)[3].": no entry"; + return; + } + + unless($templates = shift) { + say "Error: ".(caller 0)[3].": no templates"; + return; + } + + # check for 'albumid' parameter in QUERY_STRING + if($ENV{QUERY_STRING}) { + foreach(split(/;/, $ENV{QUERY_STRING})) { + (my $param, my $val) = split(/=/, $_); + next unless ($param =~ /^albumid$/); + + # found -> print album detail page + &KTmusic::print_albumdetails( + $c, + $entry, + $templates, + $val, + ); + return; + } + } + + # not found -> print album overview + &KTmusic::print_overview( + $c, + $entry, + $templates, + ); +} + +# print album overview +# in: $config, $entry (menu entry from $config), $templates +# out: nothing +sub print_overview +{ + my $c; + my $entry; + my $templates; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($entry = shift) { + say "Error: ".(caller 0)[3].": no entry"; + return; + } + + unless($templates = shift) { + say "Error: ".(caller 0)[3].": no templates"; + return; + } + + # set global variables + $templates->{music_overview}->param( + PAGETITLE => &KTmain::get_string($c, 'music_contents'), + SCRIPT => $ENV{SCRIPT_NAME}, + LANGUAGE => &KTmain::get_language($c), + MENUID => $entry->{id}, + MENUTITLE => &KTmain::get_string($c, $entry->{id}), + TRACKS => &KTmain::get_string($c, 'music_tracks'), + ARTIST => &KTmain::get_string($c, 'music_artist'), + LICENSE => &KTmain::get_string($c, 'license'), + ); + + # set per-album variables + my @albums = @{$music->{$entry->{id}}->{titles}}; + my @loopdata; + for my $index (0 .. $#albums) { + my %albumdata; + my $albuminfo = + $music->{$entry->{id}}->{albums}->{$albums[$index]}; + + $albumdata{ALBUMID} = $index; + $albumdata{ALBUMTITLE} = $albums[$index]; + $albumdata{ALBUMCOVER} = $c->{dirs}->{webcontent} . + $entry->{folder} . + $albuminfo->{path} . + "/cover.jpg"; + $albumdata{TRACKCOUNT} = $albuminfo->{albumtrackcount}; + $albumdata{ARTISTNAME} = $albuminfo->{albumartist}; + $albumdata{LICENSETEXT} = $albuminfo->{albumlicense}; + + # fill in license data + (my $url, my $img) = + &KTmain::get_license($c, $albuminfo->{albumlicense}); + if(($url) && ($img)) { + $albumdata{LICENSEURL} = $url; + $albumdata{LICENSETEXT} = ""; + } else { + $albumdata{LICENSEURL} = $c->{dirs}->{webcontent} . + $entry->{folder} . + $albuminfo->{path} . "/" . + $albuminfo->{albumlicense}; + $albumdata{LICENSETEXT} = + &KTmain::get_string($c, 'license'); + } + + push(@loopdata, \%albumdata); + } + $templates->{music_overview}->param(ALBUMLOOP => \@loopdata); + + print $templates->{music_overview}->output; +} + +# print album details +# in: $config, $entry, $templates, $albumid +# ($albumid: index in $music->{id]->{titles} array) +# out: nothing +sub print_albumdetails +{ + my $c; + my $entry; + my $templates; + my $albumid; + + unless($c = shift) { + say "Error: ".(caller 0)[3].": no config"; + return; + } + + unless($entry = shift) { + say "Error: ".(caller 0)[3].": no entry"; + return; + } + + unless($templates = shift) { + say "Error: ".(caller 0)[3].": no templates"; + return; + } + + unless(defined($albumid = shift)) { + say "Error: ".(caller 0)[3].": no albumid"; + return; + } + + my $albumtitle = $music->{$entry->{id}}->{titles}->[$albumid]; + my $albuminfo = $music->{$entry->{id}}->{albums}->{$albumtitle}; + + # set global variables + $templates->{music_details}->param( + # general + PAGETITLE => &KTmain::get_string($c, 'music_details'), + SCRIPT => $ENV{SCRIPT_NAME}, + LANGUAGE => &KTmain::get_language($c), + MENUID => $entry->{id}, + + # translations + MENUTITLE => &KTmain::get_string($c, $entry->{id}), + TRACKS => &KTmain::get_string($c, 'music_tracks'), + ARTIST => &KTmain::get_string($c, 'music_artist'), + LICENSE => &KTmain::get_string($c, 'license'), + TRACK => &KTmain::get_string($c, 'music_track'), + TITLE => &KTmain::get_string($c, 'music_title'), + LENGTH => &KTmain::get_string($c, 'music_length'), + DOWNLOAD => &KTmain::get_string($c, 'music_download'), + DOWNLOADTEXT => &KTmain::get_string($c, 'music_downloadtext'), + FETCHALBUM => &KTmain::get_string($c, 'music_fetchalbum'), + + # album specific + ALBUMID => $albumid, + ALBUMTITLE => $albumtitle, + TRACKCOUNT => $albuminfo->{albumtrackcount}, + ARTISTNAME => $albuminfo->{albumartist}, + LICENSETEXT => $albuminfo->{albumlicense}, + ALBUMCOVER => $c->{dirs}->{webcontent} . + $entry->{folder} . + $albuminfo->{path} . + "/cover.jpg", + # TODO: dynamically create zipfile + FETCHALBUMLINK => "javascript:alert(\'not implemented\')", + ); + + # fill in license data + (my $url, my $img) = + &KTmain::get_license($c, $albuminfo->{albumlicense}); + if(($url) && ($img)) { + $templates->{music_details}->param( + LICENSEURL => $url, + LICENSETEXT => "", + ); + } else { + $templates->{music_details}->param( + LICENSEURL => $c->{dirs}->{webcontent} . + $entry->{folder} . + $albuminfo->{path} . "/" . + $albuminfo->{albumlicense}, + LICENSETEXT => + &KTmain::get_string($c, 'license'), + ); + } + + # set track-specific variables + my @loopdata; + foreach my $track (@{$albuminfo->{song}}) { + my %trackdata; + + $trackdata{TRACKTITLE} = $track->{title}, + $trackdata{TRACKLENGTH} = &get_time($track->{playtime}), + $trackdata{TRACKPATH} = $c->{dirs}->{webcontent} . + $entry->{folder} . + $albuminfo->{path} . '/' . + $track->{filename}, + + push(@loopdata, \%trackdata); + } + $templates->{music_details}->param(TRACKLOOP => \@loopdata); + + print $templates->{music_details}->output; +} + +# turn number of seconds into human-readable format m:ss or h:mm:ss +# in: $num_seconds +# out: string or undef +sub get_time +{ + my $seconds; + my $output; + + unless($seconds = shift) { + say "Error: ".(caller 0)[3].": no seconds"; + return; + } + + (my $sec, my $min, my $hour) = gmtime($seconds); + if($hour) { + $output = sprintf("%u:%02u:%02u", $hour, $min, $sec); + } else { + $output = sprintf("%u:%02u", $min, $sec); + } + return $output; +} + +1; diff --git a/kulturtankstelle/style.css b/kulturtankstelle/style.css new file mode 100644 index 0000000..0271d51 --- /dev/null +++ b/kulturtankstelle/style.css @@ -0,0 +1,168 @@ +/* stylesheet fuer kulturtankstelle */ + +/* main */ + +body { + margin: 0; + padding: 0; + font-family: sans-serif; +} + +a { + font-weight: bold; + text-decoration: none; + color: black; +} + +a:hover { + color: #FF6600; +} + +/* menu */ + +.menu { + background-image: url(header.jpg); + background-repeat: no-repeat; + background-color: gray; + width: 150px; + height: 100%; + padding-top: 134px; + float: left; +} + +.menu ul { + list-style: none; + padding: 5px; +} + +.menu ul a { + display: block; + width: 100%; + border: 1px solid black; + border-left-color: white; + border-top-color: white; + background-color: silver; +} + +.menu ul a:hover { + width: 100%; + border-color: white; + border-left-color: black; + border-top-color: black; + background-color: silver; +} + +/* content */ + +.content { + position: absolute; + left: 150px; + width: 80%; + margin: 0; + padding-top: 20px; + padding-right: 10px; + padding-bottom: 20px; + padding-left: 10px; +} + +.content_header { + font-size: 16px; + font-weight: bold; + padding-top: 50px; + padding-bottom: 50px; +} + +.content_linkpath { + font-size: 10px; +} + +.language_selector { + text-align: right; + font-size: 12pt; +} + +/* music */ + +.music_cover { + border: 1px solid black; + float: left; + margin-right: 10px; + width: 100px; + height: 100px; +} + +.music_album { + height: 105px; + font-size: 12px; +} + +.music_albumtitle { + font-size: 16px; + font-weight: bold; + padding-bottom: 20px; +} + +.music_content table { + border-style: solid; + border-width: 1px; +} + +.music_content tr#rowhead { + background-color: #c0c0c0; +} + +.music_content tr#row0 { + background-color: #ffffff; +} + +.music_content tr#row1 { + background-color: #e0e0e0; +} + +.music_content td { + padding-left: 5px; + padding-right: 20px; +} + +.music_content table a { + font-weight: normal; + text-decoration: underline; +} + +/* art */ + +.art_cover { + border: 1px solid black; + float: left; + margin-right: 10px; + width: 100px; + height: 100px; +} + +.art_collection { + height: 105px; + font-size: 12px; +} + +.art_collectiontitle { + font-size: 16px; + font-weight: bold; + padding-bottom: 20px; +} + +.art_content { + font-size: 12px; +} + +.art_image { + border: 1px solid black; + background-color: #333333; + padding: 10px; +} + +.art_imagetitle { + font-size: 16px; + font-weight: bold; + padding-bottom: 20px; +} + diff --git a/kulturtankstelle/templates/kt_art_details.tmpl b/kulturtankstelle/templates/kt_art_details.tmpl new file mode 100644 index 0000000..772d2ca --- /dev/null +++ b/kulturtankstelle/templates/kt_art_details.tmpl @@ -0,0 +1,40 @@ +
+
+ +
+ +
+ Kulturtankstelle >> + >> + +
+ +
+ + <TMPL_VAR NAME=COLLECTIONTITLE> + + +
+ :
+ :
+ :

+
+

+ +
+ +
+ +
+ + +
+ :
+ :
+ :
+
+
+
+
+
+ diff --git a/kulturtankstelle/templates/kt_art_overview.tmpl b/kulturtankstelle/templates/kt_art_overview.tmpl new file mode 100644 index 0000000..406d94a --- /dev/null +++ b/kulturtankstelle/templates/kt_art_overview.tmpl @@ -0,0 +1,27 @@ +
+
+ +
+ +
+ Kulturtankstelle >> + +
+ + +
+ + <TMPL_VAR NAME=COLLECTIONTITLE> + + +
+ +
+ + :
+ :
+ :
+

+
+
+ diff --git a/kulturtankstelle/templates/kt_footer.tmpl b/kulturtankstelle/templates/kt_footer.tmpl new file mode 100644 index 0000000..b605728 --- /dev/null +++ b/kulturtankstelle/templates/kt_footer.tmpl @@ -0,0 +1,2 @@ + + diff --git a/kulturtankstelle/templates/kt_header.tmpl b/kulturtankstelle/templates/kt_header.tmpl new file mode 100644 index 0000000..50b4f65 --- /dev/null +++ b/kulturtankstelle/templates/kt_header.tmpl @@ -0,0 +1,7 @@ + + + Kulturtankstelle + + + + diff --git a/kulturtankstelle/templates/kt_index.tmpl b/kulturtankstelle/templates/kt_index.tmpl new file mode 100644 index 0000000..24ea4e1 --- /dev/null +++ b/kulturtankstelle/templates/kt_index.tmpl @@ -0,0 +1,7 @@ +
+
+ Kulturtankstelle +
+ + Hier kommt ein schöner Willkommengruß hin! +
diff --git a/kulturtankstelle/templates/kt_language_selector.tmpl b/kulturtankstelle/templates/kt_language_selector.tmpl new file mode 100644 index 0000000..d8dfe03 --- /dev/null +++ b/kulturtankstelle/templates/kt_language_selector.tmpl @@ -0,0 +1,3 @@ +
+ +
diff --git a/kulturtankstelle/templates/kt_menu.tmpl b/kulturtankstelle/templates/kt_menu.tmpl new file mode 100644 index 0000000..7039a82 --- /dev/null +++ b/kulturtankstelle/templates/kt_menu.tmpl @@ -0,0 +1,7 @@ + diff --git a/kulturtankstelle/templates/kt_music_details.tmpl b/kulturtankstelle/templates/kt_music_details.tmpl new file mode 100644 index 0000000..8d5e6ef --- /dev/null +++ b/kulturtankstelle/templates/kt_music_details.tmpl @@ -0,0 +1,50 @@ +
+
+ +
+ +
+ Kulturtankstelle >> + >> + +
+ +
+ + <TMPL_VAR NAME=ALBUMTITLE> + + +
+ :
+ :
+ :

+
+

+ + +
+ + + + + + + + + + + + + + + + + + + + +
+
+
+
+ diff --git a/kulturtankstelle/templates/kt_music_overview.tmpl b/kulturtankstelle/templates/kt_music_overview.tmpl new file mode 100644 index 0000000..ffe2a3a --- /dev/null +++ b/kulturtankstelle/templates/kt_music_overview.tmpl @@ -0,0 +1,27 @@ +
+
+ +
+ +
+ Kulturtankstelle >> + +
+ + +
+ + <TMPL_VAR NAME=ALBUMTITLE> + + +
+ +
+ + :
+ :
+ :
+

+
+
+ -- 2.30.2