From 88dc400edd8350244eb2c7d03cf75a2e6cf70227 Mon Sep 17 00:00:00 2001 From: muchtea Date: Tue, 8 Sep 2020 15:53:05 +0200 Subject: [PATCH 1/4] Add .idea to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 96c21121..8e34e980 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,9 @@ *.back *.bak +# pycharm project specific settings files +.idea + cleanup.sh FanFictionDownLoader.zip *.epub From cac74157b9388f14af17eead630b7e3a26be9e5c Mon Sep 17 00:00:00 2001 From: muchtea Date: Tue, 8 Sep 2020 15:54:43 +0200 Subject: [PATCH 2/4] fiction.live - add support for multi route stories Route chapters simply are added at the end after the appendices --- fanficfare/adapters/adapter_fictionlive.py | 32 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/fanficfare/adapters/adapter_fictionlive.py b/fanficfare/adapters/adapter_fictionlive.py index 2824fa24..bc4b427c 100644 --- a/fanficfare/adapters/adapter_fictionlive.py +++ b/fanficfare/adapters/adapter_fictionlive.py @@ -87,9 +87,15 @@ class FictionLiveAdapter(BaseSiteAdapter): data = json.loads(response) - # I have no idea how you'd make this work in a book. + ## get metadata for multi route chapters if 'multiRoute' in data and data['multiRoute'] == True: - raise NotImplementedError("Multiple-route fiction.live stories are not supported.") + route_metadata_url = "https://fiction.live/api/anonkun/routes/{s_id}/" + response = self._fetchUrl(route_metadata_url.format(s_id = self.story_id)) + + if not response: # this is how fiction.live responds to nonsense urls -- HTTP200 with empty response + raise exceptions.StoryDoesNotExist("Empty response for " + self.url) + + data["route_metadata"] = json.loads(response) self.extract_metadata(data, get_cover) self.add_chapters(data) @@ -172,20 +178,33 @@ class FictionLiveAdapter(BaseSiteAdapter): ## chapter urls are for the api. they return json and aren't user-navigatable, or the same as on the website chunkrange_url = "https://fiction.live/api/anonkun/chapters/{s_id}/{start}/{end}/" + ## api url to get content of a multi route chapter. requires only the route id and no timestamps + route_chunkrange_url = "https://fiction.live/api/anonkun/route/{c_id}/chapters" + def add_chapter_url(title, start, end): "Adds a chapter url based on the start/end chunk-range timestamps." chapter_url = chunkrange_url.format(s_id = data['_id'], start = start, end = end) self.add_chapter(title, chapter_url) + def add_route_chapter_url(title, route_id): + "Adds a route chapter url based on the route id." + chapter_url = route_chunkrange_url.format(c_id = route_id) + self.add_chapter(title, chapter_url) + ### chapter addition loop. bit complex, as both first and last chapters have special handling ## first thing to do is seperate out the appendices - appendices, maintext = [], [] - chapters = data['bm'] if 'bm' in data else [{"title": "Home", "ct": data['ct']}] + appendices, maintext, routes = [], [], [] + chapters = data['bm'] if 'bm' in data else [{"title": "Home", "ct": data['ct']}] for c in chapters: appendices.append(c) if c['title'].startswith('#special') else maintext.append(c) + ## not all stories use multiple routes. Those that do have a route id and a title for each route + if 'route_metadata' in data and data['route_metadata']: + for r in data['route_metadata']: + routes.append({"id": r['_id'], "title": r['t']}) + # loop setup chapter_iter = iter(maintext) first_chapter = next(chapter_iter) @@ -214,6 +233,11 @@ class FictionLiveAdapter(BaseSiteAdapter): chapter_title = "Appendix: " + a['title'][9:] # 'Appendix: ' rather than '#special' at beginning of name add_chapter_url(chapter_title, chapter_start, chapter_start + 1) # 1 msec range = this one chunk only + for r in routes: # add route at the end, after appendices + route_id = r['id'] # to get route chapter content, the route id is needed, not the timestamp + chapter_title = "Route: " + r['title'] # 'Route: ' at beginning of name, since it's a multiroute chapter + add_route_chapter_url(chapter_title, route_id) + def getChapterText(self, url): chunk_handler = { From 445e26158f475bb22b21d5752ff821ef60e5b3e2 Mon Sep 17 00:00:00 2001 From: muchtea Date: Wed, 9 Sep 2020 20:15:03 +0200 Subject: [PATCH 3/4] fiction.live - add support for internal links from choices to route chapters --- fanficfare/adapters/adapter_fictionlive.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/fanficfare/adapters/adapter_fictionlive.py b/fanficfare/adapters/adapter_fictionlive.py index bc4b427c..a30497a9 100644 --- a/fanficfare/adapters/adapter_fictionlive.py +++ b/fanficfare/adapters/adapter_fictionlive.py @@ -26,7 +26,6 @@ # music / audio embeds # per-user achivement tracking with fancy achievement-get animations # story scripting (shows script tags visible in the text, not computed values or input fields) -# multiroute stories (won't download them at all) import json from datetime import datetime @@ -373,6 +372,23 @@ class FictionLiveAdapter(BaseSiteAdapter): total_votes = counter(chunk['votes'] if 'votes' in chunk else {}) verified_votes = counter(chunk['userVotes'] if 'userVotes' in chunk else {}) + # Choices can link to route chapters, where the index of the choice in list 'choices' is a key in the + # 'routes' dict and the dict value is the route id. + # That route id is needed for the url to create the internal link from the choice to the route chapter. + routes = chunk['routes'] if 'routes' in chunk else {} + if choices and len(routes) > 0: + altered_choices = [] + for i, choice in enumerate(choices): + choice_index = str(i) + if choice_index in routes.keys(): + route_chunkrange_url = "https://fiction.live/api/anonkun/route/{c_id}/chapters" + route_url = route_chunkrange_url.format(c_id=routes[choice_index]) + choice_link = "" + choice + "" + altered_choices.append(choice_link) + else: + altered_choices.append(choice) + choices = altered_choices + return zip(choices, verified_votes, total_votes) def format_choice(self, chunk): From e7496f0e3a113cf22b35e22bbf83d55805394cc7 Mon Sep 17 00:00:00 2001 From: muchtea Date: Thu, 10 Sep 2020 09:09:01 +0200 Subject: [PATCH 4/4] fiction.live - handling possibly optional route titles --- fanficfare/adapters/adapter_fictionlive.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fanficfare/adapters/adapter_fictionlive.py b/fanficfare/adapters/adapter_fictionlive.py index a30497a9..d4cd9618 100644 --- a/fanficfare/adapters/adapter_fictionlive.py +++ b/fanficfare/adapters/adapter_fictionlive.py @@ -202,7 +202,12 @@ class FictionLiveAdapter(BaseSiteAdapter): ## not all stories use multiple routes. Those that do have a route id and a title for each route if 'route_metadata' in data and data['route_metadata']: for r in data['route_metadata']: - routes.append({"id": r['_id'], "title": r['t']}) + # checking if route title even exists or is None, since most things in the api are optional + if 't' in r and r['t'] is not None: + title = r['t'] + else: + title = "" + routes.append({{"id": r['_id'], "title": title}}) # loop setup chapter_iter = iter(maintext)