diff --git a/src/account/models.py b/src/account/models.py
index b8cee53..dacec53 100644
--- a/src/account/models.py
+++ b/src/account/models.py
@@ -6,7 +6,7 @@ class User(AbstractUser):
first_name = None
last_name = None
email = models.EmailField('email', null=True, blank=True, unique=True)
- imdb_api_key = models.CharField(max_length=15, blank=False, null=False)
+ imdb_api_key = models.CharField(max_length=15, blank=False, null=False, unique=True)
email_is_verified = models.BooleanField(default=False)
send_email = models.BooleanField(default=False)
diff --git a/src/account/views/profile_editing.py b/src/account/views/profile_editing.py
index 0ce34f9..430e53e 100644
--- a/src/account/views/profile_editing.py
+++ b/src/account/views/profile_editing.py
@@ -3,7 +3,8 @@ from django.shortcuts import (render,
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from account.forms import ProfileEditingForm
-from requests import get
+from imdb_api_access._requests import get_request
+from imdb_api_access.exceptions import *
from .send_otp import send_otp_view
@@ -13,22 +14,19 @@ def profile_editing_view(request):
form = ProfileEditingForm(request.POST, instance=request.user)
if form.is_valid():
if 'imdb_api_key' in form.changed_data:
- raw_data = get(f"https://imdb-api.com/en/API/Title/{request.POST['imdb_api_key']}/tt0110413")
-
- if raw_data.status_code != 200:
+ try:
+ get_request(f"https://imdb-api.com/en/API/Title/{request.POST['imdb_api_key']}/tt0110413")
+ except StatusCodeError:
messages.info(request, 'Account not created. Please try again later')
return redirect('profile-editing')
- data = raw_data.json()
-
- if data['errorMessage']:
- if 'Maximum usage' in data['errorMessage']:
- messages.info(request, f"IMDB API: {data['errorMessage']}")
- return redirect('profile-editing')
-
- elif data['errorMessage'] == 'Invalid API Key':
+ except MaximumUsageError as e:
+ messages.info(request, str(e))
+ return redirect('profile-editing')
+ except APIError as e:
+ if e.message == 'Invalid API Key':
form.add_error('imdb_api_key', 'Invalid API Key')
return render(request, 'profile_editing.html', context={"form": form})
- messages.info(request, f"IMDB API: {data['errorMessage']}")
+ messages.info(request, str(e))
return redirect('profile-editing')
if 'email' in form.changed_data:
diff --git a/src/account/views/register.py b/src/account/views/register.py
index b877ec6..92b85c8 100644
--- a/src/account/views/register.py
+++ b/src/account/views/register.py
@@ -4,7 +4,8 @@ from django.contrib import messages
from account.forms import RegisterForm
from django.contrib.auth import (login,
authenticate)
-from requests import get
+from imdb_api_access._requests import get_request
+from imdb_api_access.exceptions import *
from django.shortcuts import render
from .send_otp import send_otp_view
@@ -13,22 +14,19 @@ def register_view(request): # sourcery skip: extract-method
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
- raw_data = get(f"https://imdb-api.com/en/API/Title/{request.POST['imdb_api_key']}/tt0110413")
-
- if raw_data.status_code != 200:
+ try:
+ get_request(f"https://imdb-api.com/en/API/Title/{request.POST['imdb_api_key']}/tt0110413")
+ except StatusCodeError:
messages.info(request, 'Account not created. Please try again later')
return redirect('register')
- data = raw_data.json()
-
- if data['errorMessage']:
- if 'Maximum usage' in data['errorMessage']:
- messages.info(request, f"IMDB API: {data['errorMessage']}")
- return redirect('register')
-
- elif data['errorMessage'] == 'Invalid API Key':
+ except MaximumUsageError as e:
+ messages.info(request, str(e))
+ return redirect('register')
+ except APIError as e:
+ if e.message == 'Invalid API Key':
form.add_error('imdb_api_key', 'Invalid API Key')
return render(request, 'register.html', context={"form": form})
- messages.info(request, f"IMDB API: {data['errorMessage']}")
+ messages.info(request, str(e))
return redirect('register')
to_email = form.cleaned_data.get('email')
diff --git a/src/imdb_api_access/_requests.py b/src/imdb_api_access/_requests.py
index e06f593..995581e 100644
--- a/src/imdb_api_access/_requests.py
+++ b/src/imdb_api_access/_requests.py
@@ -13,6 +13,6 @@ def get_request(url: str) -> Union[StatusCodeError, APIError, MaximumUsageError,
if data['errorMessage']:
if 'Maximum usage' in data['errorMessage']:
- raise MaximumUsageError()
+ raise MaximumUsageError(data['errorMessage'])
raise APIError(data['errorMessage'])
return data
\ No newline at end of file
diff --git a/src/imdb_api_access/exceptions.py b/src/imdb_api_access/exceptions.py
index 16704b7..2a2e80a 100644
--- a/src/imdb_api_access/exceptions.py
+++ b/src/imdb_api_access/exceptions.py
@@ -20,4 +20,4 @@ class MaximumUsageError(Exception):
self.message = message
def __str__(self) -> str:
- return self.message
\ No newline at end of file
+ return f"IMDB API: {self.message}"
\ No newline at end of file
diff --git a/src/imdb_api_access/new_series_model.py b/src/imdb_api_access/new_series_model.py
index 2ce725c..97e3cf0 100644
--- a/src/imdb_api_access/new_series_model.py
+++ b/src/imdb_api_access/new_series_model.py
@@ -6,6 +6,6 @@ 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
\ No newline at end of file
+ new_episodes_count: int
+ last_season: int
+ last_episode: int
\ No newline at end of file
diff --git a/src/imdb_api_access/series_counter.py b/src/imdb_api_access/series_counter.py
index 1e92ceb..9d4e569 100644
--- a/src/imdb_api_access/series_counter.py
+++ b/src/imdb_api_access/series_counter.py
@@ -4,7 +4,6 @@ from .exceptions import *
from .new_series_model import NewSeries
from series.models import SeriesModel
from typing import (List,
- Tuple,
Dict,
Union)
@@ -15,49 +14,60 @@ class SeriesCounter:
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]:
+ def get_episode_count(self, series: SeriesModel, data_seasons: Dict) -> Union[StatusCodeError,
+ APIError,
+ MaximumUsageError,
+ Dict]:
# sourcery skip: aware-datetime-for-utc
now_date = datetime.strptime(datetime.strftime(datetime.utcnow(),'%d %b %Y'), '%d %b %Y')
- new_episodes_count = 0
+ data_return = {
+ 'new_episodes_count': 0,
+ 'last_season': series.watched_season,
+ 'last_episode': series.watched_episode
+ }
+ seasons = data_seasons['tvSeriesInfo']['seasons']
- 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}")
+ for season_number in seasons[seasons.index(str(series.watched_season)):]:
+ data_episodes = get_request(f"https://imdb-api.com/en/API/SeasonEpisodes/k_ae700oad/{series.imdb_id}/{season_number}")
+ episodes = data_episodes['episodes']
+
+ for episode_number in range(int(series.watched_episode) if season_number == str(series.watched_season) else 0, len(episodes)):
+ released_date = episodes[episode_number]['released'].replace('.', '')
- 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
+ data_return['last_season'] = int(season_number)
+ data_return['last_episode'] = episode_number+1
+ data_return['new_episodes_count'] += 1
- return new_episodes_count, n, i+1 if new_episodes_count > 0 else 0, 0, 0
+ except ValueError: return data_return
+ return data_return
- def find_new_series(self, series: List[NewSeries]) -> Union[MaximumUsageError, None]:
+ def find_new_series(self, series: List[SeriesModel]) -> 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]
+ try:
+ data = self.get_episode_count(s, data)
+ if data['new_episodes_count'] != s.new_episodes_count:
+ self.new_series_list.append(
+ NewSeries(series=s, **data)
)
- )
\ No newline at end of file
+ except (StatusCodeError, APIError):
+ self.error_series.append(s)
+
+ def find_last_episode(self, series: SeriesModel) -> Union[MaximumUsageError,
+ StatusCodeError,
+ APIError,
+ NewSeries]:
+
+ data = get_request(f"https://imdb-api.com/en/API/Title/{self.api_key}/{series.imdb_id}")
+ data = self.get_episode_count(series, data)
+ return NewSeries(series=series, **data)
\ No newline at end of file
diff --git a/src/series/models.py b/src/series/models.py
index 6f9c87e..b7fdc89 100644
--- a/src/series/models.py
+++ b/src/series/models.py
@@ -10,14 +10,26 @@ class SeriesModel(models.Model):
title = models.CharField(max_length=35, blank=False, null=False)
imdb_id = models.CharField(max_length=10, validators=[MinLengthValidator(9)],
blank=False, null=False)
- last_season = models.IntegerField(validators=[
+ watched_season = models.IntegerField(validators=[
MaxValueValidator(30),
MinValueValidator(1)
], blank=False, null=False)
- last_episode = models.IntegerField(validators=[
+ watched_episode = models.IntegerField(validators=[
MaxValueValidator(60),
MinValueValidator(1)
], blank=False, null=False)
+ last_season = models.IntegerField(validators=[
+ MaxValueValidator(30),
+ MinValueValidator(1)],
+ default=1)
+ last_episode = models.IntegerField(validators=[
+ MaxValueValidator(60),
+ MinValueValidator(1)],
+ default=1)
+ new_episodes_count = models.IntegerField(validators=[
+ MaxValueValidator(200),
+ MinValueValidator(0)],
+ default=0)
show = models.BooleanField(default=True)
slug = AutoSlugField(populate_from='title', unique=True)
diff --git a/src/series/tasks.py b/src/series/tasks.py
index f022224..6309bb8 100644
--- a/src/series/tasks.py
+++ b/src/series/tasks.py
@@ -5,78 +5,61 @@ from datetime import datetime
from django.template.loader import render_to_string
from django.core.mail import EmailMessage
from celery.utils.log import get_task_logger
+from imdb_api_access import SeriesCounter
+from imdb_api_access import MaximumUsageError
-logger = get_task_logger(__name__)
+# logger = get_task_logger(__name__)
-def get_request(link):
- raw_data = get(link)
- if raw_data.status_code == 200:
- data = raw_data.json()
- if not data['errorMessage']:
- return data
- logger.info(f"error message: {data['errorMessage']}\nlink: {link}")
- return None
- logger.info(f"status code: {raw_data.status_code}\nlink: {link}")
+def update_series(updated_series):
+ updated_series.series.last_season = updated_series.last_season
+ updated_series.series.last_episode = updated_series.last_episode
+ updated_series.series.new_episodes_count = updated_series.new_episodes_count
-def episode_counter(imdb_api_key, s, data):
- now_date = datetime.strptime(datetime.strftime(datetime.utcnow(),'%d %b %Y'), '%d %b %Y')
- new_episodes_count = 0
+def send_email(user):
+ series = user.series.filter(show=True).order_by('-id')
- for n in data['tvSeriesInfo']['seasons'][data['tvSeriesInfo']['seasons'].index(str(s.last_season)):]:
- data = get_request(f"https://imdb-api.com/en/API/SeasonEpisodes/{imdb_api_key}/{s.imdb_id}/{n}")
- if data is None: return None
-
- 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
-
-@shared_task(name='send_emails')
-def send_feedback_email_task():
- users = User.objects.filter(send_email=True)
- for user in users:
- series = user.series.filter(show=True).order_by('-id')
- series_new_episodes = []
-
- for s in series:
- data = get_request(f"https://imdb-api.com/en/API/Title/{user.imdb_api_key}/{s.imdb_id}")
-
- if data is None:
- series_new_episodes = []
- break
- data = episode_counter(user.imdb_api_key, s, data)
- if data is None:
- series_new_episodes = []
- break
-
- if data[0]:
- series_new_episodes.append([s,
- {'count': data[0],
- 'last_season': data[1],
- 'last_episode': data[2]}
- ])
-
- if series_new_episodes:
- message = render_to_string('new_episodes_verification.html', {
+ series_counter = SeriesCounter(user.imdb_api_key)
+ try:
+ series_counter.find_new_series(series)
+ series_len = len(series_counter.new_series_list)
+ except MaximumUsageError as e:
+ if series_len := len(series_counter.new_series_list):
+ for updated_series in series_counter.new_series_list:
+ update_series(updated_series)
+ updated_series.save()
+ message = render_to_string('new_episodes_notification.html', {
'user': user,
- 'data': series_new_episodes
+ 'new_series_list': series_counter.new_series_list,
+ 'error_series_list': series_counter.error_series,
+ 'maximum_usage': str(e)
})
email = EmailMessage(
'New Episodes!', message, to=[user.email]
)
- email.send()
\ No newline at end of file
+ email.send()
+ return
+ return
+
+ if series_len:
+ for updated_series in series_counter.new_series_list:
+ update_series(updated_series)
+ updated_series.series.save()
+
+ message = render_to_string('new_episodes_notification.html', {
+ 'user': user,
+ 'new_series_list': series_counter.new_series_list,
+ 'error_series_list': series_counter.error_series,
+ 'maximum_usage': ''
+ })
+ email = EmailMessage(
+ 'New Episodes!', message, to=[user.email]
+ )
+ email.send()
+ return
+
+@shared_task(name='send_emails')
+def send_feedback_email_task():
+ users = User.objects.filter(send_email=True)
+ for user in users: send_email(user)
\ No newline at end of file
diff --git a/src/series/templates/homepage.html b/src/series/templates/homepage.html
index f94c678..806eaef 100644
--- a/src/series/templates/homepage.html
+++ b/src/series/templates/homepage.html
@@ -12,7 +12,9 @@
@@ -31,11 +33,19 @@
Title ({{series.paginator.count}})
- Season - Episode
+ Watched
+ Last
+ Unwatched
Show
+
| Title | -Watched Season - Episode | -Last Season - Episode | -Number of New Episodes | -
|---|---|---|---|
|
-
- {{d.series.title}}
-
- - - |
- - - {{d.series.last_season}} - {{d.series.last_episode}} - - | -- - {{d.last_season}} - {{d.last_episode}} - - | -{{d.new_episodes_count}} | -