Merge branch 'dev'
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
Some checks failed
Create and publish a Docker image / build-and-push-image (push) Has been cancelled
This commit is contained in:
commit
557a646d65
14
code/bot.py
14
code/bot.py
@ -1,10 +1,9 @@
|
|||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands, tasks
|
||||||
from discord.ext import tasks
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from utils.database import Base, engine
|
||||||
import utils.config as config
|
import utils.config as config
|
||||||
from utils.jellyfin_delete import delete_accounts
|
|
||||||
|
|
||||||
|
|
||||||
class MyBot(commands.Bot):
|
class MyBot(commands.Bot):
|
||||||
@ -15,7 +14,7 @@ class MyBot(commands.Bot):
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def setup_hook(self):
|
async def setup_hook(self):
|
||||||
delete_old_temp_accounts.start()
|
delete_accounts_task.start()
|
||||||
for ext in os.listdir("./code/cogs"):
|
for ext in os.listdir("./code/cogs"):
|
||||||
if ext.endswith(".py"):
|
if ext.endswith(".py"):
|
||||||
await self.load_extension(f"cogs.{ext[:-3]}")
|
await self.load_extension(f"cogs.{ext[:-3]}")
|
||||||
@ -30,8 +29,11 @@ async def on_ready():
|
|||||||
config.LOG.info(f"{bot.user} has connected to Discord.")
|
config.LOG.info(f"{bot.user} has connected to Discord.")
|
||||||
|
|
||||||
|
|
||||||
@tasks.loop(seconds=60)
|
@tasks.loop(minutes=1)
|
||||||
async def delete_old_temp_accounts():
|
async def delete_accounts_task():
|
||||||
|
from utils.jellyfin_delete import delete_accounts
|
||||||
|
|
||||||
|
Base.metadata.create_all(bind=engine)
|
||||||
delete_accounts()
|
delete_accounts()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import discord
|
import discord
|
||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
|
from utils.database import Session
|
||||||
from utils.jellyfin_create import create_jellyfin_account
|
from utils.jellyfin_create import create_jellyfin_account
|
||||||
|
from utils.models import JellyfinAccounts
|
||||||
from utils.config import (
|
from utils.config import (
|
||||||
JELLYFIN_PUBLIC_URL,
|
JELLYFIN_PUBLIC_URL,
|
||||||
JELLYFIN_ENABLED,
|
JELLYFIN_ENABLED,
|
||||||
@ -19,15 +20,15 @@ class NewAccount(commands.Cog):
|
|||||||
@app_commands.check(lambda inter: JELLYFIN_ENABLED)
|
@app_commands.check(lambda inter: JELLYFIN_ENABLED)
|
||||||
async def newaccount(self, interaction: discord.Interaction) -> None:
|
async def newaccount(self, interaction: discord.Interaction) -> None:
|
||||||
"""Create a new temporary Jellyfin account"""
|
"""Create a new temporary Jellyfin account"""
|
||||||
|
# Defer in case it takes too long
|
||||||
|
await interaction.response.defer(ephemeral=True)
|
||||||
# Make sure the user doesn't already have an account
|
# Make sure the user doesn't already have an account
|
||||||
db = sqlite3.connect("data/cordarr.db")
|
with Session() as session:
|
||||||
cursor = db.cursor()
|
account = (
|
||||||
cursor.execute(
|
session.query(JellyfinAccounts)
|
||||||
"SELECT * FROM jellyfin_accounts WHERE user_id = ?",
|
.filter(JellyfinAccounts.user_id == interaction.user.id)
|
||||||
(interaction.user.id,),
|
.first()
|
||||||
)
|
)
|
||||||
account = cursor.fetchone()
|
|
||||||
db.close()
|
|
||||||
# Account already allocated
|
# Account already allocated
|
||||||
if account:
|
if account:
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
@ -39,9 +40,7 @@ class NewAccount(commands.Cog):
|
|||||||
),
|
),
|
||||||
color=0xD01B86,
|
color=0xD01B86,
|
||||||
)
|
)
|
||||||
return await interaction.response.send_message(
|
return await interaction.followup.send(embed=embed)
|
||||||
embed=embed, ephemeral=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create a new Jellyfin account for the user
|
# Create a new Jellyfin account for the user
|
||||||
response = create_jellyfin_account(interaction.user.id)
|
response = create_jellyfin_account(interaction.user.id)
|
||||||
@ -54,17 +53,15 @@ class NewAccount(commands.Cog):
|
|||||||
),
|
),
|
||||||
color=0xD01B86,
|
color=0xD01B86,
|
||||||
)
|
)
|
||||||
await interaction.response.send_message(
|
await interaction.followup.send(embed=embed)
|
||||||
embed=embed, ephemeral=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Send the user their account information
|
# Send the user their account information
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="Jellyfin Account Information",
|
title="Jellyfin Account Information",
|
||||||
description=(
|
description=(
|
||||||
# fmt: off
|
# fmt: off
|
||||||
"Here is your temporary account information.\n\n",
|
"Here is your temporary account information.\n\n"
|
||||||
f"**Server URL:** `[{JELLYFIN_PUBLIC_URL}]({JELLYFIN_PUBLIC_URL})`\n"
|
f"**Server URL:** `{JELLYFIN_PUBLIC_URL}`\n"
|
||||||
f"**Username:** `{response[0]}`\n"
|
f"**Username:** `{response[0]}`\n"
|
||||||
f"**Password:** `{response[1]}`\n\n"
|
f"**Password:** `{response[1]}`\n\n"
|
||||||
"Your account will be automatically deleted in"
|
"Your account will be automatically deleted in"
|
||||||
@ -84,9 +81,7 @@ class NewAccount(commands.Cog):
|
|||||||
),
|
),
|
||||||
color=0xD01B86,
|
color=0xD01B86,
|
||||||
)
|
)
|
||||||
return await interaction.response.send_message(
|
return await interaction.followup.send(embed=embed)
|
||||||
embed=embed, ephemeral=True
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
async def setup(bot):
|
||||||
|
@ -31,6 +31,8 @@ class Request(commands.Cog):
|
|||||||
name: str,
|
name: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Request a movie or tv show to be added to the library"""
|
"""Request a movie or tv show to be added to the library"""
|
||||||
|
# Could take a sec. so defer the response
|
||||||
|
await interaction.response.defer(ephemeral=True)
|
||||||
# Get matching content from relevant service
|
# Get matching content from relevant service
|
||||||
if form == "Movie":
|
if form == "Movie":
|
||||||
content_data = get_content(
|
content_data = get_content(
|
||||||
@ -54,9 +56,7 @@ class Request(commands.Cog):
|
|||||||
),
|
),
|
||||||
color=0xD01B86,
|
color=0xD01B86,
|
||||||
)
|
)
|
||||||
return await interaction.response.send_message(
|
return await interaction.followup.send(embed=embed, ephemeral=True)
|
||||||
embed=embed, ephemeral=True
|
|
||||||
)
|
|
||||||
|
|
||||||
if content_data == "ALREADY ADDED":
|
if content_data == "ALREADY ADDED":
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
@ -70,9 +70,7 @@ class Request(commands.Cog):
|
|||||||
),
|
),
|
||||||
color=0xD01B86,
|
color=0xD01B86,
|
||||||
)
|
)
|
||||||
return await interaction.response.send_message(
|
return await interaction.followup.send(embed=embed, ephemeral=True)
|
||||||
embed=embed, ephemeral=True
|
|
||||||
)
|
|
||||||
|
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="Results Found",
|
title="Results Found",
|
||||||
@ -103,9 +101,7 @@ class Request(commands.Cog):
|
|||||||
SONARR_QUALITY_PROFILE_ID,
|
SONARR_QUALITY_PROFILE_ID,
|
||||||
)
|
)
|
||||||
|
|
||||||
await interaction.response.send_message(
|
await interaction.followup.send(embed=embed, view=view, ephemeral=True)
|
||||||
embed=embed, view=view, ephemeral=True
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
async def setup(bot):
|
||||||
|
@ -2,8 +2,9 @@ import discord
|
|||||||
from discord import app_commands
|
from discord import app_commands
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
import requests
|
import requests
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
|
from utils.models import Requests
|
||||||
|
from utils.database import Session
|
||||||
from utils.config import (
|
from utils.config import (
|
||||||
RADARR_HOST_URL,
|
RADARR_HOST_URL,
|
||||||
RADARR_HEADERS,
|
RADARR_HEADERS,
|
||||||
@ -20,17 +21,20 @@ class Status(commands.Cog):
|
|||||||
async def status(self, interaction: discord.Interaction) -> None:
|
async def status(self, interaction: discord.Interaction) -> None:
|
||||||
"""Get the status of the movies you have requested"""
|
"""Get the status of the movies you have requested"""
|
||||||
# Defer the response
|
# Defer the response
|
||||||
await interaction.response.defer()
|
await interaction.response.defer(ephemeral=True)
|
||||||
|
|
||||||
db = sqlite3.connect("data/cordarr.db")
|
with Session() as session:
|
||||||
cursor = db.cursor()
|
requested_content = (
|
||||||
cursor.execute(
|
session.query(
|
||||||
"SELECT title, release_year, local_id, tmdbid, tvdbid FROM"
|
Requests.title,
|
||||||
" requests WHERE user_id = ?",
|
Requests.release_year,
|
||||||
(interaction.user.id,),
|
Requests.local_id,
|
||||||
)
|
Requests.tmdbid,
|
||||||
requested_content = cursor.fetchall()
|
Requests.tvdbid,
|
||||||
db.close()
|
)
|
||||||
|
.filter(Requests.user_id == interaction.user.id)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
# No content requested
|
# No content requested
|
||||||
if len(requested_content) == 0:
|
if len(requested_content) == 0:
|
||||||
@ -42,9 +46,7 @@ class Status(commands.Cog):
|
|||||||
),
|
),
|
||||||
color=0xD01B86,
|
color=0xD01B86,
|
||||||
)
|
)
|
||||||
return await interaction.response.send_message(
|
return await interaction.followup.send(embed=embed)
|
||||||
embed=embed, ephemeral=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create template embed
|
# Create template embed
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
@ -76,8 +78,8 @@ class Status(commands.Cog):
|
|||||||
|
|
||||||
embed.description += radarr_desc + sonarr_desc + non_queue_desc
|
embed.description += radarr_desc + sonarr_desc + non_queue_desc
|
||||||
|
|
||||||
# Send the embed
|
# Send the follow-up message
|
||||||
await interaction.response.send_message(embed=embed, ephemeral=True)
|
await interaction.followup.send(embed=embed)
|
||||||
|
|
||||||
def unpack_content(self, requested_content: list) -> tuple:
|
def unpack_content(self, requested_content: list) -> tuple:
|
||||||
"""
|
"""
|
||||||
@ -94,18 +96,18 @@ class Status(commands.Cog):
|
|||||||
sonarr_content_info = {}
|
sonarr_content_info = {}
|
||||||
|
|
||||||
for content in requested_content:
|
for content in requested_content:
|
||||||
title, (release_year), local_id, tmdbid, tvdbid = content
|
title, release_year, local_id, tmdbid, tvdbid = content
|
||||||
if tmdbid is not None:
|
if tmdbid is not None:
|
||||||
radarr_content_info[int(local_id)] = {
|
radarr_content_info[local_id] = {
|
||||||
"title": title,
|
"title": title,
|
||||||
"release_year": int(release_year),
|
"release_year": release_year,
|
||||||
"tmdbid": int(tmdbid),
|
"tmdbid": tmdbid,
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
sonarr_content_info[int(local_id)] = {
|
sonarr_content_info[local_id] = {
|
||||||
"title": title,
|
"title": title,
|
||||||
"release_year": int(release_year),
|
"release_year": release_year,
|
||||||
"tvdbid": int(tvdbid),
|
"tvdbid": tvdbid,
|
||||||
}
|
}
|
||||||
|
|
||||||
return radarr_content_info, sonarr_content_info
|
return radarr_content_info, sonarr_content_info
|
||||||
@ -171,7 +173,7 @@ class Status(commands.Cog):
|
|||||||
for content in requested_content:
|
for content in requested_content:
|
||||||
title, release_year, local_id, tmdbid, _ = content
|
title, release_year, local_id, tmdbid, _ = content
|
||||||
# If not in queue
|
# If not in queue
|
||||||
if int(local_id) not in added_ids:
|
if local_id not in added_ids:
|
||||||
# Pull the movie data from the service
|
# Pull the movie data from the service
|
||||||
if tmdbid is not None:
|
if tmdbid is not None:
|
||||||
data = requests.get(
|
data = requests.get(
|
||||||
@ -187,23 +189,26 @@ class Status(commands.Cog):
|
|||||||
# If the movie has a file, then it has finished downloading
|
# If the movie has a file, then it has finished downloading
|
||||||
if data.get("hasFile", True):
|
if data.get("hasFile", True):
|
||||||
# Remove from database
|
# Remove from database
|
||||||
db = sqlite3.connect("data/cordarr.db")
|
with Session() as session:
|
||||||
cursor = db.cursor()
|
request = (
|
||||||
cursor.execute(
|
session.query(Requests)
|
||||||
"DELETE FROM requests WHERE user_id = ? AND"
|
.filter(Requests.user_id == user_id)
|
||||||
" local_id = ?",
|
.filter(Requests.local_id == local_id)
|
||||||
(user_id, int(local_id)),
|
.first()
|
||||||
)
|
)
|
||||||
db.commit()
|
session.delete(request)
|
||||||
db.close()
|
session.commit()
|
||||||
|
|
||||||
# If series and only a portion of episodes have been downloaded
|
# If series and only a portion of episodes have been downloaded
|
||||||
if data.get("statistics").get("percentOfEpisodes"):
|
# If data["statistics"] exists and is not None
|
||||||
description += (
|
if "statistics" in data and data["statistics"] != None:
|
||||||
f"\n**{title} ({release_year})** - Status: `NOT"
|
if "percentOfEpisodes" in data["statistics"]:
|
||||||
" FOUND"
|
description += (
|
||||||
f" ({int(data['statistics']['percentOfEpisodes'])}%"
|
f"\n**{title} ({release_year})** - Status: `NOT"
|
||||||
" of eps.)`"
|
" FOUND"
|
||||||
)
|
f" ({int(data['statistics']['percentOfEpisodes'])}%"
|
||||||
|
" of eps.)`"
|
||||||
|
)
|
||||||
# All other scenarios, download not found
|
# All other scenarios, download not found
|
||||||
else:
|
else:
|
||||||
description += (
|
description += (
|
||||||
|
@ -4,7 +4,6 @@ import sys
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import requests
|
import requests
|
||||||
import sqlite3
|
|
||||||
from colorlog import ColoredFormatter
|
from colorlog import ColoredFormatter
|
||||||
|
|
||||||
|
|
||||||
@ -108,10 +107,9 @@ schema = {
|
|||||||
|
|
||||||
def load_config() -> None:
|
def load_config() -> None:
|
||||||
"""
|
"""
|
||||||
Load DB, then load and validate the config file
|
Load the config file and validate it
|
||||||
If the file does not exist, generate it
|
If the file does not exist, generate it
|
||||||
"""
|
"""
|
||||||
database_setup()
|
|
||||||
if os.path.exists("/.dockerenv"):
|
if os.path.exists("/.dockerenv"):
|
||||||
file_path = "config/config.yaml"
|
file_path = "config/config.yaml"
|
||||||
else:
|
else:
|
||||||
@ -157,26 +155,6 @@ jellyfin:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def database_setup() -> None:
|
|
||||||
"""
|
|
||||||
Create the database if it does not exist
|
|
||||||
"""
|
|
||||||
if not os.path.exists("data"):
|
|
||||||
os.makedirs("data")
|
|
||||||
db = sqlite3.connect("data/cordarr.db")
|
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute(
|
|
||||||
"CREATE TABLE IF NOT EXISTS requests (title TEXT, release_year TEXT,"
|
|
||||||
" local_id INTEGER, tmdbid INTEGER, tvdbid INTEGER, user_id INTEGER)"
|
|
||||||
)
|
|
||||||
cursor.execute(
|
|
||||||
"CREATE TABLE IF NOT EXISTS jellyfin_accounts (user_id INTEGER,"
|
|
||||||
" jellyfin_user_id INTEGER, deletion_time DATETIME)"
|
|
||||||
)
|
|
||||||
db.commit()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
|
|
||||||
def validate_config(contents) -> None:
|
def validate_config(contents) -> None:
|
||||||
"""
|
"""
|
||||||
Validate the contents of the config file and assign variables
|
Validate the contents of the config file and assign variables
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import discord
|
import discord
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
|
from utils.models import Requests
|
||||||
|
from utils.database import Session
|
||||||
from utils.content_add import add_content
|
from utils.content_add import add_content
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -147,7 +148,8 @@ class RequestButtonView(discord.ui.View):
|
|||||||
),
|
),
|
||||||
color=0xD01B86,
|
color=0xD01B86,
|
||||||
)
|
)
|
||||||
await interaction.response.send_message(embed=embed)
|
await interaction.response.edit_message(view=None)
|
||||||
|
await interaction.followup.send(embed=embed)
|
||||||
# Alert the user that the content failed to be added
|
# Alert the user that the content failed to be added
|
||||||
else:
|
else:
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
@ -158,33 +160,30 @@ class RequestButtonView(discord.ui.View):
|
|||||||
f" {self.service} library."
|
f" {self.service} library."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return await interaction.response.send_message(embed=embed)
|
await interaction.delete_original_response()
|
||||||
|
return await interaction.response.edit_message(embed=embed)
|
||||||
|
|
||||||
# Keep track of the requests for the `/status` command
|
# Keep track of the requests for the `/status` command
|
||||||
db = sqlite3.connect("data/cordarr.db")
|
with Session() as session:
|
||||||
cursor = db.cursor()
|
session.add(
|
||||||
cursor.execute(
|
Requests(
|
||||||
"INSERT INTO requests (title, release_year, local_id, tmdbid,"
|
title=self.content_info["title"],
|
||||||
" tvdbid, user_id) VALUES (?, ?, ?, ?, ?, ?)",
|
release_year=self.content_info["year"],
|
||||||
(
|
local_id=local_id,
|
||||||
self.content_info["title"],
|
tmdbid=(
|
||||||
self.content_info["year"],
|
self.content_info["contentId"]
|
||||||
local_id,
|
if self.service == "radarr"
|
||||||
(
|
else None
|
||||||
self.content_info["contentId"]
|
),
|
||||||
if self.service == "radarr"
|
tvdbid=(
|
||||||
else None
|
None
|
||||||
),
|
if self.service == "radarr"
|
||||||
(
|
else self.content_info["contentId"]
|
||||||
None
|
),
|
||||||
if self.service == "radarr"
|
user_id=interaction.user.id,
|
||||||
else self.content_info["contentId"]
|
)
|
||||||
),
|
)
|
||||||
interaction.user.id,
|
session.commit()
|
||||||
),
|
|
||||||
)
|
|
||||||
db.commit()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
@discord.ui.button(label="Don't Request", style=discord.ButtonStyle.danger)
|
@discord.ui.button(label="Don't Request", style=discord.ButtonStyle.danger)
|
||||||
async def dont_request_button(
|
async def dont_request_button(
|
||||||
@ -200,4 +199,4 @@ class RequestButtonView(discord.ui.View):
|
|||||||
),
|
),
|
||||||
color=0xD01B86,
|
color=0xD01B86,
|
||||||
)
|
)
|
||||||
await interaction.response.send_message(embed=embed)
|
await interaction.response.edit_message(embed=embed, view=None)
|
||||||
|
13
code/utils/database.py
Normal file
13
code/utils/database.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
import os
|
||||||
|
|
||||||
|
if not os.path.exists("data"):
|
||||||
|
os.makedirs("data")
|
||||||
|
|
||||||
|
database_url = "sqlite:///data/cordarr.db"
|
||||||
|
|
||||||
|
engine = create_engine(database_url)
|
||||||
|
Session = sessionmaker(bind=engine)
|
||||||
|
Base = declarative_base()
|
@ -1,10 +1,11 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import requests
|
import requests
|
||||||
import random
|
import random
|
||||||
import sqlite3
|
|
||||||
from wonderwords import RandomWord
|
from wonderwords import RandomWord
|
||||||
from string import ascii_lowercase, digits
|
from string import ascii_lowercase, digits
|
||||||
|
|
||||||
|
from utils.database import Session
|
||||||
|
from utils.models import JellyfinAccounts
|
||||||
from utils.config import (
|
from utils.config import (
|
||||||
JELLYFIN_URL,
|
JELLYFIN_URL,
|
||||||
JELLYFIN_HEADERS,
|
JELLYFIN_HEADERS,
|
||||||
@ -67,14 +68,14 @@ def create_jellyfin_account(user_id):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Add the information to the database
|
# Add the information to the database
|
||||||
db = sqlite3.connect("data/cordarr.db")
|
with Session() as session:
|
||||||
cursor = db.cursor()
|
session.add(
|
||||||
cursor.execute(
|
JellyfinAccounts(
|
||||||
"INSERT INTO jellyfin_accounts (user_id, jellyfin_user_id,"
|
user_id=user_id,
|
||||||
" deletion_time) VALUES (?, ?, ?)",
|
jellyfin_user_id=jellyfin_user_id,
|
||||||
(user_id, jellyfin_user_id, deletion_time),
|
deletion_time=deletion_time,
|
||||||
)
|
)
|
||||||
db.commit()
|
)
|
||||||
db.close()
|
session.commit()
|
||||||
|
|
||||||
return username, password
|
return username, password
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import sqlite3
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from utils.config import JELLYFIN_URL, JELLYFIN_HEADERS
|
from utils.database import Session
|
||||||
|
from utils.models import JellyfinAccounts
|
||||||
|
from utils.config import LOG, JELLYFIN_URL, JELLYFIN_HEADERS
|
||||||
|
|
||||||
|
|
||||||
def delete_accounts():
|
def delete_accounts():
|
||||||
@ -10,29 +11,36 @@ def delete_accounts():
|
|||||||
Delete Jellyfin accounts that have passed their deletion time
|
Delete Jellyfin accounts that have passed their deletion time
|
||||||
"""
|
"""
|
||||||
# Get all expired Jellyfin accounts
|
# Get all expired Jellyfin accounts
|
||||||
db = sqlite3.connect("data/cordarr.db")
|
with Session() as session:
|
||||||
cursor = db.cursor()
|
jellyfin_user_ids = (
|
||||||
cursor.execute(
|
session.query(JellyfinAccounts.jellyfin_user_id)
|
||||||
"SELECT jellyfin_user_id FROM jellyfin_accounts WHERE"
|
.filter(JellyfinAccounts.deletion_time < datetime.datetime.now())
|
||||||
" deletion_time < ?",
|
.all()
|
||||||
(datetime.datetime.now(),),
|
|
||||||
)
|
|
||||||
jellyfin_user_ids = cursor.fetchall()
|
|
||||||
|
|
||||||
# Delete the Jellyfin accounts
|
|
||||||
for jellyfin_user_id in jellyfin_user_ids:
|
|
||||||
request = requests.delete(
|
|
||||||
f"{JELLYFIN_URL}/Users/{jellyfin_user_id[0]}",
|
|
||||||
headers=JELLYFIN_HEADERS,
|
|
||||||
)
|
)
|
||||||
# If 204 - account deleted
|
|
||||||
# If 404 - account not found
|
|
||||||
# Either way, remove account from database
|
|
||||||
if request.status_code in (404, 204):
|
|
||||||
cursor.execute(
|
|
||||||
"DELETE FROM jellyfin_accounts WHERE jellyfin_user_id = ?",
|
|
||||||
(jellyfin_user_id,),
|
|
||||||
)
|
|
||||||
|
|
||||||
db.commit()
|
# Delete each account
|
||||||
db.close()
|
for jellyfin_user_id in jellyfin_user_ids:
|
||||||
|
print(f"Deleting account {jellyfin_user_id[0]}")
|
||||||
|
try:
|
||||||
|
response = requests.delete(
|
||||||
|
f"{JELLYFIN_URL}/Users/{jellyfin_user_id[0]}",
|
||||||
|
headers=JELLYFIN_HEADERS,
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
# Get the account and delete it
|
||||||
|
account = (
|
||||||
|
session.query(JellyfinAccounts)
|
||||||
|
.filter(
|
||||||
|
JellyfinAccounts.jellyfin_user_id
|
||||||
|
== jellyfin_user_id[0]
|
||||||
|
)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
session.delete(account)
|
||||||
|
except:
|
||||||
|
LOG.error(
|
||||||
|
"Failed deleting Jellyfin account w/ ID"
|
||||||
|
f" {jellyfin_user_id[0]}"
|
||||||
|
)
|
||||||
|
# Commit changes
|
||||||
|
session.commit()
|
||||||
|
31
code/utils/models.py
Normal file
31
code/utils/models.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
from sqlalchemy import (
|
||||||
|
Column,
|
||||||
|
Integer,
|
||||||
|
String,
|
||||||
|
DateTime,
|
||||||
|
BigInteger,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
from utils.database import Base
|
||||||
|
|
||||||
|
|
||||||
|
class Requests(Base):
|
||||||
|
__tablename__ = "requests"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
title = Column(String)
|
||||||
|
release_year = Column(Integer)
|
||||||
|
local_id = Column(Integer)
|
||||||
|
tmdbid = Column(Integer)
|
||||||
|
tvdbid = Column(Integer)
|
||||||
|
user_id = Column(BigInteger)
|
||||||
|
|
||||||
|
|
||||||
|
class JellyfinAccounts(Base):
|
||||||
|
__tablename__ = "jellyfin_accounts"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
user_id = Column(BigInteger)
|
||||||
|
jellyfin_user_id = Column(String)
|
||||||
|
deletion_time = Column(DateTime)
|
@ -4,4 +4,5 @@ wonderwords==2.2.0
|
|||||||
PyYAML==6.0.2
|
PyYAML==6.0.2
|
||||||
jsonschema==4.23.0
|
jsonschema==4.23.0
|
||||||
jsonschema-specifications==2024.10.1
|
jsonschema-specifications==2024.10.1
|
||||||
discord.py==2.4.0
|
discord.py==2.4.0
|
||||||
|
SQLAlchemy==2.0.37
|
Loading…
x
Reference in New Issue
Block a user