mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 02:34:06 -04:00
Switch to reading plugin index from plugins mirror
This commit is contained in:
parent
66d897893a
commit
eb9714c761
@ -23,10 +23,8 @@ from calibre.gui2 import error_dialog, question_dialog, info_dialog, NONE, open_
|
||||
from calibre.gui2.preferences.plugins import ConfigWidget
|
||||
from calibre.utils.date import UNDEFINED_DATE, format_date
|
||||
|
||||
|
||||
MR_URL = 'http://www.mobileread.com/forums/'
|
||||
MR_INDEX_URL = MR_URL + 'showpost.php?p=1362767&postcount=1'
|
||||
|
||||
SERVER = 'http://plugins.calibre-ebook.com/'
|
||||
INDEX_URL = '%splugins.json.bz2' % SERVER
|
||||
FILTER_ALL = 0
|
||||
FILTER_INSTALLED = 1
|
||||
FILTER_UPDATE_AVAILABLE = 2
|
||||
@ -55,33 +53,30 @@ def filter_not_installed_plugins(display_plugin):
|
||||
return not display_plugin.is_installed()
|
||||
|
||||
def read_available_plugins(raise_error=False):
|
||||
import json, bz2
|
||||
display_plugins = []
|
||||
br = browser()
|
||||
br.set_handle_gzip(True)
|
||||
try:
|
||||
raw = br.open_novisit(MR_INDEX_URL).read()
|
||||
raw = br.open_novisit(INDEX_URL).read()
|
||||
if not raw:
|
||||
return
|
||||
raw = json.loads(bz2.decompress(raw))
|
||||
except:
|
||||
if raise_error:
|
||||
raise
|
||||
traceback.print_exc()
|
||||
return
|
||||
raw = raw.decode('utf-8', errors='replace')
|
||||
root = html.fromstring(raw)
|
||||
list_nodes = root.xpath('//div[@id="post_message_1362767"]/ul/li')
|
||||
# Add our deprecated plugins which are nested in a grey span
|
||||
list_nodes.extend(root.xpath('//div[@id="post_message_1362767"]/span/ul/li'))
|
||||
for list_node in list_nodes:
|
||||
for plugin in raw.itervalues():
|
||||
try:
|
||||
display_plugin = DisplayPlugin(list_node)
|
||||
display_plugin = DisplayPlugin(plugin)
|
||||
get_installed_plugin_status(display_plugin)
|
||||
display_plugins.append(display_plugin)
|
||||
except:
|
||||
if DEBUG:
|
||||
prints('======= MobileRead Parse Error =======')
|
||||
prints('======= Plugin Parse Error =======')
|
||||
traceback.print_exc()
|
||||
prints(html.tostring(list_node))
|
||||
import pprint
|
||||
pprint.pprint(plugin)
|
||||
display_plugins = sorted(display_plugins, key=lambda k: k.name)
|
||||
return display_plugins
|
||||
|
||||
@ -189,61 +184,21 @@ class PluginFilterComboBox(QComboBox):
|
||||
|
||||
class DisplayPlugin(object):
|
||||
|
||||
def __init__(self, list_node):
|
||||
# The html from the index web page looks like this:
|
||||
'''
|
||||
<li><a href="http://www.mobileread.com/forums/showthread.php?t=121787">Book Sync</a><br />
|
||||
<i>Add books to a list to be automatically sent to your device the next time it is connected.<br />
|
||||
<span class="resize_1">Version: 1.1; Released: 02-22-2011; Calibre: 0.7.42; Author: kiwidude; <br />
|
||||
Platforms: Windows, OSX, Linux; History: Yes;</span></i></li>
|
||||
'''
|
||||
self.name = list_node.xpath('a')[0].text_content().strip()
|
||||
self.forum_link = list_node.xpath('a/@href')[0].strip()
|
||||
def __init__(self, plugin):
|
||||
self.name = plugin['name']
|
||||
self.forum_link = plugin['thread_url']
|
||||
self.zip_url = SERVER + plugin['file']
|
||||
self.installed_version = None
|
||||
|
||||
description_text = list_node.xpath('i')[0].text_content()
|
||||
description_parts = description_text.partition('Version:')
|
||||
self.description = description_parts[0].strip()
|
||||
|
||||
details_text = description_parts[1] + description_parts[2].replace('\r\n','')
|
||||
details_pairs = details_text.split(';')
|
||||
details = {}
|
||||
for details_pair in details_pairs:
|
||||
pair = details_pair.split(':')
|
||||
if len(pair) == 2:
|
||||
key = pair[0].strip().lower()
|
||||
value = pair[1].strip()
|
||||
details[key] = value
|
||||
|
||||
donation_node = list_node.xpath('i/span/a/@href')
|
||||
self.donation_link = donation_node[0] if donation_node else None
|
||||
|
||||
self.available_version = self._version_text_to_tuple(details.get('version', None))
|
||||
|
||||
release_date = details.get('released', '01-01-0101').split('-')
|
||||
date_parts = [int(re.search(r'(\d+)', x).group(1)) for x in release_date]
|
||||
self.release_date = datetime.date(date_parts[2], date_parts[0], date_parts[1])
|
||||
|
||||
self.calibre_required_version = self._version_text_to_tuple(details.get('calibre', None))
|
||||
self.author = details.get('author', '')
|
||||
self.platforms = [p.strip().lower() for p in details.get('platforms', '').split(',')]
|
||||
# Optional pairing just for plugins which require checking for uninstall first
|
||||
self.uninstall_plugins = []
|
||||
uninstall = details.get('uninstall', None)
|
||||
if uninstall:
|
||||
self.uninstall_plugins = [i.strip() for i in uninstall.split(',')]
|
||||
self.has_changelog = details.get('history', 'No').lower() in ['yes', 'true']
|
||||
self.is_deprecated = details.get('deprecated', 'No').lower() in ['yes', 'true']
|
||||
|
||||
def _version_text_to_tuple(self, version_text):
|
||||
if version_text:
|
||||
ver = version_text.split('.')
|
||||
while len(ver) < 3:
|
||||
ver.append('0')
|
||||
ver = [int(re.search(r'(\d+)', x).group(1)) for x in ver]
|
||||
return tuple(ver)
|
||||
else:
|
||||
return None
|
||||
self.description = plugin['description']
|
||||
self.donation_link = plugin['donate']
|
||||
self.available_version = tuple(plugin['version'])
|
||||
self.release_date = datetime.datetime(*tuple(map(int, re.split(r'\D', plugin['last_modified'])))[:6]).date()
|
||||
self.calibre_required_version = plugin['minimum_calibre_version']
|
||||
self.author = plugin['author']
|
||||
self.platforms = plugin['supported_platforms']
|
||||
self.uninstall_plugins = plugin['uninstall'] or []
|
||||
self.has_changelog = plugin['history']
|
||||
self.is_deprecated = plugin['deprecated']
|
||||
|
||||
def is_disabled(self):
|
||||
if self.plugin is None:
|
||||
@ -456,6 +411,7 @@ class PluginUpdaterDialog(SizePersistedDialog):
|
||||
SizePersistedDialog.__init__(self, gui, 'Plugin Updater plugin:plugin updater dialog')
|
||||
self.gui = gui
|
||||
self.forum_link = None
|
||||
self.zip_url = None
|
||||
self.model = None
|
||||
self.do_restart = False
|
||||
self._initialize_controls()
|
||||
@ -475,8 +431,8 @@ class PluginUpdaterDialog(SizePersistedDialog):
|
||||
self._select_and_focus_view()
|
||||
else:
|
||||
error_dialog(self.gui, _('Update Check Failed'),
|
||||
_('Unable to reach the MobileRead plugins forum index page.'),
|
||||
det_msg=MR_INDEX_URL, show=True)
|
||||
_('Unable to reach the plugin index page.'),
|
||||
det_msg=INDEX_URL, show=True)
|
||||
self.filter_combo.setEnabled(False)
|
||||
# Cause our dialog size to be restored from prefs or created on first usage
|
||||
self.resize_dialog()
|
||||
@ -599,6 +555,7 @@ class PluginUpdaterDialog(SizePersistedDialog):
|
||||
display_plugin = self.model.display_plugins[actual_idx.row()]
|
||||
self.description.setText(display_plugin.description)
|
||||
self.forum_link = display_plugin.forum_link
|
||||
self.zip_url = display_plugin.zip_url
|
||||
self.forum_action.setEnabled(bool(self.forum_link))
|
||||
self.install_button.setEnabled(display_plugin.is_valid_to_install())
|
||||
self.install_action.setEnabled(self.install_button.isEnabled())
|
||||
@ -611,6 +568,7 @@ class PluginUpdaterDialog(SizePersistedDialog):
|
||||
else:
|
||||
self.description.setText('')
|
||||
self.forum_link = None
|
||||
self.zip_url = None
|
||||
self.forum_action.setEnabled(False)
|
||||
self.install_button.setEnabled(False)
|
||||
self.install_action.setEnabled(False)
|
||||
@ -703,17 +661,7 @@ class PluginUpdaterDialog(SizePersistedDialog):
|
||||
for name_to_remove in uninstall_names:
|
||||
self._uninstall_plugin(name_to_remove)
|
||||
|
||||
if DEBUG:
|
||||
prints('Locating zip file for %s: %s'% (display_plugin.name, display_plugin.forum_link))
|
||||
self.gui.status_bar.showMessage(
|
||||
_('Locating zip file for %(name)s: %(link)s') % dict(
|
||||
name=display_plugin.name, link=display_plugin.forum_link))
|
||||
plugin_zip_url = self._read_zip_attachment_url(display_plugin.forum_link)
|
||||
if not plugin_zip_url:
|
||||
return error_dialog(self.gui, _('Install Plugin Failed'),
|
||||
_('Unable to locate a plugin zip file for <b>%s</b>') % display_plugin.name,
|
||||
det_msg=display_plugin.forum_link, show=True)
|
||||
|
||||
plugin_zip_url = display_plugin.zip_url
|
||||
if DEBUG:
|
||||
prints('Downloading plugin zip attachment: ', plugin_zip_url)
|
||||
self.gui.status_bar.showMessage(_('Downloading plugin zip attachment: %s') % plugin_zip_url)
|
||||
@ -852,39 +800,11 @@ class PluginUpdaterDialog(SizePersistedDialog):
|
||||
prints(html.tostring(spoiler_node))
|
||||
return None
|
||||
|
||||
def _read_zip_attachment_url(self, forum_link):
|
||||
br = browser()
|
||||
br.set_handle_gzip(True)
|
||||
try:
|
||||
raw = br.open_novisit(forum_link).read()
|
||||
if not raw:
|
||||
return None
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return None
|
||||
raw = raw.decode('utf-8', errors='replace')
|
||||
root = html.fromstring(raw)
|
||||
attachment_nodes = root.xpath('//fieldset/table/tr/td/a')
|
||||
for attachment_node in attachment_nodes:
|
||||
try:
|
||||
filename = attachment_node.text_content().lower()
|
||||
if filename.find('.zip') != -1:
|
||||
full_url = MR_URL + attachment_node.attrib['href']
|
||||
return full_url
|
||||
except:
|
||||
if DEBUG:
|
||||
prints('======= MobileRead Parse Error =======')
|
||||
traceback.print_exc()
|
||||
prints(html.tostring(attachment_node))
|
||||
return None
|
||||
|
||||
def _download_zip(self, plugin_zip_url):
|
||||
from calibre.ptempfile import PersistentTemporaryFile
|
||||
br = browser()
|
||||
br.set_handle_gzip(True)
|
||||
raw = br.open_novisit(plugin_zip_url).read()
|
||||
pt = PersistentTemporaryFile('.zip')
|
||||
with PersistentTemporaryFile('.zip') as pt:
|
||||
pt.write(raw)
|
||||
pt.close()
|
||||
return pt.name
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user