mirror of
https://github.com/JimmXinu/FanFicFare.git
synced 2026-04-26 00:43:08 +02:00
Save IMAP story url fetch feature. Needs translation strings updated.
This commit is contained in:
parent
2d5fe07baf
commit
83ea401eaf
5 changed files with 259 additions and 13 deletions
|
|
@ -4,7 +4,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
|||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2014, Jim Miller'
|
||||
__copyright__ = '2015, Jim Miller'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import logging
|
||||
|
|
@ -14,15 +14,15 @@ import traceback, copy, threading
|
|||
from collections import OrderedDict
|
||||
|
||||
try:
|
||||
from PyQt5.Qt import (QDialog, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QLineEdit, QFont, QWidget, QTextEdit, QComboBox,
|
||||
from PyQt5.Qt import (QDialog, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
|
||||
QLabel, QLineEdit, QFont, QWidget, QTextEdit, QComboBox,
|
||||
QCheckBox, QPushButton, QTabWidget, QScrollArea,
|
||||
QDialogButtonBox, QGroupBox )
|
||||
QDialogButtonBox, QGroupBox, Qt )
|
||||
except ImportError as e:
|
||||
from PyQt4.Qt import (QDialog, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QLineEdit, QFont, QWidget, QTextEdit, QComboBox,
|
||||
from PyQt4.Qt import (QDialog, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
|
||||
QLabel, QLineEdit, QFont, QWidget, QTextEdit, QComboBox,
|
||||
QCheckBox, QPushButton, QTabWidget, QScrollArea,
|
||||
QDialogButtonBox, QGroupBox )
|
||||
QDialogButtonBox, QGroupBox, Qt )
|
||||
try:
|
||||
from calibre.gui2 import QVariant
|
||||
del QVariant
|
||||
|
|
@ -216,6 +216,9 @@ class ConfigWidget(QWidget):
|
|||
self.cust_columns_tab = CustomColumnsTab(self, plugin_action)
|
||||
tab_widget.addTab(self.cust_columns_tab, _('Custom Columns'))
|
||||
|
||||
self.imap_tab = ImapTab(self, plugin_action)
|
||||
tab_widget.addTab(self.imap_tab, _('Email Settings'))
|
||||
|
||||
self.other_tab = OtherTab(self, plugin_action)
|
||||
tab_widget.addTab(self.other_tab, _('Other'))
|
||||
|
||||
|
|
@ -319,6 +322,13 @@ class ConfigWidget(QWidget):
|
|||
prefs['custom_cols_newonly'] = colsnewonly
|
||||
|
||||
prefs['allow_custcol_from_ini'] = self.cust_columns_tab.allow_custcol_from_ini.isChecked()
|
||||
|
||||
prefs['imapserver'] = unicode(self.imap_tab.imapserver.text())
|
||||
prefs['imapuser'] = unicode(self.imap_tab.imapuser.text())
|
||||
prefs['imappass'] = unicode(self.imap_tab.imappass.text())
|
||||
prefs['imapfolder'] = unicode(self.imap_tab.imapfolder.text())
|
||||
prefs['imapmarkread'] = self.imap_tab.imapmarkread.isChecked()
|
||||
prefs['imapsessionpass'] = self.imap_tab.imapsessionpass.isChecked()
|
||||
|
||||
prefs.save_to_db()
|
||||
|
||||
|
|
@ -1118,3 +1128,82 @@ class StandardColumnsTab(QWidget):
|
|||
|
||||
self.l.insertStretch(-1)
|
||||
|
||||
class ImapTab(QWidget):
|
||||
|
||||
def __init__(self, parent_dialog, plugin_action):
|
||||
self.parent_dialog = parent_dialog
|
||||
self.plugin_action = plugin_action
|
||||
QWidget.__init__(self)
|
||||
|
||||
self.l = QGridLayout()
|
||||
self.setLayout(self.l)
|
||||
row=0
|
||||
|
||||
label = QLabel(_('These settings will allow FFDL to fetch story URLs from your email account. It will only look for story URLs in unread emails in the folder specified below.'))
|
||||
label.setWordWrap(True)
|
||||
self.l.addWidget(label,row,0,1,-1)
|
||||
row+=1
|
||||
|
||||
label = QLabel(_('IMAP Server Name'))
|
||||
tooltip = _("Name of IMAP server--must allow IMAP4 with SSL. Eg: imap.gmail.com")
|
||||
label.setToolTip(tooltip)
|
||||
self.l.addWidget(label,row,0)
|
||||
self.imapserver = QLineEdit(self)
|
||||
self.imapserver.setToolTip(tooltip)
|
||||
self.imapserver.setText(prefs['imapserver'])
|
||||
self.l.addWidget(self.imapserver,row,1)
|
||||
row+=1
|
||||
|
||||
label = QLabel(_('IMAP User Name'))
|
||||
tooltip = _("Name of IMAP user. Eg: yourname@gmail.com\nNote that Gmail addresses need to have IMAP enabled in Gmail Settings first.")
|
||||
label.setToolTip(tooltip)
|
||||
self.l.addWidget(label,row,0)
|
||||
self.imapuser = QLineEdit(self)
|
||||
self.imapuser.setToolTip(tooltip)
|
||||
self.imapuser.setText(prefs['imapuser'])
|
||||
self.l.addWidget(self.imapuser,row,1)
|
||||
row+=1
|
||||
|
||||
label = QLabel(_('IMAP User Password'))
|
||||
tooltip = _("IMAP password. If left empty, FFDL will ask you for your password when you .")
|
||||
label.setToolTip(tooltip)
|
||||
self.l.addWidget(label,row,0)
|
||||
self.imappass = QLineEdit(self)
|
||||
self.imappass.setToolTip(tooltip)
|
||||
self.imappass.setEchoMode(QLineEdit.Password)
|
||||
self.imappass.setText(prefs['imappass'])
|
||||
self.l.addWidget(self.imappass,row,1)
|
||||
row+=1
|
||||
|
||||
self.imapsessionpass = QCheckBox(_('Remember Password for Session (when not entered above)'),self)
|
||||
self.imapsessionpass.setToolTip(_('If checked, and no password is entered above, FFDL will remember your password until you close calibre or change libraries.'))
|
||||
self.imapsessionpass.setChecked(prefs['imapsessionpass'])
|
||||
self.l.addWidget(self.imapsessionpass,row,0,1,-1)
|
||||
row+=1
|
||||
|
||||
label = QLabel(_('IMAP Folder Name'))
|
||||
tooltip = _("Name of IMAP folder to search for new emails. The folder (or label) has to already exist. Use INBOX for your default inbox.")
|
||||
label.setToolTip(tooltip)
|
||||
self.l.addWidget(label,row,0)
|
||||
self.imapfolder = QLineEdit(self)
|
||||
self.imapfolder.setToolTip(tooltip)
|
||||
self.imapfolder.setText(prefs['imapfolder'])
|
||||
self.l.addWidget(self.imapfolder,row,1)
|
||||
row+=1
|
||||
|
||||
self.imapmarkread = QCheckBox(_('Mark Emails Read'),self)
|
||||
self.imapmarkread.setToolTip(_('If checked, emails will be marked as having been read if they contain any story URLs.'))
|
||||
self.imapmarkread.setChecked(prefs['imapmarkread'])
|
||||
self.l.addWidget(self.imapmarkread,row,0,1,-1)
|
||||
row+=1
|
||||
|
||||
label = QLabel(_("<b>It's safest if you create a separate email account that you use only "
|
||||
"for your story update notices. FFDL and calibre cannot guarantee that "
|
||||
"malicious code cannot get your email password once you've entered it. "
|
||||
"<br>Use this feature at your own risk. </b>"))
|
||||
label.setWordWrap(True)
|
||||
self.l.addWidget(label,row,0,1,-1,Qt.AlignTop)
|
||||
self.l.setRowStretch(row,1)
|
||||
row+=1
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from __future__ import (unicode_literals, division,
|
|||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2014, Jim Miller'
|
||||
__copyright__ = '2015, Jim Miller'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import traceback, re
|
||||
|
|
@ -1435,3 +1435,49 @@ class ViewLog(SizePersistedDialog):
|
|||
txt = self.tb.toPlainText()
|
||||
QApplication.clipboard().setText(txt)
|
||||
|
||||
class EmailPassDialog(QDialog):
|
||||
'''
|
||||
Need to collect Pass for imap.
|
||||
'''
|
||||
def __init__(self, gui, user):
|
||||
QDialog.__init__(self, gui)
|
||||
self.status=False
|
||||
|
||||
self.l = QGridLayout()
|
||||
self.setLayout(self.l)
|
||||
|
||||
self.setWindowTitle(_('Password'))
|
||||
self.l.addWidget(QLabel(_("Enter Email Password for %s:"%user)),0,0,1,2)
|
||||
|
||||
# self.l.addWidget(QLabel(_("Password:")),1,0)
|
||||
self.passwd = QLineEdit(self)
|
||||
self.passwd.setEchoMode(QLineEdit.Password)
|
||||
self.l.addWidget(self.passwd,1,0,1,2)
|
||||
|
||||
self.ok_button = QPushButton(_('OK'), self)
|
||||
self.ok_button.clicked.connect(self.ok)
|
||||
self.l.addWidget(self.ok_button,2,0)
|
||||
|
||||
self.cancel_button = QPushButton(_('Cancel'), self)
|
||||
self.cancel_button.clicked.connect(self.cancel)
|
||||
self.l.addWidget(self.cancel_button,2,1)
|
||||
|
||||
# set stretch factors the same.
|
||||
self.l.setColumnStretch(0,1)
|
||||
self.l.setColumnStretch(1,1)
|
||||
|
||||
self.resize(self.sizeHint())
|
||||
|
||||
def ok(self):
|
||||
self.status=True
|
||||
self.hide()
|
||||
|
||||
def cancel(self):
|
||||
self.status=False
|
||||
self.hide()
|
||||
|
||||
def get_pass(self):
|
||||
return u"%s"%self.passwd.text()
|
||||
|
||||
def get_remember(self):
|
||||
return self.remember_pass.isChecked()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
|||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2014, Jim Miller'
|
||||
__copyright__ = '2015, Jim Miller'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import logging
|
||||
|
|
@ -53,14 +53,14 @@ from calibre_plugins.fanfictiondownloader_plugin.common_utils import (set_plugin
|
|||
|
||||
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader import adapters, exceptions
|
||||
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader.epubutils import get_dcsource, get_dcsource_chaptercount, get_story_url_from_html
|
||||
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader.geturls import get_urls_from_page, get_urls_from_html, get_urls_from_text
|
||||
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader.geturls import get_urls_from_page, get_urls_from_html, get_urls_from_text, get_urls_from_imap
|
||||
|
||||
from calibre_plugins.fanfictiondownloader_plugin.ffdl_util import (get_ffdl_adapter, get_ffdl_config, get_ffdl_personalini)
|
||||
from calibre_plugins.fanfictiondownloader_plugin.config import (permitted_values, rejecturllist)
|
||||
from calibre_plugins.fanfictiondownloader_plugin.prefs import prefs
|
||||
from calibre_plugins.fanfictiondownloader_plugin.dialogs import (
|
||||
AddNewDialog, UpdateExistingDialog,
|
||||
LoopProgressDialog, UserPassDialog, AboutDialog, CollectURLDialog, RejectListDialog,
|
||||
LoopProgressDialog, UserPassDialog, AboutDialog, CollectURLDialog, RejectListDialog, EmailPassDialog,
|
||||
OVERWRITE, OVERWRITEALWAYS, UPDATE, UPDATEALWAYS, ADDNEW, SKIP, CALIBREONLY,
|
||||
NotGoingToDownload, RejectUrlEntry )
|
||||
|
||||
|
|
@ -135,6 +135,8 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
|
|||
self.menus_lock = threading.RLock()
|
||||
self.menu.aboutToShow.connect(self.about_to_show_menu)
|
||||
|
||||
self.imap_pass = None
|
||||
|
||||
def initialization_complete(self):
|
||||
# otherwise configured hot keys won't work until the menu's
|
||||
# been displayed once.
|
||||
|
|
@ -231,6 +233,7 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
|
|||
# We need to reset our menus after switching libraries
|
||||
self.rebuild_menus()
|
||||
rejecturllist.clear_cache()
|
||||
self.imap_pass = None
|
||||
|
||||
def rebuild_menus(self):
|
||||
with self.menus_lock:
|
||||
|
|
@ -257,6 +260,10 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
|
|||
|
||||
if self.get_epubmerge_plugin():
|
||||
self.menu.addSeparator()
|
||||
self.get_list_imap_action = self.create_menu_item_ex(self.menu, _('Get Story URLs to Download from Email'), image='view.png',
|
||||
unique_name='Get Story URLs from IMAP',
|
||||
triggered=self.get_urls_from_imap_menu)
|
||||
|
||||
self.get_list_url_action = self.create_menu_item_ex(self.menu, _('Get Story URLs to Download from Web Page'), image='view.png',
|
||||
unique_name='Get Story URLs from Web Page',
|
||||
triggered=self.get_urls_from_page_menu)
|
||||
|
|
@ -306,6 +313,10 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
|
|||
triggered=self.list_story_urls)
|
||||
|
||||
if not self.get_epubmerge_plugin():
|
||||
self.get_list_imap_action = self.create_menu_item_ex(self.menu, _('Get Story URLs to Download from Email'), image='view.png',
|
||||
unique_name='Get Story URLs from IMAP',
|
||||
triggered=self.get_urls_from_imap_menu)
|
||||
|
||||
self.get_list_url_action = self.create_menu_item_ex(self.menu, _('Get Story URLs from Web Page'),
|
||||
unique_name='Get Story URLs from Web Page',
|
||||
image='view.png',
|
||||
|
|
@ -385,6 +396,44 @@ class FanFictionDownLoaderPlugin(InterfaceAction):
|
|||
|
||||
self.update_reading_lists(self.gui.library_view.get_selected_ids(),add)
|
||||
|
||||
def get_urls_from_imap_menu(self):
|
||||
|
||||
if not prefs['imapserver'] or not prefs['imapuser'] or not prefs['imapfolder']:
|
||||
info_dialog(self.gui, _('Email Settings not Configured'),
|
||||
_('FFDL Email Settings are not configured.'),
|
||||
show=True,
|
||||
show_copy_button=False)
|
||||
return
|
||||
|
||||
imap_pass = None
|
||||
if prefs['imappass']:
|
||||
imap_pass = prefs['imappass']
|
||||
elif self.imap_pass is not None:
|
||||
imap_pass = self.imap_pass
|
||||
|
||||
if not imap_pass:
|
||||
d = EmailPassDialog(self.gui,prefs['imapuser'])
|
||||
d.exec_()
|
||||
if not d.status:
|
||||
return
|
||||
imap_pass = d.get_pass()
|
||||
if prefs['imapsessionpass']:
|
||||
self.imap_pass = imap_pass
|
||||
|
||||
url_list = get_urls_from_imap(prefs['imapserver'],
|
||||
prefs['imapuser'],
|
||||
imap_pass,
|
||||
prefs['imapfolder'],
|
||||
prefs['imapmarkread'],)
|
||||
|
||||
if url_list:
|
||||
self.add_dialog("\n".join(url_list),merge=False)
|
||||
else:
|
||||
info_dialog(self.gui, _('Get Story URLs from Email'),
|
||||
_('No Valid Story URLs Found in Unread Emails.'),
|
||||
show=True,
|
||||
show_copy_button=False)
|
||||
|
||||
def get_urls_from_page_menu(self):
|
||||
|
||||
urltxt = ""
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
|||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2013, Jim Miller'
|
||||
__copyright__ = '2015, Jim Miller'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import copy
|
||||
|
|
@ -71,6 +71,13 @@ default_prefs['allow_custcol_from_ini'] = True
|
|||
|
||||
default_prefs['std_cols_newonly'] = {}
|
||||
|
||||
default_prefs['imapserver'] = ''
|
||||
default_prefs['imapuser'] = ''
|
||||
default_prefs['imappass'] = ''
|
||||
default_prefs['imapsessionpass'] = False
|
||||
default_prefs['imapfolder'] = 'INBOX'
|
||||
default_prefs['imapmarkread'] = True
|
||||
|
||||
# This is where all preferences for this plugin *were* stored
|
||||
# Remember that this name (i.e. plugins/fanfictiondownloader_plugin) is also
|
||||
# in a global namespace, so make it as unique as possible.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2012 Fanficdownloader team
|
||||
# Copyright 2015 Fanficdownloader team
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
|
@ -19,6 +19,9 @@ import re
|
|||
import urlparse
|
||||
import urllib2 as u2
|
||||
|
||||
import imaplib
|
||||
import email
|
||||
|
||||
from BeautifulSoup import BeautifulSoup
|
||||
from gziphttp import GZipProcessor
|
||||
|
||||
|
|
@ -173,3 +176,55 @@ def form_url(parenturl,url):
|
|||
'','',''))
|
||||
return returl
|
||||
|
||||
def get_urls_from_imap(srv,user,passwd,folder,markread=True):
|
||||
|
||||
mail = imaplib.IMAP4_SSL(srv)
|
||||
mail.login(user, passwd)
|
||||
mail.list()
|
||||
# Out: list of "folders" aka labels in gmail.
|
||||
mail.select(folder) # , readonly=True connect to inbox.
|
||||
|
||||
result, data = mail.uid('search', None, "UNSEEN")
|
||||
|
||||
#print("result:%s"%result)
|
||||
#print("data:%s"%data)
|
||||
urls=set()
|
||||
|
||||
#latest_email_uid = data[0].split()[-1]
|
||||
for email_uid in data[0].split():
|
||||
|
||||
result, data = mail.uid('fetch', email_uid, '(BODY.PEEK[])') #RFC822
|
||||
|
||||
#print("result:%s"%result)
|
||||
#print("data:%s"%data)
|
||||
|
||||
raw_email = data[0][1]
|
||||
|
||||
#raw_email = data[0][1] # here's the body, which is raw text of the whole email
|
||||
# including headers and alternate payloads
|
||||
|
||||
email_message = email.message_from_string(raw_email)
|
||||
|
||||
#print "To:%s"%email_message['To']
|
||||
#print "From:%s"%email_message['From']
|
||||
#print "Subject:%s"%email_message['Subject']
|
||||
|
||||
# print("payload:%s"%email_message.get_payload())
|
||||
|
||||
urllist=[]
|
||||
for part in email_message.walk():
|
||||
#print("part mime:%s"%part.get_content_type())
|
||||
if part.get_content_type() == 'text/plain':
|
||||
urllist.extend(get_urls_from_text(part.get_payload(decode=True)))
|
||||
if part.get_content_type() == 'text/html':
|
||||
urllist.extend(get_urls_from_html(part.get_payload(decode=True)))
|
||||
#print "urls:%s"%get_urls_from_text(get_first_text_block(email_message))
|
||||
|
||||
if urllist and markread:
|
||||
#obj.store(data[0].replace(' ',','),'+FLAGS','\Seen')
|
||||
r,d = mail.uid('store',email_uid,'+FLAGS','(\\SEEN)')
|
||||
#print("seen result:%s->%s"%(email_uid,r))
|
||||
|
||||
[ urls.add(x) for x in urllist ]
|
||||
|
||||
return urls
|
||||
|
|
|
|||
Loading…
Reference in a new issue