mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Plugin to read metadata from RAR files
This commit is contained in:
parent
3363f70602
commit
6056fa4da1
@ -189,6 +189,17 @@ class ZipMetadataReader(MetadataReaderPlugin):
|
|||||||
from calibre.ebooks.metadata.zip import get_metadata
|
from calibre.ebooks.metadata.zip import get_metadata
|
||||||
return get_metadata(stream)
|
return get_metadata(stream)
|
||||||
|
|
||||||
|
class RARMetadataReader(MetadataReaderPlugin):
|
||||||
|
|
||||||
|
name = 'Read RAR metadata'
|
||||||
|
file_types = set(['rar'])
|
||||||
|
description = _('Read metadata from ebooks in RAR archives')
|
||||||
|
|
||||||
|
def get_metadata(self, stream, ftype):
|
||||||
|
from calibre.ebooks.metadata.rar import get_metadata
|
||||||
|
return get_metadata(stream)
|
||||||
|
|
||||||
|
|
||||||
class EPUBMetadataWriter(MetadataWriterPlugin):
|
class EPUBMetadataWriter(MetadataWriterPlugin):
|
||||||
|
|
||||||
name = 'Set EPUB metadata'
|
name = 'Set EPUB metadata'
|
||||||
|
36
src/calibre/ebooks/metadata/rar.py
Normal file
36
src/calibre/ebooks/metadata/rar.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2009, Kovid Goyal kovid@kovidgoyal.net'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
'''
|
||||||
|
Read metadata from RAR archives
|
||||||
|
'''
|
||||||
|
|
||||||
|
import os
|
||||||
|
from cStringIO import StringIO
|
||||||
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
|
from calibre.libunrar import extract_member, names
|
||||||
|
|
||||||
|
def get_metadata(stream):
|
||||||
|
path = getattr(stream, 'name', False)
|
||||||
|
if not path:
|
||||||
|
pt = PersistentTemporaryFile('_rar-meta.rar')
|
||||||
|
pt.write(stream.read())
|
||||||
|
pt.close()
|
||||||
|
path = pt.name
|
||||||
|
path = os.path.abspath(path)
|
||||||
|
file_names = list(names(path))
|
||||||
|
for f in file_names:
|
||||||
|
stream_type = os.path.splitext(f)[1].lower()
|
||||||
|
if stream_type:
|
||||||
|
stream_type = stream_type[1:]
|
||||||
|
if stream_type in ('lit', 'opf', 'prc', 'mobi', 'fb2', 'epub',
|
||||||
|
'rb', 'imp', 'pdf', 'lrf'):
|
||||||
|
data = extract_member(path, match=None, name=f)[1]
|
||||||
|
stream = StringIO(data)
|
||||||
|
from calibre.ebooks.metadata.meta import get_metadata
|
||||||
|
return get_metadata(stream, stream_type)
|
||||||
|
raise ValueError('No ebook found in RAR archive')
|
||||||
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>800</width>
|
<width>755</width>
|
||||||
<height>581</height>
|
<height>557</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle" >
|
<property name="windowTitle" >
|
||||||
@ -328,8 +328,8 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="page" >
|
<widget class="QWidget" name="page" >
|
||||||
<layout class="QGridLayout" name="gridLayout_3" >
|
<layout class="QVBoxLayout" name="verticalLayout_4" >
|
||||||
<item row="0" column="0" >
|
<item>
|
||||||
<widget class="QCheckBox" name="roman_numerals" >
|
<widget class="QCheckBox" name="roman_numerals" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>Use &Roman numerals for series number</string>
|
<string>Use &Roman numerals for series number</string>
|
||||||
@ -339,12 +339,47 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0" >
|
<item>
|
||||||
|
<widget class="QCheckBox" name="systray_icon" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Enable system &tray icon (needs restart)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="systray_notifications" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Show &notifications in system tray</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="separate_cover_flow" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Show cover &browser in a separate window (needs restart)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="sync_news" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Automatically send downloaded &news to ebook reader</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="delete_news" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>&Delete news from library when it is sent to reader</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout" >
|
<layout class="QHBoxLayout" name="horizontalLayout" >
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_6" >
|
<widget class="QLabel" name="label_6" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>&Number of covers to show in browse mode (after restart):</string>
|
<string>&Number of covers to show in browse mode (needs restart):</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy" >
|
<property name="buddy" >
|
||||||
<cstring>cover_browse</cstring>
|
<cstring>cover_browse</cstring>
|
||||||
@ -356,7 +391,7 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="0" >
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox_2" >
|
<widget class="QGroupBox" name="groupBox_2" >
|
||||||
<property name="title" >
|
<property name="title" >
|
||||||
<string>Toolbar</string>
|
<string>Toolbar</string>
|
||||||
@ -402,14 +437,22 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
<zorder>toolbar_button_size</zorder>
|
||||||
|
<zorder>label_4</zorder>
|
||||||
|
<zorder>show_toolbar_text</zorder>
|
||||||
|
<zorder>columns</zorder>
|
||||||
|
<zorder></zorder>
|
||||||
|
<zorder>groupBox_3</zorder>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="0" >
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_7" >
|
||||||
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox" >
|
<widget class="QGroupBox" name="groupBox" >
|
||||||
<property name="title" >
|
<property name="title" >
|
||||||
<string>Select visible &columns in library view</string>
|
<string>Select visible &columns in library view</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4" >
|
<layout class="QVBoxLayout" name="verticalLayout_7" >
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3" >
|
<layout class="QHBoxLayout" name="horizontalLayout_3" >
|
||||||
<item>
|
<item>
|
||||||
@ -463,10 +506,14 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
</layout>
|
||||||
|
<zorder>columns</zorder>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox_3" >
|
<widget class="QGroupBox" name="groupBox_3" >
|
||||||
<property name="title" >
|
<property name="title" >
|
||||||
<string>Use internal &viewer for the following formats:</string>
|
<string>Use internal &viewer for:</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_4" >
|
<layout class="QGridLayout" name="gridLayout_4" >
|
||||||
<item row="0" column="0" >
|
<item row="0" column="0" >
|
||||||
@ -483,44 +530,19 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0" >
|
|
||||||
<widget class="QCheckBox" name="systray_icon" >
|
|
||||||
<property name="text" >
|
|
||||||
<string>Enable system &tray icon (needs restart)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="0" >
|
|
||||||
<widget class="QCheckBox" name="sync_news" >
|
|
||||||
<property name="text" >
|
|
||||||
<string>Automatically send downloaded &news to ebook reader</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="0" >
|
|
||||||
<widget class="QCheckBox" name="delete_news" >
|
|
||||||
<property name="text" >
|
|
||||||
<string>&Delete news from library when it is sent to reader</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="0" >
|
|
||||||
<widget class="QCheckBox" name="separate_cover_flow" >
|
|
||||||
<property name="text" >
|
|
||||||
<string>Show cover &browser in a separate window (needs restart)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0" >
|
|
||||||
<widget class="QCheckBox" name="systray_notifications" >
|
|
||||||
<property name="text" >
|
|
||||||
<string>Show &notifications in system tray</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
<zorder>roman_numerals</zorder>
|
||||||
|
<zorder>groupBox_2</zorder>
|
||||||
|
<zorder>groupBox</zorder>
|
||||||
|
<zorder>systray_icon</zorder>
|
||||||
|
<zorder>sync_news</zorder>
|
||||||
|
<zorder>delete_news</zorder>
|
||||||
|
<zorder>separate_cover_flow</zorder>
|
||||||
|
<zorder>systray_notifications</zorder>
|
||||||
|
<zorder>groupBox_3</zorder>
|
||||||
|
<zorder></zorder>
|
||||||
|
<zorder></zorder>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="page_2" >
|
<widget class="QWidget" name="page_2" >
|
||||||
<layout class="QVBoxLayout" >
|
<layout class="QVBoxLayout" >
|
||||||
|
@ -189,7 +189,30 @@ def extract(path, dir):
|
|||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
_libunrar.RARCloseArchive(arc_data)
|
_libunrar.RARCloseArchive(arc_data)
|
||||||
|
|
||||||
def extract_member(path, match=re.compile(r'\.(jpg|jpeg|gif|png)\s*$', re.I)):
|
def names(path):
|
||||||
|
if hasattr(path, 'read'):
|
||||||
|
data = path.read()
|
||||||
|
f = NamedTemporaryFile(suffix='.rar')
|
||||||
|
f.write(data)
|
||||||
|
f.flush()
|
||||||
|
path = f.name
|
||||||
|
open_archive_data = RAROpenArchiveDataEx(ArcName=path, OpenMode=RAR_OM_LIST, CmtBuf=None)
|
||||||
|
arc_data = _libunrar.RAROpenArchiveEx(byref(open_archive_data))
|
||||||
|
try:
|
||||||
|
if open_archive_data.OpenResult != 0:
|
||||||
|
raise UnRARException(_interpret_open_error(open_archive_data.OpenResult, path))
|
||||||
|
header_data = RARHeaderDataEx(CmtBuf=None)
|
||||||
|
while True:
|
||||||
|
if _libunrar.RARReadHeaderEx(arc_data, byref(header_data)) != 0:
|
||||||
|
break
|
||||||
|
PFCode = _libunrar.RARProcessFileW(arc_data, RAR_SKIP, None, None)
|
||||||
|
if PFCode != 0:
|
||||||
|
raise UnRARException(_interpret_process_file_error(PFCode))
|
||||||
|
yield header_data.FileNameW
|
||||||
|
finally:
|
||||||
|
_libunrar.RARCloseArchive(arc_data)
|
||||||
|
|
||||||
|
def extract_member(path, match=re.compile(r'\.(jpg|jpeg|gif|png)\s*$', re.I), name=None):
|
||||||
if hasattr(path, 'read'):
|
if hasattr(path, 'read'):
|
||||||
data = path.read()
|
data = path.read()
|
||||||
f = NamedTemporaryFile(suffix='.rar')
|
f = NamedTemporaryFile(suffix='.rar')
|
||||||
@ -210,7 +233,9 @@ def extract_member(path, match=re.compile(r'\.(jpg|jpeg|gif|png)\s*$', re.I)):
|
|||||||
PFCode = _libunrar.RARProcessFileW(arc_data, RAR_EXTRACT, None, None)
|
PFCode = _libunrar.RARProcessFileW(arc_data, RAR_EXTRACT, None, None)
|
||||||
if PFCode != 0:
|
if PFCode != 0:
|
||||||
raise UnRARException(_interpret_process_file_error(PFCode))
|
raise UnRARException(_interpret_process_file_error(PFCode))
|
||||||
if match.search(header_data.FileNameW):
|
file_name = header_data.FileNameW
|
||||||
|
if (name is not None and file_name == name) or \
|
||||||
|
(match is not None and match.search(file_name)):
|
||||||
return header_data.FileNameW.replace('/', os.sep), \
|
return header_data.FileNameW.replace('/', os.sep), \
|
||||||
open(os.path.join(dir, *header_data.FileNameW.split('/')), 'rb').read()
|
open(os.path.join(dir, *header_data.FileNameW.split('/')), 'rb').read()
|
||||||
finally:
|
finally:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user