Added 'imdb_api_access' app

removed 'new_episodes' page
changed series_count algorithm
This commit is contained in:
ayxan 2022-12-16 11:27:51 +04:00
parent 939f8ad578
commit 8ec01acc4c
20 changed files with 318 additions and 256 deletions

View File

@ -6,7 +6,7 @@ class User(AbstractUser):
first_name = None first_name = None
last_name = None last_name = None
email = models.EmailField('email', null=True, blank=True, unique=True) 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) email_is_verified = models.BooleanField(default=False)
send_email = models.BooleanField(default=False) send_email = models.BooleanField(default=False)

View File

@ -3,7 +3,8 @@ 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.forms import ProfileEditingForm 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 from .send_otp import send_otp_view
@ -13,22 +14,19 @@ def profile_editing_view(request):
form = ProfileEditingForm(request.POST, instance=request.user) form = ProfileEditingForm(request.POST, instance=request.user)
if form.is_valid(): if form.is_valid():
if 'imdb_api_key' in form.changed_data: 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") try:
get_request(f"https://imdb-api.com/en/API/Title/{request.POST['imdb_api_key']}/tt0110413")
if raw_data.status_code != 200: except StatusCodeError:
messages.info(request, 'Account not created. Please try again later') messages.info(request, 'Account not created. Please try again later')
return redirect('profile-editing') return redirect('profile-editing')
data = raw_data.json() except MaximumUsageError as e:
messages.info(request, str(e))
if data['errorMessage']: return redirect('profile-editing')
if 'Maximum usage' in data['errorMessage']: except APIError as e:
messages.info(request, f"IMDB API: {data['errorMessage']}") if e.message == 'Invalid API Key':
return redirect('profile-editing')
elif data['errorMessage'] == 'Invalid API Key':
form.add_error('imdb_api_key', 'Invalid API Key') form.add_error('imdb_api_key', 'Invalid API Key')
return render(request, 'profile_editing.html', context={"form": form}) 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') return redirect('profile-editing')
if 'email' in form.changed_data: if 'email' in form.changed_data:

View File

@ -4,7 +4,8 @@ from django.contrib import messages
from account.forms import RegisterForm from account.forms import RegisterForm
from django.contrib.auth import (login, from django.contrib.auth import (login,
authenticate) 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 django.shortcuts import render
from .send_otp import send_otp_view from .send_otp import send_otp_view
@ -13,22 +14,19 @@ def register_view(request): # sourcery skip: extract-method
if request.method == 'POST': if request.method == 'POST':
form = RegisterForm(request.POST) form = RegisterForm(request.POST)
if form.is_valid(): if form.is_valid():
raw_data = get(f"https://imdb-api.com/en/API/Title/{request.POST['imdb_api_key']}/tt0110413") try:
get_request(f"https://imdb-api.com/en/API/Title/{request.POST['imdb_api_key']}/tt0110413")
if raw_data.status_code != 200: except StatusCodeError:
messages.info(request, 'Account not created. Please try again later') messages.info(request, 'Account not created. Please try again later')
return redirect('register') return redirect('register')
data = raw_data.json() except MaximumUsageError as e:
messages.info(request, str(e))
if data['errorMessage']: return redirect('register')
if 'Maximum usage' in data['errorMessage']: except APIError as e:
messages.info(request, f"IMDB API: {data['errorMessage']}") if e.message == 'Invalid API Key':
return redirect('register')
elif data['errorMessage'] == 'Invalid API Key':
form.add_error('imdb_api_key', 'Invalid API Key') form.add_error('imdb_api_key', 'Invalid API Key')
return render(request, 'register.html', context={"form": form}) return render(request, 'register.html', context={"form": form})
messages.info(request, f"IMDB API: {data['errorMessage']}") messages.info(request, str(e))
return redirect('register') return redirect('register')
to_email = form.cleaned_data.get('email') to_email = form.cleaned_data.get('email')

View File

@ -13,6 +13,6 @@ def get_request(url: str) -> Union[StatusCodeError, APIError, MaximumUsageError,
if data['errorMessage']: if data['errorMessage']:
if 'Maximum usage' in data['errorMessage']: if 'Maximum usage' in data['errorMessage']:
raise MaximumUsageError() raise MaximumUsageError(data['errorMessage'])
raise APIError(data['errorMessage']) raise APIError(data['errorMessage'])
return data return data

View File

@ -20,4 +20,4 @@ class MaximumUsageError(Exception):
self.message = message self.message = message
def __str__(self) -> str: def __str__(self) -> str:
return self.message return f"IMDB API: {self.message}"

View File

@ -6,6 +6,6 @@ from typing import Optional
@dataclass @dataclass
class NewSeries: class NewSeries:
series: SeriesModel series: SeriesModel
new_episodes_count: Optional[int] = None new_episodes_count: int
last_season: Optional[int] = None last_season: int
last_episode: Optional[int] = None last_episode: int

View File

@ -4,7 +4,6 @@ from .exceptions import *
from .new_series_model import NewSeries from .new_series_model import NewSeries
from series.models import SeriesModel from series.models import SeriesModel
from typing import (List, from typing import (List,
Tuple,
Dict, Dict,
Union) Union)
@ -15,49 +14,60 @@ class SeriesCounter:
self.new_series_list: List[NewSeries] = [] self.new_series_list: List[NewSeries] = []
self.error_series: List[SeriesModel] = [] 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 # sourcery skip: aware-datetime-for-utc
now_date = datetime.strptime(datetime.strftime(datetime.utcnow(),'%d %b %Y'), '%d %b %Y') 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)):]: for season_number in seasons[seasons.index(str(series.watched_season)):]:
data = get_request(f"https://imdb-api.com/en/API/SeasonEpisodes/{self.api_key}/{series.imdb_id}/{n}") 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: try:
episode_date = datetime.strptime(released_date, '%d %b %Y') episode_date = datetime.strptime(released_date, '%d %b %Y')
if (episode_date - now_date).days > 0: if (episode_date - now_date).days > 0:
raise ValueError 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 data_return['last_season'] = int(season_number)
new_episodes_count += 1 data_return['last_episode'] = episode_number+1
last_n = n 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: for s in series:
try: try:
data = get_request(f"https://imdb-api.com/en/API/Title/{self.api_key}/{s.imdb_id}") data = get_request(f"https://imdb-api.com/en/API/Title/{self.api_key}/{s.imdb_id}")
except (StatusCodeError, APIError): except (StatusCodeError, APIError):
self.error_series.append(s) self.error_series.append(s)
else: else:
data = self.get_episode_count(s, data) try:
if data[0]: data = self.get_episode_count(s, data)
self.new_series_list.append( if data['new_episodes_count'] != s.new_episodes_count:
NewSeries( self.new_series_list.append(
series=s, NewSeries(series=s, **data)
new_episodes_count=data[0],
last_season=data[1],
last_episode=data[2]
) )
) 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)

View File

@ -10,14 +10,26 @@ class SeriesModel(models.Model):
title = models.CharField(max_length=35, blank=False, null=False) title = models.CharField(max_length=35, blank=False, null=False)
imdb_id = models.CharField(max_length=10, validators=[MinLengthValidator(9)], imdb_id = models.CharField(max_length=10, validators=[MinLengthValidator(9)],
blank=False, null=False) blank=False, null=False)
last_season = models.IntegerField(validators=[ watched_season = models.IntegerField(validators=[
MaxValueValidator(30), MaxValueValidator(30),
MinValueValidator(1) MinValueValidator(1)
], blank=False, null=False) ], blank=False, null=False)
last_episode = models.IntegerField(validators=[ watched_episode = models.IntegerField(validators=[
MaxValueValidator(60), MaxValueValidator(60),
MinValueValidator(1) MinValueValidator(1)
], blank=False, null=False) ], 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) show = models.BooleanField(default=True)
slug = AutoSlugField(populate_from='title', unique=True) slug = AutoSlugField(populate_from='title', unique=True)

View File

@ -5,78 +5,61 @@ from datetime import datetime
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.core.mail import EmailMessage from django.core.mail import EmailMessage
from celery.utils.log import get_task_logger 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: def update_series(updated_series):
data = raw_data.json() updated_series.series.last_season = updated_series.last_season
if not data['errorMessage']: updated_series.series.last_episode = updated_series.last_episode
return data updated_series.series.new_episodes_count = updated_series.new_episodes_count
logger.info(f"error message: {data['errorMessage']}\nlink: {link}")
return None
logger.info(f"status code: {raw_data.status_code}\nlink: {link}")
def episode_counter(imdb_api_key, s, data): def send_email(user):
now_date = datetime.strptime(datetime.strftime(datetime.utcnow(),'%d %b %Y'), '%d %b %Y') series = user.series.filter(show=True).order_by('-id')
new_episodes_count = 0
for n in data['tvSeriesInfo']['seasons'][data['tvSeriesInfo']['seasons'].index(str(s.last_season)):]: series_counter = SeriesCounter(user.imdb_api_key)
data = get_request(f"https://imdb-api.com/en/API/SeasonEpisodes/{imdb_api_key}/{s.imdb_id}/{n}") try:
if data is None: return None series_counter.find_new_series(series)
series_len = len(series_counter.new_series_list)
episodes = data['episodes'] except MaximumUsageError as e:
for i in range(int(s.last_episode) if n == str(s.last_season) else 0, len(episodes)): if series_len := len(series_counter.new_series_list):
released_date = episodes[i]['released'].replace('.', '') for updated_series in series_counter.new_series_list:
try: update_series(updated_series)
episode_date = datetime.strptime(released_date, '%d %b %Y') updated_series.save()
if (episode_date - now_date).days > 0: message = render_to_string('new_episodes_notification.html', {
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', {
'user': user, '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( email = EmailMessage(
'New Episodes!', message, to=[user.email] 'New Episodes!', message, to=[user.email]
) )
email.send() 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)

View File

@ -12,7 +12,9 @@
<thead> <thead>
<tr> <tr>
<th scope="col">Title ({{series.paginator.count}})</th> <th scope="col">Title ({{series.paginator.count}})</th>
<th scope="col">Season - Episode</th> <th scope="col">Watched</th>
<th scope="col">Last</th>
<th scope="col">Unwatched</th>
<th scope="col">Show</th> <th scope="col">Show</th>
</tr> </tr>
</thead> </thead>
@ -31,11 +33,19 @@
<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>
<a href="https://www.imdb.com/title/{{s.imdb_id}}/episodes?season={{s.last_season}}" style="text-decoration: none;" target="_blank">
{{s.watched_season}} - {{s.watched_episode}}
</a>
</td>
<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/{{s.imdb_id}}/episodes?season={{s.last_season}}" style="text-decoration: none;" target="_blank">
{{s.last_season}} - {{s.last_episode}} {{s.last_season}} - {{s.last_episode}}
</a> </a>
</td> </td>
<td>
{{s.new_episodes_count}}
</td>
<td> <td>
{% if s.show %} {% if s.show %}
<img src="{% static 'icons/true-check-button.png' %}" width="22px" height="22px"> <img src="{% static 'icons/true-check-button.png' %}" width="22px" height="22px">
@ -51,7 +61,13 @@
<div style="margin-bottom: 8.5rem;"> <div style="margin-bottom: 8.5rem;">
<div class="btn-new-episode"> <div class="btn-new-episode">
<button type="button" class="btn btn-outline-primary"> <button type="button" class="btn btn-outline-primary">
<a href="/series/new-episodes/" style="text-decoration: none; color: inherit;">New Episodes</a> <a href="/" style="text-decoration: none; color: inherit;">All</a>
</button>
<button type="button" class="btn btn-outline-primary" style="margin-left: 4px;">
<a href="?new=true" style="text-decoration: none; color: inherit;">Unwatched</a>
</button> <br>
<button type="button" class="btn btn-outline-primary" style="margin-top: 4.7%; margin-bottom: 77%;">
<a href="/series/new-episodes/" style="text-decoration: none; color: inherit;">Update</a>
</button> </button>
</div> </div>

View File

@ -1,51 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% block title %} New Episodes of The Series {% endblock title %}
{% block content %}
<link rel="stylesheet" href="{% static 'css/new_episodes.css' %}">
<div class="table-div">
<table class="table">
<thead>
<tr>
<th scope="col">Title</th>
<th scope="col">Watched Season - Episode</th>
<th scope="col">Last Season - Episode</th>
<th scope="col">Number of New Episodes</th>
</tr>
</thead>
<tbody>
{% for d in data %}
<tr>
<th scope="row">
<a href="https://www.imdb.com/title/{{s.imdb_id}}/" style="text-decoration: none;" target="_blank">
{{d.series.title}}
</a>
<br>
<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">
</a>
<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">
</a>
</th>
<td>
<a href="https://www.imdb.com/title/{{d.series.imdb_id}}/episodes?season={{d.series.last_season}}" style="text-decoration: none;" target="_blank">
{{d.series.last_season}} - {{d.series.last_episode}}
</a>
</td>
<td>
<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}}
</a>
</td>
<td>{{d.new_episodes_count}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock content %}

View File

@ -0,0 +1,36 @@
{% autoescape off %}
Hi {{ user.username }},
There are new episodes of the series you recorded.
{% if maximum_usage %}
Some series could not be updated ({{maximum_usage}})
{% for s in new_series_list %}
{{s.series.title}}: watched - {{s.series.watched_season}}-{{s.series.watched_episode}}
last - {{s.last_season}}-{{s.last_episode}}
new episodes count - {{s.new_episodes_count}}
{% endfor %}
{% else %}
{% if error_series_list %}
Some series could not be updated:
{% for e in error_series_list %}
e.title
{% endfor %}
{% for s in new_series_list %}
{{s.series.title}}: watched - {{s.series.watched_season}}-{{s.series.watched_episode}}
last - {{s.last_season}}-{{s.last_episode}}
new episodes count - {{s.new_episodes_count}}
{% endfor %}
{% else %}
{% for s in new_series_list %}
{{s.series.title}}: watched - {{s.series.watched_season}}-{{s.series.watched_episode}}
last - {{s.last_season}}-{{s.last_episode}}
new episodes count - {{s.new_episodes_count}}
{% endfor %}
{% endif %}
{% endif %}
{% endautoescape %}

View File

@ -1,9 +0,0 @@
{% autoescape off %}
Hi {{ user.username }},
There are new episodes of the series you recorded.
{% for s, d in data %}
{{d.count}} episodes of {{s.title}} you haven't watched (watched episode: {{s.last_season}} - {{s.last_episode}}).
{% endfor %}
{% endautoescape %}

View File

@ -4,15 +4,17 @@ from django.urls import reverse_lazy, reverse
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages from django.contrib import messages
from django.shortcuts import redirect from django.shortcuts import redirect
from requests import get
from datetime import datetime from datetime import datetime
from imdb_api_access import SeriesCounter
from imdb_api_access._requests import get_request
from imdb_api_access.exceptions import *
class AddSeriesView(LoginRequiredMixin, CreateView): class AddSeriesView(LoginRequiredMixin, CreateView):
login_url = reverse_lazy('login') login_url = reverse_lazy('login')
template_name = 'add_series.html' template_name = 'add_series.html'
model = SeriesModel model = SeriesModel
fields = ('title', 'imdb_id', 'last_season', 'last_episode', 'show') fields = ('title', 'imdb_id', 'watched_season', 'watched_episode', 'show')
def get_success_url(self): def get_success_url(self):
messages.success(self.request, 'Series Added') messages.success(self.request, 'Series Added')
@ -22,58 +24,73 @@ class AddSeriesView(LoginRequiredMixin, CreateView):
series = form.save(commit=False) series = form.save(commit=False)
series.user = self.request.user series.user = self.request.user
raw_data = get(f"https://imdb-api.com/en/API/Title/{series.user.imdb_api_key}/{series.imdb_id}") try:
data = get_request(f"https://imdb-api.com/en/API/Title/{series.user.imdb_api_key}/{series.imdb_id}")
if raw_data.status_code != 200: except StatusCodeError:
messages.info(self.request, 'TV Series can not added. Please try again.') messages.info(self.request, 'TV Series can not added. Please try again.')
return redirect('add-series') return redirect('add-series')
data = raw_data.json() except MaximumUsageError:
messages.info(self.request, f"IMDB API: {data['errorMessage']}")
if data['errorMessage']: return redirect('add-series')
if 'Maximum usage' in data['errorMessage']: except APIError:
messages.info(self.request, f"IMDB API: {data['errorMessage']}")
return redirect('add-series')
form.add_error('imdb_id', 'ID is not correct.') form.add_error('imdb_id', 'ID is not correct.')
return self.form_invalid(form) return self.form_invalid(form)
if not data['tvSeriesInfo']: if not data['tvSeriesInfo']:
form.add_error('imdb_id', 'This is not a TV series id.') form.add_error('imdb_id', 'This is not a TV series id.')
return self.form_invalid(form) return self.form_invalid(form)
seasons = data['tvSeriesInfo']['seasons'] seasons = data['tvSeriesInfo']['seasons']
if str(series.last_season) not in seasons: if str(series.watched_season) not in seasons:
form.add_error('last_season', 'The season number is not correct.') form.add_error('watched_season', 'The season number is not correct.')
return self.form_invalid(form) return self.form_invalid(form)
raw_data = get(f"https://imdb-api.com/en/API/SeasonEpisodes/{series.user.imdb_api_key}/{series.imdb_id}/{series.last_season}") try:
if raw_data.status_code != 200: data = get_request(f"https://imdb-api.com/en/API/SeasonEpisodes/{series.user.imdb_api_key}/{series.imdb_id}/{series.watched_season}")
except StatusCodeError:
messages.info(self.request, 'TV Series can not added. Please try again.') messages.info(self.request, 'TV Series can not added. Please try again.')
return redirect('add-series') return redirect('add-series')
data = raw_data.json() except MaximumUsageError:
messages.info(self.request, f"IMDB API: {data['errorMessage']}")
if data['errorMessage']: return redirect('add-series')
if 'Maximum usage' in data['errorMessage']: except APIError:
messages.info(self.request, f"IMDB API: {data['errorMessage']}")
return redirect('add-series')
form.add_error('imdb_id', 'ID is not correct.') form.add_error('imdb_id', 'ID is not correct.')
return self.form_invalid(form) return self.form_invalid(form)
episodes = data['episodes']
episodes = data['episodes']
episodes_count = len(episodes) episodes_count = len(episodes)
if series.last_episode > episodes_count:
form.add_error('last_episode', 'The episode number is not correct.') if series.watched_episode > episodes_count:
form.add_error('watched_episode', 'The episode number is not correct.')
return self.form_invalid(form) return self.form_invalid(form)
released_date = episodes[int(series.last_episode) - 1]['released'].replace('.', '') released_date = episodes[int(series.watched_episode) - 1]['released'].replace('.', '')
now_date = datetime.strptime(datetime.strftime(datetime.utcnow(),'%d %b %Y'), '%d %b %Y') now_date = datetime.strptime(datetime.strftime(datetime.utcnow(),'%d %b %Y'), '%d %b %Y')
try: try:
last_episode_date = datetime.strptime(released_date, '%d %b %Y') watched_episode_date = datetime.strptime(released_date, '%d %b %Y')
if (last_episode_date - now_date).days > 0: if (watched_episode_date - now_date).days > 0:
raise ValueError raise ValueError
except ValueError: except ValueError:
form.add_error('last_episode', 'This episode has not been published yet.') form.add_error('watched_episode', 'This episode has not been published yet.')
return self.form_invalid(form) return self.form_invalid(form)
series_counter = SeriesCounter(self.request.user.imdb_api_key)
try:
new_series = series_counter.find_last_episode(series)
series.last_season = new_series.last_season
series.last_episode = new_series.last_episode
series.new_episodes_count = new_series.new_episodes_count
except (StatusCodeError, APIError):
messages.info(self.request, 'TV Series can not added. Please try again later.')
return redirect('add-series')
except MaximumUsageError as e:
messages.info(self.request, str(e))
return redirect('homepage')
series.save() series.save()
form.save_m2m() form.save_m2m()
return super().form_valid(form) return super().form_valid(form)

View File

@ -7,7 +7,7 @@ from django.contrib import messages
class SeriesDeleteView(LoginRequiredMixin, DeleteView): class SeriesDeleteView(LoginRequiredMixin, DeleteView):
login_url = reverse_lazy('login') login_url = reverse_lazy('login')
template_name = 'article_deletion_confirmation.html' template_name = 'series_deletion_confirmation.html'
def get_success_url(self): def get_success_url(self):
messages.success(self.request, 'Series Deleted') messages.success(self.request, 'Series Deleted')

View File

@ -2,13 +2,19 @@ from django.shortcuts import render
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator from django.core.paginator import Paginator
from account.models import User from account.models import User
from django.db.models import Q
@login_required(login_url='/account/login') @login_required(login_url='/account/login')
def homepage_view(request): def homepage_view(request):
user = User.objects.get(id=request.user.id) user = User.objects.get(id=request.user.id)
series_true = user.series.filter(show=True).order_by('-id') if request.GET.get('new') == 'true':
series_false = user.series.filter(show=False).order_by('-id') series_true = user.series.filter(~Q(new_episodes_count=0), show=True).order_by('-id')
series_false = user.series.filter(~Q(new_episodes_count=0), show=False).order_by('-id')
else:
series_true = user.series.filter(show=True).order_by('-id')
series_false = user.series.filter(show=False).order_by('-id')
page = request.GET.get('page') page = request.GET.get('page')
paginator = Paginator(list(series_true) + list(series_false), 5) paginator = Paginator(list(series_true) + list(series_false), 5)

View File

@ -1,5 +1,4 @@
from django.shortcuts import (render, from django.shortcuts import redirect
redirect)
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
@ -14,10 +13,41 @@ def new_episodes_view(request):
series_counter = SeriesCounter(request.user.imdb_api_key) series_counter = SeriesCounter(request.user.imdb_api_key)
try: try:
series_counter.find_new_series(series) series_counter.find_new_series(series)
except MaximumUsageError as e: ... series_len = len(series_counter.new_series_list)
# messages.warning(request, f"{e} (some series could not be updated)") error_series_len = len(series_counter.error_series)
except MaximumUsageError as e:
if series_len := len(series_counter.new_series_list):
for updated_series in series_counter.new_series_list:
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
updated_series.save()
messages.warning(request,
f"{series_len} series updated (some series could not be updated). {str(e)}")
return redirect('homepage')
if series_counter.new_series_list: messages.warning(request,
return render(request, 'new_episodes.html', context={'data': series_counter.new_series_list}) f"Series could not be updated. {str(e)}")
messages.warning(request, "There are no new episodes of any series :(") return redirect('homepage')
if series_len:
for updated_series in series_counter.new_series_list:
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
updated_series.series.save()
if error_series_len:
messages.warning(request,
f"{series_len} series updated ({error_series_len} series could not be updated).")
return redirect('homepage')
messages.warning(request,
f"{series_len} series updated.")
return redirect('homepage')
if error_series_len:
messages.warning(request,
f"{error_series_len} series could not be updated.")
return redirect('homepage')
messages.warning(request, "0 series updated :(")
return redirect('homepage') return redirect('homepage')

View File

@ -5,14 +5,16 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages from django.contrib import messages
from django.shortcuts import (get_object_or_404, from django.shortcuts import (get_object_or_404,
redirect) redirect)
from requests import get
from datetime import datetime from datetime import datetime
from imdb_api_access._requests import get_request
from imdb_api_access import SeriesCounter
from imdb_api_access.exceptions import *
class UpdateSeriesView(LoginRequiredMixin, UpdateView): class UpdateSeriesView(LoginRequiredMixin, UpdateView):
login_url = reverse_lazy('login') login_url = reverse_lazy('login')
template_name = 'update_series.html' template_name = 'update_series.html'
fields = ('title', 'imdb_id', 'last_season', 'last_episode', 'show') fields = ('title', 'imdb_id', 'watched_season', 'watched_episode', 'show')
def get_object(self): def get_object(self):
return get_object_or_404(SeriesModel, slug=self.kwargs.get('slug'), user=self.request.user) return get_object_or_404(SeriesModel, slug=self.kwargs.get('slug'), user=self.request.user)
@ -25,22 +27,20 @@ class UpdateSeriesView(LoginRequiredMixin, UpdateView):
series = form.save(commit=False) series = form.save(commit=False)
series.user = self.request.user series.user = self.request.user
if not {'imdb_id', 'last_season', 'last_episode'} & set(form.changed_data): if not {'imdb_id', 'watched_season', 'watched_episode'} & set(form.changed_data):
series.save() series.save()
form.save_m2m() form.save_m2m()
return super().form_valid(form) return super().form_valid(form)
raw_data = get(f"https://imdb-api.com/en/API/Title/{series.user.imdb_api_key}/{series.imdb_id}") try:
data = get_request(f"https://imdb-api.com/en/API/Title/{series.user.imdb_api_key}/{series.imdb_id}")
if raw_data.status_code != 200: except StatusCodeError:
messages.info(self.request, 'TV Series can not updated. Please try again.') messages.info(self.request, 'TV Series can not added. Please try again.')
return redirect('update-series', self.kwargs.get('slug')) return redirect('update-series', self.kwargs.get('slug'))
data = raw_data.json() except MaximumUsageError:
messages.info(self.request, f"IMDB API: {data['errorMessage']}")
if data['errorMessage']: return redirect('update-series', self.kwargs.get('slug'))
if 'Maximum usage' in data['errorMessage']: except APIError:
messages.info(self.request, f"IMDB Key: {data['errorMessage']}")
return redirect("update-series", self.kwargs.get('slug'))
form.add_error('imdb_id', 'ID is not correct.') form.add_error('imdb_id', 'ID is not correct.')
return self.form_invalid(form) return self.form_invalid(form)
@ -49,39 +49,55 @@ class UpdateSeriesView(LoginRequiredMixin, UpdateView):
return self.form_invalid(form) return self.form_invalid(form)
seasons = data['tvSeriesInfo']['seasons'] seasons = data['tvSeriesInfo']['seasons']
if str(series.last_season) not in seasons: if str(series.watched_season) not in seasons:
form.add_error('last_season', 'The season number is not correct.') form.add_error('watched_season', 'The season number is not correct.')
return self.form_invalid(form) return self.form_invalid(form)
raw_data = get(f"https://imdb-api.com/en/API/SeasonEpisodes/{series.user.imdb_api_key}/{series.imdb_id}/{series.last_season}") try:
if raw_data.status_code != 200: data = get_request(f"https://imdb-api.com/en/API/SeasonEpisodes/{series.user.imdb_api_key}/{series.imdb_id}/{series.watched_season}")
except StatusCodeError:
messages.info(self.request, 'TV Series can not added. Please try again.') messages.info(self.request, 'TV Series can not added. Please try again.')
return redirect('update-series', self.kwargs.get('slug')) return redirect('update-series', self.kwargs.get('slug'))
data = raw_data.json() except MaximumUsageError:
messages.info(self.request, f"IMDB API: {data['errorMessage']}")
if data['errorMessage']: return redirect('update-series', self.kwargs.get('slug'))
if 'Maximum usage' in data['errorMessage']: except APIError:
messages.info(self.request, f"IMDB API: {data['errorMessage']}")
return redirect('update-series', self.kwargs.get('slug'))
form.add_error('imdb_id', 'ID is not correct.') form.add_error('imdb_id', 'ID is not correct.')
return self.form_invalid(form) return self.form_invalid(form)
episodes = data['episodes']
episodes = data['episodes']
episodes_count = len(episodes) episodes_count = len(episodes)
if series.last_episode > episodes_count:
form.add_error('last_episode', 'The episode number is not correct.') if series.watched_episode > episodes_count:
form.add_error('watched_episode', 'The episode number is not correct.')
return self.form_invalid(form) return self.form_invalid(form)
released_date = episodes[int(series.last_episode) - 1]['released'].replace('.', '') released_date = episodes[int(series.watched_episode) - 1]['released'].replace('.', '')
now_date = datetime.strptime(datetime.strftime(datetime.utcnow(),'%d %b %Y'), '%d %b %Y') now_date = datetime.strptime(datetime.strftime(datetime.utcnow(),'%d %b %Y'), '%d %b %Y')
try: try:
last_episode_date = datetime.strptime(released_date, '%d %b %Y') last_episode_date = datetime.strptime(released_date, '%d %b %Y')
if (last_episode_date - now_date).days > 0: if (last_episode_date - now_date).days > 0:
raise ValueError raise ValueError
except ValueError: except ValueError:
form.add_error('last_episode', 'This episode has not been published yet.') form.add_error('watched_episode', 'This episode has not been published yet.')
return self.form_invalid(form) return self.form_invalid(form)
series_counter = SeriesCounter(self.request.user.imdb_api_key)
try:
new_series = series_counter.find_last_episode(series)
series.last_season = new_series.last_season
series.last_episode = new_series.last_episode
series.new_episodes_count = new_series.new_episodes_count
except (StatusCodeError, APIError):
messages.info(self.request, 'TV Series can not updated. Please try again later.')
return redirect('update-series', self.kwargs.get('slug'))
except MaximumUsageError as e:
messages.info(self.request, str(e))
return redirect('homepage')
series.save() series.save()
form.save_m2m() form.save_m2m()
return super().form_valid(form) return super().form_valid(form)

View File

@ -14,7 +14,7 @@
<a class="btn btn-outline-light btn-floating m-1 contact-links" style="padding: 2px 4px 2px 4px;" target="_blank" href="https://github.com/Ayxan-z" role="button"> <a class="btn btn-outline-light btn-floating m-1 contact-links" style="padding: 2px 4px 2px 4px;" target="_blank" href="https://github.com/Ayxan-z" role="button">
<img class="contact-img" src="{% static 'icons/github.png' %}"> <img class="contact-img" src="{% static 'icons/github.png' %}">
</a> </a>
<a class="btn btn-outline-light btn-floating m-1 contact-links" style="padding: 5px 6px 5px 6px;" target="_blank" href="https://www.linkedin.com/in/ayxan-shahsuvarov-59a314187" role="button"> <a class="btn btn-outline-light btn-floating m-1 contact-links" style="padding: 5px 6px 5px 6px;" target="_blank" href="https://www.linkedin.com/in/aykhan-shahsuvarov-59a314187/" role="button">
<img class="contact-img" src="{% static 'icons/linkedin.png' %}" style="background-color: white;"> <img class="contact-img" src="{% static 'icons/linkedin.png' %}" style="background-color: white;">
</a> </a>
<a class="btn btn-outline-light btn-floating m-1 contact-links" style="padding: 6px 7px 6px 7px;" target="_blank" href="mailto:ayxan.shahsuvarov1@gmail.com" role="button"> <a class="btn btn-outline-light btn-floating m-1 contact-links" style="padding: 6px 7px 6px 7px;" target="_blank" href="mailto:ayxan.shahsuvarov1@gmail.com" role="button">