Skip to content

Commit 4ce154d

Browse files
authored
Merge pull request #25 from burkasaurusrex/master
Docker initial commit
2 parents 8d36c41 + 60e8579 commit 4ce154d

24 files changed

+152
-163
lines changed

.dockerignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
**/dist
2+
**/build
3+
*.spec
4+
**/__pycache__
5+
/.vscode
6+
README.md
7+
.gitignore

.gitignore

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
/config.yml
2-
/dist/config.yml
3-
/venv/
4-
/.gitignore
5-
/.idea
6-
/build
7-
/plex_auto_collections.spec
8-
/__pycache__/
9-
/config-*
1+
config.yml
2+
**/dist
3+
**/build
4+
*.spec
5+
**/__pycache__
106
/.vscode

Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
FROM python:3.7-slim
2+
MAINTAINER burkasaurusrex
3+
VOLUME /config
4+
COPY /app/. /app
5+
COPY /config/. /config
6+
RUN \
7+
echo "**** install system packages ****" && \
8+
apt-get update && \
9+
apt-get upgrade -y && \
10+
apt-get install -y tzdata && \
11+
echo "**** install python packages ****" && \
12+
pip3 install --upgrade --requirement /app/requirements.txt && \
13+
echo "**** install Plex-Auto-Collections ****" && \
14+
chmod +x /app/plex_auto_collections.py && \
15+
echo "**** cleanup ****" && \
16+
apt-get autoremove -y && \
17+
apt-get clean && \
18+
rm -rf \
19+
/app/requirements.txt \
20+
/tmp/* \
21+
/var/tmp/* \
22+
/var/lib/apt/lists/*
23+
WORKDIR /app
24+
ENTRYPOINT ["python3", "plex_auto_collections.py", "--config_path", "/config/config.yml", "--update"]

README.md

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
# Plex Auto Collections
22
![https://i.imgur.com/iHAYFIZ.png](https://i.imgur.com/iHAYFIZ.png)
3-
Plex Auto Collections is a Python 3 script/[standalone builds](https://github.com/vladimir-tutin/Plex-Auto-Collections/tree/master/dist) that
4-
works off a configuration file to create/update Plex collection. Collection management with this tool can be automated
5-
in a varying degree of customizability. Supports IMDB, TMDb, and Trakt lists as well as built in Plex
6-
filters such as actors, genres, year, studio and more. For more filters refer to the
7-
[plexapi.video.Movie](https://python-plexapi.readthedocs.io/en/latest/modules/video.html#plexapi.video.Movie)
8-
documentation. Not everything has been tested, so results may vary based off the filter. A TMDb api key is required to
9-
scan TMDb URLs.
3+
Plex Auto Collections is a Python 3 script that works off a configuration file to create/update Plex collection. Collection management with this tool can be automated in a varying degree of customizability. Supports IMDB, TMDb, and Trakt lists as well as built in Plex filters such as actors, genres, year, studio and more. For more filters refer to the [plexapi.video.Movie](https://python-plexapi.readthedocs.io/en/latest/modules/video.html#plexapi.video.Movie) documentation. Not everything has been tested, so results may vary based off the filter. A TMDb api key is required to scan TMDb URLs.
104

115
When parsing IMDB or TMBd lists the script will create a list of movies that are missing from Plex. If an TMDb and
126
Radarr api-key are supplied then the option will be presented to pass the list of movies along to Radarr. Trakt lists will be matched against items in both a Movie and a TV library, each.
@@ -115,7 +109,17 @@ collections:
115109
details:
116110
summary: A collection of Pixar movies
117111
1990s:
118-
year: [1990,1991,1992,1993,1994,1995,1996,1997,1998,1999]
112+
year:
113+
- 1990
114+
- 1991
115+
- 1992
116+
- 1993
117+
- 1994
118+
- 1995
119+
- 1996
120+
- 1997
121+
- 1998
122+
- 1999
119123
details:
120124
summary: A collection of 1990s movies
121125
plex:
@@ -145,38 +149,19 @@ trakt:
145149
scope:
146150
created_at:
147151
image-server:
148-
host: 192.168.1.41
152+
host: 192.168.1.1
149153
port: 5000
154+
poster-directory: /config/posters
150155
```
151156

152157
# Usage
153-
[Standalone binaries](https://github.com/vladimir-tutin/Plex-Auto-Collections/tree/master/dist) have been created for both Windows and Linux.
154-
155-
If you would like to run from Python I have only tested this fully on Python 3.7.4. Dependencies must be installed by running
158+
Limited testing has been done only on Python 3.7. Dependencies must be installed by running
156159

157160
pip install -r requirements.txt
158161

159-
If there are issues installing PyYAML 1.5.4 try
162+
If there are issues installing PyYAML 1.5.4 or tmdbv3api 1.5.1 try
160163

161164
pip install -r requirements.txt --ignore-installed
162-
163-
Make sure that plexapi is installed from the github source in requirements.txt. The one provided by pip contains a bug
164-
that will cause certain movies to crash the script when processing IMDB lists. To ensure that you are running the of
165-
plexapi check utils.py contains the following around line 172:
166-
167-
def toDatetime(value, format=None):
168-
""" Returns a datetime object from the specified value.
169-
170-
Parameters:
171-
value (str): value to return as a datetime
172-
format (str): Format to pass strftime (optional; if value is a str).
173-
"""
174-
if value and value is not None:
175-
if format:
176-
value = datetime.strptime(value, format)
177-
else:
178-
value = datetime.fromtimestamp(int(value))
179-
return value
180165

181166
To run the script in a terminal run
182167

config_tools.py renamed to app/config_tools.py

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import yaml
44
import requests
55
import socket
6+
import urllib
67
from plexapi.server import PlexServer
78
from plexapi.video import Movie
89
from plexapi.video import Show
@@ -23,12 +24,15 @@ def __init__(self, config_path):
2324
self.config_path = config_path
2425
with open(self.config_path, 'rt', encoding='utf-8') as yml:
2526
self.data = yaml.load(yml, Loader=yaml.FullLoader)
27+
self.collections = self.data['collections']
2628
self.plex = self.data['plex']
2729
self.tmdb = self.data['tmdb']
2830
self.trakt = self.data['trakt']
2931
self.radarr = self.data['radarr']
30-
self.collections = self.data['collections']
31-
self.image_server = self.data['image-server']
32+
if 'image-server' in self.data:
33+
self.image_server = self.data['image-server']
34+
else:
35+
self.image_server = {}
3236

3337

3438
class Plex:
@@ -93,16 +97,44 @@ def __init__(self, config_path):
9397

9498

9599
class ImageServer:
96-
def __init__(self, config_path):
100+
def __init__(self, config_path, mode="server"):
97101
config = Config(config_path).image_server
98-
try:
102+
# Best defaults for "host" are 0.0.0.0 for server and 127.0.0.1 for client
103+
# Set respective defaults in server and client
104+
if 'host' in config:
99105
self.host = config['host']
100-
except:
101-
a = 1
102-
try:
106+
else:
107+
if mode == "server":
108+
self.host = "0.0.0.0"
109+
else:
110+
self.host = "127.0.0.1"
111+
# Set default port
112+
if 'port' in config:
103113
self.port = config['port']
104-
except:
105-
a = 1
114+
else:
115+
self.port = 5000
116+
# Test and set default folder path
117+
if mode == "server":
118+
if 'poster-directory' in config:
119+
self.posterdirectory = config['poster-directory']
120+
else:
121+
app_dir = os.path.dirname(os.path.realpath(__file__))
122+
123+
# Test separate config folder with nested 'posters' folder
124+
if os.path.exists(os.path.join(app_dir, "..", "config", "posters")):
125+
self.posterdirectory = os.path.join("..", "config", "posters")
126+
# Test separate config folder with nested 'images' folder
127+
elif os.path.exists(os.path.join(app_dir, "..", "config", "images")):
128+
self.posterdirectory = os.path.join("..", "config", "images")
129+
# Test nested posters folder
130+
elif os.path.exists(os.path.join(app_dir, "posters")):
131+
self.posterdirectory = "posters"
132+
# Test nested images folder
133+
elif os.path.exists(os.path.join(app_dir, "images")):
134+
self.posterdirectory = "images"
135+
else:
136+
raise RuntimeError("Invalid poster-directory setting")
137+
106138

107139
def update_from_config(config_path, plex):
108140
config = Config(config_path)
@@ -209,19 +241,12 @@ def update_from_config(config_path, plex):
209241
if not poster:
210242
# try to pull image from image_server. File is Collection name.png
211243
# Setup connection to image_server
212-
try:
213-
host = config.image_server["host"]
214-
except AttributeError:
215-
host = "127.0.0.1"
216-
try:
217-
port = config.image_server["port"]
218-
except AttributeError:
219-
port = "5000"
244+
config_client = ImageServer(config_path, "client")
220245

221-
# Replace spaces in collection name with %20
222-
c_name = c.replace(" ", "%20")
246+
# Url encode collection name
247+
c_name = urllib.parse.quote(c, safe='')
223248
# Create url to where image would be if exists
224-
poster = "http://" + host + ":" + str(port) + "/images/" + c_name
249+
poster = "http://" + config_client.host + ":" + str(config_client.port) + "/images/" + c_name
225250
try:
226251
r = requests.request("GET", poster)
227252
if not r.status_code == 404:

app/image_server.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from flask import Flask
2+
from flask import send_from_directory
3+
from flask import abort
4+
from config_tools import ImageServer
5+
import requests
6+
import logging
7+
import os
8+
import time
9+
10+
def check_running(config_path):
11+
time.sleep(1)
12+
config_client = ImageServer(config_path, "client")
13+
try:
14+
r = requests.get("http://" + config_client.host + ":" + str(config_client.port), verify=False, timeout=1)
15+
return "IMAGE SERVER RUNNING ON http://{}:{}/images/".format(config_client.host, config_client.port)
16+
except (requests.exceptions.ConnectTimeout, requests.exceptions.ConnectionError):
17+
return "IMAGE SERVER NOT RUNNING"
18+
19+
20+
def start_srv(config_path):
21+
config_server = ImageServer(config_path, "server")
22+
server = Flask(__name__)
23+
server.upload_folder = config_server.posterdirectory
24+
log = logging.getLogger("werkzeug")
25+
os.environ['WERKZEUG_RUN_MAIN'] = 'true'
26+
log.setLevel(logging.ERROR)
27+
@server.route('/images/<path:c_name>')
28+
def send_file(c_name):
29+
app_dir = os.path.dirname(os.path.realpath(__file__))
30+
poster_dir = os.path.join(app_dir, config_server.posterdirectory)
31+
posters = os.listdir(poster_dir)
32+
for img in posters:
33+
if (c_name + ".") in img:
34+
return send_from_directory(server.upload_folder, img)
35+
return abort(404)
36+
37+
try:
38+
server.run(host=config_server.host, port=config_server.port)
39+
except (OSError, TypeError) as e:
40+
print(e)
41+
42+
43+
if __name__ == '__main__':
44+
start_srv(config_path)
File renamed without changes.

plex_auto_collections.py renamed to app/plex_auto_collections.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ def append_collection(config_path, config_update=None):
210210

211211
if args.update:
212212
# sys.stdout = open("pac.log", "w")
213-
update_from_config(config_path, plex, True)
213+
update_from_config(config_path, plex)
214214
sys.exit(0)
215215

216216
if input("Update Collections from Config? (y/n): ").upper() == "Y":
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)