Merge from source

This commit is contained in:
Sengian 2011-08-18 20:47:55 +02:00
commit b3ff85a8f7
367 changed files with 203972 additions and 224270 deletions

View File

@ -19,6 +19,291 @@
# 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
new features:
- title: "Content server: Return the correct last modified date when serving ebook files. Also allow getting of book metadata as /get/opf/<book_id>"
- title: "Driver for the COBY MP977"
- title: "Get Books: Remove epub bud store. Add Ozon.ru and e-knigni.net stores. Fix broken amazon UK and DE stores."
tickets: [816091]
- title: "Add a new tweak to Preferences->Tweaks that allows auto generation of series numbers when importing books with a series name, but no number"
tickets: [815573]
bug fixes:
- title: "Fix a regression in 0.8.11 that broke calibre on linux systems that use a file system encoding that cannot support cyrillic characters"
tickets: [815224]
- title: "Fix long titles not wrapping in cover browser"
tickets: [816595]
- title: "When adding books, handle the case of files without read permission more gracefully."
tickets: [814771]
- title: "When changing metadata in EPUB files do not use the opf: namespace prefix on newly created elements. Apparently, FBReaderJ doesn't understand XML namespaces."
tickets: [814722]
- title: "Prevent metadata download from returning published dates earlier than 101 A.D."
- title: "Fix a bug where dates before 101AD in the database could cause errors"
tickets: [814964]
- title: "Fix an error in the book details panel if the user sets the default author link to blank"
improved recipes:
- The Economist
- Instapaper
- Corren
new recipes:
- title: Counterpunch
author: O. Emmerson
- title: National Geographic (PL)
author: Marcin Urban
- title: Caros Amigos
author: Pablo Aldama
- title: Aksiyon Dergisi
author: thomass
- title: Dnevnik (MK) and +Info
author: Darko Spasovski
- title: Dagens Industri
author: Jonas Svensson
- version: 0.8.11
date: 2011-07-22
new features:
- title: "When doing a conversion from some format to the same format, save the original file"
description: "When calibre does a conversion from the same format to the same format, for
example, from EPUB to EPUB, the original file is saved as original_epub, so that in case the
conversion is poor, you can change the settings and run it again. The original is automatically used
every time you run a conversion with that format as input. If you want to disable this,
there is a tweak that prevents calibre from saving the originals in Preferences->Tweaks. You can
easily replace the converted version with the original in the Edit metadata dialog by right
clicking on the list of formats in the top right corner."
type: major
- title: "Conversion pipeline: Add an option to control the height of the blank lines inserted by calibre"
- title: "Drivers for bq DaVinci, Samsung Galaxy ACE GT-S5830 and Medion e-reader"
- title: "Get Books: Add stores Chitanka and Bookoteka. Remove epubbuy.de at store's request"
- title: "Content server: Add a link at the bottom of the mobile interface to switch to the full interface."
tickets: [812525]
- title: "Update the kindle icon shown when a Kindle is connected to use a picture of the Kindle 3"
tickets: [810852]
- title: "MOBI Output: When converting epub documents that have a start element in their guide, use it to mark the starting position at which the MOBI file will be opened."
tickets: [804755]
- title: "News download: Add a default Accept header to all requests"
bug fixes:
- title: "Fix regression that broke loading translations from .po files in the working directory"
- title: "Fix conversion dialog not allowing series numbers larger than 9999"
tickets: [813281]
- title: "Conversion pipeline: When adding/removing entries to the manifest, ignore unparseable URLs instead of erroring out on them"
- title: "SD Card in Azbooka not being detected"
tickets: [812750]
- title: "Conversion pipeline: Strip out large blocks of contiguous space (more than 10000 contiguous blanks) as these slow down the conversion process and are almost always indicative of an error in the input document."
- title: "ebook-convert: Abort if a keyboard interrupt is raised during parsing"
- title: "Regex builder: Show a nicer error message when the user has the file open in another program on windows."
tickets: [811641]
- title: "When converting in the GUI, set all identifiers present in the book's metadata in the output file, if the output format supports them."
improved recipes:
- NBObline
- JBPress
- Instapaper
- Die Zeit
- Wired (UK)
new recipes:
- title: Utrinski Vesnik
author: Darko Spasovski
- title: IDG.se
author: zapt0
- title: Los Andes
author: Darko Miletic
- title: De Luns a Venres
author: Susana Sotelo Docío
- title: "Nikkei News subscription version"
author: Ado Nishimura
- version: 0.8.10
date: 2011-07-15
new features:
- title: "Add a right click menu to the cover browser. It allows you to view a book, edit metadata etc. from within the cover browser. The menu can be customized in Preferences->Toolbars"
- title: "Allow selecting and stopping multiple jobs at once in the jobs window"
tickets: [810349]
- title: "When editing metadata directly in the book list, have a little pop up menu so that all existing values can be accessed by mouse only. For example, when you edit authors, you can use the mouse to select an existing author."
- title: "Get Books: Add ebook.nl and fix price parsing for the legimi store"
- title: "Drivers for Samsung Infuse and Motorola XPERT"
- title: "Tag Browser: Make hierarchical items work in group searched terms."
bug fixes:
- title: "Allow setting numbers larger than 99 in custom series columns"
- title: "Fix a bug that caused the same news download sent via a USB connection to the device on two different days resulting in a duplicate on the device"
- title: "Ensure English in the list of interface languages in Preferences is always listed in English, so that it does not become hard to find"
- title: "SNB Output: Fix bug in handling unicode file names"
- title: "Fix sorting problem in manage categories. Fix poor performance problem when dropping multiple books onto a user category."
- title: "Remove 'empty field' error dialogs in bulk search/replace, instead setting the fields to their default value."
- title: "Fix regression that broke communicating with Kobo devices using outdated firmware"
tickets: [807832]
- title: "LRF Input: Fix conversion of LRF files with non ascii titles on some windows systems"
tickets: [807641]
improved recipes:
- Time
- Freakonomics Blog
- io9
- "Computer Act!ve"
new recipes:
- title: Techcrunch and Pecat
author: Darko Miletic
- title: "Vio Mundo, IDG Now! and Tojolaco"
author: Diniz Bortolotto
- title: Geek and Poke, Automatiseringgids IT
author: DrMerry
- version: 0.8.9
date: 2011-07-08
@ -32,7 +317,7 @@
- title: "Conversion pipeline: Add option to control if duplicate entries are allowed when generating the Table of Contents from links."
tickets: [806095]
- title: "Metadata download: When merging results, if the query to the xisbn service hangs, wait no more than 10 seconds. Also try harder to preserve the month when downlaoding published date. Do not throw away isbnless results if there are some sources that return isbns and some that do not."
- title: "Metadata download: When merging results, if the query to the xisbn service hangs, wait no more than 10 seconds. Also try harder to preserve the month when downloading published date. Do not throw away isbnless results if there are some sources that return isbns and some that do not."
tickets: [798309]
- title: "Get Books: Remove OpenLibrary since it has the same files as archive.org. Allow direct downloading from Project Gutenberg."
@ -617,7 +902,7 @@
- version: 0.8.0
date: 2010-05-06
date: 2011-05-06
new features:
- title: "Go to http://calibre-ebook.com/new-in/eight to see what's new in 0.8.0"

912
imgsrc/keyboard-prefs.svg Normal file
View 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
View 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
View 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

758
imgsrc/random.svg Normal file
View File

@ -0,0 +1,758 @@
<?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"
width="128"
height="128"
id="svg10643"
sodipodi:version="0.32"
inkscape:version="0.46+devel"
sodipodi:docname="pointer.svgz"
inkscape:output_extension="org.inkscape.output.svgz.inkscape"
inkscape:export-filename="/home/pinheiro/pics/oxygen-icons/scalable/actions/small/32x32/pointer.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
version="1.0">
<defs
id="defs10645">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 12 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="24 : 12 : 1"
inkscape:persp3d-origin="12 : 8 : 1"
id="perspective108" />
<linearGradient
id="linearGradient3233">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop3235" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop3237" />
</linearGradient>
<linearGradient
id="linearGradient3866">
<stop
id="stop3868"
offset="0"
style="stop-color:#fff299;stop-opacity:1;" />
<stop
id="stop3870"
offset="1"
style="stop-color:#dcd8bd;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient11059">
<stop
style="stop-color:#727272;stop-opacity:1;"
offset="0"
id="stop11061" />
<stop
id="stop11067"
offset="0.5"
style="stop-color:#a6a6a6;stop-opacity:1;" />
<stop
style="stop-color:#cdcdcd;stop-opacity:1;"
offset="0.75"
id="stop11069" />
<stop
style="stop-color:#acacac;stop-opacity:1;"
offset="1"
id="stop11063" />
</linearGradient>
<linearGradient
id="linearGradient10925">
<stop
style="stop-color:#bf0303;stop-opacity:0;"
offset="0"
id="stop10927" />
<stop
id="stop10978"
offset="0.39309064"
style="stop-color:#bf0303;stop-opacity:0;" />
<stop
id="stop10935"
offset="0.46538317"
style="stop-color:#bf0303;stop-opacity:0.49803922;" />
<stop
style="stop-color:#bf0303;stop-opacity:1;"
offset="0.5"
id="stop10976" />
<stop
id="stop10933"
offset="0.5"
style="stop-color:#bf0303;stop-opacity:1;" />
<stop
style="stop-color:#bf0303;stop-opacity:0.49803922;"
offset="0.55339807"
id="stop10937" />
<stop
id="stop10980"
offset="0.60542935"
style="stop-color:#bf0303;stop-opacity:0;" />
<stop
style="stop-color:#bf0303;stop-opacity:0;"
offset="1"
id="stop10929" />
</linearGradient>
<linearGradient
id="linearGradient10901">
<stop
id="stop10903"
offset="0"
style="stop-color:#fff299;stop-opacity:0;" />
<stop
style="stop-color:#fff299;stop-opacity:1;"
offset="0.5"
id="stop10909" />
<stop
id="stop10905"
offset="1"
style="stop-color:#fff299;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient10854">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop10856" />
<stop
id="stop10862"
offset="0.5"
style="stop-color:#000000;stop-opacity:0;" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop10858" />
</linearGradient>
<linearGradient
id="linearGradient10711">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop10713" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop10715" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="radialGradient10875"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8967678,0.05935673,-0.05873468,0.8873664,-5.4012494,0.1392525)"
spreadMethod="reflect"
cx="18.708233"
cy="24.759357"
fx="18.708233"
fy="24.759357"
r="13.169441" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10925"
id="radialGradient10931"
cx="9.996233"
cy="23.364098"
fx="7.6629176"
fy="18.295921"
r="8.7188435"
gradientTransform="matrix(3.0577456,1.8802807,-0.9054531,1.4724637,3.4545267,-24.480143)"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="radialGradient10968"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8967678,0.05935673,-0.05873468,0.8873664,-5.4012494,0.1392525)"
spreadMethod="reflect"
cx="18.708233"
cy="24.759357"
fx="18.708233"
fy="24.759357"
r="13.169441" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10925"
id="radialGradient10971"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.7002217,0.5715519,-0.4374946,2.0668853,-4.8632848,-26.818351)"
cx="9.1802711"
cy="24.942194"
fx="6.0336409"
fy="17.669048"
r="8.7188435" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath10999">
<path
sodipodi:nodetypes="ccccc"
id="path11001"
d="M 3.6413483,1.9681703 3.779696,17.490509 14.887308,19.785771 21.079035,17.498126 3.6413483,1.9681703 z"
style="fill:#ff80ff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
</clipPath>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10925"
id="radialGradient11003"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.7002217,0.5715519,-0.4374946,2.0668853,-4.8632848,-26.818351)"
cx="8.2921495"
cy="23.935163"
fx="8.2488832"
fy="19.781427"
r="8.7188435" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10925"
id="radialGradient11030"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.7002217,0.5715519,-0.4374946,2.0668853,-4.8632848,-26.818351)"
cx="8.2921495"
cy="23.935163"
fx="8.2488832"
fy="19.781427"
r="8.7188435" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="radialGradient11032"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8967678,0.05935673,-0.05873468,0.8873664,-5.4012494,0.1392525)"
spreadMethod="reflect"
cx="18.708233"
cy="24.759357"
fx="18.708233"
fy="24.759357"
r="13.169441" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10925"
id="radialGradient11034"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.7002217,0.5715519,-0.4374946,2.0668853,-4.8632848,-26.818351)"
cx="8.2921495"
cy="23.935163"
fx="8.2488832"
fy="19.781427"
r="8.7188435" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="radialGradient3294"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7030075,0.6357809,-0.8060735,0.8913044,14.84311,-8.1934483)"
spreadMethod="reflect"
cx="16.993044"
cy="20.648924"
fx="16.993044"
fy="20.648924"
r="13.169441" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="linearGradient3297"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9823337,0,0,0.9823337,0.03300739,0.6182451)"
spreadMethod="pad"
x1="19.879225"
y1="12.061514"
x2="16.034332"
y2="15.552854" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="linearGradient3353"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9823337,0,0,0.9823337,0.03300739,0.6182451)"
spreadMethod="pad"
x1="19.879225"
y1="12.061514"
x2="16.034332"
y2="15.552854" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="radialGradient3355"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7030075,0.6357809,-0.8060735,0.8913044,14.84311,-8.1934483)"
spreadMethod="reflect"
cx="16.993044"
cy="20.648924"
fx="16.993044"
fy="20.648924"
r="13.169441" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="linearGradient3362"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9823337,0,0,0.9823337,0.03300739,0.6182451)"
spreadMethod="pad"
x1="19.879225"
y1="12.061514"
x2="16.034332"
y2="15.552854" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="radialGradient3364"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8341244,0.2489558,-0.2435026,0.8158514,0.7851109,-0.01382395)"
spreadMethod="reflect"
cx="17.54755"
cy="21.708042"
fx="17.54755"
fy="21.708042"
r="13.169441" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="radialGradient3367"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8151394,0.2358626,-0.2306962,0.7972824,0.7011221,-1.0582457)"
spreadMethod="reflect"
cx="17.54755"
cy="21.708042"
fx="17.54755"
fy="21.708042"
r="13.169441" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="linearGradient3370"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9575785,-0.00803118,0.00803118,0.9575785,-0.0268605,-0.4359562)"
spreadMethod="pad"
x1="19.879225"
y1="12.061514"
x2="16.034332"
y2="15.552854" />
<linearGradient
y2="19.626715"
x2="10.711697"
y1="18.63658"
x1="9.7192469"
gradientTransform="matrix(3.547255,-0.03993894,0.03993894,3.547255,-27.397339,-48.790495)"
gradientUnits="userSpaceOnUse"
id="linearGradient3488"
xlink:href="#linearGradient10711"
inkscape:collect="always" />
<radialGradient
r="1.15625"
fy="20.478674"
fx="11.413477"
cy="20.478674"
cx="11.413477"
spreadMethod="pad"
gradientTransform="matrix(1.7083003,-0.01851949,0.01798426,1.6589328,-8.4797796,-13.189665)"
gradientUnits="userSpaceOnUse"
id="radialGradient3486"
xlink:href="#linearGradient3330"
inkscape:collect="always" />
<linearGradient
y2="19.626715"
x2="10.711697"
y1="18.63658"
x1="9.7192469"
gradientTransform="matrix(3.5474799,0,0,3.5474799,-26.927898,-62.356391)"
gradientUnits="userSpaceOnUse"
id="linearGradient3475"
xlink:href="#linearGradient10711"
inkscape:collect="always" />
<radialGradient
r="1.15625"
fy="20.478674"
fx="11.413477"
cy="20.478674"
cx="11.413477"
spreadMethod="pad"
gradientTransform="matrix(1.7083003,-0.01851949,0.01798426,1.6589328,-8.4797796,-13.189665)"
gradientUnits="userSpaceOnUse"
id="radialGradient3473"
xlink:href="#linearGradient3330"
inkscape:collect="always" />
<radialGradient
spreadMethod="reflect"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7809876,0.01449707,-0.0055455,0.2987498,-0.2924169,2.0957246)"
r="11.765625"
fy="10.911069"
fx="1.1416299"
cy="10.911069"
cx="1.1416299"
id="radialGradient3317"
xlink:href="#linearGradient3206"
inkscape:collect="always" />
<linearGradient
y2="26.641653"
x2="16.836901"
y1="6.8943019"
x1="5.6869311"
gradientTransform="translate(0,-7.2094174)"
gradientUnits="userSpaceOnUse"
id="linearGradient3265"
xlink:href="#linearGradient3267"
inkscape:collect="always" />
<linearGradient
y2="17.133453"
x2="16.836901"
y1="-2.6138983"
x1="5.6869311"
gradientTransform="translate(0,2.298783)"
gradientUnits="userSpaceOnUse"
id="linearGradient3261"
xlink:href="#linearGradient3267"
inkscape:collect="always" />
<linearGradient
gradientTransform="translate(0,-4.8361309)"
y2="24.268368"
x2="16.836901"
y1="4.5210156"
x1="5.6869311"
gradientUnits="userSpaceOnUse"
id="linearGradient3257"
xlink:href="#linearGradient3267"
inkscape:collect="always" />
<linearGradient
gradientTransform="translate(0,-2.4628444)"
y2="21.895081"
x2="16.836901"
y1="2.1477292"
x1="5.6869311"
gradientUnits="userSpaceOnUse"
id="linearGradient3249"
xlink:href="#linearGradient3267"
inkscape:collect="always" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="19.432236"
x2="16.836901"
y1="-0.31511527"
x1="5.6869311"
id="linearGradient3239"
xlink:href="#linearGradient3267"
inkscape:collect="always" />
<linearGradient
y2="19.626715"
x2="10.711697"
y1="18.384007"
x1="9.8687286"
gradientTransform="matrix(3.6334443,0,0,3.6334443,-27.580699,-51.677773)"
gradientUnits="userSpaceOnUse"
id="linearGradient3220"
xlink:href="#linearGradient10711"
inkscape:collect="always" />
<radialGradient
r="1.15625"
fy="20.478674"
fx="11.413477"
cy="20.478674"
cx="11.413477"
spreadMethod="pad"
gradientTransform="matrix(1.7083003,-0.01851949,0.01798426,1.6589328,-8.4797796,-13.189665)"
gradientUnits="userSpaceOnUse"
id="radialGradient3218"
xlink:href="#linearGradient10711"
inkscape:collect="always" />
<linearGradient
id="linearGradient2657">
<stop
id="stop2659"
offset="0"
style="stop-color:#ff80ff;stop-opacity:1;" />
<stop
id="stop2661"
offset="1"
style="stop-color:#ff80ff;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient3206">
<stop
style="stop-color:#b1d28f;stop-opacity:1;"
offset="0"
id="stop3208" />
<stop
style="stop-color:#b1d28f;stop-opacity:1;"
offset="1"
id="stop3210" />
</linearGradient>
<linearGradient
id="linearGradient3241">
<stop
id="stop3243"
offset="0"
style="stop-color:#000000;stop-opacity:1;" />
<stop
id="stop3245"
offset="1"
style="stop-color:#debc85;stop-opacity:0" />
</linearGradient>
<linearGradient
id="linearGradient3267">
<stop
style="stop-color:#debc85;stop-opacity:1;"
offset="0"
id="stop3269" />
<stop
style="stop-color:#debc85;stop-opacity:0;"
offset="1"
id="stop3271" />
</linearGradient>
<linearGradient
id="linearGradient3273">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3275" />
<stop
style="stop-color:#debc85;stop-opacity:0"
offset="1"
id="stop3277" />
</linearGradient>
<linearGradient
id="linearGradient3279">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3281" />
<stop
style="stop-color:#debc85;stop-opacity:0"
offset="1"
id="stop3283" />
</linearGradient>
<linearGradient
id="linearGradient3285">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3287" />
<stop
style="stop-color:#debc85;stop-opacity:0"
offset="1"
id="stop3289" />
</linearGradient>
<linearGradient
id="linearGradient3330">
<stop
style="stop-color:#ff80ff;stop-opacity:0;"
offset="0"
id="stop3332" />
<stop
style="stop-color:#666666;stop-opacity:1;"
offset="1"
id="stop3334" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="radialGradient4021"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9318803,-0.2210697,0.2308678,0.9731826,-3.9252239,2.7241703)"
spreadMethod="pad"
cx="11.074039"
cy="20.428291"
fx="11.074039"
fy="20.428291"
r="1.15625" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="linearGradient4023"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8514941,0.5243642,-0.5243642,0.8514941,24.154135,2.8247022)"
x1="21.461079"
y1="23.349636"
x2="22.96941"
y2="28.038134" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="linearGradient4030"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8514941,0.5243642,-0.5243642,0.8514941,18.007546,-15.657615)"
x1="21.461079"
y1="23.349636"
x2="22.96941"
y2="28.038134" />
<filter
inkscape:collect="always"
x="-0.20028582"
width="1.4005716"
y="-0.11837127"
height="1.2367425"
id="filter3484">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.97202214"
id="feGaussianBlur3486" />
</filter>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="radialGradient3490"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1086176,-0.4093269,0.6608062,1.7897223,-9.2289678,-4.0397151)"
spreadMethod="reflect"
cx="8.8133469"
cy="14.235861"
fx="8.8133469"
fy="14.235861"
r="5.3238101" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath3496">
<rect
style="opacity:0.62633481;fill:none;stroke:#000000;stroke-width:0.19602102;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect3498"
width="13.277639"
height="22.63365"
x="5.309958"
y="1.2316679"
ry="1.171887" />
</clipPath>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="radialGradient3508"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1106976,-0.4036489,0.6516398,1.7930801,-9.2127514,-4.7972628)"
spreadMethod="reflect"
cx="8.8133469"
cy="14.235861"
fx="8.8133469"
fy="14.235861"
r="5.3238101" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3233"
id="linearGradient3240"
x1="9.4485903"
y1="2.761672"
x2="7.6776314"
y2="19.013866"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(4.1741381,0,0,4.1613891,14.977639,14.527008)" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient10711"
id="radialGradient3253"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(4.7157796,-1.4428762,2.6160831,8.4980426,-22.699134,-22.277012)"
spreadMethod="reflect"
cx="8.2230186"
cy="14.316785"
fx="8.2230186"
fy="14.316785"
r="5.3238101" />
<filter
inkscape:collect="always"
id="filter3757"
x="-0.14567212"
width="1.2913442"
y="-0.098205952"
height="1.1964119">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.79012916"
id="feGaussianBlur3759" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2"
inkscape:cx="8.5584572"
inkscape:cy="52.628863"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1280"
inkscape:window-height="742"
inkscape:window-x="296"
inkscape:window-y="56"
showguides="true"
inkscape:guide-bbox="true"
width="24px"
height="24px"
inkscape:object-paths="false"
inkscape:object-nodes="true"
inkscape:snap-nodes="false"
inkscape:snap-global="false">
<inkscape:grid
type="xygrid"
id="grid3664"
empspacing="2"
visible="true"
enabled="true"
spacingx="2.6666px"
spacingy="2.6666px" />
<sodipodi:guide
orientation="1,0"
position="10.507812,7.328125"
id="guide3666" />
<sodipodi:guide
orientation="0,1"
position="10.292968,7.5546875"
id="guide3668" />
</sodipodi:namedview>
<metadata
id="metadata10648">
<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"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.18099551;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3757);enable-background:accumulate;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
d="m 5,19 c 5.24e-5,0.523584 0.4764155,0.999948 1,1 l 3.59375,0 2.5,2.5625 c 0.272702,0.267764 0.706204,0.357015 1.0625,0.21875 l 1.25,-0.46875 c 0.353635,-0.127466 0.619754,-0.46962 0.65625,-0.84375 l 0.34375,-3.3125 2.40625,-3 c 0.296435,-0.374818 0.26821,-0.967546 -0.0625,-1.3125 L 5.2034921,1.0488435 5,19 z"
id="path3670"
sodipodi:nodetypes="cccccccccccc"
transform="matrix(3.8351065,0,0,3.8305733,20.000787,24.35592)" />
<path
style="fill:#201020;fill-rule:evenodd;stroke:#595959;stroke-width:5.33333349;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 40.022468,18.688398 0,66.582224 16.696553,0 L 68.436432,97.122145 73.70512,95.153883 75.247683,80.05609 86.03678,66.636329 40.022468,18.688398 z"
id="path3502"
sodipodi:nodetypes="cccccccc" />
<path
sodipodi:nodetypes="cccccccc"
id="path3504"
d="m 40.022468,18.688397 0,66.58222 16.696554,0 11.717412,11.851511 5.268688,-1.968253 1.54256,-15.09779 L 85.892267,66.67168 40.022468,18.688397 z"
style="fill:#c4c4c4;fill-opacity:1;fill-rule:evenodd;stroke:none" />
<path
style="fill:url(#radialGradient3253);fill-opacity:1;fill-rule:evenodd;stroke:none"
d="m 40.022468,18.688397 0,66.58222 16.696554,0 11.717412,11.851511 5.268688,-1.968253 1.54256,-15.09779 10.56036,-13.22296 -45.785574,-48.144728 z"
id="path3506"
sodipodi:nodetypes="cccccccc" />
<path
style="fill:none;stroke:url(#linearGradient3240);stroke-width:2.667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 41.38037,83.915714 58.396539,84.11082 69.204513,94.929961 72.193882,93.656427 73.839587,79.399575 84.08764,66.742537 41.448646,22.246495 41.38037,83.915714 z"
id="path2253"
sodipodi:nodetypes="cccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
from calibre.web.feeds.news import BasicNewsRecipe
class Aksiyon (BasicNewsRecipe):
title = u'Aksiyon Dergisi'
__author__ = u'thomass'
description = 'Haftalık haber dergisi '
oldest_article =13
max_articles_per_feed =100
no_stylesheets = True
#delay = 1
#use_embedded_content = False
encoding = 'utf-8'
publisher = 'Aksiyon'
category = 'news, haberler,TR,gazete'
language = 'tr'
publication_type = 'magazine'
#extra_css = ' body{ font-family: Verdana,Helvetica,Arial,sans-serif } .introduction{font-weight: bold} .story-feature{display: block; padding: 0; border: 1px solid; width: 40%; font-size: small} .story-feature h2{text-align: center; text-transform: uppercase} '
#keep_only_tags = [dict(name='font', attrs={'class':['newsDetail','agenda2NewsSpot']}),dict(name='span', attrs={'class':['agenda2Title']}),dict(name='div', attrs={'id':['gallery']})]
remove_tags = [dict(name='img', attrs={'src':[ 'http://medya.aksiyon.com.tr/aksiyon/images/logo/logo.bmp','/aksiyon/images/template/green/baslik0.gif','mobile/home.jpg']}) ]
cover_img_url = 'http://www.aksiyon.com.tr/aksiyon/images/aksiyon/top-page/aksiyon_top_r2_c1.jpg'
masthead_url = 'http://aksiyon.com.tr/aksiyon/images/aksiyon/top-page/aksiyon_top_r2_c1.jpg'
remove_empty_feeds= True
remove_attributes = ['width','height']
feeds = [
( u'ANASAYFA', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=0'),
( u'KARAKUTU', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=11'),
( u'EKONOMİ', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=35'),
( u'EKOANALİZ', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=284'),
( u'YAZARLAR', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=17'),
( u'KİTAPLIK', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=13'),
( u'SİNEMA', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=14'),
( u'ARKA PENCERE', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=27'),
( u'DÜNYA', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=32'),
( u'DOSYALAR', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=34'),
( u'KÜLTÜR & SANAT', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=12'),
( u'KAPAK', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=26'),
( u'SPOR', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=38'),
( u'BİLİŞİM - TEKNOLOJİ', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=39'),
( u'3. BOYUT', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=172'),
( u'HAYAT BİLGİSİ', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=283'),
( u'İŞ DÜNYASI', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=283'),
]
def print_version(self, url):
return url.replace('http://www.aksiyon.com.tr/aksiyon/newsDetail_getNewsById.action?load=detay&', 'http://www.aksiyon.com.tr/aksiyon/mobile_detailn.action?')

View File

@ -0,0 +1,39 @@
import re
from calibre.web.feeds.news import BasicNewsRecipe
class autogids(BasicNewsRecipe):
title = u'Automatiseringgids IT'
oldest_article = 7
__author__ = 'DrMerry'
description = 'IT-nieuws van Automatiseringgids'
language = 'nl'
publisher = 'AutomatiseringGids'
category = 'Nieuws, IT, Nederlandstalig'
simultaneous_downloads = 5
#delay = 1
timefmt = ' [%A, %d %B, %Y]'
#timefmt = ''
no_stylesheets = True
remove_javascript = True
remove_empty_feeds = True
publication_type = 'newspaper'
encoding = 'utf-8'
cover_url = 'http://www.automatiseringgids.nl/siteimg/header_logo.gif'
keep_only_tags = [dict(id=['content'])]
extra_css = '.artikelheader {font-size:0.8em; color: #666;} .artikelintro {font-weight:bold} div.imgArticle {float: right; margin: 0 0em 1em 1em; display: block; position: relative; } \
h2 { margin: 0 0 0.5em; min-height: 30px; font-size: 1.5em; letter-spacing: -0.2px; margin: 0 0 0.5em; color: black; font-weight: bold; line-height: 1.2em; padding: 4px 3px 0; }'
remove_tags = [dict(name='div', attrs={'id':['loginbox','reactiecollapsible','reactiebox']}),
dict(name='div', attrs={'class':['column_a','column_c','bannerfullsize','reactieheader','reactiecollapsible','formulier','artikel_headeroptions']}),
dict(name='ul', attrs={'class':['highlightlist']}),
dict(name='input', attrs={'type':['button']}),
dict(name='div', attrs={'style':['display:block; width:428px; height:30px; float:left;']}),
]
preprocess_regexps = [
(re.compile(r'(<h3>Reacties</h3>|<h2>Zie ook:</h2>|<div style=".*</div>|<a[^>]*>|</a>)', re.DOTALL|re.IGNORECASE),
lambda match: ''),
]
feeds = [(u'Actueel', u'http://www.automatiseringgids.nl/rss.aspx')]

View File

@ -0,0 +1,17 @@
__copyright__ = '2011, Pablo Aldama <pabloaldama at gmail.com>'
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1311839910(BasicNewsRecipe):
title = u'Caros Amigos'
oldest_article = 20
max_articles_per_feed = 100
language = 'pt_BR'
__author__ = 'Pablo Aldama'
feeds = [(u'Caros Amigos', u'http://carosamigos.terra.com.br/index/index.php?format=feed&type=rss')]
keep_only_tags = [dict(name='div', attrs={'class':['blog']})
,dict(name='div', attrs={'class':['blogcontent']})
]
remove_tags = [dict(name='div', attrs={'class':'addtoany'})]

View File

@ -0,0 +1,23 @@
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1312361378(BasicNewsRecipe):
title = u'Carta capital'
__author__ = 'Pablo Aldama'
language = 'pt_BR'
oldest_article = 9
max_articles_per_feed = 100
feeds = [(u'Politica', u'http://www.cartacapital.com.br/category/politica/feed')
,(u'Economia', u'http://www.cartacapital.com.br/category/economia/feed')
,(u'Cultura', u'http://www.cartacapital.com.br/category/cultura/feed')
,(u'Internacional', u'http://www.cartacapital.com.br/category/internacional/feed')
,(u'Saude', u'http://www.cartacapital.com.br/category/saude/feed')
,(u'Sociedade', u'http://www.cartacapital.com.br/category/sociedade/feed')
,(u'Tecnologia', u'http://www.cartacapital.com.br/category/tecnologia/feed')
,(u'Carta na escola', u'http://www.cartacapital.com.br/category/carta-na-escola/feed')
,(u'Carta fundamental', u'http://www.cartacapital.com.br/category/carta-fundamental/feed')
,(u'Carta verde', u'http://www.cartacapital.com.br/category/carta-verde/feed')
]
def print_version(self, url):
return url + '/print'

View File

@ -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')]

View File

@ -1,9 +1,9 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__author__ = 'DrMerry Based on v1.01 by Lorenzo Vigentini'
__copyright__ = 'For version 1.02: DrMerry'
__version__ = 'v1.02'
__date__ = '08, July 2011'
__copyright__ = 'For version 1.02, 1.03: DrMerry'
__version__ = 'v1.03'
__date__ = '11, July 2011'
__description__ = 'Computeractive publishes new downloads, reviews, news stories, step-by-step guides and answers to PC problems every day. Original version (c): 2009, Lorenzo Vigentini <l.vigentini at gmail.com>'
'''
@ -11,9 +11,10 @@ http://www.computeractive.co.uk/
'''
from calibre.web.feeds.news import BasicNewsRecipe
import re
class computeractive(BasicNewsRecipe):
__author__ = 'Lorenzo Vigentini'
__author__ = 'DrMerry'
description = 'Computeractive publishes new downloads, reviews, news stories, step-by-step guides and answers to PC problems every day.'
cover_url = 'http://images.pcworld.com/images/common/header/header-logo.gif'
@ -31,6 +32,8 @@ class computeractive(BasicNewsRecipe):
remove_javascript = True
no_stylesheets = True
remove_empty_feeds = True
remove_tags_after = dict(name='div', attrs={'class':'article_tags_block'})
keep_only_tags = [
dict(name='div', attrs={'id':'container_left'})
@ -42,13 +45,14 @@ class computeractive(BasicNewsRecipe):
dict(name='a', attrs={'class':'largerImage'})
]
preprocess_regexps = [
(re.compile(r'(<a [^>]*>|</a>)', re.DOTALL|re.IGNORECASE),
lambda match: ''),
]
feeds = [
(u'General content', u'http://feeds.computeractive.co.uk/rss/latest/computeractive/all'),
(u'News', u'http://feeds.computeractive.co.uk/rss/latest/computeractive/news'),
(u'Downloads', u'http://feeds.computeractive.co.uk/rss/latest/computeractive/downloads'),
(u'Hardware', u'http://feeds.computeractive.co.uk/rss/latest/computeractive/hardware'),
(u'Software', u'http://feeds.computeractive.co.uk/rss/latest/computeractive/software'),
(u'Competitions', u'http://www.v3.co.uk/feeds/rss20/personal-technology/competitions')
]

View File

@ -1,39 +1,34 @@
# -*- coding: utf-8 -*-
__license__ = 'GPLv3'
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1255797795(BasicNewsRecipe):
title = u'Corren'
language = 'sv'
__author__ = 'Jonas Svensson'
simultaneous_downloads = 1
no_stylesheets = True
oldest_article = 7
class AdvancedUserRecipe1311446032(BasicNewsRecipe):
title = 'Corren'
__author__ = 'Jonas Svensson'
description = 'News from Sweden'
publisher = 'Corren'
category = 'news, politics, Sweden'
oldest_article = 2
delay = 1
max_articles_per_feed = 100
remove_attributes = ['onload']
timefmt = ''
no_stylesheets = True
use_embedded_content = False
encoding = 'iso-8859-1'
language = 'sv'
feeds = [
(u'Toppnyheter (alla kategorier)', u'http://www.corren.se/inc/RssHandler.ashx?id=4122151&ripurl=http://www.corren.se/nyheter/'),
(u'Bostad', u'http://www.corren.se/inc/RssHandler.ashx?id=4122174&ripurl=http://www.corren.se/bostad/'),
(u'Ekonomi & Jobb', u'http://www.corren.se/inc/RssHandler.ashx?id=4122176&ripurl=http://www.corren.se/ekonomi/'),
(u'Kultur & Nöje', u'http://www.corren.se/inc/RssHandler.ashx?id=4122192&ripurl=http://www.corren.se/kultur/'),
(u'Mat & dryck', u'http://www.corren.se/inc/RssHandler.ashx?id=4122201&ripurl=http://www.corren.se/mat-dryck/'),
(u'Motor', u'http://www.corren.se/inc/RssHandler.ashx?id=4122203&ripurl=http://www.corren.se/motor/'),
(u'Sport', u'http://www.corren.se/inc/RssHandler.ashx?id=4122206&ripurl=http://www.corren.se/sport/'),
(u'Åsikter', u'http://www.corren.se/inc/RssHandler.ashx?id=4122223&ripurl=http://www.corren.se/asikter/'),
(u'Mjölby', u'http://www.corren.se/inc/RssHandler.ashx?id=4122235&ripurl=http://www.corren.se/ostergotland/mjolby/'),
(u'Motala', u'http://www.corren.se/inc/RssHandler.ashx?id=4122236&ripurl=http://www.corren.se/ostergotland/motala/')
]
def print_version(self, url):
url = url.replace("ekonomi/artikel.aspx", "Print.aspx")
url = url.replace("bostad/artikel.aspx", "Print.aspx")
url = url.replace("kultur/artikel.aspx", "Print.aspx")
url = url.replace("motor/artikel.aspx", "Print.aspx")
url = url.replace("mat-dryck/artikel.aspx", "Print.aspx")
url = url.replace("sport/artikel.aspx", "Print.aspx")
url = url.replace("asikter/artikel.aspx", "Print.aspx")
url = url.replace("mat-dryck/artikel.aspx", "Print.aspx")
url = url.replace("ostergotland/mjolby/artikel.aspx", "Print.aspx")
url = url.replace("ostergotland/motala/artikel.aspx", "Print.aspx")
return url.replace("nyheter/artikel.aspx", "Print.aspx")
feeds = [
(u'Toppnyheter', u'http://www.corren.se/inc/RssHandler.ashx?id=4122151&ripurl=http://www.corren.se/nyheter/')
,(u'Ekonomi', u'http://www.corren.se/inc/RssHandler.ashx?id=4122176&ripurl=http://www.corren.se/ekonomi/')
,(u'Link\xf6ping', u'http://www.corren.se/inc/RssHandler.ashx?id=4122234')
,(u'Åsikter', u'http://www.corren.se/inc/RssHandler.ashx?id=4122223,4122224,4122226,4122227,4122228,4122229,4122230')
]
keep_only_tags = [dict(name='div', attrs={'id':'article'}),dict(name='div', attrs={'class':'body'})]
remove_tags = [
dict(name='ul',attrs={'class':'functions'})
,dict(name='a',attrs={'href':'javascript*'})
,dict(name='div',attrs={'class':'box'})
,dict(name='div',attrs={'class':'functionsbottom'})
]

View File

@ -0,0 +1,40 @@
import re
from lxml.html import parse
from calibre.web.feeds.news import BasicNewsRecipe
class Counterpunch(BasicNewsRecipe):
'''
Parses counterpunch.com for articles
'''
title = 'Counterpunch'
description = 'Daily political opinion from www.Counterpunch.com'
language = 'en'
__author__ = 'O. Emmerson'
keep_only_tags = [dict(name='td', attrs={'width': '522'})]
max_articles_per_feed = 10
def parse_index(self):
feeds = []
title, url = 'Counterpunch', 'http://www.counterpunch.com'
articles = self.parse_page(url)
if articles:
feeds.append((title, articles))
return feeds
def parse_page(self, url):
parsed_page = parse(url).getroot()
articles = []
unwanted_text = re.compile('Website\ of\ the|I\ urge\ you|Subscribe\ now|DONATE|\@asis\.com|donation\ button|click\ over\ to\ our')
parsed_articles = [a for a in parsed_page.cssselect("html>body>table tr>td>p[class='style2']") if not unwanted_text.search(a.text_content())]
for art in parsed_articles:
try:
author = art.text
title = art.cssselect("a")[0].text + ' by {0}'.format(author)
art_url = 'http://www.counterpunch.com/' + art.cssselect("a")[0].attrib['href']
articles.append({'title': title, 'url': art_url})
except Exception as e:
e
#print('Handler Error: ', e, 'title :', a.text_content())
pass
return articles

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
__license__ = 'GPLv3'
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1311450855(BasicNewsRecipe):
title = u'Dagens Industri'
__author__ = 'Jonas Svensson'
description = 'Economy news from Sweden'
publisher = 'DI'
category = 'news, politics, Sweden'
oldest_article = 2
delay = 1
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
encoding = 'utf-8'
language = 'sv'
feeds = [(u'DI', u'http://di.se/rss')]
keep_only_tags = [dict(name='h1', attrs={'id':'ctl00_ExtraWideContentRegion_WideContentRegion_MainRegion_MainContentRegion_MainBodyRegion_headlineNormal'}),dict(name='div', attrs={'id':'articleBody'})]
remove_tags = [
dict(name='div',attrs={'class':'article-actions clear'})
,dict(name='div',attrs={'class':'article-action-popup'})
,dict(name='div',attrs={'class':'header'})
,dict(name='div',attrs={'class':'content clear'})
,dict(name='div',attrs={'id':'articleAdvertisementDiv'})
,dict(name='ul',attrs={'class':'action-list'})
]

98
recipes/dnevnik_mk.recipe Normal file
View File

@ -0,0 +1,98 @@
#!/usr/bin/env python
__author__ = 'Darko Spasovski'
__license__ = 'GPL v3'
__copyright__ = '2011, Darko Spasovski <darko.spasovski at gmail.com>'
'''
dnevnik.com.mk
'''
import re
import datetime
from calibre.web.feeds.news import BasicNewsRecipe
from calibre import browser
from calibre.ebooks.BeautifulSoup import BeautifulSoup
class Dnevnik(BasicNewsRecipe):
INDEX = 'http://www.dnevnik.com.mk'
__author__ = 'Darko Spasovski'
title = 'Dnevnik - mk'
description = 'Daily Macedonian newspaper'
masthead_url = 'http://www.dnevnik.com.mk/images/re-logo.gif'
language = 'mk'
publication_type = 'newspaper'
category = 'news, Macedonia'
max_articles_per_feed = 100
remove_javascript = True
no_stylesheets = True
use_embedded_content = False
preprocess_regexps = [(re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in
[
## Remove anything before the start of the article.
(r'<body.*?<\?xml version=\"1.0\"\?><!--Article start-->', lambda match: '<body>'),
## Remove anything after the end of the article.
(r'<!--Article end.*?</body>', lambda match : '</body>'),
]
]
extra_css = """
body{font-family: Arial,Helvetica,sans-serif}
.WB_DNEVNIK_Naslov{FONT-WEIGHT: bold; FONT-SIZE: 18px; FONT-FAMILY: Arial, Verdana, Tahoma; TEXT-DECORATION: none}
"""
conversion_options = {
'comment' : description,
'tags' : category,
'language' : language,
'linearize_tables' : True
}
def parse_index(self):
datum = datetime.datetime.today().strftime('%d.%m.%Y')
soup = self.index_to_soup(self.INDEX + '/default.asp?section=arhiva&arhDatum=' + datum)
feeds = []
for section in soup.findAll('td', attrs={'class':'WB_DNEVNIK_ArhivaFormTitle'}):
sectionTitle = section.contents[0].string
if sectionTitle.lower().startswith('online'):
# Skip online articles
continue
containerTable = section.findPrevious(name='table').findNextSibling(name='table')
if containerTable==None:
print 'No container table found - page layout may have been changed.'
continue
articles = []
for article in containerTable.findAll('a', attrs={'class': 'WB_DNEVNIK_ArhivaFormText'}):
title = self.tag_to_string(article, use_alt=True).strip()
articles.append({'title': title, 'url':'http://www.dnevnik.com.mk/' + article['href'], 'description':'', 'date':''})
if articles:
feeds.append((sectionTitle, articles))
return sorted(feeds, key=lambda section: self.get_weight(section))
def get_weight(self, section):
"""
Returns 'weight' of a section.
Used for sorting the sections based on their 'natural' order in the printed edition.
"""
natural_order = { u'во фокусот': 1, u'актуелно': 2, u'економија': 3,
u'отворена': 4, u'свет': 5, u'интервју': 6, u'џубокс': 7,
u'репортажа': 8, u'наш туризам': 9, u'живот': 10,
u'автомобилизам': 11, u'спорт': 12, u'омнибус': 13 }
if section[0].string.lower() in natural_order:
return natural_order[section[0].string.lower()]
else:
return 999 # section names not on the list go to the bottom
def get_cover_url(self):
datum = datetime.datetime.today().strftime('%d.%m.%Y')
soup = self.index_to_soup(self.INDEX + '/default.asp?section=arhiva&arhDatum=' + datum)
anchor = soup.find('a', attrs={'class': 'WB_DNEVNIK_MoreLink'})
if anchor != None:
raw = browser().open_novisit(self.INDEX + '/' + anchor['href']).read()
cover_soup = BeautifulSoup(raw)
url = cover_soup.find('div', attrs={'class':'WB_DNEVNIK_Datum2'}).findNext('img')['src']
return self.INDEX + '/' + url
return ''

View File

@ -6,10 +6,10 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
economist.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup
from calibre.ebooks.BeautifulSoup import Tag, NavigableString
from collections import OrderedDict
import string, time, re
import re
class Economist(BasicNewsRecipe):
@ -22,97 +22,99 @@ class Economist(BasicNewsRecipe):
' 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://www.economist.com/images/covers/currentcoverus_large.jpg'
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']}),
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
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 = BeautifulSoup(self.browser.open(self.INDEX).read(),
convertEntities=BeautifulSoup.HTML_ENTITIES)
index_started = False
feeds = {}
ans = []
key = None
for tag in soup.findAll(['h1', 'h2']):
text = ''.join(tag.findAll(text=True))
if tag.name in ('h1', 'h2') and 'Classified ads' in text:
break
if tag.name == 'h1':
if 'The world this week' in text or 'The world this year' in text:
index_started = True
if not index_started:
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
text = string.capwords(text)
if text not in feeds.keys():
feeds[text] = []
if text not in ans:
ans.append(text)
key = text
continue
if key is None:
continue
a = tag.find('a', href=True)
if a is not None:
url=a['href']
id_ = re.search(r'story_id=(\d+)', url).group(1)
url = 'http://www.economist.com/node/%s/print'%id_
if url.startswith('Printer'):
url = '/'+url
if url.startswith('/'):
url = 'http://www.economist.com' + url
try:
subtitle = tag.previousSibling.contents[0].contents[0]
text = subtitle + ': ' + text
except:
pass
article = dict(title=text,
url = url,
description='', content='', date='')
feeds[key].append(article)
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':''})
ans = [(key, feeds[key]) for key in ans if feeds.has_key(key)]
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. Has your subscription expired?')
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):

View File

@ -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
@ -16,11 +153,12 @@ class Economist(BasicNewsRecipe):
' Much slower than the print edition based version.')
extra_css = '.headline {font-size: x-large;} \n h2 { font-size: small; } \n h1 { font-size: medium; }'
oldest_article = 7.0
cover_url = 'http://www.economist.com/images/covers/currentcoverus_large.jpg'
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']}),
'share_inline_header', 'related-items']}),
{'class': lambda x: x and 'share-links-header' in x},
]
keep_only_tags = [dict(id='ec-article-body')]
@ -144,3 +282,5 @@ class Economist(BasicNewsRecipe):
div.insert(2, img)
table.replaceWith(div)
return soup
'''

View File

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1311790237(BasicNewsRecipe):
title = u'Periódico El Colombiano'
language = 'es_CO'
__author__ = 'BIGO-CAVA'
cover_url = 'http://www.elcolombiano.com/images/logoElColombiano348x46.gif'
remove_tags_before = dict(id='contenidoArt')
remove_tags_after = dict(id='enviaTips')
remove_tags_after = dict(id='zonaPata')
oldest_article = 1
max_articles_per_feed = 100
remove_javascript = True
no_stylesheets = True
use_embedded_content = False
remove_empty_feeds = True
masthead_url = 'http://www.elcolombiano.com/images/logoElColombiano348x46.gif'
publication_type = 'newspaper'
extra_css = """
p{text-align: justify; font-size: 100%}
body{ text-align: left; font-size:100% }
h1{font-family: sans-serif; font-size:150%; font-weight:bold; text-align: justify; }
h3{font-family: sans-serif; font-size:100%; font-style: italic; text-align: justify; }
"""
feeds = [(u'Portada', u'http://www.elcolombiano.com/rss/portada.xml'),
(u'Antioquia', u'http://www.elcolombiano.com/rss/Antioquia.xml'),
(u'Colombia', u'http://www.elcolombiano.com/rss/Colombia.xml'),
(u'Economia', u'http://www.elcolombiano.com/rss/Economia.xml'),
(u'Internacional', u'http://www.elcolombiano.com/rss/Internacional.xml'),
(u'Politica', u'http://www.elcolombiano.com/rss/Politica.xml'),
(u'Cultura', u'http://www.elcolombiano.com/rss/Cultura.xml'),
(u'Entretenimiento', u'http://www.elcolombiano.com/rss/Farandula.xml'),
(u'Tecnologia', u'http://www.elcolombiano.com/rss/Tecnologia.xml'),
(u'Television', u'http://www.elcolombiano.com/rss/Television.xml'),
(u'Vida y Sociedad', u'http://www.elcolombiano.com/rss/Vida.xml'),
(u'Turismo', u'http://www.elcolombiano.com/rss/Turismo.xm'),
(u'Salud', u'http://www.elcolombiano.com/rss/Salud.xml'),
(u'Ciencia', u'http://www.elcolombiano.com/rss/Ciencia.xml')]
remove_tags = [dict(name='div', attrs={'class':'objetosRelacionados'}),
dict(name='div', attrs={'class':'notasRelacionadas contenedor'}),
dict(name='div', attrs={'class':'comentarios'}),
dict(name='div', attrs={'class':'mapaDelSitio'}),
dict(name='div', attrs={'class':'creditos'}),
dict(name='div', attrs={'class':'votos'}),
dict(name='div', attrs={'class':'divopt2'}),
dict(name='div', attrs={'class':'comentarios'}),
dict(name='div', attrs={'class':'pestanasLateral'}),
dict(name='div', attrs={'class':'resumenSeccion'}),
dict(name='div', attrs={'class':'zonaComercial'}),
dict(name='div', attrs={'id':'zonaPata'})]

View 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/')
]

53
recipes/el_tiempo.recipe Normal file
View File

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
from calibre.web.feeds.news import BasicNewsRecipe
class ColombiaElTiempo02(BasicNewsRecipe):
title = u'Periódico el Tiempo'
language = 'es_CO'
__author__ = 'BIGO-CAVA'
cover_url = 'http://www.eltiempo.com/media/css/images/logo_footer.png'
remove_tags_before = dict(id='fb-root')
remove_tags_after = [dict(name='div', attrs={'class':'modulo reporte'})]
keep_only_tags = [dict(name='div', id='contenidoArt')]
remove_tags = [dict(name='div', attrs={'class':'social-media'}),
dict(name='div', attrs={'class':'caja-facebook'}),
dict(name='div', attrs={'class':'caja-twitter'}),
dict(name='div', attrs={'class':'caja-buzz'}),
dict(name='div', attrs={'class':'ico-mail2'}),
dict(name='div', attrs={'id':'caja-instapaper'}),
dict(name='div', attrs={'class':'modulo herramientas'})]
oldest_article = 2
max_articles_per_feed = 100
remove_javascript = True
no_stylesheets = True
use_embedded_content = False
remove_empty_feeds = True
masthead_url = 'http://www.eltiempo.com/media/css/images/logo_footer.png'
publication_type = 'newspaper'
extra_css = """
p{text-align: justify; font-size: 100%}
body{ text-align: left; font-size:100% }
h1{font-family: sans-serif; font-size:150%; font-weight:bold; text-align: justify; }
h3{font-family: sans-serif; font-size:100%; font-style: italic; text-align: justify; }
"""
feeds = [(u'Colombia', u'http://www.eltiempo.com/colombia/rss.xml'),
(u'Medellin', u'http://www.eltiempo.com/colombia/medellin/rss.xml'),
(u'Economia', u'http://www.eltiempo.com/economia/rss.xml'),
(u'Deportes', u'http://www.eltiempo.com/deportes/rss.xml'),
(u'Mundo', u'http://www.eltiempo.com/mundo/rss.xml'),
(u'Gente', u'http://www.eltiempo.com/gente/rss.xml'),
(u'Vida de Hoy', u'http://www.eltiempo.com/vida-de-hoy/rss.xml'),
(u'EEUU', u'http://www.eltiempo.com/mundo/estados-unidos/rss.xml'),
(u'LatinoAmerica', u'http://www.eltiempo.com/mundo/latinoamerica/rss.xml'),
(u'Europa', u'http://www.eltiempo.com/mundo/europa/rss.xml'),
(u'Medio Oriente', u'http://www.eltiempo.com/mundo/medio-oriente/rss.xml'),
(u'Vive in Medellin', u'http://medellin.vive.in/medellin/rss.xml'),
(u'Don Juan', u'http://www.revistadonjuan.com/feedrss/'),
(u'Alo', u'http://www.eltiempo.com/alo/rss.xml')]

View File

@ -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 = """

View File

@ -9,7 +9,7 @@ engadget.com
from calibre.web.feeds.news import BasicNewsRecipe
class Engadget(BasicNewsRecipe):
title = u'Engadget_Full'
title = u'Engadget'
__author__ = 'Starson17'
__version__ = 'v1.00'
__date__ = '02, July 2011'

View 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'})
]

View File

@ -1,25 +1,29 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal kovid@kovidgoyal.net'
__copyright__ = '2011, Starson17'
__docformat__ = 'restructuredtext en'
from calibre.web.feeds.news import BasicNewsRecipe
class Freakonomics(BasicNewsRecipe):
title = 'Freakonomics Blog'
description = 'The Hidden side of everything'
__author__ = 'Starson17'
__author__ = 'Starson17'
__version__ = '1.02'
__date__ = '11 July 2011'
language = 'en'
cover_url = 'http://ilkerugur.files.wordpress.com/2009/04/freakonomics.jpg'
use_embedded_content= False
no_stylesheets = True
oldest_article = 30
remove_javascript = True
remove_empty_feeds = True
max_articles_per_feed = 50
feeds = [('Blog', 'http://feeds.feedburner.com/freakonomicsblog')]
keep_only_tags = [dict(name='div', attrs={'id':'header'}),
dict(name='h1'),
dict(name='h2'),
dict(name='div', attrs={'class':'entry-content'}),
]
feeds = [(u'Freakonomics Blog', u'http://www.freakonomics.com/feed/')]
keep_only_tags = [dict(name='div', attrs={'id':['content']})]
remove_tags_after = [dict(name='div', attrs={'class':['simple_socialmedia']})]
remove_tags = [dict(name='div', attrs={'class':['simple_socialmedia','single-fb-share','wp-polls']})]
extra_css = '''
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.web.feeds import Feed
@ -36,14 +35,13 @@ class GC_gl(BasicNewsRecipe):
def feed_to_index_append(self, feedObject, masterFeed):
for feed in feedObject:
newArticles = []
for article in feed.articles:
newArt = {
'title' : article.title,
'url' : article.url,
'date' : article.date
}
newArticles.append(newArt)
masterFeed.append((feed.title,newArticles))
for feed in feedObject:
newArticles = []
for article in feed.articles:
newArt = {
'title' : article.title,
'url' : article.url,
'date' : article.date
}
newArticles.append(newArt)
masterFeed.append((feed.title,newArticles))

35
recipes/geek_poke.recipe Normal file
View File

@ -0,0 +1,35 @@
#!/usr/bin/python
from calibre.web.feeds.news import BasicNewsRecipe
import re
class AdvancedUserRecipe1307556816(BasicNewsRecipe):
title = u'Geek and Poke'
__author__ = u'DrMerry'
description = u'Geek and Poke Cartoons'
oldest_article = 31
max_articles_per_feed = 100
language = u'en'
simultaneous_downloads = 5
#delay = 1
timefmt = ' [%A, %d %B, %Y]'
summary_length = -1
no_stylesheets = True
cover_url = 'http://geekandpoke.typepad.com/aboutcoders.jpeg'
remove_javascript = True
remove_empty_feeds = True
publication_type = 'blog'
preprocess_regexps = [ (re.compile(r'(<p>&nbsp;</p>|<iframe.*</iframe>|<a[^>]*>Tweet</a>|<a[^>]*>|</a>)', re.DOTALL|re.IGNORECASE),lambda match: ''),
(re.compile(r'(&nbsp;| )', re.DOTALL|re.IGNORECASE),lambda match: ' '),
(re.compile(r'<br( /)?>(<br( /)?>)+', re.DOTALL|re.IGNORECASE),lambda match: '<br>')
]
extra_css = 'body, h3, p, h2, h1, div, span{margin:0px} h2.date-header {font-size: 0.7em; color:#eee;} h3.entry-header{font-size: 1.0em} div.entry-body{font-size: 0.9em}'
remove_tags_before = dict(name='h2', attrs={'class':'date-header'})
remove_tags_after = dict(name='div', attrs={'class':'entry-body'})
feeds = [(u'Geek and Poke', u'http://feeds.feedburner.com/GeekAndPoke?format=xml')]

View File

@ -12,7 +12,7 @@ from datetime import date
class Guardian(BasicNewsRecipe):
title = u'The Guardian / The Observer'
title = u'The Guardian and The Observer'
if date.today().weekday() == 6:
base_url = "http://www.guardian.co.uk/theobserver"
else:
@ -28,7 +28,7 @@ class Guardian(BasicNewsRecipe):
# List of section titles to ignore
# For example: ['Sport']
ignore_sections = []
timefmt = ' [%a, %d %b %Y]'
keep_only_tags = [
dict(name='div', attrs={'id':["content","article_header","main-article-info",]}),
@ -94,7 +94,7 @@ class Guardian(BasicNewsRecipe):
prefix = section_title + ': '
for subsection in s.parent.findAll('a', attrs={'class':'book-section'}):
yield (prefix + self.tag_to_string(subsection), subsection['href'])
def find_articles(self, url):
soup = self.index_to_soup(url)
div = soup.find('div', attrs={'class':'book-index'})
@ -115,7 +115,7 @@ class Guardian(BasicNewsRecipe):
'title': title, 'url':url, 'description':desc,
'date' : strftime('%a, %d %b'),
}
def parse_index(self):
try:
feeds = []

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

BIN
recipes/icons/losandes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

33
recipes/idg_se.recipe Normal file
View File

@ -0,0 +1,33 @@
__license__ = 'GPLv3'
from calibre.web.feeds.news import BasicNewsRecipe
class IDGse(BasicNewsRecipe):
title = 'IDG'
description = 'IDG.se'
language = 'se'
__author__ = 'zapt0'
oldest_article = 1
max_articles_per_feed = 40
no_stylesheets = True
encoding = 'ISO-8859-1'
remove_javascript = True
feeds = [(u'Senaste nytt',u'http://feeds.idg.se/idg/vzzs')]
def print_version(self,url):
return url + '?articleRenderMode=print&m=print'
def get_cover_url(this):
return 'http://idgmedia.idg.se/polopoly_fs/2.3275!images/idgmedia_logo_75.jpg'
keep_only_tags = [
dict(name='h1'),
dict(name='div', attrs={'class':['divColumn1Article']}),
]
#remove ads
remove_tags = [
dict(name='div', attrs={'id':['preamble_ad']}),
dict(name='ul', attrs={'class':['share']})
]

View File

@ -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

View File

@ -1,22 +1,31 @@
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1299694372(BasicNewsRecipe):
title = u'Instapaper'
__author__ = 'Darko Miletic'
publisher = 'Instapaper.com'
category = 'info, custom, Instapaper'
oldest_article = 365
title = u'Instapaper'
__author__ = 'Darko Miletic'
publisher = 'Instapaper.com'
category = 'info, custom, Instapaper'
oldest_article = 365
max_articles_per_feed = 100
no_stylesheets = True
remove_javascript = True
remove_tags = [
dict(name='div', attrs={'id':'text_controls_toggle'})
,dict(name='script')
,dict(name='div', attrs={'id':'text_controls'})
,dict(name='div', attrs={'id':'editing_controls'})
,dict(name='div', attrs={'class':'bar bottom'})
]
use_embedded_content = False
needs_subscription = True
INDEX = u'http://www.instapaper.com'
LOGIN = INDEX + u'/user/login'
feeds = [(u'Instapaper Unread', u'http://www.instapaper.com/u'), (u'Instapaper Starred', u'http://www.instapaper.com/starred')]
feeds = [
(u'Instapaper Unread', u'http://www.instapaper.com/u'),
(u'Instapaper Starred', u'http://www.instapaper.com/starred')
]
def get_browser(self):
br = BasicNewsRecipe.get_browser()
@ -34,21 +43,28 @@ class AdvancedUserRecipe1299694372(BasicNewsRecipe):
lfeeds = self.get_feeds()
for feedobj in lfeeds:
feedtitle, feedurl = feedobj
self.report_progress(0, _('Fetching feed')+' %s...'%(feedtitle if feedtitle else feedurl))
self.report_progress(0, 'Fetching feed'+' %s...'%(feedtitle if feedtitle else feedurl))
articles = []
soup = self.index_to_soup(feedurl)
for item in soup.findAll('div', attrs={'class':'titleRow'}):
description = self.tag_to_string(item.div)
for item in soup.findAll('div', attrs={'class':'cornerControls'}):
#description = self.tag_to_string(item.div)
atag = item.a
if atag and atag.has_key('href'):
url = atag['href']
title = self.tag_to_string(atag)
date = strftime(self.timefmt)
articles.append({
'title' :title
,'date' :date
,'url' :url
,'description':description
'url' :url
})
totalfeeds.append((feedtitle, articles))
return totalfeeds
def print_version(self, url):
return 'http://www.instapaper.com' + url
def populate_article_metadata(self, article, soup, first):
article.title = soup.find('title').contents[0].strip()
def postprocess_html(self, soup, first_fetch):
for link_tag in soup.findAll(attrs={"id" : "story"}):
link_tag.insert(0,'<h1>'+soup.find('title').contents[0].strip()+'</h1>')
return soup

View File

@ -16,16 +16,14 @@ class i09(BasicNewsRecipe):
max_articles_per_feed = 100
no_stylesheets = True
encoding = 'utf-8'
use_embedded_content = False
use_embedded_content = True
language = 'en'
masthead_url = 'http://cache.gawkerassets.com/assets/io9.com/img/logo.png'
extra_css = '''
body{font-family: "Lucida Grande",Helvetica,Arial,sans-serif}
img{margin-bottom: 1em}
h1{font-family :Arial,Helvetica,sans-serif; font-size:large}
h2{font-family :Arial,Helvetica,sans-serif; font-size:x-small}
'''
conversion_options = {
'comment' : description
, 'tags' : category
@ -33,13 +31,11 @@ class i09(BasicNewsRecipe):
, 'language' : language
}
remove_attributes = ['width','height']
keep_only_tags = [dict(attrs={'class':'content permalink'})]
remove_tags_before = dict(name='h1')
remove_tags = [dict(attrs={'class':'contactinfo'})]
remove_tags_after = dict(attrs={'class':'contactinfo'})
feeds = [(u'Articles', u'http://feeds.gawker.com/io9/vip?format=xml')]
feeds = [(u'Articles', u'http://feeds.gawker.com/io9/full')]
remove_tags = [
{'class': 'feedflare'},
]
def preprocess_html(self, soup):
return self.adeify_images(soup)

View File

@ -1,4 +1,4 @@
__license__ = 'GPL v3'
__license__ = 'GPL v3'
__copyright__ = "2008, Derry FitzGerald. 2009 Modified by Ray Kinsella and David O'Callaghan, 2011 Modified by Phil Burns"
'''
irishtimes.com
@ -10,7 +10,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
class IrishTimes(BasicNewsRecipe):
title = u'The Irish Times'
encoding = 'ISO-8859-15'
__author__ = "Derry FitzGerald, Ray Kinsella, David O'Callaghan and Phil Burns"
__author__ = "Derry FitzGerald, Ray Kinsella, David O'Callaghan and Phil Burns"
language = 'en_IE'
timefmt = ' (%A, %B %d, %Y)'
@ -18,6 +18,7 @@ class IrishTimes(BasicNewsRecipe):
oldest_article = 1.0
max_articles_per_feed = 100
no_stylesheets = True
simultaneous_downloads= 5
r = re.compile('.*(?P<url>http:\/\/(www.irishtimes.com)|(rss.feedsportal.com\/c)\/.*\.html?).*')
remove_tags = [dict(name='div', attrs={'class':'footer'})]
@ -25,17 +26,17 @@ class IrishTimes(BasicNewsRecipe):
feeds = [
('Frontpage', 'http://www.irishtimes.com/feeds/rss/newspaper/index.rss'),
('Ireland', 'http://rss.feedsportal.com/c/851/f/10845/index.rss'),
('World', 'http://rss.feedsportal.com/c/851/f/10846/index.rss'),
('Finance', 'http://rss.feedsportal.com/c/851/f/10847/index.rss'),
('Features', 'http://rss.feedsportal.com/c/851/f/10848/index.rss'),
('Sport', 'http://rss.feedsportal.com/c/851/f/10849/index.rss'),
('Opinion', 'http://rss.feedsportal.com/c/851/f/10850/index.rss'),
('Letters', 'http://rss.feedsportal.com/c/851/f/10851/index.rss'),
('Ireland', 'http://www.irishtimes.com/feeds/rss/newspaper/ireland.rss'),
('World', 'http://www.irishtimes.com/feeds/rss/newspaper/world.rss'),
('Finance', 'http://www.irishtimes.com/feeds/rss/newspaper/finance.rss'),
('Features', 'http://www.irishtimes.com/feeds/rss/newspaper/features.rss'),
('Sport', 'http://www.irishtimes.com/feeds/rss/newspaper/sport.rss'),
('Opinion', 'http://www.irishtimes.com/feeds/rss/newspaper/opinion.rss'),
('Letters', 'http://www.irishtimes.com/feeds/rss/newspaper/letters.rss'),
('Magazine', 'http://www.irishtimes.com/feeds/rss/newspaper/magazine.rss'),
('Health', 'http://rss.feedsportal.com/c/851/f/10852/index.rss'),
('Education & Parenting', 'http://rss.feedsportal.com/c/851/f/10853/index.rss'),
('Motors', 'http://rss.feedsportal.com/c/851/f/10854/index.rss'),
('Health', 'http://www.irishtimes.com/feeds/rss/newspaper/health.rss'),
('Education & Parenting', 'http://www.irishtimes.com/feeds/rss/newspaper/education.rss'),
('Motors', 'http://www.irishtimes.com/feeds/rss/newspaper/motors.rss'),
('An Teanga Bheo', 'http://www.irishtimes.com/feeds/rss/newspaper/anteangabheo.rss'),
('Commercial Property', 'http://www.irishtimes.com/feeds/rss/newspaper/commercialproperty.rss'),
('Science Today', 'http://www.irishtimes.com/feeds/rss/newspaper/sciencetoday.rss'),
@ -49,10 +50,16 @@ class IrishTimes(BasicNewsRecipe):
def print_version(self, url):
if url.count('rss.feedsportal.com'):
u = url.replace('0Bhtml/story01.htm','_pf0Bhtml/story01.htm')
#u = url.replace('0Bhtml/story01.htm','_pf0Bhtml/story01.htm')
u = url.find('irishtimes')
u = 'http://www.irishtimes.com' + url[u + 12:]
u = u.replace('0C', '/')
u = u.replace('A', '')
u = u.replace('0Bhtml/story01.htm', '_pf.html')
else:
u = url.replace('.html','_pf.html')
return u
def get_article_url(self, article):
return article.link

View File

@ -1,4 +1,4 @@
import urllib2
import urllib2, re
from calibre.web.feeds.news import BasicNewsRecipe
class JBPress(BasicNewsRecipe):
@ -40,3 +40,12 @@ class JBPress(BasicNewsRecipe):
def print_version(self, url):
url = urllib2.urlopen(url).geturl() # resolve redirect.
return url.replace('/-/', '/print/')
def preprocess_html(self, soup):
# remove breadcrumb
h3s = soup.findAll('h3')
for h3 in h3s:
if re.compile('^JBpress&gt;').match(h3.string):
h3.extract()
return soup

View File

@ -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')]

View File

@ -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 = [

View File

@ -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):

View File

@ -23,7 +23,7 @@ class LaTribuna(BasicNewsRecipe):
encoding = 'utf-8'
language = 'es_HN'
lang = 'es-HN'
lang = 'es_HN'
direction = 'ltr'
html2lrf_options = [

78
recipes/losandes.recipe Normal file
View File

@ -0,0 +1,78 @@
__license__ = 'GPL v3'
__copyright__ = '2011, Darko Miletic <darko.miletic at gmail.com>'
'''
www.losandes.com.ar
'''
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class LosAndes(BasicNewsRecipe):
title = 'Los Andes'
__author__ = 'Darko Miletic'
description = 'Noticias de Mendoza, Argentina y el resto del mundo'
publisher = 'Los Andes'
category = 'news, politics, Argentina'
oldest_article = 2
max_articles_per_feed = 200
no_stylesheets = True
encoding = 'cp1252'
use_embedded_content = False
language = 'es_AR'
remove_empty_feeds = True
publication_type = 'newspaper'
masthead_url = 'http://www.losandes.com.ar/graficos/losandes.png'
extra_css = """
body{font-family: Arial,Helvetica,sans-serif }
h1,h2{font-family: "Times New Roman",Times,serif}
.fechaNota{font-weight: bold; color: gray}
"""
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
remove_tags = [
dict(name=['meta','link'])
,dict(attrs={'class':['cabecera', 'url']})
]
remove_tags_before=dict(attrs={'class':'cabecera'})
remove_tags_after=dict(attrs={'class':'url'})
feeds = [
(u'Ultimas Noticias' , u'http://www.losandes.com.ar/servicios/rss.asp?r=78' )
,(u'Politica' , u'http://www.losandes.com.ar/servicios/rss.asp?r=68' )
,(u'Economia nacional' , u'http://www.losandes.com.ar/servicios/rss.asp?r=65' )
,(u'Economia internacional' , u'http://www.losandes.com.ar/servicios/rss.asp?r=505')
,(u'Internacionales' , u'http://www.losandes.com.ar/servicios/rss.asp?r=66' )
,(u'Turismo' , u'http://www.losandes.com.ar/servicios/rss.asp?r=502')
,(u'Fincas' , u'http://www.losandes.com.ar/servicios/rss.asp?r=504')
,(u'Isha nos habla' , u'http://www.losandes.com.ar/servicios/rss.asp?r=562')
,(u'Estilo' , u'http://www.losandes.com.ar/servicios/rss.asp?r=81' )
,(u'Cultura' , u'http://www.losandes.com.ar/servicios/rss.asp?r=503')
,(u'Policiales' , u'http://www.losandes.com.ar/servicios/rss.asp?r=70' )
,(u'Deportes' , u'http://www.losandes.com.ar/servicios/rss.asp?r=69' )
,(u'Sociedad' , u'http://www.losandes.com.ar/servicios/rss.asp?r=67' )
,(u'Opinion' , u'http://www.losandes.com.ar/servicios/rss.asp?r=80' )
,(u'Editorial' , u'http://www.losandes.com.ar/servicios/rss.asp?r=76' )
,(u'Mirador' , u'http://www.losandes.com.ar/servicios/rss.asp?r=79' )
]
def print_version(self, url):
artid = url.rpartition('.')[0].rpartition('-')[2]
return "http://www.losandes.com.ar/includes/modulos/imprimir.asp?tipo=noticia&id=" + artid
def get_cover_url(self):
month = strftime("%m").lstrip('0')
day = strftime("%d").lstrip('0')
year = strftime("%Y")
return "http://www.losandes.com.ar/fotografias/fotosnoticias/" + year + "/" + month + "/" + day + "/th_tapa.jpg"
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
from calibre.web.feeds.news import BasicNewsRecipe
class LV_gl(BasicNewsRecipe):
title = u'De Luns a Venres (RSS)'
__author__ = u'Susana Sotelo Docío'
description = u'O gratuíto galego'
publisher = u'Galiciaé'
category = u'news'
encoding = 'utf-8'
language = 'gl'
direction = 'ltr'
cover_url = 'http://lv.galiciae.com/new_estilos/lv/logo.gif'
oldest_article = 2
max_articles_per_feed = 200
center_navbar = False
feeds = [
(u'Galicia', u'http://lv.galiciae.com/cache/rss/sec_galicia_gl.rss'),
(u'Cultura', u'http://lv.galiciae.com/cache/rss/sec_cultura_gl.rss'),
(u'Mundo', u'http://lv.galiciae.com/cache/rss/sec_mundo_gl.rss'),
(u'Cidadanía', u'http://lv.galiciae.com/cache/rss/sec_ciudadania_gl.rss'),
(u'Tecnoloxía', u'http://lv.galiciae.com/cache/rss/sec_tecnologia_gl.rss'),
(u'España', u'http://lv.galiciae.com/cache/rss/sec_espana_gl.rss'),
(u'Deportes', u'http://lv.galiciae.com/cache/rss/sec_deportes_gl.rss'),
(u'Economía', u'http://lv.galiciae.com/cache/rss/sec_economia_gl.rss'),
(u'Lercheo', u'http://lv.galiciae.com/cache/rss/sec_gente_gl.rss'),
(u'Medio ambiente', u'http://lv.galiciae.com/cache/rss/sec_medioambiente_gl.rss'),
(u'España/Mundo', u'http://lv.galiciae.com/cache/rss/sec_espanamundo_gl.rss'),
(u'Sociedade', u'http://lv.galiciae.com/cache/rss/sec_sociedad_gl.rss'),
(u'Ciencia', u'http://lv.galiciae.com/cache/rss/sec_ciencia_gl.rss'),
(u'Motor', u'http://lv.galiciae.com/cache/rss/sec_motor_gl.rss'),
(u'Coches', u'http://lv.galiciae.com/cache/rss/sec_coches_gl.rss'),
(u'Motos', u'http://lv.galiciae.com/cache/rss/sec_motos_gl.rss'),
(u'Industriais', u'http://lv.galiciae.com/cache/rss/sec_industriales_gl.rss')
]
extra_css = u' p{text-align:left} '
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\nencoding="' + encoding + '"\ntags="' + category + '"\noverride_css=" p {text-align:left; text-indent: 0cm} "'
def print_version(self, url):
url += '?imprimir&lang=gl'
return url

View File

@ -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 = """

View File

@ -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'})

View File

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
__license__ = 'GPL v3'
__copyright__ = 'Marcin Urban 2011'
import re
from calibre.web.feeds.recipes import BasicNewsRecipe
class recipeMagic(BasicNewsRecipe):
title = 'National Geographic PL'
__author__ = 'Marcin Urban 2011'
description = 'legenda wśród magazynów z historią sięgającą 120 lat'
cover_url = 'http://www.guj.pl/var/guj/storage/images/media/nasze_magazyny/national_geographic/logo/ng_logo/2606-1-pol-PL/ng_logo.jpg'
oldest_article = 7
max_articles_per_feed = 100
no_stylesheets = True
#delay = 1
use_embedded_content = False
encoding = 'utf8'
publisher = 'G+J Gruner+Jahr Polska'
category = 'news, PL,'
language = 'pl'
publication_type = 'newsportal'
extra_css = ''' body {font-family: verdana, arial, helvetica, geneva, sans-serif ;}
h1{text-align: center;}
h2{font-size: medium; font-weight: bold;}
.authordate {font-size: small; color: #696969;}
p.lead {font-weight: bold; text-align: center;}
.fot{font-size: x-small; color: #666666;} '''
preprocess_regexps = [(re.compile(r'<!--.*?-->', re.DOTALL), lambda m: '')]
conversion_options = {
'comments' : description
,'tags' : category
,'language' : language
,'publisher' : publisher
,'linearize_tables': True
}
remove_tags = [
dict(name='div', attrs={'class':'add_inf'}),
dict(name='div', attrs={'class':'add_f'}),
]
remove_attributes = ['width','height']
feeds = [
('National Geographic PL', 'http://www.national-geographic.pl/rss/'),
]
def print_version(self, url):
return url.replace('artykuly0Cpokaz', 'drukuj-artykul')

View File

@ -1,11 +1,10 @@
EMAILADDRESS = 'hoge@foobar.co.jp'
from calibre.web.feeds.news import BasicNewsRecipe
class NBOnline(BasicNewsRecipe):
title = u'Nikkei Business Online'
language = 'ja'
description = u'Nikkei Business Online New articles. PLEASE NOTE: You need to edit EMAILADDRESS line of this "nbonline.recipe" file to set your e-mail address which is needed when login. (file is in "Calibre2/resources/recipes" directory.)'
description = u'Nikkei Business Online.\u6CE8\uFF1A\u30E6\u30FC\u30B6\u30FC\u540D\u306Bemail\u30A2\u30C9\u30EC\u30B9\u3068\u30E6\u30FC\u30B6\u30FC\u540D\u3092\u30BB\u30DF\u30B3\u30ED\u30F3\u3067\u533A\u5207\u3063\u3066\u5165\u308C\u3066\u304F\u3060\u3055\u3044\u3002\u4F8B\uFF1Aemail@address.jp;username . PLEASE NOTE: You need to put your email address and username into username filed separeted by ; (semi-colon).'
__author__ = 'Ado Nishimura'
needs_subscription = True
oldest_article = 7
@ -23,8 +22,8 @@ class NBOnline(BasicNewsRecipe):
if self.username is not None and self.password is not None:
br.open('https://signon.nikkeibp.co.jp/front/login/?ct=p&ts=nbo')
br.select_form(name='loginActionForm')
br['email'] = EMAILADDRESS
br['userId'] = self.username
br['email'] = self.username.split(';')[0]
br['userId'] = self.username.split(';')[1]
br['password'] = self.password
br.submit()
return br

View File

@ -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'

View File

@ -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

View File

@ -0,0 +1,89 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
import re
#import pprint, sys
#pp = pprint.PrettyPrinter(indent=4)
class NikkeiNet_paper_subscription(BasicNewsRecipe):
title = u'\u65E5\u672C\u7D4C\u6E08\u65B0\u805E\uFF08\u671D\u520A\u30FB\u5915\u520A\uFF09'
__author__ = 'Ado Nishimura'
description = u'\u65E5\u7D4C\u96FB\u5B50\u7248\u306B\u3088\u308B\u65E5\u672C\u7D4C\u6E08\u65B0\u805E\u3002\u671D\u520A\u30FB\u5915\u520A\u306F\u53D6\u5F97\u6642\u9593\u306B\u3088\u308A\u5207\u308A\u66FF\u308F\u308A\u307E\u3059\u3002\u8981\u8CFC\u8AAD'
needs_subscription = True
oldest_article = 1
max_articles_per_feed = 30
language = 'ja'
no_stylesheets = True
cover_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
masthead_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
remove_tags_before = {'class':"cmn-indent"}
remove_tags = [
# {'class':"cmn-article_move"},
# {'class':"cmn-pr_list"},
# {'class':"cmnc-zoom"},
{'class':"cmn-hide"},
{'name':'form'},
]
remove_tags_after = {'class':"cmn-indent"}
def get_browser(self):
br = BasicNewsRecipe.get_browser()
#pp.pprint(self.parse_index())
#exit(1)
#br.set_debug_http(True)
#br.set_debug_redirects(True)
#br.set_debug_responses(True)
if self.username is not None and self.password is not None:
print "----------------------------open top page----------------------------------------"
br.open('http://www.nikkei.com/')
print "----------------------------open first login form--------------------------------"
link = br.links(url_regex="www.nikkei.com/etc/accounts/login").next()
br.follow_link(link)
#response = br.response()
#print response.get_data()
print "----------------------------JS redirect(send autoPostForm)-----------------------"
br.select_form(name='autoPostForm')
br.submit()
#response = br.response()
print "----------------------------got login form---------------------------------------"
br.select_form(name='LA0210Form01')
br['LA0210Form01:LA0210Email'] = self.username
br['LA0210Form01:LA0210Password'] = self.password
br.submit()
#response = br.response()
print "----------------------------JS redirect------------------------------------------"
br.select_form(nr=0)
br.submit()
#br.set_debug_http(False)
#br.set_debug_redirects(False)
#br.set_debug_responses(False)
return br
def cleanup(self):
print "----------------------------logout-----------------------------------------------"
self.browser.open('https://regist.nikkei.com/ds/etc/accounts/logout')
def parse_index(self):
print "----------------------------get index of paper-----------------------------------"
result = []
soup = self.index_to_soup('http://www.nikkei.com/paper/')
#soup = self.index_to_soup(self.test_data())
for sect in soup.findAll('div', 'cmn-section kn-special JSID_baseSection'):
sect_title = sect.find('h3', 'cmnc-title').string
sect_result = []
for elem in sect.findAll(attrs={'class':['cmn-article_title']}):
url = 'http://www.nikkei.com' + elem.span.a['href']
url = re.sub("/article/", "/print-article/", url) # print version.
span = elem.span.a.span
if ((span is not None) and (len(span.contents) > 1)):
title = span.contents[1].string
sect_result.append(dict(title=title, url=url, date='',
description='', content=''))
result.append([sect_title, sect_result])
#pp.pprint(result)
return result

35
recipes/novinite.recipe Normal file
View 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')]

View 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/')
]

47
recipes/plus_info.recipe Normal file
View File

@ -0,0 +1,47 @@
#!/usr/bin/env python
__author__ = 'Darko Spasovski'
__license__ = 'GPL v3'
__copyright__ = '2011, Darko Spasovski <darko.spasovski at gmail.com>'
'''
www.plusinfo.mk
'''
from calibre.web.feeds.news import BasicNewsRecipe
class PlusInfo(BasicNewsRecipe):
INDEX = 'www.plusinfo.mk'
title = u'+info'
__author__ = 'Darko Spasovski'
description = 'Macedonian news portal'
publication_type = 'newsportal'
category = 'news, Macedonia'
language = 'mk'
masthead_url = 'http://www.plusinfo.mk/style/images/logo.jpg'
remove_javascript = True
no_stylesheets = True
use_embedded_content = False
remove_empty_feeds = True
oldest_article = 1
max_articles_per_feed = 100
keep_only_tags = [dict(name='div', attrs={'class': 'vest'})]
remove_tags = [dict(name='div', attrs={'class':['komentari_holder', 'objava']})]
feeds = [(u'Македонија', u'http://www.plusinfo.mk/rss/makedonija'),
(u'Бизнис', u'http://www.plusinfo.mk/rss/biznis'),
(u'Скопје', u'http://www.plusinfo.mk/rss/skopje'),
(u'Култура', u'http://www.plusinfo.mk/rss/kultura'),
(u'Свет', u'http://www.plusinfo.mk/rss/svet'),
(u'Сцена', u'http://www.plusinfo.mk/rss/scena'),
(u'Здравје', u'http://www.plusinfo.mk/rss/zdravje'),
(u'Магазин', u'http://www.plusinfo.mk/rss/magazin'),
(u'Спорт', u'http://www.plusinfo.mk/rss/sport')]
# uncomment the following block if you want the print version (note: it lacks photos)
# def print_version(self,url):
# segments = url.split('/')
# printURL = '/'.join(segments[0:3]) + '/print/' + '/'.join(segments[5:])
# return printURL

36
recipes/portafolio.recipe Normal file
View File

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1311799898(BasicNewsRecipe):
title = u'Periódico Portafolio Colombia'
language = 'es_CO'
__author__ = 'BIGO-CAVA'
cover_url = 'http://www.portafolio.co/sites/portafolio.co/themes/portafolio_2011/logo.png'
remove_tags_before = dict(id='contenidoArt')
remove_tags_after = [dict(name='div', attrs={'class':'articulo-mas'})]
keep_only_tags = [dict(name='div', id='contenidoArt')]
oldest_article = 1
max_articles_per_feed = 100
remove_javascript = True
no_stylesheets = True
use_embedded_content = False
remove_empty_feeds = True
masthead_url = 'http://www.portafolio.co/sites/portafolio.co/themes/portafolio_2011/logo.png'
publication_type = 'newspaper'
extra_css = """
p{text-align: justify; font-size: 100%}
body{ text-align: left; font-size:100% }
h1{font-family: sans-serif; font-size:150%; font-weight:bold; text-align: justify; }
h3{font-family: sans-serif; font-size:100%; font-style: italic; text-align: justify; }
"""
feeds = [(u'Negocios', u'http://www.portafolio.co/negocios/feed'),
(u'Economia', u'http://www.portafolio.co/economia/feed'),
(u'Internacional', u'http://www.portafolio.co/internacional/feed'),
(u'Indicadores', u'http://www.portafolio.co/indicadores/feed'),
(u'Opinion', u'http://www.portafolio.co/opinion/feed'),
(u'Finanzas Personales', u'http://www.portafolio.co/finanzas-personales/feed'),
(u'Herramientas', u'http://www.portafolio.co/herramientas/feed')]

View File

@ -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'

63
recipes/techcrunch.recipe Normal file
View File

@ -0,0 +1,63 @@
__license__ = 'GPL v3'
__copyright__ = '2011, Darko Miletic <darko.miletic at gmail.com>'
'''
techcrunch.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
class TechCrunch(BasicNewsRecipe):
title = 'TechCrunch'
__author__ = 'Darko Miletic'
description = 'IT News'
publisher = 'AOL Inc.'
category = 'news, IT'
oldest_article = 2
max_articles_per_feed = 200
no_stylesheets = True
encoding = 'utf8'
use_embedded_content = False
language = 'en'
remove_empty_feeds = True
publication_type = 'newsportal'
masthead_url = 'http://s2.wp.com/wp-content/themes/vip/tctechcrunch2/images/site-logo.png'
extra_css = """
body{font-family: Helvetica,Arial,sans-serif }
img{margin-bottom: 0.4em; display:block}
"""
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
remove_tags = [dict(name=['meta','link'])]
remove_attributes=['lang']
keep_only_tags=[
dict(name='h1', attrs={'class':'headline'})
,dict(attrs={'class':['author','post-time','body-copy']})
]
feeds = [(u'News', u'http://feeds.feedburner.com/TechCrunch/')]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
for item in soup.findAll('a'):
limg = item.find('img')
if item.string is not None:
str = item.string
item.replaceWith(str)
else:
if limg:
item.name = 'div'
item.attrs = []
else:
str = self.tag_to_string(item)
item.replaceWith(str)
for item in soup.findAll('img'):
if not item.has_key('alt'):
item['alt'] = 'image'
return soup

View 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/')]

24
recipes/tijolaco.recipe Normal file
View File

@ -0,0 +1,24 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
class Tijolaco(BasicNewsRecipe):
title = u'Tijolaco.com'
__author__ = u'Diniz Bortolotto'
description = u'Posts do Blog Tijola\xe7o.com'
oldest_article = 7
max_articles_per_feed = 50
encoding = 'utf8'
publisher = u'Brizola Neto'
category = 'politics, Brazil'
language = 'pt_BR'
publication_type = 'politics portal'
use_embedded_content = False
no_stylesheets = True
remove_javascript = True
feeds = [(u'Blog Tijola\xe7o.com', u'http://feeds.feedburner.com/Tijolacoblog')]
reverse_article_order = True
keep_only_tags = [dict(name='div', attrs={'class':'post'})]
remove_tags = [dict(name='span', attrs={'class':'com'})]

View File

@ -8,47 +8,33 @@ time.com
import re
from calibre.web.feeds.news import BasicNewsRecipe
from lxml import html
class Time(BasicNewsRecipe):
#recipe_disabled = ('This recipe has been disabled as TIME no longer'
# ' publish complete articles on the web.')
title = u'Time'
__author__ = 'Kovid Goyal and Sujata Raman'
__author__ = 'Kovid Goyal'
description = 'Weekly magazine'
encoding = 'utf-8'
no_stylesheets = True
language = 'en'
remove_javascript = True
extra_css = ''' h1 {font-family:georgia,serif;color:#000000;}
.mainHd{font-family:georgia,serif;color:#000000;}
h2 {font-family:Arial,Sans-serif;}
.name{font-family:Arial,Sans-serif; font-size:x-small;font-weight:bold; }
.date{font-family:Arial,Sans-serif; font-size:x-small ;color:#999999;}
.byline{font-family:Arial,Sans-serif; font-size:x-small ;}
.photoBkt{ font-size:x-small ;}
.vertPhoto{font-size:x-small ;}
.credits{font-family:Arial,Sans-serif; font-size:x-small ;color:gray;}
.credit{font-family:Arial,Sans-serif; font-size:x-small ;color:gray;}
.artTxt{font-family:georgia,serif;}
#content{font-family:georgia,serif;}
.caption{font-family:georgia,serif; font-size:x-small;color:#333333;}
.credit{font-family:georgia,serif; font-size:x-small;color:#999999;}
a:link{color:#CC0000;}
.breadcrumb{font-family:Arial,Sans-serif;font-size:x-small;}
'''
keep_only_tags = [
{
'class':['artHd', 'articleContent',
'entry-title','entry-meta', 'entry-content', 'thumbnail']
},
]
remove_tags = [
{'class':['content-tools', 'quigo', 'see',
'first-tier-social-tools', 'navigation', 'enlarge lightbox']},
{'id':['share-tools']},
{'rel':'lightbox'},
]
keep_only_tags = [ dict(name ="div",attrs = {"id" :["content"]}) ,
dict(name ="div",attrs = {"class" :["artHd","artTxt","photoBkt","vertPhoto","image","copy"]}) ,]
remove_tags = [ dict(name ="div",attrs = {'class':['articleFooterNav','listsByTopic','articleTools2','relatedContent','sideContent','topBannerWrap','articlePagination','nextUp',"rtCol","pagination","enlarge","contentTools2",]}),
dict(name ="span",attrs = {'class':['see']}),
dict(name ="div",attrs = {'id':['header','articleSideBar',"articleTools","articleFooter","cmBotLt","quigoPackage"]}),
dict(name ="a",attrs = {'class':['listLink']}),
dict(name ="ul",attrs = {'id':['shareSocial','tabs']}),
dict(name ="li",attrs = {'class':['back']}),
dict(name ="ul",attrs = {'class':['navCount']}),
]
recursions = 10
match_regexps = [r'/[0-9,]+-(2|3|4|5|6|7|8|9)(,\d+){0,1}.html',r'http://www.time.com/time/specials/packages/article/.*']
@ -56,10 +42,11 @@ class Time(BasicNewsRecipe):
r'<meta .+/>'), lambda m:'')]
def parse_index(self):
soup = self.index_to_soup('http://www.time.com/time/magazine')
img = soup.find('a', title="View Large Cover", href=True)
if img is not None:
cover_url = 'http://www.time.com'+img['href']
raw = self.index_to_soup('http://www.time.com/time/magazine', raw=True)
root = html.fromstring(raw)
img = root.xpath('//a[.="View Large Cover" and @href]')
if img:
cover_url = 'http://www.time.com' + img[0].get('href')
try:
nsoup = self.index_to_soup(cover_url)
img = nsoup.find('img', src=re.compile('archive/covers'))
@ -70,46 +57,48 @@ class Time(BasicNewsRecipe):
feeds = []
parent = soup.find(id='tocGuts')
for seched in parent.findAll(attrs={'class':'toc_seched'}):
section = self.tag_to_string(seched).capitalize()
articles = list(self.find_articles(seched))
feeds.append((section, articles))
parent = root.xpath('//div[@class="content-main-aside"]')[0]
for sec in parent.xpath(
'descendant::section[contains(@class, "sec-mag-section")]'):
h3 = sec.xpath('./h3')
if h3:
section = html.tostring(h3[0], encoding=unicode,
method='text').strip().capitalize()
self.log('Found section', section)
articles = list(self.find_articles(sec))
if articles:
feeds.append((section, articles))
return feeds
def find_articles(self, seched):
for a in seched.findNextSiblings( attrs={'class':['toc_hed','rule2']}):
if a.name in "div":
break
else:
yield {
'title' : self.tag_to_string(a),
'url' : 'http://www.time.com'+a['href'],
'date' : '',
'description' : self.article_description(a)
}
def find_articles(self, sec):
def article_description(self, a):
ans = []
while True:
t = a.nextSibling
if t is None:
break
a = t
if getattr(t, 'name', False):
if t.get('class', '') == 'toc_parens' or t.name == 'br':
continue
if t.name in ('div', 'a'):
break
ans.append(self.tag_to_string(t))
else:
ans.append(unicode(t))
return u' '.join(ans).replace(u'\xa0', u'').strip()
for article in sec.xpath('./article'):
h2 = article.xpath('./*[@class="entry-title"]')
if not h2: continue
a = h2[0].xpath('./a[@href]')
if not a: continue
title = html.tostring(a[0], encoding=unicode,
method='text').strip()
if not title: continue
url = a[0].get('href')
if url.startswith('/'):
url = 'http://www.time.com'+url
desc = ''
p = article.xpath('./*[@class="entry-content"]')
if p:
desc = html.tostring(p[0], encoding=unicode,
method='text')
self.log('\t', title, ':\n\t\t', desc)
yield {
'title' : title,
'url' : url,
'date' : '',
'description' : desc
}
def postprocess_html(self,soup,first):
for tag in soup.findAll(attrs ={'class':['artPag','pagination']}):
tag.extract()
return soup

View File

@ -64,7 +64,7 @@ class UnitedDaily(BasicNewsRecipe):
__author__ = 'Eddie Lau'
__version__ = '1.1'
language = 'zh-TW'
language = 'zh_TW'
publisher = 'United Daily News Group'
description = 'United Daily (Taiwan)'
category = 'News, Chinese, Taiwan'

71
recipes/utrinski.recipe Normal file
View File

@ -0,0 +1,71 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2011, Darko Spasovski <darko.spasovski at gmail.com>'
'''
utrinski.com.mk
'''
import re
import datetime
from calibre.web.feeds.news import BasicNewsRecipe
class UtrinskiVesnik(BasicNewsRecipe):
__author__ = 'Darko Spasovski'
INDEX = 'http://www.utrinski.com.mk/'
title = 'Utrinski Vesnik'
description = 'Daily Macedonian newspaper'
masthead_url = 'http://www.utrinski.com.mk/images/LogoTop.jpg'
language = 'mk'
remove_javascript = True
publication_type = 'newspaper'
category = 'news, Macedonia'
oldest_article = 2
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
preprocess_regexps = [(re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in
[
## Remove anything before the start of the article.
(r'<body.*?Article start-->', lambda match: '<body>'),
## Remove anything after the end of the article.
(r'<!--Article end.*?</body>', lambda match : '</body>'),
]
]
extra_css = """
body{font-family: Arial,Helvetica,sans-serif}
.WB_UTRINSKIVESNIK_Naslov{FONT-WEIGHT: bold; FONT-SIZE: 18px; FONT-FAMILY: Arial, Verdana, Tahoma; TEXT-DECORATION: none}
"""
conversion_options = {
'comment' : description,
'tags' : category,
'language' : language,
'linearize_tables' : True
}
def parse_index(self):
soup = self.index_to_soup(self.INDEX)
feeds = []
for section in soup.findAll('a', attrs={'class':'WB_UTRINSKIVESNIK_TOCTitleBig'}):
sectionTitle = section.contents[0].string
tocItemTable = section.findAllPrevious('table')[1]
if tocItemTable is None: continue
articles = []
while True:
tocItemTable = tocItemTable.nextSibling
if tocItemTable is None: break
article = tocItemTable.findAll('a', attrs={'class': 'WB_UTRINSKIVESNIK_TocItem'})
if len(article)==0: break
title = self.tag_to_string(article[0], use_alt=True).strip()
articles.append({'title': title, 'url':'http://www.utrinski.com.mk/' + article[0]['href'], 'description':'', 'date':''})
if articles:
feeds.append((sectionTitle, articles))
return feeds
def get_cover_url(self):
datum = datetime.datetime.today().strftime('%d_%m_%Y')
return 'http://www.utrinski.com.mk/WBStorage/Files/' + datum + '.jpg'

30
recipes/vio_mundo.recipe Normal file
View File

@ -0,0 +1,30 @@
import re
from calibre.web.feeds.news import BasicNewsRecipe
class VioMundo(BasicNewsRecipe):
title = 'Blog VioMundo'
__author__ = 'Diniz Bortolotto'
description = 'Posts do Blog VioMundo'
publisher = 'Luiz Carlos Azenha'
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 VioMundo', u'http://www.viomundo.com.br/feed')]
reverse_article_order = True
def print_version(self, url):
return url + '/print/'
remove_tags_after = dict(id='BlogContent')
preprocess_regexps = [
(re.compile(r'\|\ <u>.*</p>'),
lambda match: '</p>')
]

View File

@ -1,28 +1,29 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
__copyright__ = '2011, Starson17 <Starson17 at gmail.com>'
'''
www.wired.co.uk
'''
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
import re
class Wired_UK(BasicNewsRecipe):
title = 'Wired Magazine - UK edition'
__author__ = 'Darko Miletic'
__author__ = 'Starson17'
__version__ = 'v1.30'
__date__ = '15 July 2011'
description = 'Gaming news'
publisher = 'Conde Nast Digital'
category = 'news, games, IT, gadgets'
oldest_article = 32
oldest_article = 40
max_articles_per_feed = 100
no_stylesheets = True
encoding = 'utf-8'
use_embedded_content = False
masthead_url = 'http://www.wired.co.uk/_/media/wired-logo_UK.gif'
#masthead_url = 'http://www.wired.co.uk/_/media/wired-logo_UK.gif'
language = 'en_GB'
extra_css = ' body{font-family: Palatino,"Palatino Linotype","Times New Roman",Times,serif} img{margin-bottom: 0.8em } .img-descr{font-family: Tahoma,Arial,Helvetica,sans-serif; font-size: 0.6875em; display: block} '
index = 'http://www.wired.co.uk/wired-magazine.aspx'
index = 'http://www.wired.co.uk'
conversion_options = {
'comment' : description
@ -31,44 +32,118 @@ class Wired_UK(BasicNewsRecipe):
, 'language' : language
}
keep_only_tags = [dict(name='div', attrs={'class':'article-box'})]
remove_tags = [
dict(name=['object','embed','iframe','link'])
,dict(attrs={'class':['opts','comment','stories']})
]
remove_tags_after = dict(name='div',attrs={'class':'stories'})
keep_only_tags = [dict(name='div', attrs={'class':['layoutColumn1']})]
remove_tags = [dict(name='div',attrs={'class':['articleSidebar1','commentAddBox linkit','commentCountBox commentCountBoxBig']})]
remove_tags_after = dict(name='div',attrs={'class':['mainCopy entry-content','mainCopy']})
'''
remove_attributes = ['height','width']
,dict(name=['object','embed','iframe','link'])
,dict(attrs={'class':['opts','comment','stories']})
]
'''
def parse_index(self):
totalfeeds = []
soup = self.index_to_soup(self.index)
maincontent = soup.find('div',attrs={'class':'main-content'})
recentcontent = soup.find('ul',attrs={'class':'linkList3'})
mfeed = []
if maincontent:
st = maincontent.find(attrs={'class':'most-wired-box'})
if st:
for itt in st.findAll('a',href=True):
url = 'http://www.wired.co.uk' + itt['href']
title = self.tag_to_string(itt)
description = ''
date = strftime(self.timefmt)
mfeed.append({
'title' :title
,'date' :date
,'url' :url
,'description':description
})
totalfeeds.append(('Articles', mfeed))
if recentcontent:
for li in recentcontent.findAll('li'):
a = li.h2.a
url = self.index + a['href'] + '?page=all'
title = self.tag_to_string(a)
description = ''
date = strftime(self.timefmt)
mfeed.append({
'title' :title
,'date' :date
,'url' :url
,'description':description
})
totalfeeds.append(('Wired UK Magazine Latest News', mfeed))
popmagcontent = soup.findAll('div',attrs={'class':'sidebarLinkList'})
magcontent = popmagcontent[1]
mfeed2 = []
if magcontent:
a = magcontent.h3.a
if a:
url = self.index + a['href'] + '?page=all'
title = self.tag_to_string(a)
description = ''
date = strftime(self.timefmt)
mfeed2.append({
'title' :title
,'date' :date
,'url' :url
,'description':description
})
for li in magcontent.findAll('li'):
a = li.a
url = self.index + a['href'] + '?page=all'
title = self.tag_to_string(a)
description = ''
date = strftime(self.timefmt)
mfeed2.append({
'title' :title
,'date' :date
,'url' :url
,'description':description
})
totalfeeds.append(('Wired UK Magazine Features', mfeed2))
magsoup = self.index_to_soup(self.index + '/magazine')
startcontent = magsoup.find('h3',attrs={'class':'magSubSectionTitle titleStart'}).parent
mfeed3 = []
if startcontent:
for li in startcontent.findAll('li'):
a = li.a
url = self.index + a['href'] + '?page=all'
title = self.tag_to_string(a)
description = ''
date = strftime(self.timefmt)
mfeed3.append({
'title' :title
,'date' :date
,'url' :url
,'description':description
})
totalfeeds.append(('Wired UK Magazine More', mfeed3))
playcontent = magsoup.find('h3',attrs={'class':'magSubSectionTitle titlePlay'}).parent
mfeed4 = []
if playcontent:
for li in playcontent.findAll('li'):
a = li.a
url = self.index + a['href'] + '?page=all'
title = self.tag_to_string(a)
description = ''
date = strftime(self.timefmt)
mfeed4.append({
'title' :title
,'date' :date
,'url' :url
,'description':description
})
totalfeeds.append(('Wired UK Magazine Play', mfeed4))
return totalfeeds
def get_cover_url(self):
cover_url = None
soup = self.index_to_soup(self.index)
cover_item = soup.find('span', attrs={'class':'cover'})
cover_url = ''
soup = self.index_to_soup(self.index + '/magazine/archive')
cover_item = soup.find('div', attrs={'class':'image linkme'})
if cover_item:
cover_url = cover_item.img['src']
return cover_url
def print_version(self, url):
return url + '?page=all'
def preprocess_html(self, soup):
for tag in soup.findAll(name='p'):
if tag.find(name='span', text=re.compile(r'This article was taken from.*', re.DOTALL|re.IGNORECASE)):
tag.extract()
return soup
extra_css = '''
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''

View File

@ -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"},]

View File

@ -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"},]

View File

@ -15,15 +15,16 @@ class ZeitDe(BasicNewsRecipe):
encoding = 'UTF-8'
__author__ = 'Martin Pitt, Sujata Raman, Ingo Paschke and Marc Toensing'
no_stylesheets = True
max_articles_per_feed = 40
remove_tags = [
dict(name='iframe'),
dict(name='div', attrs={'class':["response","pagination block","pagenav","inline link", "copyright"] }),
dict(name='p', attrs={'class':["ressortbacklink", "copyright"] }),
dict(name='div', attrs={'id':["place_5","place_4","comments"]})
]
dict(name='iframe'),
dict(name='div', attrs={'class':["response","pagination block","pagenav","inline link", "copyright"] }),
dict(name='p', attrs={'class':["ressortbacklink", "copyright"] }),
dict(name='div', attrs={'id':["place_5","place_4","comments"]})
]
keep_only_tags = [dict(id=['main'])]

View File

@ -2,18 +2,21 @@
# -*- coding: utf-8 mode: python -*-
__license__ = 'GPL v3'
__copyright__ = '2010-2011, Steffen Siebert <calibre at steffensiebert.de>'
__copyright__ = '2010, Steffen Siebert <calibre at steffensiebert.de>'
__docformat__ = 'restructuredtext de'
__version__ = '1.2'
__version__ = '1.5'
"""
Die Zeit EPUB
"""
import os, urllib2, zipfile, re
import os, zipfile, re, cStringIO
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ptempfile import PersistentTemporaryFile
from calibre import walk
from urlparse import urlparse
from contextlib import closing
from calibre.utils.magick.draw import save_cover_data_to
class ZeitEPUBAbo(BasicNewsRecipe):
@ -22,49 +25,112 @@ class ZeitEPUBAbo(BasicNewsRecipe):
language = 'de'
lang = 'de-DE'
__author__ = 'Steffen Siebert and Tobias Isenberg'
__author__ = 'Steffen Siebert, revised by Tobias Isenberg (with some code by Kovid Goyal)'
needs_subscription = True
conversion_options = {
'no_default_epub_cover' : True,
# fixing the wrong left margin
'mobi_ignore_margins' : True,
'keep_ligatures' : True,
}
preprocess_regexps = [
# filtering for correct dashes
(re.compile(r' - '), lambda match: ' '), # regular "Gedankenstrich"
(re.compile(r' -,'), lambda match: ' ,'), # "Gedankenstrich" before a comma
(re.compile(r'(?<=\d)-(?=\d)'), lambda match: ''), # number-number
# filtering for correct dashes ("Gedankenstrich" and "bis")
(re.compile(u' (-|\u2212)(?=[ ,])'), lambda match: u' \u2013'),
(re.compile(r'(?<=\d)-(?=\d)'), lambda match: u'\u2013'), # number-number
(re.compile(u'(?<=\d,)-(?= ?\u20AC)'), lambda match: u'\u2013'), # ,- Euro
# fix the number dash number dash for the title image that was broken by the previous line
(re.compile(u'(?<=\d\d\d\d)\u2013(?=\d?\d\.png)'), lambda match: '-'),
# filtering for certain dash cases
(re.compile(r'Bild - Zeitung'), lambda match: 'Bild-Zeitung'), # the obvious
(re.compile(r'EMail'), lambda match: 'E-Mail'), # the obvious
(re.compile(r'SBahn'), lambda match: 'S-Bahn'), # the obvious
(re.compile(r'UBoot'), lambda match: 'U-Boot'), # the obvious
(re.compile(r'T Shirt'), lambda match: 'T-Shirt'), # the obvious
(re.compile(r'TShirt'), lambda match: 'T-Shirt'), # the obvious
# the next two lines not only fix errors but also create new ones. this is due to additional errors in
# the typesetting such as missing commas or wrongly placed dashes. but more is fixed than broken.
(re.compile(r'(?<!und|der|\w\w,) -(?=\w)'), lambda match: '-'), # space too much before a connecting dash
(re.compile(r'(?<=\w)- (?!und\b|oder\b|wie\b|aber\b|auch\b|sondern\b|bis\b|&amp;|&\s|bzw\.|auf\b|eher\b)'), lambda match: '-'), # space too much after a connecting dash
# filtering for missing spaces before the month in long dates
(re.compile(u'(?<=\d)\.(?=(Januar|Februar|M\u00E4rz|April|Mai|Juni|Juli|August|September|Oktober|November|Dezember))'), lambda match: '. '),
# filtering for other missing spaces
(re.compile(r'Stuttgart21'), lambda match: 'Stuttgart 21'), # the obvious
(re.compile(u'(?<=\d)(?=\u20AC)'), lambda match: u'\u2013'), # Zahl[no space]Euro
(re.compile(r':(?=[^\d\s</])'), lambda match: ': '), # missing space after colon
(re.compile(u'\u00AB(?=[^\-\.:;,\?!<\)\s])'), lambda match: u'\u00AB '), # missing space after closing quotation
(re.compile(u'(?<=[^\s\(>])\u00BB'), lambda match: u' \u00BB'), # missing space before opening quotation
(re.compile(r'(?<=[a-z])(?=(I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII|XIII|XIV|XV|XVI|XVII|XVIII|XIX|XX)\.)'), lambda match: ' '), # missing space before Roman numeral
(re.compile(r'(?<=(I|V|X)\.)(?=[\w])'), lambda match: ' '), # missing space after Roman numeral
(re.compile(r'(?<=(II|IV|VI|IX|XI|XV|XX)\.)(?=[\w])'), lambda match: ' '), # missing space after Roman numeral
(re.compile(r'(?<=(III|VII|XII|XIV|XVI|XIX)\.)(?=[\w])'), lambda match: ' '), # missing space after Roman numeral
(re.compile(r'(?<=(VIII|XIII|XVII)\.)(?=[\w])'), lambda match: ' '), # missing space after Roman numeral
(re.compile(r'(?<=(XVIII)\.)(?=[\w])'), lambda match: ' '), # missing space after Roman numeral
(re.compile(r'(?<=[A-Za-zÄÖÜäöü]),(?=[A-Za-zÄÖÜäöü])'), lambda match: ', '), # missing space after comma
(re.compile(r'(?<=[a-zäöü])\.(?=[A-ZÄÖÜ][A-Za-zÄÖÜäöü])'), lambda match: '. '), # missing space after full-stop
(re.compile(r'(?<=[uU]\.) (?=a\.)'), lambda match: u'\u2008'), # fix abbreviation that was potentially broken previously
(re.compile(r'(?<=[iI]\.) (?=A\.)'), lambda match: u'\u2008'), # fix abbreviation that was potentially broken previously
(re.compile(r'(?<=[zZ]\.) (?=B\.)'), lambda match: u'\u2008'), # fix abbreviation that was potentially broken previously
(re.compile(r'(?<=\w\.) (?=[A-Z][a-z]*@)'), lambda match: ''), # fix e-mail address that was potentially broken previously
(re.compile(r'(?<=\d)[Pp]rozent'), lambda match: ' Prozent'),
(re.compile(r'\.\.\.\.+'), lambda match: '...'), # too many dots (....)
(re.compile(r'(?<=[^\s])\.\.\.'), lambda match: ' ...'), # spaces before ...
(re.compile(r'\.\.\.(?=[^\s])'), lambda match: '... '), # spaces after ...
(re.compile(r'(?<=[\[\(]) \.\.\. (?=[\]\)])'), lambda match: '...'), # fix special cases of ... in brackets
(re.compile(u'(?<=[\u00BB\u203A]) \.\.\.'), lambda match: '...'), # fix special cases of ... after a quotation mark
(re.compile(u'\.\.\. (?=[\u00AB\u2039,])'), lambda match: '...'), # fix special cases of ... before a quotation mark or comma
# fix missing spaces between numbers and any sort of units, possibly with dot
(re.compile(r'(?<=\d)(?=(Femto|Piko|Nano|Mikro|Milli|Zenti|Dezi|Hekto|Kilo|Mega|Giga|Tera|Peta|Tausend|Trilli|Kubik|Quadrat|Meter|Uhr|Jahr|Schuljahr|Seite))'), lambda match: ' '),
(re.compile(r'(?<=\d\.)(?=(Femto|Piko|Nano|Mikro|Milli|Zenti|Dezi|Hekto|Kilo|Mega|Giga|Tera|Peta|Tausend|Trilli|Kubik|Quadrat|Meter|Uhr|Jahr|Schuljahr|Seite))'), lambda match: ' '),
# fix wrong spaces
(re.compile(r'(?<=<p class="absatz">[A-ZÄÖÜ]) (?=[a-zäöü\-])'), lambda match: ''), # at beginning of paragraphs
(re.compile(u' \u00AB'), lambda match: u'\u00AB '), # before closing quotation
(re.compile(u'\u00BB '), lambda match: u' \u00BB'), # after opening quotation
# filtering for spaces in large numbers for better readability
(re.compile(r'(?<=\d\d)(?=\d\d\d[ ,\.;\)<\?!-])'), lambda match: u'\u2008'), # end of the number with some character following
(re.compile(r'(?<=\d\d)(?=\d\d\d. )'), lambda match: u'\u2008'), # end of the number with full-stop following, then space is necessary (avoid file names)
(re.compile(u'(?<=\d)(?=\d\d\d\u2008)'), lambda match: u'\u2008'), # next level
(re.compile(u'(?<=\d)(?=\d\d\d\u2008)'), lambda match: u'\u2008'), # next level
(re.compile(u'(?<=\d)(?=\d\d\d\u2008)'), lambda match: u'\u2008'), # next level
(re.compile(u'(?<=\d)(?=\d\d\d\u2008)'), lambda match: u'\u2008'), # next level
# filtering for unicode characters that are missing on the Kindle,
# try to replace them with meaningful work-arounds
(re.compile(u'\u2080'), lambda match: '<span style="font-size: 50%;">0</span>'), # subscript-0
(re.compile(u'\u2081'), lambda match: '<span style="font-size: 50%;">1</span>'), # subscript-1
(re.compile(u'\u2082'), lambda match: '<span style="font-size: 50%;">2</span>'), # subscript-2
(re.compile(u'\u2083'), lambda match: '<span style="font-size: 50%;">3</span>'), # subscript-3
(re.compile(u'\u2084'), lambda match: '<span style="font-size: 50%;">4</span>'), # subscript-4
(re.compile(u'\u2085'), lambda match: '<span style="font-size: 50%;">5</span>'), # subscript-5
(re.compile(u'\u2086'), lambda match: '<span style="font-size: 50%;">6</span>'), # subscript-6
(re.compile(u'\u2087'), lambda match: '<span style="font-size: 50%;">7</span>'), # subscript-7
(re.compile(u'\u2088'), lambda match: '<span style="font-size: 50%;">8</span>'), # subscript-8
(re.compile(u'\u2089'), lambda match: '<span style="font-size: 50%;">9</span>'), # subscript-9
(re.compile(u'\u2080'), lambda match: '<span style="font-size: 40%;">0</span>'), # subscript-0
(re.compile(u'\u2081'), lambda match: '<span style="font-size: 40%;">1</span>'), # subscript-1
(re.compile(u'\u2082'), lambda match: '<span style="font-size: 40%;">2</span>'), # subscript-2
(re.compile(u'\u2083'), lambda match: '<span style="font-size: 40%;">3</span>'), # subscript-3
(re.compile(u'\u2084'), lambda match: '<span style="font-size: 40%;">4</span>'), # subscript-4
(re.compile(u'\u2085'), lambda match: '<span style="font-size: 40%;">5</span>'), # subscript-5
(re.compile(u'\u2086'), lambda match: '<span style="font-size: 40%;">6</span>'), # subscript-6
(re.compile(u'\u2087'), lambda match: '<span style="font-size: 40%;">7</span>'), # subscript-7
(re.compile(u'\u2088'), lambda match: '<span style="font-size: 40%;">8</span>'), # subscript-8
(re.compile(u'\u2089'), lambda match: '<span style="font-size: 40%;">9</span>'), # subscript-9
# always chance CO2
(re.compile(r'CO2'), lambda match: 'CO<span style="font-size: 40%;">2</span>'), # CO2
# remove *** paragraphs
(re.compile(r'<p class="absatz">\*\*\*</p>'), lambda match: ''),
# better layout for the top line of each article
(re.compile(u'(?<=DIE ZEIT N\u00B0 \d /) (?=\d\d)'), lambda match: ' 20'), # proper year in edition number
(re.compile(u'(?<=DIE ZEIT N\u00B0 \d\d /) (?=\d\d)'), lambda match: ' 20'), # proper year in edition number
(re.compile(u'(?<=>)(?=DIE ZEIT N\u00B0 \d\d / 20\d\d)'), lambda match: u' \u2014 '), # m-dash between category and DIE ZEIT
]
def build_index(self):
domain = "http://premium.zeit.de"
url = domain + "/abovorteile/cgi-bin/_er_member/p4z.fpl?ER_Do=getUserData&ER_NextTemplate=login_ok"
domain = "https://premium.zeit.de"
url = domain + "/abo/zeit_digital"
browser = self.get_browser()
browser.add_password("http://premium.zeit.de", self.username, self.password)
try:
browser.open(url)
except urllib2.HTTPError:
self.report_progress(0,_("Can't login to download issue"))
raise ValueError('Failed to login, check your username and password')
response = browser.follow_link(text="DIE ZEIT als E-Paper")
response = browser.follow_link(url_regex=re.compile('^http://contentserver.hgv-online.de/nodrm/fulfillment\\?distributor=zeit-online&orderid=zeit_online.*'))
# new login process
response = browser.open(url)
browser.select_form(nr=2)
browser.form['name']=self.username
browser.form['pass']=self.password
browser.submit()
# now find the correct file, we will still use the ePub file
epublink = browser.find_link(text_regex=re.compile('.*Ausgabe als Datei im ePub-Format.*'))
response = browser.follow_link(epublink)
self.report_progress(1,_('next step'))
tmp = PersistentTemporaryFile(suffix='.epub')
self.report_progress(0,_('downloading epub'))
@ -104,9 +170,45 @@ class ZeitEPUBAbo(BasicNewsRecipe):
# getting url of the cover
def get_cover_url(self):
self.log.warning('Downloading cover')
try:
inhalt = self.index_to_soup('http://www.zeit.de/inhalt')
cover_url = inhalt.find('div', attrs={'class':'singlearchive clearfix'}).img['src'].replace('icon_','')
self.log.warning('Trying PDF-based cover')
domain = "https://premium.zeit.de"
url = domain + "/abo/zeit_digital"
browser = self.get_browser()
# new login process
browser.open(url)
browser.select_form(nr=2)
browser.form['name']=self.username
browser.form['pass']=self.password
browser.submit()
# actual cover search
pdflink = browser.find_link(url_regex=re.compile('system/files/epaper/DZ/pdf/DZ_ePaper*'))
cover_url = urlparse(pdflink.base_url)[0]+'://'+urlparse(pdflink.base_url)[1]+''+(urlparse(pdflink.url)[2]).replace('ePaper_','').replace('.pdf','_001.pdf')
self.log.warning('PDF link found:')
self.log.warning(cover_url)
# download the cover (has to be here due to new login process)
with closing(browser.open(cover_url)) as r:
cdata = r.read()
from calibre.ebooks.metadata.pdf import get_metadata
stream = cStringIO.StringIO(cdata)
cdata = None
mi = get_metadata(stream)
if mi.cover_data and mi.cover_data[1]:
cdata = mi.cover_data[1]
cpath = os.path.join(self.output_dir, 'cover.jpg')
save_cover_data_to(cdata, cpath)
cover_url = cpath
except:
cover_url = 'http://images.zeit.de/bilder/titelseiten_zeit/1946/001_001.jpg'
self.log.warning('Trying low-res cover')
try:
inhalt = self.index_to_soup('http://www.zeit.de/inhalt')
cover_url = inhalt.find('div', attrs={'class':'singlearchive clearfix'}).img['src'].replace('icon_','')
except:
self.log.warning('Using static old low-res cover')
cover_url = 'http://images.zeit.de/bilder/titelseiten_zeit/1946/001_001.jpg'
return cover_url

View File

@ -11,6 +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="{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>

View File

@ -11,7 +11,7 @@ defaults.
'''
#: Auto increment series index
# The algorithm used to assign a new book in an existing series a series number.
# The algorithm used to assign a book added to an existing series a series number.
# New series numbers assigned using this tweak are always integer values, except
# if a constant non-integer is specified.
# Possible values are:
@ -27,7 +27,19 @@ defaults.
# series_index_auto_increment = 'next'
# series_index_auto_increment = 'next_free'
# series_index_auto_increment = 16.5
#
# Set the use_series_auto_increment_tweak_when_importing tweak to True to
# use the above values when importing/adding books. If this tweak is set to
# False (the default) then the series number will be set to 1 if it is not
# explicitly set to during the import. If set to True, then the
# series index will be set according to the series_index_auto_increment setting.
# Note that the use_series_auto_increment_tweak_when_importing tweak is used
# only when a value is not provided during import. If the importing regular
# expression produces a value for series_index, or if you are reading metadata
# from books and the import plugin produces a value, than that value will
# be used irrespective of the setting of the tweak.
series_index_auto_increment = 'next'
use_series_auto_increment_tweak_when_importing = False
#: Add separator after completing an author name
# Should the completion separator be append
@ -167,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+'
@ -366,3 +381,10 @@ server_listen_on = '0.0.0.0'
# on at your own risk!
unified_title_toolbar_on_osx = False
#: Save original file when converting from same format to same format
# When calibre does a conversion from the same format to the same format, for
# example, from EPUB to EPUB, the original file is saved, so that in case the
# conversion is poor, you can tweak the settings and run it again. By setting
# this to False you can prevent calibre from saving the original file.
save_original_format = True

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
resources/images/random.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -379,7 +379,8 @@
<!-- image -->
<xsl:template match="fb:image">
<div align="center">
<img border="1">
<xsl:element name="img">
<xsl:attribute name="border">1</xsl:attribute>
<xsl:choose>
<xsl:when test="starts-with(@xlink:href,'#')">
<xsl:attribute name="src"><xsl:value-of select="substring-after(@xlink:href,'#')"/></xsl:attribute>
@ -388,7 +389,10 @@
<xsl:attribute name="src"><xsl:value-of select="@xlink:href"/></xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</img>
<xsl:if test="@title">
<xsl:attribute name="title"><xsl:value-of select="@title"/></xsl:attribute>
</xsl:if>
</xsl:element>
</div>
</xsl:template>
</xsl:stylesheet>

View File

@ -1,5 +1,5 @@
" Project wide builtins
let g:pyflakes_builtins += ["dynamic_property", "__", "P", "I", "lopen", "icu_lower", "icu_upper", "icu_title"]
let g:pyflakes_builtins = ["_", "dynamic_property", "__", "P", "I", "lopen", "icu_lower", "icu_upper", "icu_title", "ngettext"]
python << EOFPY
import os
@ -15,9 +15,11 @@ vipy.session.initialize(project_name='calibre', src_dir=src_dir,
project_dir=project_dir, base_dir=base_dir)
def recipe_title_callback(raw):
return eval(raw.decode('utf-8'))
return eval(raw.decode('utf-8')).replace(' ', '_')
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>

View File

@ -25,18 +25,11 @@ class Message:
return '%s:%s: %s'%(self.filename, self.lineno, self.msg)
def check_for_python_errors(code_string, filename):
# Since compiler.parse does not reliably report syntax errors, use the
# built in compiler first to detect those.
import _ast
# First, compile into an AST and handle syntax errors.
try:
try:
compile(code_string, filename, "exec")
except MemoryError:
# Python 2.4 will raise MemoryError if the source can't be
# decoded.
if sys.version_info[:2] == (2, 4):
raise SyntaxError(None)
raise
except (SyntaxError, IndentationError), value:
tree = compile(code_string, filename, "exec", _ast.PyCF_ONLY_AST)
except (SyntaxError, IndentationError) as value:
msg = value.args[0]
(lineno, offset, text) = value.lineno, value.offset, value.text
@ -47,13 +40,11 @@ def check_for_python_errors(code_string, filename):
# bogus message that claims the encoding the file declared was
# unknown.
msg = "%s: problem decoding source" % filename
return [Message(filename, lineno, msg)]
else:
# Okay, it's syntactically valid. Now parse it into an ast and check
# it.
import compiler
checker = __import__('pyflakes.checker').checker
tree = compiler.parse(code_string)
# Okay, it's syntactically valid. Now check it.
w = checker.Checker(tree, filename)
w.messages.sort(lambda a, b: cmp(a.lineno, b.lineno))
return [Message(x.filename, x.lineno, x.message%x.message_args) for x in
@ -64,7 +55,7 @@ class Check(Command):
description = 'Check for errors in the calibre source code'
BUILTINS = ['_', '__', 'dynamic_property', 'I', 'P', 'lopen', 'icu_lower',
'icu_upper', 'icu_title']
'icu_upper', 'icu_title', 'ngettext']
CACHE = '.check-cache.pickle'
def get_files(self, cache):

View File

@ -373,7 +373,7 @@ class Win32Freeze(Command, WixMixIn):
src = self.j(self.src_root, 'setup', 'installer', 'windows',
'portable.c')
obj = self.j(self.obj_dir, self.b(src)+'.obj')
cflags = '/c /EHsc /MT /W3 /Ox /nologo /D_UNICODE'.split()
cflags = '/c /EHsc /MT /W3 /Ox /nologo /D_UNICODE /DUNICODE'.split()
if self.newer(obj, [src]):
self.info('Compiling', obj)
@ -386,6 +386,7 @@ class Win32Freeze(Command, WixMixIn):
cmd = [msvc.linker] + ['/INCREMENTAL:NO', '/MACHINE:X86',
'/LIBPATH:'+self.obj_dir, '/SUBSYSTEM:WINDOWS',
'/RELEASE',
'/ENTRY:wWinMainCRTStartup',
'/OUT:'+exe, self.embed_resources(exe),
obj, 'User32.lib']
self.run_builder(cmd)

View File

@ -2,15 +2,21 @@
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#include <windows.h>
#include <tchar.h>
#include <wchar.h>
#include <stdio.h>
#define BUFSIZE 4096
void show_error(LPCTSTR msg) {
MessageBeep(MB_ICONERROR);
MessageBox(NULL, msg, TEXT("Error"), MB_OK|MB_ICONERROR);
MessageBox(NULL, msg, _T("Error"), MB_OK|MB_ICONERROR);
}
void show_detailed_error(LPCTSTR preamble, LPCTSTR msg, int code) {
@ -20,7 +26,7 @@ void show_detailed_error(LPCTSTR preamble, LPCTSTR msg, int code) {
_sntprintf_s(buf,
LocalSize(buf) / sizeof(TCHAR), _TRUNCATE,
TEXT("%s\r\n %s (Error Code: %d)\r\n"),
_T("%s\r\n %s (Error Code: %d)\r\n"),
preamble, msg, code);
show_error(buf);
@ -32,7 +38,7 @@ void show_last_error_crt(LPCTSTR preamble) {
int err = 0;
_get_errno(&err);
_wcserror_s(buf, BUFSIZE, err);
_tcserror_s(buf, BUFSIZE, err);
show_detailed_error(preamble, buf, err);
}
@ -57,7 +63,7 @@ void show_last_error(LPCTSTR preamble) {
LPTSTR get_app_dir() {
LPTSTR buf, buf2, buf3;
DWORD sz;
TCHAR drive[4] = TEXT("\0\0\0");
TCHAR drive[4] = _T("\0\0\0");
errno_t err;
buf = (LPTSTR)calloc(BUFSIZE, sizeof(TCHAR));
@ -67,18 +73,18 @@ LPTSTR get_app_dir() {
sz = GetModuleFileName(NULL, buf, BUFSIZE);
if (sz == 0 || sz > BUFSIZE-1) {
show_error(TEXT("Failed to get path to calibre-portable.exe"));
show_error(_T("Failed to get path to calibre-portable.exe"));
ExitProcess(1);
}
err = _tsplitpath_s(buf, drive, 4, buf2, BUFSIZE, NULL, 0, NULL, 0);
if (err != 0) {
show_last_error_crt(TEXT("Failed to split path to calibre-portable.exe"));
show_last_error_crt(_T("Failed to split path to calibre-portable.exe"));
ExitProcess(1);
}
_sntprintf_s(buf3, BUFSIZE-1, _TRUNCATE, TEXT("%s%s"), drive, buf2);
_sntprintf_s(buf3, BUFSIZE-1, _TRUNCATE, _T("%s%s"), drive, buf2);
free(buf); free(buf2);
return buf3;
}
@ -90,18 +96,18 @@ void launch_calibre(LPCTSTR exe, LPCTSTR config_dir, LPCTSTR library_dir) {
BOOL fSuccess;
TCHAR cmdline[BUFSIZE];
if (! SetEnvironmentVariable(TEXT("CALIBRE_CONFIG_DIRECTORY"), config_dir)) {
show_last_error(TEXT("Failed to set environment variables"));
if (! SetEnvironmentVariable(_T("CALIBRE_CONFIG_DIRECTORY"), config_dir)) {
show_last_error(_T("Failed to set environment variables"));
ExitProcess(1);
}
if (! SetEnvironmentVariable(TEXT("CALIBRE_PORTABLE_BUILD"), exe)) {
show_last_error(TEXT("Failed to set environment variables"));
if (! SetEnvironmentVariable(_T("CALIBRE_PORTABLE_BUILD"), exe)) {
show_last_error(_T("Failed to set environment variables"));
ExitProcess(1);
}
dwFlags = CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP;
_sntprintf_s(cmdline, BUFSIZE, _TRUNCATE, TEXT(" \"--with-library=%s\""), library_dir);
_sntprintf_s(cmdline, BUFSIZE, _TRUNCATE, _T(" \"--with-library=%s\""), library_dir);
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
@ -119,7 +125,7 @@ void launch_calibre(LPCTSTR exe, LPCTSTR config_dir, LPCTSTR library_dir) {
);
if (fSuccess == 0) {
show_last_error(TEXT("Failed to launch the calibre program"));
show_last_error(_T("Failed to launch the calibre program"));
}
// Close process and thread handles.
@ -137,9 +143,9 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
library_dir = (LPTSTR)calloc(BUFSIZE, sizeof(TCHAR));
exe = (LPTSTR)calloc(BUFSIZE, sizeof(TCHAR));
_sntprintf_s(config_dir, BUFSIZE, _TRUNCATE, TEXT("%sCalibre Settings"), app_dir);
_sntprintf_s(exe, BUFSIZE, _TRUNCATE, TEXT("%sCalibre\\calibre.exe"), app_dir);
_sntprintf_s(library_dir, BUFSIZE, _TRUNCATE, TEXT("%sCalibre Library"), app_dir);
_sntprintf_s(config_dir, BUFSIZE, _TRUNCATE, _T("%sCalibre Settings"), app_dir);
_sntprintf_s(exe, BUFSIZE, _TRUNCATE, _T("%sCalibre\\calibre.exe"), app_dir);
_sntprintf_s(library_dir, BUFSIZE, _TRUNCATE, _T("%sCalibre Library"), app_dir);
launch_calibre(exe, config_dir, library_dir);

2169
setup/iso639.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,646 +0,0 @@
#! /usr/bin/env python
# Originally written by Barry Warsaw <barry@zope.com>
#
# Minimally patched to make it even more xgettext compatible
# by Peter Funk <pf@artcom-gmbh.de>
#
# 2002-11-22 Jrgen Hermann <jh@web.de>
# Added checks that _() only contains string literals, and
# command line args are resolved to module lists, i.e. you
# can now pass a filename, a module or package name, or a
# directory (including globbing chars, important for Win32).
# Made docstring fit in 80 chars wide displays using pydoc.
#
__doc__ = """pygettext -- Python equivalent of xgettext(1)
Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the
internationalization of C programs. Most of these tools are independent of
the programming language and can be used from within Python programs.
Martin von Loewis' work[1] helps considerably in this regard.
There's one problem though; xgettext is the program that scans source code
looking for message strings, but it groks only C (or C++). Python
introduces a few wrinkles, such as dual quoting characters, triple quoted
strings, and raw strings. xgettext understands none of this.
Enter pygettext, which uses Python's standard tokenize module to scan
Python source code, generating .pot files identical to what GNU xgettext[2]
generates for C and C++ code. From there, the standard GNU tools can be
used.
A word about marking Python strings as candidates for translation. GNU
xgettext recognizes the following keywords: gettext, dgettext, dcgettext,
and gettext_noop. But those can be a lot of text to include all over your
code. C and C++ have a trick: they use the C preprocessor. Most
internationalized C source includes a #define for gettext() to _() so that
what has to be written in the source is much less. Thus these are both
translatable strings:
gettext("Translatable String")
_("Translatable String")
Python of course has no preprocessor so this doesn't work so well. Thus,
pygettext searches only for _() by default, but see the -k/--keyword flag
below for how to augment this.
[1] http://www.python.org/workshops/1997-10/proceedings/loewis.html
[2] http://www.gnu.org/software/gettext/gettext.html
NOTE: pygettext attempts to be option and feature compatible with GNU
xgettext where ever possible. However some options are still missing or are
not fully implemented. Also, xgettext's use of command line switches with
option arguments is broken, and in these cases, pygettext just defines
additional switches.
Usage: pygettext [options] inputfile ...
Options:
-a
--extract-all
Extract all strings.
-d name
--default-domain=name
Rename the default output file from messages.pot to name.pot.
-E
--escape
Replace non-ASCII characters with octal escape sequences.
-D
--docstrings
Extract module, class, method, and function docstrings. These do
not need to be wrapped in _() markers, and in fact cannot be for
Python to consider them docstrings. (See also the -X option).
-h
--help
Print this help message and exit.
-k word
--keyword=word
Keywords to look for in addition to the default set, which are:
%(DEFAULTKEYWORDS)s
You can have multiple -k flags on the command line.
-K
--no-default-keywords
Disable the default set of keywords (see above). Any keywords
explicitly added with the -k/--keyword option are still recognized.
--no-location
Do not write filename/lineno location comments.
-n
--add-location
Write filename/lineno location comments indicating where each
extracted string is found in the source. These lines appear before
each msgid. The style of comments is controlled by the -S/--style
option. This is the default.
-o filename
--output=filename
Rename the default output file from messages.pot to filename. If
filename is `-' then the output is sent to standard out.
-p dir
--output-dir=dir
Output files will be placed in directory dir.
-S stylename
--style stylename
Specify which style to use for location comments. Two styles are
supported:
Solaris # File: filename, line: line-number
GNU #: filename:line
The style name is case insensitive. GNU style is the default.
-v
--verbose
Print the names of the files being processed.
-V
--version
Print the version of pygettext and exit.
-w columns
--width=columns
Set width of output to columns.
-x filename
--exclude-file=filename
Specify a file that contains a list of strings that are not be
extracted from the input files. Each string to be excluded must
appear on a line by itself in the file.
-X filename
--no-docstrings=filename
Specify a file that contains a list of files (one per line) that
should not have their docstrings extracted. This is only useful in
conjunction with the -D option above.
If `inputfile' is -, standard input is read.
"""
import os
import imp
import sys
import glob
import time
import getopt
import token
import tokenize
import operator
__version__ = '1.5'
default_keywords = ['_']
DEFAULTKEYWORDS = ', '.join(default_keywords)
EMPTYSTRING = ''
from setup import __appname__, __version__ as version
# The normal pot-file header. msgmerge and Emacs's po-mode work better if it's
# there.
pot_header = '''\
# Translation template file..
# Copyright (C) %(year)s Kovid Goyal
# Kovid Goyal <kovid@kovidgoyal.net>, %(year)s.
#
msgid ""
msgstr ""
"Project-Id-Version: %(appname)s %(version)s\\n"
"POT-Creation-Date: %%(time)s\\n"
"PO-Revision-Date: %%(time)s\\n"
"Last-Translator: Automatically generated\\n"
"Language-Team: LANGUAGE\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Generated-By: pygettext.py %%(version)s\\n"
'''%dict(appname=__appname__, version=version, year=time.strftime('%Y'))
def usage(code, msg=''):
print >> sys.stderr, __doc__ % globals()
if msg:
print >> sys.stderr, msg
sys.exit(code)
escapes = []
def make_escapes(pass_iso8859):
global escapes
if pass_iso8859:
# Allow iso-8859 characters to pass through so that e.g. 'msgid
# would result not result in 'msgid "H\366he"'. Otherwise we
# escape any character outside the 32..126 range.
mod = 128
else:
mod = 256
for i in range(256):
if 32 <= (i % mod) <= 126:
escapes.append(chr(i))
else:
escapes.append("\\%03o" % i)
escapes[ord('\\')] = '\\\\'
escapes[ord('\t')] = '\\t'
escapes[ord('\r')] = '\\r'
escapes[ord('\n')] = '\\n'
escapes[ord('\"')] = '\\"'
def escape(s):
global escapes
s = list(s)
for i in range(len(s)):
s[i] = escapes[ord(s[i])]
return EMPTYSTRING.join(s)
def safe_eval(s):
# unwrap quotes, safely
return eval(s, {'__builtins__':{}}, {})
def normalize(s):
# This converts the various Python string types into a format that is
# appropriate for .po files, namely much closer to C style.
lines = s.split('\n')
if len(lines) == 1:
s = '"' + escape(s) + '"'
else:
if not lines[-1]:
del lines[-1]
lines[-1] = lines[-1] + '\n'
for i in range(len(lines)):
lines[i] = escape(lines[i])
lineterm = '\\n"\n"'
s = '""\n"' + lineterm.join(lines) + '"'
return s
def containsAny(str, set):
"""Check whether 'str' contains ANY of the chars in 'set'"""
return 1 in [c in str for c in set]
def _visit_pyfiles(list, dirname, names):
"""Helper for getFilesForName()."""
# get extension for python source files
if not globals().has_key('_py_ext'):
global _py_ext
_py_ext = [triple[0] for triple in imp.get_suffixes()
if triple[2] == imp.PY_SOURCE][0]
# don't recurse into CVS directories
if 'CVS' in names:
names.remove('CVS')
# add all *.py files to list
list.extend(
[os.path.join(dirname, file) for file in names
if os.path.splitext(file)[1] == _py_ext]
)
def _get_modpkg_path(dotted_name, pathlist=None):
"""Get the filesystem path for a module or a package.
Return the file system path to a file for a module, and to a directory for
a package. Return None if the name is not found, or is a builtin or
extension module.
"""
# split off top-most name
parts = dotted_name.split('.', 1)
if len(parts) > 1:
# we have a dotted path, import top-level package
try:
file, pathname, description = imp.find_module(parts[0], pathlist)
if file: file.close()
except ImportError:
return None
# check if it's indeed a package
if description[2] == imp.PKG_DIRECTORY:
# recursively handle the remaining name parts
pathname = _get_modpkg_path(parts[1], [pathname])
else:
pathname = None
else:
# plain name
try:
file, pathname, description = imp.find_module(
dotted_name, pathlist)
if file:
file.close()
if description[2] not in [imp.PY_SOURCE, imp.PKG_DIRECTORY]:
pathname = None
except ImportError:
pathname = None
return pathname
def getFilesForName(name):
"""Get a list of module files for a filename, a module or package name,
or a directory.
"""
if not os.path.exists(name):
# check for glob chars
if containsAny(name, "*?[]"):
files = glob.glob(name)
list = []
for file in files:
list.extend(getFilesForName(file))
return list
# try to find module or package
name = _get_modpkg_path(name)
if not name:
return []
if os.path.isdir(name):
# find all python files in directory
list = []
os.path.walk(name, _visit_pyfiles, list)
return list
elif os.path.exists(name):
# a single file
return [name]
return []
class TokenEater:
def __init__(self, options):
self.__options = options
self.__messages = {}
self.__state = self.__waiting
self.__data = []
self.__lineno = -1
self.__freshmodule = 1
self.__curfile = None
def __call__(self, ttype, tstring, stup, etup, line):
# dispatch
## import token
## print >> sys.stderr, 'ttype:', token.tok_name[ttype], \
## 'tstring:', tstring
self.__state(ttype, tstring, stup[0])
def __waiting(self, ttype, tstring, lineno):
opts = self.__options
# Do docstring extractions, if enabled
if opts.docstrings and not opts.nodocstrings.get(self.__curfile):
# module docstring?
if self.__freshmodule:
if ttype == tokenize.STRING:
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
self.__freshmodule = 0
elif ttype not in (tokenize.COMMENT, tokenize.NL):
self.__freshmodule = 0
return
# class docstring?
if ttype == tokenize.NAME and tstring in ('class', 'def'):
self.__state = self.__suiteseen
return
if ttype == tokenize.NAME and tstring in opts.keywords:
self.__state = self.__keywordseen
def __suiteseen(self, ttype, tstring, lineno):
# ignore anything until we see the colon
if ttype == tokenize.OP and tstring == ':':
self.__state = self.__suitedocstring
def __suitedocstring(self, ttype, tstring, lineno):
# ignore any intervening noise
if ttype == tokenize.STRING:
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
self.__state = self.__waiting
elif ttype not in (tokenize.NEWLINE, tokenize.INDENT,
tokenize.COMMENT):
# there was no class docstring
self.__state = self.__waiting
def __keywordseen(self, ttype, tstring, lineno):
if ttype == tokenize.OP and tstring == '(':
self.__data = []
self.__lineno = lineno
self.__state = self.__openseen
else:
self.__state = self.__waiting
def __openseen(self, ttype, tstring, lineno):
if ttype == tokenize.OP and tstring == ')':
# We've seen the last of the translatable strings. Record the
# line number of the first line of the strings and update the list
# of messages seen. Reset state for the next batch. If there
# were no strings inside _(), then just ignore this entry.
if self.__data:
self.__addentry(EMPTYSTRING.join(self.__data))
self.__state = self.__waiting
elif ttype == tokenize.STRING:
self.__data.append(safe_eval(tstring))
elif ttype not in [tokenize.COMMENT, token.INDENT, token.DEDENT,
token.NEWLINE, tokenize.NL]:
# warn if we see anything else than STRING or whitespace
print >> sys.stderr, \
'*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"'\
% {
'token': tstring,
'file': self.__curfile,
'lineno': self.__lineno
}
self.__state = self.__waiting
def __addentry(self, msg, lineno=None, isdocstring=0):
if lineno is None:
lineno = self.__lineno
if not msg in self.__options.toexclude:
entry = (self.__curfile, lineno)
self.__messages.setdefault(msg, {})[entry] = isdocstring
def set_filename(self, filename):
self.__curfile = filename
self.__freshmodule = 1
def write(self, fp):
options = self.__options
timestamp = time.strftime('%Y-%m-%d %H:%M+%Z')
# The time stamp in the header doesn't have the same format as that
# generated by xgettext...
print >> fp, pot_header % {'time': timestamp, 'version': __version__}
# Sort the entries. First sort each particular entry's keys, then
# sort all the entries by their first item.
reverse = {}
for k, v in self.__messages.items():
keys = v.keys()
keys.sort()
reverse.setdefault(tuple(keys), []).append((k, v))
rkeys = reverse.keys()
rkeys.sort()
for rkey in rkeys:
rentries = reverse[rkey]
rentries.sort()
for k, v in rentries:
isdocstring = 0
# If the entry was gleaned out of a docstring, then add a
# comment stating so. This is to aid translators who may wish
# to skip translating some unimportant docstrings.
if reduce(operator.__add__, v.values()):
isdocstring = 1
# k is the message string, v is a dictionary-set of (filename,
# lineno) tuples. We want to sort the entries in v first by
# file name and then by line number.
v = v.keys()
v.sort()
if not options.writelocations:
pass
# location comments are different b/w Solaris and GNU:
elif options.locationstyle == options.SOLARIS:
for filename, lineno in v:
d = {'filename': filename, 'lineno': lineno}
print >>fp, \
'# File: %(filename)s, line: %(lineno)d' % d
elif options.locationstyle == options.GNU:
# fit as many locations on one line, as long as the
# resulting line length doesn't exceeds 'options.width'
locline = '#:'
for filename, lineno in v:
d = {'filename': filename, 'lineno': lineno}
s = ' %(filename)s:%(lineno)d' % d
if len(locline) + len(s) <= options.width:
locline = locline + s
else:
print >> fp, locline
locline = "#:" + s
if len(locline) > 2:
print >> fp, locline
if isdocstring:
print >> fp, '#, docstring'
print >> fp, 'msgid', normalize(k)
print >> fp, 'msgstr ""\n'
def main(outfile, args=sys.argv[1:]):
global default_keywords
try:
opts, args = getopt.getopt(
args,
'ad:DEhk:Kno:p:S:Vvw:x:X:',
['extract-all', 'default-domain=', 'escape', 'help',
'keyword=', 'no-default-keywords',
'add-location', 'no-location', 'output=', 'output-dir=',
'style=', 'verbose', 'version', 'width=', 'exclude-file=',
'docstrings', 'no-docstrings',
])
except getopt.error, msg:
usage(1, msg)
# for holding option values
class Options:
# constants
GNU = 1
SOLARIS = 2
# defaults
extractall = 0 # FIXME: currently this option has no effect at all.
escape = 0
keywords = []
outpath = ''
outfile = 'messages.pot'
writelocations = 1
locationstyle = GNU
verbose = 0
width = 78
excludefilename = ''
docstrings = 0
nodocstrings = {}
options = Options()
locations = {'gnu' : options.GNU,
'solaris' : options.SOLARIS,
}
# parse options
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-a', '--extract-all'):
options.extractall = 1
elif opt in ('-d', '--default-domain'):
options.outfile = arg + '.pot'
elif opt in ('-E', '--escape'):
options.escape = 1
elif opt in ('-D', '--docstrings'):
options.docstrings = 1
elif opt in ('-k', '--keyword'):
options.keywords.append(arg)
elif opt in ('-K', '--no-default-keywords'):
default_keywords = []
elif opt in ('-n', '--add-location'):
options.writelocations = 1
elif opt in ('--no-location',):
options.writelocations = 0
elif opt in ('-S', '--style'):
options.locationstyle = locations.get(arg.lower())
if options.locationstyle is None:
usage(1, ('Invalid value for --style: %s') % arg)
elif opt in ('-o', '--output'):
options.outfile = arg
elif opt in ('-p', '--output-dir'):
options.outpath = arg
elif opt in ('-v', '--verbose'):
options.verbose = 1
elif opt in ('-V', '--version'):
print ('pygettext.py (xgettext for Python) %s') % __version__
sys.exit(0)
elif opt in ('-w', '--width'):
try:
options.width = int(arg)
except ValueError:
usage(1, ('--width argument must be an integer: %s') % arg)
elif opt in ('-x', '--exclude-file'):
options.excludefilename = arg
elif opt in ('-X', '--no-docstrings'):
fp = open(arg)
try:
while 1:
line = fp.readline()
if not line:
break
options.nodocstrings[line[:-1]] = 1
finally:
fp.close()
# calculate escapes
make_escapes(options.escape)
# calculate all keywords
options.keywords.extend(default_keywords)
# initialize list of strings to exclude
if options.excludefilename:
try:
fp = open(options.excludefilename)
options.toexclude = fp.readlines()
fp.close()
except IOError:
print >> sys.stderr, (
"Can't read --exclude-file: %s") % options.excludefilename
sys.exit(1)
else:
options.toexclude = []
# resolve args to module lists
expanded = []
for arg in args:
if arg == '-':
expanded.append(arg)
else:
expanded.extend(getFilesForName(arg))
args = expanded
# slurp through all the files
eater = TokenEater(options)
for filename in args:
if filename == '-':
if options.verbose:
print ('Reading standard input')
fp = sys.stdin
closep = 0
else:
if options.verbose:
print ('Working on %s') % filename
fp = open(filename)
closep = 1
try:
eater.set_filename(filename)
try:
tokenize.tokenize(fp.readline, eater)
except tokenize.TokenError, e:
print >> sys.stderr, '%s: %s, line %d, column %d' % (
e[0], filename, e[1][0], e[1][1])
except IndentationError, e:
print >> sys.stderr, '%s: %s, line %s, column %s' % (
e[0], filename, e.lineno, e[1][1])
finally:
if closep:
fp.close()
# write the output
eater.write(outfile)
if __name__ == '__main__':
main(sys.stdout)

View File

@ -205,8 +205,8 @@ class Resources(Command):
dest = self.j(self.RESOURCES, 'template-functions.json')
function_dict = {}
import inspect
from calibre.utils.formatter_functions import all_builtin_functions
for obj in all_builtin_functions:
from calibre.utils.formatter_functions import formatter_functions
for obj in formatter_functions.get_builtins().values():
eval_func = inspect.getmembers(obj,
lambda x: inspect.ismethod(x) and x.__name__ == 'evaluate')
try:

View File

@ -6,14 +6,20 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os, cStringIO, tempfile, shutil, atexit, subprocess, glob, re
import os, tempfile, shutil, subprocess, glob, re, time, textwrap
from distutils import sysconfig
from functools import partial
from setup import Command, __appname__
from setup.pygettext import main as pygettext
from setup.build_environment import pyqt
from setup import Command, __appname__, __version__
class POT(Command):
def qt_sources():
qtdir = glob.glob('/usr/src/qt-*')[-1]
j = partial(os.path.join, qtdir)
return list(map(j, [
'src/gui/widgets/qdialogbuttonbox.cpp',
]))
class POT(Command): # {{{
description = 'Update the .pot translation template'
PATH = os.path.join(Command.SRC, __appname__, 'translations')
@ -60,22 +66,63 @@ class POT(Command):
def run(self, opts):
pot_header = textwrap.dedent('''\
# Translation template file..
# Copyright (C) %(year)s Kovid Goyal
# Kovid Goyal <kovid@kovidgoyal.net>, %(year)s.
#
msgid ""
msgstr ""
"Project-Id-Version: %(appname)s %(version)s\\n"
"POT-Creation-Date: %(time)s\\n"
"PO-Revision-Date: %(time)s\\n"
"Last-Translator: Automatically generated\\n"
"Language-Team: LANGUAGE\\n"
"MIME-Version: 1.0\\n"
"Report-Msgid-Bugs-To: https://bugs.launchpad.net/calibre\\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
''')%dict(appname=__appname__, version=__version__,
year=time.strftime('%Y'),
time=time.strftime('%Y-%m-%d %H:%M+%Z'))
files = self.source_files()
buf = cStringIO.StringIO()
self.info('Creating translations template...')
tempdir = tempfile.mkdtemp()
atexit.register(shutil.rmtree, tempdir)
pygettext(buf, ['-k', '__', '-p', tempdir]+files)
src = buf.getvalue()
src += '\n\n' + self.get_tweaks_docs()
pot = os.path.join(self.PATH, __appname__+'.pot')
with open(pot, 'wb') as f:
f.write(src)
self.info('Translations template:', os.path.abspath(pot))
qt_inputs = qt_sources()
with tempfile.NamedTemporaryFile() as fl:
fl.write('\n'.join(files))
fl.flush()
out = tempfile.NamedTemporaryFile(suffix='.pot', delete=False)
out.close()
self.info('Creating translations template...')
subprocess.check_call(['xgettext', '-f', fl.name,
'--default-domain=calibre', '-o', out.name, '-L', 'Python',
'--from-code=UTF-8', '--sort-by-file', '--omit-header',
'--no-wrap', '-k__', '--add-comments=NOTE:',
])
subprocess.check_call(['xgettext', '-j',
'--default-domain=calibre', '-o', out.name,
'--from-code=UTF-8', '--sort-by-file', '--omit-header',
'--no-wrap', '-kQT_TRANSLATE_NOOP:2',
] + qt_inputs)
with open(out.name, 'rb') as f:
src = f.read()
os.remove(out.name)
src = pot_header + '\n' + src
src += '\n\n' + self.get_tweaks_docs()
pot = os.path.join(self.PATH, __appname__+'.pot')
with open(pot, 'wb') as f:
f.write(src)
self.info('Translations template:', os.path.abspath(pot))
return pot
# }}}
class Translations(POT):
class Translations(POT): # {{{
description='''Compile the translations'''
DEST = os.path.join(os.path.dirname(POT.SRC), 'resources', 'localization',
'locales')
@ -87,7 +134,6 @@ class Translations(POT):
locale = os.path.splitext(os.path.basename(po_file))[0]
return locale, os.path.join(self.DEST, locale, 'messages.mo')
def run(self, opts):
for f in self.po_files():
locale, dest = self.mo_file(f)
@ -96,7 +142,7 @@ class Translations(POT):
os.makedirs(base)
self.info('\tCompiling translations for', locale)
subprocess.check_call(['msgfmt', '-o', dest, f])
if locale in ('en_GB', 'nds', 'te', 'yi'):
if locale in ('en_GB', 'en_CA', 'en_AU', 'si', 'ur', 'sc', 'ltg', 'nds', 'te', 'yi'):
continue
pycountry = self.j(sysconfig.get_python_lib(), 'pycountry',
'locales', locale, 'LC_MESSAGES')
@ -110,17 +156,6 @@ class Translations(POT):
self.warn('No ISO 639 translations for locale:', locale,
'\nDo you have pycountry installed?')
base = os.path.join(pyqt.qt_data_dir, 'translations')
qt_translations = glob.glob(os.path.join(base, 'qt_*.qm'))
if not qt_translations:
raise Exception('Could not find qt translations')
for f in qt_translations:
locale = self.s(self.b(f))[0][3:]
dest = self.j(self.DEST, locale, 'LC_MESSAGES', 'qt.qm')
if self.e(self.d(dest)) and self.newer(dest, f):
self.info('\tCopying Qt translation for locale:', locale)
shutil.copy2(f, dest)
self.write_stats()
self.freeze_locales()
@ -171,7 +206,7 @@ class Translations(POT):
for x in (i, j, d):
if os.path.exists(x):
os.remove(x)
# }}}
class GetTranslations(Translations):
@ -238,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',
@ -255,20 +289,36 @@ 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'))
base_name = name.lower()
nm[base_name] = threet
simple_name = base_name.partition(';')[0].strip()
if simple_name not in nm:
nm[simple_name] = 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)

View File

@ -341,7 +341,7 @@ def random_user_agent():
def browser(honor_time=True, max_time=2, mobile_browser=False, user_agent=None):
'''
Create a mechanize browser for web scraping. The browser handles cookies,
refresh requests and ignores robots.txt. Also uses proxy if avaialable.
refresh requests and ignores robots.txt. Also uses proxy if available.
:param honor_time: If True honors pause time in refresh requests
:param max_time: Maximum time in seconds to wait during a refresh request
@ -353,9 +353,14 @@ def browser(honor_time=True, max_time=2, mobile_browser=False, user_agent=None):
if user_agent is None:
user_agent = USER_AGENT_MOBILE if mobile_browser else USER_AGENT
opener.addheaders = [('User-agent', user_agent)]
http_proxy = get_proxies().get('http', None)
proxies = get_proxies()
http_proxy = proxies.get('http', None)
if http_proxy:
opener.set_proxies({'http':http_proxy})
https_proxy = proxies.get('https', None)
if https_proxy:
opener.set_proxies({'https':https_proxy})
return opener
def fit_image(width, height, pwidth, pheight):
@ -474,7 +479,7 @@ def strftime(fmt, t=None):
def my_unichr(num):
try:
return unichr(num)
except ValueError:
except (ValueError, OverflowError):
return u'?'
def entity_to_unicode(match, exceptions=[], encoding='cp1252',

View File

@ -4,7 +4,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
__appname__ = u'calibre'
numeric_version = (0, 8, 9)
numeric_version = (0, 8, 14)
__version__ = u'.'.join(map(unicode, numeric_version))
__author__ = u"Kovid Goyal <kovid@kovidgoyal.net>"

View File

@ -570,7 +570,7 @@ from calibre.devices.teclast.driver import (TECLAST_K3, NEWSMY, IPAPYRUS,
from calibre.devices.sne.driver import SNE
from calibre.devices.misc import (PALMPRE, AVANT, SWEEX, PDNOVEL,
GEMEI, VELOCITYMICRO, PDNOVEL_KOBO, LUMIREAD, ALURATEK_COLOR,
TREKSTOR, EEEREADER, NEXTBOOK, ADAM, MOOVYBOOK)
TREKSTOR, EEEREADER, NEXTBOOK, ADAM, MOOVYBOOK, COBY)
from calibre.devices.folder_device.driver import FOLDER_DEVICE_FOR_CONFIG
from calibre.devices.kobo.driver import KOBO
from calibre.devices.bambook.driver import BAMBOOK
@ -705,7 +705,7 @@ plugins += [
EEEREADER,
NEXTBOOK,
ADAM,
MOOVYBOOK,
MOOVYBOOK, COBY,
ITUNES,
BOEYE_BEX,
BOEYE_BDX,
@ -843,6 +843,12 @@ class ActionNextMatch(InterfaceActionBase):
description = _('Find the next or previous match when searching in '
'your calibre library in highlight mode')
class ActionPickRandom(InterfaceActionBase):
name = 'Pick Random Book'
actual_plugin = 'calibre.gui2.actions.random:PickRandomAction'
description = _('Choose a random book from your calibre library')
class ActionStore(InterfaceActionBase):
name = 'Store'
author = 'John Schember'
@ -873,7 +879,7 @@ plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog,
ActionSendToDevice, ActionHelp, ActionPreferences, ActionSimilarBooks,
ActionAddToLibrary, ActionEditCollections, ActionChooseLibrary,
ActionCopyToLibrary, ActionTweakEpub, ActionNextMatch, ActionStore,
ActionPluginUpdater]
ActionPluginUpdater, ActionPickRandom]
# }}}
@ -1023,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')
@ -1086,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')
@ -1100,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]
#}}}
@ -1181,6 +1198,26 @@ class StoreBeWriteStore(StoreBase):
headquarters = 'US'
formats = ['EPUB', 'MOBI', 'PDF']
class StoreBookotekaStore(StoreBase):
name = 'Bookoteka'
author = u'Tomasz Długosz'
description = u'E-booki w Bookotece dostępne są w formacie EPUB oraz PDF. Publikacje sprzedawane w Bookotece są objęte prawami autorskimi. Zobowiązaliśmy się chronić te prawa, ale bez ograniczania dostępu do książki użytkownikowi, który nabył ją w legalny sposób. Dlatego też Bookoteka stosuje tak zwany „watermarking transakcyjny” czyli swego rodzaju znaki wodne.'
actual_plugin = 'calibre.gui2.store.stores.bookoteka_plugin:BookotekaStore'
drm_free_only = True
headquarters = 'PL'
formats = ['EPUB', 'PDF']
class StoreChitankaStore(StoreBase):
name = u'Моята библиотека'
author = 'Alex Stanev'
description = u'Независим сайт за DRM свободна литература на български език'
actual_plugin = 'calibre.gui2.store.stores.chitanka_plugin:ChitankaStore'
drm_free_only = True
headquarters = 'BG'
formats = ['FB2', 'EPUB', 'TXT', 'SFB']
class StoreDieselEbooksStore(StoreBase):
name = 'Diesel eBooks'
description = u'Instant access to over 2.4 million titles from hundreds of publishers including Harlequin, HarperCollins, John Wiley & Sons, McGraw-Hill, Simon & Schuster and Random House.'
@ -1190,6 +1227,15 @@ class StoreDieselEbooksStore(StoreBase):
formats = ['EPUB', 'PDF']
affiliate = True
class StoreEbookNLStore(StoreBase):
name = 'eBook.nl'
description = u'De eBookwinkel van Nederland'
actual_plugin = 'calibre.gui2.store.stores.ebook_nl_plugin:EBookNLStore'
headquarters = 'NL'
formats = ['EPUB', 'PDF']
affiliate = True
class StoreEbookscomStore(StoreBase):
name = 'eBooks.com'
description = u'Sells books in multiple electronic formats in all categories. Technical infrastructure is cutting edge, robust and scalable, with servers in the US and Europe.'
@ -1199,17 +1245,6 @@ class StoreEbookscomStore(StoreBase):
formats = ['EPUB', 'LIT', 'MOBI', 'PDF']
affiliate = True
class StoreEPubBuyDEStore(StoreBase):
name = 'EPUBBuy DE'
author = 'Charles Haley'
description = u'Bei EPUBBuy.com finden Sie ausschliesslich eBooks im weitverbreiteten EPUB-Format und ohne DRM. So haben Sie die freie Wahl, wo Sie Ihr eBook lesen: Tablet, eBook-Reader, Smartphone oder einfach auf Ihrem PC. So macht eBook-Lesen Spaß!'
actual_plugin = 'calibre.gui2.store.stores.epubbuy_de_plugin:EPubBuyDEStore'
drm_free_only = True
headquarters = 'DE'
formats = ['EPUB']
affiliate = True
class StoreEBookShoppeUKStore(StoreBase):
name = 'ebookShoppe UK'
author = u'Charles Haley'
@ -1229,14 +1264,15 @@ class StoreEHarlequinStore(StoreBase):
formats = ['EPUB', 'PDF']
affiliate = True
class StoreEpubBudStore(StoreBase):
name = 'ePub Bud'
description = 'Well, it\'s pretty much just "YouTube for Children\'s eBooks. A not-for-profit organization devoted to brining self published childrens books to the world.'
actual_plugin = 'calibre.gui2.store.stores.epubbud_plugin:EpubBudStore'
class StoreEKnigiStore(StoreBase):
name = u'еКниги'
author = 'Alex Stanev'
description = u'Онлайн книжарница за електронни книги и аудио риалити романи'
actual_plugin = 'calibre.gui2.store.stores.eknigi_plugin:eKnigiStore'
drm_free_only = True
headquarters = 'US'
formats = ['EPUB']
headquarters = 'BG'
formats = ['EPUB', 'PDF', 'HTML']
affiliate = True
class StoreFeedbooksStore(StoreBase):
name = 'Feedbooks'
@ -1272,6 +1308,7 @@ class StoreGoogleBooksStore(StoreBase):
headquarters = 'US'
formats = ['EPUB', 'PDF', 'TXT']
affiliate = True
class StoreGutenbergStore(StoreBase):
name = 'Project Gutenberg'
@ -1355,6 +1392,17 @@ class StoreOReillyStore(StoreBase):
headquarters = 'US'
formats = ['APK', 'DAISY', 'EPUB', 'MOBI', 'PDF']
class StoreOzonRUStore(StoreBase):
name = 'OZON.ru'
description = u'ebooks from OZON.ru'
actual_plugin = 'calibre.gui2.store.stores.ozon_ru_plugin:OzonRUStore'
author = 'Roman Mukhin'
drm_free_only = True
headquarters = 'RU'
formats = ['TXT', 'PDF', 'DJVU', 'RTF', 'DOC', 'JAR', 'FB2']
affiliate = True
class StorePragmaticBookshelfStore(StoreBase):
name = 'Pragmatic Bookshelf'
description = u'The Pragmatic Bookshelf\'s collection of programming and tech books avaliable as ebooks.'
@ -1446,12 +1494,14 @@ plugins += [
StoreBNStore,
StoreBeamEBooksDEStore,
StoreBeWriteStore,
StoreBookotekaStore,
StoreChitankaStore,
StoreDieselEbooksStore,
StoreEbookNLStore,
StoreEbookscomStore,
StoreEBookShoppeUKStore,
StoreEPubBuyDEStore,
StoreEHarlequinStore,
StoreEpubBudStore,
StoreEKnigiStore,
StoreFeedbooksStore,
StoreFoylesUKStore,
StoreGandalfStore,
@ -1465,6 +1515,7 @@ plugins += [
StoreNextoStore,
StoreOpenBooksStore,
StoreOReillyStore,
StoreOzonRUStore,
StorePragmaticBookshelfStore,
StoreSmashwordsStore,
StoreVirtualoStore,

View File

@ -8,7 +8,7 @@ __copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
# Imports {{{
import os, shutil, uuid, json
import os, shutil, uuid, json, glob, time, tempfile
from functools import partial
import apsw
@ -25,7 +25,7 @@ from calibre.utils.config import to_json, from_json, prefs, tweaks
from calibre.utils.date import utcfromtimestamp, parse_date
from calibre.utils.filenames import is_case_sensitive
from calibre.db.tables import (OneToOneTable, ManyToOneTable, ManyToManyTable,
SizeTable, FormatsTable, AuthorsTable, IdentifiersTable)
SizeTable, FormatsTable, AuthorsTable, IdentifiersTable, CompositeTable)
# }}}
'''
@ -37,6 +37,8 @@ Differences in semantics from pysqlite:
'''
SPOOL_SIZE = 30*1024*1024
class DynamicFilter(object): # {{{
'No longer used, present for legacy compatibility'
@ -478,7 +480,6 @@ class DB(object):
remove.append(data)
continue
self.custom_column_label_map[data['label']] = data['num']
self.custom_column_num_map[data['num']] = \
self.custom_column_label_map[data['label']] = data
@ -613,10 +614,31 @@ class DB(object):
tables['size'] = SizeTable('size', self.field_metadata['size'].copy())
for label, data in self.custom_column_label_map.iteritems():
label = '#' + label
self.FIELD_MAP = {'id':0, 'title':1, 'authors':2, 'timestamp':3,
'size':4, 'rating':5, 'tags':6, 'comments':7, 'series':8,
'publisher':9, 'series_index':10, 'sort':11, 'author_sort':12,
'formats':13, 'path':14, 'pubdate':15, 'uuid':16, 'cover':17,
'au_map':18, 'last_modified':19, 'identifiers':20}
for k,v in self.FIELD_MAP.iteritems():
self.field_metadata.set_field_record_index(k, v, prefer_custom=False)
base = max(self.FIELD_MAP.itervalues())
for label_, data in self.custom_column_label_map.iteritems():
label = self.field_metadata.custom_field_prefix + label_
metadata = self.field_metadata[label].copy()
link_table = self.custom_table_names(data['num'])[1]
self.FIELD_MAP[data['num']] = base = base+1
self.field_metadata.set_field_record_index(label_, base,
prefer_custom=True)
if data['datatype'] == 'series':
# account for the series index column. Field_metadata knows that
# the series index is one larger than the series. If you change
# it here, be sure to change it there as well.
self.FIELD_MAP[str(data['num'])+'_index'] = base = base+1
self.field_metadata.set_field_record_index(label_+'_index', base,
prefer_custom=True)
if data['normalized']:
if metadata['is_multiple']:
@ -633,7 +655,16 @@ class DB(object):
metadata['table'] = link_table
tables[label] = OneToOneTable(label, metadata)
else:
tables[label] = OneToOneTable(label, metadata)
if data['datatype'] == 'composite':
tables[label] = CompositeTable(label, metadata)
else:
tables[label] = OneToOneTable(label, metadata)
self.FIELD_MAP['ondevice'] = base = base+1
self.field_metadata.set_field_record_index('ondevice', base, prefer_custom=False)
self.FIELD_MAP['marked'] = base = base+1
self.field_metadata.set_field_record_index('marked', base, prefer_custom=False)
# }}}
@property
@ -732,5 +763,57 @@ class DB(object):
pprint.pprint(table.metadata)
raise
def format_abspath(self, book_id, fmt, fname, path):
path = os.path.join(self.library_path, path)
fmt = ('.' + fmt.lower()) if fmt else ''
fmt_path = os.path.join(path, fname+fmt)
if os.path.exists(fmt_path):
return fmt_path
try:
candidates = glob.glob(os.path.join(path, '*'+fmt))
except: # If path contains strange characters this throws an exc
candidates = []
if fmt and candidates and os.path.exists(candidates[0]):
shutil.copyfile(candidates[0], fmt_path)
return fmt_path
def format_metadata(self, book_id, fmt, fname, path):
path = self.format_abspath(book_id, fmt, fname, path)
ans = {}
if path is not None:
stat = os.stat(path)
ans['size'] = stat.st_size
ans['mtime'] = utcfromtimestamp(stat.st_mtime)
return ans
def cover(self, path, as_file=False, as_image=False,
as_path=False):
path = os.path.join(self.library_path, path, 'cover.jpg')
ret = None
if os.access(path, os.R_OK):
try:
f = lopen(path, 'rb')
except (IOError, OSError):
time.sleep(0.2)
f = lopen(path, 'rb')
with f:
if as_path:
pt = PersistentTemporaryFile('_dbcover.jpg')
with pt:
shutil.copyfileobj(f, pt)
return pt.name
if as_file:
ret = tempfile.SpooledTemporaryFile(SPOOL_SIZE)
shutil.copyfileobj(f, ret)
ret.seek(0)
else:
ret = f.read()
if as_image:
from PyQt4.Qt import QImage
i = QImage()
i.loadFromData(ret)
ret = i
return ret
# }}}

View File

@ -7,5 +7,380 @@ __license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os
from collections import defaultdict
from functools import wraps, partial
from calibre.db.locking import create_locks, RecordLock
from calibre.db.fields import create_field
from calibre.ebooks.book.base import Metadata
from calibre.utils.date import now
def api(f):
f.is_cache_api = True
return f
def read_api(f):
f = api(f)
f.is_read_api = True
return f
def write_api(f):
f = api(f)
f.is_read_api = False
return f
def wrap_simple(lock, func):
@wraps(func)
def ans(*args, **kwargs):
with lock:
return func(*args, **kwargs)
return ans
class Cache(object):
def __init__(self, backend):
self.backend = backend
self.fields = {}
self.composites = set()
self.read_lock, self.write_lock = create_locks()
self.record_lock = RecordLock(self.read_lock)
self.format_metadata_cache = defaultdict(dict)
# Implement locking for all simple read/write API methods
# An unlocked version of the method is stored with the name starting
# with a leading underscore. Use the unlocked versions when the lock
# has already been acquired.
for name in dir(self):
func = getattr(self, name)
ira = getattr(func, 'is_read_api', None)
if ira is not None:
# Save original function
setattr(self, '_'+name, func)
# Wrap it in a lock
lock = self.read_lock if ira else self.write_lock
setattr(self, name, wrap_simple(lock, func))
@property
def field_metadata(self):
return self.backend.field_metadata
def _format_abspath(self, book_id, fmt):
'''
Return absolute path to the ebook file of format `format`
WARNING: This method will return a dummy path for a network backend DB,
so do not rely on it, use format(..., as_path=True) instead.
Currently used only in calibredb list, the viewer and the catalogs (via
get_data_as_dict()).
Apart from the viewer, I don't believe any of the others do any file
I/O with the results of this call.
'''
try:
name = self.fields['formats'].format_fname(book_id, fmt)
path = self._field_for('path', book_id).replace('/', os.sep)
except:
return None
if name and path:
return self.backend.format_abspath(book_id, fmt, name, path)
def _get_metadata(self, book_id, get_user_categories=True): # {{{
mi = Metadata(None)
author_ids = self._field_ids_for('authors', book_id)
aut_list = [self._author_data(i) for i in author_ids]
aum = []
aus = {}
aul = {}
for rec in aut_list:
aut = rec['name']
aum.append(aut)
aus[aut] = rec['sort']
aul[aut] = rec['link']
mi.title = self._field_for('title', book_id,
default_value=_('Unknown'))
mi.authors = aum
mi.author_sort = self._field_for('author_sort', book_id,
default_value=_('Unknown'))
mi.author_sort_map = aus
mi.author_link_map = aul
mi.comments = self._field_for('comments', book_id)
mi.publisher = self._field_for('publisher', book_id)
n = now()
mi.timestamp = self._field_for('timestamp', book_id, default_value=n)
mi.pubdate = self._field_for('pubdate', book_id, default_value=n)
mi.uuid = self._field_for('uuid', book_id,
default_value='dummy')
mi.title_sort = self._field_for('sort', book_id,
default_value=_('Unknown'))
mi.book_size = self._field_for('size', book_id, default_value=0)
mi.ondevice_col = self._field_for('ondevice', book_id, default_value='')
mi.last_modified = self._field_for('last_modified', book_id,
default_value=n)
formats = self._field_for('formats', book_id)
mi.format_metadata = {}
if not formats:
formats = None
else:
for f in formats:
mi.format_metadata[f] = self._format_metadata(book_id, f)
formats = ','.join(formats)
mi.formats = formats
mi.has_cover = _('Yes') if self._field_for('cover', book_id,
default_value=False) else ''
mi.tags = list(self._field_for('tags', book_id, default_value=()))
mi.series = self._field_for('series', book_id)
if mi.series:
mi.series_index = self._field_for('series_index', book_id,
default_value=1.0)
mi.rating = self._field_for('rating', book_id)
mi.set_identifiers(self._field_for('identifiers', book_id,
default_value={}))
mi.application_id = book_id
mi.id = book_id
composites = {}
for key, meta in self.field_metadata.custom_iteritems():
mi.set_user_metadata(key, meta)
if meta['datatype'] == 'composite':
composites.append(key)
else:
mi.set(key, val=self._field_for(meta['label'], book_id),
extra=self._field_for(meta['label']+'_index', book_id))
for c in composites:
mi.set(key, val=self._composite_for(key, book_id, mi))
user_cat_vals = {}
if get_user_categories:
user_cats = self.prefs['user_categories']
for ucat in user_cats:
res = []
for name,cat,ign in user_cats[ucat]:
v = mi.get(cat, None)
if isinstance(v, list):
if name in v:
res.append([name,cat])
elif name == v:
res.append([name,cat])
user_cat_vals[ucat] = res
mi.user_categories = user_cat_vals
return mi
# }}}
# Cache Layer API {{{
@api
def init(self):
'''
Initialize this cache with data from the backend.
'''
with self.write_lock:
self.backend.read_tables()
for field, table in self.backend.tables.iteritems():
self.fields[field] = create_field(field, table)
if table.metadata['datatype'] == 'composite':
self.composites.add(field)
self.fields['ondevice'] = create_field('ondevice', None)
@read_api
def field_for(self, name, book_id, default_value=None):
'''
Return the value of the field ``name`` for the book identified by
``book_id``. If no such book exists or it has no defined value for the
field ``name`` or no such field exists, then ``default_value`` is returned.
The returned value for is_multiple fields are always tuples.
'''
if self.composites and name in self.composites:
return self.composite_for(name, book_id,
default_value=default_value)
try:
return self.fields[name].for_book(book_id, default_value=default_value)
except (KeyError, IndexError):
return default_value
@read_api
def composite_for(self, name, book_id, mi=None, default_value=''):
try:
f = self.fields[name]
except KeyError:
return default_value
if mi is None:
return f.get_value_with_cache(book_id, partial(self._get_metadata,
get_user_categories=False))
else:
return f.render_composite(book_id, mi)
@read_api
def field_ids_for(self, name, book_id):
'''
Return the ids (as a tuple) for the values that the field ``name`` has on the book
identified by ``book_id``. If there are no values, or no such book, or
no such field, an empty tuple is returned.
'''
try:
return self.fields[name].ids_for_book(book_id)
except (KeyError, IndexError):
return ()
@read_api
def books_for_field(self, name, item_id):
'''
Return all the books associated with the item identified by
``item_id``, where the item belongs to the field ``name``.
Returned value is a tuple of book ids, or the empty tuple if the item
or the field does not exist.
'''
try:
return self.fields[name].books_for(item_id)
except (KeyError, IndexError):
return ()
@read_api
def all_book_ids(self):
'''
Frozen set of all known book ids.
'''
return frozenset(self.fields['uuid'].iter_book_ids())
@read_api
def all_field_ids(self, name):
'''
Frozen set of ids for all values in the field ``name``.
'''
return frozenset(iter(self.fields[name]))
@read_api
def author_data(self, author_id):
'''
Return author data as a dictionary with keys: name, sort, link
If no author with the specified id is found an empty dictionary is
returned.
'''
try:
return self.fields['authors'].author_data(author_id)
except (KeyError, IndexError):
return {}
@read_api
def format_metadata(self, book_id, fmt, allow_cache=True):
if not fmt:
return {}
fmt = fmt.upper()
if allow_cache:
x = self.format_metadata_cache[book_id].get(fmt, None)
if x is not None:
return x
try:
name = self.fields['formats'].format_fname(book_id, fmt)
path = self._field_for('path', book_id).replace('/', os.sep)
except:
return {}
ans = {}
if path and name:
ans = self.backend.format_metadata(book_id, fmt, name, path)
self.format_metadata_cache[book_id][fmt] = ans
return ans
@api
def get_metadata(self, book_id,
get_cover=False, get_user_categories=True, cover_as_data=False):
'''
Return metadata for the book identified by book_id as a :class:`Metadata` object.
Note that the list of formats is not verified. If get_cover is True,
the cover is returned, either a path to temp file as mi.cover or if
cover_as_data is True then as mi.cover_data.
'''
with self.read_lock:
mi = self._get_metadata(book_id, get_user_categories=get_user_categories)
if get_cover:
if cover_as_data:
cdata = self.cover(book_id)
if cdata:
mi.cover_data = ('jpeg', cdata)
else:
mi.cover = self.cover(book_id, as_path=True)
return mi
@api
def cover(self, book_id,
as_file=False, as_image=False, as_path=False):
'''
Return the cover image or None. By default, returns the cover as a
bytestring.
WARNING: Using as_path will copy the cover to a temp file and return
the path to the temp file. You should delete the temp file when you are
done with it.
:param as_file: If True return the image as an open file object (a SpooledTemporaryFile)
:param as_image: If True return the image as a QImage object
:param as_path: If True return the image as a path pointing to a
temporary file
'''
with self.read_lock:
try:
path = self._field_for('path', book_id).replace('/', os.sep)
except:
return None
with self.record_lock.lock(book_id):
return self.backend.cover(path, as_file=as_file, as_image=as_image,
as_path=as_path)
@read_api
def multisort(self, fields):
all_book_ids = frozenset(self._all_book_ids())
get_metadata = partial(self._get_metadata, get_user_categories=False)
sort_keys = tuple(self.fields[field[0]].sort_keys_for_books(get_metadata,
all_book_ids) for field in fields)
if len(sort_keys) == 1:
sk = sort_keys[0]
return sorted(all_book_ids, key=lambda i:sk[i], reverse=not
fields[1])
else:
return sorted(all_book_ids, key=partial(SortKey, fields, sort_keys))
# }}}
class SortKey(object):
def __init__(self, fields, sort_keys, book_id):
self.orders = tuple(1 if f[1] else -1 for f in fields)
self.sort_key = tuple(sk[book_id] for sk in sort_keys)
def __cmp__(self, other):
for i, order in enumerate(self.orders):
ans = cmp(self.sort_key[i], other.sort_key[i])
if ans != 0:
return ans * order
return 0
# Testing {{{
def test(library_path):
from calibre.db.backend import DB
backend = DB(library_path)
cache = Cache(backend)
cache.init()
print ('All book ids:', cache.all_book_ids())
if __name__ == '__main__':
from calibre.utils.config import prefs
test(prefs['library_path'])
# }}}

257
src/calibre/db/fields.py Normal file
View File

@ -0,0 +1,257 @@
#!/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)
from future_builtins import map
__license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from threading import Lock
from calibre.db.tables import ONE_ONE, MANY_ONE, MANY_MANY
from calibre.utils.icu import sort_key
class Field(object):
def __init__(self, name, table):
self.name, self.table = name, table
self.has_text_data = self.metadata['datatype'] in ('text', 'comments',
'series', 'enumeration')
self.table_type = self.table.table_type
dt = self.metadata['datatype']
self._sort_key = (sort_key if dt == 'text' else lambda x: x)
@property
def metadata(self):
return self.table.metadata
def for_book(self, book_id, default_value=None):
'''
Return the value of this field for the book identified by book_id.
When no value is found, returns ``default_value``.
'''
raise NotImplementedError()
def ids_for_book(self, book_id):
'''
Return a tuple of items ids for items associated with the book
identified by book_ids. Returns an empty tuple if no such items are
found.
'''
raise NotImplementedError()
def books_for(self, item_id):
'''
Return the ids of all books associated with the item identified by
item_id as a tuple. An empty tuple is returned if no books are found.
'''
raise NotImplementedError()
def __iter__(self):
'''
Iterate over the ids for all values in this field
'''
raise NotImplementedError()
def sort_keys_for_books(self, get_metadata, all_book_ids):
'''
Return a mapping of book_id -> sort_key. The sort key is suitable for
use in sorting the list of all books by this field, via the python cmp
method.
'''
raise NotImplementedError()
class OneToOneField(Field):
def for_book(self, book_id, default_value=None):
return self.table.book_col_map.get(book_id, default_value)
def ids_for_book(self, book_id):
return (book_id,)
def books_for(self, item_id):
return (item_id,)
def __iter__(self):
return self.table.book_col_map.iterkeys()
def iter_book_ids(self):
return self.table.book_col_map.iterkeys()
def sort_keys_for_books(self, get_metadata, all_book_ids):
return {id_ : self._sort_key(self.book_col_map.get(id_, '')) for id_ in
all_book_ids}
class CompositeField(OneToOneField):
def __init__(self, *args, **kwargs):
OneToOneField.__init__(self, *args, **kwargs)
self._render_cache = {}
self._lock = Lock()
def render_composite(self, book_id, mi):
with self._lock:
ans = self._render_cache.get(book_id, None)
if ans is None:
ans = mi.get(self.metadata['label'])
with self._lock:
self._render_cache[book_id] = ans
return ans
def clear_cache(self):
with self._lock:
self._render_cache = {}
def pop_cache(self, book_id):
with self._lock:
self._render_cache.pop(book_id, None)
def get_value_with_cache(self, book_id, get_metadata):
with self._lock:
ans = self._render_cache.get(book_id, None)
if ans is None:
mi = get_metadata(book_id)
ans = mi.get(self.metadata['label'])
return ans
def sort_keys_for_books(self, get_metadata, all_book_ids):
return {id_ : sort_key(self.get_value_with_cache(id_, get_metadata)) for id_ in
all_book_ids}
class OnDeviceField(OneToOneField):
def __init__(self, name, table):
self.name = name
self.book_on_device_func = None
def book_on_device(self, book_id):
if callable(self.book_on_device_func):
return self.book_on_device_func(book_id)
return None
def set_book_on_device_func(self, func):
self.book_on_device_func = func
def for_book(self, book_id, default_value=None):
loc = []
count = 0
on = self.book_on_device(book_id)
if on is not None:
m, a, b, count = on[:4]
if m is not None:
loc.append(_('Main'))
if a is not None:
loc.append(_('Card A'))
if b is not None:
loc.append(_('Card B'))
return ', '.join(loc) + ((' (%s books)'%count) if count > 1 else '')
def __iter__(self):
return iter(())
def iter_book_ids(self):
return iter(())
def sort_keys_for_books(self, get_metadata, all_book_ids):
return {id_ : self.for_book(id_) for id_ in
all_book_ids}
class ManyToOneField(Field):
def for_book(self, book_id, default_value=None):
ids = self.table.book_col_map.get(book_id, None)
if ids is not None:
ans = self.id_map[ids]
else:
ans = default_value
return ans
def ids_for_book(self, book_id):
id_ = self.table.book_col_map.get(book_id, None)
if id_ is None:
return ()
return (id_,)
def books_for(self, item_id):
return self.table.col_book_map.get(item_id, ())
def __iter__(self):
return self.table.id_map.iterkeys()
def sort_keys_for_books(self, get_metadata, all_book_ids):
keys = {id_ : self._sort_key(self.id_map.get(id_, '')) for id_ in
all_book_ids}
return {id_ : keys.get(
self.book_col_map.get(id_, None), '') for id_ in all_book_ids}
class ManyToManyField(Field):
def __init__(self, *args, **kwargs):
Field.__init__(self, *args, **kwargs)
self.alphabetical_sort = self.name != 'authors'
def for_book(self, book_id, default_value=None):
ids = self.table.book_col_map.get(book_id, ())
if ids:
ans = tuple(self.id_map[i] for i in ids)
else:
ans = default_value
return ans
def ids_for_book(self, book_id):
return self.table.book_col_map.get(book_id, ())
def books_for(self, item_id):
return self.table.col_book_map.get(item_id, ())
def __iter__(self):
return self.table.id_map.iterkeys()
def sort_keys_for_books(self, get_metadata, all_book_ids):
keys = {id_ : self._sort_key(self.id_map.get(id_, '')) for id_ in
all_book_ids}
def sort_key_for_book(book_id):
item_ids = self.table.book_col_map.get(book_id, ())
if self.alphabetical_sort:
item_ids = sorted(item_ids, key=keys.get)
return tuple(map(keys.get, item_ids))
return {id_ : sort_key_for_book(id_) for id_ in all_book_ids}
class AuthorsField(ManyToManyField):
def author_data(self, author_id):
return {
'name' : self.table.id_map[author_id],
'sort' : self.table.asort_map[author_id],
'link' : self.table.alink_map[author_id],
}
class FormatsField(ManyToManyField):
def format_fname(self, book_id, fmt):
return self.table.fname_map[book_id][fmt.upper()]
def create_field(name, table):
cls = {
ONE_ONE : OneToOneField,
MANY_ONE : ManyToOneField,
MANY_MANY : ManyToManyField,
}[table.table_type]
if name == 'authors':
cls = AuthorsField
elif name == 'ondevice':
cls = OnDeviceField
elif name == 'formats':
cls = FormatsField
elif table.metadata['datatype'] == 'composite':
cls = CompositeField
return cls(name, table)

View File

@ -7,7 +7,9 @@ __license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from threading import Lock, Condition, current_thread
from threading import Lock, Condition, current_thread, RLock
from functools import partial
from collections import Counter
class LockingError(RuntimeError):
pass
@ -37,7 +39,7 @@ def create_locks():
l = SHLock()
return RWLockWrapper(l), RWLockWrapper(l, is_shared=False)
class SHLock(object):
class SHLock(object): # {{{
'''
Shareable lock class. Used to implement the Multiple readers-single writer
paradigm. As best as I can tell, neither writer nor reader starvation
@ -79,6 +81,11 @@ class SHLock(object):
return self._acquire_exclusive(blocking)
assert not (self.is_shared and self.is_exclusive)
def owns_lock(self):
me = current_thread()
with self._lock:
return self._exclusive_owner is me or me in self._shared_owners
def release(self):
''' Release the lock. '''
# This decrements the appropriate lock counters, and if the lock
@ -189,6 +196,8 @@ class SHLock(object):
def _return_waiter(self, waiter):
self._free_waiters.append(waiter)
# }}}
class RWLockWrapper(object):
def __init__(self, shlock, is_shared=True):
@ -200,16 +209,146 @@ class RWLockWrapper(object):
return self
def __exit__(self, *args):
self.release()
def release(self):
self._shlock.release()
def owns_lock(self):
return self._shlock.owns_lock()
class RecordLock(object):
'''
Lock records identified by hashable ids. To use
rl = RecordLock()
with rl.lock(some_id):
# do something
This will lock the record identified by some_id exclusively. The lock is
recursive, which means that you can lock the same record multiple times in
the same thread.
This class co-operates with the SHLock class. If you try to lock a record
in a thread that already holds the SHLock, a LockingError is raised. This
is to prevent the possibility of a cross-lock deadlock.
A cross-lock deadlock is still possible if you first lock a record and then
acquire the SHLock, but the usage pattern for this lock makes this highly
unlikely (this lock should be acquired immediately before any file I/O on
files in the library and released immediately after).
'''
class Wrap(object):
def __init__(self, release):
self.release = release
def __enter__(self):
return self
def __exit__(self, *args, **kwargs):
self.release()
self.release = None
def __init__(self, sh_lock):
self._lock = Lock()
# This is for recycling lock objects.
self._free_locks = [RLock()]
self._records = {}
self._counter = Counter()
self.sh_lock = sh_lock
def lock(self, record_id):
if self.sh_lock.owns_lock():
raise LockingError('Current thread already holds a shared lock,'
' you cannot also ask for record lock as this could cause a'
' deadlock.')
with self._lock:
l = self._records.get(record_id, None)
if l is None:
l = self._take_lock()
self._records[record_id] = l
self._counter[record_id] += 1
l.acquire()
return RecordLock.Wrap(partial(self.release, record_id))
def release(self, record_id):
with self._lock:
l = self._records.pop(record_id, None)
if l is None:
raise LockingError('No lock acquired for record %r'%record_id)
l.release()
self._counter[record_id] -= 1
if self._counter[record_id] > 0:
self._records[record_id] = l
else:
self._return_lock(l)
def _take_lock(self):
try:
return self._free_locks.pop()
except IndexError:
return RLock()
def _return_lock(self, lock):
self._free_locks.append(lock)
# Tests {{{
if __name__ == '__main__':
import time, random, unittest
from threading import Thread
class TestSHLock(unittest.TestCase):
"""Testcases for SHLock class."""
class TestLock(unittest.TestCase):
"""Testcases for Lock classes."""
def test_owns_locks(self):
lock = SHLock()
self.assertFalse(lock.owns_lock())
lock.acquire(shared=True)
self.assertTrue(lock.owns_lock())
lock.release()
self.assertFalse(lock.owns_lock())
lock.acquire(shared=False)
self.assertTrue(lock.owns_lock())
lock.release()
self.assertFalse(lock.owns_lock())
done = []
def test():
if not lock.owns_lock():
done.append(True)
lock.acquire()
t = Thread(target=test)
t.daemon = True
t.start()
t.join(1)
self.assertEqual(len(done), 1)
lock.release()
def test_multithread_deadlock(self):
lock = SHLock()
def two_shared():
r = RWLockWrapper(lock)
with r:
time.sleep(0.2)
with r:
pass
def one_exclusive():
time.sleep(0.1)
w = RWLockWrapper(lock, is_shared=False)
with w:
pass
threads = [Thread(target=two_shared), Thread(target=one_exclusive)]
for t in threads:
t.daemon = True
t.start()
for t in threads:
t.join(5)
live = [t for t in threads if t.is_alive()]
self.assertListEqual(live, [], 'ShLock hung')
def test_upgrade(self):
lock = SHLock()
@ -323,8 +462,38 @@ if __name__ == '__main__':
self.assertFalse(lock.is_shared)
self.assertFalse(lock.is_exclusive)
def test_record_lock(self):
shlock = SHLock()
lock = RecordLock(shlock)
suite = unittest.TestLoader().loadTestsFromTestCase(TestSHLock)
shlock.acquire()
self.assertRaises(LockingError, lock.lock, 1)
shlock.release()
with lock.lock(1):
with lock.lock(1):
pass
def dolock():
with lock.lock(1):
time.sleep(0.1)
t = Thread(target=dolock)
t.daemon = True
with lock.lock(1):
t.start()
t.join(0.2)
self.assertTrue(t.is_alive())
t.join(0.11)
self.assertFalse(t.is_alive())
t = Thread(target=dolock)
t.daemon = True
with lock.lock(2):
t.start()
t.join(0.11)
self.assertFalse(t.is_alive())
suite = unittest.TestLoader().loadTestsFromTestCase(TestLock)
unittest.TextTestRunner(verbosity=2).run(suite)
# }}}

View File

@ -12,11 +12,13 @@ from datetime import datetime
from dateutil.tz import tzoffset
from calibre.constants import plugins
from calibre.utils.date import parse_date, local_tz
from calibre.utils.date import parse_date, local_tz, UNDEFINED_DATE
from calibre.ebooks.metadata import author_to_author_sort
_c_speedup = plugins['speedup'][0]
ONE_ONE, MANY_ONE, MANY_MANY = xrange(3)
def _c_convert_timestamp(val):
if not val:
return None
@ -27,8 +29,11 @@ def _c_convert_timestamp(val):
if ret is None:
return parse_date(val, as_utc=False)
year, month, day, hour, minutes, seconds, tzsecs = ret
return datetime(year, month, day, hour, minutes, seconds,
try:
return datetime(year, month, day, hour, minutes, seconds,
tzinfo=tzoffset(None, tzsecs)).astimezone(local_tz)
except OverflowError:
return UNDEFINED_DATE.astimezone(local_tz)
class Table(object):
@ -57,6 +62,8 @@ class OneToOneTable(Table):
timestamp, size, etc.
'''
table_type = ONE_ONE
def read(self, db):
self.book_col_map = {}
idcol = 'id' if self.metadata['table'] == 'books' else 'book'
@ -73,6 +80,17 @@ class SizeTable(OneToOneTable):
'WHERE data.book=books.id) FROM books'):
self.book_col_map[row[0]] = self.unserialize(row[1])
class CompositeTable(OneToOneTable):
def read(self, db):
self.book_col_map = {}
d = self.metadata['display']
self.composite_template = ['composite_template']
self.contains_html = d['contains_html']
self.make_category = d['make_category']
self.composite_sort = d['composite_sort']
self.use_decorations = d['use_decorations']
class ManyToOneTable(Table):
'''
@ -82,9 +100,10 @@ class ManyToOneTable(Table):
Each book however has only one value for data of this type.
'''
table_type = MANY_ONE
def read(self, db):
self.id_map = {}
self.extra_map = {}
self.col_book_map = {}
self.book_col_map = {}
self.read_id_maps(db)
@ -105,6 +124,9 @@ class ManyToOneTable(Table):
self.col_book_map[row[1]].append(row[0])
self.book_col_map[row[0]] = row[1]
for key in tuple(self.col_book_map.iterkeys()):
self.col_book_map[key] = tuple(self.col_book_map[key])
class ManyToManyTable(ManyToOneTable):
'''
@ -113,6 +135,8 @@ class ManyToManyTable(ManyToOneTable):
book. For example: tags or authors.
'''
table_type = MANY_MANY
def read_maps(self, db):
for row in db.conn.execute(
'SELECT book, {0} FROM {1}'.format(
@ -124,14 +148,21 @@ class ManyToManyTable(ManyToOneTable):
self.book_col_map[row[0]] = []
self.book_col_map[row[0]].append(row[1])
for key in tuple(self.col_book_map.iterkeys()):
self.col_book_map[key] = tuple(self.col_book_map[key])
for key in tuple(self.book_col_map.iterkeys()):
self.book_col_map[key] = tuple(self.book_col_map[key])
class AuthorsTable(ManyToManyTable):
def read_id_maps(self, db):
self.alink_map = {}
self.asort_map = {}
for row in db.conn.execute(
'SELECT id, name, sort, link FROM authors'):
self.id_map[row[0]] = row[1]
self.extra_map[row[0]] = (row[2] if row[2] else
self.asort_map[row[0]] = (row[2] if row[2] else
author_to_author_sort(row[1]))
self.alink_map[row[0]] = row[3]
@ -141,14 +172,25 @@ class FormatsTable(ManyToManyTable):
pass
def read_maps(self, db):
self.fname_map = {}
for row in db.conn.execute('SELECT book, format, name FROM data'):
if row[1] is not None:
if row[1] not in self.col_book_map:
self.col_book_map[row[1]] = []
self.col_book_map[row[1]].append(row[0])
fmt = row[1].upper()
if fmt not in self.col_book_map:
self.col_book_map[fmt] = []
self.col_book_map[fmt].append(row[0])
if row[0] not in self.book_col_map:
self.book_col_map[row[0]] = []
self.book_col_map[row[0]].append((row[1], row[2]))
self.book_col_map[row[0]].append(fmt)
if row[0] not in self.fname_map:
self.fname_map[row[0]] = {}
self.fname_map[row[0]][fmt] = row[2]
for key in tuple(self.col_book_map.iterkeys()):
self.col_book_map[key] = tuple(self.col_book_map[key])
for key in tuple(self.book_col_map.iterkeys()):
self.book_col_map[key] = tuple(self.book_col_map[key])
class IdentifiersTable(ManyToManyTable):
@ -162,6 +204,9 @@ class IdentifiersTable(ManyToManyTable):
self.col_book_map[row[1]] = []
self.col_book_map[row[1]].append(row[0])
if row[0] not in self.book_col_map:
self.book_col_map[row[0]] = []
self.book_col_map[row[0]].append((row[1], row[2]))
self.book_col_map[row[0]] = {}
self.book_col_map[row[0]][row[1]] = row[2]
for key in tuple(self.col_book_map.iterkeys()):
self.col_book_map[key] = tuple(self.col_book_map[key])

109
src/calibre/db/view.py Normal file
View File

@ -0,0 +1,109 @@
#!/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 functools import partial
def sanitize_sort_field_name(field_metadata, field):
field = field_metadata.search_term_to_field_key(field.lower().strip())
# translate some fields to their hidden equivalent
field = {'title': 'sort', 'authors':'author_sort'}.get(field, field)
return field
class View(object):
def __init__(self, cache):
self.cache = cache
self.marked_ids = {}
self._field_getters = {}
for col, idx in cache.backend.FIELD_MAP.iteritems():
if isinstance(col, int):
label = self.cache.backend.custom_column_num_map[col]['label']
label = (self.cache.backend.field_metadata.custom_field_prefix
+ label)
self._field_getters[idx] = partial(self.get, label)
else:
try:
self._field_getters[idx] = {
'id' : self._get_id,
'au_map' : self.get_author_data,
'ondevice': self.get_ondevice,
'marked' : self.get_marked,
}[col]
except KeyError:
self._field_getters[idx] = partial(self.get, col)
self._map = list(self.cache.all_book_ids())
self._map_filtered = list(self._map)
@property
def field_metadata(self):
return self.cache.field_metadata
def _get_id(self, idx, index_is_id=True):
ans = idx if index_is_id else self.index_to_id(idx)
return ans
def get_field_map_field(self, row, col, index_is_id=True):
'''
Supports the legacy FIELD_MAP interface for getting metadata. Do not use
in new code.
'''
getter = self._field_getters[col]
return getter(row, index_is_id=index_is_id)
def index_to_id(self, idx):
return self._map_filtered[idx]
def get(self, field, idx, index_is_id=True, default_value=None):
id_ = idx if index_is_id else self.index_to_id(idx)
return self.cache.field_for(field, id_)
def get_ondevice(self, idx, index_is_id=True, default_value=''):
id_ = idx if index_is_id else self.index_to_id(idx)
self.cache.field_for('ondevice', id_, default_value=default_value)
def get_marked(self, idx, index_is_id=True, default_value=None):
id_ = idx if index_is_id else self.index_to_id(idx)
return self.marked_ids.get(id_, default_value)
def get_author_data(self, idx, index_is_id=True, default_value=()):
'''
Return author data for all authors of the book identified by idx as a
tuple of dictionaries. The dictionaries should never be empty, unless
there is a bug somewhere. The list could be empty if idx point to an
non existent book, or book with no authors (though again a book with no
authors should never happen).
Each dictionary has the keys: name, sort, link. Link can be an empty
string.
default_value is ignored, this method always returns a tuple
'''
id_ = idx if index_is_id else self.index_to_id(idx)
with self.cache.read_lock:
ids = self.cache._field_ids_for('authors', id_)
ans = []
for id_ in ids:
ans.append(self.cache._author_data(id_))
return tuple(ans)
def multisort(self, fields=[], subsort=False):
fields = [(sanitize_sort_field_name(self.field_metadata, x), bool(y)) for x, y in fields]
keys = self.field_metadata.sortable_field_keys()
fields = [x for x in fields if x[0] in keys]
if subsort and 'sort' not in [x[0] for x in fields]:
fields += [('sort', True)]
if not fields:
fields = [('timestamp', False)]
sorted_book_ids = self.cache.multisort(fields)
sorted_book_ids
# TODO: change maps

View File

@ -39,7 +39,8 @@ class ANDROID(USBMS):
0x22b8 : { 0x41d9 : [0x216], 0x2d61 : [0x100], 0x2d67 : [0x100],
0x41db : [0x216], 0x4285 : [0x216], 0x42a3 : [0x216],
0x4286 : [0x216], 0x42b3 : [0x216], 0x42b4 : [0x216],
0x7086 : [0x0226], 0x70a8: [0x9999],
0x7086 : [0x0226], 0x70a8: [0x9999], 0x42c4 : [0x216],
0x70c6 : [0x226]
},
# Sony Ericsson
@ -47,10 +48,12 @@ class ANDROID(USBMS):
# Google
0x18d1 : {
0x0001 : [0x0223, 0x9999],
0x4e11 : [0x0100, 0x226, 0x227],
0x4e12: [0x0100, 0x226, 0x227],
0x4e21: [0x0100, 0x226, 0x227],
0xb058: [0x0222, 0x226, 0x227]},
0x4e12 : [0x0100, 0x226, 0x227],
0x4e21 : [0x0100, 0x226, 0x227],
0xb058 : [0x0222, 0x226, 0x227]
},
# Samsung
0x04e8 : { 0x681d : [0x0222, 0x0223, 0x0224, 0x0400],
@ -60,6 +63,8 @@ class ANDROID(USBMS):
0x685e : [0x0400],
0x6860 : [0x0400],
0x6877 : [0x0400],
0x689e : [0x0400],
0xdeed : [0x0222],
},
# Viewsonic
@ -72,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 : {
@ -124,11 +132,12 @@ class ANDROID(USBMS):
'IDEOS_TABLET', 'MYTOUCH_4G', 'UMS_COMPOSITE', 'SCH-I800_CARD',
'7', 'A956', 'A955', 'A43', 'ANDROID_PLATFORM', 'TEGRA_2',
'MB860', 'MULTI-CARD', 'MID7015A', 'INCREDIBLE', 'A7EB', 'STREAK',
'MB525', 'ANDROID2.3']
'MB525', 'ANDROID2.3', 'SGH-I997', 'GT-I5800_CARD', 'MB612',
'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']
'__UMS_COMPOSITE', 'SGH-I997_CARD', 'MB870']
OSX_MAIN_MEM = 'Android Device Main Memory'

View File

@ -446,7 +446,8 @@ class ITUNES(DriverBase):
}
if self.report_progress is not None:
self.report_progress((i+1)/book_count, _('%d of %d') % (i+1, book_count))
self.report_progress((i+1)/book_count,
_('%(num)d of %(tot)d') % dict(num=i+1, tot=book_count))
self._purge_orphans(library_books, cached_books)
elif iswindows:
@ -485,7 +486,8 @@ class ITUNES(DriverBase):
if self.report_progress is not None:
self.report_progress((i+1)/book_count,
_('%d of %d') % (i+1, book_count))
_('%(num)d of %(tot)d') % dict(num=i+1,
tot=book_count))
self._purge_orphans(library_books, cached_books)
finally:
@ -1075,7 +1077,8 @@ class ITUNES(DriverBase):
# Report progress
if self.report_progress is not None:
self.report_progress((i+1)/file_count, _('%d of %d') % (i+1, file_count))
self.report_progress((i+1)/file_count,
_('%(num)d of %(tot)d') % dict(num=i+1, tot=file_count))
elif iswindows:
try:
@ -1118,7 +1121,8 @@ class ITUNES(DriverBase):
# Report progress
if self.report_progress is not None:
self.report_progress((i+1)/file_count, _('%d of %d') % (i+1, file_count))
self.report_progress((i+1)/file_count,
_('%(num)d of %(tot)d') % dict(num=i+1, tot=file_count))
finally:
pythoncom.CoUninitialize()
@ -3107,7 +3111,8 @@ class ITUNES_ASYNC(ITUNES):
}
if self.report_progress is not None:
self.report_progress((i+1)/book_count, _('%d of %d') % (i+1, book_count))
self.report_progress((i+1)/book_count,
_('%(num)d of %(tot)d') % dict(num=i+1, tot=book_count))
elif iswindows:
try:
@ -3147,7 +3152,8 @@ class ITUNES_ASYNC(ITUNES):
if self.report_progress is not None:
self.report_progress((i+1)/book_count,
_('%d of %d') % (i+1, book_count))
_('%(num)d of %(tot)d') % dict(num=i+1,
tot=book_count))
finally:
pythoncom.CoUninitialize()

View File

@ -59,7 +59,7 @@ class BAMBOOK(DeviceConfig, DevicePlugin):
def reset(self, key='-1', log_packets=False, report_progress=None,
detected_device=None) :
self.open()
self.open(None)
def open(self, library_uuid):
# Make sure the Bambook library is ready

View File

@ -35,9 +35,9 @@ class EB600(USBMS):
PRODUCT_ID = [0x1688]
BCD = [0x110]
VENDOR_NAME = ['NETRONIX', 'WOLDER']
WINDOWS_MAIN_MEM = ['EBOOK', 'MIBUK_GAMMA_6.2']
WINDOWS_CARD_A_MEM = 'EBOOK'
VENDOR_NAME = ['NETRONIX', 'WOLDER', 'MD86371']
WINDOWS_MAIN_MEM = ['EBOOK', 'MIBUK_GAMMA_6.2', 'MD86371']
WINDOWS_CARD_A_MEM = ['EBOOK', 'MD86371']
OSX_MAIN_MEM = 'EB600 Internal Storage Media'
OSX_CARD_A_MEM = 'EB600 Card Storage Media'

View File

@ -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]

View File

@ -131,7 +131,7 @@ class AZBOOKA(ALEX):
description = _('Communicate with the Azbooka')
VENDOR_NAME = 'LINUX'
WINDOWS_MAIN_MEM = 'FILE-STOR_GADGET'
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = 'FILE-STOR_GADGET'
MAIN_MEMORY_VOLUME_LABEL = 'Azbooka Internal Memory'

Some files were not shown because too many files have changed in this diff Show More