2011-06-16 05:59:20 +00:00
#!/usr/bin/env python
from __future__ import with_statement
from calibre . customize import FileTypePlugin
from calibre . gui2 import is_ok_to_use_qt
2012-03-06 18:24:28 +00:00
from calibre . utils . config import config_dir
from calibre . constants import iswindows , isosx
2011-06-16 05:59:20 +00:00
# from calibre.ptempfile import PersistentTemporaryDirectory
import sys
import os
import re
2012-03-06 18:24:28 +00:00
from zipfile import ZipFile
2011-06-16 05:59:20 +00:00
class K4DeDRM ( FileTypePlugin ) :
name = ' K4PC, K4Mac, Kindle Mobi and Topaz DeDRM ' # Name of the plugin
2011-09-05 06:17:36 +00:00
description = ' Removes DRM from Mobipocket, Kindle/Mobi, Kindle/Topaz and Kindle/Print Replica files. Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc. '
2011-06-16 05:59:20 +00:00
supported_platforms = [ ' osx ' , ' windows ' , ' linux ' ] # Platforms this plugin will run on
author = ' DiapDealer, SomeUpdates ' # The author of this plugin
2012-03-06 18:24:28 +00:00
version = ( 0 , 4 , 1 ) # The version number of this plugin
2011-09-05 06:17:36 +00:00
file_types = set ( [ ' prc ' , ' mobi ' , ' azw ' , ' azw1 ' , ' azw4 ' , ' tpz ' ] ) # The file types that this plugin will be applied to
2011-06-16 05:59:20 +00:00
on_import = True # Run this plugin during the import
priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm
minimum_calibre_version = ( 0 , 7 , 55 )
2012-03-06 18:24:28 +00:00
def initialize ( self ) :
"""
Dynamic modules can ' t be imported/loaded from a zipfile... so this routine
runs whenever the plugin gets initialized . This will extract the appropriate
library for the target OS and copy it to the ' alfcrypto ' subdirectory of
calibre ' s configuration directory. That ' alfcrypto ' directory is then
inserted into the syspath ( as the very first entry ) in the run function
so the CDLL stuff will work in the alfcrypto . py script .
"""
if iswindows :
names = [ ' alfcrypto.dll ' , ' alfcrypto64.dll ' ]
elif isosx :
names = [ ' libalfcrypto.dylib ' ]
else :
names = [ ' libalfcrypto32.so ' , ' libalfcrypto64.so ' ]
lib_dict = self . load_resources ( names )
self . alfdir = os . path . join ( config_dir , ' alfcrypto ' )
if not os . path . exists ( self . alfdir ) :
os . mkdir ( self . alfdir )
for entry , data in lib_dict . items ( ) :
file_path = os . path . join ( self . alfdir , entry )
with open ( file_path , ' wb ' ) as f :
f . write ( data )
2011-06-16 05:59:20 +00:00
def run ( self , path_to_ebook ) :
2012-03-06 18:24:28 +00:00
# add the alfcrypto directory to sys.path so alfcrypto.py
# will be able to locate the custom lib(s) for CDLL import.
sys . path . insert ( 0 , self . alfdir )
# Had to move these imports here so the custom libs can be
# extracted to the appropriate places beforehand these routines
# look for them.
from calibre_plugins . k4mobidedrm import kgenpids
from calibre_plugins . k4mobidedrm import topazextract
from calibre_plugins . k4mobidedrm import mobidedrm
2011-09-05 06:17:36 +00:00
plug_ver = ' . ' . join ( str ( self . version ) . strip ( ' () ' ) . replace ( ' ' , ' ' ) . split ( ' , ' ) )
2011-06-16 05:59:20 +00:00
k4 = True
if sys . platform . startswith ( ' linux ' ) :
k4 = False
pids = [ ]
serials = [ ]
kInfoFiles = [ ]
# Get supplied list of PIDs to try from plugin customization.
customvalues = self . site_customization . split ( ' , ' )
for customvalue in customvalues :
customvalue = str ( customvalue )
customvalue = customvalue . strip ( )
if len ( customvalue ) == 10 or len ( customvalue ) == 8 :
pids . append ( customvalue )
else :
if len ( customvalue ) == 16 and customvalue [ 0 ] == ' B ' :
serials . append ( customvalue )
else :
print " %s is not a valid Kindle serial number or PID. " % str ( customvalue )
2012-03-06 18:24:28 +00:00
2011-06-16 05:59:20 +00:00
# Load any kindle info files (*.info) included Calibre's config directory.
try :
# Find Calibre's configuration directory.
confpath = os . path . split ( os . path . split ( self . plugin_path ) [ 0 ] ) [ 0 ]
2011-09-05 06:17:36 +00:00
print ' K4MobiDeDRM v %s : Calibre configuration directory = %s ' % ( plug_ver , confpath )
2011-06-16 05:59:20 +00:00
files = os . listdir ( confpath )
filefilter = re . compile ( " \ .info$| \ .kinf$ " , re . IGNORECASE )
files = filter ( filefilter . search , files )
if files :
for filename in files :
fpath = os . path . join ( confpath , filename )
kInfoFiles . append ( fpath )
2011-09-05 06:17:36 +00:00
print ' K4MobiDeDRM v %s : Kindle info/kinf file %s found in config folder. ' % ( plug_ver , filename )
2011-06-16 05:59:20 +00:00
except IOError :
2011-09-05 06:17:36 +00:00
print ' K4MobiDeDRM v %s : Error reading kindle info/kinf files from config directory. ' % plug_ver
2011-06-16 05:59:20 +00:00
pass
mobi = True
magic3 = file ( path_to_ebook , ' rb ' ) . read ( 3 )
if magic3 == ' TPZ ' :
mobi = False
bookname = os . path . splitext ( os . path . basename ( path_to_ebook ) ) [ 0 ]
if mobi :
mb = mobidedrm . MobiBook ( path_to_ebook )
else :
mb = topazextract . TopazBook ( path_to_ebook )
title = mb . getBookTitle ( )
md1 , md2 = mb . getPIDMetaInfo ( )
2012-03-06 18:24:28 +00:00
pidlst = kgenpids . getPidList ( md1 , md2 , k4 , pids , serials , kInfoFiles )
2011-06-16 05:59:20 +00:00
try :
mb . processBook ( pidlst )
2011-09-05 06:17:36 +00:00
except mobidedrm . DrmException , e :
2011-06-16 05:59:20 +00:00
#if you reached here then no luck raise and exception
if is_ok_to_use_qt ( ) :
from PyQt4 . Qt import QMessageBox
2011-09-05 06:17:36 +00:00
d = QMessageBox ( QMessageBox . Warning , " K4MobiDeDRM v %s Plugin " % plug_ver , " Error: " + str ( e ) + " ... %s \n " % path_to_ebook )
2011-06-16 05:59:20 +00:00
d . show ( )
d . raise_ ( )
d . exec_ ( )
2011-09-05 06:17:36 +00:00
raise Exception ( " K4MobiDeDRM plugin v %s Error: %s " % ( plug_ver , str ( e ) ) )
except topazextract . TpzDRMError , e :
2011-06-16 05:59:20 +00:00
#if you reached here then no luck raise and exception
if is_ok_to_use_qt ( ) :
2012-03-06 18:24:28 +00:00
from PyQt4 . Qt import QMessageBox
d = QMessageBox ( QMessageBox . Warning , " K4MobiDeDRM v %s Plugin " % plug_ver , " Error: " + str ( e ) + " ... %s \n " % path_to_ebook )
d . show ( )
d . raise_ ( )
d . exec_ ( )
2011-09-05 06:17:36 +00:00
raise Exception ( " K4MobiDeDRM plugin v %s Error: %s " % ( plug_ver , str ( e ) ) )
2011-06-16 05:59:20 +00:00
print " Success! "
if mobi :
2011-09-05 06:17:36 +00:00
if mb . getPrintReplica ( ) :
of = self . temporary_file ( bookname + ' .azw4 ' )
print ' K4MobiDeDRM v %s : Print Replica format detected. ' % plug_ver
else :
of = self . temporary_file ( bookname + ' .mobi ' )
2011-06-16 05:59:20 +00:00
mb . getMobiFile ( of . name )
2011-09-05 06:17:36 +00:00
else :
2011-06-16 05:59:20 +00:00
of = self . temporary_file ( bookname + ' .htmlz ' )
mb . getHTMLZip ( of . name )
mb . cleanup ( )
return of . name
def customization_help ( self , gui = False ) :
return ' Enter 10 character PIDs and/or Kindle serial numbers, use a comma (no spaces) to separate each PID or SerialNumber from the next. '
2012-03-06 18:24:28 +00:00
def load_resources ( self , names ) :
ans = { }
with ZipFile ( self . plugin_path , ' r ' ) as zf :
for candidate in zf . namelist ( ) :
if candidate in names :
ans [ candidate ] = zf . read ( candidate )
return ans