diff --git a/resources/jacket/stylesheet.css b/resources/jacket/stylesheet.css index 5f4f012d01..c45f8fe977 100644 --- a/resources/jacket/stylesheet.css +++ b/resources/jacket/stylesheet.css @@ -36,22 +36,37 @@ /* ** Title */ -.cbj_title { +table.cbj_header td.cbj_title { font-size: x-large; + font-style: italic; + text-align: center; +} + +/* +** Series +*/ +table.cbj_header td.cbj_series { + font-size: medium; text-align: center; } /* ** Author */ -.cbj_author { +table.cbj_header td.cbj_author { font-size: medium; text-align: center; - margin-bottom: 1ex; } /* -** Table containing Series, Publication Year, Rating and Tags +** Publisher/published +*/ +table.cbj_header td.cbj_pubdata { + text-align: center; +} + +/* +** Table containing Rating and Tags */ table.cbj_header { width: 100%; @@ -62,9 +77,8 @@ table.cbj_header { */ table.cbj_header td.cbj_label { font-family: sans-serif; - font-weight: bold; text-align: right; - width: 40%; + width: 33%; } /* @@ -73,9 +87,23 @@ table.cbj_header td.cbj_label { table.cbj_header td.cbj_content { font-family: sans-serif; text-align: left; - width:60%; + width:67%; } +/* +** Metadata divider +*/ +hr.metadata_divider { + width:90%; + margin-left:5%; + border-top: solid white 0px; + border-right: solid white 0px; + border-bottom: solid black 1px; + border-left: solid white 0px; + } + + + /* ** To skip a banner item (Series|Published|Rating|Tags), ** edit the appropriate CSS rule below. diff --git a/resources/jacket/template.xhtml b/resources/jacket/template.xhtml index 8447b1d6b3..056ac0aad3 100644 --- a/resources/jacket/template.xhtml +++ b/resources/jacket/template.xhtml @@ -6,17 +6,24 @@
-
{title}
-
{author}
- - - + + + + + - - - + + + + + + + + + + diff --git a/resources/mime.types b/resources/mime.types new file mode 100644 index 0000000000..ab98b3bf4a --- /dev/null +++ b/resources/mime.types @@ -0,0 +1,1381 @@ +## Mimetypes from my linux system + +application/activemessage +application/andrew-inset ez +application/applefile +application/applixware aw +application/atom+xml atom +application/atomcat+xml atomcat +application/atomicmail +application/atomsvc+xml atomsvc +application/auth-policy+xml +application/batch-smtp +application/beep+xml +application/cals-1840 +application/ccxml+xml ccxml +application/cea-2018+xml +application/cellml+xml +application/cnrp+xml +application/commonground +application/conference-info+xml +application/cpl+xml +application/csta+xml +application/cstadata+xml +application/cu-seeme cu +application/cybercash +application/davmount+xml davmount +application/dca-rft +application/dec-dx +application/dialog-info+xml +application/dicom +application/dns +application/dsptype tsp +application/dvcs +application/ecmascript ecma +application/edi-consent +application/edi-x12 +application/edifact +application/emma+xml emma +application/epp+xml +application/epub+zip epub +application/eshop +application/example +application/fastinfoset +application/fastsoap +application/fits +application/font-tdpfr pfr +application/futuresplash spl +application/h224 +application/hta hta +application/http +application/hyperstudio stk +application/ibe-key-request+xml +application/ibe-pkg-reply+xml +application/ibe-pp-data +application/iges +application/im-iscomposing+xml +application/index +application/index.cmd +application/index.obj +application/index.response +application/index.vnd +application/iotp +application/ipp +application/isup +application/java-archive jar +application/java-serialized-object ser +application/java-vm class +application/javascript js +application/json json +application/kpml-request+xml +application/kpml-response+xml +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/macwriteii +application/marc mrc +application/mathematica ma mb nb +application/mathml+xml mathml +application/mbms-associated-procedure-description+xml +application/mbms-deregister+xml +application/mbms-envelope+xml +application/mbms-msk+xml +application/mbms-msk-response+xml +application/mbms-protection-description+xml +application/mbms-reception-report+xml +application/mbms-register+xml +application/mbms-register-response+xml +application/mbms-user-service-description+xml +application/mbox mbox +application/media_control+xml +application/mediaservercontrol+xml mscml +application/mikey +application/moss-keys +application/moss-signature +application/mosskey-data +application/mosskey-request +application/mp4 mp4s +application/mpeg4-generic +application/mpeg4-iod +application/mpeg4-iod-xmt +application/msaccess mdb +application/msword doc dot +application/mxf mxf +application/nasdata +application/news-checkgroups +application/news-groupinfo +application/news-transmission +application/nss +application/ocsp-request +application/ocsp-response +application/octet-stream bin bpk deploy dist distz dmg dms dump elc iso lha lrf lzh pkg so +application/oda oda +application/oebps-package+xml opf +application/ogg ogg ogx +application/onenote onepkg onetmp onetoc onetoc2 +application/parityfec +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +application/pgp-keys key +application/pgp-signature asc pgp sig +application/pics-rules prf +application/pidf+xml +application/pidf-diff+xml +application/pkcs10 p10 +application/pkcs7-mime p7c p7m +application/pkcs7-signature p7s +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +application/poc-settings+xml +application/postscript ai eps ps +application/prs.alvestrand.titrax-sheet +application/prs.cww cww +application/prs.nprend +application/prs.plucker +application/qsig +application/rar rar +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +application/remote-printing +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +application/riscos +application/rlmi+xml +application/rls-services+xml rs +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +application/rtx +application/samlassertion+xml +application/samlmetadata+xml +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +application/set-payment +application/set-payment-initiation setpay +application/set-registration +application/set-registration-initiation setreg +application/sgml +application/sgml-open-catalog +application/shf+xml shf +application/sieve +application/simple-filter+xml +application/simple-message-summary +application/simplesymbolcontainer +application/slate +application/smil smi smil +application/smil+xml smi smil +application/soap+fastinfoset +application/soap+xml +application/sparql-query rq +application/sparql-results+xml srx +application/spirits-event+xml +application/srgs gram +application/srgs+xml grxml +application/ssml+xml ssml +application/timestamp-query +application/timestamp-reply +application/tve-trigger +application/ulpfec +application/vemmi +application/vividence.scriptfile +application/vnd.3gpp.bsf+xml +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +application/vnd.3gpp.sms +application/vnd.3gpp2.bcmcsinfo+xml +application/vnd.3gpp2.sms +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp acutc atc +application/vnd.adobe.air-application-installer-package+zip air +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +application/vnd.aether.imp +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.ebook azw +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.arastra.swi swi +application/vnd.audiograph aep +application/vnd.autopackage +application/vnd.avistar+xml +application/vnd.blueice.multipass mpm +application/vnd.bluetooth.ep.oob +application/vnd.bmi bmi +application/vnd.businessobjects rep +application/vnd.cab-jscript +application/vnd.canon-cpdl +application/vnd.canon-lips +application/vnd.cendio.thinlinc.clientconf +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +application/vnd.cirpack.isdn-ext +application/vnd.claymore cla +application/vnd.clonk.c4group c4d c4f c4g c4p c4u +application/vnd.commerce-battelle +application/vnd.commonspace csp +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +application/vnd.ctct.ws+xml +application/vnd.cups-pdf +application/vnd.cups-postscript +application/vnd.cups-ppd ppd +application/vnd.cups-raster +application/vnd.cups-raw +application/vnd.curl.car car +application/vnd.curl.pcurl pcurl +application/vnd.cybank +application/vnd.data-vision.rdz rdz +application/vnd.denovo.fcselayout-link fe_launch +application/vnd.dir-bi.plate-dl-nosuffix +application/vnd.dna dna +application/vnd.dolby.mlp mlp +application/vnd.dolby.mobile.1 +application/vnd.dolby.mobile.2 +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.dvb.esgcontainer +application/vnd.dvb.ipdcdftnotifaccess +application/vnd.dvb.ipdcesgaccess +application/vnd.dvb.ipdcroaming +application/vnd.dvb.iptv.alfec-base +application/vnd.dvb.iptv.alfec-enhancement +application/vnd.dvb.notif-aggregate-root+xml +application/vnd.dvb.notif-container+xml +application/vnd.dvb.notif-generic+xml +application/vnd.dvb.notif-ia-msglist+xml +application/vnd.dvb.notif-ia-registration-request+xml +application/vnd.dvb.notif-ia-registration-response+xml +application/vnd.dvb.notif-init+xml +application/vnd.dxr +application/vnd.dynageo geo +application/vnd.ecdis-update +application/vnd.ecowin.chart mag +application/vnd.ecowin.filerequest +application/vnd.ecowin.fileupdate +application/vnd.ecowin.series +application/vnd.ecowin.seriesrequest +application/vnd.ecowin.seriesupdate +application/vnd.emclient.accessrequest+xml +application/vnd.enliven nml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +application/vnd.ericsson.quickcall +application/vnd.eszigno3+xml es3 et3 +application/vnd.etsi.aoc+xml +application/vnd.etsi.cug+xml +application/vnd.etsi.iptvcommand+xml +application/vnd.etsi.iptvdiscovery+xml +application/vnd.etsi.iptvprofile+xml +application/vnd.etsi.iptvsad-bc+xml +application/vnd.etsi.iptvsad-cod+xml +application/vnd.etsi.iptvsad-npvr+xml +application/vnd.etsi.iptvueprofile+xml +application/vnd.etsi.mcid+xml +application/vnd.etsi.sci+xml +application/vnd.etsi.simservs+xml +application/vnd.eudora.data +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +application/vnd.f-secure.mobile +application/vnd.fdf fdf +application/vnd.fdsn.mseed mseed +application/vnd.fdsn.seed dataless seed +application/vnd.ffsns +application/vnd.fints +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +application/vnd.font-fontforge-sfd +application/vnd.framemaker book fm frame maker +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +application/vnd.fujixerox.art-ex +application/vnd.fujixerox.art4 +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +application/vnd.fujixerox.hbpl +application/vnd.fut-misnet +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex gre +application/vnd.gmx gmx +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +application/vnd.gridmp +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +application/vnd.hcl-bireports +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +application/vnd.httphone +application/vnd.hydrostatix.sof-data sfd-hdstx +application/vnd.hzn-3d-crossword x3d +application/vnd.ibm.afplinedata +application/vnd.ibm.electronic-media +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp list3820 listafp +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +application/vnd.informedcontrol.rms+xml +application/vnd.informix-visionary +application/vnd.intercon.formnet xpw xpx +application/vnd.intertrust.digibox +application/vnd.intertrust.nncp +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +application/vnd.iptc.g2.conceptitem+xml +application/vnd.iptc.g2.knowledgeitem+xml +application/vnd.iptc.g2.newsitem+xml +application/vnd.iptc.g2.packageitem+xml +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.jam jam +application/vnd.japannet-directory-service +application/vnd.japannet-jpnstore-wakeup +application/vnd.japannet-payment-wakeup +application/vnd.japannet-registration +application/vnd.japannet-registration-wakeup +application/vnd.japannet-setstore-wakeup +application/vnd.japannet-verification +application/vnd.japannet-verification-wakeup +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktr ktz +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skd skm skp skt +application/vnd.kodak-descriptor sse +application/vnd.liberty-request+xml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +application/vnd.marlin.drm.actiontoken+xml +application/vnd.marlin.drm.conftoken+xml +application/vnd.marlin.drm.license+xml +application/vnd.marlin.drm.mdcf +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +application/vnd.meridian-slingshot +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +application/vnd.minisoft-hp3000-save +application/vnd.mitsubishi.misty-guard.trustweb +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +application/vnd.motorola.flexsuite +application/vnd.motorola.flexsuite.adsi +application/vnd.motorola.flexsuite.fis +application/vnd.motorola.flexsuite.gotap +application/vnd.motorola.flexsuite.kmr +application/vnd.motorola.flexsuite.ttc +application/vnd.motorola.flexsuite.wem +application/vnd.motorola.iprm +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +application/vnd.ms-asf +application/vnd.ms-cab-compressed cab +application/vnd.ms-excel xla xlb xlc xlm xls xlt xlw +application/vnd.ms-excel.addin.macroenabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb +application/vnd.ms-excel.sheet.macroenabled.12 xlsm +application/vnd.ms-excel.template.macroenabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +application/vnd.ms-playready.initiator+xml +application/vnd.ms-powerpoint pot pps ppt +application/vnd.ms-powerpoint.addin.macroenabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm +application/vnd.ms-powerpoint.slide.macroenabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm +application/vnd.ms-powerpoint.template.macroenabled.12 potm +application/vnd.ms-project mpp mpt +application/vnd.ms-tnef +application/vnd.ms-wmdrm.lic-chlg-req +application/vnd.ms-wmdrm.lic-resp +application/vnd.ms-wmdrm.meter-chlg-req +application/vnd.ms-wmdrm.meter-resp +application/vnd.ms-word.document.macroenabled.12 docm +application/vnd.ms-word.template.macroenabled.12 dotm +application/vnd.ms-works wcm wdb wks wps +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +application/vnd.msign +application/vnd.multiad.creator +application/vnd.multiad.creator.cif +application/vnd.music-niff +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.ncd.control +application/vnd.ncd.reference +application/vnd.nervana +application/vnd.netfpx +application/vnd.neurolanguage.nlu nlu +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +application/vnd.nokia.catalogs +application/vnd.nokia.conml+wbxml +application/vnd.nokia.conml+xml +application/vnd.nokia.iptv.config+xml +application/vnd.nokia.isds-radio-presets +application/vnd.nokia.landmark+wbxml +application/vnd.nokia.landmark+xml +application/vnd.nokia.landmarkcollection+xml +application/vnd.nokia.n-gage.ac+xml +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +application/vnd.nokia.ncd +application/vnd.nokia.pcd+wbxml +application/vnd.nokia.pcd+xml +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template odft +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm otm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +application/vnd.obn +application/vnd.olpc-sugar xo +application/vnd.oma-scws-config +application/vnd.oma-scws-http-request +application/vnd.oma-scws-http-response +application/vnd.oma.bcast.associated-procedure-parameter+xml +application/vnd.oma.bcast.drm-trigger+xml +application/vnd.oma.bcast.imd+xml +application/vnd.oma.bcast.ltkm +application/vnd.oma.bcast.notification+xml +application/vnd.oma.bcast.provisioningtrigger +application/vnd.oma.bcast.sgboot +application/vnd.oma.bcast.sgdd+xml +application/vnd.oma.bcast.sgdu +application/vnd.oma.bcast.simple-symbol-container +application/vnd.oma.bcast.smartcard-trigger+xml +application/vnd.oma.bcast.sprov+xml +application/vnd.oma.bcast.stkm +application/vnd.oma.dcd +application/vnd.oma.dcdc +application/vnd.oma.dd2+xml dd2 +application/vnd.oma.drm.risd+xml +application/vnd.oma.group-usage-list+xml +application/vnd.oma.poc.detailed-progress-report+xml +application/vnd.oma.poc.final-report+xml +application/vnd.oma.poc.groups+xml +application/vnd.oma.poc.invocation-descriptor+xml +application/vnd.oma.poc.optimized-progress-report+xml +application/vnd.oma.xcap-directory+xml +application/vnd.omads-email+xml +application/vnd.omads-file+xml +application/vnd.omads-folder+xml +application/vnd.omaloc-supl-init +application/vnd.openofficeorg.extension oxt +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +application/vnd.openxmlformats-officedocument.presentationml.template potx +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +application/vnd.osa.netdeploy +application/vnd.osgi.bundle +application/vnd.osgi.dp dp +application/vnd.otps.ct-kip+xml +application/vnd.palm oprc pdb pqa +application/vnd.paos.xml +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +application/vnd.piaccess.application-licence +application/vnd.picsel efif +application/vnd.poc.group-advertisement+xml +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +application/vnd.powerbuilder6-s +application/vnd.powerbuilder7 +application/vnd.powerbuilder7-s +application/vnd.powerbuilder75 +application/vnd.powerbuilder75-s +application/vnd.preminet +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +application/vnd.pwg-multiplexed +application/vnd.pwg-xhtml-print+xml +application/vnd.qualcomm.brew-app-res +application/vnd.quark.quarkxpress qwd qwt qxb qxd qxl qxt +application/vnd.rapid +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml musicxml +application/vnd.renlearn.rlprint +application/vnd.rim.cod cod +application/vnd.rn-realmedia rm +application/vnd.route66.link66+xml link66 +application/vnd.ruckus.download +application/vnd.s3sms +application/vnd.sbm.cid +application/vnd.sbm.mid2 +application/vnd.scribus +application/vnd.sealed.3df +application/vnd.sealed.csf +application/vnd.sealed.doc +application/vnd.sealed.eml +application/vnd.sealed.mht +application/vnd.sealed.net +application/vnd.sealed.ppt +application/vnd.sealed.tiff +application/vnd.sealed.xls +application/vnd.sealedmedia.softseal.html +application/vnd.sealedmedia.softseal.pdf +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +application/vnd.smart.teacher teacher +application/vnd.software602.filler.form+xml +application/vnd.software602.filler.form-xml-zip +application/vnd.solent.sdkm+xml sdkd sdkm +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +application/vnd.sss-cod +application/vnd.sss-dtf +application/vnd.sss-ntf +application/vnd.stardivision.calc sdc +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd sdp +application/vnd.stardivision.math sdf smf +application/vnd.stardivision.writer sdw vor +application/vnd.stardivision.writer-global sgl +application/vnd.street-stream +application/vnd.sun.wadl+xml +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +application/vnd.sus-calendar sus susp +application/vnd.svd svd +application/vnd.swiftview-ics +application/vnd.symbian.install sis sisx +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +application/vnd.syncml.dm.notification +application/vnd.syncml.ds.notification +application/vnd.tao.intent-module-archive tao +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +application/vnd.truedoc +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +application/vnd.uplanet.alert +application/vnd.uplanet.alert-wbxml +application/vnd.uplanet.bearer-choice +application/vnd.uplanet.bearer-choice-wbxml +application/vnd.uplanet.cacheop +application/vnd.uplanet.cacheop-wbxml +application/vnd.uplanet.channel +application/vnd.uplanet.channel-wbxml +application/vnd.uplanet.list +application/vnd.uplanet.list-wbxml +application/vnd.uplanet.listcmd +application/vnd.uplanet.listcmd-wbxml +application/vnd.uplanet.signal +application/vnd.vcx vcx +application/vnd.vd-study +application/vnd.vectorworks +application/vnd.vidsoft.vidconference +application/vnd.visio vsd vss vst vsw +application/vnd.visionary vis +application/vnd.vividence.scriptfile +application/vnd.vsf vsf +application/vnd.wap.sic +application/vnd.wap.slc +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +application/vnd.wfa.wsc +application/vnd.wmc +application/vnd.wmf.bootstrap +application/vnd.wordperfect wpd +application/vnd.wqd wqd +application/vnd.wrq-hp3000-labelled +application/vnd.wt.stf stf +application/vnd.wv.csp+wbxml +application/vnd.wv.csp+xml +application/vnd.wv.ssp+xml +application/vnd.xara xar +application/vnd.xfdl xfdl +application/vnd.xfdl.webform +application/vnd.xmi+xml +application/vnd.xmpie.cpkg +application/vnd.xmpie.dpkg +application/vnd.xmpie.plan +application/vnd.xmpie.ppkg +application/vnd.xmpie.xlim +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +application/watcherinfo+xml +application/whoispp-query +application/whoispp-response +application/winhlp hlp +application/wita +application/wordperfect wpd +application/wordperfect5.1 wp5 +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-123 wk +application/x-abiword abw +application/x-ace-compressed ace +application/x-apple-diskimage dmg +application/x-authorware-bin aab u32 vox x32 +application/x-authorware-map aam +application/x-authorware-seg aas +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-bzip bz +application/x-bzip2 boz bz2 +application/x-cdf cdf +application/x-cdlink vcd +application/x-chat chat +application/x-chess-pgn pgn +application/x-compress +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb udeb +application/x-director cct cst cxt dcr dir dxr fgd swa w3d +application/x-dms dms +application/x-doom wad +application/x-dtbncx+xml ncx +application/x-dtbook+xml dtb +application/x-dtbresource+xml res +application/x-dvi dvi +application/x-flac flac +application/x-font gsf pcf pcf.Z pfa pfb +application/x-font-bdf bdf +application/x-font-dos +application/x-font-framemaker +application/x-font-ghostscript gsf +application/x-font-libgrx +application/x-font-linux-psf psf +application/x-font-otf otf +application/x-font-pcf pcf +application/x-font-snf snf +application/x-font-speedo +application/x-font-sunos-news +application/x-font-ttf ttc ttf +application/x-font-type1 afm pfa pfb pfm +application/x-font-vfont +application/x-freemind mm +application/x-futuresplash spl +application/x-gnumeric gnumeric +application/x-go-sgf sgf +application/x-graphing-calculator gcf +application/x-gtar gtar taz tgz +application/x-gzip +application/x-hdf hdf +application/x-ica ica +application/x-internet-signup ins isp +application/x-iphone iii +application/x-iso9660-image iso +application/x-java-jnlp-file jnlp +application/x-javascript js +application/x-jmol jmz +application/x-kchart chrt +application/x-killustrator kil +application/x-koan skd skm skp skt +application/x-kpresenter kpr kpt +application/x-kspread ksp +application/x-kword kwd kwt +application/x-latex latex +application/x-lha lha +application/x-lzh lzh +application/x-lzx lzx +application/x-maker book fb fbdoc fm frame frm maker +application/x-mif mif +application/x-mobipocket-ebook mobi prc +application/x-ms-application application +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-ms-xbap xbap +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdos-program bat com dll exe +application/x-msdownload bat com dll exe msi +application/x-msi msi +application/x-msmediaview m13 m14 mvb +application/x-msmetafile wmf +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf cdf nc +application/x-ns-proxy-autoconfig pac +application/x-nwc nwc +application/x-object o +application/x-oz-application oza +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-pkcs7-crl crl +application/x-python-code pyc pyo +application/x-quicktimeplayer qtl +application/x-rar-compressed rar +application/x-redhat-package-manager rpm +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf swfl +application/x-silverlight-app xap +application/x-stuffit sit sitx +application/x-stuffitx sitx +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-tex-gf gf +application/x-tex-pk pk +application/x-tex-tfm tfm +application/x-texinfo texi texinfo +application/x-trash % bak old sik ~ +application/x-troff roff t tr +application/x-troff-man man +application/x-troff-me me +application/x-troff-ms ms +application/x-ustar ustar +application/x-wais-source src +application/x-wingz wz +application/x-x509-ca-cert crt der +application/x-xcf xcf +application/x-xfig fig +application/x-xpinstall xpi +application/x400-bp +application/xcap-att+xml +application/xcap-caps+xml +application/xcap-el+xml +application/xcap-error+xml +application/xcap-ns+xml +application/xcon-conference-info+xml +application/xcon-conference-info-diff+xml +application/xenc+xml xenc +application/xhtml+xml xht xhtml +application/xhtml-voice+xml +application/xml xml xsl +application/xml-dtd dtd +application/xml-external-parsed-entity +application/xmpp+xml +application/xop+xml xop +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvm xvml +application/zip zip +audio/32kadpcm +audio/3gpp +audio/3gpp2 +audio/ac3 +audio/adpcm adp +audio/amr +audio/amr-wb +audio/amr-wb+ +audio/asc +audio/basic au snd +audio/bv16 +audio/bv32 +audio/clearmode +audio/cn +audio/dat12 +audio/dls +audio/dsr-es201108 +audio/dsr-es202050 +audio/dsr-es202211 +audio/dsr-es202212 +audio/dvi4 +audio/eac3 +audio/evrc +audio/evrc-qcp +audio/evrc0 +audio/evrc1 +audio/evrcb +audio/evrcb0 +audio/evrcb1 +audio/evrcwb +audio/evrcwb0 +audio/evrcwb1 +audio/example +audio/g719 +audio/g722 +audio/g7221 +audio/g723 +audio/g726-16 +audio/g726-24 +audio/g726-32 +audio/g726-40 +audio/g728 +audio/g729 +audio/g7291 +audio/g729d +audio/g729e +audio/gsm +audio/gsm-efr +audio/ilbc +audio/l16 +audio/l20 +audio/l24 +audio/l8 +audio/lpc +audio/midi kar mid midi rmi +audio/mobile-xmf +audio/mp4 mp4a +audio/mp4a-latm +audio/mpa +audio/mpa-robust +audio/mpeg m2a m3a m4a mp2 mp2a mp3 mpega mpga +audio/mpeg4-generic +audio/mpegurl m3u +audio/ogg oga ogg spx +audio/parityfec +audio/pcma +audio/pcma-wb +audio/pcmu +audio/pcmu-wb +audio/prs.sid sid +audio/qcelp +audio/red +audio/rtp-enc-aescm128 +audio/rtp-midi +audio/rtx +audio/smv +audio/smv-qcp +audio/smv0 +audio/sp-midi +audio/t140c +audio/t38 +audio/telephone-event +audio/tone +audio/ulpfec +audio/vdvi +audio/vmr-wb +audio/vnd.3gpp.iufp +audio/vnd.4sb +audio/vnd.audiokoz +audio/vnd.celp +audio/vnd.cisco.nse +audio/vnd.cmles.radio-events +audio/vnd.cns.anp1 +audio/vnd.cns.inf1 +audio/vnd.digital-winds eol +audio/vnd.dlna.adts +audio/vnd.dolby.heaac.1 +audio/vnd.dolby.heaac.2 +audio/vnd.dolby.mlp +audio/vnd.dolby.mps +audio/vnd.dolby.pl2 +audio/vnd.dolby.pl2x +audio/vnd.dolby.pl2z +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +audio/vnd.everad.plj +audio/vnd.hns.audio +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +audio/vnd.nokia.mobile-xmf +audio/vnd.nortel.vbk +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +audio/vnd.octel.sbc +audio/vnd.qcelp +audio/vnd.rhetorex.32kadpcm +audio/vnd.sealedmedia.softseal.mpeg +audio/vnd.vmx.cvsd +audio/vorbis +audio/vorbis-config +audio/x-aac aac +audio/x-aiff aif aifc aiff +audio/x-gsm gsm +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ra ram rm +audio/x-pn-realaudio-plugin rmp +audio/x-realaudio ra +audio/x-scpls pls +audio/x-sd2 sd2 +audio/x-wav wav +chemical/x-alchemy alc +chemical/x-cache cac cache +chemical/x-cache-csf csf +chemical/x-cactvs-binary cascii cbin ctab +chemical/x-cdx cdx +chemical/x-cerius cer +chemical/x-chem3d c3d +chemical/x-chemdraw chm +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-compass cpa +chemical/x-crossfire bsd +chemical/x-csml csm csml +chemical/x-ctx ctx +chemical/x-cxf cef cxf +chemical/x-embl-dl-nucleotide emb embl +chemical/x-galactic-spc spc +chemical/x-gamess-input gam gamin inp +chemical/x-gaussian-checkpoint fch fchk +chemical/x-gaussian-cube cub +chemical/x-gaussian-input gau gjc gjf +chemical/x-gaussian-log gal +chemical/x-gcg8-sequence gcg +chemical/x-genbank gen +chemical/x-hin hin +chemical/x-isostar ist istr +chemical/x-jcamp-dx dx jdx +chemical/x-kinemage kin +chemical/x-macmolecule mcm +chemical/x-macromodel-input mmd mmod +chemical/x-mdl-molfile mol +chemical/x-mdl-rdfile rd +chemical/x-mdl-rxnfile rxn +chemical/x-mdl-sdfile sd sdf +chemical/x-mdl-tgf tgf +chemical/x-mmcif mcif +chemical/x-mol2 mol2 +chemical/x-molconn-Z b +chemical/x-mopac-graph gpt +chemical/x-mopac-input dat mop mopcrt mpc zmt +chemical/x-mopac-out moo +chemical/x-mopac-vib mvb +chemical/x-ncbi-asn1 asn +chemical/x-ncbi-asn1-ascii ent prt +chemical/x-ncbi-asn1-binary aso val +chemical/x-ncbi-asn1-spec asn +chemical/x-pdb ent pdb +chemical/x-rosdal ros +chemical/x-swissprot sw +chemical/x-vamas-iso14976 vms +chemical/x-vmd vmd +chemical/x-xtel xtel +chemical/x-xyz xyz +image/bmp bmp +image/cgm cgm +image/example +image/fits +image/g3fax g3 +image/gif gif +image/ief ief +image/jp2 +image/jpeg jpe jpeg jpg +image/jpm +image/jpx +image/naplps +image/pcx pcx +image/png png +image/prs.btif btif +image/prs.pti +image/svg+xml svg svgz +image/t38 +image/tiff tif tiff +image/tiff-fx +image/vnd.adobe.photoshop psd +image/vnd.cns.inf2 +image/vnd.djvu djv djvu +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +image/vnd.globalgraphics.pgb +image/vnd.microsoft.icon +image/vnd.mix +image/vnd.ms-modi mdi +image/vnd.net-fpx npx +image/vnd.radiance +image/vnd.sealed.png +image/vnd.sealedmedia.softseal.gif +image/vnd.sealedmedia.softseal.jpg +image/vnd.svf +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/x-cmu-raster ras +image/x-cmx cmx +image/x-coreldraw cdr +image/x-coreldrawpattern pat +image/x-coreldrawtemplate cdt +image/x-corelphotopaint cpt +image/x-freehand fh fh4 fh5 fh7 fhc +image/x-icon ico +image/x-jg art +image/x-jng jng +image/x-ms-bmp bmp +image/x-pcx pcx +image/x-photoshop psd +image/x-pict pct pic +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/cpim +message/delivery-status +message/disposition-notification +message/example +message/external-body +message/global +message/global-delivery-status +message/global-disposition-notification +message/global-headers +message/http +message/imdn+xml +message/news +message/partial +message/rfc822 eml mime +message/s-http +message/sip +message/sipfrag +message/tracking-status +message/vnd.si.simp +model/example +model/iges iges igs +model/mesh mesh msh silo +model/vnd.dwf dwf +model/vnd.flatland.3dml +model/vnd.gdl gdl +model/vnd.gs-gdl +model/vnd.gs.gdl +model/vnd.gtw gtw +model/vnd.moml+xml +model/vnd.mts mts +model/vnd.parasolid.transmit.binary +model/vnd.parasolid.transmit.text +model/vnd.vtu vtu +model/vrml vrml wrl +multipart/alternative +multipart/appledouble +multipart/byteranges +multipart/digest +multipart/encrypted +multipart/example +multipart/form-data +multipart/header-set +multipart/mixed +multipart/parallel +multipart/related +multipart/report +multipart/signed +multipart/voice-message +text/calendar ics icz ifb +text/comma-separated-values csv +text/css css +text/csv csv +text/directory +text/dns +text/ecmascript +text/enriched +text/example +text/h323 323 +text/html htm html shtml +text/iuls uls +text/javascript +text/mathml mml +text/parityfec +text/plain asc conf def diff in list log pot text txt +text/prs.fallenstein.rst +text/prs.lines.tag dsc +text/red +text/rfc822-headers +text/richtext rtx +text/rtf rtf +text/rtp-enc-aescm128 +text/rtx +text/scriptlet sct wsc +text/sgml sgm sgml +text/t140 +text/tab-separated-values tsv +text/texmacs tm ts +text/troff man me ms roff t tr +text/ulpfec +text/uri-list uri uris urls +text/vnd.abc +text/vnd.curl curl +text/vnd.curl.dcurl dcurl +text/vnd.curl.mcurl mcurl +text/vnd.curl.scurl scurl +text/vnd.dmclientscript +text/vnd.esmertec.theme-descriptor +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +text/vnd.iptc.newsml +text/vnd.iptc.nitf +text/vnd.latex-z +text/vnd.motorola.reflex +text/vnd.ms-mediapackage +text/vnd.net2phone.commcenter.command +text/vnd.si.uricatalogue +text/vnd.sun.j2me.app-descriptor jad +text/vnd.trolltech.linguist +text/vnd.wap.si +text/vnd.wap.sl +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-asm asm s +text/x-bibtex bib +text/x-c c cc cpp cxx dic h hh +text/x-c++hdr h++ hh hpp hxx +text/x-c++src c++ cc cpp cxx +text/x-chdr h +text/x-csh csh +text/x-csrc c +text/x-fortran f f77 f90 for +text/x-haskell hs +text/x-java java +text/x-java-source java +text/x-literate-haskell lhs +text/x-moc moc +text/x-pascal p pas +text/x-pcs-gcd gcd +text/x-perl pl pm +text/x-psp psp +text/x-python py +text/x-setext etx +text/x-sh sh +text/x-tcl tcl tk +text/x-tex cls ltx sty tex +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +text/xml +text/xml-external-parsed-entity +video/3gpp 3gp +video/3gpp-tt +video/3gpp2 3g2 +video/bmpeg +video/bt656 +video/celb +video/dl dl +video/dv dif dv +video/example +video/fli fli +video/gl gl +video/h261 h261 +video/h263 h263 +video/h263-1998 +video/h263-2000 +video/h264 h264 +video/jpeg jpgv +video/jpeg2000 +video/jpm jpgm jpm +video/mj2 mj2 mjp2 +video/mp1s +video/mp2p +video/mp2t +video/mp4 mp4 mp4v mpg4 +video/mp4v-es +video/mpeg m1v m2v mpe mpeg mpg +video/mpeg4-generic +video/mpv +video/nv +video/ogg ogv +video/parityfec +video/pointer +video/quicktime mov qt +video/raw +video/rtp-enc-aescm128 +video/rtx +video/smpte292m +video/ulpfec +video/vc1 +video/vnd.cctv +video/vnd.dlna.mpeg-tts +video/vnd.fvt fvt +video/vnd.hns.video +video/vnd.iptvforum.1dparityfec-1010 +video/vnd.iptvforum.1dparityfec-2005 +video/vnd.iptvforum.2dparityfec-1010 +video/vnd.iptvforum.2dparityfec-2005 +video/vnd.iptvforum.ttsavc +video/vnd.iptvforum.ttsmpeg2 +video/vnd.motorola.video +video/vnd.motorola.videop +video/vnd.mpegurl m4u mxu +video/vnd.ms-playready.media.pyv pyv +video/vnd.nokia.interleaved-multimedia +video/vnd.nokia.videovoip +video/vnd.objectvideo +video/vnd.sealed.mpeg1 +video/vnd.sealed.mpeg4 +video/vnd.sealed.swf +video/vnd.sealedmedia.softseal.mov +video/vnd.vivo viv +video/x-f4v f4v +video/x-fli fli +video/x-flv flv +video/x-la-asf lsf lsx +video/x-m4v m4v +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +x-conference/x-cooltalk ice +x-world/x-vrml vrm vrml wrl + + + +## calibre specific mime types + +text/fb2+xml fb2 +text/x-sony-bbeb+xml lrs +application/x-sony-bbeb lrf lrx +application/adobe-page-template+xml xpgt +application/x-font-opentype otf +application/x-font-truetype ttf +application/x-mobipocket-ebook mobi prc azw +application/x-cbz cbz +application/x-cbr cbr +application/x-cb7 cb7 +application/x-koboreader-ebook kobo +image/wmf wmf diff --git a/resources/recipes/abc_au.recipe b/resources/recipes/abc_au.recipe new file mode 100644 index 0000000000..1330f8e4b5 --- /dev/null +++ b/resources/recipes/abc_au.recipe @@ -0,0 +1,54 @@ +__license__ = 'GPL v3' +__copyright__ = '2010, Dean Cording' +''' +abc.net.au/news +''' +import re +from calibre.web.feeds.recipes import BasicNewsRecipe + +class ABCNews(BasicNewsRecipe): + title = 'ABC News' + __author__ = 'Dean Cording' + description = 'News from Australia' + masthead_url = 'http://www.abc.net.au/news/assets/v5/images/common/logo-news.png' + cover_url = 'http://www.abc.net.au/news/assets/v5/images/common/logo-news.png' + + oldest_article = 2 + max_articles_per_feed = 100 + no_stylesheets = False + #delay = 1 + use_embedded_content = False + encoding = 'utf8' + publisher = 'ABC News' + category = 'News, Australia, World' + language = 'en_AU' + publication_type = 'newsportal' + preprocess_regexps = [(re.compile(r'', re.DOTALL), lambda m: '')] + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + ,'linearize_tables': False + } + + keep_only_tags = dict(id='article') + + remove_tags = [dict(attrs={'class':['related', 'tags']}), + dict(id='statepromo') + ] + + remove_attributes = ['width','height'] + + feeds = [ + ('Top Stories', 'http://www.abc.net.au/news/syndicate/topstoriesrss.xml'), + ('Canberra', 'http://www.abc.net.au/news/indexes/idx-act/rss.xml'), + ('Sydney', 'http://www.abc.net.au/news/indexes/sydney/rss.xml'), + ('Melbourne', 'http://www.abc.net.au/news/indexes/melbourne/rss.xml'), + ('Brisbane', 'http://www.abc.net.au/news/indexes/brisbane/rss.xml'), + ('Perth', 'http://www.abc.net.au/news/indexes/perth/rss.xml'), + ('Australia', 'http://www.abc.net.au/news/indexes/idx-australia/rss.xml'), + ('World', 'http://www.abc.net.au/news/indexes/world/rss.xml'), + ('Business', 'http://www.abc.net.au/news/indexes/business/rss.xml'), + ('Science and Technology', 'http://www.abc.net.au/news/tag/science-and-technology/rss.xml'), + ] diff --git a/resources/recipes/business_spectator.recipe b/resources/recipes/business_spectator.recipe new file mode 100644 index 0000000000..ef58424c6c --- /dev/null +++ b/resources/recipes/business_spectator.recipe @@ -0,0 +1,48 @@ +__license__ = 'GPL v3' +__copyright__ = '2010, Dean Cording' +''' +abc.net.au/news +''' +import re +from calibre.web.feeds.recipes import BasicNewsRecipe + +class BusinessSpectator(BasicNewsRecipe): + title = 'Business Spectator' + __author__ = 'Dean Cording' + description = 'Australian Business News & commentary delivered the way you want it.' + masthead_url = 'http://www.businessspectator.com.au/bs.nsf/logo-business-spectator.gif' + cover_url = masthead_url + + oldest_article = 2 + max_articles_per_feed = 100 + no_stylesheets = True + #delay = 1 + use_embedded_content = False + encoding = 'utf8' + publisher = 'Business Spectator' + category = 'News, Australia, Business' + language = 'en_AU' + publication_type = 'newsportal' + preprocess_regexps = [(re.compile(r'', re.DOTALL), lambda m: '')] + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + ,'linearize_tables': False + } + + keep_only_tags = [dict(id='storyHeader'), dict(id='body-html')] + + remove_tags = [dict(attrs={'class':'hql'})] + + remove_attributes = ['width','height','style'] + + feeds = [ + ('Top Stories', 'http://www.businessspectator.com.au/top-stories.rss'), + ('Alan Kohler', 'http://www.businessspectator.com.au/bs.nsf/RSS?readform&type=spectators&cat=Alan%20Kohler'), + ('Robert Gottliebsen', 'http://www.businessspectator.com.au/bs.nsf/RSS?readform&type=spectators&cat=Robert%20Gottliebsen'), + ('Stephen Bartholomeusz', 'http://www.businessspectator.com.au/bs.nsf/RSS?readform&type=spectators&cat=Stephen%20Bartholomeusz'), + ('Daily Dossier', 'http://www.businessspectator.com.au/bs.nsf/RSS?readform&type=kgb&cat=dossier'), + ('Australia', 'http://www.businessspectator.com.au/bs.nsf/RSS?readform&type=region&cat=australia'), + ] diff --git a/resources/recipes/esenja.recipe b/resources/recipes/esenja.recipe new file mode 100644 index 0000000000..b8b94ad66e --- /dev/null +++ b/resources/recipes/esenja.recipe @@ -0,0 +1,87 @@ +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = '2010, matek09, matek09@gmail.com' + +from calibre.web.feeds.news import BasicNewsRecipe +import re + +class Esensja(BasicNewsRecipe): + + title = u'Esensja' + __author__ = 'matek09' + description = 'Monthly magazine' + encoding = 'utf-8' + no_stylesheets = True + language = 'pl' + remove_javascript = True + HREF = '0' + + #keep_only_tags =[] + #keep_only_tags.append(dict(name = 'div', attrs = {'class' : 'article'}) + remove_tags_before = dict(dict(name = 'div', attrs = {'class' : 't-title'})) + remove_tags_after = dict(dict(name = 'img', attrs = {'src' : '../../../2000/01/img/tab_bot.gif'})) + + remove_tags =[] + remove_tags.append(dict(name = 'img', attrs = {'src' : '../../../2000/01/img/tab_top.gif'})) + remove_tags.append(dict(name = 'img', attrs = {'src' : '../../../2000/01/img/tab_bot.gif'})) + remove_tags.append(dict(name = 'div', attrs = {'class' : 't-title2 nextpage'})) + + extra_css = ''' + .t-title {font-size: x-large; font-weight: bold; text-align: left} + .t-author {font-size: x-small; text-align: left} + .t-title2 {font-size: x-small; font-style: italic; text-align: left} + .text {font-size: small; text-align: left} + .annot-ref {font-style: italic; text-align: left} + ''' + + preprocess_regexps = [(re.compile(r'alt="[^"]*"'), + lambda match: '')] + + def parse_index(self): + soup = self.index_to_soup('http://www.esensja.pl/magazyn/') + a = soup.find('a', attrs={'href' : re.compile('.*/index.html')}) + year = a['href'].split('/')[0] + month = a['href'].split('/')[1] + self.HREF = 'http://www.esensja.pl/magazyn/' + year + '/' + month + '/iso/' + soup = self.index_to_soup(self.HREF + '01.html') + self.cover_url = 'http://www.esensja.pl/magazyn/' + year + '/' + month + '/img/ilustr/cover_b.jpg' + feeds = [] + intro = soup.find('div', attrs={'class' : 'n-title'}) + introduction = {'title' : self.tag_to_string(intro.a), + 'url' : self.HREF + intro.a['href'], + 'date' : '', + 'description' : ''} + chapter = 'Wprowadzenie' + subchapter = '' + articles = [] + articles.append(introduction) + for tag in intro.findAllNext(attrs={'class': ['chapter', 'subchapter', 'n-title']}): + if tag.name in 'td': + if len(articles) > 0: + section = chapter + if len(subchapter) > 0: + section += ' - ' + subchapter + feeds.append((section, articles)) + articles = [] + if tag['class'] == 'chapter': + chapter = self.tag_to_string(tag).capitalize() + subchapter = '' + else: + subchapter = self.tag_to_string(tag) + subchapter = self.tag_to_string(tag) + continue + articles.append({'title' : self.tag_to_string(tag.a), 'url' : self.HREF + tag.a['href'], 'date' : '', 'description' : ''}) + + a = self.index_to_soup(self.HREF + tag.a['href']) + i = 1 + while True: + div = a.find('div', attrs={'class' : 't-title2 nextpage'}) + if div is not None: + a = self.index_to_soup(self.HREF + div.a['href']) + articles.append({'title' : self.tag_to_string(tag.a) + ' c. d. ' + str(i), 'url' : self.HREF + div.a['href'], 'date' : '', 'description' : ''}) + i = i + 1 + else: + break + + return feeds diff --git a/resources/recipes/fr_online.recipe b/resources/recipes/fr_online.recipe index e4a817d0d6..b3448c17dc 100644 --- a/resources/recipes/fr_online.recipe +++ b/resources/recipes/fr_online.recipe @@ -1,67 +1,61 @@ -__license__ = 'GPL v3' -__copyright__ = '2009, Justus Bisser ' +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = '2010, Christian Schmitt' + ''' fr-online.de ''' -import re -from calibre.web.feeds.news import BasicNewsRecipe +from calibre.web.feeds.recipes import BasicNewsRecipe -class Spiegel_ger(BasicNewsRecipe): - title = 'Frankfurter Rundschau' - __author__ = 'Justus Bisser' - description = "Dies ist die Online-Ausgabe der Frankfurter Rundschau. Um die abgerufenen individuell einzustellen bearbeiten sie die Liste im erweiterten Modus. Die Feeds findet man auf http://www.fr-online.de/verlagsservice/fr_newsreader/?em_cnt=574255" - publisher = 'Druck- und Verlagshaus Frankfurt am Main GmbH' - category = 'FR Online, Frankfurter Rundschau, Nachrichten, News,Dienste, RSS, RSS, Feedreader, Newsfeed, iGoogle, Netvibes, Widget' - oldest_article = 7 - max_articles_per_feed = 100 - language = 'de' - lang = 'de-DE' - no_stylesheets = True - use_embedded_content = False - #encoding = 'cp1252' +class FROnlineRecipe(BasicNewsRecipe): + title = 'Frankfurter Rundschau' + __author__ = 'maccs' + description = 'Nachrichten aus D und aller Welt' + encoding = 'utf-8' + masthead_url = 'http://www.fr-online.de/image/view/-/1474018/data/823552/-/logo.png' + publisher = 'Druck- und Verlagshaus Frankfurt am Main GmbH' + category = 'news, germany, world' + language = 'de' + publication_type = 'newspaper' + use_embedded_content = False + remove_javascript = True + no_stylesheets = True + oldest_article = 1 # Increase this number if you're interested in older articles + max_articles_per_feed = 50 # Seems a reasonable number to me + extra_css = ''' + body { font-family: "arial", "verdana", "geneva", sans-serif; font-size: 12px; margin: 0px; background-color: #ffffff;} + .imgSubline{background-color: #f4f4f4; font-size: 0.8em;} + .p--heading-1 {font-weight: bold;} + .calibre_navbar {font-size: 0.8em; font-family: "arial", "verdana", "geneva", sans-serif;} + ''' + remove_tags = [dict(name='div', attrs={'id':'Logo'})] + cover_url = 'http://www.fr-online.de/image/view/-/1474018/data/823552/-/logo.png' + cover_margins = (100, 150, '#ffffff') - conversion_options = { - 'comment' : description - , 'tags' : category - , 'publisher' : publisher - , 'language' : lang - } - recursions = 0 - max_articles_per_feed = 100 - #keep_only_tags = [dict(name='div', attrs={'class':'text'})] - #tags_remove = [dict(name='div', attrs={'style':'text-align: left; margin: 4px 0px 0px 4px; width: 200px; float: right;'})] - remove_attributes = ['style'] - feeds = [] - #remove_tags_before = [dict(name='div', attrs={'style':'padding-left: 0px;'})] - #remove_tags_after = [dict(name='div', attrs={'class':'box_head_text'})] + feeds = [] + feeds.append(('Startseite', u'http://www.fr-online.de/home/-/1472778/1472778/-/view/asFeed/-/index.xml')) + feeds.append(('Politik', u'http://www.fr-online.de/politik/-/1472596/1472596/-/view/asFeed/-/index.xml')) + feeds.append(('Meinung', u'http://www.fr-online.de/politik/meinung/-/1472602/1472602/-/view/asFeed/-/index.xml')) + feeds.append(('Wirtschaft', u'http://www.fr-online.de/wirtschaft/-/1472780/1472780/-/view/asFeed/-/index.xml')) + feeds.append(('Sport', u'http://www.fr-online.de/sport/-/1472784/1472784/-/view/asFeed/-/index.xml')) + feeds.append(('Eintracht Frankfurt', u'http://www.fr-online.de/sport/eintracht-frankfurt/-/1473446/1473446/-/view/asFeed/-/index.xml')) + feeds.append(('Kultur und Medien', u'http://www.fr-online.de/kultur/-/1472786/1472786/-/view/asFeed/-/index.xml')) + feeds.append(('Panorama', u'http://www.fr-online.de/panorama/-/1472782/1472782/-/view/asFeed/-/index.xml')) + feeds.append(('Frankfurt', u'http://www.fr-online.de/frankfurt/-/1472798/1472798/-/view/asFeed/-/index.xml')) + feeds.append(('Rhein-Main', u'http://www.fr-online.de/rhein-main/-/1472796/1472796/-/view/asFeed/-/index.xml')) + feeds.append(('Hanau', u'http://www.fr-online.de/rhein-main/hanau/-/1472866/1472866/-/view/asFeed/-/index.xml')) + feeds.append(('Darmstadt', u'http://www.fr-online.de/rhein-main/darmstadt/-/1472858/1472858/-/view/asFeed/-/index.xml')) + feeds.append(('Wiesbaden', u'http://www.fr-online.de/rhein-main/wiesbaden/-/1472860/1472860/-/view/asFeed/-/index.xml')) + feeds.append(('Offenbach', u'http://www.fr-online.de/rhein-main/offenbach/-/1472856/1472856/-/view/asFeed/-/index.xml')) + feeds.append(('Bad Homburg', u'http://www.fr-online.de/rhein-main/bad-homburg/-/1472864/1472864/-/view/asFeed/-/index.xml')) + feeds.append(('Digital', u'http://www.fr-online.de/digital/-/1472406/1472406/-/view/asFeed/-/index.xml')) + feeds.append(('Wissenschaft', u'http://www.fr-online.de/wissenschaft/-/1472788/1472788/-/view/asFeed/-/index.xml')) - # enable for all news - allNews = 0 - if allNews: - feeds = [(u'Frankfurter Rundschau', u'http://www.fr-online.de/rss/sport/index.xml')] - else: - #select the feeds you like - feeds = [(u'Nachrichten', u'http://www.fr-online.de/rss/politik/index.xml')] - feeds.append((u'Kommentare und Analysen', u'http://www.fr-online.de/rss/meinung/index.xml')) - feeds.append((u'Dokumentationen', u'http://www.fr-online.de/rss/dokumentation/index.xml')) - feeds.append((u'Deutschlandtrend', u'http://www.fr-online.de/rss/deutschlandtrend/index.xml')) - feeds.append((u'Wirtschaft', u'http://www.fr-online.de/rss/wirtschaft/index.xml')) - feeds.append((u'Sport', u'http://www.fr-online.de/rss/sport/index.xml')) - feeds.append((u'Feuilleton', u'http://www.fr-online.de/rss/feuilleton/index.xml')) - feeds.append((u'Panorama', u'http://www.fr-online.de/rss/panorama/index.xml')) - feeds.append((u'Rhein Main und Hessen', u'http://www.fr-online.de/rss/hessen/index.xml')) - feeds.append((u'Fitness und Gesundheit', u'http://www.fr-online.de/rss/fit/index.xml')) - feeds.append((u'Multimedia', u'http://www.fr-online.de/rss/multimedia/index.xml')) - feeds.append((u'Wissen und Bildung', u'http://www.fr-online.de/rss/wissen/index.xml')) - def get_article_url(self, article): - url = article.link - regex = re.compile("0C[0-9]{6,8}0A?") + def print_version(self, url): + return url.replace('index.html', 'view/printVersion/-/index.html') - liste = regex.findall(url) - string = liste.pop(0) - string = string[2:len(string)-1] - return "http://www.fr-online.de/_em_cms/_globals/print.php?em_cnt=" + string diff --git a/resources/recipes/histmag.recipe b/resources/recipes/histmag.recipe new file mode 100644 index 0000000000..38956e7995 --- /dev/null +++ b/resources/recipes/histmag.recipe @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = '2010, matek09, matek09@gmail.com' + +from calibre.web.feeds.news import BasicNewsRecipe +import re + +class Histmag(BasicNewsRecipe): + + title = u'Histmag' + __author__ = 'matek09' + description = u"Artykuly historyczne i publicystyczne" + encoding = 'utf-8' + no_stylesheets = True + language = 'pl' + remove_javascript = True + #max_articles_per_feed = 1 + remove_tags_before = dict(dict(name = 'div', attrs = {'id' : 'article'})) + remove_tags_after = dict(dict(name = 'h2', attrs = {'class' : 'komentarze'})) + #keep_only_tags =[] + #keep_only_tags.append(dict(name = 'h2')) + #keep_only_tags.append(dict(name = 'p')) + + remove_tags =[] + remove_tags.append(dict(name = 'p', attrs = {'class' : 'podpis'})) + remove_tags.append(dict(name = 'h2', attrs = {'class' : 'komentarze'})) + remove_tags.append(dict(name = 'img', attrs = {'src' : 'style/buttons/wesprzyjnas-1.jpg'})) + + preprocess_regexps = [(re.compile(r''), lambda match: '

'), + (re.compile(r''), lambda match: '

')] + extra_css = ''' + .left {font-size: x-small} + .right {font-size: x-small} + ''' + + def find_articles(self, soup): + articles = [] + for div in soup.findAll('div', attrs={'class' : 'text'}): + articles.append({ + 'title' : self.tag_to_string(div.h3.a), + 'url' : 'http://www.histmag.org/' + div.h3.a['href'], + 'date' : self.tag_to_string(div.next('p')).split('|')[0], + 'description' : self.tag_to_string(div.next('p', podpis=False)), + }) + return articles + + def parse_index(self): + soup = self.index_to_soup('http://histmag.org/?arc=4&dx=0') + feeds = [] + feeds.append((u"Artykuly historyczne", self.find_articles(soup))) + soup = self.index_to_soup('http://histmag.org/?arc=5&dx=0') + feeds.append((u"Artykuly publicystyczne", self.find_articles(soup))) + soup = self.index_to_soup('http://histmag.org/?arc=1&dx=0') + feeds.append((u"Wydarzenia", self.find_articles(soup))) + + return feeds + + diff --git a/resources/recipes/newsweek_polska.recipe b/resources/recipes/newsweek_polska.recipe index 31dd8ccddd..4227a88026 100644 --- a/resources/recipes/newsweek_polska.recipe +++ b/resources/recipes/newsweek_polska.recipe @@ -1,19 +1,22 @@ #!/usr/bin/env python __license__ = 'GPL v3' -__copyright__ = '2010, Mateusz Kielar, matek09@gmail.com' +__copyright__ = '2010, matek09, matek09@gmail.com' from calibre.web.feeds.news import BasicNewsRecipe class Newsweek(BasicNewsRecipe): - EDITION = 0 + FIND_LAST_FULL_ISSUE = True + EDITION = '0' + EXCLUDE_LOCKED = True + LOCKED_ICO = 'http://www.newsweek.pl/bins/media/static/newsweek/img/ico_locked.gif' title = u'Newsweek Polska' - __author__ = 'Mateusz Kielar' + __author__ = 'matek09' description = 'Weekly magazine' encoding = 'utf-8' no_stylesheets = True - language = 'en' + language = 'pl' remove_javascript = True keep_only_tags =[] @@ -33,34 +36,54 @@ class Newsweek(BasicNewsRecipe): def print_version(self, url): return url.replace("http://www.newsweek.pl/artykuly/wydanie/" + str(self.EDITION), "http://www.newsweek.pl/artykuly") + '/print' + def is_locked(self, a): + if a.findNext('img')['src'] == 'http://www.newsweek.pl/bins/media/static/newsweek/img/ico_locked.gif': + return True + else: + return False + + def is_full(self, issue_soup): + if len(issue_soup.findAll('img', attrs={'src' : 'http://www.newsweek.pl/bins/media/static/newsweek/img/ico_locked.gif'})) > 1: + return False + else: + return True + def find_last_full_issue(self): - page = self.index_to_soup('http://www.newsweek.pl/Frames/IssueCover.aspx') - issue = 'http://www.newsweek.pl/Frames/' + page.find(lambda tag: tag.name == 'span' and not tag.attrs).a['href'] - page = self.index_to_soup(issue) - issue = 'http://www.newsweek.pl/Frames/' + page.find(lambda tag: tag.name == 'span' and not tag.attrs).a['href'] - page = self.index_to_soup(issue) - self.EDITION = page.find('a', attrs={'target' : '_parent'})['href'].replace('/wydania/','') + frame_url = 'http://www.newsweek.pl/Frames/IssueCover.aspx' + while True: + frame_soup = self.index_to_soup(frame_url) + self.EDITION = frame_soup.find('a', attrs={'target' : '_parent'})['href'].replace('/wydania/','') + issue_soup = self.index_to_soup('http://www.newsweek.pl/wydania/' + self.EDITION) + if self.is_full(issue_soup): + break + frame_url = 'http://www.newsweek.pl/Frames/' + frame_soup.find(lambda tag: tag.name == 'span' and not tag.attrs).a['href'] + + def parse_index(self): - self.find_last_full_issue() - soup = self.index_to_soup('http://www.newsweek.pl/wydania/' + str(self.EDITION)) + if self.FIND_LAST_FULL_ISSUE: + self.find_last_full_issue() + soup = self.index_to_soup('http://www.newsweek.pl/wydania/' + self.EDITION) img = soup.find('img', id="ctl00_C1_PaperIsssueView_IssueImage", src=True) self.cover_url = img['src'] feeds = [] parent = soup.find(id='content-left-big') for txt in parent.findAll(attrs={'class':'txt_normal_red strong'}): - section = self.tag_to_string(txt).capitalize() articles = list(self.find_articles(txt)) - feeds.append((section, articles)) + if len(articles) > 0: + section = self.tag_to_string(txt).capitalize() + feeds.append((section, articles)) return feeds def find_articles(self, txt): for a in txt.findAllNext( attrs={'class':['strong','hr']}): if a.name in "div": break + if (not self.FIND_LAST_FULL_ISSUE) & self.EXCLUDE_LOCKED & self.is_locked(a): + continue yield { 'title' : self.tag_to_string(a), - 'url' : 'http://www.newsweek.pl'+a['href'], + 'url' : 'http://www.newsweek.pl' + a['href'], 'date' : '', 'description' : '' } diff --git a/resources/recipes/nin.recipe b/resources/recipes/nin.recipe index 70fd998a09..27942f7d43 100644 --- a/resources/recipes/nin.recipe +++ b/resources/recipes/nin.recipe @@ -8,12 +8,15 @@ www.nin.co.rs import re from calibre import strftime from calibre.web.feeds.news import BasicNewsRecipe +from contextlib import nested, closing +from calibre.ebooks.BeautifulSoup import BeautifulSoup, NavigableString, CData, Tag +from calibre import entity_to_unicode class Nin(BasicNewsRecipe): title = 'NIN online' __author__ = 'Darko Miletic' description = 'Nedeljne Informativne Novine' - publisher = 'NIN d.o.o.' + publisher = 'NIN d.o.o. - Ringier d.o.o.' category = 'news, politics, Serbia' no_stylesheets = True delay = 1 @@ -26,18 +29,29 @@ class Nin(BasicNewsRecipe): use_embedded_content = False language = 'sr' publication_type = 'magazine' - extra_css = ' @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: Verdana, Lucida, sans1, sans-serif} .article_description{font-family: Verdana, Lucida, sans1, sans-serif} .artTitle{font-size: x-large; font-weight: bold; color: #900} .izjava{font-size: x-large; font-weight: bold} .columnhead{font-size: small; font-weight: bold;} img{margin-top:0.5em; margin-bottom: 0.7em} b{margin-top: 1em} ' + extra_css = """ + @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} + body{font-family: Verdana, Lucida, sans1, sans-serif} + .article_description{font-family: Verdana, Lucida, sans1, sans-serif} + .artTitle{font-size: x-large; font-weight: bold; color: #900} + .izjava{font-size: x-large; font-weight: bold} + .columnhead{font-size: small; font-weight: bold;} + img{margin-top:0.5em; margin-bottom: 0.7em; display: block} + b{margin-top: 1em} + """ conversion_options = { - 'comment' : description - , 'tags' : category - , 'publisher' : publisher - , 'language' : language - , 'linearize_tables' : True + 'comment' : description + , 'tags' : category + , 'publisher' : publisher + , 'language' : language } - preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] - remove_attributes = ['height','width'] + preprocess_regexps = [ + (re.compile(r'.*?', re.DOTALL|re.IGNORECASE),lambda match: '') + ,(re.compile(r'.*?', re.DOTALL|re.IGNORECASE),lambda match: '') + ,(re.compile(u'\u0110'), lambda match: u'\u00D0') + ] def get_browser(self): br = BasicNewsRecipe.get_browser() @@ -50,7 +64,10 @@ class Nin(BasicNewsRecipe): return br keep_only_tags =[dict(name='td', attrs={'width':'520'})] + remove_tags_before =dict(name='span', attrs={'class':'izjava'}) remove_tags_after =dict(name='html') + remove_tags = [dict(name=['object','link','iframe','meta','base'])] + remove_attributes=['border','background','height','width','align','valign'] def get_cover_url(self): cover_url = None @@ -63,7 +80,7 @@ class Nin(BasicNewsRecipe): def parse_index(self): articles = [] count = 0 - soup = self.index_to_soup(self.PREFIX) + soup = self.index_to_soup(self.INDEX) for item in soup.findAll('a',attrs={'class':'lmeninavFont'}): count = count +1 if self.test and count > 2: @@ -90,3 +107,45 @@ class Nin(BasicNewsRecipe): articles.append((section,inarts)) return articles + def index_to_soup(self, url_or_raw, raw=False): + if re.match(r'\w+://', url_or_raw): + open_func = getattr(self.browser, 'open_novisit', self.browser.open) + with closing(open_func(url_or_raw)) as f: + _raw = f.read() + if not _raw: + raise RuntimeError('Could not fetch index from %s'%url_or_raw) + else: + _raw = url_or_raw + if raw: + return _raw + if not isinstance(_raw, unicode) and self.encoding: + if callable(self.encoding): + _raw = self.encoding(_raw) + else: + _raw = _raw.decode(self.encoding, 'replace') + massage = list(BeautifulSoup.MARKUP_MASSAGE) + enc = 'cp1252' if callable(self.encoding) or self.encoding is None else self.encoding + massage.append((re.compile(r'&(\S+?);'), lambda match: + entity_to_unicode(match, encoding=enc))) + massage.append((re.compile(r'[\x00-\x08]+'), lambda match: + '')) + return BeautifulSoup(_raw, markupMassage=massage) + + def preprocess_html(self, soup): + for item in soup.findAll(style=True): + del item['style'] + for item in soup.findAll('div'): + if len(item.contents) == 0: + item.extract() + for item in soup.findAll(['td','tr']): + item.name='div' + for item in soup.findAll('img'): + if not item.has_key('alt'): + item['alt'] = 'image' + for tbl in soup.findAll('table'): + img = tbl.find('img') + if img: + img.extract() + tbl.replaceWith(img) + return soup + \ No newline at end of file diff --git a/resources/recipes/polityka.recipe b/resources/recipes/polityka.recipe index ab31e148aa..16ccae6085 100644 --- a/resources/recipes/polityka.recipe +++ b/resources/recipes/polityka.recipe @@ -1,18 +1,18 @@ #!/usr/bin/env python __license__ = 'GPL v3' -__copyright__ = '2010, Mateusz Kielar, matek09@gmail.com' +__copyright__ = '2010, matek09, matek09@gmail.com' from calibre.web.feeds.news import BasicNewsRecipe class Polityka(BasicNewsRecipe): title = u'Polityka' - __author__ = 'Mateusz Kielar' + __author__ = 'matek09' description = 'Weekly magazine. Last archive issue' encoding = 'utf-8' no_stylesheets = True - language = 'en' + language = 'pl' remove_javascript = True remove_tags_before = dict(dict(name = 'h2', attrs = {'class' : 'box_nag'})) @@ -48,7 +48,6 @@ class Polityka(BasicNewsRecipe): for div in box.findAll('div', attrs={'class': 'list_tresc'}): article_page = self.index_to_soup('http://archiwum.polityka.pl' + div.a['href'],) section = self.tag_to_string(article_page.find('h2', attrs = {'class' : 'box_nag'})).split('/')[0].lstrip().rstrip() - print section if not articles.has_key(section): articles[section] = [] articles[section].append( { diff --git a/resources/recipes/wprost.recipe b/resources/recipes/wprost.recipe new file mode 100644 index 0000000000..b317571981 --- /dev/null +++ b/resources/recipes/wprost.recipe @@ -0,0 +1,91 @@ +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = '2010, matek09, matek09@gmail.com' + +from calibre.web.feeds.news import BasicNewsRecipe +import re + +class Wprost(BasicNewsRecipe): + EDITION = 0 + FIND_LAST_FULL_ISSUE = True + EXCLUDE_LOCKED = True + ICO_BLOCKED = 'http://www.wprost.pl/G/icons/ico_blocked.gif' + + title = u'Wprost' + __author__ = 'matek09' + description = 'Weekly magazine' + encoding = 'ISO-8859-2' + no_stylesheets = True + language = 'pl' + remove_javascript = True + + remove_tags_before = dict(dict(name = 'div', attrs = {'id' : 'print-layer'})) + remove_tags_after = dict(dict(name = 'div', attrs = {'id' : 'print-layer'})) + + '''keep_only_tags =[] + keep_only_tags.append(dict(name = 'table', attrs = {'id' : 'title-table'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class' : 'div-header'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class' : 'div-content'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class' : 'def element-autor'}))''' + + preprocess_regexps = [(re.compile(r'style="display: none;"'), lambda match: ''), + (re.compile(r'display: block;'), lambda match: '')] + + + remove_tags =[] + remove_tags.append(dict(name = 'div', attrs = {'class' : 'def element-date'})) + remove_tags.append(dict(name = 'div', attrs = {'class' : 'def silver'})) + remove_tags.append(dict(name = 'div', attrs = {'id' : 'content-main-column-right'})) + + + extra_css = ''' + .div-header {font-size: x-small; font-weight: bold} + ''' +#h2 {font-size: x-large; font-weight: bold} + def is_blocked(self, a): + if a.findNextSibling('img') is None: + return False + else: + return True + + + + def find_last_issue(self): + soup = self.index_to_soup('http://www.wprost.pl/archiwum/') + a = 0 + if self.FIND_LAST_FULL_ISSUE: + ico_blocked = soup.findAll('img', attrs={'src' : self.ICO_BLOCKED}) + a = ico_blocked[-1].findNext('a', attrs={'title' : re.compile('Zobacz spis tre.ci')}) + else: + a = soup.find('a', attrs={'title' : re.compile('Zobacz spis tre.ci')}) + self.EDITION = a['href'].replace('/tygodnik/?I=', '') + self.cover_url = a.img['src'] + + + + def parse_index(self): + self.find_last_issue() + soup = self.index_to_soup('http://www.wprost.pl/tygodnik/?I=' + self.EDITION) + feeds = [] + for main_block in soup.findAll(attrs={'class':'main-block-s3 s3-head head-red3'}): + articles = list(self.find_articles(main_block)) + if len(articles) > 0: + section = self.tag_to_string(main_block) + feeds.append((section, articles)) + return feeds + + def find_articles(self, main_block): + for a in main_block.findAllNext( attrs={'style':['','padding-top: 15px;']}): + if a.name in "td": + break + if self.EXCLUDE_LOCKED & self.is_blocked(a): + continue + yield { + 'title' : self.tag_to_string(a), + 'url' : 'http://www.wprost.pl' + a['href'], + 'date' : '', + 'description' : '' + } + + diff --git a/setup/installer/linux/freeze2.py b/setup/installer/linux/freeze2.py index 0379c0d839..684b33b80d 100644 --- a/setup/installer/linux/freeze2.py +++ b/setup/installer/linux/freeze2.py @@ -340,6 +340,8 @@ class LinuxFreeze(Command): __builtin__.help = _Helper() def set_qt_plugin_path(): + import uuid + uuid.uuid4() # Workaround for libuuid/PyQt conflict from PyQt4.Qt import QCoreApplication paths = list(map(unicode, QCoreApplication.libraryPaths())) paths.insert(0, sys.frozen_path + '/lib/qt_plugins') diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py index 688d7793a4..a8cbe87e3e 100644 --- a/src/calibre/__init__.py +++ b/src/calibre/__init__.py @@ -3,7 +3,7 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import uuid, sys, os, re, logging, time, mimetypes, \ +import uuid, sys, os, re, logging, time, \ __builtin__, warnings, multiprocessing from urllib import getproxies __builtin__.__dict__['dynamic_property'] = lambda(func): func(None) @@ -19,43 +19,18 @@ from calibre.constants import iswindows, isosx, islinux, isfreebsd, isfrozen, \ __appname__, __version__, __author__, \ win32event, win32api, winerror, fcntl, \ filesystem_encoding, plugins, config_dir -from calibre.startup import winutil, winutilerror +from calibre.startup import winutil, winutilerror, guess_type -uuid.uuid4() # Imported before PyQt4 to workaround PyQt4 util-linux conflict on gentoo +if islinux and not getattr(sys, 'frozen', False): + # Imported before PyQt4 to workaround PyQt4 util-linux conflict on gentoo + uuid.uuid4() if False: + # Prevent pyflakes from complaining winutil, winutilerror, __appname__, islinux, __version__ fcntl, win32event, isfrozen, __author__, terminal_controller - winerror, win32api, isfreebsd + winerror, win32api, isfreebsd, guess_type -mimetypes.add_type('application/epub+zip', '.epub') -mimetypes.add_type('text/x-sony-bbeb+xml', '.lrs') -mimetypes.add_type('application/xhtml+xml', '.xhtml') -mimetypes.add_type('image/svg+xml', '.svg') -mimetypes.add_type('text/fb2+xml', '.fb2') -mimetypes.add_type('application/x-sony-bbeb', '.lrf') -mimetypes.add_type('application/x-sony-bbeb', '.lrx') -mimetypes.add_type('application/x-dtbncx+xml', '.ncx') -mimetypes.add_type('application/adobe-page-template+xml', '.xpgt') -mimetypes.add_type('application/x-font-opentype', '.otf') -mimetypes.add_type('application/x-font-truetype', '.ttf') -mimetypes.add_type('application/oebps-package+xml', '.opf') -mimetypes.add_type('application/vnd.palm', '.pdb') -mimetypes.add_type('application/x-mobipocket-ebook', '.mobi') -mimetypes.add_type('application/x-mobipocket-ebook', '.prc') -mimetypes.add_type('application/x-mobipocket-ebook', '.azw') -mimetypes.add_type('application/x-cbz', '.cbz') -mimetypes.add_type('application/x-cbr', '.cbr') -mimetypes.add_type('application/x-koboreader-ebook', '.kobo') -mimetypes.add_type('image/wmf', '.wmf') -mimetypes.add_type('image/jpeg', '.jpg') -mimetypes.add_type('image/jpeg', '.jpeg') -mimetypes.add_type('image/png', '.png') -mimetypes.add_type('image/gif', '.gif') -mimetypes.add_type('image/bmp', '.bmp') -mimetypes.add_type('image/svg+xml', '.svg') - -guess_type = mimetypes.guess_type import cssutils cssutils.log.setLevel(logging.WARN) diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py index 2d944c8519..811acbe55b 100644 --- a/src/calibre/devices/android/driver.py +++ b/src/calibre/devices/android/driver.py @@ -19,7 +19,7 @@ class ANDROID(USBMS): VENDOR_ID = { # HTC - 0x0bb4 : { 0x0c02 : [0x100, 0x0227], 0x0c01 : [0x100, 0x0227], 0x0ff9 + 0x0bb4 : { 0x0c02 : [0x100, 0x0227, 0x0226], 0x0c01 : [0x100, 0x0227], 0x0ff9 : [0x0100, 0x0227, 0x0226], 0x0c87: [0x0100, 0x0227, 0x0226], 0xc92 : [0x100]}, diff --git a/src/calibre/ebooks/fb2/fb2ml.py b/src/calibre/ebooks/fb2/fb2ml.py index 3987ffa1b8..2a9a92612e 100644 --- a/src/calibre/ebooks/fb2/fb2ml.py +++ b/src/calibre/ebooks/fb2/fb2ml.py @@ -91,6 +91,10 @@ class FB2MLizer(object): return u'\n%s' % etree.tostring(etree.fromstring(output), encoding=unicode, pretty_print=True) def clean_text(self, text): + text = re.sub(r'(?miu)
\s*
', '', text) + text = re.sub(r'(?miu)\s+', '', text) + text = re.sub(r'(?miu)
', '
\n\n
', text) + text = re.sub(r'(?miu)

\s*

', '', text) text = re.sub(r'(?miu)\s+

', '

', text) text = re.sub(r'(?miu)

', '

\n\n

', text) @@ -166,11 +170,15 @@ class FB2MLizer(object): def get_text(self): text = [] - for item in self.oeb_book.spine: + for i, item in enumerate(self.oeb_book.spine): + if self.opts.sectionize_chapters_using_file_structure and i is not 0: + text.append('

') self.log.debug('Converting %s to FictionBook2 XML' % item.href) stylizer = Stylizer(item.data, item.href, self.oeb_book, self.opts, self.opts.output_profile) text.append(self.add_page_anchor(item)) text += self.dump_text(item.data.find(XHTML('body')), stylizer, item) + if self.opts.sectionize_chapters_using_file_structure and i is not len(self.oeb_book.spine) - 1: + text.append('
') return ''.join(text) def fb2_body_footer(self): @@ -258,6 +266,10 @@ class FB2MLizer(object): if id_name: fb2_text.append(self.get_anchor(page, id_name)) + if tag == 'h1' and self.opts.h1_to_title or tag == 'h2' and self.opts.h2_to_title or tag == 'h3' and self.opts.h3_to_title: + fb2_text.append('') + tags.append('title') + fb2_tag = TAG_MAP.get(tag, None) if fb2_tag == 'p': if 'p' in tag_stack+tags: diff --git a/src/calibre/ebooks/fb2/output.py b/src/calibre/ebooks/fb2/output.py index d6c7a25a90..bacaf0da91 100644 --- a/src/calibre/ebooks/fb2/output.py +++ b/src/calibre/ebooks/fb2/output.py @@ -25,6 +25,20 @@ class FB2Output(OutputFormatPlugin): 'WARNING: ' \ 'This option is experimental. It can cause conversion ' \ 'to fail. It can also produce unexpected output.')), + OptionRecommendation(name='sectionize_chapters_using_file_structure', + recommended_value=False, level=OptionRecommendation.LOW, + help=_('Try to turn chapters into individual sections using the ' \ + 'internal structure of the ebook. This works well for EPUB ' \ + 'books that have been internally split by chapter.')), + OptionRecommendation(name='h1_to_title', + recommended_value=False, level=OptionRecommendation.LOW, + help=_('Wrap all h1 tags with fb2 title elements.')), + OptionRecommendation(name='h2_to_title', + recommended_value=False, level=OptionRecommendation.LOW, + help=_('Wrap all h2 tags with fb2 title elements.')), + OptionRecommendation(name='h3_to_title', + recommended_value=False, level=OptionRecommendation.LOW, + help=_('Wrap all h3 tags with fb2 title elements.')), ]) def convert(self, oeb_book, output_path, input_plugin, opts, log): diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py index f80d15359c..48ece79f45 100644 --- a/src/calibre/ebooks/mobi/reader.py +++ b/src/calibre/ebooks/mobi/reader.py @@ -504,6 +504,9 @@ class MobiReader(object): 'x-large': '5', 'xx-large': '6', } + def barename(x): + return x.rpartition(':')[-1] + mobi_version = self.book_header.mobi_version for x in root.xpath('//ncx'): x.getparent().remove(x) @@ -512,8 +515,9 @@ class MobiReader(object): for x in tag.attrib: if ':' in x: del tag.attrib[x] - if tag.tag in ('country-region', 'place', 'placetype', 'placename', - 'state', 'city', 'street', 'address', 'content', 'form'): + if tag.tag and barename(tag.tag.lower()) in \ + ('country-region', 'place', 'placetype', 'placename', + 'state', 'city', 'street', 'address', 'content', 'form'): tag.tag = 'div' if tag.tag in ('content', 'form') else 'span' for key in tag.attrib.keys(): tag.attrib.pop(key) diff --git a/src/calibre/ebooks/oeb/transforms/jacket.py b/src/calibre/ebooks/oeb/transforms/jacket.py index e744a14389..84f2dd5d6a 100644 --- a/src/calibre/ebooks/oeb/transforms/jacket.py +++ b/src/calibre/ebooks/oeb/transforms/jacket.py @@ -93,7 +93,7 @@ class Jacket(object): # Render Jacket {{{ -def get_rating(rating, rchar): +def get_rating(rating, rchar, e_rchar): ans = '' try: num = float(rating)/2 @@ -104,12 +104,12 @@ def get_rating(rating, rchar): if num < 1: return ans - ans = rchar * int(num) + ans = ("%s%s") % (rchar * int(num), e_rchar * (5 - int(num))) return ans - def render_jacket(mi, output_profile, - alt_title=_('Unknown'), alt_tags=[], alt_comments=''): + alt_title=_('Unknown'), alt_tags=[], alt_comments='', + alt_publisher=('Unknown publisher')): css = P('jacket/stylesheet.css', data=True).decode('utf-8') try: @@ -124,12 +124,17 @@ def render_jacket(mi, output_profile, if not mi.series: series = '' + try: + publisher = mi.publisher if mi.publisher else alt_publisher + except: + publisher = _('Unknown publisher') + try: pubdate = strftime(u'%Y', mi.pubdate.timetuple()) except: pubdate = '' - rating = get_rating(mi.rating, output_profile.ratings_char) + rating = get_rating(mi.rating, output_profile.ratings_char, output_profile.empty_ratings_char) tags = mi.tags if mi.tags else alt_tags if tags: @@ -154,6 +159,7 @@ def render_jacket(mi, output_profile, css=css, title=title, author=author, + publisher=publisher, pubdate_label=_('Published'), pubdate=pubdate, series_label=_('Series'), series=series, rating_label=_('Rating'), rating=rating, @@ -168,16 +174,16 @@ def render_jacket(mi, output_profile, # Post-process the generated html to strip out empty header items soup = BeautifulSoup(generated_html) if not series: - series_tag = soup.find('tr', attrs={'class':'cbj_series'}) + series_tag = soup.find(attrs={'class':'cbj_series'}) series_tag.extract() if not rating: - rating_tag = soup.find('tr', attrs={'class':'cbj_rating'}) + rating_tag = soup.find(attrs={'class':'cbj_rating'}) rating_tag.extract() if not tags: - tags_tag = soup.find('tr', attrs={'class':'cbj_tags'}) + tags_tag = soup.find(attrs={'class':'cbj_tags'}) tags_tag.extract() if not pubdate: - pubdate_tag = soup.find('tr', attrs={'class':'cbj_pubdate'}) + pubdate_tag = soup.find(attrs={'class':'cbj_pubdate'}) pubdate_tag.extract() if output_profile.short_name != 'kindle': hr_tag = soup.find('hr', attrs={'class':'cbj_kindle_banner_hr'}) diff --git a/src/calibre/ebooks/pml/pmlml.py b/src/calibre/ebooks/pml/pmlml.py index 560a132ce1..ceb7f36124 100644 --- a/src/calibre/ebooks/pml/pmlml.py +++ b/src/calibre/ebooks/pml/pmlml.py @@ -216,7 +216,9 @@ class PMLMLizer(object): w = '\\w' width = elem.get('width') if width: - w += '="%s%%"' % width + if not width.endswith('%'): + width += '%' + w += '="%s"' % width else: w += '="50%"' text.append(w) @@ -252,8 +254,8 @@ class PMLMLizer(object): if href not in self.link_hrefs.keys(): self.link_hrefs[href] = 'calibre_link-%s' % len(self.link_hrefs.keys()) href = '#%s' % self.link_hrefs[href] - text.append('\\q="%s"' % href) - tags.append('q') + text.append('\\q="%s"' % href) + tags.append('q') # Anchor ids id_name = elem.get('id') diff --git a/src/calibre/gui2/actions/catalog.py b/src/calibre/gui2/actions/catalog.py index 77fa4755c1..a253664a1e 100644 --- a/src/calibre/gui2/actions/catalog.py +++ b/src/calibre/gui2/actions/catalog.py @@ -37,7 +37,8 @@ class GenerateCatalogAction(InterfaceAction): dbspec[id] = {'ondevice': db.ondevice(id, index_is_id=True)} # Calling gui2.tools:generate_catalog() - ret = generate_catalog(self.gui, dbspec, ids, self.gui.device_manager) + ret = generate_catalog(self.gui, dbspec, ids, self.gui.device_manager, + db) if ret is None: return diff --git a/src/calibre/gui2/actions/view.py b/src/calibre/gui2/actions/view.py index 5f4f7ce428..0a26653771 100644 --- a/src/calibre/gui2/actions/view.py +++ b/src/calibre/gui2/actions/view.py @@ -12,7 +12,7 @@ from PyQt4.Qt import Qt, QMenu from calibre.constants import isosx from calibre.gui2 import error_dialog, Dispatcher, question_dialog, config, \ - open_local_file + open_local_file, info_dialog from calibre.gui2.dialogs.choose_format import ChooseFormatDialog from calibre.utils.config import prefs from calibre.ptempfile import PersistentTemporaryFile @@ -89,18 +89,34 @@ class ViewAction(InterfaceAction): self._launch_viewer(name, viewer, internal) def view_specific_format(self, triggered): - rows = self.gui.library_view.selectionModel().selectedRows() + rows = list(self.gui.library_view.selectionModel().selectedRows()) if not rows or len(rows) == 0: d = error_dialog(self.gui, _('Cannot view'), _('No book selected')) d.exec_() return - row = rows[0].row() - formats = self.gui.library_view.model().db.formats(row).upper().split(',') - d = ChooseFormatDialog(self.gui, _('Choose the format to view'), formats) + db = self.gui.library_view.model().db + rows = [r.row() for r in rows] + formats = [db.formats(row) for row in rows] + formats = [list(f.upper().split(',')) if f else None for f in formats] + all_fmts = set([]) + for x in formats: + for f in x: all_fmts.add(f) + d = ChooseFormatDialog(self.gui, _('Choose the format to view'), + list(sorted(all_fmts))) if d.exec_() == d.Accepted: - format = d.format() - self.view_format(row, format) + fmt = d.format() + orig_num = len(rows) + rows = [rows[i] for i in range(len(rows)) if formats[i] and fmt in + formats[i]] + if self._view_check(len(rows)): + for row in rows: + self.view_format(row, fmt) + if len(rows) < orig_num: + info_dialog(self.gui, _('Format unavailable'), + _('Not all the selected books were available in' + ' the %s format. You should convert' + ' them first.')%fmt, show=True) def _view_check(self, num, max_=3): if num <= max_: diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index 4ffc8da650..b101d4c44f 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -208,8 +208,9 @@ class BookInfo(QWebView): rows = u'\n'.join([u'<tr><td valign="top"><b>%s:</b></td><td valign="top">%s</td></tr>'%(k,t) for k, t in rows]) comments = data.get(_('Comments'), '') - if comments and comments != u'None': - self.renderer.queue.put((rows, comments)) + if not comments or comments == u'None': + comments = '' + self.renderer.queue.put((rows, comments)) self._show_data(rows, '') diff --git a/src/calibre/gui2/catalog/catalog_bibtex.py b/src/calibre/gui2/catalog/catalog_bibtex.py index 6bbe85833c..5030cf6ec8 100644 --- a/src/calibre/gui2/catalog/catalog_bibtex.py +++ b/src/calibre/gui2/catalog/catalog_bibtex.py @@ -34,7 +34,7 @@ class PluginWidget(QWidget, Ui_Form): self.all_fields.append(x) QListWidgetItem(x, self.db_fields) - def initialize(self, name): #not working properly to update + def initialize(self, name, db): #not working properly to update self.name = name fields = gprefs.get(name+'_db_fields', self.all_fields) # Restore the activated db_fields from last use diff --git a/src/calibre/gui2/catalog/catalog_csv_xml.py b/src/calibre/gui2/catalog/catalog_csv_xml.py index 7ccb5e017e..077d4cbbca 100644 --- a/src/calibre/gui2/catalog/catalog_csv_xml.py +++ b/src/calibre/gui2/catalog/catalog_csv_xml.py @@ -28,7 +28,7 @@ class PluginWidget(QWidget, Ui_Form): self.all_fields.append(x) QListWidgetItem(x, self.db_fields) - def initialize(self, name): + def initialize(self, name, db): self.name = name fields = gprefs.get(name+'_db_fields', self.all_fields) # Restore the activated fields from last use diff --git a/src/calibre/gui2/catalog/catalog_epub_mobi.py b/src/calibre/gui2/catalog/catalog_epub_mobi.py index ea4edb10b9..1ae4efd014 100644 --- a/src/calibre/gui2/catalog/catalog_epub_mobi.py +++ b/src/calibre/gui2/catalog/catalog_epub_mobi.py @@ -7,10 +7,11 @@ __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>' __docformat__ = 'restructuredtext en' -from calibre.gui2 import gprefs -from catalog_epub_mobi_ui import Ui_Form from calibre.ebooks.conversion.config import load_defaults -from PyQt4.Qt import QWidget +from calibre.gui2 import gprefs + +from catalog_epub_mobi_ui import Ui_Form +from PyQt4.Qt import QWidget, QLineEdit class PluginWidget(QWidget,Ui_Form): @@ -23,7 +24,8 @@ class PluginWidget(QWidget,Ui_Form): ('generate_recently_added', True), ('note_tag','*'), ('numbers_as_text', False), - ('read_tag','+'), + ('read_pattern','+'), + ('read_source_field_cb','Tag'), ('wishlist_tag','Wishlist'), ] @@ -38,16 +40,54 @@ class PluginWidget(QWidget,Ui_Form): QWidget.__init__(self, parent) self.setupUi(self) - def initialize(self, name): + def initialize(self, name, db): self.name = name + + # Populate the 'Read book' source fields + all_custom_fields = db.custom_field_keys() + custom_fields = {} + custom_fields['Tag'] = {'field':'tag', 'datatype':u'text'} + for custom_field in all_custom_fields: + field_md = db.metadata_for_field(custom_field) + if field_md['datatype'] in ['bool','composite','datetime','text']: + custom_fields[field_md['name']] = {'field':custom_field, + 'datatype':field_md['datatype']} + + # Add the sorted eligible fields to the combo box + for cf in sorted(custom_fields): + self.read_source_field_cb.addItem(cf) + + self.read_source_fields = custom_fields + self.read_source_field_cb.currentIndexChanged.connect(self.read_source_field_changed) + # Update dialog fields from stored options for opt in self.OPTION_FIELDS: opt_value = gprefs.get(self.name + '_' + opt[0], opt[1]) - if opt[0] in ['numbers_as_text','generate_titles','generate_series','generate_recently_added']: + if opt[0] in [ + 'generate_recently_added', + 'generate_series', + 'generate_titles', + 'numbers_as_text', + ]: getattr(self, opt[0]).setChecked(opt_value) + + # Combo box + elif opt[0] in ['read_source_field_cb']: + # Look for last-stored combo box value + index = self.read_source_field_cb.findText(opt_value) + if index == -1: + index = self.read_source_field_cb.findText('Tag') + self.read_source_field_cb.setCurrentIndex(index) + + # Text fields else: getattr(self, opt[0]).setText(opt_value) + # Init self.read_source_field + cs = unicode(self.read_source_field_cb.currentText()) + read_source_spec = self.read_source_fields[cs] + self.read_source_field = read_source_spec['field'] + def options(self): # Save/return the current options # exclude_genre stores literally @@ -55,16 +95,60 @@ class PluginWidget(QWidget,Ui_Form): # others store as lists opts_dict = {} for opt in self.OPTION_FIELDS: - if opt[0] in ['numbers_as_text','generate_titles','generate_series','generate_recently_added']: + # Save values to gprefs + if opt[0] in [ + 'generate_recently_added', + 'generate_series', + 'generate_titles', + 'numbers_as_text', + ]: opt_value = getattr(self,opt[0]).isChecked() + + # Combo box uses .currentText() + elif opt[0] in ['read_source_field_cb']: + opt_value = unicode(getattr(self, opt[0]).currentText()) + + # text fields use .text() else: opt_value = unicode(getattr(self, opt[0]).text()) gprefs.set(self.name + '_' + opt[0], opt_value) - if opt[0] in ['exclude_genre','numbers_as_text','generate_titles','generate_series','generate_recently_added']: + # Construct opts + if opt[0] in [ + 'exclude_genre', + 'generate_recently_added', + 'generate_series', + 'generate_titles', + 'numbers_as_text', + ]: opts_dict[opt[0]] = opt_value else: opts_dict[opt[0]] = opt_value.split(',') - opts_dict['output_profile'] = [load_defaults('page_setup')['output_profile']] + # Generate read_book_marker + opts_dict['read_book_marker'] = "%s:%s" % (self.read_source_field, self.read_pattern.text()) + + # Append the output profile + opts_dict['output_profile'] = [load_defaults('page_setup')['output_profile']] return opts_dict + + def read_source_field_changed(self,new_index): + ''' + Process changes in the read_source_field combo box + Currently using QLineEdit for all field types + Possible to modify to switch QWidget type + ''' + new_source = str(self.read_source_field_cb.currentText()) + read_source_spec = self.read_source_fields[str(new_source)] + self.read_source_field = read_source_spec['field'] + + # Change pattern input widget to match the source field datatype + if read_source_spec['datatype'] in ['bool','composite','datetime','text']: + if not isinstance(self.read_pattern, QLineEdit): + self.read_spec_hl.removeWidget(self.read_pattern) + dw = QLineEdit(self) + dw.setObjectName('read_pattern') + dw.setToolTip('Pattern for read book') + self.read_pattern = dw + self.read_spec_hl.addWidget(dw) + diff --git a/src/calibre/gui2/catalog/catalog_epub_mobi.ui b/src/calibre/gui2/catalog/catalog_epub_mobi.ui index 3956886c4a..d72566f581 100644 --- a/src/calibre/gui2/catalog/catalog_epub_mobi.ui +++ b/src/calibre/gui2/catalog/catalog_epub_mobi.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>579</width> - <height>411</height> + <width>627</width> + <height>549</height> </rect> </property> <property name="windowTitle"> @@ -28,42 +28,28 @@ </property> </widget> </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>'Mark this book as read' tag:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="read_tag"> - <property name="toolTip"> - <string extracomment="Default: +"/> - </property> - </widget> - </item> - <item row="3" column="0"> + <item row="4" column="0"> <widget class="QLabel" name="label_4"> <property name="text"> <string>Additional note tag prefix:</string> </property> </widget> </item> - <item row="3" column="1"> + <item row="4" column="1"> <widget class="QLineEdit" name="note_tag"> <property name="toolTip"> <string extracomment="Default: *"/> </property> </widget> </item> - <item row="5" column="1"> + <item row="6" column="1"> <widget class="QLineEdit" name="exclude_genre"> <property name="toolTip"> <string extracomment="Default: \[[\w]*\]"/> </property> </widget> </item> - <item row="5" column="0"> + <item row="6" column="0"> <widget class="QLabel" name="label"> <property name="text"> <string>Regex pattern describing tags to exclude as genres:</string> @@ -76,7 +62,7 @@ </property> </widget> </item> - <item row="6" column="1"> + <item row="7" column="1"> <widget class="QLabel" name="label_6"> <property name="text"> <string>Regex tips: @@ -88,7 +74,7 @@ </property> </widget> </item> - <item row="7" column="0"> + <item row="8" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -101,44 +87,84 @@ </property> </spacer> </item> - <item row="9" column="0"> + <item row="10" column="0"> <widget class="QCheckBox" name="generate_titles"> <property name="text"> <string>Include 'Titles' Section</string> </property> </widget> </item> - <item row="11" column="0"> + <item row="12" column="0"> <widget class="QCheckBox" name="generate_recently_added"> <property name="text"> <string>Include 'Recently Added' Section</string> </property> </widget> </item> - <item row="12" column="0"> + <item row="13" column="0"> <widget class="QCheckBox" name="numbers_as_text"> <property name="text"> <string>Sort numbers as text</string> </property> </widget> </item> - <item row="10" column="0"> + <item row="11" column="0"> <widget class="QCheckBox" name="generate_series"> <property name="text"> <string>Include 'Series' Section</string> </property> </widget> </item> - <item row="2" column="1"> + <item row="3" column="1"> <widget class="QLineEdit" name="wishlist_tag"/> </item> - <item row="2" column="0"> + <item row="3" column="0"> <widget class="QLabel" name="label_5"> <property name="text"> <string>Wishlist tag:</string> </property> </widget> </item> + <item row="2" column="1"> + <layout class="QHBoxLayout" name="read_spec_hl"> + <property name="sizeConstraint"> + <enum>QLayout::SetMinimumSize</enum> + </property> + <item> + <widget class="QComboBox" name="read_source_field_cb"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Source column for read book</string> + </property> + <property name="statusTip"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="read_pattern"> + <property name="toolTip"> + <string>Pattern for read book</string> + </property> + <property name="statusTip"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Books marked as read:</string> + </property> + </widget> + </item> </layout> </widget> <resources/> diff --git a/src/calibre/gui2/convert/fb2_output.py b/src/calibre/gui2/convert/fb2_output.py index a3cbe0e647..5d927146a5 100644 --- a/src/calibre/gui2/convert/fb2_output.py +++ b/src/calibre/gui2/convert/fb2_output.py @@ -17,6 +17,8 @@ class PluginWidget(Widget, Ui_Form): ICON = I('mimetypes/fb2.png') def __init__(self, parent, get_option, get_help, db=None, book_id=None): - Widget.__init__(self, parent, ['inline_toc', 'sectionize_chapters']) + Widget.__init__(self, parent, ['inline_toc', 'sectionize_chapters', + 'sectionize_chapters_using_file_structure', 'h1_to_title', + 'h2_to_title', 'h3_to_title']) self.db, self.book_id = db, book_id self.initialize_options(get_option, get_help, db, book_id) diff --git a/src/calibre/gui2/convert/fb2_output.ui b/src/calibre/gui2/convert/fb2_output.ui index a43a8b72ea..a90ecd615e 100644 --- a/src/calibre/gui2/convert/fb2_output.ui +++ b/src/calibre/gui2/convert/fb2_output.ui @@ -14,7 +14,7 @@ <string>Form</string> </property> <layout class="QGridLayout" name="gridLayout"> - <item row="2" column="0"> + <item row="6" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -41,6 +41,34 @@ </property> </widget> </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="opt_sectionize_chapters_using_file_structure"> + <property name="text"> + <string>Sectionize Chapters using file structure</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QCheckBox" name="opt_h1_to_title"> + <property name="text"> + <string>Wrap h1 tags with <title> elements</string> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QCheckBox" name="opt_h2_to_title"> + <property name="text"> + <string>Wrap h2 tags with <title> elements</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QCheckBox" name="opt_h3_to_title"> + <property name="text"> + <string>Wrap h3 tags with <title> elements</string> + </property> + </widget> + </item> </layout> </widget> <resources/> diff --git a/src/calibre/gui2/dialogs/catalog.py b/src/calibre/gui2/dialogs/catalog.py index f8e0f83746..7bb288ed20 100644 --- a/src/calibre/gui2/dialogs/catalog.py +++ b/src/calibre/gui2/dialogs/catalog.py @@ -19,7 +19,7 @@ from calibre.customize.ui import catalog_plugins class Catalog(QDialog, Ui_Dialog): ''' Catalog Dialog builder''' - def __init__(self, parent, dbspec, ids): + def __init__(self, parent, dbspec, ids, db): import re, cStringIO from calibre import prints as info from PyQt4.uic import compileUi @@ -51,7 +51,7 @@ class Catalog(QDialog, Ui_Dialog): catalog_widget = __import__('calibre.gui2.catalog.'+name, fromlist=[1]) pw = catalog_widget.PluginWidget() - pw.initialize(name) + pw.initialize(name, db) pw.ICON = I('forward.png') self.widgets.append(pw) [self.fmts.append([file_type.upper(), pw.sync_enabled,pw]) for file_type in plugin.file_types] diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index 2c40665187..ab5b1e06e9 100644 --- a/src/calibre/gui2/search_box.py +++ b/src/calibre/gui2/search_box.py @@ -29,10 +29,6 @@ class SearchLineEdit(QLineEdit): QLineEdit.mouseReleaseEvent(self, event) QLineEdit.selectAll(self) - def focusInEvent(self, event): - QLineEdit.focusInEvent(self, event) - QLineEdit.selectAll(self) - def dropEvent(self, ev): self.parent().normalize_state() return QLineEdit.dropEvent(self, ev) @@ -256,7 +252,11 @@ class SavedSearchBox(QComboBox): def initialize(self, _search_box, colorize=False, help_text=_('Search')): self.search_box = _search_box - self.line_edit.setPlaceholderText(help_text) + try: + self.line_edit.setPlaceholderText(help_text) + except: + # Using Qt < 4.7 + pass self.colorize = colorize self.clear() @@ -350,14 +350,17 @@ class SearchBoxMixin(object): shortcuts = QKeySequence.keyBindings(QKeySequence.Find) shortcuts = list(shortcuts) + [QKeySequence('/'), QKeySequence('Alt+S')] self.action_focus_search.setShortcuts(shortcuts) - self.action_focus_search.triggered.connect(lambda x: - self.search.setFocus(Qt.OtherFocusReason)) + self.action_focus_search.triggered.connect(self.focus_search_box) self.addAction(self.action_focus_search) self.search.setStatusTip(re.sub(r'<\w+>', ' ', unicode(self.search.toolTip()))) self.advanced_search_button.setStatusTip(self.advanced_search_button.toolTip()) self.clear_button.setStatusTip(self.clear_button.toolTip()) + def focus_search_box(self, *args): + self.search.setFocus(Qt.OtherFocusReason) + self.search.lineEdit().selectAll() + def search_box_cleared(self): self.tags_view.clear() self.saved_search.clear() diff --git a/src/calibre/gui2/tools.py b/src/calibre/gui2/tools.py index 2919493d12..fc84e88d09 100644 --- a/src/calibre/gui2/tools.py +++ b/src/calibre/gui2/tools.py @@ -245,11 +245,11 @@ def fetch_scheduled_recipe(arg): return 'gui_convert', args, _('Fetch news from ')+arg['title'], fmt.upper(), [pt] -def generate_catalog(parent, dbspec, ids, device_manager): +def generate_catalog(parent, dbspec, ids, device_manager, db): from calibre.gui2.dialogs.catalog import Catalog # Build the Catalog dialog in gui2.dialogs.catalog - d = Catalog(parent, dbspec, ids) + d = Catalog(parent, dbspec, ids, db) if d.exec_() != d.Accepted: return None diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py index 33525f6540..eed258a6b0 100644 --- a/src/calibre/library/catalog.py +++ b/src/calibre/library/catalog.py @@ -606,12 +606,12 @@ class EPUB_MOBI(CatalogPlugin): help=_("Specifies the output profile. In some cases, an output profile is required to optimize the catalog for the device. For example, 'kindle' or 'kindle_dx' creates a structured Table of Contents with Sections and Articles.\n" "Default: '%default'\n" "Applies to: ePub, MOBI output formats")), - Option('--read-tag', - default='+', - dest='read_tag', + Option('--read-book-marker', + default='tag:+', + dest='read_book_marker', action = None, - help=_("Tag indicating book has been read.\n" "Default: '%default'\n" - "Applies to: ePub, MOBI output formats")), + help=_("field:pattern indicating book has been read.\n" "Default: '%default'\n" + "Applies to ePub, MOBI output formats")), Option('--wishlist-tag', default='Wishlist', dest='wishlist_tag', @@ -898,6 +898,8 @@ class EPUB_MOBI(CatalogPlugin): self.__plugin = plugin self.__progressInt = 0.0 self.__progressString = '' + f, _, p = opts.read_book_marker.partition(':') + self.__read_book_marker = {'field':f, 'pattern':p} self.__reporter = report_progress self.__stylesheet = stylesheet self.__thumbs = None @@ -936,7 +938,6 @@ class EPUB_MOBI(CatalogPlugin): if self.opts.generate_series: self.__totalSteps += 2 - # Accessors if True: ''' @@ -1210,7 +1211,7 @@ class EPUB_MOBI(CatalogPlugin): def READING_SYMBOL(self): def fget(self): return '<span style="color:black">▷</span>' if self.generateForKindle else \ - '<span style="color:white">%s</span>' % self.opts.read_tag + '<span style="color:white">+</span>' return property(fget=fget) @dynamic_property def READ_SYMBOL(self): @@ -1401,8 +1402,7 @@ class EPUB_MOBI(CatalogPlugin): if record['cover']: this_title['cover'] = re.sub('&', '&', record['cover']) - # This may be updated in self.processSpecialTags() - this_title['read'] = False + this_title['read'] = self.discoverReadStatus(record) if record['tags']: this_title['tags'] = self.processSpecialTags(record['tags'], @@ -2675,13 +2675,7 @@ class EPUB_MOBI(CatalogPlugin): pBookTag = Tag(soup, "p") ptc = 0 - # book with read/reading/unread symbol - for tag in book['tags']: - if tag == self.opts.read_tag: - book['read'] = True - break - else: - book['read'] = False + book['read'] = self.discoverReadStatus(book) # book with read|reading|unread symbol or wishlist item if self.opts.wishlist_tag in book.get('tags', []): @@ -2689,7 +2683,7 @@ class EPUB_MOBI(CatalogPlugin): pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL)) ptc += 1 else: - if book['read']: + if book.get('read', False): # check mark pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL)) pBookTag['class'] = "read_book" @@ -4027,6 +4021,34 @@ class EPUB_MOBI(CatalogPlugin): if not os.path.isdir(images_path): os.makedirs(images_path) + def discoverReadStatus(self, record): + ''' + Given a field:pattern spec, discover if this book marked as read + + if field == tag, scan tags for pattern + if custom field, try regex match for pattern + This allows maximum flexibility with fields of type + datatype bool: #field_name:True + datatype text: #field_name:<string> + datatype datetime: #field_name:.* + + ''' + # Legacy handling of special 'read' tag + field = self.__read_book_marker['field'] + pat = self.__read_book_marker['pattern'] + if field == 'tag' and pat in record['tags']: + return True + + field_contents = self.__db.get_field(record['id'], + field, + index_is_id=True) + if field_contents: + if re.search(pat, unicode(field_contents), + re.IGNORECASE) is not None: + return True + + return False + def filterDbTags(self, tags): # Remove the special marker tags from the database's tag list, # return sorted list of normalized genre tags @@ -4519,7 +4541,6 @@ class EPUB_MOBI(CatalogPlugin): markerTags = [] markerTags.extend(self.opts.exclude_tags.split(',')) markerTags.extend(self.opts.note_tag.split(',')) - markerTags.extend(self.opts.read_tag.split(',')) return markerTags def letter_or_symbol(self,char): @@ -4629,6 +4650,7 @@ class EPUB_MOBI(CatalogPlugin): if open_pTag: result.insert(rtc, pTag) + rtc += 1 paras = result.findAll('p') for p in paras: @@ -4647,10 +4669,12 @@ class EPUB_MOBI(CatalogPlugin): tag = self.convertHTMLEntities(tag) if tag.startswith(opts.note_tag): this_title['notes'] = tag[len(self.opts.note_tag):] - elif tag == opts.read_tag: - this_title['read'] = True elif re.search(opts.exclude_genre, tag): continue + elif self.__read_book_marker['field'] == 'tag' and \ + tag == self.__read_book_marker['pattern']: + # remove 'read' tag + continue else: tag_list.append(tag) return tag_list @@ -4759,7 +4783,7 @@ class EPUB_MOBI(CatalogPlugin): for key in keys: if key in ['catalog_title','authorClip','connected_kindle','descriptionClip', 'exclude_genre','exclude_tags','note_tag','numbers_as_text', - 'output_profile','read_tag', + 'output_profile','read_book_marker', 'search_text','sort_by','sort_descriptions_by_author','sync', 'wishlist_tag']: build_log.append(" %s: %s" % (key, opts_dict[key])) diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py index 7d3fb329e0..747cd59abb 100644 --- a/src/calibre/library/cli.py +++ b/src/calibre/library/cli.py @@ -640,7 +640,7 @@ def catalog_option_parser(args): log = Log() parser = get_parser(_( ''' - %prog catalog /path/to/destination.(csv|epub|mobi|xml ...) [options] + %prog catalog /path/to/destination.(CSV|EPUB|MOBI|XML ...) [options] Export a catalog in format specified by path/to/destination extension. Options control how entries are displayed in the generated catalog ouput. diff --git a/src/calibre/startup.py b/src/calibre/startup.py index e74660d0bc..9c9c7651b7 100644 --- a/src/calibre/startup.py +++ b/src/calibre/startup.py @@ -199,6 +199,11 @@ if not _run_once: __builtin__.__dict__['lopen'] = local_open + + import mimetypes + mimetypes.init([P('mime.types')]) + guess_type = mimetypes.guess_type + def test_lopen(): from calibre.ptempfile import TemporaryDirectory from calibre import CurrentDir
{series_label}:{series}
{title}
{series}
{pubdate_label}:{pubdate}
{author}
{publisher} ({pubdate})
{rating_label}: {rating}