mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Pull from trunk
This commit is contained in:
commit
c134c96b96
@ -71,3 +71,5 @@ gui_pubdate_display_format = 'MMM yyyy'
|
||||
# order until the title is edited. Double-clicking on a title and hitting return
|
||||
# without changing anything is sufficient to change the sort.
|
||||
title_series_sorting = 'library_order'
|
||||
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
@ -10,446 +9,238 @@
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="128"
|
||||
height="128"
|
||||
width="48"
|
||||
height="48"
|
||||
id="svg2"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.44.1"
|
||||
inkscape:version="0.45"
|
||||
version="1.0"
|
||||
sodipodi:docbase="/Users/david/Progetti/oxygen-svn/theme/svg/actions"
|
||||
sodipodi:docname="bookmark.svg">
|
||||
sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/apps"
|
||||
sodipodi:docname="accessories-dictionary.svg"
|
||||
inkscape:export-filename="/home/ulisse/Desktop/accessories-dictionary.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="linearGradient26907"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-84.002403"
|
||||
y1="-383.9971"
|
||||
x2="-12.0029"
|
||||
y2="-383.9971"
|
||||
gradientTransform="matrix(0,1,-1,0,-39.9985,140.0029)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#888a85;stop-opacity:1;"
|
||||
id="stop26909" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#2e3436;stop-opacity:1;"
|
||||
id="stop26911" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0,1,-1,0,-39.9985,140.0029)"
|
||||
y2="-383.9975"
|
||||
x2="-23.516129"
|
||||
y1="-383.9971"
|
||||
x1="-84.002403"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3711">
|
||||
<stop
|
||||
id="stop3713"
|
||||
style="stop-color:white;stop-opacity:1;"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3715"
|
||||
style="stop-color:white;stop-opacity:0;"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3081">
|
||||
<stop
|
||||
id="stop3083"
|
||||
offset="0"
|
||||
style="stop-color:#28691f;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3085"
|
||||
offset="1"
|
||||
style="stop-color:#00bf00;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3290">
|
||||
<stop
|
||||
style="stop-color:yellow;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3292" />
|
||||
<stop
|
||||
style="stop-color:#ffb66d;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3294" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3765">
|
||||
id="linearGradient2309">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3767" />
|
||||
id="stop2311" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3769" />
|
||||
id="stop2313" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3747">
|
||||
id="linearGradient2301">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
style="stop-color:#790000;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop3749" />
|
||||
id="stop2303" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
style="stop-color:#b03636;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3751" />
|
||||
id="stop2305" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3638">
|
||||
inkscape:collect="always"
|
||||
id="linearGradient2286">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
style="stop-color:#555753"
|
||||
offset="0"
|
||||
id="stop3640" />
|
||||
id="stop2288" />
|
||||
<stop
|
||||
id="stop3661"
|
||||
offset="0.06868132"
|
||||
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3659"
|
||||
offset="0.5"
|
||||
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
style="stop-color:#555753;stop-opacity:0"
|
||||
offset="1"
|
||||
id="stop3642" />
|
||||
id="stop2290" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient1563">
|
||||
inkscape:collect="always"
|
||||
id="linearGradient2276">
|
||||
<stop
|
||||
id="stop1565"
|
||||
style="stop-color:#babdb6;stop-opacity:1;"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||
id="stop2278" />
|
||||
<stop
|
||||
id="stop1567"
|
||||
style="stop-color:#8f9488;stop-opacity:1"
|
||||
offset="1"
|
||||
style="stop-color:white;stop-opacity:0;" />
|
||||
id="stop2280" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3273">
|
||||
inkscape:collect="always"
|
||||
id="linearGradient2258">
|
||||
<stop
|
||||
id="stop3275"
|
||||
style="stop-color:#ffa4a4;stop-opacity:1"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:0.55035973;" />
|
||||
id="stop2260" />
|
||||
<stop
|
||||
id="stop3277"
|
||||
style="stop-color:#a40000"
|
||||
offset="1"
|
||||
style="stop-color:#ffffff;stop-opacity:0;" />
|
||||
id="stop2262" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3291"
|
||||
inkscape:collect="always"
|
||||
id="linearGradient2235">
|
||||
<stop
|
||||
style="stop-color:#cccccc;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop2237" />
|
||||
<stop
|
||||
style="stop-color:#9b9b9b;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop2239" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient2229">
|
||||
<stop
|
||||
style="stop-color:#888a85"
|
||||
offset="0"
|
||||
id="stop2231" />
|
||||
<stop
|
||||
style="stop-color:#d3d7cf;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2233" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2221"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop3293"
|
||||
id="stop2223"
|
||||
offset="0"
|
||||
style="stop-color:#000000;stop-opacity:1;" />
|
||||
style="stop-color:#babdb6" />
|
||||
<stop
|
||||
id="stop3295"
|
||||
id="stop2225"
|
||||
offset="1"
|
||||
style="stop-color:#000000;stop-opacity:0;" />
|
||||
style="stop-color:#d3d7cf;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient12948">
|
||||
inkscape:collect="always"
|
||||
id="linearGradient2184">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop12950" />
|
||||
id="stop2186" />
|
||||
<stop
|
||||
style="stop-color:#c0c0c0;stop-opacity:0;"
|
||||
style="stop-color:#e3e3e3;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop12952" />
|
||||
id="stop2188" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3273"
|
||||
id="linearGradient3605"
|
||||
x1="80.100487"
|
||||
y1="44.807674"
|
||||
x2="77.714729"
|
||||
y2="101.4734"
|
||||
xlink:href="#linearGradient2229"
|
||||
id="linearGradient2211"
|
||||
x1="24"
|
||||
y1="19.505583"
|
||||
x2="19.982143"
|
||||
y2="19.550226"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.959962,0,0,0.959962,2.35549,3.275418)"
|
||||
spreadMethod="reflect" />
|
||||
gradientTransform="matrix(-1,0,0,1,48,0)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3638"
|
||||
id="linearGradient3644"
|
||||
x1="57.287113"
|
||||
y1="1.1597457"
|
||||
x2="144.2531"
|
||||
y2="16.876789"
|
||||
xlink:href="#linearGradient2221"
|
||||
id="linearGradient2219"
|
||||
x1="24"
|
||||
y1="19.996655"
|
||||
x2="32"
|
||||
y2="19.90625"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-1,0,0,1,48,0)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2184"
|
||||
id="linearGradient2245"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="15.714286"
|
||||
y1="16.82852"
|
||||
x2="36.482143"
|
||||
y2="20.667807" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2235"
|
||||
id="linearGradient2247"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="19.940901"
|
||||
y1="10.918805"
|
||||
x2="24"
|
||||
y2="22.750927" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2258"
|
||||
id="linearGradient2264"
|
||||
x1="32.794643"
|
||||
y1="21.696428"
|
||||
x2="34.79464"
|
||||
y2="32.321426"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3638"
|
||||
id="linearGradient3646"
|
||||
x1="57.287113"
|
||||
y1="1.1597457"
|
||||
x2="144.2531"
|
||||
y2="16.876789"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3638"
|
||||
id="linearGradient3648"
|
||||
x1="57.287113"
|
||||
y1="1.1597457"
|
||||
x2="144.2531"
|
||||
y2="16.876789"
|
||||
xlink:href="#linearGradient2276"
|
||||
id="linearGradient2282"
|
||||
x1="37.535713"
|
||||
y1="34.196426"
|
||||
x2="9.9285688"
|
||||
y2="20.089285"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient12948"
|
||||
id="radialGradient3716"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,-7.045514e-15,1.946707e-15,0.941176,2.788953e-13,3.492906)"
|
||||
cx="23.190451"
|
||||
cy="59.379417"
|
||||
fx="22.471308"
|
||||
fy="59.354759"
|
||||
r="2.1082227" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1563"
|
||||
id="linearGradient3732"
|
||||
x1="98.291809"
|
||||
y1="-126.7503"
|
||||
x2="44.242641"
|
||||
y2="101.45739"
|
||||
xlink:href="#linearGradient2286"
|
||||
id="radialGradient2292"
|
||||
cx="24"
|
||||
cy="36.75"
|
||||
fx="24"
|
||||
fy="36.75"
|
||||
r="22.5"
|
||||
gradientTransform="matrix(1,0,0,0.3,-3.16587e-17,25.725)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1563"
|
||||
id="linearGradient3739"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="98.291809"
|
||||
y1="-44.01474"
|
||||
x2="44.242641"
|
||||
y2="101.45739" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3291"
|
||||
id="radialGradient3743"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
|
||||
cx="63.912209"
|
||||
cy="115.70919"
|
||||
fx="63.975182"
|
||||
fy="116.88514"
|
||||
r="63.912209" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3747"
|
||||
id="radialGradient3753"
|
||||
cx="5.7531347"
|
||||
cy="-45.41592"
|
||||
fx="74.816956"
|
||||
fy="-43.169445"
|
||||
r="124.10334"
|
||||
gradientTransform="matrix(1,-5.290907e-17,-3.962245e-18,9.492274e-2,9.333694e-14,-41.10492)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3747"
|
||||
id="radialGradient3757"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,-1.087455e-16,-5.565153e-18,9.492274e-2,-1.420331e-15,-41.10492)"
|
||||
cx="5.7531347"
|
||||
cy="-45.41592"
|
||||
fx="74.816956"
|
||||
fy="-43.169445"
|
||||
r="124.10334" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3747"
|
||||
id="radialGradient3761"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,-1.302059e-16,-7.897474e-18,9.492274e-2,1.345372e-13,-41.10492)"
|
||||
cx="5.7531347"
|
||||
cy="-45.41592"
|
||||
fx="74.816956"
|
||||
fy="-43.169445"
|
||||
r="124.10334" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3765"
|
||||
id="radialGradient3771"
|
||||
cx="23.662739"
|
||||
cy="95.898506"
|
||||
fx="24.26058"
|
||||
fy="96.778763"
|
||||
r="2.793914"
|
||||
gradientTransform="matrix(1.484142,0.129521,-0.489782,5.61225,35.51325,-445.3727)"
|
||||
xlink:href="#linearGradient2301"
|
||||
id="linearGradient2307"
|
||||
x1="23.955357"
|
||||
y1="10.008928"
|
||||
x2="29.214285"
|
||||
y2="30.276785"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3290"
|
||||
id="linearGradient3106"
|
||||
x1="84.634949"
|
||||
y1="116.10083"
|
||||
x2="89.72541"
|
||||
y2="-15.33666"
|
||||
xlink:href="#linearGradient2309"
|
||||
id="linearGradient2315"
|
||||
x1="6.7230334"
|
||||
y1="37.683041"
|
||||
x2="37.804565"
|
||||
y2="29.096745"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.111111,0,138.1081)"
|
||||
r="64.796692"
|
||||
fy="177.29686"
|
||||
fx="80.738739"
|
||||
cy="155.37218"
|
||||
cx="80.738739"
|
||||
id="radialGradient5079"
|
||||
xlink:href="#linearGradient5073"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient5073"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop5075"
|
||||
offset="0"
|
||||
style="stop-color:#000000;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop5077"
|
||||
offset="1"
|
||||
style="stop-color:#000000;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<foreignObject
|
||||
id="foreignObject7221"
|
||||
height="1"
|
||||
width="1"
|
||||
y="0"
|
||||
x="0"
|
||||
requiredExtensions="http://ns.adobe.com/AdobeIllustrator/10.0/">
|
||||
<i:pgfRef
|
||||
xlink:href="#adobe_illustrator_pgf" />
|
||||
</foreignObject>
|
||||
<linearGradient
|
||||
id="XMLID_1_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="95.693398"
|
||||
y1="141.1738"
|
||||
x2="32.308601"
|
||||
y2="77.789001">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#75511A"
|
||||
id="stop7227" />
|
||||
<stop
|
||||
offset="0.3988"
|
||||
style="stop-color:#563A11"
|
||||
id="stop7229" />
|
||||
<stop
|
||||
offset="0.7642"
|
||||
style="stop-color:#402B0B"
|
||||
id="stop7231" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#382509"
|
||||
id="stop7233" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="XMLID_3_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="63.9995"
|
||||
y1="92.865196"
|
||||
x2="63.9995"
|
||||
y2="120.8652"
|
||||
gradientTransform="translate(175.0067,11.74752)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#888A85"
|
||||
id="stop7261" />
|
||||
<stop
|
||||
offset="0.3226"
|
||||
style="stop-color:#A6A7A3"
|
||||
id="stop7263" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#EEEEEC"
|
||||
id="stop7265" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="XMLID_4_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="64.000504"
|
||||
y1="108.8652"
|
||||
x2="64.000504"
|
||||
y2="92.865196">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#EEEEEC"
|
||||
id="stop7270" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFFFFF"
|
||||
id="stop7272" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3081"
|
||||
id="linearGradient2149"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="62.112335"
|
||||
y1="90.513916"
|
||||
x2="67.887672"
|
||||
y2="39.095695" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient26907"
|
||||
id="linearGradient3226"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0,1,-1,0,-39.9985,140.0029)"
|
||||
x1="-70.002899"
|
||||
y1="-383.9971"
|
||||
x2="-11.91648"
|
||||
y2="-383.9971" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3711"
|
||||
id="radialGradient3228"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="343.99899"
|
||||
cy="92"
|
||||
fx="343.99899"
|
||||
fy="92"
|
||||
r="36" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3711"
|
||||
id="linearGradient3230"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0,1.022977,-1.022977,0,111.9686,137.8125)"
|
||||
x1="-88.058083"
|
||||
y1="-131.93112"
|
||||
x2="-45.096584"
|
||||
y2="-131.93112" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#a8a8a8"
|
||||
borderopacity="1"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="4.8203125"
|
||||
inkscape:cx="64"
|
||||
inkscape:cy="64"
|
||||
inkscape:zoom="7.919596"
|
||||
inkscape:cx="41.482905"
|
||||
inkscape:cy="24.425816"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:window-width="1247"
|
||||
inkscape:window-height="816"
|
||||
inkscape:window-x="388"
|
||||
inkscape:window-y="110"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:grid-bbox="true"
|
||||
showgrid="true"
|
||||
gridspacingx="4px"
|
||||
gridspacingy="4px"
|
||||
gridempspacing="0"
|
||||
inkscape:grid-points="true" />
|
||||
inkscape:grid-points="true"
|
||||
gridspacingx="0.5px"
|
||||
gridspacingy="0.5px"
|
||||
gridempspacing="2"
|
||||
inkscape:window-width="872"
|
||||
inkscape:window-height="694"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="25"
|
||||
fill="#75507b" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
@ -458,133 +249,108 @@
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Ulisse Perusin</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>Dictionary</dc:title>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>dictionary</rdf:li>
|
||||
<rdf:li>translation</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/SourceCode" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:label="Livello 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
transform="matrix(0.511285,0.187762,-0.187762,0.511285,41.72321,44.08266)"
|
||||
d="M 153.09403,94.713757 C 144.53658,107.09689 92.616372,93.013297 78.414631,98.001518 C 64.21289,102.98974 32.50348,146.4474 18.082028,142.13539 C 3.6605746,137.82337 1.0106378,84.092245 -8.1220219,72.127031 C -17.254681,60.161818 -68.384124,43.433534 -68.739625,28.385431 C -69.095125,13.337327 -18.812666,-5.7867426 -10.255219,-18.169872 C -1.697772,-30.553002 -1.5880954,-84.349316 12.613645,-89.337536 C 26.815387,-94.325757 60.541592,-52.41396 74.963045,-48.101941 C 89.384498,-43.789923 140.58172,-60.30959 149.71438,-48.344376 C 158.84704,-36.379162 129.40853,8.6478227 129.76403,23.695927 C 130.11953,38.74403 161.65148,82.330628 153.09403,94.713757 z "
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0.20136392"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:arg2="1.2330172"
|
||||
sodipodi:arg1="0.60469864"
|
||||
sodipodi:r2="76.832565"
|
||||
sodipodi:r1="121.72647"
|
||||
sodipodi:cy="25.510532"
|
||||
sodipodi:cx="52.952892"
|
||||
sodipodi:sides="5"
|
||||
id="path3574"
|
||||
style="opacity:1;fill:#e3ad00;fill-opacity:1.0;fill-rule:nonzero;stroke:none;stroke-width:14.80892919;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
|
||||
sodipodi:type="star" />
|
||||
<path
|
||||
style="opacity:1;fill:url(#linearGradient3106);fill-opacity:1.0;fill-rule:nonzero;stroke:url(#linearGradient3605);stroke-width:6.803;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
|
||||
d="M 64.817613,10.159328 C 64.581604,10.317484 63.312654,10.957094 61.843149,12.708869 C 60.101516,14.785047 58.138879,17.917081 56.177505,21.235666 C 54.216128,24.55425 52.251443,28.092247 50.341888,31.150546 C 48.432331,34.208845 46.806952,36.762169 44.279648,38.544213 C 41.752344,40.326257 38.764915,41.002069 35.242943,41.773631 C 31.720971,42.545192 27.75285,43.193621 23.968308,43.926576 C 20.183765,44.659533 16.5656,45.476237 14.025101,46.419462 C 11.841858,47.230044 10.829167,48.201295 10.625712,48.345781 C 10.626839,48.347738 10.624524,48.371367 10.625712,48.374108 C 10.696321,48.571093 10.870285,49.989399 12.127109,52.000123 C 13.563478,54.298089 15.950898,57.154462 18.50096,60.045339 C 21.051023,62.936217 23.774397,65.867627 26.092925,68.628793 C 28.411454,71.389955 30.363146,73.748045 31.27699,76.702337 C 32.190833,79.656627 31.914822,82.68926 31.560274,86.277278 C 31.205724,89.8653 30.616267,93.839413 30.143862,97.665227 C 30.113483,97.911252 30.08362,98.156728 30.054361,98.401429 C 29.628627,101.96194 29.330856,105.3582 29.435657,107.89172 C 29.533657,110.26089 30.173974,111.54076 30.228847,111.74436 C 30.438123,111.73798 31.837454,111.97838 34.138142,111.40442 C 36.7675,110.74847 40.20401,109.39531 43.741411,107.86339 C 47.278812,106.33148 50.937026,104.62602 54.279513,103.27421 C 57.621999,101.9224 60.450754,100.79418 63.542844,100.838 C 66.634933,100.8818 69.418339,102.08321 72.721189,103.52916 C 76.024038,104.97512 79.653393,106.79843 83.145977,108.42996 C 86.638561,110.06147 90.026215,111.49575 92.635935,112.22595 C 94.919441,112.86485 96.334003,112.66799 96.54523,112.67918 C 96.605258,112.47676 97.286649,111.22034 97.451733,108.85487 C 97.640395,106.1515 97.418963,102.46604 97.055137,98.628384 C 96.691312,94.790732 96.174767,90.780408 95.922008,87.183781 C 95.669251,83.587159 95.491404,80.56438 96.488573,77.637169 C 97.485753,74.709955 99.503438,72.399636 101.89927,69.705264 C 104.29508,67.010894 107.11524,64.16591 109.74619,61.348436 C 112.37711,58.530963 114.78913,55.729544 116.29001,53.47319 C 117.57984,51.534136 117.84976,50.137859 117.93304,49.903833 C 117.93436,49.901119 117.93183,49.877435 117.93304,49.875506 C 117.7318,49.725835 116.72138,48.73631 114.56198,47.864201 C 112.04922,46.849382 108.49434,45.927914 104.73209,45.088035 C 100.96983,44.248155 97.012813,43.466178 93.514108,42.595149 C 90.015409,41.724119 87.038194,40.992031 84.562389,39.139105 C 82.086586,37.286179 80.548923,34.65831 78.726774,31.54714 C 76.904626,28.435971 75.041014,24.863438 73.174441,21.49062 C 71.307869,18.117801 69.417536,14.946869 67.735421,12.822182 C 66.263569,10.963081 64.982527,10.293346 64.817613,10.159328 z "
|
||||
id="path3580"
|
||||
sodipodi:nodetypes="cssssssssssssssssscssssssscssssssssssssssssc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
id="path2276"
|
||||
d="M -106.3852,44.124126 L -106.3852,41.329417 L -106.3852,44.124126 z "
|
||||
style="fill:#ffffff;fill-opacity:0.75688076;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0.38139535;fill:url(#radialGradient3743);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
|
||||
id="path3289"
|
||||
sodipodi:cx="63.912209"
|
||||
sodipodi:cy="115.70919"
|
||||
sodipodi:rx="63.912209"
|
||||
sodipodi:ry="12.641975"
|
||||
d="M 127.82442 115.70919 A 63.912209 12.641975 0 1 1 0,115.70919 A 63.912209 12.641975 0 1 1 127.82442 115.70919 z"
|
||||
transform="matrix(-1.001374,0,0,0.410379,128,75.32738)" />
|
||||
style="opacity:0.50196078;color:#000000;fill:url(#radialGradient2292);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:17.85;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
|
||||
id="path2284"
|
||||
sodipodi:cx="24"
|
||||
sodipodi:cy="36.75"
|
||||
sodipodi:rx="22.5"
|
||||
sodipodi:ry="6.75"
|
||||
d="M 46.5 36.75 A 22.5 6.75 0 1 1 1.5,36.75 A 22.5 6.75 0 1 1 46.5 36.75 z"
|
||||
transform="matrix(1.066667,0,0,0.962963,-1.600001,1.111111)" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1.0;fill-rule:evenodd;stroke:url(#linearGradient3648);stroke-width:0.50672567;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.5813008"
|
||||
d="M 55.266721,10.739701 C 56.520212,8.5685899 61.220699,1.3579337 65.008418,1.4134271 C 71.889436,1.5172832 83.511202,31.129589 88.946059,34.460427 C 95.635958,38.560436 119.92387,41.46414 124.34296,44.969282"
|
||||
id="path3632"
|
||||
sodipodi:nodetypes="csss" />
|
||||
style="color:#000000;fill:#523856;fill-opacity:1;fill-rule:nonzero;stroke:#3e263b;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:17.85;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
|
||||
d="M 4.5,11.5 L 43.5,11.5 L 47.5,38.5 L 29,38.5 L 28,37.5 C 26,39 22,39 20,37.5 L 19,38.5 L 0.5,38.5 L 4.5,11.5 z "
|
||||
id="rect1304"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="csss"
|
||||
id="path3634"
|
||||
d="M 55.236135,11.274949 C 56.489626,9.1038383 61.236542,1.57297 65.023711,1.6581121 C 71.830955,1.8111507 83.271335,31.483209 88.869595,34.705112 C 95.670099,38.618929 119.98852,41.765855 124.40761,45.270997"
|
||||
style="fill:none;fill-opacity:1.0;fill-rule:evenodd;stroke:url(#linearGradient3646);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.43089432" />
|
||||
sodipodi:type="inkscape:offset"
|
||||
inkscape:radius="-0.91809106"
|
||||
inkscape:original="M 4.5 11.5 L 0.5 38.5 L 19 38.5 L 20 37.5 C 22 39 26 39 28 37.5 L 29 38.5 L 47.5 38.5 L 43.5 11.5 L 4.5 11.5 z "
|
||||
xlink:href="#rect1304"
|
||||
style="opacity:0.13333333;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:17.85;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
|
||||
id="path2274"
|
||||
inkscape:href="#rect1304"
|
||||
d="M 5.28125,12.40625 L 1.5625,37.59375 L 18.59375,37.59375 L 19.34375,36.84375 C 19.667151,36.507336 20.191452,36.467006 20.5625,36.75 C 21.327469,37.323727 22.653015,37.71875 24,37.71875 C 25.346985,37.71875 26.672531,37.323727 27.4375,36.75 C 27.808548,36.467006 28.332849,36.507336 28.65625,36.84375 L 29.40625,37.59375 L 46.4375,37.59375 L 42.71875,12.40625 L 5.28125,12.40625 z " />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1.0;fill-rule:evenodd;stroke:url(#linearGradient3644);stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.43089432"
|
||||
d="M 55.205632,12.312054 C 56.459123,10.140944 61.420826,2.0361374 65.023711,2.1461616 C 71.282863,2.3391656 83.42385,32.459308 88.778086,35.193162 C 95.766183,38.761259 121.08663,42.680948 124.71264,46.094581"
|
||||
id="path3636"
|
||||
sodipodi:nodetypes="csss" />
|
||||
style="fill:url(#linearGradient2282);fill-opacity:1.0;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 2,36.5 C 7.6666667,36.5 16,35 19,36.5 C 22,34 26,34 29,36.5 C 32,35 41,36.5 46,36.5 L 45.5,34 C 38.5,31.5 29,28.5 24,33 C 19,28.5 9.5,31.5 2.5,34 L 2,36.5 z "
|
||||
id="path2180"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0.70232556;fill:url(#radialGradient3716);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
|
||||
id="path11160"
|
||||
sodipodi:cx="23.190451"
|
||||
sodipodi:cy="59.379417"
|
||||
sodipodi:rx="2.1082227"
|
||||
sodipodi:ry="1.9842097"
|
||||
d="M 25.298673 59.379417 A 2.1082227 1.9842097 0 1 1 21.082228,59.379417 A 2.1082227 1.9842097 0 1 1 25.298673 59.379417 z"
|
||||
transform="matrix(-1.742936,-1.063485,-0.470527,1.244278,191.1539,-3.699137)" />
|
||||
sodipodi:type="inkscape:offset"
|
||||
inkscape:radius="-1.0582203"
|
||||
inkscape:original="M 14 30.875 C 10.125 31.375 6 32.75 2.5 34 L 2 36.5 C 7.6666667 36.5 16 35 19 36.5 C 22 34 26 34 29 36.5 C 32 35 41 36.5 46 36.5 L 45.5 34 C 38.5 31.5 29 28.5 24 33 C 21.5 30.75 17.875 30.375 14 30.875 z "
|
||||
xlink:href="#path2180"
|
||||
style="opacity:0.30196078;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2315);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path2266"
|
||||
inkscape:href="#path2180"
|
||||
d="M 14.375,31.9375 C 10.963293,32.392394 7.260823,33.622273 3.90625,34.8125 L 3.8125,35.34375 C 6.2979599,35.262594 9.0476285,35.037732 11.6875,34.875 C 14.462294,34.703951 16.881256,34.711661 18.78125,35.40625 C 20.133116,34.409774 21.661646,33.894157 23.21875,33.75 C 21.042747,31.830616 17.941674,31.461944 14.375,31.9375 z M 28.625,31.9375 C 27.145571,32.213473 25.86037,32.798142 24.78125,33.75 C 26.338354,33.894157 27.866884,34.409774 29.21875,35.40625 C 31.163554,34.697135 33.704549,34.703523 36.5625,34.875 C 39.261382,35.036933 41.920385,35.260963 44.1875,35.34375 L 44.09375,34.8125 C 40.739177,33.622273 37.036707,32.392394 33.625,31.9375 C 31.827105,31.697781 30.128781,31.656984 28.625,31.9375 z " />
|
||||
<path
|
||||
style="opacity:1;fill:url(#linearGradient3732);fill-opacity:1.0;fill-rule:nonzero;stroke:none;stroke-width:6.803;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
|
||||
d="M 64.8125 10.15625 C 64.576492 10.314406 63.313255 10.966975 61.84375 12.71875 C 60.102119 14.794928 58.148874 17.931415 56.1875 21.25 C 54.226123 24.568584 52.253305 28.097951 50.34375 31.15625 C 48.434193 34.21455 46.808554 36.749206 44.28125 38.53125 C 41.753946 40.313295 38.771972 41.009688 35.25 41.78125 C 31.728028 42.55281 27.753292 43.204545 23.96875 43.9375 C 20.184208 44.670458 16.571749 45.463025 14.03125 46.40625 C 11.848007 47.216834 10.828455 48.199264 10.625 48.34375 C 10.62496 48.346283 10.625145 48.371753 10.625 48.375 C 10.695609 48.571986 10.868176 49.989276 12.125 52 C 13.561369 54.297967 15.949938 57.140373 18.5 60.03125 C 20.422509 62.210702 22.440722 64.427292 24.3125 66.5625 C 47.187815 68.967477 71.532076 77.450485 95.75 81.53125 C 95.830132 80.186335 96.067405 78.894893 96.5 77.625 C 97.497182 74.697786 99.510418 72.413122 101.90625 69.71875 C 104.30206 67.024383 107.11905 64.161224 109.75 61.34375 C 112.38092 58.526279 114.78037 55.725104 116.28125 53.46875 C 117.57108 51.529696 117.85422 50.140276 117.9375 49.90625 C 117.93747 49.903618 117.93766 49.878251 117.9375 49.875 C 117.73626 49.725328 116.7219 48.747109 114.5625 47.875 C 112.04974 46.860181 108.481 45.933629 104.71875 45.09375 C 100.95649 44.253869 96.998705 43.464779 93.5 42.59375 C 90.001302 41.722719 87.038305 40.977926 84.5625 39.125 C 82.0867 37.272072 80.540899 34.67367 78.71875 31.5625 C 76.8966 28.451331 75.054073 24.872818 73.1875 21.5 C 71.320931 18.127181 69.432115 14.937187 67.75 12.8125 C 66.278149 10.953399 64.977414 10.290268 64.8125 10.15625 z "
|
||||
id="path3718" />
|
||||
style="fill:url(#linearGradient2245);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2247);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 2.5,34 C 9,31.5 20,29 24,33 C 28,29 39,31.5 45.5,34 L 42.5,10.5 C 37,8 27.5,6 24,9 C 20,6 12,8 5.5,10.5 L 2.5,34 z "
|
||||
id="path2182"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
<path
|
||||
style="opacity:0.41393443;fill:url(#linearGradient3739);fill-opacity:1.0;fill-rule:nonzero;stroke:none;stroke-width:6.803;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
|
||||
d="M 64.8125 10.15625 C 64.576492 10.314406 63.313255 10.966975 61.84375 12.71875 C 60.102119 14.794928 58.148874 17.931415 56.1875 21.25 C 54.226123 24.568584 52.253305 28.097951 50.34375 31.15625 C 48.434193 34.21455 46.808554 36.749206 44.28125 38.53125 C 41.753946 40.313295 38.771972 41.009688 35.25 41.78125 C 31.728028 42.55281 27.753292 43.204545 23.96875 43.9375 C 20.184208 44.670458 16.571749 45.463025 14.03125 46.40625 C 11.848007 47.216834 10.828455 48.199264 10.625 48.34375 C 10.62496 48.346283 10.625145 48.371753 10.625 48.375 C 10.695609 48.571986 10.868176 49.989276 12.125 52 C 13.561369 54.297967 15.949938 57.140373 18.5 60.03125 C 20.422509 62.210702 22.440722 64.427292 24.3125 66.5625 C 25.752576 66.713901 27.204929 66.896788 28.65625 67.09375 C 42.328845 56.623879 60.733777 43.188439 78.53125 31.25 C 76.771363 28.21678 74.98888 24.755017 73.1875 21.5 C 71.320931 18.127181 69.432115 14.937187 67.75 12.8125 C 66.278149 10.953399 64.977414 10.290268 64.8125 10.15625 z M 99.34375 43.90625 C 86.79565 53.381359 75.792347 63.914843 66.25 75.09375 C 76.032927 77.504442 85.901575 79.871772 95.75 81.53125 C 95.830132 80.186335 96.067405 78.894893 96.5 77.625 C 97.497182 74.697786 99.510418 72.413122 101.90625 69.71875 C 104.30206 67.024383 107.11905 64.161224 109.75 61.34375 C 112.38092 58.526279 114.78037 55.725104 116.28125 53.46875 C 117.57108 51.529696 117.85422 50.140276 117.9375 49.90625 C 117.93747 49.903618 117.93766 49.878251 117.9375 49.875 C 117.73626 49.725328 116.7219 48.747109 114.5625 47.875 C 112.04974 46.860181 108.481 45.933629 104.71875 45.09375 C 102.94925 44.698729 101.13165 44.292609 99.34375 43.90625 z "
|
||||
id="path3736" />
|
||||
<path
|
||||
id="path3741"
|
||||
d="M 64.8125,10.15625 C 64.576492,10.314406 63.313255,10.966975 61.84375,12.71875 C 60.102119,14.794928 58.148874,17.931415 56.1875,21.25 C 54.226123,24.568584 52.253305,28.097951 50.34375,31.15625 C 48.434193,34.21455 46.808554,36.749206 44.28125,38.53125 C 41.753946,40.313295 38.771972,41.009688 35.25,41.78125 C 31.728028,42.55281 27.753292,43.204545 23.96875,43.9375 C 20.184208,44.670458 16.571749,45.463025 14.03125,46.40625 C 11.848007,47.216834 10.828455,48.199264 10.625,48.34375 C 10.62496,48.346283 10.625145,48.371753 10.625,48.375 C 10.695609,48.571986 10.868176,49.989276 12.125,52 C 13.561369,54.297967 60.733777,43.188439 78.53125,31.25 C 76.771363,28.21678 74.98888,24.755017 73.1875,21.5 C 71.320931,18.127181 69.432115,14.937187 67.75,12.8125 C 66.278149,10.953399 64.977414,10.290268 64.8125,10.15625 z M 99.34375,43.90625 C 68.470207,67.487324 85.901575,79.871772 95.75,81.53125 C 95.830132,80.186335 96.067405,78.894893 96.5,77.625 C 97.497182,74.697786 99.510418,72.413122 101.90625,69.71875 C 104.30206,67.024383 107.11905,64.161224 109.75,61.34375 C 112.38092,58.526279 114.78037,55.725104 116.28125,53.46875 C 117.57108,51.529696 117.85422,50.140276 117.9375,49.90625 C 117.93747,49.903618 117.93766,49.878251 117.9375,49.875 C 117.73626,49.725328 116.7219,48.747109 114.5625,47.875 C 112.04974,46.860181 108.481,45.933629 104.71875,45.09375 C 102.94925,44.698729 101.13165,44.292609 99.34375,43.90625 z "
|
||||
style="opacity:0.34836066;fill:url(#linearGradient3739);fill-opacity:1.0;fill-rule:nonzero;stroke:none;stroke-width:6.803;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
|
||||
sodipodi:nodetypes="csssssssssscsscccssssssssc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0.35655739;fill:url(#radialGradient3753);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:0.43089432"
|
||||
id="path3745"
|
||||
sodipodi:cx="5.7531347"
|
||||
sodipodi:cy="-45.41592"
|
||||
sodipodi:rx="124.10334"
|
||||
sodipodi:ry="11.780229"
|
||||
d="M 129.85647 -45.41592 A 124.10334 11.780229 0 1 1 -118.35021,-45.41592 A 124.10334 11.780229 0 1 1 129.85647 -45.41592 z"
|
||||
transform="matrix(0.126835,-5.623734e-2,-3.870485e-2,-9.211943e-2,44.81196,106.2565)" />
|
||||
<path
|
||||
transform="matrix(-0.126834,-5.702883e-2,3.870485e-2,-9.341592e-2,81.95911,106.3126)"
|
||||
d="M 129.85647 -45.41592 A 124.10334 11.780229 0 1 1 -118.35021,-45.41592 A 124.10334 11.780229 0 1 1 129.85647 -45.41592 z"
|
||||
sodipodi:ry="11.780229"
|
||||
sodipodi:rx="124.10334"
|
||||
sodipodi:cy="-45.41592"
|
||||
sodipodi:cx="5.7531347"
|
||||
id="path3755"
|
||||
style="opacity:0.49590164;fill:url(#radialGradient3757);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:0.43089432"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(-6.548665e-3,-0.135343,-9.988208e-2,2.696531e-3,91.9485,98.93228)"
|
||||
d="M 129.85647 -45.41592 A 124.10334 11.780229 0 1 1 -118.35021,-45.41592 A 124.10334 11.780229 0 1 1 129.85647 -45.41592 z"
|
||||
sodipodi:ry="11.780229"
|
||||
sodipodi:rx="124.10334"
|
||||
sodipodi:cy="-45.41592"
|
||||
sodipodi:cx="5.7531347"
|
||||
id="path3759"
|
||||
style="opacity:0.27459016;fill:url(#radialGradient3761);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:0.43089432"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
style="opacity:0.17;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:14.80892944;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
|
||||
d="M 126.314,45.945281 C 127.57715,54.014451 105.05512,70.888621 102.47025,78.476531 C 99.826558,86.237151 107.76438,114.43949 101.06401,119.16403 C 94.363618,123.88859 70.449248,106.96767 62.251508,106.85153 C 54.053768,106.73539 29.690348,122.98275 23.126508,118.07028 C 22.815738,117.8377 22.558998,117.52665 22.314008,117.19528 C 22.708398,118.50348 23.279848,119.53038 24.126508,120.16403 C 30.690348,125.0765 55.053768,108.82913 63.251508,108.94528 C 71.449248,109.06142 95.363618,126.01358 102.064,121.28903 C 108.76438,116.56449 100.82656,88.362141 103.47025,80.601531 C 106.11395,72.840911 129.61178,55.340191 127.189,47.507781 C 127.02007,46.961651 126.72727,46.430131 126.314,45.945281 z M 1.5015079,49.851531 C 4.5831579,57.838661 18.613888,70.110761 22.845258,77.320281 C 20.896748,71.159061 6.3960679,58.682221 1.5015079,49.851531 z "
|
||||
id="path3308" />
|
||||
<path
|
||||
style="opacity:0.17;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:14.80892944;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
|
||||
d="M 127.1265,47.382781 C 127.77543,55.569451 105.80307,72.111371 103.2515,79.601531 C 100.60781,87.362151 108.54563,115.56449 101.84525,120.28903 C 95.144868,125.01357 71.261748,108.06142 63.064008,107.94528 C 54.866278,107.82913 30.471598,124.10775 23.907758,119.19528 C 22.913828,118.45141 22.292008,117.15904 21.907758,115.50778 C 22.250148,117.65334 22.937778,119.30561 24.126508,120.19528 C 30.690348,125.10775 55.053778,108.82913 63.251508,108.94528 C 71.449248,109.06142 95.363638,126.01357 102.064,121.28903 C 108.76438,116.56449 100.82655,88.362151 103.47025,80.601531 C 106.11395,72.840911 129.61177,55.340181 127.189,47.507781 C 127.17552,47.464201 127.14164,47.425951 127.1265,47.382781 z M 0.93900787,47.757781 C 1.9815279,56.300511 21.645828,72.265141 23.876508,79.476531 C 23.903658,79.564291 23.914628,79.665031 23.939008,79.757781 C 23.870988,79.288551 23.775168,78.856101 23.657758,78.476531 C 21.511968,71.539581 3.2557579,56.495971 0.93900787,47.757781 z "
|
||||
id="path3303" />
|
||||
<path
|
||||
style="fill:url(#radialGradient3771);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;opacity:0.55327869"
|
||||
d="M 25.088207,80.21837 C 25.534474,90.747814 22.054583,105.95279 22.237274,111.46459 L 24.632057,111.69267 C 26.600057,101.69251 28.017156,91.508728 28.167214,80.902594 L 25.088207,80.21837 z "
|
||||
id="path3763"
|
||||
style="color:#000000;fill:url(#linearGradient2219);fill-opacity:1.0;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:17.85;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
|
||||
d="M 24,9.5 C 22,8 19.5,7.5 16,8 L 16,30.5 C 18,29.5 22,30.5 24,32.5 L 24,9.5 z "
|
||||
id="rect2192"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="opacity:0.62;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:14.80892944;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
|
||||
d="M 0.89521787,47.070281 C 0.89114787,55.417331 21.603498,72.067851 23.895208,79.476531 C 24.122348,80.210811 24.248638,81.111361 24.301458,82.164031 C 24.258118,80.995191 24.141798,79.961201 23.895208,79.164031 C 21.629398,71.839061 1.3489179,55.506151 0.89521787,47.070281 z M 127.36395,48.789031 C 126.76815,57.193121 105.96742,73.013441 103.48895,80.289031 C 103.13757,81.320501 102.96318,82.732101 102.92645,84.382781 C 102.97549,82.859581 103.15849,81.571601 103.48895,80.601531 C 105.99802,73.236121 127.27213,57.108781 127.36395,48.789031 z M 63.270208,108.63278 C 55.072468,108.51664 30.709048,124.79525 24.145208,119.88278 C 22.709368,118.80818 21.987678,116.61813 21.738958,113.78903 C 21.963318,116.76637 22.658218,119.08239 24.145208,120.19528 C 30.709048,125.10775 55.072468,108.82913 63.270208,108.94528 C 71.467938,109.06142 95.382328,126.01357 102.0827,121.28903 C 103.80587,120.07399 104.52313,117.30046 104.73895,113.72653 C 104.49958,117.15646 103.75779,119.79539 102.0827,120.97653 C 95.382328,125.70107 71.467938,108.74892 63.270208,108.63278 z "
|
||||
id="path3296" />
|
||||
style="color:#000000;fill:url(#linearGradient2211);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:17.85;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
|
||||
d="M 24,9.5 C 25.221264,8.803878 26.327771,7.9069322 28,8 L 29,30.5 C 27.5,30 25.5,31.5 24,32.5 L 24,9.5 z "
|
||||
id="path2195"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
sodipodi:type="inkscape:offset"
|
||||
inkscape:radius="-0.92850536"
|
||||
inkscape:original="M 20.34375 7.625 C 16.101562 7.0390625 10.375 8.625 5.5 10.5 L 2.5 34 C 9 31.5 20 29 24 33 C 28 29 39 31.5 45.5 34 L 42.5 10.5 C 37 8 27.5 6 24 9 C 23 8.25 21.757812 7.8203125 20.34375 7.625 z "
|
||||
xlink:href="#path2182"
|
||||
style="opacity:0.65098039;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path2243"
|
||||
inkscape:href="#path2182"
|
||||
d="M 17.03125,8.375 C 14.611845,8.6563261 11.827815,9.5624782 8.78125,10.71875 L 4.25,32.59375 C 7.5567067,31.338728 11.345145,30.271354 14.90625,29.9375 C 16.969491,29.744071 18.927893,29.768608 20.625,30.125 C 21.963283,30.406039 23.09173,31.003906 24,31.8125 C 24.90827,31.003906 26.036717,30.406039 27.375,30.125 C 29.072107,29.768608 31.030509,29.744071 33.09375,29.9375 C 36.654855,30.271354 40.443293,31.338728 43.75,32.59375 L 39.1875,10.6875 C 36.612085,9.5579242 33.750698,8.6570052 31.15625,8.375 C 28.420939,8.0776836 26.053467,8.4675643 24.59375,9.71875 C 24.262671,9.9972426 23.783138,10.010203 23.4375,9.75 C 21.660341,8.417131 19.571761,8.0795918 17.03125,8.375 z " />
|
||||
<path
|
||||
style="fill:url(#linearGradient2264);fill-opacity:1.0;fill-rule:evenodd;stroke:url(#linearGradient2307);stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M 24.455357,8.7321429 C 24.5,20.5 34,20 33.5,30.5 L 32.5,34.5 L 34,34 L 35,35 L 35.5,31 C 36,20 24.544643,19.089286 24.5,8.5 L 24.455357,8.7321429 z "
|
||||
id="path2227"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 15 KiB |
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 47 KiB |
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 14 KiB |
@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008-2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
@ -23,7 +22,14 @@ class Danas(BasicNewsRecipe):
|
||||
language = 'sr'
|
||||
publication_type = 'newspaper'
|
||||
remove_empty_feeds = True
|
||||
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} .article_description,body,.lokacija{font-family: Tahoma,Arial,Helvetica,sans1,sans-serif} .nadNaslov,h1,.preamble{font-family: Georgia,"Times New Roman",Times,serif1,serif} .antrfileText{border-left: 2px solid #999999; margin-left: 0.8em; padding-left: 1.2em; margin-bottom: 0; margin-top: 0} h2,.datum,.lokacija,.autor{font-size: small} .antrfileNaslov{border-left: 2px solid #999999; margin-left: 0.8em; padding-left: 1.2em; font-weight:bold; margin-bottom: 0; margin-top: 0} img{margin-bottom: 0.8em} '
|
||||
extra_css = """ @font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)}
|
||||
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
|
||||
.article_description,body,.lokacija{font-family: Tahoma,Arial,Helvetica,sans1,sans-serif}
|
||||
.nadNaslov,h1,.preamble{font-family: Georgia,"Times New Roman",Times,serif1,serif}
|
||||
.antrfileText{border-left: 2px solid #999999; margin-left: 0.8em; padding-left: 1.2em;
|
||||
margin-bottom: 0; margin-top: 0} h2,.datum,.lokacija,.autor{font-size: small}
|
||||
.antrfileNaslov{border-left: 2px solid #999999; margin-left: 0.8em; padding-left: 1.2em;
|
||||
font-weight:bold; margin-bottom: 0; margin-top: 0} img{margin-bottom: 0.8em} """
|
||||
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
@ -42,19 +48,32 @@ class Danas(BasicNewsRecipe):
|
||||
]
|
||||
|
||||
feeds = [
|
||||
(u'Politika' , u'http://www.danas.rs/rss/rss.asp?column_id=27')
|
||||
,(u'Hronika' , u'http://www.danas.rs/rss/rss.asp?column_id=2' )
|
||||
,(u'Dru\xc5\xa1tvo', u'http://www.danas.rs/rss/rss.asp?column_id=24')
|
||||
,(u'Dijalog' , u'http://www.danas.rs/rss/rss.asp?column_id=1' )
|
||||
,(u'Ekonomija', u'http://www.danas.rs/rss/rss.asp?column_id=6' )
|
||||
,(u'Svet' , u'http://www.danas.rs/rss/rss.asp?column_id=25')
|
||||
,(u'Srbija' , u'http://www.danas.rs/rss/rss.asp?column_id=28')
|
||||
,(u'Kultura' , u'http://www.danas.rs/rss/rss.asp?column_id=5' )
|
||||
,(u'Sport' , u'http://www.danas.rs/rss/rss.asp?column_id=13')
|
||||
,(u'Scena' , u'http://www.danas.rs/rss/rss.asp?column_id=42')
|
||||
,(u'Feljton' , u'http://www.danas.rs/rss/rss.asp?column_id=19')
|
||||
,(u'Periskop' , u'http://www.danas.rs/rss/rss.asp?column_id=4' )
|
||||
,(u'Famozno' , u'http://www.danas.rs/rss/rss.asp?column_id=47')
|
||||
(u'Politika' , u'http://www.danas.rs/rss/rss.asp?column_id=27')
|
||||
,(u'Hronika' , u'http://www.danas.rs/rss/rss.asp?column_id=2' )
|
||||
,(u'Drustvo' , u'http://www.danas.rs/rss/rss.asp?column_id=24')
|
||||
,(u'Dijalog' , u'http://www.danas.rs/rss/rss.asp?column_id=1' )
|
||||
,(u'Ekonomija' , u'http://www.danas.rs/rss/rss.asp?column_id=6' )
|
||||
,(u'Svet' , u'http://www.danas.rs/rss/rss.asp?column_id=25')
|
||||
,(u'Srbija' , u'http://www.danas.rs/rss/rss.asp?column_id=28')
|
||||
,(u'Kultura' , u'http://www.danas.rs/rss/rss.asp?column_id=5' )
|
||||
,(u'Sport' , u'http://www.danas.rs/rss/rss.asp?column_id=13')
|
||||
,(u'Scena' , u'http://www.danas.rs/rss/rss.asp?column_id=42')
|
||||
,(u'Feljton' , u'http://www.danas.rs/rss/rss.asp?column_id=19')
|
||||
,(u'Periskop' , u'http://www.danas.rs/rss/rss.asp?column_id=4' )
|
||||
,(u'Famozno' , u'http://www.danas.rs/rss/rss.asp?column_id=47')
|
||||
,(u'Sluzbena beleska' , u'http://www.danas.rs/rss/rss.asp?column_id=48')
|
||||
,(u'Suocavanja' , u'http://www.danas.rs/rss/rss.asp?column_id=49')
|
||||
,(u'Moj Izbor' , u'http://www.danas.rs/rss/rss.asp?column_id=50')
|
||||
,(u'Direktno' , u'http://www.danas.rs/rss/rss.asp?column_id=51')
|
||||
,(u'I tome slicno' , u'http://www.danas.rs/rss/rss.asp?column_id=52')
|
||||
,(u'No longer and not yet', u'http://www.danas.rs/rss/rss.asp?column_id=53')
|
||||
,(u'Resetovanje' , u'http://www.danas.rs/rss/rss.asp?column_id=54')
|
||||
,(u'Iza scene' , u'http://www.danas.rs/rss/rss.asp?column_id=60')
|
||||
,(u'Drustvoslovlje' , u'http://www.danas.rs/rss/rss.asp?column_id=55')
|
||||
,(u'Zvaka u pepeljari' , u'http://www.danas.rs/rss/rss.asp?column_id=56')
|
||||
,(u'Vostani Serbie' , u'http://www.danas.rs/rss/rss.asp?column_id=57')
|
||||
,(u'Med&Jad-a' , u'http://www.danas.rs/rss/rss.asp?column_id=58')
|
||||
,(u'Svetlosti pozornice' , u'http://www.danas.rs/rss/rss.asp?column_id=59')
|
||||
]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
@ -65,3 +84,10 @@ class Danas(BasicNewsRecipe):
|
||||
def print_version(self, url):
|
||||
return url + '&action=print'
|
||||
|
||||
def get_cover_url(self):
|
||||
cover_url = None
|
||||
soup = self.index_to_soup('http://www.danas.rs/')
|
||||
for citem in soup.findAll('img'):
|
||||
if citem['src'].endswith('naslovna.jpg'):
|
||||
return 'http://www.danas.rs' + citem['src']
|
||||
return cover_url
|
||||
|
58
resources/recipes/thairath.recipe
Normal file
58
resources/recipes/thairath.recipe
Normal file
@ -0,0 +1,58 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1271637235(BasicNewsRecipe):
|
||||
|
||||
title = u'Thairath'
|
||||
__author__ = 'Anat R.'
|
||||
language = 'th'
|
||||
|
||||
oldest_article = 7
|
||||
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
|
||||
remove_javascript = True
|
||||
|
||||
use_embedded_content = False
|
||||
feeds = [(u'News',
|
||||
u'http://www.thairath.co.th/rss/news.xml'), (u'Politics',
|
||||
u'http://www.thairath.co.th/rss/pol.xml'), (u'Economy',
|
||||
u'http://www.thairath.co.th/rss/eco.xml'), (u'International',
|
||||
u'http://www.thairath.co.th/rss/oversea.xml'), (u'Sports',
|
||||
u'http://www.thairath.co.th/rss/sport.xml'), (u'Life',
|
||||
u'http://www.thairath.co.th/rss/life.xml'), (u'Education',
|
||||
u'http://www.thairath.co.th/rss/edu.xml'), (u'Tech',
|
||||
u'http://www.thairath.co..th/rss/tech.xml'), (u'Entertainment',
|
||||
u'http://www.thairath.co.th/rss/ent.xml')]
|
||||
keep_only_tags = []
|
||||
|
||||
keep_only_tags.append(dict(name = 'h1', attrs = {'id' : 'title'}))
|
||||
|
||||
keep_only_tags.append(dict(name = 'ul', attrs = {'class' :
|
||||
'detail-info'}))
|
||||
|
||||
keep_only_tags.append(dict(name = 'img', attrs = {'class' :
|
||||
'detail-image'}))
|
||||
|
||||
keep_only_tags.append(dict(name = 'div', attrs = {'class' :
|
||||
'entry'}))
|
||||
remove_tags = []
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id':
|
||||
'menu-holder'}))
|
||||
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class':
|
||||
'addthis_toolbox addthis_default_style'}))
|
||||
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class': 'box top-item'}))
|
||||
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class': 'column-200 column-margin-430'}))
|
||||
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id':
|
||||
'detail-related'}))
|
||||
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id': 'related'}))
|
||||
|
||||
remove_tags.append(dict(name = 'id', attrs = {'class': 'footer'}))
|
||||
|
||||
remove_tags.append(dict(name = "ul",attrs =
|
||||
{'id':'banner-highlights-images'}))
|
44
resources/recipes/the_nation_thai.recipe
Normal file
44
resources/recipes/the_nation_thai.recipe
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1271596863(BasicNewsRecipe):
|
||||
|
||||
title = u'The Nation'
|
||||
__author__ = 'Anat R.'
|
||||
language = 'en_TH'
|
||||
|
||||
oldest_article = 7
|
||||
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
|
||||
remove_javascript = True
|
||||
|
||||
use_embedded_content = False
|
||||
feeds = [(u'Topstory',
|
||||
u'http://www.nationmultimedia.com/home/rss/topstories.rss'),
|
||||
(u'National', u'http://www.nationmultimedia.com/home/rss/national.rss'),
|
||||
(u'Politics',
|
||||
u'http://www.nationmultimedia.com/home/rss/politics.rss'), (u'Business',
|
||||
u'http://www.nationmultimedia.com/home/rss/business.rss'),
|
||||
(u'Regional', u'http://www.nationmultimedia.com/home/rss/regional.rss'),
|
||||
(u'Sports', u'http://www.nationmultimedia.com/home/rss/sport.rss'),
|
||||
(u'Travel', u'http://www.nationmultimedia.com/home/rss/travel.rss'),
|
||||
(u'Life', u'http://www.nationmultimedia.com/home/rss/life.rss')]
|
||||
keep_only_tags = []
|
||||
|
||||
keep_only_tags.append(dict(name = 'div', attrs = {'class' :
|
||||
'pd10'}))
|
||||
remove_tags = []
|
||||
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class':
|
||||
'WrapperHeaderCol2-2'}))
|
||||
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class':
|
||||
'LayoutMenu2'}))
|
||||
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class':
|
||||
'TextHeaderRight'}))
|
||||
|
||||
remove_tags.append(dict(name = "ul",attrs = {'id':'toolZoom'}))
|
||||
|
@ -30,7 +30,7 @@ def authors_to_string(authors):
|
||||
|
||||
def author_to_author_sort(author):
|
||||
method = tweaks['author_sort_copy_method']
|
||||
if method == 'copy' or (method == 'comma' and author.count(',') > 0):
|
||||
if method == 'copy' or (method == 'comma' and ',' in author):
|
||||
return author
|
||||
tokens = author.split()
|
||||
tokens = tokens[-1:] + tokens[:-1]
|
||||
@ -223,6 +223,7 @@ class MetaInformation(object):
|
||||
'isbn', 'tags', 'cover_data', 'application_id', 'guide',
|
||||
'manifest', 'spine', 'toc', 'cover', 'language',
|
||||
'book_producer', 'timestamp', 'lccn', 'lcc', 'ddc',
|
||||
'author_sort_map',
|
||||
'pubdate', 'rights', 'publication_type', 'uuid'):
|
||||
if hasattr(mi, attr):
|
||||
setattr(ans, attr, getattr(mi, attr))
|
||||
@ -244,6 +245,7 @@ class MetaInformation(object):
|
||||
self.tags = getattr(mi, 'tags', [])
|
||||
#: mi.cover_data = (ext, data)
|
||||
self.cover_data = getattr(mi, 'cover_data', (None, None))
|
||||
self.author_sort_map = getattr(mi, 'author_sort_map', {})
|
||||
|
||||
for x in ('author_sort', 'title_sort', 'comments', 'category', 'publisher',
|
||||
'series', 'series_index', 'rating', 'isbn', 'language',
|
||||
@ -258,7 +260,7 @@ class MetaInformation(object):
|
||||
'series', 'series_index', 'tags', 'rating', 'isbn', 'language',
|
||||
'application_id', 'manifest', 'toc', 'spine', 'guide', 'cover',
|
||||
'book_producer', 'timestamp', 'lccn', 'lcc', 'ddc', 'pubdate',
|
||||
'rights', 'publication_type', 'uuid'
|
||||
'rights', 'publication_type', 'uuid', 'author_sort_map'
|
||||
):
|
||||
prints(x, getattr(self, x, 'None'))
|
||||
|
||||
@ -288,6 +290,9 @@ class MetaInformation(object):
|
||||
self.tags += mi.tags
|
||||
self.tags = list(set(self.tags))
|
||||
|
||||
if mi.author_sort_map:
|
||||
self.author_sort_map.update(mi.author_sort_map)
|
||||
|
||||
if getattr(mi, 'cover_data', False):
|
||||
other_cover = mi.cover_data[-1]
|
||||
self_cover = self.cover_data[-1] if self.cover_data else ''
|
||||
|
@ -35,6 +35,8 @@ PUBLICATION_METADATA_FIELDS = frozenset([
|
||||
'title_sort',
|
||||
# Ordered list of authors. Must never be None, can be [_('Unknown')]
|
||||
'authors',
|
||||
# Map of sort strings for each author
|
||||
'author_sort_map',
|
||||
# Pseudo field that can be set, but if not set is auto generated
|
||||
# from authors and languages
|
||||
'author_sort',
|
||||
|
@ -16,6 +16,7 @@ NULL_VALUES = {
|
||||
'classifiers' : {},
|
||||
'languages' : [],
|
||||
'device_collections': [],
|
||||
'author_sort_map': {},
|
||||
'authors' : [_('Unknown')],
|
||||
'title' : _('Unknown'),
|
||||
}
|
||||
|
@ -741,7 +741,7 @@ class OPF(object):
|
||||
|
||||
def fset(self, val):
|
||||
for tag in list(self.tags_path(self.metadata)):
|
||||
self.metadata.remove(tag)
|
||||
tag.getparent().remove(tag)
|
||||
for tag in val:
|
||||
elem = self.create_metadata_element('subject')
|
||||
self.set_text(elem, unicode(tag))
|
||||
|
@ -43,8 +43,8 @@ def _config():
|
||||
help=_('Notify when a new version is available'))
|
||||
c.add_opt('use_roman_numerals_for_series_number', default=True,
|
||||
help=_('Use Roman numerals for series number'))
|
||||
c.add_opt('sort_by_popularity', default=False,
|
||||
help=_('Sort tags list by popularity'))
|
||||
c.add_opt('sort_tags_by', default='name',
|
||||
help=_('Sort tags list by name, popularity, or rating'))
|
||||
c.add_opt('cover_flow_queue_length', default=6,
|
||||
help=_('Number of covers to show in the cover browsing mode'))
|
||||
c.add_opt('LRF_conversion_defaults', default=[],
|
||||
@ -101,6 +101,8 @@ def _config():
|
||||
help=_('tag browser categories not to display'))
|
||||
c.add_opt('gui_layout', choices=['wide', 'narrow'],
|
||||
help=_('The layout of the user interface'), default='wide')
|
||||
c.add_opt('show_avg_rating', default=True,
|
||||
help=_('Show the average rating per item indication in the tag browser'))
|
||||
return ConfigProxy(c)
|
||||
|
||||
config = _config()
|
||||
|
@ -109,7 +109,7 @@ class CoverView(QWidget): # {{{
|
||||
|
||||
def show_data(self, data):
|
||||
self.animation.stop()
|
||||
if data.get('id', None) == self.data.get('id', None):
|
||||
if data.get('id', True) == self.data.get('id', False):
|
||||
return
|
||||
self.data = {'id':data.get('id', None)}
|
||||
if data.has_key('cover'):
|
||||
@ -258,8 +258,7 @@ class BookDetails(QWidget):
|
||||
id_, fmt = val.split(':')
|
||||
self.view_specific_format.emit(int(id_), fmt)
|
||||
elif typ == 'devpath':
|
||||
path = os.path.dirname(val)
|
||||
QDesktopServices.openUrl(QUrl.fromLocalFile(path))
|
||||
QDesktopServices.openUrl(QUrl.fromLocalFile(val))
|
||||
|
||||
|
||||
def mouseReleaseEvent(self, ev):
|
||||
@ -275,8 +274,6 @@ class BookDetails(QWidget):
|
||||
self.setToolTip('<p>'+_('Click to open Book Details window') +
|
||||
'<br><br>' + _('Path') + ': ' + data.get(_('Path'), ''))
|
||||
|
||||
|
||||
|
||||
def reset_info(self):
|
||||
self.show_data({})
|
||||
|
||||
|
@ -13,7 +13,7 @@ from PyQt4.Qt import QPixmap, SIGNAL
|
||||
from calibre.gui2 import choose_images, error_dialog
|
||||
from calibre.gui2.convert.metadata_ui import Ui_Form
|
||||
from calibre.ebooks.metadata import authors_to_string, string_to_authors, \
|
||||
MetaInformation, authors_to_sort_string
|
||||
MetaInformation
|
||||
from calibre.ebooks.metadata.opf2 import metadata_to_opf
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
from calibre.gui2.convert import Widget
|
||||
@ -57,7 +57,7 @@ class MetadataWidget(Widget, Ui_Form):
|
||||
au = unicode(self.author.currentText())
|
||||
au = re.sub(r'\s+et al\.$', '', au)
|
||||
authors = string_to_authors(au)
|
||||
self.author_sort.setText(authors_to_sort_string(authors))
|
||||
self.author_sort.setText(self.db.author_sort_from_authors(authors))
|
||||
|
||||
|
||||
def initialize_metadata_options(self):
|
||||
|
@ -23,7 +23,7 @@ from calibre.devices.scanner import DeviceScanner
|
||||
from calibre.gui2 import config, error_dialog, Dispatcher, dynamic, \
|
||||
pixmap_to_data, warning_dialog, \
|
||||
question_dialog, info_dialog, choose_dir
|
||||
from calibre.ebooks.metadata import authors_to_string, authors_to_sort_string
|
||||
from calibre.ebooks.metadata import authors_to_string
|
||||
from calibre import preferred_encoding, prints
|
||||
from calibre.utils.filenames import ascii_filename
|
||||
from calibre.devices.errors import FreeSpaceError
|
||||
@ -1409,7 +1409,7 @@ class DeviceMixin(object): # {{{
|
||||
# Set author_sort if it isn't already
|
||||
asort = getattr(book, 'author_sort', None)
|
||||
if not asort and book.authors:
|
||||
book.author_sort = authors_to_sort_string(book.authors)
|
||||
book.author_sort = self.library_view.model().db.author_sort_from_authors(book.authors)
|
||||
resend_metadata = True
|
||||
|
||||
if resend_metadata:
|
||||
|
@ -481,6 +481,8 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
||||
self.opt_enforce_cpu_limit.setChecked(config['enforce_cpu_limit'])
|
||||
self.device_detection_button.clicked.connect(self.debug_device_detection)
|
||||
self.port.editingFinished.connect(self.check_port_value)
|
||||
self.search_as_you_type.setChecked(config['search_as_you_type'])
|
||||
self.show_avg_rating.setChecked(config['show_avg_rating'])
|
||||
self.show_splash_screen.setChecked(gprefs.get('show_splash_screen',
|
||||
True))
|
||||
li = None
|
||||
@ -862,6 +864,7 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
||||
config['delete_news_from_library_on_upload'] = self.delete_news.isChecked()
|
||||
config['upload_news_to_device'] = self.sync_news.isChecked()
|
||||
config['search_as_you_type'] = self.search_as_you_type.isChecked()
|
||||
config['show_avg_rating'] = self.show_avg_rating.isChecked()
|
||||
config['get_social_metadata'] = self.opt_get_social_metadata.isChecked()
|
||||
config['overwrite_author_title_metadata'] = self.opt_overwrite_author_title_metadata.isChecked()
|
||||
config['enforce_cpu_limit'] = bool(self.opt_enforce_cpu_limit.isChecked())
|
||||
|
@ -371,6 +371,16 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="show_avg_rating">
|
||||
<property name="text">
|
||||
<string>Show &average ratings in the tags browser</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="search_as_you_type">
|
||||
<property name="text">
|
||||
<string>Search as you type</string>
|
||||
@ -380,21 +390,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<item row="7" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="sync_news">
|
||||
<property name="text">
|
||||
<string>Automatically send downloaded &news to ebook reader</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="delete_news">
|
||||
<property name="text">
|
||||
<string>&Delete news from library when it is automatically sent to reader</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="2">
|
||||
<item row="9" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
@ -411,7 +421,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="9" column="0" colspan="2">
|
||||
<item row="10" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Toolbar</string>
|
||||
@ -459,7 +469,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" colspan="2">
|
||||
<item row="11" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
|
82
src/calibre/gui2/dialogs/edit_authors_dialog.py
Normal file
82
src/calibre/gui2/dialogs/edit_authors_dialog.py
Normal file
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__license__ = 'GPL v3'
|
||||
|
||||
from PyQt4.Qt import Qt, QDialog, QTableWidgetItem, QAbstractItemView
|
||||
|
||||
from calibre.ebooks.metadata import author_to_author_sort
|
||||
from calibre.gui2.dialogs.edit_authors_dialog_ui import Ui_EditAuthorsDialog
|
||||
|
||||
class tableItem(QTableWidgetItem):
|
||||
def __ge__(self, other):
|
||||
return unicode(self.text()).lower() >= unicode(other.text()).lower()
|
||||
|
||||
def __lt__(self, other):
|
||||
return unicode(self.text()).lower() < unicode(other.text()).lower()
|
||||
|
||||
class EditAuthorsDialog(QDialog, Ui_EditAuthorsDialog):
|
||||
|
||||
def __init__(self, parent, db, id_to_select):
|
||||
QDialog.__init__(self, parent)
|
||||
Ui_EditAuthorsDialog.__init__(self)
|
||||
self.setupUi(self)
|
||||
|
||||
self.buttonBox.accepted.connect(self.accepted)
|
||||
|
||||
self.table.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||
self.table.setColumnCount(2)
|
||||
self.table.setHorizontalHeaderLabels([_('Author'), _('Author sort')])
|
||||
|
||||
self.authors = {}
|
||||
auts = db.get_authors_with_ids()
|
||||
self.table.setRowCount(len(auts))
|
||||
select_item = None
|
||||
for row, (id, author, sort) in enumerate(auts):
|
||||
author = author.replace('|', ',')
|
||||
self.authors[id] = (author, sort)
|
||||
aut = tableItem(author)
|
||||
aut.setData(Qt.UserRole, id)
|
||||
sort = tableItem(sort)
|
||||
self.table.setItem(row, 0, aut)
|
||||
self.table.setItem(row, 1, sort)
|
||||
if id == id_to_select:
|
||||
select_item = sort
|
||||
self.table.resizeColumnsToContents()
|
||||
|
||||
# set up the signal after the table is filled
|
||||
self.table.cellChanged.connect(self.cell_changed)
|
||||
|
||||
self.table.setSortingEnabled(True)
|
||||
self.table.sortByColumn(1, Qt.AscendingOrder)
|
||||
if select_item is not None:
|
||||
self.table.setCurrentItem(select_item)
|
||||
self.table.editItem(select_item)
|
||||
else:
|
||||
self.table.setCurrentCell(0, 0)
|
||||
|
||||
def accepted(self):
|
||||
self.result = []
|
||||
for row in range(0,self.table.rowCount()):
|
||||
id = self.table.item(row, 0).data(Qt.UserRole).toInt()[0]
|
||||
aut = unicode(self.table.item(row, 0).text()).strip()
|
||||
sort = unicode(self.table.item(row, 1).text()).strip()
|
||||
orig_aut,orig_sort = self.authors[id]
|
||||
if orig_aut != aut or orig_sort != sort:
|
||||
self.result.append((id, orig_aut, aut, sort))
|
||||
|
||||
def cell_changed(self, row, col):
|
||||
if col == 0:
|
||||
item = self.table.item(row, 0)
|
||||
aut = unicode(item.text()).strip()
|
||||
c = self.table.item(row, 1)
|
||||
c.setText(author_to_author_sort(aut))
|
||||
item = c
|
||||
else:
|
||||
item = self.table.item(row, 1)
|
||||
self.table.setCurrentItem(item)
|
||||
# disable and reenable sorting to force the sort now, so we can scroll
|
||||
# to the item after it moves
|
||||
self.table.setSortingEnabled(False)
|
||||
self.table.setSortingEnabled(True)
|
||||
self.table.scrollToItem(item)
|
86
src/calibre/gui2/dialogs/edit_authors_dialog.ui
Normal file
86
src/calibre/gui2/dialogs/edit_authors_dialog.ui
Normal file
@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditAuthorsDialog</class>
|
||||
<widget class="QDialog" name="EditAuthorsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>730</width>
|
||||
<height>342</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Manage authors</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTableWidget" name="table">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>EditAuthorsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>229</x>
|
||||
<y>211</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>234</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>EditAuthorsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>297</x>
|
||||
<y>217</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>234</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -8,7 +8,7 @@ from PyQt4.QtGui import QDialog, QGridLayout
|
||||
|
||||
from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog
|
||||
from calibre.gui2.dialogs.tag_editor import TagEditor
|
||||
from calibre.ebooks.metadata import string_to_authors, authors_to_sort_string, \
|
||||
from calibre.ebooks.metadata import string_to_authors, \
|
||||
authors_to_string
|
||||
from calibre.gui2.custom_column_widgets import populate_bulk_metadata_page
|
||||
|
||||
@ -110,10 +110,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
||||
au = string_to_authors(au)
|
||||
self.db.set_authors(id, au, notify=False)
|
||||
if self.auto_author_sort.isChecked():
|
||||
aut = self.db.authors(id, index_is_id=True)
|
||||
aut = aut if aut else ''
|
||||
aut = [a.strip().replace('|', ',') for a in aut.strip().split(',')]
|
||||
x = authors_to_sort_string(aut)
|
||||
x = self.db.author_sort_from_book(id, index_is_id=True)
|
||||
if x:
|
||||
self.db.set_author_sort(id, x, notify=False)
|
||||
aus = unicode(self.author_sort.text())
|
||||
|
@ -23,7 +23,7 @@ from calibre.gui2.dialogs.fetch_metadata import FetchMetadata
|
||||
from calibre.gui2.dialogs.tag_editor import TagEditor
|
||||
from calibre.gui2.widgets import ProgressIndicator
|
||||
from calibre.ebooks import BOOK_EXTENSIONS
|
||||
from calibre.ebooks.metadata import authors_to_sort_string, string_to_authors, \
|
||||
from calibre.ebooks.metadata import string_to_authors, \
|
||||
authors_to_string, check_isbn
|
||||
from calibre.ebooks.metadata.library_thing import cover_from_isbn
|
||||
from calibre import islinux, isfreebsd
|
||||
@ -460,7 +460,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
au = unicode(self.authors.text())
|
||||
au = re.sub(r'\s+et al\.$', '', au)
|
||||
authors = string_to_authors(au)
|
||||
self.author_sort.setText(authors_to_sort_string(authors))
|
||||
self.author_sort.setText(self.db.author_sort_from_authors(authors))
|
||||
|
||||
def swap_title_author(self):
|
||||
title = self.title.text()
|
||||
|
@ -121,6 +121,9 @@
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -420,8 +420,11 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
pt.orig_file_path = os.path.abspath(src.name)
|
||||
pt.seek(0)
|
||||
if set_metadata:
|
||||
_set_metadata(pt, self.db.get_metadata(id, get_cover=True, index_is_id=True),
|
||||
try:
|
||||
_set_metadata(pt, self.db.get_metadata(id, get_cover=True, index_is_id=True),
|
||||
format)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
pt.close()
|
||||
def to_uni(x):
|
||||
if isbytestring(x):
|
||||
|
@ -239,8 +239,7 @@ class StatusBar(QStatusBar, StatusBarInterface, BookDetailsInterface):
|
||||
id_, fmt = val.split(':')
|
||||
self.view_specific_format.emit(int(id_), fmt)
|
||||
elif typ == 'devpath':
|
||||
path = os.path.dirname(val)
|
||||
QDesktopServices.openUrl(QUrl.fromLocalFile(path))
|
||||
QDesktopServices.openUrl(QUrl.fromLocalFile(val))
|
||||
|
||||
|
||||
def resizeEvent(self, ev):
|
||||
|
@ -10,10 +10,10 @@ Browsing book collection by tags.
|
||||
from itertools import izip
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import Qt, QTreeView, QApplication, pyqtSignal, QCheckBox, \
|
||||
from PyQt4.Qt import Qt, QTreeView, QApplication, pyqtSignal, \
|
||||
QFont, QSize, QIcon, QPoint, QVBoxLayout, QComboBox, \
|
||||
QAbstractItemModel, QVariant, QModelIndex, QMenu, \
|
||||
QPushButton, QWidget
|
||||
QPushButton, QWidget, QItemDelegate
|
||||
|
||||
from calibre.gui2 import config, NONE
|
||||
from calibre.utils.config import prefs
|
||||
@ -22,6 +22,39 @@ from calibre.utils.search_query_parser import saved_searches
|
||||
from calibre.gui2 import error_dialog
|
||||
from calibre.gui2.dialogs.tag_categories import TagCategories
|
||||
from calibre.gui2.dialogs.tag_list_editor import TagListEditor
|
||||
from calibre.gui2.dialogs.edit_authors_dialog import EditAuthorsDialog
|
||||
|
||||
class TagDelegate(QItemDelegate): # {{{
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
item = index.internalPointer()
|
||||
if item.type != TagTreeItem.TAG:
|
||||
QItemDelegate.paint(self, painter, option, index)
|
||||
return
|
||||
r = option.rect
|
||||
model = self.parent().model()
|
||||
icon = model.data(index, Qt.DecorationRole).toPyObject()
|
||||
painter.save()
|
||||
if item.tag.state != 0 or not config['show_avg_rating'] or \
|
||||
item.tag.avg_rating is None:
|
||||
icon.paint(painter, r, Qt.AlignLeft)
|
||||
else:
|
||||
painter.setOpacity(0.3)
|
||||
icon.paint(painter, r, Qt.AlignLeft)
|
||||
painter.setOpacity(1)
|
||||
rating = item.tag.avg_rating
|
||||
painter.setClipRect(r.left(), r.bottom()-int(r.height()*(rating/5.0)),
|
||||
r.width(), r.height())
|
||||
icon.paint(painter, r, Qt.AlignLeft)
|
||||
painter.setClipRect(r)
|
||||
|
||||
# Paint the text
|
||||
r.setLeft(r.left()+r.height()+3)
|
||||
painter.drawText(r, Qt.AlignLeft|Qt.AlignVCenter,
|
||||
model.data(index, Qt.DisplayRole).toString())
|
||||
painter.restore()
|
||||
|
||||
# }}}
|
||||
|
||||
class TagsView(QTreeView): # {{{
|
||||
|
||||
@ -30,6 +63,7 @@ class TagsView(QTreeView): # {{{
|
||||
user_category_edit = pyqtSignal(object)
|
||||
tag_list_edit = pyqtSignal(object, object)
|
||||
saved_search_edit = pyqtSignal(object)
|
||||
author_sort_edit = pyqtSignal(object, object)
|
||||
tag_item_renamed = pyqtSignal()
|
||||
search_item_renamed = pyqtSignal()
|
||||
|
||||
@ -43,13 +77,14 @@ class TagsView(QTreeView): # {{{
|
||||
self.setAlternatingRowColors(True)
|
||||
self.setAnimated(True)
|
||||
self.setHeaderHidden(True)
|
||||
self.setItemDelegate(TagDelegate(self))
|
||||
|
||||
def set_database(self, db, tag_match, popularity):
|
||||
def set_database(self, db, tag_match, sort_by):
|
||||
self.hidden_categories = config['tag_browser_hidden_categories']
|
||||
self._model = TagsModel(db, parent=self,
|
||||
hidden_categories=self.hidden_categories,
|
||||
search_restriction=None)
|
||||
self.popularity = popularity
|
||||
self.sort_by = sort_by
|
||||
self.tag_match = tag_match
|
||||
self.db = db
|
||||
self.search_restriction = None
|
||||
@ -57,8 +92,9 @@ class TagsView(QTreeView): # {{{
|
||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.clicked.connect(self.toggle)
|
||||
self.customContextMenuRequested.connect(self.show_context_menu)
|
||||
self.popularity.setChecked(config['sort_by_popularity'])
|
||||
self.popularity.stateChanged.connect(self.sort_changed)
|
||||
pop = config['sort_tags_by']
|
||||
self.sort_by.setCurrentIndex(self.db.CATEGORY_SORTS.index(pop))
|
||||
self.sort_by.currentIndexChanged.connect(self.sort_changed)
|
||||
self.refresh_required.connect(self.recount, type=Qt.QueuedConnection)
|
||||
db.add_listener(self.database_changed)
|
||||
|
||||
@ -69,8 +105,8 @@ class TagsView(QTreeView): # {{{
|
||||
def match_all(self):
|
||||
return self.tag_match and self.tag_match.currentIndex() > 0
|
||||
|
||||
def sort_changed(self, state):
|
||||
config.set('sort_by_popularity', state == Qt.Checked)
|
||||
def sort_changed(self, pop):
|
||||
config.set('sort_tags_by', self.db.CATEGORY_SORTS[pop])
|
||||
self.recount()
|
||||
|
||||
def set_search_restriction(self, s):
|
||||
@ -112,6 +148,9 @@ class TagsView(QTreeView): # {{{
|
||||
if action == 'manage_searches':
|
||||
self.saved_search_edit.emit(category)
|
||||
return
|
||||
if action == 'edit_author_sort':
|
||||
self.author_sort_edit.emit(self, index)
|
||||
return
|
||||
if action == 'hide':
|
||||
self.hidden_categories.add(category)
|
||||
elif action == 'show':
|
||||
@ -132,6 +171,7 @@ class TagsView(QTreeView): # {{{
|
||||
if item.type == TagTreeItem.TAG:
|
||||
tag_item = item
|
||||
tag_name = item.tag.name
|
||||
tag_id = item.tag.id
|
||||
item = item.parent
|
||||
if item.type == TagTreeItem.CATEGORY:
|
||||
category = unicode(item.name.toString())
|
||||
@ -147,9 +187,13 @@ class TagsView(QTreeView): # {{{
|
||||
(key in ['authors', 'tags', 'series', 'publisher', 'search'] or \
|
||||
self.db.field_metadata[key]['is_custom'] and \
|
||||
self.db.field_metadata[key]['datatype'] != 'rating'):
|
||||
self.context_menu.addAction(_('Rename') + " '" + tag_name + "'",
|
||||
self.context_menu.addAction(_('Rename \'%s\'')%tag_name,
|
||||
partial(self.context_menu_handler, action='edit_item',
|
||||
category=tag_item, index=index))
|
||||
if key == 'authors':
|
||||
self.context_menu.addAction(_('Edit sort for \'%s\'')%tag_name,
|
||||
partial(self.context_menu_handler,
|
||||
action='edit_author_sort', index=tag_id))
|
||||
self.context_menu.addSeparator()
|
||||
# Hide/Show/Restore categories
|
||||
self.context_menu.addAction(_('Hide category %s') % category,
|
||||
@ -166,9 +210,12 @@ class TagsView(QTreeView): # {{{
|
||||
self.context_menu.addSeparator()
|
||||
if key in ['tags', 'publisher', 'series'] or \
|
||||
self.db.field_metadata[key]['is_custom']:
|
||||
self.context_menu.addAction(_('Manage ') + category,
|
||||
self.context_menu.addAction(_('Manage %s')%category,
|
||||
partial(self.context_menu_handler, action='open_editor',
|
||||
category=tag_name, key=key))
|
||||
elif key == 'authors':
|
||||
self.context_menu.addAction(_('Manage %s')%category,
|
||||
partial(self.context_menu_handler, action='edit_author_sort'))
|
||||
elif key == 'search':
|
||||
self.context_menu.addAction(_('Manage Saved Searches'),
|
||||
partial(self.context_menu_handler, action='manage_searches',
|
||||
@ -332,6 +379,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
':custom' : QIcon(I('column.svg')),
|
||||
':user' : QIcon(I('drawer.svg')),
|
||||
'search' : QIcon(I('search.svg'))})
|
||||
self.categories_with_ratings = ['authors', 'series', 'publisher', 'tags']
|
||||
|
||||
self.icon_state_map = [None, QIcon(I('plus.svg')), QIcon(I('minus.svg'))]
|
||||
self.db = db
|
||||
@ -341,7 +389,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
self.row_map = []
|
||||
|
||||
# get_node_tree cannot return None here, because row_map is empty
|
||||
data = self.get_node_tree(config['sort_by_popularity'])
|
||||
data = self.get_node_tree(config['sort_tags_by'])
|
||||
self.root_item = TagTreeItem()
|
||||
for i, r in enumerate(self.row_map):
|
||||
if self.hidden_categories and self.categories[i] in self.hidden_categories:
|
||||
@ -354,7 +402,14 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
data=self.categories[i],
|
||||
category_icon=self.category_icon_map[r],
|
||||
tooltip=tt, category_key=r)
|
||||
# This duplicates code in refresh(). Having it here as well
|
||||
# can save seconds during startup, because we avoid a second
|
||||
# call to get_node_tree.
|
||||
for tag in data[r]:
|
||||
if r not in self.categories_with_ratings and \
|
||||
not self.db.field_metadata[r]['is_custom'] and \
|
||||
not self.db.field_metadata[r]['kind'] == 'user':
|
||||
tag.avg_rating = None
|
||||
TagTreeItem(parent=c, data=tag, icon_map=self.icon_state_map)
|
||||
|
||||
def set_search_restriction(self, s):
|
||||
@ -378,11 +433,11 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
|
||||
# Now get the categories
|
||||
if self.search_restriction:
|
||||
data = self.db.get_categories(sort_on_count=sort,
|
||||
data = self.db.get_categories(sort=sort,
|
||||
icon_map=self.category_icon_map,
|
||||
ids=self.db.search('', return_matches=True))
|
||||
else:
|
||||
data = self.db.get_categories(sort_on_count=sort, icon_map=self.category_icon_map)
|
||||
data = self.db.get_categories(sort=sort, icon_map=self.category_icon_map)
|
||||
|
||||
tb_categories = self.db.field_metadata
|
||||
for category in tb_categories:
|
||||
@ -396,7 +451,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
return data
|
||||
|
||||
def refresh(self):
|
||||
data = self.get_node_tree(config['sort_by_popularity']) # get category data
|
||||
data = self.get_node_tree(config['sort_tags_by']) # get category data
|
||||
if data is None:
|
||||
return False
|
||||
row_index = -1
|
||||
@ -417,6 +472,10 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
if len(data[r]) > 0:
|
||||
self.beginInsertRows(category_index, 0, len(data[r])-1)
|
||||
for tag in data[r]:
|
||||
if r not in self.categories_with_ratings and \
|
||||
not self.db.field_metadata[r]['is_custom'] and \
|
||||
not self.db.field_metadata[r]['kind'] == 'user':
|
||||
tag.avg_rating = None
|
||||
tag.state = state_map.get(tag.name, 0)
|
||||
t = TagTreeItem(parent=category, data=tag, icon_map=self.icon_state_map)
|
||||
self.endInsertRows()
|
||||
@ -601,12 +660,13 @@ class TagBrowserMixin(object): # {{{
|
||||
def __init__(self, db):
|
||||
self.library_view.model().count_changed_signal.connect(self.tags_view.recount)
|
||||
self.tags_view.set_database(self.library_view.model().db,
|
||||
self.tag_match, self.popularity)
|
||||
self.tag_match, self.sort_by)
|
||||
self.tags_view.tags_marked.connect(self.search.search_from_tags)
|
||||
self.tags_view.tags_marked.connect(self.saved_search.clear_to_help)
|
||||
self.tags_view.tag_list_edit.connect(self.do_tags_list_edit)
|
||||
self.tags_view.user_category_edit.connect(self.do_user_categories_edit)
|
||||
self.tags_view.saved_search_edit.connect(self.do_saved_search_edit)
|
||||
self.tags_view.author_sort_edit.connect(self.do_author_sort_edit)
|
||||
self.tags_view.tag_item_renamed.connect(self.do_tag_item_renamed)
|
||||
self.tags_view.search_item_renamed.connect(self.saved_search.clear_to_help)
|
||||
self.edit_categories.clicked.connect(lambda x:
|
||||
@ -636,6 +696,19 @@ class TagBrowserMixin(object): # {{{
|
||||
self.saved_search.clear_to_help()
|
||||
self.search.clear_to_help()
|
||||
|
||||
def do_author_sort_edit(self, parent, id):
|
||||
db = self.library_view.model().db
|
||||
editor = EditAuthorsDialog(parent, db, id)
|
||||
d = editor.exec_()
|
||||
if d:
|
||||
for (id, old_author, new_author, new_sort) in editor.result:
|
||||
if old_author != new_author:
|
||||
# The id might change if the new author already exists
|
||||
id = db.rename_author(id, new_author)
|
||||
db.set_sort_field_for_author(id, unicode(new_sort))
|
||||
self.library_view.model().refresh()
|
||||
self.tags_view.recount()
|
||||
|
||||
# }}}
|
||||
|
||||
class TagBrowserWidget(QWidget): # {{{
|
||||
@ -648,9 +721,13 @@ class TagBrowserWidget(QWidget): # {{{
|
||||
parent.tags_view = TagsView(parent)
|
||||
self._layout.addWidget(parent.tags_view)
|
||||
|
||||
parent.popularity = QCheckBox(parent)
|
||||
parent.popularity.setText(_('Sort by &popularity'))
|
||||
self._layout.addWidget(parent.popularity)
|
||||
parent.sort_by = QComboBox(parent)
|
||||
# Must be in the same order as db2.CATEGORY_SORTS
|
||||
for x in (_('Sort by name'), _('Sort by popularity'),
|
||||
_('Sort by average rating')):
|
||||
parent.sort_by.addItem(x)
|
||||
parent.sort_by.setCurrentIndex(0)
|
||||
self._layout.addWidget(parent.sort_by)
|
||||
|
||||
parent.tag_match = QComboBox(parent)
|
||||
for x in (_('Match any'), _('Match all')):
|
||||
|
@ -430,7 +430,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin, # {{{
|
||||
self.book_on_device(None, reset=True)
|
||||
db.set_book_on_device_func(self.book_on_device)
|
||||
self.library_view.set_database(db)
|
||||
self.tags_view.set_database(db, self.tag_match, self.popularity)
|
||||
self.tags_view.set_database(db, self.tag_match, self.sort_by)
|
||||
self.library_view.model().set_book_on_device_func(self.book_on_device)
|
||||
self.status_bar.clear_message()
|
||||
self.search.clear_to_help()
|
||||
|
@ -461,14 +461,27 @@ class CustomColumns(object):
|
||||
CREATE VIEW tag_browser_{table} AS SELECT
|
||||
id,
|
||||
value,
|
||||
(SELECT COUNT(id) FROM {lt} WHERE value={table}.id) count
|
||||
(SELECT COUNT(id) FROM {lt} WHERE value={table}.id) count,
|
||||
(SELECT AVG(r.rating)
|
||||
FROM {lt},
|
||||
books_ratings_link as bl,
|
||||
ratings as r
|
||||
WHERE {lt}.value={table}.id and bl.book={lt}.book and
|
||||
r.id = bl.rating and r.rating <> 0) avg_rating
|
||||
FROM {table};
|
||||
|
||||
CREATE VIEW tag_browser_filtered_{table} AS SELECT
|
||||
id,
|
||||
value,
|
||||
(SELECT COUNT({lt}.id) FROM {lt} WHERE value={table}.id AND
|
||||
books_list_filter(book)) count
|
||||
books_list_filter(book)) count,
|
||||
(SELECT AVG(r.rating)
|
||||
FROM {lt},
|
||||
books_ratings_link as bl,
|
||||
ratings as r
|
||||
WHERE {lt}.value={table}.id AND bl.book={lt}.book AND
|
||||
r.id = bl.rating AND r.rating <> 0 AND
|
||||
books_list_filter(bl.book)) avg_rating
|
||||
FROM {table};
|
||||
|
||||
'''.format(lt=lt, table=table),
|
||||
@ -505,7 +518,6 @@ class CustomColumns(object):
|
||||
END;
|
||||
'''.format(table=table),
|
||||
]
|
||||
|
||||
script = ' \n'.join(lines)
|
||||
self.conn.executescript(script)
|
||||
self.conn.commit()
|
||||
|
@ -12,7 +12,7 @@ from math import floor
|
||||
|
||||
from PyQt4.QtGui import QImage
|
||||
|
||||
from calibre.ebooks.metadata import title_sort
|
||||
from calibre.ebooks.metadata import title_sort, author_to_author_sort
|
||||
from calibre.library.database import LibraryDatabase
|
||||
from calibre.library.field_metadata import FieldMetadata, TagsIcons
|
||||
from calibre.library.schema_upgrades import SchemaUpgrade
|
||||
@ -20,7 +20,7 @@ from calibre.library.caches import ResultCache
|
||||
from calibre.library.custom_columns import CustomColumns
|
||||
from calibre.library.sqlite import connect, IntegrityError, DBThread
|
||||
from calibre.ebooks.metadata import string_to_authors, authors_to_string, \
|
||||
MetaInformation, authors_to_sort_string
|
||||
MetaInformation
|
||||
from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats
|
||||
from calibre.constants import preferred_encoding, iswindows, isosx, filesystem_encoding
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
@ -56,11 +56,18 @@ copyfile = os.link if hasattr(os, 'link') else shutil.copyfile
|
||||
|
||||
class Tag(object):
|
||||
|
||||
def __init__(self, name, id=None, count=0, state=0, tooltip=None, icon=None):
|
||||
def __init__(self, name, id=None, count=0, state=0, avg=0, sort=None,
|
||||
tooltip=None, icon=None):
|
||||
self.name = name
|
||||
self.id = id
|
||||
self.count = count
|
||||
self.state = state
|
||||
self.avg_rating = avg/2.0 if avg is not None else 0
|
||||
self.sort = sort
|
||||
if self.avg_rating > 0:
|
||||
if tooltip:
|
||||
tooltip = tooltip + ': '
|
||||
tooltip = _('%sAverage rating is %3.1f')%(tooltip, self.avg_rating)
|
||||
self.tooltip = tooltip
|
||||
self.icon = icon
|
||||
|
||||
@ -133,7 +140,9 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
CREATE TEMP VIEW IF NOT EXISTS tag_browser_news AS SELECT DISTINCT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(books_tags_link.id) FROM books_tags_link WHERE tag=x.id) count
|
||||
(SELECT COUNT(books_tags_link.id) FROM books_tags_link WHERE tag=x.id) count,
|
||||
(0) as avg_rating,
|
||||
name as sort
|
||||
FROM tags as x WHERE name!="{0}" AND id IN
|
||||
(SELECT DISTINCT tag FROM books_tags_link WHERE book IN
|
||||
(SELECT DISTINCT book FROM books_tags_link WHERE tag IN
|
||||
@ -144,7 +153,9 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
CREATE TEMP VIEW IF NOT EXISTS tag_browser_filtered_news AS SELECT DISTINCT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(books_tags_link.id) FROM books_tags_link WHERE tag=x.id and books_list_filter(book)) count
|
||||
(SELECT COUNT(books_tags_link.id) FROM books_tags_link WHERE tag=x.id and books_list_filter(book)) count,
|
||||
(0) as avg_rating,
|
||||
name as sort
|
||||
FROM tags as x WHERE name!="{0}" AND id IN
|
||||
(SELECT DISTINCT tag FROM books_tags_link WHERE book IN
|
||||
(SELECT DISTINCT book FROM books_tags_link WHERE tag IN
|
||||
@ -422,6 +433,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
if aum: aum = [a.strip().replace('|', ',') for a in aum.split(',')]
|
||||
mi = MetaInformation(self.title(idx, index_is_id=index_is_id), aum)
|
||||
mi.author_sort = self.author_sort(idx, index_is_id=index_is_id)
|
||||
if mi.authors:
|
||||
mi.author_sort_map = {}
|
||||
for name, sort in zip(mi.authors, self.authors_sort_strings(idx,
|
||||
index_is_id)):
|
||||
mi.author_sort_map[name] = sort
|
||||
mi.comments = self.comments(idx, index_is_id=index_is_id)
|
||||
mi.publisher = self.publisher(idx, index_is_id=index_is_id)
|
||||
mi.timestamp = self.timestamp(idx, index_is_id=index_is_id)
|
||||
@ -679,7 +695,9 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
tn=field['table'], col=field['link_column']), (id_,))
|
||||
return set(x[0] for x in ans)
|
||||
|
||||
def get_categories(self, sort_on_count=False, ids=None, icon_map=None):
|
||||
CATEGORY_SORTS = ('name', 'popularity', 'rating')
|
||||
|
||||
def get_categories(self, sort='name', ids=None, icon_map=None):
|
||||
self.books_list_filter.change([] if not ids else ids)
|
||||
|
||||
categories = {}
|
||||
@ -698,13 +716,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
continue
|
||||
cn = cat['column']
|
||||
if ids is None:
|
||||
query = 'SELECT id, {0}, count FROM tag_browser_{1}'.format(cn, tn)
|
||||
query = '''SELECT id, {0}, count, avg_rating, sort
|
||||
FROM tag_browser_{1}'''.format(cn, tn)
|
||||
else:
|
||||
query = 'SELECT id, {0}, count FROM tag_browser_filtered_{1}'.format(cn, tn)
|
||||
if sort_on_count:
|
||||
query += ' ORDER BY count DESC'
|
||||
query = '''SELECT id, {0}, count, avg_rating, sort
|
||||
FROM tag_browser_filtered_{1}'''.format(cn, tn)
|
||||
if sort == 'popularity':
|
||||
query += ' ORDER BY count DESC, sort ASC'
|
||||
elif sort == 'name':
|
||||
query += ' ORDER BY sort ASC'
|
||||
else:
|
||||
query += ' ORDER BY {0} ASC'.format(cn)
|
||||
query += ' ORDER BY avg_rating DESC, sort ASC'
|
||||
data = self.conn.get(query)
|
||||
|
||||
# icon_map is not None if get_categories is to store an icon and
|
||||
@ -722,6 +744,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
|
||||
datatype = cat['datatype']
|
||||
if datatype == 'rating':
|
||||
# eliminate the zero ratings line as well as count == 0
|
||||
item_not_zero_func = (lambda x: x[1] > 0 and x[2] > 0)
|
||||
formatter = (lambda x:u'\u2605'*int(round(x/2.)))
|
||||
elif category == 'authors':
|
||||
@ -733,15 +756,9 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
formatter = (lambda x:unicode(x))
|
||||
|
||||
categories[category] = [Tag(formatter(r[1]), count=r[2], id=r[0],
|
||||
icon=icon, tooltip = tooltip)
|
||||
avg=r[3], sort=r[4],
|
||||
icon=icon, tooltip=tooltip)
|
||||
for r in data if item_not_zero_func(r)]
|
||||
if category == 'series' and not sort_on_count:
|
||||
if tweaks['title_series_sorting'] == 'library_order':
|
||||
ts = lambda x: title_sort(x)
|
||||
else:
|
||||
ts = lambda x:x
|
||||
categories[category].sort(cmp=lambda x,y:cmp(ts(x.name).lower(),
|
||||
ts(y.name).lower()))
|
||||
|
||||
# We delayed computing the standard formats category because it does not
|
||||
# use a view, but is computed dynamically
|
||||
@ -765,11 +782,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
if count > 0:
|
||||
categories['formats'].append(Tag(fmt, count=count, icon=icon))
|
||||
|
||||
if sort_on_count:
|
||||
categories['formats'].sort(cmp=lambda x,y:cmp(x.count, y.count),
|
||||
reverse=True)
|
||||
else:
|
||||
categories['formats'].sort(cmp=lambda x,y:cmp(x.name, y.name))
|
||||
if sort == 'popularity':
|
||||
categories['formats'].sort(key=lambda x: x.count, reverse=True)
|
||||
else: # no ratings exist to sort on
|
||||
categories['formats'].sort(key = lambda x:x.name)
|
||||
|
||||
#### Now do the user-defined categories. ####
|
||||
user_categories = prefs['user_categories']
|
||||
@ -794,12 +810,15 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
# Not a problem if we accumulate entries in the icon map
|
||||
if icon_map is not None:
|
||||
icon_map[cat_name] = icon_map[':user']
|
||||
if sort_on_count:
|
||||
if sort == 'popularity':
|
||||
categories[cat_name] = \
|
||||
sorted(items, cmp=(lambda x, y: cmp(y.count, x.count)))
|
||||
sorted(items, key=lambda x: x.count, reverse=True)
|
||||
elif sort == 'name':
|
||||
categories[cat_name] = \
|
||||
sorted(items, key=lambda x: x.sort.lower())
|
||||
else:
|
||||
categories[cat_name] = \
|
||||
sorted(items, cmp=(lambda x, y: cmp(x.name.lower(), y.name.lower())))
|
||||
sorted(items, key=lambda x:x.avg_rating, reverse=True)
|
||||
|
||||
#### Finally, the saved searches category ####
|
||||
items = []
|
||||
@ -909,6 +928,38 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
self.set_path(id, True)
|
||||
self.notify('metadata', [id])
|
||||
|
||||
# Given a book, return the list of author sort strings for the book's authors
|
||||
def authors_sort_strings(self, id, index_is_id=False):
|
||||
id = id if index_is_id else self.id(id)
|
||||
aut_strings = self.conn.get('''
|
||||
SELECT sort
|
||||
FROM authors, books_authors_link as bl
|
||||
WHERE bl.book=? and authors.id=bl.author
|
||||
ORDER BY bl.id''', (id,))
|
||||
result = []
|
||||
for (sort,) in aut_strings:
|
||||
result.append(sort)
|
||||
return result
|
||||
|
||||
# Given a book, return the author_sort string for authors of the book
|
||||
def author_sort_from_book(self, id, index_is_id=False):
|
||||
auts = self.authors_sort_strings(id, index_is_id)
|
||||
return ' & '.join(auts).replace('|', ',')
|
||||
|
||||
# Given a list of authors, return the author_sort string for the authors,
|
||||
# preferring the author sort associated with the author over the computed
|
||||
# string
|
||||
def author_sort_from_authors(self, authors):
|
||||
result = []
|
||||
for aut in authors:
|
||||
r = self.conn.get('SELECT sort FROM authors WHERE name=?',
|
||||
(aut.replace(',', '|'),), all=False)
|
||||
if r is None:
|
||||
result.append(author_to_author_sort(aut))
|
||||
else:
|
||||
result.append(r)
|
||||
return ' & '.join(result).replace('|', ',')
|
||||
|
||||
def set_authors(self, id, authors, notify=True):
|
||||
'''
|
||||
`authors`: A list of authors.
|
||||
@ -935,7 +986,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
(id, aid))
|
||||
except IntegrityError: # Sometimes books specify the same author twice in their metadata
|
||||
pass
|
||||
ss = authors_to_sort_string(authors)
|
||||
self.conn.commit()
|
||||
ss = self.author_sort_from_book(id, index_is_id=True)
|
||||
self.conn.execute('UPDATE books SET author_sort=? WHERE id=?',
|
||||
(ss, id))
|
||||
self.conn.commit()
|
||||
@ -1007,6 +1059,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
return result
|
||||
|
||||
def rename_tag(self, old_id, new_name):
|
||||
new_name = new_name.strip()
|
||||
new_id = self.conn.get(
|
||||
'''SELECT id from tags
|
||||
WHERE name=?''', (new_name,), all=False)
|
||||
@ -1046,6 +1099,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
return result
|
||||
|
||||
def rename_series(self, old_id, new_name):
|
||||
new_name = new_name.strip()
|
||||
new_id = self.conn.get(
|
||||
'''SELECT id from series
|
||||
WHERE name=?''', (new_name,), all=False)
|
||||
@ -1075,7 +1129,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
index = index + 1
|
||||
self.conn.commit()
|
||||
|
||||
|
||||
def delete_series_using_id(self, id):
|
||||
books = self.conn.get('SELECT book from books_series_link WHERE series=?', (id,))
|
||||
self.conn.execute('DELETE FROM books_series_link WHERE series=?', (id,))
|
||||
@ -1091,6 +1144,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
return result
|
||||
|
||||
def rename_publisher(self, old_id, new_name):
|
||||
new_name = new_name.strip()
|
||||
new_id = self.conn.get(
|
||||
'''SELECT id from publishers
|
||||
WHERE name=?''', (new_name,), all=False)
|
||||
@ -1113,12 +1167,25 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
self.conn.execute('DELETE FROM publishers WHERE id=?', (old_id,))
|
||||
self.conn.commit()
|
||||
|
||||
# There is no editor for author, so we do not need get_authors_with_ids or
|
||||
# delete_author_using_id.
|
||||
def get_authors_with_ids(self):
|
||||
result = self.conn.get('SELECT id,name,sort FROM authors')
|
||||
if not result:
|
||||
return []
|
||||
return result
|
||||
|
||||
def set_sort_field_for_author(self, old_id, new_sort):
|
||||
self.conn.execute('UPDATE authors SET sort=? WHERE id=?', \
|
||||
(new_sort.strip(), old_id))
|
||||
self.conn.commit()
|
||||
# Now change all the author_sort fields in books by this author
|
||||
bks = self.conn.get('SELECT book from books_authors_link WHERE author=?', (old_id,))
|
||||
for (book_id,) in bks:
|
||||
ss = self.author_sort_from_book(book_id, index_is_id=True)
|
||||
self.set_author_sort(book_id, ss)
|
||||
|
||||
def rename_author(self, old_id, new_name):
|
||||
# Make sure that any commas in new_name are changed to '|'!
|
||||
new_name = new_name.replace(',', '|')
|
||||
new_name = new_name.replace(',', '|').strip()
|
||||
|
||||
# Get the list of books we must fix up, one way or the other
|
||||
# Save the list so we can use it twice
|
||||
@ -1141,7 +1208,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
self.conn.execute('UPDATE authors SET name=? WHERE id=?',
|
||||
(new_name, old_id))
|
||||
self.conn.commit()
|
||||
return
|
||||
return new_id
|
||||
# Author exists. To fix this, we must replace all the authors
|
||||
# instead of replacing the one. Reason: db integrity checks can stop
|
||||
# the rename process, which would leave everything half-done. We
|
||||
@ -1184,24 +1251,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
# now fix the filesystem paths
|
||||
self.set_path(book_id, index_is_id=True)
|
||||
# Next fix the author sort. Reset it to the default
|
||||
authors = self.conn.get('''
|
||||
SELECT authors.name
|
||||
FROM authors, books_authors_link as bl
|
||||
WHERE bl.book = ? and bl.author = authors.id
|
||||
ORDER BY bl.id
|
||||
''' , (book_id,))
|
||||
# unpack the double-list structure
|
||||
for i,aut in enumerate(authors):
|
||||
authors[i] = aut[0]
|
||||
ss = authors_to_sort_string(authors)
|
||||
# Change the '|'s to ','
|
||||
ss = ss.replace('|', ',')
|
||||
self.conn.execute('''UPDATE books
|
||||
SET author_sort=?
|
||||
WHERE id=?''', (ss, book_id))
|
||||
self.conn.commit()
|
||||
ss = self.author_sort_from_book(book_id, index_is_id=True)
|
||||
self.set_author_sort(book_id, ss)
|
||||
# the caller will do a general refresh, so we don't need to
|
||||
# do one here
|
||||
return new_id
|
||||
|
||||
# end convenience methods
|
||||
|
||||
@ -1436,7 +1490,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
if not add_duplicates and self.has_book(mi):
|
||||
return None
|
||||
series_index = 1.0 if mi.series_index is None else mi.series_index
|
||||
aus = mi.author_sort if mi.author_sort else ', '.join(mi.authors)
|
||||
aus = mi.author_sort if mi.author_sort else self.author_sort_from_authors(mi.authors)
|
||||
title = mi.title
|
||||
if isinstance(aus, str):
|
||||
aus = aus.decode(preferred_encoding, 'replace')
|
||||
@ -1476,7 +1530,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
duplicates.append((path, format, mi))
|
||||
continue
|
||||
series_index = 1.0 if mi.series_index is None else mi.series_index
|
||||
aus = mi.author_sort if mi.author_sort else ', '.join(mi.authors)
|
||||
aus = mi.author_sort if mi.author_sort else self.author_sort_from_authors(mi.authors)
|
||||
title = mi.title
|
||||
if isinstance(aus, str):
|
||||
aus = aus.decode(preferred_encoding, 'replace')
|
||||
@ -1515,7 +1569,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
mi.title = _('Unknown')
|
||||
if not mi.authors:
|
||||
mi.authors = [_('Unknown')]
|
||||
aus = mi.author_sort if mi.author_sort else authors_to_sort_string(mi.authors)
|
||||
aus = mi.author_sort if mi.author_sort else self.author_sort_from_authors(mi.authors)
|
||||
if isinstance(aus, str):
|
||||
aus = aus.decode(preferred_encoding, 'replace')
|
||||
title = mi.title if isinstance(mi.title, unicode) else \
|
||||
|
@ -44,9 +44,12 @@ class FieldMetadata(dict):
|
||||
is_category: is a tag browser category. If true, then:
|
||||
table: name of the db table used to construct item list
|
||||
column: name of the column in the normalized table to join on
|
||||
link_column: name of the column in the connection table to join on
|
||||
link_column: name of the column in the connection table to join on. This
|
||||
key should not be present if there is no link table
|
||||
category_sort: the field in the normalized table to sort on. This
|
||||
key must be present if is_category is True
|
||||
If these are None, then the category constructor must know how
|
||||
to build the item list (e.g., formats).
|
||||
to build the item list (e.g., formats, news).
|
||||
The order below is the order that the categories will
|
||||
appear in the tags pane.
|
||||
|
||||
@ -66,6 +69,7 @@ class FieldMetadata(dict):
|
||||
('authors', {'table':'authors',
|
||||
'column':'name',
|
||||
'link_column':'author',
|
||||
'category_sort':'sort',
|
||||
'datatype':'text',
|
||||
'is_multiple':',',
|
||||
'kind':'field',
|
||||
@ -76,6 +80,7 @@ class FieldMetadata(dict):
|
||||
('series', {'table':'series',
|
||||
'column':'name',
|
||||
'link_column':'series',
|
||||
'category_sort':'(title_sort(name))',
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
@ -95,6 +100,7 @@ class FieldMetadata(dict):
|
||||
('publisher', {'table':'publishers',
|
||||
'column':'name',
|
||||
'link_column':'publisher',
|
||||
'category_sort':'name',
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
@ -105,6 +111,7 @@ class FieldMetadata(dict):
|
||||
('rating', {'table':'ratings',
|
||||
'column':'rating',
|
||||
'link_column':'rating',
|
||||
'category_sort':'rating',
|
||||
'datatype':'rating',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
@ -114,6 +121,7 @@ class FieldMetadata(dict):
|
||||
'is_category':True}),
|
||||
('news', {'table':'news',
|
||||
'column':'name',
|
||||
'category_sort':'name',
|
||||
'datatype':None,
|
||||
'is_multiple':None,
|
||||
'kind':'category',
|
||||
@ -124,6 +132,7 @@ class FieldMetadata(dict):
|
||||
('tags', {'table':'tags',
|
||||
'column':'name',
|
||||
'link_column': 'tag',
|
||||
'category_sort':'name',
|
||||
'datatype':'text',
|
||||
'is_multiple':',',
|
||||
'kind':'field',
|
||||
@ -374,7 +383,7 @@ class FieldMetadata(dict):
|
||||
'search_terms':[key], 'label':label,
|
||||
'colnum':colnum, 'display':display,
|
||||
'is_custom':True, 'is_category':is_category,
|
||||
'link_column':'value',
|
||||
'link_column':'value','category_sort':'value',
|
||||
'is_editable': is_editable,}
|
||||
self._add_search_terms_to_map(key, [key])
|
||||
self.custom_label_to_key_map[label] = key
|
||||
|
@ -296,3 +296,117 @@ class SchemaUpgrade(object):
|
||||
('books_%s_link'%field['table'],), all=False)
|
||||
if table is not None:
|
||||
create_tag_browser_view(field['table'], field['link_column'], field['column'])
|
||||
|
||||
def upgrade_version_11(self):
|
||||
'Add average rating to tag browser views'
|
||||
def create_std_tag_browser_view(table_name, column_name,
|
||||
view_column_name, sort_column_name):
|
||||
script = ('''
|
||||
DROP VIEW IF EXISTS tag_browser_{tn};
|
||||
CREATE VIEW tag_browser_{tn} AS SELECT
|
||||
id,
|
||||
{vcn},
|
||||
(SELECT COUNT(id) FROM books_{tn}_link WHERE {cn}={tn}.id) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_{tn}_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.{cn}={tn}.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0) avg_rating,
|
||||
{scn} AS sort
|
||||
FROM {tn};
|
||||
DROP VIEW IF EXISTS tag_browser_filtered_{tn};
|
||||
CREATE VIEW tag_browser_filtered_{tn} AS SELECT
|
||||
id,
|
||||
{vcn},
|
||||
(SELECT COUNT(books_{tn}_link.id) FROM books_{tn}_link WHERE
|
||||
{cn}={tn}.id AND books_list_filter(book)) count,
|
||||
(SELECT AVG(ratings.rating)
|
||||
FROM books_{tn}_link AS tl, books_ratings_link AS bl, ratings
|
||||
WHERE tl.{cn}={tn}.id AND bl.book=tl.book AND
|
||||
ratings.id = bl.rating AND ratings.rating <> 0 AND
|
||||
books_list_filter(bl.book)) avg_rating,
|
||||
{scn} AS sort
|
||||
FROM {tn};
|
||||
|
||||
'''.format(tn=table_name, cn=column_name,
|
||||
vcn=view_column_name, scn= sort_column_name))
|
||||
self.conn.executescript(script)
|
||||
|
||||
def create_cust_tag_browser_view(table_name, link_table_name):
|
||||
script = '''
|
||||
DROP VIEW IF EXISTS tag_browser_{table};
|
||||
CREATE VIEW tag_browser_{table} AS SELECT
|
||||
id,
|
||||
value,
|
||||
(SELECT COUNT(id) FROM {lt} WHERE value={table}.id) count,
|
||||
(SELECT AVG(r.rating)
|
||||
FROM {lt},
|
||||
books_ratings_link AS bl,
|
||||
ratings AS r
|
||||
WHERE {lt}.value={table}.id AND bl.book={lt}.book AND
|
||||
r.id = bl.rating AND r.rating <> 0) avg_rating,
|
||||
value AS sort
|
||||
FROM {table};
|
||||
|
||||
DROP VIEW IF EXISTS tag_browser_filtered_{table};
|
||||
CREATE VIEW tag_browser_filtered_{table} AS SELECT
|
||||
id,
|
||||
value,
|
||||
(SELECT COUNT({lt}.id) FROM {lt} WHERE value={table}.id AND
|
||||
books_list_filter(book)) count,
|
||||
(SELECT AVG(r.rating)
|
||||
FROM {lt},
|
||||
books_ratings_link AS bl,
|
||||
ratings AS r
|
||||
WHERE {lt}.value={table}.id AND bl.book={lt}.book AND
|
||||
r.id = bl.rating AND r.rating <> 0 AND
|
||||
books_list_filter(bl.book)) avg_rating,
|
||||
value AS sort
|
||||
FROM {table};
|
||||
'''.format(lt=link_table_name, table=table_name)
|
||||
self.conn.executescript(script)
|
||||
|
||||
for field in self.field_metadata.itervalues():
|
||||
if field['is_category'] and not field['is_custom'] and 'link_column' in field:
|
||||
table = self.conn.get(
|
||||
'SELECT name FROM sqlite_master WHERE type="table" AND name=?',
|
||||
('books_%s_link'%field['table'],), all=False)
|
||||
if table is not None:
|
||||
create_std_tag_browser_view(field['table'], field['link_column'],
|
||||
field['column'], field['category_sort'])
|
||||
|
||||
db_tables = self.conn.get('''SELECT name FROM sqlite_master
|
||||
WHERE type='table'
|
||||
ORDER BY name''');
|
||||
tables = []
|
||||
for (table,) in db_tables:
|
||||
tables.append(table)
|
||||
for table in tables:
|
||||
link_table = 'books_%s_link'%table
|
||||
if table.startswith('custom_column_') and link_table in tables:
|
||||
create_cust_tag_browser_view(table, link_table)
|
||||
|
||||
from calibre.ebooks.metadata import author_to_author_sort
|
||||
|
||||
aut = self.conn.get('SELECT id, name FROM authors');
|
||||
records = []
|
||||
for (id, author) in aut:
|
||||
records.append((id, author.replace('|', ',')))
|
||||
for id,author in records:
|
||||
self.conn.execute('UPDATE authors SET sort=? WHERE id=?',
|
||||
(author_to_author_sort(author.replace('|', ',')).strip(), id))
|
||||
self.conn.commit()
|
||||
self.conn.executescript('''
|
||||
DROP TRIGGER IF EXISTS author_insert_trg;
|
||||
CREATE TRIGGER author_insert_trg
|
||||
AFTER INSERT ON authors
|
||||
BEGIN
|
||||
UPDATE authors SET sort=author_to_author_sort(NEW.name) WHERE id=NEW.id;
|
||||
END;
|
||||
DROP TRIGGER IF EXISTS author_update_trg;
|
||||
CREATE TRIGGER author_update_trg
|
||||
BEFORE UPDATE ON authors
|
||||
BEGIN
|
||||
UPDATE authors SET sort=author_to_author_sort(NEW.name)
|
||||
WHERE id=NEW.id AND name <> NEW.name;
|
||||
END;
|
||||
''')
|
||||
|
@ -99,17 +99,20 @@ def html_to_lxml(raw):
|
||||
raw = etree.tostring(root, encoding=None)
|
||||
return etree.fromstring(raw)
|
||||
|
||||
def CATALOG_ENTRY(item, base_href, version, updated):
|
||||
def CATALOG_ENTRY(item, base_href, version, updated, ignore_count=False):
|
||||
id_ = 'calibre:category:'+item.name
|
||||
iid = 'N' + item.name
|
||||
if item.id is not None:
|
||||
iid = 'I' + str(item.id)
|
||||
link = NAVLINK(href = base_href + '/' + hexlify(iid))
|
||||
count = _('%d books')%item.count
|
||||
if ignore_count:
|
||||
count = ''
|
||||
return E.entry(
|
||||
TITLE(item.name),
|
||||
ID(id_),
|
||||
UPDATED(updated),
|
||||
E.content(_('%d books')%item.count, type='text'),
|
||||
E.content(count, type='text'),
|
||||
link
|
||||
)
|
||||
|
||||
@ -265,8 +268,12 @@ class CategoryFeed(NavFeed):
|
||||
def __init__(self, items, which, id_, updated, version, offsets, page_url, up_url):
|
||||
NavFeed.__init__(self, id_, updated, version, offsets, page_url, up_url)
|
||||
base_href = self.base_href + '/category/' + hexlify(which)
|
||||
ignore_count = False
|
||||
if which == 'search':
|
||||
ignore_count = True
|
||||
for item in items:
|
||||
self.root.append(CATALOG_ENTRY(item, base_href, version, updated))
|
||||
self.root.append(CATALOG_ENTRY(item, base_href, version, updated,
|
||||
ignore_count=ignore_count))
|
||||
|
||||
class CategoryGroupFeed(NavFeed):
|
||||
|
||||
@ -393,7 +400,7 @@ class OPDSServer(object):
|
||||
owhich = hexlify('N'+which)
|
||||
up_url = url_for('opdsnavcatalog', version, which=owhich)
|
||||
items = categories[category]
|
||||
items = [x for x in items if x.name.startswith(which)]
|
||||
items = [x for x in items if getattr(x, 'sort', x.name).startswith(which)]
|
||||
if not items:
|
||||
raise cherrypy.HTTPError(404, 'No items in group %r:%r'%(category,
|
||||
which))
|
||||
@ -458,11 +465,11 @@ class OPDSServer(object):
|
||||
def __init__(self, text, count):
|
||||
self.text, self.count = text, count
|
||||
|
||||
starts = set([x.name[0] for x in items])
|
||||
starts = set([getattr(x, 'sort', x.name)[0] for x in items])
|
||||
category_groups = OrderedDict()
|
||||
for x in sorted(starts, cmp=lambda x,y:cmp(x.lower(), y.lower())):
|
||||
category_groups[x] = len([y for y in items if
|
||||
y.name.startswith(x)])
|
||||
getattr(y, 'sort', y.name).startswith(x)])
|
||||
items = [Group(x, y) for x, y in category_groups.items()]
|
||||
max_items = self.opts.max_opds_items
|
||||
offsets = OPDSOffsets(offset, max_items, len(items))
|
||||
|
@ -14,7 +14,7 @@ from Queue import Queue
|
||||
from threading import RLock
|
||||
from datetime import datetime
|
||||
|
||||
from calibre.ebooks.metadata import title_sort
|
||||
from calibre.ebooks.metadata import title_sort, author_to_author_sort
|
||||
from calibre.utils.config import tweaks
|
||||
from calibre.utils.date import parse_date, isoformat
|
||||
|
||||
@ -116,10 +116,12 @@ class DBThread(Thread):
|
||||
self.conn.create_aggregate('concat', 1, Concatenate)
|
||||
self.conn.create_aggregate('sortconcat', 2, SortedConcatenate)
|
||||
self.conn.create_aggregate('sort_concat', 2, SafeSortedConcatenate)
|
||||
if tweaks['title_series_sorting'] == 'library_order':
|
||||
self.conn.create_function('title_sort', 1, title_sort)
|
||||
else:
|
||||
if tweaks['title_series_sorting'] == 'strictly_alphabetic':
|
||||
self.conn.create_function('title_sort', 1, lambda x:x)
|
||||
else:
|
||||
self.conn.create_function('title_sort', 1, title_sort)
|
||||
self.conn.create_function('author_to_author_sort', 1,
|
||||
lambda x: author_to_author_sort(x.replace('|', ',')))
|
||||
self.conn.create_function('uuid4', 0, lambda : str(uuid.uuid4()))
|
||||
# Dummy functions for dynamically created filters
|
||||
self.conn.create_function('books_list_filter', 1, lambda x: 1)
|
||||
|
@ -103,6 +103,7 @@ _extra_lang_codes = {
|
||||
'en_TH' : _('English (Thailand)'),
|
||||
'en_CY' : _('English (Cyprus)'),
|
||||
'en_PK' : _('English (Pakistan)'),
|
||||
'en_IL' : _('English (Israel)'),
|
||||
'en_SG' : _('English (Singapore)'),
|
||||
'en_YE' : _('English (Yemen)'),
|
||||
'en_IE' : _('English (Ireland)'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user