Source code for moddb.pages.opinion

from __future__ import annotations

import re
from typing import TYPE_CHECKING

from ..boxes import ModDBList, Option, Thumbnail
from ..enums import ThumbnailType
from ..utils import concat_docs, get_date, get_list_stats, join
from .base import BaseMetaClass

if TYPE_CHECKING:
    from bs4 import BeautifulSoup


[docs] class ReviewList(ModDBList): """Represents a list of reviews Attributes ----------- current_page : int The page of results this objects represents total_pages : int The total amount of result pages available total_results : int The total amount of results available """ def _parse_method(self, html: BeautifulSoup): return parse_reviews(html)
def parse_reviews(html): review_box = html.find("div", class_="normalbox browsebox") try: raw_ratings = ( review_box.find("div", class_="inner") .find("div", class_="table") .find_all("div", class_=["rowrating"], recursive=False) ) except AttributeError: return [], 1, 1, 0 reviews = [] for rating in raw_ratings: next_sibling = rating.find_next_sibling("div", class_=["rowcontent"]) if next_sibling is not None and "rowcontentnext" in next_sibling["class"]: reviews.append(Review(rating=rating, text=next_sibling)) else: reviews.append(Review(rating=rating)) return reviews, *get_list_stats(review_box, 10)
[docs] @concat_docs class Review: """Represents a review. Filtering ----------- rating : int A value from 1 to 10 denoting the rating number you're looking for sitearea : Category The type of model the rating is for (mod, engine, game) Sorting -------- * **ratingalt** - rating number, desc is biggest to lowest, asc is lowest to biggest * **memberipid** - sort reviewer account age, asc is oldest reviewer first * **positive** - how many people agree with it, desc is most to least people agreeing * **negative** - how many people disagree with it, desc is most to least people disagreeing * **id** - when it was added to moddb, asc is oldest, desc is most recent Attributes ----------- id : int The review id text : str The contents of the review. Can be none if the member hasn't left any rating : int An int out of 10 representing the rating left with this review. author : Thumbnail A member like thumbnail of the member who left the review date : datetime.datetime Date and time of the review creation agree : str Link to agree with the review disagree : str Link to disagree with the review """ def __init__(self, **attrs): text = attrs.get("text") if text: self.text = text.text else: self.text = None review = attrs.get("rating") self.rating = int(review.span.string) # id and hash are none if the review doesn't have content try: strings = ("Agree", "Delete", "Disagree") self.id = int( re.findall(r"siteareaid=(\d*)", review.find("a", title=strings)["href"])[0] ) except TypeError: self.id = None try: self._hash = re.findall(r"hash=(.*)&", review.find("a", title="Delete")["href"])[0] except TypeError: self._hash = None author = review.div.a self.author = Thumbnail( url=author["href"], name=author.string.split(" ")[0], type=ThumbnailType.member, ) self.date = get_date(review.div.span.time["datetime"]) try: self.agree = join(review.find("a", title="Agree")["href"]) self.disagree = join(review.find("a", title="Disagree")["href"]) except TypeError: self.agree = None self.disagree = None def __repr__(self): return f"<Review author={self.author.name} rating={self.rating}>"
[docs] @concat_docs class Poll(BaseMetaClass): """Represents a poll. Cannot be voted for due to restrictions implemented by the website. Parameters ----------- html : bs4.BeautifulSoup The html to parse. Allows for finer control. Filtering ---------- month : Month The month the poll you're looking for should be from year : int A int representing a year between 2002 and now. Anything below or above 2002 will always return zero results. Sorting -------- * **totalvotes** - how many people voted on the poll, desc is most to least * **name** - sort the poll alphabetically by name, asc is a-z * **date** - when it was added to moddb, asc is oldest, desc is most recent Attributes ----------- question : str The question of the poll author : Thumbnail A member like thumbnail of the member who posted the poll, usually ModDB staff total : int The total number of votes that have been cast options : List[Option] The list of available options for the poll """ def __init__(self, html: BeautifulSoup): poll = html.find("div", class_="poll") self.question = ( poll.parent.parent.parent.find("div", class_="normalcorner") .find("span", class_="heading") .string ) self.name = self.question super().__init__(html) author = poll.find("p", class_="question").find("a") self.author = Thumbnail(name=author.string, url=author["href"], type=ThumbnailType.member) self.total = int( re.search(r"([\d,]*) votes", poll.find("p", class_="question").text)[1].replace(",", "") ) percentage = poll.find_all("div", class_="barouter") rest = poll.find_all("p")[1:] self.options = [] for index, _ in enumerate(percentage): raw = percentage[index].div.string.replace("%", "").replace("\xa0", "") percent = float(f"0.{raw}") text = re.sub(r"\([\d,]* vote(s)?\)", "", rest[index].text) votes = int( re.search(r"([\d,]*) vote(s)?", rest[index].span.string)[1].replace(",", "") ) self.options.append(Option(text=text, votes=votes, percent=percent)) def __repr__(self): return f"<Poll question={self.question}>"