mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-10 06:54:21 +00:00
[11] add BoxOfficeMojo builders
This commit is contained in:
parent
3356a40e22
commit
e6523d6902
11 changed files with 831 additions and 10 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1.20.0-develop10
|
||||
1.20.0-develop11
|
||||
|
|
BIN
docs/assets/icons/boxofficemojo.png
Normal file
BIN
docs/assets/icons/boxofficemojo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.9 KiB |
394
docs/files/builders/mojo.md
Normal file
394
docs/files/builders/mojo.md
Normal file
|
@ -0,0 +1,394 @@
|
|||
# BoxOfficeMojo Builders
|
||||
|
||||
You can find items using the lists on [boxofficemojo.com](https://www.boxofficemojo.com/) (BoxOfficeMojo).
|
||||
|
||||
No configuration is required for these builders.
|
||||
|
||||
??? blank "`mojo_domestic` - Uses the Domestic Box Office.<a class="headerlink" href="#mojo-domestic" title="Permanent link">¶</a>"
|
||||
|
||||
<div id="mojo-domestic" />Uses the Domestic Box Office to collection items.
|
||||
|
||||
<hr style="margin: 0px;">
|
||||
|
||||
**Works With:** Movies, Playlists, and Custom Sort
|
||||
|
||||
**Builder Attribute:** `mojo_domestic`
|
||||
|
||||
**Builder Value:** [Dictionary](../../pmm/yaml.md#dictionaries) of Attributes
|
||||
|
||||
??? blank "`range` - Determines the type of time range of the Box Office"
|
||||
|
||||
Determines the type of the time range of the Box Office.
|
||||
|
||||
**Allowed Values:** `daily`, `weekend`, `weekly`, `monthly`, `quarterly`, `yearly`, `season`, or `holiday`
|
||||
|
||||
??? blank "`year` - Determines the year of the Box Office"
|
||||
|
||||
Determines the year of the Box Office. This attribute is ignored for the `daily` range.
|
||||
|
||||
**Default Value:** `current`
|
||||
|
||||
**Allowed Values:** Number between 1977 and the current year, `current`, or relative current (`current-#`; where
|
||||
`#` is the number of year before the current)
|
||||
|
||||
??? blank "`range_data` - Determines the actual time range of the Box Office"
|
||||
|
||||
Determines the actual time range of the Box Office. The input for this value changes depending on the value
|
||||
of `range`. This attribute is required for all ranges expect the `yearly` range.
|
||||
|
||||
**Daily Allowed Values:** Date in the format `MM-DD-YYYY`, `current`, or relative current (`current-#`; where
|
||||
`#` is the number of days before the current)
|
||||
|
||||
**Weekend Allowed Values:** Week Number between 1-53, `current`, or relative current (`current-#`; where `#`
|
||||
is the number of days before the current)
|
||||
|
||||
**Weekly Allowed Values:** Week Number between 1-53, `current`, or relative current (`current-#`; where `#`
|
||||
is the number of days before the current)
|
||||
|
||||
**Monthly Allowed Values:** `january`, `february`, `march`, `april`, `may`, `june`, `july`, `august`,
|
||||
`september`, `october`, `november`, `december`, `current`, or relative current (`current-#`; where `#` is the
|
||||
number of days before the current)
|
||||
|
||||
**Quarterly Allowed Values:** `q1`, `q2`, `q3`, `q4`, `current`, or relative current (`current-#`; where `#`
|
||||
is the number of days before the current)
|
||||
|
||||
**Season Allowed Values:** `winter`, `spring`, `summer`, `fall`, `holiday`, or `current`
|
||||
|
||||
**Holiday Allowed Values:** `new_years_day`, `new_year_weekend`, `mlk_day`, `mlk_day_weekend`,
|
||||
`presidents_day`, `presidents_day_weekend`, `easter`, `easter_weekend`, `memorial_day`, `memorial_day_weekend`,
|
||||
`independence_day`, `independence_day_weekend`, `labor_day`, `labor_day_weekend`, `indigenous_day`,
|
||||
`indigenous_day_weekend`, `halloween`, `thanksgiving`, `thanksgiving_3`, `thanksgiving_4`, `thanksgiving_5`,
|
||||
`post_thanksgiving_weekend`, `christmas_day`, `christmas_weekend`, or `new_years_eve`
|
||||
|
||||
??? blank "`limit` - The maximum number of result to return"
|
||||
|
||||
This determines the maximum number of results to return. If there are less results then the limit then all will
|
||||
be returned.
|
||||
|
||||
**Default Value:** Returns all results
|
||||
|
||||
**Allowed Values:** Number greter than 0
|
||||
|
||||
???+ example "Example"
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
|
||||
Current Domestic Box Office:
|
||||
mojo_domestic:
|
||||
range: yearly
|
||||
year: current
|
||||
|
||||
Last Year's Domestic Box Office:
|
||||
mojo_domestic:
|
||||
range: yearly
|
||||
year: current-1
|
||||
|
||||
Last Months Top 10 Domestic Box Office:
|
||||
mojo_domestic:
|
||||
range: monthly
|
||||
year: current-1
|
||||
limit: 10
|
||||
```
|
||||
|
||||
??? blank "`mojo_international` - Uses the International Box Office.<a class="headerlink" href="#mojo-international" title="Permanent link">¶</a>"
|
||||
|
||||
<div id="mojo-international" />Uses the International Box Office to collection items.
|
||||
|
||||
<hr style="margin: 0px;">
|
||||
|
||||
**Works With:** Movies, Playlists, and Custom Sort
|
||||
|
||||
**Builder Attribute:** `mojo_international`
|
||||
|
||||
**Builder Value:** [Dictionary](../../pmm/yaml.md#dictionaries) of Attributes
|
||||
|
||||
??? blank "`range` - Determines the type of time range of the Box Office"
|
||||
|
||||
Determines the type of the time range of the Box Office.
|
||||
|
||||
**Allowed Values:** `weekend`, `monthly`, `quarterly`, or `yearly`
|
||||
|
||||
??? blank "`chart` - Determines the chart you want to use"
|
||||
|
||||
Determines the chart you want to use.
|
||||
|
||||
**Default Value:** `international`
|
||||
|
||||
**Allowed Values:** Item in the drop down found [here](https://www.boxofficemojo.com/intl/)
|
||||
|
||||
??? blank "`year` - Determines the year of the Box Office"
|
||||
|
||||
Determines the year of the Box Office.
|
||||
|
||||
**Default Value:** `current`
|
||||
|
||||
**Allowed Values:** Number between 1977 and the current year, `current`, or relative current (`current-#`; where
|
||||
`#` is the number of year before the current)
|
||||
|
||||
??? blank "`range_data` - Determines the actual time range of the Box Office"
|
||||
|
||||
Determines the actual time range of the Box Office. The input for this value changes depending on the value
|
||||
of `range`. This attribute is required for all ranges expect the `yearly` range.
|
||||
|
||||
**Weekend Allowed Values:** Week Number between 1-53, `current`, or relative current (`current-#`; where `#`
|
||||
is the number of days before the current)
|
||||
|
||||
**Monthly Allowed Values:** `january`, `february`, `march`, `april`, `may`, `june`, `july`, `august`,
|
||||
`september`, `october`, `november`, `december`, `current`, or relative current (`current-#`; where `#` is the
|
||||
number of days before the current)
|
||||
|
||||
**Quarterly Allowed Values:** `q1`, `q2`, `q3`, `q4`, `current`, or relative current (`current-#`; where `#`
|
||||
is the number of days before the current)
|
||||
|
||||
??? blank "`limit` - The maximum number of result to return"
|
||||
|
||||
This determines the maximum number of results to return. If there are less results then the limit then all will
|
||||
be returned.
|
||||
|
||||
**Default Value:** Returns all results
|
||||
|
||||
**Allowed Values:** Number greter than 0
|
||||
|
||||
???+ example "Example"
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
|
||||
Current International Box Office:
|
||||
mojo_international:
|
||||
range: yearly
|
||||
year: current
|
||||
|
||||
Last Year's International Box Office:
|
||||
mojo_international:
|
||||
range: yearly
|
||||
year: current-1
|
||||
|
||||
Last Months Top 10 German Box Office:
|
||||
mojo_international:
|
||||
range: monthly
|
||||
chart: germany
|
||||
year: current-1
|
||||
limit: 10
|
||||
```
|
||||
|
||||
??? blank "`mojo_world` - Uses the Worldwide Box Office.<a class="headerlink" href="#mojo-world" title="Permanent link">¶</a>"
|
||||
|
||||
<div id="mojo-world" />Uses the [Worldwide Box Office](https://www.boxofficemojo.com/year/world/) to collection items.
|
||||
|
||||
<hr style="margin: 0px;">
|
||||
|
||||
**Works With:** Movies, Playlists, and Custom Sort
|
||||
|
||||
**Builder Attribute:** `mojo_world`
|
||||
|
||||
**Builder Value:** [Dictionary](../../pmm/yaml.md#dictionaries) of Attributes
|
||||
|
||||
??? blank "`year` - The year of the Worldwide Box Office"
|
||||
|
||||
This determines the year of the [Worldwide Box Office](https://www.boxofficemojo.com/year/world/) to pull.
|
||||
|
||||
**Allowed Values:** Number between 1977 and the current year, `current`, or relative current (`current-#`; where
|
||||
`#` is the number of year before the current)
|
||||
|
||||
??? blank "`limit` - The maximum number of result to return"
|
||||
|
||||
This determines the maximum number of results to return. If there are less results then the limit then all will
|
||||
be returned.
|
||||
|
||||
**Default Value:** Returns all results
|
||||
|
||||
**Allowed Values:** Number greter than 0
|
||||
|
||||
???+ example "Example"
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
|
||||
Current Worlwide Box Office:
|
||||
mojo_world:
|
||||
year: current
|
||||
|
||||
Last Year's Worlwide Box Office:
|
||||
mojo_world:
|
||||
year: current-1
|
||||
|
||||
2020 Top 10 Worlwide Box Office:
|
||||
mojo_world:
|
||||
year: 2020
|
||||
limit: 10
|
||||
```
|
||||
|
||||
??? blank "`mojo_all_time` - Uses the All Time Lists.<a class="headerlink" href="#mojo-all-time" title="Permanent link">¶</a>"
|
||||
|
||||
<div id="mojo-all-time" />Uses the [All Time Lists](https://www.boxofficemojo.com/charts/overall/) to collection items.
|
||||
|
||||
<hr style="margin: 0px;">
|
||||
|
||||
**Works With:** Movies, Playlists, and Custom Sort
|
||||
|
||||
**Builder Attribute:** `mojo_all_time`
|
||||
|
||||
**Builder Value:** [Dictionary](../../pmm/yaml.md#dictionaries) of Attributes
|
||||
|
||||
??? blank "`chart` - Determines the chart you want to use"
|
||||
|
||||
Determines the chart you want to use.
|
||||
|
||||
**Allowed Values:** `domestic` or `worldwide`
|
||||
|
||||
??? blank "`content_rating_filter` - Determines the content rating chart to use"
|
||||
|
||||
Determines the content rating chart to use.
|
||||
|
||||
**Allowed Values:** `g`, `g/pg`, `pg`, `pg-13`, `r` or `nc-17`
|
||||
|
||||
??? blank "`limit` - The maximum number of result to return"
|
||||
|
||||
This determines the maximum number of results to return. If there are less results then the limit then all will
|
||||
be returned.
|
||||
|
||||
**Default Value:** Returns all results
|
||||
|
||||
**Allowed Values:** Number greter than 0
|
||||
|
||||
???+ example "Example"
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
|
||||
Top 100 Domestic All Time Grosses:
|
||||
mojo_all_time:
|
||||
chart: domestic
|
||||
limit: 100
|
||||
|
||||
Top 100 Worldwide All Time Grosses:
|
||||
mojo_all_time:
|
||||
chart: worldwide
|
||||
limit: 100
|
||||
|
||||
Top 10 Domestic All Time G Movie Grosses:
|
||||
mojo_world:
|
||||
chart: domestic
|
||||
content_rating_filter: g
|
||||
limit: 10
|
||||
```
|
||||
|
||||
??? blank "`mojo_never` - Uses the Never Hit Lists.<a class="headerlink" href="#mojo-never" title="Permanent link">¶</a>"
|
||||
|
||||
<div id="mojo-never" />Uses the [Never Hit Lists](https://www.boxofficemojo.com/charts/overall/) (Bottom Section) to
|
||||
collection items.
|
||||
|
||||
<hr style="margin: 0px;">
|
||||
|
||||
**Works With:** Movies, Playlists, and Custom Sort
|
||||
|
||||
**Builder Attribute:** `mojo_never`
|
||||
|
||||
**Builder Value:** [Dictionary](../../pmm/yaml.md#dictionaries) of Attributes
|
||||
|
||||
??? blank "`chart` - Determines the chart you want to use"
|
||||
|
||||
Determines the chart you want to use.
|
||||
|
||||
**Allowed Values:** Item in the drop down found [here](https://www.boxofficemojo.com/charts/overall/)
|
||||
|
||||
??? blank "`never` - Determines the never filter to use"
|
||||
|
||||
Determines the never filter to use.
|
||||
|
||||
**Default Value:** `1`
|
||||
|
||||
**Allowed Values:** `1`, `5`, or `10`
|
||||
|
||||
??? blank "`limit` - The maximum number of result to return"
|
||||
|
||||
This determines the maximum number of results to return. If there are less results then the limit then all will
|
||||
be returned.
|
||||
|
||||
**Default Value:** Returns all results
|
||||
|
||||
**Allowed Values:** Number greter than 0
|
||||
|
||||
???+ example "Example"
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
|
||||
Top 100 Domestic Never #1:
|
||||
mojo_never:
|
||||
chart: domestic
|
||||
limit: 100
|
||||
|
||||
Top 100 Domestic Never #10:
|
||||
mojo_never:
|
||||
chart: domestic
|
||||
never: 10
|
||||
limit: 100
|
||||
|
||||
Top 100 German Never #1:
|
||||
mojo_never:
|
||||
chart: germany
|
||||
limit: 100
|
||||
```
|
||||
|
||||
??? blank "`mojo_record` - Uses other Record Lists.<a class="headerlink" href="#mojo-record" title="Permanent link">¶</a>"
|
||||
|
||||
<div id="mojo-record" />Uses the [Weekend Records](https://www.boxofficemojo.com/charts/weekend/),
|
||||
[Daily Records](https://www.boxofficemojo.com/charts/daily/), and
|
||||
[Miscellaneous Records](https://www.boxofficemojo.com/charts/misc/) to collection items.
|
||||
|
||||
<hr style="margin: 0px;">
|
||||
|
||||
**Works With:** Movies, Playlists, and Custom Sort
|
||||
|
||||
**Builder Attribute:** `mojo_record`
|
||||
|
||||
**Builder Value:** [Dictionary](../../pmm/yaml.md#dictionaries) of Attributes
|
||||
|
||||
??? blank "`chart` - Determines the record you want to use"
|
||||
|
||||
Determines the chart you want to use.
|
||||
|
||||
**Allowed Values:** `second_weekend_drop`, `post_thanksgiving_weekend_drop`, `top_opening_weekend`,
|
||||
`worst_opening_weekend_theater_avg`, `mlk_opening`, `easter_opening`, `memorial_opening`, `labor_opening`,
|
||||
`president_opening`, `thanksgiving_3_opening`, `thanksgiving_5_opening`, `mlk`, `easter`, `4th`, `memorial`,
|
||||
`labor`, `president`, `thanksgiving_3`, `thanksgiving_5`, `january`, `february`, `march`, `april`, `may`,
|
||||
`june`, `july`, `august`, `september`, `october`, `november`, `december`, `spring`, `summer`, `fall`,
|
||||
`holiday_season`, `winter`, `g`, `g/pg`, `pg`, `pg-13`, `r`, `nc-17`, `top_opening_weekend_theater_avg_all`,
|
||||
`top_opening_weekend_theater_avg_wide`, `opening_day`, `single_day_grosses`, `christmas_day_gross`,
|
||||
`new_years_day_gross`, `friday`, `saturday`, `sunday`, `monday`, `tuesday`, `wednesday`, `thursday`,
|
||||
`friday_non_opening`, `saturday_non_opening`, `sunday_non_opening`, `monday_non_opening`, `tuesday_non_opening`,
|
||||
`wednesday_non_opening`, `thursday_non_opening`, `biggest_theater_drop`, or `opening_week`
|
||||
|
||||
|
||||
??? blank "`limit` - The maximum number of result to return"
|
||||
|
||||
This determines the maximum number of results to return. If there are less results then the limit then all will
|
||||
be returned.
|
||||
|
||||
**Default Value:** Returns all results
|
||||
|
||||
**Allowed Values:** Number greter than 0
|
||||
|
||||
???+ example "Example"
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
|
||||
Top 10 Biggest Opening Weekends:
|
||||
mojo_record:
|
||||
chart: top_opening_weekend
|
||||
limit: 10
|
||||
|
||||
Top 10 Biggest Opening Day:
|
||||
mojo_record:
|
||||
chart: opening_day
|
||||
limit: 10
|
||||
|
||||
Top 10 Biggest Opening Weeks:
|
||||
mojo_record:
|
||||
chart: opening_week
|
||||
limit: 10
|
||||
```
|
|
@ -30,6 +30,11 @@ Builders use third-party services to source items to be added to the collection.
|
|||
image: ../../../assets/icons/imdb.png
|
||||
url: "../imdb"
|
||||
|
||||
- title: Box Office Mojo
|
||||
content: Grabs items based on metadata and lists on Boxofficemojo.com
|
||||
image: ../../../assets/icons/boxofficemojo.png
|
||||
url: "../boxofficemojo"
|
||||
|
||||
- title: Trakt
|
||||
content: Grabs items based on metadata and lists on Trakt.tv
|
||||
image: ../../../assets/icons/trakt.png
|
||||
|
|
|
@ -319,6 +319,7 @@ nav:
|
|||
- Letterboxd Builders: files/builders/letterboxd.md
|
||||
- ICheckMovies Builders: files/builders/icheckmovies.md
|
||||
- FlixPatrol Builders: files/builders/flixpatrol.md
|
||||
- BoxOfficeMojo Builders: files/builders/mojo.md
|
||||
- Reciperr Builders: files/builders/reciperr.md
|
||||
- StevenLu Builders: files/builders/stevenlu.md
|
||||
- AniDB Builders: files/builders/anidb.md
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import os, re, time
|
||||
from arrapi import ArrException
|
||||
from datetime import datetime
|
||||
from modules import anidb, anilist, flixpatrol, icheckmovies, imdb, letterboxd, mal, plex, radarr, reciperr, sonarr, tautulli, tmdb, trakt, tvdb, mdblist, util
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from modules import anidb, anilist, flixpatrol, icheckmovies, imdb, letterboxd, mal, mojo, plex, radarr, reciperr, sonarr, tautulli, tmdb, trakt, tvdb, mdblist, util
|
||||
from modules.util import Failed, FilterFailed, NonExisting, NotScheduled, NotScheduledRange, Deleted
|
||||
from modules.overlay import Overlay
|
||||
from modules.poster import PMMImage
|
||||
|
@ -16,7 +17,7 @@ logger = util.logger
|
|||
advance_new_agent = ["item_metadata_language", "item_use_original_title"]
|
||||
advance_show = ["item_episode_sorting", "item_keep_episodes", "item_delete_episodes", "item_season_display", "item_episode_sorting"]
|
||||
all_builders = anidb.builders + anilist.builders + flixpatrol.builders + icheckmovies.builders + imdb.builders + \
|
||||
letterboxd.builders + mal.builders + plex.builders + reciperr.builders + tautulli.builders + \
|
||||
letterboxd.builders + mal.builders + mojo.builders + plex.builders + reciperr.builders + tautulli.builders + \
|
||||
tmdb.builders + trakt.builders + tvdb.builders + mdblist.builders + radarr.builders + sonarr.builders
|
||||
show_only_builders = [
|
||||
"tmdb_network", "tmdb_show", "tmdb_show_details", "tvdb_show", "tvdb_show_details", "tmdb_airing_today",
|
||||
|
@ -25,7 +26,8 @@ show_only_builders = [
|
|||
movie_only_builders = [
|
||||
"letterboxd_list", "letterboxd_list_details", "icheckmovies_list", "icheckmovies_list_details", "stevenlu_popular",
|
||||
"tmdb_collection", "tmdb_collection_details", "tmdb_movie", "tmdb_movie_details", "tmdb_now_playing", "item_edition",
|
||||
"tvdb_movie", "tvdb_movie_details", "tmdb_upcoming", "trakt_boxoffice", "reciperr_list", "radarr_all", "radarr_taglist"
|
||||
"tvdb_movie", "tvdb_movie_details", "tmdb_upcoming", "trakt_boxoffice", "reciperr_list", "radarr_all", "radarr_taglist",
|
||||
"mojo_world", "mojo_domestic", "mojo_international", "mojo_record", "mojo_all_time", "mojo_never"
|
||||
]
|
||||
music_only_builders = ["item_album_sorting"]
|
||||
summary_details = [
|
||||
|
@ -153,7 +155,8 @@ custom_sort_builders = [
|
|||
"tautulli_popular", "tautulli_watched", "mdblist_list", "letterboxd_list", "icheckmovies_list", "flixpatrol_top",
|
||||
"anilist_top_rated", "anilist_popular", "anilist_trending", "anilist_search", "anilist_userlist",
|
||||
"mal_all", "mal_airing", "mal_upcoming", "mal_tv", "mal_movie", "mal_ova", "mal_special", "mal_search",
|
||||
"mal_popular", "mal_favorite", "mal_suggested", "mal_userlist", "mal_season", "mal_genre", "mal_studio"
|
||||
"mal_popular", "mal_favorite", "mal_suggested", "mal_userlist", "mal_season", "mal_genre", "mal_studio",
|
||||
"mojo_world", "mojo_domestic", "mojo_international", "mojo_record", "mojo_all_time", "mojo_never"
|
||||
]
|
||||
episode_parts_only = ["plex_pilots"]
|
||||
overlay_only = ["overlay", "suppress_overlays"]
|
||||
|
@ -1037,6 +1040,8 @@ class CollectionBuilder:
|
|||
self._imdb(method_name, method_data)
|
||||
elif method_name in mal.builders:
|
||||
self._mal(method_name, method_data)
|
||||
elif method_name in mojo.builders:
|
||||
self._mojo(method_name, method_data)
|
||||
elif method_name in plex.builders or method_final in plex.searches:
|
||||
self._plex(method_name, method_data)
|
||||
elif method_name in reciperr.builders:
|
||||
|
@ -1800,6 +1805,127 @@ class CollectionBuilder:
|
|||
final_text = f"MyAnimeList Search\n{method_name[4:].capitalize()}: {' or '.join([str(all_items[i]) for i in final_items])}"
|
||||
self.builders.append(("mal_search", ({"genres" if method_name == "mal_genre" else "producers": ",".join(final_items)}, final_text, 0)))
|
||||
|
||||
def _mojo(self, method_name, method_data):
|
||||
for dict_data in util.parse(self.Type, method_name, method_data, datatype="listdict"):
|
||||
dict_methods = {dm.lower(): dm for dm in dict_data}
|
||||
final = {}
|
||||
if method_name == "mojo_record":
|
||||
final["chart"] = util.parse(self.Type, "chart", dict_data, methods=dict_methods, parent=method_name, options=mojo.top_options)
|
||||
elif method_name == "mojo_world":
|
||||
if "year" not in dict_methods:
|
||||
raise Failed(f"{self.Type} Error: {method_name} year attribute not found")
|
||||
og_year = dict_data[dict_methods["year"]]
|
||||
if not og_year:
|
||||
raise Failed(f"{self.Type} Error: {method_name} year attribute is blank")
|
||||
if og_year == "current":
|
||||
final["year"] = str(self.current_year) # noqa
|
||||
elif str(og_year).startswith("current-"):
|
||||
try:
|
||||
final["year"] = str(self.current_year - int(og_year.split("-")[1])) # noqa
|
||||
if final["year"] not in mojo.year_options:
|
||||
raise Failed(f"{self.Type} Error: {method_name} year attribute final value must be 1977 or greater: {og_year}")
|
||||
except ValueError:
|
||||
raise Failed(f"{self.Type} Error: {method_name} year attribute invalid: {og_year}")
|
||||
else:
|
||||
final["year"] = util.parse(self.Type, "year", dict_data, methods=dict_methods, parent=method_name, options=mojo.year_options)
|
||||
elif method_name == "mojo_all_time":
|
||||
final["chart"] = util.parse(self.Type, "chart", dict_data, methods=dict_methods, parent=method_name, options=mojo.chart_options)
|
||||
final["content_rating_filter"] = util.parse(self.Type, "content_rating_filter", dict_data, methods=dict_methods, parent=method_name, options=mojo.content_rating_options) if "content_rating_filter" in dict_methods else None
|
||||
elif method_name == "mojo_never":
|
||||
final["chart"] = util.parse(self.Type, "chart", dict_data, methods=dict_methods, parent=method_name, default="domestic", options=self.config.BoxOfficeMojo.never_options)
|
||||
final["never"] = str(util.parse(self.Type, "never", dict_data, methods=dict_methods, parent=method_name, default="1", options=mojo.never_in_options)) if "never" in dict_methods else "1"
|
||||
elif method_name in ["mojo_domestic", "mojo_international"]:
|
||||
dome = method_name == "mojo_domestic"
|
||||
final["range"] = util.parse(self.Type, "range", dict_data, methods=dict_methods, parent=method_name, options=mojo.dome_range_options if dome else mojo.intl_range_options)
|
||||
if not dome:
|
||||
final["chart"] = util.parse(self.Type, "chart", dict_data, methods=dict_methods, parent=method_name, default="international", options=self.config.BoxOfficeMojo.intl_options)
|
||||
chart_date = self.current_time
|
||||
if final["range"] != "daily":
|
||||
_m = "range_data" if final["range"] == "yearly" and "year" not in dict_methods and "range_data" in dict_methods else "year"
|
||||
if _m not in dict_methods:
|
||||
raise Failed(f"{self.Type} Error: {method_name} {_m} attribute not found")
|
||||
og_year = dict_data[dict_methods[_m]]
|
||||
if not og_year:
|
||||
raise Failed(f"{self.Type} Error: {method_name} {_m} attribute is blank")
|
||||
if str(og_year).startswith("current-"):
|
||||
try:
|
||||
chart_date = self.current_time - relativedelta(years=int(og_year.split("-")[1]))
|
||||
except ValueError:
|
||||
raise Failed(f"{self.Type} Error: {method_name} {_m} attribute invalid: {og_year}")
|
||||
else:
|
||||
_y = util.parse(self.Type, _m, dict_data, methods=dict_methods, parent=method_name, default="current", options=mojo.year_options)
|
||||
if _y != "current":
|
||||
chart_date = self.current_time - relativedelta(years=self.current_time.year - _y)
|
||||
if final["range"] != "yearly":
|
||||
if "range_data" not in dict_methods:
|
||||
raise Failed(f"{self.Type} Error: {method_name} range_data attribute not found")
|
||||
og_data = dict_data[dict_methods["range_data"]]
|
||||
if not og_data:
|
||||
raise Failed(f"{self.Type} Error: {method_name} range_data attribute is blank")
|
||||
|
||||
if final["range"] == "holiday":
|
||||
final["range_data"] = util.parse(self.Type, "range_data", dict_data, methods=dict_methods, parent=method_name, options=mojo.holiday_options)
|
||||
elif final["range"] == "daily":
|
||||
if og_data == "current":
|
||||
final["range_data"] = datetime.strftime(self.current_time, "%Y-%m-%d") # noqa
|
||||
elif str(og_data).startswith("current-"):
|
||||
try:
|
||||
final["range_data"] = datetime.strftime(self.current_time - timedelta(days=int(og_data.split("-")[1])), "%Y-%m-%d") # noqa
|
||||
except ValueError:
|
||||
raise Failed(f"{self.Type} Error: {method_name} range_data attribute invalid: {og_data}")
|
||||
else:
|
||||
final["range_data"] = util.parse(self.Type, "range_data", dict_data, methods=dict_methods, parent=method_name, default="current", datatype="date", date_return="%Y-%m-%d")
|
||||
if final["range_data"] == "current":
|
||||
final["range_data"] = datetime.strftime(self.current_time, "%Y-%m-%d") # noqa
|
||||
elif final["range"] in ["weekend", "weekly"]:
|
||||
if str(og_data).startswith("current-"):
|
||||
try:
|
||||
final_date = chart_date - timedelta(weeks=int(og_data.split("-")[1]))
|
||||
final_iso = final_date.isocalendar()
|
||||
final["range_data"] = final_iso.week
|
||||
final["year"] = final_iso.year
|
||||
except ValueError:
|
||||
raise Failed(f"{self.Type} Error: {method_name} range_data attribute invalid: {og_data}")
|
||||
else:
|
||||
_v = util.parse(self.Type, "range_data", dict_data, methods=dict_methods, parent=method_name, default="current", options=["current"] + [str(i) for i in range(1, 54)])
|
||||
current_iso = chart_date.isocalendar()
|
||||
final["range_data"] = current_iso.week if _v == "current" else _v
|
||||
final["year"] = current_iso.year
|
||||
elif final["range"] == "monthly":
|
||||
if str(og_data).startswith("current-"):
|
||||
try:
|
||||
final_date = chart_date - relativedelta(months=int(og_data.split("-")[1]))
|
||||
final["range_data"] = final_date.month
|
||||
final["year"] = final_date.year
|
||||
except ValueError:
|
||||
raise Failed(f"{self.Type} Error: {method_name} range_data attribute invalid: {og_data}")
|
||||
else:
|
||||
_v = util.parse(self.Type, "range_data", dict_data, methods=dict_methods, parent=method_name, default="current", options=["current"] + util.lower_months)
|
||||
final["range_data"] = chart_date.month if _v == "current" else util.lower_months[_v]
|
||||
elif final["range"] == "quarterly":
|
||||
if str(og_data).startswith("current-"):
|
||||
try:
|
||||
final_date = chart_date - relativedelta(months=int(og_data.split("-")[1]) * 3)
|
||||
final["range_data"] = mojo.quarters[final_date.month]
|
||||
final["year"] = final_date.year
|
||||
except ValueError:
|
||||
raise Failed(f"{self.Type} Error: {method_name} range_data attribute invalid: {og_data}")
|
||||
else:
|
||||
_v = util.parse(self.Type, "range_data", dict_data, methods=dict_methods, parent=method_name, default="current", options=mojo.quarter_options)
|
||||
final["range_data"] = mojo.quarters[chart_date.month] if _v == "current" else _v
|
||||
elif final["range"] == "season":
|
||||
_v = util.parse(self.Type, "range_data", dict_data, methods=dict_methods, parent=method_name, default="current", options=mojo.season_options)
|
||||
final["range_data"] = mojo.seasons[chart_date.month] if _v == "current" else _v
|
||||
else:
|
||||
final["range_data"] = chart_date.year
|
||||
if "year" not in final:
|
||||
final["year"] = chart_date.year
|
||||
if final["year"] < 1977:
|
||||
raise Failed(f"{self.Type} Error: {method_name} attribute final date value must be on year 1977 or greater: {final['year']}")
|
||||
|
||||
final["limit"] = util.parse(self.Type, "limit", dict_data, methods=dict_methods, parent=method_name, default=0, datatype="int", maximum=1000) if "limit" in dict_methods else 0
|
||||
self.builders.append((method_name, final))
|
||||
|
||||
def _plex(self, method_name, method_data):
|
||||
if method_name in ["plex_all", "plex_pilots"]:
|
||||
self.builders.append((method_name, self.builder_level))
|
||||
|
@ -2088,6 +2214,8 @@ class CollectionBuilder:
|
|||
ids = self.config.Letterboxd.get_tmdb_ids(method, value, self.language)
|
||||
elif "reciperr" in method or "stevenlu" in method:
|
||||
ids = self.config.Reciperr.get_imdb_ids(method, value)
|
||||
elif "mojo" in method:
|
||||
ids = self.config.BoxOfficeMojo.get_imdb_ids(method, value)
|
||||
elif "mdblist" in method:
|
||||
ids = self.config.Mdblist.get_tmdb_ids(method, value, self.library.is_movie if not self.playlist else None)
|
||||
elif "tmdb" in method:
|
||||
|
|
|
@ -72,6 +72,13 @@ class Cache:
|
|||
tmdb_id TEXT,
|
||||
expiration_date TEXT)"""
|
||||
)
|
||||
cursor.execute(
|
||||
"""CREATE TABLE IF NOT EXISTS mojo_map (
|
||||
key INTEGER PRIMARY KEY,
|
||||
mojo_url TEXT UNIQUE,
|
||||
imdb_id TEXT,
|
||||
expiration_date TEXT)"""
|
||||
)
|
||||
cursor.execute(
|
||||
"""CREATE TABLE IF NOT EXISTS omdb_data3 (
|
||||
key INTEGER PRIMARY KEY,
|
||||
|
@ -377,6 +384,12 @@ class Cache:
|
|||
def update_letterboxd_map(self, expired, letterboxd_id, tmdb_id):
|
||||
self._update_map("letterboxd_map", "letterboxd_id", letterboxd_id, "tmdb_id", tmdb_id, expired)
|
||||
|
||||
def query_mojo_map(self, mojo_url):
|
||||
return self._query_map("mojo_map", mojo_url, "mojo_url", "imdb_id")
|
||||
|
||||
def update_mojo_map(self, expired, mojo_url, imdb_id):
|
||||
self._update_map("mojo_map", "mojo_url", mojo_url, "imdb_id", imdb_id, expired)
|
||||
|
||||
def _query_map(self, map_name, _id, from_id, to_id, media_type=None, return_type=False):
|
||||
id_to_return = None
|
||||
expired = None
|
||||
|
|
|
@ -14,6 +14,7 @@ from modules.github import GitHub
|
|||
from modules.letterboxd import Letterboxd
|
||||
from modules.mal import MyAnimeList
|
||||
from modules.meta import PlaylistFile
|
||||
from modules.mojo import BoxOfficeMojo
|
||||
from modules.notifiarr import Notifiarr
|
||||
from modules.omdb import OMDb
|
||||
from modules.overlays import Overlays
|
||||
|
@ -704,6 +705,7 @@ class ConfigFile:
|
|||
self.FlixPatrol = FlixPatrol(self)
|
||||
self.ICheckMovies = ICheckMovies(self)
|
||||
self.Letterboxd = Letterboxd(self)
|
||||
self.BoxOfficeMojo = BoxOfficeMojo(self)
|
||||
self.Reciperr = Reciperr(self)
|
||||
self.Ergast = Ergast(self)
|
||||
|
||||
|
|
273
modules/mojo.py
Normal file
273
modules/mojo.py
Normal file
|
@ -0,0 +1,273 @@
|
|||
from datetime import datetime
|
||||
from modules import util
|
||||
from modules.util import Failed
|
||||
from num2words import num2words
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
|
||||
logger = util.logger
|
||||
|
||||
builders = ["mojo_world", "mojo_domestic", "mojo_international", "mojo_record", "mojo_all_time", "mojo_never"]
|
||||
top_options = {
|
||||
"second_weekend_drop": ("Biggest Second Weekend Drops", "/chart/biggest_second_weekend_gross_drop/", None),
|
||||
"post_thanksgiving_weekend_drop": ("Largest Post-Thanksgiving Weekend Drops", "/chart/post_thanksgiving_weekend_drop/", None),
|
||||
"top_opening_weekend": ("Top Opening Weekends", "/chart/top_opening_weekend/", None),
|
||||
"worst_opening_weekend_theater_avg": ("Worst Opening Weekend Per-Theater Averages", "/chart/btm_wide_opening_weekend_theater_avg/", None),
|
||||
"top_opening_weekend_theater_avg_all": ("Top Opening Theater Averages", "/chart/top_opening_weekend_theater_avg/", {"by_release_scale": "all"}),
|
||||
"top_opening_weekend_theater_avg_wide": ("Top Wide Opening Theater Averages", "/chart/top_opening_weekend_theater_avg/", {"by_release_scale": "wide"}),
|
||||
"january": ("Top Opening Weekend in January", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "january"}),
|
||||
"february": ("Top Opening Weekend in February", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "february"}),
|
||||
"march": ("Top Opening Weekend in March", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "march"}),
|
||||
"april": ("Top Opening Weekend in April", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "april"}),
|
||||
"may": ("Top Opening Weekend in May", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "may"}),
|
||||
"june": ("Top Opening Weekend in June", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "june"}),
|
||||
"july": ("Top Opening Weekend in July", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "july"}),
|
||||
"august": ("Top Opening Weekend in August", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "august"}),
|
||||
"september": ("Top Opening Weekend in September", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "september"}),
|
||||
"october": ("Top Opening Weekend in October", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "october"}),
|
||||
"november": ("Top Opening Weekend in November", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "november"}),
|
||||
"december": ("Top Opening Weekend in December", "/chart/release_top_opn_wkd_in_month/", {"in_occasion": "december"}),
|
||||
"spring": ("Top Opening Weekend in Spring", "/chart/release_top_opn_wkd_in_season/", {"in_occasion": "spring"}),
|
||||
"summer": ("Top Opening Weekend in Summer", "/chart/release_top_opn_wkd_in_season/", {"in_occasion": "summer"}),
|
||||
"fall": ("Top Opening Weekend in Fall", "/chart/release_top_opn_wkd_in_season/", {"in_occasion": "fall"}),
|
||||
"holiday_season": ("Top Opening Weekend in The Holiday Season", "/chart/release_top_opn_wkd_in_season/", {"in_occasion": "holiday_season"}),
|
||||
"winter": ("Top Opening Weekend in Winter", "/chart/release_top_opn_wkd_in_season/", {"in_occasion": "winter"}),
|
||||
"g": ("Top Opening Weekend for G Ratings", "/chart/top_opening_wknd_by_mpaa/", {"by_mpaa": "G"}),
|
||||
"g/pg": ("Top Opening Weekend for G/PG Ratings", "/chart/top_opening_wknd_by_mpaa/", {"by_mpaa": "G%2FPG"}),
|
||||
"pg": ("Top Opening Weekend for PG Ratings", "/chart/top_opening_wknd_by_mpaa/", {"by_mpaa": "PG"}),
|
||||
"pg-13": ("Top Opening Weekend for PG-13 Ratings", "/chart/top_opening_wknd_by_mpaa/", {"by_mpaa": "PG-13"}),
|
||||
"r": ("Top Opening Weekend for R Ratings", "/chart/top_opening_wknd_by_mpaa/", {"by_mpaa": "R"}),
|
||||
"nc-17": ("Top Opening Weekend for NC-17 Ratings", "/chart/top_opening_wknd_by_mpaa/", {"by_mpaa": "NC-17"}),
|
||||
"mlk": ("Top Weekend for MLK Day", "/chart/release_top_weekend_gross/", {"by_occasion", "us_mlkday_weekend"}),
|
||||
"easter": ("Top Weekend for Easter", "/chart/release_top_weekend_gross/", {"by_occasion", "easter_weekend"}),
|
||||
"4th": ("Top Weekend for the 4th of July", "/chart/release_top_weekend_gross/", {"by_occasion", "us_july4_weekend"}),
|
||||
"memorial": ("Top Weekend for Memorial Day", "/chart/release_top_weekend_gross/", {"by_occasion", "us_memorialday_weekend"}),
|
||||
"labor": ("Top Weekend for Labor Day", "/chart/release_top_weekend_gross/", {"by_occasion", "us_laborday_weekend"}),
|
||||
"president": ("Top Weekend for President's Day", "/chart/release_top_weekend_gross/", {"by_occasion", "us_presidentsday_weekend"}),
|
||||
"thanksgiving_3": ("Top 3 Day Weekend for Thanksgiving", "/chart/release_top_weekend_gross/", {"by_occasion", "us_thanksgiving_3"}),
|
||||
"thanksgiving_5": ("Top 5 Day Weekend for Thanksgiving", "/chart/release_top_weekend_gross/", {"by_occasion", "us_thanksgiving_5"}),
|
||||
"mlk_opening": ("Top Opening Weekend for MLK Day", "/chart/top_opening_holiday_weekends/", {"by_occasion", "us_mlkday_weekend"}),
|
||||
"easter_opening": ("Top Opening Weekend for Easter", "/chart/top_opening_holiday_weekends/", {"by_occasion", "easter_weekend"}),
|
||||
"memorial_opening": ("Top Opening Weekend for Memorial Day", "/chart/top_opening_holiday_weekends/", {"by_occasion", "us_memorialday_weekend"}),
|
||||
"labor_opening": ("Top Opening Weekend for Labor Day", "/chart/top_opening_holiday_weekends/", {"by_occasion", "us_laborday_weekend"}),
|
||||
"president_opening": ("Top Opening Weekend for MLK Day", "/chart/top_opening_holiday_weekends/", {"by_occasion", "us_presidentsday_weekend"}),
|
||||
"thanksgiving_3_opening": ("Top 3 Day Opening Weekend for Thanksgiving", "/chart/top_thanksgiving_openings/", {"by_occasion", "us_thanksgiving_3"}),
|
||||
"thanksgiving_5_opening": ("Top 5 Day Opening Weekend for Thanksgiving", "/chart/top_thanksgiving_openings/", {"by_occasion", "us_thanksgiving_5"}),
|
||||
"opening_week": ("Top Opening Week", "/chart/top_opening_week/", None),
|
||||
"biggest_theater_drop": ("Biggest Theater Drops", "/chart/biggest_third_weekend_num_theaters_drop/", None),
|
||||
"opening_day": ("Top Opening Day", "/chart/top_opening_day/", None),
|
||||
"single_day_grosses": ("Top Day", "/chart/release_top_daily_gross/", None),
|
||||
"christmas_day_gross": ("Top Christmas Day", "/chart/release_top_holiday_gross/", {"by_occasion": "christmas_day"}),
|
||||
"new_years_day_gross": ("Top New Years Day", "/chart/release_top_holiday_gross/", {"by_occasion": "newyearsday"}),
|
||||
"friday": ("Top Friday", "/chart/release_top_daily_gross_by_dow/", {"by_occasion": "friday"}),
|
||||
"saturday": ("Top Saturday", "/chart/release_top_daily_gross_by_dow/", {"by_occasion": "saturday"}),
|
||||
"sunday": ("Top Sunday", "/chart/release_top_daily_gross_by_dow/", {"by_occasion": "sunday"}),
|
||||
"monday": ("Top Monday", "/chart/release_top_daily_gross_by_dow/", {"by_occasion": "monday"}),
|
||||
"tuesday": ("Top Tuesday", "/chart/release_top_daily_gross_by_dow/", {"by_occasion": "tuesday"}),
|
||||
"wednesday": ("Top Wednesday", "/chart/release_top_daily_gross_by_dow/", {"by_occasion": "wednesday"}),
|
||||
"thursday": ("Top Thursday", "/chart/release_top_daily_gross_by_dow/", {"by_occasion": "thursday"}),
|
||||
"friday_non_opening": ("Top Friday Non-Opening", "/chart/top_non_opening_by_dow/", {"by_occasion": "friday"}),
|
||||
"saturday_non_opening": ("Top Saturday Non-Opening", "/chart/top_non_opening_by_dow/", {"by_occasion": "saturday"}),
|
||||
"sunday_non_opening": ("Top Sunday Non-Opening", "/chart/top_non_opening_by_dow/", {"by_occasion": "sunday"}),
|
||||
"monday_non_opening": ("Top Monday Non-Opening", "/chart/top_non_opening_by_dow/", {"by_occasion": "monday"}),
|
||||
"tuesday_non_opening": ("Top Tuesday Non-Opening", "/chart/top_non_opening_by_dow/", {"by_occasion": "tuesday"}),
|
||||
"wednesday_non_opening": ("Top Wednesday Non-Opening", "/chart/top_non_opening_by_dow/", {"by_occasion": "wednesday"}),
|
||||
"thursday_non_opening": ("Top Thursday Non-Opening", "/chart/top_non_opening_by_dow/", {"by_occasion": "thursday"}),
|
||||
}
|
||||
chart_options = ["domestic", "worldwide"]
|
||||
content_rating_options = {
|
||||
"g": "G",
|
||||
"g/pg": "G%2FPG",
|
||||
"pg": "PG",
|
||||
"pg-13": "PG-13",
|
||||
"r": "R",
|
||||
"nc-17": "NC-17",
|
||||
}
|
||||
never_in_options = {
|
||||
"1": ("#1", "never_1"),
|
||||
"5": ("the Top 5", "never_5"),
|
||||
"10": ("the Top 10", "never_10"),
|
||||
}
|
||||
intl_range_options = ["weekend", "monthly", "quarterly", "yearly"]
|
||||
dome_range_options = intl_range_options + ["daily", "weekly", "season", "holiday"]
|
||||
year_options = ["current"] + [str(t) for t in range(1977, datetime.now().year + 1)]
|
||||
quarter_options = ["current", "q1", "q2", "q3", "q4"]
|
||||
quarters = {1: "q1", 2: "q1", 3: "q1", 4: "q2", 5: "q2", 6: "q2", 7: "q3", 8: "q3", 9: "q3", 10: "q4", 11: "q4", 12: "q4"}
|
||||
season_options = ["current", "winter", "spring", "summer", "fall", "holiday"]
|
||||
seasons = {1: "winter", 2: "winter", 3: "spring", 4: "spring", 5: "summer", 6: "summer", 7: "summer", 8: "summer", 9: "fall", 10: "fall", 11: "holiday", 12: "holiday"}
|
||||
holiday_options = {
|
||||
"new_years_day": ("New Year's Day", "newyearsday"),
|
||||
"new_year_weekend": ("New Year Weekend", "us_newyear_weekend"),
|
||||
"mlk_day": ("MLK Day", "us_mlkday"),
|
||||
"mlk_day_weekend": ("MLK Day Weekend", "us_mlkday_weekend"),
|
||||
"presidents_day": ("President's Day", "us_presidentsday"),
|
||||
"presidents_day_weekend": ("President's Day Weekend", "us_presidentsday_weekend"),
|
||||
"easter": ("Easter", "easter_sunday"),
|
||||
"easter_weekend": ("Easter Weekend", "easter_weekend"),
|
||||
"memorial_day": ("Memorial Day", "us_memorialday"),
|
||||
"memorial_day_weekend": ("Memorial Day Weekend", "us_memorialday_weekend"),
|
||||
"independence_day": ("Independence Day", "us_july4"),
|
||||
"independence_day_weekend": ("Independence Day Weekend", "us_july4_weekend"),
|
||||
"labor_day": ("Labor Day", "us_laborday"),
|
||||
"labor_day_weekend": ("Labor Day Weekend", "us_laborday_weekend"),
|
||||
"indigenous_day": ("Indigenous People's Day", "us_indig_peoples_day"),
|
||||
"indigenous_day_weekend": ("", "us_indig_peoples_day_weekend"),
|
||||
"halloween": ("Halloween", "halloween"),
|
||||
"thanksgiving": ("Thanksgiving", "us_thanksgiving"),
|
||||
"thanksgiving_3": ("Thanksgiving Weekend", "us_thanksgiving_3"),
|
||||
"thanksgiving_4": ("Thanksgiving 4-Day Weekend", "us_thanksgiving_4"),
|
||||
"thanksgiving_5": ("Thanksgiving 5-Day Weekend", "us_thanksgiving_5"),
|
||||
"post_thanksgiving_weekend": ("Post-Thanksgiving Weekend", "us_post_thanksgiving_weekend"),
|
||||
"christmas_day": ("Christmas Day", "christmas_day"),
|
||||
"christmas_weekend": ("Christmas Weekend", "us_christmas_weekend"),
|
||||
"new_years_eve": ("New Year's Eve", "newyearseve")
|
||||
}
|
||||
base_url = "https://www.boxofficemojo.com"
|
||||
|
||||
|
||||
class BoxOfficeMojo:
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self._never_options = None
|
||||
self._intl_options = None
|
||||
self._year_options = None
|
||||
|
||||
def _options(self, url, nav_type="area"):
|
||||
output = {}
|
||||
options = self._request(url, xpath=f"//select[@id='{nav_type}-navSelector']/option")
|
||||
for option in options:
|
||||
query = parse_qs(urlparse(option.xpath("@value")[0]).query)
|
||||
output[option.xpath("text()")[0].lower()] = query["area"][0] if "area" in query else ""
|
||||
return output
|
||||
|
||||
@property
|
||||
def never_options(self):
|
||||
if self._never_options is None:
|
||||
self._never_options = self._options("/chart/never_in_top/")
|
||||
return self._never_options
|
||||
|
||||
@property
|
||||
def intl_options(self):
|
||||
if self._intl_options is None:
|
||||
self._intl_options = self._options("/intl/")
|
||||
return self._intl_options
|
||||
|
||||
@property
|
||||
def year_options(self):
|
||||
if self._year_options is None:
|
||||
self._year_options = [y for y in self._options("/year/world/", nav_type="year")]
|
||||
return self._year_options
|
||||
|
||||
def _request(self, url, xpath=None, params=None):
|
||||
logger.trace(f"URL: {base_url}{url}")
|
||||
if params:
|
||||
logger.trace(f"Params: {params}")
|
||||
response = self.config.get_html(f"{base_url}{url}", headers=util.header(), params=params)
|
||||
return response.xpath(xpath) if xpath else response
|
||||
|
||||
def _parse_list(self, url, params, limit):
|
||||
response = self._request(url, params=params)
|
||||
total_html = response.xpath("//li[contains(@class, 'mojo-pagination-button-center')]/a/text()")
|
||||
total = int(total_html[0].replace(",", "").split(" ")[2]) if total_html else 0
|
||||
if total and (limit < 1 or total < limit):
|
||||
limit = total
|
||||
pages = int((limit - 1) / 200) + 1 if total else 0
|
||||
for field_name in ["release ", "title", "release_group"]:
|
||||
output = response.xpath(f"//td[contains(@class, 'mojo-field-type-{field_name}')]/a/@href")
|
||||
if output:
|
||||
break
|
||||
for i in range(1, pages):
|
||||
response = self._request(url, params={"offset": 200 * i})
|
||||
output.extend(response.xpath(f"//td[contains(@class, 'mojo-field-type-{field_name}')]/a/@href"))
|
||||
if not limit or len(output) < limit:
|
||||
limit = len(output)
|
||||
return [i[:i.index("?")] for i in output[:limit]]
|
||||
|
||||
def _imdb(self, url):
|
||||
response = self._request(url)
|
||||
imdb_url = response.xpath("//select[@id='releasegroup-picker-navSelector']/option[text()='All Releases']/@value")
|
||||
if not imdb_url:
|
||||
raise Failed(f"Mojo Error: IMDb ID not found at {base_url}{url}")
|
||||
return imdb_url[0][7:-1]
|
||||
|
||||
def get_imdb_ids(self, method, data):
|
||||
params = None
|
||||
if method == "mojo_record":
|
||||
text, url, params = top_options[data["chart"]]
|
||||
elif method == "mojo_world":
|
||||
text = f"{data['year']} Worldwide Box Office"
|
||||
url = f"/year/world/{data['year']}/"
|
||||
elif method == "mojo_all_time":
|
||||
text = f"Top Lifetime {data['chart'].capitalize()}"
|
||||
if data["content_rating_filter"] is None:
|
||||
url = "/chart/top_lifetime_gross/" if data["chart"] == "domestic" else "/chart/ww_top_lifetime_gross/"
|
||||
else:
|
||||
text += f" {data['content_rating_filter'].upper()}"
|
||||
url = f"/chart/mpaa_title_lifetime_gross/"
|
||||
params = {"by_mpaa": content_rating_options[data['content_rating_filter']]}
|
||||
text += " Grosses"
|
||||
elif method == "mojo_never":
|
||||
pretty, arg_key = never_in_options[data["never"]]
|
||||
text = f"Top-Grossing Movies That Never Hit {pretty} {data['chart'].capitalize()}"
|
||||
url = f"/chart/never_in_top/"
|
||||
params = {"by_rank_threshold": data["never"]}
|
||||
if data["chart"] != "domestic":
|
||||
params["area"] = self.never_options[data["chart"]]
|
||||
else:
|
||||
chart = data["chart"].capitalize() if "chart" in data else "Domestic"
|
||||
|
||||
if data["range"] == "daily":
|
||||
day = datetime.strptime(data["range_data"], "%Y-%m-%d")
|
||||
day = day.strftime("%b {th}, %Y").replace("{th}", num2words(day.day, to='ordinal_num'))
|
||||
chart_title = f"{day}"
|
||||
url = f"/date/{data['range_data']}/"
|
||||
elif data["range"] == "weekend":
|
||||
chart_title = f"Weekend {data['range_data']} {data['year']}"
|
||||
url = f"/weekend/{data['year']}W{data['range_data']:02}/"
|
||||
elif data["range"] == "weekly":
|
||||
chart_title = f"Week {data['range_data']} {data['year']}"
|
||||
url = f"/weekly/{data['year']}W{data['range_data']:02}/"
|
||||
elif data["range"] == "monthly":
|
||||
chart_title = f"{data['range_data'].capitalize()} {data['year']}"
|
||||
url = f"/month/{data['range_data']}/{data['year']}/"
|
||||
elif data["range"] == "quarterly":
|
||||
chart_title = f"{data['range_data'].capitalize()} {data['year']}"
|
||||
url = f"/quarter/{data['range_data']}/{data['year']}/"
|
||||
elif data["range"] == "season":
|
||||
chart_title = f"{data['range_data'].capitalize()} {data['year']}"
|
||||
url = f"/season/{data['range_data']}/{data['year']}/"
|
||||
elif data["range"] == "holiday":
|
||||
title, slug = holiday_options[data["range_data"]]
|
||||
chart_title = f"{title} {data['year']}"
|
||||
url = f"/holiday/{slug}/{data['year']}/"
|
||||
else:
|
||||
chart_title = f"{data['year']}"
|
||||
url = f"/year/{data['year']}/"
|
||||
text = f"{chart} Box Office For {chart_title}"
|
||||
if data["limit"]:
|
||||
text += f" ({data['limit']})"
|
||||
logger.info(f"Processing {method.replace('_', ' ').title()}: {text}")
|
||||
items = self._parse_list(url, params, data["limit"])
|
||||
if not items:
|
||||
raise Failed(f"Mojo Error: No List Items found in {method}: {data}")
|
||||
ids = []
|
||||
total_items = len(items)
|
||||
for i, item in enumerate(items, 1):
|
||||
logger.ghost(f"Finding IMDb ID {i}/{total_items}")
|
||||
if "title" in item:
|
||||
imdb_id = item[7:-1]
|
||||
else:
|
||||
imdb_id = None
|
||||
expired = None
|
||||
if self.config.Cache:
|
||||
imdb_id, expired = self.config.Cache.query_letterboxd_map(item)
|
||||
if not imdb_id or expired is not False:
|
||||
try:
|
||||
imdb_id = self._imdb(item)
|
||||
except Failed as e:
|
||||
logger.error(e)
|
||||
continue
|
||||
if self.config.Cache:
|
||||
self.config.Cache.update_letterboxd_map(expired, item, imdb_id)
|
||||
ids.append((imdb_id, "imdb"))
|
||||
logger.info(f"Processed {total_items} IMDb IDs")
|
||||
return ids
|
|
@ -76,10 +76,12 @@ mod_displays = {
|
|||
".gt": "is greater than", ".gte": "is greater than or equal", ".lt": "is less than", ".lte": "is less than or equal", ".regex": "is"
|
||||
}
|
||||
pretty_days = {0: "Monday", 1: "Tuesday", 2: "Wednesday", 3: "Thursday", 4: "Friday", 5: "Saturday", 6: "Sunday"}
|
||||
lower_days = {v.lower(): k for k, v in pretty_days.items()}
|
||||
pretty_months = {
|
||||
1: "January", 2: "February", 3: "March", 4: "April", 5: "May", 6: "June",
|
||||
7: "July", 8: "August", 9: "September", 10: "October", 11: "November", 12: "December"
|
||||
}
|
||||
lower_months = {v.lower(): k for k, v in pretty_months.items()}
|
||||
seasons = ["current", "winter", "spring", "summer", "fall"]
|
||||
advance_tags_to_edit = {
|
||||
"Movie": ["metadata_language", "use_original_title"],
|
||||
|
@ -782,7 +784,7 @@ def parse(error, attribute, data, datatype=None, methods=None, parent=None, defa
|
|||
if options is None or (options and (v in options or (datatype == "strlist" and str(v) in options))):
|
||||
final_list.append(str(v) if datatype == "strlist" else v)
|
||||
elif options:
|
||||
raise Failed(f"{error} Error: {display} {v} is invalid; Options include: {', '.join(options)}")
|
||||
raise Failed(f"{error} Error: {display} {v} is invalid; Options include: {', '.join([o for o in options])}")
|
||||
return final_list
|
||||
elif datatype == "intlist":
|
||||
if value:
|
||||
|
@ -861,7 +863,9 @@ def parse(error, attribute, data, datatype=None, methods=None, parent=None, defa
|
|||
message = f"{message} separated by a {range_split}"
|
||||
elif datatype == "date":
|
||||
try:
|
||||
return validate_date(datetime.now() if data == "today" else data, return_as=date_return)
|
||||
if default in ["today", "current"]:
|
||||
default = validate_date(datetime.now(), return_as=date_return)
|
||||
return validate_date(datetime.now() if data in ["today", "current"] else data, return_as=date_return)
|
||||
except Failed as e:
|
||||
message = f"{e}"
|
||||
elif (translation is not None and str(value).lower() not in translation) or \
|
||||
|
|
|
@ -7,9 +7,10 @@ pillow==10.2.0
|
|||
PlexAPI==4.15.7
|
||||
psutil==5.9.7
|
||||
python-dotenv==1.0.0
|
||||
python-dateutil==2.8.2
|
||||
requests==2.31.0
|
||||
retrying==1.3.4
|
||||
ruamel.yaml==0.18.5
|
||||
schedule==1.2.1
|
||||
tmdbapis==1.2.6
|
||||
setuptools==69.0.3
|
||||
tmdbapis==1.2.6
|
Loading…
Reference in a new issue