From c511d2dc98ccebfae21d488283f41ccc791965c3 Mon Sep 17 00:00:00 2001 From: Jeremy Hansen Date: Sat, 15 Jul 2023 17:24:53 +0700 Subject: [PATCH] multimedia/sickchill: Added (Video Library Manager). Signed-off-by: Willy Sudiarto Raharjo --- multimedia/sickchill/README | 32 ++++ multimedia/sickchill/config.ini | 3 + multimedia/sickchill/doinst.sh | 27 +++ multimedia/sickchill/rc.sickchill | 118 +++++++++++++ multimedia/sickchill/sickchill.SlackBuild | 111 ++++++++++++ multimedia/sickchill/sickchill.conf | 6 + multimedia/sickchill/sickchill.info | 10 ++ multimedia/sickchill/slack-desc | 19 ++ .../sickchill/use-older-SQLAlchemy.patch | 167 ++++++++++++++++++ 9 files changed, 493 insertions(+) create mode 100644 multimedia/sickchill/README create mode 100644 multimedia/sickchill/config.ini create mode 100644 multimedia/sickchill/doinst.sh create mode 100644 multimedia/sickchill/rc.sickchill create mode 100644 multimedia/sickchill/sickchill.SlackBuild create mode 100644 multimedia/sickchill/sickchill.conf create mode 100644 multimedia/sickchill/sickchill.info create mode 100644 multimedia/sickchill/slack-desc create mode 100644 multimedia/sickchill/use-older-SQLAlchemy.patch diff --git a/multimedia/sickchill/README b/multimedia/sickchill/README new file mode 100644 index 0000000000..bd6ad6e1f8 --- /dev/null +++ b/multimedia/sickchill/README @@ -0,0 +1,32 @@ +sickchill (Less rage, more chill.) + +Automatic Video Library Manager for TV Shows. It watches for new +episodes of your favorite shows, and when they are posted it does its +magic. + +NOTE: Requires sickchill user and group. + groupadd -g 377 sickchill + useradd -u 377 -g sickchill -d /var/lib/sickchill -s /bin/false sickchill + +If you previously had sickrage installed, please change the user and +group with the following: + + groupmod -n sickchill sickrage + usermod -l sickchill -g sickchill -d /var/lib/sickchill sickrage + +To have this start up with Slackware, please add the following to your +/etc/rc.d/rc.local: + +# Start sickrage +if [ -x /etc/rc.d/rc.sickrage ]; then + /etc/rc.d/rc.sickrage start +fi + +If you want it to shut down properly when Slackware restarts or shuts +down, please add the following to your /etc/rc.d/rc.local_shutdown +(it may need to be created): + +# Stop sickrage +if [ -x /etc/rc.d/rc.sickrage ]; then + /etc/rc.d/rc.sickrage stop +fi diff --git a/multimedia/sickchill/config.ini b/multimedia/sickchill/config.ini new file mode 100644 index 0000000000..b2e8361381 --- /dev/null +++ b/multimedia/sickchill/config.ini @@ -0,0 +1,3 @@ +[General] +log_dir = /var/log/sickchill +version_notify = 0 diff --git a/multimedia/sickchill/doinst.sh b/multimedia/sickchill/doinst.sh new file mode 100644 index 0000000000..26340579ec --- /dev/null +++ b/multimedia/sickchill/doinst.sh @@ -0,0 +1,27 @@ +config() { + NEW="$1" + OLD="$(dirname $NEW)/$(basename $NEW .new)" + # If there's no config file by that name, mv it over: + if [ ! -r $OLD ]; then + mv $NEW $OLD + elif [ "$(cat $OLD | md5sum)" = "$(cat $NEW | md5sum)" ]; then + # toss the redundant copy + rm $NEW + fi + # Otherwise, we leave the .new copy for the admin to consider... +} + +preserve_perms() { + NEW="$1" + OLD="$(dirname $NEW)/$(basename $NEW .new)" + if [ -e $OLD ]; then + cp -a $OLD ${NEW}.incoming + cat $NEW > ${NEW}.incoming + mv ${NEW}.incoming $NEW + fi + config $NEW +} + +preserve_perms etc/rc.d/rc.sickchill.new +config etc/sickchill.conf.new +config var/lib/sickchill/config.ini.new diff --git a/multimedia/sickchill/rc.sickchill b/multimedia/sickchill/rc.sickchill new file mode 100644 index 0000000000..bb89629a9c --- /dev/null +++ b/multimedia/sickchill/rc.sickchill @@ -0,0 +1,118 @@ +#!/bin/bash +# Start/stop/restart sickchill. + +# rc.sickrage created by Jeremy Hansen for Slackware in 2016 +# rc.sickchill was updated by Jeremy Hansen for Slackware in 2023 + +# Set program name in case you want to run sick{beard|rage|gear|etc} +PROG=${PROG:-sickchill} + +# Source SickRage configuration +if [ -f /etc/"$PROG".conf ]; then + . /etc/"$PROG".conf +fi + +# Ensure all required variables are set in conf file +# Edit conf file in /etc/sickchill.conf for any changes +for var in USERNAME HOMEDIR DATADIR PIDFILE PORT; do + if [ -z "${!var}" ]; then + echo "/etc/$PROG.conf is missing some or all required variables ($var)." + echo "Please check the file and try again." + exit 1 + fi +done + +# Check if the program is running and pid file exists +check() { + if pgrep "$PROG" > /dev/null; then + if [ -e "$PIDFILE" ] && ! pgrep -F "$PIDFILE" > /dev/null; then + STATUS=broken + echo "WARNING: $PROG is running, but its PID does not match the one in $PIDFILE." + elif [ ! -e "$PIDFILE" ]; then + STATUS=broken + echo "WARNING: $PROG is running, but $PIDFILE does not exist." + echo "Maybe you ran $PROG from the commandline rather than rc.sickchill?" + else + STATUS=running + fi + else + if [ -e "$PIDFILE" ]; then + STATUS=broken + echo "WARNING: $PROG is not running but $PIDFILE exists." + else + STATUS=stopped + fi + fi +} + +status() { + if [ $STATUS == "running" ]; then + echo "$PROG currently running." + elif [ $STATUS == "stopped" ]; then + echo "$PROG not running." + elif [ $STATUS == "broken" ]; then + echo "Please fix the issue before attempting to run $(basename "$0") again." + else + echo "Status unknown." + fi +} + +start() { + if [ $STATUS == "running" ]; then + echo "$PROG already running or not shut down properly." + else + echo -n "Starting $PROG: " + if su "$USERNAME" -s /bin/sh -c "/usr/bin/sickchill --daemon --pidfile=${PIDFILE} --datadir=${DATADIR} --port=${PORT} &> /dev/null"; then + echo "Startup Successful" + else + echo "Startup Failed. Please try running the following to see the errors." + echo "su $USERNAME -s /bin/sh -c \"/usr/bin/sickchill --daemon --pidfile=${PIDFILE} --datadir=${DATADIR} --port=${PORT}\"" + fi + fi +} + +stop() { + if [ $STATUS == "stopped" ]; then + echo "$PROG doesn't seem to be running. Please try running" + echo "$0 start" + elif [ $STATUS == "broken" ]; then + echo "Cannot stop. Please correct issue and try again." + else + if [ "$EUID" -ne 0 ];then + echo "Please run as root" + exit 1 + fi + PID=$(cat "$PIDFILE") + echo -n $"Shutting down $PROG: " + if ! curl -s http://localhost:"$PORT"/home/shutdown/?pid="$PID" | grep -q "shutting down"; then + echo "Normal Shutdown Failed - Attempting to kill the process." + sleep 7 + kill -9 "$PID" + else + echo "Shutdown Successful" + fi + fi +} + +case "$1" in + start) + check + start + ;; + stop) + check + stop + ;; + restart) + check + stop + start + ;; + status) + check + status + ;; + *) + echo "Usage: $0 {start|stop|restart|status}" + exit 1 +esac diff --git a/multimedia/sickchill/sickchill.SlackBuild b/multimedia/sickchill/sickchill.SlackBuild new file mode 100644 index 0000000000..19464ff0f0 --- /dev/null +++ b/multimedia/sickchill/sickchill.SlackBuild @@ -0,0 +1,111 @@ +#!/bin/bash + +# Slackware build script for sickchill + +# Copyright 2023 Jeremy Hansen jebrhansen+SBo@gmail.com +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +cd $(dirname $0) ; CWD=$(pwd) + +PRGNAM=sickchill +VERSION=${VERSION:-2023.6.27} +BUILD=${BUILD:-1} +TAG=${TAG:-_SBo} +PKGTYPE=${PKGTYPE:-tgz} + +if [ -z "$ARCH" ]; then + case "$( uname -m )" in + i?86) ARCH=i586 ;; + arm*) ARCH=arm ;; + *) ARCH=$( uname -m ) ;; + esac +fi + +SICKUSER=${SICKUSER:-sickchill} +SICKGROUP=${SICKGROUP:-sickchill} + +# The user and group accounts need to be created manually. +# For slackbuilds.org, assigned sickchill uid/gid are 377/377 +# See http://slackbuilds.org/uid_gid.txt +if ! grep ^$SICKGROUP: /etc/group 2>&1 > /dev/null; then + echo " You must have a \"$SICKGROUP\" group to run this script." + echo " # groupadd -g 377 $SICKGROUP" + echo " If you previously had sickrage installed, change the group using" + echo " # groupmod -n sickchill sickrage" + exit 1 +elif ! grep ^$SICKUSER: /etc/passwd 2>&1 > /dev/null; then + echo " You must have a \"$SICKUSER\" user to run this script." + echo " # useradd -u 377 -g $SICKGROUP -d /var/lib/sickchill -s /bin/false $SICKUSER" + echo " If you previously had sickrage installed, change the user using" + echo " # usermod -l sickchill -g sickchill -d /var/lib/sickchill sickrage" + exit 1 +fi + +if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then + echo "$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE" + exit 0 +fi + +TMP=${TMP:-/tmp/SBo} +PKG=$TMP/package-$PRGNAM +OUTPUT=${OUTPUT:-/tmp} + +set -e + +rm -rf $PKG +mkdir -p $TMP $PKG $OUTPUT +cd $TMP +rm -rf $PRGNAM-$VERSION +tar xvf $CWD/$PRGNAM-$VERSION.tar.gz +cd $PRGNAM-$VERSION +chown -R root:root . +find -L . \ + \( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \ + -o -perm 511 \) -exec chmod 755 {} \; -o \ + \( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \ + -o -perm 440 -o -perm 400 \) -exec chmod 644 {} \; + +# Revert changes that require SQLAlchmey > 2.0 until SBo catches up +patch -p1 < $CWD/use-older-SQLAlchemy.patch + +python3 -m build --wheel --no-isolation +python3 -m installer --destdir=$PKG dist/*.whl + +find $PKG -print0 | xargs -0 file | grep -e "executable" -e "shared object" | grep ELF \ + | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true + +mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION +cp -a \ + COPYING.txt LICENSE.md README.md SECURITY.md \ + $PKG/usr/doc/$PRGNAM-$VERSION +cat $CWD/$PRGNAM.SlackBuild > $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild + +mkdir -p $PKG/etc/rc.d/ +install -m 0644 $CWD/rc.sickchill $PKG/etc/rc.d/rc.sickchill.new +install -m 0644 $CWD/sickchill.conf $PKG/etc/sickchill.conf.new +install -dm 0755 --owner=$SICKUSER $PKG/var/lib/sickchill/ +install -m 0644 --owner=$SICKUSER $CWD/config.ini $PKG/var/lib/sickchill/config.ini.new +install -dm 0755 --owner=$SICKUSER $PKG/var/log/sickchill/ + +mkdir -p $PKG/install +cat $CWD/slack-desc > $PKG/install/slack-desc +cat $CWD/doinst.sh > $PKG/install/doinst.sh + +cd $PKG +/sbin/makepkg -l y -c n $OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD$TAG.$PKGTYPE diff --git a/multimedia/sickchill/sickchill.conf b/multimedia/sickchill/sickchill.conf new file mode 100644 index 0000000000..e63d927d91 --- /dev/null +++ b/multimedia/sickchill/sickchill.conf @@ -0,0 +1,6 @@ +USERNAME=sickchill +HOMEDIR=/usr/share/sickchill +DATADIR=/var/lib/sickchill +PIDFILE=${DATADIR}/sickchill.pid +PORT=8081 +LOGDIR=/var/log/sickchill \ No newline at end of file diff --git a/multimedia/sickchill/sickchill.info b/multimedia/sickchill/sickchill.info new file mode 100644 index 0000000000..f98d98f594 --- /dev/null +++ b/multimedia/sickchill/sickchill.info @@ -0,0 +1,10 @@ +PRGNAM="sickchill" +VERSION="2023.6.27" +HOMEPAGE="https://sickchill.github.io/" +DOWNLOAD="https://github.com/SickChill/sickchill/archive/refs/tags/2023.6.27/sickchill-2023.6.27.tar.gz" +MD5SUM="e38394951cead23e349470c48706fa7e" +DOWNLOAD_x86_64="" +MD5SUM_x86_64="" +REQUIRES="python3-poetry-core python3-PyGithub rarfile python3-ifaddr python3-cacheyou python3-tornado Unidecode python-gntp python3-kodipydent python3-cinemagoer python3-validators python3-bencode python-jsonrpclib python3-markdown2 python3-guessit subliminal twitter requests-oauthlib configobj imagesize python3-tvdbsimple python3-fanart python3-tmdbsimple python3-slugify send2trash pyOpenSSL pymediainfo python3-putio.py python3-pynma python3-deluge-client python3-qbittorrent-api python3-new-rtorrent" +MAINTAINER="Jeremy Hansen" +EMAIL="jebrhansen+SBo@gmail.com" diff --git a/multimedia/sickchill/slack-desc b/multimedia/sickchill/slack-desc new file mode 100644 index 0000000000..af844946bf --- /dev/null +++ b/multimedia/sickchill/slack-desc @@ -0,0 +1,19 @@ +# HOW TO EDIT THIS FILE: +# The "handy ruler" below makes it easier to edit a package description. +# Line up the first '|' above the ':' following the base package name, and +# the '|' on the right side marks the last column you can put a character in. +# You must make exactly 11 lines for the formatting to be correct. It's also +# customary to leave one space after the ':' except on otherwise blank lines. + + |-----handy-ruler------------------------------------------------------| +sickchill: sickchill (Less rage, more chill.) +sickchill: +sickchill: Automatic Video Library Manager for TV Shows. It watches for new +sickchill: episodes of your favorite shows, and when they are posted it does +sickchill: its magic. +sickchill: +sickchill: HOMEPAGE: https://sickchill.github.io/ +sickchill: +sickchill: +sickchill: +sickchill: diff --git a/multimedia/sickchill/use-older-SQLAlchemy.patch b/multimedia/sickchill/use-older-SQLAlchemy.patch new file mode 100644 index 0000000000..4ab716afa2 --- /dev/null +++ b/multimedia/sickchill/use-older-SQLAlchemy.patch @@ -0,0 +1,167 @@ +diff --git a/sickchill/oldbeard/databases/movie.py b/sickchill/oldbeard/databases/movie.py +index 3598dcc..52000a3 100644 +--- a/sickchill/oldbeard/databases/movie.py ++++ b/sickchill/oldbeard/databases/movie.py +@@ -4,45 +4,43 @@ from typing import List + + import guessit + from slugify import slugify +-from sqlalchemy import ForeignKey, JSON ++from sqlalchemy import Boolean, Column, Date, DateTime, ForeignKey, Integer, Interval, JSON, SmallInteger, String + from sqlalchemy.event import listen + from sqlalchemy.ext.declarative import declarative_base +-from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, sessionmaker ++from sqlalchemy.orm import relationship, sessionmaker + + logger = logging.getLogger("sickchill.movie") + +- +-class Base(DeclarativeBase): +- """Declarative Base Class""" +- ++Base = declarative_base() + + Session = sessionmaker() + + + class Movie(Base): + __tablename__ = "movie" +- pk: Mapped[int] = mapped_column(primary_key=True) +- name: Mapped[str] +- date: Mapped[datetime.date] +- year: Mapped[int] +- status: Mapped[int] +- paused: Mapped[bool] = mapped_column(default=False) +- location: Mapped[str] +- start: Mapped[datetime.timedelta] = mapped_column(default=datetime.timedelta(days=-7)) +- interval: Mapped[datetime.timedelta] = mapped_column(default=datetime.timedelta(days=1)) +- added: Mapped[datetime.datetime] = mapped_column(default=datetime.datetime.now) +- updated: Mapped[datetime.datetime] = mapped_column(onupdate=datetime.datetime.now) +- completed: Mapped[datetime.datetime] +- searched: Mapped[datetime.datetime] +- slug: Mapped[str] +- +- language: Mapped[str] +- +- result_pk: Mapped[int] = mapped_column(ForeignKey("result.pk")) +- results: Mapped[List["Result"]] = relationship(backref="movie") +- +- images: Mapped[List["Images"]] = relationship(backref="movie") +- indexer_data: Mapped[List["IndexerData"]] = relationship(backref="movie") ++ ++ pk = Column(Integer, primary_key=True) ++ name = Column(String) ++ date = Column(Date) ++ year = Column(SmallInteger) ++ status = Column(Integer) ++ paused = Column(Boolean, default=False) ++ location = Column(String) ++ start = Column(Interval, default=datetime.timedelta(days=-7)) ++ interval = Column(Interval, default=datetime.timedelta(days=1)) ++ added = Column(DateTime, default=datetime.datetime.now) ++ updated = Column(DateTime, onupdate=datetime.datetime.now) ++ completed = Column(DateTime) ++ searched = Column(DateTime) ++ slug = Column(String) ++ ++ language = Column(String) ++ ++ result_pk = Column(Integer, ForeignKey("result.pk")) ++ results: list = relationship("Result", backref="movie") ++ ++ images: list = relationship("Images", backref="movie") ++ indexer_data: list = relationship("IndexerData", backref="movie") + + def __init__(self, name: str, year: int): + self.name = name +@@ -134,21 +132,21 @@ listen(Movie.name, "set", Movie.slugify, retval=False) + + class Result(Base): + __tablename__ = "result" +- pk: Mapped[int] = mapped_column(primary_key=True) +- name: Mapped[str] +- title: Mapped[str] +- url: Mapped[str] +- size: Mapped[int] +- year: Mapped[int] +- provider: Mapped[str] +- seeders: Mapped[int] +- leechers: Mapped[int] +- info_hash: Mapped[str] +- group: Mapped[str] +- kind: Mapped[str] +- guess = mapped_column(JSON) +- found: Mapped[datetime.datetime] = mapped_column(default=datetime.datetime.now) +- updated: Mapped[datetime.datetime] = mapped_column(onupdate=datetime.datetime.now) ++ pk = Column(Integer, primary_key=True) ++ name = Column(String) ++ title = Column(String) ++ url = Column(String) ++ size = Column(Integer) ++ year = Column(SmallInteger) ++ provider = Column(String) ++ seeders = Column(Integer) ++ leechers = Column(Integer) ++ info_hash = Column(String) ++ group = Column(String) ++ type = Column(String) ++ guess = Column(JSON) ++ found = Column(DateTime, default=datetime.datetime.now) ++ updated = Column(DateTime, onupdate=datetime.datetime.now) + + session = Session() + +@@ -172,7 +170,7 @@ class Result(Base): + self.leechers = result["leechers"] + self.size = result["size"] + self.year = guess["year"] or movie.year +- self.kind = provider.provider_type ++ self.type = provider.provider_type + + self.provider = provider.get_id() + +@@ -187,12 +185,12 @@ class Result(Base): + class Images(Base): + __tablename__ = "images" + +- url: Mapped[str] = mapped_column(primary_key=True) +- path: Mapped[str] +- site: Mapped[str] +- style: Mapped[int] ++ url = Column(String, primary_key=True) ++ path = Column(String) ++ site = Column(String) ++ style = Column(Integer) + +- movie_pk: Mapped[int] = mapped_column(ForeignKey("movie.pk")) ++ movie_pk = Column(Integer, ForeignKey("movie.pk")) + + def __init__(self, site: str, movie_pk: int, url: str, path: str, style: int): + self.url = url +@@ -204,13 +202,13 @@ class Images(Base): + + class IndexerData(Base): + __tablename__ = "indexer_data" +- pk: Mapped[str] = mapped_column(primary_key=True) +- site: Mapped[str] +- data = mapped_column(JSON) ++ pk = Column(String, primary_key=True) ++ site = Column(String) ++ data = Column(JSON) + +- movie_pk: Mapped[int] = mapped_column(ForeignKey("movie.pk")) ++ movie_pk = Column(Integer, ForeignKey("movie.pk")) + +- genres: Mapped[List["Genres"]] = relationship(backref="indexer_data") ++ genres: list = relationship("Genres", backref="indexer_data") + + def __repr__(self): + return f"[{self.__tablename__.replace('_', ' ').title()}] {self.site}: {self.pk} - {self.movie.name}" +@@ -218,5 +216,5 @@ class IndexerData(Base): + + class Genres(Base): + __tablename__ = "genres" +- pk: Mapped[str] = mapped_column(primary_key=True) +- indexer_data_pk: Mapped[int] = mapped_column(ForeignKey("indexer_data.pk")) ++ pk = Column(String, primary_key=True) ++ indexer_data_pk = Column(Integer, ForeignKey("indexer_data.pk"))