diff options
author | morpheus65535 <[email protected]> | 2024-12-16 06:50:47 -0500 |
---|---|---|
committer | morpheus65535 <[email protected]> | 2024-12-16 06:50:47 -0500 |
commit | 1172a87e8aa9e008cf5bb1d6a00572e6fc95d372 (patch) | |
tree | f92d23284856adef97e3dcc12bd76c6f422a42ac | |
parent | f81780fac564080301b06be76dbd33267b8f0ac8 (diff) | |
download | bazarr-1172a87e8aa9e008cf5bb1d6a00572e6fc95d372.tar.gz bazarr-1172a87e8aa9e008cf5bb1d6a00572e6fc95d372.zip |
Added series status and last air date
-rw-r--r-- | bazarr/api/series/series.py | 6 | ||||
-rw-r--r-- | bazarr/app/database.py | 2 | ||||
-rw-r--r-- | bazarr/sonarr/sync/parser.py | 40 | ||||
-rw-r--r-- | frontend/src/pages/Episodes/index.tsx | 11 | ||||
-rw-r--r-- | frontend/src/pages/Series/index.tsx | 20 | ||||
-rw-r--r-- | frontend/src/types/api.d.ts | 2 | ||||
-rw-r--r-- | migrations/utils.py | 10 | ||||
-rw-r--r-- | migrations/versions/4274a5dfc4ad_.py | 32 |
8 files changed, 106 insertions, 17 deletions
diff --git a/bazarr/api/series/series.py b/bazarr/api/series/series.py index b858f03de..a16db2322 100644 --- a/bazarr/api/series/series.py +++ b/bazarr/api/series/series.py @@ -34,9 +34,11 @@ class Series(Resource): 'alternativeTitles': fields.List(fields.String), 'audio_language': fields.Nested(get_audio_language_model), 'episodeFileCount': fields.Integer(default=0), + 'ended': fields.Boolean(), 'episodeMissingCount': fields.Integer(default=0), 'fanart': fields.String(), 'imdbId': fields.String(), + 'lastAired': fields.String(), 'monitored': fields.Boolean(), 'overview': fields.String(), 'path': fields.String(), @@ -100,6 +102,8 @@ class Series(Resource): TableShows.tags, TableShows.title, TableShows.year, + TableShows.ended, + TableShows.lastAired, episodeFileCount.c.episodeFileCount, episodeMissingCount.c.episodeMissingCount) \ .select_from(TableShows) \ @@ -128,6 +132,8 @@ class Series(Resource): 'tags': x.tags, 'title': x.title, 'year': x.year, + 'ended': x.ended, + 'lastAired': x.lastAired, 'episodeFileCount': x.episodeFileCount, 'episodeMissingCount': x.episodeMissingCount, }) for x in database.execute(stmt).all()] diff --git a/bazarr/app/database.py b/bazarr/app/database.py index 09297ac96..6166e4258 100644 --- a/bazarr/app/database.py +++ b/bazarr/app/database.py @@ -276,8 +276,10 @@ class TableShows(Base): alternativeTitles = mapped_column(Text) audio_language = mapped_column(Text) created_at_timestamp = mapped_column(DateTime) + ended = mapped_column(Text) fanart = mapped_column(Text) imdbId = mapped_column(Text) + lastAired = mapped_column(Text) monitored = mapped_column(Text) overview = mapped_column(Text) path = mapped_column(Text, nullable=False, unique=True) diff --git a/bazarr/sonarr/sync/parser.py b/bazarr/sonarr/sync/parser.py index 27da32117..4e7dd4997 100644 --- a/bazarr/sonarr/sync/parser.py +++ b/bazarr/sonarr/sync/parser.py @@ -2,6 +2,8 @@ import os +from dateutil import parser + from app.config import settings from app.database import TableShows, database, select from constants import MINIMUM_VIDEO_SIZE @@ -45,6 +47,10 @@ def seriesParser(show, action, tags_dict, language_profiles, serie_default_profi imdbId = show['imdbId'] if 'imdbId' in show else None + ended = 'True' if 'ended' in show and show['ended'] else 'False' + + lastAired = parser.parse(show['lastAired']).strftime("%Y-%m-%d") if 'lastAired' in show and show['lastAired'] else None + audio_language = [] if not settings.general.parse_embedded_audio_track: if get_sonarr_info.is_legacy(): @@ -56,22 +62,24 @@ def seriesParser(show, action, tags_dict, language_profiles, serie_default_profi audio_language = [] parsed_series = { - 'title': show["title"], - 'path': show["path"], - 'tvdbId': int(show["tvdbId"]), - 'sonarrSeriesId': int(show["id"]), - 'overview': overview, - 'poster': poster, - 'fanart': fanart, - 'audio_language': str(audio_language), - 'sortTitle': show['sortTitle'], - 'year': str(show['year']), - 'alternativeTitles': str(alternate_titles), - 'tags': str(tags), - 'seriesType': show['seriesType'], - 'imdbId': imdbId, - 'monitored': str(bool(show['monitored'])) - } + 'title': show["title"], + 'path': show["path"], + 'tvdbId': int(show["tvdbId"]), + 'sonarrSeriesId': int(show["id"]), + 'overview': overview, + 'poster': poster, + 'fanart': fanart, + 'audio_language': str(audio_language), + 'sortTitle': show['sortTitle'], + 'year': str(show['year']), + 'alternativeTitles': str(alternate_titles), + 'tags': str(tags), + 'seriesType': show['seriesType'], + 'imdbId': imdbId, + 'monitored': str(bool(show['monitored'])), + 'ended': ended, + 'lastAired': lastAired, + } if action == 'insert': parsed_series['profileId'] = serie_default_profile diff --git a/frontend/src/pages/Episodes/index.tsx b/frontend/src/pages/Episodes/index.tsx index 69a8d67e8..2a518ae4c 100644 --- a/frontend/src/pages/Episodes/index.tsx +++ b/frontend/src/pages/Episodes/index.tsx @@ -13,11 +13,14 @@ import { showNotification } from "@mantine/notifications"; import { faAdjust, faBriefcase, + faCalendar, faCircleChevronDown, faCircleChevronRight, faCloudUploadAlt, faHdd, + faPlay, faSearch, + faStop, faSync, faTriangleExclamation, faWrench, @@ -68,6 +71,14 @@ const SeriesEpisodesView: FunctionComponent = () => { text: `${series?.episodeMissingCount} missing subtitles`, }, { + icon: series?.ended ? faStop : faPlay, + text: series?.ended ? "Ended" : "Continuing", + }, + { + icon: faCalendar, + text: `Last ${series?.ended ? "aired on" : "known airdate"}: ${series?.lastAired}`, + }, + { icon: faAdjust, text: series?.seriesType ?? "", }, diff --git a/frontend/src/pages/Series/index.tsx b/frontend/src/pages/Series/index.tsx index c142a6767..d117e7a6f 100644 --- a/frontend/src/pages/Series/index.tsx +++ b/frontend/src/pages/Series/index.tsx @@ -3,7 +3,12 @@ import { Link } from "react-router-dom"; import { Anchor, Container, Progress } from "@mantine/core"; import { useDocumentTitle } from "@mantine/hooks"; import { faBookmark as farBookmark } from "@fortawesome/free-regular-svg-icons"; -import { faBookmark, faWrench } from "@fortawesome/free-solid-svg-icons"; +import { + faBookmark, + faPlay, + faStop, + faWrench, +} from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { ColumnDef } from "@tanstack/react-table"; import { useSeriesModification, useSeriesPagination } from "@/apis/hooks"; @@ -36,6 +41,19 @@ const SeriesView: FunctionComponent = () => { ), }, { + id: "ended", + cell: ({ + row: { + original: { ended }, + }, + }) => ( + <FontAwesomeIcon + title={ended ? "Ended" : "Continuing"} + icon={ended ? faStop : faPlay} + ></FontAwesomeIcon> + ), + }, + { header: "Name", accessorKey: "title", cell: ({ row: { original } }) => { diff --git a/frontend/src/types/api.d.ts b/frontend/src/types/api.d.ts index f5746ea4b..21180aa4f 100644 --- a/frontend/src/types/api.d.ts +++ b/frontend/src/types/api.d.ts @@ -151,6 +151,8 @@ declare namespace Item { SeriesIdType & { episodeFileCount: number; episodeMissingCount: number; + ended: boolean; + lastAired: string; seriesType: SonarrSeriesType; tvdbId: number; }; diff --git a/migrations/utils.py b/migrations/utils.py new file mode 100644 index 000000000..069f36d0c --- /dev/null +++ b/migrations/utils.py @@ -0,0 +1,10 @@ +from alembic import op +import sqlalchemy as sa + +bind = op.get_context().bind +insp = sa.inspect(bind) + + +def column_exists(table_name, column_name): + columns = insp.get_columns(table_name) + return any(c["name"] == column_name for c in columns) diff --git a/migrations/versions/4274a5dfc4ad_.py b/migrations/versions/4274a5dfc4ad_.py new file mode 100644 index 000000000..6787936fa --- /dev/null +++ b/migrations/versions/4274a5dfc4ad_.py @@ -0,0 +1,32 @@ +"""empty message + +Revision ID: 4274a5dfc4ad +Revises: 8baf97427327 +Create Date: 2024-12-15 21:19:19.406290 + +""" +from alembic import op +import sqlalchemy as sa + +from migrations.utils import column_exists + + +# revision identifiers, used by Alembic. +revision = '4274a5dfc4ad' +down_revision = '8baf97427327' +branch_labels = None +depends_on = None + + +def upgrade(): + if not column_exists('table_shows', 'ended'): + with op.batch_alter_table('table_shows', schema=None) as batch_op: + batch_op.add_column(sa.Column('ended', sa.TEXT(), nullable=True)) + + if not column_exists('table_shows', 'lastAired'): + with op.batch_alter_table('table_shows', schema=None) as batch_op: + batch_op.add_column(sa.Column('lastAired', sa.TEXT(), nullable=True)) + + +def downgrade(): + pass |