# -*- coding: utf-8 -*- # Copyright 2011 Fanficdownloader team # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import logging ## XXX cli option for logging level. logging.basicConfig(level=logging.DEBUG,format="%(levelname)s:%(filename)s(%(lineno)d):%(message)s") import sys, os from os.path import normpath, expanduser, isfile, join from StringIO import StringIO from optparse import OptionParser import getpass import string from subprocess import call from epubmerge import doMerge if sys.version_info < (2, 5): print "This program requires Python 2.5 or newer." sys.exit(1) from fanficdownloader import adapters,writers,exceptions import ConfigParser def writeStory(config,adapter,writeformat,metaonly=False,outstream=None): writer = writers.getWriter(writeformat,config,adapter) writer.writeStory(outstream=outstream,metaonly=metaonly) output_filename=writer.getOutputFileName() del writer return output_filename def main(): # read in args, anything starting with -- will be treated as --= usage = "usage: %prog [options] storyurl" parser = OptionParser(usage) parser.add_option("-f", "--format", dest="format", default="epub", help="write story as FORMAT, epub(default), text or html", metavar="FORMAT") parser.add_option("-c", "--config", action="append", dest="configfile", default=None, help="read config from specified file(s) in addition to ~/.fanficdownloader/defaults.ini, ~/.fanficdownloader/personal.ini, ./defaults.ini, ./personal.ini", metavar="CONFIG") parser.add_option("-b", "--begin", dest="begin", default=None, help="Begin with Chapter START", metavar="START") parser.add_option("-e", "--end", dest="end", default=None, help="End with Chapter END", metavar="END") parser.add_option("-o", "--option", action="append", dest="options", help="set an option NAME=VALUE", metavar="NAME=VALUE") parser.add_option("-m", "--meta-only", action="store_true", dest="metaonly", help="Retrieve metadata and stop. Or, if --update-epub, update metadata title page only.",) parser.add_option("-u", "--update-epub", action="store_true", dest="update", help="Update an existing epub with new chapter, give epub filename instead of storyurl. Not compatible with inserted TOC.",) parser.add_option("--force", action="store_true", dest="force", help="Force overwrite or update of an existing epub, download and overwrite all chapters.",) (options, args) = parser.parse_args() if len(args) != 1: parser.error("incorrect number of arguments") if options.update and options.format != 'epub': parser.error("-u/--update-epub only works with epub") config = ConfigParser.SafeConfigParser() conflist = [] homepath = join(expanduser("~"),".fanficdownloader") if isfile(join(homepath,"defaults.ini")): conflist.append(join(homepath,"defaults.ini")) if isfile(join(homepath,"personal.ini")): conflist.append(join(homepath,"personal.ini")) if isfile("defaults.ini"): conflist.append("defaults.ini") if isfile("personal.ini"): conflist.append("personal.ini") if options.configfile: conflist.extend(options.configfile) logging.debug('reading %s config file(s), if present'%conflist) config.read(conflist) try: config.add_section("overrides") except ConfigParser.DuplicateSectionError: pass if options.force: config.set("overrides","always_overwrite","true") if options.options: for opt in options.options: (var,val) = opt.split('=') config.set("overrides",var,val) try: ## Attempt to update an existing epub. if options.update: updateio = StringIO() (url,chaptercount) = doMerge(updateio, args, titlenavpoints=False, striptitletoc=True, forceunique=False) print "Updating %s, URL: %s" % (args[0],url) output_filename = args[0] config.set("overrides","output_filename",args[0]) else: url = args[0] adapter = adapters.getAdapter(config,url) try: adapter.getStoryMetadataOnly() except exceptions.FailedToLogin: print "Login Failed, Need Username/Password." sys.stdout.write("Username: ") adapter.username = sys.stdin.readline().strip() adapter.password = getpass.getpass(prompt='Password: ') #print("Login: `%s`, Password: `%s`" % (adapter.username, adapter.password)) adapter.getStoryMetadataOnly() except exceptions.AdultCheckRequired: print "Please confirm you are an adult in your locale: (y/n)?" if sys.stdin.readline().strip().lower().startswith('y'): adapter.is_adult=True adapter.getStoryMetadataOnly() if options.update and not options.force: urlchaptercount = int(adapter.getStoryMetadataOnly().getMetadata('numChapters')) if chaptercount == urlchaptercount and not options.metaonly: print "%s already contains %d chapters." % (args[0],chaptercount) elif chaptercount > urlchaptercount: print "%s contains %d chapters, more than source: %d." % (args[0],chaptercount,urlchaptercount) else: print "Do update - epub(%d) vs url(%d)" % (chaptercount, urlchaptercount) ## Get updated title page/metadata by itself in an epub. ## Even if the title page isn't included, this carries the metadata. titleio = StringIO() writeStory(config,adapter,"epub",metaonly=True,outstream=titleio) newchaptersio = None if not options.metaonly: ## Go get the new chapters only in another epub. newchaptersio = StringIO() adapter.setChaptersRange(chaptercount+1,urlchaptercount) config.set("overrides",'include_tocpage','false') config.set("overrides",'include_titlepage','false') writeStory(config,adapter,"epub",outstream=newchaptersio) # out = open("testing/titleio.epub","wb") # out.write(titleio.getvalue()) # out.close() # out = open("testing/updateio.epub","wb") # out.write(updateio.getvalue()) # out.close() # out = open("testing/newchaptersio.epub","wb") # out.write(newchaptersio.getvalue()) # out.close() ## Merge the three epubs together. doMerge(args[0], [titleio,updateio,newchaptersio], fromfirst=True, titlenavpoints=False, striptitletoc=False, forceunique=False) else: # regular download if options.metaonly: print adapter.getStoryMetadataOnly() adapter.setChaptersRange(options.begin,options.end) output_filename=writeStory(config,adapter,options.format,options.metaonly) if not options.metaonly and adapter.getConfig("post_process_cmd"): metadata = adapter.story.metadata metadata['output_filename']=output_filename call(string.Template(adapter.getConfig("post_process_cmd")) .substitute(metadata)) del adapter except exceptions.InvalidStoryURL, isu: print isu except exceptions.StoryDoesNotExist, dne: print dne except exceptions.UnknownSite, us: print us if __name__ == "__main__": main()