mirror of
https://github.com/Xevion/the-office.git
synced 2025-12-17 00:13:32 -06:00
reformat using Black
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
# Main Flask and Flask configs
|
# Main Flask and Flask configs
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from config import Config
|
from config import Config
|
||||||
|
|
||||||
# Flask Extensions
|
# Flask Extensions
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from flask_migrate import Migrate
|
from flask_migrate import Migrate
|
||||||
@@ -14,7 +15,7 @@ app.config.from_object(Config)
|
|||||||
app.url_map.strict_slashes = False
|
app.url_map.strict_slashes = False
|
||||||
# App extension setup
|
# App extension setup
|
||||||
login = LoginManager(app)
|
login = LoginManager(app)
|
||||||
login.login_view = 'login'
|
login.login_view = "login"
|
||||||
db = SQLAlchemy(app)
|
db = SQLAlchemy(app)
|
||||||
migrate = Migrate(app, db)
|
migrate = Migrate(app, db)
|
||||||
limiter = Limiter(app, key_func=get_remote_address, default_limits=["10 per second"])
|
limiter = Limiter(app, key_func=get_remote_address, default_limits=["10 per second"])
|
||||||
|
|||||||
124
app/models.py
124
app/models.py
@@ -4,32 +4,44 @@ import re
|
|||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from app import db, login
|
from app import db, login
|
||||||
|
|
||||||
episodes = [5, 6, 22, 23, 14, 26, 24, 24, 24, 23] # Episode counts. Index 0 is for Webisodes.
|
episodes = [
|
||||||
quotePattern = r'([\w\s\.\',-\[\]\d&\"#]+):(.+)'
|
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):
|
class Season(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
episodes = db.relationship('Episode', backref='season', lazy='dynamic')
|
episodes = db.relationship("Episode", backref="season", lazy="dynamic")
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
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)
|
super(Season, self).__init__(**kwargs)
|
||||||
|
|
||||||
def build(self, rebuild=False):
|
def build(self, rebuild=False):
|
||||||
"""runs build operations on every Episode under this season"""
|
"""runs build operations on every Episode under this season"""
|
||||||
print(f'Running build() on Season {self.id}')
|
print(f"Running build() on Season {self.id}")
|
||||||
for episode in range(1, episodes[self.id - 1] + 1):
|
for episode in range(1, episodes[self.id - 1] + 1):
|
||||||
ep = Episode.query.filter_by(season_id=self.id, number=episode).first()
|
ep = Episode.query.filter_by(season_id=self.id, number=episode).first()
|
||||||
if ep is None:
|
if ep is None:
|
||||||
# Add the episode, then build
|
# Add the episode, then build
|
||||||
print(f'Creating new Episode, Season {self.id}, Episode {episode}')
|
print(f"Creating new Episode, Season {self.id}, Episode {episode}")
|
||||||
ep = Episode(season_id=self.id, number=episode)
|
ep = Episode(season_id=self.id, number=episode)
|
||||||
db.session.add(ep)
|
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.
|
# 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()
|
db.session.commit()
|
||||||
ep.build()
|
ep.build()
|
||||||
else:
|
else:
|
||||||
print(f'Rebuilding Season {self.id}, Episode {episode}')
|
print(f"Rebuilding Season {self.id}, Episode {episode}")
|
||||||
if rebuild:
|
if rebuild:
|
||||||
ep.build()
|
ep.build()
|
||||||
pass
|
pass
|
||||||
@@ -41,7 +53,8 @@ class Season(db.Model):
|
|||||||
if Season.query.get(i) is None:
|
if Season.query.get(i) is None:
|
||||||
s = Season(id=i)
|
s = Season(id=i)
|
||||||
db.session.add(s)
|
db.session.add(s)
|
||||||
if build: s.build()
|
if build:
|
||||||
|
s.build()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -60,42 +73,54 @@ class Season(db.Model):
|
|||||||
"""returns a List of Characters under this Season, sorted by number of spoken lines"""
|
"""returns a List of Characters under this Season, sorted by number of spoken lines"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Episode(db.Model):
|
class Episode(db.Model):
|
||||||
"""represents a Episode with underlying Sections (representing a specific cutscene or area"""
|
"""represents a Episode with underlying Sections (representing a specific cutscene or area"""
|
||||||
id = db.Column(db.Integer, primary_key=True) # arbitrary ID, should NOT be relied on to determine episode number or correlating season
|
|
||||||
number = db.Column(db.Integer) # episode number
|
id = db.Column(
|
||||||
season_id = db.Column(db.Integer, db.ForeignKey('season.id')) # correlating season number
|
db.Integer, primary_key=True
|
||||||
|
) # arbitrary ID, should NOT be relied on to determine episode number or correlating season
|
||||||
|
number = db.Column(db.Integer) # episode number
|
||||||
|
season_id = db.Column(
|
||||||
|
db.Integer, db.ForeignKey("season.id")
|
||||||
|
) # correlating season number
|
||||||
built = db.Column(db.Boolean, default=False)
|
built = db.Column(db.Boolean, default=False)
|
||||||
sections = db.relationship('Section', backref='episode', lazy='dynamic') # sections of quotes under this episode
|
sections = db.relationship(
|
||||||
|
"Section", backref="episode", lazy="dynamic"
|
||||||
|
) # sections of quotes under this episode
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
"""downloads, processes, and automatically creates Sections and Quotes"""
|
"""downloads, processes, and automatically creates Sections and Quotes"""
|
||||||
link = f'http://officequotes.net/no{self.season_id}-{str(self.number).zfill(2)}.php'
|
link = f"http://officequotes.net/no{self.season_id}-{str(self.number).zfill(2)}.php"
|
||||||
data = requests.get(link).text
|
data = requests.get(link).text
|
||||||
open('test.html', 'w+', encoding='utf-8').write(data)
|
open("test.html", "w+", encoding="utf-8").write(data)
|
||||||
soup = BeautifulSoup(data, 'html.parser')
|
soup = BeautifulSoup(data, "html.parser")
|
||||||
|
|
||||||
sections = soup.find_all(attrs={'class' : 'quote'})
|
sections = soup.find_all(attrs={"class": "quote"})
|
||||||
deleted = 0
|
deleted = 0
|
||||||
|
|
||||||
for section in sections:
|
for section in sections:
|
||||||
isNewpeat = False
|
isNewpeat = False
|
||||||
quotes = []
|
quotes = []
|
||||||
for quote in section.find_all('b'):
|
for quote in section.find_all("b"):
|
||||||
if 'Newpeat' in quote.string:
|
if "Newpeat" in quote.string:
|
||||||
quote = quote.next_sibling
|
quote = quote.next_sibling
|
||||||
isNewpeat = True
|
isNewpeat = True
|
||||||
if quote is None or quote.next_sibling is None:
|
if quote is None or quote.next_sibling is None:
|
||||||
print('Quote is None or next sibling is None')
|
print("Quote is None or next sibling is None")
|
||||||
continue
|
continue
|
||||||
quotes.append(quote.string + quote.next_sibling.string)
|
quotes.append(quote.string + quote.next_sibling.string)
|
||||||
if len(quotes) == 0:
|
if len(quotes) == 0:
|
||||||
print(f'Section found with Zero quotes. Newpeat: {isNewpeat}')
|
print(f"Section found with Zero quotes. Newpeat: {isNewpeat}")
|
||||||
continue
|
continue
|
||||||
isDeletedScene = quotes[0].lower().startswith('deleted scene')
|
isDeletedScene = quotes[0].lower().startswith("deleted scene")
|
||||||
if isDeletedScene:
|
if isDeletedScene:
|
||||||
deleted += 1
|
deleted += 1
|
||||||
s = Section(episode_id=self.id, deleted=deleted if isDeletedScene else -1, newpeat=isNewpeat)
|
s = Section(
|
||||||
|
episode_id=self.id,
|
||||||
|
deleted=deleted if isDeletedScene else -1,
|
||||||
|
newpeat=isNewpeat,
|
||||||
|
)
|
||||||
s.build(quotes[1:] if isDeletedScene else quotes)
|
s.build(quotes[1:] if isDeletedScene else quotes)
|
||||||
db.session.add(s)
|
db.session.add(s)
|
||||||
self.built = True
|
self.built = True
|
||||||
@@ -109,7 +134,9 @@ class Episode(db.Model):
|
|||||||
def clear(self):
|
def clear(self):
|
||||||
"""delete all sections relevant to this episode in order to reprocess"""
|
"""delete all sections relevant to this episode in order to reprocess"""
|
||||||
sections = Section.query.filter_by(episode_id=self.id).all()
|
sections = Section.query.filter_by(episode_id=self.id).all()
|
||||||
print(f'Clearing {len(sections)} Sections of Ep {self.number} Season {self.season_id}')
|
print(
|
||||||
|
f"Clearing {len(sections)} Sections of Ep {self.number} Season {self.season_id}"
|
||||||
|
)
|
||||||
for section in sections:
|
for section in sections:
|
||||||
section.clear(commit=False, delete=True)
|
section.clear(commit=False, delete=True)
|
||||||
self.built = False
|
self.built = False
|
||||||
@@ -123,50 +150,69 @@ class Episode(db.Model):
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
sections = len(Section.query.filter_by(episode_id=self.id).all())
|
sections = len(Section.query.filter_by(episode_id=self.id).all())
|
||||||
return f'Episode(id={self.id} 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):
|
class Section(db.Model):
|
||||||
"""represents a Section of Quotes, a specific scene with relevant dialog"""
|
"""represents a Section of Quotes, a specific scene with relevant dialog"""
|
||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
episode_id = db.Column(db.Integer, db.ForeignKey('episode.id'))
|
episode_id = db.Column(db.Integer, db.ForeignKey("episode.id"))
|
||||||
deleted = db.Column(db.Integer, default=-1)
|
deleted = db.Column(db.Integer, default=-1)
|
||||||
newpeat = db.Column(db.Boolean, default=False)
|
newpeat = db.Column(db.Boolean, default=False)
|
||||||
quotes = db.relationship('Quote', backref='section', lazy='dynamic')
|
quotes = db.relationship("Quote", backref="section", lazy="dynamic")
|
||||||
|
|
||||||
def build(self, quotes, commit=False, reset=False):
|
def build(self, quotes, commit=False, reset=False):
|
||||||
"""given an List of unformatted script quotes, automatically creates Quotes assigned to this Section"""
|
"""given an List of unformatted script quotes, automatically creates Quotes assigned to this Section"""
|
||||||
for i, quote in enumerate(quotes):
|
for i, quote in enumerate(quotes):
|
||||||
if quote.lower().startswith('deleted scene'):
|
if quote.lower().startswith("deleted scene"):
|
||||||
raise Exception(f'Deleted Scene Quote passed to Section Builder: "{quote}"')
|
raise Exception(
|
||||||
|
f'Deleted Scene Quote passed to Section Builder: "{quote}"'
|
||||||
|
)
|
||||||
# match = re.match(quotePattern, quote)
|
# match = re.match(quotePattern, quote)
|
||||||
# assert match != None, f"Quote '{quote}' could not be processed."
|
# assert match != None, f"Quote '{quote}' could not be processed."
|
||||||
# q = Quote(section=self, speaker=match[1].strip(), text=match[2].strip())
|
# q = Quote(section=self, speaker=match[1].strip(), text=match[2].strip())
|
||||||
mark = quote.find(':')
|
mark = quote.find(":")
|
||||||
q = Quote(section=self, speaker=quote[:mark], text=quote[mark + 1:], section_index=i)
|
q = Quote(
|
||||||
|
section=self,
|
||||||
|
speaker=quote[:mark],
|
||||||
|
text=quote[mark + 1 :],
|
||||||
|
section_index=i,
|
||||||
|
)
|
||||||
db.session.add(q)
|
db.session.add(q)
|
||||||
if commit: db.session.commit()
|
if commit:
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
def clear(self, doprint=True, commit=True, delete=False):
|
def clear(self, doprint=True, commit=True, delete=False):
|
||||||
"""delete all quotes relevant to this section"""
|
"""delete all quotes relevant to this section"""
|
||||||
quotes = Quote.query.filter_by(section_id=self.id).all()
|
quotes = Quote.query.filter_by(section_id=self.id).all()
|
||||||
if doprint: 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:
|
for quote in quotes:
|
||||||
db.session.delete(quote)
|
db.session.delete(quote)
|
||||||
if delete: db.session.delete(self)
|
if delete:
|
||||||
if commit: db.session.commit()
|
db.session.delete(self)
|
||||||
|
if commit:
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
season = Episode.query.get(self.episode_id).id
|
season = Episode.query.get(self.episode_id).id
|
||||||
quotes = len(Quote.query.filter_by(section_id=self.id).all())
|
quotes = len(Quote.query.filter_by(section_id=self.id).all())
|
||||||
return f'Section(id={self.id} S-EP={season}/{self.episode_id} quotes=[{quotes}...])'
|
return f"Section(id={self.id} S-EP={season}/{self.episode_id} quotes=[{quotes}...])"
|
||||||
|
|
||||||
|
|
||||||
class Quote(db.Model):
|
class Quote(db.Model):
|
||||||
"""represents a specific quote by a specific speaker"""
|
"""represents a specific quote by a specific speaker"""
|
||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
section_id = db.Column(db.Integer, db.ForeignKey('section.id')) # The section this quote belongs to.
|
section_id = db.Column(
|
||||||
speaker = db.Column(db.String(32)) # The name of a character
|
db.Integer, db.ForeignKey("section.id")
|
||||||
text = db.Column(db.String(512)) # The content of the Quote. Usually a sentence, sometimes more.
|
) # The section this quote belongs to.
|
||||||
section_index = db.Column(db.Integer) # The index of this quote in the section
|
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
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"Quote(speaker='{self.speaker}' text='{self.text[:50]}{'...' if len(self.text) > 51 else ''}')"
|
return f"Quote(speaker='{self.speaker}' text='{self.text[:50]}{'...' if len(self.text) > 51 else ''}')"
|
||||||
@@ -2,24 +2,30 @@ from flask import send_from_directory, redirect, url_for, render_template, reque
|
|||||||
from app.models import Season, Episode
|
from app.models import Season, Episode
|
||||||
from app import app
|
from app import app
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
return render_template('view.html', seasons=Season.query.all())
|
return render_template("view.html", seasons=Season.query.all())
|
||||||
|
|
||||||
@app.route('/season/<season>/')
|
|
||||||
|
@app.route("/season/<season>/")
|
||||||
def viewSeason(season):
|
def viewSeason(season):
|
||||||
return render_template('season.html', season=Season.query.filter_by(id=season).first_or_404())
|
return render_template(
|
||||||
|
"season.html", season=Season.query.filter_by(id=season).first_or_404()
|
||||||
|
)
|
||||||
|
|
||||||
@app.route('/season/<season>/<episode>/')
|
|
||||||
|
@app.route("/season/<season>/<episode>/")
|
||||||
def viewEpisode(season, episode):
|
def viewEpisode(season, episode):
|
||||||
e = Episode.query.filter_by(season_id=season, number=episode).first_or_404()
|
e = Episode.query.filter_by(season_id=season, number=episode).first_or_404()
|
||||||
if not e.built:
|
if not e.built:
|
||||||
print('Rebuilding')
|
print("Rebuilding")
|
||||||
e.build()
|
e.build()
|
||||||
return render_template('episode.html', episode=e)
|
return render_template("episode.html", episode=e)
|
||||||
|
|
||||||
@app.route('/season/<season>/<episode>/rebuild')
|
|
||||||
|
@app.route("/season/<season>/<episode>/rebuild")
|
||||||
def rebuildEpisode(season, episode):
|
def rebuildEpisode(season, episode):
|
||||||
e = Episode.query.filter_by(season_id=season, number=episode).first_or_404()
|
e = Episode.query.filter_by(season_id=season, number=episode).first_or_404()
|
||||||
e.rebuild()
|
e.rebuild()
|
||||||
return redirect(url_for('viewEpisode', season=season, episode=episode))
|
return redirect(url_for("viewEpisode", season=season, episode=episode))
|
||||||
|
|||||||
Reference in New Issue
Block a user