From 575bb34ea0f1a6092764d98bb86e916b3ea600ad Mon Sep 17 00:00:00 2001 From: Xevion Date: Sun, 19 Jan 2020 23:18:51 -0600 Subject: [PATCH 01/20] finish episode builder, change deleted scene handler to use -1 for false and track nth Deleted Scene --- app/models.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/models.py b/app/models.py index 4c9976e..87f354f 100644 --- a/app/models.py +++ b/app/models.py @@ -34,7 +34,7 @@ class Season(db.Model): @property def episodes(self): """returns a List of Episodes under this Season""" - return Episode.query.filter_by(season=self).all() + return Episode.query.filter_by(season=self).all().sort(key=lambda ep : ep.number) @property def characters(self, sort): @@ -55,11 +55,12 @@ class Episode(db.Model): soup = BeautifulSoup(data, 'html.parser') sections = soup.find_all(attrs={'class' : 'quote'}) + deleted = 0 for section in sections: - quotes = [] - for quote in section.find_all("b"): - quotes.append(quote.string + quote.next_sibling.string) - deleted = quotes[0].startswith('Deleted Scene'): + quotes = [quote.string + quote.next_sibling.string for quote in section.find_all('b')] + isDeletedScene = quotes[0].lower().startswith('deleted scene') + if isDeletedScene: deleted += 1 + s = Section(episode=self, deleted=deleted if isDeletedScene else -1, quotes=) @property def scrapeURL(self): @@ -69,7 +70,7 @@ class Section(db.Model): """represents a Section of Quotes, a specific scene with relevant dialog""" id = db.Column(db.Integer, primary_key=True) episode_id = db.Column(db.Integer, db.ForeignKey('episode.id')) - deleted = db.Column(db.Boolean) + deleted = db.Column(db.Integer, default=-1) quotes = db.relationship('Quote', backref='section', lazy='dynamic') def build(self, quotes, commit=False): From 9c00745503dff0420a837687159cff9076aa6191 Mon Sep 17 00:00:00 2001 From: Xevion Date: Sun, 19 Jan 2020 23:19:48 -0600 Subject: [PATCH 02/20] add session add & commit, fix quote arg --- app/models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index 87f354f..df60a51 100644 --- a/app/models.py +++ b/app/models.py @@ -60,7 +60,9 @@ class Episode(db.Model): quotes = [quote.string + quote.next_sibling.string for quote in section.find_all('b')] isDeletedScene = quotes[0].lower().startswith('deleted scene') if isDeletedScene: deleted += 1 - s = Section(episode=self, deleted=deleted if isDeletedScene else -1, quotes=) + s = Section(episode=self, deleted=deleted if isDeletedScene else -1, quotes=quotes) + db.session.add(s) + db.session.commit() @property def scrapeURL(self): From 94099c364dc4a1d31603d32d12a70a97a03a95e4 Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 06:08:16 -0600 Subject: [PATCH 03/20] fix assert, fix quote patern, fix Section builder with deleted scene handling, added clearing methods, added Section repr --- app/models.py | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/app/models.py b/app/models.py index df60a51..a7047bf 100644 --- a/app/models.py +++ b/app/models.py @@ -5,14 +5,14 @@ from bs4 import BeautifulSoup from app import db, login episodes = [5, 6, 22, 23, 14, 26, 24, 24, 24, 23] -quotePattern = r'(\w+):.+' +quotePattern = r'([\w\s]+):(.+)' class Season(db.Model): id = db.Column(db.Integer, primary_key=True) episodes = db.relationship('Episode', backref='season', lazy='dynamic') def __init__(self, **kwargs): - assert 0 >= kwargs.get('id') <= 9, "Season ID must be 0-9 inclusive" + assert 0 <= kwargs.get('id') <= 9, "Season ID must be 0-9 inclusive" super(Season, self).__init__(**kwargs) def build(self): @@ -50,20 +50,30 @@ class Episode(db.Model): def build(self): """downloads, processes, and automatically creates Sections and Quotes""" - link = f'http://officequotes.net/no{self.season_id}-{str(self.episode).zfill(2)}.php' + link = f'http://officequotes.net/no{self.season_id}-{str(self.number).zfill(2)}.php' data = requests.get(link).text soup = BeautifulSoup(data, 'html.parser') sections = soup.find_all(attrs={'class' : 'quote'}) deleted = 0 + for section in sections: quotes = [quote.string + quote.next_sibling.string for quote in section.find_all('b')] isDeletedScene = quotes[0].lower().startswith('deleted scene') - if isDeletedScene: deleted += 1 - s = Section(episode=self, deleted=deleted if isDeletedScene else -1, quotes=quotes) + if isDeletedScene: + deleted += 1 + s = Section(episode_id=self.id, deleted=deleted if isDeletedScene else -1) + s.build(quotes[1:] if isDeletedScene else quotes) db.session.add(s) db.session.commit() + def clear(self): + sections = Section.query.filter_by(episode_id=self.id).all() + print(f'Clearing {len(sections)} from Databse for Episode {self.number} of Season {self.season_id}') + for section in sections: + section.clear(commit=False) + db.session.commit() + @property def scrapeURL(self): return f'http://officequotes.net/no{self.season_id}-{str(self.number).zfill(2)}.php' @@ -75,17 +85,29 @@ class Section(db.Model): deleted = db.Column(db.Integer, default=-1) quotes = db.relationship('Quote', backref='section', lazy='dynamic') - def build(self, quotes, commit=False): + def build(self, quotes, commit=False, reset=False): """given an List of unformatted script quotes, automatically creates Quotes assigned to this Section""" for quote in quotes: if quote.lower().startswith('deleted scene'): raise Exception(f'Deleted Scene Quote passed to Section Builder: "{quote}"') match = re.match(quotePattern, quote) assert match != None, f"Quote '{quote}' could not be processed." - q = Quote(section=self, speaker=match[1], text=match[2]) + q = Quote(section=self, speaker=match[1].strip(), text=match[2].strip()) db.session.add(q) if commit: db.session.commit() + def clear(self, commit=True): + quotes = Quote.query.filter_by(section_id=self.id).all() + print(f'Clearing {len(quotes)} quotes from Section ID {self.id}') + for quote in quotes: + db.session.delete(quote) + if commit: db.session.commit() + + def __repr__(self): + season = Episode.query.get(self.episode_id).first().id + quotes = len(Quote.query.filter_by(section_id=self.id).all()) + return f'Section(id={self.id} episode={self.episode_id} season={season} quotes=[{quotes}...])' + class Quote(db.Model): """represents a specific quote by a specific speaker""" id = db.Column(db.Integer, primary_key=True) From 18607442ecb2302efe19bea544dfb99c675e7895 Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 06:18:05 -0600 Subject: [PATCH 04/20] Episode repr & fix clearer not destroying sections, fix Section repr --- app/models.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/models.py b/app/models.py index a7047bf..17fd50c 100644 --- a/app/models.py +++ b/app/models.py @@ -69,15 +69,20 @@ class Episode(db.Model): def clear(self): sections = Section.query.filter_by(episode_id=self.id).all() - print(f'Clearing {len(sections)} from Databse for Episode {self.number} of Season {self.season_id}') + print(f'Clearing {len(sections)} Sections of Ep {self.number} Season {self.season_id}') for section in sections: section.clear(commit=False) + db.session.delete(section) db.session.commit() @property def scrapeURL(self): return f'http://officequotes.net/no{self.season_id}-{str(self.number).zfill(2)}.php' + def __repr__(self): + sections = len(Section.query.filter_by(episode_id=self.id).all()) + return f'Episode(s={self.season_id} ep={self.number} sects=[{sections}...])' + class Section(db.Model): """represents a Section of Quotes, a specific scene with relevant dialog""" id = db.Column(db.Integer, primary_key=True) @@ -104,9 +109,9 @@ class Section(db.Model): if commit: db.session.commit() def __repr__(self): - season = Episode.query.get(self.episode_id).first().id + season = Episode.query.get(self.episode_id).id quotes = len(Quote.query.filter_by(section_id=self.id).all()) - return f'Section(id={self.id} episode={self.episode_id} season={season} quotes=[{quotes}...])' + return f'Section(id={self.id} S-EP={season}/{self.episode_id} quotes=[{quotes}...])' class Quote(db.Model): """represents a specific quote by a specific speaker""" From 2053d5f1c1b171cf58b9ca2e3637a4c6bcb8ff3e Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 06:21:07 -0600 Subject: [PATCH 05/20] Quote repr --- app/models.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index 17fd50c..6af795d 100644 --- a/app/models.py +++ b/app/models.py @@ -119,4 +119,7 @@ class Quote(db.Model): section_id = db.Column(db.Integer, db.ForeignKey('section.id')) # The section this quote belongs to. speaker = db.Column(db.String(32)) # The name of a character text = db.Column(db.String(512)) # The content of the Quote. Usually a sentence, sometimes more. - section_index = db.Column(db.Integer) # The index of this quote in the section \ No newline at end of file + section_index = db.Column(db.Integer) # The index of this quote in the section + + def __repr__(self): + return f"Quote(speaker='{self.speaker}' text={self.text[:50]}{'...' if len(self.text) > 51 else ''})" \ No newline at end of file From c86d299ef122a772174f87f30a6fbc95762c301c Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 15:22:18 -0600 Subject: [PATCH 06/20] periods in speaker, Quote text quotes, Season builder fixes --- app/models.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/models.py b/app/models.py index 6af795d..46d5033 100644 --- a/app/models.py +++ b/app/models.py @@ -5,7 +5,7 @@ from bs4 import BeautifulSoup from app import db, login episodes = [5, 6, 22, 23, 14, 26, 24, 24, 24, 23] -quotePattern = r'([\w\s]+):(.+)' +quotePattern = r'([\w\s\.]+):(.+)' class Season(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -18,18 +18,19 @@ class Season(db.Model): def build(self): """runs build operations on every Episode under this season""" for episode in range(1, episodes[self.id - 1] + 1): - ep = Episode.query.filter_by(season=self, number=episode).first() + print('Running build()') + ep = Episode.query.filter_by(season_id=self.id, number=episode).first() if ep is None: # Add the episode, then build print(f'Creating new Episode, Season {self.id}, Episode {episode}') - ep = Episode(season=self, number=episode) + ep = Episode(season_id=self.id, number=episode) db.session.add(ep) # I'm commiting early, which is a bit taboo, but I'm more worried about what the Episode object will need while building. db.session.commit() + ep.build() else: # Regardless of whether it existended before hand, the episode will be built. pass - ep.build() @property def episodes(self): @@ -122,4 +123,4 @@ class Quote(db.Model): section_index = db.Column(db.Integer) # The index of this quote in the section def __repr__(self): - return f"Quote(speaker='{self.speaker}' text={self.text[:50]}{'...' if len(self.text) > 51 else ''})" \ No newline at end of file + return f"Quote(speaker='{self.speaker}' text='{self.text[:50]}{'...' if len(self.text) > 51 else ''}')" \ No newline at end of file From 15d163b3ef4e86c40f2645446518fa4fbaad2acb Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 16:12:17 -0600 Subject: [PATCH 07/20] create a Season wide builder --- app/models.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/models.py b/app/models.py index 46d5033..cbf69bc 100644 --- a/app/models.py +++ b/app/models.py @@ -31,6 +31,16 @@ class Season(db.Model): else: # Regardless of whether it existended before hand, the episode will be built. pass + + @staticmethod + def create_all(build=True): + """creates new Season objects and runs build() on them""" + for i in range(1, 10): + if Season.query.get(i) is None: + s = Season(id=i) + db.session.add(s) + s.build() + db.session.commit() @property def episodes(self): From aafd477d554f8ee8ded323656a2d015e5e39e4f9 Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 16:12:30 -0600 Subject: [PATCH 08/20] start adding HTML viewing options --- app/routes.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/app/routes.py b/app/routes.py index 91130d5..be7e855 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,6 +1,22 @@ +from flask import send_from_directory, redirect, url_for, render_template, request +from app.models import Season, Episode from app import app -from flask import send_from_directory, redirect, url_for, render_template @app.route('/') def index(): - return 'WIP' \ No newline at end of file + return 'WIP' + +@app.route('/view') +def view(): + seasonID = request.args.get('season') + episodeNUM = request.args.get('episode') + + season = Season.query.get(int(seasonID)) + episode = Episode.query.filter_by(season_id=season.id, number=int(episodeNUM)) + + if season: + if episode: + return render_template('episode.html') + else: + return render_template('season.html', season=Season.query.get()) + return redirect(url_for('index')) \ No newline at end of file From 98bef2f46fe2a26e78588ecdf2be73b2b14f7b00 Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 16:12:39 -0600 Subject: [PATCH 09/20] first templates --- app/templates/episode.html | 0 app/templates/season.html | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/templates/episode.html create mode 100644 app/templates/season.html diff --git a/app/templates/episode.html b/app/templates/episode.html new file mode 100644 index 0000000..e69de29 diff --git a/app/templates/season.html b/app/templates/season.html new file mode 100644 index 0000000..e69de29 From da69e4812a2862ecf1ed57fe80867faa3438347f Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 16:18:57 -0600 Subject: [PATCH 10/20] add static methods for database clearing/building of scripts --- app/models.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/models.py b/app/models.py index cbf69bc..b95ec5e 100644 --- a/app/models.py +++ b/app/models.py @@ -5,7 +5,7 @@ from bs4 import BeautifulSoup from app import db, login episodes = [5, 6, 22, 23, 14, 26, 24, 24, 24, 23] -quotePattern = r'([\w\s\.]+):(.+)' +quotePattern = r'([\w\s\.\',-\[\]\d&\"]+):(.+)' class Season(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -39,11 +39,15 @@ class Season(db.Model): if Season.query.get(i) is None: s = Season(id=i) db.session.add(s) - s.build() + if build: s.build() db.session.commit() + + @staticmethod + def rebuild_all(): + """runs build() on all Season objects in database""" @property - def episodes(self): + def episodes(self): """returns a List of Episodes under this Season""" return Episode.query.filter_by(season=self).all().sort(key=lambda ep : ep.number) @@ -90,6 +94,12 @@ class Episode(db.Model): def scrapeURL(self): return f'http://officequotes.net/no{self.season_id}-{str(self.number).zfill(2)}.php' + @staticmethod + def clear_all(): + """runs clear() on every episode in the database""" + for episode in Episode.query.all(): + episode.clear() + def __repr__(self): sections = len(Section.query.filter_by(episode_id=self.id).all()) return f'Episode(s={self.season_id} ep={self.number} sects=[{sections}...])' From 2fbfcb85a57b004f19924c9e9a4733ba8b8b03f2 Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 16:34:36 -0600 Subject: [PATCH 11/20] rebuild_all() and Season.build() printing notification multiple times --- .gitignore | 3 ++- app/models.py | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 0eec845..a2e4b43 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ migrations/** app.db keys.json process.py +app.db-journal # Byte-compiled / optimized / DLL files __pycache__/ @@ -133,4 +134,4 @@ venv.bak/ dmypy.json # Pyre type checker -.pyre/ \ No newline at end of file +.pyre/ diff --git a/app/models.py b/app/models.py index b95ec5e..921b389 100644 --- a/app/models.py +++ b/app/models.py @@ -5,7 +5,7 @@ from bs4 import BeautifulSoup from app import db, login episodes = [5, 6, 22, 23, 14, 26, 24, 24, 24, 23] -quotePattern = r'([\w\s\.\',-\[\]\d&\"]+):(.+)' +quotePattern = r'([\w\s\.\',-\[\]\d&\"#]+):(.+)' class Season(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -18,7 +18,7 @@ class Season(db.Model): def build(self): """runs build operations on every Episode under this season""" for episode in range(1, episodes[self.id - 1] + 1): - print('Running build()') + print(f'Running build() on Season {self.id}') ep = Episode.query.filter_by(season_id=self.id, number=episode).first() if ep is None: # Add the episode, then build @@ -45,6 +45,8 @@ class Season(db.Model): @staticmethod def rebuild_all(): """runs build() on all Season objects in database""" + for season in Season.query.all(): + season.build() @property def episodes(self): From 9a01764812df1ce706289390b32df98a2cca4c26 Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 16:35:58 -0600 Subject: [PATCH 12/20] add rebuild parameter, fix multi printing --- app/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/models.py b/app/models.py index 921b389..00ad675 100644 --- a/app/models.py +++ b/app/models.py @@ -15,10 +15,10 @@ class Season(db.Model): assert 0 <= kwargs.get('id') <= 9, "Season ID must be 0-9 inclusive" super(Season, self).__init__(**kwargs) - def build(self): + def build(self, rebuild=False): """runs build operations on every Episode under this season""" + print(f'Running build() on Season {self.id}') for episode in range(1, episodes[self.id - 1] + 1): - print(f'Running build() on Season {self.id}') ep = Episode.query.filter_by(season_id=self.id, number=episode).first() if ep is None: # Add the episode, then build @@ -29,7 +29,8 @@ class Season(db.Model): db.session.commit() ep.build() else: - # Regardless of whether it existended before hand, the episode will be built. + if rebuild: + ep.build() pass @staticmethod From 81365da041f2115970749f3423169582bb253303 Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 17:08:13 -0600 Subject: [PATCH 13/20] add more rebuild prints, episode id in repr, change Quote processing to use simpler processing. hopefully once I look into how it works, it will successfully process everything --- app/models.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/app/models.py b/app/models.py index 00ad675..3fc5364 100644 --- a/app/models.py +++ b/app/models.py @@ -4,7 +4,7 @@ import re from bs4 import BeautifulSoup from app import db, login -episodes = [5, 6, 22, 23, 14, 26, 24, 24, 24, 23] +episodes = [5, 6, 22, 23, 14, 26, 24, 24, 24, 23] # Episode counts. Index 0 is for Webisodes. quotePattern = r'([\w\s\.\',-\[\]\d&\"#]+):(.+)' class Season(db.Model): @@ -29,6 +29,7 @@ class Season(db.Model): db.session.commit() ep.build() else: + print(f'Rebuilding Season {self.id}, Episode {episode}') if rebuild: ep.build() pass @@ -47,7 +48,7 @@ class Season(db.Model): def rebuild_all(): """runs build() on all Season objects in database""" for season in Season.query.all(): - season.build() + season.build(rebuild=True) @property def episodes(self): @@ -76,7 +77,11 @@ class Episode(db.Model): deleted = 0 for section in sections: - quotes = [quote.string + quote.next_sibling.string for quote in section.find_all('b')] + try: + quotes = [quote.string + quote.next_sibling.string for quote in section.find_all('b')] + except BaseException as e: + print(section) + raise e isDeletedScene = quotes[0].lower().startswith('deleted scene') if isDeletedScene: deleted += 1 @@ -105,7 +110,7 @@ class Episode(db.Model): def __repr__(self): sections = len(Section.query.filter_by(episode_id=self.id).all()) - return f'Episode(s={self.season_id} ep={self.number} sects=[{sections}...])' + return f'Episode(id={self.id} s={self.season_id} ep={self.number} sects=[{sections}...])' class Section(db.Model): """represents a Section of Quotes, a specific scene with relevant dialog""" @@ -119,9 +124,11 @@ class Section(db.Model): for quote in quotes: if quote.lower().startswith('deleted scene'): raise Exception(f'Deleted Scene Quote passed to Section Builder: "{quote}"') - match = re.match(quotePattern, quote) - assert match != None, f"Quote '{quote}' could not be processed." - q = Quote(section=self, speaker=match[1].strip(), text=match[2].strip()) + # match = re.match(quotePattern, quote) + # assert match != None, f"Quote '{quote}' could not be processed." + # q = Quote(section=self, speaker=match[1].strip(), text=match[2].strip()) + mark = quote.find(':') + q = Quote(section=self, speaker=quote[:mark], text=quote[mark + 1:]) db.session.add(q) if commit: db.session.commit() From c12eb65eb29603864d7d1bb19d25604696116e6c Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 17:12:01 -0600 Subject: [PATCH 14/20] add comments, add section index to Quote, making printing optional on Section.clear(), remove scrapeURL --- app/models.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/models.py b/app/models.py index 3fc5364..03e25f4 100644 --- a/app/models.py +++ b/app/models.py @@ -91,6 +91,7 @@ class Episode(db.Model): db.session.commit() def clear(self): + """delete all sections relevant to this episode in order to reprocess""" sections = Section.query.filter_by(episode_id=self.id).all() print(f'Clearing {len(sections)} Sections of Ep {self.number} Season {self.season_id}') for section in sections: @@ -98,10 +99,6 @@ class Episode(db.Model): db.session.delete(section) db.session.commit() - @property - def scrapeURL(self): - return f'http://officequotes.net/no{self.season_id}-{str(self.number).zfill(2)}.php' - @staticmethod def clear_all(): """runs clear() on every episode in the database""" @@ -121,20 +118,21 @@ class Section(db.Model): def build(self, quotes, commit=False, reset=False): """given an List of unformatted script quotes, automatically creates Quotes assigned to this Section""" - for quote in quotes: + for i, quote in enumerate(quotes): if quote.lower().startswith('deleted scene'): raise Exception(f'Deleted Scene Quote passed to Section Builder: "{quote}"') # match = re.match(quotePattern, quote) # assert match != None, f"Quote '{quote}' could not be processed." # q = Quote(section=self, speaker=match[1].strip(), text=match[2].strip()) mark = quote.find(':') - q = Quote(section=self, speaker=quote[:mark], text=quote[mark + 1:]) + q = Quote(section=self, speaker=quote[:mark], text=quote[mark + 1:], section_index=i) db.session.add(q) if commit: db.session.commit() - def clear(self, commit=True): + def clear(self, doprint=True, commit=True): + """delete all quotes relevant to this section""" quotes = Quote.query.filter_by(section_id=self.id).all() - print(f'Clearing {len(quotes)} quotes from Section ID {self.id}') + if doprint: print(f'Clearing {len(quotes)} quotes from Section ID {self.id}') for quote in quotes: db.session.delete(quote) if commit: db.session.commit() From 5882282c7e2a53495bc3a84b76018bf6b094cedd Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 18:22:12 -0600 Subject: [PATCH 15/20] fix routes up to support rendering using passed Season/Episode still need to decide how to display "errors", perhaps a custom 404 page containing all episode links --- app/routes.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/app/routes.py b/app/routes.py index be7e855..1666312 100644 --- a/app/routes.py +++ b/app/routes.py @@ -8,15 +8,12 @@ def index(): @app.route('/view') def view(): - seasonID = request.args.get('season') - episodeNUM = request.args.get('episode') + season = request.args.get('season', default=-1, type=int) + episode = request.args.get('episode', default=-1, type=int) - season = Season.query.get(int(seasonID)) - episode = Episode.query.filter_by(season_id=season.id, number=int(episodeNUM)) - - if season: - if episode: - return render_template('episode.html') + if season != -1: + if episode != -1: + return render_template('episode.html', episode=Episode.query.filter_by(season_id=season, episode=episode).first_or_404()) else: - return render_template('season.html', season=Season.query.get()) + return render_template('season.html', season=Season.query.filter_by(id=season).first_or_404()) return redirect(url_for('index')) \ No newline at end of file From 0dca7f2a026259ea17bb6017a8f2d7745eaced71 Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 18:22:43 -0600 Subject: [PATCH 16/20] fix linger non id based filter, object based --- app/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models.py b/app/models.py index 03e25f4..e381471 100644 --- a/app/models.py +++ b/app/models.py @@ -53,7 +53,7 @@ class Season(db.Model): @property def episodes(self): """returns a List of Episodes under this Season""" - return Episode.query.filter_by(season=self).all().sort(key=lambda ep : ep.number) + return Episode.query.filter_by(season_id=self.id).all().sort(key=lambda ep : ep.number) @property def characters(self, sort): From a15a2b3344cdb79013a5ee0de75ad98e29d5d657 Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 18:47:45 -0600 Subject: [PATCH 17/20] add in html pages for season and episode, baseline zero css --- app/models.py | 2 +- app/routes.py | 2 +- app/templates/base.html | 13 +++++++++++++ app/templates/content.html | 4 ++++ app/templates/episode.html | 10 ++++++++++ app/templates/season.html | 9 +++++++++ 6 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 app/templates/content.html diff --git a/app/models.py b/app/models.py index e381471..6d32633 100644 --- a/app/models.py +++ b/app/models.py @@ -53,7 +53,7 @@ class Season(db.Model): @property def episodes(self): """returns a List of Episodes under this Season""" - return Episode.query.filter_by(season_id=self.id).all().sort(key=lambda ep : ep.number) + return Episode.query.filter_by(season_id=self.id).all() @property def characters(self, sort): diff --git a/app/routes.py b/app/routes.py index 1666312..efd0199 100644 --- a/app/routes.py +++ b/app/routes.py @@ -13,7 +13,7 @@ def view(): if season != -1: if episode != -1: - return render_template('episode.html', episode=Episode.query.filter_by(season_id=season, episode=episode).first_or_404()) + return render_template('episode.html', episode=Episode.query.filter_by(season_id=season, number=episode).first_or_404()) else: return render_template('season.html', season=Season.query.filter_by(id=season).first_or_404()) return redirect(url_for('index')) \ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html index e69de29..4cbd66b 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -0,0 +1,13 @@ + + + + The Office Quotes{% if title %} - {{ title }}{% endif %} + {% block head %} + {% endblock head %} + + + + {% block body %} + + {% endblock body %} + \ No newline at end of file diff --git a/app/templates/content.html b/app/templates/content.html new file mode 100644 index 0000000..a185b0d --- /dev/null +++ b/app/templates/content.html @@ -0,0 +1,4 @@ +{% extends 'base.html' %} +{% block body %} +{{ super() }} +{% endblock body %} \ No newline at end of file diff --git a/app/templates/episode.html b/app/templates/episode.html index e69de29..bbdfcf8 100644 --- a/app/templates/episode.html +++ b/app/templates/episode.html @@ -0,0 +1,10 @@ +{% extends 'content.html' %} +{% block body %} +{% for section in episode.sections %} +{% for quote in section.quotes %} +{{ quote.speaker }}: {{ quote.text }} +
+{% endfor %} +
+{% endfor %} +{% endblock body %} \ No newline at end of file diff --git a/app/templates/season.html b/app/templates/season.html index e69de29..330244e 100644 --- a/app/templates/season.html +++ b/app/templates/season.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} +{% block body %} +{{ super() }} +Season {{ season.id }} +{% for episode in season.episodes %} +Episode {{ episode.number }} +{% endfor %} + +{% endblock body %} \ No newline at end of file From 8a1b8060c06cdd3504f27ce75f9b15f057a81ca5 Mon Sep 17 00:00:00 2001 From: Xevion Date: Mon, 20 Jan 2020 19:28:05 -0600 Subject: [PATCH 18/20] newpeat quote check --- app/models.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/models.py b/app/models.py index 6d32633..908d79a 100644 --- a/app/models.py +++ b/app/models.py @@ -78,14 +78,18 @@ class Episode(db.Model): for section in sections: try: - quotes = [quote.string + quote.next_sibling.string for quote in section.find_all('b')] - except BaseException as e: - print(section) - raise e + isNewpeat = False + quotes = [] + for quote in section.find_all('b'): + print(quote.string.lower()) + if 'newpeat' in quote.string.lower(): + isNewPeat = True + else: + quotes.append(quote.string + quote.next_sibling.string) isDeletedScene = quotes[0].lower().startswith('deleted scene') if isDeletedScene: deleted += 1 - s = Section(episode_id=self.id, deleted=deleted if isDeletedScene else -1) + s = Section(episode_id=self.id, deleted=deleted if isDeletedScene else -1, newpeat=isNewpeat) s.build(quotes[1:] if isDeletedScene else quotes) db.session.add(s) db.session.commit() @@ -114,6 +118,7 @@ class Section(db.Model): id = db.Column(db.Integer, primary_key=True) episode_id = db.Column(db.Integer, db.ForeignKey('episode.id')) deleted = db.Column(db.Integer, default=-1) + newpeat = db.Column(db.Boolean, default=False) quotes = db.relationship('Quote', backref='section', lazy='dynamic') def build(self, quotes, commit=False, reset=False): From 7cb1121cd0c3d1a8e821491051433054f60240ab Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 21 Jan 2020 03:13:18 -0600 Subject: [PATCH 19/20] attempt at fixing newpeat quotes breaking database building --- app/models.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/app/models.py b/app/models.py index 908d79a..aa454a4 100644 --- a/app/models.py +++ b/app/models.py @@ -71,21 +71,26 @@ class Episode(db.Model): """downloads, processes, and automatically creates Sections and Quotes""" link = f'http://officequotes.net/no{self.season_id}-{str(self.number).zfill(2)}.php' data = requests.get(link).text + open('test.html', 'w+', encoding='utf-8').write(data) soup = BeautifulSoup(data, 'html.parser') - sections = soup.find_all(attrs={'class' : 'quote'}) + sections = soup.find_all(attrs={'class' : 'quote'}) deleted = 0 for section in sections: - try: - isNewpeat = False - quotes = [] - for quote in section.find_all('b'): - print(quote.string.lower()) - if 'newpeat' in quote.string.lower(): - isNewPeat = True - else: - quotes.append(quote.string + quote.next_sibling.string) + isNewpeat = False + quotes = [] + for quote in section.find_all('b'): + if 'Newpeat' in quote.string: + quote = quote.next_sibling + isNewpeat = True + if quote is None or quote.next_sibling is None: + print('Quote is None or next sibling is None') + continue + quotes.append(quote.string + quote.next_sibling.string) + if len(quotes) == 0: + print(f'Section found with Zero quotes. Newpeat: {isNewpeat}') + continue isDeletedScene = quotes[0].lower().startswith('deleted scene') if isDeletedScene: deleted += 1 From 418ea9c2e95c4529011fbed47a7c00902ce16253 Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 21 Jan 2020 06:24:45 -0600 Subject: [PATCH 20/20] add basic "Seasons" view --- .gitignore | 1 + app/routes.py | 2 +- app/templates/season.html | 4 +++- app/templates/view.html | 9 +++++++++ 4 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 app/templates/view.html diff --git a/.gitignore b/.gitignore index a2e4b43..f51df2f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ app.db keys.json process.py app.db-journal +test.html # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/app/routes.py b/app/routes.py index efd0199..9f5ae46 100644 --- a/app/routes.py +++ b/app/routes.py @@ -16,4 +16,4 @@ def view(): return render_template('episode.html', episode=Episode.query.filter_by(season_id=season, number=episode).first_or_404()) else: return render_template('season.html', season=Season.query.filter_by(id=season).first_or_404()) - return redirect(url_for('index')) \ No newline at end of file + return render_template('view.html', seasons=Season.query.all()) \ No newline at end of file diff --git a/app/templates/season.html b/app/templates/season.html index 330244e..aec2de8 100644 --- a/app/templates/season.html +++ b/app/templates/season.html @@ -2,8 +2,10 @@ {% block body %} {{ super() }} Season {{ season.id }} +
{% for episode in season.episodes %} -Episode {{ episode.number }} +Episode {{ episode.number }} +
{% endfor %} {% endblock body %} \ No newline at end of file diff --git a/app/templates/view.html b/app/templates/view.html new file mode 100644 index 0000000..2af8502 --- /dev/null +++ b/app/templates/view.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} +{% block body %} +{{ super() }} +{% for season in seasons %} +Season {{ season.id }} +
+{% endfor %} + +{% endblock body %} \ No newline at end of file