Esempio n. 1
0
    def load(self, filename, initial_page=0):

        image_extensions = [
            '.bmp', '.jpg', '.jpeg', '.gif', '.png', '.pbm', '.pgm', '.ppm',
            '.tiff', '.xbm', '.xpm', '.webp'
        ]

        ld = LoaderFactory.create_loader(Utility.get_file_extension(filename),
                                         set(image_extensions))

        ld.progress.connect(self.load_progressbar_value)

        try:
            ld.load(filename)
        except NoDataFindException as excp:
            # Caso nao exista nenhuma imagem, carregamos a imagem indicando
            # erro
            from page import Page
            print excp.message
            q_file = QtCore.QFile(":/icons/notCover.png")
            q_file.open(QtCore.QIODevice.ReadOnly)
            ld.data.append(Page(q_file.readAll(), 'exit_red_1.png', 0))

        self.comic = Comic(Utility.get_base_name(filename),
                           Utility.get_dir_name(filename), initial_page)

        self.comic.pages = ld.data
        self.current_directory = Utility.get_dir_name(filename)
        self.path_file_filter.parse(filename)
Esempio n. 2
0
def deploy():
    db.drop_all()
    db.create_all()
    DC = Author(name='DC', about='DC is a comic publisher that owns the Justice League, known as being dark.')
    Marvel = Author(name='Marvel', about='Marvel is a comic publisher that owns avengers and is known for being family friendly.')
    DarkHorse = Author(name='Dark Horse', about='Dark House is a lesser known comic publisher.')
    comic1 = Comic(name='Deathstroke', year=1980, lyrics="Mercenary considered an antihero with enhanced abilities", author=DC)
    comic2 = Comic(name='Deadpool', year=1991, lyrics="Psychotic mercenary capable of breaking the 4th wall and considered immortal. Antihero.", author=Marvel)
    comic3 = Comic(name='Hellboy', year=1993  , lyrics="A devil like character with enhanced abilities who is hated, but still fights for good", author=DarkHorse)
    db.session.add(DC)
    db.session.add(Marvel)
    db.session.add(DarkHorse)
    db.session.add(comic1)
    db.session.add(comic2)
    db.session.add(comic3)
    db.session.commit()
    def load(self, filename, initial_page=0):

        image_extensions = ['.bmp', '.jpg', '.jpeg', '.gif', '.png', '.pbm',
                            '.pgm', '.ppm', '.tiff', '.xbm', '.xpm', '.webp']

        loader = LoaderFactory.create_loader(
            Utility.get_file_extension(filename), set(image_extensions))

        loader.progress.connect(self.load_progressbar_value)

        try:
            loader.load(filename)
        except NoDataFindException as excp:
            # Caso nao exista nenhuma imagem, carregamos a imagem indicando
            # erro
            from page import Page
            print excp.message
            q_file = QtCore.QFile(":/icons/notCover.png")
            q_file.open(QtCore.QIODevice.ReadOnly)
            loader.data.append(Page(q_file.readAll(), 'exit_red_1.png', 0))

        self.comic = Comic(Utility.get_base_name(filename),
                           Utility.get_dir_name(filename), initial_page)

        self.comic.pages = loader.data
        self.current_directory = Utility.get_dir_name(filename)
        self.path_file_filter.parse(filename)
Esempio n. 4
0
def addComic():
    comicLibrary = "comicLibrary.csv"

    itemName = input("Enter comic name: ")
    itemCreators = input("Enter comic's writer and artist: ")
    itemType = input("Enter comic's publisher: ")
    itemPublished = input("Enter comic's publication date: ")
    itemIssue = input("Enter the comic's issue: ")
    itemVariant = input("Is the comic a variant?: ")

    createComic = Comic(itemName,itemCreators,itemType,itemPublished, itemIssue, itemVariant)
    writeFile (comicLibrary, createComic)
Esempio n. 5
0
def patch(*args):
    """patch
    Patches the metadata of a comic edited with 'edit' into it"""
    from comic import Comic
    from __main__ import printhelp
    if not args:
        return printhelp("patch")
    title = " ".join(args).strip()
    print("Patching '{0}'...".format(title))

    # Look for an edited metadata file in the folder for those :)
    metapath = os.path.join(metadir, title + "_meta.toml")
    progpath = os.path.join(metadir, title + "_prog.toml")

    with Comic.load(title) as comic:
        # Validate the metadata file
        if os.path.exists(metapath):
            with open(metapath) as f:
                metadict = toml.load(f)
            valid, errors = validate_metadata(metadict)
            if not valid:
                print(
                    "Could not patch the metadata due to the following errors:"
                )
                return printiter(errors)
            else:
                print("- Patching metadata...")
                comic.metadata = metadict
                os.remove(metapath)

        if os.path.exists(progpath):
            with open(progpath) as f:
                progdict = toml.load(f)
            valid, errors = validate_progdata(progdict)
            if not valid:
                print(
                    "Could not patch the metadata due to the following errors:"
                )
                return printiter(errors)
            else:
                print("- Patching progress data...")
                comic.progress = progdict
                os.remove(progpath)

    print("Done!")
Esempio n. 6
0
def edit(*args):
    """Moves and opens the medadata (or progress) of a comic for editing"""
    from __main__ import _editcmd
    desc = "Moves and opens the medadata of a comic for editing"
    prog = os.path.basename(sys.argv[0]) + " " + _editcmd
    parser = ArgumentParser(description=desc, prog=prog)
    parser.add_argument("comic", help="The comic whose metadata to edit")
    parser.add_argument(
        "-p",
        "--edit_progress_data",
        action="store_true",
        default=False,
        help="Whether the progress data should be edited instead")
    args = parser.parse_args(args)
    editprog = args.edit_progress_data
    affix = "prog" if editprog else "meta"

    from comic import Comic
    title = args.comic
    comic = Comic.load(title)
    ensure(metadir)
    target = os.path.join(metadir, title + "_" + affix + ".toml")
    if not os.path.exists(target):  # use the existing one if possible
        with open(target, "w") as w:
            if editprog:
                toml.dump(comic.progress, w)
            else:
                toml.dump(comic.metadata, w)
    else:
        print("- Found existing patch file")
    print("The file is now available at '{0}'".format(target))
    print("Use <{0} patch '{1}'> to apply the changes".format(
        sys.argv[0], title))

    # TODO improve this, yes?
    if "darwin" in sys.platform:
        subprocess.Popen(["open", "-a", "TextMate", target])
Esempio n. 7
0
class MainWindowModel(QtCore.QObject):
    _ORIGINAL_FIT = 'action_original_fit'
    _VERTICAL_FIT = 'action_vertical_fit'
    _HORIZONTAL_FIT = 'action_horizontal_fit'
    _BEST_FIT = 'action_best_fit'

    load_progress = QtCore.Signal(int)
    load_done = QtCore.Signal()

    def __init__(self):
        QtCore.QObject.__init__(self)
        self.comic = None
        self.settings_manager = SettingsManager()
        self.rotate_angle = 0
        self.scroll_area_size = None
        self.fit_type = self.load_view_adjust(MainWindowModel._ORIGINAL_FIT)
        self.current_directory = self.load_current_directory()

        ext_list = ["*.cbr", "*.cbz", "*.rar", "*.zip", "*.tar", "*.cbt"]
        self.path_file_filter = PathFileFilter(ext_list)

    def save_recent_files(self, recent_files_list):
        self.settings_manager.save_recent_files(recent_files_list)

    def load_recent_files(self):
        return self.settings_manager.load_recent_files()

    def save_view_adjust(self, object_name):
        self.settings_manager.save_view_adjust(object_name)

    def load_view_adjust(self, default_object_name):
        return self.settings_manager.load_view_adjust(default_object_name)

    def save_current_directory(self, current_directory):
        self.settings_manager.save_current_directory(current_directory)

    def load_current_directory(self):
        return self.settings_manager.load_current_directory()

    def load(self, filename, initial_page=0):

        image_extensions = [
            '.bmp', '.jpg', '.jpeg', '.gif', '.png', '.pbm', '.pgm', '.ppm',
            '.tiff', '.xbm', '.xpm', '.webp'
        ]

        ld = LoaderFactory.create_loader(Utility.get_file_extension(filename),
                                         set(image_extensions))

        ld.progress.connect(self.load_progressbar_value)

        try:
            ld.load(filename)
        except NoDataFindException as excp:
            # Caso nao exista nenhuma imagem, carregamos a imagem indicando
            # erro
            from page import Page
            print excp.message
            q_file = QtCore.QFile(":/icons/notCover.png")
            q_file.open(QtCore.QIODevice.ReadOnly)
            ld.data.append(Page(q_file.readAll(), 'exit_red_1.png', 0))

        self.comic = Comic(Utility.get_base_name(filename),
                           Utility.get_dir_name(filename), initial_page)

        self.comic.pages = ld.data
        self.current_directory = Utility.get_dir_name(filename)
        self.path_file_filter.parse(filename)

    def save_current_page_image(self, file_name):
        self.get_current_page().save(file_name)

    def next_page(self):
        if self.comic:
            self.comic.go_next_page()

    def previous_page(self):
        if self.comic:
            self.comic.go_previous_page()

    def first_page(self):
        if self.comic:
            self.comic.go_first_page()

    def last_page(self):
        if self.comic:
            self.comic.go_last_page()

    def next_comic(self):
        return self.path_file_filter.next_path.decode('utf-8')

    def previous_comic(self):
        return self.path_file_filter.previous_path.decode('utf-8')

    def rotate_left(self):
        self.rotate_angle = (self.rotate_angle - 90) % 360

    def rotate_right(self):
        self.rotate_angle = (self.rotate_angle + 90) % 360

    def get_comic_name(self):
        return self.comic.name if self.comic else ''

    def get_comic_title(self):
        return self.comic.name + ' - Pynocchio Comic Reader'

    def get_current_page(self):
        if self.comic:
            pix_map = self.comic.get_current_page().pixmap
            pix_map = self._rotate_page(pix_map)
            pix_map = self._resize_page(pix_map)
            return pix_map

        return None

    def get_current_page_title(self):
        return self.comic.get_current_page_title() if self.comic else ''

    def set_current_page_index(self, idx):
        if self.comic:
            self.comic.set_current_page_index(idx)

    def get_current_page_index(self):
        return self.comic.current_page_index if self.comic else -1

    def is_first_page(self):
        if self.comic and self.comic.current_page_index == 0:
            return True
        return False

    def is_last_page(self):
        if self.comic and self.comic.current_page_index + 1 == \
                self.comic.get_number_of_pages():
            return True
        return False

    def is_firts_comic(self):
        return self.path_file_filter.is_first_file()

    def is_last_comic(self):
        return self.path_file_filter.is_last_file()

    def _rotate_page(self, pix_map):
        if self.rotate_angle != 0:
            trans = QtGui.QTransform().rotate(self.rotate_angle)
            pix_map = QtGui.QPixmap(pix_map.transformed(trans))
        return pix_map

    def _resize_page(self, pix_map):

        if self.fit_type == MainWindowModel._VERTICAL_FIT:
            pix_map = pix_map.scaledToHeight(self.scroll_area_size.height(),
                                             QtCore.Qt.SmoothTransformation)

        elif self.fit_type == MainWindowModel._HORIZONTAL_FIT:
            pix_map = pix_map.scaledToWidth(self.scroll_area_size.width(),
                                            QtCore.Qt.SmoothTransformation)

        elif self.fit_type == MainWindowModel._BEST_FIT:
            pix_map = pix_map.scaledToWidth(
                self.scroll_area_size.width() * 0.8,
                QtCore.Qt.SmoothTransformation)

        return pix_map

    def original_fit(self):
        self.fit_type = MainWindowModel._ORIGINAL_FIT

    def vertical_fit(self):
        self.fit_type = MainWindowModel._VERTICAL_FIT

    def horizontal_fit(self):
        self.fit_type = MainWindowModel._HORIZONTAL_FIT

    def best_fit(self):
        self.fit_type = MainWindowModel._BEST_FIT

    @QtCore.Slot(int)
    def load_progressbar_value(self, percent):
        self.load_progress.emit(percent)

    @QtCore.Slot()
    def load_progressbar_done(self):
        self.load_done.emit()

    def save_settings(self):
        self.save_view_adjust(self.fit_type)
        self.save_current_directory(self.current_directory)

    @staticmethod
    def get_bookmark_list(n):
        BookmarkManager.connect()
        bookmark_list = BookmarkManager.get_bookmarks(n)
        BookmarkManager.close()
        return bookmark_list

    def is_bookmark(self):
        BookmarkManager.connect()
        is_bookmark = BookmarkManager.is_bookmark(self.comic.get_path())
        BookmarkManager.close()
        return is_bookmark

    @staticmethod
    def get_bookmark_from_path(path):
        BookmarkManager.connect()
        bk = BookmarkManager.get_bookmark_by_path(path)
        BookmarkManager.close()
        return bk

    def add_bookmark(self):
        if self.comic:
            BookmarkManager.connect()
            BookmarkManager.add_bookmark(self.comic.name,
                                         self.comic.get_path(),
                                         self.comic.get_current_page_number(),
                                         self.comic.get_current_page().data)
            BookmarkManager.close()

    def remove_bookmark(self):
        if self.comic:
            BookmarkManager.connect()
            BookmarkManager.remove_bookmark(self.comic.get_path())
            BookmarkManager.close()
miLibrero.agregaRevista(
    Revista(nombreR="Mi bebé y yo",
            articulosR="Salud y cuidados, Alimentacion, Juegos ",
            editorialR="Zinet Media Global",
            fechaEmision="enero 2020"))

miLibrero.agregaRevista(
    Revista(nombreR="National Geographic",
            articulosR="Fotografía",
            editorialR="Zinet Media Global",
            fechaEmision="noviembre 2017"))

# Comic
miLibrero.agregarComic(
    Comic(autor="Gerard Way",
          titulo="The umbrella academy",
          anio="2018",
          editorial="Dark Horse Comics"))

# Manga
miLibrero.agregarManga(
    Manga(autorM="Sui ishida", tituloM="Tokyo Ghoul: re", editorialM="Panni"))

miLibrero.agregarManga(
    Manga(tituloM="Suicide boy",
          autorM="ParkGee",
          numeroM="57",
          tomoM="2",
          editorialM="Lezhin"))

miLibrero.agregarManga(
    Manga(tituloM="Platinum end",
Esempio n. 9
0
 def get(self, date):
     if date not in self.comics:
         comic = Comic(date)
         self.comics[comic.date_str()] = comic
     url = self.comics[date].url()
     return {'url': url, 'seps': '224 457 666'}
Esempio n. 10
0
def editComic(comic_id):
    comic = Comic(request.form.get('name'), request.form.get('description'),
                  request.form.get('thumbnail'))

    return jsonify(comics.editComic(comic_id, comic=comic))
Esempio n. 11
0
def createComic():
    comic = Comic(request.form.get('name'), request.form.get('description'),
                  request.form.get('thumbnail'))

    return jsonify(comics.createComic(comic=comic))
class MainWindowModel(QtCore.QObject):
    _ORIGINAL_FIT = 'action_original_fit'
    _VERTICAL_FIT = 'action_vertical_fit'
    _HORIZONTAL_FIT = 'action_horizontal_fit'
    _BEST_FIT = 'action_best_fit'

    load_progress = QtCore.Signal(int)
    load_done = QtCore.Signal()

    def __init__(self):
        QtCore.QObject.__init__(self)
        self.comic = None
        self.settings_manager = SettingsManager()
        self.rotate_angle = 0
        self.scroll_area_size = None
        self.fit_type = self.load_view_adjust(MainWindowModel._ORIGINAL_FIT)
        self.current_directory = self.load_current_directory()

        ext_list = ["*.cbr", "*.cbz", "*.rar", "*.zip", "*.tar", "*.cbt"]
        self.path_file_filter = PathFileFilter(ext_list)

    def save_recent_files(self, recent_files_list):
        self.settings_manager.save_recent_files(recent_files_list)

    def load_recent_files(self):
        return self.settings_manager.load_recent_files()

    def save_view_adjust(self, object_name):
        self.settings_manager.save_view_adjust(object_name)

    def load_view_adjust(self, default_object_name):
        return self.settings_manager.load_view_adjust(default_object_name)

    def save_current_directory(self, current_directory):
        self.settings_manager.save_current_directory(current_directory)

    def load_current_directory(self):
        return self.settings_manager.load_current_directory()

    def load(self, filename, initial_page=0):

        image_extensions = ['.bmp', '.jpg', '.jpeg', '.gif', '.png', '.pbm',
                            '.pgm', '.ppm', '.tiff', '.xbm', '.xpm', '.webp']

        loader = LoaderFactory.create_loader(
            Utility.get_file_extension(filename), set(image_extensions))

        loader.progress.connect(self.load_progressbar_value)

        try:
            loader.load(filename)
        except NoDataFindException as excp:
            # Caso nao exista nenhuma imagem, carregamos a imagem indicando
            # erro
            from page import Page
            print excp.message
            q_file = QtCore.QFile(":/icons/notCover.png")
            q_file.open(QtCore.QIODevice.ReadOnly)
            loader.data.append(Page(q_file.readAll(), 'exit_red_1.png', 0))

        self.comic = Comic(Utility.get_base_name(filename),
                           Utility.get_dir_name(filename), initial_page)

        self.comic.pages = loader.data
        self.current_directory = Utility.get_dir_name(filename)
        self.path_file_filter.parse(filename)

    def save_current_page_image(self, file_name):
        self.get_current_page().save(file_name)

    def next_page(self):
        if self.comic:
            self.comic.go_next_page()

    def previous_page(self):
        if self.comic:
            self.comic.go_previous_page()

    def first_page(self):
        if self.comic:
            self.comic.go_first_page()

    def last_page(self):
        if self.comic:
            self.comic.go_last_page()

    def next_comic(self):
        return self.path_file_filter.next_path.decode('utf-8')

    def previous_comic(self):
        return self.path_file_filter.previous_path.decode('utf-8')

    def rotate_left(self):
        self.rotate_angle = (self.rotate_angle - 90) % 360

    def rotate_right(self):
        self.rotate_angle = (self.rotate_angle + 90) % 360

    def get_comic_name(self):
        return self.comic.name if self.comic else ''

    def get_comic_title(self):
        return self.comic.name + ' - Pynocchio Comic Reader'

    def get_current_page(self):
        if self.comic:
            pix_map = self.comic.get_current_page().pixmap
            pix_map = self._rotate_page(pix_map)
            pix_map = self._resize_page(pix_map)
            return pix_map

        return None

    def get_current_page_title(self):
        return self.comic.get_current_page_title() if self.comic else ''

    def set_current_page_index(self, idx):
        if self.comic:
            self.comic.set_current_page_index(idx)

    def get_current_page_index(self):
        return self.comic.current_page_index if self.comic else -1

    def is_first_page(self):
        if self.comic and self.comic.current_page_index == 0:
            return True
        return False

    def is_last_page(self):
        if self.comic and self.comic.current_page_index + 1 == \
                self.comic.get_number_of_pages():
            return True
        return False

    def is_firts_comic(self):
        return self.path_file_filter.is_first_file()

    def is_last_comic(self):
        return self.path_file_filter.is_last_file()

    def _rotate_page(self, pix_map):
        if self.rotate_angle != 0:
            trans = QtGui.QTransform().rotate(self.rotate_angle)
            pix_map = QtGui.QPixmap(pix_map.transformed(trans))
        return pix_map

    def _resize_page(self, pix_map):

        if self.fit_type == MainWindowModel._VERTICAL_FIT:
            pix_map = pix_map.scaledToHeight(
                self.scroll_area_size.height(),
                QtCore.Qt.SmoothTransformation)

        elif self.fit_type == MainWindowModel._HORIZONTAL_FIT:
            pix_map = pix_map.scaledToWidth(
                self.scroll_area_size.width(),
                QtCore.Qt.SmoothTransformation)

        elif self.fit_type == MainWindowModel._BEST_FIT:
            pix_map = pix_map.scaledToWidth(
                self.scroll_area_size.width() * 0.8,
                QtCore.Qt.SmoothTransformation)

        return pix_map

    def original_fit(self):
        self.fit_type = MainWindowModel._ORIGINAL_FIT

    def vertical_fit(self):
        self.fit_type = MainWindowModel._VERTICAL_FIT

    def horizontal_fit(self):
        self.fit_type = MainWindowModel._HORIZONTAL_FIT

    def best_fit(self):
        self.fit_type = MainWindowModel._BEST_FIT

    @QtCore.Slot(int)
    def load_progressbar_value(self, percent):
        self.load_progress.emit(percent)

    @QtCore.Slot()
    def load_progressbar_done(self):
        self.load_done.emit()

    def save_settings(self):
        self.save_view_adjust(self.fit_type)
        self.save_current_directory(self.current_directory)

    @staticmethod
    def get_bookmark_list(qty):
        BookmarkManager.connect()
        bookmark_list = BookmarkManager.get_bookmarks(qty)
        BookmarkManager.close()
        return bookmark_list

    def is_bookmark(self):
        BookmarkManager.connect()
        is_bookmark = BookmarkManager.is_bookmark(self.comic.get_path())
        BookmarkManager.close()
        return is_bookmark

    @staticmethod
    def get_bookmark_from_path(path):
        BookmarkManager.connect()
        bookmark = BookmarkManager.get_bookmark_by_path(path)
        BookmarkManager.close()
        return bookmark

    def add_bookmark(self):
        if self.comic:
            BookmarkManager.connect()
            BookmarkManager.add_bookmark(self.comic.name,
                                         self.comic.get_path(),
                                         self.comic.get_current_page_number(),
                                         self.comic.get_current_page().data)
            BookmarkManager.close()

    def remove_bookmark(self):
        if self.comic:
            BookmarkManager.connect()
            BookmarkManager.remove_bookmark(self.comic.get_path())
            BookmarkManager.close()
 def get(self, date):
   if date not in self.comics:
     comic = Comic(date)
     self.comics[comic.date_str()] = comic
   url = self.comics[date].url()
   return {'url': url, 'seps': '224 457 666'}
Esempio n. 14
0
def fetchcomic(request, overwrite=False, startpage=None, pages=-1):
    """Fetches the comic described in the given request"""
    from utils import getcomiclist, printiter
    # If it is not a comic name that is known
    if os.path.exists(request):
        with open(request) as f:
            specs = toml.load(f)
        title = specs['title']
        directory = os.path.dirname(request) or os.getcwd()
    else:
        title = request.strip()
        directory = os.getcwd()

    if (not title in getcomiclist()) or overwrite:
        if not os.path.exists(request):
            return print(
                "Could not find any specfile or comic '{0}'!".format(request))

        # Validate the given specification
        print("Validating... ", end="")
        valid, errors = validate_specs(specs, directory=directory)
        print("OK" if valid else "FAILED")
        if not valid:
            print(
                "Cannot fetch a comic from the given spec due to the following errors:"
            )
            return printiter(errors)

        Comic.create(specs, directory=directory)

    print("Preparing scrape...")
    with Comic.load(title) as comic:
        print("- Comic:", comic)
        link_identifier = Identifier.load(comic.progress['link_identifier'])
        image_identifier = Identifier.load(comic.progress['image_identifier'])

        lastimages = comic.progress['lastimages']
        remaining = pages
        reconnect = comic.progress.get('reconnect', False)
        lastpage = comic.progress['lastpage']
        if (not lastpage) or startpage:  # No previous, or start supplied
            nextpage = startpage or specs['startpage']
            print("- Starting new scrape from", nextpage)
        else:
            print("- Resuming scrape from", lastpage)
            data = _getter.get_read(lastpage)
            soup = BeautifulSoup(data)
            nextpage = findlink(soup, lastpage, link_identifier)

        # Do the actual scraping
        try:
            if nextpage:
                pagestamp = "({0} pages)".format(pages) if (
                    pages != -1) else ""
                print("Starting scrape..." + pagestamp)

            while nextpage and remaining:  # There is a way!
                print("- {0:03}: {1}".format(comic.progress['lastindex'] + 1,
                                             nextpage))
                data = _getter.get_read(nextpage, reconnect=reconnect)
                soup = BeautifulSoup(data)
                imageurls = findimages(soup, nextpage, image_identifier)
                if not imageurls:
                    print(
                        "No images found at '{0}'! Ending...".format(nextpage))
                    break
                if imageurls == lastimages:
                    print("Image duplicates found at '{0}'! Ending...".format(
                        nextpage))
                    break
                for url in imageurls:
                    comic.add(url, reconnect=reconnect)
                comic.setscraped(nextpage, imageurls)
                lastimages = imageurls  # Don't repeat content!
                lastpage = nextpage
                nextpage = findlink(soup, nextpage, link_identifier)
                if nextpage == lastpage:
                    print("No further links found at '{0}'! Ending...".format(
                        lastpage))
                    break
                remaining -= 1
            lastpage = comic.progress['lastpage']
            print(
                "No more comics found after '{0}', ending...".format(lastpage))
        except KeyboardInterrupt:
            print("\nInterrupted!")
            print("Progress:")
            print("- Last page: ", comic.progress['lastpage'])
            print("- Last index:", comic.progress['lastindex'])
            print("Closing...", end=" ")
        except Exception as e:
            print("CAUGHT EXCEPTION!")
            print("Closing...", end=" ")
            raise

    meta = {"lastcomic": title}
    with open(lastcomicfile, "w") as f:
        toml.dump(meta, f)
    print("Scrape ended.")