mirror of
https://github.com/nwithan8/plex-prerolls
synced 2024-08-30 16:52:17 +00:00
- Edit file path names
- Add Docker + Docker Compose with cron job - Clean, update README.md
This commit is contained in:
parent
1fdb20a998
commit
16d2738356
13
.dockerignore
Normal file
13
.dockerignore
Normal file
@ -0,0 +1,13 @@
|
||||
*.md
|
||||
LICENSE
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
.gitignore
|
||||
.github
|
||||
.git
|
||||
.idea
|
||||
docker-compose.yml
|
||||
venv
|
||||
__pycache__
|
||||
documentation
|
||||
templates
|
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,36 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: "[BUG]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Environment (please complete the following information):**
|
||||
- OS: [e.g. macOS, Ubuntu, Alpine]
|
||||
- Version [e.g. 22]
|
||||
- Python Version:
|
||||
|
||||
**Setup (please complete the following information):**
|
||||
- Did you ensure all required modules are installed? yes / no
|
||||
- Does code/modules work outside the context of this script or program? yes / no
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[REQUEST]"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
20
.github/release.yml
vendored
20
.github/release.yml
vendored
@ -1,20 +0,0 @@
|
||||
# .github/release.yml
|
||||
|
||||
changelog:
|
||||
exclude:
|
||||
labels:
|
||||
- ignore-for-release
|
||||
authors:
|
||||
- octocat
|
||||
categories:
|
||||
- title: Breaking Changes 🛠
|
||||
labels:
|
||||
- Semver-Major
|
||||
- breaking-change
|
||||
- title: Exciting New Features 🎉
|
||||
labels:
|
||||
- Semver-Minor
|
||||
- enhancement
|
||||
- title: Other Changes
|
||||
labels:
|
||||
- "*"
|
85
.github/workflows/docker.yml
vendored
Normal file
85
.github/workflows/docker.yml
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
name: Build & Publish Docker image
|
||||
on:
|
||||
release:
|
||||
types: [ created ]
|
||||
secrets:
|
||||
DOCKER_USERNAME:
|
||||
required: true
|
||||
DOCKER_TOKEN:
|
||||
required: true
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
type: string
|
||||
description: Version number
|
||||
required: true
|
||||
jobs:
|
||||
publish:
|
||||
name: Build & Publish to DockerHub and GitHub Packages
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.head_commit.message, '[no build]') == false
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Establish variables
|
||||
id: vars
|
||||
run: |
|
||||
VERSION=${{ github.event.inputs.version || github.ref_name }}
|
||||
echo ::set-output name=version::${VERSION}
|
||||
echo ::set-output name=today::$(date +'%Y-%m-%d')
|
||||
echo "::set-output name=year::$(date +'%Y')"
|
||||
|
||||
- name: Update version number
|
||||
uses: jacobtomlinson/gha-find-replace@2.0.0
|
||||
with:
|
||||
find: "VERSIONADDEDBYGITHUB"
|
||||
replace: "${{ steps.vars.outputs.version }}"
|
||||
regex: false
|
||||
|
||||
- name: Update copyright year
|
||||
uses: jacobtomlinson/gha-find-replace@2.0.0
|
||||
with:
|
||||
find: "YEARADDEDBYGITHUB"
|
||||
replace: "${{ steps.vars.outputs.year }}"
|
||||
regex: false
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
id: docker-buildx
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
builder: ${{ steps.docker-buildx.outputs.name }}
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/armhf,linux/arm64
|
||||
tags: |
|
||||
nwithan8/plex_prerolls:latest
|
||||
nwithan8/plex_prerolls:${{ steps.vars.outputs.version }}
|
||||
ghcr.io/nwithan8/plex_prerolls:latest
|
||||
ghcr.io/nwithan8/plex_prerolls:${{ steps.vars.outputs.version }}
|
||||
labels: |
|
||||
org.opencontainers.image.title=plex_prerolls
|
||||
org.opencontainers.image.version=${{ steps.vars.outputs.version }}
|
||||
org.opencontainers.image.created=${{ steps.vars.outputs.today }}
|
19
.github/workflows/publish-release-manual.yml
vendored
19
.github/workflows/publish-release-manual.yml
vendored
@ -1,19 +0,0 @@
|
||||
# .github/workflows/publish-release-manual.yml
|
||||
name: Publish release (manual)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: The tag to publish
|
||||
required: true
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
name: Publish release
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: refs/tags/${{ github.event.inputs.tag }}
|
||||
- name: Publish release
|
||||
uses: eloquent/github-release-action@v3
|
15
.github/workflows/publish-release.yml
vendored
15
.github/workflows/publish-release.yml
vendored
@ -1,15 +0,0 @@
|
||||
# .github/workflows/publish-release.yml
|
||||
name: Publish release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
name: Publish release
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Publish release
|
||||
uses: eloquent/github-release-action@v3
|
36
.github/workflows/upload_unraid_template.yml
vendored
Normal file
36
.github/workflows/upload_unraid_template.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: Copy Unraid Community Applications template(s) to templates repository
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [ created ]
|
||||
workflow_dispatch: ~
|
||||
|
||||
jobs:
|
||||
copy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Establish variables
|
||||
id: vars
|
||||
run: |
|
||||
VERSION=${{ github.event.inputs.version || github.ref_name }}
|
||||
echo ::set-output name=version::${VERSION}
|
||||
echo ::set-output name=today::$(date +'%Y-%m-%d')
|
||||
|
||||
- name: Open PR with template changes to unraid_templates
|
||||
uses: nwithan8/action-pull-request-another-repo@v1.1.1
|
||||
env:
|
||||
API_TOKEN_GITHUB: ${{ secrets.PR_OPEN_GITHUB_TOKEN }}
|
||||
with:
|
||||
# Will mirror folder structure (copying "templates" folder to "templates" folder in destination repo)
|
||||
source_folder: 'templates'
|
||||
destination_repo: 'nwithan8/unraid_templates'
|
||||
destination_base_branch: 'main'
|
||||
destination_head_branch: prerolls-${{ steps.vars.outputs.version }}
|
||||
user_email: 'nwithan8@users.noreply.github.com'
|
||||
user_name: 'nwithan8'
|
||||
pull_request_assignees: 'nwithan8'
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,7 +1,6 @@
|
||||
# Exclude local Config files
|
||||
config.ini
|
||||
preroll_schedules.yaml
|
||||
preroll_schedules.yml
|
||||
schedules.yaml
|
||||
|
||||
#Dev environmet
|
||||
.devcontainer
|
||||
|
40
Dockerfile
Executable file
40
Dockerfile
Executable file
@ -0,0 +1,40 @@
|
||||
FROM python:3.11-alpine3.18
|
||||
WORKDIR /
|
||||
|
||||
# Install Python and other utilities
|
||||
RUN apk add --no-cache --update alpine-sdk git wget python3 python3-dev ca-certificates musl-dev libc-dev gcc bash nano linux-headers && \
|
||||
python3 -m ensurepip && \
|
||||
pip3 install --no-cache-dir --upgrade pip setuptools
|
||||
|
||||
# Copy requirements.txt from build machine to WORKDIR (/app) folder (important we do this BEFORE copying the rest of the files to avoid re-running pip install on every code change)
|
||||
COPY requirements.txt requirements.txt
|
||||
|
||||
# Install Python requirements
|
||||
RUN pip3 install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Make Docker /config volume for optional config file
|
||||
VOLUME /config
|
||||
|
||||
# Copy logging.conf file from build machine to Docker /config folder
|
||||
COPY logging.conf /config/
|
||||
|
||||
# Copy example config file from build machine to Docker /config folder
|
||||
# Also copies any existing config.ini file from build machine to Docker /config folder, (will cause the bot to use the existing config file if it exists)
|
||||
COPY config.ini* /config/
|
||||
|
||||
# Copy example schedule file from build machine to Docker /config folder
|
||||
# Also copies any existing schedules.yaml file from build machine to Docker /config folder, (will cause the bot to use the existing schedule file if it exists)
|
||||
COPY schedules.yaml* /config/
|
||||
|
||||
# Make Docker /logs volume for log file
|
||||
VOLUME /logs
|
||||
|
||||
# Copy source code from build machine to WORKDIR (/app) folder
|
||||
COPY . .
|
||||
|
||||
# Delete unnecessary files in WORKDIR (/app) folder (not caught by .dockerignore)
|
||||
RUN echo "**** removing unneeded files ****"
|
||||
RUN rm -rf /requirements.txt
|
||||
|
||||
# Run entrypoint.sh script
|
||||
ENTRYPOINT ["sh", "/entrypoint.sh"]
|
318
README.md
318
README.md
@ -1,171 +1,51 @@
|
||||
# Schedule Plex server related Pre-roll intro videos
|
||||
# Plex Preroll Scheduler
|
||||
|
||||
A helper script to automate management of Plex pre-rolls. \
|
||||
Define when you want different pre-rolls to play throughout the year.
|
||||
A script to automate management of Plex pre-rolls.
|
||||
|
||||
Ideas include:
|
||||
Define when you want different pre-rolls to play throughout the year. For example:
|
||||
|
||||
- Holiday pre-roll rotations
|
||||
- Special occasions
|
||||
- Summer/Winter/Seasonal rotations
|
||||
- Seasonal rotations
|
||||
- Breaking up the monotony
|
||||
- Keeping your family on their toes!
|
||||
|
||||
Simple steps:
|
||||
|
||||
> 1. Config the schedule
|
||||
> 2. Schedule script on server
|
||||
> 3. ...
|
||||
> 4. Profit!
|
||||
|
||||
See [Installation & Setup](#install) section
|
||||
|
||||
---
|
||||
|
||||
## Schedule Rules
|
||||
## Installation and Usage
|
||||
|
||||
Schedule priority for a given Date:
|
||||
### Run Script Directly
|
||||
|
||||
1. **misc** \
|
||||
always_use - always includes in listing (append)
|
||||
#### Requirements
|
||||
|
||||
2. **date_range** \
|
||||
Include listing for the specified Start/End date range that include the given Date \
|
||||
Range can be specified as a Date or DateTime \
|
||||
Advanced features to have recurring timeframes \
|
||||
**overrides usage of *week/month/default* listings
|
||||
- Python 3.8+
|
||||
|
||||
3. **weekly** \
|
||||
Include listing for the specified WEEK of the year for the given Date \
|
||||
**override usage of *month/default* listings
|
||||
|
||||
4. **monthly** \
|
||||
Include listing for the specified MONTH of the year for the given Date \
|
||||
**overrides usage of *default* listings
|
||||
|
||||
5. **default** \
|
||||
Default listing used of none of above apply to the given Date
|
||||
|
||||
Note: Script tries to find the closest matching range if multiple overlap at same time
|
||||
|
||||
---
|
||||
|
||||
## Installation & Setup <a id="install"></a>
|
||||
|
||||
Grab a copy of the code
|
||||
Clone the repo:
|
||||
|
||||
```sh
|
||||
cd /path/to/your/location
|
||||
git clone https://github.com/BrianLindner/plex-schedule-prerolls.git
|
||||
git clone https://github.com/nwithan8/plex-schedule-prerolls.git
|
||||
```
|
||||
|
||||
### Install Requirements <a id="requirements"></a>
|
||||
|
||||
Requires:
|
||||
|
||||
- Python 3.8+ [may work on 3.6+ but not tested]
|
||||
- See `requirements.txt` for Python modules and versions [link](requirements.txt)
|
||||
- plexapi, configparser, pyyaml, etc.
|
||||
|
||||
Install Python requirements \
|
||||
(highly recomend using <a href="https://docs.python.org/3/tutorial/venv.html" target="_blank">Virtual Environments</a> )
|
||||
Install Python requirements:
|
||||
|
||||
```sh
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Create `config.ini` file with Plex connection information
|
||||
Copy `config.ini.sample` to `config.ini` and complete the `[auth]` section with your Plex server information.
|
||||
|
||||
Script checks for:
|
||||
Copy `schedules.yaml.sample` to `schedules.yaml` and [edit your schedule](#schedule-rules).
|
||||
|
||||
- local ./config.ini (See: [Sample](config.ini.sample))
|
||||
- PlexAPI global config.ini
|
||||
- Custom location config.ini (see [Arguments](#arguments))
|
||||
|
||||
(See: <a href="https://python-plexapi.readthedocs.io/en/latest/configuration.html" target="_blank">plexapi.CONFIG</a> for more info)
|
||||
|
||||
Rename `config.ini.sample` -> `config.ini` and update to your environment
|
||||
|
||||
Example `config.ini`
|
||||
|
||||
```ini
|
||||
[auth]
|
||||
server_baseurl = http://127.0.0.1:32400 # your plex server url
|
||||
server_token = <PLEX_TOKEN> # access token
|
||||
```
|
||||
|
||||
### Create `preroll_schedules.yaml` file with desired schedule
|
||||
|
||||
#### Date Range Section Scheduling
|
||||
|
||||
Use it for *Day* or *Ranges of Dates* needs \
|
||||
Now with Time support! (optional)
|
||||
|
||||
Formatting Supported:
|
||||
|
||||
- Dates: yyyy-mm-dd
|
||||
- DateTime: yyyy-mm-dd hh:mm:ss (24hr time format)
|
||||
|
||||
Rename `preroll_schedules.yaml.sample` -> `preroll_schedules.yaml` and update for your environment
|
||||
|
||||
Example YAML config layout (See: [Sample](preroll_schedules.yaml.sample) for more info)
|
||||
|
||||
```yaml
|
||||
---
|
||||
monthly:
|
||||
enabled: (yes/no)
|
||||
jan: /path/to/file.mp4;/path/to/file.mp4
|
||||
...
|
||||
dec: /path/to/file.mp4;/path/to/file.mp4
|
||||
date_range:
|
||||
enabled: (yes/no)
|
||||
ranges:
|
||||
- start_date: 2020-01-01
|
||||
end_date: 2020-01-01
|
||||
path: /path/to/video.mp4
|
||||
- start_date: 2020-07-03
|
||||
end_date: 2020-07-05
|
||||
path: /path/to/video.mp4
|
||||
- start_date: 2020-12-19
|
||||
end_date: 2020-12-26
|
||||
path: /path/to/video.mp4
|
||||
weekly:
|
||||
enabled: (yes/no)
|
||||
"1": /path/to/file(s)
|
||||
...
|
||||
"52": /path/to/file(s)
|
||||
misc:
|
||||
enabled: (yes/no)
|
||||
always_use: /path/to/file(s)
|
||||
default:
|
||||
enabled: (yes/no)
|
||||
path: /path/to/file.mp4;/path/to/file.mp4
|
||||
```
|
||||
|
||||
See [Advancecd Date Ranges](#advanced_date) for additional features
|
||||
|
||||
## Usage <a id="usage"></a>
|
||||
|
||||
### Default Usage
|
||||
Run the script:
|
||||
|
||||
```sh
|
||||
python schedule_preroll.py
|
||||
```
|
||||
|
||||
### Runtime Arguments <a id="arguments" ></a>
|
||||
|
||||
- -v : version information
|
||||
- -h : help information
|
||||
- -c : config.ini (local or PlexAPI system central) for Connection Info (see [config.ini.sample](config.ini.sample))
|
||||
- -s : preroll_schedules.yaml for various scheduling information (see [spreroll_schedules.yaml.sample](preroll_schedules.yaml.sample))
|
||||
- -lc : location of custom logger.conf config file \
|
||||
See:
|
||||
- Sample [logger config](logging.conf)
|
||||
- Logger usage <a href="https://github.com/amilstead/python-logging-examples/blob/master/configuration/fileConfig/config.ini" target="_blank" >Examples</a>
|
||||
- Logging <a href="https://www.internalpointers.com/post/logging-python-sub-modules-and-configuration-files" target="_blank">Doc Info</a>
|
||||
#### Advanced Usage
|
||||
|
||||
```sh
|
||||
python schedule_preroll.py -h
|
||||
$ python schedule_preroll.py -h
|
||||
|
||||
usage: schedule_preroll.py [-h] [-v] [-l LOG_CONFIG_FILE] [-c CONFIG_FILE] [-s SCHEDULE_FILE]
|
||||
|
||||
@ -179,100 +59,134 @@ optional arguments:
|
||||
-c CONFIG_FILE, --config-path CONFIG_FILE
|
||||
Path to Config.ini to use for Plex Server info. [Default: ./config.ini]
|
||||
-s SCHEDULE_FILE, --schedule-path SCHEDULE_FILE
|
||||
Path to pre-roll schedule file (YAML) to be use. [Default: ./preroll_schedules.yaml]
|
||||
Path to pre-roll schedule file (YAML) to be use. [Default: ./schedules.yaml]
|
||||
```
|
||||
|
||||
### Runtime Arguments Example
|
||||
##### Example
|
||||
|
||||
```sh
|
||||
python schedule_preroll.py \
|
||||
-c path/to/custom/config.ini \
|
||||
-s path/to/custom/preroll_schedules.yaml \
|
||||
-s path/to/custom/schedules.yaml \
|
||||
-lc path/to/custom/logger.conf
|
||||
```
|
||||
|
||||
### Run as Docker Container
|
||||
|
||||
#### Requirements
|
||||
|
||||
- Docker
|
||||
|
||||
#### Docker Compose
|
||||
|
||||
Complete the provided `docker-compose.yml` file and run:
|
||||
|
||||
```sh
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
#### Docker CLI
|
||||
|
||||
```sh
|
||||
docker run -d \
|
||||
--name=plex_prerolls \
|
||||
-e PUID=1000 \
|
||||
-e PGID=1000 \
|
||||
-e TZ=Etc/UTC \
|
||||
-e CRON_SCHEDULE="0 0 * * *" \
|
||||
-v /path/to/config:/config \
|
||||
-v /path/to/logs:/logs \
|
||||
--restart unless-stopped \
|
||||
nwithan8/plex_prerolls:latest
|
||||
```
|
||||
|
||||
#### Paths and Environment Variables
|
||||
|
||||
| Path | Description |
|
||||
|-----------|-------------------------------------------------------------------------------------|
|
||||
| `/config` | Path to config files (`config.ini` and `schedule.yaml` should be in this directory) |
|
||||
| `/logs` | Path to log files (`schedule_preroll.log` will be in this directory) |
|
||||
|
||||
| Environment Variable | Description |
|
||||
|----------------------|-------------------------------------------------------------------|
|
||||
| `PUID` | UID of user to run as |
|
||||
| `PGID` | GID of user to run as |
|
||||
| `TZ` | Timezone to use for cron schedule |
|
||||
| `CRON_SCHEDULE` | Cron schedule to run script (see <https://crontab.guru> for help) |
|
||||
|
||||
---
|
||||
|
||||
## Scheduling Script (Optional) <a id="scheduling"></a>
|
||||
## Schedule Rules
|
||||
|
||||
Schedules follow the following priority:
|
||||
1. **misc**: Items listed in `always_use` will always be included (appended) to the preroll list
|
||||
|
||||
2. **date_range**: Schedule based on a specific date/time range
|
||||
|
||||
3. **weekly**: Schedule based on a specific week of the year
|
||||
|
||||
4. **monthly**: Schedule based on a specific month of the year
|
||||
|
||||
5. **default**: Default item to use if none of the above apply
|
||||
|
||||
For any conflicting schedules, the script tries to find the closest matching range and highest priority.
|
||||
|
||||
### Advanced Scheduling
|
||||
|
||||
#### Date Range Section Scheduling
|
||||
|
||||
`date_range` entries can accept both dates (`yyyy-mm-dd`) and datetimes (`yyyy-mm-dd hh:mm:ss`, 24-hour time).
|
||||
|
||||
`date_range` entries can also accept wildcards for any of the date/time fields. This can be useful for scheduling recurring events, such as annual events, "first-of-the-month" events, or even hourly events.
|
||||
|
||||
```yaml
|
||||
date_range:
|
||||
enabled: true
|
||||
ranges:
|
||||
# Each entry requires start_date, end_date, path values
|
||||
- start_date: 2020-01-01 # Jan 1st, 2020
|
||||
end_date: 2020-01-02 # Jan 2nd, 2020
|
||||
path: /path/to/video.mp4
|
||||
- start_date: xxxx-07-04 # Every year on July 4th
|
||||
end_date: xxxx-07-04 # Every year on July 4th
|
||||
path: /path/to/video.mp4
|
||||
- start_date: xxxx-xx-02 # Every year on the 2nd of every month
|
||||
end_date: xxxx-xx-03 # Every year on the 3rd of every month
|
||||
path: /path/to/video.mp4
|
||||
- start_date: xxxx-xx-xx 08:00:00 # Every day at 8am
|
||||
end_date: xxxx-xx-xx 09:30:00 # Every day at 9:30am
|
||||
path: /path/to/holiday_video.mp4
|
||||
```
|
||||
|
||||
You should [adjust your cron schedule](#scheduling-script) to run the script more frequently if you use this feature.
|
||||
|
||||
---
|
||||
|
||||
## Scheduling Script
|
||||
|
||||
**NOTE:** Scheduling is handled automatically in the Docker version of this script via the `CRON_SCHEDULE` environment variable.
|
||||
|
||||
### Linux
|
||||
|
||||
Add to system scheduler:
|
||||
|
||||
Linux:
|
||||
|
||||
```sh
|
||||
crontab -e
|
||||
```
|
||||
|
||||
Place desired schedule (example below for everyday at midnight)
|
||||
Place desired schedule (example below for every day at midnight)
|
||||
|
||||
```sh
|
||||
0 0 * * * python /path/to/schedule_preroll.py >/dev/null 2>&1
|
||||
```
|
||||
|
||||
or \
|
||||
(Optional) Wrap in a shell script: \
|
||||
useful if running other scripts/commands, using venv encapsulation, customizing arguments
|
||||
You can also wrap the execution in a shell script (useful if running other scripts/commands, using venv encapsulation, customizing arguments, etc.)
|
||||
|
||||
```sh
|
||||
0 0 * * * /path/to/schedule_preroll.sh >/dev/null 2>&1
|
||||
```
|
||||
|
||||
Schedule as frequently as needed for your environment and how specific and to your personal rotation schedule needs
|
||||
|
||||
---
|
||||
|
||||
## Advanced Date Range Section Scheduling <a id="advanced_date"></a> (Optional)
|
||||
|
||||
Date Ranges with Recurring Timeframes \
|
||||
Useful for static dates or times where you want recurring preroll activity
|
||||
|
||||
Examples:
|
||||
|
||||
- Every Morning
|
||||
- Yearly holidays (Halloween, New Years, Independence)
|
||||
- Birthdays, Anniversaries
|
||||
|
||||
For either Start and/or End date of range \
|
||||
Substitute "xx" for date/times to schedule for "any" \
|
||||
Substitute "xxxx" for recurring year
|
||||
|
||||
- xxxx-xx-01 - Every first of month
|
||||
- xxxx-xx-xx - Every day
|
||||
- xxxx-xx-xx 08:00:00 - every day from 8am
|
||||
- xxxx-01-01 - Every year on Jan 1 (new years day)
|
||||
|
||||
if using Time, still must have a full datetime pattern (ex: hour, minute, second hh:mm:ss)
|
||||
|
||||
```yaml
|
||||
#every July 4
|
||||
- start_date: xxxx-07-04
|
||||
end_date: xxxx-07-04
|
||||
path: /path/to/video.mp4
|
||||
# every first of month, all day
|
||||
- start_date: xxxx-xx-01
|
||||
end_date: xxxx-xx-01
|
||||
path: /path/to/video.mp4
|
||||
# 8-9 am every day
|
||||
- start_date: xxxx-xx-xx 08:00:00
|
||||
end_date: xxxx-xx-xx 08:59:59
|
||||
path: /path/to/video.mp4
|
||||
|
||||
```
|
||||
|
||||
Note: Detailed time based schedules benefit from increased running of the Python script for frequently - ex: Hourly \
|
||||
(See: [Scheduling Script](#scheduling) section)
|
||||
|
||||
---
|
||||
|
||||
## Config `logger.conf` to your needs (Optional)
|
||||
|
||||
See: <a href="https://docs.python.org/3/howto/logging.html" target="_blank"><https://docs.python.org/3/howto/logging.html></a>
|
||||
|
||||
---
|
||||
|
||||
## Wrapping Up
|
||||
|
||||
> Sit back and enjoy the Intros!
|
||||
Schedule as frequently as needed for your schedule (ex: hourly, daily, weekly, etc.)
|
||||
|
||||
---
|
||||
|
||||
|
10
docker-compose.yml
Normal file
10
docker-compose.yml
Normal file
@ -0,0 +1,10 @@
|
||||
version: "3.9"
|
||||
services:
|
||||
plex_prerolls:
|
||||
image: nwithan8/plex_prerolls:latest
|
||||
volumes:
|
||||
- /path/to/config:/config
|
||||
- /path/to/logs:/logs
|
||||
environment:
|
||||
CRON_SCHEDULE: "0 0 * * *" # Run every day at midnight, see https://crontab.guru/ for help
|
||||
TZ: America/New_York
|
22
entrypoint.sh
Normal file
22
entrypoint.sh
Normal file
@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Create cron directory
|
||||
mkdir -p /etc/cron.d
|
||||
|
||||
# Read cron schedule from environment variable
|
||||
CRON_SCHEDULE=${CRON_SCHEDULE:-"0 0 * * *"} # Default to midnight every day if not supplied
|
||||
|
||||
# Schedule cron job with supplied cron schedule
|
||||
echo "$CRON_SCHEDULE python3 /schedule_preroll.py -c /config/config.ini -s /config/schedules.yaml -lc /config/logging.conf > /proc/1/fd/1 2>/proc/1/fd/2" > /etc/cron.d/schedule_preroll
|
||||
|
||||
# Give execution rights on the cron job
|
||||
chmod 0644 /etc/cron.d/schedule_preroll
|
||||
|
||||
# Apply cron job
|
||||
crontab /etc/cron.d/schedule_preroll
|
||||
|
||||
# Create the log file to be able to run tail
|
||||
touch /var/log/cron.log
|
||||
|
||||
# Run the command on container startup
|
||||
crond && tail -f /var/log/cron.log
|
@ -1,56 +0,0 @@
|
||||
---
|
||||
# all Key items must be in lowercase
|
||||
# all PATH entries will be case sensitive based on your Environment (Linux, Windows)
|
||||
monthly:
|
||||
# If enabled, List out each month (lowercase;3-char abreviation) (optional)
|
||||
# dont have to have all the months here, script will skip but log a Warning
|
||||
enabled: Yes
|
||||
jan: /path/to/video.mp4
|
||||
feb:
|
||||
mar:
|
||||
apr:
|
||||
may: /path/to/video.mp4
|
||||
jun:
|
||||
jul:
|
||||
aug:
|
||||
sep: /path/to/video.mp4;/path/to/video.mp4
|
||||
oct:
|
||||
nov:
|
||||
dec:
|
||||
date_range:
|
||||
# If enabled, use a list of various date ranges/timeframes for different lists of pre-rolls
|
||||
# list must be under ranges:
|
||||
# each entry requires start_date, end_date, path values
|
||||
enabled: Yes
|
||||
ranges:
|
||||
- start_date: 2020-01-01
|
||||
end_date: 2020-01-01
|
||||
path: /path/to/video.mp4
|
||||
- start_date: 2020-07-03
|
||||
end_date: 2020-07-05
|
||||
path: /path/to/video.mp4
|
||||
- start_date: 2020-12-19
|
||||
end_date: 2020-12-26
|
||||
path: /path/to/video.mp4
|
||||
# every year on Dec 25
|
||||
- start_date: xxxx-12-25
|
||||
end_date: xxxx-12-25
|
||||
path: /path/to/holiday_video.mp4
|
||||
weekly:
|
||||
# If enabled, list any weeks of the year to have specific prerolls 1-52 (optional)
|
||||
# Dont need to have all the week numbers; the script skips over missing entries
|
||||
# each week number must be surrounded by quotes
|
||||
enabled: No
|
||||
"1":
|
||||
"2": /path/to/video.mkv
|
||||
"52":
|
||||
misc:
|
||||
# If enabled, additional items for preroll selecton processing
|
||||
# always_use: If enabled, always include these video files in pre-role listing
|
||||
enabled: Yes
|
||||
always_use: /path/to/video.mp4
|
||||
# TBD: Future Use - other features
|
||||
default:
|
||||
# If enabled, Default listing of prerolls to use if no Schedule (above) is specified for date
|
||||
enabled: Yes
|
||||
path: /path/to/video1.mp4;/path/to/video3.mp4;/path/to/video4.mp4
|
@ -15,8 +15,8 @@ Optional Arguments:
|
||||
Path to Config.ini to use for Plex Server info.
|
||||
[Default: ./config.ini]
|
||||
-s SCHEDULE_FILE, --schedule-path SCHEDULE_FILE
|
||||
Path to pre-roll schedule file (YAML) to be use.
|
||||
[Default: ./preroll_schedules.yaml]
|
||||
Path to pre-roll schedule file (YAML) to be used.
|
||||
[Default: ./schedules.yaml]
|
||||
|
||||
Requirements:
|
||||
- See Requirements.txt for Python modules
|
||||
@ -24,7 +24,7 @@ Requirements:
|
||||
Scheduling:
|
||||
Add to system scheduler such as:
|
||||
> crontab -e
|
||||
> 0 0 * * * python path/to/schedule_preroll.py >/dev/null 2>&1
|
||||
> 0 0 * * * python path/to/schedule_pre_roll.py >/dev/null 2>&1
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: [description]
|
||||
@ -60,8 +60,8 @@ script_dir = os.path.dirname(__file__)
|
||||
|
||||
class ScheduleEntry(NamedTuple):
|
||||
type: str
|
||||
startdate: datetime
|
||||
enddate: datetime
|
||||
start_date: datetime
|
||||
end_date: datetime
|
||||
force: bool
|
||||
path: str
|
||||
|
||||
@ -81,7 +81,7 @@ def arguments() -> Namespace:
|
||||
|
||||
config_default = "./config.ini"
|
||||
log_config_default = "./logging.conf"
|
||||
schedule_default = "./preroll_schedules.yaml"
|
||||
schedule_default = "./schedules.yaml"
|
||||
parser = ArgumentParser(description=f"{description}")
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
@ -141,18 +141,18 @@ def schedule_types() -> ScheduleType:
|
||||
return schema
|
||||
|
||||
|
||||
def week_range(year: int, weeknum: int) -> Tuple[datetime, datetime]:
|
||||
def week_range(year: int, week_num: int) -> Tuple[datetime, datetime]:
|
||||
"""Return the starting/ending date range of a given year/week
|
||||
|
||||
Args:
|
||||
year (int): Year to calc range for
|
||||
weeknum (int): Month of the year (1-12)
|
||||
week_num (int): Month of the year (1-12)
|
||||
|
||||
Returns:
|
||||
DateTime: Start date of the Year/Month
|
||||
DateTime: End date of the Year/Month
|
||||
"""
|
||||
start = datetime.strptime(f"{year}-W{int(weeknum) - 1}-0", "%Y-W%W-%w").date()
|
||||
start = datetime.strptime(f"{year}-W{int(week_num) - 1}-0", "%Y-W%W-%w").date()
|
||||
end = start + timedelta(days=6)
|
||||
|
||||
start = datetime.combine(start, datetime.min.time())
|
||||
@ -161,18 +161,18 @@ def week_range(year: int, weeknum: int) -> Tuple[datetime, datetime]:
|
||||
return (start, end)
|
||||
|
||||
|
||||
def month_range(year: int, monthnum: int) -> Tuple[datetime, datetime]:
|
||||
def month_range(year: int, month_num: int) -> Tuple[datetime, datetime]:
|
||||
"""Return the starting/ending date range of a given year/month
|
||||
|
||||
Args:
|
||||
year (int): Year to calc range for
|
||||
monthnum (int): Month of the year (1-12)
|
||||
month_num (int): Month of the year (1-12)
|
||||
|
||||
Returns:
|
||||
DateTime: Start date of the Year/Month
|
||||
DateTime: End date of the Year/Month
|
||||
"""
|
||||
start = date(year, monthnum, 1)
|
||||
start = date(year, month_num, 1)
|
||||
next_month = start.replace(day=28) + timedelta(days=4)
|
||||
end = next_month - timedelta(days=next_month.day)
|
||||
|
||||
@ -247,23 +247,23 @@ def make_datetime(value: Union[str, date, datetime], lowtime: bool = True) -> da
|
||||
year, month, day = today.year, today.month, today.day
|
||||
hour, minute, second = time.hour, time.minute, time.second
|
||||
|
||||
# start parsing the Time out, for later additional processing
|
||||
dateparts = value.lower().split("-")
|
||||
# start parsing the timeout, for later additional processing
|
||||
date_parts = value.lower().split("-")
|
||||
|
||||
year = today.year if dateparts[0] == "xxxx" else int(dateparts[0])
|
||||
month = today.month if dateparts[1] == "xx" else int(dateparts[1])
|
||||
year = today.year if date_parts[0] == "xxxx" else int(date_parts[0])
|
||||
month = today.month if date_parts[1] == "xx" else int(date_parts[1])
|
||||
|
||||
dateparts_day = dateparts[2].split(" ")
|
||||
date_parts_day = date_parts[2].split(" ")
|
||||
|
||||
day = today.day if dateparts_day[0] == "xx" else int(dateparts_day[0])
|
||||
day = today.day if date_parts_day[0] == "xx" else int(date_parts_day[0])
|
||||
|
||||
# attempt to parse out Time components
|
||||
if len(dateparts_day) > 1:
|
||||
timeparts = dateparts_day[1].split(":")
|
||||
if len(timeparts) > 1:
|
||||
hour = now.hour if timeparts[0] == "xx" else int(timeparts[0])
|
||||
minute = now.minute if timeparts[1] == "xx" else int(timeparts[1])
|
||||
second = now.second + 1 if timeparts[2] == "xx" else int(timeparts[2])
|
||||
if len(date_parts_day) > 1:
|
||||
time_parts = date_parts_day[1].split(":")
|
||||
if len(time_parts) > 1:
|
||||
hour = now.hour if time_parts[0] == "xx" else int(time_parts[0])
|
||||
minute = now.minute if time_parts[1] == "xx" else int(time_parts[1])
|
||||
second = now.second + 1 if time_parts[2] == "xx" else int(time_parts[2])
|
||||
|
||||
dt_val = datetime(year, month, day, hour, minute, second)
|
||||
logger.debug("Datetime-> '%s'", dt_val)
|
||||
@ -278,7 +278,7 @@ def make_datetime(value: Union[str, date, datetime], lowtime: bool = True) -> da
|
||||
return dt_val
|
||||
|
||||
|
||||
def schedulefile_contents(schedule_filename: Optional[str]) -> dict[str, any]: # type: ignore
|
||||
def schedule_file_contents(schedule_filename: Optional[str]) -> dict[str, any]: # type: ignore
|
||||
"""Returns a contents of the provided YAML file and validates
|
||||
|
||||
Args:
|
||||
@ -290,7 +290,7 @@ def schedulefile_contents(schedule_filename: Optional[str]) -> dict[str, any]:
|
||||
Returns:
|
||||
YAML Contents: YAML structure of Dict[str, Any]
|
||||
"""
|
||||
default_files = ["preroll_schedules.yaml", "preroll_schedules.yml"]
|
||||
default_files = ["schedules.yaml"]
|
||||
|
||||
filename = None
|
||||
if schedule_filename not in ("", None):
|
||||
@ -312,11 +312,11 @@ def schedulefile_contents(schedule_filename: Optional[str]) -> dict[str, any]:
|
||||
|
||||
# if we still cant find a schedule file, we abort
|
||||
if not filename:
|
||||
filestr = '" / "'.join(default_files)
|
||||
logger.error('Missing schedule file: "%s"', filestr)
|
||||
raise FileNotFoundError(filestr)
|
||||
file_str = '" / "'.join(default_files)
|
||||
logger.error('Missing schedule file: "%s"', file_str)
|
||||
raise FileNotFoundError(file_str)
|
||||
|
||||
schema_filename = os.path.join(script_dir, "util/schedulefile_schema.json")
|
||||
schema_filename = os.path.join(script_dir, "util/schedule_file_schema.json")
|
||||
|
||||
logger.debug('using schema validation file "%s"', schema_filename)
|
||||
|
||||
@ -354,17 +354,17 @@ def schedulefile_contents(schedule_filename: Optional[str]) -> dict[str, any]:
|
||||
raise
|
||||
|
||||
if not v.validate(contents): # type: ignore
|
||||
logger.error("Preroll-Schedule YAML Validation Error: %s", v.errors) # type: ignore
|
||||
raise yaml.YAMLError(f"Preroll-Schedule YAML Validation Error: {v.errors}") # type: ignore
|
||||
logger.error("Pre-roll Schedule YAML Validation Error: %s", v.errors) # type: ignore
|
||||
raise yaml.YAMLError(f"Pre-roll Schedule YAML Validation Error: {v.errors}") # type: ignore
|
||||
|
||||
return contents
|
||||
|
||||
|
||||
def preroll_schedule(schedule_file: Optional[str] = None) -> List[ScheduleEntry]:
|
||||
"""Return a listing of defined preroll schedules for searching/use
|
||||
def pre_roll_schedule(schedule_file: Optional[str] = None) -> List[ScheduleEntry]:
|
||||
"""Return a listing of defined pre_roll schedules for searching/use
|
||||
|
||||
Args:
|
||||
schedule_file (str): path/to/schedule_preroll.yaml style config file (YAML Format)
|
||||
schedule_file (str): path/to/schedule_pre_roll.yaml style config file (YAML Format)
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: If no schedule config file exists
|
||||
@ -373,7 +373,7 @@ def preroll_schedule(schedule_file: Optional[str] = None) -> List[ScheduleEntry]
|
||||
list: list of ScheduleEntries
|
||||
"""
|
||||
|
||||
contents = schedulefile_contents(schedule_file) # type: ignore
|
||||
contents = schedule_file_contents(schedule_file) # type: ignore
|
||||
|
||||
today = date.today()
|
||||
schedule: List[ScheduleEntry] = []
|
||||
@ -399,8 +399,8 @@ def preroll_schedule(schedule_file: Optional[str] = None) -> List[ScheduleEntry]
|
||||
entry = ScheduleEntry(
|
||||
type=schedule_section,
|
||||
force=False,
|
||||
startdate=start,
|
||||
enddate=end,
|
||||
start_date=start,
|
||||
end_date=end,
|
||||
path=path,
|
||||
)
|
||||
|
||||
@ -432,8 +432,8 @@ def preroll_schedule(schedule_file: Optional[str] = None) -> List[ScheduleEntry]
|
||||
entry = ScheduleEntry(
|
||||
type=schedule_section,
|
||||
force=False,
|
||||
startdate=start,
|
||||
enddate=end,
|
||||
start_date=start,
|
||||
end_date=end,
|
||||
path=path,
|
||||
)
|
||||
|
||||
@ -468,8 +468,8 @@ def preroll_schedule(schedule_file: Optional[str] = None) -> List[ScheduleEntry]
|
||||
entry = ScheduleEntry(
|
||||
type=schedule_section,
|
||||
force=force, # type: ignore
|
||||
startdate=start,
|
||||
enddate=end,
|
||||
start_date=start,
|
||||
end_date=end,
|
||||
path=path,
|
||||
)
|
||||
|
||||
@ -496,8 +496,8 @@ def preroll_schedule(schedule_file: Optional[str] = None) -> List[ScheduleEntry]
|
||||
entry = ScheduleEntry(
|
||||
type=schedule_section,
|
||||
force=False,
|
||||
startdate=datetime(today.year, today.month, today.day, 0, 0, 0),
|
||||
enddate=datetime(today.year, today.month, today.day, 23, 59, 59),
|
||||
start_date=datetime(today.year, today.month, today.day, 0, 0, 0),
|
||||
end_date=datetime(today.year, today.month, today.day, 23, 59, 59),
|
||||
path=path,
|
||||
)
|
||||
|
||||
@ -521,8 +521,8 @@ def preroll_schedule(schedule_file: Optional[str] = None) -> List[ScheduleEntry]
|
||||
entry = ScheduleEntry(
|
||||
type=schedule_section,
|
||||
force=False,
|
||||
startdate=datetime(today.year, today.month, today.day, 0, 0, 0),
|
||||
enddate=datetime(today.year, today.month, today.day, 23, 59, 59),
|
||||
start_date=datetime(today.year, today.month, today.day, 0, 0, 0),
|
||||
end_date=datetime(today.year, today.month, today.day, 23, 59, 59),
|
||||
path=path,
|
||||
)
|
||||
|
||||
@ -539,7 +539,7 @@ def preroll_schedule(schedule_file: Optional[str] = None) -> List[ScheduleEntry]
|
||||
raise ValueError(msg)
|
||||
|
||||
# Sort list so most recent Ranges appear first
|
||||
schedule.sort(reverse=True, key=lambda x: x.startdate)
|
||||
schedule.sort(reverse=True, key=lambda x: x.start_date)
|
||||
|
||||
logger.debug("***START Schedule Set to be used***")
|
||||
logger.debug(schedule)
|
||||
@ -549,14 +549,14 @@ def preroll_schedule(schedule_file: Optional[str] = None) -> List[ScheduleEntry]
|
||||
|
||||
|
||||
def build_listing_string(items: List[str], play_all: bool = False) -> str:
|
||||
"""Build the Plex formatted string of preroll paths
|
||||
"""Build the Plex formatted string of pre_roll paths
|
||||
|
||||
Args:
|
||||
items (list): List of preroll video paths to place into a string listing
|
||||
items (list): List of pre_roll video paths to place into a string listing
|
||||
play_all (bool, optional): Play all videos. [Default: False (Random choice)]
|
||||
|
||||
Returns:
|
||||
string: CSV Listing (, or ;) based on play_all param of preroll video paths
|
||||
string: CSV Listing (, or ;) based on play_all param of pre_roll video paths
|
||||
"""
|
||||
|
||||
if len(items) == 0:
|
||||
@ -572,8 +572,8 @@ def build_listing_string(items: List[str], play_all: bool = False) -> str:
|
||||
return listing
|
||||
|
||||
|
||||
def preroll_listing(schedule: List[ScheduleEntry], for_datetime: Optional[datetime] = None) -> str:
|
||||
"""Return listing of preroll videos to be used by Plex
|
||||
def pre_roll_listing(schedule: List[ScheduleEntry], for_datetime: Optional[datetime] = None) -> str:
|
||||
"""Return listing of pre_roll videos to be used by Plex
|
||||
|
||||
Args:
|
||||
schedule (List[ScheduleEntry]): List of schedule entries (See: getPrerollSchedule)
|
||||
@ -581,7 +581,7 @@ def preroll_listing(schedule: List[ScheduleEntry], for_datetime: Optional[dateti
|
||||
Useful for simulating what different dates produce
|
||||
|
||||
Returns:
|
||||
string: listing of preroll video paths to be used for Extras. CSV style: (;|,)
|
||||
string: listing of pre_roll video paths to be used for Extras. CSV style: (;|,)
|
||||
"""
|
||||
listing = ""
|
||||
entries = schedule_types()
|
||||
@ -598,8 +598,8 @@ def preroll_listing(schedule: List[ScheduleEntry], for_datetime: Optional[dateti
|
||||
# process the schedule for the given date
|
||||
for entry in schedule:
|
||||
try:
|
||||
entry_start = entry.startdate
|
||||
entry_end = entry.enddate
|
||||
entry_start = entry.start_date
|
||||
entry_end = entry.end_date
|
||||
if not isinstance(entry_start, datetime): # type: ignore
|
||||
entry_start = datetime.combine(entry_start, datetime.min.time())
|
||||
if not isinstance(entry_end, datetime): # type: ignore
|
||||
@ -628,7 +628,7 @@ def preroll_listing(schedule: List[ScheduleEntry], for_datetime: Optional[dateti
|
||||
# check new schedule item against exist list
|
||||
for e in entries[entry_type]:
|
||||
duration_new = duration_seconds(entry_start, entry_end)
|
||||
duration_curr = duration_seconds(e.startdate, e.enddate)
|
||||
duration_curr = duration_seconds(e.start_date, e.end_date)
|
||||
|
||||
# only the narrowest timeframe should stay
|
||||
# disregard if a force entry is there
|
||||
@ -655,10 +655,10 @@ def preroll_listing(schedule: List[ScheduleEntry], for_datetime: Optional[dateti
|
||||
if entries["monthly"] and not entries["weekly"] and not entries["date_range"]:
|
||||
merged_list.extend([p.path for p in entries["monthly"]]) # type: ignore
|
||||
if (
|
||||
entries["default"]
|
||||
and not entries["monthly"]
|
||||
and not entries["weekly"]
|
||||
and not entries["date_range"]
|
||||
entries["default"]
|
||||
and not entries["monthly"]
|
||||
and not entries["weekly"]
|
||||
and not entries["date_range"]
|
||||
):
|
||||
merged_list.extend([p.path for p in entries["default"]]) # type: ignore
|
||||
|
||||
@ -667,27 +667,27 @@ def preroll_listing(schedule: List[ScheduleEntry], for_datetime: Optional[dateti
|
||||
return listing
|
||||
|
||||
|
||||
def save_preroll_listing(plex: PlexServer, preroll_listing: Union[str, List[str]]) -> None:
|
||||
def save_pre_roll_listing(plex: PlexServer, pre_roll_listing: Union[str, List[str]]) -> None:
|
||||
"""Save Plex Preroll info to PlexServer settings
|
||||
|
||||
Args:
|
||||
plex (PlexServer): Plex server to update
|
||||
preroll_listing (str, list[str]): csv listing or List of preroll paths to save
|
||||
pre_roll_listing (str, list[str]): csv listing or List of pre_roll paths to save
|
||||
"""
|
||||
# if happend to send in an Iterable List, merge to a string
|
||||
if isinstance(preroll_listing, list):
|
||||
preroll_listing = build_listing_string(list(preroll_listing))
|
||||
# if happened to send in an Iterable List, merge to a string
|
||||
if isinstance(pre_roll_listing, list):
|
||||
pre_roll_listing = build_listing_string(list(pre_roll_listing))
|
||||
|
||||
logger.debug('Attempting save of pre-rolls: "%s"', preroll_listing)
|
||||
logger.debug('Attempting save of pre-rolls: "%s"', pre_roll_listing)
|
||||
|
||||
plex.settings.get("cinemaTrailersPrerollID").set(preroll_listing) # type: ignore
|
||||
plex.settings.get("cinemaTrailersPrerollID").set(pre_roll_listing) # type: ignore
|
||||
try:
|
||||
plex.settings.save() # type: ignore
|
||||
except Exception as e:
|
||||
logger.error('Unable to save Pre-Rolls to Server: "%s"', plex.friendlyName, exc_info=e) # type: ignore
|
||||
raise e
|
||||
|
||||
logger.info('Saved Pre-Rolls: Server: "%s" Pre-Rolls: "%s"', plex.friendlyName, preroll_listing) # type: ignore
|
||||
logger.info('Saved Pre-Rolls: Server: "%s" Pre-Rolls: "%s"', plex.friendlyName, pre_roll_listing) # type: ignore
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@ -716,12 +716,12 @@ if __name__ == "__main__":
|
||||
logger.error("Error connecting to Plex", exc_info=e)
|
||||
raise e
|
||||
|
||||
schedule = preroll_schedule(args.schedule_file)
|
||||
prerolls = preroll_listing(schedule)
|
||||
schedule = pre_roll_schedule(args.schedule_file)
|
||||
pre_rolls = pre_roll_listing(schedule)
|
||||
|
||||
if args.do_test_run:
|
||||
msg = f"Test Run of Plex Pre-Rolls: **Nothing being saved**\n{prerolls}\n"
|
||||
msg = f"Test Run of Plex Pre-Rolls: **Nothing being saved**\n{pre_rolls}\n"
|
||||
logger.debug(msg)
|
||||
print(msg)
|
||||
else:
|
||||
save_preroll_listing(plex, prerolls)
|
||||
save_pre_roll_listing(plex, pre_rolls)
|
||||
|
64
schedules.yaml.sample
Normal file
64
schedules.yaml.sample
Normal file
@ -0,0 +1,64 @@
|
||||
# All keys must be in lowercase
|
||||
# All paths will be case-sensitive based on your environment (Linux, Windows)
|
||||
|
||||
# Order of precedence:
|
||||
# 1. Misc always_use
|
||||
# 2. Date range
|
||||
# 3. Weekly
|
||||
# 4. Monthly
|
||||
# 5. Default
|
||||
|
||||
# Additional items for preroll selection processing
|
||||
misc:
|
||||
enabled: true
|
||||
always_use: /path/to/video.mp4 # If enabled, always include these video files in pre-role listing
|
||||
|
||||
# Schedule prerolls by date and time frames
|
||||
date_range:
|
||||
enabled: false
|
||||
ranges:
|
||||
# Each entry requires start_date, end_date, path values
|
||||
- start_date: 2020-01-01 # Jan 1st, 2020
|
||||
end_date: 2020-01-02 # Jan 2nd, 2020
|
||||
path: /path/to/video.mp4
|
||||
- start_date: xxxx-07-04 # Every year on July 4th
|
||||
end_date: xxxx-07-04 # Every year on July 4th
|
||||
path: /path/to/video.mp4
|
||||
- start_date: xxxx-xx-02 # Every year on the 2nd of every month
|
||||
end_date: xxxx-xx-03 # Every year on the 3rd of every month
|
||||
path: /path/to/video.mp4
|
||||
- start_date: xxxx-xx-xx 08:00:00 # Every day at 8am
|
||||
end_date: xxxx-xx-xx 09:30:00 # Every day at 9:30am
|
||||
path: /path/to/holiday_video.mp4
|
||||
|
||||
# Schedule prerolls by week of the year
|
||||
weekly:
|
||||
# No need to have all the week numbers; the script skips over missing entries
|
||||
# Each week number must be surrounded by quotes
|
||||
enabled: false
|
||||
"1":
|
||||
"2": /path/to/video.mkv
|
||||
"52":
|
||||
|
||||
# Schedule prerolls by month of the year
|
||||
monthly:
|
||||
# No need to have all the months here, script will skip over missing entries (logs a warning)
|
||||
# Keys must be lowercase, three-char month abbreviation
|
||||
enabled: false
|
||||
jan: /path/to/video.mp4
|
||||
feb:
|
||||
mar:
|
||||
apr:
|
||||
may: /path/to/video.mp4
|
||||
jun:
|
||||
jul:
|
||||
aug:
|
||||
sep: /path/to/video.mp4;/path/to/video.mp4
|
||||
oct:
|
||||
nov:
|
||||
dec:
|
||||
|
||||
# Use a default preroll if no other schedule is matched
|
||||
default:
|
||||
enabled: true
|
||||
path: /path/to/video.mp4
|
@ -21,7 +21,7 @@ SCRIPT_NAME = os.path.splitext(filename)[0]
|
||||
|
||||
|
||||
def plex_config(config_file: Optional[str] = "") -> Dict[str, str]:
|
||||
"""Return Plex Config paramaters for connection info {PLEX_URL, PLEX_TOKEN}\n
|
||||
"""Return Plex Config parameters for connection info {PLEX_URL, PLEX_TOKEN}\n
|
||||
Attempts to use one of either:\n
|
||||
* supplier path/to/config file (INI Format)
|
||||
* local config.ini (primary)
|
||||
|
Loading…
Reference in New Issue
Block a user