diff --git a/.gitignore b/.gitignore index 0ecf766..db1f598 100644 --- a/.gitignore +++ b/.gitignore @@ -98,11 +98,3 @@ ENV/ # mypy .mypy_cache/ -# Personal Files -config.ini -defaults.ini -fanfiction_file -notifications.py -personal.ini -run.sh - diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..380fb3f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,77 @@ +FROM python:3.9-alpine + +# set version label +ARG BUILD_DATE +ARG VERSION +ARG CALIBRE_RELEASE +ARG FFF_RELEASE +LABEL build_version="FFDL-Auto version:- ${VERSION} Calibre: ${CALIBRE_RELEASE} FFF: ${FFF_RELEASE} Build-date:- ${BUILD_DATE}" + +RUN set -x && \ + addgroup --gid "$PGID" abc && \ + adduser \ + --gecos "" \ + --disabled-password \ + --no-create-home \ + --uid "$PUID" \ + --ingroup abc \ + --shell /bin/bash \ + abc + +RUN mkdir -p /opt/calibre && \ + apk update && \ + apk add --no-cache --upgrade \ + bash \ + ca-certificates \ + gcc \ + mesa-gl \ + qt5-qtbase-x11 \ + wget \ + xdg-utils \ + xz \ + curl \ + dbus \ + jq \ + python3 + +RUN echo "**** install calibre ****" && \ + mkdir -p \ + /opt/calibre && \ + if [ -z ${CALIBRE_RELEASE+x} ]; then \ + CALIBRE_RELEASE=$(curl -sX GET "https://api.github.com/repos/kovidgoyal/calibre/releases/latest" \ + | jq -r .tag_name); \ + fi && \ + CALIBRE_VERSION="$(echo ${CALIBRE_RELEASE} | cut -c2-)" && \ + CALIBRE_URL="https://download.calibre-ebook.com/${CALIBRE_VERSION}/calibre-${CALIBRE_VERSION}-x86_64.txz" && \ + curl -o \ + /tmp/calibre-tarball.txz -L \ + "$CALIBRE_URL" && \ + tar xvf /tmp/calibre-tarball.txz -C \ + /opt/calibre && \ + /opt/calibre/calibre_postinstall && \ + dbus-uuidgen > /etc/machine-id + +RUN echo "**** cleanup ****" && \ + apt-get clean && \ + rm -rf \ + /tmp/* \ + /var/lib/apt/lists/* \ + /var/tmp/* + +RUN echo *** Install Packages *** && \ + apk add --no-cache --upgrade py-pillow && \ + if [ -z ${FFF_RELEASE+x} ]; then \ + python3 -m pip --no-cache-dir install FanFicFare \ + else \ + python3 -m pip --no-cache-dir install --extra-index-url https://testpypi.python.org/pypi FanFicFare==${FFF_RELEASE} \ + fi && \ + python3 -m pip --no-cache-dir install pushbullet.py && \ + ln -s /opt/calibre/calibredb /bin/calibredb + +COPY root/ / + +VOLUME /config + +WORKDIR /config + +ENTRYPOINT ["/init"] diff --git a/README.md b/README.md deleted file mode 100644 index 73848b8..0000000 --- a/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# AutomatedFanfic - -Python script to automate the use of FanFicFare CLI (https://github.com/JimmXinu/FanFicFare) with calibre. - -Primary script is fanficdownload.py. Use -h or --help to see the options. - -All of the options can be loaded into the config file, of which the template is provided in `config_template.ini`, and utilized with `python3 fanficdownload.py -c path_to_config.ini`. - -There is additional support for notifications, including pushbullet integration, through runner_notify. Use -h to see options. - -Works with Fanficfare 2.3.6+. Rewrite underway to take advantage of new features in Fanficfare 2.4.0 - -Requires Python 3.6.9. Unsure if it will work on higher versions of Python. - -For basic cron usage, this is not needed, `fanficfare -dowload-imap -u` should work if you're not integrating into calibre. This script is best used if you want to update the calibre library, for the usage of calibre-server for instance. - -If anything does not work, please open a ticket. \ No newline at end of file diff --git a/balloonNotify.py b/balloonNotify.py deleted file mode 100755 index a857d61..0000000 --- a/balloonNotify.py +++ /dev/null @@ -1,85 +0,0 @@ -# -- coding: utf-8 -- - -from win32api import * -from win32gui import * -import win32con -import sys, os -import struct -import time -import threading -import cmd -from os.path import join, dirname, abspath - -# Class -class WindowsBalloonTip: - def __init__(self, title, msg): - message_map = { win32con.WM_DESTROY: self.OnDestroy,} - - # Register the window class. - wc = WNDCLASS() - hinst = wc.hInstance = GetModuleHandle(None) - wc.lpszClassName = 'PythonTaskbar' - wc.lpfnWndProc = message_map # could also specify a wndproc. - while True: - try: - classAtom = RegisterClass(wc) - break - except: - continue - # Create the window. - style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU - self.hwnd = CreateWindow(classAtom, "Taskbar", style, 0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT, 0, 0, hinst, None) - UpdateWindow(self.hwnd) - - # Icons managment - iconPathName = join(dirname(abspath(__file__)), 'ff.png') - #print iconPathName - icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE - try: - hicon = LoadImage(hinst, iconPathName, win32con.IMAGE_ICON, 0, 0, icon_flags) - except: - hicon = LoadIcon(0, win32con.IDI_APPLICATION) - flags = NIF_ICON | NIF_MESSAGE | NIF_TIP - nid = (self.hwnd, 0, flags, win32con.WM_USER+20, hicon, 'Tooltip') - - # Notify - Shell_NotifyIcon(NIM_ADD, nid) - Shell_NotifyIcon(NIM_MODIFY, (self.hwnd, 0, NIF_INFO, win32con.WM_USER+20, hicon, 'Balloon Tooltip', msg, 200, title)) - - # self.show_balloon(title, msg) - time.sleep(5) - - # Destroy - DestroyWindow(self.hwnd) - classAtom = UnregisterClass(classAtom, hinst) - def OnDestroy(self, hwnd, msg, wparam, lparam): - nid = (self.hwnd, 0) - Shell_NotifyIcon(NIM_DELETE, nid) - #PostQuitMessage(0) # Terminate the app. - -# Function - -class myThread(threading.Thread): - def __init__(self, title, msg): - - threading.Thread.__init__(self) - self.title = title - self.msg = msg - def run(self): - w = WindowsBalloonTip(self.title, self.msg) - - -def balloon_tip(title, msg): - - thread1 = myThread(title, msg) - thread1.start() - return - #w=WindowsBalloonTip(title, msg) - -class Notification(): - def __init__(self): - pass - - def send_notification(self, title, text): - balloon_tip(title, msg) - diff --git a/config_template.ini b/config_template.ini deleted file mode 100644 index 3d7ad91..0000000 --- a/config_template.ini +++ /dev/null @@ -1,27 +0,0 @@ -# Email Login Information, so that the script can download from email subscription notifications. -[login] -# Username for email -user= -# Password for email -password= -# IMAP address for email -server= -# The mailbox to look in the emails for, such as INBOX -mailbox= - -[locations] -# Web Address for the calibre library to update -library= -# Path to file to read links from, or to output links that didn't work. -input= - -# If you want to user runner_notify.py to send alerts to your phone, fill out the fields here. -[runner] -notification= -pushbullet= -pbdevice= -tag= - -# How to display output. True will display as the program runs, false will wait until the end. -[output] -live= diff --git a/ff.png b/ff.png deleted file mode 100644 index 413cb46..0000000 Binary files a/ff.png and /dev/null differ diff --git a/giNotify.py b/giNotify.py deleted file mode 100644 index 3158cd4..0000000 --- a/giNotify.py +++ /dev/null @@ -1,21 +0,0 @@ -from gi import require_version as gir - -gir('Notify', '0.7') - -from gi.repository import GObject -from gi.repository import Notify -import sys -from os.path import join, dirname, abspath - -class Notification(GObject.Object): - def __init__(self): - - super(Notification, self).__init__() - # lets initialise with the application name - Notify.init("Fanfiction") - self.icon = join(dirname(abspath(__file__)), 'ff.png') - - def send_notification(self, title, text): - - n = Notify.Notification.new(title, text, self.icon) - n.show() diff --git a/release-versions/calibre.txt b/release-versions/calibre.txt new file mode 100644 index 0000000..d47ce0c --- /dev/null +++ b/release-versions/calibre.txt @@ -0,0 +1 @@ +5.39.1 \ No newline at end of file diff --git a/release-versions/fff.txt b/release-versions/fff.txt new file mode 100644 index 0000000..012d0f0 --- /dev/null +++ b/release-versions/fff.txt @@ -0,0 +1 @@ +4.11.1 \ No newline at end of file diff --git a/release-versions/latest.txt b/release-versions/latest.txt new file mode 100644 index 0000000..06d48f1 --- /dev/null +++ b/release-versions/latest.txt @@ -0,0 +1 @@ +Release: v2022.02.25 \ No newline at end of file diff --git a/fanficdownload.py b/root/app/fanficdownload.py similarity index 93% rename from fanficdownload.py rename to root/app/fanficdownload.py index 124c750..bd9df46 100644 --- a/fanficdownload.py +++ b/root/app/fanficdownload.py @@ -149,11 +149,12 @@ def downloader(args): # story is not in calibre cur = url moving = 'cd "{}" && '.format(loc) - copyfile("personal.ini", "{}/personal.ini".format(loc)) - output += log('\tRunning: {}python -m fanficfare.cli -u "{}" --update-cover --non-interactive'.format( + copyfile("/config/personal.ini", "{}/personal.ini".format(loc)) + copyfile("/config/defaults.ini", "{}/defaults.ini".format(moving)) + output += log('\tRunning: {}python3.9 -m fanficfare.cli -u "{}" --update-cover --non-interactive'.format( moving, cur), 'BLUE', live) - res = check_output('{}python -m fanficfare.cli -u "{}" --update-cover'.format( - moving, cur), shell=True, stderr=STDOUT, stdin=PIPE).decode('utf-8') + res = check_output('{}python3.9 -m fanficfare.cli -u "{}" --update-cover --non-interactive --config={}/personal.ini'.format( + moving, cur, loc), shell=True, stderr=STDOUT, stdin=PIPE).decode('utf-8') check_regexes(res) if chapter_difference.search(res) or more_chapters.search(res): output += log("\tForcing download update due to:", @@ -162,8 +163,8 @@ def downloader(args): if line: output += log("\t\t{}".format(line), 'WARNING', live) res = check_output( - '{}python -m fanficfare.cli -u "{}" --force --update-cover --non-interactive'.format( - moving, cur), shell=True, stderr=STDOUT, stdin=PIPE).decode('utf-8') + '{}python3.9 -m fanficfare.cli -u "{}" --force --update-cover --non-interactive --config={}/personal.ini'.format( + moving, cur, loc), shell=True, stderr=STDOUT, stdin=PIPE).decode('utf-8') check_regexes(res) cur = get_files(loc, '.epub', True)[0] @@ -275,9 +276,12 @@ def main(user, password, server, label, inout_file, path, live): if len(urls) == 1: downloader([list(urls)[0], inout_file, path, True]) else: - p = Pool() - p.map(downloader, [[url, inout_file, path, live] for url in urls]) - + for url in urls: + downloader([url, inout_file, path, True]) + with open(inout_file, "r") as fp: + urls = set([x.replace("\n", "") for x in fp.readlines()]) + with open(inout_file, "w") as fp: + fp.writelines(["{}\n".format(x) for x in urls]) return diff --git a/root/app/notifications.py b/root/app/notifications.py new file mode 100644 index 0000000..340f772 --- /dev/null +++ b/root/app/notifications.py @@ -0,0 +1,8 @@ +class Notification(): + def __init__(self): + + self.name="Fanfiction" + + def send_notification(self, title, text): + return + diff --git a/root/app/run.sh b/root/app/run.sh new file mode 100644 index 0000000..77e0c8c --- /dev/null +++ b/root/app/run.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +function fix_linux_internal_host() { + DOCKER_INTERNAL_HOST="host.docker.internal" + + if ! grep $DOCKER_INTERNAL_HOST /etc/hosts > /dev/null ; then + DOCKER_INTERNAL_IP=`/sbin/ip route | awk '/default/ { print $3 }' | awk '!seen[$0]++'` + echo -e "$DOCKER_INTERNAL_IP\t$DOCKER_INTERNAL_HOST" | tee -a /etc/hosts > /dev/null + fi +} + +fix_linux_internal_host + +python3 runner_notify.py -c config.ini +sleep 60 + diff --git a/runner_notify.py b/root/app/runner_notify.py similarity index 93% rename from runner_notify.py rename to root/app/runner_notify.py index e98de11..cd8980a 100644 --- a/runner_notify.py +++ b/root/app/runner_notify.py @@ -7,13 +7,11 @@ import ntpath from os import utime from os.path import join -from notifications import Notification from pushbullet import Pushbullet from optparse import OptionParser from configparser import ConfigParser - def enable_notifications(options): if options.pushbullet: fail = False @@ -34,10 +32,6 @@ def enable_notifications(options): temp_note.send_notification = pb.push_note yield temp_note - if options.notify: - notary = Notification() - yield notary - def touch(fname, times=None): with open(fname, 'a'): @@ -47,7 +41,7 @@ def touch(fname, times=None): def main(options): try: res = check_output( - "python3 fanficdownload.py -c config.ini", + "python3.9 fanficdownload.py -c config.ini", shell=True, stderr=STDOUT) except Exception as e: @@ -134,13 +128,6 @@ if __name__ == "__main__": def updater(option, newval): return newval if newval != "" else option - try: - options.notify = updater( - options.notify, config.getboolean( - 'runner', 'notification')) - except BaseException: - pass - try: options.pushbullet = updater( options.pushbullet, config.get( diff --git a/root/config.default/config.ini b/root/config.default/config.ini new file mode 100644 index 0000000..faacc91 --- /dev/null +++ b/root/config.default/config.ini @@ -0,0 +1,16 @@ +[login] +user= +password= +server= +mailbox= + +[locations] +library= +input=/config/fanfiction_file + +[runner] +pushbullet=False +pbdevice= + +[output] +live=False diff --git a/root/config.default/defaults.ini b/root/config.default/defaults.ini new file mode 100644 index 0000000..b45ac5e --- /dev/null +++ b/root/config.default/defaults.ini @@ -0,0 +1,2372 @@ +# Copyright 2015 Fanficdownloader team, 2016 FanFicFare team +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +[defaults] + +## [defaults] section applies to all formats and sites but may be +## overridden at several levels. Example: + +## [defaults] +## titlepage_entries: category,genre, status +## [www.whofic.com] +## # overrides defaults. +## titlepage_entries: category,genre, status,dateUpdated,rating +## [epub] +## # overrides defaults & site section +## titlepage_entries: category,genre, status,datePublished,dateUpdated,dateCreated +## [www.whofic.com:epub] +## # overrides defaults, site section & format section +## titlepage_entries: category,genre, status,datePublished +## [overrides] +## # overrides all other sections +## titlepage_entries: category + +## Some sites also require the user to confirm they are adult for +## adult content. Uncomment by removing '#' in front of is_adult. +is_adult:true + +## All available titlepage_entries and the label used for them: +## _label: