[Sync] Sync with trunk. Revision 10173
104
Changelog.yaml
@ -19,6 +19,106 @@
|
||||
# new recipes:
|
||||
# - title:
|
||||
|
||||
- version: 0.8.14
|
||||
date: 2011-08-12
|
||||
|
||||
new features:
|
||||
- title: "Make the keyboard shortcuts used by the main calibre interface user customizable, via Preferences->Advanced->Keyboard"
|
||||
type: major
|
||||
|
||||
- title: "When switching libraries, if the library no longer exists, give the user a chance to specify a new location for the library, in case it was moved, before forgetting it."
|
||||
tickets: [822018]
|
||||
|
||||
- title: "Template language: Add strcat and strlen builtin functions."
|
||||
tickets: [821935]
|
||||
|
||||
bug fixes:
|
||||
- title: "The various options to control how automerging works when adding books now also apply when copying a book from one library to another."
|
||||
tickets: [822033]
|
||||
|
||||
- title: "Ebook viewer: Respond to key presses even when the book display area does not have keyboard focus"
|
||||
|
||||
- title: "Allow integer and float column values to go to -999999. -1000000 is the value of 'undefined'."
|
||||
tickets: [821941]
|
||||
|
||||
- title: "Fix in calibre browser not working for the Open books store in Get Books."
|
||||
tickets: [822359]
|
||||
|
||||
- title: "Fix regression in 0.8.13 that caused incorrect title/author for downloaded news if you turned off reading metadata from file contents in Preferences->Adding books"
|
||||
|
||||
- title: "Save to disk: When saving to a single directory, handle the case of the save to disk template containing path separators inside template expression correctly."
|
||||
tickets: [821912]
|
||||
|
||||
- title: "Get Books: Always read metadata from the file contents, ignoring the setting in Preferences->Adding books"
|
||||
|
||||
- title: "Fix merge_metadata to not overwrite non-text fields ('bool', 'int', 'float', 'rating', 'datetime') that have a value of zero/false instead of None."
|
||||
tickets: [821665]
|
||||
|
||||
improved recipes:
|
||||
- The Independent
|
||||
|
||||
new recipes:
|
||||
- title: "Novinite"
|
||||
author: Martin Tsanchev
|
||||
|
||||
- title: "Blog Escrevinhador"
|
||||
author: Diniz Bortolotto
|
||||
|
||||
|
||||
|
||||
- version: 0.8.13
|
||||
date: 2011-08-05
|
||||
|
||||
new features:
|
||||
- title: "Add a new action 'Pick Random Book' that can be added to the toolbar via Preferences->Toolbars."
|
||||
tickets: [818315]
|
||||
|
||||
- title: "Driver for Droid X2"
|
||||
tickets: [821053]
|
||||
|
||||
- title: "PDF metadata: Support reading/writing of tags from the Keywords field in PDF files."
|
||||
|
||||
- title: "MOBI Input: Speedup reading of HUFF/CDIC compressed files"
|
||||
|
||||
- title: "MOBI Output: Add a command line option --extract-to that uses the inspect MOBI tool to extract the created MOBI file to the specified directory"
|
||||
|
||||
- title: "Template language: Add a few new functions to manipulate lists (list_difference, list_intersection, list_sort)"
|
||||
|
||||
- title: "Make the Manage Tags/Publishers/etc. dialog show a column with counts for each item, to easily sort by number of items"
|
||||
|
||||
- title: "MOBI Output: Generate navpoints for items at every level in the TOC, not just the deepest level"
|
||||
|
||||
bug fixes:
|
||||
- title: "MOBI Output: Remove option to choose masthead font as the font selection control causes crashes on some windows systems"
|
||||
|
||||
- title: "MOBI Output: Fix bug that caused paragraphs that had only a non breaking space as text before the first child element to be removed."
|
||||
tickets: [819058]
|
||||
|
||||
- title: "Display undefined dates properly in the Book details panel."
|
||||
tickets: [819222]
|
||||
|
||||
- title: "Fix regression that broke deleting of books from first generation Kobos with un-upgraded firmware"
|
||||
tickets: [818704]
|
||||
|
||||
- title: "Get books: Fix Gutenberg store and improvements to chitanka.info and e-knigni.net"
|
||||
|
||||
- title: "News download: Support https proxies"
|
||||
|
||||
- title: "Check library did not know about original_* files"
|
||||
|
||||
- title: "Fix crash caused by having very large numbers of authors > 100 for a book"
|
||||
|
||||
improved recipes:
|
||||
- Nikkei News
|
||||
|
||||
new recipes:
|
||||
- title: Carta Capital
|
||||
author: Pablo Aldama
|
||||
|
||||
- title: El Tiempo, El Colombiano and Portafolio Colombia
|
||||
author: Cavalencia
|
||||
|
||||
|
||||
- version: 0.8.12
|
||||
date: 2011-07-29
|
||||
|
||||
@ -198,8 +298,8 @@
|
||||
- title: Techcrunch and Pecat
|
||||
author: Darko Miletic
|
||||
|
||||
- title: Vio Mundo, IDG Now and Tojolaco
|
||||
author: Diniz Bortoletto
|
||||
- title: "Vio Mundo, IDG Now! and Tojolaco"
|
||||
author: Diniz Bortolotto
|
||||
|
||||
- title: Geek and Poke, Automatiseringgids IT
|
||||
author: DrMerry
|
||||
|
912
imgsrc/keyboard-prefs.svg
Normal file
@ -0,0 +1,912 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
|
||||
<svg
|
||||
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#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
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"
|
||||
version="1.0"
|
||||
id="Livello_1"
|
||||
width="128"
|
||||
height="128"
|
||||
viewBox="0 0 144 94"
|
||||
overflow="visible"
|
||||
enable-background="new 0 0 144 94"
|
||||
xml:space="preserve"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.45+devel"
|
||||
sodipodi:docname="preferences-desktop-keyboard.svgz"
|
||||
inkscape:output_extension="org.inkscape.output.svgz.inkscape"
|
||||
style="overflow:visible"><metadata
|
||||
id="metadata224"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs222"><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#XMLID_35_"
|
||||
id="linearGradient2719"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)"
|
||||
x1="72.000504"
|
||||
y1="83.799797"
|
||||
x2="72.000504"
|
||||
y2="5.8003001" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#rect3941_1_"
|
||||
id="linearGradient2721"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.474754,0,0,-0.465075,-255.92554,-542.49842)"
|
||||
x1="780.77576"
|
||||
y1="-1248.1824"
|
||||
x2="780.81049"
|
||||
y2="-1195.5962" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#rect3941_1_"
|
||||
id="linearGradient2723"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.474754,0,0,-0.465075,-263.1733,-542.49842)"
|
||||
x1="708.36438"
|
||||
y1="-1248.1824"
|
||||
x2="708.39648"
|
||||
y2="-1195.5962" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#rect3941_1_"
|
||||
id="linearGradient2725"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.474754,0,0,-0.465075,-270.42218,-542.49842)"
|
||||
x1="635.95538"
|
||||
y1="-1248.1824"
|
||||
x2="635.9834"
|
||||
y2="-1195.5962" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#rect3941_1_"
|
||||
id="linearGradient2727"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.474754,0,0,-0.465075,-253.92268,-535.12325)"
|
||||
x1="790.77502"
|
||||
y1="-1324.245"
|
||||
x2="790.81049"
|
||||
y2="-1271.6509" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#rect3941_1_"
|
||||
id="linearGradient2729"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.474754,0,0,-0.465075,-261.17157,-535.12325)"
|
||||
x1="718.36609"
|
||||
y1="-1324.245"
|
||||
x2="718.39838"
|
||||
y2="-1271.6509" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#rect3941_1_"
|
||||
id="linearGradient2731"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.474754,0,0,-0.465075,-268.41933,-535.12325)"
|
||||
x1="645.95471"
|
||||
y1="-1324.245"
|
||||
x2="645.9834"
|
||||
y2="-1271.6509" /><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.36659993"
|
||||
width="1.7331999"
|
||||
y="-0.17839379"
|
||||
height="1.3567876"
|
||||
id="filter3416"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.51430916"
|
||||
id="feGaussianBlur3418" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.36972603"
|
||||
width="1.7394521"
|
||||
y="-0.17766281"
|
||||
height="1.3553256"
|
||||
id="filter3424"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.51984026"
|
||||
id="feGaussianBlur3426" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.22179123"
|
||||
width="1.4435825"
|
||||
y="-0.10660794"
|
||||
height="1.2132159"
|
||||
id="filter3444"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.31193415"
|
||||
id="feGaussianBlur3446" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.21995996"
|
||||
width="1.4399199"
|
||||
y="-0.10703628"
|
||||
height="1.2140726"
|
||||
id="filter3448"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.30858549"
|
||||
id="feGaussianBlur3450" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.22183562"
|
||||
width="1.4436712"
|
||||
y="-0.10659768"
|
||||
height="1.2131954"
|
||||
id="filter3452"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.31190415"
|
||||
id="feGaussianBlur3454" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.21995996"
|
||||
width="1.4399199"
|
||||
y="-0.10703628"
|
||||
height="1.2140726"
|
||||
id="filter3456"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.30858549"
|
||||
id="feGaussianBlur3458" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.22179123"
|
||||
width="1.4435825"
|
||||
y="-0.10660794"
|
||||
height="1.2132159"
|
||||
id="filter3460"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.31193415"
|
||||
id="feGaussianBlur3462" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.21991603"
|
||||
width="1.4398321"
|
||||
y="-0.10704668"
|
||||
height="1.2140934"
|
||||
id="filter3464"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.30861549"
|
||||
id="feGaussianBlur3466" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.22179123"
|
||||
width="1.4435825"
|
||||
y="-0.10660794"
|
||||
height="1.2132159"
|
||||
id="filter3468"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.31193415"
|
||||
id="feGaussianBlur3470" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.21995996"
|
||||
width="1.4399199"
|
||||
y="-0.10703628"
|
||||
height="1.2140726"
|
||||
id="filter3472"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.30858549"
|
||||
id="feGaussianBlur3474" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.22183562"
|
||||
width="1.4436712"
|
||||
y="-0.10659768"
|
||||
height="1.2131954"
|
||||
id="filter3476"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.31190415"
|
||||
id="feGaussianBlur3478" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.21995996"
|
||||
width="1.4399199"
|
||||
y="-0.10703628"
|
||||
height="1.2140726"
|
||||
id="filter3484"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.30858549"
|
||||
id="feGaussianBlur3486" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.02891983"
|
||||
width="1.0578397"
|
||||
y="-0.14107949"
|
||||
height="1.282159"
|
||||
id="filter3492"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.33591005"
|
||||
id="feGaussianBlur3494" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.02891983"
|
||||
width="1.0578397"
|
||||
y="-0.14107949"
|
||||
height="1.282159"
|
||||
id="filter3496"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.33591005"
|
||||
id="feGaussianBlur3498" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.028919654"
|
||||
width="1.0578393"
|
||||
y="-0.14108369"
|
||||
height="1.2821674"
|
||||
id="filter3500"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.33592005"
|
||||
id="feGaussianBlur3502" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.02891983"
|
||||
width="1.0578397"
|
||||
y="-0.14107949"
|
||||
height="1.282159"
|
||||
id="filter3504"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.33591005"
|
||||
id="feGaussianBlur3506" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.02891983"
|
||||
width="1.0578397"
|
||||
y="-0.14107949"
|
||||
height="1.282159"
|
||||
id="filter3508"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.33591005"
|
||||
id="feGaussianBlur3510" /></filter><filter
|
||||
inkscape:collect="always"
|
||||
x="-0.02891983"
|
||||
width="1.0578397"
|
||||
y="-0.14107949"
|
||||
height="1.282159"
|
||||
id="filter3512"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.33591005"
|
||||
id="feGaussianBlur3514" /></filter><linearGradient
|
||||
id="XMLID_31_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="69.333504"
|
||||
y1="17.6504"
|
||||
x2="69.333504"
|
||||
y2="9.7958002"
|
||||
xlink:href="#XMLID_32_">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF"
|
||||
id="stop169" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#DDDDDD"
|
||||
id="stop171" />
|
||||
</linearGradient><linearGradient
|
||||
id="XMLID_32_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="106.334"
|
||||
y1="17.6504"
|
||||
x2="106.334"
|
||||
y2="9.7958002">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF"
|
||||
id="stop186" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#DDDDDD"
|
||||
id="stop188" />
|
||||
</linearGradient><linearGradient
|
||||
id="XMLID_30_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="31.742201"
|
||||
y1="17.6504"
|
||||
x2="31.742201"
|
||||
y2="9.7958002">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF"
|
||||
id="stop152" /><stop
|
||||
id="stop3366"
|
||||
style="stop-color:#eaeaea;stop-opacity:1;"
|
||||
offset="0.68235296" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#c8c8c8;stop-opacity:1;"
|
||||
id="stop154" />
|
||||
</linearGradient><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#XMLID_30_"
|
||||
id="linearGradient2945"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="69.333504"
|
||||
y1="17.6504"
|
||||
x2="69.333504"
|
||||
y2="9.7958002" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#XMLID_30_"
|
||||
id="linearGradient2947"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="106.334"
|
||||
y1="17.6504"
|
||||
x2="106.334"
|
||||
y2="9.7958002" /><linearGradient
|
||||
xlink:href="#XMLID_30_"
|
||||
id="XMLID_28_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="38.033699"
|
||||
y1="55.649399"
|
||||
x2="38.033699"
|
||||
y2="47.795502"
|
||||
spreadMethod="pad">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF"
|
||||
id="stop118" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#DDDDDD"
|
||||
id="stop120" />
|
||||
</linearGradient><linearGradient
|
||||
id="XMLID_29_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="75.333"
|
||||
y1="55.649399"
|
||||
x2="75.333"
|
||||
y2="47.795502">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF"
|
||||
id="stop135" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#DDDDDD"
|
||||
id="stop137" />
|
||||
</linearGradient><linearGradient
|
||||
id="XMLID_33_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="112.334"
|
||||
y1="55.649399"
|
||||
x2="112.334"
|
||||
y2="47.795502">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF"
|
||||
id="stop203" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#DDDDDD"
|
||||
id="stop205" />
|
||||
</linearGradient><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#XMLID_30_"
|
||||
id="linearGradient2979"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
spreadMethod="pad"
|
||||
x1="38.033699"
|
||||
y1="55.649399"
|
||||
x2="38.033699"
|
||||
y2="47.795502" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#XMLID_30_"
|
||||
id="linearGradient2981"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="75.333"
|
||||
y1="55.649399"
|
||||
x2="75.333"
|
||||
y2="47.795502" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#XMLID_30_"
|
||||
id="linearGradient2983"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="112.334"
|
||||
y1="55.649399"
|
||||
x2="112.334"
|
||||
y2="47.795502" /><filter
|
||||
inkscape:collect="always"
|
||||
id="filter3372"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.3179705"
|
||||
id="feGaussianBlur3374" /></filter><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#XMLID_30_"
|
||||
id="linearGradient3378"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="106.334"
|
||||
y1="17.6504"
|
||||
x2="106.334"
|
||||
y2="9.7958002" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#XMLID_30_"
|
||||
id="linearGradient3380"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="31.742201"
|
||||
y1="17.6504"
|
||||
x2="31.742201"
|
||||
y2="9.7958002" /></defs><sodipodi:namedview
|
||||
inkscape:window-height="696"
|
||||
inkscape:window-width="998"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
guidetolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
objecttolerance="10.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base"
|
||||
height="128px"
|
||||
width="128px"
|
||||
inkscape:zoom="2.8284271"
|
||||
inkscape:cx="65.761733"
|
||||
inkscape:cy="68.182683"
|
||||
inkscape:window-x="26"
|
||||
inkscape:window-y="0"
|
||||
inkscape:current-layer="g2620" />
|
||||
<filter
|
||||
id="AI_Sfocatura_2">
|
||||
<feGaussianBlur
|
||||
stdDeviation="2"
|
||||
id="feGaussianBlur4" />
|
||||
</filter>
|
||||
<path
|
||||
display="none"
|
||||
d="M 89.758,1.8 C 88.983,1.8 88.229,1.945 87.501,2.17 C 86.774,1.945 86.022,1.8 85.248,1.8 L 52.752,1.8 C 51.978,1.8 51.226,1.945 50.499,2.17 C 49.772,1.944 49.02,1.8 48.245,1.8 L 15.755,1.8 C 11.479,1.8 8,5.275 8,9.546 L 8,42.054 C 8,45.72 10.57,48.783 14,49.582 C 14,53.16 14,80.057 14,80.057 C 14,84.327 17.478,87.8 21.752,87.8 L 54.248,87.8 C 55.022,87.8 55.774,87.655 56.5,87.431 C 57.227,87.656 57.979,87.8 58.754,87.8 L 91.241,87.8 C 92.017,87.8 92.77,87.655 93.498,87.431 C 94.225,87.655 94.977,87.8 95.751,87.8 L 128.241,87.8 C 132.518,87.8 135.999,84.326 135.999,80.057 L 135.999,47.546 C 135.999,43.881 133.43,40.818 129.999,40.019 C 129.999,36.442 129.999,9.546 129.999,9.546 C 129.999,5.275 126.521,1.8 122.247,1.8 L 89.758,1.8 L 89.758,1.8 z"
|
||||
id="path6"
|
||||
style="fill:#ff00bf;display:none" />
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_35_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="72.000504"
|
||||
y1="83.799797"
|
||||
x2="72.000504"
|
||||
y2="5.8003001">
|
||||
<stop
|
||||
offset="0.0059"
|
||||
style="stop-color:#888888"
|
||||
id="stop13" />
|
||||
<stop
|
||||
offset="0.5"
|
||||
style="stop-color:#555555"
|
||||
id="stop15" />
|
||||
<stop
|
||||
offset="0.54"
|
||||
style="stop-color:#888888"
|
||||
id="stop17" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#555555"
|
||||
id="stop19" />
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient
|
||||
id="rect3785_1_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="780.81049"
|
||||
y1="-1240.9404"
|
||||
x2="780.81049"
|
||||
y2="-1195.5962"
|
||||
gradientTransform="matrix(0.422,0,0,-0.4134,-223.4874,-472.1986)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#BEBEBE"
|
||||
id="stop24" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#EDEDED"
|
||||
id="stop26" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="rect3791_1_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="708.39648"
|
||||
y1="-1240.9404"
|
||||
x2="708.39648"
|
||||
y2="-1195.5962"
|
||||
gradientTransform="matrix(0.422,0,0,-0.4134,-229.9298,-472.1986)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#BEBEBE"
|
||||
id="stop38" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#EDEDED"
|
||||
id="stop40" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="rect3797_1_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="635.9834"
|
||||
y1="-1240.9404"
|
||||
x2="635.9834"
|
||||
y2="-1195.5962"
|
||||
gradientTransform="matrix(0.422,0,0,-0.4134,-236.3732,-472.1986)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#BEBEBE"
|
||||
id="stop52" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#EDEDED"
|
||||
id="stop54" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="rect3929_1_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="790.81049"
|
||||
y1="-1316.9951"
|
||||
x2="790.81049"
|
||||
y2="-1271.6509"
|
||||
gradientTransform="matrix(0.422,0,0,-0.4134,-221.7071,-465.6429)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#BEBEBE"
|
||||
id="stop66" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#EDEDED"
|
||||
id="stop68" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="rect3935_1_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="718.39838"
|
||||
y1="-1316.9951"
|
||||
x2="718.39838"
|
||||
y2="-1271.6509"
|
||||
gradientTransform="matrix(0.422,0,0,-0.4134,-228.1505,-465.6429)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#BEBEBE"
|
||||
id="stop80" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#EDEDED"
|
||||
id="stop82" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="rect3941_1_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="645.9834"
|
||||
y1="-1316.9951"
|
||||
x2="645.9834"
|
||||
y2="-1271.6509"
|
||||
gradientTransform="matrix(0.422,0,0,-0.4134,-234.5929,-465.6429)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#e4e4e4;stop-opacity:1;"
|
||||
id="stop94" /><stop
|
||||
id="stop3516"
|
||||
style="stop-color:#bebebe;stop-opacity:1;"
|
||||
offset="0.18012393" /><stop
|
||||
offset="0.61417598"
|
||||
style="stop-color:#cdcdcd;stop-opacity:1;"
|
||||
id="stop3376" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#b3b3b3;stop-opacity:1;"
|
||||
id="stop96" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<g
|
||||
id="g8"
|
||||
style="opacity:0.8;filter:url(#AI_Sfocatura_2)"
|
||||
transform="matrix(1.1250094,0,0,1.125,-9.0001128,-12.4)">
|
||||
<path
|
||||
d="M 128.242,45.8 L 125.547,45.8 C 125.826,45.276 126,44.688 126,44.054 L 126,11.546 C 126,9.481 124.316,7.8 122.248,7.8 L 89.758,7.8 C 88.907,7.8 88.131,8.093 87.501,8.57 C 86.872,8.093 86.097,7.8 85.248,7.8 L 52.752,7.8 C 51.903,7.8 51.128,8.093 50.499,8.57 C 49.869,8.094 49.094,7.8 48.245,7.8 L 15.755,7.8 C 13.685,7.8 12,9.48 12,11.546 L 12,44.054 C 12,46.119 13.685,47.8 15.755,47.8 L 18.453,47.8 C 18.173,48.323 18,48.912 18,49.546 L 18,82.057 C 18,84.121 19.683,85.8 21.752,85.8 L 54.248,85.8 C 55.097,85.8 55.872,85.507 56.5,85.031 C 57.13,85.507 57.905,85.8 58.754,85.8 L 91.241,85.8 C 92.092,85.8 92.868,85.507 93.498,85.03 C 94.127,85.507 94.902,85.8 95.751,85.8 L 128.241,85.8 C 130.313,85.8 131.999,84.121 131.999,82.057 L 131.999,49.546 C 132,47.48 130.314,45.8 128.242,45.8 z"
|
||||
id="path10"
|
||||
style="opacity:0.8" />
|
||||
</g><g
|
||||
id="g2620"
|
||||
transform="translate(-4.5,0)"><path
|
||||
style="fill:url(#linearGradient2721);fill-opacity:1"
|
||||
d="M 96.478481,-2.5 L 133.03004,-2.5 C 134.11905,-2.5 135.00105,-1.621375 135.00105,-0.53575 L 135.00105,36.03575 C 135.00105,37.121374 134.11905,38 133.03004,38 L 96.478481,38 C 95.382722,38 94.500715,37.121374 94.500715,36.03575 L 94.500715,-0.53575 C 94.500715,-1.621375 95.382722,-2.5 96.478481,-2.5 z"
|
||||
id="rect3785" /><g
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)"
|
||||
nodetypes="cccsssssscccc"
|
||||
id="path3787">
|
||||
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.6404,-8.5e-3,-7.7e-3,-0.6279,-240.4975,-567.9111)"
|
||||
r="40.036301"
|
||||
cy="-971.75677"
|
||||
cx="527.62299"
|
||||
id="XMLID_17_">
|
||||
<stop
|
||||
id="stop31"
|
||||
style="stop-color:#E8E8E8"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop33"
|
||||
style="stop-color:#FFFFFF"
|
||||
offset="1" />
|
||||
</radialGradient>
|
||||
<path
|
||||
style="fill:url(#XMLID_17_)"
|
||||
id="path35"
|
||||
d="M 91.145,9.856 L 89.924,35.848 L 89.852,37.041 C 91.107,37.752 92.344,38.38 93.661,38.908 C 93.683,38.914 93.717,38.9 93.738,38.908 C 97.663,40.465 101.819,41.179 105.966,41.145 C 106.662,41.14 107.359,41.12 108.055,41.072 C 109.436,40.973 110.852,40.816 112.223,40.55 C 113.593,40.285 114.914,39.932 116.252,39.504 C 118.259,38.861 120.26,38.043 122.15,37.042 L 122.077,35.849 L 120.928,9.857 L 91.145,9.857 L 91.145,9.856 z" />
|
||||
</g><path
|
||||
style="fill:url(#linearGradient2723);fill-opacity:1"
|
||||
d="M 54.846383,-2.5 L 91.404689,-2.5 C 92.492573,-2.5 93.375705,-1.621375 93.375705,-0.53575 L 93.375705,36.03575 C 93.375705,37.121374 92.492573,38 91.404689,38 L 54.846383,38 C 53.758499,38 52.875367,37.121374 52.875367,36.03575 L 52.875367,-0.53575 C 52.875367,-1.621375 53.758499,-2.5 54.846383,-2.5 z"
|
||||
id="rect3791" /><g
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)"
|
||||
nodetypes="cccsssssscccc"
|
||||
id="path3793">
|
||||
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.6404,-8.5e-3,-7.7e-3,-0.6279,-247.2058,-567.9111)"
|
||||
r="40.036098"
|
||||
cy="-971.12653"
|
||||
cx="480.29791"
|
||||
id="XMLID_19_">
|
||||
<stop
|
||||
id="stop45"
|
||||
style="stop-color:#E8E8E8"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop47"
|
||||
style="stop-color:#FFFFFF"
|
||||
offset="1" />
|
||||
</radialGradient>
|
||||
<path
|
||||
style="fill:url(#XMLID_19_)"
|
||||
id="path49"
|
||||
d="M 54.145,9.856 L 52.921,35.848 L 52.849,37.041 C 54.109,37.752 55.348,38.38 56.663,38.908 C 56.682,38.914 56.715,38.9 56.734,38.908 C 60.662,40.465 64.821,41.179 68.962,41.145 C 69.658,41.14 70.355,41.12 71.048,41.072 C 72.433,40.973 73.848,40.816 75.218,40.55 C 76.589,40.285 77.909,39.932 79.253,39.504 C 81.254,38.861 83.255,38.043 85.147,37.042 L 85.08,35.849 L 83.927,9.856 L 54.145,9.856 z" />
|
||||
</g><path
|
||||
style="fill:url(#linearGradient2725);fill-opacity:1"
|
||||
d="M 13.224411,-2.5 L 49.775966,-2.5 C 50.867225,-2.5 51.750357,-1.621375 51.750357,-0.53575 L 51.750357,36.03575 C 51.750357,37.121374 50.867225,38 49.775966,38 L 13.224411,38 C 12.133151,38 11.250019,37.121374 11.250019,36.03575 L 11.250019,-0.53575 C 11.250019,-1.621375 12.133151,-2.5 13.224411,-2.5 z"
|
||||
id="rect3797" /><g
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)"
|
||||
nodetypes="cccsssssscccc"
|
||||
id="path3799">
|
||||
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.6403,-8.5e-3,-7.7e-3,-0.6279,-253.8748,-567.9111)"
|
||||
r="40.033199"
|
||||
cy="-970.48578"
|
||||
cx="432.98141"
|
||||
id="XMLID_24_">
|
||||
<stop
|
||||
id="stop59"
|
||||
style="stop-color:#E8E8E8"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop61"
|
||||
style="stop-color:#FFFFFF"
|
||||
offset="1" />
|
||||
</radialGradient>
|
||||
<path
|
||||
style="fill:url(#XMLID_24_)"
|
||||
id="path63"
|
||||
d="M 17.146,9.856 L 15.924,35.848 L 15.852,37.041 C 17.109,37.752 18.348,38.38 19.663,38.908 C 19.682,38.914 19.716,38.9 19.735,38.908 C 23.662,40.465 27.821,41.179 31.964,41.145 C 32.657,41.14 33.357,41.12 34.05,41.072 C 35.435,40.973 36.85,40.816 38.22,40.55 C 39.591,40.285 40.909,39.932 42.249,39.504 C 44.258,38.861 46.254,38.043 48.146,37.042 L 48.075,35.849 L 46.925,9.857 L 17.146,9.857 L 17.146,9.856 z" />
|
||||
</g><path
|
||||
style="fill:url(#linearGradient2727);fill-opacity:1"
|
||||
d="M 103.22179,40.25 L 139.77334,40.25 C 140.8691,40.25 141.75111,41.128625 141.75111,42.21425 L 141.75111,78.789125 C 141.75111,79.87475 140.8691,80.75 139.77334,80.75 L 103.22179,80.75 C 102.13278,80.75 101.25077,79.873625 101.25077,78.789125 L 101.25077,42.21425 C 101.25077,41.128625 102.13278,40.25 103.22179,40.25 z"
|
||||
id="rect3929" /><g
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)"
|
||||
nodetypes="cccsssssscccc"
|
||||
id="path3931">
|
||||
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.6404,-8.5e-3,-7.7e-3,-0.6279,-238.6489,-561.7972)"
|
||||
r="40.036499"
|
||||
cy="-1022.5366"
|
||||
cx="533.49512"
|
||||
id="XMLID_25_">
|
||||
<stop
|
||||
id="stop73"
|
||||
style="stop-color:#E8E8E8"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop75"
|
||||
style="stop-color:#FFFFFF"
|
||||
offset="1" />
|
||||
</radialGradient>
|
||||
<path
|
||||
style="fill:url(#XMLID_25_)"
|
||||
id="path77"
|
||||
d="M 97.145,47.856 L 95.918,73.85 L 95.851,75.04 C 97.113,75.751 98.35,76.383 99.665,76.908 C 99.682,76.914 99.716,76.902 99.731,76.908 C 103.661,78.47 107.824,79.181 111.963,79.148 C 112.654,79.142 113.357,79.125 114.047,79.075 C 115.434,78.979 116.849,78.821 118.221,78.55 C 119.591,78.29 120.912,77.936 122.25,77.506 C 124.262,76.863 126.252,76.045 128.147,75.04 L 128.075,73.85 L 126.926,47.857 L 97.145,47.857 L 97.145,47.856 z" />
|
||||
</g><path
|
||||
style="fill:url(#linearGradient2729);fill-opacity:1"
|
||||
d="M 61.599815,40.25 L 98.148,40.25 C 99.24263,40.25 100.12576,41.128625 100.12576,42.21425 L 100.12576,78.789125 C 100.12576,79.87475 99.24263,80.75 98.148,80.75 L 61.599815,80.75 C 60.511931,80.75 59.625423,79.873625 59.625423,78.789125 L 59.625423,42.21425 C 59.625423,41.128625 60.511931,40.25 61.599815,40.25 z"
|
||||
id="rect3935" /><g
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)"
|
||||
nodetypes="cccsssssscccc"
|
||||
id="path3937">
|
||||
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.6403,-8.5e-3,-7.7e-3,-0.6279,-245.3333,-561.7972)"
|
||||
r="40.038898"
|
||||
cy="-1021.9087"
|
||||
cx="486.17969"
|
||||
id="XMLID_26_">
|
||||
<stop
|
||||
id="stop87"
|
||||
style="stop-color:#E8E8E8"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop89"
|
||||
style="stop-color:#FFFFFF"
|
||||
offset="1" />
|
||||
</radialGradient>
|
||||
<path
|
||||
style="fill:url(#XMLID_26_)"
|
||||
id="path91"
|
||||
d="M 60.145,47.856 L 58.923,73.85 L 58.852,75.04 C 60.112,75.751 61.347,76.383 62.663,76.908 C 62.684,76.914 62.715,76.902 62.735,76.908 C 66.662,78.47 70.824,79.181 74.964,79.148 C 75.654,79.142 76.357,79.125 77.048,79.075 C 78.441,78.979 79.856,78.821 81.227,78.55 C 82.597,78.29 83.913,77.936 85.25,77.506 C 87.263,76.863 89.258,76.045 91.153,75.04 L 91.076,73.85 L 89.926,47.857 L 60.145,47.857 L 60.145,47.856 z" />
|
||||
</g><path
|
||||
style="fill:url(#linearGradient2731)"
|
||||
d="M 19.971092,40.25 L 56.529397,40.25 C 57.617282,40.25 58.500414,41.128625 58.500414,42.21425 L 58.500414,78.789125 C 58.500414,79.87475 57.617282,80.75 56.529397,80.75 L 19.971092,80.75 C 18.883208,80.75 18.000075,79.873625 18.000075,78.789125 L 18.000075,42.21425 C 18.000075,41.128625 18.883208,40.25 19.971092,40.25 z"
|
||||
id="rect3941" /><g
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)"
|
||||
nodetypes="cccsssssscccc"
|
||||
id="path3943"
|
||||
style="filter:url(#filter3372)">
|
||||
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.6404,-8.5e-3,-7.7e-3,-0.6279,-252.0475,-561.7972)"
|
||||
r="40.039001"
|
||||
cy="-1021.27"
|
||||
cx="438.85059"
|
||||
id="XMLID_27_">
|
||||
<stop
|
||||
id="stop101"
|
||||
style="stop-color:#E8E8E8"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop103"
|
||||
style="stop-color:#FFFFFF"
|
||||
offset="0.5858" />
|
||||
</radialGradient>
|
||||
<path
|
||||
style="fill:url(#XMLID_27_)"
|
||||
id="path105"
|
||||
d="M 23.146,47.856 L 21.921,73.85 L 21.849,75.04 C 23.11,75.751 24.348,76.383 25.663,76.908 C 25.682,76.914 25.715,76.902 25.734,76.908 C 29.662,78.47 33.821,79.181 37.965,79.148 C 38.658,79.142 39.358,79.125 40.049,79.075 C 41.436,78.979 42.851,78.821 44.222,78.55 C 45.593,78.29 46.911,77.936 48.252,77.506 C 50.262,76.863 52.257,76.045 54.15,75.04 L 54.078,73.85 L 52.926,47.857 L 23.146,47.857 L 23.146,47.856 z" />
|
||||
</g><g
|
||||
style="filter:url(#filter3460)"
|
||||
id="g109"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)">
|
||||
<path
|
||||
d="M 22.213,81.018 L 23.666,76.231 C 23.666,76.231 23.743,74.036 21.849,75.041 L 21.921,76.231 L 20.291,81.018 C 20.605,81.49 21.142,81.8 21.752,81.8 L 23.515,81.8 C 22.971,81.8 22.493,81.489 22.213,81.018 z"
|
||||
id="path111"
|
||||
style="fill:#ffffff" />
|
||||
</g><g
|
||||
style="filter:url(#filter3464)"
|
||||
id="g113"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)">
|
||||
<path
|
||||
d="M 54.079,76.23 L 54.151,75.04 C 52.89,74.329 52.333,76.23 52.333,76.23 L 53.779,81.033 C 53.498,81.496 53.023,81.8 52.485,81.8 L 54.249,81.8 C 54.853,81.8 55.386,81.496 55.701,81.033 L 54.079,76.23 z"
|
||||
id="path115"
|
||||
style="fill:#ffffff" />
|
||||
</g><path
|
||||
d="M 24.1,48.856 C 23.693,57.45 52.262,55.434 51.971,48.856 C 42.68,48.856 33.39,48.856 24.1,48.856"
|
||||
id="path122"
|
||||
style="fill:url(#linearGradient2979);fill-opacity:1;filter:url(#filter3500)"
|
||||
transform="matrix(1.1250094,0,0,1.7718407,-4.5001124,-41.815049)" /><g
|
||||
style="filter:url(#filter3468)"
|
||||
id="g126"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)">
|
||||
<path
|
||||
d="M 59.513,81.018 L 60.966,76.231 C 60.966,76.231 61.043,74.036 59.149,75.041 L 59.221,76.231 L 57.591,81.018 C 57.905,81.49 58.442,81.8 59.052,81.8 L 60.815,81.8 C 60.271,81.8 59.792,81.489 59.513,81.018 z"
|
||||
id="path128"
|
||||
style="fill:#ffffff" />
|
||||
</g><g
|
||||
style="filter:url(#filter3472)"
|
||||
id="g130"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)">
|
||||
<path
|
||||
d="M 91.379,76.23 L 91.451,75.04 C 90.189,74.329 89.633,76.23 89.633,76.23 L 91.078,81.033 C 90.797,81.496 90.322,81.8 89.784,81.8 L 91.548,81.8 C 92.152,81.8 92.685,81.496 93,81.033 L 91.379,76.23 z"
|
||||
id="path132"
|
||||
style="fill:#ffffff" />
|
||||
</g><path
|
||||
d="M 61.399,48.856 C 60.992,57.45 89.56,55.434 89.269,48.856 C 79.98,48.856 70.689,48.856 61.399,48.856"
|
||||
id="path139"
|
||||
style="fill:url(#linearGradient2981);filter:url(#filter3496)"
|
||||
transform="matrix(1.1250094,0,0,1.7718407,-4.5001124,-41.815049)" /><g
|
||||
id="g143"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)">
|
||||
<path
|
||||
d="M 15.921,43.018 L 17.374,38.231 C 17.374,38.231 17.451,36.036 15.557,37.041 L 15.629,38.231 L 14,43.018 C 14.314,43.49 14.851,43.8 15.461,43.8 L 17.224,43.8 C 16.68,43.8 16.201,43.489 15.921,43.018 z"
|
||||
id="path145"
|
||||
style="fill:#ffffff;filter:url(#filter3424)" />
|
||||
</g><path
|
||||
id="path149"
|
||||
d="M 47.788,38.23 L 47.86,37.04 C 46.598,36.329 46.042,38.23 46.042,38.23 L 47.487,43.033 C 47.206,43.496 46.731,43.8 46.193,43.8 L 47.957,43.8 C 48.561,43.8 49.094,43.496 49.409,43.033 L 47.788,38.23 z"
|
||||
style="fill:#ffffff;filter:url(#filter3416)"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)" /><path
|
||||
d="M 17.808,10.856 C 17.401,19.45 45.969,17.434 45.678,10.856 C 36.389,10.856 27.098,10.856 17.808,10.856"
|
||||
id="path156"
|
||||
style="fill:url(#linearGradient3380);fill-opacity:1;filter:url(#filter3504)"
|
||||
transform="matrix(1.1250094,0,0,1.7718407,-4.5001124,-17.235103)" /><g
|
||||
style="filter:url(#filter3444)"
|
||||
id="g160"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)">
|
||||
<path
|
||||
d="M 53.513,43.018 L 54.966,38.231 C 54.966,38.231 55.043,36.036 53.149,37.041 L 53.221,38.231 L 51.591,43.018 C 51.905,43.49 52.442,43.8 53.052,43.8 L 54.815,43.8 C 54.271,43.8 53.792,43.489 53.513,43.018 z"
|
||||
id="path162"
|
||||
style="fill:#ffffff" />
|
||||
</g><g
|
||||
style="filter:url(#filter3448)"
|
||||
id="g164"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)">
|
||||
<path
|
||||
d="M 85.379,38.23 L 85.451,37.04 C 84.189,36.329 83.633,38.23 83.633,38.23 L 85.078,43.033 C 84.797,43.496 84.322,43.8 83.784,43.8 L 85.548,43.8 C 86.152,43.8 86.685,43.496 87,43.033 L 85.379,38.23 z"
|
||||
id="path166"
|
||||
style="fill:#ffffff" />
|
||||
</g><path
|
||||
d="M 55.399,10.856 C 54.992,19.45 83.56,17.434 83.269,10.856 C 73.98,10.856 64.689,10.856 55.399,10.856"
|
||||
id="path173"
|
||||
style="fill:url(#linearGradient2945);fill-opacity:1;filter:url(#filter3508)"
|
||||
transform="matrix(1.1250094,0,0,1.7718407,-4.5001124,-17.235103)" /><g
|
||||
style="filter:url(#filter3452)"
|
||||
id="g177"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)">
|
||||
<path
|
||||
d="M 90.513,43.018 L 91.966,38.231 C 91.966,38.231 92.043,36.036 90.149,37.041 L 90.221,38.231 L 88.592,43.018 C 88.905,43.49 89.442,43.8 90.053,43.8 L 91.815,43.8 C 91.271,43.8 90.793,43.489 90.513,43.018 z"
|
||||
id="path179"
|
||||
style="fill:#ffffff" />
|
||||
</g><g
|
||||
style="filter:url(#filter3456)"
|
||||
id="g181"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)">
|
||||
<path
|
||||
d="M 122.379,38.23 L 122.451,37.04 C 121.189,36.329 120.633,38.23 120.633,38.23 L 122.078,43.033 C 121.797,43.496 121.322,43.8 120.784,43.8 L 122.548,43.8 C 123.152,43.8 123.685,43.496 124,43.033 L 122.379,38.23 z"
|
||||
id="path183"
|
||||
style="fill:#ffffff" />
|
||||
</g><path
|
||||
d="M 92.399,10.856 C 91.992,19.45 120.56,17.434 120.269,10.856 C 110.98,10.856 101.689,10.856 92.399,10.856"
|
||||
id="path190"
|
||||
style="fill:url(#linearGradient3378);fill-opacity:1;filter:url(#filter3512)"
|
||||
transform="matrix(1.1250094,0,0,1.7718407,-4.5001124,-17.235103)" /><g
|
||||
style="filter:url(#filter3476)"
|
||||
id="g194"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)">
|
||||
<path
|
||||
d="M 96.513,81.018 L 97.966,76.231 C 97.966,76.231 98.043,74.036 96.149,75.041 L 96.221,76.231 L 94.592,81.018 C 94.905,81.49 95.442,81.8 96.053,81.8 L 97.815,81.8 C 97.271,81.8 96.793,81.489 96.513,81.018 z"
|
||||
id="path196"
|
||||
style="fill:#ffffff" />
|
||||
</g><g
|
||||
style="filter:url(#filter3484)"
|
||||
id="g198"
|
||||
transform="matrix(1.1250094,0,0,1.125,-4.5001124,-11.275)">
|
||||
<path
|
||||
d="M 128.379,76.23 L 128.451,75.04 C 127.189,74.329 126.633,76.23 126.633,76.23 L 128.078,81.033 C 127.797,81.496 127.322,81.8 126.784,81.8 L 128.548,81.8 C 129.152,81.8 129.685,81.496 130,81.033 L 128.379,76.23 z"
|
||||
id="path200"
|
||||
style="fill:#ffffff" />
|
||||
</g><path
|
||||
d="M 98.399,48.856 C 97.992,57.45 126.56,55.434 126.269,48.856 C 116.98,48.856 107.689,48.856 98.399,48.856"
|
||||
id="path207"
|
||||
style="fill:url(#linearGradient2983);filter:url(#filter3492)"
|
||||
transform="matrix(1.1250094,0,0,1.7718407,-4.5001124,-41.815049)" /><path
|
||||
style="fill:#323232"
|
||||
id="path209"
|
||||
d="M 21.99503,12.125 L 19.778139,23.842759 C 19.61869,24.635599 19.540614,25.268992 19.540614,25.848502 C 19.540614,27.088895 20.172912,27.749779 21.150501,27.749779 C 22.470079,27.749779 23.261827,26.799689 23.788558,23.974716 L 26.058233,12.125 L 28.723782,12.125 L 26.533281,23.632728 C 25.715142,27.960908 24.079966,30.125 20.832702,30.125 C 18.27382,30.125 16.875066,28.645985 16.875066,26.112415 C 16.875066,25.399849 16.981732,24.502542 17.166473,23.47328 L 19.330582,12.125 L 21.99503,12.125 L 21.99503,12.125 z" /><path
|
||||
style="fill:#323232"
|
||||
id="path211"
|
||||
d="M 64.643632,12.125 L 61.198712,30.125 L 58.500414,30.125 L 61.918629,12.125 L 64.643632,12.125 L 64.643632,12.125 z" /><path
|
||||
style="fill:#323232"
|
||||
id="path213"
|
||||
d="M 111.34148,17.759442 C 111.34148,21.280968 110.11546,26.238278 107.82102,28.532705 C 106.7515,29.602206 105.57766,30.125 104.19402,30.125 C 100.56813,30.125 100.12576,26.368704 100.12576,24.464472 C 100.12576,20.995117 101.35178,16.037807 103.77666,13.664038 C 104.79508,12.672793 105.99394,12.125 107.35038,12.125 C 110.95129,12.125 111.34148,15.62044 111.34148,17.759442 z M 105.60374,15.124819 C 103.82883,16.899712 102.83867,21.985274 102.83867,24.593812 C 102.83867,25.793739 102.94301,27.802314 104.58532,27.802314 C 105.05486,27.802314 105.4983,27.567546 105.91676,27.15018 C 107.76775,25.270946 108.60358,19.585419 108.60358,17.629015 C 108.60358,16.089978 108.47315,14.446599 106.98627,14.446599 C 106.48956,14.447686 106.0211,14.681367 105.60374,15.124819 z" /><path
|
||||
style="fill:#323232"
|
||||
id="path215"
|
||||
d="M 30.011882,54.875 L 32.678531,54.875 L 30.223015,67.727587 C 29.431267,71.819347 27.794991,72.875 25.182225,72.875 C 24.522435,72.875 23.91543,72.768335 23.625122,72.663868 L 24.073779,70.288648 C 24.443261,70.394213 24.785251,70.420605 25.287791,70.420605 C 26.450121,70.420605 27.161593,69.681647 27.531075,67.728687 L 30.011882,54.875 z" /><path
|
||||
style="fill:#323232"
|
||||
id="path217"
|
||||
d="M 68.668474,54.876125 L 71.338789,54.876125 L 69.683194,63.422176 L 69.763303,63.422176 C 70.350773,62.407464 70.804726,61.659781 71.285383,60.885397 L 75.156227,54.877238 L 78.146981,54.877238 L 72.512615,62.72901 L 74.782383,72.876125 L 71.978553,72.876125 L 70.428657,64.732844 L 69.148018,66.387312 L 67.895195,72.875012 L 65.25047,72.875012 L 68.668474,54.876125 z" /><path
|
||||
style="fill:#323232"
|
||||
id="path219"
|
||||
d="M 110.29425,54.873875 L 113.0183,54.873875 L 110.02717,70.523727 L 114.67522,70.523727 L 114.22121,72.873875 L 106.87582,72.873875 L 110.29425,54.873875 z" /></g>
|
||||
</svg>
|
After Width: | Height: | Size: 34 KiB |
98
imgsrc/languages.svg
Normal file
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="128" width="128" version="1.0" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 256 256">
|
||||
<defs>
|
||||
<linearGradient id="b" y2="158.07" gradientUnits="userSpaceOnUse" x2="141.27" gradientTransform="matrix(1.68, 0, 0, 1.68, -86.7, -86.7)" y1="70.428" x1="141.27">
|
||||
<stop stop-color="#FFF" offset="0"/>
|
||||
<stop stop-color="#00a200" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="a" y2="158.07" gradientUnits="userSpaceOnUse" y1="70.428" gradientTransform="matrix(1.68, 0, 0, 1.68, -86.7, -86.7)" x2="141.27" x1="141.27">
|
||||
<stop stop-color="#FFF" offset="0"/>
|
||||
<stop stop-color="#00a100" offset="0.5"/>
|
||||
<stop stop-color="#000" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="c" y2="397.34" gradientUnits="userSpaceOnUse" x2="12.991" gradientTransform="matrix(2.573, 0, 0, -2.573, 207.924, 1307.73)" y1="397.34" x1="-117">
|
||||
<stop stop-color="#0053BD" offset="0"/>
|
||||
<stop stop-color="#0032A4" offset="1"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="d" gradientUnits="userSpaceOnUse" cy="439.63" cx="-57.022" gradientTransform="matrix(2.573, 0, 0, -2.573, 207.924, 1307.73)" r="98">
|
||||
<stop stop-color="#FFF" offset="0"/>
|
||||
<stop stop-color="#57ADFF" offset="0.6"/>
|
||||
<stop stop-color="#C9E6FF" offset="1"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="e" y2="183.37" gradientUnits="userSpaceOnUse" x2="127.66" gradientTransform="matrix(2.573, 0, 0, 2.573, -251.365, -39.26)" y1="63.215" x1="127.66">
|
||||
<stop stop-color="#006a00" offset="0"/>
|
||||
<stop stop-color="#004000" offset="0.2"/>
|
||||
<stop stop-color="#00d000" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="f" y2="361.42" gradientUnits="userSpaceOnUse" x2="-52.251" gradientTransform="matrix(2.573, 0, 0, -2.573, 207.924, 1307.73)" y1="457.03" x1="-52.251">
|
||||
<stop stop-color="#FFF" offset="0"/>
|
||||
<stop stop-color="#94CAFF" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="g" y2="158.07" xlink:href="#a" gradientUnits="userSpaceOnUse" x2="141.27" gradientTransform="matrix(2.573, 0, 0, 2.573, -251.365, -39.26)" y1="70.428" x1="141.27"/>
|
||||
<linearGradient id="h" y2="130.03" xlink:href="#a" gradientUnits="userSpaceOnUse" x2="100.51" gradientTransform="matrix(2.573, 0, 0, 2.573, -251.365, -39.26)" y1="70.033" x1="100.51"/>
|
||||
<linearGradient id="i" y2="85.32" xlink:href="#b" gradientUnits="userSpaceOnUse" x2="120.48" gradientTransform="matrix(2.573, 0, 0, 2.573, -251.365, -39.26)" y1="68.117" x1="120.48"/>
|
||||
<linearGradient id="j" y2="79.161" xlink:href="#b" gradientUnits="userSpaceOnUse" x2="124.57" y1="73.444" x1="124.57"/>
|
||||
<linearGradient id="k" y2="73.865" xlink:href="#b" gradientUnits="userSpaceOnUse" x2="132.78" y1="67.756" x1="132.78"/>
|
||||
<linearGradient id="l" y2="323.36" gradientUnits="userSpaceOnUse" x2="258.77" gradientTransform="translate(5.58, -12.8322)" y1="408.7" x1="258.77">
|
||||
<stop stop-color="#3434ff" offset="0"/>
|
||||
<stop stop-color="#b9b9b9" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="m" y2="85.792" gradientUnits="userSpaceOnUse" x2="-60.735" gradientTransform="translate(2.16, -1.33)" y1="171.13" x1="-60.735">
|
||||
<stop stop-color="#ffff01" offset="0"/>
|
||||
<stop stop-color="#b9b9b9" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="n" y2="298.71" gradientUnits="userSpaceOnUse" x2="-105.42" y1="384.04" x1="-105.42">
|
||||
<stop stop-color="red" offset="0"/>
|
||||
<stop stop-color="#b9b9b9" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="o" y2="408.7" gradientUnits="userSpaceOnUse" x2="32.595" gradientTransform="translate(-3.45, -0.43)" y1="494.61" x1="32.595">
|
||||
<stop stop-color="lime" offset="0"/>
|
||||
<stop stop-color="#b9b9b9" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="p" y2="99.849" gradientUnits="userSpaceOnUse" x2="230.67" gradientTransform="translate(1.59, 1.61)" y1="171.13" x1="230.67">
|
||||
<stop stop-color="#F0F" offset="0"/>
|
||||
<stop stop-color="#b9b9b9" offset="1"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(-3.417, 1.068)">
|
||||
<g transform="matrix(0.6, 0, 0, 0.6, 83.43, -47.62)">
|
||||
<path fill-opacity="0.3" d="M-39.634,171.47c-31.743,31.66-49.227,73.53-49.227,117.89,0,92.35,75.02,167.48,167.23,167.48,92.218,0,167.25-75.13,167.25-167.48,0-92.06-75.03-166.96-167.25-166.96-44.38,0.01-86.288,17.43-118.01,49.07z" fill="#000"/>
|
||||
<path d="M-43.9,167.2c-31.744,31.66-49.228,73.53-49.228,117.89,0,92.35,75.02,167.48,167.23,167.48,92.225,0,167.24-75.13,167.24-167.48,0-92.06-75.02-166.96-167.24-166.96-44.38,0.01-86.287,17.43-118,49.07z" fill="url(#c)"/>
|
||||
<path d="M-39.03,172.09c-30.439,30.35-47.207,70.49-47.207,113,0,88.55,71.929,160.59,160.34,160.59,88.42,0,160.35-72.04,160.35-160.59,0-88.25-71.93-160.06-160.35-160.06-42.533,0.01-82.714,16.72-113.13,47.06z" fill="#b0d9ff"/>
|
||||
<path d="M74.105,440.51c85.675,0,155.18-69.8,155.18-155.42,0-85.08-69.51-154.88-155.18-154.88-85.068,0-155.16,69.8-155.16,154.88,0,85.62,70.098,155.42,155.16,155.42z" fill="#FFF"/>
|
||||
<path d="M74.105,440.51c85.675,0,155.18-69.8,155.18-155.42,0-85.08-69.51-154.88-155.18-154.88-85.068,0-155.16,69.8-155.16,154.88,0,85.62,70.098,155.42,155.16,155.42z" fill="url(#d)"/>
|
||||
<path d="M22.564,147.28c-0.767,0-1.608,0.31-2.467,0.8,2.019-0.59,2.969-0.8,2.467-0.8m49.961,9.74l0.502-7.31-7.712,0.49,1.019,6.82h6.191m-87.044,126.31c-1.554-1.46-0.512-7.81-0.512-7.81s-23.183-12.18-48.417-19.5c-3.111-0.9-1.541-7.31,1.539-9.74l-1.022-6.84c-0.512-3.41,5.157-19.99,10.82-21.44,5.669-1.47-0.517,9.74-0.517,9.74l-5.661,3.41s6.693,7.8,8.244,7.8c1.542,0,4.117-3.9,4.117-3.9l-7.207-4.87,6.695-2.93,0.422-2.57,1.125-0.36,11.087-16.79c7.662-3.14,17.08-7.02,18.276-7.59,2.064-0.97,16.478-9.26,19.056-11.2,2.5833-1.97,8.2368-1.47,10.292-1.47,2.072,0,5.157-0.98,5.669-6.35,0.514-5.36,2.578-6.34,4.127-4.87,1.549,1.45-1.549,3.9,2.061,4.87,3.602,0.98,6.69,3.42,9.273,0.98,1.881-1.78-0.638-3.82-2.336-5.35h28.599l3.096-8.8-6.695-0.97-24.735-2.43v-2.93l-1.971,0.33c2.679-14.71,18.58-12.29,6.608-20.8-0.729-0.53-11.203,16.5-13.869,16.17-4.83-0.64-11.067-0.69-12.395,0.88-1.7595,2.08,3.95-7.13,8.862-9.92-7.845,2.31-32.626,10.79-58.82,38.7-25.046,26.67-35.032,62.62-35.032,63.88,0,2.43,5.156,3.41,5.668,6.34,0.518,2.91-9.785,12.68-9.785,17.55,0,2.25-2.426,32.3,6.17,57.06,10.051,28.89,31.505,53.03,34.001,54.62l5.146-2.44s-11.847-20.97-12.359-22.93c-0.509-1.94,13.391-30.23,20.093-29.24,6.693,0.95,5.152,2.92,9.271,0.48,4.122-2.43,6.6951-22.44,11.332-24.38,4.6392-1.96,9.7853-4.39,9.2733-9.27-0.5378-4.89-18.047-13.66-19.589-15.12m111.77-143.37l-13.905-4.88,2.578,7.81,11.327-2.93m-52.022,18.04c1.552,0,32.449-20.47,29.359-20.96-3.08-0.49-3.598,0-11.854-0.98-8.229-0.98-16.993,11.7-19.049,13.66-2.061,1.95-1.366,8.28,1.544,8.28m141.8,147.04l3.99-5.18-3.99-1.4-2.99,3.76-3.48,5.16,2.99,1.41,3.48-3.75m17.45,16.93l-1-7.53h-6.48l-0.5,5.64-5.99-0.93-1.48-6.12-2.99-1.88-3.5,4.23-3.48-0.94-1,3.29,3.99,0.95v30.54l14.11,3.4c-0.33,0.56-0.57,1.03-0.65,1.29-1.01,3.29,3.98,4.72,7.46,3.29,1.3-0.51,5.4-4.66,7.98-10.8,3.59-8.54,6.73-19.82,7.36-23.8l1.61-3.45-9.97,3.75-5.49-0.93h0.02m20.94-56.88l-2.61-5.04c-3.08-17.39-10.15-39.64-25.3-62.64-22.8-34.57-86.26-54.51-86.26-54.51l-3.48,4.22-2-3.28-4.99-1.89v4.24l4.5,3.76-2.99,1.41-11.476,0.93-25.918,14.11,2.488,11.28-2.997,0.94-1.483,2.35,8.474,12.68,0.496,4.24-6.978,1.41v8.45l-3.986,0.94,0.5,6.58-33.906,23.52,0.999,13.14c2.488,3.29,21.935,23.04,21.935,23.04s22.429,0.92,27.413-1.88c4.987-2.82,1.493,2.82,2.995,4.23,1.488,1.42,1.989,11.28,3.482,12.22,1.495,0.93,0,6.57,1.994,8.46,1.991,1.87,1.991,24.44,1.991,24.44s11.967,20.2,11.967,25.37c0,5.18-0.504,4.7,8.97,4.24,9.48-0.47,11.47-4.24,13.45-5.64,2.01-1.41,2.01-4.7,4-7.52,2-2.83,5.48-13.63,9.98-17.39,4.48-3.77,16.45-6.59,17.43-13.16,1-6.58,5.49-11.75,5.49-11.75l21.55-22.8-0.6,3.06-0.5,11.74,6.48-2.34-0.49-12.7-2.33-2.46,0.33-0.36s-1.49-2.82-3.48-2.82-13.97,2.82-15.95,2.35c-2-0.47-10.48-23.03-11.97-23.96-1.5-0.94-10.97-16.46-10.97-16.46s21.93,26.32,25.43,36.66c2.02,6.02,9.63,0.41,15.82-5.87l1.64,4,3.98-0.95-0.5-4.7h4.48v7.05l-1.49,3.76-0.51,6.1,3.99,3.77,2-3.28,6.47-6.12,7.48-3.76,2,3.76,1,5.18-2,5.63-3.99,3.29-1.99,8.46v4.23l-4.48-2.82-0.49-8.93-6.49,0.48-2.99,7.98,4.49,6.59,10.46,1.41,8.48-8,1-15.49,3.77-4.98c2.45,6.31,4.21,12.92,4.21,19.08,0,6.74,3.08-4.68,0.46-25.26l1.52-2.02m-125.63-47.94l-26.917-0.95,11.46-9.39h5.983l9.474,6.57v3.77m32.913-3.29v4.23h-11.46l0.99,2.83-6.98,0.95-0.49,2.34-4.99-0.93-8.98-1.89,1.5-2.34,1.5-2.84,4.98-5.16,2,3.76,7.48-0.48,3.98-4.23,15.46,2.82-4.99,0.94m0.98-6.11l-5.97,0.94-1-4.24,7.47-0.93,1-4.23,5.5,5.65-7,2.8v0.01m28.93,146.16l-3.5,2.82,0.5,7.06h4.49v-6.1l3.99-5.18v-10.81l-2.5-0.48-2.98,12.69m-33.4-14.08s-3.49,0.91,0.49,2.33,19.94-23.01,19.94-23.01l-13.46,8.45-6.98,12.23h0.01m-27.14,90.07l-2.978-2.84-5.985-0.95-0.991,2.84-7.976-0.94-0.499-3.78h-5.98l-6.476,3.78h-11.458l-0.996-2.84-18.433-1.9-2.995,2.84-7.462-1.88-1.001-6.63-3.487-0.49-3.988,7.12-13.452-0.47c2.4088,1.13,22.491,13.12,53.301,15.61,40.856,3.31,60.296-6.62,60.296-6.62l-1.5-1.43-17.94-1.41v-0.01z" fill="url(#e)"/>
|
||||
<path d="M73.583,254c53.147,0,99.387-18.31,123.18-45.31-23.96-45.72-70.24-76.92-123.41-76.92-52.699,0-99.045,31.1-123.15,76.69,23.726,27.12,70.075,45.54,123.38,45.54z" fill="url(#f)"/>
|
||||
<path d="M141.67,229.84s3.61,4.33,8.13,10.17c19.53-7.86,35.75-18.61,46.96-31.32-7.94-15.15-18.35-28.7-30.64-40.06-25.84-16.6-54.87-25.73-54.87-25.73l-3.48,4.22-2-3.28-4.99-1.89v4.24l4.5,3.76-2.99,1.41-11.476,0.93-25.918,14.11,2.488,11.28-2.997,0.94-1.483,2.35,8.474,12.68,0.496,4.24-6.978,1.41v8.45l-3.986,0.94,0.5,6.58-33.906,23.52,0.803,10.55c14.209,3,29.423,4.66,45.276,4.66,27.537,0,53.187-4.94,74.847-13.44-3.12-4.76-6.76-10.72-6.76-10.72zm-41.883-12.69l-26.917-0.95,11.46-9.39h5.983l9.474,6.57v3.77zm32.913-3.29v4.23h-11.46l0.99,2.83-6.98,0.95-0.49,2.34-4.99-0.93-8.98-1.89,1.5-2.34,1.5-2.84,4.98-5.16,2,3.76,7.48-0.48,3.98-4.23,15.46,2.82-4.99,0.94zm0.98-6.12v0.01l-5.97,0.94-1-4.24,7.47-0.93,1-4.23,5.5,5.65-7,2.8z" fill="url(#g)"/>
|
||||
<path d="M-15.54,199.94c2.063-0.97,16.478-9.26,19.056-11.2,2.5833-1.97,8.2361-1.47,10.292-1.47,2.071,0,5.156-0.98,5.669-6.35,0.514-5.36,2.578-6.34,4.127-4.87,1.549,1.45-1.549,3.9,2.061,4.87,3.602,0.98,6.69,3.42,9.273,0.98,1.881-1.78-0.638-3.82-2.336-5.35h28.599l3.095-8.8-6.695-0.97-24.734-2.43v-2.93l-1.971,0.33c2.678-14.71,18.58-12.29,6.607-20.8-0.728-0.53-11.203,16.5-13.868,16.17-4.83-0.64-11.067-0.69-12.395,0.88-1.7598,2.08,3.95-7.13,8.862-9.92-6.106,1.8-22.478,7.38-41.781,22.9-11.17,10.8-20.701,23.45-28.121,37.48,2.789,3.19,5.918,6.25,9.309,9.18l6.674-10.11c7.663-3.13,17.083-7.02,18.277-7.59z" fill="url(#h)"/>
|
||||
<path d="M43.679,149.72c-2.059,1.95-1.364,8.28,1.546,8.28,1.552,0,32.449-20.47,29.359-20.96-3.08-0.49-3.598,0-11.854-0.98-8.232-0.98-16.996,11.7-19.051,13.66z" fill="url(#i)"/>
|
||||
<polygon points="126.07,73.444,123.08,73.631,123.47,76.284,125.88,76.284,125.88,76.285,126.07,73.444" transform="matrix(2.573, 0, 0, 2.573, -251.365, -39.26)" fill="url(#j)"/>
|
||||
<polygon points="135.49,69.653,130.08,67.756,131.08,70.792,135.49,69.653" transform="matrix(2.573, 0, 0, 2.573, -251.365, -39.26)" fill="url(#k)"/>
|
||||
</g>
|
||||
<g transform="matrix(0.6, 0, 0, 0.6, 83.43, -47.62)">
|
||||
<path d="M247.4,375.48l15.77,2.64c-2.02,5.79-5.23,10.19-9.6,13.21-4.38,3.02-9.85,4.54-16.42,4.54-10.4,0-18.1-3.4-23.09-10.2-3.95-5.44-5.92-12.32-5.92-20.61,0-9.92,2.59-17.68,7.78-23.3,5.18-5.61,11.73-8.42,19.65-8.42,8.9,0,15.92,2.94,21.07,8.82,5.14,5.88,7.6,14.88,7.38,27.01h-39.66c0.12,4.69,1.39,8.34,3.83,10.95,2.45,2.61,5.49,3.92,9.13,3.92,2.48,0,4.56-0.68,6.25-2.03s2.97-3.53,3.83-6.53zm0.9-16c-0.11-4.58-1.29-8.07-3.55-10.45-2.25-2.38-4.99-3.58-8.22-3.58-3.45,0-6.31,1.26-8.56,3.78-2.25,2.51-3.36,5.93-3.32,10.25h23.65zm-20.22-32.11l7.78-16.84h17.74l-15.49,16.84h-10.03z" stroke="#000064" stroke-width="10" fill="none"/>
|
||||
<path fill-opacity="0.3" d="M236.03,308.41l-1.72,3.71-7.78,16.85-3.06,6.62c-2.91,1.64-5.67,3.57-8,6.1-6.46,6.99-9.47,16.59-9.47,27.62,0,9.31,2.28,17.68,7.12,24.38l0.04,0.03c6.25,8.5,16.45,12.81,28.25,12.81,7.55,0,14.45-1.78,20.06-5.65,5.56-3.85,9.61-9.57,12-16.38l2.53-7.16-1.38-0.25,0.07-3.53c0.24-13.05-2.36-23.79-8.97-31.34-4.14-4.73-9.57-7.82-15.66-9.5l12.5-13.6,9.88-10.71h-36.41zm-2.75,36.59c-2.2,1.01-4.2,2.42-5.81,4.22-3.48,3.88-5.02,9.15-4.97,14.59l0.03,3.22h-0.47l0.16,6.56c0.14,5.78,1.85,11.19,5.56,15.16,1.5,1.6,3.33,2.86,5.28,3.84-4.13-1.16-7.22-3.21-9.59-6.43-3.04-4.2-4.66-9.56-4.66-16.85,0-8.8,2.16-14.7,6.07-18.93,2.5-2.72,5.24-4.41,8.4-5.38zm15.94,0.59c0.6,0.25,1.1,0.64,1.66,0.94-0.53-0.36-1.1-0.63-1.66-0.94zm1.72,0.97c1.9,1.05,3.63,2.35,5.15,4.1,2.93,3.34,4.95,8.71,5.57,16.37h-2.6l-0.09-3.44c-0.14-5.6-1.66-10.85-5.28-14.68-0.83-0.88-1.77-1.66-2.75-2.35zm-10.13,9.56c1.43,0.01,2.18,0.34,3.13,1.22h-6.44c0.91-0.86,1.7-1.21,3.31-1.22zm-3.78,23.72h7.75c-0.38,0.77-0.75,1.3-0.94,1.44-0.49,0.4-0.93,0.63-2.25,0.63-2.11,0-3.11-0.43-4.47-1.88-0.04-0.04-0.05-0.14-0.09-0.19zm18.53,7.07l1.97,0.31c-1,1.18-2.09,2.26-3.34,3.12-1.14,0.79-2.44,1.38-3.85,1.91,0.51-0.31,1.04-0.6,1.5-0.97,1.54-1.23,2.75-2.72,3.72-4.37z" fill="#000"/>
|
||||
<path d="M247.4,375.48l15.77,2.64c-2.02,5.79-5.23,10.19-9.6,13.21-4.38,3.02-9.85,4.54-16.42,4.54-10.4,0-18.1-3.4-23.09-10.2-3.95-5.44-5.92-12.32-5.92-20.61,0-9.92,2.59-17.68,7.78-23.3,5.18-5.61,11.73-8.42,19.65-8.42,8.9,0,15.92,2.94,21.07,8.82,5.14,5.88,7.6,14.88,7.38,27.01h-39.66c0.12,4.69,1.39,8.34,3.83,10.95,2.45,2.61,5.49,3.92,9.13,3.92,2.48,0,4.56-0.68,6.25-2.03s2.97-3.53,3.83-6.53zm0.9-16c-0.11-4.58-1.29-8.07-3.55-10.45-2.25-2.38-4.99-3.58-8.22-3.58-3.45,0-6.31,1.26-8.56,3.78-2.25,2.51-3.36,5.93-3.32,10.25h23.65zm-20.22-32.11l7.78-16.84h17.74l-15.49,16.84h-10.03z" fill="url(#l)"/>
|
||||
</g>
|
||||
<g transform="matrix(0.6, 0, 0, 0.6, 83.43, -47.62)">
|
||||
<path fill-opacity="0.3" d="M25.844,80.688c-3.427,0.201-6.099,1.831-7.969,3.968-0.97,1.099-1.8,2.437-2.344,4-2.276,0.558-4.235,1.611-5.656,3.032l-0.0312-0.032c-0.1083,0.101-0.2094,0.206-0.3126,0.313-0.0412,0.042-0.0845,0.081-0.125,0.125l-0.1562,0.156-0.125,0.156c-1.8144,2.203-3.1928,5.222-2.5625,9.034,0.4099,2.47,1.6306,4.23,2.9063,5.62-0.4704-0.02-0.9399-0.09-1.4063-0.09h-14.75c-0.0153-1.66-0.0326-3.43-0.0937-6.13v-2.871c0.0081-0.22,0.0081-0.218,0-0.438v-0.219c-0.2142-2.996-1.4385-6.385-4.5628-8.781-2.742-2.103-5.854-2.492-8.312-2.406v-0.063h-0.313c-2.23,0.081-5.351,0.632-8,2.782-3.122,2.534-4.187,5.874-4.187,9.125-0.004,0.146-0.004,0.135,0,0.281v0.188c0.148,2.732,0.27,5.532,0.344,8.342,0.001,0.07-0.002,0.12,0,0.19h-17.563c-2.952,0-6.189,0.93-8.719,3.78-2.285,2.57-2.885,5.66-2.968,7.91v0.03c-0.077,2.15,0.238,5.34,2.343,8.12,2.478,3.27,5.856,4.32,9,4.31h15.875c-1.561,6.33-4.261,11.82-8.281,16.69-3.494,4.25-8.049,8.02-13.844,11.28-2.61,1.47-5.285,3.91-6.437,7.66-0.904,2.94-0.651,5.87,0.594,8.59,0.075,0.17,0.135,0.34,0.218,0.5,0.133,0.32,0.25,0.63,0.25,0.63l0.063,0.09c0.007,0.01,0.024,0.02,0.031,0.03l0.031,0.07c-0.541-0.91-0.521-0.79,0.157,0.28l3.093,4.87,1.563-0.78c0.986,0.54,1.933,1.15,3.062,1.41,3.446,0.79,6.763,0.03,9.406-1.38l0.219-0.12,0.125-0.1c0.021-0.01,0.042-0.02,0.063-0.03,0.111-0.07,0.235-0.14,0.343-0.22v-0.03c10.4-6.22,18.697-14.33,24.75-24.03h0.376l1.812-3.34c3.595-6.66,6.063-14.07,7.6875-22.07h9.5625c-0.44,5.74-0.9,11.66-1.1562,14.1v0.09l-0.03,0.22c-0.5064,5.19-1.1158,9.15-1.5625,10.94-0.2162,0.78-0.4454,1.14-0.625,1.47h-6.4688c-2.9742,0-6.5122,0.82-9.3122,3.62-2.488,2.49-3.5,5.52-3.5,8.63-0.011,0.25-0.011,0.24,0,0.5v0.25c0.061,0.73,0.386,1.33,0.562,2l-1.344,1.34,4.532,4.53c1.718,1.72,1.831,1.74,0.187,0.16-0.202-0.2-0.188-0.18,0.063,0.06,2.71,2.56,6.053,3.5,9.156,3.5l7.2812,0.13h0.1876c6.6615,0,12.942-2.73,17.25-7.57h0.719l1.812-3.15,0.031-0.03c2.821-4.91,4.094-11.02,5.313-19.07l0.156-0.31,0.125-1.06c0.479-4.07,0.943-9.08,1.406-15.09,0.467-5.21,0.696-8.98,0.781-11.72,0.104-1.87-0.192-3.7-0.687-5.5,2.84,0.2,5.131-0.73,7.031-2l0.032,0.06c0.073-0.04,0.146-0.06,0.218-0.1l0.688-0.37,0.625-0.53c1.368-1.22,2.599-2.87,3.343-4.94,1.367-0.35,2.474-0.98,3.532-1.69l0.031,0.07c0.073-0.04,0.146-0.06,0.219-0.1l0.687-0.37,0.625-0.53c2.042-1.82,3.909-4.57,4.032-8.32,0.116-3.585-1.544-6.502-3.188-8.34l-0.062-0.062-0.094-0.094c-0.072-0.075-0.144-0.147-0.219-0.219-1.61-1.691-2.862-2.91-4.094-4.063l-0.093-0.093-0.094-0.094c-1.897-1.724-3.728-3.203-5.625-4.469-1.827-1.279-4.511-2.402-7.625-2.218zm-17.75,37.752c0.1539,0.02,0.9063,0.12,0.9062,0.12-0.0002,0,0.3432,0.11,0.625,0.19-0.3653-0.07-1.4337-0.29-1.5312-0.31zm-4.2188,1.34h0.1875c-0.3096,0.23-0.3931,0.27-0.625,0.44,0.0494-0.07,0.25-0.35,0.25-0.34,0,0,0.1622-0.09,0.1875-0.1zm8.063,0.78c0.02,0.01,0.042,0.02,0.062,0.03l-0.625,0.53,0.563-0.56zm0.843,0.53c0.027,0.03,0.037,0.07,0.063,0.1l-0.938,0.65,0.875-0.75zm0.5,0.69c0.093,0.16,0.184,0.31,0.25,0.5-0.048-0.08-0.113-0.26-0.25-0.5zm-11.594,1.03c-0.0233,0.11-0.0516,0.24-0.0937,0.44,0.0065-0.07,0.0312-0.34,0.0312-0.34s0.0587-0.09,0.0625-0.1zm11.906,4.28c-0.003,0.06-0.028,0.16-0.032,0.22-0.137,0.23-1,1.72-1,1.72,0.001,0-0.369,0.28-0.593,0.44,0.331-0.49,1.323-1.94,1.625-2.38zm-10.938,1.6c0.1258,0.16,0.316,0.33,0.4688,0.5l-0.0625,0.06c-0.0913-0.1-0.2038-0.23-0.25-0.28-0.1353-0.16-0.1402-0.2-0.1563-0.22-0.004,0-0.0291-0.03-0.0312-0.03l0.0312-0.03zm0.6876,0.75c0.1283,0.12,0.1857,0.25,0.3437,0.37-0.1548-0.12-0.3158-0.25-0.4063-0.34l0.0626-0.03zm0.5312,0.53c0.2412,0.19,0.5718,0.42,1.25,0.72-0.1829-0.08-0.3407-0.14-0.5938-0.28-0.0098-0.01-0.0212-0.03-0.0312-0.03,0.0002,0-0.4694-0.29-0.625-0.41zm7.031,0.25c-0.319,0.23-0.75,0.53-0.75,0.53s-0.3648,0.06-0.531,0.09c0.399-0.19,0.73-0.35,1.281-0.62z" fill="#000"/>
|
||||
<path d="M21.968,82.795c-1.392,0.082-2.666,0.824-3.531,1.812-0.889,1.008-1.555,2.502-1.312,4,0.242,1.499,1.174,2.603,2.218,3.438,1.879,1.503,3.31,2.692,4.219,3.531,1.214,1.143,2.159,2.174,2.906,3.125,0.021,0.032,0.041,0.063,0.063,0.094,0.933,1.088,2.154,1.985,3.687,2.185,1.534,0.21,3.014-0.43,4.094-1.341,0.021-0.01,0.042-0.021,0.063-0.032,1.018-0.905,1.857-2.235,1.906-3.75,0.049-1.514-0.646-2.818-1.563-3.843-0.02-0.021-0.041-0.042-0.062-0.063-1.559-1.636-2.918-2.965-4.094-4.062-0.01-0.011-0.021-0.021-0.031-0.032-1.741-1.582-3.356-2.893-4.875-3.906-1.063-0.744-2.266-1.24-3.688-1.156zm-45.968,5.406c-1.526,0.055-2.976,0.36-4.188,1.344-1.228,0.997-1.844,2.662-1.844,4.156-0.001,0.042-0.001,0.084,0,0.125,0.151,2.794,0.269,5.661,0.344,8.534,0.055,2.48,0.026,4.61,0,6.75h-23.969c-1.377,0-2.914,0.51-3.906,1.62-0.992,1.12-1.323,2.52-1.375,3.91-0.05,1.4,0.145,2.82,1.063,4.03,0.917,1.21,2.503,1.78,3.875,1.78h23.5c-1.118,10.52-4.697,19.55-10.969,27.16-4.045,4.91-9.235,9.18-15.625,12.78-1.585,0.89-2.932,2.22-3.469,3.97-0.472,1.53-0.261,3.32,0.563,4.72,0.003,0-0.004,0.02,0,0.03,0.023,0.04,0.037,0.08,0.062,0.12l0.063-0.03c0.814,1.38,2.219,2.37,3.718,2.72,1.664,0.38,3.407,0.04,4.938-0.78,0.032-0.02,0.063-0.04,0.094-0.06,10.928-6.45,19.303-14.87,24.937-25.19h0.031c3.976-7.36,6.576-15.91,8-25.44h20.688c0.9846,0,0.952,0.2,0.875,0.09,0.0205,0.03,0.0413,0.05,0.0625,0.07-0.1075-0.15,0.1515,0.24,0.0937,1.28-0.6844,9.66-1.2515,16.24-1.625,19.75v0.03c-0.5275,5.5-1.1278,9.6-1.75,12.09-0.76,2.76-1.7441,4.35-2.5937,5.07-0.021,0.01-0.0418,0.02-0.0625,0.03-0.8088,0.72-2.0336,1.22-4.125,1.22h-6.5309c-1.748,0-3.534,0.5-4.782,1.75-1.062,1.06-1.625,2.63-1.625,4.09-0.003,0.07-0.003,0.15,0,0.22,0.123,1.47,0.862,2.86,1.907,3.84l-0.032,0.03c0.027,0.03,0.067,0.04,0.094,0.07,0.011,0.01,0.021,0.02,0.031,0.03,1.262,1.19,3.032,1.75,4.75,1.75l7.4066,0.12h0.0313c6.2648,0,11.418-2.61,14.281-7.53h0.0313c2.1206-3.69,3.5126-9.5,4.7496-17.94,0.011-0.02,0.022-0.04,0.032-0.06,0.462-3.93,0.916-8.88,1.375-14.84,0.459-5.13,0.702-8.88,0.781-11.41,0.184-3.32-0.967-6.4-3.406-8.44v-0.03c-2.262-1.85-5.2882-2.62-8.7191-2.62h-21.188c0.036-1.59,0.094-3.12,0.094-4.88,0-1.65-0.049-4.14-0.125-7.498v-3.031c0.002-0.062,0.002-0.125,0-0.187-0.11-1.546-0.755-3.154-2.062-4.157-1.29-0.989-2.871-1.245-4.438-1.156h-0.062zm37.406,2.094c-1.368,0.121-2.581,0.835-3.4689,1.781-0.0431,0.04-0.0848,0.082-0.125,0.125-0.8348,1.014-1.4285,2.481-1.1875,3.938,0.2411,1.457,1.1663,2.537,2.1874,3.343,1.792,1.498,3.121,2.698,4.156,3.658,0.011,0.01,0.021,0.02,0.032,0.03,1.298,1.15,2.297,2.17,3,3.06,0.02,0.03,0.041,0.07,0.062,0.1,0.934,1.09,2.159,2,3.688,2.21,1.529,0.22,3.029-0.42,4.125-1.34,0.021-0.01,0.041-0.02,0.062-0.03,1.026-0.91,1.875-2.27,1.906-3.78,0.032-1.52-0.683-2.8-1.593-3.814-0.021-0.021-0.042-0.042-0.063-0.062-1.547-1.625-2.9-2.98-4.094-4.094-0.01-0.011-0.02-0.021-0.031-0.031-1.727-1.57-3.347-2.912-4.937-4-1.059-0.725-2.349-1.215-3.719-1.094z" stroke="#3c3c00" stroke-width="10" fill="none"/>
|
||||
<path d="M21.968,82.795c-1.392,0.082-2.666,0.824-3.531,1.812-0.889,1.008-1.555,2.502-1.312,4,0.242,1.499,1.174,2.603,2.218,3.438,1.879,1.503,3.31,2.692,4.219,3.531,1.214,1.143,2.159,2.174,2.906,3.125,0.021,0.032,0.041,0.063,0.063,0.094,0.933,1.088,2.154,1.985,3.687,2.185,1.534,0.21,3.014-0.43,4.094-1.341,0.021-0.01,0.042-0.021,0.063-0.032,1.018-0.905,1.857-2.235,1.906-3.75,0.049-1.514-0.646-2.818-1.563-3.843-0.02-0.021-0.041-0.042-0.062-0.063-1.559-1.636-2.918-2.965-4.094-4.062-0.01-0.011-0.021-0.021-0.031-0.032-1.741-1.582-3.356-2.893-4.875-3.906-1.063-0.744-2.266-1.24-3.688-1.156zm-45.968,5.406c-1.526,0.055-2.976,0.36-4.188,1.344-1.228,0.997-1.844,2.662-1.844,4.156-0.001,0.042-0.001,0.084,0,0.125,0.151,2.794,0.269,5.661,0.344,8.534,0.055,2.48,0.026,4.61,0,6.75h-23.969c-1.377,0-2.914,0.51-3.906,1.62-0.992,1.12-1.323,2.52-1.375,3.91-0.05,1.4,0.145,2.82,1.063,4.03,0.917,1.21,2.503,1.78,3.875,1.78h23.5c-1.118,10.52-4.697,19.55-10.969,27.16-4.045,4.91-9.235,9.18-15.625,12.78-1.585,0.89-2.932,2.22-3.469,3.97-0.472,1.53-0.261,3.32,0.563,4.72,0.003,0-0.004,0.02,0,0.03,0.023,0.04,0.037,0.08,0.062,0.12l0.063-0.03c0.814,1.38,2.219,2.37,3.718,2.72,1.664,0.38,3.407,0.04,4.938-0.78,0.032-0.02,0.063-0.04,0.094-0.06,10.928-6.45,19.303-14.87,24.937-25.19h0.031c3.976-7.36,6.576-15.91,8-25.44h20.688c0.9846,0,0.952,0.2,0.875,0.09,0.0205,0.03,0.0413,0.05,0.0625,0.07-0.1075-0.15,0.1515,0.24,0.0937,1.28-0.6844,9.66-1.2515,16.24-1.625,19.75v0.03c-0.5275,5.5-1.1278,9.6-1.75,12.09-0.76,2.76-1.7441,4.35-2.5937,5.07-0.021,0.01-0.0418,0.02-0.0625,0.03-0.8088,0.72-2.0336,1.22-4.125,1.22h-6.5309c-1.748,0-3.534,0.5-4.782,1.75-1.062,1.06-1.625,2.63-1.625,4.09-0.003,0.07-0.003,0.15,0,0.22,0.123,1.47,0.862,2.86,1.907,3.84l-0.032,0.03c0.027,0.03,0.067,0.04,0.094,0.07,0.011,0.01,0.021,0.02,0.031,0.03,1.262,1.19,3.032,1.75,4.75,1.75l7.4066,0.12h0.0313c6.2648,0,11.418-2.61,14.281-7.53h0.0313c2.1206-3.69,3.5126-9.5,4.7496-17.94,0.011-0.02,0.022-0.04,0.032-0.06,0.462-3.93,0.916-8.88,1.375-14.84,0.459-5.13,0.702-8.88,0.781-11.41,0.184-3.32-0.967-6.4-3.406-8.44v-0.03c-2.262-1.85-5.2882-2.62-8.7191-2.62h-21.188c0.036-1.59,0.094-3.12,0.094-4.88,0-1.65-0.049-4.14-0.125-7.498v-3.031c0.002-0.062,0.002-0.125,0-0.187-0.11-1.546-0.755-3.154-2.062-4.157-1.29-0.989-2.871-1.245-4.438-1.156h-0.062zm37.406,2.094c-1.368,0.121-2.581,0.835-3.4689,1.781-0.0431,0.04-0.0848,0.082-0.125,0.125-0.8348,1.014-1.4285,2.481-1.1875,3.938,0.2411,1.457,1.1663,2.537,2.1874,3.343,1.792,1.498,3.121,2.698,4.156,3.658,0.011,0.01,0.021,0.02,0.032,0.03,1.298,1.15,2.297,2.17,3,3.06,0.02,0.03,0.041,0.07,0.062,0.1,0.934,1.09,2.159,2,3.688,2.21,1.529,0.22,3.029-0.42,4.125-1.34,0.021-0.01,0.041-0.02,0.062-0.03,1.026-0.91,1.875-2.27,1.906-3.78,0.032-1.52-0.683-2.8-1.593-3.814-0.021-0.021-0.042-0.042-0.063-0.062-1.547-1.625-2.9-2.98-4.094-4.094-0.01-0.011-0.02-0.021-0.031-0.031-1.727-1.57-3.347-2.912-4.937-4-1.059-0.725-2.349-1.215-3.719-1.094z" fill="url(#m)"/>
|
||||
</g>
|
||||
<g transform="matrix(0.6, 0, 0, 0.6, 83.43, -47.62)">
|
||||
<path fill-opacity="0.3" d="M-61.025,286.89c-3.782,0-7.29,2.17-8.968,5.56-2.725,5.45-4,11.45-4,17.66,0.002,2.9,1.311,5.59,3.437,7.47l1,6.03c1.254,7.88,2.268,14.86,3.125,21.22,0.957,7.16,1.294,11.61,1.406,14.46-0.503,0.33-0.753,0.54-2.125,1.1-3.979,1.6-8.262,2.44-13.218,2.44-4.428,0-6.878-0.95-7.75-1.57-1.089-0.76-0.594,0.48-0.594-1.93,0-1.31,0.182-2.78,0.656-4.47,0.403-1.41,1.087-3.24,2.094-5.41,0.778-1.65,1.762-3.55,3.031-5.84,2.602-4.68,0.949-10.72-3.656-13.44l-1.688-1.03c-2.324-1.4-5.099-1.77-7.718-1.06-2.619,0.7-4.847,2.43-6.157,4.81-1.99,3.6-3.62,6.73-4.91,9.56-1.75,3.83-3.1,7.47-4.03,10.97-1.11,4.12-1.68,8.22-1.68,12.28,0,7.05,2.85,13.72,7.9,18.47v0.62l2.81,1.88c6.143,4.11,13.616,5.53,21.785,5.53,6.2,0,11.614-0.55,16.532-1.75h0.437l0.656-0.19,0.125-0.03,0.063-0.03c6.188-1.71,11.792-4.84,15.781-9.78l0.031-0.03c4.435-5.56,6.282-12.64,6.282-20.03,0-4.72-0.518-10.68-1.407-18.38-0.561-4.86-1.368-11.12-2.5-18.75v-0.03c-0.239-1.59-0.264-1.84-0.375-2.59,0.733-1.01,1.337-2.11,1.657-3.35,0.59-2.28,1.016-4.12,1.281-5.81,0.335-2.15,0.406-4.35,0.406-7.09-0.003-3.79-2.172-7.29-5.562-8.97-0.744-0.37-1.617-0.81-2.657-1.31-0.48-0.24-0.886-0.39-1.343-0.6-1.431-3.8-4.989-6.58-9.188-6.59h-0.969zm2.5,11.25h0.032c-0.007,0.01-0.025,0.02-0.032,0.03v-0.03zm1,6.37c0.79,0.35,1.549,0.68,2.407,1.1h0.031v0.03c0.334,0.16,0.597,0.28,0.906,0.44-0.038,1.29-0.061,2.76-0.156,3.37-0.103,0.66-0.436,1.97-0.719,3.16l-3.187,1.09-0.157-0.97-0.531-3.09-2.094-1.13c0.071-1.36,0.191-2.7,0.438-3.97l3.062-0.03zm4.938,2.35h0.031v0.03c-0.013-0.01-0.018-0.03-0.031-0.03zm-47.344,59.28c1.065,2.28,2.593,4.26,4.438,5.56,3.942,2.78,8.992,3.94,15.125,3.94,6.437,0,12.488-1.14,18.031-3.38,3.08-1.24,5.327-2.45,7.312-4.37,0.407-0.4,0.767-1.03,1.157-1.53-0.585,2.41-1.505,4.43-2.782,6.03-1.939,2.4-4.919,4.22-9.062,5.4l-0.188,0.07c-3.645,0.99-8.417,1.53-14.375,1.53-6.53,0-11.23-1.15-14.437-3.22l-0.219-0.16c-3.183-2.14-4.887-5.42-5-9.87z" fill="#000"/>
|
||||
<path d="M-63.656,295.12c-1.366,0.01-2.613,0.78-3.219,2-2.252,4.51-3.344,9.49-3.344,14.82,0.001,1.34,0.748,2.57,1.938,3.18l0.937,0.5,1.469,8.76c1.262,7.93,2.292,15.03,3.156,21.43,1.113,8.33,1.656,14.29,1.657,17.41-0.001,0.55-0.107,1.01-1.032,1.9-0.924,0.9-2.69,1.99-5.281,3.04-4.761,1.91-9.928,2.9-15.625,2.9-5.28,0-9.03-1.05-11.438-2.75-2.331-1.64-3.312-3.57-3.312-7.15,0-1.96,0.297-4.01,0.906-6.19,0.512-1.79,1.306-3.94,2.438-6.38,0.868-1.84,1.945-3.88,3.25-6.25,0.948-1.7,0.365-3.85-1.313-4.84l-1.719-1.03c-0.836-0.5-1.842-0.65-2.785-0.39-0.943,0.25-1.743,0.88-2.215,1.73-1.942,3.52-3.502,6.53-4.692,9.13-1.62,3.55-2.83,6.87-3.65,9.97-0.98,3.63-1.47,7.17-1.47,10.62,0,6.5,2.76,12.18,7.88,15.63-0.01,0.01-0.01,0.02,0,0.03,4.669,3.13,10.796,4.44,18.214,4.43,6.324,0,11.633-0.54,16.062-1.74h0.032c5.224-1.45,9.549-3.97,12.531-7.66,3.326-4.17,4.875-9.67,4.875-16.03,0-4.25-0.468-10.07-1.344-17.66-0.55-4.76-1.375-10.95-2.5-18.53-0.547-3.63-0.617-4.16-0.875-6,1.142-0.39,2.01-1.33,2.313-2.5,0.563-2.18,0.948-3.89,1.156-5.22,0.239-1.53,0.312-3.47,0.312-6.09-0.001-1.37-0.776-2.62-2-3.22-0.754-0.38-1.612-0.81-2.594-1.28-1.378-0.67-2.668-1.25-3.874-1.75h-0.032c0.001-0.03-0.201-0.54-0.312-1.6-0.193-1.82-1.728-3.21-3.563-3.22h-0.937z" transform="translate(-1.63, -6.1)" stroke="#510000" stroke-width="10" fill="none"/>
|
||||
<path transform="translate(-1.63, -6.1)" d="M-63.656,295.12c-1.366,0.01-2.613,0.78-3.219,2-2.252,4.51-3.344,9.49-3.344,14.82,0.001,1.34,0.748,2.57,1.938,3.18l0.937,0.5,1.469,8.76c1.262,7.93,2.292,15.03,3.156,21.43,1.113,8.33,1.656,14.29,1.657,17.41-0.001,0.55-0.107,1.01-1.032,1.9-0.924,0.9-2.69,1.99-5.281,3.04-4.761,1.91-9.928,2.9-15.625,2.9-5.28,0-9.03-1.05-11.438-2.75-2.331-1.64-3.312-3.57-3.312-7.15,0-1.96,0.297-4.01,0.906-6.19,0.512-1.79,1.306-3.94,2.438-6.38,0.868-1.84,1.945-3.88,3.25-6.25,0.948-1.7,0.365-3.85-1.313-4.84l-1.719-1.03c-0.836-0.5-1.842-0.65-2.785-0.39-0.943,0.25-1.743,0.88-2.215,1.73-1.942,3.52-3.502,6.53-4.692,9.13-1.62,3.55-2.83,6.87-3.65,9.97-0.98,3.63-1.47,7.17-1.47,10.62,0,6.5,2.76,12.18,7.88,15.63-0.01,0.01-0.01,0.02,0,0.03,4.669,3.13,10.796,4.44,18.214,4.43,6.324,0,11.633-0.54,16.062-1.74h0.032c5.224-1.45,9.549-3.97,12.531-7.66,3.326-4.17,4.875-9.67,4.875-16.03,0-4.25-0.468-10.07-1.344-17.66-0.55-4.76-1.375-10.95-2.5-18.53-0.547-3.63-0.617-4.16-0.875-6,1.142-0.39,2.01-1.33,2.313-2.5,0.563-2.18,0.948-3.89,1.156-5.22,0.239-1.53,0.312-3.47,0.312-6.09-0.001-1.37-0.776-2.62-2-3.22-0.754-0.38-1.612-0.81-2.594-1.28-1.378-0.67-2.668-1.25-3.874-1.75h-0.032c0.001-0.03-0.201-0.54-0.312-1.6-0.193-1.82-1.728-3.21-3.563-3.22h-0.937z" fill="url(#n)"/>
|
||||
</g>
|
||||
<g transform="matrix(0.6, 0, 0, 0.6, 83.43, -47.62)">
|
||||
<path fill-opacity="0.3" d="M84.844,406.06c-1.134,0.12-2.236,0.56-3.25,1.25-2.029,1.38-3.196,3.74-3.063,6.19,0.174,5.03,0.324,11.84,0.5,18.62h-3.937l-1.406-1.24c0.945-0.89,1.658-2.03,2-3.32,0.671-2.53-0.141-5.28-2.094-7.03l-0.094-0.09-0.125-0.1-6.156-5.06c-1.462-1.3-3.212-1.76-5.157-1.56-0.608-0.95-1.353-1.81-2.374-2.38l-7.032-4.25c-1.169-0.73-2.433-1.03-3.812-1h-0.032c-3.379,0.1-6.28,2.69-6.75,6.03,0.078-0.54-0.176,0.75-0.812,2.35-0.636,1.59-1.628,3.76-2.906,6.44-2.398,5.01-6.437,11.81-12.094,20.06-1.892,2.72-1.551,6.46,0.75,8.84l0.031,0.03,0.031,0.04,1.094,1.09c1.083,1.09,2.488,1.66,3.938,1.87-0.042,8.6-0.07,18.19-0.219,22.94v0.03c-0.029,1.03,0.291,1.99,0.687,2.91-0.999,3.22-2.13,5.28-2.093,5.25-1.466,1.29-3.047,2.89-3.907,5.47-1.038,3.11-0.225,6.71,2.126,9.06,2.968,2.97,8.227,3.76,11.937,1.91,1.539-0.77,2.807-1.85,3.875-3.07,2.082,1.47,4.625,1.82,6.625,1.54,1.928-0.28,3.638-1.36,5.094-2.69,0.346,0.2,0.676,0.45,1.031,0.59-0.108,1.44,0.166,2.93,0.969,4.25l0.062,0.09,0.063,0.1,0.718,1.09c2.045,3.15,6.379,4.08,9.563,2.1,7.964-4.74,14.225-11.13,18.937-18.88v2.44c0,3.22,0.735,6.66,3.094,9.47,2.405,2.86,5.991,4.2,9.282,4.4h0.252c0.12,0.01,0.23,0.01,0.34,0h11.06c5.8,0,11.08-4.17,13.29-9.31,0.95-2.06,0.78-4.28-0.35-6.25-0.64-1.12-1.61-1.95-2.72-2.56-0.19-2.55-0.31-5.72-0.31-9.84,0.02-1.89-0.73-3.64-2.06-4.97-1.34-1.34-3.18-2.09-5.06-2.07h-1.72c-2.79-0.03-5.22,1.65-6.35,4.07v-22.94h12.13c2.86,0.05,5.41-1.69,6.5-4.35,1.09-2.65,0.44-5.73-1.63-7.71l-6.03-6.07c-0.43-0.43-0.98-0.69-1.5-1-0.14-2.99-1.36-5.84-3.06-7.96-3-3.75-7.01-5.8-12.69-8.38-0.143-0.07-0.294-0.04-0.436-0.09-0.658-0.82-1.432-1.58-2.406-2.03l-0.126-0.07-0.124-0.03-8.688-3.62c-1.113-0.52-2.272-0.72-3.406-0.6zm-5.813,42.6c-0.196,5.17-0.706,10.05-1.75,14.46-0.072-4-0.164-8.36-0.187-14.12,0.509-0.04,0.999-0.09,1.5-0.25l0.062-0.03h0.063c0.085-0.03,0.225-0.04,0.312-0.06z" fill="#000"/>
|
||||
<path d="M44.734,408.22c-0.301,0.01-0.552,0.23-0.593,0.53-0.21,1.47-1.637,5.13-4.282,10.66-2.628,5.5-6.819,12.48-12.593,20.91-0.169,0.24-0.143,0.56,0.062,0.78l1.094,1.09c0.229,0.23,0.598,0.25,0.844,0.03,1.939-1.74,3.586-3.5,5.062-5.25-0.009,15.45-0.083,27.42-0.312,34.75-0.007,0.22,0.104,0.43,0.291,0.54,0.187,0.12,0.421,0.13,0.615,0.02l4.687-2.53c0.204-0.1,0.336-0.3,0.344-0.53v-2.62h20.438v3.97c-0.06-0.03-0.097-0.07-0.157-0.1-0.286-0.15-0.641-0.05-0.812,0.22l-0.719,1.09c-0.152,0.24-0.126,0.55,0.063,0.75,1.673,1.92,2.84,3.45,3.531,4.6,0.687,1.14,1.345,2.7,1.937,4.59,0.325,1.04,0.759,1.82,1.469,2.22s1.604,0.24,2.375-0.25c0.324-0.21,0.57-0.47,0.813-0.75-2.695,3.53-5.749,6.78-9.313,9.69-0.253,0.19-0.32,0.54-0.156,0.81l0.719,1.09c0.183,0.29,0.558,0.37,0.843,0.19,17.903-10.64,26.682-29.9,26.344-57.4h2.375v46.37c0,2.26,0.507,4.08,1.594,5.38,1.086,1.29,2.737,1.99,4.781,2.12h11.252c3.35,0,5.9-1.92,7.4-5.44,0.09-0.18,0.08-0.39-0.02-0.56-0.1-0.18-0.28-0.29-0.48-0.31-0.95-0.11-1.59-0.47-2.09-1.13s-0.82-1.66-0.94-3.03c-0.24-2.87-0.37-6.56-0.37-11.12,0-0.17-0.07-0.33-0.18-0.45-0.12-0.12-0.28-0.18-0.45-0.18h-1.81c-0.33,0-0.61,0.26-0.62,0.6-0.25,5.29-0.55,9.38-0.91,12.25-0.17,1.37-0.53,2.34-1,2.93s-1,0.85-1.81,0.85h-4.03c-1.827,0.22-2.995-0.07-3.661-0.78-0.666-0.72-0.949-2.02-0.718-3.97,0.001-0.02,0.001-0.05,0-0.07v-43.46h18.529c0.26,0,0.49-0.15,0.58-0.39,0.1-0.23,0.04-0.5-0.14-0.68l-6.13-6.15c-0.11-0.12-0.27-0.19-0.43-0.19-0.17,0-0.32,0.07-0.44,0.19l-4.16,4.15h-16.122v-19.31l2.969-1.97c0.179-0.13,0.278-0.34,0.258-0.56-0.019-0.22-0.153-0.41-0.352-0.5l-8.687-3.63c-0.197-0.09-0.427-0.07-0.606,0.05s-0.281,0.33-0.269,0.55c0.235,6.82,0.482,15.34,0.718,25.37h-12c-0.238,0-0.457,0.13-0.562,0.35l-5.188-4.53c-0.128-0.11-0.292-0.16-0.457-0.14-0.164,0.02-0.315,0.1-0.418,0.23l-2.718,3.37h-7.094c2.095-2.77,3.962-5.22,5.312-6.84,1.548-1.86,2.694-2.98,3.094-3.22,1.15-0.69,2.306-1.15,3.438-1.37,0.226-0.05,0.406-0.22,0.465-0.45,0.06-0.22-0.012-0.46-0.184-0.62l-6.156-5.06c-0.13-0.11-0.302-0.17-0.474-0.15-0.173,0.02-0.33,0.11-0.433,0.25l-2.343,3h-8.688c0.965-1.64,1.886-3,2.688-3.85,0.961-1.02,1.763-1.4,2.343-1.4,0.284,0,0.534-0.19,0.608-0.46s-0.048-0.56-0.295-0.7l-7.219-4.34c-0.103-0.07-0.222-0.1-0.344-0.1zm48.094,5.78c-0.154,0.01-0.299,0.08-0.406,0.19l-1.094,1.09c-0.119,0.13-0.179,0.3-0.168,0.47,0.012,0.17,0.096,0.33,0.231,0.44,3.795,3.08,6.048,6.14,6.843,9.09,0.432,1.61,0.907,2.79,1.5,3.6,0.296,0.4,0.626,0.72,1.036,0.9,0.4,0.19,0.88,0.23,1.31,0.1,1.44-0.44,2.42-1.73,2.94-3.53,0.54-1.9-0.04-3.85-1.57-5.75-1.59-1.99-5.003-4.11-10.341-6.53-0.087-0.05-0.184-0.07-0.281-0.07zm-47.75,8.13h9.531l-5.562,11.4h-8.094l-2.562-1.71c2.227-2.93,4.462-6.15,6.687-9.69zm24.438,13.81l2.281,2.28c0.162,0.17,0.404,0.23,0.625,0.16,2.098-0.7,4.468-1.06,7.062-1.06h1.907c0.622,18.59-3.482,33.69-12.282,45.37,0.239-0.33,0.435-0.72,0.563-1.12,0.278-0.89,0.285-1.89,0.094-3.04-0.221-1.32-1.188-2.59-2.782-3.9-1.344-1.11-3.247-2.29-5.531-3.5l4.875-2.06c0.236-0.11,0.386-0.34,0.375-0.6-0.238-6.18-0.342-16.38-0.344-30.37l2.969-2c0.072-0.04,0.136-0.1,0.188-0.16zm-29.563,0.66h7.438v11.75h-7.438v-11.75zm13.031,0h7.407v11.75h-7.407v-11.75zm-13.031,14.81h7.438v12.12h-7.438v-12.12zm13.031,0h7.407v12.12h-7.407v-12.12zm-1.812,20.09c-0.089,0.02-0.175,0.05-0.25,0.1l-1.094,0.72c-0.282,0.18-0.365,0.55-0.187,0.84,0.953,1.67,1.786,3.33,2.5,5,0.7,1.63,1.238,3.49,1.593,5.62,0.193,1.16,0.497,2.05,1.157,2.57,0.659,0.52,1.595,0.48,2.437,0.06,1.68-0.84,2.471-2.67,2.344-5.09-0.072-1.37-0.845-2.79-2.188-4.38s-3.29-3.37-5.843-5.31c-0.133-0.11-0.302-0.15-0.469-0.13zm-8.656,1.44c-0.144,0.02-0.276,0.08-0.375,0.19l-0.719,0.72c-0.167,0.17-0.216,0.43-0.125,0.65,0.466,1.17,0.894,2.59,1.25,4.25,0.345,1.62,0.431,3.56,0.312,5.82-0.064,1.22,0.113,2.2,0.657,2.9,0.543,0.7,1.46,0.95,2.437,0.81,0.993-0.14,1.811-0.67,2.344-1.5,0.532-0.82,0.811-1.91,0.875-3.25,0.137-2.88-2.012-6.26-6.156-10.4-0.13-0.14-0.314-0.21-0.5-0.19zm-6.875,0.72c-0.256,0.04-0.455,0.24-0.5,0.5-1.192,5.24-2.85,8.69-4.719,10.34-1.067,0.94-1.765,1.8-2.063,2.69s-0.075,1.86,0.594,2.53c1.23,1.23,2.914,1.5,4.531,0.69,1.597-0.8,2.767-2.25,3.532-4.16,0.816-2.04,1.023-5.81,0.781-11.62-0.016-0.27-0.206-0.5-0.469-0.56l-1.437-0.38c-0.081-0.03-0.166-0.04-0.25-0.03z" stroke="#003c00" stroke-width="10" fill="none"/>
|
||||
<path d="M44.734,408.22c-0.301,0.01-0.552,0.23-0.593,0.53-0.21,1.47-1.637,5.13-4.282,10.66-2.628,5.5-6.819,12.48-12.593,20.91-0.169,0.24-0.143,0.56,0.062,0.78l1.094,1.09c0.229,0.23,0.598,0.25,0.844,0.03,1.939-1.74,3.586-3.5,5.062-5.25-0.009,15.45-0.083,27.42-0.312,34.75-0.007,0.22,0.104,0.43,0.291,0.54,0.187,0.12,0.421,0.13,0.615,0.02l4.687-2.53c0.204-0.1,0.336-0.3,0.344-0.53v-2.62h20.438v3.97c-0.06-0.03-0.097-0.07-0.157-0.1-0.286-0.15-0.641-0.05-0.812,0.22l-0.719,1.09c-0.152,0.24-0.126,0.55,0.063,0.75,1.673,1.92,2.84,3.45,3.531,4.6,0.687,1.14,1.345,2.7,1.937,4.59,0.325,1.04,0.759,1.82,1.469,2.22s1.604,0.24,2.375-0.25c0.324-0.21,0.57-0.47,0.813-0.75-2.695,3.53-5.749,6.78-9.313,9.69-0.253,0.19-0.32,0.54-0.156,0.81l0.719,1.09c0.183,0.29,0.558,0.37,0.843,0.19,17.903-10.64,26.682-29.9,26.344-57.4h2.375v46.37c0,2.26,0.507,4.08,1.594,5.38,1.086,1.29,2.737,1.99,4.781,2.12h11.252c3.35,0,5.9-1.92,7.4-5.44,0.09-0.18,0.08-0.39-0.02-0.56-0.1-0.18-0.28-0.29-0.48-0.31-0.95-0.11-1.59-0.47-2.09-1.13s-0.82-1.66-0.94-3.03c-0.24-2.87-0.37-6.56-0.37-11.12,0-0.17-0.07-0.33-0.18-0.45-0.12-0.12-0.28-0.18-0.45-0.18h-1.81c-0.33,0-0.61,0.26-0.62,0.6-0.25,5.29-0.55,9.38-0.91,12.25-0.17,1.37-0.53,2.34-1,2.93s-1,0.85-1.81,0.85h-4.03c-1.827,0.22-2.995-0.07-3.661-0.78-0.666-0.72-0.949-2.02-0.718-3.97,0.001-0.02,0.001-0.05,0-0.07v-43.46h18.529c0.26,0,0.49-0.15,0.58-0.39,0.1-0.23,0.04-0.5-0.14-0.68l-6.13-6.15c-0.11-0.12-0.27-0.19-0.43-0.19-0.17,0-0.32,0.07-0.44,0.19l-4.16,4.15h-16.122v-19.31l2.969-1.97c0.179-0.13,0.278-0.34,0.258-0.56-0.019-0.22-0.153-0.41-0.352-0.5l-8.687-3.63c-0.197-0.09-0.427-0.07-0.606,0.05s-0.281,0.33-0.269,0.55c0.235,6.82,0.482,15.34,0.718,25.37h-12c-0.238,0-0.457,0.13-0.562,0.35l-5.188-4.53c-0.128-0.11-0.292-0.16-0.457-0.14-0.164,0.02-0.315,0.1-0.418,0.23l-2.718,3.37h-7.094c2.095-2.77,3.962-5.22,5.312-6.84,1.548-1.86,2.694-2.98,3.094-3.22,1.15-0.69,2.306-1.15,3.438-1.37,0.226-0.05,0.406-0.22,0.465-0.45,0.06-0.22-0.012-0.46-0.184-0.62l-6.156-5.06c-0.13-0.11-0.302-0.17-0.474-0.15-0.173,0.02-0.33,0.11-0.433,0.25l-2.343,3h-8.688c0.965-1.64,1.886-3,2.688-3.85,0.961-1.02,1.763-1.4,2.343-1.4,0.284,0,0.534-0.19,0.608-0.46s-0.048-0.56-0.295-0.7l-7.219-4.34c-0.103-0.07-0.222-0.1-0.344-0.1zm48.094,5.78c-0.154,0.01-0.299,0.08-0.406,0.19l-1.094,1.09c-0.119,0.13-0.179,0.3-0.168,0.47,0.012,0.17,0.096,0.33,0.231,0.44,3.795,3.08,6.048,6.14,6.843,9.09,0.432,1.61,0.907,2.79,1.5,3.6,0.296,0.4,0.626,0.72,1.036,0.9,0.4,0.19,0.88,0.23,1.31,0.1,1.44-0.44,2.42-1.73,2.94-3.53,0.54-1.9-0.04-3.85-1.57-5.75-1.59-1.99-5.003-4.11-10.341-6.53-0.087-0.05-0.184-0.07-0.281-0.07zm-47.75,8.13h9.531l-5.562,11.4h-8.094l-2.562-1.71c2.227-2.93,4.462-6.15,6.687-9.69zm24.438,13.81l2.281,2.28c0.162,0.17,0.404,0.23,0.625,0.16,2.098-0.7,4.468-1.06,7.062-1.06h1.907c0.622,18.59-3.482,33.69-12.282,45.37,0.239-0.33,0.435-0.72,0.563-1.12,0.278-0.89,0.285-1.89,0.094-3.04-0.221-1.32-1.188-2.59-2.782-3.9-1.344-1.11-3.247-2.29-5.531-3.5l4.875-2.06c0.236-0.11,0.386-0.34,0.375-0.6-0.238-6.18-0.342-16.38-0.344-30.37l2.969-2c0.072-0.04,0.136-0.1,0.188-0.16zm-29.563,0.66h7.438v11.75h-7.438v-11.75zm13.031,0h7.407v11.75h-7.407v-11.75zm-13.031,14.81h7.438v12.12h-7.438v-12.12zm13.031,0h7.407v12.12h-7.407v-12.12zm-1.812,20.09c-0.089,0.02-0.175,0.05-0.25,0.1l-1.094,0.72c-0.282,0.18-0.365,0.55-0.187,0.84,0.953,1.67,1.786,3.33,2.5,5,0.7,1.63,1.238,3.49,1.593,5.62,0.193,1.16,0.497,2.05,1.157,2.57,0.659,0.52,1.595,0.48,2.437,0.06,1.68-0.84,2.471-2.67,2.344-5.09-0.072-1.37-0.845-2.79-2.188-4.38s-3.29-3.37-5.843-5.31c-0.133-0.11-0.302-0.15-0.469-0.13zm-8.656,1.44c-0.144,0.02-0.276,0.08-0.375,0.19l-0.719,0.72c-0.167,0.17-0.216,0.43-0.125,0.65,0.466,1.17,0.894,2.59,1.25,4.25,0.345,1.62,0.431,3.56,0.312,5.82-0.064,1.22,0.113,2.2,0.657,2.9,0.543,0.7,1.46,0.95,2.437,0.81,0.993-0.14,1.811-0.67,2.344-1.5,0.532-0.82,0.811-1.91,0.875-3.25,0.137-2.88-2.012-6.26-6.156-10.4-0.13-0.14-0.314-0.21-0.5-0.19zm-6.875,0.72c-0.256,0.04-0.455,0.24-0.5,0.5-1.192,5.24-2.85,8.69-4.719,10.34-1.067,0.94-1.765,1.8-2.063,2.69s-0.075,1.86,0.594,2.53c1.23,1.23,2.914,1.5,4.531,0.69,1.597-0.8,2.767-2.25,3.532-4.16,0.816-2.04,1.023-5.81,0.781-11.62-0.016-0.27-0.206-0.5-0.469-0.56l-1.437-0.38c-0.081-0.03-0.166-0.04-0.25-0.03z" fill="url(#o)"/>
|
||||
</g>
|
||||
<g transform="matrix(0.6, 0, 0, 0.6, 83.43, -47.62)">
|
||||
<path fill-opacity="0.3" d="M208.28,99.312c-9.25,0.001-16.95,1.548-22.87,5.718-5.68,4-9.54,10.17-11.6,17.53l-1.87,6.78,6.9,1.25,7.72,1.41c-0.33,0.15-0.77,0.25-1.09,0.41-4.18,2.02-7.7,5.14-10.09,9.06-2.4,3.92-3.57,8.51-3.57,13.22,0,7.06,2.76,13.73,7.81,18.5,5.22,4.91,12.4,7.19,20.29,7.19,4.61,0,9.11-0.88,13.28-2.66,1.26-0.54,2.42-1.31,3.62-2l1.25,3.19h31.69l-4.47-9.19c-1.33-2.73-2.17-5.18-2.59-7.25-0.38-1.87-0.69-5.87-0.69-11.41l0.16-20.12v-0.06c0-7.95-0.41-13.62-3.1-18.54-2.31-4.23-6.15-7.42-10.78-9.65-5.31-2.57-11.79-3.377-20-3.378zm0,12.808c7.2,0.01,12.2,1.02,14.44,2.1,2.92,1.41,4.36,2.86,5.12,4.25,0.39,0.7,1.53,5.34,1.54,12.41l-0.19,20.12v0.06c0,5.95,0.24,10.39,0.97,13.97,0.07,0.36,0.22,0.73,0.31,1.09h-3.41c-0.06-0.22-0.09-0.26-0.15-0.5-0.31-1.08-0.44-1.65-0.75-2.5l-2.6-6.9c0.2-0.49,0.54-0.9,0.69-1.41,0.94-3.07,0.94-5.84,0.94-10.22v-16.43c0-4.38-1.17-8.91-4.69-11.94-3.86-3.33-8.22-3.69-13.44-3.69-3.91,0-7.68,0.76-10.87,3-1.72,1.21-3.04,2.73-4.13,4.44l-3.03-0.56c1.08-1.63,2.34-2.91,3.75-3.91,2.69-1.89,7.78-3.37,15.5-3.38zm-1.22,13.22c1.61,0,2.63,0.2,3.5,0.38-2.14,0.54-5.01,1.15-8.03,1.75,0.47-0.85,0.89-1.39,1-1.47,0.26-0.18,1.3-0.66,3.53-0.66zm-13.47,17.66c-2.66,2.57-4.5,6.2-4.5,9.91,0,4.01,1.78,8.05,4.63,10.84,1.89,1.84,4.29,3.08,6.84,3.78-0.22,0.01-0.42,0.06-0.65,0.06-5.57,0-8.97-1.36-11.5-3.75-2.69-2.53-3.82-5.06-3.82-9.15,0-2.67,0.59-4.71,1.72-6.57,1.14-1.86,2.57-3.13,4.75-4.18,0.61-0.3,1.67-0.63,2.53-0.94zm18.5,6.44c-0.03,0.33-0.1,1.75-0.09,1.72v0.03l-0.03,0.03c-0.26,0.88-0.62,1.51-1.78,2.37-1.93,1.4-3.38,1.82-5.1,1.82-1.44,0-1.81-0.21-2.43-0.82-0.76-0.74-0.78-0.86-0.78-1.68,0-0.51-0.31-0.18,0.68-0.88-0.33,0.22,2.55-1,7.06-1.97,1.09-0.23,1.51-0.41,2.47-0.62z" fill="#000"/>
|
||||
<path d="M191.4,122.86l-15.68-2.83c1.76-6.31,4.8-10.99,9.1-14.02,4.31-3.04,10.7-4.55,19.19-4.55,7.71,0,13.45,0.91,17.22,2.73,3.77,1.83,6.43,4.14,7.97,6.95,1.53,2.81,2.3,7.97,2.3,15.47l-0.18,20.17c0,5.74,0.28,9.98,0.83,12.7,0.55,2.73,1.59,5.65,3.1,8.77h-17.09c-0.45-1.15-1.01-2.85-1.66-5.11-0.29-1.02-0.5-1.7-0.62-2.03-2.95,2.87-6.11,5.03-9.47,6.46-3.36,1.44-6.95,2.15-10.76,2.15-6.73,0-12.03-1.82-15.9-5.47-3.88-3.65-5.81-8.26-5.81-13.84,0-3.69,0.88-6.98,2.64-9.87,1.77-2.89,4.24-5.1,7.41-6.64,3.18-1.54,7.76-2.88,13.75-4.03,8.08-1.52,13.67-2.93,16.79-4.24v-1.73c0-3.32-0.82-5.68-2.46-7.1-1.64-1.41-4.74-2.12-9.29-2.12-3.07,0-5.47,0.6-7.19,1.81-1.73,1.21-3.12,3.33-4.19,6.37zm23.13,14.02c-2.22,0.74-5.72,1.62-10.52,2.65-4.8,1.02-7.93,2.03-9.41,3.01-2.25,1.6-3.38,3.63-3.38,6.09,0,2.42,0.9,4.51,2.71,6.27,1.8,1.76,4.1,2.65,6.88,2.65,3.12,0,6.09-1.03,8.92-3.08,2.09-1.56,3.47-3.46,4.12-5.72,0.45-1.48,0.68-4.28,0.68-8.42v-3.45z" stroke="#500050" stroke-width="10" fill="none"/>
|
||||
<path d="M191.4,122.86l-15.68-2.83c1.76-6.31,4.8-10.99,9.1-14.02,4.31-3.04,10.7-4.55,19.19-4.55,7.71,0,13.45,0.91,17.22,2.73,3.77,1.83,6.43,4.14,7.97,6.95,1.53,2.81,2.3,7.97,2.3,15.47l-0.18,20.17c0,5.74,0.28,9.98,0.83,12.7,0.55,2.73,1.59,5.65,3.1,8.77h-17.09c-0.45-1.15-1.01-2.85-1.66-5.11-0.29-1.02-0.5-1.7-0.62-2.03-2.95,2.87-6.11,5.03-9.47,6.46-3.36,1.44-6.95,2.15-10.76,2.15-6.73,0-12.03-1.82-15.9-5.47-3.88-3.65-5.81-8.26-5.81-13.84,0-3.69,0.88-6.98,2.64-9.87,1.77-2.89,4.24-5.1,7.41-6.64,3.18-1.54,7.76-2.88,13.75-4.03,8.08-1.52,13.67-2.93,16.79-4.24v-1.73c0-3.32-0.82-5.68-2.46-7.1-1.64-1.41-4.74-2.12-9.29-2.12-3.07,0-5.47,0.6-7.19,1.81-1.73,1.21-3.12,3.33-4.19,6.37zm23.13,14.02c-2.22,0.74-5.72,1.62-10.52,2.65-4.8,1.02-7.93,2.03-9.41,3.01-2.25,1.6-3.38,3.63-3.38,6.09,0,2.42,0.9,4.51,2.71,6.27,1.8,1.76,4.1,2.65,6.88,2.65,3.12,0,6.09-1.03,8.92-3.08,2.09-1.56,3.47-3.46,4.12-5.72,0.45-1.48,0.68-4.28,0.68-8.42v-3.45z" fill="url(#p)"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 41 KiB |
438
imgsrc/mimetypes/djvu.svg
Normal file
@ -0,0 +1,438 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
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"
|
||||
version="1.0"
|
||||
width="128"
|
||||
height="128"
|
||||
id="svg2606"
|
||||
inkscape:version="0.48.1 "
|
||||
sodipodi:docname="C:\cygwin\home\mperry\calibre\imgsrc\mimetypes\djvu.svg">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="975"
|
||||
inkscape:window-height="735"
|
||||
id="namedview3077"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.0390625"
|
||||
inkscape:cx="64"
|
||||
inkscape:cy="64"
|
||||
inkscape:window-x="298"
|
||||
inkscape:window-y="122"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg2606" />
|
||||
<defs
|
||||
id="defs2608">
|
||||
<linearGradient
|
||||
id="linearGradient10207">
|
||||
<stop
|
||||
id="stop10209"
|
||||
style="stop-color:#a2a2a2;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop10211"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="96"
|
||||
y1="104"
|
||||
x2="88.000198"
|
||||
y2="96.000198"
|
||||
id="XMLID_12_"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
id="stop83"
|
||||
style="stop-color:#888a85;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop85"
|
||||
style="stop-color:#8c8e89;stop-opacity:1"
|
||||
offset="0.0072" />
|
||||
<stop
|
||||
id="stop87"
|
||||
style="stop-color:#abaca9;stop-opacity:1"
|
||||
offset="0.0673" />
|
||||
<stop
|
||||
id="stop89"
|
||||
style="stop-color:#c5c6c4;stop-opacity:1"
|
||||
offset="0.1347" />
|
||||
<stop
|
||||
id="stop91"
|
||||
style="stop-color:#dbdbda;stop-opacity:1"
|
||||
offset="0.2652576" />
|
||||
<stop
|
||||
id="stop93"
|
||||
style="stop-color:#ebebeb;stop-opacity:1"
|
||||
offset="0.37646064" />
|
||||
<stop
|
||||
id="stop95"
|
||||
style="stop-color:#f7f7f6;stop-opacity:1"
|
||||
offset="0.48740286" />
|
||||
<stop
|
||||
id="stop97"
|
||||
style="stop-color:#fdfdfd;stop-opacity:1"
|
||||
offset="0.6324091" />
|
||||
<stop
|
||||
id="stop99"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
cx="102"
|
||||
cy="112.3047"
|
||||
r="139.55859"
|
||||
id="XMLID_8_"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
id="stop41"
|
||||
style="stop-color:#b7b8b9;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop47"
|
||||
style="stop-color:#ececec;stop-opacity:1"
|
||||
offset="0.18851049" />
|
||||
<stop
|
||||
id="stop49"
|
||||
style="stop-color:#fafafa;stop-opacity:1"
|
||||
offset="0.25718147" />
|
||||
<stop
|
||||
id="stop51"
|
||||
style="stop-color:#ffffff;stop-opacity:1"
|
||||
offset="0.30111277" />
|
||||
<stop
|
||||
id="stop53"
|
||||
style="stop-color:#fafafa;stop-opacity:1"
|
||||
offset="0.53130001" />
|
||||
<stop
|
||||
id="stop55"
|
||||
style="stop-color:#ebecec;stop-opacity:1"
|
||||
offset="0.84490001" />
|
||||
<stop
|
||||
id="stop57"
|
||||
style="stop-color:#e1e2e3;stop-opacity:1"
|
||||
offset="1" />
|
||||
</radialGradient>
|
||||
<filter
|
||||
x="-0.19200002"
|
||||
y="-0.19199999"
|
||||
width="1.3839999"
|
||||
height="1.3839999"
|
||||
color-interpolation-filters="sRGB"
|
||||
id="filter6697">
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur6699"
|
||||
stdDeviation="1.9447689" />
|
||||
</filter>
|
||||
<clipPath
|
||||
id="clipPath7084">
|
||||
<path
|
||||
d="m 72,88 -32,32 -8,0 0,-40 40,0 0,8 z"
|
||||
id="path7086"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none" />
|
||||
</clipPath>
|
||||
<radialGradient
|
||||
cx="102"
|
||||
cy="112.3047"
|
||||
r="139.55859"
|
||||
id="radialGradient9437"
|
||||
xlink:href="#XMLID_8_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.9996653,2e-6,0.00301608)" />
|
||||
<linearGradient
|
||||
x1="98.617439"
|
||||
y1="106.41443"
|
||||
x2="91.228737"
|
||||
y2="99.254974"
|
||||
id="linearGradient10213"
|
||||
xlink:href="#linearGradient10207"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<filter
|
||||
color-interpolation-filters="sRGB"
|
||||
id="filter2770">
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur2772"
|
||||
stdDeviation="2.0786429" />
|
||||
</filter>
|
||||
<linearGradient
|
||||
x1="45.033901"
|
||||
y1="44.966038"
|
||||
x2="11.675456"
|
||||
y2="1.4610662"
|
||||
id="linearGradient2774"
|
||||
xlink:href="#linearGradient2545"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0115079,0,0,1.0161106,5.5234761,9.1336546)" />
|
||||
<linearGradient
|
||||
x1="25.553648"
|
||||
y1="34.006008"
|
||||
x2="0"
|
||||
y2="34.153435"
|
||||
id="linearGradient2756"
|
||||
xlink:href="#linearGradient11545"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0237894,0,0,1.0414051,4.9857129,9.0513362)" />
|
||||
<linearGradient
|
||||
x1="40.864098"
|
||||
y1="40.518246"
|
||||
x2="33.136433"
|
||||
y2="32.651588"
|
||||
id="linearGradient2749"
|
||||
xlink:href="#linearGradient11663"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0237894,0,0,1.0414051,4.9857129,9.0513362)" />
|
||||
<linearGradient
|
||||
x1="45.033901"
|
||||
y1="44.966038"
|
||||
x2="11.675456"
|
||||
y2="1.4610662"
|
||||
id="linearGradient2543"
|
||||
xlink:href="#linearGradient2545"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.9880039,0,0,0.9757112,0.5252674,0.07904551)" />
|
||||
<linearGradient
|
||||
id="linearGradient2545">
|
||||
<stop
|
||||
id="stop2547"
|
||||
style="stop-color:#342679;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop2553"
|
||||
style="stop-color:#7b51ae;stop-opacity:0.96862745"
|
||||
offset="0.72235626" />
|
||||
<stop
|
||||
id="stop2549"
|
||||
style="stop-color:#d9cce8;stop-opacity:0.96862745"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="25.553648"
|
||||
y1="34.006008"
|
||||
x2="0"
|
||||
y2="34.153435"
|
||||
id="linearGradient11653"
|
||||
xlink:href="#linearGradient11545"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.4601868,0,0,0.9728475,2.2307835,28.622031)" />
|
||||
<linearGradient
|
||||
id="linearGradient11545">
|
||||
<stop
|
||||
id="stop11547"
|
||||
style="stop-color:#f89c11;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop11549"
|
||||
style="stop-color:#fabf60;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
id="clip7">
|
||||
<path
|
||||
d="m 10.84375,39.414062 -10.84375,0 0,-10.953124 10.84375,0 0,-28.45703175 35.542969,0 0,32.73437475 -13.058594,13.058594 -22.484375,0 0,-6.382813"
|
||||
id="path25" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clip32">
|
||||
<path
|
||||
d="m 10.84375,39.414062 -10.84375,0 0,-10.953124 10.84375,0 0,-28.45703175 35.542969,0 0,32.73437475 -13.058594,13.058594 -22.484375,0 0,-6.382813"
|
||||
id="path100" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
id="clip48">
|
||||
<path
|
||||
d="m 10.84375,39.414062 -10.84375,0 0,-10.953124 10.84375,0 0,-28.45703175 35.542969,0 0,32.73437475 -13.058594,13.058594 -22.484375,0 0,-6.382813"
|
||||
id="path148" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
x1="25.553648"
|
||||
y1="34.006008"
|
||||
x2="0"
|
||||
y2="34.153435"
|
||||
id="linearGradient2525"
|
||||
xlink:href="#linearGradient11545"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
x1="40.864098"
|
||||
y1="40.518246"
|
||||
x2="33.136433"
|
||||
y2="32.651588"
|
||||
id="linearGradient2518"
|
||||
xlink:href="#linearGradient11663"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient11663">
|
||||
<stop
|
||||
id="stop11665"
|
||||
style="stop-color:#342679;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop11667"
|
||||
style="stop-color:#dacfe4;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata2611">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 16,8 0,112 c 0,0 63.15625,0 63.15625,0 l 0.03125,0 c 3e-6,0 11.90625,-9.90625 17.40625,-15.40625 C 102.09375,99.09375 112,87.1875 112,87.1875 L 112,87.15625 112,8 16,8 z"
|
||||
transform="matrix(1.0416667,0,0,1.0267857,-2.6666667,-1.2142891)"
|
||||
id="path7865"
|
||||
style="opacity:0.5;fill:#000000;fill-opacity:1;filter:url(#filter2770)" />
|
||||
<path
|
||||
d="M 16.000001,8 16,120 c 0,0 63.146418,0 63.146418,0 L 112,87.14642 112,8 16.000001,8 z"
|
||||
id="path34"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
d="m 18.000002,9.0000034 c -0.551,0 -1,0.44885 -1,0.999665 l 0,107.9638516 c 0,0.55181 0.449,0.99966 1,0.99966 l 59.171997,0 c 0.263,0 2.76268,0.11813 2.948681,-0.0688 L 110.707,88.094202 C 110.894,87.907264 111,85.40942 111,85.146508 l 0,-75.1468396 c 0,-0.550815 -0.448,-0.999665 -1,-0.999665 l -91.999998,0 z"
|
||||
id="path59"
|
||||
style="fill:url(#radialGradient9437);fill-opacity:1" />
|
||||
<path
|
||||
d="m 41.879531,115.98249 c 0,0 24.309609,-24.309614 24.309609,-24.309614 0,0 -9.35314,2.913124 -19.60314,2.913124 0,10.25 -4.706469,21.39649 -4.706469,21.39649 z"
|
||||
transform="translate(40,0)"
|
||||
clip-path="url(#clipPath7084)"
|
||||
id="path5540"
|
||||
style="opacity:0.4;fill:#000000;fill-opacity:1;filter:url(#filter6697)" />
|
||||
<path
|
||||
d="m 79.172,120 c 0,0 11.914,-9.914 17.414,-15.414 5.5,-5.5 15.414,-17.414 15.414,-17.414 0,0 -13.75,8.828 -24,8.828 0,10.25 -8.828,24 -8.828,24 z"
|
||||
id="path14523"
|
||||
style="fill:url(#linearGradient10213);fill-opacity:1" />
|
||||
<g
|
||||
transform="matrix(2.6666667,0,0,2.6666667,-26.364309,-16.219923)"
|
||||
id="layer1-2">
|
||||
<g
|
||||
transform="matrix(1.000026,0,0,0.9968473,-1.2968723e-4,0.405534)"
|
||||
id="g2454">
|
||||
<g
|
||||
transform="matrix(1.0237894,0,0,1.0414051,9.6816161,-27.57005)"
|
||||
id="g11649">
|
||||
<rect
|
||||
width="11.895136"
|
||||
height="11.569371"
|
||||
ry="2.7001941e-017"
|
||||
x="3.1296141"
|
||||
y="57.056187"
|
||||
transform="matrix(0.9396926,-0.3420201,0.3420201,0.9396926,0,0)"
|
||||
id="rect11645"
|
||||
style="fill:#000000;fill-opacity:1" />
|
||||
<rect
|
||||
width="11.895135"
|
||||
height="11.56937"
|
||||
ry="2.7001941e-017"
|
||||
x="2.2307839"
|
||||
y="56.063431"
|
||||
transform="matrix(0.9396926,-0.3420201,0.3420201,0.9396926,0,0)"
|
||||
id="rect11641"
|
||||
style="fill:url(#linearGradient11653);fill-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(1.0237894,0,0,1.0414051,4.9857129,9.0513362)"
|
||||
clip-path="url(#clip7)"
|
||||
id="g1139" />
|
||||
<g
|
||||
transform="matrix(1.0237894,0,0,1.0414051,0.779179,8.770206)"
|
||||
id="g11677"
|
||||
style="fill:#816392;fill-opacity:0.86179516">
|
||||
<g
|
||||
transform="translate(4.2261802,1.3274155)"
|
||||
clip-path="url(#clip32)"
|
||||
id="g11679"
|
||||
style="fill:#816392;fill-opacity:0.86179516">
|
||||
<path
|
||||
d="m 26.128906,23.296875 c 2.015625,1.242187 4.480469,1.78125 6.523438,0.195313 1.574218,-1.210938 1.84375,-3.335938 1.324218,-5.414063 -0.917968,-3.585937 -4.5625,-7.527344 -4.5625,-7.527344 L 18.972656,-2.15625 c 0,0 -0.136718,-0.171875 -0.433594,-0.261719 -0.414062,-0.117187 -1.035156,0.261719 -0.683593,1.027344 l 10.910156,13.445313 c 0,0 3.265625,3.304687 3.886719,6.472656 0.296875,1.484375 0.214844,2.960937 -0.917969,3.871094 C 30.214844,23.621094 28.289062,22.9375 26.605469,21.863281 24.34375,20.417969 22.429688,18.09375 22.429688,18.09375 L 7.777344,0.679688 7.613281,2.613281 21.472656,19.136719 c 0,0 2.082032,2.566406 4.65625,4.160156"
|
||||
id="path11681"
|
||||
style="fill:#816392;fill-opacity:0.86179516;fill-rule:nonzero;stroke:none" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(4.2261807,1.4535628)"
|
||||
clip-path="url(#clip48)"
|
||||
id="g11683"
|
||||
style="fill:#816392;fill-opacity:0.86179516">
|
||||
<path
|
||||
d="m 28.304688,15.984375 c 2.003906,2.550781 0.160156,3.707031 -1.125,3.027344 -1.875,-1 -4.425782,-4.386719 -4.425782,-4.386719 L 15.613281,6.003906 C 15.070312,5.257812 14.429688,5.644531 14.296875,6.09375 c -0.09766,0.347656 0.238281,0.683594 0.238281,0.683594 l 7.191406,8.703125 c 0,0 2.207032,2.601562 3.398438,3.738281 3.5,3.367188 7.761719,0.152344 4.050781,-4.558594 C 27.074219,12 23.867188,8.175781 23.867188,8.175781 L 13.371094,-4.707031 11.859375,-4.839844 11.789062,-4.050781 22.511719,8.71875 c 0,0 3.636719,4.523438 5.792969,7.265625"
|
||||
id="path11685"
|
||||
style="fill:#816392;fill-opacity:0.86179516;fill-rule:nonzero;stroke:none" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(1.0237894,0,0,1.0414051,0.659598,7.725718)"
|
||||
id="g11671">
|
||||
<g
|
||||
transform="translate(4.2261802,1.3274155)"
|
||||
clip-path="url(#clip32)"
|
||||
id="g3875">
|
||||
<path
|
||||
d="m 26.128906,23.296875 c 2.015625,1.242187 4.480469,1.78125 6.523438,0.195313 1.574218,-1.210938 1.84375,-3.335938 1.324218,-5.414063 -0.917968,-3.585937 -4.5625,-7.527344 -4.5625,-7.527344 L 18.972656,-2.15625 c 0,0 -0.136718,-0.171875 -0.433594,-0.261719 -0.414062,-0.117187 -1.035156,0.261719 -0.683593,1.027344 l 10.910156,13.445313 c 0,0 3.265625,3.304687 3.886719,6.472656 0.296875,1.484375 0.214844,2.960937 -0.917969,3.871094 C 30.214844,23.621094 28.289062,22.9375 26.605469,21.863281 24.34375,20.417969 22.429688,18.09375 22.429688,18.09375 L 7.777344,0.679688 7.613281,2.613281 21.472656,19.136719 c 0,0 2.082032,2.566406 4.65625,4.160156"
|
||||
id="path3877"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(4.2261807,1.4535628)"
|
||||
clip-path="url(#clip48)"
|
||||
id="g6171">
|
||||
<path
|
||||
d="m 28.304688,15.984375 c 2.003906,2.550781 0.160156,3.707031 -1.125,3.027344 -1.875,-1 -4.425782,-4.386719 -4.425782,-4.386719 L 15.613281,6.003906 C 15.070312,5.257812 14.429688,5.644531 14.296875,6.09375 c -0.09766,0.347656 0.238281,0.683594 0.238281,0.683594 l 7.191406,8.703125 c 0,0 2.207032,2.601562 3.398438,3.738281 3.5,3.367188 7.761719,0.152344 4.050781,-4.558594 C 27.074219,12 23.867188,8.175781 23.867188,8.175781 L 13.371094,-4.707031 11.859375,-4.839844 11.789062,-4.050781 22.511719,8.71875 c 0,0 3.636719,4.523438 5.792969,7.265625"
|
||||
id="path6173"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" />
|
||||
</g>
|
||||
</g>
|
||||
<text
|
||||
x="6.855123"
|
||||
y="40.434292"
|
||||
transform="scale(0.9915063,1.0085665)"
|
||||
id="text11553"
|
||||
xml:space="preserve"
|
||||
style="font-size:41.30238724px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"><tspan
|
||||
x="6.855123"
|
||||
y="40.434292"
|
||||
id="tspan11555" /></text>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.10181328,0,0,0.10181328,23.503861,90.420112)"
|
||||
id="g8370">
|
||||
<path
|
||||
d="m 20.795,23.442 c 41.244,-1.555 81.688,-2.171 104.79,17.582 10.619,27.832 15.009,83.404 4.99,117.209 -18.421,31.11 -62.996,31.504 -109.78,29.303 0,-54.699 0,-109.396 0,-164.094 z m 34.93,134.79 c 11.643,0 23.287,0 34.93,0 16.604,-30.859 22.254,-125.032 -34.93,-105.488 0,35.163 0,70.326 0,105.488 z"
|
||||
id="path8372"
|
||||
style="fill-rule:evenodd" />
|
||||
<path
|
||||
d="m 165.505,23.442 c 33.267,0 66.533,0 99.8,0 7.251,46.182 16.995,89.436 34.931,123.07 14.479,-35.739 17.123,-85.377 29.939,-123.07 11.644,0 23.287,0 34.93,0 -12.062,58.113 -35.35,103.042 -44.909,164.093 -14.971,0 -29.94,0 -44.91,0 -9.471,-49.436 -28.165,-88.039 -39.92,-134.791 -23.287,0 -46.573,0 -69.86,0 -0.001,-9.767 -0.001,-19.535 -0.001,-29.302 z"
|
||||
id="path8374"
|
||||
style="fill-rule:evenodd" />
|
||||
<path
|
||||
d="m 385.065,76.186 c 12.301,-0.773 24.042,-0.888 29.939,5.86 -2.146,26.978 -3.585,49.781 4.99,76.186 45.408,12.307 33.898,-42.234 34.93,-82.046 9.98,0 19.96,0 29.94,0 0,37.116 0,74.232 0,111.349 -22.437,6.814 -26.368,-8.103 -29.94,-23.442 -14.933,22.293 -52.771,32.37 -69.859,5.86 0,-31.255 0,-62.511 0,-93.767 z"
|
||||
id="path8376"
|
||||
style="fill-rule:evenodd" />
|
||||
<path
|
||||
d="m 165.505,87.907 c 9.98,0 19.96,0 29.94,0 -2.328,48.057 6.913,109.699 -9.98,140.651 -23.857,2.642 -21.052,2.642 -44.91,0 24.686,-27.659 29.399,-78.774 24.95,-140.651 z"
|
||||
id="path8378"
|
||||
style="fill-rule:evenodd" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 17 KiB |
@ -30,8 +30,14 @@ class CnetNews(BasicNewsRecipe):
|
||||
remove_tags = [
|
||||
dict(name='div', attrs={'id':'tweetmemeAndFacebook'})
|
||||
,dict(name='ul', attrs={'class':'contentTools'})
|
||||
,dict(name='aside', attrs={'id':'filed'})
|
||||
,dict(name='div', attrs={'class':'postLinks'})
|
||||
,dict(name='span', attrs={'class':'shareButton'})
|
||||
,dict(name='span', attrs={'class':'printButton'})
|
||||
,dict(name='span', attrs={'class':'emailButton'})
|
||||
,dict(name='div', attrs={'class':'editorBio'})
|
||||
]
|
||||
keep_only_tags = dict(name='div', attrs={'class':'txtWrap'})
|
||||
keep_only_tags = dict(name='div', attrs={'class':'post'})
|
||||
|
||||
feeds = [(u'News', u'http://news.cnet.com/2547-1_3-0-20.xml')]
|
||||
|
||||
|
@ -9,7 +9,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import Tag, NavigableString
|
||||
from collections import OrderedDict
|
||||
|
||||
import time, re
|
||||
import re
|
||||
|
||||
class Economist(BasicNewsRecipe):
|
||||
|
||||
@ -31,45 +31,41 @@ class Economist(BasicNewsRecipe):
|
||||
{'class': lambda x: x and 'share-links-header' in x},
|
||||
]
|
||||
keep_only_tags = [dict(id='ec-article-body')]
|
||||
needs_subscription = False
|
||||
no_stylesheets = True
|
||||
preprocess_regexps = [(re.compile('</html>.*', re.DOTALL),
|
||||
lambda x:'</html>')]
|
||||
|
||||
# economist.com has started throttling after about 60% of the total has
|
||||
# downloaded with connection reset by peer (104) errors.
|
||||
delay = 1
|
||||
|
||||
needs_subscription = False
|
||||
'''
|
||||
def get_browser(self):
|
||||
br = BasicNewsRecipe.get_browser()
|
||||
br.open('http://www.economist.com')
|
||||
req = mechanize.Request(
|
||||
'http://www.economist.com/members/members.cfm?act=exec_login',
|
||||
headers = {
|
||||
'Referer':'http://www.economist.com/',
|
||||
},
|
||||
data=urllib.urlencode({
|
||||
'logging_in' : 'Y',
|
||||
'returnURL' : '/',
|
||||
'email_address': self.username,
|
||||
'fakepword' : 'Password',
|
||||
'pword' : self.password,
|
||||
'x' : '0',
|
||||
'y' : '0',
|
||||
}))
|
||||
br.open(req).read()
|
||||
if self.username and self.password:
|
||||
br.open('http://www.economist.com/user/login')
|
||||
br.select_form(nr=1)
|
||||
br['name'] = self.username
|
||||
br['pass'] = self.password
|
||||
res = br.submit()
|
||||
raw = res.read()
|
||||
if '>Log out<' not in raw:
|
||||
raise ValueError('Failed to login to economist.com. '
|
||||
'Check your username and password.')
|
||||
return br
|
||||
'''
|
||||
|
||||
def parse_index(self):
|
||||
try:
|
||||
return self.economist_parse_index()
|
||||
except:
|
||||
raise
|
||||
self.log.warn(
|
||||
'Initial attempt to parse index failed, retrying in 30 seconds')
|
||||
time.sleep(30)
|
||||
return self.economist_parse_index()
|
||||
return self.economist_parse_index()
|
||||
|
||||
def economist_parse_index(self):
|
||||
soup = self.index_to_soup(self.INDEX)
|
||||
div = soup.find('div', attrs={'class':'issue-image'})
|
||||
if div is not None:
|
||||
img = div.find('img', src=True)
|
||||
if img is not None:
|
||||
self.cover_url = img['src']
|
||||
feeds = OrderedDict()
|
||||
for section in soup.findAll(attrs={'class':lambda x: x and 'section' in
|
||||
x}):
|
||||
@ -109,7 +105,9 @@ class Economist(BasicNewsRecipe):
|
||||
'description':'', 'date':''})
|
||||
|
||||
if articles:
|
||||
feeds[section_title] = articles
|
||||
if section_title not in feeds:
|
||||
feeds[section_title] = []
|
||||
feeds[section_title] += articles
|
||||
|
||||
ans = [(key, val) for key, val in feeds.iteritems()]
|
||||
if not ans:
|
||||
|
@ -1,3 +1,140 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
'''
|
||||
economist.com
|
||||
'''
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import Tag, NavigableString
|
||||
from collections import OrderedDict
|
||||
|
||||
import time, re
|
||||
|
||||
class Economist(BasicNewsRecipe):
|
||||
|
||||
title = 'The Economist'
|
||||
language = 'en'
|
||||
|
||||
__author__ = "Kovid Goyal"
|
||||
INDEX = 'http://www.economist.com/printedition'
|
||||
description = ('Global news and current affairs from a European'
|
||||
' perspective. Best downloaded on Friday mornings (GMT)')
|
||||
extra_css = '.headline {font-size: x-large;} \n h2 { font-size: small; } \n h1 { font-size: medium; }'
|
||||
oldest_article = 7.0
|
||||
cover_url = 'http://media.economist.com/sites/default/files/imagecache/print-cover-thumbnail/print-covers/currentcoverus_large.jpg'
|
||||
#cover_url = 'http://www.economist.com/images/covers/currentcoverus_large.jpg'
|
||||
remove_tags = [
|
||||
dict(name=['script', 'noscript', 'title', 'iframe', 'cf_floatingcontent']),
|
||||
dict(attrs={'class':['dblClkTrk', 'ec-article-info',
|
||||
'share_inline_header', 'related-items']}),
|
||||
{'class': lambda x: x and 'share-links-header' in x},
|
||||
]
|
||||
keep_only_tags = [dict(id='ec-article-body')]
|
||||
needs_subscription = False
|
||||
no_stylesheets = True
|
||||
preprocess_regexps = [(re.compile('</html>.*', re.DOTALL),
|
||||
lambda x:'</html>')]
|
||||
|
||||
# economist.com has started throttling after about 60% of the total has
|
||||
# downloaded with connection reset by peer (104) errors.
|
||||
delay = 1
|
||||
|
||||
|
||||
def parse_index(self):
|
||||
try:
|
||||
return self.economist_parse_index()
|
||||
except:
|
||||
raise
|
||||
self.log.warn(
|
||||
'Initial attempt to parse index failed, retrying in 30 seconds')
|
||||
time.sleep(30)
|
||||
return self.economist_parse_index()
|
||||
|
||||
def economist_parse_index(self):
|
||||
soup = self.index_to_soup(self.INDEX)
|
||||
div = soup.find('div', attrs={'class':'issue-image'})
|
||||
if div is not None:
|
||||
img = div.find('img', src=True)
|
||||
if img is not None:
|
||||
self.cover_url = img['src']
|
||||
feeds = OrderedDict()
|
||||
for section in soup.findAll(attrs={'class':lambda x: x and 'section' in
|
||||
x}):
|
||||
h4 = section.find('h4')
|
||||
if h4 is None:
|
||||
continue
|
||||
section_title = self.tag_to_string(h4).strip()
|
||||
if not section_title:
|
||||
continue
|
||||
self.log('Found section: %s'%section_title)
|
||||
articles = []
|
||||
for h5 in section.findAll('h5'):
|
||||
article_title = self.tag_to_string(h5).strip()
|
||||
if not article_title:
|
||||
continue
|
||||
data = h5.findNextSibling(attrs={'class':'article'})
|
||||
if data is None: continue
|
||||
a = data.find('a', href=True)
|
||||
if a is None: continue
|
||||
url = a['href']
|
||||
if url.startswith('/'): url = 'http://www.economist.com'+url
|
||||
url += '/print'
|
||||
article_title += ': %s'%self.tag_to_string(a).strip()
|
||||
articles.append({'title':article_title, 'url':url,
|
||||
'description':'', 'date':''})
|
||||
if not articles:
|
||||
# We have last or first section
|
||||
for art in section.findAll(attrs={'class':'article'}):
|
||||
a = art.find('a', href=True)
|
||||
if a is not None:
|
||||
url = a['href']
|
||||
if url.startswith('/'): url = 'http://www.economist.com'+url
|
||||
url += '/print'
|
||||
title = self.tag_to_string(a)
|
||||
if title:
|
||||
articles.append({'title':title, 'url':url,
|
||||
'description':'', 'date':''})
|
||||
|
||||
if articles:
|
||||
if section_title not in feeds:
|
||||
feeds[section_title] = []
|
||||
feeds[section_title] += articles
|
||||
|
||||
ans = [(key, val) for key, val in feeds.iteritems()]
|
||||
if not ans:
|
||||
raise Exception('Could not find any articles, either the '
|
||||
'economist.com server is having trouble and you should '
|
||||
'try later or the website format has changed and the '
|
||||
'recipe needs to be updated.')
|
||||
return ans
|
||||
|
||||
def eco_find_image_tables(self, soup):
|
||||
for x in soup.findAll('table', align=['right', 'center']):
|
||||
if len(x.findAll('font')) in (1,2) and len(x.findAll('img')) == 1:
|
||||
yield x
|
||||
|
||||
def postprocess_html(self, soup, first):
|
||||
body = soup.find('body')
|
||||
for name, val in body.attrs:
|
||||
del body[name]
|
||||
|
||||
for table in list(self.eco_find_image_tables(soup)):
|
||||
caption = table.find('font')
|
||||
img = table.find('img')
|
||||
div = Tag(soup, 'div')
|
||||
div['style'] = 'text-align:left;font-size:70%'
|
||||
ns = NavigableString(self.tag_to_string(caption))
|
||||
div.insert(0, ns)
|
||||
div.insert(1, Tag(soup, 'br'))
|
||||
del img['width']
|
||||
del img['height']
|
||||
img.extract()
|
||||
div.insert(2, img)
|
||||
table.replaceWith(div)
|
||||
return soup
|
||||
|
||||
'''
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.utils.threadpool import ThreadPool, makeRequests
|
||||
from calibre.ebooks.BeautifulSoup import Tag, NavigableString
|
||||
@ -145,3 +282,5 @@ class Economist(BasicNewsRecipe):
|
||||
div.insert(2, img)
|
||||
table.replaceWith(div)
|
||||
return soup
|
||||
'''
|
||||
|
||||
|
40
recipes/el_mostrador.recipe
Normal file
@ -0,0 +1,40 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1313609361(BasicNewsRecipe):
|
||||
news = True
|
||||
title = u'El Mostrador'
|
||||
__author__ = 'Alex Mitrani'
|
||||
description = u'Chilean online newspaper'
|
||||
publisher = u'La Plaza S.A.'
|
||||
category = 'news, rss'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
summary_length = 1000
|
||||
language = 'es_CL'
|
||||
remove_javascript = True
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
remove_empty_feeds = True
|
||||
masthead_url = 'http://www.elmostrador.cl/assets/img/logo-elmostrador-m.jpg'
|
||||
remove_tags_before = dict(name='div', attrs={'class':'news-heading cf'})
|
||||
remove_tags_after = dict(name='div', attrs={'class':'footer-actions cf'})
|
||||
remove_tags = [dict(name='div', attrs={'class':'footer-actions cb cf'})
|
||||
,dict(name='div', attrs={'class':'news-aside fl'})
|
||||
,dict(name='div', attrs={'class':'footer-actions cf'})
|
||||
,dict(name='div', attrs={'class':'user-bar','id':'top'})
|
||||
,dict(name='div', attrs={'class':'indicators'})
|
||||
,dict(name='div', attrs={'id':'header'})
|
||||
]
|
||||
|
||||
|
||||
feeds = [(u'Temas Destacados'
|
||||
, u'http://www.elmostrador.cl/destacado/feed/')
|
||||
, (u'El D\xeda', u'http://www.elmostrador.cl/dia/feed/')
|
||||
, (u'Pa\xeds', u'http://www.elmostrador.cl/noticias/pais/feed/')
|
||||
, (u'Mundo', u'http://www.elmostrador.cl/noticias/mundo/feed/')
|
||||
, (u'Negocios', u'http://www.elmostrador.cl/noticias/negocios/feed/')
|
||||
, (u'Cultura', u'http://www.elmostrador.cl/noticias/cultura/feed/')
|
||||
, (u'Vida en L\xednea', u'http://www.elmostrador.cl/vida-en-linea/feed/')
|
||||
, (u'Opini\xf3n & Blogs', u'http://www.elmostrador.cl/opinion/feed/')
|
||||
]
|
||||
|
@ -18,7 +18,7 @@ class ElMundo(BasicNewsRecipe):
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
encoding = 'iso8859_15'
|
||||
language = 'es_ES'
|
||||
language = 'es'
|
||||
masthead_url = 'http://estaticos03.elmundo.es/elmundo/iconos/v4.x/v4.01/bg_h1.png'
|
||||
publication_type = 'newspaper'
|
||||
extra_css = """
|
||||
|
28
recipes/escrevinhador.recipe
Normal file
@ -0,0 +1,28 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class Escrevinhador(BasicNewsRecipe):
|
||||
title = 'Blog Escrevinhador'
|
||||
__author__ = 'Diniz Bortolotto'
|
||||
description = 'Posts do Blog Escrevinhador'
|
||||
publisher = 'Rodrigo Viana'
|
||||
oldest_article = 5
|
||||
max_articles_per_feed = 20
|
||||
category = 'news, politics, Brazil'
|
||||
language = 'pt_BR'
|
||||
publication_type = 'news and politics portal'
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
|
||||
feeds = [(u'Blog Escrevinhador', u'http://www.rodrigovianna.com.br/feed')]
|
||||
|
||||
reverse_article_order = True
|
||||
|
||||
remove_tags_after = [dict(name='div', attrs={'class':'text'})]
|
||||
|
||||
remove_tags = [
|
||||
dict(id='header'),
|
||||
dict(name='p', attrs={'class':'tags'}),
|
||||
dict(name='div', attrs={'class':'sociable'})
|
||||
]
|
||||
|
BIN
recipes/icons/independent.png
Normal file
After Width: | Height: | Size: 343 B |
@ -1,70 +1,86 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2011, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
www.independent.co.uk
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||
|
||||
class TheIndependent(BasicNewsRecipe):
|
||||
title = u'The Independent'
|
||||
language = 'en_GB'
|
||||
__author__ = 'Krittika Goyal'
|
||||
oldest_article = 1 #days
|
||||
max_articles_per_feed = 30
|
||||
encoding = 'latin1'
|
||||
title = 'The Independent'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'Independent News - Breaking news, comment and features from The Independent newspaper'
|
||||
publisher = 'The Independent'
|
||||
category = 'news, politics, UK'
|
||||
oldest_article = 2
|
||||
max_articles_per_feed = 200
|
||||
no_stylesheets = True
|
||||
encoding = 'cp1252'
|
||||
use_embedded_content = False
|
||||
language = 'en_GB'
|
||||
remove_empty_feeds = True
|
||||
publication_type = 'newspaper'
|
||||
masthead_url = 'http://www.independent.co.uk/independent.co.uk/images/logo-london.png'
|
||||
extra_css = """
|
||||
h1{font-family: Georgia,serif }
|
||||
body{font-family: Verdana,Arial,Helvetica,sans-serif}
|
||||
img{margin-bottom: 0.4em; display:block}
|
||||
.info,.caption,.credits{font-size: x-small}
|
||||
"""
|
||||
|
||||
no_stylesheets = True
|
||||
#remove_tags_before = dict(name='h1', attrs={'class':'heading'})
|
||||
#remove_tags_after = dict(name='td', attrs={'class':'newptool1'})
|
||||
remove_tags = [
|
||||
dict(name='iframe'),
|
||||
dict(name='div', attrs={'class':'related-articles'}),
|
||||
dict(name='div', attrs={'id':['qrformdiv', 'inSection', 'alpha-inner']}),
|
||||
dict(name='ul', attrs={'class':'article-tools'}),
|
||||
dict(name='ul', attrs={'class':'articleTools'}),
|
||||
]
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher' : publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
feeds = [
|
||||
('UK',
|
||||
'http://www.independent.co.uk/news/uk/rss'),
|
||||
('World',
|
||||
'http://www.independent.co.uk/news/world/rss'),
|
||||
('Business',
|
||||
'http://www.independent.co.uk/news/business/rss'),
|
||||
('People',
|
||||
'http://www.independent.co.uk/news/people/rss'),
|
||||
('Science',
|
||||
'http://www.independent.co.uk/news/science/rss'),
|
||||
('Media',
|
||||
'http://www.independent.co.uk/news/media/rss'),
|
||||
('Education',
|
||||
'http://www.independent.co.uk/news/education/rss'),
|
||||
('Obituaries',
|
||||
'http://www.independent.co.uk/news/obituaries/rss'),
|
||||
remove_tags =[
|
||||
dict(name=['meta','link','object','embed','iframe','base','style'])
|
||||
,dict(attrs={'class':['related-articles','share','googleCols','article-tools','paging','googleArt']})
|
||||
,dict(attrs={'id':['newsVideoPlayer','yahoobook','google-intext']})
|
||||
]
|
||||
keep_only_tags =[dict(attrs={'id':'article'})]
|
||||
remove_attributes=['lang','onclick','width','xmlns:fb']
|
||||
|
||||
('Opinion',
|
||||
'http://www.independent.co.uk/opinion/rss'),
|
||||
|
||||
('Environment',
|
||||
'http://www.independent.co.uk/environment/rss'),
|
||||
feeds = [
|
||||
(u'UK' , u'http://www.independent.co.uk/news/uk/rss' )
|
||||
,(u'World' , u'http://www.independent.co.uk/news/world/rss' )
|
||||
,(u'Business' , u'http://www.independent.co.uk/news/business/rss' )
|
||||
,(u'People' , u'http://www.independent.co.uk/news/people/rss' )
|
||||
,(u'Science' , u'http://www.independent.co.uk/news/science/rss' )
|
||||
,(u'Media' , u'http://www.independent.co.uk/news/media/rss' )
|
||||
,(u'Education' , u'http://www.independent.co.uk/news/education/rss' )
|
||||
,(u'Leading Articles' , u'http://www.independent.co.uk/opinion/leading-articles/rss')
|
||||
,(u'Comentators' , u'http://www.independent.co.uk/opinion/commentators/rss' )
|
||||
,(u'Columnists' , u'http://www.independent.co.uk/opinion/columnists/rss' )
|
||||
,(u'Letters' , u'http://www.independent.co.uk/opinion/letters/rss' )
|
||||
,(u'Big Question' , u'http://www.independent.co.uk/extras/big-question/rss' )
|
||||
,(u'Sport' , u'http://www.independent.co.uk/sport/rss' )
|
||||
,(u'Life&Style' , u'http://www.independent.co.uk/life-style/rss' )
|
||||
,(u'Arts&Entertainment' , u'http://www.independent.co.uk/arts-entertainment/rss' )
|
||||
,(u'Travel' , u'http://www.independent.co.uk/travel/rss' )
|
||||
,(u'Money' , u'http://www.independent.co.uk/money/rss' )
|
||||
]
|
||||
|
||||
('Sport',
|
||||
'http://www.independent.co.uk/sport/rss'),
|
||||
|
||||
('Life and Style',
|
||||
'http://www.independent.co.uk/life-style/rss'),
|
||||
|
||||
('Arts and Entertainment',
|
||||
'http://www.independent.co.uk/arts-entertainment/rss'),
|
||||
|
||||
('Travel',
|
||||
'http://www.independent.co.uk/travel/rss'),
|
||||
|
||||
('Money',
|
||||
'http://www.independent.co.uk/money/rss'),
|
||||
]
|
||||
def get_article_url(self, article):
|
||||
return article.get('guid', None)
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
story = soup.find(name='div', attrs={'id':'mainColumn'})
|
||||
#td = heading.findParent(name='td')
|
||||
#td.extract()
|
||||
soup = BeautifulSoup('<html><head><title>t</title></head><body></body></html>')
|
||||
body = soup.find(name='body')
|
||||
body.insert(0, story)
|
||||
return soup
|
||||
for item in soup.body.findAll(style=True):
|
||||
del item['style']
|
||||
for item in soup.body.findAll(['author','preform']):
|
||||
item.name='span'
|
||||
for item in soup.body.findAll('img'):
|
||||
if not item.has_key('alt'):
|
||||
item['alt'] = 'image'
|
||||
for item in soup.body.findAll('div', attrs={'class':['clear-o','body','photoCaption']}):
|
||||
item.name = 'p'
|
||||
for item in soup.body.findAll('div'):
|
||||
if not item.attrs and not item.contents:
|
||||
item.extract()
|
||||
soup2 = BeautifulSoup('<html><head><title>t</title></head><body></body></html>')
|
||||
soup2.body.replaceWith(soup.body)
|
||||
return soup2
|
||||
|
@ -1,55 +1,46 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||
__copyright__ = '2011, Oscar Megia Lopez'
|
||||
'''
|
||||
juventudrebelde.cu
|
||||
'''
|
||||
import re
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
|
||||
from calibre import strftime
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
class JuventudRebelde(BasicNewsRecipe):
|
||||
title = u'Juventud Rebelde'
|
||||
__author__ = 'Oscar Megia Lopez'
|
||||
description = 'Periodico cubano'
|
||||
oldest_article = 30
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
#delay = 1
|
||||
use_embedded_content = False
|
||||
encoding = 'utf8'
|
||||
publisher = 'Juventud Rebelde'
|
||||
category = 'Noticias'
|
||||
language = 'es'
|
||||
publication_type = 'Periodico'
|
||||
extra_css = ' body{ font-family: Verdana,Helvetica,Arial,sans-serif } .title{font-weight: bold} .read{display: block; padding: 0; border: 1px solid; width: 40%; font-size: small} .story-feature h2{text-align: center; text-transform: uppercase} '
|
||||
preprocess_regexps = [(re.compile(r'<!--.*?-->', re.DOTALL), lambda m: '')]
|
||||
conversion_options = {
|
||||
'comments' : description
|
||||
,'tags' : category
|
||||
,'language' : language
|
||||
,'publisher' : publisher
|
||||
,'linearize_tables': True
|
||||
}
|
||||
|
||||
class Juventudrebelde(BasicNewsRecipe):
|
||||
title = 'Juventud Rebelde'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'Diario de la Juventud Cubana'
|
||||
publisher = 'Juventud rebelde'
|
||||
category = 'news, politics, Cuba'
|
||||
oldest_article = 2
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
encoding = 'cp1252'
|
||||
language = 'es_CU'
|
||||
|
||||
cover_url = strftime('http://www.juventudrebelde.cu/UserFiles/File/impreso/iportada-%Y-%m-%d.jpg')
|
||||
remove_javascript = True
|
||||
|
||||
html2lrf_options = [
|
||||
'--comment' , description
|
||||
, '--category' , category
|
||||
, '--publisher', publisher
|
||||
, '--ignore-tables'
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'class':['title']})
|
||||
,dict(attrs={'class':['read']})
|
||||
,dict(attrs={'class':['author']})
|
||||
]
|
||||
|
||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
|
||||
remove_tags = [
|
||||
dict(name='div', attrs={'class':['share']}),
|
||||
]
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'noticia'})]
|
||||
remove_attributes = ['width','height']
|
||||
|
||||
feeds = [
|
||||
(u'Generales', u'http://www.juventudrebelde.cu/rss/generales.php' )
|
||||
,(u'Cuba', u'http://www.juventudrebelde.cu/rss/generales.php?seccion=cuba' )
|
||||
,(u'Internacionales', u'http://www.juventudrebelde.cu/rss/generales.php?seccion=internacionales' )
|
||||
,(u'Opinion', u'http://www.juventudrebelde.cu/rss/generales.php?seccion=opinion' )
|
||||
,(u'Cultura', u'http://www.juventudrebelde.cu/rss/generales.php?seccion=cultura' )
|
||||
,(u'Deportes', u'http://www.juventudrebelde.cu/rss/generales.php?seccion=deportes' )
|
||||
,(u'Lectura', u'http://www.juventudrebelde.cu/rss/generales.php?seccion=lectura' )
|
||||
]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
mtag = '<meta http-equiv="Content-Language" content="es-CU"/>'
|
||||
soup.head.insert(0,mtag)
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
return soup
|
||||
feeds = [(u'Generales', u'http://www.juventudrebelde.cu/get/rss/grupo/generales/'), (u'Internacionales', u'http://www.psychologytoday.com/blog/romance-redux/feed'), (u'Ciencia y Tecnica', u'http://www.juventudrebelde.cu/get/rss/noticias/ciencia-tecnica/'), (u'Opini\xf3n', u'http://www.juventudrebelde.cu/get/rss/noticias/opinion/'), (u'Cuba', u'http://www.juventudrebelde.cu/get/rss/noticias/cuba/'), (u'Cultura', u'http://www.juventudrebelde.cu/get/rss/noticias/cultura/'), (u'Deportes', u'http://www.juventudrebelde.cu/get/rss/noticias/deportes')]
|
||||
|
||||
|
@ -26,7 +26,7 @@ class AdvancedUserRecipe1294946868(BasicNewsRecipe):
|
||||
use_embedded_content = False
|
||||
|
||||
encoding = 'utf-8'
|
||||
language = 'es_ES'
|
||||
language = 'es'
|
||||
timefmt = '[%a, %d %b, %Y]'
|
||||
|
||||
keep_only_tags = [
|
||||
|
@ -17,18 +17,15 @@ class Lanacion(BasicNewsRecipe):
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'es_AR'
|
||||
delay = 14
|
||||
publication_type = 'newspaper'
|
||||
remove_empty_feeds = True
|
||||
masthead_url = 'http://www.lanacion.com.ar/_ui/desktop/imgs/layout/logos/ln341x47.gif'
|
||||
masthead_url = 'http://www.lanacion.com.ar/_ui/desktop/imgs/layout/logos/ln-home.gif'
|
||||
extra_css = """
|
||||
h1{font-family: Georgia,serif}
|
||||
h2{color: #626262; font-weight: normal; font-size: 1.1em}
|
||||
h1{font-family: TheSans,Arial,sans-serif}
|
||||
body{font-family: Arial,sans-serif}
|
||||
img{margin-top: 0.5em; margin-bottom: 0.2em; display: block}
|
||||
.notaFecha{color: #808080; font-size: small}
|
||||
.notaEpigrafe{font-size: x-small}
|
||||
.topNota h1{font-family: Arial,sans-serif}
|
||||
img{display: block}
|
||||
.firma,.fecha{font-size: small}
|
||||
.epigrafe-columna{font-size: x-small}
|
||||
"""
|
||||
|
||||
|
||||
@ -39,21 +36,13 @@ class Lanacion(BasicNewsRecipe):
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'class':['topNota','itemHeader','nota','itemBody']})
|
||||
,dict(name='div', attrs={'id':'content'})
|
||||
]
|
||||
|
||||
remove_tags = [
|
||||
dict(name='div' , attrs={'class':'notaComentario floatFix noprint' })
|
||||
,dict(name='ul' , attrs={'class':['cajaHerramientas cajaTop noprint','herramientas noprint']})
|
||||
,dict(name='div' , attrs={'class':['titulosMultimedia','herramientas noprint','cajaHerramientas noprint','cajaHerramientas floatFix'] })
|
||||
,dict(attrs={'class':['izquierda','espacio17','espacio10','espacio20','floatFix ultimasNoticias','relacionadas','titulosMultimedia','derecha','techo color','encuesta','izquierda compartir','floatFix','videoCentro']})
|
||||
,dict(name=['iframe','embed','object','form','base','hr','meta','link','input'])
|
||||
dict(name=['iframe','embed','object','meta','link'])
|
||||
,dict(attrs={'id':['herramientas','relacionadas','ampliar']})
|
||||
]
|
||||
|
||||
remove_tags_after = dict(attrs={'class':['tags','nota-destacado']})
|
||||
remove_attributes = ['height','width','visible','onclick','data-count','name']
|
||||
remove_tags_before = dict(attrs={'id':'encabezado'})
|
||||
remove_tags_after = dict(attrs={'id':'relacionadas'})
|
||||
|
||||
feeds = [
|
||||
(u'Politica' , u'http://servicios.lanacion.com.ar/herramientas/rss/categoria_id=30' )
|
||||
@ -91,6 +80,15 @@ class Lanacion(BasicNewsRecipe):
|
||||
if link.rfind('galeria=') > 0:
|
||||
return None
|
||||
return link
|
||||
|
||||
def get_cover_url(self):
|
||||
soup = self.index_to_soup('http://www.lanacion.com.ar/edicion-impresa')
|
||||
atap = soup.find(attrs={'class':'tapa'})
|
||||
if atap:
|
||||
li = atap.find('img')
|
||||
if li:
|
||||
return li['src']
|
||||
return None
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(style=True):
|
||||
|
@ -23,7 +23,7 @@ class LaTribuna(BasicNewsRecipe):
|
||||
encoding = 'utf-8'
|
||||
language = 'es_HN'
|
||||
|
||||
lang = 'es-HN'
|
||||
lang = 'es_HN'
|
||||
direction = 'ltr'
|
||||
|
||||
html2lrf_options = [
|
||||
|
@ -19,7 +19,7 @@ class Marca(BasicNewsRecipe):
|
||||
use_embedded_content = False
|
||||
delay = 1
|
||||
encoding = 'iso-8859-15'
|
||||
language = 'es_ES'
|
||||
language = 'es'
|
||||
publication_type = 'newsportal'
|
||||
masthead_url = 'http://estaticos.marca.com/deporte/img/v3.0/img_marca-com.png'
|
||||
extra_css = """
|
||||
|
@ -2,6 +2,9 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1306097511(BasicNewsRecipe):
|
||||
title = u'Metro Nieuws NL'
|
||||
description = u'Metro Nieuws - NL'
|
||||
# Version 1.2, updated cover image to match the changed website.
|
||||
# added info date on title
|
||||
oldest_article = 2
|
||||
max_articles_per_feed = 100
|
||||
__author__ = u'DrMerry'
|
||||
@ -10,11 +13,11 @@ class AdvancedUserRecipe1306097511(BasicNewsRecipe):
|
||||
simultaneous_downloads = 5
|
||||
delay = 1
|
||||
# timefmt = ' [%A, %d %B, %Y]'
|
||||
timefmt = ''
|
||||
timefmt = ' [%A, %d %b %Y]'
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
remove_empty_feeds = True
|
||||
cover_url = 'http://www.readmetro.com/img/en/metroholland/last/1/small.jpg'
|
||||
cover_url = 'http://www.oldreadmetro.com/img/en/metroholland/last/1/small.jpg'
|
||||
remove_empty_feeds = True
|
||||
publication_type = 'newspaper'
|
||||
remove_tags_before = dict(name='div', attrs={'id':'date'})
|
||||
|
@ -8,6 +8,9 @@ class Newsweek(BasicNewsRecipe):
|
||||
language = 'en'
|
||||
encoding = 'utf-8'
|
||||
no_stylesheets = True
|
||||
recipe_disabled = ('Newsweek was taken over by The Daily Beast,'
|
||||
' newsweek.com no longer exists, so this recipe '
|
||||
' has been disabled.')
|
||||
|
||||
BASE_URL = 'http://www.newsweek.com'
|
||||
|
||||
|
@ -1,91 +1,135 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#!/usr/bin/env python
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, matek09, matek09@gmail.com'
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
import datetime
|
||||
|
||||
|
||||
class Newsweek(BasicNewsRecipe):
|
||||
FIND_LAST_FULL_ISSUE = True
|
||||
EDITION = '0'
|
||||
EXCLUDE_LOCKED = True
|
||||
LOCKED_ICO = 'http://www.newsweek.pl/bins/media/static/newsweek/img/ico_locked.gif'
|
||||
DATE = None
|
||||
YEAR = datetime.datetime.now().year
|
||||
|
||||
title = u'Newsweek Polska'
|
||||
__author__ = 'matek09'
|
||||
description = 'Weekly magazine'
|
||||
encoding = 'utf-8'
|
||||
no_stylesheets = True
|
||||
language = 'pl'
|
||||
remove_javascript = True
|
||||
|
||||
keep_only_tags =[]
|
||||
keep_only_tags.append(dict(name = 'div', attrs = {'class' : 'article'}))
|
||||
temp_files = []
|
||||
articles_are_obfuscated = True
|
||||
|
||||
remove_tags =[]
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class' : 'copy'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class' : 'url'}))
|
||||
|
||||
extra_css = '''
|
||||
.body {font-size: small}
|
||||
.author {font-size: x-small}
|
||||
.lead {font-size: x-small}
|
||||
.title{font-size: x-large; font-weight: bold}
|
||||
'''
|
||||
|
||||
def print_version(self, url):
|
||||
return url.replace("http://www.newsweek.pl/artykuly/wydanie/" + str(self.EDITION), "http://www.newsweek.pl/artykuly") + '/print'
|
||||
|
||||
def is_locked(self, a):
|
||||
if a.findNext('img')['src'] == 'http://www.newsweek.pl/bins/media/static/newsweek/img/ico_locked.gif':
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def get_obfuscated_article(self, url):
|
||||
br = self.get_browser()
|
||||
br.open(url)
|
||||
source = br.response().read()
|
||||
page = self.index_to_soup(source)
|
||||
|
||||
main_section = page.find(id='mainSection')
|
||||
|
||||
title = main_section.find('h1')
|
||||
info = main_section.find('ul', attrs={'class' : 'articleInfo'})
|
||||
authors = info.find('li').find('h4')
|
||||
article = main_section.find('div', attrs={'id' : 'article'})
|
||||
html = unicode(title) + unicode(authors) + unicode(article)
|
||||
next = main_section.find('li', attrs={'class' : 'next'})
|
||||
|
||||
while next:
|
||||
url = next.find('a')['href']
|
||||
br.open(url)
|
||||
source = br.response().read()
|
||||
page = self.index_to_soup(source)
|
||||
main_section = page.find(id='mainSection')
|
||||
article = main_section.find('div', attrs={'id' : 'article'})
|
||||
aside = article.find(id='articleAside')
|
||||
if aside is not None:
|
||||
aside.extract()
|
||||
html = html + unicode(article)
|
||||
next = main_section.find('li', attrs={'class' : 'next'})
|
||||
|
||||
|
||||
self.temp_files.append(PersistentTemporaryFile('_temparse.html'))
|
||||
self.temp_files[-1].write(html)
|
||||
self.temp_files[-1].close()
|
||||
return self.temp_files[-1].name
|
||||
|
||||
def is_full(self, issue_soup):
|
||||
if len(issue_soup.findAll('img', attrs={'src' : 'http://www.newsweek.pl/bins/media/static/newsweek/img/ico_locked.gif'})) > 1:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def find_last_full_issue(self):
|
||||
frame_url = 'http://www.newsweek.pl/Frames/IssueCover.aspx'
|
||||
while True:
|
||||
frame_soup = self.index_to_soup(frame_url)
|
||||
self.EDITION = frame_soup.find('a', attrs={'target' : '_parent'})['href'].replace('/wydania/','')
|
||||
main_section = issue_soup.find(id='mainSection')
|
||||
next = main_section.find('li', attrs={'class' : 'next'})
|
||||
if len(main_section.findAll(attrs={'class' : 'locked'})) > 1:
|
||||
return False
|
||||
elif next is None:
|
||||
return True
|
||||
else:
|
||||
issue_soup = self.index_to_soup(next.find('a')['href'])
|
||||
|
||||
def find_last_full_issue(self, archive_url):
|
||||
archive_soup = self.index_to_soup(archive_url)
|
||||
select = archive_soup.find('select', attrs={'id' : 'paper_issue_select'})
|
||||
for option in select.findAll(lambda tag: tag.name == 'option' and tag.has_key('value')):
|
||||
self.EDITION = option['value'].replace('http://www.newsweek.pl/wydania/','')
|
||||
issue_soup = self.index_to_soup('http://www.newsweek.pl/wydania/' + self.EDITION)
|
||||
if self.is_full(issue_soup):
|
||||
break
|
||||
frame_url = 'http://www.newsweek.pl/Frames/' + frame_soup.find(lambda tag: tag.name == 'span' and not tag.attrs).a['href']
|
||||
|
||||
|
||||
|
||||
return
|
||||
|
||||
self.YEAR = self.YEAR - 1
|
||||
self.find_last_full_issue(archive_url + ',' + str(self.YEAR))
|
||||
|
||||
def parse_index(self):
|
||||
if self.FIND_LAST_FULL_ISSUE:
|
||||
self.find_last_full_issue()
|
||||
archive_url = 'http://www.newsweek.pl/wydania/archiwum'
|
||||
self.find_last_full_issue(archive_url)
|
||||
soup = self.index_to_soup('http://www.newsweek.pl/wydania/' + self.EDITION)
|
||||
img = soup.find('img', id="ctl00_C1_PaperIsssueView_IssueImage", src=True)
|
||||
self.DATE = self.tag_to_string(soup.find('span', attrs={'class' : 'data'}))
|
||||
main_section = soup.find(id='mainSection')
|
||||
img = main_section.find(lambda tag: tag.name == 'img' and tag.has_key('alt') and tag.has_key('title'))
|
||||
self.cover_url = img['src']
|
||||
feeds = []
|
||||
parent = soup.find(id='content-left-big')
|
||||
for txt in parent.findAll(attrs={'class':'txt_normal_red strong'}):
|
||||
articles = list(self.find_articles(txt))
|
||||
if len(articles) > 0:
|
||||
section = self.tag_to_string(txt).capitalize()
|
||||
feeds.append((section, articles))
|
||||
articles = {}
|
||||
sections = []
|
||||
while True:
|
||||
news_list = main_section.find('ul', attrs={'class' : 'newsList'})
|
||||
for h2 in news_list.findAll('h2'):
|
||||
|
||||
article = self.create_article(h2)
|
||||
category_div = h2.findNext('div', attrs={'class' : 'kategorie'})
|
||||
section = self.tag_to_string(category_div)
|
||||
if articles.has_key(section):
|
||||
articles[section].append(article)
|
||||
else:
|
||||
articles[section] = [article]
|
||||
sections.append(section)
|
||||
|
||||
next = main_section.find('li', attrs={'class' : 'next'})
|
||||
if next is None:
|
||||
break
|
||||
soup = self.index_to_soup(next.find('a')['href'])
|
||||
main_section = soup.find(id='mainSection')
|
||||
|
||||
for section in sections:
|
||||
feeds.append((section, articles[section]))
|
||||
return feeds
|
||||
|
||||
def find_articles(self, txt):
|
||||
for a in txt.findAllNext( attrs={'class':['strong','hr']}):
|
||||
if a.name in "div":
|
||||
break
|
||||
if (not self.FIND_LAST_FULL_ISSUE) & self.EXCLUDE_LOCKED & self.is_locked(a):
|
||||
continue
|
||||
yield {
|
||||
'title' : self.tag_to_string(a),
|
||||
'url' : 'http://www.newsweek.pl' + a['href'],
|
||||
'date' : '',
|
||||
'description' : ''
|
||||
}
|
||||
def create_article(self, h2):
|
||||
article = {}
|
||||
a = h2.find('a')
|
||||
article['title'] = self.tag_to_string(a)
|
||||
article['url'] = a['href']
|
||||
article['date'] = self.DATE
|
||||
desc = h2.findNext('p')
|
||||
|
||||
if desc is not None:
|
||||
article['description'] = self.tag_to_string(desc)
|
||||
else:
|
||||
article['description'] = ''
|
||||
return article
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -85,4 +85,5 @@ class NikkeiNet_paper_subscription(BasicNewsRecipe):
|
||||
description='', content=''))
|
||||
result.append([sect_title, sect_result])
|
||||
#pp.pprint(result)
|
||||
return result
|
||||
|
||||
|
35
recipes/novinite.recipe
Normal file
@ -0,0 +1,35 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1308572538(BasicNewsRecipe):
|
||||
title = u'Novinite.com'
|
||||
__author__ = 'Martin Tsanchev'
|
||||
description = 'Real time provider of the latest Bulgarian news in English'
|
||||
category = 'Business, Politics, Society, Sports, Crime, Lifestyle, World, People'
|
||||
language = 'en_BG'
|
||||
encoding = 'utf-8'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 10
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'content'})]
|
||||
remove_tags = [dict(name='a', attrs={'class':'twitter-share-button'})]
|
||||
remove_tags_after = dict(id='textsize')
|
||||
no_stylesheets = True
|
||||
feeds = [(u'Business', u'http://www.novinite.com/services/news_rdf.php?category_id=1'),
|
||||
(u'Finance', u'http://www.novinite.com/services/news_rdf.php?category_id=15'),
|
||||
(u'Energy', u'http://www.novinite.com/services/news_rdf.php?category_id=16'),
|
||||
(u'Industry', u'http://www.novinite.com/services/news_rdf.php?category_id=17'),
|
||||
(u'Properties', u'http://www.novinite.com/services/news_rdf.php?category_id=18'),
|
||||
(u'Politics', u'http://www.novinite.com/services/news_rdf.php?category_id=2'),
|
||||
(u'Diplomacy', u'http://www.novinite.com/services/news_rdf.php?category_id=20'),
|
||||
(u'Defense', u'http://www.novinite.com/services/news_rdf.php?category_id=21'),
|
||||
(u'Bulgaria in EU', u'http://www.novinite.com/services/news_rdf.php?category_id=22'),
|
||||
(u'Domestic', u'http://www.novinite.com/services/news_rdf.php?category_id=23'),
|
||||
(u'Society', u'http://www.novinite.com/services/news_rdf.php?category_id=3'),
|
||||
(u'Environment', u'http://www.novinite.com/services/news_rdf.php?category_id=24'),
|
||||
(u'Education', u'http://www.novinite.com/services/news_rdf.php?category_id=25'),
|
||||
(u'Culture', u'http://www.novinite.com/services/news_rdf.php?category_id=26'),
|
||||
(u'Archaeology', u'http://www.novinite.com/services/news_rdf.php?category_id=34'),
|
||||
(u'Health', u'http://www.novinite.com/services/news_rdf.php?category_id=62'),
|
||||
(u'Sports', u'http://www.novinite.com/services/news_rdf.php?category_id=4'),
|
||||
(u'Crime', u'http://www.novinite.com/services/news_rdf.php?category_id=5'),
|
||||
(u'Lifestyle', u'http://www.novinite.com/services/news_rdf.php?category_id=6'),
|
||||
(u'World', u'http://www.novinite.com/services/news_rdf.php?category_id=30')]
|
43
recipes/patente_de_corso.recipe
Normal file
@ -0,0 +1,43 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2011, Oscar Megia Lopez'
|
||||
'''
|
||||
perezreverte.com
|
||||
'''
|
||||
import re
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
|
||||
class PerezReverte(BasicNewsRecipe):
|
||||
title = u'Patente de Corso'
|
||||
__author__ = 'Oscar Megia Lopez'
|
||||
description = 'Arturo Perez Reverte'
|
||||
oldest_article = 90
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
#delay = 1
|
||||
use_embedded_content = False
|
||||
encoding = 'utf8'
|
||||
publisher = 'Arturo Perez Reverte'
|
||||
category = 'Articulo'
|
||||
language = 'es'
|
||||
publication_type = 'Magazine'
|
||||
extra_css = ' body{ font-family: Verdana,Helvetica,Arial,sans-serif } .contentheading{font-weight: bold} .txt_articulo{display: block; padding: 0; border: 1px solid; width: 40%; font-size: small} .story-feature h2{text-align: center; text-transform: uppercase} '
|
||||
preprocess_regexps = [(re.compile(r'<!--.*?-->', re.DOTALL), lambda m: '')]
|
||||
conversion_options = {
|
||||
'comments' : description
|
||||
,'tags' : category
|
||||
,'language' : language
|
||||
,'publisher' : publisher
|
||||
,'linearize_tables': True
|
||||
}
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='h2', attrs={'class':['titular']}),
|
||||
dict(name='p', attrs={'class':['fecha']}),
|
||||
dict(name='div', attrs={'class':['bloqueTexto']})
|
||||
]
|
||||
|
||||
remove_attributes = ['width','height']
|
||||
|
||||
feeds = [
|
||||
('Patente de corso - Web oficial de Arturo Perez Reverte', 'http://www.perezreverte.com/rss/patentes-corso/')
|
||||
]
|
@ -1,12 +1,12 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class RzeczpospolitaRecipe(BasicNewsRecipe):
|
||||
__license__ = 'GPL v3'
|
||||
__license__ = 'GPL v3'
|
||||
__author__ = u'kwetal and Tomasz Dlugosz'
|
||||
language = 'pl'
|
||||
version = 1
|
||||
|
||||
title = u'Rzeczpospolita OnLine'
|
||||
title = u'Rzeczpospolita OnLine'
|
||||
publisher = u'Presspublica Sp.'
|
||||
category = u'News'
|
||||
description = u'Newspaper'
|
||||
@ -31,15 +31,19 @@ class RzeczpospolitaRecipe(BasicNewsRecipe):
|
||||
feeds.append(u'http://www.rp.pl/rss/8.html')
|
||||
|
||||
keep_only_tags =[]
|
||||
keep_only_tags.append(dict(name = 'div', attrs = {'id' : 'storyp'}))
|
||||
keep_only_tags.append(dict(name = 'div', attrs = {'id' : 'story'}))
|
||||
|
||||
remove_tags =[]
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id' : 'adk_0'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id' : 'socialTools'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class' : 'articleToolBoxTop'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class' : 'clr'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id' : 'share_bottom'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id' : 'copyright_law'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id' : 'recommendations'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id' : 'editorPicks'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id' : 'articleCopyrightText'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id' : 'articleCopyrightButton'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class' : 'articleToolBoxBottom'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class' : 'more'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class' : 'editorPicks'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'class' : 'addRecommendation'}))
|
||||
|
||||
extra_css = '''
|
||||
body {font-family: verdana, arial, helvetica, geneva, sans-serif ;}
|
||||
@ -62,3 +66,4 @@ class RzeczpospolitaRecipe(BasicNewsRecipe):
|
||||
forget, sep, index = rest.rpartition(',')
|
||||
|
||||
return start + '/' + index + '?print=tak'
|
||||
|
||||
|
27
recipes/the_clinic_online.recipe
Normal file
@ -0,0 +1,27 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1313555075(BasicNewsRecipe):
|
||||
news = True
|
||||
title = u'The Clinic'
|
||||
__author__ = 'Alex Mitrani'
|
||||
description = u'Online version of Chilean satirical weekly'
|
||||
publisher = u'The Clinic'
|
||||
category = 'news, politics, Chile, rss'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
summary_length = 1000
|
||||
language = 'es_CL'
|
||||
|
||||
remove_javascript = True
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
remove_empty_feeds = True
|
||||
masthead_url = 'http://www.theclinic.cl/wp-content/themes/tc12m/css/ui/mainLogoTC-top.png'
|
||||
remove_tags_before = dict(name='article', attrs={'class':'scope bordered'})
|
||||
remove_tags_after = dict(name='div', attrs={'id':'commentsSection'})
|
||||
remove_tags = [dict(name='span', attrs={'class':'relTags'})
|
||||
,dict(name='div', attrs={'class':'articleActivity hdcol'})
|
||||
,dict(name='div', attrs={'id':'commentsSection'})
|
||||
]
|
||||
|
||||
feeds = [(u'The Clinic Online', u'http://www.theclinic.cl/feed/')]
|
@ -38,6 +38,7 @@ class WallStreetJournal(BasicNewsRecipe):
|
||||
dict(id=["articleTabs_tab_article", "articleTabs_tab_comments", "articleTabs_tab_interactive","articleTabs_tab_video","articleTabs_tab_map","articleTabs_tab_slideshow","articleTabs_tab_quotes","articleTabs_tab_document"]),
|
||||
{'class':['footer_columns','network','insetCol3wide','interactive','video','slideshow','map','insettip','insetClose','more_in', "insetContent", 'articleTools_bottom', 'aTools', "tooltip", "adSummary", "nav-inline"]},
|
||||
dict(rel='shortcut icon'),
|
||||
{'class':lambda x: x and 'sTools' in x},
|
||||
]
|
||||
remove_tags_after = [dict(id="article_story_body"), {'class':"article story"},]
|
||||
|
||||
|
@ -40,6 +40,7 @@ class WallStreetJournal(BasicNewsRecipe):
|
||||
dict(name='div', attrs={'data-flash-settings':True}),
|
||||
{'class':['insetContent embedType-interactive insetCol3wide','insetCol6wide','insettipUnit']},
|
||||
dict(rel='shortcut icon'),
|
||||
{'class':lambda x: x and 'sTools' in x},
|
||||
]
|
||||
remove_tags_after = [dict(id="article_story_body"), {'class':"article story"},]
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="{prefix}/static/browse/browse.css" />
|
||||
<link type="text/css" href="{prefix}/static/jquery_ui/css/humanity-custom/jquery-ui-1.8.5.custom.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" type="text/css" href="{prefix}/static/jquery.multiselect.css" />
|
||||
<link rel="apple-touch-icon" href="/static/calibre.png" />
|
||||
<link rel="apple-touch-icon" href="{prefix}/static/calibre.png" />
|
||||
|
||||
<script type="text/javascript" src="{prefix}/static/jquery.js"></script>
|
||||
<script type="text/javascript" src="{prefix}/static/jquery.corner.js"></script>
|
||||
|
@ -179,6 +179,9 @@ save_template_title_series_sorting = 'library_order'
|
||||
# changed. Changes to this tweak won't have an effect until the book is modified
|
||||
# in some way. If you enter an invalid pattern, it is silently ignored.
|
||||
# To disable use the expression: '^$'
|
||||
# This expression is designed for articles that are followed by spaces. If you
|
||||
# also need to match articles that are followed by other characters, for example L'
|
||||
# in French, use: r"^(A\s+|The\s+|An\s+|L')" instead.
|
||||
# Default: '^(A|The|An)\s+'
|
||||
title_sort_articles=r'^(A|The|An)\s+'
|
||||
|
||||
|
BIN
resources/images/keyboard-prefs.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
resources/images/languages.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
resources/images/mimetypes/djvu.png
Executable file
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.9 KiB |
BIN
resources/images/mimetypes/xps.png
Executable file
After Width: | Height: | Size: 13 KiB |
@ -21,3 +21,5 @@ vipy.session.add_content_browser('.r', ',r', 'Recipe',
|
||||
vipy.session.glob_based_iterator(os.path.join(project_dir, 'recipes', '*.recipe')),
|
||||
vipy.session.regexp_based_matcher(r'title\s*=\s*(?P<title>.+)', 'title', recipe_title_callback))
|
||||
EOFPY
|
||||
|
||||
nmap \log :enew<CR>:read ! bzr log -l 500 ../.. <CR>:e ../../Changelog.yaml<CR>:e constants.py<CR>
|
||||
|
2169
setup/iso639.xml
Normal file
@ -273,10 +273,9 @@ class GetTranslations(Translations):
|
||||
class ISO639(Command):
|
||||
|
||||
description = 'Compile translations for ISO 639 codes'
|
||||
XML = '/usr/lib/python2.7/site-packages/pycountry/databases/iso639.xml'
|
||||
|
||||
def run(self, opts):
|
||||
src = self.XML
|
||||
src = self.j(self.d(self.SRC), 'setup', 'iso639.xml')
|
||||
if not os.path.exists(src):
|
||||
raise Exception(src + ' does not exist')
|
||||
dest = self.j(self.d(self.SRC), 'resources', 'localization',
|
||||
@ -290,20 +289,32 @@ class ISO639(Command):
|
||||
by_2 = {}
|
||||
by_3b = {}
|
||||
by_3t = {}
|
||||
m2to3 = {}
|
||||
m3to2 = {}
|
||||
m3bto3t = {}
|
||||
nm = {}
|
||||
codes2, codes3t, codes3b = set([]), set([]), set([])
|
||||
for x in root.xpath('//iso_639_entry'):
|
||||
name = x.get('name')
|
||||
two = x.get('iso_639_1_code', None)
|
||||
threeb = x.get('iso_639_2B_code')
|
||||
threet = x.get('iso_639_2T_code')
|
||||
if two is not None:
|
||||
by_2[two] = name
|
||||
codes2.add(two)
|
||||
by_3b[x.get('iso_639_2B_code')] = name
|
||||
by_3t[x.get('iso_639_2T_code')] = name
|
||||
m2to3[two] = threet
|
||||
m3to2[threeb] = m3to2[threet] = two
|
||||
by_3b[threeb] = name
|
||||
by_3t[threet] = name
|
||||
if threeb != threet:
|
||||
m3bto3t[threeb] = threet
|
||||
codes3b.add(x.get('iso_639_2B_code'))
|
||||
codes3t.add(x.get('iso_639_2T_code'))
|
||||
nm[name.lower().partition(';')[0].strip()] = threet
|
||||
|
||||
from cPickle import dump
|
||||
x = {'by_2':by_2, 'by_3b':by_3b, 'by_3t':by_3t, 'codes2':codes2,
|
||||
'codes3b':codes3b, 'codes3t':codes3t}
|
||||
'codes3b':codes3b, 'codes3t':codes3t, '2to3':m2to3,
|
||||
'3to2':m3to2, '3bto3t':m3bto3t, 'name_map':nm}
|
||||
dump(x, open(dest, 'wb'), -1)
|
||||
|
||||
|
@ -4,7 +4,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = u'calibre'
|
||||
numeric_version = (0, 8, 12)
|
||||
numeric_version = (0, 8, 14)
|
||||
__version__ = u'.'.join(map(unicode, numeric_version))
|
||||
__author__ = u"Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
|
||||
|
@ -1029,7 +1029,7 @@ class TemplateFunctions(PreferencesPlugin):
|
||||
category = 'Advanced'
|
||||
gui_category = _('Advanced')
|
||||
category_order = 5
|
||||
name_order = 4
|
||||
name_order = 5
|
||||
config_widget = 'calibre.gui2.preferences.template_functions'
|
||||
description = _('Create your own template functions')
|
||||
|
||||
@ -1092,6 +1092,17 @@ class Tweaks(PreferencesPlugin):
|
||||
config_widget = 'calibre.gui2.preferences.tweaks'
|
||||
description = _('Fine tune how calibre behaves in various contexts')
|
||||
|
||||
class Keyboard(PreferencesPlugin):
|
||||
name = 'Keyboard'
|
||||
icon = I('keyboard-prefs.png')
|
||||
gui_name = _('Keyboard')
|
||||
category = 'Advanced'
|
||||
gui_category = _('Advanced')
|
||||
category_order = 5
|
||||
name_order = 4
|
||||
config_widget = 'calibre.gui2.preferences.keyboard'
|
||||
description = _('Customize the keyboard shortcuts used by calibre')
|
||||
|
||||
class Misc(PreferencesPlugin):
|
||||
name = 'Misc'
|
||||
icon = I('exec.png')
|
||||
@ -1106,7 +1117,7 @@ class Misc(PreferencesPlugin):
|
||||
plugins += [LookAndFeel, Behavior, Columns, Toolbar, Search, InputOptions,
|
||||
CommonOptions, OutputOptions, Adding, Saving, Sending, Plugboard,
|
||||
Email, Server, Plugins, Tweaks, Misc, TemplateFunctions,
|
||||
MetadataSources]
|
||||
MetadataSources, Keyboard]
|
||||
|
||||
#}}}
|
||||
|
||||
|
@ -40,6 +40,7 @@ class ANDROID(USBMS):
|
||||
0x41db : [0x216], 0x4285 : [0x216], 0x42a3 : [0x216],
|
||||
0x4286 : [0x216], 0x42b3 : [0x216], 0x42b4 : [0x216],
|
||||
0x7086 : [0x0226], 0x70a8: [0x9999], 0x42c4 : [0x216],
|
||||
0x70c6 : [0x226]
|
||||
},
|
||||
|
||||
# Sony Ericsson
|
||||
@ -47,7 +48,7 @@ class ANDROID(USBMS):
|
||||
|
||||
# Google
|
||||
0x18d1 : {
|
||||
0x0001 : [0x0223],
|
||||
0x0001 : [0x0223, 0x9999],
|
||||
0x4e11 : [0x0100, 0x226, 0x227],
|
||||
0x4e12 : [0x0100, 0x226, 0x227],
|
||||
0x4e21 : [0x0100, 0x226, 0x227],
|
||||
@ -63,6 +64,7 @@ class ANDROID(USBMS):
|
||||
0x6860 : [0x0400],
|
||||
0x6877 : [0x0400],
|
||||
0x689e : [0x0400],
|
||||
0xdeed : [0x0222],
|
||||
},
|
||||
|
||||
# Viewsonic
|
||||
@ -75,8 +77,11 @@ class ANDROID(USBMS):
|
||||
0x413c : { 0xb007 : [0x0100, 0x0224, 0x0226]},
|
||||
|
||||
# LG
|
||||
0x1004 : { 0x61cc : [0x100], 0x61ce : [0x100], 0x618e : [0x226,
|
||||
0x9999] },
|
||||
0x1004 : {
|
||||
0x61cc : [0x100],
|
||||
0x61ce : [0x100],
|
||||
0x618e : [0x226, 0x9999, 0x100]
|
||||
},
|
||||
|
||||
# Archos
|
||||
0x0e79 : {
|
||||
@ -128,11 +133,11 @@ class ANDROID(USBMS):
|
||||
'7', 'A956', 'A955', 'A43', 'ANDROID_PLATFORM', 'TEGRA_2',
|
||||
'MB860', 'MULTI-CARD', 'MID7015A', 'INCREDIBLE', 'A7EB', 'STREAK',
|
||||
'MB525', 'ANDROID2.3', 'SGH-I997', 'GT-I5800_CARD', 'MB612',
|
||||
'GT-S5830_CARD', 'GT-S5570_CARD']
|
||||
'GT-S5830_CARD', 'GT-S5570_CARD', 'MB870', 'MID7015A']
|
||||
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
|
||||
'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD',
|
||||
'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB', 'SGH-T849_CARD',
|
||||
'__UMS_COMPOSITE', 'SGH-I997_CARD']
|
||||
'__UMS_COMPOSITE', 'SGH-I997_CARD', 'MB870']
|
||||
|
||||
OSX_MAIN_MEM = 'Android Device Main Memory'
|
||||
|
||||
|
@ -6,6 +6,7 @@ Created on 15 May 2010
|
||||
import os
|
||||
|
||||
from calibre.devices.usbms.driver import USBMS, BookList
|
||||
from calibre.ebooks import BOOK_EXTENSIONS
|
||||
|
||||
# This class is added to the standard device plugin chain, so that it can
|
||||
# be configured. It has invalid vendor_id etc, so it will never match a
|
||||
@ -16,8 +17,8 @@ class FOLDER_DEVICE_FOR_CONFIG(USBMS):
|
||||
description = _('Use an arbitrary folder as a device.')
|
||||
author = 'John Schember/Charles Haley'
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
FORMATS = ['epub', 'fb2', 'mobi', 'azw', 'lrf', 'tcr', 'pmlz', 'lit',
|
||||
'rtf', 'rb', 'pdf', 'oeb', 'txt', 'pdb', 'prc']
|
||||
FORMATS = list(BOOK_EXTENSIONS)
|
||||
|
||||
VENDOR_ID = [0xffff]
|
||||
PRODUCT_ID = [0xffff]
|
||||
BCD = [0xffff]
|
||||
|
@ -64,7 +64,7 @@ class KINDLE(USBMS):
|
||||
|
||||
EBOOK_DIR_MAIN = 'documents'
|
||||
EBOOK_DIR_CARD_A = 'documents'
|
||||
DELETE_EXTS = ['.mbp','.tan','.pdr']
|
||||
DELETE_EXTS = ['.mbp', '.tan', '.pdr', '.ea', '.apnx', '.phl']
|
||||
SUPPORTS_SUB_DIRS = True
|
||||
SUPPORTS_ANNOTATIONS = True
|
||||
|
||||
|
@ -252,8 +252,8 @@ class EEEREADER(USBMS):
|
||||
|
||||
EBOOK_DIR_MAIN = EBOOK_DIR_CARD_A = 'Book'
|
||||
|
||||
VENDOR_NAME = 'LINUX'
|
||||
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = 'FILE-STOR_GADGET'
|
||||
VENDOR_NAME = ['LINUX', 'ASUS']
|
||||
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = ['FILE-STOR_GADGET', 'EEE_NOTE']
|
||||
|
||||
class ADAM(USBMS):
|
||||
|
||||
|
@ -7,6 +7,7 @@ __docformat__ = 'restructuredtext en'
|
||||
import os, shutil, time
|
||||
|
||||
from calibre.devices.errors import PathError
|
||||
from calibre.utils.filenames import case_preserving_open_file
|
||||
|
||||
class File(object):
|
||||
|
||||
@ -46,10 +47,8 @@ class CLI(object):
|
||||
path = os.path.join(path, infile.name)
|
||||
if not replace_file and os.path.exists(path):
|
||||
raise PathError('File already exists: ' + path)
|
||||
d = os.path.dirname(path)
|
||||
if not os.path.exists(d):
|
||||
os.makedirs(d)
|
||||
with open(path, 'w+b') as dest:
|
||||
dest, actual_path = case_preserving_open_file(path)
|
||||
with dest:
|
||||
try:
|
||||
shutil.copyfileobj(infile, dest)
|
||||
except IOError:
|
||||
@ -62,6 +61,7 @@ class CLI(object):
|
||||
#if not check_transfer(infile, dest): raise Exception('Transfer failed')
|
||||
if close:
|
||||
infile.close()
|
||||
return actual_path
|
||||
|
||||
def munge_path(self, path):
|
||||
if path.startswith('/') and not (path.startswith(self._main_prefix) or \
|
||||
|
@ -258,10 +258,10 @@ class USBMS(CLI, Device):
|
||||
for i, infile in enumerate(files):
|
||||
mdata, fname = metadata.next(), names.next()
|
||||
filepath = self.normalize_path(self.create_upload_path(path, mdata, fname))
|
||||
paths.append(filepath)
|
||||
if not hasattr(infile, 'read'):
|
||||
infile = self.normalize_path(infile)
|
||||
self.put_file(infile, filepath, replace_file=True)
|
||||
filepath = self.put_file(infile, filepath, replace_file=True)
|
||||
paths.append(filepath)
|
||||
try:
|
||||
self.upload_cover(os.path.dirname(filepath),
|
||||
os.path.splitext(os.path.basename(filepath))[0],
|
||||
|
@ -28,8 +28,9 @@ class ParserError(ValueError):
|
||||
|
||||
BOOK_EXTENSIONS = ['lrf', 'rar', 'zip', 'rtf', 'lit', 'txt', 'txtz', 'text', 'htm', 'xhtm',
|
||||
'html', 'htmlz', 'xhtml', 'pdf', 'pdb', 'pdr', 'prc', 'mobi', 'azw', 'doc',
|
||||
'epub', 'fb2', 'djvu', 'lrx', 'cbr', 'cbz', 'cbc', 'oebzip',
|
||||
'rb', 'imp', 'odt', 'chm', 'tpz', 'azw1', 'pml', 'pmlz', 'mbp', 'tan', 'snb']
|
||||
'epub', 'fb2', 'djv', 'djvu', 'lrx', 'cbr', 'cbz', 'cbc', 'oebzip',
|
||||
'rb', 'imp', 'odt', 'chm', 'tpz', 'azw1', 'pml', 'pmlz', 'mbp', 'tan', 'snb',
|
||||
'xps', 'oxps']
|
||||
|
||||
class HTMLRenderer(object):
|
||||
|
||||
|
@ -47,8 +47,7 @@ PUBLICATION_METADATA_FIELDS = frozenset([
|
||||
# If None, means book
|
||||
'publication_type',
|
||||
'uuid', # A UUID usually of type 4
|
||||
'language', # the primary language of this book
|
||||
'languages', # ordered list
|
||||
'languages', # ordered list of languages in this publication
|
||||
'publisher', # Simple string, no special semantics
|
||||
# Absolute path to image file encoded in filesystem_encoding
|
||||
'cover',
|
||||
@ -109,7 +108,7 @@ STANDARD_METADATA_FIELDS = SOCIAL_METADATA_FIELDS.union(
|
||||
# Metadata fields that smart update must do special processing to copy.
|
||||
SC_FIELDS_NOT_COPIED = frozenset(['title', 'title_sort', 'authors',
|
||||
'author_sort', 'author_sort_map',
|
||||
'cover_data', 'tags', 'language',
|
||||
'cover_data', 'tags', 'languages',
|
||||
'identifiers'])
|
||||
|
||||
# Metadata fields that smart update should copy only if the source is not None
|
||||
|
@ -102,6 +102,7 @@ class Metadata(object):
|
||||
@param other: None or a metadata object
|
||||
'''
|
||||
_data = copy.deepcopy(NULL_VALUES)
|
||||
_data.pop('language')
|
||||
object.__setattr__(self, '_data', _data)
|
||||
if other is not None:
|
||||
self.smart_update(other)
|
||||
@ -136,6 +137,11 @@ class Metadata(object):
|
||||
_data = object.__getattribute__(self, '_data')
|
||||
if field in TOP_LEVEL_IDENTIFIERS:
|
||||
return _data.get('identifiers').get(field, None)
|
||||
if field == 'language':
|
||||
try:
|
||||
return _data.get('languages', [])[0]
|
||||
except:
|
||||
return NULL_VALUES['language']
|
||||
if field in STANDARD_METADATA_FIELDS:
|
||||
return _data.get(field, None)
|
||||
try:
|
||||
@ -175,6 +181,11 @@ class Metadata(object):
|
||||
if not val:
|
||||
val = copy.copy(NULL_VALUES.get('identifiers', None))
|
||||
self.set_identifiers(val)
|
||||
elif field == 'language':
|
||||
langs = []
|
||||
if val and val.lower() != 'und':
|
||||
langs = [val]
|
||||
_data['languages'] = langs
|
||||
elif field in STANDARD_METADATA_FIELDS:
|
||||
if val is None:
|
||||
val = copy.copy(NULL_VALUES.get(field, None))
|
||||
@ -553,9 +564,9 @@ class Metadata(object):
|
||||
for attr in TOP_LEVEL_IDENTIFIERS:
|
||||
copy_not_none(self, other, attr)
|
||||
|
||||
other_lang = getattr(other, 'language', None)
|
||||
if other_lang and other_lang.lower() != 'und':
|
||||
self.language = other_lang
|
||||
other_lang = getattr(other, 'languages', [])
|
||||
if other_lang and other_lang != ['und']:
|
||||
self.languages = list(other_lang)
|
||||
if not getattr(self, 'series', None):
|
||||
self.series_index = None
|
||||
|
||||
@ -706,8 +717,8 @@ class Metadata(object):
|
||||
fmt('Tags', u', '.join([unicode(t) for t in self.tags]))
|
||||
if self.series:
|
||||
fmt('Series', self.series + ' #%s'%self.format_series_index())
|
||||
if not self.is_null('language'):
|
||||
fmt('Language', self.language)
|
||||
if not self.is_null('languages'):
|
||||
fmt('Languages', ', '.join(self.languages))
|
||||
if self.rating is not None:
|
||||
fmt('Rating', self.rating)
|
||||
if self.timestamp is not None:
|
||||
@ -743,7 +754,7 @@ class Metadata(object):
|
||||
ans += [(_('Tags'), u', '.join([unicode(t) for t in self.tags]))]
|
||||
if self.series:
|
||||
ans += [(_('Series'), unicode(self.series) + ' #%s'%self.format_series_index())]
|
||||
ans += [(_('Language'), unicode(self.language))]
|
||||
ans += [(_('Languages'), u', '.join(self.languages))]
|
||||
if self.timestamp is not None:
|
||||
ans += [(_('Timestamp'), unicode(self.timestamp.isoformat(' ')))]
|
||||
if self.pubdate is not None:
|
||||
|
@ -38,17 +38,17 @@ def get_metadata_(src, encoding=None):
|
||||
if match:
|
||||
title = match.group(2)
|
||||
else:
|
||||
pat = re.compile('<title>([^<>]+?)</title>', re.IGNORECASE)
|
||||
match = pat.search(src)
|
||||
if match:
|
||||
title = match.group(1)
|
||||
if not title:
|
||||
for x in ('Title','DC.title','DCTERMS.title'):
|
||||
for x in ('DC.title','DCTERMS.title','Title'):
|
||||
pat = get_meta_regexp_(x)
|
||||
match = pat.search(src)
|
||||
if match:
|
||||
title = match.group(1)
|
||||
break
|
||||
if not title:
|
||||
pat = re.compile('<title>([^<>]+?)</title>', re.IGNORECASE)
|
||||
match = pat.search(src)
|
||||
if match:
|
||||
title = match.group(1)
|
||||
|
||||
# Author
|
||||
author = None
|
||||
@ -57,7 +57,7 @@ def get_metadata_(src, encoding=None):
|
||||
if match:
|
||||
author = match.group(2).replace(',', ';')
|
||||
else:
|
||||
for x in ('Author','DC.creator.aut','DCTERMS.creator.aut'):
|
||||
for x in ('Author','DC.creator.aut','DCTERMS.creator.aut', 'DC.creator'):
|
||||
pat = get_meta_regexp_(x)
|
||||
match = pat.search(src)
|
||||
if match:
|
||||
|
@ -67,10 +67,6 @@ def _metadata_from_formats(formats, force_read_metadata=False, pattern=None):
|
||||
|
||||
return mi
|
||||
|
||||
def is_recipe(filename):
|
||||
return filename.startswith('calibre') and \
|
||||
filename.rpartition('.')[0].endswith('_recipe_out')
|
||||
|
||||
def get_metadata(stream, stream_type='lrf', use_libprs_metadata=False,
|
||||
force_read_metadata=False, pattern=None):
|
||||
pos = 0
|
||||
@ -106,7 +102,7 @@ def _get_metadata(stream, stream_type, use_libprs_metadata,
|
||||
mi = MetaInformation(None, None)
|
||||
name = os.path.basename(getattr(stream, 'name', ''))
|
||||
base = metadata_from_filename(name, pat=pattern)
|
||||
if force_read_metadata or is_recipe(name) or prefs['read_file_metadata']:
|
||||
if force_read_metadata or prefs['read_file_metadata']:
|
||||
mi = get_file_type_metadata(stream, stream_type)
|
||||
if base.title == os.path.splitext(name)[0] and \
|
||||
base.is_null('authors') and base.is_null('isbn'):
|
||||
|
@ -19,7 +19,7 @@ from calibre.ebooks.metadata.toc import TOC
|
||||
from calibre.ebooks.metadata import string_to_authors, MetaInformation, check_isbn
|
||||
from calibre.ebooks.metadata.book.base import Metadata
|
||||
from calibre.utils.date import parse_date, isoformat
|
||||
from calibre.utils.localization import get_lang
|
||||
from calibre.utils.localization import get_lang, canonicalize_lang
|
||||
from calibre import prints, guess_type
|
||||
from calibre.utils.cleantext import clean_ascii_chars
|
||||
from calibre.utils.config import tweaks
|
||||
@ -515,6 +515,7 @@ class OPF(object): # {{{
|
||||
'(re:match(@opf:scheme, "calibre|libprs500", "i") or re:match(@scheme, "calibre|libprs500", "i"))]')
|
||||
uuid_id_path = XPath('descendant::*[re:match(name(), "identifier", "i") and '+
|
||||
'(re:match(@opf:scheme, "uuid", "i") or re:match(@scheme, "uuid", "i"))]')
|
||||
languages_path = XPath('descendant::*[local-name()="language"]')
|
||||
|
||||
manifest_path = XPath('descendant::*[re:match(name(), "manifest", "i")]/*[re:match(name(), "item", "i")]')
|
||||
manifest_ppath = XPath('descendant::*[re:match(name(), "manifest", "i")]')
|
||||
@ -523,7 +524,6 @@ class OPF(object): # {{{
|
||||
|
||||
title = MetadataField('title', formatter=lambda x: re.sub(r'\s+', ' ', x))
|
||||
publisher = MetadataField('publisher')
|
||||
language = MetadataField('language')
|
||||
comments = MetadataField('description')
|
||||
category = MetadataField('type')
|
||||
rights = MetadataField('rights')
|
||||
@ -930,6 +930,44 @@ class OPF(object): # {{{
|
||||
return property(fget=fget, fset=fset)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def language(self):
|
||||
|
||||
def fget(self):
|
||||
ans = self.languages
|
||||
if ans:
|
||||
return ans[0]
|
||||
|
||||
def fset(self, val):
|
||||
self.languages = [val]
|
||||
|
||||
return property(fget=fget, fset=fset)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def languages(self):
|
||||
|
||||
def fget(self):
|
||||
ans = []
|
||||
for match in self.languages_path(self.metadata):
|
||||
t = self.get_text(match)
|
||||
if t and t.strip():
|
||||
l = canonicalize_lang(t.strip())
|
||||
if l:
|
||||
ans.append(l)
|
||||
return ans
|
||||
|
||||
def fset(self, val):
|
||||
matches = self.languages_path(self.metadata)
|
||||
for x in matches:
|
||||
x.getparent().remove(x)
|
||||
|
||||
for lang in val:
|
||||
l = self.create_metadata_element('language')
|
||||
self.set_text(l, unicode(lang))
|
||||
|
||||
return property(fget=fget, fset=fset)
|
||||
|
||||
|
||||
@dynamic_property
|
||||
def book_producer(self):
|
||||
@ -1052,9 +1090,9 @@ class OPF(object): # {{{
|
||||
val = getattr(mi, attr, None)
|
||||
if val is not None and val != [] and val != (None, None):
|
||||
setattr(self, attr, val)
|
||||
lang = getattr(mi, 'language', None)
|
||||
if lang and lang != 'und':
|
||||
self.language = lang
|
||||
langs = getattr(mi, 'languages', [])
|
||||
if langs and langs != ['und']:
|
||||
self.languages = langs
|
||||
temp = self.to_book_metadata()
|
||||
temp.smart_update(mi, replace_metadata=replace_metadata)
|
||||
self._user_metadata_ = temp.get_all_user_metadata(True)
|
||||
@ -1202,10 +1240,11 @@ class OPFCreator(Metadata):
|
||||
dc_attrs={'id':__appname__+'_id'}))
|
||||
if getattr(self, 'pubdate', None) is not None:
|
||||
a(DC_ELEM('date', self.pubdate.isoformat()))
|
||||
lang = self.language
|
||||
if not lang or lang.lower() == 'und':
|
||||
lang = get_lang().replace('_', '-')
|
||||
a(DC_ELEM('language', lang))
|
||||
langs = self.languages
|
||||
if not langs or langs == ['und']:
|
||||
langs = [get_lang().replace('_', '-').partition('-')[0]]
|
||||
for lang in langs:
|
||||
a(DC_ELEM('language', lang))
|
||||
if self.comments:
|
||||
a(DC_ELEM('description', self.comments))
|
||||
if self.publisher:
|
||||
@ -1288,8 +1327,9 @@ def metadata_to_opf(mi, as_string=True):
|
||||
mi.book_producer = __appname__ + ' (%s) '%__version__ + \
|
||||
'[http://calibre-ebook.com]'
|
||||
|
||||
if not mi.language:
|
||||
mi.language = 'UND'
|
||||
if not mi.languages:
|
||||
lang = get_lang().replace('_', '-').partition('-')[0]
|
||||
mi.languages = [lang]
|
||||
|
||||
root = etree.fromstring(textwrap.dedent(
|
||||
'''
|
||||
@ -1339,8 +1379,10 @@ def metadata_to_opf(mi, as_string=True):
|
||||
factory(DC('identifier'), val, scheme=icu_upper(key))
|
||||
if mi.rights:
|
||||
factory(DC('rights'), mi.rights)
|
||||
factory(DC('language'), mi.language if mi.language and mi.language.lower()
|
||||
!= 'und' else get_lang().replace('_', '-'))
|
||||
for lang in mi.languages:
|
||||
if not lang or lang.lower() == 'und':
|
||||
continue
|
||||
factory(DC('language'), lang)
|
||||
if mi.tags:
|
||||
for tag in mi.tags:
|
||||
factory(DC('subject'), tag)
|
||||
|
@ -22,6 +22,7 @@ from calibre.ebooks.chardet import xml_to_unicode
|
||||
from calibre.ebooks.metadata.book.base import Metadata
|
||||
from calibre.library.comments import sanitize_comments_html
|
||||
from calibre.utils.date import parse_date
|
||||
from calibre.utils.localization import canonicalize_lang
|
||||
|
||||
class Worker(Thread): # Get details {{{
|
||||
|
||||
@ -106,10 +107,11 @@ class Worker(Thread): # Get details {{{
|
||||
r'([0-9.]+) (out of|von|su|étoiles sur) (\d+)( (stars|Sternen|stelle)){0,1}')
|
||||
|
||||
lm = {
|
||||
'en': ('English', 'Englisch'),
|
||||
'fr': ('French', 'Français'),
|
||||
'it': ('Italian', 'Italiano'),
|
||||
'de': ('German', 'Deutsch'),
|
||||
'eng': ('English', 'Englisch'),
|
||||
'fra': ('French', 'Français'),
|
||||
'ita': ('Italian', 'Italiano'),
|
||||
'deu': ('German', 'Deutsch'),
|
||||
'spa': ('Spanish', 'Espa\xf1ol', 'Espaniol'),
|
||||
}
|
||||
self.lang_map = {}
|
||||
for code, names in lm.iteritems():
|
||||
@ -374,8 +376,11 @@ class Worker(Thread): # Get details {{{
|
||||
def parse_language(self, pd):
|
||||
for x in reversed(pd.xpath(self.language_xpath)):
|
||||
if x.tail:
|
||||
ans = x.tail.strip()
|
||||
ans = self.lang_map.get(ans, None)
|
||||
raw = x.tail.strip()
|
||||
ans = self.lang_map.get(raw, None)
|
||||
if ans:
|
||||
return ans
|
||||
ans = canonicalize_lang(ans)
|
||||
if ans:
|
||||
return ans
|
||||
# }}}
|
||||
@ -388,7 +393,7 @@ class Amazon(Source):
|
||||
capabilities = frozenset(['identify', 'cover'])
|
||||
touched_fields = frozenset(['title', 'authors', 'identifier:amazon',
|
||||
'identifier:isbn', 'rating', 'comments', 'publisher', 'pubdate',
|
||||
'language'])
|
||||
'languages'])
|
||||
has_html_comments = True
|
||||
supports_gzip_transfer_encoding = True
|
||||
|
||||
|
@ -20,6 +20,7 @@ from calibre.ebooks.metadata.book.base import Metadata
|
||||
from calibre.ebooks.chardet import xml_to_unicode
|
||||
from calibre.utils.date import parse_date, utcnow
|
||||
from calibre.utils.cleantext import clean_ascii_chars
|
||||
from calibre.utils.localization import canonicalize_lang
|
||||
from calibre import as_unicode
|
||||
|
||||
NAMESPACES = {
|
||||
@ -95,7 +96,9 @@ def to_metadata(browser, log, entry_, timeout): # {{{
|
||||
return mi
|
||||
|
||||
mi.comments = get_text(extra, description)
|
||||
#mi.language = get_text(extra, language)
|
||||
lang = canonicalize_lang(get_text(extra, language))
|
||||
if lang:
|
||||
mi.language = lang
|
||||
mi.publisher = get_text(extra, publisher)
|
||||
|
||||
# ISBN
|
||||
@ -162,7 +165,7 @@ class GoogleBooks(Source):
|
||||
capabilities = frozenset(['identify', 'cover'])
|
||||
touched_fields = frozenset(['title', 'authors', 'tags', 'pubdate',
|
||||
'comments', 'publisher', 'identifier:isbn', 'rating',
|
||||
'identifier:google']) # language currently disabled
|
||||
'identifier:google', 'languages'])
|
||||
supports_gzip_transfer_encoding = True
|
||||
cached_cover_url_is_reliable = False
|
||||
|
||||
|
@ -484,6 +484,7 @@ def identify(log, abort, # {{{
|
||||
'publication dates')
|
||||
start_time = time.time()
|
||||
results = merge_identify_results(results, log)
|
||||
|
||||
log('We have %d merged results, merging took: %.2f seconds' %
|
||||
(len(results), time.time() - start_time))
|
||||
|
||||
|
@ -35,7 +35,7 @@ class ISBNDB(Source):
|
||||
|
||||
options = (
|
||||
Option('isbndb_key', 'string', None, _('IsbnDB key:'),
|
||||
_('To use isbndb.com you have to sign up for a free account'
|
||||
_('To use isbndb.com you have to sign up for a free account '
|
||||
'at isbndb.com and get an access key.')),
|
||||
)
|
||||
|
||||
|
@ -35,7 +35,7 @@ class OverDrive(Source):
|
||||
capabilities = frozenset(['identify', 'cover'])
|
||||
touched_fields = frozenset(['title', 'authors', 'tags', 'pubdate',
|
||||
'comments', 'publisher', 'identifier:isbn', 'series', 'series_index',
|
||||
'language', 'identifier:overdrive'])
|
||||
'languages', 'identifier:overdrive'])
|
||||
has_html_comments = True
|
||||
supports_gzip_transfer_encoding = False
|
||||
cached_cover_url_is_reliable = True
|
||||
@ -421,8 +421,10 @@ class OverDrive(Source):
|
||||
pass
|
||||
if lang:
|
||||
lang = lang[0].strip().lower()
|
||||
mi.language = {'english':'en', 'french':'fr', 'german':'de',
|
||||
'spanish':'es'}.get(lang, None)
|
||||
lang = {'english':'eng', 'french':'fra', 'german':'deu',
|
||||
'spanish':'spa'}.get(lang, None)
|
||||
if lang:
|
||||
mi.language = lang
|
||||
|
||||
if ebook_isbn:
|
||||
#print "ebook isbn is "+str(ebook_isbn[0])
|
||||
|
@ -320,7 +320,7 @@ class MOBIHeader(object): # {{{
|
||||
self.exth = EXTHHeader(self.raw[self.exth_offset:])
|
||||
|
||||
self.end_of_exth = self.exth_offset + self.exth.length
|
||||
self.bytes_after_exth = self.fullname_offset - self.end_of_exth
|
||||
self.bytes_after_exth = self.raw[self.end_of_exth:self.fullname_offset]
|
||||
|
||||
def __str__(self):
|
||||
ans = ['*'*20 + ' MOBI Header '+ '*'*20]
|
||||
@ -386,7 +386,9 @@ class MOBIHeader(object): # {{{
|
||||
|
||||
if self.has_exth:
|
||||
ans += '\n\n' + str(self.exth)
|
||||
ans += '\n\nBytes after EXTH: %d'%self.bytes_after_exth
|
||||
ans += '\n\nBytes after EXTH (%d bytes): %s'%(
|
||||
len(self.bytes_after_exth),
|
||||
format_bytes(self.bytes_after_exth))
|
||||
|
||||
ans += '\nNumber of bytes after full name: %d' % (len(self.raw) - (self.fullname_offset +
|
||||
self.fullname_length))
|
||||
@ -588,7 +590,7 @@ class IndexHeader(object): # {{{
|
||||
|
||||
|
||||
def __str__(self):
|
||||
ans = ['*'*20 + ' Index Header '+ '*'*20]
|
||||
ans = ['*'*20 + ' Index Header (%d bytes)'%len(self.record.raw)+ '*'*20]
|
||||
a = ans.append
|
||||
def u(w):
|
||||
a('Unknown: %r (%d bytes) (All zeros: %r)'%(w,
|
||||
@ -644,7 +646,7 @@ class Tag(object): # {{{
|
||||
|
||||
INTERPRET_MAP = {
|
||||
'subchapter': {
|
||||
5 : ('Parent chapter index', 'parent_index')
|
||||
21 : ('Parent chapter index', 'parent_index')
|
||||
},
|
||||
|
||||
'article' : {
|
||||
@ -700,7 +702,8 @@ class Tag(object): # {{{
|
||||
self.desc, self.attr = td[tag_type]
|
||||
except:
|
||||
print ('Unknown tag value: %d'%tag_type)
|
||||
self.desc = '??Unknown (tag value: %d)'%tag_type
|
||||
self.desc = '??Unknown (tag value: %d type: %s)'%(
|
||||
tag_type, entry_type)
|
||||
self.attr = 'unknown'
|
||||
if '_offset' in self.attr:
|
||||
self.cncx_value = cncx[self.value]
|
||||
@ -748,7 +751,7 @@ class IndexEntry(object): # {{{
|
||||
try:
|
||||
self.entry_type = self.TYPES[entry_type]
|
||||
except KeyError:
|
||||
raise ValueError('Unknown Index Entry type: %s'%hex(entry_type))
|
||||
raise ValueError('Unknown Index Entry type: %s'%bin(entry_type))
|
||||
|
||||
if control_byte_count not in (1, 2):
|
||||
raise ValueError('Unknown control byte count: %d'%
|
||||
@ -766,6 +769,7 @@ class IndexEntry(object): # {{{
|
||||
flags = self.flags
|
||||
for tag in expected_tags:
|
||||
vals = []
|
||||
|
||||
if tag.tag > 64:
|
||||
has_tag = flags & 0b1
|
||||
flags = flags >> 1
|
||||
@ -781,8 +785,8 @@ class IndexEntry(object): # {{{
|
||||
self.consumed = len(orig_raw) - len(raw)
|
||||
self.trailing_bytes = raw
|
||||
if self.trailing_bytes.replace(b'\0', b''):
|
||||
raise ValueError('IndexEntry has leftover bytes: %s'%format_bytes(
|
||||
self.trailing_bytes))
|
||||
raise ValueError('%s has leftover bytes: %s'%(self, format_bytes(
|
||||
self.trailing_bytes)))
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
@ -1023,8 +1027,14 @@ class IndexRecord(object): # {{{
|
||||
for entry in self.indices:
|
||||
offset = entry.offset
|
||||
a(str(entry))
|
||||
t = self.alltext
|
||||
if offset is not None and self.alltext is not None:
|
||||
a('\tHTML at offset: %r'%self.alltext[offset:offset+100])
|
||||
a('\tHTML before offset: %r'%t[offset-50:offset])
|
||||
a('\tHTML after offset: %r'%t[offset:offset+50])
|
||||
p = offset+entry.size
|
||||
a('\tHTML before end: %r'%t[p-50:p])
|
||||
a('\tHTML after end: %r'%t[p:p+50])
|
||||
|
||||
a('')
|
||||
|
||||
return '\n'.join(ans)
|
||||
@ -1052,11 +1062,12 @@ class CNCX(object): # {{{
|
||||
self.records[pos+record_offset] = raw[
|
||||
pos+consumed:pos+consumed+length].decode(codec)
|
||||
except:
|
||||
byts = raw[pos+consumed:pos+consumed+length]
|
||||
byts = raw[pos:]
|
||||
r = format_bytes(byts)
|
||||
print ('CNCX entry at offset %d has unknown format %s'%(
|
||||
pos+record_offset, r))
|
||||
self.records[pos+record_offset] = r
|
||||
pos = len(raw)
|
||||
pos += consumed+length
|
||||
record_offset += 0x10000
|
||||
|
||||
@ -1213,8 +1224,7 @@ class TBSIndexing(object): # {{{
|
||||
tbs_type = 0
|
||||
is_periodical = self.doc_type in (257, 258, 259)
|
||||
if len(byts):
|
||||
outermost_index, extra, consumed = decode_tbs(byts, flag_size=4 if
|
||||
is_periodical else 3)
|
||||
outermost_index, extra, consumed = decode_tbs(byts, flag_size=3)
|
||||
byts = byts[consumed:]
|
||||
for k in extra:
|
||||
tbs_type |= k
|
||||
|
@ -4,6 +4,7 @@ __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from struct import pack
|
||||
from calibre.utils.localization import lang_as_iso639_1
|
||||
|
||||
lang_codes = {
|
||||
}
|
||||
@ -314,7 +315,8 @@ def iana2mobi(icode):
|
||||
subtags = list(icode.split('-'))
|
||||
while len(subtags) > 0:
|
||||
lang = subtags.pop(0).lower()
|
||||
if lang in IANA_MOBI:
|
||||
lang = lang_as_iso639_1(lang)
|
||||
if lang and lang in IANA_MOBI:
|
||||
langdict = IANA_MOBI[lang]
|
||||
break
|
||||
|
||||
|
@ -55,13 +55,6 @@ class MOBIOutput(OutputFormatPlugin):
|
||||
' specified directory. If the directory already '
|
||||
'exists, it will be deleted.')
|
||||
),
|
||||
OptionRecommendation(name='mobi_navpoints_only_deepest',
|
||||
recommended_value=False,
|
||||
help=_('When adding navpoints for the chapter-to-chapter'
|
||||
' navigation on the kindle, use only the lowest level '
|
||||
'of items in the TOC, instead of items at every level.')
|
||||
),
|
||||
|
||||
OptionRecommendation(name='kindlegen',
|
||||
recommended_value=False,
|
||||
help=('Use kindlegen (must be in your PATH) to generate the'
|
||||
|
@ -13,9 +13,9 @@ First sequences:
|
||||
0b0110 : 80 2
|
||||
0b0111 : 80 2 80
|
||||
|
||||
Other sequences:
|
||||
0b0101 : 4 1a
|
||||
0b0001 : c b1
|
||||
0b0001 = 0
|
||||
0b0010 = 0
|
||||
0b0100 = 2
|
||||
|
||||
Opening record
|
||||
----------------
|
||||
|
@ -1710,8 +1710,6 @@ class MobiWriter(object):
|
||||
'''
|
||||
from calibre.ebooks.oeb.base import TOC
|
||||
items = list(self._oeb.toc.iterdescendants())
|
||||
if self.opts.mobi_navpoints_only_deepest:
|
||||
items = [i for i in items if i.depth == 1]
|
||||
offsets = {i:self._id_offsets.get(i.href, -1) for i in items if i.href}
|
||||
items = [i for i in items if offsets[i] > -1]
|
||||
items.sort(key=lambda i:offsets[i])
|
||||
|
@ -33,8 +33,10 @@ class CNCX(object): # {{{
|
||||
self.strings[item.title] = 0
|
||||
if is_periodical:
|
||||
self.strings[item.klass] = 0
|
||||
aut, desc = item.author, item.description
|
||||
self.strings[item.author] = self.strings[item.description] = 0
|
||||
if item.author:
|
||||
self.strings[item.author] = 0
|
||||
if item.description:
|
||||
self.strings[item.description] = 0
|
||||
|
||||
self.records = []
|
||||
offset = 0
|
||||
@ -65,10 +67,10 @@ class CNCX(object): # {{{
|
||||
class TAGX(object): # {{{
|
||||
|
||||
BITMASKS = {11:0b1}
|
||||
BITMASKS.update({x:i+1 for i, x in enumerate([1, 2, 3, 4, 5, 21, 22, 23])})
|
||||
BITMASKS.update({x:i+1 for i, x in enumerate([69, 70, 71, 72, 73])})
|
||||
BITMASKS.update({x:(1 << i) for i, x in enumerate([1, 2, 3, 4, 5, 21, 22, 23])})
|
||||
BITMASKS.update({x:(1 << i) for i, x in enumerate([69, 70, 71, 72, 73])})
|
||||
|
||||
NUM_VALUES = defaultdict(lambda x:1)
|
||||
NUM_VALUES = defaultdict(lambda :1)
|
||||
NUM_VALUES[11] = 3
|
||||
NUM_VALUES[0] = 0
|
||||
|
||||
@ -80,7 +82,7 @@ class TAGX(object): # {{{
|
||||
buf.append(tag)
|
||||
buf.append(self.NUM_VALUES[tag])
|
||||
# bitmask
|
||||
buf.append((1 << (self.BITMASKS[tag])) if tag else 0)
|
||||
buf.append(self.BITMASKS[tag] if tag else 0)
|
||||
# eof
|
||||
buf.append(0 if tag else 1)
|
||||
|
||||
@ -95,7 +97,8 @@ class TAGX(object): # {{{
|
||||
'''
|
||||
TAGX block for the Primary index header of a periodical
|
||||
'''
|
||||
map(self.add_tag, (1, 2, 3, 4, 5, 21, 22, 23, 0, 69, 70, 71, 72, 73, 0))
|
||||
list(map(self.add_tag, (1, 2, 3, 4, 5, 21, 22, 23, 0, 69, 70, 71, 72,
|
||||
73, 0)))
|
||||
return self.header(2) + bytes(self.byts)
|
||||
|
||||
@property
|
||||
@ -103,7 +106,21 @@ class TAGX(object): # {{{
|
||||
'''
|
||||
TAGX block for the secondary index header of a periodical
|
||||
'''
|
||||
map(self.add_tag, (11, 0))
|
||||
list(map(self.add_tag, (11, 0)))
|
||||
return self.header(1) + bytes(self.byts)
|
||||
|
||||
|
||||
|
||||
class TAGX_BOOK(TAGX):
|
||||
BITMASKS = dict(TAGX.BITMASKS)
|
||||
BITMASKS.update({x:(1 << i) for i, x in enumerate([1, 2, 3, 4, 21, 22, 23])})
|
||||
|
||||
@property
|
||||
def hierarchical_book(self):
|
||||
'''
|
||||
TAGX block for the primary index header of a hierarchical book
|
||||
'''
|
||||
list(map(self.add_tag, (1, 2, 3, 4, 21, 22, 23, 0)))
|
||||
return self.header(1) + bytes(self.byts)
|
||||
|
||||
@property
|
||||
@ -111,9 +128,10 @@ class TAGX(object): # {{{
|
||||
'''
|
||||
TAGX block for the primary index header of a flat book
|
||||
'''
|
||||
map(self.add_tag, (1, 2, 3, 4, 0))
|
||||
list(map(self.add_tag, (1, 2, 3, 4, 0)))
|
||||
return self.header(1) + bytes(self.byts)
|
||||
|
||||
|
||||
# }}}
|
||||
|
||||
# Index Entries {{{
|
||||
@ -181,9 +199,12 @@ class IndexEntry(object):
|
||||
def entry_type(self):
|
||||
ans = 0
|
||||
for tag in self.tag_nums:
|
||||
ans |= (1 << (TAGX.BITMASKS[tag])) # 1 << x == 2**x
|
||||
ans |= TAGX.BITMASKS[tag]
|
||||
return ans
|
||||
|
||||
def attr_for_tag(self, tag):
|
||||
return self.RTAG_MAP[tag]
|
||||
|
||||
@property
|
||||
def bytestring(self):
|
||||
buf = StringIO()
|
||||
@ -201,13 +222,13 @@ class IndexEntry(object):
|
||||
for attr in ('image_index', 'desc_offset', 'author_offset'):
|
||||
val = getattr(self, attr)
|
||||
if val is not None:
|
||||
tag = self.RTAG_MAP[attr]
|
||||
tag = self.TAG_VALUES[attr]
|
||||
bm = TAGX.BITMASKS[tag]
|
||||
flags |= bm
|
||||
buf.write(bytes(bytearray([flags])))
|
||||
|
||||
for tag in self.tag_nums:
|
||||
attr = self.RTAG_MAP[tag]
|
||||
attr = self.attr_for_tag(tag)
|
||||
val = getattr(self, attr)
|
||||
if isinstance(val, int):
|
||||
val = [val]
|
||||
@ -223,10 +244,21 @@ class IndexEntry(object):
|
||||
ans = buf.getvalue()
|
||||
return ans
|
||||
|
||||
class BookIndexEntry(IndexEntry):
|
||||
|
||||
@property
|
||||
def entry_type(self):
|
||||
tagx = TAGX_BOOK()
|
||||
ans = 0
|
||||
for tag in self.tag_nums:
|
||||
ans |= tagx.BITMASKS[tag]
|
||||
return ans
|
||||
|
||||
|
||||
class PeriodicalIndexEntry(IndexEntry):
|
||||
|
||||
def __init__(self, offset, label_offset, class_offset, depth):
|
||||
IndexEntry.__init__(offset, label_offset)
|
||||
IndexEntry.__init__(self, offset, label_offset)
|
||||
self.depth = depth
|
||||
self.class_offset = class_offset
|
||||
self.control_byte_count = 2
|
||||
@ -237,12 +269,14 @@ class SecondaryIndexEntry(IndexEntry):
|
||||
'mastheadImage':69}
|
||||
|
||||
def __init__(self, index):
|
||||
IndexEntry.__init__(self, index, 0)
|
||||
IndexEntry.__init__(self, 0, 0)
|
||||
self.index = index
|
||||
|
||||
tag = self.INDEX_MAP[index]
|
||||
|
||||
# The values for this index entry
|
||||
self.secondary = [len(self.INDEX_MAP) if tag == min(
|
||||
# I dont know what the 5 means, it is not the number of entries
|
||||
self.secondary = [5 if tag == min(
|
||||
self.INDEX_MAP.itervalues()) else 0, 0, tag]
|
||||
|
||||
@property
|
||||
@ -456,7 +490,6 @@ class Indexer(object): # {{{
|
||||
if not desc: desc = _('No details available')
|
||||
node.author, node.description = aut, desc
|
||||
|
||||
|
||||
self.cncx = CNCX(oeb.toc, self.is_periodical)
|
||||
|
||||
if self.is_periodical:
|
||||
@ -478,7 +511,7 @@ class Indexer(object): # {{{
|
||||
def create_index_record(self, secondary=False): # {{{
|
||||
header_length = 192
|
||||
buf = StringIO()
|
||||
indices = list(SecondaryIndexEntry.entries) if secondary else self.indices
|
||||
indices = list(SecondaryIndexEntry.entries()) if secondary else self.indices
|
||||
|
||||
# Write index entries
|
||||
offsets = []
|
||||
@ -524,7 +557,9 @@ class Indexer(object): # {{{
|
||||
tagx_block = TAGX().secondary
|
||||
else:
|
||||
tagx_block = (TAGX().periodical if self.is_periodical else
|
||||
TAGX().flat_book)
|
||||
(TAGX_BOOK().hierarchical_book if
|
||||
self.book_has_subchapters else
|
||||
TAGX_BOOK().flat_book))
|
||||
header_length = 192
|
||||
|
||||
# Ident 0 - 4
|
||||
@ -552,7 +587,7 @@ class Indexer(object): # {{{
|
||||
buf.write(b'\xff'*4)
|
||||
|
||||
# Number of index entries 36-40
|
||||
indices = list(SecondaryIndexEntry.entries) if secondary else self.indices
|
||||
indices = list(SecondaryIndexEntry.entries()) if secondary else self.indices
|
||||
buf.write(pack(b'>I', len(indices)))
|
||||
|
||||
# ORDT offset 40-44
|
||||
@ -583,8 +618,12 @@ class Indexer(object): # {{{
|
||||
|
||||
# The index of the last entry in the NCX
|
||||
idx = indices[-1].index
|
||||
buf.write(encode_number_as_hex(idx) if isinstance(idx, int) else
|
||||
idx.encode('ascii'))
|
||||
if isinstance(idx, int):
|
||||
idx = encode_number_as_hex(idx)
|
||||
else:
|
||||
idx = idx.encode('ascii')
|
||||
idx = (bytes(bytearray([len(idx)]))) + idx
|
||||
buf.write(idx)
|
||||
|
||||
# The number of entries in the NCX
|
||||
buf.write(pack(b'>H', num))
|
||||
@ -606,47 +645,98 @@ class Indexer(object): # {{{
|
||||
# }}}
|
||||
|
||||
def create_book_index(self): # {{{
|
||||
self.book_has_subchapters = False
|
||||
indices = []
|
||||
seen = set()
|
||||
seen, sub_seen = set(), set()
|
||||
id_offsets = self.serializer.id_offsets
|
||||
|
||||
for node in self.oeb.toc.iterdescendants():
|
||||
# Flatten toc to contain only chapters and subchapters
|
||||
# Anything deeper than a subchapter is made into a subchapter
|
||||
chapters = []
|
||||
for node in self.oeb.toc:
|
||||
try:
|
||||
offset = id_offsets[node.href]
|
||||
label = self.cncx[node.title]
|
||||
except:
|
||||
self.log.warn('TOC item %s not found in document'%node.href)
|
||||
self.log.warn('TOC item %s [%s] not found in document'%(
|
||||
node.title, node.href))
|
||||
continue
|
||||
|
||||
if offset in seen:
|
||||
continue
|
||||
seen.add(offset)
|
||||
index = IndexEntry(offset, label)
|
||||
indices.append(index)
|
||||
|
||||
indices.sort(key=lambda x:x.offset)
|
||||
subchapters = []
|
||||
chapters.append((offset, label, subchapters))
|
||||
|
||||
# Set lengths
|
||||
for i, index in enumerate(indices):
|
||||
try:
|
||||
next_offset = indices[i+1].offset
|
||||
except:
|
||||
next_offset = self.serializer.body_end_offset
|
||||
index.length = next_offset - index.offset
|
||||
for descendant in node.iterdescendants():
|
||||
try:
|
||||
offset = id_offsets[descendant.href]
|
||||
label = self.cncx[descendant.title]
|
||||
except:
|
||||
self.log.warn('TOC item %s [%s] not found in document'%(
|
||||
descendant.title, descendant.href))
|
||||
continue
|
||||
|
||||
# Remove empty nodes
|
||||
indices = [i for i in indices if i.length > 0]
|
||||
if offset in sub_seen:
|
||||
continue
|
||||
sub_seen.add(offset)
|
||||
subchapters.append((offset, label))
|
||||
|
||||
# Set index values
|
||||
for i, index in enumerate(indices):
|
||||
index.index = i
|
||||
subchapters.sort(key=lambda x:x[0])
|
||||
|
||||
# Set lengths again to close up any gaps left by filtering
|
||||
for i, index in enumerate(indices):
|
||||
try:
|
||||
next_offset = indices[i+1].offset
|
||||
except:
|
||||
next_offset = self.serializer.body_end_offset
|
||||
index.length = next_offset - index.offset
|
||||
chapters.sort(key=lambda x:x[0])
|
||||
|
||||
chapters = [(BookIndexEntry(x[0], x[1]), [
|
||||
BookIndexEntry(y[0], y[1]) for y in x[2]]) for x in chapters]
|
||||
|
||||
def set_length(indices):
|
||||
for i, index in enumerate(indices):
|
||||
try:
|
||||
next_offset = indices[i+1].offset
|
||||
except:
|
||||
next_offset = self.serializer.body_end_offset
|
||||
index.length = next_offset - index.offset
|
||||
|
||||
# Set chapter and subchapter lengths
|
||||
set_length([x[0] for x in chapters])
|
||||
for x in chapters:
|
||||
set_length(x[1])
|
||||
|
||||
# Remove empty chapters
|
||||
chapters = [x for x in chapters if x[0].length > 0]
|
||||
|
||||
# Remove invalid subchapters
|
||||
for i, x in enumerate(list(chapters)):
|
||||
chapter, subchapters = x
|
||||
ok_subchapters = []
|
||||
for sc in subchapters:
|
||||
if sc.offset < chapter.next_offset and sc.length > 0:
|
||||
ok_subchapters.append(sc)
|
||||
chapters[i] = (chapter, ok_subchapters)
|
||||
|
||||
# Reset chapter and subchapter lengths in case any were removed
|
||||
set_length([x[0] for x in chapters])
|
||||
for x in chapters:
|
||||
set_length(x[1])
|
||||
|
||||
# Set index and depth values
|
||||
indices = []
|
||||
for index, x in enumerate(chapters):
|
||||
x[0].index = index
|
||||
indices.append(x[0])
|
||||
|
||||
for chapter, subchapters in chapters:
|
||||
for sc in subchapters:
|
||||
index += 1
|
||||
sc.index = index
|
||||
sc.parent_index = chapter.index
|
||||
indices.append(sc)
|
||||
sc.depth = 1
|
||||
self.book_has_subchapters = True
|
||||
if subchapters:
|
||||
chapter.first_child_index = subchapters[0].index
|
||||
chapter.last_child_index = subchapters[-1].index
|
||||
|
||||
return indices
|
||||
|
||||
|
@ -106,7 +106,7 @@ class MobiWriter(object):
|
||||
self.log.exception('Failed to generate MOBI index:')
|
||||
else:
|
||||
self.primary_index_record_idx = len(self.records)
|
||||
for i in xrange(len(self.records)):
|
||||
for i in xrange(self.last_text_record_idx + 1):
|
||||
if i == 0: continue
|
||||
tbs = self.indexer.get_trailing_byte_sequence(i)
|
||||
self.records[i] += encode_trailing_data(tbs)
|
||||
@ -146,6 +146,7 @@ class MobiWriter(object):
|
||||
oeb = self.oeb
|
||||
oeb.logger.info('Serializing images...')
|
||||
self.image_records = []
|
||||
self.image_map = {}
|
||||
|
||||
mh_href = self.masthead_offset = None
|
||||
if 'masthead' in oeb.guide:
|
||||
@ -171,10 +172,12 @@ class MobiWriter(object):
|
||||
oeb.logger.warn('Bad image file %r' % item.href)
|
||||
continue
|
||||
else:
|
||||
self.image_map[item.href] = len(self.image_records)
|
||||
self.image_records.append(data)
|
||||
|
||||
if item.href == mh_href:
|
||||
self.masthead_offset = len(self.image_records) - 1
|
||||
elif item.href == cover_href:
|
||||
self.image_records.append(data)
|
||||
self.cover_offset = len(self.image_records) - 1
|
||||
try:
|
||||
data = rescale_image(item.data, dimen=MAX_THUMB_DIMEN,
|
||||
@ -193,7 +196,7 @@ class MobiWriter(object):
|
||||
|
||||
def generate_text(self):
|
||||
self.oeb.logger.info('Serializing markup content...')
|
||||
self.serializer = Serializer(self.oeb, self.images,
|
||||
self.serializer = Serializer(self.oeb, self.image_map,
|
||||
write_page_breaks_after_item=self.write_page_breaks_after_item)
|
||||
text = self.serializer()
|
||||
self.text_length = len(text)
|
||||
@ -331,7 +334,9 @@ class MobiWriter(object):
|
||||
if self.indexer.is_flat_periodical:
|
||||
bt = 0x102
|
||||
elif self.indexer.is_periodical:
|
||||
bt = 0x101
|
||||
# If you change this, remember to change the cdetype in the EXTH
|
||||
# header as well
|
||||
bt = 0x103
|
||||
|
||||
record0.write(pack(b'>IIIII',
|
||||
0xe8, bt, 65001, uid, 6))
|
||||
@ -506,7 +511,9 @@ class MobiWriter(object):
|
||||
|
||||
# Write cdetype
|
||||
if self.is_periodical:
|
||||
data = b'NWPR'
|
||||
# If you set the book type header field to 0x101 use NWPR here if
|
||||
# you use 0x103 use MAGZ
|
||||
data = b'MAGZ'
|
||||
else:
|
||||
data = b'EBOK'
|
||||
exth.write(pack(b'>II', 501, len(data)+8))
|
||||
@ -530,8 +537,6 @@ class MobiWriter(object):
|
||||
exth.write(pack(b'>II', EXTH_CODES['lastupdatetime'], len(datestr) + 8))
|
||||
exth.write(datestr)
|
||||
nrecs += 1
|
||||
exth.write(pack(b'>III', EXTH_CODES['versionnumber'], 12, 7))
|
||||
nrecs += 1
|
||||
|
||||
if self.is_periodical:
|
||||
# Pretend to be amazon's super secret periodical generator
|
||||
@ -539,7 +544,7 @@ class MobiWriter(object):
|
||||
else:
|
||||
# Pretend to be kindlegen 1.2
|
||||
vals = {204:201, 205:1, 206:2, 207:33307}
|
||||
for code, val in vals:
|
||||
for code, val in vals.iteritems():
|
||||
exth.write(pack(b'>III', code, 12, val))
|
||||
nrecs += 1
|
||||
|
||||
|
@ -110,6 +110,7 @@ class Serializer(object):
|
||||
self.serialize_head()
|
||||
self.serialize_body()
|
||||
buf.write(b'</html>')
|
||||
self.end_offset = buf.tell()
|
||||
self.fixup_links()
|
||||
return buf.getvalue()
|
||||
|
||||
@ -206,20 +207,18 @@ class Serializer(object):
|
||||
self.breaks.append(buf.tell() - 1)
|
||||
self.id_offsets[urlnormalize(item.href)] = buf.tell()
|
||||
if item.is_section_start:
|
||||
buf.write(b'<div>')
|
||||
buf.write(b'<a ></a> ')
|
||||
if item.is_article_start:
|
||||
buf.write(b'<div>')
|
||||
buf.write(b'<a ></a> <a ></a>')
|
||||
for elem in item.data.find(XHTML('body')):
|
||||
self.serialize_elem(elem, item)
|
||||
if item.is_article_end:
|
||||
# Kindle periodical article end marker
|
||||
buf.write(b'<div></div>')
|
||||
if self.write_page_breaks_after_item:
|
||||
buf.write(b'<mbp:pagebreak/>')
|
||||
if item.is_article_end:
|
||||
buf.write(b'</div>')
|
||||
# Kindle periodical article end marker
|
||||
buf.write(b'<a ></a> <a ></a>')
|
||||
if item.is_section_end:
|
||||
buf.write(b'</div>')
|
||||
buf.write(b' <a ></a>')
|
||||
self.anchor_offset = None
|
||||
|
||||
def serialize_elem(self, elem, item, nsrmap=NSRMAP):
|
||||
|
@ -61,9 +61,11 @@ def meta_info_to_oeb_metadata(mi, m, log, override_input_metadata=False):
|
||||
m.add('identifier', val, scheme=typ.upper())
|
||||
if override_input_metadata and not set_isbn:
|
||||
m.filter('identifier', lambda x: x.scheme.lower() == 'isbn')
|
||||
if not mi.is_null('language'):
|
||||
if not mi.is_null('languages'):
|
||||
m.clear('language')
|
||||
m.add('language', mi.language)
|
||||
for lang in mi.languages:
|
||||
if lang and lang.lower() not in ('und', ''):
|
||||
m.add('language', lang)
|
||||
if not mi.is_null('series_index'):
|
||||
m.clear('series_index')
|
||||
m.add('series_index', mi.format_series_index())
|
||||
|
@ -94,9 +94,10 @@ gprefs.defaults['book_display_fields'] = [
|
||||
('path', True), ('publisher', False), ('rating', False),
|
||||
('author_sort', False), ('sort', False), ('timestamp', False),
|
||||
('uuid', False), ('comments', True), ('id', False), ('pubdate', False),
|
||||
('last_modified', False), ('size', False),
|
||||
('last_modified', False), ('size', False), ('languages', False),
|
||||
]
|
||||
gprefs.defaults['default_author_link'] = 'http://en.wikipedia.org/w/index.php?search={author}'
|
||||
gprefs.defaults['preserve_date_on_ctl'] = True
|
||||
|
||||
# }}}
|
||||
|
||||
@ -169,7 +170,9 @@ def _config(): # {{{
|
||||
c.add_opt('scheduler_search_history', default=[],
|
||||
help='Search history for the recipe scheduler')
|
||||
c.add_opt('plugin_search_history', default=[],
|
||||
help='Search history for the recipe scheduler')
|
||||
help='Search history for the plugin preferences')
|
||||
c.add_opt('shortcuts_search_history', default=[],
|
||||
help='Search history for the keyboard preferences')
|
||||
c.add_opt('worker_limit', default=6,
|
||||
help=_(
|
||||
'Maximum number of simultaneous conversion/news download jobs. '
|
||||
@ -423,6 +426,10 @@ class FileIconProvider(QFileIconProvider):
|
||||
'rtf' : 'rtf',
|
||||
'odt' : 'odt',
|
||||
'snb' : 'snb',
|
||||
'djv' : 'djvu',
|
||||
'djvu' : 'djvu',
|
||||
'xps' : 'xps',
|
||||
'oxps' : 'xps',
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
|
@ -8,9 +8,13 @@ __docformat__ = 'restructuredtext en'
|
||||
from functools import partial
|
||||
from zipfile import ZipFile
|
||||
|
||||
from PyQt4.Qt import QToolButton, QAction, QIcon, QObject, QMenu
|
||||
from PyQt4.Qt import (QToolButton, QAction, QIcon, QObject, QMenu,
|
||||
QKeySequence)
|
||||
|
||||
from calibre import prints
|
||||
from calibre.gui2 import Dispatcher
|
||||
from calibre.gui2.keyboard import NameConflict
|
||||
|
||||
|
||||
class InterfaceAction(QObject):
|
||||
|
||||
@ -83,7 +87,8 @@ class InterfaceAction(QObject):
|
||||
dont_remove_from = frozenset([])
|
||||
|
||||
all_locations = frozenset(['toolbar', 'toolbar-device', 'context-menu',
|
||||
'context-menu-device', 'toolbar-child', 'menubar', 'menubar-device'])
|
||||
'context-menu-device', 'toolbar-child', 'menubar', 'menubar-device',
|
||||
'context-menu-cover-browser'])
|
||||
|
||||
#: Type of action
|
||||
#: 'current' means acts on the current view
|
||||
@ -105,6 +110,13 @@ class InterfaceAction(QObject):
|
||||
self.gui.addAction(self.menuless_qaction)
|
||||
self.genesis()
|
||||
|
||||
@property
|
||||
def unique_name(self):
|
||||
bn = self.__class__.__name__
|
||||
if getattr(self.interface_action_base_plugin, 'name'):
|
||||
bn = self.interface_action_base_plugin.name
|
||||
return u'Interface Action: %s (%s)'%(bn, self.name)
|
||||
|
||||
def create_action(self, spec=None, attr='qaction'):
|
||||
if spec is None:
|
||||
spec = self.action_spec
|
||||
@ -124,13 +136,32 @@ class InterfaceAction(QObject):
|
||||
a.setToolTip(text)
|
||||
a.setStatusTip(text)
|
||||
a.setWhatsThis(text)
|
||||
if shortcut:
|
||||
a = ma if attr == 'qaction' else action
|
||||
if isinstance(shortcut, list):
|
||||
a.setShortcuts(shortcut)
|
||||
else:
|
||||
a.setShortcut(shortcut)
|
||||
setattr(self, attr, action)
|
||||
shortcut_action = action
|
||||
desc = tooltip if tooltip else None
|
||||
if attr == 'qaction':
|
||||
shortcut_action = ma
|
||||
if shortcut is not None:
|
||||
keys = ((shortcut,) if isinstance(shortcut, basestring) else
|
||||
tuple(shortcut))
|
||||
|
||||
if spec[0] and not (attr=='qaction' and self.popup_type ==
|
||||
QToolButton.InstantPopup):
|
||||
try:
|
||||
self.gui.keyboard.register_shortcut(self.unique_name + ' - ' + attr,
|
||||
unicode(spec[0]), default_keys=keys,
|
||||
action=shortcut_action, description=desc,
|
||||
group=self.action_spec[0])
|
||||
except NameConflict as e:
|
||||
try:
|
||||
prints(unicode(e))
|
||||
except:
|
||||
pass
|
||||
shortcut_action.setShortcuts([QKeySequence(key,
|
||||
QKeySequence.PortableText) for key in keys])
|
||||
|
||||
|
||||
if attr is not None:
|
||||
setattr(self, attr, action)
|
||||
if attr == 'qaction' and self.action_add_menu:
|
||||
menu = QMenu()
|
||||
action.setMenu(menu)
|
||||
@ -138,6 +169,31 @@ class InterfaceAction(QObject):
|
||||
menu.addAction(self.menuless_qaction)
|
||||
return action
|
||||
|
||||
def create_menu_action(self, menu, unique_name, text, icon=None, shortcut=None,
|
||||
description=None, triggered=None):
|
||||
ac = menu.addAction(text)
|
||||
if icon is not None:
|
||||
if not isinstance(icon, QIcon):
|
||||
icon = QIcon(I(icon))
|
||||
ac.setIcon(icon)
|
||||
keys = ()
|
||||
if shortcut is not None and shortcut is not False:
|
||||
keys = ((shortcut,) if isinstance(shortcut, basestring) else
|
||||
tuple(shortcut))
|
||||
unique_name = '%s : menu action : %s'%(self.unique_name, unique_name)
|
||||
if description is not None:
|
||||
ac.setToolTip(description)
|
||||
ac.setStatusTip(description)
|
||||
ac.setWhatsThis(description)
|
||||
|
||||
if shortcut is not False:
|
||||
self.gui.keyboard.register_shortcut(unique_name,
|
||||
unicode(text), default_keys=keys,
|
||||
action=ac, description=description, group=self.action_spec[0])
|
||||
if triggered is not None:
|
||||
ac.triggered.connect(triggered)
|
||||
return ac
|
||||
|
||||
def load_resources(self, names):
|
||||
'''
|
||||
If this plugin comes in a ZIP file (user added plugin), this method
|
||||
|
@ -54,20 +54,22 @@ class AddAction(InterfaceAction):
|
||||
def genesis(self):
|
||||
self._add_filesystem_book = self.Dispatcher(self.__add_filesystem_book)
|
||||
self.add_menu = self.qaction.menu()
|
||||
self.add_menu.addAction(_('Add books from directories, including '
|
||||
ma = partial(self.create_menu_action, self.add_menu)
|
||||
ma('recursive-single', _('Add books from directories, including '
|
||||
'sub-directories (One book per directory, assumes every ebook '
|
||||
'file is the same book in a different format)'),
|
||||
'file is the same book in a different format)')).triggered.connect(
|
||||
self.add_recursive_single)
|
||||
self.add_menu.addAction(_('Add books from directories, including '
|
||||
ma('recursive-multiple', _('Add books from directories, including '
|
||||
'sub directories (Multiple books per directory, assumes every '
|
||||
'ebook file is a different book)'), self.add_recursive_multiple)
|
||||
'ebook file is a different book)')).triggered.connect(
|
||||
self.add_recursive_multiple)
|
||||
self.add_menu.addSeparator()
|
||||
self.add_menu.addAction(_('Add Empty book. (Book entry with no '
|
||||
'formats)'), self.add_empty, _('Shift+Ctrl+E'))
|
||||
self.add_menu.addAction(_('Add from ISBN'), self.add_from_isbn)
|
||||
ma('add-empty', _('Add Empty book. (Book entry with no formats)'),
|
||||
shortcut=_('Shift+Ctrl+E')).triggered.connect(self.add_empty)
|
||||
ma('add-isbn', _('Add from ISBN')).triggered.connect(self.add_from_isbn)
|
||||
self.add_menu.addSeparator()
|
||||
self.add_menu.addAction(_('Add files to selected book records'),
|
||||
self.add_formats, _('Shift+A'))
|
||||
ma('add-formats', _('Add files to selected book records'),
|
||||
triggered=self.add_formats, shortcut=_('Shift+A'))
|
||||
|
||||
self.qaction.triggered.connect(self.add_books)
|
||||
|
||||
@ -82,7 +84,8 @@ class AddAction(InterfaceAction):
|
||||
view = self.gui.library_view
|
||||
rows = view.selectionModel().selectedRows()
|
||||
if not rows:
|
||||
return
|
||||
return error_dialog(self.gui, _('No books selected'),
|
||||
_('Cannot add files as no books are selected'), show=True)
|
||||
ids = [view.model().id(r) for r in rows]
|
||||
|
||||
if len(ids) > 1 and not question_dialog(self.gui,
|
||||
|
@ -8,13 +8,14 @@ __docformat__ = 'restructuredtext en'
|
||||
import os
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import QMenu, Qt, QInputDialog, QToolButton
|
||||
from PyQt4.Qt import (QMenu, Qt, QInputDialog, QToolButton, QDialog,
|
||||
QDialogButtonBox, QGridLayout, QLabel, QLineEdit, QIcon, QSize)
|
||||
|
||||
from calibre import isbytestring
|
||||
from calibre.constants import filesystem_encoding, iswindows
|
||||
from calibre.utils.config import prefs
|
||||
from calibre.gui2 import (gprefs, warning_dialog, Dispatcher, error_dialog,
|
||||
question_dialog, info_dialog, open_local_file)
|
||||
question_dialog, info_dialog, open_local_file, choose_dir)
|
||||
from calibre.library.database2 import LibraryDatabase2
|
||||
from calibre.gui2.actions import InterfaceAction
|
||||
|
||||
@ -76,16 +77,73 @@ class LibraryUsageStats(object): # {{{
|
||||
self.write_stats()
|
||||
# }}}
|
||||
|
||||
class MovedDialog(QDialog): # {{{
|
||||
|
||||
def __init__(self, stats, location, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
self.setWindowTitle(_('No library found'))
|
||||
self._l = l = QGridLayout(self)
|
||||
self.setLayout(l)
|
||||
self.stats, self.location = stats, location
|
||||
|
||||
loc = self.oldloc = location.replace('/', os.sep)
|
||||
self.header = QLabel(_('No existing calibre library was found at %s. '
|
||||
'If the library was moved, select its new location below. '
|
||||
'Otherwise calibre will forget this library.')%loc)
|
||||
self.header.setWordWrap(True)
|
||||
ncols = 2
|
||||
l.addWidget(self.header, 0, 0, 1, ncols)
|
||||
self.cl = QLabel('<br><b>'+_('New location of this library:'))
|
||||
l.addWidget(self.cl, 1, 0, 1, ncols)
|
||||
self.loc = QLineEdit(loc, self)
|
||||
l.addWidget(self.loc, 2, 0, 1, 1)
|
||||
self.cd = QToolButton(self)
|
||||
self.cd.setIcon(QIcon(I('document_open.png')))
|
||||
self.cd.clicked.connect(self.choose_dir)
|
||||
l.addWidget(self.cd, 2, 1, 1, 1)
|
||||
self.bb = QDialogButtonBox(self)
|
||||
b = self.bb.addButton(_('Library moved'), self.bb.AcceptRole)
|
||||
b.setIcon(QIcon(I('ok.png')))
|
||||
b = self.bb.addButton(_('Forget library'), self.bb.RejectRole)
|
||||
b.setIcon(QIcon(I('edit-clear.png')))
|
||||
self.bb.accepted.connect(self.accept)
|
||||
self.bb.rejected.connect(self.reject)
|
||||
l.addWidget(self.bb, 3, 0, 1, ncols)
|
||||
self.resize(self.sizeHint() + QSize(100, 50))
|
||||
|
||||
def choose_dir(self):
|
||||
d = choose_dir(self, 'library moved choose new loc',
|
||||
_('New library location'), default_dir=self.oldloc)
|
||||
if d is not None:
|
||||
self.loc.setText(d)
|
||||
|
||||
def reject(self):
|
||||
self.stats.remove(self.location)
|
||||
QDialog.reject(self)
|
||||
|
||||
def accept(self):
|
||||
newloc = unicode(self.loc.text())
|
||||
if not LibraryDatabase2.exists_at(newloc):
|
||||
error_dialog(self, _('No library found'),
|
||||
_('No existing calibre library found at %s')%newloc,
|
||||
show=True)
|
||||
return
|
||||
self.stats.rename(self.location, newloc)
|
||||
self.newloc = newloc
|
||||
QDialog.accept(self)
|
||||
# }}}
|
||||
|
||||
class ChooseLibraryAction(InterfaceAction):
|
||||
|
||||
name = 'Choose Library'
|
||||
action_spec = (_('%d books'), 'lt.png',
|
||||
action_spec = (_('Choose Library'), 'lt.png',
|
||||
_('Choose calibre library to work with'), None)
|
||||
dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device'])
|
||||
action_add_menu = True
|
||||
action_menu_clone_qaction = _('Switch/create library...')
|
||||
|
||||
def genesis(self):
|
||||
self.base_text = _('%d books')
|
||||
self.count_changed(0)
|
||||
self.qaction.triggered.connect(self.choose_library,
|
||||
type=Qt.QueuedConnection)
|
||||
@ -338,14 +396,14 @@ class ChooseLibraryAction(InterfaceAction):
|
||||
loc = location.replace('/', os.sep)
|
||||
exists = self.gui.library_view.model().db.exists_at(loc)
|
||||
if not exists:
|
||||
warning_dialog(self.gui, _('No library found'),
|
||||
_('No existing calibre library was found at %s.'
|
||||
' It will be removed from the list of known'
|
||||
' libraries.')%loc, show=True)
|
||||
self.stats.remove(location)
|
||||
d = MovedDialog(self.stats, location, self.gui)
|
||||
ret = d.exec_()
|
||||
self.build_menus()
|
||||
self.gui.iactions['Copy To Library'].build_menus()
|
||||
return
|
||||
if ret == d.Accepted:
|
||||
loc = d.newloc.replace('/', os.sep)
|
||||
else:
|
||||
return
|
||||
|
||||
prefs['library_path'] = loc
|
||||
#from calibre.utils.mem import memory
|
||||
@ -376,7 +434,7 @@ class ChooseLibraryAction(InterfaceAction):
|
||||
self.switch_requested(self.qs_locations[idx])
|
||||
|
||||
def count_changed(self, new_count):
|
||||
text = self.action_spec[0]%new_count
|
||||
text = self.base_text%new_count
|
||||
a = self.qaction
|
||||
a.setText(text)
|
||||
tooltip = self.action_spec[2] + '\n\n' + text
|
||||
|
@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en'
|
||||
import os
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import QModelIndex, QIcon
|
||||
from PyQt4.Qt import QModelIndex
|
||||
|
||||
from calibre.gui2 import error_dialog, Dispatcher
|
||||
from calibre.gui2.tools import convert_single_ebook, convert_bulk_ebook
|
||||
@ -25,17 +25,19 @@ class ConvertAction(InterfaceAction):
|
||||
action_add_menu = True
|
||||
|
||||
def genesis(self):
|
||||
cm = self.qaction.menu()
|
||||
cm.addAction(self.qaction.icon(), _('Convert individually'), partial(self.convert_ebook,
|
||||
m = self.convert_menu = self.qaction.menu()
|
||||
cm = partial(self.create_menu_action, self.convert_menu)
|
||||
cm('convert-individual', _('Convert individually'),
|
||||
icon=self.qaction.icon(), triggered=partial(self.convert_ebook,
|
||||
False, bulk=False))
|
||||
cm.addAction(_('Bulk convert'),
|
||||
partial(self.convert_ebook, False, bulk=True))
|
||||
cm.addSeparator()
|
||||
ac = cm.addAction(QIcon(I('catalog.png')),
|
||||
_('Create a catalog of the books in your calibre library'))
|
||||
ac.triggered.connect(self.gui.iactions['Generate Catalog'].generate_catalog)
|
||||
cm('convert-bulk', _('Bulk convert'),
|
||||
triggered=partial(self.convert_ebook, False, bulk=True))
|
||||
m.addSeparator()
|
||||
cm('create-catalog',
|
||||
_('Create a catalog of the books in your calibre library'),
|
||||
icon='catalog.png', shortcut=False,
|
||||
triggered=self.gui.iactions['Generate Catalog'].generate_catalog)
|
||||
self.qaction.triggered.connect(self.convert_ebook)
|
||||
self.convert_menu = cm
|
||||
self.conversion_jobs = {}
|
||||
|
||||
def location_selected(self, loc):
|
||||
|
@ -12,9 +12,10 @@ from threading import Thread
|
||||
from PyQt4.Qt import QToolButton
|
||||
|
||||
from calibre.gui2.actions import InterfaceAction
|
||||
from calibre.gui2 import error_dialog, Dispatcher, warning_dialog
|
||||
from calibre.gui2 import error_dialog, Dispatcher, warning_dialog, gprefs
|
||||
from calibre.gui2.dialogs.progress import ProgressDialog
|
||||
from calibre.utils.config import prefs, tweaks
|
||||
from calibre.utils.date import now
|
||||
|
||||
class Worker(Thread): # {{{
|
||||
|
||||
@ -55,6 +56,8 @@ class Worker(Thread): # {{{
|
||||
for i, x in enumerate(self.ids):
|
||||
mi = self.db.get_metadata(x, index_is_id=True, get_cover=True,
|
||||
cover_as_data=True)
|
||||
if not gprefs['preserve_date_on_ctl']:
|
||||
mi.timestamp = now()
|
||||
self.progress(i, mi.title)
|
||||
fmts = self.db.formats(x, index_is_id=True)
|
||||
if not fmts: fmts = []
|
||||
@ -65,14 +68,37 @@ class Worker(Thread): # {{{
|
||||
as_path=True)
|
||||
if p:
|
||||
paths.append(p)
|
||||
added = False
|
||||
automerged = False
|
||||
if prefs['add_formats_to_existing']:
|
||||
identical_book_list = newdb.find_identical_books(mi)
|
||||
if identical_book_list: # books with same author and nearly same title exist in newdb
|
||||
added = True
|
||||
automerged = True
|
||||
seen_fmts = set()
|
||||
for identical_book in identical_book_list:
|
||||
self.add_formats(identical_book, paths, newdb, replace=False)
|
||||
if not added:
|
||||
ib_fmts = newdb.formats(identical_book, index_is_id=True)
|
||||
if ib_fmts:
|
||||
seen_fmts |= set(ib_fmts.split(','))
|
||||
replace = gprefs['automerge'] == 'overwrite'
|
||||
self.add_formats(identical_book, paths, newdb,
|
||||
replace=replace)
|
||||
|
||||
if gprefs['automerge'] == 'new record':
|
||||
incoming_fmts = \
|
||||
set([os.path.splitext(path)[-1].replace('.',
|
||||
'').upper() for path in paths])
|
||||
|
||||
if incoming_fmts.intersection(seen_fmts):
|
||||
# There was at least one duplicate format
|
||||
# so create a new record and put the
|
||||
# incoming formats into it
|
||||
# We should arguably put only the duplicate
|
||||
# formats, but no real harm is done by having
|
||||
# all formats
|
||||
newdb.import_book(mi, paths, notify=False, import_hooks=False,
|
||||
apply_import_tags=tweaks['add_new_book_tags_when_importing_books'],
|
||||
preserve_uuid=False)
|
||||
|
||||
if not automerged:
|
||||
newdb.import_book(mi, paths, notify=False, import_hooks=False,
|
||||
apply_import_tags=tweaks['add_new_book_tags_when_importing_books'],
|
||||
preserve_uuid=self.delete_after)
|
||||
|
@ -90,21 +90,23 @@ class DeleteAction(InterfaceAction):
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.delete_books)
|
||||
self.delete_menu = self.qaction.menu()
|
||||
self.delete_menu.addAction(
|
||||
m = partial(self.create_menu_action, self.delete_menu)
|
||||
m('delete-specific',
|
||||
_('Remove files of a specific format from selected books..'),
|
||||
self.delete_selected_formats)
|
||||
self.delete_menu.addAction(
|
||||
triggered=self.delete_selected_formats)
|
||||
m('delete-except',
|
||||
_('Remove all formats from selected books, except...'),
|
||||
self.delete_all_but_selected_formats)
|
||||
self.delete_menu.addAction(
|
||||
triggered=self.delete_all_but_selected_formats)
|
||||
m('delete-all',
|
||||
_('Remove all formats from selected books'),
|
||||
self.delete_all_formats)
|
||||
self.delete_menu.addAction(
|
||||
_('Remove covers from selected books'), self.delete_covers)
|
||||
triggered=self.delete_all_formats)
|
||||
m('delete-covers',
|
||||
_('Remove covers from selected books'),
|
||||
triggered=self.delete_covers)
|
||||
self.delete_menu.addSeparator()
|
||||
self.delete_menu.addAction(
|
||||
m('delete-matching',
|
||||
_('Remove matching books from device'),
|
||||
self.remove_matching_books_from_device)
|
||||
triggered=self.remove_matching_books_from_device)
|
||||
self.qaction.setMenu(self.delete_menu)
|
||||
self.delete_memory = {}
|
||||
|
||||
|
@ -60,6 +60,19 @@ class ShareConnMenu(QMenu): # {{{
|
||||
|
||||
self.email_actions = []
|
||||
|
||||
if hasattr(parent, 'keyboard'):
|
||||
r = parent.keyboard.register_shortcut
|
||||
prefix = 'Share/Connect Menu '
|
||||
gr = ConnectShareAction.action_spec[0]
|
||||
for attr in ('folder', 'bambook', 'itunes'):
|
||||
if not (iswindows or isosx) and attr == 'itunes':
|
||||
continue
|
||||
ac = getattr(self, 'connect_to_%s_action'%attr)
|
||||
r(prefix + attr, unicode(ac.text()), action=ac,
|
||||
group=gr)
|
||||
r(prefix+' content server', _('Start/stop content server'),
|
||||
action=self.toggle_server_action, group=gr)
|
||||
|
||||
def server_state_changed(self, running):
|
||||
text = _('Start Content Server')
|
||||
if running:
|
||||
|
@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en'
|
||||
import os
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import Qt, QMenu, QModelIndex, QTimer
|
||||
from PyQt4.Qt import QMenu, QModelIndex, QTimer
|
||||
|
||||
from calibre.gui2 import error_dialog, Dispatcher, question_dialog
|
||||
from calibre.gui2.dialogs.metadata_bulk import MetadataBulkDialog
|
||||
@ -27,37 +27,38 @@ class EditMetadataAction(InterfaceAction):
|
||||
action_add_menu = True
|
||||
|
||||
def genesis(self):
|
||||
self.create_action(spec=(_('Merge book records'), 'merge_books.png',
|
||||
None, _('M')), attr='action_merge')
|
||||
md = self.qaction.menu()
|
||||
md.addAction(self.qaction.icon(), _('Edit metadata individually'),
|
||||
partial(self.edit_metadata, False, bulk=False))
|
||||
cm = partial(self.create_menu_action, md)
|
||||
cm('individual', _('Edit metadata individually'), icon=self.qaction.icon(),
|
||||
triggered=partial(self.edit_metadata, False, bulk=False))
|
||||
md.addSeparator()
|
||||
md.addAction(_('Edit metadata in bulk'),
|
||||
partial(self.edit_metadata, False, bulk=True))
|
||||
cm('bulk', _('Edit metadata in bulk'),
|
||||
triggered=partial(self.edit_metadata, False, bulk=True))
|
||||
md.addSeparator()
|
||||
md.addAction(_('Download metadata and covers'), self.download_metadata,
|
||||
Qt.ControlModifier+Qt.Key_D)
|
||||
cm('download', _('Download metadata and covers'),
|
||||
triggered=partial(self.download_metadata, ids=None),
|
||||
shortcut='Ctrl+D')
|
||||
self.metadata_menu = md
|
||||
|
||||
mb = QMenu()
|
||||
mb.addAction(_('Merge into first selected book - delete others'),
|
||||
self.merge_books)
|
||||
cm2 = partial(self.create_menu_action, mb)
|
||||
cm2('merge delete', _('Merge into first selected book - delete others'),
|
||||
triggered=self.merge_books)
|
||||
mb.addSeparator()
|
||||
mb.addAction(_('Merge into first selected book - keep others'),
|
||||
partial(self.merge_books, safe_merge=True),
|
||||
Qt.AltModifier+Qt.Key_M)
|
||||
cm2('merge keep', _('Merge into first selected book - keep others'),
|
||||
triggered=partial(self.merge_books, safe_merge=True),
|
||||
shortcut='Alt+M')
|
||||
mb.addSeparator()
|
||||
mb.addAction(_('Merge only formats into first selected book - delete others'),
|
||||
partial(self.merge_books, merge_only_formats=True),
|
||||
Qt.AltModifier+Qt.ShiftModifier+Qt.Key_M)
|
||||
cm2('merge formats', _('Merge only formats into first selected book - delete others'),
|
||||
triggered=partial(self.merge_books, merge_only_formats=True),
|
||||
shortcut='Alt+Shift+M')
|
||||
self.merge_menu = mb
|
||||
self.action_merge.setMenu(mb)
|
||||
md.addSeparator()
|
||||
md.addAction(self.action_merge)
|
||||
self.action_merge = cm('merge', _('Merge book records'), icon='merge_books.png',
|
||||
shortcut=_('M'), triggered=self.merge_books)
|
||||
self.action_merge.setMenu(mb)
|
||||
|
||||
self.qaction.triggered.connect(self.edit_metadata)
|
||||
self.action_merge.triggered.connect(self.merge_books)
|
||||
|
||||
def location_selected(self, loc):
|
||||
enabled = loc == 'library'
|
||||
@ -417,7 +418,7 @@ class EditMetadataAction(InterfaceAction):
|
||||
db.set_custom(dest_id, dest_value, num=colnum)
|
||||
if db.field_metadata[key]['datatype'] in \
|
||||
('bool', 'int', 'float', 'rating', 'datetime') \
|
||||
and not dest_value:
|
||||
and dest_value is None:
|
||||
db.set_custom(dest_id, src_value, num=colnum)
|
||||
if db.field_metadata[key]['datatype'] == 'series' \
|
||||
and not dest_value:
|
||||
|
@ -5,6 +5,8 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import QIcon, Qt
|
||||
|
||||
from calibre.gui2.actions import InterfaceAction
|
||||
@ -21,18 +23,17 @@ class PreferencesAction(InterfaceAction):
|
||||
|
||||
def genesis(self):
|
||||
pm = self.qaction.menu()
|
||||
cm = partial(self.create_menu_action, pm)
|
||||
if isosx:
|
||||
pm.addAction(QIcon(I('config.png')), _('Preferences'), self.do_config)
|
||||
pm.addAction(QIcon(I('wizard.png')), _('Run welcome wizard'),
|
||||
self.gui.run_wizard)
|
||||
pm.addAction(QIcon(I('plugins/plugin_updater.png')),
|
||||
_('Get plugins to enhance calibre'), self.get_plugins)
|
||||
cm('welcome wizard', _('Run welcome wizard'),
|
||||
icon='wizard.png', triggered=self.gui.run_wizard)
|
||||
cm('plugin updater', _('Get plugins to enhance calibre'),
|
||||
icon='plugins/plugin_updater.png', triggered=self.get_plugins)
|
||||
if not DEBUG:
|
||||
pm.addSeparator()
|
||||
ac = pm.addAction(QIcon(I('debug.png')), _('Restart in debug mode'),
|
||||
self.debug_restart)
|
||||
ac.setShortcut('Ctrl+Shift+R')
|
||||
self.gui.addAction(ac)
|
||||
cm('restart', _('Restart in debug mode'), icon='debug.png',
|
||||
triggered=self.debug_restart, shortcut='Ctrl+Shift+R')
|
||||
|
||||
self.preferences_menu = pm
|
||||
for x in (self.gui.preferences_action, self.qaction):
|
||||
|
@ -11,7 +11,7 @@ from calibre.gui2.actions import InterfaceAction
|
||||
class RestartAction(InterfaceAction):
|
||||
|
||||
name = 'Restart'
|
||||
action_spec = (_('&Restart'), None, None, _('Ctrl+R'))
|
||||
action_spec = (_('Restart'), None, None, _('Ctrl+R'))
|
||||
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.restart)
|
||||
|
@ -44,15 +44,16 @@ class SaveToDiskAction(InterfaceAction):
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.save_to_disk)
|
||||
self.save_menu = self.qaction.menu()
|
||||
self.save_menu.addAction(_('Save to disk in a single directory'),
|
||||
partial(self.save_to_single_dir, False))
|
||||
self.save_menu.addAction(_('Save only %s format to disk')%
|
||||
cm = partial(self.create_menu_action, self.save_menu)
|
||||
cm('single dir', _('Save to disk in a single directory'),
|
||||
triggered=partial(self.save_to_single_dir, False))
|
||||
cm('single format', _('Save only %s format to disk')%
|
||||
prefs['output_format'].upper(),
|
||||
partial(self.save_single_format_to_disk, False))
|
||||
self.save_menu.addAction(
|
||||
triggered=partial(self.save_single_format_to_disk, False))
|
||||
cm('single dir and format',
|
||||
_('Save only %s format to disk in a single directory')%
|
||||
prefs['output_format'].upper(),
|
||||
partial(self.save_single_fmt_to_single_dir, False))
|
||||
triggered=partial(self.save_single_fmt_to_single_dir, False))
|
||||
self.save_sub_menu = SaveMenu(self.gui)
|
||||
self.save_sub_menu_action = self.save_menu.addMenu(self.save_sub_menu)
|
||||
self.save_sub_menu.save_fmt.connect(self.save_specific_format_disk)
|
||||
@ -114,10 +115,7 @@ class SaveToDiskAction(InterfaceAction):
|
||||
opts.save_cover = False
|
||||
opts.write_opf = False
|
||||
opts.template = opts.send_template
|
||||
if single_dir:
|
||||
opts.template = opts.template.split('/')[-1].strip()
|
||||
if not opts.template:
|
||||
opts.template = '{title} - {authors}'
|
||||
opts.single_dir = single_dir
|
||||
self._saver = Saver(self.gui, self.gui.library_view.model().db,
|
||||
Dispatcher(self._books_saved), rows, path, opts,
|
||||
spare_server=self.gui.spare_server)
|
||||
|
@ -24,16 +24,21 @@ class StoreAction(InterfaceAction):
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.do_search)
|
||||
self.store_menu = self.qaction.menu()
|
||||
self.load_menu()
|
||||
|
||||
def load_menu(self):
|
||||
self.store_menu.clear()
|
||||
self.store_menu.addAction(self.menuless_qaction)
|
||||
self.store_menu.addAction(_('Search for this author'), self.search_author)
|
||||
self.store_menu.addAction(_('Search for this title'), self.search_title)
|
||||
self.store_menu.addAction(_('Search for this book'), self.search_author_title)
|
||||
cm = partial(self.create_menu_action, self.store_menu)
|
||||
for x, t in [('author', _('author')), ('title', _('title')),
|
||||
('book', _('book'))]:
|
||||
func = getattr(self, 'search_%s'%('author_title' if x == 'book'
|
||||
else x))
|
||||
ac = cm(x, _('Search for this %s'%t), triggered=func)
|
||||
setattr(self, 'action_search_by_'+x, ac)
|
||||
self.store_menu.addSeparator()
|
||||
self.store_list_menu = self.store_menu.addMenu(_('Stores'))
|
||||
self.load_menu()
|
||||
self.store_menu.addSeparator()
|
||||
cm('choose stores', _('Choose stores'), triggered=self.choose)
|
||||
|
||||
def load_menu(self):
|
||||
self.store_list_menu.clear()
|
||||
icon = QIcon()
|
||||
icon.addFile(I('donate.png'), QSize(16, 16))
|
||||
for n, p in sorted(self.gui.istores.items(), key=lambda x: x[0].lower()):
|
||||
@ -41,8 +46,6 @@ class StoreAction(InterfaceAction):
|
||||
self.store_list_menu.addAction(icon, n, partial(self.open_store, p))
|
||||
else:
|
||||
self.store_list_menu.addAction(n, partial(self.open_store, p))
|
||||
self.store_menu.addSeparator()
|
||||
self.store_menu.addAction(_('Choose stores'), self.choose)
|
||||
|
||||
def do_search(self):
|
||||
return self.search()
|
||||
|
@ -6,6 +6,7 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os, time
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import Qt, QAction, pyqtSignal
|
||||
|
||||
@ -43,36 +44,33 @@ class ViewAction(InterfaceAction):
|
||||
self.qaction.triggered.connect(self.view_book)
|
||||
self.view_action = self.menuless_qaction
|
||||
self.view_menu = self.qaction.menu()
|
||||
ac = self.view_specific_action = QAction(_('View specific format'),
|
||||
self.gui)
|
||||
ac.setShortcut(Qt.AltModifier+Qt.Key_V)
|
||||
ac.triggered.connect(self.view_specific_format, type=Qt.QueuedConnection)
|
||||
ac = self.create_action(spec=(_('Read a random book'), 'random.png',
|
||||
None, None), attr='action_pick_random')
|
||||
ac.triggered.connect(self.view_random)
|
||||
ac = self.clear_history_action = QAction(
|
||||
_('Clear recently viewed list'), self.gui)
|
||||
ac.triggered.connect(self.clear_history)
|
||||
cm = partial(self.create_menu_action, self.view_menu)
|
||||
self.view_specific_action = cm('specific', _('View specific format'),
|
||||
shortcut='Alt+V', triggered=self.view_specific_format)
|
||||
self.action_pick_random = cm('pick random', _('Read a random book'),
|
||||
icon='random.png', triggered=self.view_random)
|
||||
self.clear_sep1 = self.view_menu.addSeparator()
|
||||
self.clear_sep2 = self.view_menu.addSeparator()
|
||||
self.clear_history_action = cm('clear history',
|
||||
_('Clear recently viewed list'), triggered=self.clear_history)
|
||||
self.history_actions = [self.clear_sep1]
|
||||
|
||||
def initialization_complete(self):
|
||||
self.build_menus(self.gui.current_db)
|
||||
|
||||
def build_menus(self, db):
|
||||
self.view_menu.clear()
|
||||
self.view_menu.addAction(self.view_action)
|
||||
self.view_menu.addAction(self.view_specific_action)
|
||||
self.view_menu.addSeparator()
|
||||
self.view_menu.addAction(self.action_pick_random)
|
||||
for ac in self.history_actions:
|
||||
self.view_menu.removeAction(ac)
|
||||
self.history_actions = []
|
||||
history = db.prefs.get('gui_view_history', [])
|
||||
if history:
|
||||
self.view_menu.addSeparator()
|
||||
self.view_menu.insertAction(self.clear_sep2, self.clear_sep1)
|
||||
self.history_actions.append(self.clear_sep1)
|
||||
for id_, title in history:
|
||||
ac = HistoryAction(id_, title, self.view_menu)
|
||||
self.view_menu.addAction(ac)
|
||||
self.view_menu.insertAction(self.clear_sep2, ac)
|
||||
ac.view_historical.connect(self.view_historical)
|
||||
self.view_menu.addSeparator()
|
||||
self.view_menu.addAction(self.clear_history_action)
|
||||
self.history_actions.append(ac)
|
||||
|
||||
def clear_history(self):
|
||||
db = self.gui.current_db
|
||||
|
@ -239,7 +239,7 @@ class DBAdder(QObject): # {{{
|
||||
|
||||
class Adder(QObject): # {{{
|
||||
|
||||
ADD_TIMEOUT = 600 # seconds
|
||||
ADD_TIMEOUT = 900 # seconds (15 minutes)
|
||||
|
||||
def __init__(self, parent, db, callback, spare_server=None):
|
||||
QObject.__init__(self, parent)
|
||||
|
@ -24,6 +24,7 @@ from calibre.gui2 import (config, open_local_file, open_url, pixmap_to_data,
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.utils.formatter import EvalFormatter
|
||||
from calibre.utils.date import is_date_undefined
|
||||
from calibre.utils.localization import calibre_langcode_to_name
|
||||
|
||||
def render_html(mi, css, vertical, widget, all_fields=False): # {{{
|
||||
table = render_data(mi, all_fields=all_fields,
|
||||
@ -152,6 +153,12 @@ def render_data(mi, use_roman_numbers=True, all_fields=False):
|
||||
authors.append(aut)
|
||||
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name,
|
||||
u' & '.join(authors))))
|
||||
elif field == 'languages':
|
||||
if not mi.languages:
|
||||
continue
|
||||
names = filter(None, map(calibre_langcode_to_name, mi.languages))
|
||||
ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name,
|
||||
u', '.join(names))))
|
||||
else:
|
||||
val = mi.format_field(field)[-1]
|
||||
if val is None:
|
||||
|
@ -72,10 +72,11 @@ class HeuristicsWidget(Widget, Ui_Form):
|
||||
return True
|
||||
|
||||
def load_histories(self):
|
||||
val = unicode(self.opt_replace_scene_breaks.currentText())
|
||||
|
||||
self.opt_replace_scene_breaks.clear()
|
||||
self.opt_replace_scene_breaks.lineEdit().setText('')
|
||||
|
||||
val = unicode(self.opt_replace_scene_breaks.currentText())
|
||||
rssb_hist = gprefs.get('replace_scene_breaks_history', self.rssb_defaults)
|
||||
if val in rssb_hist:
|
||||
del rssb_hist[rssb_hist.index(val)]
|
||||
|
@ -6,11 +6,9 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from PyQt4.Qt import Qt
|
||||
|
||||
from calibre.gui2.convert.mobi_output_ui import Ui_Form
|
||||
from calibre.gui2.convert import Widget
|
||||
from calibre.gui2.widgets import FontFamilyModel
|
||||
|
||||
font_family_model = None
|
||||
|
||||
@ -26,11 +24,13 @@ class PluginWidget(Widget, Ui_Form):
|
||||
['prefer_author_sort', 'rescale_images', 'toc_title',
|
||||
'mobi_ignore_margins', 'mobi_toc_at_start',
|
||||
'dont_compress', 'no_inline_toc',
|
||||
'masthead_font','personal_doc', 'mobi_navpoints_only_deepest']
|
||||
'personal_doc']#, 'mobi_navpoints_only_deepest']
|
||||
)
|
||||
from calibre.utils.fonts import fontconfig
|
||||
self.db, self.book_id = db, book_id
|
||||
|
||||
'''
|
||||
from calibre.utils.fonts import fontconfig
|
||||
|
||||
global font_family_model
|
||||
if font_family_model is None:
|
||||
font_family_model = FontFamilyModel()
|
||||
@ -46,9 +46,11 @@ class PluginWidget(Widget, Ui_Form):
|
||||
|
||||
self.font_family_model = font_family_model
|
||||
self.opt_masthead_font.setModel(self.font_family_model)
|
||||
'''
|
||||
|
||||
self.initialize_options(get_option, get_help, db, book_id)
|
||||
|
||||
'''
|
||||
def set_value_handler(self, g, val):
|
||||
if unicode(g.objectName()) in 'opt_masthead_font':
|
||||
idx = -1
|
||||
@ -59,3 +61,4 @@ class PluginWidget(Widget, Ui_Form):
|
||||
g.setCurrentIndex(idx)
|
||||
return True
|
||||
return False
|
||||
'''
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>521</width>
|
||||
<height>331</height>
|
||||
<height>342</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -55,22 +55,12 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0" colspan="2">
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Kindle options</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Periodical masthead font:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="opt_masthead_font"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
@ -101,7 +91,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<item row="9" column="0">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@ -128,13 +118,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="opt_mobi_navpoints_only_deepest">
|
||||
<property name="text">
|
||||
<string>Use only &lowest level of items in the TOC for chapter-to-chapter navigation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
@ -87,7 +87,7 @@ class Int(Base):
|
||||
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
||||
QSpinBox(parent)]
|
||||
w = self.widgets[1]
|
||||
w.setRange(-100, 100000000)
|
||||
w.setRange(-1000000, 100000000)
|
||||
w.setSpecialValueText(_('Undefined'))
|
||||
w.setSingleStep(1)
|
||||
|
||||
@ -110,7 +110,7 @@ class Float(Int):
|
||||
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent),
|
||||
QDoubleSpinBox(parent)]
|
||||
w = self.widgets[1]
|
||||
w.setRange(-100., float(100000000))
|
||||
w.setRange(-1000000., float(100000000))
|
||||
w.setDecimals(2)
|
||||
w.setSpecialValueText(_('Undefined'))
|
||||
w.setSingleStep(1)
|
||||
@ -300,7 +300,6 @@ class Series(Base):
|
||||
w = QDoubleSpinBox(parent)
|
||||
w.setRange(-100., float(100000000))
|
||||
w.setDecimals(2)
|
||||
w.setSpecialValueText(_('Undefined'))
|
||||
w.setSingleStep(1)
|
||||
self.idx_widget=w
|
||||
self.widgets.append(w)
|
||||
@ -605,7 +604,7 @@ class BulkInt(BulkBase):
|
||||
|
||||
def setup_ui(self, parent):
|
||||
self.make_widgets(parent, QSpinBox)
|
||||
self.main_widget.setRange(-100, 100000000)
|
||||
self.main_widget.setRange(-1000000, 100000000)
|
||||
self.main_widget.setSpecialValueText(_('Undefined'))
|
||||
self.main_widget.setSingleStep(1)
|
||||
|
||||
@ -627,7 +626,7 @@ class BulkFloat(BulkInt):
|
||||
|
||||
def setup_ui(self, parent):
|
||||
self.make_widgets(parent, QDoubleSpinBox)
|
||||
self.main_widget.setRange(-100., float(100000000))
|
||||
self.main_widget.setRange(-1000000., float(100000000))
|
||||
self.main_widget.setDecimals(2)
|
||||
self.main_widget.setSpecialValueText(_('Undefined'))
|
||||
self.main_widget.setSingleStep(1)
|
||||
|
@ -134,7 +134,7 @@ class MyBlockingBusy(QDialog): # {{{
|
||||
do_autonumber, do_remove_format, remove_format, do_swap_ta, \
|
||||
do_remove_conv, do_auto_author, series, do_series_restart, \
|
||||
series_start_value, do_title_case, cover_action, clear_series, \
|
||||
pubdate, adddate, do_title_sort = self.args
|
||||
pubdate, adddate, do_title_sort, languages, clear_languages = self.args
|
||||
|
||||
|
||||
# first loop: do author and title. These will commit at the end of each
|
||||
@ -238,6 +238,12 @@ class MyBlockingBusy(QDialog): # {{{
|
||||
|
||||
if do_remove_conv:
|
||||
self.db.delete_conversion_options(id, 'PIPE', commit=False)
|
||||
|
||||
if clear_languages:
|
||||
self.db.set_languages(id, [], notify=False, commit=False)
|
||||
elif languages:
|
||||
self.db.set_languages(id, languages, notify=False, commit=False)
|
||||
|
||||
elif self.current_phase == 3:
|
||||
# both of these are fast enough to just do them all
|
||||
for w in self.cc_widgets:
|
||||
@ -329,6 +335,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
|
||||
geom = gprefs.get('bulk_metadata_window_geometry', None)
|
||||
if geom is not None:
|
||||
self.restoreGeometry(bytes(geom))
|
||||
self.languages.setEditText('')
|
||||
self.exec_()
|
||||
|
||||
def save_state(self, *args):
|
||||
@ -352,6 +359,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
|
||||
self.do_again = True
|
||||
self.accept()
|
||||
|
||||
# S&R {{{
|
||||
def prepare_search_and_replace(self):
|
||||
self.search_for.initialize('bulk_edit_search_for')
|
||||
self.replace_with.initialize('bulk_edit_replace_with')
|
||||
@ -796,6 +804,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
|
||||
# permanent. Make sure it really is.
|
||||
self.db.commit()
|
||||
self.model.refresh_ids(list(books_to_refresh))
|
||||
# }}}
|
||||
|
||||
def create_custom_column_editors(self):
|
||||
w = self.central_widget.widget(1)
|
||||
@ -919,6 +928,8 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
|
||||
do_auto_author = self.auto_author_sort.isChecked()
|
||||
do_title_case = self.change_title_to_title_case.isChecked()
|
||||
do_title_sort = self.update_title_sort.isChecked()
|
||||
clear_languages = self.clear_languages.isChecked()
|
||||
languages = self.languages.lang_codes
|
||||
pubdate = adddate = None
|
||||
if self.apply_pubdate.isChecked():
|
||||
pubdate = qt_to_dt(self.pubdate.date())
|
||||
@ -937,7 +948,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog):
|
||||
do_autonumber, do_remove_format, remove_format, do_swap_ta,
|
||||
do_remove_conv, do_auto_author, series, do_series_restart,
|
||||
series_start_value, do_title_case, cover_action, clear_series,
|
||||
pubdate, adddate, do_title_sort)
|
||||
pubdate, adddate, do_title_sort, languages, clear_languages)
|
||||
|
||||
bb = MyBlockingBusy(_('Applying changes to %d books.\nPhase {0} {1}%%.')
|
||||
%len(self.ids), args, self.db, self.ids,
|
||||
|
@ -443,7 +443,7 @@ from the value in the box</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Remove &format:</string>
|
||||
@ -453,7 +453,7 @@ from the value in the box</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<item row="13" column="1">
|
||||
<widget class="QComboBox" name="remove_format">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
@ -463,7 +463,7 @@ from the value in the box</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<item row="14" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@ -479,7 +479,7 @@ from the value in the box</string>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="13" column="0" colspan="3">
|
||||
<item row="15" column="0" colspan="3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="change_title_to_title_case">
|
||||
@ -529,7 +529,7 @@ Future conversion of these books will use the default settings.</string>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="14" column="0" colspan="3">
|
||||
<item row="16" column="0" colspan="3">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Change &cover</string>
|
||||
@ -559,7 +559,7 @@ Future conversion of these books will use the default settings.</string>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<item row="17" column="0">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@ -572,6 +572,29 @@ Future conversion of these books will use the default settings.</string>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>&Languages:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>languages</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="LanguagesEdit" name="languages"/>
|
||||
</item>
|
||||
<item row="11" column="2">
|
||||
<widget class="QCheckBox" name="clear_languages">
|
||||
<property name="text">
|
||||
<string>Remove &all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab">
|
||||
@ -1145,6 +1168,11 @@ not multiple and the destination field is multiple</string>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>widgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LanguagesEdit</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>calibre/gui2/languages.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>authors</tabstop>
|
||||
|
@ -193,6 +193,7 @@ class SchedulerDialog(QDialog, Ui_Dialog):
|
||||
self.recipe_model = recipe_model
|
||||
self.recipe_model.do_refresh()
|
||||
self.count_label.setText(
|
||||
# NOTE: Number of news sources
|
||||
_('%s news sources') %
|
||||
self.recipe_model.showing_count)
|
||||
|
||||
|
@ -66,8 +66,8 @@ class EbookDownload(object):
|
||||
raise Exception(_('Not a support ebook format.'))
|
||||
|
||||
from calibre.ebooks.metadata.meta import get_metadata
|
||||
with open(filename) as f:
|
||||
mi = get_metadata(f, ext)
|
||||
with open(filename, 'rb') as f:
|
||||
mi = get_metadata(f, ext, force_read_metadata=True)
|
||||
mi.tags.extend(tags)
|
||||
|
||||
id = gui.library_view.model().db.create_book_entry(mi)
|
||||
|
@ -218,7 +218,7 @@ class LayoutMixin(object): # {{{
|
||||
self.bd_splitter = Splitter('book_details_splitter',
|
||||
_('Book Details'), I('book.png'),
|
||||
orientation=Qt.Vertical, parent=self, side_index=1,
|
||||
shortcut=_('Alt+D'))
|
||||
shortcut=_('Shift+Alt+D'))
|
||||
self.bd_splitter.addWidget(self.stack)
|
||||
self.bd_splitter.addWidget(self.book_details)
|
||||
self.bd_splitter.setCollapsible(self.bd_splitter.other_index, False)
|
||||
|
636
src/calibre/gui2/keyboard.py
Normal file
@ -0,0 +1,636 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from collections import OrderedDict
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import (QObject, QKeySequence, QAbstractItemModel, QModelIndex,
|
||||
Qt, QStyledItemDelegate, QTextDocument, QStyle, pyqtSignal, QFrame,
|
||||
QApplication, QSize, QRectF, QWidget, QTreeView,
|
||||
QGridLayout, QLabel, QRadioButton, QPushButton, QToolButton, QIcon)
|
||||
|
||||
from calibre.utils.config import JSONConfig
|
||||
from calibre.constants import DEBUG
|
||||
from calibre import prints
|
||||
from calibre.utils.icu import sort_key, lower
|
||||
from calibre.gui2 import NONE, error_dialog, info_dialog
|
||||
from calibre.utils.search_query_parser import SearchQueryParser, ParseException
|
||||
from calibre.gui2.search_box import SearchBox2
|
||||
|
||||
ROOT = QModelIndex()
|
||||
|
||||
class NameConflict(ValueError):
|
||||
pass
|
||||
|
||||
def finalize(shortcuts, custom_keys_map={}): # {{{
|
||||
'''
|
||||
Resolve conflicts and assign keys to every action in shorcuts, which must
|
||||
be a OrderedDict. User specified mappings of unique names to keys (as a
|
||||
list of strings) should be passed in in custom_keys_map. Return a mapping
|
||||
of unique names to resolved keys. Also sets the set_to_defaul member
|
||||
correctly for each shortcut.
|
||||
'''
|
||||
seen, keys_map = {}, {}
|
||||
for unique_name, shortcut in shortcuts.iteritems():
|
||||
custom_keys = custom_keys_map.get(unique_name, None)
|
||||
if custom_keys is None:
|
||||
candidates = shortcut['default_keys']
|
||||
shortcut['set_to_default'] = True
|
||||
else:
|
||||
candidates = custom_keys
|
||||
shortcut['set_to_default'] = False
|
||||
keys = []
|
||||
for x in candidates:
|
||||
ks = QKeySequence(x, QKeySequence.PortableText)
|
||||
x = unicode(ks.toString(QKeySequence.PortableText))
|
||||
if x in seen:
|
||||
if DEBUG:
|
||||
prints('Key %r for shortcut %s is already used by'
|
||||
' %s, ignoring'%(x, shortcut['name'], seen[x]['name']))
|
||||
keys_map[unique_name] = ()
|
||||
continue
|
||||
seen[x] = shortcut
|
||||
keys.append(ks)
|
||||
keys = tuple(keys)
|
||||
#print (111111, unique_name, candidates, keys)
|
||||
|
||||
keys_map[unique_name] = keys
|
||||
ac = shortcut['action']
|
||||
if ac is not None:
|
||||
ac.setShortcuts(list(keys))
|
||||
|
||||
return keys_map
|
||||
|
||||
# }}}
|
||||
|
||||
class Manager(QObject): # {{{
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QObject.__init__(self, parent)
|
||||
|
||||
self.config = JSONConfig('shortcuts/main')
|
||||
self.shortcuts = OrderedDict()
|
||||
self.keys_map = {}
|
||||
self.groups = {}
|
||||
|
||||
def register_shortcut(self, unique_name, name, default_keys=(),
|
||||
description=None, action=None, group=None):
|
||||
'''
|
||||
Register a shortcut with calibre. calibre will manage the shortcut,
|
||||
automatically resolving conflicts and allowing the user to customize
|
||||
it.
|
||||
|
||||
:param unique_name: A string that uniquely identifies this shortcut
|
||||
:param name: A user visible name describing the action performed by
|
||||
this shortcut
|
||||
:param default_keys: A tuple of keys that trigger this shortcut. Each
|
||||
key must be a string. For example: ('Ctrl+A', 'Alt+B', 'C',
|
||||
'Shift+Meta+D'). These keys will be assigned to the
|
||||
shortcut unless there is a conflict.
|
||||
:param action: A QAction object. The shortcut will cause this QAction
|
||||
to be triggered. Connect to its triggered signal in your code to
|
||||
respond to the shortcut.
|
||||
:param group: A string describing what "group" this shortcut belongs
|
||||
to. This is used to organize the list of shortcuts when the user is
|
||||
customizing them.
|
||||
'''
|
||||
if unique_name in self.shortcuts:
|
||||
name = self.shortcuts[unique_name]['name']
|
||||
raise NameConflict('Shortcut for %r already registered by %s'%(
|
||||
unique_name, name))
|
||||
shortcut = {'name':name, 'desc':description, 'action': action,
|
||||
'default_keys':tuple(default_keys)}
|
||||
self.shortcuts[unique_name] = shortcut
|
||||
group = group if group else _('Miscellaneous')
|
||||
self.groups[group] = self.groups.get(group, []) + [unique_name]
|
||||
|
||||
def finalize(self):
|
||||
custom_keys_map = {un:tuple(keys) for un, keys in self.config.get(
|
||||
'map', {}).iteritems()}
|
||||
self.keys_map = finalize(self.shortcuts, custom_keys_map=custom_keys_map)
|
||||
#import pprint
|
||||
#pprint.pprint(self.keys_map)
|
||||
|
||||
# }}}
|
||||
|
||||
# Model {{{
|
||||
|
||||
class Node(object):
|
||||
|
||||
def __init__(self, group_map, shortcut_map, name=None, shortcut=None):
|
||||
self.data = name if name is not None else shortcut
|
||||
self.is_shortcut = shortcut is not None
|
||||
self.children = []
|
||||
if name is not None:
|
||||
self.children = [Node(None, None, shortcut=shortcut_map[uname])
|
||||
for uname in group_map[name]]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.children)
|
||||
|
||||
def __getitem__(self, row):
|
||||
return self.children[row]
|
||||
|
||||
def __iter__(self):
|
||||
for child in self.children:
|
||||
yield child
|
||||
|
||||
class ConfigModel(QAbstractItemModel, SearchQueryParser):
|
||||
|
||||
def __init__(self, keyboard, parent=None):
|
||||
QAbstractItemModel.__init__(self, parent)
|
||||
SearchQueryParser.__init__(self, ['all'])
|
||||
|
||||
self.keyboard = keyboard
|
||||
groups = sorted(keyboard.groups, key=sort_key)
|
||||
shortcut_map = {k:v.copy() for k, v in
|
||||
self.keyboard.shortcuts.iteritems()}
|
||||
for un, s in shortcut_map.iteritems():
|
||||
s['keys'] = tuple(self.keyboard.keys_map.get(un, ()))
|
||||
s['unique_name'] = un
|
||||
s['group'] = [g for g, names in self.keyboard.groups.iteritems() if un in
|
||||
names][0]
|
||||
|
||||
group_map = {group:sorted(names, key=lambda x:
|
||||
sort_key(shortcut_map[x]['name'])) for group, names in
|
||||
self.keyboard.groups.iteritems()}
|
||||
|
||||
self.data = [Node(group_map, shortcut_map, group) for group in groups]
|
||||
|
||||
@property
|
||||
def all_shortcuts(self):
|
||||
for group in self.data:
|
||||
for sc in group:
|
||||
yield sc
|
||||
|
||||
def rowCount(self, parent=ROOT):
|
||||
ip = parent.internalPointer()
|
||||
if ip is None:
|
||||
return len(self.data)
|
||||
return len(ip)
|
||||
|
||||
def columnCount(self, parent=ROOT):
|
||||
return 1
|
||||
|
||||
def index(self, row, column, parent=ROOT):
|
||||
ip = parent.internalPointer()
|
||||
if ip is None:
|
||||
ip = self.data
|
||||
try:
|
||||
return self.createIndex(row, column, ip[row])
|
||||
except:
|
||||
pass
|
||||
return ROOT
|
||||
|
||||
def parent(self, index):
|
||||
ip = index.internalPointer()
|
||||
if ip is None or not ip.is_shortcut:
|
||||
return ROOT
|
||||
group = ip.data['group']
|
||||
for i, g in enumerate(self.data):
|
||||
if g.data == group:
|
||||
return self.index(i, 0)
|
||||
return ROOT
|
||||
|
||||
def data(self, index, role=Qt.DisplayRole):
|
||||
ip = index.internalPointer()
|
||||
if ip is not None and role == Qt.UserRole:
|
||||
return ip
|
||||
return NONE
|
||||
|
||||
def flags(self, index):
|
||||
ans = QAbstractItemModel.flags(self, index)
|
||||
ip = index.internalPointer()
|
||||
if getattr(ip, 'is_shortcut', False):
|
||||
ans |= Qt.ItemIsEditable
|
||||
return ans
|
||||
|
||||
def restore_defaults(self):
|
||||
shortcut_map = {}
|
||||
for node in self.all_shortcuts:
|
||||
sc = node.data
|
||||
shortcut_map[sc['unique_name']] = sc
|
||||
shortcuts = OrderedDict([(un, shortcut_map[un]) for un in
|
||||
self.keyboard.shortcuts])
|
||||
keys_map = finalize(shortcuts)
|
||||
for node in self.all_shortcuts:
|
||||
s = node.data
|
||||
s['keys'] = tuple(keys_map[s['unique_name']])
|
||||
for r in xrange(self.rowCount()):
|
||||
group = self.index(r, 0)
|
||||
num = self.rowCount(group)
|
||||
if num > 0:
|
||||
self.dataChanged.emit(self.index(0, 0, group),
|
||||
self.index(num-1, 0, group))
|
||||
|
||||
def commit(self):
|
||||
kmap = {}
|
||||
for node in self.all_shortcuts:
|
||||
sc = node.data
|
||||
if sc['set_to_default']: continue
|
||||
keys = [unicode(k.toString(k.PortableText)) for k in sc['keys']]
|
||||
kmap[sc['unique_name']] = keys
|
||||
self.keyboard.config['map'] = kmap
|
||||
|
||||
def universal_set(self):
|
||||
ans = set()
|
||||
for i, group in enumerate(self.data):
|
||||
ans.add((i, -1))
|
||||
for j, sc in enumerate(group.children):
|
||||
ans.add((i, j))
|
||||
return ans
|
||||
|
||||
def get_matches(self, location, query, candidates=None):
|
||||
if candidates is None:
|
||||
candidates = self.universal_set()
|
||||
ans = set([])
|
||||
if not query:
|
||||
return ans
|
||||
query = lower(query)
|
||||
for c, p in candidates:
|
||||
if p < 0:
|
||||
if query in lower(self.data[c].data):
|
||||
ans.add((c, p))
|
||||
else:
|
||||
try:
|
||||
sc = self.data[c].children[p].data
|
||||
except:
|
||||
continue
|
||||
if query in lower(sc['name']):
|
||||
ans.add((c, p))
|
||||
return ans
|
||||
|
||||
def find(self, query):
|
||||
query = query.strip()
|
||||
if not query:
|
||||
return ROOT
|
||||
matches = self.parse(query)
|
||||
if not matches:
|
||||
return ROOT
|
||||
matches = list(sorted(matches))
|
||||
c, p = matches[0]
|
||||
cat_idx = self.index(c, 0)
|
||||
if p == -1:
|
||||
return cat_idx
|
||||
return self.index(p, 0, cat_idx)
|
||||
|
||||
def find_next(self, idx, query, backwards=False):
|
||||
query = query.strip()
|
||||
if not query:
|
||||
return idx
|
||||
matches = self.parse(query)
|
||||
if not matches:
|
||||
return idx
|
||||
if idx.parent().isValid():
|
||||
loc = (idx.parent().row(), idx.row())
|
||||
else:
|
||||
loc = (idx.row(), -1)
|
||||
if loc not in matches:
|
||||
return self.find(query)
|
||||
if len(matches) == 1:
|
||||
return ROOT
|
||||
matches = list(sorted(matches))
|
||||
i = matches.index(loc)
|
||||
if backwards:
|
||||
ans = i - 1 if i - 1 >= 0 else len(matches)-1
|
||||
else:
|
||||
ans = i + 1 if i + 1 < len(matches) else 0
|
||||
|
||||
ans = matches[ans]
|
||||
|
||||
return (self.index(ans[0], 0) if ans[1] < 0 else
|
||||
self.index(ans[1], 0, self.index(ans[0], 0)))
|
||||
|
||||
# }}}
|
||||
|
||||
class Editor(QFrame): # {{{
|
||||
|
||||
editing_done = pyqtSignal(object)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QFrame.__init__(self, parent)
|
||||
self.setFocusPolicy(Qt.StrongFocus)
|
||||
self.setAutoFillBackground(True)
|
||||
self.capture = 0
|
||||
|
||||
self.setFrameShape(self.StyledPanel)
|
||||
self.setFrameShadow(self.Raised)
|
||||
self._layout = l = QGridLayout(self)
|
||||
self.setLayout(l)
|
||||
|
||||
self.header = QLabel('')
|
||||
l.addWidget(self.header, 0, 0, 1, 2)
|
||||
|
||||
self.use_default = QRadioButton('')
|
||||
self.use_custom = QRadioButton(_('Custom'))
|
||||
l.addWidget(self.use_default, 1, 0, 1, 3)
|
||||
l.addWidget(self.use_custom, 2, 0, 1, 3)
|
||||
self.use_custom.toggled.connect(self.custom_toggled)
|
||||
|
||||
off = 2
|
||||
for which in (1, 2):
|
||||
text = _('&Shortcut:') if which == 1 else _('&Alternate shortcut:')
|
||||
la = QLabel(text)
|
||||
la.setStyleSheet('QLabel { margin-left: 1.5em }')
|
||||
l.addWidget(la, off+which, 0, 1, 3)
|
||||
setattr(self, 'label%d'%which, la)
|
||||
button = QPushButton(_('None'), self)
|
||||
button.clicked.connect(partial(self.capture_clicked, which=which))
|
||||
button.keyPressEvent = partial(self.key_press_event, which=which)
|
||||
setattr(self, 'button%d'%which, button)
|
||||
clear = QToolButton(self)
|
||||
clear.setIcon(QIcon(I('clear_left.png')))
|
||||
clear.clicked.connect(partial(self.clear_clicked, which=which))
|
||||
setattr(self, 'clear%d'%which, clear)
|
||||
l.addWidget(button, off+which, 1, 1, 1)
|
||||
l.addWidget(clear, off+which, 2, 1, 1)
|
||||
la.setBuddy(button)
|
||||
|
||||
self.done_button = doneb = QPushButton(_('Done'), self)
|
||||
l.addWidget(doneb, 0, 2, 1, 1)
|
||||
doneb.clicked.connect(lambda : self.editing_done.emit(self))
|
||||
l.setColumnStretch(0, 100)
|
||||
|
||||
self.custom_toggled(False)
|
||||
|
||||
def initialize(self, shortcut, all_shortcuts):
|
||||
self.header.setText('<b>%s: %s</b>'%(_('Customize'), shortcut['name']))
|
||||
self.all_shortcuts = all_shortcuts
|
||||
self.shortcut = shortcut
|
||||
|
||||
self.default_keys = [QKeySequence(k, QKeySequence.PortableText) for k
|
||||
in shortcut['default_keys']]
|
||||
self.current_keys = list(shortcut['keys'])
|
||||
default = ', '.join([unicode(k.toString(k.NativeText)) for k in
|
||||
self.default_keys])
|
||||
if not default: default = _('None')
|
||||
current = ', '.join([unicode(k.toString(k.NativeText)) for k in
|
||||
self.current_keys])
|
||||
if not current: current = _('None')
|
||||
|
||||
self.use_default.setText(_('Default: %s [Currently not conflicting: %s]')%
|
||||
(default, current))
|
||||
|
||||
if shortcut['set_to_default']:
|
||||
self.use_default.setChecked(True)
|
||||
else:
|
||||
self.use_custom.setChecked(True)
|
||||
for key, which in zip(self.current_keys, [1,2]):
|
||||
button = getattr(self, 'button%d'%which)
|
||||
button.setText(key.toString(key.NativeText))
|
||||
|
||||
def custom_toggled(self, checked):
|
||||
for w in ('1', '2'):
|
||||
for o in ('label', 'button', 'clear'):
|
||||
getattr(self, o+w).setEnabled(checked)
|
||||
|
||||
def capture_clicked(self, which=1):
|
||||
self.capture = which
|
||||
button = getattr(self, 'button%d'%which)
|
||||
button.setText(_('Press a key...'))
|
||||
button.setFocus(Qt.OtherFocusReason)
|
||||
button.setStyleSheet('QPushButton { font-weight: bold}')
|
||||
|
||||
def clear_clicked(self, which=0):
|
||||
button = getattr(self, 'button%d'%which)
|
||||
button.setText(_('None'))
|
||||
|
||||
def key_press_event(self, ev, which=0):
|
||||
code = ev.key()
|
||||
if self.capture == 0 or code in (0, Qt.Key_unknown,
|
||||
Qt.Key_Shift, Qt.Key_Control, Qt.Key_Alt, Qt.Key_Meta,
|
||||
Qt.Key_AltGr, Qt.Key_CapsLock, Qt.Key_NumLock, Qt.Key_ScrollLock):
|
||||
return QWidget.keyPressEvent(self, ev)
|
||||
button = getattr(self, 'button%d'%which)
|
||||
button.setStyleSheet('QPushButton { font-weight: normal}')
|
||||
sequence = QKeySequence(code|(int(ev.modifiers())&~Qt.KeypadModifier))
|
||||
button.setText(sequence.toString(QKeySequence.NativeText))
|
||||
self.capture = 0
|
||||
dup_desc = self.dup_check(sequence)
|
||||
if dup_desc is not None:
|
||||
error_dialog(self, _('Already assigned'),
|
||||
unicode(sequence.toString(QKeySequence.NativeText)) + ' ' +
|
||||
_('already assigned to') + ' ' + dup_desc, show=True)
|
||||
self.clear_clicked(which=which)
|
||||
|
||||
def dup_check(self, sequence):
|
||||
for sc in self.all_shortcuts:
|
||||
if sc is self.shortcut: continue
|
||||
for k in sc['keys']:
|
||||
if k == sequence:
|
||||
return sc['name']
|
||||
|
||||
@property
|
||||
def custom_keys(self):
|
||||
if self.use_default.isChecked():
|
||||
return None
|
||||
ans = []
|
||||
for which in (1, 2):
|
||||
button = getattr(self, 'button%d'%which)
|
||||
t = unicode(button.text())
|
||||
if t == _('None'):
|
||||
continue
|
||||
ks = QKeySequence(t, QKeySequence.NativeText)
|
||||
if not ks.isEmpty():
|
||||
ans.append(ks)
|
||||
return tuple(ans)
|
||||
|
||||
|
||||
# }}}
|
||||
|
||||
class Delegate(QStyledItemDelegate): # {{{
|
||||
|
||||
changed_signal = pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QStyledItemDelegate.__init__(self, parent)
|
||||
self.editing_index = None
|
||||
self.closeEditor.connect(self.editing_done)
|
||||
|
||||
def to_doc(self, index):
|
||||
data = index.data(Qt.UserRole).toPyObject()
|
||||
if data is None:
|
||||
html = _('<b>This shortcut no longer exists</b>')
|
||||
elif data.is_shortcut:
|
||||
shortcut = data.data
|
||||
# Shortcut
|
||||
keys = [unicode(k.toString(k.NativeText)) for k in shortcut['keys']]
|
||||
if not keys:
|
||||
keys = _('None')
|
||||
else:
|
||||
keys = ', '.join(keys)
|
||||
html = '<b>%s</b><br>%s: %s'%(shortcut['name'], _('Shortcuts'), keys)
|
||||
else:
|
||||
# Group
|
||||
html = '<h3>%s</h3>'%data.data
|
||||
doc = QTextDocument()
|
||||
doc.setHtml(html)
|
||||
return doc
|
||||
|
||||
def sizeHint(self, option, index):
|
||||
if index == self.editing_index:
|
||||
return QSize(200, 200)
|
||||
ans = self.to_doc(index).size().toSize()
|
||||
return ans
|
||||
|
||||
def paint(self, painter, option, index):
|
||||
painter.save()
|
||||
painter.setClipRect(QRectF(option.rect))
|
||||
if hasattr(QStyle, 'CE_ItemViewItem'):
|
||||
QApplication.style().drawControl(QStyle.CE_ItemViewItem, option, painter)
|
||||
elif option.state & QStyle.State_Selected:
|
||||
painter.fillRect(option.rect, option.palette.highlight())
|
||||
painter.translate(option.rect.topLeft())
|
||||
self.to_doc(index).drawContents(painter)
|
||||
painter.restore()
|
||||
|
||||
def createEditor(self, parent, option, index):
|
||||
w = Editor(parent=parent)
|
||||
w.editing_done.connect(self.editor_done)
|
||||
self.editing_index = index
|
||||
self.sizeHintChanged.emit(index)
|
||||
return w
|
||||
|
||||
def editor_done(self, editor):
|
||||
self.commitData.emit(editor)
|
||||
|
||||
def setEditorData(self, editor, index):
|
||||
all_shortcuts = [x.data for x in index.model().all_shortcuts]
|
||||
shortcut = index.internalPointer().data
|
||||
editor.initialize(shortcut, all_shortcuts)
|
||||
|
||||
def setModelData(self, editor, model, index):
|
||||
self.closeEditor.emit(editor, self.NoHint)
|
||||
custom_keys = editor.custom_keys
|
||||
sc = index.data(Qt.UserRole).toPyObject().data
|
||||
if custom_keys is None:
|
||||
candidates = []
|
||||
for ckey in sc['default_keys']:
|
||||
ckey = QKeySequence(ckey, QKeySequence.PortableText)
|
||||
matched = False
|
||||
for s in editor.all_shortcuts:
|
||||
for k in s['keys']:
|
||||
if k == ckey:
|
||||
matched = True
|
||||
break
|
||||
if not matched:
|
||||
candidates.append(ckey)
|
||||
candidates = tuple(candidates)
|
||||
sc['set_to_default'] = True
|
||||
else:
|
||||
sc['set_to_default'] = False
|
||||
candidates = custom_keys
|
||||
sc['keys'] = candidates
|
||||
self.changed_signal.emit()
|
||||
|
||||
def updateEditorGeometry(self, editor, option, index):
|
||||
editor.setGeometry(option.rect)
|
||||
|
||||
def editing_done(self, *args):
|
||||
idx = self.editing_index
|
||||
self.editing_index = None
|
||||
if idx is not None:
|
||||
self.sizeHintChanged.emit(idx)
|
||||
|
||||
# }}}
|
||||
|
||||
class ShortcutConfig(QWidget): # {{{
|
||||
|
||||
changed_signal = pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self._layout = l = QGridLayout()
|
||||
self.setLayout(self._layout)
|
||||
self.header = QLabel(_('Double click on any entry to change the'
|
||||
' keyboard shortcuts associated with it'))
|
||||
l.addWidget(self.header, 0, 0, 1, 3)
|
||||
self.view = QTreeView(self)
|
||||
self.view.setAlternatingRowColors(True)
|
||||
self.view.setHeaderHidden(True)
|
||||
self.view.setAnimated(True)
|
||||
l.addWidget(self.view, 1, 0, 1, 3)
|
||||
self.delegate = Delegate()
|
||||
self.view.setItemDelegate(self.delegate)
|
||||
self.delegate.sizeHintChanged.connect(self.scrollTo)
|
||||
self.delegate.changed_signal.connect(self.changed_signal)
|
||||
self.search = SearchBox2(self)
|
||||
self.search.initialize('shortcuts_search_history',
|
||||
help_text=_('Search for a shortcut by name'))
|
||||
self.search.search.connect(self.find)
|
||||
l.addWidget(self.search, 2, 0, 1, 1)
|
||||
self.nb = QPushButton(QIcon(I('arrow-down.png')), _('&Next'), self)
|
||||
self.pb = QPushButton(QIcon(I('arrow-up.png')), _('&Previous'), self)
|
||||
self.nb.clicked.connect(self.find_next)
|
||||
self.pb.clicked.connect(self.find_previous)
|
||||
l.addWidget(self.nb, 2, 1, 1, 1)
|
||||
l.addWidget(self.pb, 2, 2, 1, 1)
|
||||
l.setColumnStretch(0, 100)
|
||||
|
||||
def restore_defaults(self):
|
||||
self._model.restore_defaults()
|
||||
self.changed_signal.emit()
|
||||
|
||||
def commit(self):
|
||||
self._model.commit()
|
||||
|
||||
def initialize(self, keyboard):
|
||||
self._model = ConfigModel(keyboard, parent=self)
|
||||
self.view.setModel(self._model)
|
||||
|
||||
def scrollTo(self, index):
|
||||
if index is not None:
|
||||
self.view.scrollTo(index, self.view.PositionAtTop)
|
||||
|
||||
@property
|
||||
def is_editing(self):
|
||||
return self.view.state() == self.view.EditingState
|
||||
|
||||
def find(self, query):
|
||||
if not query:
|
||||
return
|
||||
try:
|
||||
idx = self._model.find(query)
|
||||
except ParseException:
|
||||
self.search.search_done(False)
|
||||
return
|
||||
self.search.search_done(True)
|
||||
if not idx.isValid():
|
||||
info_dialog(self, _('No matches'),
|
||||
_('Could not find any shortcuts matching %s')%query,
|
||||
show=True, show_copy_button=False)
|
||||
return
|
||||
self.highlight_index(idx)
|
||||
|
||||
def highlight_index(self, idx):
|
||||
self.view.scrollTo(idx)
|
||||
self.view.selectionModel().select(idx,
|
||||
self.view.selectionModel().ClearAndSelect)
|
||||
self.view.setCurrentIndex(idx)
|
||||
self.view.setFocus(Qt.OtherFocusReason)
|
||||
|
||||
def find_next(self, *args):
|
||||
idx = self.view.currentIndex()
|
||||
if not idx.isValid():
|
||||
idx = self._model.index(0, 0)
|
||||
idx = self._model.find_next(idx,
|
||||
unicode(self.search.currentText()))
|
||||
self.highlight_index(idx)
|
||||
|
||||
def find_previous(self, *args):
|
||||
idx = self.view.currentIndex()
|
||||
if not idx.isValid():
|
||||
idx = self._model.index(0, 0)
|
||||
idx = self._model.find_next(idx,
|
||||
unicode(self.search.currentText()), backwards=True)
|
||||
self.highlight_index(idx)
|
||||
|
||||
|
||||
# }}}
|
||||
|
62
src/calibre/gui2/languages.py
Normal file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from calibre.gui2.complete import MultiCompleteComboBox
|
||||
from calibre.utils.localization import lang_map
|
||||
from calibre.utils.icu import sort_key
|
||||
|
||||
class LanguagesEdit(MultiCompleteComboBox):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
MultiCompleteComboBox.__init__(self, parent)
|
||||
|
||||
self._lang_map = lang_map()
|
||||
self._rmap = {v:k for k,v in self._lang_map.iteritems()}
|
||||
|
||||
all_items = sorted(self._lang_map.itervalues(),
|
||||
key=sort_key)
|
||||
self.update_items_cache(all_items)
|
||||
for item in all_items:
|
||||
self.addItem(item)
|
||||
|
||||
@dynamic_property
|
||||
def lang_codes(self):
|
||||
|
||||
def fget(self):
|
||||
vals = [x.strip() for x in
|
||||
unicode(self.lineEdit().text()).split(',')]
|
||||
ans = []
|
||||
for name in vals:
|
||||
if name:
|
||||
code = self._rmap.get(name, None)
|
||||
if code is not None:
|
||||
ans.append(code)
|
||||
return ans
|
||||
|
||||
def fset(self, lang_codes):
|
||||
ans = []
|
||||
for lc in lang_codes:
|
||||
name = self._lang_map.get(lc, None)
|
||||
if name is not None:
|
||||
ans.append(name)
|
||||
self.setEditText(', '.join(ans))
|
||||
|
||||
return property(fget=fget, fset=fset)
|
||||
|
||||
def validate(self):
|
||||
vals = [x.strip() for x in
|
||||
unicode(self.lineEdit().text()).split(',')]
|
||||
bad = []
|
||||
for name in vals:
|
||||
if name:
|
||||
code = self._rmap.get(name, None)
|
||||
if code is None:
|
||||
bad.append(name)
|
||||
return bad
|
||||
|
@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en'
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import (QIcon, Qt, QWidget, QSize,
|
||||
pyqtSignal, QToolButton, QMenu,
|
||||
pyqtSignal, QToolButton, QMenu, QAction,
|
||||
QObject, QVBoxLayout, QSizePolicy, QLabel, QHBoxLayout, QActionGroup)
|
||||
|
||||
|
||||
@ -178,7 +178,12 @@ class SearchBar(QWidget): # {{{
|
||||
x.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
|
||||
|
||||
parent.advanced_search_button = x = QToolButton(self)
|
||||
parent.advanced_search_button.setShortcut(_("Shift+Ctrl+F"))
|
||||
parent.advanced_search_toggle_action = ac = QAction(parent)
|
||||
parent.addAction(ac)
|
||||
parent.keyboard.register_shortcut('advanced search toggle',
|
||||
_('Advanced search'), default_keys=(_("Shift+Ctrl+F"),),
|
||||
action=ac)
|
||||
ac.triggered.connect(x.click)
|
||||
x.setIcon(QIcon(I('search.png')))
|
||||
l.addWidget(x)
|
||||
x.setToolTip(_("Advanced search"))
|
||||
|
@ -23,6 +23,7 @@ from calibre.utils.formatter import validation_formatter
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.gui2.dialogs.comments_dialog import CommentsDialog
|
||||
from calibre.gui2.dialogs.template_dialog import TemplateDialog
|
||||
from calibre.gui2.languages import LanguagesEdit
|
||||
|
||||
|
||||
class RatingDelegate(QStyledItemDelegate): # {{{
|
||||
@ -155,7 +156,7 @@ class TextDelegate(QStyledItemDelegate): # {{{
|
||||
def __init__(self, parent):
|
||||
'''
|
||||
Delegate for text data. If auto_complete_function needs to return a list
|
||||
of text items to auto-complete with. The funciton is None no
|
||||
of text items to auto-complete with. If the function is None no
|
||||
auto-complete will be used.
|
||||
'''
|
||||
QStyledItemDelegate.__init__(self, parent)
|
||||
@ -229,6 +230,20 @@ class CompleteDelegate(QStyledItemDelegate): # {{{
|
||||
QStyledItemDelegate.setModelData(self, editor, model, index)
|
||||
# }}}
|
||||
|
||||
class LanguagesDelegate(QStyledItemDelegate): # {{{
|
||||
|
||||
def createEditor(self, parent, option, index):
|
||||
editor = LanguagesEdit(parent)
|
||||
ct = index.data(Qt.DisplayRole).toString()
|
||||
editor.setEditText(ct)
|
||||
editor.lineEdit().selectAll()
|
||||
return editor
|
||||
|
||||
def setModelData(self, editor, model, index):
|
||||
val = ','.join(editor.lang_codes)
|
||||
model.setData(index, QVariant(val), Qt.EditRole)
|
||||
# }}}
|
||||
|
||||
class CcDateDelegate(QStyledItemDelegate): # {{{
|
||||
'''
|
||||
Delegate for custom columns dates. Because this delegate stores the
|
||||
@ -300,16 +315,22 @@ class CcNumberDelegate(QStyledItemDelegate): # {{{
|
||||
col = m.column_map[index.column()]
|
||||
if m.custom_columns[col]['datatype'] == 'int':
|
||||
editor = QSpinBox(parent)
|
||||
editor.setRange(-100, 100000000)
|
||||
editor.setRange(-1000000, 100000000)
|
||||
editor.setSpecialValueText(_('Undefined'))
|
||||
editor.setSingleStep(1)
|
||||
else:
|
||||
editor = QDoubleSpinBox(parent)
|
||||
editor.setSpecialValueText(_('Undefined'))
|
||||
editor.setRange(-100., 100000000)
|
||||
editor.setRange(-1000000., 100000000)
|
||||
editor.setDecimals(2)
|
||||
return editor
|
||||
|
||||
def setModelData(self, editor, model, index):
|
||||
val = editor.value()
|
||||
if val == editor.minimum():
|
||||
val = None
|
||||
model.setData(index, QVariant(val), Qt.EditRole)
|
||||
|
||||
def setEditorData(self, editor, index):
|
||||
m = index.model()
|
||||
val = m.db.data[index.row()][m.custom_columns[m.column_map[index.column()]]['rec_index']]
|
||||
|
@ -25,6 +25,7 @@ from calibre.library.caches import (_match, CONTAINS_MATCH, EQUALS_MATCH,
|
||||
from calibre import strftime, isbytestring
|
||||
from calibre.constants import filesystem_encoding, DEBUG
|
||||
from calibre.gui2.library import DEFAULT_SORT
|
||||
from calibre.utils.localization import calibre_langcode_to_name
|
||||
|
||||
def human_readable(size, precision=1):
|
||||
""" Convert a size in bytes into megabytes """
|
||||
@ -62,8 +63,9 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
'rating' : _('Rating'),
|
||||
'publisher' : _("Publisher"),
|
||||
'tags' : _("Tags"),
|
||||
'series' : _("Series"),
|
||||
'series' : ngettext("Series", 'Series', 1),
|
||||
'last_modified' : _('Modified'),
|
||||
'languages' : _('Languages'),
|
||||
}
|
||||
|
||||
def __init__(self, parent=None, buffer=40):
|
||||
@ -71,7 +73,8 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
self.db = None
|
||||
self.book_on_device = None
|
||||
self.editable_cols = ['title', 'authors', 'rating', 'publisher',
|
||||
'tags', 'series', 'timestamp', 'pubdate']
|
||||
'tags', 'series', 'timestamp', 'pubdate',
|
||||
'languages']
|
||||
self.default_image = default_image()
|
||||
self.sorted_on = DEFAULT_SORT
|
||||
self.sort_history = [self.sorted_on]
|
||||
@ -540,6 +543,13 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
else:
|
||||
return None
|
||||
|
||||
def languages(r, idx=-1):
|
||||
lc = self.db.data[r][idx]
|
||||
if lc:
|
||||
langs = [calibre_langcode_to_name(l.strip()) for l in lc.split(',')]
|
||||
return QVariant(', '.join(langs))
|
||||
return None
|
||||
|
||||
def tags(r, idx=-1):
|
||||
tags = self.db.data[r][idx]
|
||||
if tags:
|
||||
@ -641,6 +651,8 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
siix=self.db.field_metadata['series_index']['rec_index']),
|
||||
'ondevice' : functools.partial(text_type,
|
||||
idx=self.db.field_metadata['ondevice']['rec_index'], mult=None),
|
||||
'languages': functools.partial(languages,
|
||||
idx=self.db.field_metadata['languages']['rec_index']),
|
||||
}
|
||||
|
||||
self.dc_decorator = {
|
||||
@ -694,7 +706,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
# we will get asked to display columns we don't know about. Must test for this.
|
||||
if col >= len(self.column_to_dc_map):
|
||||
return NONE
|
||||
if role in (Qt.DisplayRole, Qt.EditRole):
|
||||
if role in (Qt.DisplayRole, Qt.EditRole, Qt.ToolTipRole):
|
||||
return self.column_to_dc_map[col](index.row())
|
||||
elif role == Qt.BackgroundRole:
|
||||
if self.id(index) in self.ids_to_highlight_set:
|
||||
@ -884,6 +896,9 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
if val.isNull() or not val.isValid():
|
||||
return False
|
||||
self.db.set_pubdate(id, qt_to_dt(val, as_utc=False))
|
||||
elif column == 'languages':
|
||||
val = val.split(',')
|
||||
self.db.set_languages(id, val)
|
||||
else:
|
||||
books_to_refresh |= self.db.set(row, column, val,
|
||||
allow_case_change=True)
|
||||
|
@ -8,14 +8,14 @@ __docformat__ = 'restructuredtext en'
|
||||
import os
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import QTableView, Qt, QAbstractItemView, QMenu, pyqtSignal, \
|
||||
QModelIndex, QIcon, QItemSelection, QMimeData, QDrag, QApplication, \
|
||||
QPoint, QPixmap, QUrl, QImage, QPainter, QColor, QRect
|
||||
from PyQt4.Qt import (QTableView, Qt, QAbstractItemView, QMenu, pyqtSignal,
|
||||
QModelIndex, QIcon, QItemSelection, QMimeData, QDrag, QApplication,
|
||||
QPoint, QPixmap, QUrl, QImage, QPainter, QColor, QRect)
|
||||
|
||||
from calibre.gui2.library.delegates import RatingDelegate, PubDateDelegate, \
|
||||
TextDelegate, DateDelegate, CompleteDelegate, CcTextDelegate, \
|
||||
CcBoolDelegate, CcCommentsDelegate, CcDateDelegate, CcTemplateDelegate, \
|
||||
CcEnumDelegate, CcNumberDelegate
|
||||
from calibre.gui2.library.delegates import (RatingDelegate, PubDateDelegate,
|
||||
TextDelegate, DateDelegate, CompleteDelegate, CcTextDelegate,
|
||||
CcBoolDelegate, CcCommentsDelegate, CcDateDelegate, CcTemplateDelegate,
|
||||
CcEnumDelegate, CcNumberDelegate, LanguagesDelegate)
|
||||
from calibre.gui2.library.models import BooksModel, DeviceBooksModel
|
||||
from calibre.utils.config import tweaks, prefs
|
||||
from calibre.gui2 import error_dialog, gprefs
|
||||
@ -85,6 +85,7 @@ class BooksView(QTableView): # {{{
|
||||
self.pubdate_delegate = PubDateDelegate(self)
|
||||
self.last_modified_delegate = DateDelegate(self,
|
||||
tweak_name='gui_last_modified_display_format')
|
||||
self.languages_delegate = LanguagesDelegate(self)
|
||||
self.tags_delegate = CompleteDelegate(self, ',', 'all_tags')
|
||||
self.authors_delegate = CompleteDelegate(self, '&', 'all_author_names', True)
|
||||
self.cc_names_delegate = CompleteDelegate(self, '&', 'all_custom', True)
|
||||
@ -306,6 +307,7 @@ class BooksView(QTableView): # {{{
|
||||
state['hidden_columns'] = [cm[i] for i in range(h.count())
|
||||
if h.isSectionHidden(i) and cm[i] != 'ondevice']
|
||||
state['last_modified_injected'] = True
|
||||
state['languages_injected'] = True
|
||||
state['sort_history'] = \
|
||||
self.cleanup_sort_history(self.model().sort_history)
|
||||
state['column_positions'] = {}
|
||||
@ -390,7 +392,7 @@ class BooksView(QTableView): # {{{
|
||||
|
||||
def get_default_state(self):
|
||||
old_state = {
|
||||
'hidden_columns': ['last_modified'],
|
||||
'hidden_columns': ['last_modified', 'languages'],
|
||||
'sort_history':[DEFAULT_SORT],
|
||||
'column_positions': {},
|
||||
'column_sizes': {},
|
||||
@ -399,6 +401,7 @@ class BooksView(QTableView): # {{{
|
||||
'timestamp':'center',
|
||||
'pubdate':'center'},
|
||||
'last_modified_injected': True,
|
||||
'languages_injected': True,
|
||||
}
|
||||
h = self.column_header
|
||||
cm = self.column_map
|
||||
@ -430,11 +433,20 @@ class BooksView(QTableView): # {{{
|
||||
if ans is not None:
|
||||
db.prefs[name] = ans
|
||||
else:
|
||||
injected = False
|
||||
if not ans.get('last_modified_injected', False):
|
||||
injected = True
|
||||
ans['last_modified_injected'] = True
|
||||
hc = ans.get('hidden_columns', [])
|
||||
if 'last_modified' not in hc:
|
||||
hc.append('last_modified')
|
||||
if not ans.get('languages_injected', False):
|
||||
injected = True
|
||||
ans['languages_injected'] = True
|
||||
hc = ans.get('hidden_columns', [])
|
||||
if 'languages' not in hc:
|
||||
hc.append('languages')
|
||||
if injected:
|
||||
db.prefs[name] = ans
|
||||
return ans
|
||||
|
||||
@ -501,7 +513,7 @@ class BooksView(QTableView): # {{{
|
||||
for i in range(self.model().columnCount(None)):
|
||||
if self.itemDelegateForColumn(i) in (self.rating_delegate,
|
||||
self.timestamp_delegate, self.pubdate_delegate,
|
||||
self.last_modified_delegate):
|
||||
self.last_modified_delegate, self.languages_delegate):
|
||||
self.setItemDelegateForColumn(i, self.itemDelegate())
|
||||
|
||||
cm = self.column_map
|
||||
@ -719,7 +731,7 @@ class BooksView(QTableView): # {{{
|
||||
break
|
||||
|
||||
def set_current_row(self, row, select=True):
|
||||
if row > -1:
|
||||
if row > -1 and row < self.model().rowCount(QModelIndex()):
|
||||
h = self.horizontalHeader()
|
||||
logical_indices = list(range(h.count()))
|
||||
logical_indices = [x for x in logical_indices if not
|
||||
|
@ -34,6 +34,7 @@ from calibre.library.comments import comments_to_html
|
||||
from calibre.gui2.dialogs.tag_editor import TagEditor
|
||||
from calibre.utils.icu import strcmp
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
from calibre.gui2.languages import LanguagesEdit as LE
|
||||
|
||||
def save_dialog(parent, title, msg, det_msg=''):
|
||||
d = QMessageBox(parent)
|
||||
@ -1133,6 +1134,43 @@ class TagsEdit(MultiCompleteLineEdit): # {{{
|
||||
|
||||
# }}}
|
||||
|
||||
class LanguagesEdit(LE): # {{{
|
||||
|
||||
LABEL = _('&Languages:')
|
||||
TOOLTIP = _('A comma separated list of languages for this book')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
LE.__init__(self, *args, **kwargs)
|
||||
self.setToolTip(self.TOOLTIP)
|
||||
|
||||
@dynamic_property
|
||||
def current_val(self):
|
||||
def fget(self): return self.lang_codes
|
||||
def fset(self, val): self.lang_codes = val
|
||||
return property(fget=fget, fset=fset)
|
||||
|
||||
def initialize(self, db, id_):
|
||||
lc = []
|
||||
langs = db.languages(id_, index_is_id=True)
|
||||
if langs:
|
||||
lc = [x.strip() for x in langs.split(',')]
|
||||
self.current_val = self.original_val = lc
|
||||
|
||||
def commit(self, db, id_):
|
||||
bad = self.validate()
|
||||
if bad:
|
||||
error_dialog(self, _('Unknown language'),
|
||||
ngettext('The language %s is not recognized',
|
||||
'The languages %s are not recognized', len(bad))%(
|
||||
', '.join(bad)),
|
||||
show=True)
|
||||
return False
|
||||
cv = self.current_val
|
||||
if cv != self.original_val:
|
||||
db.set_languages(id_, cv)
|
||||
return True
|
||||
# }}}
|
||||
|
||||
class IdentifiersEdit(QLineEdit): # {{{
|
||||
LABEL = _('I&ds:')
|
||||
BASE_TT = _('Edit the identifiers for this book. '
|
||||
|
@ -13,19 +13,21 @@ from functools import partial
|
||||
from PyQt4.Qt import (Qt, QVBoxLayout, QHBoxLayout, QWidget, QPushButton,
|
||||
QGridLayout, pyqtSignal, QDialogButtonBox, QScrollArea, QFont,
|
||||
QTabWidget, QIcon, QToolButton, QSplitter, QGroupBox, QSpacerItem,
|
||||
QSizePolicy, QPalette, QFrame, QSize, QKeySequence, QMenu)
|
||||
QSizePolicy, QPalette, QFrame, QSize, QKeySequence, QMenu, QShortcut)
|
||||
|
||||
from calibre.ebooks.metadata import authors_to_string, string_to_authors
|
||||
from calibre.gui2 import ResizableDialog, error_dialog, gprefs, pixmap_to_data
|
||||
from calibre.gui2.metadata.basic_widgets import (TitleEdit, AuthorsEdit,
|
||||
AuthorSortEdit, TitleSortEdit, SeriesEdit, SeriesIndexEdit, IdentifiersEdit,
|
||||
RatingEdit, PublisherEdit, TagsEdit, FormatsManager, Cover, CommentsEdit,
|
||||
BuddyLabel, DateEdit, PubdateEdit)
|
||||
BuddyLabel, DateEdit, PubdateEdit, LanguagesEdit)
|
||||
from calibre.gui2.metadata.single_download import FullFetch
|
||||
from calibre.gui2.custom_column_widgets import populate_metadata_page
|
||||
from calibre.utils.config import tweaks
|
||||
from calibre.ebooks.metadata.book.base import Metadata
|
||||
|
||||
BASE_TITLE = _('Edit Metadata')
|
||||
|
||||
class MetadataSingleDialogBase(ResizableDialog):
|
||||
|
||||
view_format = pyqtSignal(object, object)
|
||||
@ -43,6 +45,16 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
def setupUi(self, *args): # {{{
|
||||
self.resize(990, 650)
|
||||
|
||||
self.download_shortcut = QShortcut(self)
|
||||
self.download_shortcut.setKey(QKeySequence('Ctrl+D',
|
||||
QKeySequence.PortableText))
|
||||
p = self.parent()
|
||||
if hasattr(p, 'keyboard'):
|
||||
kname = u'Interface Action: Edit Metadata (Edit Metadata) : menu action : download'
|
||||
sc = p.keyboard.keys_map.get(kname, None)
|
||||
if sc:
|
||||
self.download_shortcut.setKey(sc[0])
|
||||
|
||||
self.button_box = QDialogButtonBox(
|
||||
QDialogButtonBox.Ok|QDialogButtonBox.Cancel, Qt.Horizontal,
|
||||
self)
|
||||
@ -77,7 +89,7 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
ll.addSpacing(10)
|
||||
|
||||
self.setWindowIcon(QIcon(I('edit_input.png')))
|
||||
self.setWindowTitle(_('Edit Metadata'))
|
||||
self.setWindowTitle(BASE_TITLE)
|
||||
|
||||
self.create_basic_metadata_widgets()
|
||||
|
||||
@ -183,6 +195,9 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
self.publisher = PublisherEdit(self)
|
||||
self.basic_metadata_widgets.append(self.publisher)
|
||||
|
||||
self.languages = LanguagesEdit(self)
|
||||
self.basic_metadata_widgets.append(self.languages)
|
||||
|
||||
self.timestamp = DateEdit(self)
|
||||
self.pubdate = PubdateEdit(self)
|
||||
self.basic_metadata_widgets.extend([self.timestamp, self.pubdate])
|
||||
@ -190,6 +205,7 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
self.fetch_metadata_button = QPushButton(
|
||||
_('&Download metadata'), self)
|
||||
self.fetch_metadata_button.clicked.connect(self.fetch_metadata)
|
||||
self.download_shortcut.activated.connect(self.fetch_metadata_button.click)
|
||||
font = self.fmb_font = QFont()
|
||||
font.setBold(True)
|
||||
self.fetch_metadata_button.setFont(font)
|
||||
@ -264,8 +280,11 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
title = self.title.current_val
|
||||
if len(title) > 50:
|
||||
title = title[:50] + u'\u2026'
|
||||
self.setWindowTitle(_('Edit Metadata') + ' - ' +
|
||||
title)
|
||||
self.setWindowTitle(BASE_TITLE + ' - ' +
|
||||
title + ' - ' +
|
||||
_(' [%(num)d of %(tot)d]')%dict(num=
|
||||
self.current_row+1,
|
||||
tot=len(self.row_list)))
|
||||
|
||||
def swap_title_author(self, *args):
|
||||
title = self.title.current_val
|
||||
@ -351,6 +370,8 @@ class MetadataSingleDialogBase(ResizableDialog):
|
||||
self.series.current_val = mi.series
|
||||
if mi.series_index is not None:
|
||||
self.series_index.current_val = float(mi.series_index)
|
||||
if not mi.is_null('languages'):
|
||||
self.languages.lang_codes = mi.languages
|
||||
if mi.comments and mi.comments.strip():
|
||||
self.comments.current_val = mi.comments
|
||||
|
||||
@ -610,11 +631,13 @@ class MetadataSingleDialog(MetadataSingleDialogBase): # {{{
|
||||
create_row2(5, self.pubdate, self.pubdate.clear_button)
|
||||
sto(self.pubdate.clear_button, self.publisher)
|
||||
create_row2(6, self.publisher)
|
||||
sto(self.publisher, self.languages)
|
||||
create_row2(7, self.languages)
|
||||
self.tabs[0].spc_two = QSpacerItem(10, 10, QSizePolicy.Expanding,
|
||||
QSizePolicy.Expanding)
|
||||
l.addItem(self.tabs[0].spc_two, 8, 0, 1, 3)
|
||||
l.addWidget(self.fetch_metadata_button, 9, 0, 1, 2)
|
||||
l.addWidget(self.config_metadata_button, 9, 2, 1, 1)
|
||||
l.addItem(self.tabs[0].spc_two, 9, 0, 1, 3)
|
||||
l.addWidget(self.fetch_metadata_button, 10, 0, 1, 2)
|
||||
l.addWidget(self.config_metadata_button, 10, 2, 1, 1)
|
||||
|
||||
self.tabs[0].gb2 = gb = QGroupBox(_('Co&mments'), self)
|
||||
gb.l = l = QVBoxLayout()
|
||||
@ -717,16 +740,17 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{
|
||||
create_row(7, self.rating, self.pubdate)
|
||||
create_row(8, self.pubdate, self.publisher,
|
||||
button=self.pubdate.clear_button, icon='trash.png')
|
||||
create_row(9, self.publisher, self.timestamp)
|
||||
create_row(10, self.timestamp, self.identifiers,
|
||||
create_row(9, self.publisher, self.languages)
|
||||
create_row(10, self.languages, self.timestamp)
|
||||
create_row(11, self.timestamp, self.identifiers,
|
||||
button=self.timestamp.clear_button, icon='trash.png')
|
||||
create_row(11, self.identifiers, self.comments,
|
||||
create_row(12, self.identifiers, self.comments,
|
||||
button=self.clear_identifiers_button, icon='trash.png')
|
||||
sto(self.clear_identifiers_button, self.swap_title_author_button)
|
||||
sto(self.swap_title_author_button, self.manage_authors_button)
|
||||
sto(self.manage_authors_button, self.paste_isbn_button)
|
||||
tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding),
|
||||
12, 1, 1 ,1)
|
||||
13, 1, 1 ,1)
|
||||
|
||||
w = getattr(self, 'custom_metadata_widgets_parent', None)
|
||||
if w is not None:
|
||||
@ -852,16 +876,17 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{
|
||||
create_row(7, self.rating, self.pubdate)
|
||||
create_row(8, self.pubdate, self.publisher,
|
||||
button=self.pubdate.clear_button, icon='trash.png')
|
||||
create_row(9, self.publisher, self.timestamp)
|
||||
create_row(10, self.timestamp, self.identifiers,
|
||||
create_row(9, self.publisher, self.languages)
|
||||
create_row(10, self.languages, self.timestamp)
|
||||
create_row(11, self.timestamp, self.identifiers,
|
||||
button=self.timestamp.clear_button, icon='trash.png')
|
||||
create_row(11, self.identifiers, self.comments,
|
||||
create_row(12, self.identifiers, self.comments,
|
||||
button=self.clear_identifiers_button, icon='trash.png')
|
||||
sto(self.clear_identifiers_button, self.swap_title_author_button)
|
||||
sto(self.swap_title_author_button, self.manage_authors_button)
|
||||
sto(self.manage_authors_button, self.paste_isbn_button)
|
||||
tl.addItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding),
|
||||
12, 1, 1 ,1)
|
||||
13, 1, 1 ,1)
|
||||
|
||||
# Custom metadata in col 1
|
||||
w = getattr(self, 'custom_metadata_widgets_parent', None)
|
||||
|
@ -24,6 +24,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||
r('read_file_metadata', prefs)
|
||||
r('swap_author_names', prefs)
|
||||
r('add_formats_to_existing', prefs)
|
||||
r('preserve_date_on_ctl', gprefs)
|
||||
choices = [
|
||||
(_('Ignore duplicate incoming formats'), 'ignore'),
|
||||
(_('Overwrite existing duplicate formats'), 'overwrite'),
|
||||
|
@ -27,7 +27,7 @@
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="opt_read_file_metadata">
|
||||
<property name="text">
|
||||
<string>Read &metadata from &file contents rather than file name</string>
|
||||
<string>Read &metadata from file contents rather than file name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -58,7 +58,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="opt_add_formats_to_existing">
|
||||
<property name="toolTip">
|
||||
<string>Automerge: If books with similar titles and authors found, merge the incoming formats automatically into
|
||||
@ -72,7 +72,7 @@ Title match ignores leading indefinite articles ("the", "a",
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="opt_automerge">
|
||||
<property name="toolTip">
|
||||
<string>Automerge: If books with similar titles and authors found, merge the incoming formats automatically into
|
||||
@ -88,7 +88,7 @@ Author matching is exact.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_230">
|
||||
<property name="text">
|
||||
<string>&Tags to apply when adding a book:</string>
|
||||
@ -98,14 +98,14 @@ Author matching is exact.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="opt_new_book_tags">
|
||||
<property name="toolTip">
|
||||
<string>A comma-separated list of tags that will be applied to books added to the library</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="metadata_box">
|
||||
<property name="title">
|
||||
<string>&Configure metadata from file name</string>
|
||||
@ -127,6 +127,13 @@ Author matching is exact.</string>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="opt_preserve_date_on_ctl">
|
||||
<property name="text">
|
||||
<string>When using the "&Copy to library" action to copy books between libraries, preserve the date</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|