compuglobal 0.3.7__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {compuglobal-0.3.7 → compuglobal-0.4.0}/PKG-INFO +5 -25
- {compuglobal-0.3.7 → compuglobal-0.4.0}/README.rst +3 -23
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/__init__.py +7 -3
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/aio.py +223 -83
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/api/client.py +17 -14
- compuglobal-0.4.0/compuglobal/api/config.py +16 -0
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/api/discovery.py +12 -12
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/api/endpoint.py +29 -7
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/api/media.py +29 -12
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/api/metadata.py +4 -4
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/errors.py +9 -11
- compuglobal-0.4.0/compuglobal/models/base.py +25 -0
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/models/comic.py +102 -34
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/models/episode.py +18 -18
- compuglobal-0.4.0/compuglobal/models/font.py +147 -0
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/models/frame.py +10 -11
- compuglobal-0.4.0/compuglobal/models/overlay.py +106 -0
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/models/screencap.py +90 -24
- compuglobal-0.4.0/compuglobal/models/stream.py +234 -0
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/models/subtitle.py +12 -10
- compuglobal-0.4.0/compuglobal/models/timestamp.py +88 -0
- {compuglobal-0.3.7 → compuglobal-0.4.0}/pyproject.toml +15 -5
- compuglobal-0.3.7/compuglobal/api/config.py +0 -13
- compuglobal-0.3.7/compuglobal/models/base.py +0 -9
- compuglobal-0.3.7/compuglobal/models/font.py +0 -59
- compuglobal-0.3.7/compuglobal/models/stream.py +0 -135
- {compuglobal-0.3.7 → compuglobal-0.4.0}/LICENSE +0 -0
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/api/__init__.py +0 -0
- {compuglobal-0.3.7 → compuglobal-0.4.0}/compuglobal/models/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: compuglobal
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Python wrapper for the CGHMC API (Frinkiac, Morbotron Master Of All Science and more.
|
|
5
5
|
Keywords: The Simpsons,Futurama,Rick and Morty,West Wing,Frinkiac,Morbotron,Master of all Science,Capital Beat,API,API Wrapper,CompuGlobal,CompuGlobalHyperMegaNet,CGHMC
|
|
6
6
|
Author: MitchellAW
|
|
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
12
12
|
Classifier: Operating System :: OS Independent
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: aiohttp>=3.
|
|
15
|
+
Requires-Dist: aiohttp>=3.14.0
|
|
16
16
|
Requires-Dist: pydantic>=2.13.0
|
|
17
17
|
Project-URL: Documentation, https://compuglobal.readthedocs.io/en/latest/
|
|
18
18
|
Project-URL: Source, https://github.com/MitchellAW/CompuGlobal
|
|
@@ -29,6 +29,9 @@ CompuGlobal
|
|
|
29
29
|
.. image:: https://img.shields.io/pypi/pyversions/compuglobal.svg
|
|
30
30
|
:target: https://pypi.python.org/pypi/compuglobal
|
|
31
31
|
|
|
32
|
+
.. image:: https://app.readthedocs.org/projects/compuglobal/badge/?version=latest&style=flat
|
|
33
|
+
:target: https://compuglobal.readthedocs.io/en/latest/
|
|
34
|
+
|
|
32
35
|
.. image:: https://img.shields.io/github/actions/workflow/status/MitchellAW/CompuGlobal/test.yml?label=tests
|
|
33
36
|
:target: https://github.com/MitchellAW/CompuGlobal/actions/workflows/test.yml
|
|
34
37
|
|
|
@@ -86,29 +89,6 @@ Basic Usage
|
|
|
86
89
|
|
|
87
90
|
For documented examples, check `here.`_
|
|
88
91
|
|
|
89
|
-
What's New
|
|
90
|
-
------------
|
|
91
|
-
**0.3.0 - Breaking changes**
|
|
92
|
-
|
|
93
|
-
These changes are to accommodate the extensive update to the APIs with new features:
|
|
94
|
-
|
|
95
|
-
- All synchronous implementations of the package have been removed
|
|
96
|
-
- The async endpoints persist and are now accessible via **compuglobal** or **compuglobal.aio** as done previously
|
|
97
|
-
- The `Master Of All Science`_ API appears to be unavailable at this point in time and redirects to Frinkiac, I have added a **deprecation warning** to this API and it will remain unless the API returns
|
|
98
|
-
- The package now requires **Python 3.13+**
|
|
99
|
-
- Image, comic, and gif generation are all now performed using the API rather than from a Screencap
|
|
100
|
-
|
|
101
|
-
.. code-block:: py
|
|
102
|
-
|
|
103
|
-
# This is now async
|
|
104
|
-
simpsons = compuglobal.Frinkiac()
|
|
105
|
-
|
|
106
|
-
# Previous usage
|
|
107
|
-
await screencap.get_gif_url()
|
|
108
|
-
|
|
109
|
-
# New usage
|
|
110
|
-
await simpsons.get_gif_url(screencap)
|
|
111
|
-
|
|
112
92
|
Preview
|
|
113
93
|
------------
|
|
114
94
|
.. image:: https://raw.githubusercontent.com/MitchellAW/MitchellAW.github.io/refs/heads/master/images/nothing-at-all.gif
|
|
@@ -10,6 +10,9 @@ CompuGlobal
|
|
|
10
10
|
.. image:: https://img.shields.io/pypi/pyversions/compuglobal.svg
|
|
11
11
|
:target: https://pypi.python.org/pypi/compuglobal
|
|
12
12
|
|
|
13
|
+
.. image:: https://app.readthedocs.org/projects/compuglobal/badge/?version=latest&style=flat
|
|
14
|
+
:target: https://compuglobal.readthedocs.io/en/latest/
|
|
15
|
+
|
|
13
16
|
.. image:: https://img.shields.io/github/actions/workflow/status/MitchellAW/CompuGlobal/test.yml?label=tests
|
|
14
17
|
:target: https://github.com/MitchellAW/CompuGlobal/actions/workflows/test.yml
|
|
15
18
|
|
|
@@ -67,29 +70,6 @@ Basic Usage
|
|
|
67
70
|
|
|
68
71
|
For documented examples, check `here.`_
|
|
69
72
|
|
|
70
|
-
What's New
|
|
71
|
-
------------
|
|
72
|
-
**0.3.0 - Breaking changes**
|
|
73
|
-
|
|
74
|
-
These changes are to accommodate the extensive update to the APIs with new features:
|
|
75
|
-
|
|
76
|
-
- All synchronous implementations of the package have been removed
|
|
77
|
-
- The async endpoints persist and are now accessible via **compuglobal** or **compuglobal.aio** as done previously
|
|
78
|
-
- The `Master Of All Science`_ API appears to be unavailable at this point in time and redirects to Frinkiac, I have added a **deprecation warning** to this API and it will remain unless the API returns
|
|
79
|
-
- The package now requires **Python 3.13+**
|
|
80
|
-
- Image, comic, and gif generation are all now performed using the API rather than from a Screencap
|
|
81
|
-
|
|
82
|
-
.. code-block:: py
|
|
83
|
-
|
|
84
|
-
# This is now async
|
|
85
|
-
simpsons = compuglobal.Frinkiac()
|
|
86
|
-
|
|
87
|
-
# Previous usage
|
|
88
|
-
await screencap.get_gif_url()
|
|
89
|
-
|
|
90
|
-
# New usage
|
|
91
|
-
await simpsons.get_gif_url(screencap)
|
|
92
|
-
|
|
93
73
|
Preview
|
|
94
74
|
------------
|
|
95
75
|
.. image:: https://raw.githubusercontent.com/MitchellAW/MitchellAW.github.io/refs/heads/master/images/nothing-at-all.gif
|
|
@@ -11,16 +11,18 @@ from compuglobal.aio import (
|
|
|
11
11
|
from compuglobal.errors import APIPageStatusError, NoSearchResultsFoundError
|
|
12
12
|
from compuglobal.models.comic import ComicLayout, ComicOverlay, ComicPanel, ComicStrip
|
|
13
13
|
from compuglobal.models.episode import Episode, EpisodeMetadata, EpisodeSummary
|
|
14
|
-
from compuglobal.models.font import FontAlignment,
|
|
14
|
+
from compuglobal.models.font import FontAlignment, FontColor, FontFamily
|
|
15
15
|
from compuglobal.models.frame import Frame, FrameResult
|
|
16
|
+
from compuglobal.models.overlay import OverlayFormat
|
|
16
17
|
from compuglobal.models.screencap import Screencap, ScreencapMoment
|
|
17
18
|
from compuglobal.models.stream import Stream, StreamOverlay
|
|
18
19
|
from compuglobal.models.subtitle import Subtitle
|
|
20
|
+
from compuglobal.models.timestamp import Timestamp
|
|
19
21
|
|
|
20
22
|
__title__ = "compuglobal"
|
|
21
23
|
__author__ = "MitchellAW"
|
|
22
24
|
__license__ = "MIT"
|
|
23
|
-
__version__ = "0.
|
|
25
|
+
__version__ = "0.4.0"
|
|
24
26
|
|
|
25
27
|
__all__ = [
|
|
26
28
|
"APIPageStatusError",
|
|
@@ -34,7 +36,7 @@ __all__ = [
|
|
|
34
36
|
"EpisodeMetadata",
|
|
35
37
|
"EpisodeSummary",
|
|
36
38
|
"FontAlignment",
|
|
37
|
-
"
|
|
39
|
+
"FontColor",
|
|
38
40
|
"FontFamily",
|
|
39
41
|
"Frame",
|
|
40
42
|
"FrameResult",
|
|
@@ -42,9 +44,11 @@ __all__ = [
|
|
|
42
44
|
"MasterOfAllScience",
|
|
43
45
|
"Morbotron",
|
|
44
46
|
"NoSearchResultsFoundError",
|
|
47
|
+
"OverlayFormat",
|
|
45
48
|
"Screencap",
|
|
46
49
|
"ScreencapMoment",
|
|
47
50
|
"Stream",
|
|
48
51
|
"StreamOverlay",
|
|
49
52
|
"Subtitle",
|
|
53
|
+
"Timestamp",
|
|
50
54
|
]
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""Used for interacting with and building CGHMC APIs."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import logging
|
|
5
|
+
from typing import overload
|
|
4
6
|
from warnings import deprecated
|
|
5
7
|
|
|
6
8
|
import aiohttp
|
|
@@ -15,19 +17,44 @@ from compuglobal.models.comic import ComicPanel, ComicStrip
|
|
|
15
17
|
from compuglobal.models.episode import Episode, EpisodeSummary
|
|
16
18
|
from compuglobal.models.font import FontFamily
|
|
17
19
|
from compuglobal.models.frame import Frame, FrameResult
|
|
20
|
+
from compuglobal.models.overlay import OverlayFormat
|
|
18
21
|
from compuglobal.models.screencap import Screencap, ScreencapMoment
|
|
19
22
|
from compuglobal.models.stream import Stream
|
|
20
23
|
from compuglobal.models.subtitle import Subtitle
|
|
21
24
|
|
|
25
|
+
log = logging.getLogger(__name__)
|
|
26
|
+
|
|
22
27
|
"""Contains the async API Wrappers used for accessing all the cghmc API endpoints."""
|
|
23
28
|
|
|
24
29
|
|
|
25
30
|
class AsyncCompuGlobalAPI:
|
|
26
|
-
"""Represents a base API of the CGHMC family.
|
|
31
|
+
"""Represents a base API of the CGHMC family.
|
|
32
|
+
|
|
33
|
+
Parameters
|
|
34
|
+
----------
|
|
35
|
+
session : aiohttp.ClientSession, optional
|
|
36
|
+
The client session to use for all API calls
|
|
37
|
+
|
|
38
|
+
Attributes
|
|
39
|
+
----------
|
|
40
|
+
BASE_URL : str
|
|
41
|
+
The base url of the API
|
|
42
|
+
TITLE : str
|
|
43
|
+
The title of the API
|
|
44
|
+
DEFAULT_FORMAT : OverlayFormat
|
|
45
|
+
The default formatting to use in all comic/gif overlays
|
|
46
|
+
discovery : DiscoveryAPI
|
|
47
|
+
The discovery API with all discovery endpoints
|
|
48
|
+
media : MediaAPI
|
|
49
|
+
The media API with all media endpoints
|
|
50
|
+
metadata : MetadataAPI
|
|
51
|
+
The metadataAPI with all metadata endpoints
|
|
52
|
+
|
|
53
|
+
"""
|
|
27
54
|
|
|
28
55
|
BASE_URL: str
|
|
29
56
|
TITLE: str
|
|
30
|
-
|
|
57
|
+
DEFAULT_FORMAT: OverlayFormat
|
|
31
58
|
_MAX_ALLOWED_SUBTITLES = 4
|
|
32
59
|
|
|
33
60
|
discovery: DiscoveryAPI = DiscoveryAPI()
|
|
@@ -35,57 +62,31 @@ class AsyncCompuGlobalAPI:
|
|
|
35
62
|
metadata: MetadataAPI = MetadataAPI()
|
|
36
63
|
|
|
37
64
|
def __init__(self, session: aiohttp.ClientSession) -> None:
|
|
38
|
-
"""Create an API using the given session and timeout.
|
|
39
|
-
|
|
40
|
-
Parameters
|
|
41
|
-
----------
|
|
42
|
-
session : aiohttp.ClientSession | None, optional
|
|
43
|
-
The client session to use for all API calls
|
|
44
|
-
|
|
45
|
-
"""
|
|
46
65
|
self.client = CompuGlobalAPIClient(base_url=self.BASE_URL, session=session)
|
|
47
|
-
self.config = CompuGlobalAPIConfig(title=self.TITLE,
|
|
66
|
+
self.config = CompuGlobalAPIConfig(title=self.TITLE, default_format=self.DEFAULT_FORMAT)
|
|
48
67
|
|
|
49
68
|
async def get_screencap(
|
|
50
69
|
self,
|
|
70
|
+
*,
|
|
51
71
|
episode: str | None = None,
|
|
52
72
|
timestamp: int | None = None,
|
|
53
|
-
frame: Frame | None = None,
|
|
54
73
|
) -> Screencap:
|
|
55
|
-
"""Get the screencap for the given episode & timestamp
|
|
74
|
+
"""Get the screencap for the given episode & timestamp.
|
|
56
75
|
|
|
57
76
|
Parameters
|
|
58
77
|
----------
|
|
59
|
-
episode : str, optional
|
|
78
|
+
episode : str | None, optional
|
|
60
79
|
An episode key
|
|
61
|
-
timestamp : int, optional
|
|
80
|
+
timestamp : int | None, optional
|
|
62
81
|
A timestamp of the screencap
|
|
63
|
-
frame : Frame, optional
|
|
64
|
-
A Frame object
|
|
65
82
|
|
|
66
83
|
Returns
|
|
67
84
|
-------
|
|
68
85
|
Screencap
|
|
69
86
|
The screencap for the given episode key and timestamp.
|
|
70
87
|
|
|
71
|
-
Raises
|
|
72
|
-
------
|
|
73
|
-
TypeError
|
|
74
|
-
Must give only episode + timestamp, or a Frame object.
|
|
75
|
-
|
|
76
88
|
"""
|
|
77
|
-
|
|
78
|
-
params = {"e": episode, "t": timestamp, "nearby": 1}
|
|
79
|
-
|
|
80
|
-
elif isinstance(frame, Frame):
|
|
81
|
-
params = {"e": frame.key, "t": frame.timestamp, "nearby": 1}
|
|
82
|
-
|
|
83
|
-
else:
|
|
84
|
-
invalid_args_error = (
|
|
85
|
-
f"Expected str and int or compuglobal.Frame, but received {type(episode)},"
|
|
86
|
-
f" {type(timestamp)} and {type(frame)} instead"
|
|
87
|
-
)
|
|
88
|
-
raise TypeError(invalid_args_error)
|
|
89
|
+
params = {"e": episode, "t": timestamp, "nearby": 1}
|
|
89
90
|
|
|
90
91
|
request = self.discovery.CAPTION.build_request(self.client.base_url, query=params)
|
|
91
92
|
caption = await self.client.handle_request(request)
|
|
@@ -103,14 +104,14 @@ class AsyncCompuGlobalAPI:
|
|
|
103
104
|
----------
|
|
104
105
|
search_text : str
|
|
105
106
|
The search text to query
|
|
106
|
-
season_minimum: int | None, optional
|
|
107
|
+
season_minimum : int | None, optional
|
|
107
108
|
The minimum season allowed in the search results
|
|
108
|
-
season_maximum: int | None, optional
|
|
109
|
+
season_maximum : int | None, optional
|
|
109
110
|
The maximum season allowed in the search results
|
|
110
111
|
|
|
111
112
|
Returns
|
|
112
113
|
-------
|
|
113
|
-
|
|
114
|
+
list[FrameResult]
|
|
114
115
|
A list of all frames found containing the search text.
|
|
115
116
|
|
|
116
117
|
Raises
|
|
@@ -129,6 +130,13 @@ class AsyncCompuGlobalAPI:
|
|
|
129
130
|
if len(search_results) > 0:
|
|
130
131
|
return [FrameResult.model_validate(result) for result in search_results]
|
|
131
132
|
|
|
133
|
+
log.debug(
|
|
134
|
+
"No search results found | base_url=%s | search_text=%s | season_minimum=%s | season_maximum=%s",
|
|
135
|
+
self.BASE_URL,
|
|
136
|
+
search_text,
|
|
137
|
+
season_minimum,
|
|
138
|
+
season_maximum,
|
|
139
|
+
)
|
|
132
140
|
raise NoSearchResultsFoundError
|
|
133
141
|
|
|
134
142
|
async def search_for_screencap(
|
|
@@ -143,9 +151,9 @@ class AsyncCompuGlobalAPI:
|
|
|
143
151
|
----------
|
|
144
152
|
search_text : str
|
|
145
153
|
The search text to query
|
|
146
|
-
season_minimum: int | None, optional
|
|
154
|
+
season_minimum : int | None, optional
|
|
147
155
|
The minimum season allowed in the search
|
|
148
|
-
season_maximum: int | None, optional
|
|
156
|
+
season_maximum : int | None, optional
|
|
149
157
|
The maximum season allowed in the search
|
|
150
158
|
|
|
151
159
|
Returns
|
|
@@ -156,7 +164,7 @@ class AsyncCompuGlobalAPI:
|
|
|
156
164
|
"""
|
|
157
165
|
search_results = await self.search(search_text, season_minimum=season_minimum, season_maximum=season_maximum)
|
|
158
166
|
result = search_results[0]
|
|
159
|
-
return await self.get_screencap(result.key, result.timestamp)
|
|
167
|
+
return await self.get_screencap(episode=result.key, timestamp=result.timestamp)
|
|
160
168
|
|
|
161
169
|
async def get_random_screencap(
|
|
162
170
|
self,
|
|
@@ -165,9 +173,16 @@ class AsyncCompuGlobalAPI:
|
|
|
165
173
|
) -> Screencap:
|
|
166
174
|
"""Get a random TV Show screencap.
|
|
167
175
|
|
|
176
|
+
Parameters
|
|
177
|
+
----------
|
|
178
|
+
season_minimum : int | None, optional
|
|
179
|
+
Minimum season number allowed in random result
|
|
180
|
+
season_maximum : int | None, optional
|
|
181
|
+
Maximum season number allowed in random result
|
|
182
|
+
|
|
168
183
|
Returns
|
|
169
184
|
-------
|
|
170
|
-
|
|
185
|
+
Screencap
|
|
171
186
|
A random screencap object.
|
|
172
187
|
|
|
173
188
|
"""
|
|
@@ -208,7 +223,7 @@ class AsyncCompuGlobalAPI:
|
|
|
208
223
|
|
|
209
224
|
Returns
|
|
210
225
|
-------
|
|
211
|
-
|
|
226
|
+
list[Subtitle]
|
|
212
227
|
The list of subtitles
|
|
213
228
|
|
|
214
229
|
"""
|
|
@@ -222,7 +237,7 @@ class AsyncCompuGlobalAPI:
|
|
|
222
237
|
|
|
223
238
|
Returns
|
|
224
239
|
-------
|
|
225
|
-
|
|
240
|
+
list[ScreencapMoment]
|
|
226
241
|
List of random screencap moments
|
|
227
242
|
|
|
228
243
|
"""
|
|
@@ -235,7 +250,7 @@ class AsyncCompuGlobalAPI:
|
|
|
235
250
|
|
|
236
251
|
Returns
|
|
237
252
|
-------
|
|
238
|
-
|
|
253
|
+
list[EpisodeSummary]
|
|
239
254
|
A list of episode summaries
|
|
240
255
|
|
|
241
256
|
"""
|
|
@@ -248,18 +263,18 @@ class AsyncCompuGlobalAPI:
|
|
|
248
263
|
|
|
249
264
|
Parameters
|
|
250
265
|
----------
|
|
251
|
-
key: str
|
|
266
|
+
key : str
|
|
252
267
|
The episode key of the screencap.
|
|
253
|
-
timestamp: int
|
|
268
|
+
timestamp : int
|
|
254
269
|
The timestamp of the screencap.
|
|
255
|
-
before: int
|
|
270
|
+
before : int
|
|
256
271
|
The number of milliseconds before the timestamp.
|
|
257
|
-
after: int
|
|
272
|
+
after : int
|
|
258
273
|
The number of milliseconds after the timestamp.
|
|
259
274
|
|
|
260
275
|
Returns
|
|
261
276
|
-------
|
|
262
|
-
list
|
|
277
|
+
list[Frame]
|
|
263
278
|
A list of valid frames before and after the timestamp of
|
|
264
279
|
the episode.
|
|
265
280
|
|
|
@@ -274,6 +289,11 @@ class AsyncCompuGlobalAPI:
|
|
|
274
289
|
async def get_image_url(self, screencap: Screencap) -> str:
|
|
275
290
|
"""Get the direct image url for the screencap without any caption.
|
|
276
291
|
|
|
292
|
+
Parameters
|
|
293
|
+
----------
|
|
294
|
+
screencap : Screencap
|
|
295
|
+
The screencap to use for generating the image url
|
|
296
|
+
|
|
277
297
|
Returns
|
|
278
298
|
-------
|
|
279
299
|
str
|
|
@@ -283,15 +303,22 @@ class AsyncCompuGlobalAPI:
|
|
|
283
303
|
path_params = {"key": screencap.frame.key, "timestamp": screencap.frame.timestamp}
|
|
284
304
|
return self.media.IMAGE.build_encoded_url(self.client.base_url, path_params=path_params)
|
|
285
305
|
|
|
286
|
-
async def get_comic_panel_url(
|
|
306
|
+
async def get_comic_panel_url(
|
|
307
|
+
self,
|
|
308
|
+
screencap: Screencap,
|
|
309
|
+
subtitles: list[Subtitle] | None = None,
|
|
310
|
+
overlay_format: OverlayFormat | None = None,
|
|
311
|
+
) -> str:
|
|
287
312
|
"""Get the URL for a single comic panel showing the given screencap with subtitles.
|
|
288
313
|
|
|
289
314
|
Parameters
|
|
290
315
|
----------
|
|
291
316
|
screencap : Screencap
|
|
292
317
|
The screencap to use in the comic panel
|
|
293
|
-
subtitles :
|
|
318
|
+
subtitles : list[Subtitle] | None, optional
|
|
294
319
|
A list of subtitles to overlay in the comic panel
|
|
320
|
+
overlay_format : OverlayFormat | None, optional
|
|
321
|
+
The formatting to use in the comic panel overlay (subtitle)
|
|
295
322
|
|
|
296
323
|
Returns
|
|
297
324
|
-------
|
|
@@ -299,25 +326,30 @@ class AsyncCompuGlobalAPI:
|
|
|
299
326
|
The url of the comic panel
|
|
300
327
|
|
|
301
328
|
"""
|
|
302
|
-
|
|
303
|
-
subtitles = screencap.subtitles
|
|
329
|
+
screencap, subtitles, overlay_format = self._resolve_overlay_inputs(screencap, subtitles, overlay_format)
|
|
304
330
|
|
|
305
|
-
|
|
331
|
+
panel = ComicPanel.from_screencap(screencap=screencap, overlay_format=overlay_format)
|
|
306
332
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
params = {"b64": panel.get_encoded()}
|
|
333
|
+
params = {"b64": panel.encoded}
|
|
310
334
|
return self.media.COMIC_PANEL.build_encoded_url(self.client.base_url, query=params)
|
|
311
335
|
|
|
312
|
-
async def get_comic_strip_url(
|
|
336
|
+
async def get_comic_strip_url(
|
|
337
|
+
self,
|
|
338
|
+
screencap: Screencap,
|
|
339
|
+
subtitles: list[Subtitle] | None = None,
|
|
340
|
+
overlay_format: OverlayFormat | list[OverlayFormat] | None = None,
|
|
341
|
+
) -> str:
|
|
313
342
|
"""Get the URL for a comic strip showing the given screencap with subtitles.
|
|
314
343
|
|
|
315
344
|
Parameters
|
|
316
345
|
----------
|
|
317
346
|
screencap : Screencap
|
|
318
347
|
The screencap to use in the comic strip
|
|
319
|
-
subtitles :
|
|
348
|
+
subtitles : list[Subtitle] | None, optional
|
|
320
349
|
The subtitles to overlay in the comic strip
|
|
350
|
+
overlay_format : OverlayFormat | list[OverlayFormat] | None, optional
|
|
351
|
+
The formatting to use in the comic strip overlays (subtitleS). See :meth:`OverlayFormat.normalise` for
|
|
352
|
+
full details on how formats are resolved.
|
|
321
353
|
|
|
322
354
|
Returns
|
|
323
355
|
-------
|
|
@@ -325,28 +357,63 @@ class AsyncCompuGlobalAPI:
|
|
|
325
357
|
The url of the comic strip
|
|
326
358
|
|
|
327
359
|
"""
|
|
328
|
-
|
|
329
|
-
subtitles = screencap.subtitles
|
|
360
|
+
screencap, subtitles, overlay_format = self._resolve_overlay_inputs(screencap, subtitles, overlay_format)
|
|
330
361
|
|
|
331
|
-
|
|
332
|
-
|
|
362
|
+
comic_strip = ComicStrip.from_screencap(screencap=screencap, overlay_format=overlay_format)
|
|
363
|
+
params = {"b64": comic_strip.encoded, "layout": comic_strip.layout}
|
|
364
|
+
return self.media.COMIC_STRIP.build_encoded_url(self.client.base_url, query=params)
|
|
333
365
|
|
|
334
|
-
|
|
335
|
-
|
|
366
|
+
async def get_comic_maker_url(
|
|
367
|
+
self,
|
|
368
|
+
screencap: Screencap,
|
|
369
|
+
subtitles: list[Subtitle] | None = None,
|
|
370
|
+
overlay_format: OverlayFormat | list[OverlayFormat] | None = None,
|
|
371
|
+
) -> str:
|
|
372
|
+
"""Get a url for making a comic with the given screencap, subtitles, and overlay format(s).
|
|
336
373
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
374
|
+
Parameters
|
|
375
|
+
----------
|
|
376
|
+
screencap : Screencap
|
|
377
|
+
The screencap to make the comic with
|
|
378
|
+
subtitles : list[Subtitle] | None, optional
|
|
379
|
+
The subtitles to override in the comic maker, by default None
|
|
380
|
+
overlay_format : OverlayFormat | list[OverlayFormat] | None, optional
|
|
381
|
+
The subtitle/overlay formatting to override in the comic maker, by default None
|
|
382
|
+
|
|
383
|
+
Returns
|
|
384
|
+
-------
|
|
385
|
+
str
|
|
386
|
+
The url for making the comic
|
|
387
|
+
|
|
388
|
+
"""
|
|
389
|
+
screencap, subtitles, overlay_format = self._resolve_overlay_inputs(screencap, subtitles, overlay_format)
|
|
390
|
+
path_params = {"key": screencap.frame.key, "timestamp": screencap.frame.timestamp}
|
|
391
|
+
|
|
392
|
+
strip = ComicStrip.from_screencap(screencap=screencap, overlay_format=overlay_format)
|
|
340
393
|
|
|
341
|
-
|
|
394
|
+
return self.media.COMIC_MAKER.build_encoded_url(
|
|
395
|
+
base_url=self.BASE_URL,
|
|
396
|
+
path_params=path_params,
|
|
397
|
+
query={"b64": strip.encoded, "layout": strip.layout},
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
async def get_gif_url(
|
|
401
|
+
self,
|
|
402
|
+
screencap: Screencap,
|
|
403
|
+
subtitles: list[Subtitle] | None = None,
|
|
404
|
+
overlay_format: OverlayFormat | list[OverlayFormat] | None = None,
|
|
405
|
+
) -> str:
|
|
342
406
|
"""Get the URL for a gif of the given screencap with default or given subtitles.
|
|
343
407
|
|
|
344
408
|
Parameters
|
|
345
409
|
----------
|
|
346
410
|
screencap : Screencap
|
|
347
411
|
The screencap to use for the gif
|
|
348
|
-
subtitles :
|
|
412
|
+
subtitles : list[Subtitle] | None, optional
|
|
349
413
|
The subtitles to overlay in the gif
|
|
414
|
+
overlay_format : OverlayFormat | list[OverlayFormat] | None, optional
|
|
415
|
+
The formatting to use in the gif overlays (subtitles). See :meth:`OverlayFormat.normalise` for
|
|
416
|
+
full details on how formats are resolved.
|
|
350
417
|
|
|
351
418
|
Returns
|
|
352
419
|
-------
|
|
@@ -354,16 +421,9 @@ class AsyncCompuGlobalAPI:
|
|
|
354
421
|
The URL of the gif, or a comic strip as a fallback if gif rendering fails.
|
|
355
422
|
|
|
356
423
|
"""
|
|
357
|
-
|
|
358
|
-
subtitles = screencap.subtitles
|
|
424
|
+
screencap, subtitles, overlay_format = self._resolve_overlay_inputs(screencap, subtitles, overlay_format)
|
|
359
425
|
|
|
360
|
-
|
|
361
|
-
subtitles = subtitles[: self._MAX_ALLOWED_SUBTITLES]
|
|
362
|
-
|
|
363
|
-
# Change subtitles
|
|
364
|
-
screencap = screencap.model_copy(update={"subtitles": subtitles})
|
|
365
|
-
|
|
366
|
-
stream = Stream.from_screencap(screencap=screencap, font_family=self.config.default_font)
|
|
426
|
+
stream = Stream.from_screencap(screencap=screencap, overlay_format=overlay_format)
|
|
367
427
|
|
|
368
428
|
request = self.media.RENDER_GIF.build_request(self.client.base_url, body=stream)
|
|
369
429
|
request.body = [request.body]
|
|
@@ -377,13 +437,93 @@ class AsyncCompuGlobalAPI:
|
|
|
377
437
|
|
|
378
438
|
return await self.get_comic_strip_url(screencap)
|
|
379
439
|
|
|
440
|
+
async def get_gif_maker_url(
|
|
441
|
+
self,
|
|
442
|
+
screencap: Screencap,
|
|
443
|
+
subtitles: list[Subtitle] | None = None,
|
|
444
|
+
overlay_format: OverlayFormat | list[OverlayFormat] | None = None,
|
|
445
|
+
) -> str:
|
|
446
|
+
"""Get a url for making a comic with the given screencap, subtitles, and overlay format(s).
|
|
447
|
+
|
|
448
|
+
Parameters
|
|
449
|
+
----------
|
|
450
|
+
screencap : Screencap
|
|
451
|
+
The screencap to make the comic with
|
|
452
|
+
subtitles : list[Subtitle] | None, optional
|
|
453
|
+
The subtitles to override in the comic maker, by default None
|
|
454
|
+
overlay_format : OverlayFormat | list[OverlayFormat] | None, optional
|
|
455
|
+
The subtitle/overlay formatting to override in the comic maker, by default None
|
|
456
|
+
|
|
457
|
+
Returns
|
|
458
|
+
-------
|
|
459
|
+
str
|
|
460
|
+
The url for making the comic
|
|
461
|
+
|
|
462
|
+
"""
|
|
463
|
+
screencap, subtitles, overlay_format = self._resolve_overlay_inputs(screencap, subtitles, overlay_format)
|
|
464
|
+
|
|
465
|
+
path_params = {
|
|
466
|
+
"key": screencap.frame.key,
|
|
467
|
+
"start_timestamp": screencap.start,
|
|
468
|
+
"end_timestamp": screencap.end,
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
stream = Stream.from_screencap(screencap=screencap, overlay_format=overlay_format)
|
|
472
|
+
|
|
473
|
+
return self.media.GIF_MAKER.build_encoded_url(
|
|
474
|
+
base_url=self.BASE_URL,
|
|
475
|
+
path_params=path_params,
|
|
476
|
+
query={"b64": stream.encoded},
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
@overload
|
|
480
|
+
def _resolve_overlay_inputs(
|
|
481
|
+
self,
|
|
482
|
+
screencap: Screencap,
|
|
483
|
+
subtitles: list[Subtitle] | None = None,
|
|
484
|
+
overlay_format: OverlayFormat | None = None,
|
|
485
|
+
) -> tuple[Screencap, list[Subtitle], OverlayFormat]: ...
|
|
486
|
+
|
|
487
|
+
@overload
|
|
488
|
+
def _resolve_overlay_inputs(
|
|
489
|
+
self,
|
|
490
|
+
screencap: Screencap,
|
|
491
|
+
subtitles: list[Subtitle] | None = None,
|
|
492
|
+
overlay_format: OverlayFormat | list[OverlayFormat] | None = None,
|
|
493
|
+
) -> tuple[Screencap, list[Subtitle], OverlayFormat | list[OverlayFormat]]: ...
|
|
494
|
+
|
|
495
|
+
def _resolve_overlay_inputs(
|
|
496
|
+
self,
|
|
497
|
+
screencap: Screencap,
|
|
498
|
+
subtitles: list[Subtitle] | None = None,
|
|
499
|
+
overlay_format: OverlayFormat | list[OverlayFormat] | None = None,
|
|
500
|
+
) -> tuple[Screencap, list[Subtitle], OverlayFormat | list[OverlayFormat]]:
|
|
501
|
+
|
|
502
|
+
# Use default format if not given
|
|
503
|
+
overlay_format = overlay_format or self.config.default_format
|
|
504
|
+
if overlay_format != self.config.default_format:
|
|
505
|
+
log.debug("Using custom overlay format | screencap=%s | overlay_format=%s", screencap, overlay_format)
|
|
506
|
+
|
|
507
|
+
# Use screencap subtitles if not given
|
|
508
|
+
subtitles = subtitles or screencap.subtitles
|
|
509
|
+
if subtitles != screencap.subtitles:
|
|
510
|
+
log.debug("Using custom subtitles | screencap=%s | subtitles=%s", screencap, subtitles)
|
|
511
|
+
|
|
512
|
+
# Prevent too many subtitles being used
|
|
513
|
+
subtitles = subtitles[: self._MAX_ALLOWED_SUBTITLES]
|
|
514
|
+
|
|
515
|
+
# Change subtitles
|
|
516
|
+
screencap = screencap.model_copy(update={"subtitles": subtitles})
|
|
517
|
+
|
|
518
|
+
return screencap, subtitles, overlay_format
|
|
519
|
+
|
|
380
520
|
|
|
381
521
|
class CapitalBeatUs(AsyncCompuGlobalAPI):
|
|
382
522
|
"""An API Wrapper for accessing CapitalBeatUs API endpoints (West Wing)."""
|
|
383
523
|
|
|
384
524
|
BASE_URL = "https://capitalbeat.us"
|
|
385
525
|
TITLE = "West Wing"
|
|
386
|
-
|
|
526
|
+
DEFAULT_FORMAT = OverlayFormat(font_family=FontFamily.IMPACT)
|
|
387
527
|
|
|
388
528
|
|
|
389
529
|
class Frinkiac(AsyncCompuGlobalAPI):
|
|
@@ -391,7 +531,7 @@ class Frinkiac(AsyncCompuGlobalAPI):
|
|
|
391
531
|
|
|
392
532
|
BASE_URL = "https://frinkiac.com"
|
|
393
533
|
TITLE = "Simpsons"
|
|
394
|
-
|
|
534
|
+
DEFAULT_FORMAT = OverlayFormat(font_family=FontFamily.AKBAR)
|
|
395
535
|
|
|
396
536
|
|
|
397
537
|
@deprecated("The MasterOfAllScience API is deprecated, and currently redirects to Frinkiac")
|
|
@@ -400,7 +540,7 @@ class MasterOfAllScience(AsyncCompuGlobalAPI):
|
|
|
400
540
|
|
|
401
541
|
BASE_URL = "https://masterofallscience.com"
|
|
402
542
|
TITLE = "Rick and Morty"
|
|
403
|
-
|
|
543
|
+
DEFAULT_FORMAT = OverlayFormat(font_family=FontFamily.IMPACT)
|
|
404
544
|
|
|
405
545
|
|
|
406
546
|
class Morbotron(AsyncCompuGlobalAPI):
|
|
@@ -408,4 +548,4 @@ class Morbotron(AsyncCompuGlobalAPI):
|
|
|
408
548
|
|
|
409
549
|
BASE_URL = "https://morbotron.com"
|
|
410
550
|
TITLE = "Futurama"
|
|
411
|
-
|
|
551
|
+
DEFAULT_FORMAT = OverlayFormat(font_family=FontFamily.FR_BOLD)
|