mirror of
https://github.com/aykhans/series-robot-web.git
synced 2025-04-21 06:13:34 +00:00
Added 'imdb_api_access'
This commit is contained in:
parent
7bfad1a5cb
commit
939f8ad578
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,4 +9,3 @@ celerybeat-schedule
|
|||||||
databasepostgresql_env
|
databasepostgresql_env
|
||||||
SeriesRobot.pem
|
SeriesRobot.pem
|
||||||
certbot
|
certbot
|
||||||
imdb_api_access
|
|
2
src/imdb_api_access/__init__.py
Normal file
2
src/imdb_api_access/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from .series_counter import SeriesCounter
|
||||||
|
from .exceptions import *
|
18
src/imdb_api_access/_requests.py
Normal file
18
src/imdb_api_access/_requests.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from requests import get
|
||||||
|
from typing import (Union,
|
||||||
|
Dict)
|
||||||
|
from .exceptions import *
|
||||||
|
|
||||||
|
|
||||||
|
def get_request(url: str) -> Union[StatusCodeError, APIError, MaximumUsageError, Dict]:
|
||||||
|
raw_data = get(url)
|
||||||
|
|
||||||
|
if raw_data.status_code != 200:
|
||||||
|
raise StatusCodeError(raw_data.status_code)
|
||||||
|
data = raw_data.json()
|
||||||
|
|
||||||
|
if data['errorMessage']:
|
||||||
|
if 'Maximum usage' in data['errorMessage']:
|
||||||
|
raise MaximumUsageError()
|
||||||
|
raise APIError(data['errorMessage'])
|
||||||
|
return data
|
23
src/imdb_api_access/exceptions.py
Normal file
23
src/imdb_api_access/exceptions.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
class StatusCodeError(Exception):
|
||||||
|
def __init__(self, status_code: Union[int, str] = 404) -> None:
|
||||||
|
self.status_code = status_code
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"request response status code: {self.status_code}"
|
||||||
|
|
||||||
|
class APIError(Exception):
|
||||||
|
def __init__(self, message: str = 'Unknown Error') -> None:
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"IMDB API: {self.message}"
|
||||||
|
|
||||||
|
class MaximumUsageError(Exception):
|
||||||
|
def __init__(self, message: str):
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self.message
|
11
src/imdb_api_access/new_series_model.py
Normal file
11
src/imdb_api_access/new_series_model.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from series.models import SeriesModel
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NewSeries:
|
||||||
|
series: SeriesModel
|
||||||
|
new_episodes_count: Optional[int] = None
|
||||||
|
last_season: Optional[int] = None
|
||||||
|
last_episode: Optional[int] = None
|
63
src/imdb_api_access/series_counter.py
Normal file
63
src/imdb_api_access/series_counter.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
from ._requests import get_request
|
||||||
|
from datetime import datetime
|
||||||
|
from .exceptions import *
|
||||||
|
from .new_series_model import NewSeries
|
||||||
|
from series.models import SeriesModel
|
||||||
|
from typing import (List,
|
||||||
|
Tuple,
|
||||||
|
Dict,
|
||||||
|
Union)
|
||||||
|
|
||||||
|
|
||||||
|
class SeriesCounter:
|
||||||
|
def __init__(self, api_key: str) -> None:
|
||||||
|
self.api_key = api_key
|
||||||
|
self.new_series_list: List[NewSeries] = []
|
||||||
|
self.error_series: List[SeriesModel] = []
|
||||||
|
|
||||||
|
def get_episode_count(self, series: SeriesModel, data: Dict) -> Union[StatusCodeError, APIError, MaximumUsageError, Tuple]:
|
||||||
|
# sourcery skip: aware-datetime-for-utc
|
||||||
|
now_date = datetime.strptime(datetime.strftime(datetime.utcnow(),'%d %b %Y'), '%d %b %Y')
|
||||||
|
new_episodes_count = 0
|
||||||
|
|
||||||
|
for n in data['tvSeriesInfo']['seasons'][data['tvSeriesInfo']['seasons'].index(str(series.last_season)):]:
|
||||||
|
data = get_request(f"https://imdb-api.com/en/API/SeasonEpisodes/{self.api_key}/{series.imdb_id}/{n}")
|
||||||
|
|
||||||
|
episodes = data['episodes']
|
||||||
|
for i in range(int(series.last_episode) if n == str(series.last_season) else 0, len(episodes)):
|
||||||
|
released_date = episodes[i]['released'].replace('.', '')
|
||||||
|
try:
|
||||||
|
episode_date = datetime.strptime(released_date, '%d %b %Y')
|
||||||
|
if (episode_date - now_date).days > 0:
|
||||||
|
raise ValueError
|
||||||
|
except ValueError:
|
||||||
|
try:
|
||||||
|
return new_episodes_count, int(last_n)+1, last_i+1 if new_episodes_count > 0 else 0, 0, 0
|
||||||
|
except UnboundLocalError:
|
||||||
|
return new_episodes_count, int(n), last_i+1 if new_episodes_count > 0 else 0, 0, 0
|
||||||
|
|
||||||
|
last_i = i
|
||||||
|
new_episodes_count += 1
|
||||||
|
last_n = n
|
||||||
|
|
||||||
|
return new_episodes_count, n, i+1 if new_episodes_count > 0 else 0, 0, 0
|
||||||
|
|
||||||
|
def find_new_series(self, series: List[NewSeries]) -> Union[MaximumUsageError, None]:
|
||||||
|
for s in series:
|
||||||
|
try:
|
||||||
|
data = get_request(f"https://imdb-api.com/en/API/Title/{self.api_key}/{s.imdb_id}")
|
||||||
|
|
||||||
|
except (StatusCodeError, APIError):
|
||||||
|
self.error_series.append(s)
|
||||||
|
|
||||||
|
else:
|
||||||
|
data = self.get_episode_count(s, data)
|
||||||
|
if data[0]:
|
||||||
|
self.new_series_list.append(
|
||||||
|
NewSeries(
|
||||||
|
series=s,
|
||||||
|
new_episodes_count=data[0],
|
||||||
|
last_season=data[1],
|
||||||
|
last_episode=data[2]
|
||||||
|
)
|
||||||
|
)
|
@ -17,31 +17,31 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for s, d in data %}
|
{% for d in data %}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">
|
<th scope="row">
|
||||||
<a href="https://www.imdb.com/title/{{s.imdb_id}}/" style="text-decoration: none;" target="_blank">
|
<a href="https://www.imdb.com/title/{{s.imdb_id}}/" style="text-decoration: none;" target="_blank">
|
||||||
{{s.title}}
|
{{d.series.title}}
|
||||||
</a>
|
</a>
|
||||||
<br>
|
<br>
|
||||||
<a class="btn mr-1 update-btn" style="padding: 0;" href="{% url 'update-series' s.slug %}">
|
<a class="btn mr-1 update-btn" style="padding: 0;" href="{% url 'update-series' d.series.slug %}">
|
||||||
<img class="edit-icon" src="{% static 'icons/edit.png' %}" width="21px" height="21px">
|
<img class="edit-icon" src="{% static 'icons/edit.png' %}" width="21px" height="21px">
|
||||||
</a>
|
</a>
|
||||||
<a class="btn delete-btn" href="{% url 'delete-series' s.slug %}">
|
<a class="btn delete-btn" href="{% url 'delete-series' d.series.slug %}">
|
||||||
<img class="trash-icon" src="{% static 'icons/trash.png' %}" width="24px" height="24px">
|
<img class="trash-icon" src="{% static 'icons/trash.png' %}" width="24px" height="24px">
|
||||||
</a>
|
</a>
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<a href="https://www.imdb.com/title/{{s.imdb_id}}/episodes?season={{s.last_season}}" style="text-decoration: none;" target="_blank">
|
<a href="https://www.imdb.com/title/{{d.series.imdb_id}}/episodes?season={{d.series.last_season}}" style="text-decoration: none;" target="_blank">
|
||||||
{{s.last_season}} - {{s.last_episode}}
|
{{d.series.last_season}} - {{d.series.last_episode}}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="https://www.imdb.com/title/{{s.imdb_id}}/episodes?season={{d.last_season}}" style="text-decoration: none;" target="_blank">
|
<a href="https://www.imdb.com/title/{{d.series.imdb_id}}/episodes?season={{d.last_season}}" style="text-decoration: none;" target="_blank">
|
||||||
{{d.last_season}} - {{d.last_episode}}
|
{{d.last_season}} - {{d.last_episode}}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>{{d.count}}</td>
|
<td>{{d.new_episodes_count}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -3,68 +3,21 @@ from django.shortcuts import (render,
|
|||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from account.models import User
|
from account.models import User
|
||||||
from requests import get
|
from imdb_api_access import SeriesCounter
|
||||||
from datetime import datetime
|
from imdb_api_access import MaximumUsageError
|
||||||
|
|
||||||
|
|
||||||
def get_request(request, link):
|
|
||||||
raw_data = get(link)
|
|
||||||
|
|
||||||
if raw_data.status_code != 200:
|
|
||||||
messages.info(request, "Can't search for TV Series. Please try again.")
|
|
||||||
return redirect('homepage')
|
|
||||||
data = raw_data.json()
|
|
||||||
|
|
||||||
if data['errorMessage']:
|
|
||||||
messages.info(request, f"IMDB API: {data['errorMessage']}")
|
|
||||||
return redirect('homepage')
|
|
||||||
return data
|
|
||||||
|
|
||||||
def episode_counter(request, s, data):
|
|
||||||
now_date = datetime.strptime(datetime.strftime(datetime.utcnow(),'%d %b %Y'), '%d %b %Y')
|
|
||||||
new_episodes_count = 0
|
|
||||||
|
|
||||||
for n in data['tvSeriesInfo']['seasons'][data['tvSeriesInfo']['seasons'].index(str(s.last_season)):]:
|
|
||||||
data = get_request(request, f"https://imdb-api.com/en/API/SeasonEpisodes/{request.user.imdb_api_key}/{s.imdb_id}/{n}")
|
|
||||||
if type(data) is not dict: return data
|
|
||||||
|
|
||||||
episodes = data['episodes']
|
|
||||||
for i in range(int(s.last_episode) if n == str(s.last_season) else 0, len(episodes)):
|
|
||||||
released_date = episodes[i]['released'].replace('.', '')
|
|
||||||
try:
|
|
||||||
episode_date = datetime.strptime(released_date, '%d %b %Y')
|
|
||||||
if (episode_date - now_date).days > 0:
|
|
||||||
raise ValueError
|
|
||||||
except ValueError:
|
|
||||||
try:
|
|
||||||
return new_episodes_count, int(last_n)+1, last_i+1 if new_episodes_count > 0 else 0, 0, 0
|
|
||||||
except UnboundLocalError:
|
|
||||||
return new_episodes_count, int(n), last_i+1 if new_episodes_count > 0 else 0, 0, 0
|
|
||||||
|
|
||||||
last_i = i
|
|
||||||
new_episodes_count += 1
|
|
||||||
last_n = n
|
|
||||||
|
|
||||||
return new_episodes_count, n, i+1 if new_episodes_count > 0 else 0, 0, 0
|
|
||||||
|
|
||||||
@login_required(login_url='/account/login')
|
@login_required(login_url='/account/login')
|
||||||
def new_episodes_view(request):
|
def new_episodes_view(request):
|
||||||
series = User.objects.get(id=request.user.id).series.filter(show=True).order_by('-id')
|
series = User.objects.get(id=request.user.id).series.filter(show=True).order_by('-id')
|
||||||
series_new_episodes = []
|
|
||||||
|
|
||||||
for s in series:
|
series_counter = SeriesCounter(request.user.imdb_api_key)
|
||||||
data = get_request(request, f"https://imdb-api.com/en/API/Title/{request.user.imdb_api_key}/{s.imdb_id}")
|
try:
|
||||||
if type(data) is not dict: return data
|
series_counter.find_new_series(series)
|
||||||
data = episode_counter(request, s, data)
|
except MaximumUsageError as e: ...
|
||||||
if type(data) is not tuple: return data
|
# messages.warning(request, f"{e} (some series could not be updated)")
|
||||||
if data[0]:
|
|
||||||
series_new_episodes.append([s,
|
|
||||||
{'count': data[0],
|
|
||||||
'last_season': data[1],
|
|
||||||
'last_episode': data[2]}
|
|
||||||
])
|
|
||||||
|
|
||||||
if series_new_episodes:
|
if series_counter.new_series_list:
|
||||||
return render(request, 'new_episodes.html', context={'data': series_new_episodes})
|
return render(request, 'new_episodes.html', context={'data': series_counter.new_series_list})
|
||||||
messages.warning(request, "There are no new episodes of any series :(")
|
messages.warning(request, "There are no new episodes of any series :(")
|
||||||
return redirect('homepage')
|
return redirect('homepage')
|
Loading…
x
Reference in New Issue
Block a user