Sync to trunk.

This commit is contained in:
John Schember 2010-08-18 19:26:14 -04:00
commit 2f67d8b95c
299 changed files with 72190 additions and 67118 deletions

View File

@ -4,6 +4,187 @@
# for important features/bug fixes. # for important features/bug fixes.
# Also, each release can have new and improved recipes. # Also, each release can have new and improved recipes.
- version: 0.7.14
date: 2010-08-13
new features:
- title: "Device drivers for the: Teclast K-5, Samsung SNE-60 and Samsung i7500"
- title: "When showing cover browser in a separate window, remember the last used window size"
- title: "Add keyboard shortcuts to show/hide the Tag Browser, Book details and Cover Browser panels. Hover your mouse over the buttons that toggle them to see the shortcuts."
- title: "Calibre library: When the case of title or author is changed, automatically rename the folders to reflect the new case, even on case insensitive filesystems"
- title: "Metadata download: If downloaded title or author is all upper case, automatically fix the case"
- title: "Add method to add books by ISBN. Click the arrow next to Add Books to add from a list of ISBNs."
tickets: [6327]
- title: "Allow editing of tweaks via Preferences->Advanced"
- title: "Add button to the manage authors dialog to automatically reset all author sort values"
bug fixes:
- title: "Fix regression in 0.7.13 that broke changing libraries"
- title: "MOBI Output: When processing an input document that specifies non-existant files in the OPF guide, don't crash."
tickets: [6490]
- title: "E-book viewer: When opening consecutive documents in the same viewer, show the correct title in the titlebar"
- title: "Set screen size to 540x718 in Kobo output profile"
- title: "Dont allow calibredb to create custom columns with invalid labels."
tickets: [6487]
- title: "Fix preference to 'search as you type' not working"
- title: "iTunes driver: Fixed bug in PDF file name searching after adding to iTunes database (Windows only)"
- title: "Displaying HTML comments: Do not start a new paragraph at the period in words like Ph.D"
tickets: [6462]
- title: "Respect restriction in effect when refreshing book list"
- title: "Fix drives being reversed for softrooted nook"
new recipes:
- title: "Yahoo News, Skeptical Enquirer and Skeptic"
author: Startson17
- title: "Bolivian newspapers"
author: Darko Miletic
improved recipes:
- Esquire
- Big Oven
- NSPM
- version: 0.7.13
date: 2010-08-06
new features:
- title: "Add a button to the edit metadata dialog to generate a cover based on the book metadata"
tickets: [5959]
- title: "When using series or title in a save template to generate a file path, remove leading prepositions. This behavior can be controlled via a tweak."
- title: "News download: When downloading news for the Kindle, do not add date to the title, to allow the Kindle's periodical archiving to work."
tickets: [6411]
- title: "Content Server OPDS feeds: Grouping of items by first alphabet is now case-insensitive."
- title: "Do not allow the user to use save to disk to save files into the calibre library"
tickets: [6392]
- title: "Switch to a new C based API for using ImageMagick. More robust and a minor speedup when doing image manipulations"
- title: "Move cover downloading to a plugin based API. You can now add new cover sources to calibre using plugins."
bug fixes:
- title: "Content server OPDS feeds: Handle the case when the author field is blank"
tickets: [6371]
- title: "TXT Input: Strip out illegal chars from txt files."
tickets: [6335]
- title: "Save to disk/send to device templates: Always render {series_index} as an empty string when the book has no series."
tickets: [6409]
- title: "PD Novel driver: Remove covers when deleting books"
new recipes:
- title: "Snopes"
author: Startson17
- title: "dr.dk and Balkan Insight"
author: Darko Miletic
- title: Folha de Sao Paulo
author: Saverio Palmieri Neto
improved recipes:
- Honolulu Star Advertiser
- Nature News
- Associated Press
- Scientific American
- New Scientist
- version: 0.7.12
date: 2010-07-30
bug fixes:
- title: "Fix a typo that caused a harmless error message after setting preferences"
- title: "Linux build system: No longer search for poppler-qt4 libraries as they are not needed"
- version: 0.7.11
date: 2010-07-30
new features:
- title: "EPUB metadata: When setting metadata in an EPUB file, if it has a well defined image based cover, update it"
- title: "Support for Droid X, Samsung Vibrant and Promedia ebook reader"
- title: "Add entry to Connect/share menu to conveniently stop and start the Content Server"
- title: "News download: Make the navbars on the section index pages more useful, adding links to net and previous section"
- title: "Add a button to reset confirm dialogs to Preferences->General"
bug fixes:
- title: "Fix crash in edit metadata dialog if you click OK before cover download completes"
tickets: [6337]
- title: "Kobo driver: Show a warning when the user tries to export/view .kobo files. Also add support for the new sofroot vendor id"
- title: "Update check. Do not be fooled by a redirecting proxy when checking for new version"
tickets: [6325]
- title: "Add book count to tooltip of library button in toolbar"
tickets: [6340]
- title: "Content server: When serving OPDS feeds send the correct content-type header."
tickets: [6329]
- title: "PDF Output: Don't insert blank pages before every individual HTML file in the ebook."
tickets: [6315]
- title: "Fix saving of cover when path to book folder contains non ascii characters"
tickets: [6328]
- title: "Fix regression that broke showing send to actions for multiple email accounts"
- title: "Fix bug in handlling of hexadecimal entities"
tickets: [6305]
- title: "SONY driver: More fixes to handle broken media.xml files"
tickets: [6296]
- title: "Linux installer: Fix rendering of viewer icon and restrict all icons to 128x128 since GNOME can't handle large icons"
- title: "RTF Input: Fix handling of hard linebreaks"
tickets: [6208]
- title: "RTF Output: Fix regression that broke rendering of bold and italic text"
tickets: [6098]
new recipes:
- title: "Draw and Cook"
author: Startson17
improved recipes:
- La Nacion
- Vecernje Novosti
- Der Tagesspiegel
- Die Zeit Nachrichten
- Toms Hardware (DE)
- Welt Online
- version: 0.7.10 - version: 0.7.10
date: 2010-07-23 date: 2010-07-23

View File

@ -0,0 +1,83 @@
/* CSS for the mobile version of the content server webpage */
.navigation table.buttons {
width: 100%;
}
.navigation .button {
width: 50%;
}
.button a, .button:visited a {
padding: 0.5em;
font-size: 1.25em;
border: 1px solid black;
text-color: black;
background-color: #ddd;
border-top: 1px solid ThreeDLightShadow;
border-right: 1px solid ButtonShadow;
border-bottom: 1px solid ButtonShadow;
border-left: 1 px solid ThreeDLightShadow;
-moz-border-radius: 0.25em;
-webkit-border-radius: 0.25em;
}
.button:hover a {
border-top: 1px solid #666;
border-right: 1px solid #CCC;
border-bottom: 1 px solid #CCC;
border-left: 1 px solid #666;
}
div.navigation {
padding-bottom: 1em;
clear: both;
}
#search_box {
border: 1px solid #393;
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
padding: 1em;
margin-bottom: 0.5em;
float: right;
}
#listing {
width: 100%;
border-collapse: collapse;
}
#listing td {
padding: 0.25em;
}
#listing td.thumbnail {
height: 60px;
width: 60px;
}
#listing tr:nth-child(even) {
background: #eee;
}
#listing .button a{
display: inline-block;
width: 2.5em;
padding-left: 0em;
padding-right: 0em;
overflow: hidden;
text-align: center;
}
#logo {
float: left;
}
#spacer {
clear: both;
}

View File

@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
''' '''
Contains various tweaks that affect calibre behavior. Only edit this file if Contains various tweaks that affect calibre behavior. Only edit this file if
you know what you are dong. If you delete this file, it will be recreated from you know what you are doing. If you delete this file, it will be recreated from
defaults. defaults.
''' '''
@ -24,6 +24,7 @@ series_index_auto_increment = 'next'
# invert: use "fn ln" -> "ln, fn" (the original algorithm) # invert: use "fn ln" -> "ln, fn" (the original algorithm)
# copy : copy author to author_sort without modification # copy : copy author to author_sort without modification
# comma : use 'copy' if there is a ',' in the name, otherwise use 'invert' # comma : use 'copy' if there is a ',' in the name, otherwise use 'invert'
# nocomma : "fn ln" -> "ln fn" (without the comma)
author_sort_copy_method = 'invert' author_sort_copy_method = 'invert'
@ -72,4 +73,19 @@ gui_pubdate_display_format = 'MMM yyyy'
# without changing anything is sufficient to change the sort. # without changing anything is sufficient to change the sort.
title_series_sorting = 'library_order' title_series_sorting = 'library_order'
# Control how title and series names are formatted when saving to disk/sending
# to device. If set to library_order, leading articles such as The and A will
# be put at the end
# If set to 'strictly_alphabetic', the titles will be sorted without processing
# For example, with library_order, "The Client" will become "Client, The". With
# strictly_alphabetic, it would remain "The Client".
save_template_title_series_sorting = 'library_order'
# Specify a folder that calibre should connect to at startup using
# connect_to_folder. This must be a full path to the folder. If the folder does
# not exist when calibre starts, it is ignored. If there are '\' characters in
# the path (such as in Windows paths), you must double them.
# Examples:
# auto_connect_to_folder = 'C:\\Users\\someone\\Desktop\\testlib'
# auto_connect_to_folder = '/home/dropbox/My Dropbox/someone/library'
auto_connect_to_folder = ''

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/" xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -10,106 +11,573 @@
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.0" version="1.0"
width="48" width="128"
height="48" height="128"
id="svg2160" id="svg4486"
sodipodi:version="0.32" inkscape:version="0.47 r22583"
inkscape:version="0.45.1" sodipodi:docname="epub.svg">
sodipodi:docname="mobi.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
sodipodi:docbase="/home/kovid/temp">
<sodipodi:namedview
inkscape:window-height="674"
inkscape:window-width="791"
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"
inkscape:zoom="9.6458333"
inkscape:cx="24"
inkscape:cy="24"
inkscape:window-x="0"
inkscape:window-y="31"
inkscape:current-layer="svg2160" />
<metadata <metadata
id="metadata7"> id="metadata52">
<rdf:RDF> <rdf:RDF>
<cc:Work <cc:Work
rdf:about=""> rdf:about="">
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="692"
id="namedview50"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:zoom="2.3256144"
inkscape:cx="73.759964"
inkscape:cy="13.023094"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1"
inkscape:current-layer="svg4486" />
<defs <defs
id="defs2162" /> id="defs4488">
<linearGradient
id="linearGradient3672">
<stop
style="stop-color:#2b2b2b;stop-opacity:1;"
offset="0"
id="stop3674" />
<stop
id="stop3685"
offset="0.5"
style="stop-color:#242424;stop-opacity:1;" />
<stop
style="stop-color:#363636;stop-opacity:1;"
offset="0.75"
id="stop3689" />
<stop
style="stop-color:#2b2b2b;stop-opacity:1;"
offset="1"
id="stop3676" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 64 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="128 : 64 : 1"
inkscape:persp3d-origin="64 : 42.666667 : 1"
id="perspective54" />
<linearGradient
id="linearGradient5048">
<stop
id="stop5050"
style="stop-color:#000000;stop-opacity:0"
offset="0" />
<stop
id="stop5056"
style="stop-color:#000000;stop-opacity:1"
offset="0.5" />
<stop
id="stop5052"
style="stop-color:#000000;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient5060">
<stop
id="stop5062"
style="stop-color:#000000;stop-opacity:1"
offset="0" />
<stop
id="stop5064"
style="stop-color:#000000;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3104">
<stop
id="stop3106"
style="stop-color:#aaaaaa;stop-opacity:1"
offset="0" />
<stop
id="stop3108"
style="stop-color:#c8c8c8;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3600">
<stop
id="stop3602"
style="stop-color:#f4f4f4;stop-opacity:1"
offset="0" />
<stop
id="stop3604"
style="stop-color:#dbdbdb;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:0"
offset="0.25718147" />
<stop
id="stop51"
style="stop-color:#ffffff;stop-opacity:0"
offset="0.30111277" />
<stop
id="stop53"
style="stop-color:#fafafa;stop-opacity:0"
offset="0.53130001" />
<stop
id="stop55"
style="stop-color:#ebecec;stop-opacity:0"
offset="0.84490001" />
<stop
id="stop57"
style="stop-color:#e1e2e3;stop-opacity:0"
offset="1" />
</radialGradient>
<linearGradient
id="linearGradient3211">
<stop
id="stop3213"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop3215"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient8589">
<stop
id="stop8591"
style="stop-color:#fefefe;stop-opacity:1"
offset="0" />
<stop
id="stop8593"
style="stop-color:#cbcbcb;stop-opacity:1"
offset="1" />
</linearGradient>
<filter
x="-0.14846256"
y="-0.16434373"
width="1.2969251"
height="1.3286875"
color-interpolation-filters="sRGB"
id="filter3212">
<feGaussianBlur
stdDeviation="0.77391625"
id="feGaussianBlur3214" />
</filter>
<linearGradient
x1="32.892288"
y1="8.0590115"
x2="36.358372"
y2="5.4565363"
id="linearGradient2455"
xlink:href="#linearGradient8589"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.6605294,0,0,2.7751643,0.7455334,-3.5662351)" />
<linearGradient
x1="24"
y1="1.9999999"
x2="24"
y2="46.01725"
id="linearGradient2459"
xlink:href="#linearGradient3211"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.7575715,0,0,2.6744155,-2.1817183,-4.1859717)" />
<radialGradient
cx="102"
cy="112.3047"
r="139.55859"
id="radialGradient2462"
xlink:href="#XMLID_8_"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9787237,0,0,-1.0535153,1.3617012,127.48164)" />
<linearGradient
x1="25.132275"
y1="0.98520643"
x2="25.132275"
y2="47.013336"
id="linearGradient2465"
xlink:href="#linearGradient3600"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.657139,0,0,2.5422197,0.2286615,-4.9132741)" />
<linearGradient
x1="-51.786404"
y1="50.786446"
x2="-51.786404"
y2="2.9062471"
id="linearGradient2467"
xlink:href="#linearGradient3104"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.1456312,0,0,2.3791388,158.0899,-7.7465258)" />
<linearGradient
x1="302.85715"
y1="366.64789"
x2="302.85715"
y2="609.50507"
id="linearGradient2483"
xlink:href="#linearGradient5048"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.1725148,0,0,0.03920058,0.6482238,98.773724)" />
<radialGradient
cx="605.71429"
cy="486.64789"
r="117.14286"
fx="605.71429"
fy="486.64789"
id="radialGradient2485"
xlink:href="#linearGradient5060"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.05903807,0,0,0.03920058,56.929907,98.773804)" />
<radialGradient
cx="605.71429"
cy="486.64789"
r="117.14286"
fx="605.71429"
fy="486.64789"
id="radialGradient2487"
xlink:href="#linearGradient5060"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.05903808,0,0,0.03920058,69.07008,98.773804)" />
<inkscape:perspective
id="perspective2878"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient7012-661-145-733-759-865-745-661-970-94"
id="linearGradient2989"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.7993221,0,0,1.0036506,40.855793,-1.5607197)"
x1="-22.539846"
y1="11.109024"
x2="-22.539846"
y2="46.263954" />
<linearGradient
id="linearGradient7012-661-145-733-759-865-745-661-970-94">
<stop
offset="0"
style="stop-color:#f0c178;stop-opacity:1"
id="stop3618" />
<stop
offset="0.5"
style="stop-color:#e18941;stop-opacity:1"
id="stop3270" />
<stop
offset="1"
style="stop-color:#ec4f18;stop-opacity:1"
id="stop3620" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3390-178-986-453"
id="linearGradient2991"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.9110051,0,0,0.9769973,0.6027366,-0.94793564)"
x1="9.4919996"
y1="46.314064"
x2="9.4919996"
y2="1.7164899" />
<linearGradient
id="linearGradient3390-178-986-453">
<stop
offset="0"
style="stop-color:#c92e13;stop-opacity:1;"
id="stop3624" />
<stop
offset="1"
style="stop-color:#dea176;stop-opacity:1;"
id="stop3626" />
</linearGradient>
<linearGradient
y2="46.263954"
x2="-22.539846"
y1="11.109024"
x1="-22.539846"
gradientTransform="matrix(1.2084176,0,0,2.666214,69.448297,-3.8858475)"
gradientUnits="userSpaceOnUse"
id="linearGradient2892"
xlink:href="#linearGradient7012-661-145-733-759-865-745-661-970-94"
inkscape:collect="always" />
<linearGradient
y2="1.7164899"
x2="9.4919996"
y1="46.314064"
x1="9.4919996"
gradientTransform="matrix(1.3772603,0,0,2.595409,8.5935979,-2.257977)"
gradientUnits="userSpaceOnUse"
id="linearGradient2894"
xlink:href="#linearGradient3390-178-986-453"
inkscape:collect="always" />
<inkscape:perspective
id="perspective3666"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
x1="302.85715"
y1="366.64789"
x2="302.85715"
y2="609.50507"
id="linearGradient19619"
xlink:href="#linearGradient5048-1"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.08449704,0,0,0.01235294,-6.5396456,38.470822)" />
<linearGradient
id="linearGradient5048-1">
<stop
id="stop5050-2"
style="stop-color:black;stop-opacity:0"
offset="0" />
<stop
id="stop5056-0"
style="stop-color:black;stop-opacity:1"
offset="0.5" />
<stop
id="stop5052-7"
style="stop-color:black;stop-opacity:0"
offset="1" />
</linearGradient>
<radialGradient
cx="605.71429"
cy="486.64789"
r="117.14286"
fx="605.71429"
fy="486.64789"
id="radialGradient19616"
xlink:href="#linearGradient5060-3"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.0289166,0,0,0.01235294,21.026894,38.470848)" />
<linearGradient
id="linearGradient5060-3">
<stop
id="stop5062-1"
style="stop-color:black;stop-opacity:1"
offset="0" />
<stop
id="stop5064-1"
style="stop-color:black;stop-opacity:0"
offset="1" />
</linearGradient>
<radialGradient
cx="605.71429"
cy="486.64789"
r="117.14286"
fx="605.71429"
fy="486.64789"
id="radialGradient19613"
xlink:href="#linearGradient5060-3"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.02891661,0,0,0.01235294,26.973101,38.470848)" />
<linearGradient
id="linearGradient3680">
<stop
id="stop3682"
style="stop-color:black;stop-opacity:1"
offset="0" />
<stop
id="stop3684"
style="stop-color:black;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
x1="108.26451"
y1="110.28094"
x2="25.817675"
y2="14.029031"
id="linearGradient19610"
xlink:href="#linearGradient259-942"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.5066363,0,0,0.3512482,-58.338079,-49.085986)" />
<linearGradient
id="linearGradient259-942">
<stop
id="stop3802"
style="stop-color:white;stop-opacity:1"
offset="0" />
<stop
id="stop3804"
style="stop-color:#e0e0e0;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3650"
id="linearGradient3656"
x1="-44.02877"
y1="-26.590452"
x2="-4.1013746"
y2="-26.590452"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3650">
<stop
style="stop-color:#73d216;stop-opacity:1;"
offset="0"
id="stop3652" />
<stop
style="stop-color:#8ae234;stop-opacity:1;"
offset="1"
id="stop3654" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3672"
id="linearGradient3682"
x1="32.254131"
y1="57.967407"
x2="98.357651"
y2="57.967407"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(19.439951,41.709408)" />
<inkscape:perspective
id="perspective2970"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2984"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3890"
inkscape:persp3d-origin="150 : 23.333333 : 1"
inkscape:vp_z="300 : 35 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 35 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3915"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4057"
inkscape:persp3d-origin="150 : 23.333333 : 1"
inkscape:vp_z="300 : 35 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 35 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4082"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<g <g
id="layer1"> transform="matrix(1.0408163,0,0,0.6302428,-1.5714269,43.690218)"
<image id="g2478">
id="image2226" <rect
width="48" width="83.299995"
y="0" height="9.5201406"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI x="21.349998"
WXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAwAAAAMADO7oxXAAALJUlEQVRo3u2ae3DTVRbHP3k1 y="113.14653"
v6ZJk4a+W1NalAJSy4qtvKS4iCKOYtcHvvCxDuuMozu62vVRdGcRfOzsODoq7o4jyoyy49aFqYoO id="rect2879"
7rJjaREsKi2F0sC2CNImado82ib5/fJo9o+0vzS2pe2i4B97/rq553fu7/u9597zu+fcKB56+OFo style="opacity:0.3;fill:url(#linearGradient2483);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" />
bnY2fr8fKRgkIIpIosiwaAUBAK/HA8A0s1nW6fV6RsrGTZsUnGNRPL9pU/T3TzyZ0OnxuEe0PUiS <path
hBiIkero6MDb50UMBJCCQex2OwFRRK1UyjY+vx+320NamglRFDGaTLz+2ms/CTn1WJ0mU9qYbYDS d="m 21.35,113.14694 c 0,0 0,9.51962 0,9.51962 -3.040314,0.0179 -7.35,-2.13287 -7.35,-4.76043 0,-2.62755 3.392762,-4.75919 7.35,-4.75919 z"
efPGHWyY+GPbtuNtP8ZTa29HCkp8unMn66uroz+Fh9RnP0RcPm5u5s26Iyj1M3nghhky2dbWVg63 id="path2881"
tPzY2M+ewMleD0fajnGk8yQ72rpR6meSlrsU6/F/smzWHT8J4EkR2NnUwvYvGznaI57RWKmfiV6n style="opacity:0.3;fill:url(#radialGradient2485);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" />
J90wl5yCKGIogj8cpaLAiEGrPX8ENn20h7WrbuayEX2u/hAAPilMMDRIIDSIFB5EDEUIhOPgHQMe <path
VllSzwl4AOVkHposeF84QtD5NeuuvurnQ2Aq4AfEfioKjOcM/IQEpgLeGx7E2dPOQ1cv+3kQmDL4 d="m 104.64999,113.14694 c 0,0 0,9.51962 0,9.51962 3.04032,0.0179 7.35001,-2.13287 7.35001,-4.76043 0,-2.62755 -3.39277,-4.75919 -7.35001,-4.75919 z"
cJQbLIMUppsn/fKflMBUwfedbuaxFVeeU/BnJDAl8JFB7pkJuRnxr7YoipMCcNYE/H7/mIqpgKdj id="path2883"
d8LsnyvwcAYPTBq8388Lyy9khiX350VgUuCBctURfrv6+kRbSTr/BCYDPs19hDfuWDnaNvAz8MBE style="opacity:0.3;fill:url(#radialGradient2487);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" />
4LG18PK1hcy5IG+Uba+r9/wTmAj8O5UzuHXBglF2nqHM7bwTONOyeadyBmsrlo1p5/V4zymBcfOB
8Wb+hpmMCx6g025HSNJM+OL11dVRKRiUfw977q233ppS1jYugVHgxTCkzWbrKRtsfpu3H7x/TLtu
uw2LxTKmrqqqKhoQRfqkKKecMU8lZZoJdrvQAnapi0WLFkUBcnPz+PDDmgnJjEtgFPhhSc5h6ylg
89tsvv/OBBuPx4MYCAAgDFUzACwWC3V1dSiSjcxetoQ8IJixEJ8UJq3vAMyBJFsns5iF7cFaQnXT
cLZFKCsrixYVXcQHH2wbl8i4e2BM8AkkTPx9//6E7tY2KwAqTTwbe/fdd/j6wAHmXHsdV66pRF+0
FE3uLMwGDSlaNe7UMvlZ2+JacvauRlPRS+4DPVTeeCP9Of9hxYoV0SkTGBf8CBKP7mhM6DpubUOt
UsneePyx3wGx2lJawWwGUmYP/c7E1R+SSTiS5+PTGcjZuxrb4lrMu68BwLV8F8svWMOcq/QsWrFo
TBLjEzgT+CHxCDNkL9hsNux2u6x78smnmFtSAsCMOSUUqsKsKtSywDQAQJJzX8JYUr9IS84qnI13
oRUEzLuvQWfVYltci0W9hMsrBXl/TN4DE0lyDl8caQdg/4jltGP7hyxcuACLxYKqsBCtUsWg1yPr
NREnIW8fAx178ElhkjRKfBddS7SnHk/KQnw6A67luwDI2bsaSRTJcC/HVB5mzZo7EkicHQGQKxf7
v/oKgPYTJ0gWBMzz5tHd3U1+RhYhQYc0GKHl22843Pk9IVUGutnl6IuWkqJVk6KNxRJF+hUkqxX0
/eI9efxDGgNWQwau5bu4NGUFfn//j+iBIdm7dy92W2z5dPa0U1xcTF4kIuu7jx/h+/YTlFw6n7l5
FwCxfSCJ3UAs9xiWS07Xjhp/n/8iAHQ6HWk5BVRVVcleOGsClbMyqampAWIbN2NWFEEQ6FSpEEUR
x6EmLBYLupRkXO5e9nviBeFQV5vcDoRiUc9qyEC752YAPnG/gFW0cCwi8NEXf+Rd1SLasmcmHFeU
I7+GU5aAjYHT3TQ1NQFgt9spmXYdmspdRE6cAKAgP3bYi0aCCeABHMnzRw3pSVlIUsgvk2gdTCNV
peRYRGCh7jhrjCF84fhhUR04i+RjevQk1sZ4KDWka2Ifsr9VIAgCzp5eGrocZGdl0OnoIY9Pcer0
6IuW4uoPkaRR4h6ITaAUHsQdCGPy7aPDYKZDWYZXjBUWKnXNmAKfoSnvhb2r0RjjS04pjUFgdrrA
hBKwcYmqg4aGehTKWOyfe+F8hj2qqdyFRqUk5O0jcuIEeVnpGG6vw9DrlCseAFmBb+TlM1KKBg9w
Z0Y1v1lWRYGxBk1FfNb7uuLPqQEkSUSrjYNeYdaxtbkOcivGBU/DmzR+d3RMteH2OrldfHe93HZu
Kad/WgYQLxpYKYWh2R+WAmMN/mKJsbP1RFECuN3uhM7bbrudu1V26KqLgR0JvKsOGt5E/XU9fp+P
oqIiysvLWHPrrfg0hnFf5NxSji0QxZ1allDxEEMRxFAsYomhiAxeZ51ccVgN4LA7yM7OSVBs2fwq
S999h+0fb+PL7xspzb2MFJWSJeVlZC68k+IXn2XhkqUJNk0vv4EroiF/6LcUDOLcUo5LrcWVfyVZ
gW9wDAGH2LoPhGMR0RWY+Muvs2pRqhLPn2qAg00Hx7x5uffe+7j33vtG9dfVN1C/t4Gc/AuYPr1Q
7p97URG1fdMx/yWEbXEtLD7JaetmjMkaGF4uQ0CHc24AX8ALpNAlhviSP7DI+keMPSvxF9eis2o5
6b2Fot0u8rLS6cdHOBD/GCuzMjNpam4eBdLjcVNX30BdfUNC/2uvv85gfx+P5inY8kDicdqkSyYQ
jnJIY8DZeBc6q5YZjn9j7w/iDYRwB8JEe+pxB8IEwlFcgbA8811iCGc4SuOAhg2nN1ATuZg/736J
Dac3ANBhMOPU6Wk9cpjs7Ow4gY2bNim8Hg92uy0B/MbnniNJMcjsDY/zp5delHXdtk6WuFpwb91B
yqGTCQTL5pdi8sUOaR3KMow98YrF8Gx3KucghiIycF84gissYFQr6YsMysf44fh/jyF2NaVIv4Ik
Wyd2uz0ha1NCLPlobW2VX7bxued45u5fcem+f6A63Y9vTxxkkuTDvXUHqtOxM0lpycVxD5jSWGHW
AaDFx2fayzGrQph8++TZlkghO9iIFh9afJQovyUp2ENSsEceJ1WlpFLXTIZaQYeyDMm4CK1aSVtb
W8LsywRSdDpaRlzCGRVhhM9rGNjyr1FLK9TytQw+eOdNo24xV65cSb4ocrn/W1xhAVdEQ1G/Cy0+
IBbfi/udzLvsaeZd9jQZ5e+xZOnzFAunmKkSWaCJpZpW0YJRrcScrCY7VUvk0PtoBWFUzqwGeOXV
VxVr166Vd0aXL8jAlnj8LrzlJrn967++z9sffEBmVhbP/GCDezxuTn53EoXXweeqLErSv2U3Myk2
nOIKbwN6QYNtcS0uwLz7GsT8L2TbfFHkWESAiECqCvQ6PSnJWuYH9yEdF/E5bLw+RsIvd6xbty76
yCOPUFw8i+amJrZXrycadqH/5Q388CL8h4APNh2kqblZvs03mkwkCwI1g5lUFBjZ2l/Cs/nPAuAv
jpcddVatHPNfsW0kGz92dJTqk8gzaCjVHKa9tRWFwzZutSIhqB48eJDi4lmUzptH6c5PRj1st9uw
Hm/n6OFDtB07lgDYlJo66ja+qqoqum3/UcovFIk4rkda+qEMeiSJYbHoNRSqtWQHG8ELrQfqY7f8
Zyi1yIr11dVRR3c3TzzxBNOnF2K323DYHRxtO0rb0aM4urvlqvM0sxm9Xj+p/0asr66OnnJ6sSUL
5AREpi+OJf5eux5NRa9MIOK4HkdfD6HMfHwH95GmVpOVmTnhOxKU69atiw6DFAQBURQRBGFSA02G
iKevD6/HQ7u9HU2GREawiIhSIkmbRCSgIC3NhFYQMKWmnpc/jvxf/hf5L875Zqc0KDqlAAAAAElF
TkSuQmCC
"
x="0"
height="48" />
</g> </g>
<path
d="m 17.499961,1.499962 c 21.311039,0 42.622077,0 63.933118,0 3.738416,1.2619859 23.822451,15.639336 29.066961,25.594247 0,30.468614 0,60.937223 0,91.405831 -31.000026,0 -62.000051,0 -93.000079,0 0,-39.000023 0,-78.000052 0,-117.000078 z"
id="path4160"
style="fill:url(#linearGradient2465);fill-opacity:1;stroke:url(#linearGradient2467);stroke-width:0.99992192;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" />
<path
d="M 18.978723,118 C 18.439449,118 18,117.52697 18,116.94648 L 18,3.1668773 C 18,2.5853392 18.439449,2.1133645 18.978723,2.1133645 39.22709,2.4045657 61.66587,1.6777678 81.889633,2.1858707 L 109.71323,26.088148 110,116.94648 C 110,117.52697 109.56154,118 109.02128,118 l -90.042557,0 z"
id="path4191"
style="fill:url(#radialGradient2462);fill-opacity:1" />
<path
d="m 109.50003,26.517935 c 0,29.94778 0,61.034321 0,90.982105 -30.333353,0 -60.666712,0 -91.00007,0 0,-38.333364 0,-76.666721 0,-115.0000784 20.852737,0 42.202796,0 63.055535,0"
id="path2435"
style="opacity:0.6;fill:none;stroke:url(#linearGradient2459);stroke-width:0.99992174;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline" />
<path
d="m 28.617256,0.92125832 c 4.282522,0 2.15325,8.48317128 2.15325,8.48317128 0,0 10.357642,-1.8023467 10.357642,2.8187444 0,-2.6097233 -11.302304,-10.7285956 -12.510892,-11.30191568 z"
transform="matrix(2.6666667,0,0,2.6666667,0.3087257,-0.6174513)"
id="path12038"
style="opacity:0.4;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline;filter:url(#filter3212)" />
<path
d="m 76.62141,1.8392376 c 8.497314,0 6.228693,20.4316764 6.228693,20.4316764 0,0 27.133687,-2.616144 27.133687,9.706766 0,-3.002504 0.2291,-5.152653 -0.35674,-6.089581 C 105.41822,19.156956 87.239007,4.052365 80.67425,2.0726634 80.182991,1.9245177 79.093706,1.8392376 76.62141,1.8392376 z"
id="path4474"
style="fill:url(#linearGradient2455);fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline" />
<path
style="fill:url(#linearGradient2892);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2894);stroke-width:1.00930357;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:block;overflow:visible"
id="path4530"
d="m 25.816692,118.46233 c -2.652245,0 -5.304508,0 -7.956769,0 -0.64465,-1.3837 -0.154446,-4.13089 -0.307623,-6.08978 0,-36.699903 0,-73.399803 0,-110.0996953 l 0.08995,-0.4752429 0.217716,-0.1962367 0,0 c 2.76046,0 5.088125,0 7.848554,0" />
<text
xml:space="preserve"
style="font-size:72px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
x="38.310501"
y="64.757271"
id="text2892"><tspan
sodipodi:role="line"
id="tspan2894" /></text>
<text
xml:space="preserve"
style="font-size:28px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:FreeSans;-inkscape-font-specification:FreeSans"
x="35.259502"
y="109.51025"
id="text3772"><tspan
sodipodi:role="line"
id="tspan3774"
x="35.259502"
y="109.51025"
style="font-size:28px;fill:#000000;fill-opacity:1">mobi</tspan></text>
<path
id="path3858"
d="m 100.22334,68.053513 c -8.716894,6.432161 -21.357191,9.853809 -32.243032,9.853809 -15.251419,0 -28.989193,-5.636741 -39.38419,-15.021522 -0.815557,-0.738364 -0.08726,-1.746902 0.89191,-1.173831 11.217267,6.527812 25.085933,10.456247 39.410201,10.456247 9.664184,0 20.284886,-2.004491 30.058986,-6.151079 1.474215,-0.623415 2.709285,0.97246 1.266125,2.036376 z"
style="fill:#ff9201;fill-rule:evenodd" />
<path
id="path3860"
d="m 103.85056,63.911959 c -1.11342,-1.426386 -7.371902,-0.676274 -10.179364,-0.337298 -0.853315,0.09817 -0.984206,-0.641874 -0.217315,-1.184739 4.990672,-3.505554 13.168059,-2.491141 14.119539,-1.318987 0.95736,1.187256 -0.25087,9.384779 -4.92858,13.293915 -0.71907,0.604117 -1.40373,0.286117 -1.08573,-0.510142 1.05133,-2.631263 3.40906,-8.515524 2.29145,-9.942749 z"
style="fill:#ff9201;fill-rule:evenodd" />
<path
id="path4047"
d="m 69.299213,48.156661 c 0,2.157 0.052,3.954 -1.035,5.874 -0.88,1.561 -2.279,2.517 -3.833,2.517 -2.121,0 -3.366,-1.62 -3.366,-4.015 0,-4.714 4.232,-5.571 8.233,-5.571 v 1.195 z m 5.579,13.496 c -0.365,0.332 -0.896,0.352 -1.307,0.132 -1.838,-1.528 -2.167,-2.231 -3.174,-3.69 -3.035,3.094 -5.188,4.023 -9.123,4.023 -4.663,0 -8.284,-2.876 -8.284,-8.629 0,-4.49 2.433,-7.544 5.899,-9.045 3.005,-1.317 7.202,-1.556 10.41,-1.914 v -0.723 c 0,-1.313 0.104,-2.875 -0.671,-4.012 -0.674,-1.021 -1.968,-1.437 -3.106,-1.437 -2.111,0 -3.99,1.078 -4.45,3.321 -0.097,0.498 -0.46,0.991 -0.962,1.017 l -5.364,-0.581 c -0.456,-0.102 -0.958,-0.463 -0.828,-1.155 1.233,-6.511 7.109,-8.475 12.378,-8.475 2.693,0 6.215,0.719 8.335,2.757 2.693,2.515 2.432,5.869 2.432,9.524 v 8.623 c 0,2.596 1.081,3.732 2.091,5.128 0.354,0.503 0.434,1.103 -0.018,1.473 -1.131,0.949 -3.139,2.693 -4.244,3.676 l -0.014,-0.013 z"
style="fill-rule:evenodd" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.0" width="128" height="128" id="svg2176">
<defs id="defs2178">
<linearGradient x1="406.065" y1="290.50299" x2="406.065" y2="276.29501" id="linearGradient4819" xlink:href="#linearGradient7431" gradientUnits="userSpaceOnUse" gradientTransform="matrix(4.80814, 0, 0, 2.87475, -1569.44, -758.786)" spreadMethod="pad"/>
<linearGradient x1="68.374298" y1="-410.099" x2="67.912201" y2="-478.508" id="linearGradient4817" xlink:href="#linearGradient11367" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.58223, 0, 0, -0.727268, 275.522, -213.417)" spreadMethod="pad"/>
<linearGradient x1="436.48801" y1="-278.91299" x2="436.51199" y2="-299.88699" id="linearGradient4815" xlink:href="#linearGradient11377" gradientUnits="userSpaceOnUse" gradientTransform="matrix(4.59378, 0, 0, 0.359494, -1920.95, 434.897)" spreadMethod="pad"/>
<linearGradient id="linearGradient11377">
<stop id="stop11379" style="stop-color: rgb(255, 255, 255); stop-opacity: 0;" offset="0"/>
<stop id="stop11385" style="stop-color: rgb(255, 255, 255); stop-opacity: 0.575472;" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient11367">
<stop id="stop11369" style="stop-color: rgb(0, 0, 0); stop-opacity: 0;" offset="0"/>
<stop id="stop11371" style="stop-color: rgb(0, 0, 0); stop-opacity: 0.254717;" offset="0.72131097"/>
<stop id="stop18428" style="stop-color: rgb(0, 0, 0); stop-opacity: 0.12549;" offset="0.91000003"/>
<stop id="stop11375" style="stop-color: rgb(0, 0, 0); stop-opacity: 0;" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient7431">
<stop id="stop7433" style="stop-color: rgb(255, 255, 255); stop-opacity: 0;" offset="0"/>
<stop id="stop7439" style="stop-color: rgb(255, 255, 255); stop-opacity: 0.858491;" offset="0.72000003"/>
<stop id="stop8224" style="stop-color: rgb(255, 255, 255); stop-opacity: 0.707547;" offset="0.89999998"/>
<stop id="stop7435" style="stop-color: rgb(255, 255, 255); stop-opacity: 0.320755;" offset="1"/>
</linearGradient>
<filter id="filter3659">
<feGaussianBlur inkscape:collect="always" stdDeviation="0.25192676" id="feGaussianBlur3661"/>
</filter>
</defs>
<g id="layer1">
<g transform="matrix(1.1475, 0, 0, 1.1475, -368.661, -33.5075)" id="g4500">
<path d="M 326.964,34.4298 L 423.481,34.4298 C 437.856,66.0223 403.767,104.222 423.481,135.402 L 326.964,135.402 L 326.964,34.4298 z" id="path21978" style="fill: rgb(95, 123, 141); fill-opacity: 1; fill-rule: evenodd; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
<path d="M 326.964,34.4298 L 353.143,34.4298 C 367.518,66.0223 333.429,104.222 353.143,135.402 L 326.964,135.402 L 326.964,34.4298 z" id="path21980" style="fill: rgb(29, 70, 89); fill-opacity: 1; fill-rule: evenodd; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
<rect width="101.089" height="7.9108801" x="34.429798" y="326.96399" transform="matrix(0, 1, 1, 0, 0, 0)" id="rect21982" style="fill: url(&quot;#linearGradient4815&quot;) rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
<g transform="matrix(3.17412, 0, 0, 3.17412, 1038.99, -354.131)" id="g21984">
<path d="M -218.445,122.416 C -213.917,132.369 -224.656,144.405 -218.445,154.228 L -216.32,154.228 C -222.531,144.405 -211.792,132.369 -216.32,122.416 L -218.445,122.416 z" id="path21986" style="fill: rgb(0, 0, 0); fill-opacity: 0.0798122; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
<path d="M -217.955,122.416 C -213.426,132.369 -224.166,144.405 -217.955,154.228 L -216.32,154.228 C -222.531,144.405 -211.792,132.369 -216.32,122.416 L -217.955,122.416 z" id="path21988" style="fill: rgb(0, 0, 0); fill-opacity: 0.131455; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
<path d="M -217.403,122.416 C -212.875,132.369 -223.614,144.405 -217.403,154.228 L -216.32,154.228 C -222.531,144.405 -211.792,132.369 -216.32,122.416 L -217.403,122.416 z" id="path21990" style="fill: rgb(0, 0, 0); fill-opacity: 0.197183; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
<path d="M -216.852,122.416 C -212.323,132.369 -223.063,144.405 -216.852,154.228 L -216.32,154.228 C -222.531,144.405 -211.792,132.369 -216.32,122.416 L -216.852,122.416 z" id="path21992" style="fill: rgb(0, 0, 0); fill-opacity: 0.267606; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
</g>
<path d="M 326.964,135.402 L 422.488,135.402 C 412.274,118.171 416.819,101.345 421.306,83.5374 L 326.964,83.2034 L 326.964,135.402 z" id="path21994" style="fill: url(&quot;#linearGradient4817&quot;) rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
<g transform="matrix(2.41517, 0, 0, 2.41517, 876.456, -197.189)" id="g21996">
<path d="M 602.125,190.59375 C 599.45874,190.67075 596.74504,191.16798 594.53125,192.78125 C 591.5146,192.34561 588.3664,192.55749 585.5,193.6875 C 583.62824,194.43267 582.15635,195.77855 580.96875,197.34375 C 580.95544,197.36301 580.94492,197.38405 580.9375,197.40625 C 580.92091,197.43509 580.91029,197.46697 580.90625,197.5 C 580.91029,197.53303 580.92091,197.56491 580.9375,197.59375 C 580.94492,197.61595 580.95544,197.63699 580.96875,197.65625 C 580.97822,197.66757 580.98868,197.67803 581,197.6875 C 581.02605,197.71524 581.05813,197.73662 581.09375,197.75 C 581.12472,197.75595 581.15653,197.75595 581.1875,197.75 C 581.20825,197.75263 581.22925,197.75263 581.25,197.75 C 584.80749,196.49944 588.39295,195.15225 592.15625,195.5 C 593.28385,195.58867 594.35616,196.00271 595.46875,196.375 C 595.50974,196.38565 595.55276,196.38565 595.59375,196.375 C 595.62678,196.37096 595.65866,196.36034 595.6875,196.34375 C 595.7097,196.33633 595.73074,196.32581 595.75,196.3125 C 598.71379,193.45164 603.00891,192.72955 606.96875,191.90625 C 606.98007,191.89678 606.99053,191.88632 607,191.875 C 607.19563,191.80037 607.32956,191.73576 607.4375,191.625 C 607.49147,191.56962 607.55414,191.50784 607.5625,191.40625 C 607.57086,191.30466 607.51945,191.21518 607.46875,191.15625 C 607.36735,191.03839 607.25573,190.98239 607.125,190.9375 C 606.99427,190.89261 606.8215,190.87546 606.65625,190.84375 C 605.99526,190.71692 605.12704,190.6454 604.8125,190.625 C 604.80209,190.62434 604.79166,190.62434 604.78125,190.625 C 603.91011,190.58739 603.02603,190.56773 602.125,190.59375 z" transform="translate(-806.724, -92.8004)" id="path21998" style="fill: rgb(0, 0, 0); fill-opacity: 1; fill-rule: evenodd; stroke: none; stroke-width: 1pt; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1;"/>
<path d="M -224.344,103.835 C -219.295,101.9 -214.705,101.331 -211.263,102.86 C -208.45,100.119 -202.237,98.6242 -200.227,98.6199 C -207.528,97.8352 -210.552,99.4967 -212,100.582 C -216.698,100.015 -221.096,100.522 -224.344,103.834" id="path22000" style="fill: rgb(255, 255, 255); fill-opacity: 1; stroke: none;"/>
</g>
<g transform="matrix(2.41517, 0, 0, 2.41517, 876.456, -197.189)" id="g22002">
<path d="M 596.25,27.53125 C 587.9033,27.701471 579.93436,30.011449 573.84375,35.03125 C 565.49276,31.223728 554.44432,30.751141 544.375,32.28125 C 538.97209,33.102263 533.8987,34.480363 529.6875,36.34375 C 525.4884,38.201779 521.99675,40.484175 520.1875,43.8125 C 519.57732,44.883163 519.7128,46.206199 520.46875,47.15625 C 521.22471,48.106278 522.5049,48.470375 523.65625,48.125 C 544.63433,42.131263 561.86554,43.038041 573.6875,52.875 C 574.80806,53.806374 576.46471,53.801852 577.5625,52.84375 C 587.80668,43.812696 604.05857,37.910216 621.5625,38.875 C 622.98852,38.943575 624.2874,37.997938 624.625,36.625 C 624.96264,35.252044 624.25302,33.783013 622.96875,33.1875 C 614.73544,29.461107 605.28688,27.346954 596.25,27.53125 z" transform="matrix(0.292292, -0.0677077, 0.0677077, 0.292292, -381.543, 134.276)" id="path22004" style="fill: rgb(0, 0, 0); fill-opacity: 1; fill-rule: evenodd; stroke: none; stroke-width: 1pt; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1;"/>
<path d="M -225.696,112.15 C -219.345,108.564 -214.201,107.915 -209.842,110.097 C -206.945,105.454 -199.625,102.766 -197.16,102.691 C -204.796,101.053 -210.086,104.587 -211.05,106.575 C -215.328,105.394 -224.104,108.305 -225.696,112.149" id="path22006" style="fill: rgb(255, 255, 255); fill-opacity: 1; stroke: none;"/>
</g>
<g transform="matrix(1.14159, 0, 0, 1.14159, 265.142, -259.674)" id="g22010">
<path d="M 134.221,257.626 C 146.813,285.3 116.952,318.766 134.221,346.078 L 138.68,346.078 C 121.411,318.766 151.272,285.3 138.68,257.626 L 134.221,257.626 z" id="path22012" style="fill: rgb(0, 0, 0); fill-opacity: 0.0798122; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
<path d="M 135.222,257.626 C 147.814,285.3 117.953,318.766 135.222,346.078 L 138.68,346.078 C 121.411,318.766 151.272,285.3 138.68,257.626 L 135.222,257.626 z" id="path22014" style="fill: rgb(0, 0, 0); fill-opacity: 0.131455; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
<path d="M 136.393,257.626 C 148.985,285.3 119.124,318.766 136.393,346.078 L 138.68,346.078 C 121.411,318.766 151.272,285.3 138.68,257.626 L 136.393,257.626 z" id="path22016" style="fill: rgb(0, 0, 0); fill-opacity: 0.197183; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
<path d="M 137.564,257.626 C 150.156,285.3 120.295,318.766 137.564,346.078 L 138.68,346.078 C 121.411,318.766 151.272,285.3 138.68,257.626 L 137.564,257.626 z" id="path22018" style="fill: rgb(0, 0, 0); fill-opacity: 0.267606; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
<path d="M 133.134,257.626 C 145.726,285.3 115.865,318.766 133.134,346.078 L 138.68,346.078 C 121.411,318.766 151.272,285.3 138.68,257.626 L 133.134,257.626 z" id="path22020" style="fill: rgb(0, 0, 0); fill-opacity: 0.0798122; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
</g>
<g transform="matrix(1.14159, 0, 0, 1.14159, -389.722, -484.947)" id="g22103">
<path d="M 653.161,498.44 L 693.751,498.44" id="path21604" style="fill: rgb(96, 123, 142); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(255, 254, 255); stroke-width: 8; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dashoffset: 0pt; stroke-opacity: 0.698039;"/>
<path d="M 653.161,515.294 L 683.452,515.294" id="path21606" style="fill: rgb(96, 123, 142); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(255, 254, 255); stroke-width: 8; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dashoffset: 0pt; stroke-opacity: 0.698039;"/>
<path d="M 653.161,532.46 L 693.751,532.46" id="path22101" style="fill: rgb(96, 123, 142); fill-opacity: 1; fill-rule: nonzero; stroke: rgb(255, 254, 255); stroke-width: 8; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dashoffset: 0pt; stroke-opacity: 0.698039;"/>
</g>
<path d="M 326.964,34.4298 L 423.285,34.4298 C 433.146,54.4709 420.531,82.4058 417.826,102.327 L 326.964,102.327 L 326.964,34.4298 z" id="path22008" style="fill: url(&quot;#linearGradient4819&quot;) rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-opacity: 1;"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

View File

@ -0,0 +1,60 @@
from calibre.web.feeds.news import BasicNewsRecipe
class DrawAndCook(BasicNewsRecipe):
title = 'DrawAndCook'
__author__ = 'Starson17'
description = 'Drawings of recipes!'
language = 'en'
publisher = 'Starson17'
category = 'news, food, recipes'
use_embedded_content= False
no_stylesheets = True
oldest_article = 24
remove_javascript = True
remove_empty_feeds = True
cover_url = 'http://farm5.static.flickr.com/4043/4471139063_4dafced67f_o.jpg'
max_articles_per_feed = 30
remove_attributes = ['style', 'font']
def parse_index(self):
feeds = []
for title, url in [
("They Draw and Cook", "http://www.theydrawandcook.com/")
]:
articles = self.make_links(url)
if articles:
feeds.append((title, articles))
print 'feeds are: ', feeds
return feeds
def make_links(self, url):
soup = self.index_to_soup(url)
title = ''
date = ''
current_articles = []
soup = self.index_to_soup(url)
recipes = soup.findAll('div', attrs={'class': 'date-outer'})
for recipe in recipes:
title = recipe.h3.a.string
page_url = recipe.h3.a['href']
current_articles.append({'title': title, 'url': page_url, 'description':'', 'date':date})
return current_articles
keep_only_tags = [dict(name='h3', attrs={'class':'post-title entry-title'})
,dict(name='div', attrs={'class':'post-body entry-content'})
]
remove_tags = [dict(name='div', attrs={'class':['separator']})
,dict(name='div', attrs={'class':['post-share-buttons']})
]
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;}
img {max-width:100%; min-width:100%;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''

View File

@ -6,31 +6,38 @@ class AssociatedPress(BasicNewsRecipe):
title = u'Associated Press' title = u'Associated Press'
description = 'Global news' description = 'Global news'
__author__ = 'Kovid Goyal' __author__ = 'Kovid Goyal and Sujata Raman'
use_embedded_content = False use_embedded_content = False
language = 'en' language = 'en'
no_stylesheets = True
max_articles_per_feed = 15 max_articles_per_feed = 15
html2lrf_options = ['--force-page-break-before-tag="chapter"'] html2lrf_options = ['--force-page-break-before-tag="chapter"']
preprocess_regexps = [ (re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in preprocess_regexps = [ (re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in
[ [
(r'<HEAD>.*?</HEAD>' , lambda match : '<HEAD></HEAD>'), (r'<span class="entry-content">', lambda match : '<div class="entry-content">'),
(r'<body class="apple-rss-no-unread-mode" onLoad="setup(null)">.*?<!-- start Entries -->', lambda match : '<body>'),
(r'<!-- end apple-rss-content-area -->.*?</body>', lambda match : '</body>'),
(r'<script.*?>.*?</script>', lambda match : ''),
(r'<body.*?>.*?<span class="headline">', lambda match : '<body><span class="headline"><chapter>'),
(r'<tr><td><div class="body">.*?<p class="ap-story-p">', lambda match : '<p class="ap-story-p">'),
(r'<p class="ap-story-p">', lambda match : '<p>'),
(r'Learn more about our <a href="http://apdigitalnews.com/privacy.html">Privacy Policy</a>.*?</body>', lambda match : '</body>'),
] ]
] ]
keep_only_tags = [ dict(name='div', attrs={'class':['body']}),
dict(name='div', attrs={'class':['entry-content']}),
]
remove_tags = [dict(name='table', attrs={'class':['ap-video-table','ap-htmlfragment-table','ap-htmltable-table']}),
dict(name='span', attrs={'class':['apCaption','tabletitle']}),
dict(name='td', attrs={'bgcolor':['#333333']}),
]
extra_css = '''
.headline{font-family:Verdana,Arial,Helvetica,sans-serif;font-weight:bold;}
.bline{color:#003366;}
body{font-family:Arial,Helvetica,sans-serif;}
'''
feeds = [ ('AP Headlines', 'http://hosted.ap.org/lineups/TOPHEADS-rss_2.0.xml?SITE=ORAST&SECTION=HOME'),
('AP US News', 'http://hosted.ap.org/lineups/USHEADS-rss_2.0.xml?SITE=CAVIC&SECTION=HOME'), feeds = [
('AP Headlines', 'http://hosted.ap.org/lineups/TOPHEADS-rss_2.0.xml?SITE=ORAST&SECTION=HOME'),
('AP US News', 'http://hosted.ap.org/lineups/USHEADS-rss_2.0.xml?SITE=CAVIC&SECTION=HOME'),
('AP World News', 'http://hosted.ap.org/lineups/WORLDHEADS-rss_2.0.xml?SITE=SCAND&SECTION=HOME'), ('AP World News', 'http://hosted.ap.org/lineups/WORLDHEADS-rss_2.0.xml?SITE=SCAND&SECTION=HOME'),
('AP Political News', 'http://hosted.ap.org/lineups/POLITICSHEADS-rss_2.0.xml?SITE=ORMED&SECTION=HOME'), ('AP Political News', 'http://hosted.ap.org/lineups/POLITICSHEADS-rss_2.0.xml?SITE=ORMED&SECTION=HOME'),
('AP Washington State News', 'http://hosted.ap.org/lineups/WASHINGTONHEADS-rss_2.0.xml?SITE=NYPLA&SECTION=HOME'), ('AP Washington State News', 'http://hosted.ap.org/lineups/WASHINGTONHEADS-rss_2.0.xml?SITE=NYPLA&SECTION=HOME'),
@ -38,4 +45,5 @@ class AssociatedPress(BasicNewsRecipe):
('AP Health News', 'http://hosted.ap.org/lineups/HEALTHHEADS-rss_2.0.xml?SITE=FLDAY&SECTION=HOME'), ('AP Health News', 'http://hosted.ap.org/lineups/HEALTHHEADS-rss_2.0.xml?SITE=FLDAY&SECTION=HOME'),
('AP Science News', 'http://hosted.ap.org/lineups/SCIENCEHEADS-rss_2.0.xml?SITE=OHCIN&SECTION=HOME'), ('AP Science News', 'http://hosted.ap.org/lineups/SCIENCEHEADS-rss_2.0.xml?SITE=OHCIN&SECTION=HOME'),
('AP Strange News', 'http://hosted.ap.org/lineups/STRANGEHEADS-rss_2.0.xml?SITE=WCNC&SECTION=HOME'), ('AP Strange News', 'http://hosted.ap.org/lineups/STRANGEHEADS-rss_2.0.xml?SITE=WCNC&SECTION=HOME'),
] ]

View File

@ -0,0 +1,62 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
balkaninsight.com
'''
import re
from calibre.web.feeds.news import BasicNewsRecipe
class BalkanInsight(BasicNewsRecipe):
title = 'Balkan Insight'
__author__ = 'Darko Miletic'
description = 'Get exclusive news and in depth information on business, politics, events and lifestyle in the Balkans. Free and exclusive premium content.'
publisher = 'BalkanInsight.com'
category = 'news, politics, Balcans'
oldest_article = 2
max_articles_per_feed = 100
no_stylesheets = False
use_embedded_content = False
encoding = 'utf-8'
masthead_url = 'http://www.balkaninsight.com/templates/balkaninsight/images/aindex_02.jpg'
language = 'en'
publication_type = 'newsportal'
remove_empty_feeds = True
extra_css = """ @font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)}
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
.article_description,body{font-family: Arial,Verdana,Helvetica,sans1,sans-serif}
img{margin-bottom: 0.8em}
h1,h2,h3,h4{font-family: Times,Georgia,serif1,serif; color: #24569E}
.article-deck {color:#777777; font-size: small;}
.main_news_img{font-size: small} """
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
keep_only_tags = [dict(name='div', attrs={'id':'article'})]
remove_tags = [
dict(name=['object','link','iframe'])
]
feeds = [
(u'Albania' , u'http://www.balkaninsight.com/?tpl=653&tpid=144' )
,(u'Bosnia' , u'http://www.balkaninsight.com/?tpl=653&tpid=145' )
,(u'Bulgaria' , u'http://www.balkaninsight.com/?tpl=653&tpid=146' )
,(u'Croatia' , u'http://www.balkaninsight.com/?tpl=653&tpid=147' )
,(u'Kosovo' , u'http://www.balkaninsight.com/?tpl=653&tpid=148' )
,(u'Macedonia' , u'http://www.balkaninsight.com/?tpl=653&tpid=149' )
,(u'Montenegro' , u'http://www.balkaninsight.com/?tpl=653&tpid=150' )
,(u'Romania' , u'http://www.balkaninsight.com/?tpl=653&tpid=151' )
,(u'Serbia' , u'http://www.balkaninsight.com/?tpl=653&tpid=152' )
]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return self.adeify_images(soup)

View File

@ -1,4 +1,5 @@
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
import re
class BigOven(BasicNewsRecipe): class BigOven(BasicNewsRecipe):
title = 'BigOven' title = 'BigOven'
@ -26,39 +27,38 @@ class BigOven(BasicNewsRecipe):
def get_browser(self): def get_browser(self):
br = BasicNewsRecipe.get_browser() br = BasicNewsRecipe.get_browser()
if self.username is not None and self.password is not None: if self.username is not None and self.password is not None:
br.open('http://www.bigoven.com/') br.open('http://www.bigoven.com/account/login?ReturnUrl=/')
br.select_form(name='form1') br.select_form(nr=1)
br['TopMenu_bo1$email'] = self.username br['Email'] = self.username
br['TopMenu_bo1$password'] = self.password br['Password'] = self.password
br.submit() br.submit()
return br return br
remove_attributes = ['style', 'font'] remove_attributes = ['style', 'font']
keep_only_tags = [dict(name='h1') remove_tags = [dict(name='div', attrs={'class':['ppy-caption']})
,dict(name='div', attrs={'class':'img'}) ,dict(name='div', attrs={'id':['float_corner']})
,dict(name='div', attrs={'id':'intro'}) ]
]
remove_tags = [dict(name='div', attrs={'style':["overflow: visible;"]}) def preprocess_html(self, soup):
,dict(name='div', attrs={'class':['ctas']}) for tag in soup.findAll(name='a', attrs={'class':['deflink']}):
#,dict(name='a', attrs={'class':['edit']}) tag.replaceWith(tag.string)
,dict(name='p', attrs={'class':['byline']}) for tag in soup.findAll(name='a', text=re.compile(r'.*View Metric.*', re.DOTALL)):
] tag.parent.parent.extract()
for tag in soup.findAll(name='a', text=re.compile(r'.*Add my own photo.*', re.DOTALL)):
tag.parent.parent.extract()
for tag in soup.findAll(name='div', attrs={'class':['container']}):
if tag.find(name='h1'):
continue
if tag.find(name='h2', text=re.compile(r'.*Ingredients.*', re.DOTALL)):
print 'tag found Ingred h2'
continue
if tag.find(name='h2', text=re.compile(r'Preparation.*', re.DOTALL)):
print 'tag found Prep h2'
continue
tag.extract()
return soup
feeds = [(u'4 & 5 Star Rated Recipes', u'http://feeds.feedburner.com/Bigovencom-RecipeRaves?format=xml')] feeds = [(u'4 & 5 Star Rated Recipes', u'http://feeds.feedburner.com/Bigovencom-RecipeRaves?format=xml')]
def preprocess_html(self, soup):
for tag in soup.findAll(name='a', attrs={'class':['edit']}):
tag.parent.extract()
for tag in soup.findAll(name='a', attrs={'class':['deflink']}):
tag.replaceWith(tag.string)
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:medium;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''

View File

@ -0,0 +1,42 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
dr.dk
'''
from calibre.web.feeds.news import BasicNewsRecipe
class dr_dk(BasicNewsRecipe):
title = 'DR Nyheder'
__author__ = 'Darko Miletic'
description = 'Myndighederne indfører nu eskorte af brandbiler og ambulancer i Ishøj af frygt for hærværk.'
publisher = 'Nyhedsbureauet DR Nyheder'
category = 'news, politics, Denmark'
oldest_article = 2
max_articles_per_feed = 200
no_stylesheets = True
delay = 1
encoding = 'utf8'
use_embedded_content = False
language = 'da'
extra_css = """ body{font-family: Verdana,Arial,sans-serif }
img{margin-bottom: 0.4em}
.txtContent,.stamp{font-size: small}
"""
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
keep_only_tags = [dict(name='div', attrs={'class':'articleContent'})]
remove_attributes=['xmlns:msxsl','width','height']
feeds = [(u'All news', u'http://www.dr.dk/Nyheder/Service/feeds/Allenyheder.htm')]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -9,9 +9,9 @@ from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class ElPaisImpresa(BasicNewsRecipe): class ElPaisImpresa(BasicNewsRecipe):
title = 'El País - edicion impresa' title = u'El Pa\xeds - edicion impresa'
__author__ = 'Darko Miletic' __author__ = 'Darko Miletic'
description = 'el periodico global en Español' description = u'el periodico global en Espa\xf1ol'
publisher = 'EDICIONES EL PAIS, S.L.' publisher = 'EDICIONES EL PAIS, S.L.'
category = 'news, politics,Spain,actualidad,noticias,informacion,videos,fotografias,audios,graficos,nacional,internacional,deportes,economia,tecnologia,cultura,gente,television,sociedad,opinion,blogs,foros,chats,encuestas,entrevistas,participacion' category = 'news, politics,Spain,actualidad,noticias,informacion,videos,fotografias,audios,graficos,nacional,internacional,deportes,economia,tecnologia,cultura,gente,television,sociedad,opinion,blogs,foros,chats,encuestas,entrevistas,participacion'
no_stylesheets = True no_stylesheets = True
@ -32,10 +32,10 @@ class ElPaisImpresa(BasicNewsRecipe):
feeds = [ feeds = [
(u'Internacional' , index + u'internacional/' ) (u'Internacional' , index + u'internacional/' )
,(u'España' , index + u'espana/' ) ,(u'Espa\xf1a' , index + u'espana/' )
,(u'Economia' , index + u'economia/' ) ,(u'Economia' , index + u'economia/' )
,(u'Opinion' , index + u'opinion/' ) ,(u'Opinion' , index + u'opinion/' )
,(u'Viñetas' , index + u'vineta/' ) ,(u'Vi\xf1etas' , index + u'vineta/' )
,(u'Sociedad' , index + u'sociedad/' ) ,(u'Sociedad' , index + u'sociedad/' )
,(u'Cultura' , index + u'cultura/' ) ,(u'Cultura' , index + u'cultura/' )
,(u'Tendencias' , index + u'tendencias/' ) ,(u'Tendencias' , index + u'tendencias/' )

View File

@ -1,15 +1,11 @@
#!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
''' '''
www.esquire.com www.esquire.com
''' '''
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import Tag
class Esquire(BasicNewsRecipe): class Esquire(BasicNewsRecipe):
title = 'Esquire' title = 'Esquire'
@ -22,22 +18,20 @@ class Esquire(BasicNewsRecipe):
no_stylesheets = True no_stylesheets = True
encoding = 'cp1250' encoding = 'cp1250'
use_embedded_content = False use_embedded_content = False
language = 'en' language = 'en'
publication_type = 'magazine'
lang = 'en-US' masthead_url = 'http://www.esquire.com/cm/shared/site_images/print_this/esquire_logo.gif'
cover_url = strftime('http://www.esquire.com/cm/esquire/cover-images/%Y_') + strftime('%m').strip('0') + '.jpg'
conversion_options = { conversion_options = {
'comment' : description 'comment' : description
, 'tags' : category , 'tags' : category
, 'publisher' : publisher , 'publisher' : publisher
, 'language' : lang , 'language' : language
, 'pretty_print' : True
} }
keep_only_tags = [dict(name='div', attrs={'id':'content'})] keep_only_tags = [dict(name='div', attrs={'id':['article_header','article_content']})]
remove_tags = [dict(name=['object','link','embed','iframe','base'])]
remove_tags = [dict(name=['object','link','embed','iframe'])] remove_attributes = ['width','height']
feeds = [ feeds = [
(u'Style' , u'http://www.esquire.com/style/rss/' ) (u'Style' , u'http://www.esquire.com/style/rss/' )
@ -47,17 +41,7 @@ class Esquire(BasicNewsRecipe):
,(u'Frontpage', u'http://www.esquire.com/rss/' ) ,(u'Frontpage', u'http://www.esquire.com/rss/' )
] ]
def print_version(self, url):
rest = url.rpartition('?')[0]
article = rest.rpartition('/')[2]
return 'http://www.esquire.com/print-this/' + article
def preprocess_html(self, soup): def preprocess_html(self, soup):
soup.html['xml:lang'] = self.lang
soup.html['lang'] = self.lang
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
soup.head.insert(0,mlang)
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
return soup return soup

View File

@ -0,0 +1,46 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
financialexpress.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
class FE_India(BasicNewsRecipe):
title = 'The Financial Express'
__author__ = 'Darko Miletic'
description = 'Financial news from India'
publisher = 'The Indian Express Limited'
category = 'news, politics, finances, India'
oldest_article = 30
max_articles_per_feed = 200
no_stylesheets = True
encoding = 'cp1252'
use_embedded_content = False
language = 'en_IN'
remove_empty_feeds = True
masthead_url = 'http://static.expressindia.com/frontend/fe/images/fe_logo.jpg'
publication_type = 'magazine'
extra_css = ' body{font-family: Arial,Helvetica,sans-serif } '
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
keep_only_tags = [dict(attrs={'class':'txt'})]
remove_attributes = ['width','height']
feeds = [(u'Articles', u'http://www.expressindia.com/syndications/fe.xml')]
def print_version(self, url):
article_raw = url.rpartition('/')[0]
article_id = article_raw.rpartition('/')[2]
return 'http://www.financialexpress.com/printer/news/' + article_id + '/'
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -0,0 +1,74 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2010, Saverio Palmieri Neto <saverio.palmieri at gmail.com>'
'''
folha.uol.com.br
'''
from calibre.web.feeds.news import BasicNewsRecipe
class FolhaOnline(BasicNewsRecipe):
title = 'Folha de Sao Paulo'
__author__ = 'Saverio Palmieri Neto'
description = 'Brazilian news from Folha de Sao Paulo Online'
publisher = 'Folha de Sao Paulo'
category = 'Brasil, news'
oldest_article = 2
max_articles_per_feed = 1000
summary_length = 2048
no_stylesheets = True
use_embedded_content = False
timefmt = ' [%d %b %Y (%a)]'
encoding = 'cp1252'
cover_url = 'http://lh5.ggpht.com/_hEb7sFmuBvk/TFoiKLRS5dI/AAAAAAAAADM/kcVKggZwKnw/capa_folha.jpg'
cover_margins = (5,5,'white')
remove_javascript = True
keep_only_tags = [dict(name='div', attrs={'id':'articleNew'})]
remove_tags = [
dict(name='script')
,dict(name='div',
attrs={'id':[
'articleButton'
,'bookmarklets'
,'ad-180x150-1'
,'contextualAdsArticle'
,'articleEnd'
,'articleComments'
]})
,dict(name='div',
attrs={'class':[
'openBox adslibraryArticle'
]})
,dict(name='a')
,dict(name='iframe')
,dict(name='link')
]
feeds = [
(u'Em cima da hora', u'http://feeds.folha.uol.com.br/emcimadahora/rss091.xml')
,(u'Ambiente', u'http://feeds.folha.uol.com.br/ambiente/rss091.xml')
,(u'Bichos', u'http://feeds.folha.uol.com.br/bichos/rss091.xml')
,(u'Poder', u'http://feeds.folha.uol.com.br/poder/rss091.xml')
,(u'Ciencia', u'http://feeds.folha.uol.com.br/ciencia/rss091.xml')
,(u'Cotidiano', u'http://feeds.folha.uol.com.br/cotidiado/rss091.xml')
,(u'Saber', u'http://feeds.folha.uol.com.br/saber/rss091.xml')
,(u'Equilíbrio e Saúde', u'http://feeds.folha.uol.com.br/equilibrioesaude/rss091.xml')
,(u'Esporte', u'http://feeds.folha.uol.com.br/esporte/rss091.xml')
,(u'Ilustrada', u'http://feeds.folha.uol.com.br/ilustrada/rss091.xml')
,(u'Ilustríssima', u'http://feeds.folha.uol.com.br/ilustrissima/rss091.xml')
,(u'Mercado', u'http://feeds.folha.uol.com.br/mercado/rss091.xml')
,(u'Mundo', u'http://feeds.folha.uol.com.br/mundo/rss091.xml')
,(u'Tec', u'http://feeds.folha.uol.com.br/tec/rss091.xml')
,(u'Turismo', u'http://feeds.folha.uol.com.br/turismo/rss091.xml')
]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup
language = 'pt'

View File

@ -4,28 +4,23 @@ import re
class NatureNews(BasicNewsRecipe): class NatureNews(BasicNewsRecipe):
title = u'Nature News' title = u'Nature News'
language = 'en' language = 'en'
__author__ = 'Krittika Goyal' __author__ = 'Krittika Goyal, Starson17'
oldest_article = 31 #days oldest_article = 31 #days
remove_empty_feeds = True
max_articles_per_feed = 50 max_articles_per_feed = 50
#encoding = 'latin1'
no_stylesheets = True no_stylesheets = True
remove_tags_before = dict(name='h1', attrs={'class':'heading entry-title'}) remove_tags_before = dict(name='h1', attrs={'class':'heading entry-title'})
remove_tags_after = dict(name='h2', attrs={'id':'comments'}) remove_tags_after = dict(name='h2', attrs={'id':'comments'})
remove_tags = [ remove_tags = [
#dict(name='iframe'),
#dict(name='div', attrs={'class':['pt-box-title', 'pt-box-content']}),
#dict(name='div', attrs={'id':['block-td_search_160', 'block-cam_search_160']}),
dict(name='h2', attrs={'id':'comments'}), dict(name='h2', attrs={'id':'comments'}),
dict(name='ul', attrs={'class':'toolsmenu xoxo'}), dict(attrs={'alt':'Advertisement'}),
dict(name='div', attrs={'class':'ad'}),
] ]
preprocess_regexps = [ preprocess_regexps = [
(re.compile(r'<script.*?</script>', re.DOTALL), lambda m: '') (re.compile(r'<p>ADVERTISEMENT</p>', re.DOTALL|re.IGNORECASE), lambda match: ''),
] ]
feeds = [('Nature News', 'http://feeds.nature.com/news/rss/most_recent')] feeds = [('Nature News', 'http://feeds.nature.com/news/rss/most_recent')]
def get_article_url(self, article):
return article.get('id')

View File

@ -0,0 +1,38 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
futurismic.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
class Futurismic(BasicNewsRecipe):
title = 'Futurismic'
__author__ = 'Darko Miletic'
description = 'Near-future science fiction and fact since 2001'
oldest_article = 15
max_articles_per_feed = 100
language = 'en'
encoding = 'utf-8'
no_stylesheets = True
use_embedded_content = False
publication_type = 'blog'
extra_css = ' body{font-family: Arial,Verdana,sans-serif} '
conversion_options = {
'comment' : description
, 'tags' : 'blog, sf'
, 'publisher': 'Futurismic'
, 'language' : language
}
remove_attributes = ['width','height']
keep_only_tags = [dict(attrs={'class':['post','commentlist']})]
remove_tags = [dict(attrs={'class':['sociable','feedback','tagwords']})]
feeds = [(u'Posts', u'http://feeds2.feedburner.com/futurismic_feed')]
def preprocess_html(self, soup):
return self.adeify_images(soup)

View File

@ -0,0 +1,348 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = 'Copyright 2010 Starson17'
'''
www.gocomics.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
import mechanize
class GoComics(BasicNewsRecipe):
title = 'GoComics'
__author__ = 'Starson17'
__version__ = '1.02'
__date__ = '14 August 2010'
description = u'200+ Comics - Customize for more days/comics: Defaults to 7 days, 25 comics - 20 general, 5 editorial.'
category = 'news, comics'
language = 'en'
use_embedded_content= False
no_stylesheets = True
remove_javascript = True
cover_url = 'http://paulbuckley14059.files.wordpress.com/2008/06/calvin-and-hobbes.jpg'
####### USER PREFERENCES - COMICS, IMAGE SIZE AND NUMBER OF COMICS TO RETRIEVE ########
# num_comics_to_get - I've tried up to 99 on Calvin&Hobbes
num_comics_to_get = 7
# comic_size 300 is small, 600 is medium, 900 is large, 1500 is extra-large
comic_size = 900
# CHOOSE COMIC STRIPS BELOW - REMOVE COMMENT '# ' FROM IN FRONT OF DESIRED STRIPS
# Please do not overload their servers by selecting all comics and 1000 strips from each!
conversion_options = {'linearize_tables' : True
, 'comment' : description
, 'tags' : category
, 'language' : language
}
keep_only_tags = [dict(name='div', attrs={'class':['feature','banner']}),
]
remove_tags = [dict(name='a', attrs={'class':['beginning','prev','cal','next','newest']}),
dict(name='div', attrs={'class':['tag-wrapper']}),
dict(name='ul', attrs={'class':['share-nav','feature-nav']}),
]
def get_browser(self):
br = BasicNewsRecipe.get_browser(self)
cookies = mechanize.CookieJar()
br = mechanize.build_opener(mechanize.HTTPCookieProcessor(cookies))
br.addheaders = [('Referer','http://www.gocomics.com/')]
return br
def parse_index(self):
feeds = []
for title, url in [
######## COMICS - GENERAL ########
(u"2 Cows and a Chicken", u"http://www.gocomics.com/2cowsandachicken"),
# (u"9 to 5", u"http://www.gocomics.com/9to5"),
# (u"The Academia Waltz", u"http://www.gocomics.com/academiawaltz"),
# (u"Adam@Home", u"http://www.gocomics.com/adamathome"),
# (u"Agnes", u"http://www.gocomics.com/agnes"),
# (u"Andy Capp", u"http://www.gocomics.com/andycapp"),
# (u"Animal Crackers", u"http://www.gocomics.com/animalcrackers"),
# (u"Annie", u"http://www.gocomics.com/annie"),
(u"The Argyle Sweater", u"http://www.gocomics.com/theargylesweater"),
# (u"Ask Shagg", u"http://www.gocomics.com/askshagg"),
(u"B.C.", u"http://www.gocomics.com/bc"),
# (u"Back in the Day", u"http://www.gocomics.com/backintheday"),
# (u"Bad Reporter", u"http://www.gocomics.com/badreporter"),
# (u"Baldo", u"http://www.gocomics.com/baldo"),
# (u"Ballard Street", u"http://www.gocomics.com/ballardstreet"),
# (u"Barkeater Lake", u"http://www.gocomics.com/barkeaterlake"),
# (u"The Barn", u"http://www.gocomics.com/thebarn"),
# (u"Basic Instructions", u"http://www.gocomics.com/basicinstructions"),
# (u"Bewley", u"http://www.gocomics.com/bewley"),
# (u"Big Top", u"http://www.gocomics.com/bigtop"),
# (u"Biographic", u"http://www.gocomics.com/biographic"),
(u"Birdbrains", u"http://www.gocomics.com/birdbrains"),
# (u"Bleeker: The Rechargeable Dog", u"http://www.gocomics.com/bleeker"),
# (u"Bliss", u"http://www.gocomics.com/bliss"),
(u"Bloom County", u"http://www.gocomics.com/bloomcounty"),
# (u"Bo Nanas", u"http://www.gocomics.com/bonanas"),
# (u"Bob the Squirrel", u"http://www.gocomics.com/bobthesquirrel"),
# (u"The Boiling Point", u"http://www.gocomics.com/theboilingpoint"),
# (u"Boomerangs", u"http://www.gocomics.com/boomerangs"),
# (u"The Boondocks", u"http://www.gocomics.com/boondocks"),
# (u"Bottomliners", u"http://www.gocomics.com/bottomliners"),
# (u"Bound and Gagged", u"http://www.gocomics.com/boundandgagged"),
# (u"Brainwaves", u"http://www.gocomics.com/brainwaves"),
# (u"Brenda Starr", u"http://www.gocomics.com/brendastarr"),
# (u"Brewster Rockit", u"http://www.gocomics.com/brewsterrockit"),
# (u"Broom Hilda", u"http://www.gocomics.com/broomhilda"),
(u"Calvin and Hobbes", u"http://www.gocomics.com/calvinandhobbes"),
# (u"Candorville", u"http://www.gocomics.com/candorville"),
# (u"Cathy", u"http://www.gocomics.com/cathy"),
# (u"C'est la Vie", u"http://www.gocomics.com/cestlavie"),
# (u"Chuckle Bros", u"http://www.gocomics.com/chucklebros"),
# (u"Citizen Dog", u"http://www.gocomics.com/citizendog"),
# (u"The City", u"http://www.gocomics.com/thecity"),
# (u"Cleats", u"http://www.gocomics.com/cleats"),
# (u"Close to Home", u"http://www.gocomics.com/closetohome"),
# (u"Compu-toon", u"http://www.gocomics.com/compu-toon"),
# (u"Cornered", u"http://www.gocomics.com/cornered"),
(u"Cul de Sac", u"http://www.gocomics.com/culdesac"),
# (u"Daddy's Home", u"http://www.gocomics.com/daddyshome"),
# (u"Deep Cover", u"http://www.gocomics.com/deepcover"),
# (u"Dick Tracy", u"http://www.gocomics.com/dicktracy"),
# (u"The Dinette Set", u"http://www.gocomics.com/dinetteset"),
# (u"Dog Eat Doug", u"http://www.gocomics.com/dogeatdoug"),
# (u"Domestic Abuse", u"http://www.gocomics.com/domesticabuse"),
# (u"Doodles", u"http://www.gocomics.com/doodles"),
(u"Doonesbury", u"http://www.gocomics.com/doonesbury"),
# (u"The Doozies", u"http://www.gocomics.com/thedoozies"),
# (u"The Duplex", u"http://www.gocomics.com/duplex"),
# (u"Eek!", u"http://www.gocomics.com/eek"),
# (u"The Elderberries", u"http://www.gocomics.com/theelderberries"),
# (u"Flight Deck", u"http://www.gocomics.com/flightdeck"),
# (u"Flo and Friends", u"http://www.gocomics.com/floandfriends"),
# (u"The Flying McCoys", u"http://www.gocomics.com/theflyingmccoys"),
(u"For Better or For Worse", u"http://www.gocomics.com/forbetterorforworse"),
# (u"For Heaven's Sake", u"http://www.gocomics.com/forheavenssake"),
# (u"Fort Knox", u"http://www.gocomics.com/fortknox"),
# (u"FoxTrot", u"http://www.gocomics.com/foxtrot"),
(u"FoxTrot Classics", u"http://www.gocomics.com/foxtrotclassics"),
# (u"Frank & Ernest", u"http://www.gocomics.com/frankandernest"),
# (u"Fred Basset", u"http://www.gocomics.com/fredbasset"),
# (u"Free Range", u"http://www.gocomics.com/freerange"),
# (u"Frog Applause", u"http://www.gocomics.com/frogapplause"),
# (u"The Fusco Brothers", u"http://www.gocomics.com/thefuscobrothers"),
(u"Garfield", u"http://www.gocomics.com/garfield"),
# (u"Garfield Minus Garfield", u"http://www.gocomics.com/garfieldminusgarfield"),
# (u"Gasoline Alley", u"http://www.gocomics.com/gasolinealley"),
# (u"Gil Thorp", u"http://www.gocomics.com/gilthorp"),
# (u"Ginger Meggs", u"http://www.gocomics.com/gingermeggs"),
# (u"Girls & Sports", u"http://www.gocomics.com/girlsandsports"),
# (u"Haiku Ewe", u"http://www.gocomics.com/haikuewe"),
# (u"Heart of the City", u"http://www.gocomics.com/heartofthecity"),
# (u"Heathcliff", u"http://www.gocomics.com/heathcliff"),
# (u"Herb and Jamaal", u"http://www.gocomics.com/herbandjamaal"),
# (u"Home and Away", u"http://www.gocomics.com/homeandaway"),
# (u"Housebroken", u"http://www.gocomics.com/housebroken"),
# (u"Hubert and Abby", u"http://www.gocomics.com/hubertandabby"),
# (u"Imagine This", u"http://www.gocomics.com/imaginethis"),
# (u"In the Bleachers", u"http://www.gocomics.com/inthebleachers"),
# (u"In the Sticks", u"http://www.gocomics.com/inthesticks"),
# (u"Ink Pen", u"http://www.gocomics.com/inkpen"),
# (u"It's All About You", u"http://www.gocomics.com/itsallaboutyou"),
# (u"Joe Vanilla", u"http://www.gocomics.com/joevanilla"),
# (u"La Cucaracha", u"http://www.gocomics.com/lacucaracha"),
# (u"Last Kiss", u"http://www.gocomics.com/lastkiss"),
# (u"Legend of Bill", u"http://www.gocomics.com/legendofbill"),
# (u"Liberty Meadows", u"http://www.gocomics.com/libertymeadows"),
(u"Lio", u"http://www.gocomics.com/lio"),
# (u"Little Dog Lost", u"http://www.gocomics.com/littledoglost"),
# (u"Little Otto", u"http://www.gocomics.com/littleotto"),
# (u"Loose Parts", u"http://www.gocomics.com/looseparts"),
# (u"Love Is...", u"http://www.gocomics.com/loveis"),
# (u"Maintaining", u"http://www.gocomics.com/maintaining"),
# (u"The Meaning of Lila", u"http://www.gocomics.com/meaningoflila"),
# (u"Middle-Aged White Guy", u"http://www.gocomics.com/middleagedwhiteguy"),
# (u"The Middletons", u"http://www.gocomics.com/themiddletons"),
# (u"Momma", u"http://www.gocomics.com/momma"),
# (u"Mutt & Jeff", u"http://www.gocomics.com/muttandjeff"),
# (u"Mythtickle", u"http://www.gocomics.com/mythtickle"),
# (u"Nest Heads", u"http://www.gocomics.com/nestheads"),
# (u"NEUROTICA", u"http://www.gocomics.com/neurotica"),
(u"New Adventures of Queen Victoria", u"http://www.gocomics.com/thenewadventuresofqueenvictoria"),
(u"Non Sequitur", u"http://www.gocomics.com/nonsequitur"),
# (u"The Norm", u"http://www.gocomics.com/thenorm"),
# (u"On A Claire Day", u"http://www.gocomics.com/onaclaireday"),
# (u"One Big Happy", u"http://www.gocomics.com/onebighappy"),
# (u"The Other Coast", u"http://www.gocomics.com/theothercoast"),
# (u"Out of the Gene Pool Re-Runs", u"http://www.gocomics.com/outofthegenepool"),
# (u"Overboard", u"http://www.gocomics.com/overboard"),
# (u"Pibgorn", u"http://www.gocomics.com/pibgorn"),
# (u"Pibgorn Sketches", u"http://www.gocomics.com/pibgornsketches"),
(u"Pickles", u"http://www.gocomics.com/pickles"),
# (u"Pinkerton", u"http://www.gocomics.com/pinkerton"),
# (u"Pluggers", u"http://www.gocomics.com/pluggers"),
(u"Pooch Cafe", u"http://www.gocomics.com/poochcafe"),
# (u"PreTeena", u"http://www.gocomics.com/preteena"),
# (u"The Quigmans", u"http://www.gocomics.com/thequigmans"),
# (u"Rabbits Against Magic", u"http://www.gocomics.com/rabbitsagainstmagic"),
(u"Real Life Adventures", u"http://www.gocomics.com/reallifeadventures"),
# (u"Red and Rover", u"http://www.gocomics.com/redandrover"),
# (u"Red Meat", u"http://www.gocomics.com/redmeat"),
# (u"Reynolds Unwrapped", u"http://www.gocomics.com/reynoldsunwrapped"),
# (u"Ronaldinho Gaucho", u"http://www.gocomics.com/ronaldinhogaucho"),
# (u"Rubes", u"http://www.gocomics.com/rubes"),
# (u"Scary Gary", u"http://www.gocomics.com/scarygary"),
(u"Shoe", u"http://www.gocomics.com/shoe"),
# (u"Shoecabbage", u"http://www.gocomics.com/shoecabbage"),
# (u"Skin Horse", u"http://www.gocomics.com/skinhorse"),
# (u"Slowpoke", u"http://www.gocomics.com/slowpoke"),
# (u"Speed Bump", u"http://www.gocomics.com/speedbump"),
# (u"State of the Union", u"http://www.gocomics.com/stateoftheunion"),
(u"Stone Soup", u"http://www.gocomics.com/stonesoup"),
# (u"Strange Brew", u"http://www.gocomics.com/strangebrew"),
# (u"Sylvia", u"http://www.gocomics.com/sylvia"),
# (u"Tank McNamara", u"http://www.gocomics.com/tankmcnamara"),
# (u"Tiny Sepuku", u"http://www.gocomics.com/tinysepuku"),
# (u"TOBY", u"http://www.gocomics.com/toby"),
# (u"Tom the Dancing Bug", u"http://www.gocomics.com/tomthedancingbug"),
# (u"Too Much Coffee Man", u"http://www.gocomics.com/toomuchcoffeeman"),
# (u"W.T. Duck", u"http://www.gocomics.com/wtduck"),
# (u"Watch Your Head", u"http://www.gocomics.com/watchyourhead"),
# (u"Wee Pals", u"http://www.gocomics.com/weepals"),
# (u"Winnie the Pooh", u"http://www.gocomics.com/winniethepooh"),
(u"Wizard of Id", u"http://www.gocomics.com/wizardofid"),
# (u"Working It Out", u"http://www.gocomics.com/workingitout"),
# (u"Yenny", u"http://www.gocomics.com/yenny"),
# (u"Zack Hill", u"http://www.gocomics.com/zackhill"),
(u"Ziggy", u"http://www.gocomics.com/ziggy"),
######## COMICS - EDITORIAL ########
("Lalo Alcaraz","http://www.gocomics.com/laloalcaraz"),
("Nick Anderson","http://www.gocomics.com/nickanderson"),
("Chuck Asay","http://www.gocomics.com/chuckasay"),
("Tony Auth","http://www.gocomics.com/tonyauth"),
("Donna Barstow","http://www.gocomics.com/donnabarstow"),
# ("Bruce Beattie","http://www.gocomics.com/brucebeattie"),
# ("Clay Bennett","http://www.gocomics.com/claybennett"),
# ("Lisa Benson","http://www.gocomics.com/lisabenson"),
# ("Steve Benson","http://www.gocomics.com/stevebenson"),
# ("Chip Bok","http://www.gocomics.com/chipbok"),
# ("Steve Breen","http://www.gocomics.com/stevebreen"),
# ("Chris Britt","http://www.gocomics.com/chrisbritt"),
# ("Stuart Carlson","http://www.gocomics.com/stuartcarlson"),
# ("Ken Catalino","http://www.gocomics.com/kencatalino"),
# ("Paul Conrad","http://www.gocomics.com/paulconrad"),
# ("Jeff Danziger","http://www.gocomics.com/jeffdanziger"),
# ("Matt Davies","http://www.gocomics.com/mattdavies"),
# ("John Deering","http://www.gocomics.com/johndeering"),
# ("Bob Gorrell","http://www.gocomics.com/bobgorrell"),
# ("Walt Handelsman","http://www.gocomics.com/walthandelsman"),
# ("Clay Jones","http://www.gocomics.com/clayjones"),
# ("Kevin Kallaugher","http://www.gocomics.com/kevinkallaugher"),
# ("Steve Kelley","http://www.gocomics.com/stevekelley"),
# ("Dick Locher","http://www.gocomics.com/dicklocher"),
# ("Chan Lowe","http://www.gocomics.com/chanlowe"),
# ("Mike Luckovich","http://www.gocomics.com/mikeluckovich"),
# ("Gary Markstein","http://www.gocomics.com/garymarkstein"),
# ("Glenn McCoy","http://www.gocomics.com/glennmccoy"),
# ("Jim Morin","http://www.gocomics.com/jimmorin"),
# ("Jack Ohman","http://www.gocomics.com/jackohman"),
# ("Pat Oliphant","http://www.gocomics.com/patoliphant"),
# ("Joel Pett","http://www.gocomics.com/joelpett"),
# ("Ted Rall","http://www.gocomics.com/tedrall"),
# ("Michael Ramirez","http://www.gocomics.com/michaelramirez"),
# ("Marshall Ramsey","http://www.gocomics.com/marshallramsey"),
# ("Steve Sack","http://www.gocomics.com/stevesack"),
# ("Ben Sargent","http://www.gocomics.com/bensargent"),
# ("Drew Sheneman","http://www.gocomics.com/drewsheneman"),
# ("John Sherffius","http://www.gocomics.com/johnsherffius"),
# ("Small World","http://www.gocomics.com/smallworld"),
# ("Scott Stantis","http://www.gocomics.com/scottstantis"),
# ("Wayne Stayskal","http://www.gocomics.com/waynestayskal"),
# ("Dana Summers","http://www.gocomics.com/danasummers"),
# ("Paul Szep","http://www.gocomics.com/paulszep"),
# ("Mike Thompson","http://www.gocomics.com/mikethompson"),
# ("Tom Toles","http://www.gocomics.com/tomtoles"),
# ("Gary Varvel","http://www.gocomics.com/garyvarvel"),
# ("ViewsAfrica","http://www.gocomics.com/viewsafrica"),
# ("ViewsAmerica","http://www.gocomics.com/viewsamerica"),
# ("ViewsAsia","http://www.gocomics.com/viewsasia"),
# ("ViewsBusiness","http://www.gocomics.com/viewsbusiness"),
# ("ViewsEurope","http://www.gocomics.com/viewseurope"),
# ("ViewsLatinAmerica","http://www.gocomics.com/viewslatinamerica"),
# ("ViewsMidEast","http://www.gocomics.com/viewsmideast"),
# ("Views of the World","http://www.gocomics.com/viewsoftheworld"),
# ("Kerry Waghorn","http://www.gocomics.com/facesinthenews"),
# ("Dan Wasserman","http://www.gocomics.com/danwasserman"),
# ("Signe Wilkinson","http://www.gocomics.com/signewilkinson"),
# ("Wit of the World","http://www.gocomics.com/witoftheworld"),
# ("Don Wright","http://www.gocomics.com/donwright"),
]:
articles = self.make_links(url)
if articles:
feeds.append((title, articles))
return feeds
def make_links(self, url):
title = 'Temp'
current_articles = []
pages = range(1, self.num_comics_to_get+1)
for page in pages:
page_soup = self.index_to_soup(url)
if page_soup:
try:
strip_title = page_soup.h1.a.string
except:
strip_title = 'Error - no page_soup.h1.a.string'
try:
date_title = page_soup.find('ul', attrs={'class': 'feature-nav'}).li.string
except:
date_title = 'Error - no page_soup.h1.li.string'
title = strip_title + ' - ' + date_title
for i in range(2):
try:
strip_url_date = page_soup.h1.a['href']
break #success - this is normal exit
except:
continue #try to get strip_url_date again
continue # give up on this strip date
for i in range(2):
try:
prev_strip_url_date = page_soup.find('a', attrs={'class': 'prev'})['href']
break #success - this is normal exit
except:
continue #try to get prev_strip_url_date again
continue # give up on this prev strip date
if strip_url_date:
page_url = 'http://www.gocomics.com' + strip_url_date
else:
continue
if prev_strip_url_date:
prev_page_url = 'http://www.gocomics.com' + prev_strip_url_date
else:
continue
current_articles.append({'title': title, 'url': page_url, 'description':'', 'date':''})
url = prev_page_url
current_articles.reverse()
return current_articles
def preprocess_html(self, soup):
if soup.title:
title_string = soup.title.string.strip()
_cd = title_string.split(',',1)[1]
comic_date = ' '.join(_cd.split(' ', 4)[0:-1])
if soup.h1.span:
artist = soup.h1.span.string
soup.h1.span.string.replaceWith(comic_date + artist)
feature_item = soup.find('p',attrs={'class':'feature_item'})
if feature_item.a:
a_tag = feature_item.a
a_href = a_tag["href"]
img_tag = a_tag.img
img_tag["src"] = a_href
img_tag["width"] = self.comic_size
img_tag["height"] = None
return self.adeify_images(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;}
img {max-width:100%; min-width:100%;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''

View File

@ -0,0 +1,64 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
www.la-razon.com
'''
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class LaRazon_Bol(BasicNewsRecipe):
title = 'La Razón - Bolivia'
__author__ = 'Darko Miletic'
description = 'El diario nacional de Bolivia'
publisher = 'Praxsis S.R.L.'
category = 'news, politics, Bolivia'
oldest_article = 1
max_articles_per_feed = 200
no_stylesheets = True
encoding = 'cp1252'
use_embedded_content = False
language = 'es'
publication_type = 'newspaper'
delay = 1
remove_empty_feeds = True
cover_url = strftime('http://www.la-razon.com/portadas/%Y%m%d_LaRazon.jpg')
masthead_url = 'http://www.la-razon.com/imagenes/logo.jpg'
extra_css = """ body{font-family: Arial,Helvetica,sans-serif }
img{margin-bottom: 0.4em}
.noticia-titulo{font-family: Georgia,"Times New Roman",Times,serif}
.lead{font-weight: bold; font-size: 0.8em}
"""
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
keep_only_tags = [dict(name='div', attrs={'class':['noticia-titulo','noticia-desarrollo']})]
remove_tags = [dict(name=['meta','link','form','iframe','embed','object'])]
remove_attributes = ['width','height']
feeds = [
(u'Editorial' , u'http://www.la-razon.com/rss_editorial.php' )
,(u'Opinión' , u'http://www.la-razon.com/rss_opinion.php' )
,(u'Nacional' , u'http://www.la-razon.com/rss_nacional.php' )
,(u'Economia' , u'http://www.la-razon.com/rss_economia.php' )
,(u'Ciudades' , u'http://www.la-razon.com/rss_ciudades.php' )
,(u'Sociedad' , u'http://www.la-razon.com/rss_sociedad.php' )
,(u'Mundo' , u'http://www.la-razon.com/rss_sociedad.php' )
,(u'La Revista' , u'http://www.la-razon.com/rss_larevista.php' )
,(u'Sociales' , u'http://www.la-razon.com/rss_sociales.php' )
,(u'Mia' , u'http://www.la-razon.com/rss_mia.php' )
,(u'Marcas' , u'http://www.la-razon.com/rss_marcas.php' )
,(u'Escape' , u'http://www.la-razon.com/rss_escape.php' )
,(u'El Financiero' , u'http://www.la-razon.com/rss_financiero.php')
,(u'Tendencias' , u'http://www.la-razon.com/rss_tendencias.php')
]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -9,17 +9,22 @@ from calibre.web.feeds.news import BasicNewsRecipe
class Lanacion(BasicNewsRecipe): class Lanacion(BasicNewsRecipe):
title = 'La Nacion' title = 'La Nacion'
__author__ = 'Darko Miletic' __author__ = 'Darko Miletic'
description = 'Noticias de Argentina y el resto del mundo' description = "lanacion.com - Informacion actualizada las 24 horas, con noticias de Argentina y del mundo"
publisher = 'La Nacion S.A.' publisher = 'La Nacion S.A.'
category = 'news, politics, Argentina' category = 'news, politics, Argentina'
oldest_article = 2 oldest_article = 1
max_articles_per_feed = 100 max_articles_per_feed = 100
use_embedded_content = False use_embedded_content = False
no_stylesheets = True no_stylesheets = True
language = 'es' language = 'es'
encoding = 'cp1252' publication_type = 'newspaper'
remove_empty_feeds = True
masthead_url = 'http://www.lanacion.com.ar/imgs/layout/logos/ln341x47.gif' masthead_url = 'http://www.lanacion.com.ar/imgs/layout/logos/ln341x47.gif'
extra_css = ' h1{font-family: Georgia,serif} body{font-family: Arial,sans-serif} img{margin-top: 0.5em; margin-bottom: 0.2em} .notaEpigrafe{font-size: x-small} ' extra_css = """ h1{font-family: Georgia,serif}
body{font-family: Arial,sans-serif}
img{margin-top: 0.5em; margin-bottom: 0.2em}
.notaEpigrafe{font-size: x-small}
.topNota h1{font-family: Arial,sans-serif} """
conversion_options = { conversion_options = {
@ -29,19 +34,19 @@ class Lanacion(BasicNewsRecipe):
, 'language' : language , 'language' : language
} }
keep_only_tags = [dict(name='div', attrs={'class':'nota floatFix'})] keep_only_tags = [dict(name='div', attrs={'class':['nota floatFix','topNota','nota','post']})]
remove_tags = [ remove_tags = [
dict(name='div' , attrs={'class':'notaComentario floatFix noprint' }) dict(name='div' , attrs={'class':'notaComentario floatFix noprint' })
,dict(name='ul' , attrs={'class':'cajaHerramientas cajaTop noprint'}) ,dict(name='ul' , attrs={'class':['cajaHerramientas cajaTop noprint','herramientas noprint']})
,dict(name='div' , attrs={'class':'cajaHerramientas noprint' }) ,dict(name='div' , attrs={'class':'cajaHerramientas noprint' })
,dict(attrs={'class':['titulosMultimedia','derecha','techo color']}) ,dict(attrs={'class':['titulosMultimedia','derecha','techo color','encuesta','izquierda compartir','floatFix']})
,dict(name=['iframe','embed','object']) ,dict(name=['iframe','embed','object','form','base','hr'])
] ]
remove_attributes = ['height','width'] remove_tags_after = dict(attrs={'class':['tags','nota-destacado']})
remove_attributes = ['height','width','visible']
feeds = [ feeds = [
(u'Ultimas noticias' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?origen=2' ) (u'Ultimas noticias' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?origen=2' )
,(u'Diario de hoy' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?origen=1' )
,(u'Politica' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=30' ) ,(u'Politica' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=30' )
,(u'Economia' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=272' ) ,(u'Economia' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=272' )
,(u'Deportes' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=131' ) ,(u'Deportes' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=131' )
@ -50,8 +55,23 @@ class Lanacion(BasicNewsRecipe):
,(u'Opinion' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=28' ) ,(u'Opinion' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=28' )
,(u'Espectaculos' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=120' ) ,(u'Espectaculos' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=120' )
,(u'Exterior' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=7' ) ,(u'Exterior' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=7' )
,(u'Ciencia/Salud' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=498' ) ,(u'Ciencia&Salud' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=498' )
,(u'Revista' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=494' ) ,(u'Revista' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=494' )
,(u'Enfoques' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=421' )
,(u'Comercio Exterior' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=347' )
,(u'Tecnologia' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=432' )
,(u'Arquitectura' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=366' )
,(u'Turismo' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=504' )
,(u'Al volante' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=371' )
,(u'El Campo' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=337' )
,(u'Moda y Belleza' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=1312' )
,(u'Inmuebles Comerciales', u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=1363' )
,(u'Countries' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=1348' )
,(u'adnCultura' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=6734' )
,(u'The Wall Street Journal Americas', u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=6373' )
,(u'Estilo de vida' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=7353' )
,(u'Management' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=7380' )
,(u'Bicentenario' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?categoria_id=7276' )
] ]
def preprocess_html(self, soup): def preprocess_html(self, soup):

View File

@ -0,0 +1,63 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
www.lostiempos.com
'''
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class LosTiempos_Bol(BasicNewsRecipe):
title = 'Los Tiempos - Bolivia'
__author__ = 'Darko Miletic'
description = 'El periódico de mayor circulación en la ciudad de Cochabamba, Bolivia'
publisher = 'Los Tiempos'
category = 'news, politics, Bolivia'
oldest_article = 1
max_articles_per_feed = 200
no_stylesheets = True
encoding = 'cp1252'
use_embedded_content = False
language = 'es'
publication_type = 'newspaper'
delay = 1
remove_empty_feeds = True
cover_url = strftime('http://www.lostiempos.com/media_recortes/%Y/%m/%d/portada_md_1.jpg')
masthead_url = 'http://www.lostiempos.com/img_stat/logo_tiempos_sin_beta.jpg'
extra_css = """ body{font-family: Arial,Helvetica,sans-serif }
img{margin-bottom: 0.4em}
h1,.hora,.breadcum,.pie_foto{font-family: Georgia,"Times New Roman",Times,serif}
.hora,.breadcum,.pie_foto{font-size: small}
.en_gris,.pie_foto{color: #666666}
"""
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
keep_only_tags = [dict(name='div', attrs={'id':'articulo'})]
remove_tags = [
dict(name=['meta','link','form','iframe','embed','object','hr'])
,dict(attrs={'class':['caja_fonts sin_border_bot','pub']})
]
remove_attributes = ['width','height']
feeds = [
(u'Nacional' , u'http://www.lostiempos.com/rss/lostiempos-nacional.xml' )
,(u'Local' , u'http://www.lostiempos.com/rss/lostiempos-local.xml' )
,(u'Deportes' , u'http://www.lostiempos.com/rss/lostiempos-deportes.xml' )
,(u'Economía' , u'http://www.lostiempos.com/rss/lostiempos-economia.xml' )
,(u'Internacional' , u'http://www.lostiempos.com/rss/lostiempos-internacional.xml' )
,(u'Vida y Futuro' , u'http://www.lostiempos.com/rss/lostiempos-vida-y-futuro.xml' )
,(u'Tragaluz' , u'http://www.lostiempos.com/rss/lostiempos-tragaluz.xml' )
,(u'Opiniones' , u'http://www.lostiempos.com/rss/lostiempos-opiniones.xml' )
]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -6,10 +6,9 @@ www.standardmedia.co.ke
import os import os
from calibre import strftime, __appname__, __version__ from calibre import strftime, __appname__, __version__
import calibre.utils.PythonMagickWand as pw
from ctypes import byref
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.constants import preferred_encoding from calibre.constants import preferred_encoding
from calibre.utils.magick import Image
class NationKeRecipe(BasicNewsRecipe): class NationKeRecipe(BasicNewsRecipe):
@ -95,19 +94,9 @@ class NationKeRecipe(BasicNewsRecipe):
self.cover_img_path = None self.cover_img_path = None
def prepare_cover_image(self, path_to_image, out_path): def prepare_cover_image(self, path_to_image, out_path):
with pw.ImageMagick(): img = Image()
img = pw.NewMagickWand() img.open(path_to_image)
if img < 0: img.save(out_path)
raise RuntimeError('Out of memory')
if not pw.MagickReadImage(img, path_to_image):
severity = pw.ExceptionType(0)
msg = pw.MagickGetException(img, byref(severity))
raise IOError('Failed to read image from: %s: %s'
%(path_to_image, msg))
if not pw.MagickWriteImage(img, out_path):
raise RuntimeError('Failed to save image to %s'%out_path)
pw.DestroyMagickWand(img)
def default_cover(self, cover_file): def default_cover(self, cover_file):
''' '''

View File

@ -1,4 +1,3 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008-2010, AprilHare, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2010, AprilHare, Darko Miletic <darko.miletic at gmail.com>'
''' '''
@ -36,7 +35,7 @@ class NewScientist(BasicNewsRecipe):
remove_tags = [ remove_tags = [
dict(name='div' , attrs={'class':['hldBd','adline','pnl','infotext' ]}) dict(name='div' , attrs={'class':['hldBd','adline','pnl','infotext' ]})
,dict(name='div' , attrs={'id' :['compnl','artIssueInfo','artTools','comments','blgsocial']}) ,dict(name='div' , attrs={'id' :['compnl','artIssueInfo','artTools','comments','blgsocial','sharebtns']})
,dict(name='p' , attrs={'class':['marker','infotext' ]}) ,dict(name='p' , attrs={'class':['marker','infotext' ]})
,dict(name='meta' , attrs={'name' :'description' }) ,dict(name='meta' , attrs={'name' :'description' })
,dict(name='a' , attrs={'rel' :'tag' }) ,dict(name='a' , attrs={'rel' :'tag' })

View File

@ -11,7 +11,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
class Novosti(BasicNewsRecipe): class Novosti(BasicNewsRecipe):
title = 'Vecernje Novosti' title = 'Vecernje Novosti'
__author__ = 'Darko Miletic' __author__ = 'Darko Miletic'
description = 'Vesti' description = 'U početku su bile istinske večernje novine - pokrenute u vreme Tršćanske krize, Italijansko-jugoslovenskog konflikta oko grada Trsta - ali su brzo izrasle u dnevni informativno-politički list, koji već godinama ima najveći tiraž u Srbiji.'
publisher = 'Kompanija Novosti' publisher = 'Kompanija Novosti'
category = 'news, politics, Serbia' category = 'news, politics, Serbia'
oldest_article = 2 oldest_article = 2
@ -21,24 +21,22 @@ class Novosti(BasicNewsRecipe):
encoding = 'utf-8' encoding = 'utf-8'
language = 'sr' language = 'sr'
publication_type = 'newspaper' publication_type = 'newspaper'
extra_css = '@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} .article_description,body{font-family: Tahoma,Arial,Helvetica,sans1,sans-serif} ' extra_css = """ @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
.article_description,body{font-family: Arial,Helvetica,sans1,sans-serif}
.author{font-size: small}
.articleLead{font-size: large; font-weight: bold}
"""
conversion_options = { conversion_options = {
'comment' : description 'comment' : description
, 'tags' : category , 'tags' : category
, 'publisher' : publisher , 'publisher' : publisher
, 'language' : language , 'language' : language
, 'linearize_tables' : True
} }
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
keep_only_tags = [dict(name='div', attrs={'class':'jednaVest'})] keep_only_tags = [dict(attrs={'class':['articleTitle','author','articleLead','articleBody']})]
remove_tags = [dict(name='div', attrs={'class':['info','info_bottom','clip_div']})] remove_tags = [dict(name=['embed','object','iframe','base'])]
feeds = [(u'Vesti', u'http://www.novosti.rs/php/vesti/rss.php')] feeds = [(u'Vesti', u'http://www.novosti.rs/rss/rss-vesti')]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return self.adeify_images(soup)

View File

@ -6,7 +6,6 @@ nspm.rs
import re import re
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import Tag
class Nspm(BasicNewsRecipe): class Nspm(BasicNewsRecipe):
title = 'Nova srpska politicka misao' title = 'Nova srpska politicka misao'
@ -14,33 +13,39 @@ class Nspm(BasicNewsRecipe):
description = 'Casopis za politicku teoriju i drustvena istrazivanja' description = 'Casopis za politicku teoriju i drustvena istrazivanja'
publisher = 'NSPM' publisher = 'NSPM'
category = 'news, politics, Serbia' category = 'news, politics, Serbia'
oldest_article = 2 oldest_article = 7
max_articles_per_feed = 100 max_articles_per_feed = 100
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
INDEX = 'http://www.nspm.rs/?alphabet=l' INDEX = 'http://www.nspm.rs/?alphabet=l'
encoding = 'utf-8' encoding = 'utf-8'
language = 'sr' language = 'sr'
delay = 2
publication_type = 'magazine' publication_type = 'magazine'
masthead_url = 'http://www.nspm.rs/templates/jsn_epic_pro/images/logol.jpg' masthead_url = 'http://www.nspm.rs/templates/jsn_epic_pro/images/logol.jpg'
extra_css = ' @font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: "Times New Roman", serif1, serif} .article_description{font-family: Arial, sans1, sans-serif} img{margin-top:0.5em; margin-bottom: 0.7em} .author{color: #990000; font-weight: bold} .author,.createdate{font-size: 0.9em} img{margin-top:0.5em; margin-bottom: 0.7em} ' extra_css = """ @font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)}
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
body{font-family: "Times New Roman", serif1, serif}
.article_description{font-family: Arial, sans1, sans-serif}
img{margin-top:0.5em; margin-bottom: 0.7em}
.author{color: #990000; font-weight: bold}
.author,.createdate{font-size: 0.9em} """
conversion_options = { conversion_options = {
'comment' : description 'comment' : description
, 'tags' : category , 'tags' : category
, 'publisher' : publisher , 'publisher' : publisher
, 'language' : language , 'language' : language
, 'linearize_tables' : True
} }
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
keep_only_tags = [dict(attrs={'id':'jsn-mainbody'})]
remove_tags = [ remove_tags = [
dict(name=['link','object','embed','script','meta']) dict(name=['link','object','embed','script','meta','base','iframe'])
,dict(name='td', attrs={'class':'buttonheading'}) ,dict(attrs={'class':'buttonheading'})
] ]
keep_only_tags = [ remove_tags_after = dict(attrs={'class':'article_separator'})
dict(attrs={'class':['contentpagetitle','author','createdate']})
,dict(name='p')
]
remove_attributes = ['width','height'] remove_attributes = ['width','height']
def get_browser(self): def get_browser(self):
@ -48,25 +53,18 @@ class Nspm(BasicNewsRecipe):
br.open(self.INDEX) br.open(self.INDEX)
return br return br
feeds = [(u'Nova srpska politicka misao', u'http://www.nspm.rs/feed/rss.html')] feeds = [
(u'Rubrike' , u'http://www.nspm.rs/rubrike/feed/rss.html')
def print_version(self, url): ,(u'Debate' , u'http://www.nspm.rs/debate/feed/rss.html')
return url.replace('.html','/stampa.html') ,(u'Reci i misli' , u'http://www.nspm.rs/reci-i-misli/feed/rss.html')
,(u'Samo smeh srbina spasava', u'http://www.nspm.rs/samo-smeh-srbina-spasava/feed/rss.html')
,(u'Polemike' , u'http://www.nspm.rs/polemike/feed/rss.html')
,(u'Prikazi' , u'http://www.nspm.rs/prikazi/feed/rss.html')
,(u'Prenosimo' , u'http://www.nspm.rs/prenosimo/feed/rss.html')
,(u'Hronika' , u'http://www.nspm.rs/tabela/hronika/feed/rss.html')
]
def preprocess_html(self, soup): def preprocess_html(self, soup):
for item in soup.body.findAll(style=True): for item in soup.body.findAll(style=True):
del item['style'] del item['style']
att = soup.find('a',attrs={'class':'contentpagetitle'}) return self.adeify_images(soup)
if att:
att.name = 'h1';
del att['href']
att2 = soup.find('td')
if att2:
att2.name = 'p';
del att['valign']
for pt in soup.findAll('img'):
brtag = Tag(soup,'br')
brtag2 = Tag(soup,'br')
pt.append(brtag)
pt.append(brtag2)
return soup

View File

@ -1,7 +1,5 @@
#!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2010, Darko Miletic <darko.miletic at gmail.com>'
''' '''
nspm.rs/nspm-in-english nspm.rs/nspm-in-english
''' '''
@ -12,28 +10,43 @@ class Nspm_int(BasicNewsRecipe):
title = 'NSPM in English' title = 'NSPM in English'
__author__ = 'Darko Miletic' __author__ = 'Darko Miletic'
description = 'Magazine dedicated to political theory and sociological research' description = 'Magazine dedicated to political theory and sociological research'
oldest_article = 20 publisher = 'NSPM'
category = 'news, politics, Serbia'
oldest_article = 7
max_articles_per_feed = 100 max_articles_per_feed = 100
language = 'en'
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
INDEX = 'http://www.nspm.rs/?alphabet=l' encoding = 'utf-8'
cover_url = 'http://nspm.rs/templates/jsn_epic_pro/images/logol.jpg' language = 'en'
html2lrf_options = [ delay = 2
'--comment', description publication_type = 'magazine'
, '--base-font-size', '10' masthead_url = 'http://www.nspm.rs/templates/jsn_epic_pro/images/logol.jpg'
, '--category', 'news, politics, Serbia, english' extra_css = """
, '--publisher', 'IIC NSPM' body{font-family: "Times New Roman", serif}
] .article_description{font-family: Arial, sans-serif}
img{margin-top:0.5em; margin-bottom: 0.7em}
.author{color: #990000; font-weight: bold}
.author,.createdate{font-size: 0.9em} """
def get_browser(self): conversion_options = {
br = BasicNewsRecipe.get_browser() 'comment' : description
br.open(self.INDEX) , 'tags' : category
return br , 'publisher' : publisher
, 'language' : language
, 'linearize_tables' : True
}
keep_only_tags = [dict(attrs={'id':'jsn-mainbody'})]
remove_tags = [
dict(name=['link','object','embed','script','meta','base','iframe'])
,dict(attrs={'class':'buttonheading'})
]
remove_tags_after = dict(attrs={'class':'article_separator'})
remove_attributes = ['width','height']
keep_only_tags = [dict(name='div', attrs={'id':'jsn-mainbody'})] feeds = [(u'Articles', u'http://www.nspm.rs/nspm-in-english/feed/rss.html')]
remove_tags = [dict(name='div', attrs={'id':'yvComment' })]
feeds = [ (u'NSPM in English', u'http://nspm.rs/nspm-in-english/feed/rss.html')] def preprocess_html(self, soup):
for item in soup.body.findAll(style=True):
del item['style']
return self.adeify_images(soup)

View File

@ -1,13 +1,13 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
''' '''
sp.rian.ru sp.rian.ru
''' '''
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
class Ria_eng(BasicNewsRecipe): class Ria_esp(BasicNewsRecipe):
title = 'Ria Novosti' title = 'Ria Novosti'
__author__ = 'Darko Miletic' __author__ = 'Darko Miletic'
description = 'Noticias desde Russia en Castellano' description = 'Noticias desde Russia en Castellano'
@ -28,14 +28,10 @@ class Ria_eng(BasicNewsRecipe):
} }
keep_only_tags = [dict(name='div', attrs={'class':'articletxt'})] keep_only_tags = [dict(name='div', attrs={'class':['mainnewsrubric','titleblock','mainnewstxt']})]
remove_tags = [dict(name=['object','link','iframe','base'])] remove_tags = [dict(name=['object','link','iframe','base'])]
remove_tags_after = dict(name='div',attrs={'class':'text'})
feeds = [(u'Noticias', u'http://sp.rian.ru/export/rss2/index.xml')] feeds = [(u'Noticias', u'http://rss.feedsportal.com/c/860/fe.ed/sp.rian.ru/export/rss2/index.xml')]
def print_version(self, url):
return url.replace('.html','-print.html')

View File

@ -14,7 +14,7 @@ class ScientificAmerican(BasicNewsRecipe):
description = u'Popular science. Monthly magazine.' description = u'Popular science. Monthly magazine.'
__author__ = 'Kovid Goyal and Sujata Raman' __author__ = 'Kovid Goyal and Sujata Raman'
language = 'en' language = 'en'
remove_javascript = True
oldest_article = 30 oldest_article = 30
max_articles_per_feed = 100 max_articles_per_feed = 100
no_stylesheets = True no_stylesheets = True
@ -31,11 +31,13 @@ class ScientificAmerican(BasicNewsRecipe):
remove_tags_after = dict(id=['article']) remove_tags_after = dict(id=['article'])
remove_tags = [ remove_tags = [
dict(id=['sharetools', 'reddit']), dict(id=['sharetools', 'reddit']),
dict(name='script'), #dict(name='script'),
{'class':['float_left', 'atools']}, {'class':['float_left', 'atools']},
{"class": re.compile(r'also-in-this')}, {"class": re.compile(r'also-in-this')},
dict(name='a',title = ["Get the Rest of the Article","Subscribe","Buy this Issue"]), dict(name='a',title = ["Get the Rest of the Article","Subscribe","Buy this Issue"]),
dict(name = 'img',alt = ["Graphic - Get the Rest of the Article"]), dict(name = 'img',alt = ["Graphic - Get the Rest of the Article"]),
dict(name='div', attrs={'class':['commentbox']}),
dict(name='h2', attrs={'class':['discuss_h2']}),
] ]
html2lrf_options = ['--base-font-size', '8'] html2lrf_options = ['--base-font-size', '8']
@ -110,3 +112,10 @@ class ScientificAmerican(BasicNewsRecipe):
div.extract() div.extract()
return soup return soup
preprocess_regexps = [
(re.compile(r'Already a Digital subscriber.*Now</a>', re.DOTALL|re.IGNORECASE), lambda match: ''),
(re.compile(r'If your institution has site license access, enter.*here</a>.', re.DOTALL|re.IGNORECASE), lambda match: ''),
(re.compile(r'to subscribe to our.*;.*\}', re.DOTALL|re.IGNORECASE), lambda match: ''),
(re.compile(r'\)\(jQuery\);.*-->', re.DOTALL|re.IGNORECASE), lambda match: ''),
]

View File

@ -0,0 +1,49 @@
from calibre.web.feeds.news import BasicNewsRecipe
import re
class Skeptic(BasicNewsRecipe):
title = u'The Skeptic'
description = 'Discussions with leading experts and investigation of fringe science and paranormal claims.'
language = 'en'
__author__ = 'Starson17'
oldest_article = 31
cover_url = 'http://www.skeptricks.com/images/Skeptic_Magazine.jpg'
remove_empty_feeds = True
remove_javascript = True
max_articles_per_feed = 50
no_stylesheets = True
remove_tags = [dict(name='div', attrs={'class':['Introduction','divider']}),
dict(name='div', attrs={'id':['feature', 'podcast']}),
dict(name='div', attrs={'id':re.compile(r'follow.*', re.DOTALL|re.IGNORECASE)}),
dict(name='hr'),
]
feeds = [
('The Skeptic', 'http://www.skeptic.com/feed'),
('E-Skeptic', 'http://www.skeptic.com/eskeptic'),
('All-SkepticBlog', 'http://skepticblog.org/feed'),
('Brian Dunning', 'http://skepticblog.org/author/dunning/feed/'),
('Daniel Loxton', 'http://skepticblog.org/author/loxton/feed/'),
('Kirsten Sanford', 'http://skepticblog.org/author/sanford/feed/'),
('Mark Edward', 'http://skepticblog.org/author/edward/feed/'),
('Michael Shermer', 'http://skepticblog.org/author/shermer/feed/'),
('Phil Plait', 'http://skepticblog.org/author/plait/feed/'),
('Ryan Johnson', 'http://skepticblog.org/author/johnson/feed/'),
('Steven Novella', 'http://skepticblog.org/author/novella/feed/'),
('Yau-Man Chan', 'http://skepticblog.org/author/chan/feed/'),
]
def get_browser(self):
br = BasicNewsRecipe.get_browser(self)
br.addheaders = [('Accept', 'text/html')]
return br
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

@ -0,0 +1,50 @@
from calibre.web.feeds.news import BasicNewsRecipe
import re
class TheSkepticalInquirer(BasicNewsRecipe):
title = u'The Skeptical Inquirer'
description = 'Investigation of fringe science and paranormal claims.'
language = 'en'
__author__ = 'Starson17'
oldest_article = 31
cover_url = 'http://www.skeptricks.com/images/Skeptical_Inquirer_Magazine.jpg'
remove_empty_feeds = True
remove_javascript = True
max_articles_per_feed = 50
no_stylesheets = True
keep_only_tags = [dict(name='div', attrs={'id':['content', 'bio']})]
remove_tags = [
dict(name='div', attrs={'id':['socialMedia']}),
]
preprocess_regexps = [
(re.compile(r'\.\(JavaScript must be enabled to view this email address\)', re.DOTALL|re.IGNORECASE), lambda match: ''),
]
def parse_index(self):
feeds = []
for title, url in [("The Skeptical Inquirer", "http://www.csicop.org")]:
articles = self.make_links(url)
if articles:
feeds.append((title, articles))
return feeds
def make_links(self, url):
soup = self.index_to_soup(url)
title = ''
current_articles = []
for item in soup.findAll(attrs={'class':['article-single bigger']}):
page_url = url + str(item.a["href"])
title = str(item.a.string)
current_articles.append({'title': title, 'url': page_url, 'description':'', 'date':''})
return current_articles
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

@ -0,0 +1,46 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Starson17'
'''
snopes.com
'''
from calibre.web.feeds.recipes import BasicNewsRecipe
class Snopes(BasicNewsRecipe):
title = 'Snopes'
__author__ = 'Starson17'
description = 'Urban Legends'
oldest_article = 21
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
encoding = 'utf8'
publisher = 'Snopes'
category = 'news, '
language = 'en'
publication_type = 'newsportal'
remove_javascript = True
no_stylesheets = True
conversion_options = {
'comments' : description
,'tags' : category
,'language' : language
,'publisher' : publisher
,'linearize_tables': True
}
keep_only_tags = [
dict(name='h1'),
dict(name='div', attrs={'class':['article_text']}),
]
feeds = [
('Snopes', 'http://www.snopes.com/info/whatsnew.xml'),
]
extra_css = '''
h1{font-family:Trebuchet MS,Bookman Old Style,Arial;color:#75b570}
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:medium;}
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Arial,Helvetica,sans-serif;font-size:small;}
'''

View File

@ -6,11 +6,10 @@ www.standardmedia.co.ke
import os import os
from calibre import strftime, __appname__, __version__ from calibre import strftime, __appname__, __version__
import calibre.utils.PythonMagickWand as pw
from ctypes import byref
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.constants import preferred_encoding from calibre.constants import preferred_encoding
from calibre.utils.magick import Image
class StandardMediaKeRecipe(BasicNewsRecipe): class StandardMediaKeRecipe(BasicNewsRecipe):
@ -88,19 +87,9 @@ class StandardMediaKeRecipe(BasicNewsRecipe):
self.cover_img_path = None self.cover_img_path = None
def prepare_cover_image(self, path_to_image, out_path): def prepare_cover_image(self, path_to_image, out_path):
with pw.ImageMagick(): img = Image()
img = pw.NewMagickWand() img.open(path_to_image)
if img < 0: img.save(out_path)
raise RuntimeError('Out of memory')
if not pw.MagickReadImage(img, path_to_image):
severity = pw.ExceptionType(0)
msg = pw.MagickGetException(img, byref(severity))
raise IOError('Failed to read image from: %s: %s'
%(path_to_image, msg))
if not pw.MagickWriteImage(img, out_path):
raise RuntimeError('Failed to save image to %s'%out_path)
pw.DestroyMagickWand(img)
def default_cover(self, cover_file): def default_cover(self, cover_file):
''' '''

View File

@ -30,10 +30,12 @@ class Starbulletin(BasicNewsRecipe):
} }
remove_tags_before = dict(attrs={'id':'storyTitle'}) remove_tags_before = dict(attrs={'id':'storyTitle'})
remove_tags_after = dict(name='div', attrs={'class':'storytext'}) remove_tags_after = dict(name='div',attrs={'class':'storytext'})
remove_tags = [ remove_tags = [
dict(name=['object','link']) dict(name=['object','link','script','span'])
,dict(attrs={'class':'insideStoryImage'}) ,dict(attrs={'class':'insideStoryImage'})
,dict(attrs={'name':'fb_share'})
,dict(name='div',attrs={'class':'storytext'})
] ]
feeds = [ feeds = [

View File

@ -10,7 +10,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
class TagesspiegelRSS(BasicNewsRecipe): class TagesspiegelRSS(BasicNewsRecipe):
title = u'Der Tagesspiegel' title = u'Der Tagesspiegel'
__author__ = 'ipaschke' __author__ = 'Ingo Paschke'
language = 'de' language = 'de'
oldest_article = 7 oldest_article = 7
max_articles_per_feed = 100 max_articles_per_feed = 100
@ -26,7 +26,7 @@ class TagesspiegelRSS(BasicNewsRecipe):
.quote .cite{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:xx-small} .quote .cite{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:xx-small}
.hcf-inline-left{float:left;margin-right:15px;position:relative;} .hcf-inline-left{float:left;margin-right:15px;position:relative;}
.hcf-inline-right{float:right;margin-right:15px;position:relative;} .hcf-inline-right{float:right;margin-right:15px;position:relative;}
.hcf-smart-box{font-family: Arial, Helvetica, sans-serif; font-size: xx-small; margin: 0px 15px 8px 0px; width: 300px;} .hcf-smart-box{font-family: Arial, Helvetica, sans-serif; font-size: xx-small; margin: 0px 15px 8px 0px; width: 300px;}
''' '''
no_stylesheets = True no_stylesheets = True
@ -39,25 +39,30 @@ class TagesspiegelRSS(BasicNewsRecipe):
dict(name='link'), dict(name='iframe'),dict(name='style'),dict(name='meta'),dict(name='button'), dict(name='link'), dict(name='iframe'),dict(name='style'),dict(name='meta'),dict(name='button'),
dict(name='div', attrs={'class':["hcf-jump-to-comments","hcf-clear","hcf-magnify hcf-media-control"] }), dict(name='div', attrs={'class':["hcf-jump-to-comments","hcf-clear","hcf-magnify hcf-media-control"] }),
dict(name='span', attrs={'class':["hcf-mainsearch",] }), dict(name='span', attrs={'class':["hcf-mainsearch",] }),
dict(name='ul', attrs={'class':["hcf-tools"] }), dict(name='ul', attrs={'class':["hcf-tools"]}),
dict(name='ul', attrs={'class': re.compile('hcf-services')})
] ]
def parse_index(self): def parse_index(self):
soup = self.index_to_soup('http://www.tagesspiegel.de/zeitung/') soup = self.index_to_soup('http://www.tagesspiegel.de/zeitung/')
def feed_title(div): def feed_title(div):
return ''.join(div.findAll(text=True, recursive=False)).strip() return ''.join(div.findAll(text=True, recursive=False)).strip() if div is not None else None
articles = {} articles = {}
key = None key = None
ans = [] ans = []
maincol = soup.find('div', attrs={'class':re.compile('hcf-main-col')})
for div in soup.findAll(True, attrs={'class':['hcf-teaser', 'hcf-header', 'story headline']}): for div in maincol.findAll(True, attrs={'class':['hcf-teaser', 'hcf-header', 'story headline']}):
if div['class'] == 'hcf-header': if div['class'] == 'hcf-header':
key = string.capwords(feed_title(div.em.a)) try:
articles[key] = [] key = string.capwords(feed_title(div.em.a))
ans.append(key) articles[key] = []
ans.append(key)
except:
continue
elif div['class'] == 'hcf-teaser' and getattr(div.contents[0],'name','') == 'h2': elif div['class'] == 'hcf-teaser' and getattr(div.contents[0],'name','') == 'h2':
a = div.find('a', href=True) a = div.find('a', href=True)
@ -83,4 +88,3 @@ class TagesspiegelRSS(BasicNewsRecipe):
ans = [(key, articles[key]) for key in ans if articles.has_key(key)] ans = [(key, articles[key]) for key in ans if articles.has_key(key)]
return ans return ans

View File

@ -1,13 +1,10 @@
#!/usr/bin/env python
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008-2009, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2010, Darko Miletic <darko.miletic at gmail.com>'
''' '''
economictimes.indiatimes.com economictimes.indiatimes.com
''' '''
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import Tag
class TheEconomicTimes(BasicNewsRecipe): class TheEconomicTimes(BasicNewsRecipe):
title = 'The Economic Times India' title = 'The Economic Times India'
@ -21,18 +18,21 @@ class TheEconomicTimes(BasicNewsRecipe):
use_embedded_content = False use_embedded_content = False
simultaneous_downloads = 1 simultaneous_downloads = 1
encoding = 'utf-8' encoding = 'utf-8'
lang = 'en-IN' language = 'en_IN'
language = 'en_IN' publication_type = 'newspaper'
masthead_url = 'http://economictimes.indiatimes.com/photo/2676871.cms'
extra_css = """ body{font-family: Arial,Helvetica,sans-serif}
.heading1{font-size: xx-large; font-weight: bold} """
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
html2lrf_options = [ keep_only_tags = [dict(attrs={'class':['heading1','headingnext','Normal']})]
'--comment', description remove_tags = [dict(name=['object','link','embed','iframe','base','table','meta'])]
, '--category', category
, '--publisher', publisher
, '--ignore-tables'
]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\nlinearize_tables=True'
feeds = [(u'All articles', u'http://economictimes.indiatimes.com/rssfeedsdefault.cms')] feeds = [(u'All articles', u'http://economictimes.indiatimes.com/rssfeedsdefault.cms')]
@ -47,11 +47,6 @@ class TheEconomicTimes(BasicNewsRecipe):
return rurl return rurl
def preprocess_html(self, soup): def preprocess_html(self, soup):
soup.html['xml:lang'] = self.lang for item in soup.findAll(style=True):
soup.html['lang'] = self.lang del item['style']
mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=utf-8")])
soup.head.insert(0,mlang)
soup.head.insert(1,mcharset)
return self.adeify_images(soup) return self.adeify_images(soup)

View File

@ -50,12 +50,14 @@ class cdnet(BasicNewsRecipe):
dict(name='div', attrs={'class':'greyBoxR clearfix'}), dict(name='div', attrs={'class':'greyBoxR clearfix'}),
dict(name='div', attrs={'class':'greyBoxL clearfix'}), dict(name='div', attrs={'class':'greyBoxL clearfix'}),
dict(name='div', attrs={'class':'greyBox clearfix'}), dict(name='div', attrs={'class':'greyBox clearfix'}),
dict(name='div', attrs={'class':'labelized'}),
dict(id='')] dict(id='')]
#remove_tags_before = [dict(id='header-news-title')] #remove_tags_before = [dict(id='header-news-title')]
remove_tags_after = [dict(name='div', attrs={'class':'btmGreyTables'})] remove_tags_after = [dict(name='div', attrs={'class':'labelized'})]
#remove_tags_after = [dict(name='div', attrs={'class':'intelliTXT'})] #remove_tags_after = [dict(name='div', attrs={'class':'intelliTXT'})]
feeds = [ ('tomshardware', 'http://www.tomshardware.com/de/feeds/rss2/tom-s-hardware-de,12-1.xml') ] feeds = [ ('tomshardware', 'http://www.tomshardware.com/de/feeds/rss2/tom-s-hardware-de,12-1.xml') ]

View File

@ -36,7 +36,7 @@ class Vijesti(BasicNewsRecipe):
keep_only_tags = [dict(name='div', attrs={'id':'mainnews'})] keep_only_tags = [dict(name='div', attrs={'id':'mainnews'})]
remove_tags = [dict(name=['object','link','embed'])] remove_tags = [dict(name=['object','link','embed','form'])]
feeds = [(u'Sve vijesti', u'http://www.vijesti.me/rss.php' )] feeds = [(u'Sve vijesti', u'http://www.vijesti.me/rss.php' )]

View File

@ -22,7 +22,7 @@ class weltDe(BasicNewsRecipe):
remove_stylesheets = True remove_stylesheets = True
remove_javascript = True remove_javascript = True
encoding = 'utf-8' encoding = 'utf-8'
html2epub_options = 'linearize_tables = True\nbase_font_size2=10' html2epub_options = 'base_font_size=10'
BasicNewsRecipe.summary_length = 100 BasicNewsRecipe.summary_length = 100
@ -83,10 +83,9 @@ class weltDe(BasicNewsRecipe):
dict(name='div', attrs={'class':'articleOptions clear'}), dict(name='div', attrs={'class':'articleOptions clear'}),
dict(name='div', attrs={'class':'noPrint galleryIndex'}), dict(name='div', attrs={'class':'noPrint galleryIndex'}),
dict(name='div', attrs={'class':'inlineBox inlineTagCloud'}), dict(name='div', attrs={'class':'inlineBox inlineTagCloud'}),
dict(name='div', attrs={'class':'clear module imageGalleryBig bgColor1'}),
dict(name='div', attrs={'class':'clear module writeComment bgColor1'}), dict(name='div', attrs={'class':'clear module writeComment bgColor1'}),
dict(name='div', attrs={'class':'clear module textGallery bgColor1'}), dict(name='div', attrs={'class':'clear module textGallery bgColor1'}),
dict(name='div', attrs={'class':'clear module socialMedia bgColor1'}),
dict(name='div', attrs={'class':'clear module continuativeLinks'}),
dict(name='div', attrs={'class':'moreArtH3'}), dict(name='div', attrs={'class':'moreArtH3'}),
dict(name='div', attrs={'class':'jqmWindow'}), dict(name='div', attrs={'class':'jqmWindow'}),
dict(name='div', attrs={'class':'clear gap4'}), dict(name='div', attrs={'class':'clear gap4'}),
@ -99,7 +98,7 @@ class weltDe(BasicNewsRecipe):
dict(name='div', attrs={'class':'headLineH3'}), dict(name='div', attrs={'class':'headLineH3'}),
dict(name='div', attrs={'class':'print'}), dict(name='div', attrs={'class':'print'}),
dict(name='div', attrs={'class':'clear menu'}), dict(name='div', attrs={'class':'clear menu'}),
dict(name='div', attrs={'class':'clear galleryContent'}), dict(name='div', attrs={'class':'themenalarm'}),
dict(name='p', attrs={'class':'jump'}), dict(name='p', attrs={'class':'jump'}),
dict(name='a', attrs={'class':'commentLink'}), dict(name='a', attrs={'class':'commentLink'}),
dict(name='h2', attrs={'class':'jumpHeading'}), dict(name='h2', attrs={'class':'jumpHeading'}),
@ -110,7 +109,7 @@ class weltDe(BasicNewsRecipe):
dict(name='table', attrs={'class':'textGallery'}), dict(name='table', attrs={'class':'textGallery'}),
dict(name='li', attrs={'class':'active'})] dict(name='li', attrs={'class':'active'})]
remove_tags_after = [dict(name='div', attrs={'class':'clear departmentLine'})] remove_tags_after = [dict(name='div', attrs={'class':'themenalarm'})]
extra_css = ''' extra_css = '''
h2{font-family:Arial,Helvetica,sans-serif; font-size: x-small; color: #003399;} h2{font-family:Arial,Helvetica,sans-serif; font-size: x-small; color: #003399;}
@ -122,6 +121,7 @@ class weltDe(BasicNewsRecipe):
.photo {font-family:Arial,Helvetica,sans-serif; font-size: x-small; color: #666666;} ''' .photo {font-family:Arial,Helvetica,sans-serif; font-size: x-small; color: #666666;} '''
feeds = [ ('Politik', 'http://welt.de/politik/?service=Rss'), feeds = [ ('Politik', 'http://welt.de/politik/?service=Rss'),
('Deutsche Dinge', 'http://www.welt.de/deutsche-dinge/?service=Rss'),
('Wirtschaft', 'http://welt.de/wirtschaft/?service=Rss'), ('Wirtschaft', 'http://welt.de/wirtschaft/?service=Rss'),
('Finanzen', 'http://welt.de/finanzen/?service=Rss'), ('Finanzen', 'http://welt.de/finanzen/?service=Rss'),
('Sport', 'http://welt.de/sport/?service=Rss'), ('Sport', 'http://welt.de/sport/?service=Rss'),
@ -137,3 +137,4 @@ class weltDe(BasicNewsRecipe):
def print_version(self, url): def print_version(self, url):
return url.replace ('.html', '.html?print=true') return url.replace ('.html', '.html?print=true')

View File

@ -1,314 +0,0 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
'''
online.wsj.com
'''
import re
from calibre.web.feeds.recipes import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import Tag, NavigableString
from datetime import timedelta, date
class WSJ(BasicNewsRecipe):
# formatting adapted from original recipe by Kovid Goyal and Sujata Raman
title = u'Wall Street Journal (free)'
__author__ = 'Nick Redding'
language = 'en'
description = ('All the free content from the Wall Street Journal (business, financial and political news)')
no_stylesheets = True
timefmt = ' [%b %d]'
# customization notes: delete sections you are not interested in
# set omit_paid_content to False if you want the paid content article snippets
# set oldest_article to the maximum number of days back from today to include articles
sectionlist = [
['/home-page','Front Page'],
['/public/page/news-opinion-commentary.html','Commentary'],
['/public/page/news-global-world.html','World News'],
['/public/page/news-world-business.html','US News'],
['/public/page/news-business-us.html','Business'],
['/public/page/news-financial-markets-stock.html','Markets'],
['/public/page/news-tech-technology.html','Technology'],
['/public/page/news-personal-finance.html','Personal Finnce'],
['/public/page/news-lifestyle-arts-entertainment.html','Life & Style'],
['/public/page/news-real-estate-homes.html','Real Estate'],
['/public/page/news-career-jobs.html','Careers'],
['/public/page/news-small-business-marketing.html','Small Business']
]
oldest_article = 2
omit_paid_content = True
extra_css = '''h1{font-size:large; font-family:Times,serif;}
h2{font-family:Times,serif; font-size:small; font-style:italic;}
.subhead{font-family:Times,serif; font-size:small; font-style:italic;}
.insettipUnit {font-family:Times,serif;font-size:xx-small;}
.targetCaption{font-size:x-small; font-family:Times,serif; font-style:italic; margin-top: 0.25em;}
.article{font-family:Times,serif; font-size:x-small;}
.tagline { font-size:xx-small;}
.dateStamp {font-family:Times,serif;}
h3{font-family:Times,serif; font-size:xx-small;}
.byline {font-family:Times,serif; font-size:xx-small; list-style-type: none;}
.metadataType-articleCredits {list-style-type: none;}
h6{font-family:Times,serif; font-size:small; font-style:italic;}
.paperLocation{font-size:xx-small;}'''
remove_tags_before = dict({'class':re.compile('^articleHeadlineBox')})
remove_tags = [ dict({'id':re.compile('^articleTabs_tab_')}),
#dict(id=["articleTabs_tab_article", "articleTabs_tab_comments",
# "articleTabs_tab_interactive","articleTabs_tab_video",
# "articleTabs_tab_map","articleTabs_tab_slideshow"]),
{'class': ['footer_columns','network','insetCol3wide','interactive','video','slideshow','map',
'insettip','insetClose','more_in', "insetContent",
# 'articleTools_bottom','articleTools_bottom mjArticleTools',
'aTools', 'tooltip',
'adSummary', 'nav-inline','insetFullBracket']},
dict({'class':re.compile('^articleTools_bottom')}),
dict(rel='shortcut icon')
]
remove_tags_after = [dict(id="article_story_body"), {'class':"article story"}]
def get_browser(self):
br = BasicNewsRecipe.get_browser()
return br
def preprocess_html(self,soup):
def decode_us_date(datestr):
udate = datestr.strip().lower().split()
m = ['january','february','march','april','may','june','july','august','september','october','november','december'].index(udate[0])+1
d = int(udate[1])
y = int(udate[2])
return date(y,m,d)
# check if article is paid content
if self.omit_paid_content:
divtags = soup.findAll('div','tooltip')
if divtags:
for divtag in divtags:
if divtag.find(text="Subscriber Content"):
return None
# check if article is too old
datetag = soup.find('li',attrs={'class' : re.compile("^dateStamp")})
if datetag:
dateline_string = self.tag_to_string(datetag,False)
date_items = dateline_string.split(',')
datestring = date_items[0]+date_items[1]
article_date = decode_us_date(datestring)
earliest_date = date.today() - timedelta(days=self.oldest_article)
if article_date < earliest_date:
self.log("Skipping article dated %s" % datestring)
return None
datetag.parent.extract()
# place dateline in article heading
bylinetag = soup.find('h3','byline')
if bylinetag:
h3bylinetag = bylinetag
else:
bylinetag = soup.find('li','byline')
if bylinetag:
h3bylinetag = bylinetag.h3
if not h3bylinetag:
h3bylinetag = bylinetag
bylinetag = bylinetag.parent
if bylinetag:
if h3bylinetag.a:
bylinetext = 'By '+self.tag_to_string(h3bylinetag.a,False)
else:
bylinetext = self.tag_to_string(h3bylinetag,False)
h3byline = Tag(soup,'h3',[('class','byline')])
if bylinetext.isspace() or (bylinetext == ''):
h3byline.insert(0,NavigableString(date_items[0]+','+date_items[1]))
else:
h3byline.insert(0,NavigableString(bylinetext+u'\u2014'+date_items[0]+','+date_items[1]))
bylinetag.replaceWith(h3byline)
else:
headlinetag = soup.find('div',attrs={'class' : re.compile("^articleHeadlineBox")})
if headlinetag:
dateline = Tag(soup,'h3', [('class','byline')])
dateline.insert(0,NavigableString(date_items[0]+','+date_items[1]))
headlinetag.insert(len(headlinetag),dateline)
else: # if no date tag, don't process this page--it's not a news item
return None
# This gets rid of the annoying superfluous bullet symbol preceding columnist bylines
ultag = soup.find('ul',attrs={'class' : 'cMetadata metadataType-articleCredits'})
if ultag:
a = ultag.h3
if a:
ultag.replaceWith(a)
return soup
def parse_index(self):
articles = {}
key = None
ans = []
def parse_index_page(page_name,page_title):
def article_title(tag):
atag = tag.find('h2') # title is usually in an h2 tag
if not atag: # if not, get text from the a tag
atag = tag.find('a',href=True)
if not atag:
return ''
t = self.tag_to_string(atag,False)
if t == '':
# sometimes the title is in the second a tag
atag.extract()
atag = tag.find('a',href=True)
if not atag:
return ''
return self.tag_to_string(atag,False)
return t
return self.tag_to_string(atag,False)
def article_author(tag):
atag = tag.find('strong') # author is usually in a strong tag
if not atag:
atag = tag.find('h4') # if not, look for an h4 tag
if not atag:
return ''
return self.tag_to_string(atag,False)
def article_summary(tag):
atag = tag.find('p')
if not atag:
return ''
subtag = atag.strong
if subtag:
subtag.extract()
return self.tag_to_string(atag,False)
def article_url(tag):
atag = tag.find('a',href=True)
if not atag:
return ''
url = re.sub(r'\?.*', '', atag['href'])
return url
def handle_section_name(tag):
# turns a tag into a section name with special processing
# for Wat's News, U.S., World & U.S. and World
s = self.tag_to_string(tag,False)
if ("What" in s) and ("News" in s):
s = "What's News"
elif (s == "U.S.") or (s == "World & U.S.") or (s == "World"):
s = s + " News"
return s
mainurl = 'http://online.wsj.com'
pageurl = mainurl+page_name
#self.log("Page url %s" % pageurl)
soup = self.index_to_soup(pageurl)
# Find each instance of div with class including "headlineSummary"
for divtag in soup.findAll('div',attrs={'class' : re.compile("^headlineSummary")}):
# divtag contains all article data as ul's and li's
# first, check if there is an h3 tag which provides a section name
stag = divtag.find('h3')
if stag:
if stag.parent.get('class', '') == 'dynamic':
# a carousel of articles is too complex to extract a section name
# for each article, so we'll just call the section "Carousel"
section_name = 'Carousel'
else:
section_name = handle_section_name(stag)
else:
section_name = "What's News"
#self.log("div Section %s" % section_name)
# find each top-level ul in the div
# we don't restrict to class = newsItem because the section_name
# sometimes changes via a ul tag inside the div
for ultag in divtag.findAll('ul',recursive=False):
stag = ultag.find('h3')
if stag:
if stag.parent.name == 'ul':
# section name has changed
section_name = handle_section_name(stag)
#self.log("ul Section %s" % section_name)
# delete the h3 tag so it doesn't get in the way
stag.extract()
# find each top level li in the ul
for litag in ultag.findAll('li',recursive=False):
stag = litag.find('h3')
if stag:
# section name has changed
section_name = handle_section_name(stag)
#self.log("li Section %s" % section_name)
# delete the h3 tag so it doesn't get in the way
stag.extract()
# if there is a ul tag inside the li it is superfluous;
# it is probably a list of related articles
utag = litag.find('ul')
if utag:
utag.extract()
# now skip paid subscriber articles if desired
subscriber_tag = litag.find(text="Subscriber Content")
if subscriber_tag:
if self.omit_paid_content:
continue
# delete the tip div so it doesn't get in the way
tiptag = litag.find("div", { "class" : "tipTargetBox" })
if tiptag:
tiptag.extract()
h1tag = litag.h1
# if there's an h1 tag, it's parent is a div which should replace
# the li tag for the analysis
if h1tag:
litag = h1tag.parent
h5tag = litag.h5
if h5tag:
# section mame has changed
section_name = self.tag_to_string(h5tag,False)
#self.log("h5 Section %s" % section_name)
# delete the h5 tag so it doesn't get in the way
h5tag.extract()
url = article_url(litag)
if url == '':
continue
if url.startswith("/article"):
url = mainurl+url
if not url.startswith("http://online.wsj.com"):
continue
if not url.endswith(".html"):
continue
if 'video' in url:
continue
title = article_title(litag)
if title == '':
continue
#self.log("URL %s" % url)
#self.log("Title %s" % title)
pubdate = ''
#self.log("Date %s" % pubdate)
author = article_author(litag)
if author == '':
author = section_name
elif author == section_name:
author = ''
else:
author = section_name+': '+author
#if not author == '':
# self.log("Author %s" % author)
description = article_summary(litag)
#if not description == '':
# self.log("Description %s" % description)
if not articles.has_key(page_title):
articles[page_title] = []
articles[page_title].append(dict(title=title,url=url,date=pubdate,description=description,author=author,content=''))
for page_name,page_title in self.sectionlist:
parse_index_page(page_name,page_title)
ans.append(page_title)
ans = [(key, articles[key]) for key in ans if articles.has_key(key)]
return ans

View File

@ -0,0 +1,34 @@
from calibre.web.feeds.news import BasicNewsRecipe
import re
class YahooNews(BasicNewsRecipe):
title = 'Yahoo News'
__author__ = 'Starson17'
description = 'Yahoo-Science'
language = 'en'
use_embedded_content= False
no_stylesheets = True
linearize_tables = True
oldest_article = 24
remove_javascript = True
remove_empty_feeds = True
max_articles_per_feed = 10
feeds = [#There are dozens of other feeds at http://news.yahoo.com/rss
(u'Top Stories', u'http://rss.news.yahoo.com/rss/topstories'),
(u'Science', u'http://rss.news.yahoo.com/rss/science')
]
keep_only_tags = [dict(name='div', attrs={'id':'yn-story'})]
remove_tags = [dict(name='div', attrs={'class':['hd', 'ft', 'yn-share-social']}),
dict(name='div', attrs={'id':['yn-story-minor-media']})]
preprocess_regexps = [(re.compile(r'<span>Play Video</span>', re.DOTALL),lambda match: '<span></span>')]
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

@ -6,88 +6,105 @@ Fetch Die Zeit.
''' '''
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import Tag
class ZeitDe(BasicNewsRecipe): class ZeitDe(BasicNewsRecipe):
title = 'Die Zeit Nachrichten' title = 'ZEIT Online'
description = 'Die Zeit - Online Nachrichten' description = 'ZEIT Online'
language = 'de' language = 'de'
lang = 'de_DE' lang = 'de_DE'
__author__ = 'Martin Pitt and Sujata Raman' __author__ = 'Martin Pitt, Sujata Raman and Ingo Paschke'
use_embedded_content = False use_embedded_content = False
max_articles_per_feed = 40 max_articles_per_feed = 40
remove_empty_feeds = True remove_empty_feeds = True
no_stylesheets = True no_stylesheets = True
no_javascript = True
encoding = 'utf-8' encoding = 'utf-8'
feeds = [ feeds = [
('Seite 1', 'http://newsfeed.zeit.de/index_xml'),
('Politik', 'http://newsfeed.zeit.de/politik/index'), ('Politik', 'http://newsfeed.zeit.de/politik/index'),
('Wirtschaft', 'http://newsfeed.zeit.de/wirtschaft/index'), ('Wirtschaft', 'http://newsfeed.zeit.de/wirtschaft/index'),
('Meinung', 'http://newsfeed.zeit.de/meinung/index'), ('Meinung', 'http://newsfeed.zeit.de/meinung/index'),
('Gesellschaft', 'http://newsfeed.zeit.de/gesellschaft/index'), ('Gesellschaft', 'http://newsfeed.zeit.de/gesellschaft/index'),
('Kultur', 'http://newsfeed.zeit.de/kultur/index'), ('Kultur', 'http://newsfeed.zeit.de/kultur/index'),
('Wissen', 'http://newsfeed.zeit.de/wissen/index'), ('Wissen', 'http://newsfeed.zeit.de/wissen/index'),
('Digital', 'http://newsfeed.zeit.de/digital/index'),
('Studium', 'http://newsfeed.zeit.de/studium/index'),
('Karriere', 'http://newsfeed.zeit.de/karriere/index'),
('Lebensart', 'http://newsfeed.zeit.de/lebensart/index'),
('Reisen', 'http://newsfeed.zeit.de/reisen/index'),
('Auto', 'http://newsfeed.zeit.de/auto/index'),
('Sport', 'http://newsfeed.zeit.de/sport/index'),
] ]
extra_css = ''' extra_css = '''
.supertitle{color:#990000; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;} .supertitle{color:#990000; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;}
.excerpt{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:large;} .excerpt{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:small;}
.title{font-family:Arial,Helvetica,sans-serif;font-size:large} .title{font-family:Arial,Helvetica,sans-serif;font-size:large;clear:right;}
.caption{color:#666666; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;} .caption{color:#666666; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;}
.copyright{color:#666666; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;} .copyright{color:#666666; font-family:Arial,Helvetica,sans-serif;font-size:xx-small;}
.article{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:x-small} .article{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:x-small}
.quote{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:x-small}
.quote .cite{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:xx-small}
.headline iconportrait_inline{font-family:Arial,Helvetica,sans-serif;font-size:x-small} .headline iconportrait_inline{font-family:Arial,Helvetica,sans-serif;font-size:x-small}
.inline{float:left;margin-top:0;margin-right:15px;position:relative;width:180px; }
img.inline{float:none}
.intertitle{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:x-small;font-weight:700}
.ebinfobox{font-family:Georgia,Palatino,Palatino Linotype,FreeSerif,serif;font-size:xx-small;list-style-type:none;float:right;margin-top:0;border-left-style:solid;border-left-width:1px;padding-left:10px;}
.infobox {border-style: solid; border-width: 1px;padding:8px;}
.infobox dt {font-weight:700;}
''' '''
#filter_regexps = [r'ad.de.doubleclick.net/'] #filter_regexps = [r'ad.de.doubleclick.net/']
keep_only_tags = [ keep_only_tags = [
dict(name='div', attrs={'class':["article"]}) , dict(name='div', attrs={'class':["article"]}) ,
dict(name='ul', attrs={'class':["tools"]}) ,
] ]
remove_tags = [ remove_tags = [
dict(name='link'), dict(name='iframe'),dict(name='style'), dict(name='link'), dict(name='iframe'),dict(name='style'),dict(name='meta'),
dict(name='div', attrs={'class':["pagination block","pagenav","inline link"] }), dict(name='div', attrs={'class':["pagination block","pagenav","inline link", "copyright"] }),
dict(name='div', attrs={'id':["place_5","place_4"]}) dict(name='p', attrs={'class':["ressortbacklink", "copyright"] }),
dict(name='div', attrs={'id':["place_5","place_4","comments"]})
] ]
remove_attributes = ['style', 'font']
def get_article_url(self, article): def get_article_url(self, article):
ans = article.get('link',None)
ans = article.get('guid',None) ans += "?page=all"
try:
self.log('Looking for full story link in', ans)
soup = self.index_to_soup(ans)
x = soup.find(text="Auf einer Seite lesen")
if x is not None:
a = x.parent
if a and a.has_key('href'):
ans = a['href']
self.log('Found full story link', ans)
except:
pass
if 'video' in ans or 'quiz' in ans : if 'video' in ans or 'quiz' in ans :
ans = None ans = None
return ans return ans
def get_cover_url(self):
try:
inhalt = self.index_to_soup('http://www.zeit.de/inhalt')
return inhalt.find('div', attrs={'class':'singlearchive clearfix'}).img['src'].replace('icon_','')
except:
return 'http://images.zeit.de/bilder/titelseiten_zeit/1946/001_001.jpg'
def preprocess_html(self, soup): def preprocess_html(self, soup):
soup.html['xml:lang'] = self.lang soup.html['xml:lang'] = self.lang
soup.html['lang'] = self.lang soup.html['lang'] = self.lang
mtag = '<meta http-equiv="Content-Type" content="text/html; charset=' + self.encoding + '">' mtag = '<meta http-equiv="Content-Type" content="text/html; charset=' + self.encoding + '">'
soup.head.insert(0,mtag) soup.head.insert(0,mtag)
title = soup.find('h2', attrs={'class':'title'})
if title is None:
print "no title"
return soup
info = Tag(soup,'ul',[('class','ebinfobox')])
tools = soup.find('ul', attrs={'class':'tools'})
#author = tools.find('li','author first')
for tag in ['author first', 'date', 'date first', 'author', 'source']:
line = tools.find('li', tag)
if line:
info.insert(0,line)
title.parent.insert(0,info)
tools.extract()
return soup return soup
#def print_version(self,url):
# return url.replace('http://www.zeit.de/', 'http://images.zeit.de/text/').replace('?from=rss', '')

View File

@ -262,7 +262,7 @@
</xsl:if> </xsl:if>
<xsl:if test="@line-spacing"> <xsl:if test="@line-spacing">
<xsl:text>line-height:</xsl:text> <xsl:text>line-height:</xsl:text>
<xsl:value-of select="@line-height"/> <xsl:value-of select="@line-spacing"/>
<xsl:text>pt;</xsl:text> <xsl:text>pt;</xsl:text>
</xsl:if> </xsl:if>
<xsl:if test="(@align = 'just')"> <xsl:if test="(@align = 'just')">
@ -413,6 +413,10 @@
</xsl:element> </xsl:element>
</xsl:template> </xsl:template>
<xsl:template match="rtf:hardline-break">
<xsl:element name="br"/>
</xsl:template>
<xsl:template match="rtf:rtf-definition|rtf:font-table|rtf:color-table|rtf:style-table|rtf:page-definition|rtf:list-table|rtf:override-table|rtf:override-list|rtf:list-text"/> <xsl:template match="rtf:rtf-definition|rtf:font-table|rtf:color-table|rtf:style-table|rtf:page-definition|rtf:list-table|rtf:override-table|rtf:override-list|rtf:list-text"/>
<xsl:template match="rtf:body"> <xsl:template match="rtf:body">

View File

@ -115,7 +115,6 @@ if iswindows:
poppler_lib_dirs = consolidate('POPPLER_LIB_DIR', sw_lib_dir) poppler_lib_dirs = consolidate('POPPLER_LIB_DIR', sw_lib_dir)
popplerqt4_lib_dirs = poppler_lib_dirs popplerqt4_lib_dirs = poppler_lib_dirs
poppler_libs = ['poppler'] poppler_libs = ['poppler']
popplerqt4_libs = poppler_libs + ['QtCore4', 'QtGui4']
magick_inc_dirs = [os.path.join(prefix, 'build', 'ImageMagick-6.5.6')] magick_inc_dirs = [os.path.join(prefix, 'build', 'ImageMagick-6.5.6')]
magick_lib_dirs = [os.path.join(magick_inc_dirs[0], 'VisualMagick', 'lib')] magick_lib_dirs = [os.path.join(magick_inc_dirs[0], 'VisualMagick', 'lib')]
magick_libs = ['CORE_RL_wand_', 'CORE_RL_magick_'] magick_libs = ['CORE_RL_wand_', 'CORE_RL_magick_']
@ -129,8 +128,8 @@ elif isosx:
popplerqt4_inc_dirs = poppler_inc_dirs + [poppler_inc_dirs[0]+'/qt4'] popplerqt4_inc_dirs = poppler_inc_dirs + [poppler_inc_dirs[0]+'/qt4']
poppler_lib_dirs = consolidate('POPPLER_LIB_DIR', poppler_lib_dirs = consolidate('POPPLER_LIB_DIR',
'/sw/lib') '/sw/lib')
poppler_libs = ['poppler']
popplerqt4_lib_dirs = poppler_lib_dirs popplerqt4_lib_dirs = poppler_lib_dirs
poppler_libs = popplerqt4_libs = ['poppler']
podofo_inc = '/sw/podofo' podofo_inc = '/sw/podofo'
podofo_lib = '/sw/lib' podofo_lib = '/sw/lib'
magick_inc_dirs = consolidate('MAGICK_INC', magick_inc_dirs = consolidate('MAGICK_INC',
@ -162,9 +161,6 @@ else:
poppler_libs = pkgconfig_libs('poppler', '', '') poppler_libs = pkgconfig_libs('poppler', '', '')
if not poppler_libs: if not poppler_libs:
poppler_libs = ['poppler'] poppler_libs = ['poppler']
popplerqt4_libs = pkgconfig_libs('poppler-qt4', '', '')
if not popplerqt4_libs:
popplerqt4_libs = ['poppler-qt4', 'poppler']
magick_libs = pkgconfig_libs('MagickWand', '', '') magick_libs = pkgconfig_libs('MagickWand', '', '')
if not magick_libs: if not magick_libs:
magick_libs = ['MagickWand', 'MagickCore'] magick_libs = ['MagickWand', 'MagickCore']

View File

@ -72,6 +72,13 @@ extensions = [
lib_dirs=chmlib_lib_dirs, lib_dirs=chmlib_lib_dirs,
cflags=["-D__PYTHON__"]), cflags=["-D__PYTHON__"]),
Extension('magick',
['calibre/utils/magick/magick.c'],
headers=['calibre/utils/magick/magick_constants.h'],
libraries=magick_libs,
lib_dirs=magick_lib_dirs,
inc_dirs=magick_inc_dirs
),
Extension('pdfreflow', Extension('pdfreflow',
reflow_sources, reflow_sources,

View File

@ -1,244 +0,0 @@
Changes from 4.0 to 4.0.1
1) Added support for Python 2.6. On Windows a manifest file is now required
because of the switch to using the new Microsoft C runtime.
2) Ensure that hooks are run for builtin modules.
Changes from 4.0b1 to 4.0
1) Added support for copying files to the target directory.
2) Added support for a hook that runs when a module is missing.
3) Added support for binary path includes as well as excludes; use sequences
rather than dictionaries as a more convenient API; exclude the standard
locations for 32-bit and 64-bit libaries in multi-architecture systems.
4) Added support for searching zip files (egg files) for modules.
5) Added support for handling system exit exceptions similarly to what Python
does itself as requested by Sylvain.
6) Added code to wait for threads to shut down like the normal Python
interpreter does. Thanks to Mariano Disanzo for discovering this
discrepancy.
7) Hooks added or modified based on feedback from many people.
8) Don't include the version name in the display name of the MSI.
9) Use the OS dependent path normalization routines rather than simply use the
lowercase value as on Unix case is important; thanks to Artie Eoff for
pointing this out.
10) Include a version attribute in the cx_Freeze package and display it in the
output for the --version option to the script.
11) Include build instructions as requested by Norbert Sebok.
12) Add support for copying files when modules are included which require data
files to operate properly; add support for copying the necessary files for
the Tkinter and matplotlib modules.
13) Handle deferred imports recursively as needed; ensure that from lists do
not automatically indicate that they are part of the module or the deferred
import processing doesn't actually work!
14) Handle the situation where a module imports everything from a package and
the __all__ variable has been defined but the package has not actually
imported everything in the __all__ variable during initialization.
15) Modified license text to more closely match the Python Software Foundation
license as was intended.
16) Added sample script for freezing an application using matplotlib.
17) Renamed freeze to cxfreeze to avoid conflict with another package that uses
that executable as requested by Siegfried Gevatter.
Changes from 3.0.3 to 4.0b1
1) Added support for placing modules in library.zip or in a separate zip file
for each executable that is produced.
2) Added support for copying binary dependent files (DLLs and shared
libraries)
3) Added support for including all submodules in a package
4) Added support for including icons in Windows executables
5) Added support for constants module which can be used for determining
certain build constants at runtime
6) Added support for relative imports available in Python 2.5 and up
7) Added support for building Windows installers (Python 2.5 and up) and
RPM packages
8) Added support for distutils configuration scripts
9) Added support for hooks which can force inclusion or exclusion of modules
when certain modules are included
10) Added documentation and samples
11) Added setup.py for building the cx_Freeze package instead of a script
used to build only the frozen bases
12) FreezePython renamed to a script called freeze in the Python distribution
13) On Linux and other platforms that support it set LD_RUN_PATH to include
the directory in which the executable is located
Changes from 3.0.2 to 3.0.3
1) In Common.c, used MAXPATHLEN defined in the Python OS independent include
file rather than the PATH_MAX define which is OS dependent and is not
available on IRIX as noted by Andrew Jones.
2) In the initscript ConsoleSetLibPath.py, added lines from initscript
Console.py that should have been there since the only difference between
that script and this one is the automatic re-execution of the executable.
3) Added an explicit "import encodings" to the initscripts in order to handle
Unicode encodings a little better. Thanks to Ralf Schmitt for pointing out
the problem and its solution.
4) Generated a meaningful name for the extension loader script so that it is
clear which particular extension module is being loaded when an exception
is being raised.
5) In MakeFrozenBases.py, use distutils to figure out a few more
platform-dependent linker flags as suggested by Ralf Schmitt.
Changes from 3.0.1 to 3.0.2
1) Add support for compressing the byte code in the zip files that are
produced.
2) Add better support for the win32com package as requested by Barry Scott.
3) Prevent deletion of target file if it happens to be identical to the
source file.
4) Include additional flags for local modifications to a Python build as
suggested by Benjamin Rutt.
5) Expanded instructions for building cx_Freeze from source based on a
suggestion from Gregg Lind.
6) Fix typo in help string.
Changes from 3.0 to 3.0.1
1) Added option --default-path which is used to specify the path used when
finding modules. This is particularly useful when performing cross
compilations (such as for building a frozen executable for Windows CE).
2) Added option --shared-lib-name which can be used to specify the name of
the shared library (DLL) implementing the Python runtime that is required
for the frozen executable to work. This option is also particularly useful
when cross compiling since the normal method for determining this
information cannot be used.
3) Added option --zip-include which allows for additional files to be added
to the zip file that contains the modules that implement the Python
script. Thanks to Barray Warsaw for providing the initial patch.
4) Added support for handling read-only files properly. Thanks to Peter
Grayson for pointing out the problem and providing a solution.
5) Added support for a frozen executable to be a symbolic link. Thanks to
Robert Kiendl for providing the initial patch.
6) Enhanced the support for running a frozen executable that uses an existing
Python installation to locate modules it requires. This is primarily of
use for embedding Python where the interface is C but the ability to run
from source is still desired.
7) Modified the documentation to indicate that building from source on
Windows currently requires the mingw compiler (http://www.mingw.org).
8) Workaround the problem in Python 2.3 (fixed in Python 2.4) which causes a
broken module to be left in sys.modules if an ImportError takes place
during the execution of the code in that module. Thanks to Roger Binns
for pointing this out.
Changes from 3.0 beta3 to 3.0
1) Ensure that ldd is only run on extension modules.
2) Allow for using a compiler other than gcc for building the frozen base
executables by setting the environment variable CC.
3) Ensure that the import lock is not held while executing the main script;
otherwise, attempts to import a module within a thread will hang that
thread as noted by Roger Binns.
4) Added support for replacing the paths in all frozen modules with something
else (so that for example the path of the machine on which the freezing
was done is not displayed in tracebacks)
Changes from 3.0 beta2 to 3.0 beta3
1) Explicitly include the warnings module so that at runtime warnings are
suppressed as when running Python normally.
2) Improve the extension loader so that an ImportError is raised when the
dynamic module is not located; otherwise an error about missing attributes
is raised instead.
3) Extension loaders are only created when copying dependencies since the
normal module should be loadable in the situation where a Python
installation is available.
4) Added support for Python 2.4.
5) Fixed the dependency checking for wxPython to be a little more
intelligent.
Changes from 3.0 beta1 to 3.0 beta2
1) Fix issues with locating the initscripts and bases relative to the
directory in which the executable was started.
2) Added new base executable ConsoleKeepPath which is used when an existing
Python installation is required (such as for FreezePython itself).
3) Forced the existence of a Python installation to be ignored when using the
standard Console base executable.
4) Remove the existing file when copying dependent files; otherwise, an error
is raised when attempting to overwrite read-only files.
5) Added option -O (or -OO) to FreezePython to set the optimization used when
generating bytecode.
Changes from 2.2 to 3.0 beta1
1) cx_Freeze now requires Python 2.3 or higher since it takes advantage of
the ability of Python 2.3 and higher to import modules from zip files.
This makes the freezing process considerably simpler and also allows for
the execution of multiple frozen packages (such as found in COM servers or
shared libraries) without requiring modification to the Python modules.
2) All external dependencies have been removed. cx_Freeze now only requires
a standard Python distribution to do its work.
3) Added the ability to define the initialization scripts that cx_Freeze uses
on startup of the frozen program. Previously, these scripts were written
in C and could not easily be changed; now they are written in Python and
can be found in the initscripts directory (and chosen with the
new --init-script option to FreezePython).
4) The base executable ConsoleSetLibPath has been removed and replaced with
the initscript ConsoleSetLibPath.
5) Removed base executables for Win32 services and Win32 COM servers. This
functionality will be restored in the future but it is not currently in a
state that is ready for release. If this functionality is required, please
use py2exe or contact me for my work in progress.
6) The attribute sys.frozen is now set so that more recent pywin32 modules
work as expected when frozen.
7) Added option --include-path to FreezePython to allow overriding of
sys.path without modifying the environment variable PYTHONPATH.
8) Added option --target-dir/--install-dir to specify the directory in which
the frozen executable and its dependencies will be placed.
9) Removed the option --shared-lib since it was used for building shared
libraries and can be managed with the initscript SharedLib.py.
10) MakeFrozenBases.py now checks the platform specific include directory as
requested by Michael Partridge.
Changes from 2.1 to 2.2
1) Add option (--ext-list-file) to FreezePython to write the list of
extensions copied to the installation directory to a file. This option is
useful in cases where multiple builds are performed into the same
installation directory.
2) Pass the arguments on the command line through to Win32 GUI applications.
Thanks to Michael Porter for pointing this out.
3) Link directly against the python DLL when building the frozen bases on
Windows, thus eliminating the need for building an import library.
4) Force sys.path to include the directory in which the script to be frozen
is found.
5) Make sure that the installation directory exists before attempting to
copy the target binary into it.
6) The Win32GUI base has been modified to display fatal errors in message
boxes, rather than printing errors to stderr, since on Windows the
standard file IO handles are all closed.
Changes from 2.0 to 2.1
1) Remove dependency on Python 2.2. Thanks to Paul Moore for not only
pointing it out but providing patches.
2) Set up the list of frozen modules in advance, rather than doing it after
Python is initialized so that implicit imports done by Python can be
satisfied. The bug in Python 2.3 that demonstrated this issue has been
fixed in the first release candidate. Thanks to Thomas Heller for pointing
out the obvious in this instance!
3) Added additional base executable (ConsoleSetLibPath) to support setting
the LD_LIBRARY_PATH variable on Unix platforms and restarting the
executable to put the new setting into effect. This is primarily of use
in distributing wxPython applications on Unix where the shared library
has an embedded RPATH value which can cause problems.
4) Small improvements of documentation based on feedback from several people.
5) Print information about the files written or copied during the freezing
process.
6) Do not copy extensions when freezing if the path is being overridden since
it is expected that a full Python installation is available to the target
users of the frozen binary.
7) Provide meaningful error message when the wxPython library cannot be
found during the freezing process.
Changes from 1.1 to 2.0
1) Added support for in process (DLL) COM servers using PythonCOM.
2) Ensured that the frozen flag is set prior to determining the full path for
the program in order to avoid warnings about Python not being found on
some platforms.
3) Added include file and resource file to the source tree to avoid the
dependency on the Wine message compiler for Win32 builds.
4) Dropped the option --copy-extensions; this now happens automatically since
the resulting binary is useless without them.
5) Added a sample for building a Win32 service.
6) Make use of improved modules from Python 2.3 (which function under 2.2)
Changes from 1.0 to 1.1
1) Fixed import error with C extensions in packages; thanks to Thomas Heller
for pointing out the solution to this problem.
2) Added options to FreezePython to allow for the inclusion of modules which
will not be found by the module finder (--include-modules) and the
exclusion of modules which will be found by the module finder but should
not be included (--exclude-modules).
3) Fixed typo in README.txt.

View File

@ -1,53 +0,0 @@
Copyright © 2007-2008, Colt Engineering, Edmonton, Alberta, Canada.
Copyright © 2001-2006, Computronix (Canada) Ltd., Edmonton, Alberta, Canada.
All rights reserved.
NOTE: this license is derived from the Python Software Foundation License
which can be found at http://www.python.org/psf/license
License for cx_Freeze 4.0.1
---------------------------
1. This LICENSE AGREEMENT is between the copyright holders and the Individual
or Organization ("Licensee") accessing and otherwise using cx_Freeze
software in source or binary form and its associated documentation.
2. Subject to the terms and conditions of this License Agreement, the
copyright holders hereby grant Licensee a nonexclusive, royalty-free,
world-wide license to reproduce, analyze, test, perform and/or display
publicly, prepare derivative works, distribute, and otherwise use cx_Freeze
alone or in any derivative version, provided, however, that this License
Agreement and this notice of copyright are retained in cx_Freeze alone or in
any derivative version prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on or
incorporates cx_Freeze or any part thereof, and wants to make the derivative
work available to others as provided herein, then Licensee hereby agrees to
include in any such work a brief summary of the changes made to cx_Freeze.
4. The copyright holders are making cx_Freeze available to Licensee on an
"AS IS" basis. THE COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES,
EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, THE COPYRIGHT
HOLDERS MAKE NO AND DISCLAIM ANY REPRESENTATION OR WARRANTY OF
MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF
CX_FREEZE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
5. THE COPYRIGHT HOLDERS SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF
CX_FREEZE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING CX_FREEZE, OR ANY
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material breach
of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any relationship
of agency, partnership, or joint venture between the copyright holders and
Licensee. This License Agreement does not grant permission to use
copyright holder's trademarks or trade name in a trademark sense to endorse
or promote products or services of Licensee, or any third party.
8. By copying, installing or otherwise using cx_Freeze, Licensee agrees to be
bound by the terms and conditions of this License Agreement.
Computronix® is a registered trademark of Computronix (Canada) Ltd.

View File

@ -1,6 +0,0 @@
include MANIFEST.in
include *.txt
recursive-include doc *.html
recursive-include initscripts *.py
recursive-include samples *.py
recursive-include source *.c *.rc

View File

@ -1,22 +0,0 @@
Metadata-Version: 1.0
Name: cx_Freeze
Version: 4.0.1
Summary: create standalone executables from Python scripts
Home-page: http://cx-freeze.sourceforge.net
Author: Anthony Tuininga
Author-email: anthony.tuininga@gmail.com
License: Python Software Foundation License
Description: create standalone executables from Python scripts
Keywords: freeze
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Python Software Foundation License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: C
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Software Distribution
Classifier: Topic :: Utilities

View File

@ -1,12 +0,0 @@
Please see cx_Freeze.html for documentation on how to use cx_Freeze.
To build:
python setup.py build
python setup.py install
On Windows I have used the MinGW compiler (http://www.mingw.org)
python setup.py build --compiler=mingw32
python setup.py build --compiler=mingw32 install

View File

@ -1,14 +0,0 @@
version = "4.0.1"
import sys
from dist import *
if sys.platform == "win32" and sys.version_info[:2] >= (2, 5):
from windist import *
from finder import *
from freezer import *
from main import *
del dist
del finder
del freezer

View File

@ -1,279 +0,0 @@
import distutils.command.bdist_rpm
import distutils.command.build
import distutils.command.install
import distutils.core
import distutils.dir_util
import distutils.dist
import distutils.util
import distutils.version
import os
import sys
import cx_Freeze
__all__ = [ "bdist_rpm", "build", "build_exe", "install", "install_exe",
"setup" ]
class Distribution(distutils.dist.Distribution):
def __init__(self, attrs):
self.executables = []
distutils.dist.Distribution.__init__(self, attrs)
class bdist_rpm(distutils.command.bdist_rpm.bdist_rpm):
def finalize_options(self):
distutils.command.bdist_rpm.bdist_rpm.finalize_options(self)
self.use_rpm_opt_flags = 1
def _make_spec_file(self):
contents = distutils.command.bdist_rpm.bdist_rpm._make_spec_file(self)
return [c for c in contents if c != 'BuildArch: noarch']
class build(distutils.command.build.build):
user_options = distutils.command.build.build.user_options + [
('build-exe=', None, 'build directory for executables')
]
def get_sub_commands(self):
subCommands = distutils.command.build.build.get_sub_commands(self)
if self.distribution.executables:
subCommands.append("build_exe")
return subCommands
def initialize_options(self):
distutils.command.build.build.initialize_options(self)
self.build_exe = None
def finalize_options(self):
distutils.command.build.build.finalize_options(self)
if self.build_exe is None:
dirName = "exe.%s-%s" % \
(distutils.util.get_platform(), sys.version[0:3])
self.build_exe = os.path.join(self.build_base, dirName)
class build_exe(distutils.core.Command):
description = "build executables from Python scripts"
user_options = [
('build-exe=', 'b',
'directory for built executables'),
('optimize=', 'O',
'optimization level: -O1 for "python -O", '
'-O2 for "python -OO" and -O0 to disable [default: -O0]'),
('excludes=', 'e',
'comma-separated list of modules to exclude'),
('includes=', 'i',
'comma-separated list of modules to include'),
('packages=', 'p',
'comma-separated list of packages to include'),
('replace-paths=', None,
'comma-separated list of paths to replace in included modules'),
('path=', None,
'comma-separated list of paths to search'),
('init-script=', 'i',
'name of script to use during initialization'),
('base=', None,
'name of base executable to use'),
('compressed', 'c',
'create a compressed zipfile'),
('copy-dependent-files', None,
'copy all dependent files'),
('create-shared-zip', None,
'create a shared zip file containing shared modules'),
('append-script-to-exe', None,
'append the script module to the exe'),
('include-in-shared-zip', None,
'include the script module in the shared zip file'),
('icon', None,
'include the icon along with the frozen executable(s)'),
('constants=', None,
'comma-separated list of constants to include'),
('include-files=', 'f',
'list of tuples of additional files to include in distribution'),
('bin-includes', None,
'list of names of files to include when determining dependencies'),
('bin-excludes', None,
'list of names of files to exclude when determining dependencies')
]
boolean_options = ["compressed", "copy_dependent_files",
"create_shared_zip", "append_script_to_exe",
"include_in_shared_zip"]
def _normalize(self, attrName):
value = getattr(self, attrName)
if value is None:
normalizedValue = []
elif isinstance(value, basestring):
normalizedValue = value.split()
else:
normalizedValue = list(value)
setattr(self, attrName, normalizedValue)
def initialize_options(self):
self.optimize = 0
self.build_exe = None
self.excludes = []
self.includes = []
self.packages = []
self.replace_paths = []
self.compressed = None
self.copy_dependent_files = None
self.init_script = None
self.base = None
self.path = None
self.create_shared_zip = None
self.append_script_to_exe = None
self.include_in_shared_zip = None
self.icon = None
self.constants = []
self.include_files = []
self.bin_excludes = []
self.bin_includes = []
def finalize_options(self):
self.set_undefined_options('build', ('build_exe', 'build_exe'))
self.optimize = int(self.optimize)
self._normalize("excludes")
self._normalize("includes")
self._normalize("packages")
self._normalize("constants")
def run(self):
metadata = self.distribution.metadata
constantsModule = cx_Freeze.ConstantsModule(metadata.version)
for constant in self.constants:
parts = constant.split("=")
if len(parts) == 1:
name = constant
value = None
else:
name, stringValue = parts
value = eval(stringValue)
constantsModule.values[name] = value
freezer = cx_Freeze.Freezer(self.distribution.executables,
[constantsModule], self.includes, self.excludes, self.packages,
self.replace_paths, self.compressed, self.optimize,
self.copy_dependent_files, self.init_script, self.base,
self.path, self.create_shared_zip, self.append_script_to_exe,
self.include_in_shared_zip, self.build_exe, icon = self.icon,
includeFiles = self.include_files,
binIncludes = self.bin_includes,
binExcludes = self.bin_excludes)
freezer.Freeze()
class install(distutils.command.install.install):
user_options = distutils.command.install.install.user_options + [
('install-exe=', None,
'installation directory for executables')
]
def expand_dirs(self):
distutils.command.install.install.expand_dirs(self)
self._expand_attrs(['install_exe'])
def get_sub_commands(self):
subCommands = distutils.command.install.install.get_sub_commands(self)
if self.distribution.executables:
subCommands.append("install_exe")
return [s for s in subCommands if s != "install_egg_info"]
def initialize_options(self):
distutils.command.install.install.initialize_options(self)
self.install_exe = None
def finalize_options(self):
if self.prefix is None and sys.platform == "win32":
import _winreg
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
r"Software\Microsoft\Windows\CurrentVersion")
prefix = str(_winreg.QueryValueEx(key, "ProgramFilesDir")[0])
metadata = self.distribution.metadata
dirName = "%s-%s" % (metadata.name, metadata.version)
self.prefix = "%s/%s" % (prefix, dirName)
distutils.command.install.install.finalize_options(self)
self.convert_paths('exe')
if self.root is not None:
self.change_roots('exe')
def select_scheme(self, name):
distutils.command.install.install.select_scheme(self, name)
if self.install_exe is None:
if sys.platform == "win32":
self.install_exe = '$base'
else:
metadata = self.distribution.metadata
dirName = "%s-%s" % (metadata.name, metadata.version)
self.install_exe = '$base/lib/%s' % dirName
class install_exe(distutils.core.Command):
description = "install executables built from Python scripts"
user_options = [
('install-dir=', 'd', 'directory to install executables to'),
('build-dir=', 'b', 'build directory (where to install from)'),
('force', 'f', 'force installation (overwrite existing files)'),
('skip-build', None, 'skip the build steps')
]
def initialize_options(self):
self.install_dir = None
self.force = 0
self.build_dir = None
self.skip_build = None
def finalize_options(self):
self.set_undefined_options('build', ('build_exe', 'build_dir'))
self.set_undefined_options('install',
('install_exe', 'install_dir'),
('force', 'force'),
('skip_build', 'skip_build'))
def run(self):
if not self.skip_build:
self.run_command('build_exe')
self.outfiles = self.copy_tree(self.build_dir, self.install_dir)
if sys.platform != "win32":
baseDir = os.path.dirname(os.path.dirname(self.install_dir))
binDir = os.path.join(baseDir, "bin")
if not os.path.exists(binDir):
os.makedirs(binDir)
sourceDir = os.path.join("..", self.install_dir[len(baseDir) + 1:])
for executable in self.distribution.executables:
name = os.path.basename(executable.targetName)
source = os.path.join(sourceDir, name)
target = os.path.join(binDir, name)
if os.path.exists(target):
os.unlink(target)
os.symlink(source, target)
self.outfiles.append(target)
def get_inputs(self):
return self.distribution.executables or []
def get_outputs(self):
return self.outfiles or []
def _AddCommandClass(commandClasses, name, cls):
if name not in commandClasses:
commandClasses[name] = cls
def setup(**attrs):
attrs["distclass"] = Distribution
commandClasses = attrs.setdefault("cmdclass", {})
if sys.platform == "win32":
if sys.version_info[:2] >= (2, 5):
_AddCommandClass(commandClasses, "bdist_msi", cx_Freeze.bdist_msi)
else:
_AddCommandClass(commandClasses, "bdist_rpm", cx_Freeze.bdist_rpm)
_AddCommandClass(commandClasses, "build", build)
_AddCommandClass(commandClasses, "build_exe", build_exe)
_AddCommandClass(commandClasses, "install", install)
_AddCommandClass(commandClasses, "install_exe", install_exe)
distutils.core.setup(**attrs)

View File

@ -1,455 +0,0 @@
"""
Base class for finding modules.
"""
import dis
import imp
import marshal
import new
import opcode
import os
import sys
import zipfile
import cx_Freeze.hooks
BUILD_LIST = opcode.opmap["BUILD_LIST"]
INPLACE_ADD = opcode.opmap["INPLACE_ADD"]
LOAD_CONST = opcode.opmap["LOAD_CONST"]
IMPORT_NAME = opcode.opmap["IMPORT_NAME"]
IMPORT_FROM = opcode.opmap["IMPORT_FROM"]
STORE_NAME = opcode.opmap["STORE_NAME"]
STORE_GLOBAL = opcode.opmap["STORE_GLOBAL"]
STORE_OPS = (STORE_NAME, STORE_GLOBAL)
__all__ = [ "Module", "ModuleFinder" ]
class ModuleFinder(object):
def __init__(self, includeFiles, excludes, path, replacePaths):
self.includeFiles = includeFiles
self.excludes = dict.fromkeys(excludes)
self.replacePaths = replacePaths
self.path = path or sys.path
self.modules = []
self.aliases = {}
self._modules = dict.fromkeys(excludes)
self._builtinModules = dict.fromkeys(sys.builtin_module_names)
self._badModules = {}
self._zipFileEntries = {}
self._zipFiles = {}
cx_Freeze.hooks.initialize(self)
def _AddModule(self, name):
"""Add a module to the list of modules but if one is already found,
then return it instead; this is done so that packages can be
handled properly."""
module = self._modules.get(name)
if module is None:
module = self._modules[name] = Module(name)
self.modules.append(module)
if name in self._badModules:
del self._badModules[name]
return module
def _DetermineParent(self, caller):
"""Determine the parent to use when searching packages."""
if caller is not None:
if caller.path is not None:
return caller
return self._GetParentByName(caller.name)
def _EnsureFromList(self, caller, packageModule, fromList,
deferredImports):
"""Ensure that the from list is satisfied. This is only necessary for
package modules. If the caller is the package itself, actually
attempt to import right then since it must be a submodule; otherwise
defer until after all global names are defined in order to avoid
spurious complaints about missing modules."""
if caller is not packageModule:
deferredImports.append((packageModule, fromList))
else:
if fromList == ("*",):
fromList = packageModule.allNames
for name in fromList:
if name in packageModule.globalNames:
continue
subModuleName = "%s.%s" % (packageModule.name, name)
self._ImportModule(subModuleName, deferredImports, caller)
def _FindModule(self, name, path):
try:
return imp.find_module(name, path)
except ImportError:
if not path:
path = []
for location in path:
if name in self._zipFileEntries:
break
if location in self._zipFiles:
continue
if os.path.isdir(location) or not zipfile.is_zipfile(location):
self._zipFiles[location] = None
continue
zip = zipfile.ZipFile(location)
for archiveName in zip.namelist():
baseName, ext = os.path.splitext(archiveName)
if ext not in ('.pyc', '.pyo'):
continue
moduleName = ".".join(baseName.split("/"))
if moduleName in self._zipFileEntries:
continue
self._zipFileEntries[moduleName] = (zip, archiveName)
self._zipFiles[location] = None
info = self._zipFileEntries.get(name)
if info is not None:
zip, archiveName = info
fp = zip.read(archiveName)
info = (".pyc", "rb", imp.PY_COMPILED)
return fp, os.path.join(zip.filename, archiveName), info
raise
def _GetParentByName(self, name):
"""Return the parent module given the name of a module."""
pos = name.rfind(".")
if pos > 0:
parentName = name[:pos]
return self._modules[parentName]
def _ImportAllSubModules(self, module, deferredImports, recursive = True):
"""Import all sub modules to the given package."""
suffixes = dict.fromkeys([s[0] for s in imp.get_suffixes()])
for dir in module.path:
try:
fileNames = os.listdir(dir)
except os.error:
continue
for fileName in fileNames:
name, ext = os.path.splitext(fileName)
if ext not in suffixes:
continue
if name == "__init__":
continue
subModuleName = "%s.%s" % (module.name, name)
subModule, returnError = \
self._InternalImportModule(subModuleName,
deferredImports)
if returnError and subModule is None:
raise ImportError, "No module named %s" % subModuleName
module.globalNames[name] = None
if subModule.path and recursive:
self._ImportAllSubModules(subModule, deferredImports,
recursive)
def _ImportDeferredImports(self, deferredImports):
"""Import any sub modules that were deferred, if applicable."""
while deferredImports:
newDeferredImports = []
for packageModule, subModuleNames in deferredImports:
self._EnsureFromList(packageModule, packageModule,
subModuleNames, newDeferredImports)
deferredImports = newDeferredImports
def _ImportModule(self, name, deferredImports, caller = None,
relativeImportIndex = 0):
"""Attempt to find the named module and return it or None if no module
by that name could be found."""
# absolute import (available in Python 2.5 and up)
# the name given is the only name that will be searched
if relativeImportIndex == 0:
module, returnError = self._InternalImportModule(name,
deferredImports)
# old style relative import (only possibility in Python 2.4 and prior)
# the name given is tried in all parents until a match is found and if
# no match is found, the global namespace is searched
elif relativeImportIndex < 0:
parent = self._DetermineParent(caller)
while parent is not None:
fullName = "%s.%s" % (parent.name, name)
module, returnError = self._InternalImportModule(fullName,
deferredImports)
if module is not None:
parent.globalNames[name] = None
return module
parent = self._GetParentByName(parent.name)
module, returnError = self._InternalImportModule(name,
deferredImports)
# new style relative import (available in Python 2.5 and up)
# the index indicates how many levels to traverse and only that level
# is searched for the named module
elif relativeImportIndex > 0:
parent = caller
if parent.path is not None:
relativeImportIndex -= 1
while parent is not None and relativeImportIndex > 0:
parent = self._GetParentByName(parent.name)
relativeImportIndex -= 1
if parent is None:
module = None
returnError = True
elif not name:
module = parent
else:
name = "%s.%s" % (parent.name, name)
module, returnError = self._InternalImportModule(name,
deferredImports)
# if module not found, track that fact
if module is None:
if caller is None:
raise ImportError, "No module named %s" % name
self._RunHook("missing", name, caller)
if returnError and name not in caller.ignoreNames:
callers = self._badModules.setdefault(name, {})
callers[caller.name] = None
return module
def _InternalImportModule(self, name, deferredImports):
"""Internal method used for importing a module which assumes that the
name given is an absolute name. None is returned if the module
cannot be found."""
try:
return self._modules[name], False
except KeyError:
pass
if name in self._builtinModules:
module = self._AddModule(name)
self._RunHook("load", module.name, module)
return module, False
pos = name.rfind(".")
if pos < 0:
path = self.path
searchName = name
parentModule = None
else:
parentName = name[:pos]
parentModule, returnError = \
self._InternalImportModule(parentName, deferredImports)
if parentModule is None:
return None, returnError
path = parentModule.path
searchName = name[pos + 1:]
if name in self.aliases:
actualName = self.aliases[name]
module, returnError = \
self._InternalImportModule(actualName, deferredImports)
self._modules[name] = module
return module, returnError
try:
fp, path, info = self._FindModule(searchName, path)
except ImportError:
self._modules[name] = None
return None, True
module = self._LoadModule(name, fp, path, info, deferredImports,
parentModule)
return module, False
def _LoadModule(self, name, fp, path, info, deferredImports,
parent = None):
"""Load the module, given the information acquired by the finder."""
suffix, mode, type = info
if type == imp.PKG_DIRECTORY:
return self._LoadPackage(name, path, parent, deferredImports)
module = self._AddModule(name)
module.file = path
module.parent = parent
if type == imp.PY_SOURCE:
module.code = compile(fp.read() + "\n", path, "exec")
elif type == imp.PY_COMPILED:
if isinstance(fp, str):
magic = fp[:4]
else:
magic = fp.read(4)
if magic != imp.get_magic():
raise ImportError, "Bad magic number in %s" % path
if isinstance(fp, str):
module.code = marshal.loads(fp[8:])
module.inZipFile = True
else:
fp.read(4)
module.code = marshal.load(fp)
self._RunHook("load", module.name, module)
if module.code is not None:
if self.replacePaths:
topLevelModule = module
while topLevelModule.parent is not None:
topLevelModule = topLevelModule.parent
module.code = self._ReplacePathsInCode(topLevelModule,
module.code)
self._ScanCode(module.code, module, deferredImports)
return module
def _LoadPackage(self, name, path, parent, deferredImports):
"""Load the package, given its name and path."""
module = self._AddModule(name)
module.path = [path]
fp, path, info = imp.find_module("__init__", module.path)
self._LoadModule(name, fp, path, info, deferredImports, parent)
return module
def _ReplacePathsInCode(self, topLevelModule, co):
"""Replace paths in the code as directed, returning a new code object
with the modified paths in place."""
origFileName = newFileName = os.path.normpath(co.co_filename)
for searchValue, replaceValue in self.replacePaths:
if searchValue == "*":
searchValue = os.path.dirname(topLevelModule.file)
if topLevelModule.path:
searchValue = os.path.dirname(searchValue)
if searchValue:
searchValue = searchValue + os.pathsep
elif not origFileName.startswith(searchValue):
continue
newFileName = replaceValue + origFileName[len(searchValue):]
break
constants = list(co.co_consts)
for i, value in enumerate(constants):
if isinstance(value, type(co)):
constants[i] = self._ReplacePathsInCode(topLevelModule, value)
return new.code(co.co_argcount, co.co_nlocals, co.co_stacksize,
co.co_flags, co.co_code, tuple(constants), co.co_names,
co.co_varnames, newFileName, co.co_name, co.co_firstlineno,
co.co_lnotab, co.co_freevars, co.co_cellvars)
def _RunHook(self, hookName, moduleName, *args):
"""Run hook for the given module if one is present."""
name = "%s_%s" % (hookName, moduleName.replace(".", "_"))
method = getattr(cx_Freeze.hooks, name, None)
if method is not None:
method(self, *args)
def _ScanCode(self, co, module, deferredImports):
"""Scan code, looking for imported modules and keeping track of the
constants that have been created in order to better tell which
modules are truly missing."""
opIndex = 0
arguments = []
code = co.co_code
numOps = len(code)
while opIndex < numOps:
op = ord(code[opIndex])
opIndex += 1
if op >= dis.HAVE_ARGUMENT:
opArg = ord(code[opIndex]) + ord(code[opIndex + 1]) * 256
opIndex += 2
if op == LOAD_CONST:
arguments.append(co.co_consts[opArg])
elif op == IMPORT_NAME:
name = co.co_names[opArg]
if len(arguments) == 2:
relativeImportIndex, fromList = arguments
else:
relativeImportIndex = -1
fromList, = arguments
if name not in module.excludeNames:
subModule = self._ImportModule(name, deferredImports,
module, relativeImportIndex)
if subModule is not None:
module.globalNames.update(subModule.globalNames)
if fromList and subModule.path is not None:
self._EnsureFromList(module, subModule, fromList,
deferredImports)
elif op == IMPORT_FROM:
opIndex += 3
elif op not in (BUILD_LIST, INPLACE_ADD):
if op in STORE_OPS:
name = co.co_names[opArg]
if name == "__all__":
module.allNames.extend(arguments)
module.globalNames[name] = None
arguments = []
for constant in co.co_consts:
if isinstance(constant, type(co)):
self._ScanCode(constant, module, deferredImports)
def AddAlias(self, name, aliasFor):
"""Add an alias for a particular module; when an attempt is made to
import a module using the alias name, import the actual name
instead."""
self.aliases[name] = aliasFor
def ExcludeModule(self, name):
"""Exclude the named module from the resulting frozen executable."""
self.excludes[name] = None
self._modules[name] = None
def IncludeFile(self, path, moduleName = None):
"""Include the named file as a module in the frozen executable."""
name, ext = os.path.splitext(os.path.basename(path))
if moduleName is None:
moduleName = name
info = (ext, "r", imp.PY_SOURCE)
deferredImports = []
module = self._LoadModule(moduleName, file(path, "U"), path, info,
deferredImports)
self._ImportDeferredImports(deferredImports)
return module
def IncludeFiles(self, sourcePath, targetPath):
"""Include the files in the given directory in the target build."""
self.includeFiles.append((sourcePath, targetPath))
def IncludeModule(self, name):
"""Include the named module in the frozen executable."""
deferredImports = []
module = self._ImportModule(name, deferredImports)
self._ImportDeferredImports(deferredImports)
return module
def IncludePackage(self, name):
"""Include the named package and any submodules in the frozen
executable."""
deferredImports = []
module = self._ImportModule(name, deferredImports)
if module.path:
self._ImportAllSubModules(module, deferredImports)
self._ImportDeferredImports(deferredImports)
return module
def ReportMissingModules(self):
if self._badModules:
print "Missing modules:"
names = self._badModules.keys()
names.sort()
for name in names:
callers = self._badModules[name].keys()
callers.sort()
print "?", name, "imported from", ", ".join(callers)
print
class Module(object):
def __init__(self, name):
self.name = name
self.file = None
self.path = None
self.code = None
self.parent = None
self.globalNames = {}
self.excludeNames = {}
self.ignoreNames = {}
self.allNames = []
self.inZipFile = False
def __repr__(self):
parts = ["name=%s" % repr(self.name)]
if self.file is not None:
parts.append("file=%s" % repr(self.file))
if self.path is not None:
parts.append("path=%s" % repr(self.path))
return "<Module %s>" % ", ".join(parts)
def AddGlobalName(self, name):
self.globalNames[name] = None
def ExcludeName(self, name):
self.excludeNames[name] = None
def IgnoreName(self, name):
self.ignoreNames[name] = None

View File

@ -1,550 +0,0 @@
"""
Base class for freezing scripts into executables.
"""
import datetime
import distutils.sysconfig
import imp
import marshal
import os
import shutil
import socket
import stat
import struct
import sys
import time
import zipfile
import cx_Freeze
import cx_Freeze.util
__all__ = [ "ConfigError", "ConstantsModule", "Executable", "Freezer" ]
if sys.platform == "win32":
pythonDll = "python%s%s.dll" % sys.version_info[:2]
GLOBAL_BIN_PATH_EXCLUDES = [cx_Freeze.util.GetSystemDir()]
GLOBAL_BIN_INCLUDES = [
pythonDll,
"gdiplus.dll",
"mfc71.dll",
"msvcp71.dll",
"msvcr71.dll"
]
GLOBAL_BIN_EXCLUDES = [
"comctl32.dll",
"oci.dll",
"cx_Logging.pyd"
]
else:
extension = distutils.sysconfig.get_config_var("SO")
pythonSharedLib = "libpython%s.%s%s" % \
(sys.version_info[:2] + (extension,))
GLOBAL_BIN_INCLUDES = [pythonSharedLib]
GLOBAL_BIN_EXCLUDES = [
"libclntsh.so",
"libwtc9.so"
]
GLOBAL_BIN_PATH_EXCLUDES = ["/lib", "/lib32", "/lib64", "/usr/lib",
"/usr/lib32", "/usr/lib64"]
# NOTE: the try: except: block in this code is not necessary under Python 2.4
# and higher and can be removed once support for Python 2.3 is no longer needed
EXTENSION_LOADER_SOURCE = \
"""
import imp, os, sys
found = False
for p in sys.path:
if not os.path.isdir(p):
continue
f = os.path.join(p, "%s")
if not os.path.exists(f):
continue
try:
m = imp.load_dynamic(__name__, f)
except ImportError:
del sys.modules[__name__]
raise
sys.modules[__name__] = m
found = True
break
if not found:
del sys.modules[__name__]
raise ImportError, "No module named %%s" %% __name__
"""
class Freezer(object):
def __init__(self, executables, constantsModules = [], includes = [],
excludes = [], packages = [], replacePaths = [], compress = None,
optimizeFlag = 0, copyDependentFiles = None, initScript = None,
base = None, path = None, createLibraryZip = None,
appendScriptToExe = None, appendScriptToLibrary = None,
targetDir = None, binIncludes = [], binExcludes = [],
binPathIncludes = [], binPathExcludes = [], icon = None,
includeFiles = []):
self.executables = executables
self.constantsModules = constantsModules
self.includes = includes
self.excludes = excludes
self.packages = packages
self.replacePaths = replacePaths
self.compress = compress
self.optimizeFlag = optimizeFlag
self.copyDependentFiles = copyDependentFiles
self.initScript = initScript
self.base = base
self.path = path
self.createLibraryZip = createLibraryZip
self.appendScriptToExe = appendScriptToExe
self.appendScriptToLibrary = appendScriptToLibrary
self.targetDir = targetDir
self.binIncludes = [os.path.normcase(n) \
for n in GLOBAL_BIN_INCLUDES + binIncludes]
self.binExcludes = [os.path.normcase(n) \
for n in GLOBAL_BIN_EXCLUDES + binExcludes]
self.binPathIncludes = [os.path.normcase(n) for n in binPathIncludes]
self.binPathExcludes = [os.path.normcase(n) \
for n in GLOBAL_BIN_PATH_EXCLUDES + binPathExcludes]
self.icon = icon
self.includeFiles = includeFiles
self._VerifyConfiguration()
def _CopyFile(self, source, target, copyDependentFiles,
includeMode = False):
normalizedSource = os.path.normcase(os.path.normpath(source))
normalizedTarget = os.path.normcase(os.path.normpath(target))
if normalizedTarget in self.filesCopied:
return
if normalizedSource == normalizedTarget:
return
self._RemoveFile(target)
targetDir = os.path.dirname(target)
self._CreateDirectory(targetDir)
print "copying", source, "->", target
shutil.copyfile(source, target)
if includeMode:
shutil.copymode(source, target)
self.filesCopied[normalizedTarget] = None
if copyDependentFiles:
for source in self._GetDependentFiles(source):
target = os.path.join(targetDir, os.path.basename(source))
self._CopyFile(source, target, copyDependentFiles)
def _CreateDirectory(self, path):
if not os.path.isdir(path):
print "creating directory", path
os.makedirs(path)
def _FreezeExecutable(self, exe):
if self.createLibraryZip:
finder = self.finder
else:
finder = self._GetModuleFinder(exe)
if exe.script is None:
scriptModule = None
else:
scriptModule = finder.IncludeFile(exe.script, exe.moduleName)
self._CopyFile(exe.base, exe.targetName, exe.copyDependentFiles,
includeMode = True)
if exe.icon is not None:
if sys.platform == "win32":
cx_Freeze.util.AddIcon(exe.targetName, exe.icon)
else:
targetName = os.path.join(os.path.dirname(exe.targetName),
os.path.basename(exe.icon))
self._CopyFile(exe.icon, targetName,
copyDependentFiles = False)
if not os.access(exe.targetName, os.W_OK):
mode = os.stat(exe.targetName).st_mode
os.chmod(exe.targetName, mode | stat.S_IWUSR)
if not exe.appendScriptToLibrary:
if exe.appendScriptToExe:
fileName = exe.targetName
else:
baseFileName, ext = os.path.splitext(exe.targetName)
fileName = baseFileName + ".zip"
self._RemoveFile(fileName)
if not self.createLibraryZip and exe.copyDependentFiles:
scriptModule = None
self._WriteModules(fileName, exe.initScript, finder, exe.compress,
exe.copyDependentFiles, scriptModule)
def _GetBaseFileName(self, argsSource = None):
if argsSource is None:
argsSource = self
name = argsSource.base
if name is None:
if argsSource.copyDependentFiles:
name = "Console"
else:
name = "ConsoleKeepPath"
argsSource.base = self._GetFileName("bases", name)
if argsSource.base is None:
raise ConfigError("no base named %s", name)
def _GetDependentFiles(self, path):
dependentFiles = self.dependentFiles.get(path)
if dependentFiles is None:
if sys.platform == "win32":
origPath = os.environ["PATH"]
os.environ["PATH"] = origPath + os.pathsep + \
os.pathsep.join(sys.path)
dependentFiles = cx_Freeze.util.GetDependentFiles(path)
os.environ["PATH"] = origPath
else:
dependentFiles = []
for line in os.popen('ldd "%s"' % path):
parts = line.strip().split(" => ")
if len(parts) != 2:
continue
dependentFile = parts[1]
if dependentFile == "not found":
print "WARNING: cannot find", parts[0]
continue
pos = dependentFile.find(" (")
if pos >= 0:
dependentFile = dependentFile[:pos].strip()
if dependentFile:
dependentFiles.append(dependentFile)
dependentFiles = self.dependentFiles[path] = \
[f for f in dependentFiles if self._ShouldCopyFile(f)]
return dependentFiles
def _GetFileName(self, dir, name):
if os.path.isabs(name):
return name
name = os.path.normcase(name)
fullDir = os.path.join(os.path.dirname(cx_Freeze.__file__), dir)
if os.path.isdir(fullDir):
for fileName in os.listdir(fullDir):
if name == os.path.splitext(os.path.normcase(fileName))[0]:
return os.path.join(fullDir, fileName)
def _GetInitScriptFileName(self, argsSource = None):
if argsSource is None:
argsSource = self
name = argsSource.initScript
if name is None:
if argsSource.copyDependentFiles:
name = "Console"
else:
name = "ConsoleKeepPath"
argsSource.initScript = self._GetFileName("initscripts", name)
if argsSource.initScript is None:
raise ConfigError("no initscript named %s", name)
def _GetModuleFinder(self, argsSource = None):
if argsSource is None:
argsSource = self
finder = cx_Freeze.ModuleFinder(self.includeFiles, argsSource.excludes,
argsSource.path, argsSource.replacePaths)
if argsSource.copyDependentFiles:
finder.IncludeModule("imp")
finder.IncludeModule("os")
finder.IncludeModule("sys")
if argsSource.compress:
finder.IncludeModule("zlib")
for name in argsSource.includes:
finder.IncludeModule(name)
for name in argsSource.packages:
finder.IncludePackage(name)
return finder
def _PrintReport(self, fileName, modules):
print "writing zip file", fileName
print
print " %-25s %s" % ("Name", "File")
print " %-25s %s" % ("----", "----")
for module in modules:
if module.path:
print "P",
else:
print "m",
print "%-25s" % module.name, module.file or ""
print
def _RemoveFile(self, path):
if os.path.exists(path):
os.chmod(path, 0777)
os.remove(path)
def _ShouldCopyFile(self, path):
dir, name = os.path.split(os.path.normcase(path))
parts = name.split(".")
tweaked = False
while True:
if not parts[-1].isdigit():
break
parts.pop(-1)
tweaked = True
if tweaked:
name = ".".join(parts)
if name in self.binIncludes:
return True
if name in self.binExcludes:
return False
for path in self.binPathIncludes:
if dir.startswith(path):
return True
for path in self.binPathExcludes:
if dir.startswith(path):
return False
return True
def _VerifyCanAppendToLibrary(self):
if not self.createLibraryZip:
raise ConfigError("script cannot be appended to library zip if "
"one is not being created")
def _VerifyConfiguration(self):
if self.compress is None:
self.compress = True
if self.copyDependentFiles is None:
self.copyDependentFiles = True
if self.createLibraryZip is None:
self.createLibraryZip = True
if self.appendScriptToExe is None:
self.appendScriptToExe = False
if self.appendScriptToLibrary is None:
self.appendScriptToLibrary = \
self.createLibraryZip and not self.appendScriptToExe
if self.targetDir is None:
self.targetDir = os.path.abspath("dist")
self._GetInitScriptFileName()
self._GetBaseFileName()
if self.path is None:
self.path = sys.path
if self.appendScriptToLibrary:
self._VerifyCanAppendToLibrary()
for sourceFileName, targetFileName in self.includeFiles:
if not os.path.exists(sourceFileName):
raise ConfigError("cannot find file/directory named %s",
sourceFileName)
if os.path.isabs(targetFileName):
raise ConfigError("target file/directory cannot be absolute")
for executable in self.executables:
executable._VerifyConfiguration(self)
def _WriteModules(self, fileName, initScript, finder, compress,
copyDependentFiles, scriptModule = None):
initModule = finder.IncludeFile(initScript, "cx_Freeze__init__")
if scriptModule is None:
for module in self.constantsModules:
module.Create(finder)
modules = [m for m in finder.modules \
if m.name not in self.excludeModules]
else:
modules = [initModule, scriptModule]
self.excludeModules[initModule.name] = None
self.excludeModules[scriptModule.name] = None
itemsToSort = [(m.name, m) for m in modules]
itemsToSort.sort()
modules = [m for n, m in itemsToSort]
self._PrintReport(fileName, modules)
if scriptModule is None:
finder.ReportMissingModules()
targetDir = os.path.dirname(fileName)
self._CreateDirectory(targetDir)
filesToCopy = []
if os.path.exists(fileName):
mode = "a"
else:
mode = "w"
outFile = zipfile.PyZipFile(fileName, mode, zipfile.ZIP_DEFLATED)
for module in modules:
if module.code is None and module.file is not None:
fileName = os.path.basename(module.file)
baseFileName, ext = os.path.splitext(fileName)
if baseFileName != module.name and module.name != "zlib":
if "." in module.name:
fileName = module.name + ext
generatedFileName = "ExtensionLoader_%s.py" % \
module.name.replace(".", "_")
module.code = compile(EXTENSION_LOADER_SOURCE % fileName,
generatedFileName, "exec")
target = os.path.join(targetDir, fileName)
filesToCopy.append((module, target))
if module.code is None:
continue
fileName = "/".join(module.name.split("."))
if module.path:
fileName += "/__init__"
if module.file is not None and os.path.exists(module.file):
mtime = os.stat(module.file).st_mtime
else:
mtime = time.time()
zipTime = time.localtime(mtime)[:6]
data = imp.get_magic() + struct.pack("<i", mtime) + \
marshal.dumps(module.code)
zinfo = zipfile.ZipInfo(fileName + ".pyc", zipTime)
if compress:
zinfo.compress_type = zipfile.ZIP_DEFLATED
outFile.writestr(zinfo, data)
origPath = os.environ["PATH"]
for module, target in filesToCopy:
try:
if module.parent is not None:
path = os.pathsep.join([origPath] + module.parent.path)
os.environ["PATH"] = path
self._CopyFile(module.file, target, copyDependentFiles)
finally:
os.environ["PATH"] = origPath
def Freeze(self):
self.finder = None
self.excludeModules = {}
self.dependentFiles = {}
self.filesCopied = {}
cx_Freeze.util.SetOptimizeFlag(self.optimizeFlag)
if self.createLibraryZip:
self.finder = self._GetModuleFinder()
for executable in self.executables:
self._FreezeExecutable(executable)
if self.createLibraryZip:
fileName = os.path.join(self.targetDir, "library.zip")
self._RemoveFile(fileName)
self._WriteModules(fileName, self.initScript, self.finder,
self.compress, self.copyDependentFiles)
for sourceFileName, targetFileName in self.includeFiles:
fullName = os.path.join(self.targetDir, targetFileName)
if os.path.isdir(sourceFileName):
for path, dirNames, fileNames in os.walk(sourceFileName):
shortPath = path[len(sourceFileName) + 1:]
if ".svn" in dirNames:
dirNames.remove(".svn")
if "CVS" in dirNames:
dirNames.remove("CVS")
for fileName in fileNames:
fullSourceName = os.path.join(path, fileName)
fullTargetName = os.path.join(self.targetDir,
targetFileName, shortPath, fileName)
self._CopyFile(fullSourceName, fullTargetName,
copyDependentFiles = False)
else:
self._CopyFile(sourceFileName, fullName,
copyDependentFiles = False)
class ConfigError(Exception):
def __init__(self, format, *args):
self.what = format % args
def __str__(self):
return self.what
class Executable(object):
def __init__(self, script, initScript = None, base = None, path = None,
targetDir = None, targetName = None, includes = None,
excludes = None, packages = None, replacePaths = None,
compress = None, copyDependentFiles = None,
appendScriptToExe = None, appendScriptToLibrary = None,
icon = None):
self.script = script
self.initScript = initScript
self.base = base
self.path = path
self.targetDir = targetDir
self.targetName = targetName
self.includes = includes
self.excludes = excludes
self.packages = packages
self.replacePaths = replacePaths
self.compress = compress
self.copyDependentFiles = copyDependentFiles
self.appendScriptToExe = appendScriptToExe
self.appendScriptToLibrary = appendScriptToLibrary
self.icon = icon
def __repr__(self):
return "<Executable script=%s>" % self.script
def _VerifyConfiguration(self, freezer):
if self.path is None:
self.path = freezer.path
if self.targetDir is None:
self.targetDir = freezer.targetDir
if self.includes is None:
self.includes = freezer.includes
if self.excludes is None:
self.excludes = freezer.excludes
if self.packages is None:
self.packages = freezer.packages
if self.replacePaths is None:
self.replacePaths = freezer.replacePaths
if self.compress is None:
self.compress = freezer.compress
if self.copyDependentFiles is None:
self.copyDependentFiles = freezer.copyDependentFiles
if self.appendScriptToExe is None:
self.appendScriptToExe = freezer.appendScriptToExe
if self.appendScriptToLibrary is None:
self.appendScriptToLibrary = freezer.appendScriptToLibrary
if self.initScript is None:
self.initScript = freezer.initScript
else:
freezer._GetInitScriptFileName(self)
if self.base is None:
self.base = freezer.base
else:
freezer._GetBaseFileName(self)
if self.appendScriptToLibrary:
freezer._VerifyCanAppendToLibrary()
if self.icon is None:
self.icon = freezer.icon
if self.script is not None:
name, ext = os.path.splitext(os.path.basename(self.script))
if self.appendScriptToLibrary:
self.moduleName = "%s__main__" % os.path.normcase(name)
else:
self.moduleName = "__main__"
if self.targetName is None:
baseName, ext = os.path.splitext(self.base)
self.targetName = name + ext
self.targetName = os.path.join(self.targetDir, self.targetName)
class ConstantsModule(object):
def __init__(self, releaseString = None, copyright = None,
moduleName = "BUILD_CONSTANTS", timeFormat = "%B %d, %Y %H:%M:%S"):
self.moduleName = moduleName
self.timeFormat = timeFormat
self.values = {}
self.values["BUILD_RELEASE_STRING"] = releaseString
self.values["BUILD_COPYRIGHT"] = copyright
def Create(self, finder):
"""Create the module which consists of declaration statements for each
of the values."""
today = datetime.datetime.today()
sourceTimestamp = 0
for module in finder.modules:
if module.file is None:
continue
if module.inZipFile:
continue
if not os.path.exists(module.file):
raise ConfigError("no file named %s", module.file)
timestamp = os.stat(module.file).st_mtime
sourceTimestamp = max(sourceTimestamp, timestamp)
sourceTimestamp = datetime.datetime.fromtimestamp(sourceTimestamp)
self.values["BUILD_TIMESTAMP"] = today.strftime(self.timeFormat)
self.values["BUILD_HOST"] = socket.gethostname().split(".")[0]
self.values["SOURCE_TIMESTAMP"] = \
sourceTimestamp.strftime(self.timeFormat)
module = finder._AddModule(self.moduleName)
sourceParts = []
names = self.values.keys()
names.sort()
for name in names:
value = self.values[name]
sourceParts.append("%s = %r" % (name, value))
source = "\n".join(sourceParts)
module.code = compile(source, "%s.py" % self.moduleName, "exec")

View File

@ -1,281 +0,0 @@
import os
import sys
def initialize(finder):
"""upon initialization of the finder, this routine is called to set up some
automatic exclusions for various platforms."""
finder.ExcludeModule("FCNTL")
finder.ExcludeModule("os.path")
if os.name == "nt":
finder.ExcludeModule("fcntl")
finder.ExcludeModule("grp")
finder.ExcludeModule("pwd")
finder.ExcludeModule("termios")
else:
finder.ExcludeModule("_winreg")
finder.ExcludeModule("msilib")
finder.ExcludeModule("msvcrt")
finder.ExcludeModule("nt")
if os.name not in ("os2", "ce"):
finder.ExcludeModule("ntpath")
finder.ExcludeModule("nturl2path")
finder.ExcludeModule("pythoncom")
finder.ExcludeModule("pywintypes")
finder.ExcludeModule("winerror")
finder.ExcludeModule("winsound")
finder.ExcludeModule("win32api")
finder.ExcludeModule("win32con")
finder.ExcludeModule("win32event")
finder.ExcludeModule("win32file")
finder.ExcludeModule("win32pdh")
finder.ExcludeModule("win32pipe")
finder.ExcludeModule("win32process")
finder.ExcludeModule("win32security")
finder.ExcludeModule("win32service")
finder.ExcludeModule("wx.activex")
if os.name != "posix":
finder.ExcludeModule("posix")
if os.name != "mac":
finder.ExcludeModule("Carbon")
finder.ExcludeModule("gestalt")
finder.ExcludeModule("ic")
finder.ExcludeModule("mac")
finder.ExcludeModule("MacOS")
finder.ExcludeModule("macpath")
finder.ExcludeModule("macurl2path")
if os.name != "nt":
finder.ExcludeModule("EasyDialogs")
if os.name != "os2":
finder.ExcludeModule("os2")
finder.ExcludeModule("os2emxpath")
finder.ExcludeModule("_emx_link")
if os.name != "ce":
finder.ExcludeModule("ce")
if os.name != "riscos":
finder.ExcludeModule("riscos")
finder.ExcludeModule("riscosenviron")
finder.ExcludeModule("riscospath")
finder.ExcludeModule("rourl2path")
if sys.platform[:4] != "java":
finder.ExcludeModule("java.lang")
finder.ExcludeModule("org.python.core")
def load_cElementTree(finder, module):
"""the cElementTree module implicitly loads the elementtree.ElementTree
module; make sure this happens."""
finder.IncludeModule("elementtree.ElementTree")
def load_ceODBC(finder, module):
"""the ceODBC module implicitly imports both datetime and decimal; make
sure this happens."""
finder.IncludeModule("datetime")
finder.IncludeModule("decimal")
def load_cx_Oracle(finder, module):
"""the cx_Oracle module implicitly imports datetime; make sure this
happens."""
finder.IncludeModule("datetime")
def load_docutils_frontend(finder, module):
"""The optik module is the old name for the optparse module; ignore the
module if it cannot be found."""
module.IgnoreName("optik")
def load_dummy_threading(finder, module):
"""the dummy_threading module plays games with the name of the threading
module for its own purposes; ignore that here"""
finder.ExcludeModule("_dummy_threading")
def load_email(finder, module):
"""the email package has a bunch of aliases as the submodule names were
all changed to lowercase in Python 2.5; mimic that here."""
if sys.version_info[:2] >= (2, 5):
for name in ("Charset", "Encoders", "Errors", "FeedParser",
"Generator", "Header", "Iterators", "Message", "Parser",
"Utils", "base64MIME", "quopriMIME"):
finder.AddAlias("email.%s" % name, "email.%s" % name.lower())
def load_ftplib(finder, module):
"""the ftplib module attempts to import the SOCKS module; ignore this
module if it cannot be found"""
module.IgnoreName("SOCKS")
def load_matplotlib(finder, module):
"""the matplotlib module requires data to be found in mpl-data in the
same directory as the frozen executable so oblige it"""
dir = os.path.join(module.path[0], "mpl-data")
finder.IncludeFiles(dir, "mpl-data")
def load_matplotlib_numerix(finder, module):
"""the numpy.numerix module loads a number of modules dynamically"""
for name in ("ma", "fft", "linear_algebra", "random_array", "mlab"):
finder.IncludeModule("%s.%s" % (module.name, name))
def load_numpy_linalg(finder, module):
"""the numpy.linalg module implicitly loads the lapack_lite module; make
sure this happens"""
finder.IncludeModule("numpy.linalg.lapack_lite")
def load_pty(finder, module):
"""The sgi module is not needed for this module to function."""
module.IgnoreName("sgi")
def load_pythoncom(finder, module):
"""the pythoncom module is actually contained in a DLL but since those
cannot be loaded directly in Python 2.5 and higher a special module is
used to perform that task; simply use that technique directly to
determine the name of the DLL and ensure it is included as a normal
extension; also load the pywintypes module which is implicitly
loaded."""
import pythoncom
module.file = pythoncom.__file__
module.code = None
finder.IncludeModule("pywintypes")
def load_pywintypes(finder, module):
"""the pywintypes module is actually contained in a DLL but since those
cannot be loaded directly in Python 2.5 and higher a special module is
used to perform that task; simply use that technique directly to
determine the name of the DLL and ensure it is included as a normal
extension."""
import pywintypes
module.file = pywintypes.__file__
module.code = None
def load_PyQt4_Qt(finder, module):
"""the PyQt4.Qt module is an extension module which imports a number of
other modules and injects their namespace into its own. It seems a
foolish way of doing things but perhaps there is some hidden advantage
to this technique over pure Python; ignore the absence of some of
the modules since not every installation includes all of them."""
finder.IncludeModule("PyQt4.QtCore")
finder.IncludeModule("PyQt4.QtGui")
finder.IncludeModule("sip")
for name in ("PyQt4.QtSvg", "PyQt4.Qsci", "PyQt4.QtAssistant",
"PyQt4.QtNetwork", "PyQt4.QtOpenGL", "PyQt4.QtScript", "PyQt4._qt",
"PyQt4.QtSql", "PyQt4.QtSvg", "PyQt4.QtTest", "PyQt4.QtXml"):
try:
finder.IncludeModule(name)
except ImportError:
pass
def load_Tkinter(finder, module):
"""the Tkinter module has data files that are required to be loaded so
ensure that they are copied into the directory that is expected at
runtime."""
import Tkinter
import _tkinter
tk = _tkinter.create()
tclDir = os.path.dirname(tk.call("info", "library"))
tclSourceDir = os.path.join(tclDir, "tcl%s" % _tkinter.TCL_VERSION)
tkSourceDir = os.path.join(tclDir, "tk%s" % _tkinter.TK_VERSION)
finder.IncludeFiles(tclSourceDir, "tcl")
finder.IncludeFiles(tkSourceDir, "tk")
def load_tempfile(finder, module):
"""the tempfile module attempts to load the fcntl and thread modules but
continues if these modules cannot be found; ignore these modules if they
cannot be found."""
module.IgnoreName("fcntl")
module.IgnoreName("thread")
def load_time(finder, module):
"""the time module implicitly loads _strptime; make sure this happens."""
finder.IncludeModule("_strptime")
def load_win32api(finder, module):
"""the win32api module implicitly loads the pywintypes module; make sure
this happens."""
finder.IncludeModule("pywintypes")
def load_win32com(finder, module):
"""the win32com package manipulates its search path at runtime to include
the sibling directory called win32comext; simulate that by changing the
search path in a similar fashion here."""
baseDir = os.path.dirname(os.path.dirname(module.file))
module.path.append(os.path.join(baseDir, "win32comext"))
def load_win32file(finder, module):
"""the win32api module implicitly loads the pywintypes module; make sure
this happens."""
finder.IncludeModule("pywintypes")
def load_xml(finder, module):
"""the builtin xml package attempts to load the _xmlplus module to see if
that module should take its role instead; ignore the failure to find
this module, though."""
module.IgnoreName("_xmlplus")
def load_xml_etree_cElementTree(finder, module):
"""the xml.etree.cElementTree module implicitly loads the
xml.etree.ElementTree module; make sure this happens."""
finder.IncludeModule("xml.etree.ElementTree")
def load_IPython(finder, module):
ipy = os.path.join(os.path.dirname(module.file), 'Extensions')
extensions = set([])
for m in os.listdir(ipy):
extensions.add(os.path.splitext(m)[0])
extensions.remove('__init__')
for m in extensions:
finder.IncludeModule('IPython.Extensions.'+m)
def load_lxml(finder, module):
finder.IncludeModule('lxml._elementpath')
def load_cherrypy(finder, module):
finder.IncludeModule('cherrypy.lib.encoding')
def missing_cElementTree(finder, caller):
"""the cElementTree has been incorporated into the standard library in
Python 2.5 so ignore its absence if it cannot found."""
if sys.version_info[:2] >= (2, 5):
caller.IgnoreName("cElementTree")
def missing_EasyDialogs(finder, caller):
"""the EasyDialogs module is not normally present on Windows but it also
may be so instead of excluding it completely, ignore it if it can't be
found"""
if sys.platform == "win32":
caller.IgnoreName("EasyDialogs")
def missing_readline(finder, caller):
"""the readline module is not normally present on Windows but it also may
be so instead of excluding it completely, ignore it if it can't be
found"""
if sys.platform == "win32":
caller.IgnoreName("readline")
def missing_xml_etree(finder, caller):
"""the xml.etree package is new for Python 2.5 but it is common practice
to use a try..except.. block in order to support versions earlier than
Python 2.5 transparently; ignore the absence of the package in this
situation."""
if sys.version_info[:2] < (2, 5):
caller.IgnoreName("xml.etree")

View File

@ -1,171 +0,0 @@
import optparse
import os
import shutil
import stat
import sys
import cx_Freeze
__all__ = ["main"]
USAGE = \
"""
%prog [options] [SCRIPT]
Freeze a Python script and all of its referenced modules to a base
executable which can then be distributed without requiring a Python
installation."""
VERSION = \
"""
%%prog %s
Copyright (c) 2007-2008 Colt Engineering. All rights reserved.
Copyright (c) 2001-2006 Computronix Corporation. All rights reserved.""" % \
cx_Freeze.version
def ParseCommandLine():
parser = optparse.OptionParser(version = VERSION.strip(),
usage = USAGE.strip())
parser.add_option("-O",
action = "count",
default = 0,
dest = "optimized",
help = "optimize generated bytecode as per PYTHONOPTIMIZE; "
"use -OO in order to remove doc strings")
parser.add_option("-c", "--compress",
action = "store_true",
dest = "compress",
help = "compress byte code in zip files")
parser.add_option("--base-name",
dest = "baseName",
metavar = "NAME",
help = "file on which to base the target file; if the name of the "
"file is not an absolute file name, the subdirectory bases "
"(rooted in the directory in which the freezer is found) "
"will be searched for a file matching the name")
parser.add_option("--init-script",
dest = "initScript",
metavar = "NAME",
help = "script which will be executed upon startup; if the name "
"of the file is not an absolute file name, the "
"subdirectory initscripts (rooted in the directory in "
"which the cx_Freeze package is found) will be searched "
"for a file matching the name")
parser.add_option("--target-dir", "--install-dir",
dest = "targetDir",
metavar = "DIR",
help = "the directory in which to place the target file and "
"any dependent files")
parser.add_option("--target-name",
dest = "targetName",
metavar = "NAME",
help = "the name of the file to create instead of the base name "
"of the script and the extension of the base binary")
parser.add_option("--no-copy-deps",
dest = "copyDeps",
default = True,
action = "store_false",
help = "do not copy the dependent files (extensions, shared "
"libraries, etc.) to the target directory; this also "
"modifies the default init script to ConsoleKeepPath.py "
"and means that the target executable requires a Python "
"installation to execute properly")
parser.add_option("--default-path",
action = "append",
dest = "defaultPath",
metavar = "DIRS",
help = "list of paths separated by the standard path separator "
"for the platform which will be used to initialize "
"sys.path prior to running the module finder")
parser.add_option("--include-path",
action = "append",
dest = "includePath",
metavar = "DIRS",
help = "list of paths separated by the standard path separator "
"for the platform which will be used to modify sys.path "
"prior to running the module finder")
parser.add_option("--replace-paths",
dest = "replacePaths",
metavar = "DIRECTIVES",
help = "replace all the paths in modules found in the given paths "
"with the given replacement string; multiple values are "
"separated by the standard path separator and each value "
"is of the form path=replacement_string; path can be * "
"which means all paths not already specified")
parser.add_option("--include-modules",
dest = "includeModules",
metavar = "NAMES",
help = "comma separated list of modules to include")
parser.add_option("--exclude-modules",
dest = "excludeModules",
metavar = "NAMES",
help = "comma separated list of modules to exclude")
parser.add_option("--ext-list-file",
dest = "extListFile",
metavar = "NAME",
help = "name of file in which to place the list of dependent files "
"which were copied into the target directory")
parser.add_option("-z", "--zip-include",
dest = "zipIncludes",
action = "append",
default = [],
metavar = "SPEC",
help = "name of file to add to the zip file or a specification of "
"the form name=arcname which will specify the archive name "
"to use; multiple --zip-include arguments can be used")
options, args = parser.parse_args()
if len(args) == 0:
options.script = None
elif len(args) == 1:
options.script, = args
else:
parser.error("only one script can be specified")
if not args and options.includeModules is None and options.copyDeps:
parser.error("script or a list of modules must be specified")
if not args and options.targetName is None:
parser.error("script or a target name must be specified")
if options.excludeModules:
options.excludeModules = options.excludeModules.split(",")
else:
options.excludeModules = []
if options.includeModules:
options.includeModules = options.includeModules.split(",")
else:
options.includeModules = []
replacePaths = []
if options.replacePaths:
for directive in options.replacePaths.split(os.pathsep):
fromPath, replacement = directive.split("=")
replacePaths.append((fromPath, replacement))
options.replacePaths = replacePaths
if options.defaultPath is not None:
sys.path = [p for mp in options.defaultPath \
for p in mp.split(os.pathsep)]
if options.includePath is not None:
paths = [p for mp in options.includePath for p in mp.split(os.pathsep)]
sys.path = paths + sys.path
if options.script is not None:
sys.path.insert(0, os.path.dirname(options.script))
return options
def main():
options = ParseCommandLine()
executables = [cx_Freeze.Executable(options.script,
targetName = options.targetName)]
freezer = cx_Freeze.Freezer(executables,
includes = options.includeModules,
excludes = options.excludeModules,
replacePaths = options.replacePaths,
compress = options.compress,
optimizeFlag = options.optimized,
copyDependentFiles = options.copyDeps,
initScript = options.initScript,
base = options.baseName,
path = None,
createLibraryZip = False,
appendScriptToExe = True,
targetDir = options.targetDir)
freezer.Freeze()

View File

@ -1,337 +0,0 @@
import distutils.command.bdist_msi
import msilib
import os
__all__ = [ "bdist_msi" ]
# force the remove existing products action to happen first since Windows
# installer appears to be braindead and doesn't handle files shared between
# different "products" very well
sequence = msilib.sequence.InstallExecuteSequence
for index, info in enumerate(sequence):
if info[0] == u'RemoveExistingProducts':
sequence[index] = (info[0], info[1], 1450)
class bdist_msi(distutils.command.bdist_msi.bdist_msi):
user_options = distutils.command.bdist_msi.bdist_msi.user_options + [
('add-to-path=', None, 'add target dir to PATH environment variable'),
('upgrade-code=', None, 'upgrade code to use')
]
x = y = 50
width = 370
height = 300
title = "[ProductName] Setup"
modeless = 1
modal = 3
def add_config(self, fullname):
initialTargetDir = self.get_initial_target_dir(fullname)
if self.add_to_path is None:
self.add_to_path = False
for executable in self.distribution.executables:
if os.path.basename(executable.base).startswith("Console"):
self.add_to_path = True
break
if self.add_to_path:
msilib.add_data(self.db, 'Environment',
[("E_PATH", "Path", r"[~];[TARGETDIR]", "TARGETDIR")])
msilib.add_data(self.db, 'CustomAction',
[("InitialTargetDir", 256 + 51, "TARGETDIR", initialTargetDir)
])
msilib.add_data(self.db, 'InstallExecuteSequence',
[("InitialTargetDir", 'TARGETDIR=""', 401)])
msilib.add_data(self.db, 'InstallUISequence',
[("PrepareDlg", None, 140),
("InitialTargetDir", 'TARGETDIR=""', 401),
("SelectDirectoryDlg", "not Installed", 1230),
("MaintenanceTypeDlg",
"Installed and not Resume and not Preselected", 1250),
("ProgressDlg", None, 1280)
])
def add_cancel_dialog(self):
dialog = msilib.Dialog(self.db, "CancelDlg", 50, 10, 260, 85, 3,
self.title, "No", "No", "No")
dialog.text("Text", 48, 15, 194, 30, 3,
"Are you sure you want to cancel [ProductName] installation?")
button = dialog.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
button.event("EndDialog", "Exit")
button = dialog.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")
button.event("EndDialog", "Return")
def add_error_dialog(self):
dialog = msilib.Dialog(self.db, "ErrorDlg", 50, 10, 330, 101, 65543,
self.title, "ErrorText", None, None)
dialog.text("ErrorText", 50, 9, 280, 48, 3, "")
for text, x in [("No", 120), ("Yes", 240), ("Abort", 0),
("Cancel", 42), ("Ignore", 81), ("Ok", 159), ("Retry", 198)]:
button = dialog.pushbutton(text[0], x, 72, 81, 21, 3, text, None)
button.event("EndDialog", "Error%s" % text)
def add_exit_dialog(self):
dialog = distutils.command.bdist_msi.PyDialog(self.db, "ExitDialog",
self.x, self.y, self.width, self.height, self.modal,
self.title, "Finish", "Finish", "Finish")
dialog.title("Completing the [ProductName] installer")
dialog.back("< Back", "Finish", active = False)
dialog.cancel("Cancel", "Back", active = False)
dialog.text("Description", 15, 235, 320, 20, 0x30003,
"Click the Finish button to exit the installer.")
button = dialog.next("Finish", "Cancel", name = "Finish")
button.event("EndDialog", "Return")
def add_fatal_error_dialog(self):
dialog = distutils.command.bdist_msi.PyDialog(self.db, "FatalError",
self.x, self.y, self.width, self.height, self.modal,
self.title, "Finish", "Finish", "Finish")
dialog.title("[ProductName] installer ended prematurely")
dialog.back("< Back", "Finish", active = False)
dialog.cancel("Cancel", "Back", active = False)
dialog.text("Description1", 15, 70, 320, 80, 0x30003,
"[ProductName] setup ended prematurely because of an error. "
"Your system has not been modified. To install this program "
"at a later time, please run the installation again.")
dialog.text("Description2", 15, 155, 320, 20, 0x30003,
"Click the Finish button to exit the installer.")
button = dialog.next("Finish", "Cancel", name = "Finish")
button.event("EndDialog", "Exit")
def add_files_in_use_dialog(self):
dialog = distutils.command.bdist_msi.PyDialog(self.db, "FilesInUse",
self.x, self.y, self.width, self.height, 19, self.title,
"Retry", "Retry", "Retry", bitmap = False)
dialog.text("Title", 15, 6, 200, 15, 0x30003,
r"{\DlgFontBold8}Files in Use")
dialog.text("Description", 20, 23, 280, 20, 0x30003,
"Some files that need to be updated are currently in use.")
dialog.text("Text", 20, 55, 330, 50, 3,
"The following applications are using files that need to be "
"updated by this setup. Close these applications and then "
"click Retry to continue the installation or Cancel to exit "
"it.")
dialog.control("List", "ListBox", 20, 107, 330, 130, 7,
"FileInUseProcess", None, None, None)
button = dialog.back("Exit", "Ignore", name = "Exit")
button.event("EndDialog", "Exit")
button = dialog.next("Ignore", "Retry", name = "Ignore")
button.event("EndDialog", "Ignore")
button = dialog.cancel("Retry", "Exit", name = "Retry")
button.event("EndDialog", "Retry")
def add_maintenance_type_dialog(self):
dialog = distutils.command.bdist_msi.PyDialog(self.db,
"MaintenanceTypeDlg", self.x, self.y, self.width, self.height,
self.modal, self.title, "Next", "Next", "Cancel")
dialog.title("Welcome to the [ProductName] Setup Wizard")
dialog.text("BodyText", 15, 63, 330, 42, 3,
"Select whether you want to repair or remove [ProductName].")
group = dialog.radiogroup("RepairRadioGroup", 15, 108, 330, 60, 3,
"MaintenanceForm_Action", "", "Next")
group.add("Repair", 0, 18, 300, 17, "&Repair [ProductName]")
group.add("Remove", 0, 36, 300, 17, "Re&move [ProductName]")
dialog.back("< Back", None, active = False)
button = dialog.next("Finish", "Cancel")
button.event("[REINSTALL]", "ALL",
'MaintenanceForm_Action="Repair"', 5)
button.event("[Progress1]", "Repairing",
'MaintenanceForm_Action="Repair"', 6)
button.event("[Progress2]", "repairs",
'MaintenanceForm_Action="Repair"', 7)
button.event("Reinstall", "ALL",
'MaintenanceForm_Action="Repair"', 8)
button.event("[REMOVE]", "ALL",
'MaintenanceForm_Action="Remove"', 11)
button.event("[Progress1]", "Removing",
'MaintenanceForm_Action="Remove"', 12)
button.event("[Progress2]", "removes",
'MaintenanceForm_Action="Remove"', 13)
button.event("Remove", "ALL",
'MaintenanceForm_Action="Remove"', 14)
button.event("EndDialog", "Return",
'MaintenanceForm_Action<>"Change"', 20)
button = dialog.cancel("Cancel", "RepairRadioGroup")
button.event("SpawnDialog", "CancelDlg")
def add_prepare_dialog(self):
dialog = distutils.command.bdist_msi.PyDialog(self.db, "PrepareDlg",
self.x, self.y, self.width, self.height, self.modeless,
self.title, "Cancel", "Cancel", "Cancel")
dialog.text("Description", 15, 70, 320, 40, 0x30003,
"Please wait while the installer prepares to guide you through"
"the installation.")
dialog.title("Welcome to the [ProductName] installer")
text = dialog.text("ActionText", 15, 110, 320, 20, 0x30003,
"Pondering...")
text.mapping("ActionText", "Text")
text = dialog.text("ActionData", 15, 135, 320, 30, 0x30003, None)
text.mapping("ActionData", "Text")
dialog.back("Back", None, active = False)
dialog.next("Next", None, active = False)
button = dialog.cancel("Cancel", None)
button.event("SpawnDialog", "CancelDlg")
def add_progress_dialog(self):
dialog = distutils.command.bdist_msi.PyDialog(self.db, "ProgressDlg",
self.x, self.y, self.width, self.height, self.modeless,
self.title, "Cancel", "Cancel", "Cancel", bitmap = False)
dialog.text("Title", 20, 15, 200, 15, 0x30003,
r"{\DlgFontBold8}[Progress1] [ProductName]")
dialog.text("Text", 35, 65, 300, 30, 3,
"Please wait while the installer [Progress2] [ProductName].")
dialog.text("StatusLabel", 35, 100 ,35, 20, 3, "Status:")
text = dialog.text("ActionText", 70, 100, self.width - 70, 20, 3,
"Pondering...")
text.mapping("ActionText", "Text")
control = dialog.control("ProgressBar", "ProgressBar", 35, 120, 300,
10, 65537, None, "Progress done", None, None)
control.mapping("SetProgress", "Progress")
dialog.back("< Back", "Next", active = False)
dialog.next("Next >", "Cancel", active = False)
button = dialog.cancel("Cancel", "Back")
button.event("SpawnDialog", "CancelDlg")
def add_properties(self):
metadata = self.distribution.metadata
props = [
('DistVersion', metadata.get_version()),
('DefaultUIFont', 'DlgFont8'),
('ErrorDialog', 'ErrorDlg'),
('Progress1', 'Install'),
('Progress2', 'installs'),
('MaintenanceForm_Action', 'Repair')
]
email = metadata.author_email or metadata.maintainer_email
if email:
props.append(("ARPCONTACT", email))
if metadata.url:
props.append(("ARPURLINFOABOUT", metadata.url))
if self.upgrade_code is not None:
props.append(("UpgradeCode", self.upgrade_code))
msilib.add_data(self.db, 'Property', props)
def add_select_directory_dialog(self):
dialog = distutils.command.bdist_msi.PyDialog(self.db,
"SelectDirectoryDlg", self.x, self.y, self.width, self.height,
self.modal, self.title, "Next", "Next", "Cancel")
dialog.title("Select destination directory")
dialog.back("< Back", None, active = False)
button = dialog.next("Next >", "Cancel")
button.event("SetTargetPath", "TARGETDIR", ordering = 1)
button.event("SpawnWaitDialog", "WaitForCostingDlg", ordering = 2)
button.event("EndDialog", "Return", ordering = 3)
button = dialog.cancel("Cancel", "DirectoryCombo")
button.event("SpawnDialog", "CancelDlg")
dialog.control("DirectoryCombo", "DirectoryCombo", 15, 70, 272, 80,
393219, "TARGETDIR", None, "DirectoryList", None)
dialog.control("DirectoryList", "DirectoryList", 15, 90, 308, 136, 3,
"TARGETDIR", None, "PathEdit", None)
dialog.control("PathEdit", "PathEdit", 15, 230, 306, 16, 3,
"TARGETDIR", None, "Next", None)
button = dialog.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None)
button.event("DirectoryListUp", "0")
button = dialog.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None)
button.event("DirectoryListNew", "0")
def add_text_styles(self):
msilib.add_data(self.db, 'TextStyle',
[("DlgFont8", "Tahoma", 9, None, 0),
("DlgFontBold8", "Tahoma", 8, None, 1),
("VerdanaBold10", "Verdana", 10, None, 1),
("VerdanaRed9", "Verdana", 9, 255, 0)
])
def add_ui(self):
self.add_text_styles()
self.add_error_dialog()
self.add_fatal_error_dialog()
self.add_cancel_dialog()
self.add_exit_dialog()
self.add_user_exit_dialog()
self.add_files_in_use_dialog()
self.add_wait_for_costing_dialog()
self.add_prepare_dialog()
self.add_select_directory_dialog()
self.add_progress_dialog()
self.add_maintenance_type_dialog()
def add_upgrade_config(self, sversion):
if self.upgrade_code is not None:
msilib.add_data(self.db, 'Upgrade',
[(self.upgrade_code, None, sversion, None, 513, None,
"REMOVEOLDVERSION"),
(self.upgrade_code, sversion, None, None, 257, None,
"REMOVENEWVERSION")
])
def add_user_exit_dialog(self):
dialog = distutils.command.bdist_msi.PyDialog(self.db, "UserExit",
self.x, self.y, self.width, self.height, self.modal,
self.title, "Finish", "Finish", "Finish")
dialog.title("[ProductName] installer was interrupted")
dialog.back("< Back", "Finish", active = False)
dialog.cancel("Cancel", "Back", active = False)
dialog.text("Description1", 15, 70, 320, 80, 0x30003,
"[ProductName] setup was interrupted. Your system has not "
"been modified. To install this program at a later time, "
"please run the installation again.")
dialog.text("Description2", 15, 155, 320, 20, 0x30003,
"Click the Finish button to exit the installer.")
button = dialog.next("Finish", "Cancel", name = "Finish")
button.event("EndDialog", "Exit")
def add_wait_for_costing_dialog(self):
dialog = msilib.Dialog(self.db, "WaitForCostingDlg", 50, 10, 260, 85,
self.modal, self.title, "Return", "Return", "Return")
dialog.text("Text", 48, 15, 194, 30, 3,
"Please wait while the installer finishes determining your "
"disk space requirements.")
button = dialog.pushbutton("Return", 102, 57, 56, 17, 3, "Return",
None)
button.event("EndDialog", "Exit")
def get_initial_target_dir(self, fullname):
return r"[ProgramFilesFolder]\%s" % fullname
def get_installer_filename(self, fullname):
return os.path.join(self.dist_dir, "%s.msi" % fullname)
def initialize_options(self):
distutils.command.bdist_msi.bdist_msi.initialize_options(self)
self.upgrade_code = None
self.add_to_path = None
def run(self):
if not self.skip_build:
self.run_command('build')
install = self.reinitialize_command('install', reinit_subcommands = 1)
install.prefix = self.bdist_dir
install.skip_build = self.skip_build
install.warn_dir = 0
distutils.log.info("installing to %s", self.bdist_dir)
install.ensure_finalized()
install.run()
self.mkpath(self.dist_dir)
fullname = self.distribution.get_fullname()
filename = os.path.abspath(self.get_installer_filename(fullname))
if os.path.exists(filename):
os.unlink(filename)
metadata = self.distribution.metadata
author = metadata.author or metadata.maintainer or "UNKNOWN"
version = metadata.get_version()
sversion = "%d.%d.%d" % \
distutils.version.StrictVersion(version).version
self.db = msilib.init_database(filename, msilib.schema,
self.distribution.metadata.name, msilib.gen_uuid(), sversion,
author)
msilib.add_tables(self.db, msilib.sequence)
self.add_properties()
self.add_config(fullname)
self.add_upgrade_config(sversion)
self.add_ui()
self.add_files()
self.db.Commit()
if not self.keep_temp:
distutils.dir_util.remove_tree(self.bdist_dir,
dry_run = self.dry_run)

View File

@ -1,6 +0,0 @@
#!/usr/bin/python
from cx_Freeze import main
main()

View File

@ -1,35 +0,0 @@
#------------------------------------------------------------------------------
# Console.py
# Initialization script for cx_Freeze which manipulates the path so that the
# directory in which the executable is found is searched for extensions but
# no other directory is searched. It also sets the attribute sys.frozen so that
# the Win32 extensions behave as expected.
#------------------------------------------------------------------------------
import encodings
import os
import sys
import warnings
import zipimport
sys.frozen = True
sys.path = sys.path[:4]
os.environ["TCL_LIBRARY"] = os.path.join(DIR_NAME, "tcl")
os.environ["TK_LIBRARY"] = os.path.join(DIR_NAME, "tk")
m = __import__("__main__")
importer = zipimport.zipimporter(INITSCRIPT_ZIP_FILE_NAME)
if INITSCRIPT_ZIP_FILE_NAME != SHARED_ZIP_FILE_NAME:
moduleName = m.__name__
else:
name, ext = os.path.splitext(os.path.basename(os.path.normcase(FILE_NAME)))
moduleName = "%s__main__" % name
code = importer.get_code(moduleName)
exec code in m.__dict__
if sys.version_info[:2] >= (2, 5):
module = sys.modules.get("threading")
if module is not None:
module._shutdown()

View File

@ -1,19 +0,0 @@
#------------------------------------------------------------------------------
# ConsoleKeepPath.py
# Initialization script for cx_Freeze which leaves the path alone and does
# not set the sys.frozen attribute.
#------------------------------------------------------------------------------
import sys
import zipimport
m = __import__("__main__")
importer = zipimport.zipimporter(INITSCRIPT_ZIP_FILE_NAME)
code = importer.get_code(m.__name__)
exec code in m.__dict__
if sys.version_info[:2] >= (2, 5):
module = sys.modules.get("threading")
if module is not None:
module._shutdown()

View File

@ -1,38 +0,0 @@
#------------------------------------------------------------------------------
# ConsoleSetLibPath.py
# Initialization script for cx_Freeze which manipulates the path so that the
# directory in which the executable is found is searched for extensions but
# no other directory is searched. The environment variable LD_LIBRARY_PATH is
# manipulated first, however, to ensure that shared libraries found in the
# target directory are found. This requires a restart of the executable because
# the environment variable LD_LIBRARY_PATH is only checked at startup.
#------------------------------------------------------------------------------
import encodings
import os
import sys
import warnings
import zipimport
paths = os.environ.get("LD_LIBRARY_PATH", "").split(os.pathsep)
if DIR_NAME not in paths:
paths.insert(0, DIR_NAME)
os.environ["LD_LIBRARY_PATH"] = os.pathsep.join(paths)
os.execv(sys.executable, sys.argv)
sys.frozen = True
sys.path = sys.path[:4]
os.environ["TCL_LIBRARY"] = os.path.join(DIR_NAME, "tcl")
os.environ["TK_LIBRARY"] = os.path.join(DIR_NAME, "tk")
m = __import__("__main__")
importer = zipimport.zipimporter(INITSCRIPT_ZIP_FILE_NAME)
code = importer.get_code(m.__name__)
exec code in m.__dict__
if sys.version_info[:2] >= (2, 5):
module = sys.modules.get("threading")
if module is not None:
module._shutdown()

View File

@ -1,20 +0,0 @@
#------------------------------------------------------------------------------
# SharedLib.py
# Initialization script for cx_Freeze which behaves similarly to the one for
# console based applications but must handle the case where Python has already
# been initialized and another DLL of this kind has been loaded. As such it
# does not block the path unless sys.frozen is not already set.
#------------------------------------------------------------------------------
import encodings
import os
import sys
import warnings
if not hasattr(sys, "frozen"):
sys.frozen = True
sys.path = sys.path[:4]
os.environ["TCL_LIBRARY"] = os.path.join(DIR_NAME, "tcl")
os.environ["TK_LIBRARY"] = os.path.join(DIR_NAME, "tk")

View File

@ -1,23 +0,0 @@
#------------------------------------------------------------------------------
# SharedLibSource.py
# Initialization script for cx_Freeze which imports the site module (as per
# normal processing of a Python script) and then searches for a file with the
# same name as the shared library but with the extension .pth. The entries in
# this file are used to modify the path to use for subsequent imports.
#------------------------------------------------------------------------------
import os
import sys
import warnings
# the site module must be imported for normal behavior to take place; it is
# done dynamically so that cx_Freeze will not add all modules referenced by
# the site module to the frozen executable
__import__("site")
# now locate the pth file to modify the path appropriately
baseName, ext = os.path.splitext(FILE_NAME)
pathFileName = baseName + ".pth"
sys.path = [s.strip() for s in file(pathFileName).read().splitlines()] + \
sys.path

View File

@ -1,7 +0,0 @@
import sys
print "Hello from cx_Freeze Advanced #1"
print
module = __import__("testfreeze_1")

View File

@ -1,7 +0,0 @@
import sys
print "Hello from cx_Freeze Advanced #2"
print
module = __import__("testfreeze_2")

View File

@ -1 +0,0 @@
print "Test freeze module #1"

View File

@ -1 +0,0 @@
print "Test freeze module #2"

View File

@ -1,31 +0,0 @@
# An advanced setup script to create multiple executables and demonstrate a few
# of the features available to setup scripts
#
# hello.py is a very simple "Hello, world" type script which also displays the
# environment in which the script runs
#
# Run the build process by running the command 'python setup.py build'
#
# If everything works well you should find a subdirectory in the build
# subdirectory that contains the files needed to run the script without Python
import sys
from cx_Freeze import setup, Executable
executables = [
Executable("advanced_1.py"),
Executable("advanced_2.py")
]
buildOptions = dict(
compressed = True,
includes = ["testfreeze_1", "testfreeze_2"],
path = sys.path + ["modules"])
setup(
name = "advanced_cx_Freeze_sample",
version = "0.1",
description = "Advanced sample cx_Freeze script",
options = dict(build_exe = buildOptions),
executables = executables)

View File

@ -1,27 +0,0 @@
# A simple setup script to create an executable using matplotlib.
#
# test_matplotlib.py is a very simple matplotlib application that demonstrates
# its use.
#
# Run the build process by running the command 'python setup.py build'
#
# If everything works well you should find a subdirectory in the build
# subdirectory that contains the files needed to run the application
import cx_Freeze
import sys
base = None
if sys.platform == "win32":
base = "Win32GUI"
executables = [
cx_Freeze.Executable("test_matplotlib.py", base = base)
]
cx_Freeze.setup(
name = "test_matplotlib",
version = "0.1",
description = "Sample matplotlib script",
executables = executables)

View File

@ -1,48 +0,0 @@
from numpy import arange, sin, pi
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from matplotlib.figure import Figure
from wx import *
class CanvasFrame(Frame):
def __init__(self):
Frame.__init__(self,None,-1, 'CanvasFrame',size=(550,350))
self.SetBackgroundColour(NamedColor("WHITE"))
self.figure = Figure()
self.axes = self.figure.add_subplot(111)
t = arange(0.0,3.0,0.01)
s = sin(2*pi*t)
self.axes.plot(t,s)
self.canvas = FigureCanvas(self, -1, self.figure)
self.sizer = BoxSizer(VERTICAL)
self.sizer.Add(self.canvas, 1, LEFT | TOP | GROW)
self.SetSizerAndFit(self.sizer)
self.add_toolbar()
def add_toolbar(self):
self.toolbar = NavigationToolbar2Wx(self.canvas)
self.toolbar.Realize()
if Platform == '__WXMAC__':
self.SetToolBar(self.toolbar)
else:
tw, th = self.toolbar.GetSizeTuple()
fw, fh = self.canvas.GetSizeTuple()
self.toolbar.SetSize(Size(fw, th))
self.sizer.Add(self.toolbar, 0, LEFT | EXPAND)
self.toolbar.update()
def OnPaint(self, event):
self.canvas.draw()
class App(App):
def OnInit(self):
'Create the main window and insert the custom frame'
frame = CanvasFrame()
frame.Show(True)
return True
app = App(0)
app.MainLoop()

View File

@ -1,3 +0,0 @@
print "importing pkg1"
from . import sub1
from . import pkg2

View File

@ -1,3 +0,0 @@
print "importing pkg1.pkg2"
from . import sub3
from .. import sub4

View File

@ -1,3 +0,0 @@
print "importing pkg1.pkg2.sub3"
from . import sub5
from .. import sub6

View File

@ -1 +0,0 @@
print "importing pkg1.pkg2.sub5"

View File

@ -1,2 +0,0 @@
print "importing pkg1.sub1"
from . import sub2

View File

@ -1 +0,0 @@
print "importing pkg1.sub2"

View File

@ -1 +0,0 @@
print 'importing pkg1.sub4'

View File

@ -1 +0,0 @@
print "importing pkg1.sub6"

View File

@ -1 +0,0 @@
import pkg1

View File

@ -1,16 +0,0 @@
# relimport.py is a very simple script that tests importing using relative
# imports (available in Python 2.5 and up)
#
# Run the build process by running the command 'python setup.py build'
#
# If everything works well you should find a subdirectory in the build
# subdirectory that contains the files needed to run the script without Python
from cx_Freeze import setup, Executable
setup(
name = "relimport",
version = "0.1",
description = "Sample cx_Freeze script for relative imports",
executables = [Executable("relimport.py")])

View File

@ -1,19 +0,0 @@
import sys
print "Hello from cx_Freeze"
print
print "sys.executable", sys.executable
print "sys.prefix", sys.prefix
print
print "ARGUMENTS:"
for a in sys.argv:
print a
print
print "PATH:"
for p in sys.path:
print p
print

View File

@ -1,18 +0,0 @@
# A very simple setup script to create a single executable
#
# hello.py is a very simple "Hello, world" type script which also displays the
# environment in which the script runs
#
# Run the build process by running the command 'python setup.py build'
#
# If everything works well you should find a subdirectory in the build
# subdirectory that contains the files needed to run the script without Python
from cx_Freeze import setup, Executable
setup(
name = "hello",
version = "0.1",
description = "Sample cx_Freeze script",
executables = [Executable("hello.py")])

View File

@ -1,25 +0,0 @@
# A simple setup script to create an executable running wxPython. This also
# demonstrates the method for creating a Windows executable that does not have
# an associated console.
#
# wxapp.py is a very simple "Hello, world" type wxPython application
#
# Run the build process by running the command 'python setup.py build'
#
# If everything works well you should find a subdirectory in the build
# subdirectory that contains the files needed to run the application
import sys
from cx_Freeze import setup, Executable
base = None
if sys.platform == "win32":
base = "Win32GUI"
setup(
name = "hello",
version = "0.1",
description = "Sample cx_Freeze wxPython script",
executables = [Executable("wxapp.py", base = base)])

View File

@ -1,42 +0,0 @@
import wx
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent = None, title = "Hello from cx_Freeze")
panel = wx.Panel(self)
closeMeButton = wx.Button(panel, -1, "Close Me")
wx.EVT_BUTTON(self, closeMeButton.GetId(), self.OnCloseMe)
wx.EVT_CLOSE(self, self.OnCloseWindow)
pushMeButton = wx.Button(panel, -1, "Push Me")
wx.EVT_BUTTON(self, pushMeButton.GetId(), self.OnPushMe)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(closeMeButton, flag = wx.ALL, border = 20)
sizer.Add(pushMeButton, flag = wx.ALL, border = 20)
panel.SetSizer(sizer)
topSizer = wx.BoxSizer(wx.VERTICAL)
topSizer.Add(panel, flag = wx.ALL | wx.EXPAND)
topSizer.Fit(self)
def OnCloseMe(self, event):
self.Close(True)
def OnPushMe(self, event):
1 / 0
def OnCloseWindow(self, event):
self.Destroy()
class App(wx.App):
def OnInit(self):
frame = Frame()
frame.Show(True)
self.SetTopWindow(frame)
return True
app = App(1)
app.MainLoop()

View File

@ -1,197 +0,0 @@
"""
Distutils script for cx_Freeze.
"""
import distutils.command.bdist_rpm
import distutils.command.build_ext
import distutils.command.build_scripts
import distutils.command.install
import distutils.command.install_data
import distutils.sysconfig
import os
import sys
from distutils.core import setup
from distutils.extension import Extension
class bdist_rpm(distutils.command.bdist_rpm.bdist_rpm):
# rpm automatically byte compiles all Python files in a package but we
# don't want that to happen for initscripts and samples so we tell it to
# ignore those files
def _make_spec_file(self):
specFile = distutils.command.bdist_rpm.bdist_rpm._make_spec_file(self)
specFile.insert(0, "%define _unpackaged_files_terminate_build 0%{nil}")
return specFile
def run(self):
distutils.command.bdist_rpm.bdist_rpm.run(self)
specFile = os.path.join(self.rpm_base, "SPECS",
"%s.spec" % self.distribution.get_name())
queryFormat = "%{name}-%{version}-%{release}.%{arch}.rpm"
command = "rpm -q --qf '%s' --specfile %s" % (queryFormat, specFile)
origFileName = os.popen(command).read()
parts = origFileName.split("-")
parts.insert(2, "py%s%s" % sys.version_info[:2])
newFileName = "-".join(parts)
self.move_file(os.path.join("dist", origFileName),
os.path.join("dist", newFileName))
class build_ext(distutils.command.build_ext.build_ext):
def build_extension(self, ext):
if ext.name.find("bases") < 0:
distutils.command.build_ext.build_ext.build_extension(self, ext)
return
os.environ["LD_RUN_PATH"] = "${ORIGIN}:${ORIGIN}/../lib"
objects = self.compiler.compile(ext.sources,
output_dir = self.build_temp,
include_dirs = ext.include_dirs,
debug = self.debug,
depends = ext.depends)
fileName = os.path.splitext(self.get_ext_filename(ext.name))[0]
fullName = os.path.join(self.build_lib, fileName)
libraryDirs = ext.library_dirs or []
libraries = self.get_libraries(ext)
extraArgs = ext.extra_link_args or []
if sys.platform != "win32":
vars = distutils.sysconfig.get_config_vars()
libraryDirs.append(vars["LIBPL"])
libraries.append("python%s.%s" % sys.version_info[:2])
if vars["LINKFORSHARED"]:
extraArgs.extend(vars["LINKFORSHARED"].split())
if vars["LIBS"]:
extraArgs.extend(vars["LIBS"].split())
if vars["LIBM"]:
extraArgs.append(vars["LIBM"])
if vars["BASEMODLIBS"]:
extraArgs.extend(vars["BASEMODLIBS"].split())
if vars["LOCALMODLIBS"]:
extraArgs.extend(vars["LOCALMODLIBS"].split())
extraArgs.append("-s")
self.compiler.link_executable(objects, fullName,
libraries = libraries,
library_dirs = libraryDirs,
runtime_library_dirs = ext.runtime_library_dirs,
extra_postargs = extraArgs,
debug = self.debug)
def get_ext_filename(self, name):
fileName = distutils.command.build_ext.build_ext.get_ext_filename(self,
name)
if name.find("bases") < 0:
return fileName
ext = self.compiler.exe_extension or ""
return os.path.splitext(fileName)[0] + ext
class build_scripts(distutils.command.build_scripts.build_scripts):
def copy_scripts(self):
distutils.command.build_scripts.build_scripts.copy_scripts(self)
if sys.platform == "win32":
for script in self.scripts:
batFileName = os.path.join(self.build_dir, script + ".bat")
fullScriptName = r"%s\Scripts\%s" % \
(os.path.dirname(sys.executable), script)
command = "%s %s %%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9" % \
(sys.executable, fullScriptName)
file(batFileName, "w").write("@echo off\n\n%s" % command)
class install(distutils.command.install.install):
def get_sub_commands(self):
subCommands = distutils.command.install.install.get_sub_commands(self)
subCommands.append("install_packagedata")
return subCommands
class install_packagedata(distutils.command.install_data.install_data):
def run(self):
installCommand = self.get_finalized_command("install")
installDir = getattr(installCommand, "install_lib")
sourceDirs = ["samples", "initscripts"]
while sourceDirs:
sourceDir = sourceDirs.pop(0)
targetDir = os.path.join(installDir, "cx_Freeze", sourceDir)
self.mkpath(targetDir)
for name in os.listdir(sourceDir):
if name == "build" or name.startswith("."):
continue
fullSourceName = os.path.join(sourceDir, name)
if os.path.isdir(fullSourceName):
sourceDirs.append(fullSourceName)
else:
fullTargetName = os.path.join(targetDir, name)
self.copy_file(fullSourceName, fullTargetName)
self.outfiles.append(fullTargetName)
commandClasses = dict(
build_ext = build_ext,
build_scripts = build_scripts,
bdist_rpm = bdist_rpm,
install = install,
install_packagedata = install_packagedata)
if sys.platform == "win32":
libraries = ["imagehlp"]
else:
libraries = []
utilModule = Extension("cx_Freeze.util", ["source/util.c"],
libraries = libraries)
depends = ["source/bases/Common.c"]
if sys.platform == "win32":
if sys.version_info[:2] >= (2, 6):
extraSources = ["source/bases/manifest.rc"]
else:
extraSources = ["source/bases/dummy.rc"]
else:
extraSources = []
console = Extension("cx_Freeze.bases.Console",
["source/bases/Console.c"] + extraSources, depends = depends)
consoleKeepPath = Extension("cx_Freeze.bases.ConsoleKeepPath",
["source/bases/ConsoleKeepPath.c"] + extraSources, depends = depends)
extensions = [utilModule, console, consoleKeepPath]
if sys.platform == "win32":
gui = Extension("cx_Freeze.bases.Win32GUI",
["source/bases/Win32GUI.c"] + extraSources,
depends = depends, extra_link_args = ["-mwindows"])
extensions.append(gui)
docFiles = "LICENSE.txt README.txt HISTORY.txt doc/cx_Freeze.html"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: Python Software Foundation License",
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: C",
"Programming Language :: Python",
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: System :: Software Distribution",
"Topic :: Utilities"
]
setup(name = "cx_Freeze",
description = "create standalone executables from Python scripts",
long_description = "create standalone executables from Python scripts",
version = "4.0.1",
cmdclass = commandClasses,
options = dict(bdist_rpm = dict(doc_files = docFiles),
install = dict(optimize = 1)),
ext_modules = extensions,
packages = ['cx_Freeze'],
maintainer="Anthony Tuininga",
maintainer_email="anthony.tuininga@gmail.com",
url = "http://cx-freeze.sourceforge.net",
scripts = ["cxfreeze"],
classifiers = classifiers,
keywords = "freeze",
license = "Python Software Foundation License")

View File

@ -1,262 +0,0 @@
//-----------------------------------------------------------------------------
// Common.c
// Routines which are common to running frozen executables.
//-----------------------------------------------------------------------------
#include <compile.h>
#include <eval.h>
#include <osdefs.h>
// global variables (used for simplicity)
static PyObject *g_FileName = NULL;
static PyObject *g_DirName = NULL;
static PyObject *g_ExclusiveZipFileName = NULL;
static PyObject *g_SharedZipFileName = NULL;
static PyObject *g_InitScriptZipFileName = NULL;
//-----------------------------------------------------------------------------
// GetDirName()
// Return the directory name of the given path.
//-----------------------------------------------------------------------------
static int GetDirName(
const char *path, // path to calculate dir name for
PyObject **dirName) // directory name (OUT)
{
int i;
for (i = strlen(path); i > 0 && path[i] != SEP; --i);
*dirName = PyString_FromStringAndSize(path, i);
if (!*dirName)
return FatalError("cannot create string for directory name");
return 0;
}
//-----------------------------------------------------------------------------
// SetExecutableName()
// Set the script to execute and calculate the directory in which the
// executable is found as well as the exclusive (only for this executable) and
// shared zip file names.
//-----------------------------------------------------------------------------
static int SetExecutableName(
const char *fileName) // script to execute
{
char temp[MAXPATHLEN + 12], *ptr;
#ifndef WIN32
char linkData[MAXPATHLEN + 1];
struct stat statData;
size_t linkSize, i;
PyObject *dirName;
#endif
// store file name
g_FileName = PyString_FromString(fileName);
if (!g_FileName)
return FatalError("cannot create string for file name");
#ifndef WIN32
for (i = 0; i < 25; i++) {
if (lstat(fileName, &statData) < 0) {
PyErr_SetFromErrnoWithFilename(PyExc_OSError, (char*) fileName);
return FatalError("unable to stat file");
}
if (!S_ISLNK(statData.st_mode))
break;
linkSize = readlink(fileName, linkData, sizeof(linkData));
if (linkSize < 0) {
PyErr_SetFromErrnoWithFilename(PyExc_OSError, (char*) fileName);
return FatalError("unable to stat file");
}
if (linkData[0] == '/') {
Py_DECREF(g_FileName);
g_FileName = PyString_FromStringAndSize(linkData, linkSize);
} else {
if (GetDirName(PyString_AS_STRING(g_FileName), &dirName) < 0)
return -1;
if (PyString_GET_SIZE(dirName) + linkSize + 1 > MAXPATHLEN) {
Py_DECREF(dirName);
return FatalError("cannot dereference link, path too large");
}
strcpy(temp, PyString_AS_STRING(dirName));
strcat(temp, "/");
strcat(temp, linkData);
Py_DECREF(g_FileName);
g_FileName = PyString_FromString(temp);
}
if (!g_FileName)
return FatalError("cannot create string for linked file name");
fileName = PyString_AS_STRING(g_FileName);
}
#endif
// calculate and store directory name
if (GetDirName(fileName, &g_DirName) < 0)
return -1;
// calculate and store exclusive zip file name
strcpy(temp, fileName);
ptr = temp + strlen(temp) - 1;
while (ptr > temp && *ptr != SEP && *ptr != '.')
ptr--;
if (*ptr == '.')
*ptr = '\0';
strcat(temp, ".zip");
g_ExclusiveZipFileName = PyString_FromString(temp);
if (!g_ExclusiveZipFileName)
return FatalError("cannot create string for exclusive zip file name");
// calculate and store shared zip file name
strcpy(temp, PyString_AS_STRING(g_DirName));
ptr = temp + strlen(temp);
*ptr++ = SEP;
strcpy(ptr, "library.zip");
g_SharedZipFileName = PyString_FromString(temp);
if (!g_SharedZipFileName)
return FatalError("cannot create string for shared zip file name");
return 0;
}
//-----------------------------------------------------------------------------
// SetPathToSearch()
// Set the path to search. This includes the file (for those situations where
// a zip file is attached to the executable itself), the directory where the
// executable is found (to search for extensions), the exclusive zip file
// name and the shared zip file name.
//-----------------------------------------------------------------------------
static int SetPathToSearch(void)
{
PyObject *pathList;
pathList = PySys_GetObject("path");
if (!pathList)
return FatalError("cannot acquire sys.path");
if (PyList_Insert(pathList, 0, g_FileName) < 0)
return FatalError("cannot insert file name into sys.path");
if (PyList_Insert(pathList, 1, g_DirName) < 0)
return FatalError("cannot insert directory name into sys.path");
if (PyList_Insert(pathList, 2, g_ExclusiveZipFileName) < 0)
return FatalError("cannot insert exclusive zip name into sys.path");
if (PyList_Insert(pathList, 3, g_SharedZipFileName) < 0)
return FatalError("cannot insert shared zip name into sys.path");
return 0;
}
//-----------------------------------------------------------------------------
// GetImporterHelper()
// Helper which is used to locate the importer for the initscript.
//-----------------------------------------------------------------------------
static PyObject *GetImporterHelper(
PyObject *module, // zipimport module
PyObject *fileName) // name of file to search
{
PyObject *importer;
importer = PyObject_CallMethod(module, "zipimporter", "O", fileName);
if (importer)
g_InitScriptZipFileName = fileName;
else
PyErr_Clear();
return importer;
}
//-----------------------------------------------------------------------------
// GetImporter()
// Return the importer which will be used for importing the initialization
// script. The executable itself is searched first, followed by the exclusive
// zip file and finally by the shared zip file.
//-----------------------------------------------------------------------------
static int GetImporter(
PyObject **importer) // importer (OUT)
{
PyObject *module;
module = PyImport_ImportModule("zipimport");
if (!module)
return FatalError("cannot import zipimport module");
*importer = GetImporterHelper(module, g_FileName);
if (!*importer) {
*importer = GetImporterHelper(module, g_ExclusiveZipFileName);
if (!*importer)
*importer = GetImporterHelper(module, g_SharedZipFileName);
}
Py_DECREF(module);
if (!*importer)
return FatalError("cannot get zipimporter instance");
return 0;
}
//-----------------------------------------------------------------------------
// PopulateInitScriptDict()
// Return the dictionary used by the initialization script.
//-----------------------------------------------------------------------------
static int PopulateInitScriptDict(
PyObject *dict) // dictionary to populate
{
if (!dict)
return FatalError("unable to create temporary dictionary");
if (PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins()) < 0)
return FatalError("unable to set __builtins__");
if (PyDict_SetItemString(dict, "FILE_NAME", g_FileName) < 0)
return FatalError("unable to set FILE_NAME");
if (PyDict_SetItemString(dict, "DIR_NAME", g_DirName) < 0)
return FatalError("unable to set DIR_NAME");
if (PyDict_SetItemString(dict, "EXCLUSIVE_ZIP_FILE_NAME",
g_ExclusiveZipFileName) < 0)
return FatalError("unable to set EXCLUSIVE_ZIP_FILE_NAME");
if (PyDict_SetItemString(dict, "SHARED_ZIP_FILE_NAME",
g_SharedZipFileName) < 0)
return FatalError("unable to set SHARED_ZIP_FILE_NAME");
if (PyDict_SetItemString(dict, "INITSCRIPT_ZIP_FILE_NAME",
g_InitScriptZipFileName) < 0)
return FatalError("unable to set INITSCRIPT_ZIP_FILE_NAME");
return 0;
}
//-----------------------------------------------------------------------------
// ExecuteScript()
// Execute the script found within the file.
//-----------------------------------------------------------------------------
static int ExecuteScript(
const char *fileName) // name of file containing Python code
{
PyObject *importer, *dict, *code, *temp;
if (SetExecutableName(fileName) < 0)
return -1;
if (SetPathToSearch() < 0)
return -1;
importer = NULL;
if (GetImporter(&importer) < 0)
return -1;
// create and populate dictionary for initscript module
dict = PyDict_New();
if (PopulateInitScriptDict(dict) < 0) {
Py_XDECREF(dict);
Py_DECREF(importer);
return -1;
}
// locate and execute script
code = PyObject_CallMethod(importer, "get_code", "s", "cx_Freeze__init__");
Py_DECREF(importer);
if (!code)
return FatalError("unable to locate initialization module");
temp = PyEval_EvalCode( (PyCodeObject*) code, dict, dict);
Py_DECREF(code);
Py_DECREF(dict);
if (!temp)
return FatalScriptError();
Py_DECREF(temp);
return 0;
}

View File

@ -1,72 +0,0 @@
//-----------------------------------------------------------------------------
// Console.c
// Main routine for frozen programs which run in a console.
//-----------------------------------------------------------------------------
#include <Python.h>
#ifdef __WIN32__
#include <windows.h>
#endif
//-----------------------------------------------------------------------------
// FatalError()
// Prints a fatal error.
//-----------------------------------------------------------------------------
static int FatalError(
const char *message) // message to print
{
PyErr_Print();
Py_FatalError(message);
return -1;
}
//-----------------------------------------------------------------------------
// FatalScriptError()
// Prints a fatal error in the initialization script.
//-----------------------------------------------------------------------------
static int FatalScriptError(void)
{
PyErr_Print();
return -1;
}
#include "Common.c"
//-----------------------------------------------------------------------------
// main()
// Main routine for frozen programs.
//-----------------------------------------------------------------------------
int main(int argc, char **argv)
{
const char *fileName;
char *encoding;
// initialize Python
Py_NoSiteFlag = 1;
Py_FrozenFlag = 1;
Py_IgnoreEnvironmentFlag = 1;
encoding = getenv("PYTHONIOENCODING");
if (encoding != NULL) {
Py_FileSystemDefaultEncoding = strndup(encoding, 100);
}
Py_SetPythonHome("");
Py_SetProgramName(argv[0]);
fileName = Py_GetProgramFullPath();
Py_Initialize();
PySys_SetArgv(argc, argv);
// do the work
if (ExecuteScript(fileName) < 0)
return 1;
Py_Finalize();
return 0;
}

View File

@ -1,60 +0,0 @@
//-----------------------------------------------------------------------------
// ConsoleKeepPath.c
// Main routine for frozen programs which need a Python installation to do
// their work.
//-----------------------------------------------------------------------------
#include <Python.h>
#ifdef __WIN32__
#include <windows.h>
#endif
//-----------------------------------------------------------------------------
// FatalError()
// Prints a fatal error.
//-----------------------------------------------------------------------------
static int FatalError(
const char *message) // message to print
{
PyErr_Print();
Py_FatalError(message);
return -1;
}
//-----------------------------------------------------------------------------
// FatalScriptError()
// Prints a fatal error in the initialization script.
//-----------------------------------------------------------------------------
static int FatalScriptError(void)
{
PyErr_Print();
return -1;
}
#include "Common.c"
//-----------------------------------------------------------------------------
// main()
// Main routine for frozen programs.
//-----------------------------------------------------------------------------
int main(int argc, char **argv)
{
const char *fileName;
// initialize Python
Py_SetProgramName(argv[0]);
fileName = Py_GetProgramFullPath();
Py_Initialize();
PySys_SetArgv(argc, argv);
// do the work
if (ExecuteScript(fileName) < 0)
return 1;
Py_Finalize();
return 0;
}

View File

@ -1,242 +0,0 @@
//-----------------------------------------------------------------------------
// Win32GUI.c
// Main routine for frozen programs written for the Win32 GUI subsystem.
//-----------------------------------------------------------------------------
#include <Python.h>
#include <windows.h>
//-----------------------------------------------------------------------------
// FatalError()
// Handle a fatal error.
//-----------------------------------------------------------------------------
static int FatalError(
char *a_Message) // message to display
{
MessageBox(NULL, a_Message, "cx_Freeze Fatal Error", MB_ICONERROR);
Py_Finalize();
return -1;
}
//-----------------------------------------------------------------------------
// StringifyObject()
// Stringify a Python object.
//-----------------------------------------------------------------------------
static char *StringifyObject(
PyObject *object, // object to stringify
PyObject **stringRep) // string representation
{
if (object) {
*stringRep = PyObject_Str(object);
if (*stringRep)
return PyString_AS_STRING(*stringRep);
return "Unable to stringify";
}
// object is NULL
*stringRep = NULL;
return "None";
}
//-----------------------------------------------------------------------------
// FatalPythonErrorNoTraceback()
// Handle a fatal Python error without traceback.
//-----------------------------------------------------------------------------
static int FatalPythonErrorNoTraceback(
PyObject *origType, // exception type
PyObject *origValue, // exception value
char *message) // message to display
{
PyObject *typeStrRep, *valueStrRep, *origTypeStrRep, *origValueStrRep;
char *totalMessage, *typeStr, *valueStr, *origTypeStr, *origValueStr;
PyObject *type, *value, *traceback;
int totalMessageLength;
char *messageFormat;
// fetch error and string representations of the error
PyErr_Fetch(&type, &value, &traceback);
origTypeStr = StringifyObject(origType, &origTypeStrRep);
origValueStr = StringifyObject(origValue, &origValueStrRep);
typeStr = StringifyObject(type, &typeStrRep);
valueStr = StringifyObject(value, &valueStrRep);
// fill out the message to be displayed
messageFormat = "Type: %s\nValue: %s\nOther Type: %s\nOtherValue: %s\n%s";
totalMessageLength = strlen(origTypeStr) + strlen(origValueStr) +
strlen(typeStr) + strlen(valueStr) + strlen(message) +
strlen(messageFormat) + 1;
totalMessage = malloc(totalMessageLength);
if (!totalMessage)
return FatalError("Out of memory!");
sprintf(totalMessage, messageFormat, typeStr, valueStr, origTypeStr,
origValueStr, message);
// display the message
MessageBox(NULL, totalMessage,
"cx_Freeze: Python error in main script (traceback unavailable)",
MB_ICONERROR);
free(totalMessage);
return -1;
}
//-----------------------------------------------------------------------------
// ArgumentValue()
// Return a suitable argument value by replacing NULL with Py_None.
//-----------------------------------------------------------------------------
static PyObject *ArgumentValue(
PyObject *object) // argument to massage
{
if (object) {
Py_INCREF(object);
return object;
}
Py_INCREF(Py_None);
return Py_None;
}
//-----------------------------------------------------------------------------
// HandleSystemExitException()
// Handles a system exit exception differently. If an integer value is passed
// through then that becomes the exit value; otherwise the string value of the
// value passed through is displayed in a message box.
//-----------------------------------------------------------------------------
static void HandleSystemExitException()
{
PyObject *type, *value, *traceback, *valueStr;
int exitCode = 0;
char *message;
PyErr_Fetch(&type, &value, &traceback);
if (PyInstance_Check(value)) {
PyObject *code = PyObject_GetAttrString(value, "code");
if (code) {
Py_DECREF(value);
value = code;
if (value == Py_None)
Py_Exit(0);
}
}
if (PyInt_Check(value))
exitCode = PyInt_AsLong(value);
else {
message = StringifyObject(value, &valueStr);
MessageBox(NULL, message, "cx_Freeze: Application Terminated",
MB_ICONERROR);
Py_XDECREF(valueStr);
exitCode = 1;
}
Py_Exit(exitCode);
}
//-----------------------------------------------------------------------------
// FatalScriptError()
// Handle a fatal Python error with traceback.
//-----------------------------------------------------------------------------
static int FatalScriptError()
{
PyObject *type, *value, *traceback, *argsTuple, *module, *method, *result;
int tracebackLength, i;
char *tracebackStr;
// if a system exception, handle it specially
if (PyErr_ExceptionMatches(PyExc_SystemExit))
HandleSystemExitException();
// get the exception details
PyErr_Fetch(&type, &value, &traceback);
// import the traceback module
module = PyImport_ImportModule("traceback");
if (!module)
return FatalPythonErrorNoTraceback(type, value,
"Cannot import traceback module.");
// get the format_exception method
method = PyObject_GetAttrString(module, "format_exception");
Py_DECREF(module);
if (!method)
return FatalPythonErrorNoTraceback(type, value,
"Cannot get format_exception method.");
// create a tuple for the arguments
argsTuple = PyTuple_New(3);
if (!argsTuple) {
Py_DECREF(method);
return FatalPythonErrorNoTraceback(type, value,
"Cannot create arguments tuple for traceback.");
}
PyTuple_SET_ITEM(argsTuple, 0, ArgumentValue(type));
PyTuple_SET_ITEM(argsTuple, 1, ArgumentValue(value));
PyTuple_SET_ITEM(argsTuple, 2, ArgumentValue(traceback));
// call the format_exception method
result = PyObject_CallObject(method, argsTuple);
Py_DECREF(method);
Py_DECREF(argsTuple);
if (!result)
return FatalPythonErrorNoTraceback(type, value,
"Failed calling format_exception method.");
// determine length of string representation of formatted traceback
tracebackLength = 1;
for (i = 0; i < PyList_GET_SIZE(result); i++)
tracebackLength += PyString_GET_SIZE(PyList_GET_ITEM(result, i));
// create a string representation of the formatted traceback
tracebackStr = malloc(tracebackLength);
if (!tracebackStr) {
Py_DECREF(result);
return FatalError("Out of memory!");
}
tracebackStr[0] = '\0';
for (i = 0; i < PyList_GET_SIZE(result); i++)
strcat(tracebackStr, PyString_AS_STRING(PyList_GET_ITEM(result, i)));
Py_DECREF(result);
// bring up the error
MessageBox(NULL, tracebackStr, "cx_Freeze: Python error in main script",
MB_ICONERROR);
Py_Finalize();
return 1;
}
#include "Common.c"
//-----------------------------------------------------------------------------
// WinMain()
// Main routine for the executable in Windows.
//-----------------------------------------------------------------------------
int WINAPI WinMain(
HINSTANCE instance, // handle to application
HINSTANCE prevInstance, // previous handle to application
LPSTR commandLine, // command line
int showFlag) // show flag
{
const char *fileName;
// initialize Python
Py_NoSiteFlag = 1;
Py_FrozenFlag = 1;
Py_IgnoreEnvironmentFlag = 1;
Py_SetPythonHome("");
Py_SetProgramName(__argv[0]);
fileName = Py_GetProgramFullPath();
Py_Initialize();
PySys_SetArgv(__argc, __argv);
// do the work
if (ExecuteScript(fileName) < 0)
return 1;
// terminate Python
Py_Finalize();
return 0;
}

View File

@ -1,5 +0,0 @@
STRINGTABLE
{
1, "Just to ensure that buggy EndUpdateResource doesn't fall over."
}

View File

@ -1,3 +0,0 @@
#include "dummy.rc"
1 24 source/bases/manifest.txt

View File

@ -1,418 +0,0 @@
//-----------------------------------------------------------------------------
// util.c
// Shared library for use by cx_Freeze.
//-----------------------------------------------------------------------------
#include <Python.h>
#ifdef WIN32
#include <windows.h>
#include <imagehlp.h>
#pragma pack(2)
typedef struct {
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image
BYTE bReserved; // Reserved ( must be 0)
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // How many bytes in this resource?
DWORD dwImageOffset; // Where in the file is this image?
} ICONDIRENTRY;
typedef struct {
WORD idReserved; // Reserved (must be 0)
WORD idType; // Resource Type (1 for icons)
WORD idCount; // How many images?
ICONDIRENTRY idEntries[0]; // An entry for each image
} ICONDIR;
typedef struct {
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image
BYTE bReserved; // Reserved ( must be 0)
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // How many bytes in this resource?
WORD nID; // resource ID
} GRPICONDIRENTRY;
typedef struct {
WORD idReserved; // Reserved (must be 0)
WORD idType; // Resource Type (1 for icons)
WORD idCount; // How many images?
GRPICONDIRENTRY idEntries[0]; // An entry for each image
} GRPICONDIR;
#endif
//-----------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------
#ifdef WIN32
static PyObject *g_BindErrorException = NULL;
static PyObject *g_ImageNames = NULL;
#endif
#ifdef WIN32
//-----------------------------------------------------------------------------
// BindStatusRoutine()
// Called by BindImageEx() at various points. This is used to determine the
// dependency tree which is later examined by cx_Freeze.
//-----------------------------------------------------------------------------
static BOOL __stdcall BindStatusRoutine(
IMAGEHLP_STATUS_REASON reason, // reason called
PSTR imageName, // name of image being examined
PSTR dllName, // name of DLL
ULONG virtualAddress, // computed virtual address
ULONG parameter) // parameter (value depends on reason)
{
char fileName[MAX_PATH + 1];
switch (reason) {
case BindImportModule:
if (!SearchPath(NULL, dllName, NULL, sizeof(fileName), fileName,
NULL))
return FALSE;
Py_INCREF(Py_None);
if (PyDict_SetItemString(g_ImageNames, fileName, Py_None) < 0)
return FALSE;
break;
default:
break;
}
return TRUE;
}
//-----------------------------------------------------------------------------
// GetFileData()
// Return the data for the given file.
//-----------------------------------------------------------------------------
static int GetFileData(
const char *fileName, // name of file to read
char **data) // pointer to data (OUT)
{
DWORD numberOfBytesRead, dataSize;
HANDLE file;
file = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE)
return -1;
dataSize = GetFileSize(file, NULL);
if (dataSize == INVALID_FILE_SIZE) {
CloseHandle(file);
return -1;
}
*data = PyMem_Malloc(dataSize);
if (!*data) {
CloseHandle(file);
return -1;
}
if (!ReadFile(file, *data, dataSize, &numberOfBytesRead, NULL)) {
CloseHandle(file);
return -1;
}
CloseHandle(file);
return 0;
}
//-----------------------------------------------------------------------------
// CreateGroupIconResource()
// Return the group icon resource given the icon file data.
//-----------------------------------------------------------------------------
static GRPICONDIR *CreateGroupIconResource(
ICONDIR *iconDir, // icon information
DWORD *resourceSize) // size of resource (OUT)
{
GRPICONDIR *groupIconDir;
int i;
*resourceSize = sizeof(GRPICONDIR) +
sizeof(GRPICONDIRENTRY) * iconDir->idCount;
groupIconDir = PyMem_Malloc(*resourceSize);
if (!groupIconDir)
return NULL;
groupIconDir->idReserved = iconDir->idReserved;
groupIconDir->idType = iconDir->idType;
groupIconDir->idCount = iconDir->idCount;
for (i = 0; i < iconDir->idCount; i++) {
groupIconDir->idEntries[i].bWidth = iconDir->idEntries[i].bWidth;
groupIconDir->idEntries[i].bHeight = iconDir->idEntries[i].bHeight;
groupIconDir->idEntries[i].bColorCount =
iconDir->idEntries[i].bColorCount;
groupIconDir->idEntries[i].bReserved = iconDir->idEntries[i].bReserved;
groupIconDir->idEntries[i].wPlanes = iconDir->idEntries[i].wPlanes;
groupIconDir->idEntries[i].wBitCount = iconDir->idEntries[i].wBitCount;
groupIconDir->idEntries[i].dwBytesInRes =
iconDir->idEntries[i].dwBytesInRes;
groupIconDir->idEntries[i].nID = i + 1;
}
return groupIconDir;
}
//-----------------------------------------------------------------------------
// ExtAddIcon()
// Add the icon as a resource to the specified file.
//-----------------------------------------------------------------------------
static PyObject *ExtAddIcon(
PyObject *self, // passthrough argument
PyObject *args) // arguments
{
char *executableName, *iconName, *data, *iconData;
GRPICONDIR *groupIconDir;
DWORD resourceSize;
ICONDIR *iconDir;
BOOL succeeded;
HANDLE handle;
int i;
if (!PyArg_ParseTuple(args, "ss", &executableName, &iconName))
return NULL;
// begin updating the executable
handle = BeginUpdateResource(executableName, FALSE);
if (!handle) {
PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
GetLastError(), executableName);
return NULL;
}
// first attempt to get the data from the icon file
data = NULL;
succeeded = TRUE;
groupIconDir = NULL;
if (GetFileData(iconName, &data) < 0)
succeeded = FALSE;
iconDir = (ICONDIR*) data;
// next, attempt to add a group icon resource
if (succeeded) {
groupIconDir = CreateGroupIconResource(iconDir, &resourceSize);
if (groupIconDir)
succeeded = UpdateResource(handle, RT_GROUP_ICON,
MAKEINTRESOURCE(1),
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
groupIconDir, resourceSize);
else succeeded = FALSE;
}
// next, add each icon as a resource
if (succeeded) {
for (i = 0; i < iconDir->idCount; i++) {
iconData = &data[iconDir->idEntries[i].dwImageOffset];
resourceSize = iconDir->idEntries[i].dwBytesInRes;
succeeded = UpdateResource(handle, RT_ICON, MAKEINTRESOURCE(i + 1),
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), iconData,
resourceSize);
if (!succeeded)
break;
}
}
// finish writing the resource (or discarding the changes upon an error)
if (!EndUpdateResource(handle, !succeeded)) {
if (succeeded) {
succeeded = FALSE;
PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
GetLastError(), executableName);
}
}
// clean up
if (groupIconDir)
PyMem_Free(groupIconDir);
if (data)
PyMem_Free(data);
if (!succeeded)
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
//-----------------------------------------------------------------------------
// ExtBeginUpdateResource()
// Wrapper for BeginUpdateResource().
//-----------------------------------------------------------------------------
static PyObject *ExtBeginUpdateResource(
PyObject *self, // passthrough argument
PyObject *args) // arguments
{
BOOL deleteExistingResources;
char *fileName;
HANDLE handle;
deleteExistingResources = TRUE;
if (!PyArg_ParseTuple(args, "s|i", &fileName, &deleteExistingResources))
return NULL;
handle = BeginUpdateResource(fileName, deleteExistingResources);
if (!handle) {
PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
GetLastError(), fileName);
return NULL;
}
return PyInt_FromLong((long) handle);
}
//-----------------------------------------------------------------------------
// ExtUpdateResource()
// Wrapper for UpdateResource().
//-----------------------------------------------------------------------------
static PyObject *ExtUpdateResource(
PyObject *self, // passthrough argument
PyObject *args) // arguments
{
int resourceType, resourceId, resourceDataSize;
char *resourceData;
HANDLE handle;
if (!PyArg_ParseTuple(args, "iiis#", &handle, &resourceType, &resourceId,
&resourceData, &resourceDataSize))
return NULL;
if (!UpdateResource(handle, MAKEINTRESOURCE(resourceType),
MAKEINTRESOURCE(resourceId),
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), resourceData,
resourceDataSize)) {
PyErr_SetExcFromWindowsErr(PyExc_WindowsError, GetLastError());
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
//-----------------------------------------------------------------------------
// ExtEndUpdateResource()
// Wrapper for EndUpdateResource().
//-----------------------------------------------------------------------------
static PyObject *ExtEndUpdateResource(
PyObject *self, // passthrough argument
PyObject *args) // arguments
{
BOOL discardChanges;
HANDLE handle;
discardChanges = FALSE;
if (!PyArg_ParseTuple(args, "i|i", &handle, &discardChanges))
return NULL;
if (!EndUpdateResource(handle, discardChanges)) {
PyErr_SetExcFromWindowsErr(PyExc_WindowsError, GetLastError());
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
//-----------------------------------------------------------------------------
// ExtGetDependentFiles()
// Return a list of files that this file depends on.
//-----------------------------------------------------------------------------
static PyObject *ExtGetDependentFiles(
PyObject *self, // passthrough argument
PyObject *args) // arguments
{
PyObject *results;
char *imageName;
if (!PyArg_ParseTuple(args, "s", &imageName))
return NULL;
g_ImageNames = PyDict_New();
if (!g_ImageNames)
return NULL;
if (!BindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES,
imageName, NULL, NULL, BindStatusRoutine)) {
Py_DECREF(g_ImageNames);
PyErr_SetExcFromWindowsErrWithFilename(g_BindErrorException,
GetLastError(), imageName);
return NULL;
}
results = PyDict_Keys(g_ImageNames);
Py_DECREF(g_ImageNames);
return results;
}
//-----------------------------------------------------------------------------
// ExtGetSystemDir()
// Return the Windows directory (C:\Windows for example).
//-----------------------------------------------------------------------------
static PyObject *ExtGetSystemDir(
PyObject *self, // passthrough argument
PyObject *args) // arguments (ignored)
{
char dir[MAX_PATH + 1];
if (GetSystemDirectory(dir, sizeof(dir)))
return PyString_FromString(dir);
PyErr_SetExcFromWindowsErr(PyExc_RuntimeError, GetLastError());
return NULL;
}
#endif
//-----------------------------------------------------------------------------
// ExtSetOptimizeFlag()
// Set the optimize flag as needed.
//-----------------------------------------------------------------------------
static PyObject *ExtSetOptimizeFlag(
PyObject *self, // passthrough argument
PyObject *args) // arguments
{
if (!PyArg_ParseTuple(args, "i", &Py_OptimizeFlag))
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
//-----------------------------------------------------------------------------
// Methods
//-----------------------------------------------------------------------------
static PyMethodDef g_ModuleMethods[] = {
{ "SetOptimizeFlag", ExtSetOptimizeFlag, METH_VARARGS },
#ifdef WIN32
{ "BeginUpdateResource", ExtBeginUpdateResource, METH_VARARGS },
{ "UpdateResource", ExtUpdateResource, METH_VARARGS },
{ "EndUpdateResource", ExtEndUpdateResource, METH_VARARGS },
{ "AddIcon", ExtAddIcon, METH_VARARGS },
{ "GetDependentFiles", ExtGetDependentFiles, METH_VARARGS },
{ "GetSystemDir", ExtGetSystemDir, METH_NOARGS },
#endif
{ NULL }
};
//-----------------------------------------------------------------------------
// initutil()
// Initialization routine for the shared libary.
//-----------------------------------------------------------------------------
void initutil(void)
{
PyObject *module;
module = Py_InitModule("cx_Freeze.util", g_ModuleMethods);
if (!module)
return;
#ifdef WIN32
g_BindErrorException = PyErr_NewException("cx_Freeze.util.BindError",
NULL, NULL);
if (!g_BindErrorException)
return;
if (PyModule_AddObject(module, "BindError", g_BindErrorException) < 0)
return;
#endif
}

View File

@ -1,17 +1,85 @@
Notes on setting up the windows development environment Notes on setting up the windows development environment
======================================================== ========================================================
Set CMAKE_PREFIX_PATH to C:\cygwin\home\kovid\sw Overview
----------
calibre and all its dependencies are compiled using Visual Studio 2008 express edition (free from MS). All the following instructions must be run in a visual studio command prompt unless otherwise noted.
calibre contains build script to automate the building of the calibre installer. These scripts make certain assumptions about where dependencies are installed. Your best best is to setup a VM and replicate the paths mentioned below exactly.
Basic dependencies
--------------------
Install cygwin and setup sshd (optional). Used to enable automation of the calibre build VM from linux, not needed if you are building manually.
Install MS Visual Studio 2008, cmake, python and WiX.
Set CMAKE_PREFIX_PATH environment variable to C:\cygwin\home\kovid\sw
This is where all dependencies will be installed.
Add C:\Python26\Scripts and C:\Python26 to PATH
Install setuptools from http://pypi.python.org/pypi/setuptools
If there are no windows binaries already compiled for the version of python you are using then download the source and run the following command in the folder where the source has been unpacked::
python setup.py install
Run the following command to install python dependencies::
easy_install --always-unzip -U ipython mechanize BeautifulSoup pyreadline python-dateutil dnspython
Qt
--------
Extract Qt sourcecode to C:\Qt\4.x.x. Run configure and make::
configure -opensource -qt-zlib -qt-gif -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -release -platform win32-msvc -no-qt3support -webkit -xmlpatterns -no-phonon
nmake
SIP
-----
Available from: http://www.riverbankcomputing.co.uk/software/sip/download ::
python configure.py -p win32-msvc2008
nmake
nmake install
PyQt4
----------
Compiling instructions::
python configure.py -c -j5 -e QtCore -e QtGui -e QtSvg -e QtNetwork -e QtWebKit -e QtXmlPatterns --verbose
nmake
nmake install
Python Imaging Library
------------------------
Install as normal using provided installer.
Libunrar
----------
http://www.rarlab.com/rar/UnRARDLL.exe install and add C:\Program Files\UnrarDLL to PATH
lxml
------
http://pypi.python.org/pypi/lxml
jpeg-7 jpeg-7
------- -------
Copy Copy::
jconfig.vc to jconfig.h, makejsln.vc9 to jpeg.sln, jconfig.vc to jconfig.h, makejsln.vc9 to jpeg.sln,
makeasln.vc9 to apps.sln, makejvcp.vc9 to jpeg.vcproj, makeasln.vc9 to apps.sln, makejvcp.vc9 to jpeg.vcproj,
makecvcp.vc9 to cjpeg.vcproj, makedvcp.vc9 to djpeg.vcproj, makecvcp.vc9 to cjpeg.vcproj, makedvcp.vc9 to djpeg.vcproj,
maketvcp.vc9 to jpegtran.vcproj, makervcp.vc9 to rdjpgcom.vcproj, and maketvcp.vc9 to jpegtran.vcproj, makervcp.vc9 to rdjpgcom.vcproj, and
makewvcp.vc9 to wrjpgcom.vcproj. (Note that the renaming is critical!) makewvcp.vc9 to wrjpgcom.vcproj. (Note that the renaming is critical!)
Load jpeg.sln in Visual Studio Load jpeg.sln in Visual Studio
@ -169,28 +237,10 @@ cp build/podofo/build/src/Release/podofo.exp lib/
cp build/podofo/build/podofo_config.h include/podofo/ cp build/podofo/build/podofo_config.h include/podofo/
cp -r build/podofo/src/* include/podofo/ cp -r build/podofo/src/* include/podofo/
The following patch was required to get it to compile: You have to use >0.8.1 (>= revision 1269)
Index: src/PdfImage.cpp The following patch (against -r1269) was required to get it to compile:
===================================================================
--- src/PdfImage.cpp (revision 1261)
+++ src/PdfImage.cpp (working copy)
@@ -627,7 +627,7 @@
long lLen = static_cast<long>(pInfo->rowbytes * height);
char* pBuffer = static_cast<char*>(malloc(sizeof(char) * lLen));
- png_bytep pRows[height];
+ png_bytepp pRows = static_cast<png_bytepp>(malloc(sizeof(png_bytep)*height));
for(int y=0; y<height; y++)
{
pRows[y] = reinterpret_cast<png_bytep>(pBuffer + (y * pInfo->rowbytes));
@@ -672,6 +672,7 @@
this->SetImageData( width, height, pInfo->bit_depth, &stream );
free(pBuffer);
+ free(pRows);
}
#endif // PODOFO_HAVE_PNG_LIB
Index: src/PdfFiltersPrivate.cpp Index: src/PdfFiltersPrivate.cpp
=================================================================== ===================================================================
@ -214,7 +264,7 @@ Edit VisualMagick/configure/configure.cpp to set
int projectType = MULTITHREADEDDLL; int projectType = MULTITHREADEDDLL;
Run configure.bat ina visual studio command prompt Run configure.bat in a visual studio command prompt
Edit magick/magick-config.h Edit magick/magick-config.h
@ -222,3 +272,19 @@ Undefine ProvideDllMain and MAGICKCORE_X11_DELEGATE
Now open VisualMagick/VisualDynamicMT.sln set to Release Now open VisualMagick/VisualDynamicMT.sln set to Release
Remove the CORE_xlib project Remove the CORE_xlib project
calibre
---------
Take a linux calibre tree on which you have run the following command::
python setup.py stage1
and copy it to windows.
Run::
python setup.py build
python setup.py win32_freeze
This will create the .msi in the dist directory.

View File

@ -73,11 +73,11 @@ class Manual(Command):
os.makedirs(d) os.makedirs(d)
if not os.path.exists('.build'+os.sep+'html'): if not os.path.exists('.build'+os.sep+'html'):
os.makedirs('.build'+os.sep+'html') os.makedirs('.build'+os.sep+'html')
os.environ['__appname__']= __appname__ os.environ['__appname__'] = __appname__
os.environ['__version__']= __version__ os.environ['__version__'] = __version__
subprocess.check_call(['sphinx-build', '-b', 'custom', '-t', 'online', subprocess.check_call(['sphinx-build', '-b', 'html', '-t', 'online',
'-d', '.build/doctrees', '.', '.build/html']) '-d', '.build/doctrees', '.', '.build/html'])
subprocess.check_call(['sphinx-build', '-b', 'epub', '-d', subprocess.check_call(['sphinx-build', '-b', 'myepub', '-d',
'.build/doctrees', '.', '.build/epub']) '.build/doctrees', '.', '.build/epub'])
shutil.copyfile(self.j('.build', 'epub', 'calibre.epub'), self.j('.build', shutil.copyfile(self.j('.build', 'epub', 'calibre.epub'), self.j('.build',
'html', 'calibre.epub')) 'html', 'calibre.epub'))

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