Rename; Removed deps from repo

This commit is contained in:
2021-02-05 16:30:46 +01:00
parent 97f80adf0b
commit b867dc9be2
1680 changed files with 1603 additions and 290357 deletions

View File

@@ -1,11 +0,0 @@
.git
.github
.gitignore
contrib
init-scripts
package
pylintrc
snap
*.md
!CHANGELOG*.md
start.bat

3
.github/FUNDING.yml vendored
View File

@@ -1,3 +0,0 @@
github: JonnyWong16
patreon: Tautulli
custom: ["https://bit.ly/2InPp15", "https://bit.ly/2WTq83m"]

View File

@@ -1,20 +0,0 @@
## Description
Please include a summary of the change and which issue is fixed.
Fixes Tautulli/Tautulli-Issues#(issue)
## Type of change
Please delete options that are not relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
## Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added or updated the docstring for new or existing methods

View File

@@ -1,115 +0,0 @@
name: Publish Docker
on:
push:
branches: [master, beta, nightly]
tags: [v*]
pull_request: ~
jobs:
build-docker:
name: Build Docker Image
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Prepare
id: prepare
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
echo ::set-output name=tag::${GITHUB_REF#refs/tags/}
elif [[ $GITHUB_REF == refs/heads/master ]]; then
echo ::set-output name=tag::latest
else
echo ::set-output name=tag::${GITHUB_REF#refs/heads/}
fi
if [[ $GITHUB_REF == refs/tags/*-beta ]]; then
echo ::set-output name=branch::beta
elif [[ $GITHUB_REF == refs/tags/* ]]; then
echo ::set-output name=branch::master
else
echo ::set-output name=branch::${GITHUB_REF#refs/heads/}
fi
echo ::set-output name=commit::${GITHUB_SHA}
echo ::set-output name=build_date::$(date -u +'%Y-%m-%dT%H:%M:%SZ')
echo ::set-output name=docker_platforms::linux/amd64,linux/arm64/v8,linux/arm/v7,linux/arm/v6
echo ::set-output name=docker_image::${{ secrets.DOCKER_REPO }}/tautulli
- name: Set Up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
id: buildx
with:
version: latest
- name: Cache Docker Layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to DockerHub
uses: docker/login-action@v1
if: success() && github.event_name != 'pull_request'
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
if: success() && github.event_name != 'pull_request'
with:
registry: ghcr.io
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.GHCR_TOKEN }}
- name: Docker Build and Push
uses: docker/build-push-action@v2
if: success()
with:
context: .
file: ./Dockerfile
push: ${{ github.event_name != 'pull_request' }}
platforms: ${{ steps.prepare.outputs.docker_platforms }}
build-args: |
TAG=${{ steps.prepare.outputs.tag }}
BRANCH=${{ steps.prepare.outputs.branch }}
COMMIT=${{ steps.prepare.outputs.commit }}
BUILD_DATE=${{ steps.prepare.outputs.build_date }}
tags: |
${{ steps.prepare.outputs.docker_image }}:${{ steps.prepare.outputs.tag }}
ghcr.io/${{ steps.prepare.outputs.docker_image }}:${{ steps.prepare.outputs.tag }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
discord:
name: Discord Notification
needs: build-docker
if: always() && github.event_name != 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Get Build Job Status
uses: technote-space/workflow-conclusion-action@v1
- name: Combine Job Status
id: status
run: |
failures=(neutral, skipped, timed_out, action_required)
if [[ ${array[@]} =~ $WORKFLOW_CONCLUSION ]]; then
echo ::set-output name=status::failure
else
echo ::set-output name=status::$WORKFLOW_CONCLUSION
fi
- name: Post Status to Discord
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ steps.status.outputs.status }}
title: ${{ github.workflow }}
nofail: true

View File

@@ -1,194 +0,0 @@
name: Publish Installers
on:
push:
branches: [master, beta, nightly]
tags: [v*]
pull_request: ~
jobs:
build-installer:
name: Build ${{ matrix.os_upper }} Installer
runs-on: ${{ matrix.os }}-latest
strategy:
fail-fast: false
matrix:
include:
- os: 'windows'
os_upper: 'Windows'
ext: 'exe'
- os: 'macos'
os_upper: 'MacOS'
ext: 'pkg'
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Set Release Version
id: get_version
shell: bash
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
VERSION_NSIS=${GITHUB_REF#refs/tags/v}.1
echo ::set-output name=VERSION_NSIS::${VERSION_NSIS/%-beta.1/.0}
echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/v}
echo ::set-output name=RELEASE_VERSION::${GITHUB_REF#refs/tags/}
else
echo "VERSION=0.0.0" >> $GITHUB_ENV
echo ::set-output name=VERSION_NSIS::0.0.0.0
echo ::set-output name=VERSION::0.0.0
echo ::set-output name=RELEASE_VERSION::${GITHUB_SHA::7}
fi
if [[ $GITHUB_REF == refs/tags/*-beta ]]; then
echo "beta" > branch.txt
elif [[ $GITHUB_REF == refs/tags/* ]]; then
echo "master" > branch.txt
else
echo ${GITHUB_REF#refs/heads/} > branch.txt
fi
echo $GITHUB_SHA > version.txt
- name: Set Up Python
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Cache Dependencies
uses: actions/cache@v2
with:
path: ~\AppData\Local\pip\Cache
key: ${{ runner.os }}-pip-${{ hashFiles(format('package/requirements-{0}.txt', matrix.os)) }}
restore-keys: ${{ runner.os }}-pip-
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r package/requirements-${{ matrix.os }}.txt
- name: Build Package
run: |
pyinstaller -y ./package/Tautulli-${{ matrix.os }}.spec
- name: Move Windows Updater Files
if: matrix.os == 'windows'
run: |
Move-Item dist\updater\* dist\Tautulli\ -Force
- name: Create Windows Installer
uses: joncloud/makensis-action@v3.4
if: matrix.os == 'windows'
with:
script-file: ./package/Tautulli.nsi
arguments: >
/DVERSION=${{ steps.get_version.outputs.VERSION_NSIS }}
/DINSTALLER_NAME=..\Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.exe
additional-plugin-paths: package/nsis-plugins
- name: Create MacOS Installer
if: matrix.os == 'macos'
run: |
sudo pkgbuild \
--install-location /Applications \
--version ${{ steps.get_version.outputs.VERSION }} \
--component ./dist/Tautulli.app \
--scripts ./package/macos-scripts \
Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.pkg
- name: Upload Installer
uses: actions/upload-artifact@v2
with:
name: Tautulli-${{ matrix.os }}-installer
path: Tautulli-${{ matrix.os }}-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.${{ matrix.ext }}
release:
name: Release Installers
needs: build-installer
if: always() && startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Get Build Job Status
uses: technote-space/workflow-conclusion-action@v1
- name: Checkout Code
uses: actions/checkout@v2
- name: Set Release Version
id: get_version
run: |
echo ::set-output name=RELEASE_VERSION::${GITHUB_REF#refs/tags/}
- name: Download Installers
if: env.WORKFLOW_CONCLUSION == 'success'
uses: actions/download-artifact@v2
- name: Get Changelog
id: get_changelog
run: |
echo ::set-output name=CHANGELOG::"$( sed -n '/^## /{p; :loop n; p; /^## /q; b loop}' CHANGELOG.md \
| sed '$d' | sed '$d' | sed '$d' | sed ':a;N;$!ba;s/\n/%0A/g' )"
- name: Create Release
uses: actions/create-release@v1
id: create_release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.get_version.outputs.RELEASE_VERSION }}
release_name: Tautulli ${{ steps.get_version.outputs.RELEASE_VERSION }}
body: |
## Changelog
##${{ steps.get_changelog.outputs.CHANGELOG }}
draft: false
prerelease: ${{ endsWith(steps.get_version.outputs.RELEASE_VERSION, '-beta') }}
- name: Upload Windows Installer
uses: actions/upload-release-asset@v1
if: env.WORKFLOW_CONCLUSION == 'success'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: Tautulli-windows-installer/Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.exe
asset_name: Tautulli-windows-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.exe
asset_content_type: application/vnd.microsoft.portable-executable
- name: Upload MacOS Installer
uses: actions/upload-release-asset@v1
if: env.WORKFLOW_CONCLUSION == 'success'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: Tautulli-macos-installer/Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.pkg
asset_name: Tautulli-macos-${{ steps.get_version.outputs.RELEASE_VERSION }}-x64.pkg
asset_content_type: application/vnd.apple.installer+xml
discord:
name: Discord Notification
needs: [build-installer, release]
if: always() && github.event_name != 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Get Build Job Status
uses: technote-space/workflow-conclusion-action@v1
- name: Combine Job Status
id: status
run: |
failures=(neutral, skipped, timed_out, action_required)
if [[ ${array[@]} =~ $WORKFLOW_CONCLUSION ]]; then
echo ::set-output name=status::failure
else
echo ::set-output name=status::$WORKFLOW_CONCLUSION
fi
- name: Post Status to Discord
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ steps.status.outputs.status }}
title: ${{ github.workflow }}
nofail: true

View File

@@ -1,94 +0,0 @@
name: Publish Snap
on:
push:
branches: [master, beta, nightly]
tags: [v*]
pull_request: ~
jobs:
build-snap:
name: Build Snap Package (${{ matrix.architecture }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
architecture:
- i386
- amd64
- arm64
- armhf
- ppc64el
#- s390x # broken at the moment
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Prepare
id: prepare
run: |
git fetch --prune --unshallow --tags
if [[ $GITHUB_REF == refs/tags/*-beta || $GITHUB_REF == refs/heads/beta ]]; then
echo ::set-output name=RELEASE::beta
elif [[ $GITHUB_REF == refs/tags/* || $GITHUB_REF == refs/heads/master ]]; then
echo ::set-output name=RELEASE::stable
else
echo ::set-output name=RELEASE::edge
fi
- name: Set Up QEMU
uses: docker/setup-qemu-action@v1
- name: Build Snap Package
uses: diddlesnaps/snapcraft-multiarch-action@v1
id: build
with:
architecture: ${{ matrix.architecture }}
- name: Upload Snap Package
uses: actions/upload-artifact@v2
with:
name: Tautulli-snap-package-${{ matrix.architecture }}
path: ${{ steps.build.outputs.snap }}
- name: Review Snap Package
uses: diddlesnaps/snapcraft-review-tools-action@v1
with:
snap: ${{ steps.build.outputs.snap }}
- name: Publish Snap Package
uses: snapcore/action-publish@v1
if: >
github.event_name != 'pull_request' &&
(startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/nightly')
with:
store_login: ${{ secrets.SNAP_LOGIN }}
snap: ${{ steps.build.outputs.snap }}
release: ${{ steps.prepare.outputs.RELEASE }}
discord:
name: Discord Notification
needs: build-snap
if: always() && github.event_name != 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Get Build Job Status
uses: technote-space/workflow-conclusion-action@v1
- name: Combine Job Status
id: status
run: |
failures=(neutral, skipped, timed_out, action_required)
if [[ ${array[@]} =~ $WORKFLOW_CONCLUSION ]]; then
echo ::set-output name=status::failure
else
echo ::set-output name=status::$WORKFLOW_CONCLUSION
fi
- name: Post Status to Discord
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ steps.status.outputs.status }}
title: ${{ github.workflow }}
nofail: true

View File

@@ -1,28 +0,0 @@
name: Pull Requests
on:
pull_request_target:
types: [opened, synchronize, edited, reopened]
jobs:
check-branch:
name: Check Pull Request
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Comment on Pull Request
uses: mshick/add-pr-comment@v1
if: github.base_ref != 'nightly'
with:
message: Pull requests must be made to the `nightly` branch. Thanks.
repo-token: ${{ secrets.GITHUB_TOKEN }}
repo-token-user-login: 'github-actions[bot]'
- name: Fail Workflow
if: github.base_ref != 'nightly'
run: |
echo Base: ${{ github.base_ref }}
echo Head: ${{ github.head_ref }}
exit 1

343
.gitignore vendored
View File

@@ -1,92 +1,275 @@
# Compiled source #
###################
__pycache__
*.pyc
*.py~
*.pyproj
*.sln
# Created by https://www.toptal.com/developers/gitignore/api/pycharm+all,python,linux,windows
# Edit at https://www.toptal.com/developers/gitignore?templates=pycharm+all,python,linux,windows
# PlexPy files #
######################
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### PyCharm+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### PyCharm+all Patch ###
# Ignores the whole .idea folder and all .iml files
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
.idea/
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
*.iml
modules.xml
.idea/misc.xml
*.ipr
# Sonarlint plugin
.idea/sonarlint
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
pytestdebug.log
# Translations
*.mo
*.pot
# Django stuff:
*.log
*.db*
*.db-journal
*.ini
release.lock
version.lock
logs/*
backups/*
cache/*
exports/*
newsletters/*
*.mmdb
version.txt
branch.txt
local_settings.py
db.sqlite3
db.sqlite3-journal
# HTTPS Cert/Key #
##################
/*.crt
/*.key
/*.csr
/*.pem
# Flask stuff:
instance/
.webassets-cache
# Mergetool
*.orgin
# Scrapy stuff:
.scrapy
# OS generated files #
######################
.DS_Store?
.DS_Store
ehthumbs.db
Icon?
# Sphinx documentation
docs/_build/
doc/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
pythonenv*
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# profiling data
.prof
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
#Ignore files generated by PyCharm
*.idea/*
# Dump file
*.stackdump
#Ignore files generated by vi
*.swp
# Folder config file
[Dd]esktop.ini
#Ignore files build by Visual Studio
*.obj
*.exe
*.pdb
*.user
*.aps
*.pch
*.vspscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.cache
*.ilk
[Bb]in
[Dd]ebug*/
*.lib
*.sbr
obj/
[Rr]elease*/
_ReSharper*/
[Tt]est[Rr]esult*
/cache
/logs
.project
.pydevproject
# Recycle Bin used on file shares
$RECYCLE.BIN/
#Ignore files generated by pyinstaller
/build
/dist
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
#snapcraft specifics
/parts/
/stage/
/prime/
*.snap
.snapcraft
*_source.tar.bz2
snap/.snapcraft
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/pycharm+all,python,linux,windows

View File

@@ -1,26 +0,0 @@
FROM tautulli/tautulli-baseimage:python3
LABEL maintainer="Tautulli"
ARG BRANCH
ARG COMMIT
ENV TAUTULLI_DOCKER=True
ENV TZ=UTC
WORKDIR /app
RUN \
groupadd -g 1000 tautulli && \
useradd -u 1000 -g 1000 tautulli && \
echo ${BRANCH} > /app/branch.txt && \
echo ${COMMIT} > /app/version.txt
COPY . /app
CMD [ "python", "Tautulli.py", "--datadir", "/config" ]
ENTRYPOINT [ "./start.sh" ]
VOLUME /config
EXPOSE 8181
HEALTHCHECK --start-period=90s CMD curl -ILfSs http://localhost:8181/status > /dev/null || curl -ILfkSs https://localhost:8181/status > /dev/null || exit 1

View File

@@ -20,11 +20,6 @@
import os
import sys
# Ensure lib added to path, before any other imports
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'lib'))
from future.builtins import str
import appdirs
import argparse
import datetime
@@ -36,16 +31,16 @@ import time
import threading
import tzlocal
import plexpy
from plexpy import common, config, database, helpers, logger, webstart
import jellypy
from jellypy import common, config, database, helpers, logger, webstart
if common.PLATFORM == 'Windows':
from plexpy import windows
from jellypy import windows
elif common.PLATFORM == 'Darwin':
from plexpy import macos
from jellypy import macos
# Register signals, such as CTRL + C
signal.signal(signal.SIGINT, plexpy.sig_handler)
signal.signal(signal.SIGTERM, plexpy.sig_handler)
signal.signal(signal.SIGINT, jellypy.sig_handler)
signal.signal(signal.SIGTERM, jellypy.sig_handler)
def main():
@@ -56,28 +51,28 @@ def main():
# Fixed paths to Tautulli
if hasattr(sys, 'frozen') and hasattr(sys, '_MEIPASS'):
plexpy.FROZEN = True
plexpy.FULL_PATH = os.path.abspath(sys.executable)
plexpy.PROG_DIR = sys._MEIPASS
jellypy.FROZEN = True
jellypy.FULL_PATH = os.path.abspath(sys.executable)
jellypy.PROG_DIR = sys._MEIPASS
else:
plexpy.FULL_PATH = os.path.abspath(__file__)
plexpy.PROG_DIR = os.path.dirname(plexpy.FULL_PATH)
jellypy.FULL_PATH = os.path.abspath(__file__)
jellypy.PROG_DIR = os.path.dirname(jellypy.FULL_PATH)
plexpy.ARGS = sys.argv[1:]
jellypy.ARGS = sys.argv[1:]
# From sickbeard
plexpy.SYS_PLATFORM = sys.platform
plexpy.SYS_ENCODING = None
jellypy.SYS_PLATFORM = sys.platform
jellypy.SYS_ENCODING = None
try:
locale.setlocale(locale.LC_ALL, "")
plexpy.SYS_LANGUAGE, plexpy.SYS_ENCODING = locale.getdefaultlocale()
jellypy.SYS_LANGUAGE, jellypy.SYS_ENCODING = locale.getdefaultlocale()
except (locale.Error, IOError):
pass
# for OSes that are poorly configured I'll just force UTF-8
if not plexpy.SYS_ENCODING or plexpy.SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
plexpy.SYS_ENCODING = 'UTF-8'
if not jellypy.SYS_ENCODING or jellypy.SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
jellypy.SYS_ENCODING = 'UTF-8'
# Set up and gather command line arguments
parser = argparse.ArgumentParser(
@@ -107,50 +102,50 @@ def main():
args = parser.parse_args()
if args.verbose:
plexpy.VERBOSE = True
jellypy.VERBOSE = True
if args.quiet:
plexpy.QUIET = True
jellypy.QUIET = True
# Do an intial setup of the logger.
# Require verbose for pre-initilization to see critical errors
logger.initLogger(console=not plexpy.QUIET, log_dir=False, verbose=True)
logger.initLogger(console=not jellypy.QUIET, log_dir=False, verbose=True)
try:
plexpy.SYS_TIMEZONE = tzlocal.get_localzone()
jellypy.SYS_TIMEZONE = tzlocal.get_localzone()
except (pytz.UnknownTimeZoneError, LookupError, ValueError) as e:
logger.error("Could not determine system timezone: %s" % e)
plexpy.SYS_TIMEZONE = pytz.UTC
jellypy.SYS_TIMEZONE = pytz.UTC
plexpy.SYS_UTC_OFFSET = datetime.datetime.now(plexpy.SYS_TIMEZONE).strftime('%z')
jellypy.SYS_UTC_OFFSET = datetime.datetime.now(jellypy.SYS_TIMEZONE).strftime('%z')
if helpers.bool_true(os.getenv('TAUTULLI_DOCKER', False)):
plexpy.DOCKER = True
jellypy.DOCKER = True
if helpers.bool_true(os.getenv('TAUTULLI_SNAP', False)):
plexpy.SNAP = True
jellypy.SNAP = True
if args.dev:
plexpy.DEV = True
jellypy.DEV = True
logger.debug("Tautulli is running in the dev environment.")
if args.daemon:
if sys.platform == 'win32':
logger.warn("Daemonizing not supported under Windows, starting normally")
else:
plexpy.DAEMON = True
plexpy.QUIET = True
jellypy.DAEMON = True
jellypy.QUIET = True
if args.nofork:
plexpy.NOFORK = True
jellypy.NOFORK = True
logger.info("Tautulli is running as a service, it will not fork when restarted.")
if args.pidfile:
plexpy.PIDFILE = str(args.pidfile)
jellypy.PIDFILE = str(args.pidfile)
# If the pidfile already exists, plexpy may still be running, so
# If the pidfile already exists, jellypy may still be running, so
# exit
if os.path.exists(plexpy.PIDFILE):
if os.path.exists(jellypy.PIDFILE):
try:
with open(plexpy.PIDFILE, 'r') as fp:
with open(jellypy.PIDFILE, 'r') as fp:
pid = int(fp.read())
except IOError as e:
raise SystemExit("Unable to read PID file: %s", e)
@@ -160,20 +155,20 @@ def main():
except OSError:
logger.warn("PID file '%s' already exists, but PID %d is "
"not running. Ignoring PID file." %
(plexpy.PIDFILE, pid))
(jellypy.PIDFILE, pid))
else:
# The pidfile exists and points to a live PID. plexpy may
# The pidfile exists and points to a live PID. jellypy may
# still be running, so exit.
raise SystemExit("PID file '%s' already exists. Exiting." %
plexpy.PIDFILE)
jellypy.PIDFILE)
# The pidfile is only useful in daemon mode, make sure we can write the
# file properly
if plexpy.DAEMON:
plexpy.CREATEPID = True
if jellypy.DAEMON:
jellypy.CREATEPID = True
try:
with open(plexpy.PIDFILE, 'w') as fp:
with open(jellypy.PIDFILE, 'w') as fp:
fp.write("pid\n")
except IOError as e:
raise SystemExit("Unable to write PID file: %s", e)
@@ -183,107 +178,107 @@ def main():
# Determine which data directory and config file to use
if args.datadir:
plexpy.DATA_DIR = args.datadir
elif plexpy.FROZEN:
plexpy.DATA_DIR = appdirs.user_data_dir("Tautulli", False)
jellypy.DATA_DIR = args.datadir
elif jellypy.FROZEN:
jellypy.DATA_DIR = appdirs.user_data_dir("Tautulli", False)
else:
plexpy.DATA_DIR = plexpy.PROG_DIR
jellypy.DATA_DIR = jellypy.PROG_DIR
# Migrate Snap data dir
if plexpy.SNAP:
if jellypy.SNAP:
snap_common = os.environ['SNAP_COMMON']
old_data_dir = os.path.join(snap_common, 'Tautulli')
if os.path.exists(old_data_dir) and os.listdir(old_data_dir):
plexpy.SNAP_MIGRATE = True
jellypy.SNAP_MIGRATE = True
logger.info("Migrating Snap user data.")
shutil.move(old_data_dir, plexpy.DATA_DIR)
shutil.move(old_data_dir, jellypy.DATA_DIR)
if args.config:
config_file = args.config
else:
config_file = os.path.join(plexpy.DATA_DIR, config.FILENAME)
config_file = os.path.join(jellypy.DATA_DIR, config.FILENAME)
# Try to create the DATA_DIR if it doesn't exist
if not os.path.exists(plexpy.DATA_DIR):
if not os.path.exists(jellypy.DATA_DIR):
try:
os.makedirs(plexpy.DATA_DIR)
os.makedirs(jellypy.DATA_DIR)
except OSError:
raise SystemExit(
'Could not create data directory: ' + plexpy.DATA_DIR + '. Exiting....')
'Could not create data directory: ' + jellypy.DATA_DIR + '. Exiting....')
# Make sure the DATA_DIR is writeable
if not os.access(plexpy.DATA_DIR, os.W_OK):
if not os.access(jellypy.DATA_DIR, os.W_OK):
raise SystemExit(
'Cannot write to the data directory: ' + plexpy.DATA_DIR + '. Exiting...')
'Cannot write to the data directory: ' + jellypy.DATA_DIR + '. Exiting...')
# Put the database in the DATA_DIR
plexpy.DB_FILE = os.path.join(plexpy.DATA_DIR, database.FILENAME)
jellypy.DB_FILE = os.path.join(jellypy.DATA_DIR, database.FILENAME)
# Move 'plexpy.db' to 'tautulli.db'
if os.path.isfile(os.path.join(plexpy.DATA_DIR, 'plexpy.db')) and \
not os.path.isfile(os.path.join(plexpy.DATA_DIR, plexpy.DB_FILE)):
# Move 'jellypy.db' to 'tautulli.db'
if os.path.isfile(os.path.join(jellypy.DATA_DIR, 'jellypy.db')) and \
not os.path.isfile(os.path.join(jellypy.DATA_DIR, jellypy.DB_FILE)):
try:
os.rename(os.path.join(plexpy.DATA_DIR, 'plexpy.db'), plexpy.DB_FILE)
os.rename(os.path.join(jellypy.DATA_DIR, 'jellypy.db'), jellypy.DB_FILE)
except OSError as e:
raise SystemExit("Unable to rename plexpy.db to tautulli.db: %s", e)
raise SystemExit("Unable to rename jellypy.db to tautulli.db: %s", e)
if plexpy.DAEMON:
plexpy.daemonize()
if jellypy.DAEMON:
jellypy.daemonize()
# Read config and start logging
plexpy.initialize(config_file)
jellypy.initialize(config_file)
# Start the background threads
plexpy.start()
jellypy.start()
# Force the http port if neccessary
if args.port:
plexpy.HTTP_PORT = args.port
logger.info('Using forced web server port: %i', plexpy.HTTP_PORT)
jellypy.HTTP_PORT = args.port
logger.info('Using forced web server port: %i', jellypy.HTTP_PORT)
else:
plexpy.HTTP_PORT = int(plexpy.CONFIG.HTTP_PORT)
jellypy.HTTP_PORT = int(jellypy.CONFIG.HTTP_PORT)
# Check if pyOpenSSL is installed. It is required for certificate generation
# and for CherryPy.
if plexpy.CONFIG.ENABLE_HTTPS:
if jellypy.CONFIG.ENABLE_HTTPS:
try:
import OpenSSL
except ImportError:
logger.warn("The pyOpenSSL module is missing. Install this "
"module to enable HTTPS. HTTPS will be disabled.")
plexpy.CONFIG.ENABLE_HTTPS = False
jellypy.CONFIG.ENABLE_HTTPS = False
# Try to start the server. Will exit here is address is already in use.
webstart.start()
if common.PLATFORM == 'Windows':
if plexpy.CONFIG.SYS_TRAY_ICON:
plexpy.WIN_SYS_TRAY_ICON = windows.WindowsSystemTray()
plexpy.WIN_SYS_TRAY_ICON.start()
if jellypy.CONFIG.SYS_TRAY_ICON:
jellypy.WIN_SYS_TRAY_ICON = windows.WindowsSystemTray()
jellypy.WIN_SYS_TRAY_ICON.start()
windows.set_startup()
elif common.PLATFORM == 'Darwin':
macos.set_startup()
# Open webbrowser
if plexpy.CONFIG.LAUNCH_BROWSER and not args.nolaunch and not plexpy.DEV:
plexpy.launch_browser(plexpy.CONFIG.HTTP_HOST, plexpy.HTTP_PORT,
plexpy.HTTP_ROOT)
if jellypy.CONFIG.LAUNCH_BROWSER and not args.nolaunch and not jellypy.DEV:
jellypy.launch_browser(jellypy.CONFIG.HTTP_HOST, jellypy.HTTP_PORT,
jellypy.HTTP_ROOT)
if common.PLATFORM == 'Darwin' and plexpy.CONFIG.SYS_TRAY_ICON:
if common.PLATFORM == 'Darwin' and jellypy.CONFIG.SYS_TRAY_ICON:
if not macos.HAS_PYOBJC:
logger.warn("The pyobjc module is missing. Install this "
"module to enable the MacOS menu bar icon.")
plexpy.CONFIG.SYS_TRAY_ICON = False
jellypy.CONFIG.SYS_TRAY_ICON = False
if plexpy.CONFIG.SYS_TRAY_ICON:
if jellypy.CONFIG.SYS_TRAY_ICON:
# MacOS menu bar icon must be run on the main thread and is blocking
# Start the rest of Tautulli on a new thread
thread = threading.Thread(target=wait)
thread.daemon = True
thread.start()
plexpy.MAC_SYS_TRAY_ICON = macos.MacOSSystemTray()
plexpy.MAC_SYS_TRAY_ICON.start()
jellypy.MAC_SYS_TRAY_ICON = macos.MacOSSystemTray()
jellypy.MAC_SYS_TRAY_ICON.start()
else:
wait()
else:
@@ -295,29 +290,29 @@ def wait():
# Wait endlessly for a signal to happen
while True:
if not plexpy.SIGNAL:
if not jellypy.SIGNAL:
try:
time.sleep(1)
except KeyboardInterrupt:
plexpy.SIGNAL = 'shutdown'
jellypy.SIGNAL = 'shutdown'
else:
logger.info('Received signal: %s', plexpy.SIGNAL)
logger.info('Received signal: %s', jellypy.SIGNAL)
if plexpy.SIGNAL == 'shutdown':
plexpy.shutdown()
elif plexpy.SIGNAL == 'restart':
plexpy.shutdown(restart=True)
elif plexpy.SIGNAL == 'checkout':
plexpy.shutdown(restart=True, checkout=True)
elif plexpy.SIGNAL == 'reset':
plexpy.shutdown(restart=True, reset=True)
elif plexpy.SIGNAL == 'update':
plexpy.shutdown(restart=True, update=True)
if jellypy.SIGNAL == 'shutdown':
jellypy.shutdown()
elif jellypy.SIGNAL == 'restart':
jellypy.shutdown(restart=True)
elif jellypy.SIGNAL == 'checkout':
jellypy.shutdown(restart=True, checkout=True)
elif jellypy.SIGNAL == 'reset':
jellypy.shutdown(restart=True, reset=True)
elif jellypy.SIGNAL == 'update':
jellypy.shutdown(restart=True, update=True)
else:
logger.error('Unknown signal. Shutting down...')
plexpy.shutdown()
jellypy.shutdown()
plexpy.SIGNAL = None
jellypy.SIGNAL = None
if __name__ == "__main__":

View File

@@ -1,24 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Tautulli is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from Tautulli import main
# Call main() from Tautulli.py
if __name__ == "__main__":
main()

View File

@@ -1,8 +1,8 @@
# Tautulli
# JellyPy
A python based web application for monitoring, analytics and notifications for [Plex Media Server](https://plex.tv).
A python based web application for monitoring, analytics and notifications for [Jellyfin](https://jellyfin.org/).
This project is based on code from [Headphones](https://github.com/rembo10/headphones) and [PlexWatchWeb](https://github.com/ecleese/plexWatchWeb).
This project is based on [Tautulli](https://github.com/Tautulli/Tautulli).
## Features
@@ -63,4 +63,6 @@ This project is based on code from [Headphones](https://github.com/rembo10/headp
This is free software under the GPL v3 open source license. Feel free to do with it what you wish, but any modification must be open sourced. A copy of the license is included.
This software includes Highsoft software libraries which you may freely distribute for non-commercial use. Commerical users must licence this software, for more information visit https://shop.highsoft.com/faq/non-commercial#non-commercial-redistribution.
This software includes Highsoft software libraries which you may freely distribute for non-commercial use. Commerical users must licence this software, for more information visit https://shop.highsoft.com/faq/non-commercial#non-commercial-redistribution.
[Tautulli]: https://github.com/Tautulli/Tautulli

View File

@@ -2024,7 +2024,7 @@ Rating: {rating}/10 --> Rating: /10
cache: false,
async: true,
complete: function(xhr, status) {
$("#plexpy-configuration-table").html(xhr.responseText);
$("#jellypy-configuration-table").html(xhr.responseText);
}
});
}
@@ -2035,7 +2035,7 @@ Rating: {rating}/10 --> Rating: /10
cache: false,
async: true,
complete: function(xhr, status) {
$("#plexpy-scheduler-table").html(xhr.responseText);
$("#jellypy-scheduler-table").html(xhr.responseText);
}
});
}
@@ -2046,7 +2046,7 @@ Rating: {rating}/10 --> Rating: /10
cache: false,
async: true,
complete: function(xhr, status) {
$("#plexpy-notifiers-table").html(xhr.responseText);
$("#jellypy-notifiers-table").html(xhr.responseText);
}
});
}
@@ -2071,7 +2071,7 @@ Rating: {rating}/10 --> Rating: /10
cache: false,
async: true,
complete: function(xhr, status) {
$("#plexpy-newsletters-table").html(xhr.responseText);
$("#jellypy-newsletters-table").html(xhr.responseText);
}
});
}
@@ -2096,7 +2096,7 @@ Rating: {rating}/10 --> Rating: /10
cache: false,
async: true,
complete: function(xhr, status) {
$("#plexpy-mobile-devices-table").html(xhr.responseText);
$("#jellypy-mobile-devices-table").html(xhr.responseText);
}
});
}

View File

@@ -13,73 +13,48 @@
# You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
from future.builtins import range
import datetime
import os
import future.moves.queue as queue
import sqlite3
import sys
import subprocess
import sys
import threading
import uuid
import future.moves.queue as queue
from future.builtins import range
# Some cut down versions of Python may not include this module and it's not critical for us
try:
import webbrowser
no_browser = False
except ImportError:
no_browser = True
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.interval import IntervalTrigger
from UniversalAnalytics import Tracker
import pytz
PYTHON2 = sys.version_info[0] == 2
if PYTHON2:
import activity_handler
import activity_pinger
import common
import database
import datafactory
import exporter
import libraries
import logger
import mobile_app
import newsletters
import newsletter_handler
import notification_handler
import notifiers
import plextv
import users
import versioncheck
import web_socket
import webstart
import config
else:
from plexpy import activity_handler
from plexpy import activity_pinger
from plexpy import common
from plexpy import database
from plexpy import datafactory
from plexpy import exporter
from plexpy import libraries
from plexpy import logger
from plexpy import mobile_app
from plexpy import newsletters
from plexpy import newsletter_handler
from plexpy import notification_handler
from plexpy import notifiers
from plexpy import plextv
from plexpy import users
from plexpy import versioncheck
from plexpy import web_socket
from plexpy import webstart
from plexpy import config
from jellypy import activity_handler
from jellypy import activity_pinger
from jellypy import common
from jellypy import database
from jellypy import datafactory
from jellypy import exporter
from jellypy import libraries
from jellypy import logger
from jellypy import mobile_app
from jellypy import newsletters
from jellypy import newsletter_handler
from jellypy import notification_handler
from jellypy import notifiers
from jellypy import plextv
from jellypy import users
from jellypy import versioncheck
from jellypy import web_socket
from jellypy import webstart
from jellypy import config
PROG_DIR = None
FULL_PATH = None
@@ -502,7 +477,7 @@ def initialize_scheduler():
def schedule_job(func, name, hours=0, minutes=0, seconds=0, args=None):
"""
Start scheduled job if starting or restarting plexpy.
Start scheduled job if starting or restarting jellypy.
Reschedule job if Interval Settings have changed.
Remove job if if Interval Settings changed to 0
@@ -2388,47 +2363,6 @@ def generate_uuid():
return uuid.uuid4().hex
def initialize_tracker():
data = {
'dataSource': 'server',
'appName': common.PRODUCT,
'appVersion': common.RELEASE,
'appId': INSTALL_TYPE,
'appInstallerId': CONFIG.GIT_BRANCH,
'dimension1': '{} {}'.format(common.PLATFORM, common.PLATFORM_RELEASE), # App Platform
'dimension2': common.PLATFORM_LINUX_DISTRO, # Linux Distro
'dimension3': common.PYTHON_VERSION,
'userLanguage': SYS_LANGUAGE,
'documentEncoding': SYS_ENCODING,
'noninteractive': True
}
tracker = Tracker.create('UA-111522699-2', client_id=CONFIG.PMS_UUID, hash_client_id=True,
user_agent=common.USER_AGENT)
tracker.set(data)
return tracker
def analytics_event(category, action, label=None, value=None, **kwargs):
data = {'category': category, 'action': action}
if label is not None:
data['label'] = label
if value is not None:
data['value'] = value
if kwargs:
data.update(kwargs)
if TRACKER:
try:
TRACKER.send('event', data)
except Exception as e:
logger.warn("Failed to send analytics event for category '%s', action '%s': %s" % (category, action, e))
def check_folder_writable(folder, fallback, name):
if not folder:
folder = fallback
@@ -2461,7 +2395,7 @@ def get_tautulli_info():
'tautulli_version': common.RELEASE,
'tautulli_branch': CONFIG.GIT_BRANCH,
'tautulli_commit': CURRENT_VERSION,
'tautulli_platform':common.PLATFORM,
'tautulli_platform': common.PLATFORM,
'tautulli_platform_release': common.PLATFORM_RELEASE,
'tautulli_platform_version': common.PLATFORM_VERSION,
'tautulli_platform_linux_distro': common.PLATFORM_LINUX_DISTRO,

View File

@@ -24,8 +24,8 @@ import time
from apscheduler.triggers.date import DateTrigger
import pytz
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import activity_processor
import datafactory
import helpers
@@ -33,12 +33,12 @@ if plexpy.PYTHON2:
import notification_handler
import pmsconnect
else:
from plexpy import activity_processor
from plexpy import datafactory
from plexpy import helpers
from plexpy import logger
from plexpy import notification_handler
from plexpy import pmsconnect
from jellypy import activity_processor
from jellypy import datafactory
from jellypy import helpers
from jellypy import logger
from jellypy import notification_handler
from jellypy import pmsconnect
ACTIVITY_SCHED = None
@@ -134,7 +134,7 @@ class ActivityHandler(object):
str(session['rating_key']), session['full_title'], '[Live TV]' if session['live'] else ''))
# Send notification after updating db
#plexpy.NOTIFY_QUEUE.put({'stream_data': session.copy(), 'notify_action': 'on_play'})
#jellypy.NOTIFY_QUEUE.put({'stream_data': session.copy(), 'notify_action': 'on_play'})
# Write the new session to our temp session table
self.update_db_session(session=session, notify=True)
@@ -162,7 +162,7 @@ class ActivityHandler(object):
# Retrieve the session data from our temp table
db_session = ap.get_session_by_key(session_key=self.get_session_key())
plexpy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_stop'})
jellypy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_stop'})
# Write it to the history table
monitor_proc = activity_processor.ActivityProcessor()
@@ -198,7 +198,7 @@ class ActivityHandler(object):
db_session = ap.get_session_by_key(session_key=self.get_session_key())
if not still_paused:
plexpy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_pause'})
jellypy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_pause'})
def on_resume(self):
if self.is_valid_session():
@@ -214,7 +214,7 @@ class ActivityHandler(object):
# Retrieve the session data from our temp table
db_session = ap.get_session_by_key(session_key=self.get_session_key())
plexpy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_resume'})
jellypy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_resume'})
def on_change(self):
if self.is_valid_session():
@@ -227,7 +227,7 @@ class ActivityHandler(object):
ap = activity_processor.ActivityProcessor()
db_session = ap.get_session_by_key(session_key=self.get_session_key())
plexpy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_change'})
jellypy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_change'})
def on_buffer(self):
if self.is_valid_session():
@@ -255,14 +255,14 @@ class ActivityHandler(object):
(self.get_session_key(), buffer_last_triggered))
time_since_last_trigger = helpers.timestamp() - int(buffer_last_triggered)
if current_buffer_count >= plexpy.CONFIG.BUFFER_THRESHOLD and time_since_last_trigger == 0 or \
time_since_last_trigger >= plexpy.CONFIG.BUFFER_WAIT:
if current_buffer_count >= jellypy.CONFIG.BUFFER_THRESHOLD and time_since_last_trigger == 0 or \
time_since_last_trigger >= jellypy.CONFIG.BUFFER_WAIT:
ap.set_session_buffer_trigger_time(session_key=self.get_session_key())
# Retrieve the session data from our temp table
db_session = ap.get_session_by_key(session_key=self.get_session_key())
plexpy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_buffer'})
jellypy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_buffer'})
def on_error(self):
if self.is_valid_session():
@@ -275,7 +275,7 @@ class ActivityHandler(object):
ap = activity_processor.ActivityProcessor()
db_session = ap.get_session_by_key(session_key=self.get_session_key())
plexpy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_error'})
jellypy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_error'})
# This function receives events from our websocket connection
def process(self):
@@ -358,10 +358,10 @@ class ActivityHandler(object):
# The only purpose of this is for notifications
if not db_session['watched'] and this_state != 'buffering':
progress_percent = helpers.get_percent(self.timeline['viewOffset'], db_session['duration'])
watched_percent = {'movie': plexpy.CONFIG.MOVIE_WATCHED_PERCENT,
'episode': plexpy.CONFIG.TV_WATCHED_PERCENT,
'track': plexpy.CONFIG.MUSIC_WATCHED_PERCENT,
'clip': plexpy.CONFIG.TV_WATCHED_PERCENT
watched_percent = {'movie': jellypy.CONFIG.MOVIE_WATCHED_PERCENT,
'episode': jellypy.CONFIG.TV_WATCHED_PERCENT,
'track': jellypy.CONFIG.MUSIC_WATCHED_PERCENT,
'clip': jellypy.CONFIG.TV_WATCHED_PERCENT
}
if progress_percent >= watched_percent.get(db_session['media_type'], 101):
@@ -373,7 +373,7 @@ class ActivityHandler(object):
session=db_session, notify_action='on_watched', notified=False)
for d in watched_notifiers:
plexpy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(),
jellypy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(),
'notifier_id': d['notifier_id'],
'notify_action': 'on_watched'})
@@ -440,7 +440,7 @@ class TimelineHandler(object):
# Add a new media item to the recently added queue
if media_type and section_id > 0 and \
((state_type == 0 and metadata_state == 'created')): # or \
#(plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_UPGRADE and state_type in (1, 5) and \
#(jellypy.CONFIG.NOTIFY_RECENTLY_ADDED_UPGRADE and state_type in (1, 5) and \
#media_state == 'analyzing' and queue_size is None)):
if media_type in ('episode', 'track'):
@@ -467,7 +467,7 @@ class TimelineHandler(object):
schedule_callback('rating_key-{}'.format(grandparent_rating_key),
func=clear_recently_added_queue,
args=[grandparent_rating_key, grandparent_title],
seconds=plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY)
seconds=jellypy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY)
elif media_type in ('season', 'album'):
metadata = self.get_metadata()
@@ -486,7 +486,7 @@ class TimelineHandler(object):
schedule_callback('rating_key-{}'.format(parent_rating_key),
func=clear_recently_added_queue,
args=[parent_rating_key, parent_title],
seconds=plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY)
seconds=jellypy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY)
else:
queue_set = RECENTLY_ADDED_QUEUE.get(rating_key, set())
@@ -499,7 +499,7 @@ class TimelineHandler(object):
schedule_callback('rating_key-{}'.format(rating_key),
func=clear_recently_added_queue,
args=[rating_key, title],
seconds=plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY)
seconds=jellypy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY)
# A movie, show, or artist is done processing
elif media_type in ('movie', 'show', 'artist') and section_id > 0 and \
@@ -536,10 +536,10 @@ class ReachabilityHandler(object):
return helpers.bool_true(pref)
def on_down(self, server_response):
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_extdown', 'remote_access_info': server_response})
jellypy.NOTIFY_QUEUE.put({'notify_action': 'on_extdown', 'remote_access_info': server_response})
def on_up(self, server_response):
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_extup', 'remote_access_info': server_response})
jellypy.NOTIFY_QUEUE.put({'notify_action': 'on_extup', 'remote_access_info': server_response})
def process(self):
# Check if remote access is enabled
@@ -547,7 +547,7 @@ class ReachabilityHandler(object):
return
# Do nothing if remote access is still up and hasn't changed
if self.is_reachable() and plexpy.PLEX_REMOTE_ACCESS_UP:
if self.is_reachable() and jellypy.PLEX_REMOTE_ACCESS_UP:
return
pms_connect = pmsconnect.PmsConnect()
@@ -558,22 +558,22 @@ class ReachabilityHandler(object):
if server_response['mapping_state'] == 'waiting':
logger.warn("Tautulli ReachabilityHandler :: Remote access waiting for port mapping.")
elif plexpy.PLEX_REMOTE_ACCESS_UP is not False and server_response['reason']:
elif jellypy.PLEX_REMOTE_ACCESS_UP is not False and server_response['reason']:
logger.warn("Tautulli ReachabilityHandler :: Remote access failed: %s" % server_response['reason'])
logger.info("Tautulli ReachabilityHandler :: Plex remote access is down.")
plexpy.PLEX_REMOTE_ACCESS_UP = False
jellypy.PLEX_REMOTE_ACCESS_UP = False
if not ACTIVITY_SCHED.get_job('on_extdown'):
logger.debug("Tautulli ReachabilityHandler :: Schedule remote access down callback in %d seconds.",
plexpy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD)
jellypy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD)
schedule_callback('on_extdown', func=self.on_down, args=[server_response],
seconds=plexpy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD)
seconds=jellypy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD)
elif plexpy.PLEX_REMOTE_ACCESS_UP is False and not server_response['reason']:
elif jellypy.PLEX_REMOTE_ACCESS_UP is False and not server_response['reason']:
logger.info("Tautulli ReachabilityHandler :: Plex remote access is back up.")
plexpy.PLEX_REMOTE_ACCESS_UP = True
jellypy.PLEX_REMOTE_ACCESS_UP = True
if ACTIVITY_SCHED.get_job('on_extdown'):
logger.debug("Tautulli ReachabilityHandler :: Cancelling scheduled remote access down callback.")
@@ -581,8 +581,8 @@ class ReachabilityHandler(object):
else:
self.on_up(server_response)
elif plexpy.PLEX_REMOTE_ACCESS_UP is None:
plexpy.PLEX_REMOTE_ACCESS_UP = self.is_reachable()
elif jellypy.PLEX_REMOTE_ACCESS_UP is None:
jellypy.PLEX_REMOTE_ACCESS_UP = self.is_reachable()
def del_keys(key):
@@ -626,7 +626,7 @@ def force_stop_stream(session_key, title, user):
else:
session['write_attempts'] += 1
if session['write_attempts'] < plexpy.CONFIG.SESSION_DB_WRITE_ATTEMPTS:
if session['write_attempts'] < jellypy.CONFIG.SESSION_DB_WRITE_ATTEMPTS:
logger.warn("Tautulli ActivityHandler :: Failed to write stream with sessionKey %s ratingKey %s to the database. " \
"Will try again in 30 seconds. Write attempt %s."
% (session['session_key'], session['rating_key'], str(session['write_attempts'])))
@@ -649,14 +649,14 @@ def force_stop_stream(session_key, title, user):
def clear_recently_added_queue(rating_key, title):
child_keys = RECENTLY_ADDED_QUEUE[rating_key]
if plexpy.CONFIG.NOTIFY_GROUP_RECENTLY_ADDED_GRANDPARENT and len(child_keys) > 1:
if jellypy.CONFIG.NOTIFY_GROUP_RECENTLY_ADDED_GRANDPARENT and len(child_keys) > 1:
on_created(rating_key, child_keys=child_keys)
elif child_keys:
for child_key in child_keys:
grandchild_keys = RECENTLY_ADDED_QUEUE.get(child_key, [])
if plexpy.CONFIG.NOTIFY_GROUP_RECENTLY_ADDED_PARENT and len(grandchild_keys) > 1:
if jellypy.CONFIG.NOTIFY_GROUP_RECENTLY_ADDED_PARENT and len(grandchild_keys) > 1:
on_created(child_key, child_keys=grandchild_keys)
elif grandchild_keys:
@@ -697,7 +697,7 @@ def on_created(rating_key, **kwargs):
if notify:
data = {'timeline_data': metadata, 'notify_action': 'on_created'}
data.update(kwargs)
plexpy.NOTIFY_QUEUE.put(data)
jellypy.NOTIFY_QUEUE.put(data)
all_keys = [rating_key]
if 'child_keys' in kwargs:
@@ -714,7 +714,7 @@ def on_created(rating_key, **kwargs):
def delete_metadata_cache(session_key):
try:
os.remove(os.path.join(plexpy.CONFIG.CACHE_DIR, 'session_metadata/metadata-sessionKey-%s.json' % session_key))
os.remove(os.path.join(jellypy.CONFIG.CACHE_DIR, 'session_metadata/metadata-sessionKey-%s.json' % session_key))
except OSError as e:
logger.error("Tautulli ActivityHandler :: Failed to remove metadata cache file (sessionKey %s): %s"
% (session_key, e))

View File

@@ -18,8 +18,8 @@ from future.builtins import str
import threading
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import activity_handler
import activity_processor
import database
@@ -31,16 +31,16 @@ if plexpy.PYTHON2:
import pmsconnect
import web_socket
else:
from plexpy import activity_handler
from plexpy import activity_processor
from plexpy import database
from plexpy import helpers
from plexpy import libraries
from plexpy import logger
from plexpy import notification_handler
from plexpy import plextv
from plexpy import pmsconnect
from plexpy import web_socket
from jellypy import activity_handler
from jellypy import activity_processor
from jellypy import database
from jellypy import helpers
from jellypy import libraries
from jellypy import logger
from jellypy import notification_handler
from jellypy import plextv
from jellypy import pmsconnect
from jellypy import web_socket
monitor_lock = threading.Lock()
@@ -82,28 +82,28 @@ def check_active_sessions(ws_request=False):
if session['state'] == 'paused':
logger.debug("Tautulli Monitor :: Session %s paused." % stream['session_key'])
plexpy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_pause'})
jellypy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_pause'})
if session['state'] == 'playing' and stream['state'] == 'paused':
logger.debug("Tautulli Monitor :: Session %s resumed." % stream['session_key'])
plexpy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_resume'})
jellypy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_resume'})
if session['state'] == 'error':
logger.debug("Tautulli Monitor :: Session %s encountered an error." % stream['session_key'])
plexpy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_error'})
jellypy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_error'})
if stream['state'] == 'paused' and not ws_request:
# The stream is still paused so we need to increment the paused_counter
# Using the set config parameter as the interval, probably not the most accurate but
# it will have to do for now. If it's a websocket request don't use this method.
paused_counter = int(stream['paused_counter']) + plexpy.CONFIG.MONITORING_INTERVAL
paused_counter = int(stream['paused_counter']) + jellypy.CONFIG.MONITORING_INTERVAL
monitor_db.action('UPDATE sessions SET paused_counter = ? '
'WHERE session_key = ? AND rating_key = ?',
[paused_counter, stream['session_key'], stream['rating_key']])
if session['state'] == 'buffering' and plexpy.CONFIG.BUFFER_THRESHOLD > 0:
if session['state'] == 'buffering' and jellypy.CONFIG.BUFFER_THRESHOLD > 0:
# The stream is buffering so we need to increment the buffer_count
# We're going just increment on every monitor ping,
# would be difficult to keep track otherwise
@@ -117,11 +117,11 @@ def check_active_sessions(ws_request=False):
'WHERE session_key = ? AND rating_key = ?',
[stream['session_key'], stream['rating_key']])
if buffer_values[0]['buffer_count'] >= plexpy.CONFIG.BUFFER_THRESHOLD:
if buffer_values[0]['buffer_count'] >= jellypy.CONFIG.BUFFER_THRESHOLD:
# Push any notifications -
# Push it on it's own thread so we don't hold up our db actions
# Our first buffer notification
if buffer_values[0]['buffer_count'] == plexpy.CONFIG.BUFFER_THRESHOLD:
if buffer_values[0]['buffer_count'] == jellypy.CONFIG.BUFFER_THRESHOLD:
logger.info("Tautulli Monitor :: User '%s' has triggered a buffer warning."
% stream['user'])
# Set the buffer trigger time
@@ -130,12 +130,12 @@ def check_active_sessions(ws_request=False):
'WHERE session_key = ? AND rating_key = ?',
[stream['session_key'], stream['rating_key']])
plexpy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_buffer'})
jellypy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_buffer'})
else:
# Subsequent buffer notifications after wait time
if helpers.timestamp() > buffer_values[0]['buffer_last_triggered'] + \
plexpy.CONFIG.BUFFER_WAIT:
jellypy.CONFIG.BUFFER_WAIT:
logger.info("Tautulli Monitor :: User '%s' has triggered multiple buffer warnings."
% stream['user'])
# Set the buffer trigger time
@@ -144,7 +144,7 @@ def check_active_sessions(ws_request=False):
'WHERE session_key = ? AND rating_key = ?',
[stream['session_key'], stream['rating_key']])
plexpy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_buffer'})
jellypy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_buffer'})
logger.debug("Tautulli Monitor :: Session %s is buffering. Count is now %s. Last triggered %s."
% (stream['session_key'],
@@ -157,11 +157,11 @@ def check_active_sessions(ws_request=False):
if session['state'] != 'buffering':
progress_percent = helpers.get_percent(session['view_offset'], session['duration'])
notify_states = notification_handler.get_notify_state(session=session)
if (session['media_type'] == 'movie' and progress_percent >= plexpy.CONFIG.MOVIE_WATCHED_PERCENT or
session['media_type'] == 'episode' and progress_percent >= plexpy.CONFIG.TV_WATCHED_PERCENT or
session['media_type'] == 'track' and progress_percent >= plexpy.CONFIG.MUSIC_WATCHED_PERCENT) \
if (session['media_type'] == 'movie' and progress_percent >= jellypy.CONFIG.MOVIE_WATCHED_PERCENT or
session['media_type'] == 'episode' and progress_percent >= jellypy.CONFIG.TV_WATCHED_PERCENT or
session['media_type'] == 'track' and progress_percent >= jellypy.CONFIG.MUSIC_WATCHED_PERCENT) \
and not any(d['notify_action'] == 'on_watched' for d in notify_states):
plexpy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_watched'})
jellypy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_watched'})
else:
# The user has stopped playing a stream
@@ -177,13 +177,13 @@ def check_active_sessions(ws_request=False):
progress_percent = helpers.get_percent(stream['view_offset'], stream['duration'])
notify_states = notification_handler.get_notify_state(session=stream)
if (stream['media_type'] == 'movie' and progress_percent >= plexpy.CONFIG.MOVIE_WATCHED_PERCENT or
stream['media_type'] == 'episode' and progress_percent >= plexpy.CONFIG.TV_WATCHED_PERCENT or
stream['media_type'] == 'track' and progress_percent >= plexpy.CONFIG.MUSIC_WATCHED_PERCENT) \
if (stream['media_type'] == 'movie' and progress_percent >= jellypy.CONFIG.MOVIE_WATCHED_PERCENT or
stream['media_type'] == 'episode' and progress_percent >= jellypy.CONFIG.TV_WATCHED_PERCENT or
stream['media_type'] == 'track' and progress_percent >= jellypy.CONFIG.MUSIC_WATCHED_PERCENT) \
and not any(d['notify_action'] == 'on_watched' for d in notify_states):
plexpy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_watched'})
jellypy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_watched'})
plexpy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_stop'})
jellypy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_stop'})
# Write the item history on playback stop
row_id = monitor_process.write_session_history(session=stream)
@@ -196,7 +196,7 @@ def check_active_sessions(ws_request=False):
else:
stream['write_attempts'] += 1
if stream['write_attempts'] < plexpy.CONFIG.SESSION_DB_WRITE_ATTEMPTS:
if stream['write_attempts'] < jellypy.CONFIG.SESSION_DB_WRITE_ATTEMPTS:
logger.warn("Tautulli Monitor :: Failed to write sessionKey %s ratingKey %s to the database. " \
"Will try again on the next pass. Write attempt %s."
% (stream['session_key'], stream['rating_key'], str(stream['write_attempts'])))
@@ -223,7 +223,7 @@ def check_active_sessions(ws_request=False):
def connect_server(log=True, startup=False):
if plexpy.CONFIG.PMS_IS_CLOUD:
if jellypy.CONFIG.PMS_IS_CLOUD:
if log:
logger.info("Tautulli Monitor :: Checking for Plex Cloud server status...")
@@ -264,12 +264,12 @@ def check_server_updates():
download_info = plex_tv.get_plex_downloads()
if download_info:
logger.info("Tautulli Monitor :: Current PMS version: %s", plexpy.CONFIG.PMS_VERSION)
logger.info("Tautulli Monitor :: Current PMS version: %s", jellypy.CONFIG.PMS_VERSION)
if download_info['update_available']:
logger.info("Tautulli Monitor :: PMS update available version: %s", download_info['version'])
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_pmsupdate', 'pms_download_info': download_info})
jellypy.NOTIFY_QUEUE.put({'notify_action': 'on_pmsupdate', 'pms_download_info': download_info})
else:
logger.info("Tautulli Monitor :: No PMS update available.")

View File

@@ -20,8 +20,8 @@ from future.builtins import object
from collections import defaultdict
import json
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import database
import helpers
import libraries
@@ -29,12 +29,12 @@ if plexpy.PYTHON2:
import pmsconnect
import users
else:
from plexpy import database
from plexpy import helpers
from plexpy import libraries
from plexpy import logger
from plexpy import pmsconnect
from plexpy import users
from jellypy import database
from jellypy import helpers
from jellypy import libraries
from jellypy import logger
from jellypy import pmsconnect
from jellypy import users
class ActivityProcessor(object):
@@ -165,7 +165,7 @@ class ActivityProcessor(object):
# Check if any notification agents have notifications enabled
if notify:
session.update(timestamp)
plexpy.NOTIFY_QUEUE.put({'stream_data': session.copy(), 'notify_action': 'on_play'})
jellypy.NOTIFY_QUEUE.put({'stream_data': session.copy(), 'notify_action': 'on_play'})
# Add Live TV library if it hasn't been added
if values['live']:
@@ -231,14 +231,14 @@ class ActivityProcessor(object):
real_play_time = stopped - helpers.cast_to_int(session['started']) - helpers.cast_to_int(session['paused_counter'])
if not is_import and plexpy.CONFIG.LOGGING_IGNORE_INTERVAL:
if not is_import and jellypy.CONFIG.LOGGING_IGNORE_INTERVAL:
if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \
(real_play_time < int(plexpy.CONFIG.LOGGING_IGNORE_INTERVAL)):
(real_play_time < int(jellypy.CONFIG.LOGGING_IGNORE_INTERVAL)):
logging_enabled = False
logger.debug("Tautulli ActivityProcessor :: Play duration for session %s ratingKey %s is %s secs "
"which is less than %s seconds, so we're not logging it." %
(session['session_key'], session['rating_key'], str(real_play_time),
plexpy.CONFIG.LOGGING_IGNORE_INTERVAL))
jellypy.CONFIG.LOGGING_IGNORE_INTERVAL))
if not is_import and session['media_type'] == 'track':
if real_play_time < 15 and helpers.cast_to_int(session['duration']) >= 30:
logging_enabled = False
@@ -360,9 +360,9 @@ class ActivityProcessor(object):
'view_offset': result[1]['view_offset'],
'reference_id': result[1]['reference_id']}
watched_percent = {'movie': plexpy.CONFIG.MOVIE_WATCHED_PERCENT,
'episode': plexpy.CONFIG.TV_WATCHED_PERCENT,
'track': plexpy.CONFIG.MUSIC_WATCHED_PERCENT
watched_percent = {'movie': jellypy.CONFIG.MOVIE_WATCHED_PERCENT,
'episode': jellypy.CONFIG.TV_WATCHED_PERCENT,
'track': jellypy.CONFIG.MUSIC_WATCHED_PERCENT
}
prev_progress_percent = helpers.get_percent(prev_session['view_offset'], session['duration'])
media_watched_percent = watched_percent.get(session['media_type'], 0)
@@ -661,4 +661,4 @@ class ActivityProcessor(object):
'WHERE user_id = ? AND machine_id = ? AND media_type = ? '
'ORDER BY stopped DESC',
[user_id, machine_id, media_type])
return int(started - last_session.get('stopped', 0) >= plexpy.CONFIG.NOTIFY_CONTINUED_SESSION_THRESHOLD)
return int(started - last_session.get('stopped', 0) >= jellypy.CONFIG.NOTIFY_CONTINUED_SESSION_THRESHOLD)

View File

@@ -35,8 +35,8 @@ import traceback
import cherrypy
import xmltodict
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import config
import database
@@ -51,19 +51,19 @@ if plexpy.PYTHON2:
import plextv
import users
else:
from plexpy import common
from plexpy import config
from plexpy import database
from plexpy import helpers
from plexpy import libraries
from plexpy import logger
from plexpy import mobile_app
from plexpy import notification_handler
from plexpy import notifiers
from plexpy import newsletter_handler
from plexpy import newsletters
from plexpy import plextv
from plexpy import users
from jellypy import common
from jellypy import config
from jellypy import database
from jellypy import helpers
from jellypy import libraries
from jellypy import logger
from jellypy import mobile_app
from jellypy import notification_handler
from jellypy import notifiers
from jellypy import newsletter_handler
from jellypy import newsletters
from jellypy import plextv
from jellypy import users
class API2(object):
@@ -107,15 +107,15 @@ class API2(object):
def _api_validate(self, *args, **kwargs):
""" Sets class vars and remove unneeded parameters. """
if not plexpy.CONFIG.API_ENABLED:
if not jellypy.CONFIG.API_ENABLED:
self._api_msg = 'API not enabled'
self._api_response_code = 404
elif not plexpy.CONFIG.API_KEY:
elif not jellypy.CONFIG.API_KEY:
self._api_msg = 'API key not generated'
self._api_response_code = 401
elif len(plexpy.CONFIG.API_KEY) != 32:
elif len(jellypy.CONFIG.API_KEY) != 32:
self._api_msg = 'API key not generated correctly'
self._api_response_code = 401
@@ -142,8 +142,8 @@ class API2(object):
if 'app' in kwargs and helpers.bool_true(kwargs.pop('app')):
self._api_app = True
if plexpy.CONFIG.API_ENABLED and not self._api_msg or self._api_cmd in ('get_apikey', 'docs', 'docs_md'):
if not self._api_app and self._api_apikey == plexpy.CONFIG.API_KEY:
if jellypy.CONFIG.API_ENABLED and not self._api_msg or self._api_cmd in ('get_apikey', 'docs', 'docs_md'):
if not self._api_app and self._api_apikey == jellypy.CONFIG.API_KEY:
self._api_authenticated = True
elif self._api_app and self._api_apikey == mobile_app.get_temp_device_token() and \
@@ -203,7 +203,7 @@ class API2(object):
]
```
"""
logfile = os.path.join(plexpy.CONFIG.LOG_DIR, logger.FILENAME)
logfile = os.path.join(jellypy.CONFIG.LOG_DIR, logger.FILENAME)
templog = []
start = int(start)
end = int(end)
@@ -290,11 +290,11 @@ class API2(object):
```
"""
interface_dir = os.path.join(plexpy.PROG_DIR, 'data/interfaces/')
interface_dir = os.path.join(jellypy.PROG_DIR, 'data/interfaces/')
interface_list = [name for name in os.listdir(interface_dir) if
os.path.isdir(os.path.join(interface_dir, name))]
conf = plexpy.CONFIG._config
conf = jellypy.CONFIG._config
config = {}
# Truthify the dict
@@ -332,7 +332,7 @@ class API2(object):
None
```
"""
if not plexpy.CONFIG.API_SQL:
if not jellypy.CONFIG.API_SQL:
self._api_msg = 'SQL not enabled for the API.'
return
@@ -342,12 +342,12 @@ class API2(object):
# allow the user to shoot them self
# in the foot but not in the head..
if not len(os.listdir(plexpy.CONFIG.BACKUP_DIR)):
if not len(os.listdir(jellypy.CONFIG.BACKUP_DIR)):
self.backup_db()
else:
# If the backup is less then 24 h old lets make a backup
if not any(os.path.getctime(os.path.join(plexpy.CONFIG.BACKUP_DIR, file_)) > (time.time() - 86400)
and file_.endswith('.db') for file_ in os.listdir(plexpy.CONFIG.BACKUP_DIR)):
if not any(os.path.getctime(os.path.join(jellypy.CONFIG.BACKUP_DIR, file_)) > (time.time() - 86400)
and file_.endswith('.db') for file_ in os.listdir(jellypy.CONFIG.BACKUP_DIR)):
self.backup_db()
db = database.MonitorDatabase()
@@ -363,7 +363,7 @@ class API2(object):
return data
def backup_db(self):
""" Create a manual backup of the `plexpy.db` file."""
""" Create a manual backup of the `jellypy.db` file."""
data = database.make_backup()
self._api_result_type = 'success' if data else 'error'
@@ -373,14 +373,14 @@ class API2(object):
def restart(self, **kwargs):
""" Restart Tautulli."""
plexpy.SIGNAL = 'restart'
jellypy.SIGNAL = 'restart'
self._api_msg = 'Restarting Tautulli'
self._api_result_type = 'success'
def update(self, **kwargs):
""" Update Tautulli."""
plexpy.SIGNAL = 'update'
jellypy.SIGNAL = 'update'
self._api_msg = 'Updating Tautulli'
self._api_result_type = 'success'
@@ -472,9 +472,9 @@ class API2(object):
mobile_app.set_temp_device_token(True)
plex_server = plextv.get_server_resources(return_info=True)
tautulli = plexpy.get_tautulli_info()
tautulli = jellypy.get_tautulli_info()
data = {"server_id": plexpy.CONFIG.PMS_UUID}
data = {"server_id": jellypy.CONFIG.PMS_UUID}
data.update(plex_server)
data.update(tautulli)
@@ -646,32 +646,32 @@ General optional parameters:
"""
data = None
apikey = hashlib.sha224(str(random.getrandbits(256)).encode('utf-8')).hexdigest()[0:32]
if plexpy.CONFIG.HTTP_USERNAME and plexpy.CONFIG.HTTP_PASSWORD:
if jellypy.CONFIG.HTTP_USERNAME and jellypy.CONFIG.HTTP_PASSWORD:
authenticated = False
if plexpy.CONFIG.HTTP_HASHED_PASSWORD and \
username == plexpy.CONFIG.HTTP_USERNAME and check_hash(password, plexpy.CONFIG.HTTP_PASSWORD):
if jellypy.CONFIG.HTTP_HASHED_PASSWORD and \
username == jellypy.CONFIG.HTTP_USERNAME and check_hash(password, jellypy.CONFIG.HTTP_PASSWORD):
authenticated = True
elif not plexpy.CONFIG.HTTP_HASHED_PASSWORD and \
username == plexpy.CONFIG.HTTP_USERNAME and password == plexpy.CONFIG.HTTP_PASSWORD:
elif not jellypy.CONFIG.HTTP_HASHED_PASSWORD and \
username == jellypy.CONFIG.HTTP_USERNAME and password == jellypy.CONFIG.HTTP_PASSWORD:
authenticated = True
if authenticated:
if plexpy.CONFIG.API_KEY:
data = plexpy.CONFIG.API_KEY
if jellypy.CONFIG.API_KEY:
data = jellypy.CONFIG.API_KEY
else:
data = apikey
plexpy.CONFIG.API_KEY = apikey
plexpy.CONFIG.write()
jellypy.CONFIG.API_KEY = apikey
jellypy.CONFIG.write()
else:
self._api_msg = 'Authentication is enabled, please add the correct username and password to the parameters'
else:
if plexpy.CONFIG.API_KEY:
data = plexpy.CONFIG.API_KEY
if jellypy.CONFIG.API_KEY:
data = jellypy.CONFIG.API_KEY
else:
# Make a apikey if the doesn't exist
data = apikey
plexpy.CONFIG.API_KEY = apikey
plexpy.CONFIG.write()
jellypy.CONFIG.API_KEY = apikey
jellypy.CONFIG.write()
return data

View File

@@ -24,11 +24,11 @@ from __future__ import unicode_literals
from future.moves.urllib.request import FancyURLopener
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
from common import USER_AGENT
else:
from plexpy.common import USER_AGENT
from jellypy.common import USER_AGENT
class PlexPyURLopener(FancyURLopener):

View File

@@ -21,11 +21,11 @@ import distro
import platform
from collections import OrderedDict
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import version
else:
from plexpy import version
from jellypy import version
# Identify Our Application

View File

@@ -25,13 +25,13 @@ import threading
from configobj import ConfigObj, ParseError
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import helpers
import logger
else:
from plexpy import helpers
from plexpy import logger
from jellypy import helpers
from jellypy import logger
def bool_int(value):
@@ -257,20 +257,20 @@ def import_tautulli_config(config=None, backup=False):
# Remove keys that should not be imported
for key in _DO_NOT_IMPORT_KEYS:
delattr(imported_config, key)
if plexpy.DOCKER or plexpy.SNAP:
if jellypy.DOCKER or jellypy.SNAP:
for key in _DO_NOT_IMPORT_KEYS_DOCKER:
delattr(imported_config, key)
# Merge the imported config file into the current config file
plexpy.CONFIG._config.merge(imported_config._config)
plexpy.CONFIG.write()
jellypy.CONFIG._config.merge(imported_config._config)
jellypy.CONFIG.write()
logger.info("Tautulli Config :: Tautulli config import complete.")
set_import_thread(None)
set_is_importing(False)
# Restart to apply changes
plexpy.SIGNAL = 'restart'
jellypy.SIGNAL = 'restart'
def make_backup(cleanup=False, scheduler=False):
@@ -280,15 +280,15 @@ def make_backup(cleanup=False, scheduler=False):
backup_file = 'config.backup-{}.sched.ini'.format(helpers.now())
else:
backup_file = 'config.backup-{}.ini'.format(helpers.now())
backup_folder = plexpy.CONFIG.BACKUP_DIR
backup_folder = jellypy.CONFIG.BACKUP_DIR
backup_file_fp = os.path.join(backup_folder, backup_file)
# In case the user has deleted it manually
if not os.path.exists(backup_folder):
os.makedirs(backup_folder)
plexpy.CONFIG.write()
shutil.copyfile(plexpy.CONFIG_FILE, backup_file_fp)
jellypy.CONFIG.write()
shutil.copyfile(jellypy.CONFIG_FILE, backup_file_fp)
if cleanup:
now = time.time()
@@ -296,17 +296,17 @@ def make_backup(cleanup=False, scheduler=False):
for root, dirs, files in os.walk(backup_folder):
ini_files = [os.path.join(root, f) for f in files if f.endswith('.sched.ini')]
for file_ in ini_files:
if os.stat(file_).st_mtime < now - plexpy.CONFIG.BACKUP_DAYS * 86400:
if os.stat(file_).st_mtime < now - jellypy.CONFIG.BACKUP_DAYS * 86400:
try:
os.remove(file_)
except OSError as e:
logger.error("Tautulli Config :: Failed to delete %s from the backup folder: %s" % (file_, e))
if backup_file in os.listdir(backup_folder):
logger.debug("Tautulli Config :: Successfully backed up %s to %s" % (plexpy.CONFIG_FILE, backup_file))
logger.debug("Tautulli Config :: Successfully backed up %s to %s" % (jellypy.CONFIG_FILE, backup_file))
return True
else:
logger.error("Tautulli Config :: Failed to backup %s to %s" % (plexpy.CONFIG_FILE, backup_file))
logger.error("Tautulli Config :: Failed to backup %s to %s" % (jellypy.CONFIG_FILE, backup_file))
return False
@@ -530,7 +530,7 @@ class Config(object):
self.CONFIG_VERSION = 14
if self.CONFIG_VERSION == 14:
if plexpy.DOCKER:
if jellypy.DOCKER:
self.PLEXPY_AUTO_UPDATE = 0
self.CONFIG_VERSION = 15
@@ -542,7 +542,7 @@ class Config(object):
self.CONFIG_VERSION = 16
if self.CONFIG_VERSION == 16:
if plexpy.SNAP:
if jellypy.SNAP:
self.PLEXPY_AUTO_UPDATE = 0
self.CONFIG_VERSION = 17

View File

@@ -23,13 +23,13 @@ import shutil
import threading
import time
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import helpers
import logger
else:
from plexpy import helpers
from plexpy import logger
from jellypy import helpers
from jellypy import logger
FILENAME = "tautulli.db"
@@ -308,7 +308,7 @@ def optimize_db():
def db_filename(filename=FILENAME):
""" Returns the filepath to the db """
return os.path.join(plexpy.DATA_DIR, filename)
return os.path.join(jellypy.DATA_DIR, filename)
def make_backup(cleanup=False, scheduler=False):
@@ -320,13 +320,13 @@ def make_backup(cleanup=False, scheduler=False):
corrupt = ''
if not integrity:
corrupt = '.corrupt'
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_plexpydbcorrupt'})
jellypy.NOTIFY_QUEUE.put({'notify_action': 'on_plexpydbcorrupt'})
if scheduler:
backup_file = 'tautulli.backup-{}{}.sched.db'.format(helpers.now(), corrupt)
else:
backup_file = 'tautulli.backup-{}{}.db'.format(helpers.now(), corrupt)
backup_folder = plexpy.CONFIG.BACKUP_DIR
backup_folder = jellypy.CONFIG.BACKUP_DIR
backup_file_fp = os.path.join(backup_folder, backup_file)
# In case the user has deleted it manually
@@ -345,7 +345,7 @@ def make_backup(cleanup=False, scheduler=False):
for root, dirs, files in os.walk(backup_folder):
db_files = [os.path.join(root, f) for f in files if f.endswith('.sched.db')]
for file_ in db_files:
if os.stat(file_).st_mtime < now - plexpy.CONFIG.BACKUP_DAYS * 86400:
if os.stat(file_).st_mtime < now - jellypy.CONFIG.BACKUP_DAYS * 86400:
try:
os.remove(file_)
except OSError as e:
@@ -361,10 +361,10 @@ def make_backup(cleanup=False, scheduler=False):
def get_cache_size():
# This will protect against typecasting problems produced by empty string and None settings
if not plexpy.CONFIG.CACHE_SIZEMB:
if not jellypy.CONFIG.CACHE_SIZEMB:
# sqlite will work with this (very slowly)
return 0
return int(plexpy.CONFIG.CACHE_SIZEMB)
return int(jellypy.CONFIG.CACHE_SIZEMB)
def dict_factory(cursor, row):
@@ -381,9 +381,9 @@ class MonitorDatabase(object):
self.filename = filename
self.connection = sqlite3.connect(db_filename(filename), timeout=20)
# Set database synchronous mode (default NORMAL)
self.connection.execute("PRAGMA synchronous = %s" % plexpy.CONFIG.SYNCHRONOUS_MODE)
self.connection.execute("PRAGMA synchronous = %s" % jellypy.CONFIG.SYNCHRONOUS_MODE)
# Set database journal mode (default WAL)
self.connection.execute("PRAGMA journal_mode = %s" % plexpy.CONFIG.JOURNAL_MODE)
self.connection.execute("PRAGMA journal_mode = %s" % jellypy.CONFIG.JOURNAL_MODE)
# Set database cache size (default 32MB)
self.connection.execute("PRAGMA cache_size = -%s" % (get_cache_size() * 1024))
self.connection.row_factory = dict_factory

View File

@@ -24,8 +24,8 @@ from future.builtins import object
import json
from itertools import groupby
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import database
import datatables
@@ -34,13 +34,13 @@ if plexpy.PYTHON2:
import pmsconnect
import session
else:
from plexpy import common
from plexpy import database
from plexpy import datatables
from plexpy import helpers
from plexpy import logger
from plexpy import pmsconnect
from plexpy import session
from jellypy import common
from jellypy import database
from jellypy import datatables
from jellypy import helpers
from jellypy import logger
from jellypy import pmsconnect
from jellypy import session
class DataFactory(object):
@@ -58,10 +58,10 @@ class DataFactory(object):
custom_where = []
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
if include_activity is None:
include_activity = plexpy.CONFIG.HISTORY_TABLE_ACTIVITY
include_activity = jellypy.CONFIG.HISTORY_TABLE_ACTIVITY
if session.get_session_user_id():
session_user_id = str(session.get_session_user_id())
@@ -218,11 +218,11 @@ class DataFactory(object):
filter_duration = 0
total_duration = self.get_total_duration(custom_where=custom_where)
watched_percent = {'movie': plexpy.CONFIG.MOVIE_WATCHED_PERCENT,
'episode': plexpy.CONFIG.TV_WATCHED_PERCENT,
'track': plexpy.CONFIG.MUSIC_WATCHED_PERCENT,
watched_percent = {'movie': jellypy.CONFIG.MOVIE_WATCHED_PERCENT,
'episode': jellypy.CONFIG.TV_WATCHED_PERCENT,
'track': jellypy.CONFIG.MUSIC_WATCHED_PERCENT,
'photo': 0,
'clip': plexpy.CONFIG.TV_WATCHED_PERCENT
'clip': jellypy.CONFIG.TV_WATCHED_PERCENT
}
rows = []
@@ -309,13 +309,13 @@ class DataFactory(object):
if stat_id:
stats_cards = [stat_id]
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
if stats_cards is None:
stats_cards = plexpy.CONFIG.HOME_STATS_CARDS
stats_cards = jellypy.CONFIG.HOME_STATS_CARDS
movie_watched_percent = plexpy.CONFIG.MOVIE_WATCHED_PERCENT
tv_watched_percent = plexpy.CONFIG.TV_WATCHED_PERCENT
music_watched_percent = plexpy.CONFIG.MUSIC_WATCHED_PERCENT
movie_watched_percent = jellypy.CONFIG.MOVIE_WATCHED_PERCENT
tv_watched_percent = jellypy.CONFIG.TV_WATCHED_PERCENT
music_watched_percent = jellypy.CONFIG.MUSIC_WATCHED_PERCENT
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
sort_type = 'total_duration' if stats_type == 'duration' else 'total_plays'

View File

@@ -18,15 +18,15 @@ from future.builtins import object
import re
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import database
import helpers
import logger
else:
from plexpy import database
from plexpy import helpers
from plexpy import logger
from jellypy import database
from jellypy import helpers
from jellypy import logger
class DataTables(object):

View File

@@ -29,8 +29,8 @@ from functools import partial, reduce
from io import open
from multiprocessing.dummy import Pool as ThreadPool
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import database
import datatables
import helpers
@@ -38,12 +38,12 @@ if plexpy.PYTHON2:
import users
from plex import Plex
else:
from plexpy import database
from plexpy import datatables
from plexpy import helpers
from plexpy import logger
from plexpy import users
from plexpy.plex import Plex
from jellypy import database
from jellypy import datatables
from jellypy import helpers
from jellypy import logger
from jellypy import users
from jellypy.plex import Plex
class Export(object):
@@ -1534,9 +1534,9 @@ class Export(object):
user_tokens = user_data.get_tokens(user_id=self.user_id)
plex_token = user_tokens['server_token']
else:
plex_token = plexpy.CONFIG.PMS_TOKEN
plex_token = jellypy.CONFIG.PMS_TOKEN
plex = Plex(plexpy.CONFIG.PMS_URL, plex_token)
plex = Plex(jellypy.CONFIG.PMS_URL, plex_token)
if self.rating_key:
logger.debug(
@@ -1691,7 +1691,7 @@ class Export(object):
self.total_items = len(items)
logger.info("Tautulli Exporter :: Exporting %d item(s).", self.total_items)
pool = ThreadPool(processes=plexpy.CONFIG.EXPORT_THREADS)
pool = ThreadPool(processes=jellypy.CONFIG.EXPORT_THREADS)
items = [ExportObject(self, item) for item in items]
try:
@@ -2107,7 +2107,7 @@ def delete_export(export_id):
def delete_all_exports():
logger.info("Tautulli Exporter :: Deleting all exports from the export directory.")
export_dir = plexpy.CONFIG.EXPORT_DIR
export_dir = jellypy.CONFIG.EXPORT_DIR
try:
shutil.rmtree(export_dir, ignore_errors=True)
except OSError as e:
@@ -2233,7 +2233,7 @@ def format_export_filename(title, file_format):
def get_export_dirpath(title, timestamp=None, images_directory=None):
if timestamp:
title = format_export_directory(title, timestamp)
dirpath = os.path.join(plexpy.CONFIG.EXPORT_DIR, title)
dirpath = os.path.join(jellypy.CONFIG.EXPORT_DIR, title)
if images_directory:
dirpath = os.path.join(dirpath, '{}.images'.format(images_directory))
return dirpath

View File

@@ -22,19 +22,19 @@ from future.builtins import object
import datetime
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import database
import logger
import libraries
import session
else:
from plexpy import common
from plexpy import database
from plexpy import logger
from plexpy import libraries
from plexpy import session
from jellypy import common
from jellypy import database
from jellypy import logger
from jellypy import libraries
from jellypy import session
class Graphs(object):
@@ -55,7 +55,7 @@ class Graphs(object):
user_cond = 'AND session_history.user_id = %s ' % user_id
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
@@ -169,7 +169,7 @@ class Graphs(object):
user_cond = 'AND session_history.user_id = %s ' % user_id
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
@@ -227,7 +227,7 @@ class Graphs(object):
logger.warn("Tautulli Graphs :: Unable to execute database query for get_total_plays_per_dayofweek: %s." % e)
return None
if plexpy.CONFIG.WEEK_START_MONDAY:
if jellypy.CONFIG.WEEK_START_MONDAY:
days_list = ['Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday', 'Sunday']
else:
@@ -300,7 +300,7 @@ class Graphs(object):
user_cond = 'AND session_history.user_id = %s ' % user_id
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
@@ -413,7 +413,7 @@ class Graphs(object):
user_cond = 'AND session_history.user_id = %s ' % user_id
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
@@ -534,7 +534,7 @@ class Graphs(object):
user_cond = 'AND session_history.user_id = %s ' % user_id
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
@@ -630,7 +630,7 @@ class Graphs(object):
user_cond = 'AND session_history.user_id = %s ' % user_id
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
@@ -739,7 +739,7 @@ class Graphs(object):
user_cond = 'AND session_history.user_id = %s ' % user_id
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
@@ -845,7 +845,7 @@ class Graphs(object):
user_cond = 'AND session_history.user_id = %s ' % user_id
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
@@ -931,7 +931,7 @@ class Graphs(object):
user_cond = 'AND session_history.user_id = %s ' % user_id
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
@@ -1041,7 +1041,7 @@ class Graphs(object):
user_cond = 'AND session_history.user_id = %s ' % user_id
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
@@ -1131,7 +1131,7 @@ class Graphs(object):
user_cond = 'AND session_history.user_id = %s ' % user_id
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
group_by = 'session_history.reference_id' if grouping else 'session_history.id'

View File

@@ -52,17 +52,17 @@ from future.moves.urllib.parse import urlencode
from xml.dom import minidom
import xmltodict
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import logger
import request
from api2 import API2
else:
from plexpy import common
from plexpy import logger
from plexpy import request
from plexpy.api2 import API2
from jellypy import common
from jellypy import logger
from jellypy import request
from jellypy.api2 import API2
def addtoapi(*dargs, **dkwargs):
@@ -367,7 +367,7 @@ def replace_all(text, dic, normalize=False):
else:
j = unicodedata.normalize('NFC', j)
except TypeError:
j = unicodedata.normalize('NFC', j.decode(plexpy.SYS_ENCODING, 'replace'))
j = unicodedata.normalize('NFC', j.decode(jellypy.SYS_ENCODING, 'replace'))
text = text.replace(i, j)
return text
@@ -479,8 +479,8 @@ def create_https_certificates(ssl_cert, ssl_key):
serial = timestamp()
not_before = 0
not_after = 60 * 60 * 24 * 365 * 10 # ten years
domains = ['DNS:' + d.strip() for d in plexpy.CONFIG.HTTPS_DOMAIN.split(',') if d]
ips = ['IP:' + d.strip() for d in plexpy.CONFIG.HTTPS_IP.split(',') if d]
domains = ['DNS:' + d.strip() for d in jellypy.CONFIG.HTTPS_DOMAIN.split(',') if d]
ips = ['IP:' + d.strip() for d in jellypy.CONFIG.HTTPS_IP.split(',') if d]
alt_names = ','.join(domains + ips).encode('utf-8')
# Create the self-signed Tautulli certificate
@@ -739,15 +739,15 @@ def anon_url(*url):
"""
Return a URL string consisting of the Anonymous redirect URL and an arbitrary number of values appended.
"""
return '' if None in url else '%s%s' % (plexpy.CONFIG.ANON_REDIRECT, ''.join(str(s) for s in url))
return '' if None in url else '%s%s' % (jellypy.CONFIG.ANON_REDIRECT, ''.join(str(s) for s in url))
def get_img_service(include_self=False):
if plexpy.CONFIG.NOTIFY_UPLOAD_POSTERS == 1:
if jellypy.CONFIG.NOTIFY_UPLOAD_POSTERS == 1:
return 'imgur'
elif plexpy.CONFIG.NOTIFY_UPLOAD_POSTERS == 2 and include_self:
elif jellypy.CONFIG.NOTIFY_UPLOAD_POSTERS == 2 and include_self:
return 'self-hosted'
elif plexpy.CONFIG.NOTIFY_UPLOAD_POSTERS == 3:
elif jellypy.CONFIG.NOTIFY_UPLOAD_POSTERS == 3:
return 'cloudinary'
else:
return None
@@ -757,11 +757,11 @@ def upload_to_imgur(img_data, img_title='', rating_key='', fallback=''):
""" Uploads an image to Imgur """
img_url = delete_hash = ''
if not plexpy.CONFIG.IMGUR_CLIENT_ID:
if not jellypy.CONFIG.IMGUR_CLIENT_ID:
logger.error("Tautulli Helpers :: Cannot upload image to Imgur. No Imgur client id specified in the settings.")
return img_url, delete_hash
headers = {'Authorization': 'Client-ID %s' % plexpy.CONFIG.IMGUR_CLIENT_ID}
headers = {'Authorization': 'Client-ID %s' % jellypy.CONFIG.IMGUR_CLIENT_ID}
data = {'image': base64.b64encode(img_data),
'title': img_title.encode('utf-8'),
'name': str(rating_key) + '.png',
@@ -789,11 +789,11 @@ def upload_to_imgur(img_data, img_title='', rating_key='', fallback=''):
def delete_from_imgur(delete_hash, img_title='', fallback=''):
""" Deletes an image from Imgur """
if not plexpy.CONFIG.IMGUR_CLIENT_ID:
if not jellypy.CONFIG.IMGUR_CLIENT_ID:
logger.error("Tautulli Helpers :: Cannot delete image from Imgur. No Imgur client id specified in the settings.")
return False
headers = {'Authorization': 'Client-ID %s' % plexpy.CONFIG.IMGUR_CLIENT_ID}
headers = {'Authorization': 'Client-ID %s' % jellypy.CONFIG.IMGUR_CLIENT_ID}
response, err_msg, req_msg = request.request_response2('https://api.imgur.com/3/image/%s' % delete_hash, 'DELETE',
headers=headers)
@@ -813,18 +813,18 @@ def upload_to_cloudinary(img_data, img_title='', rating_key='', fallback=''):
""" Uploads an image to Cloudinary """
img_url = ''
if not plexpy.CONFIG.CLOUDINARY_CLOUD_NAME or not plexpy.CONFIG.CLOUDINARY_API_KEY or not plexpy.CONFIG.CLOUDINARY_API_SECRET:
if not jellypy.CONFIG.CLOUDINARY_CLOUD_NAME or not jellypy.CONFIG.CLOUDINARY_API_KEY or not jellypy.CONFIG.CLOUDINARY_API_SECRET:
logger.error("Tautulli Helpers :: Cannot upload image to Cloudinary. Cloudinary settings not specified in the settings.")
return img_url
cloudinary.config(
cloud_name=plexpy.CONFIG.CLOUDINARY_CLOUD_NAME,
api_key=plexpy.CONFIG.CLOUDINARY_API_KEY,
api_secret=plexpy.CONFIG.CLOUDINARY_API_SECRET
cloud_name=jellypy.CONFIG.CLOUDINARY_CLOUD_NAME,
api_key=jellypy.CONFIG.CLOUDINARY_API_KEY,
api_secret=jellypy.CONFIG.CLOUDINARY_API_SECRET
)
# Cloudinary library has very poor support for non-ASCII characters on Python 2
if plexpy.PYTHON2:
if jellypy.PYTHON2:
_img_title = latinToAscii(img_title, replace=True)
else:
_img_title = img_title
@@ -844,14 +844,14 @@ def upload_to_cloudinary(img_data, img_title='', rating_key='', fallback=''):
def delete_from_cloudinary(rating_key=None, delete_all=False):
""" Deletes an image from Cloudinary """
if not plexpy.CONFIG.CLOUDINARY_CLOUD_NAME or not plexpy.CONFIG.CLOUDINARY_API_KEY or not plexpy.CONFIG.CLOUDINARY_API_SECRET:
if not jellypy.CONFIG.CLOUDINARY_CLOUD_NAME or not jellypy.CONFIG.CLOUDINARY_API_KEY or not jellypy.CONFIG.CLOUDINARY_API_SECRET:
logger.error("Tautulli Helpers :: Cannot delete image from Cloudinary. Cloudinary settings not specified in the settings.")
return False
cloudinary.config(
cloud_name=plexpy.CONFIG.CLOUDINARY_CLOUD_NAME,
api_key=plexpy.CONFIG.CLOUDINARY_API_KEY,
api_secret=plexpy.CONFIG.CLOUDINARY_API_SECRET
cloud_name=jellypy.CONFIG.CLOUDINARY_CLOUD_NAME,
api_key=jellypy.CONFIG.CLOUDINARY_API_KEY,
api_secret=jellypy.CONFIG.CLOUDINARY_API_SECRET
)
if delete_all:
@@ -870,14 +870,14 @@ def cloudinary_transform(rating_key=None, width=1000, height=1500, opacity=100,
img_format='png', img_title='', fallback=None):
url = ''
if not plexpy.CONFIG.CLOUDINARY_CLOUD_NAME or not plexpy.CONFIG.CLOUDINARY_API_KEY or not plexpy.CONFIG.CLOUDINARY_API_SECRET:
if not jellypy.CONFIG.CLOUDINARY_CLOUD_NAME or not jellypy.CONFIG.CLOUDINARY_API_KEY or not jellypy.CONFIG.CLOUDINARY_API_SECRET:
logger.error("Tautulli Helpers :: Cannot transform image on Cloudinary. Cloudinary settings not specified in the settings.")
return url
cloudinary.config(
cloud_name=plexpy.CONFIG.CLOUDINARY_CLOUD_NAME,
api_key=plexpy.CONFIG.CLOUDINARY_API_KEY,
api_secret=plexpy.CONFIG.CLOUDINARY_API_SECRET
cloud_name=jellypy.CONFIG.CLOUDINARY_CLOUD_NAME,
api_key=jellypy.CONFIG.CLOUDINARY_API_KEY,
api_secret=jellypy.CONFIG.CLOUDINARY_API_SECRET
)
img_options = {'format': img_format,
@@ -914,7 +914,7 @@ def cache_image(url, image=None):
If no image is provided, tries to return the image from the cache directory.
"""
# Create image directory if it doesn't exist
imgdir = os.path.join(plexpy.CONFIG.CACHE_DIR, 'images/')
imgdir = os.path.join(jellypy.CONFIG.CACHE_DIR, 'images/')
if not os.path.exists(imgdir):
logger.debug("Tautulli Helpers :: Creating image cache directory at %s" % imgdir)
os.makedirs(imgdir)
@@ -1122,12 +1122,12 @@ def eval_logic_groups_to_bool(logic_groups, eval_conds):
def get_plexpy_url(hostname=None):
if plexpy.CONFIG.ENABLE_HTTPS:
if jellypy.CONFIG.ENABLE_HTTPS:
scheme = 'https'
else:
scheme = 'http'
if hostname is None and plexpy.CONFIG.HTTP_HOST == '0.0.0.0':
if hostname is None and jellypy.CONFIG.HTTP_HOST == '0.0.0.0':
import socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
@@ -1142,18 +1142,18 @@ def get_plexpy_url(hostname=None):
if not hostname:
hostname = 'localhost'
elif hostname == 'localhost' and plexpy.CONFIG.HTTP_HOST != '0.0.0.0':
hostname = plexpy.CONFIG.HTTP_HOST
elif hostname == 'localhost' and jellypy.CONFIG.HTTP_HOST != '0.0.0.0':
hostname = jellypy.CONFIG.HTTP_HOST
else:
hostname = hostname or plexpy.CONFIG.HTTP_HOST
hostname = hostname or jellypy.CONFIG.HTTP_HOST
if plexpy.HTTP_PORT not in (80, 443):
port = ':' + str(plexpy.HTTP_PORT)
if jellypy.HTTP_PORT not in (80, 443):
port = ':' + str(jellypy.HTTP_PORT)
else:
port = ''
if plexpy.HTTP_ROOT is not None and plexpy.HTTP_ROOT.strip('/'):
root = '/' + plexpy.HTTP_ROOT.strip('/')
if jellypy.HTTP_ROOT is not None and jellypy.HTTP_ROOT.strip('/'):
root = '/' + jellypy.HTTP_ROOT.strip('/')
else:
root = ''
@@ -1202,10 +1202,10 @@ def split_args(args=None):
if isinstance(args, list):
return args
elif isinstance(args, str):
if plexpy.PYTHON2:
if jellypy.PYTHON2:
args = args.encode('utf-8')
args = shlex.split(args)
if plexpy.PYTHON2:
if jellypy.PYTHON2:
args = [a.decode('utf-8') for a in args]
return args
return []

View File

@@ -26,13 +26,13 @@ import certifi
import requests
import urllib3
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import helpers
import logger
else:
from plexpy import helpers
from plexpy import logger
from jellypy import helpers
from jellypy import logger
class HTTPHandler(object):
@@ -53,14 +53,14 @@ class HTTPHandler(object):
self.headers = headers
else:
self.headers = {
'X-Plex-Product': plexpy.common.PRODUCT,
'X-Plex-Version': plexpy.common.RELEASE,
'X-Plex-Client-Identifier': plexpy.CONFIG.PMS_UUID,
'X-Plex-Platform': plexpy.common.PLATFORM,
'X-Plex-Platform-Version': plexpy.common.PLATFORM_RELEASE,
'X-Plex-Device': '{} {}'.format(plexpy.common.PLATFORM,
plexpy.common.PLATFORM_RELEASE),
'X-Plex-Device-Name': plexpy.common.PLATFORM_DEVICE_NAME
'X-Plex-Product': jellypy.common.PRODUCT,
'X-Plex-Version': jellypy.common.RELEASE,
'X-Plex-Client-Identifier': jellypy.CONFIG.PMS_UUID,
'X-Plex-Platform': jellypy.common.PLATFORM,
'X-Plex-Platform-Version': jellypy.common.PLATFORM_RELEASE,
'X-Plex-Device': '{} {}'.format(jellypy.common.PLATFORM,
jellypy.common.PLATFORM_RELEASE),
'X-Plex-Device-Name': jellypy.common.PLATFORM_DEVICE_NAME
}
self.token = token

View File

@@ -23,8 +23,8 @@ from future.builtins import object
import json
import os
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import database
import datatables
@@ -36,22 +36,22 @@ if plexpy.PYTHON2:
import users
from plex import Plex
else:
from plexpy import common
from plexpy import database
from plexpy import datatables
from plexpy import helpers
from plexpy import logger
from plexpy import plextv
from plexpy import pmsconnect
from plexpy import session
from plexpy import users
from plexpy.plex import Plex
from jellypy import common
from jellypy import database
from jellypy import datatables
from jellypy import helpers
from jellypy import logger
from jellypy import plextv
from jellypy import pmsconnect
from jellypy import session
from jellypy import users
from jellypy.plex import Plex
def refresh_libraries():
logger.info("Tautulli Libraries :: Requesting libraries list refresh...")
server_id = plexpy.CONFIG.PMS_IDENTIFIER
server_id = jellypy.CONFIG.PMS_IDENTIFIER
if not server_id:
logger.error("Tautulli Libraries :: No PMS identifier, cannot refresh libraries. Verify server in settings.")
return
@@ -96,15 +96,15 @@ def refresh_libraries():
query = 'UPDATE library_sections SET is_active = 0 WHERE server_id != ? OR ' \
'section_id NOT IN ({})'.format(', '.join(['?'] * len(section_ids)))
monitor_db.action(query=query, args=[plexpy.CONFIG.PMS_IDENTIFIER] + section_ids)
monitor_db.action(query=query, args=[jellypy.CONFIG.PMS_IDENTIFIER] + section_ids)
if plexpy.CONFIG.HOME_LIBRARY_CARDS == ['first_run_wizard']:
plexpy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', library_keys)
plexpy.CONFIG.write()
if jellypy.CONFIG.HOME_LIBRARY_CARDS == ['first_run_wizard']:
jellypy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', library_keys)
jellypy.CONFIG.write()
else:
new_keys = plexpy.CONFIG.HOME_LIBRARY_CARDS + new_keys
plexpy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', new_keys)
plexpy.CONFIG.write()
new_keys = jellypy.CONFIG.HOME_LIBRARY_CARDS + new_keys
jellypy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', new_keys)
jellypy.CONFIG.write()
logger.info("Tautulli Libraries :: Libraries list refreshed.")
return True
@@ -117,7 +117,7 @@ def add_live_tv_library(refresh=False):
monitor_db = database.MonitorDatabase()
result = monitor_db.select_single('SELECT * FROM library_sections '
'WHERE section_id = ? and server_id = ?',
[common.LIVE_TV_SECTION_ID, plexpy.CONFIG.PMS_IDENTIFIER])
[common.LIVE_TV_SECTION_ID, jellypy.CONFIG.PMS_IDENTIFIER])
if result and not refresh or not result and refresh:
return
@@ -125,9 +125,9 @@ def add_live_tv_library(refresh=False):
if not refresh:
logger.info("Tautulli Libraries :: Adding Live TV library to the database.")
section_keys = {'server_id': plexpy.CONFIG.PMS_IDENTIFIER,
section_keys = {'server_id': jellypy.CONFIG.PMS_IDENTIFIER,
'section_id': common.LIVE_TV_SECTION_ID}
section_values = {'server_id': plexpy.CONFIG.PMS_IDENTIFIER,
section_values = {'server_id': jellypy.CONFIG.PMS_IDENTIFIER,
'section_id': common.LIVE_TV_SECTION_ID,
'section_name': common.LIVE_TV_SECTION_NAME,
'section_type': 'live',
@@ -148,7 +148,7 @@ def has_library_type(section_type):
def get_collections(section_id=None):
plex = Plex(plexpy.CONFIG.PMS_URL, session.get_session_user_token())
plex = Plex(jellypy.CONFIG.PMS_URL, session.get_session_user_token())
library = plex.get_library(section_id)
if library.type not in ('movie', 'show', 'artist'):
@@ -246,7 +246,7 @@ def get_playlists(section_id=None, user_id=None):
if not plex_token:
return []
plex = Plex(plexpy.CONFIG.PMS_URL, plex_token)
plex = Plex(jellypy.CONFIG.PMS_URL, plex_token)
if user_id:
playlists = plex.plex.playlists()
@@ -321,7 +321,7 @@ class Libraries(object):
custom_where = [['library_sections.deleted_section', 0]]
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
if session.get_session_shared_libraries():
custom_where.append(['library_sections.section_id', session.get_session_shared_libraries()])
@@ -484,7 +484,7 @@ class Libraries(object):
# Get play counts from the database
monitor_db = database.MonitorDatabase()
if plexpy.CONFIG.GROUP_HISTORY_TABLES:
if jellypy.CONFIG.GROUP_HISTORY_TABLES:
count_by = 'reference_id'
else:
count_by = 'id'
@@ -517,7 +517,7 @@ class Libraries(object):
# Import media info cache from json file
if rating_key:
try:
inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key))
inFilePath = os.path.join(jellypy.CONFIG.CACHE_DIR, 'media_info_%s-%s.json' % (section_id, rating_key))
with open(inFilePath, 'r') as inFile:
rows = json.load(inFile)
library_count = len(rows)
@@ -527,7 +527,7 @@ class Libraries(object):
pass
elif section_id:
try:
inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
inFilePath = os.path.join(jellypy.CONFIG.CACHE_DIR, 'media_info_%s.json' % section_id)
with open(inFilePath, 'r') as inFile:
rows = json.load(inFile)
library_count = len(rows)
@@ -594,14 +594,14 @@ class Libraries(object):
# Cache the media info to a json file
if rating_key:
try:
outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key))
outFilePath = os.path.join(jellypy.CONFIG.CACHE_DIR, 'media_info_%s-%s.json' % (section_id, rating_key))
with open(outFilePath, 'w') as outFile:
json.dump(rows, outFile)
except IOError as e:
logger.debug("Tautulli Libraries :: Unable to create cache file for rating_key %s." % rating_key)
elif section_id:
try:
outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
outFilePath = os.path.join(jellypy.CONFIG.CACHE_DIR, 'media_info_%s.json' % section_id)
with open(outFilePath, 'w') as outFile:
json.dump(rows, outFile)
except IOError as e:
@@ -694,7 +694,7 @@ class Libraries(object):
if rating_key:
#logger.debug("Tautulli Libraries :: Getting file sizes for rating_key %s." % rating_key)
try:
inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key))
inFilePath = os.path.join(jellypy.CONFIG.CACHE_DIR, 'media_info_%s-%s.json' % (section_id, rating_key))
with open(inFilePath, 'r') as inFile:
rows = json.load(inFile)
except IOError as e:
@@ -704,7 +704,7 @@ class Libraries(object):
elif section_id:
logger.debug("Tautulli Libraries :: Getting file sizes for section_id %s." % section_id)
try:
inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
inFilePath = os.path.join(jellypy.CONFIG.CACHE_DIR, 'media_info_%s.json' % section_id)
with open(inFilePath, 'r') as inFile:
rows = json.load(inFile)
except IOError as e:
@@ -738,14 +738,14 @@ class Libraries(object):
# Cache the media info to a json file
if rating_key:
try:
outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key))
outFilePath = os.path.join(jellypy.CONFIG.CACHE_DIR, 'media_info_%s-%s.json' % (section_id, rating_key))
with open(outFilePath, 'w') as outFile:
json.dump(rows, outFile)
except IOError as e:
logger.debug("Tautulli Libraries :: Unable to create cache file with file sizes for rating_key %s." % rating_key)
elif section_id:
try:
outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
outFilePath = os.path.join(jellypy.CONFIG.CACHE_DIR, 'media_info_%s.json' % section_id)
with open(outFilePath, 'w') as outFile:
json.dump(rows, outFile)
except IOError as e:
@@ -796,7 +796,7 @@ class Libraries(object):
return default_return
if server_id is None:
server_id = plexpy.CONFIG.PMS_IDENTIFIER
server_id = jellypy.CONFIG.PMS_IDENTIFIER
def get_library_details(section_id=section_id, server_id=server_id):
monitor_db = database.MonitorDatabase()
@@ -877,7 +877,7 @@ class Libraries(object):
return []
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
if query_days and query_days is not None:
query_days = map(helpers.cast_to_int, query_days.split(','))
@@ -941,7 +941,7 @@ class Libraries(object):
return []
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
monitor_db = database.MonitorDatabase()
@@ -1088,13 +1088,13 @@ class Libraries(object):
return all(success)
elif str(section_id).isdigit():
server_id = server_id or plexpy.CONFIG.PMS_IDENTIFIER
if server_id == plexpy.CONFIG.PMS_IDENTIFIER:
server_id = server_id or jellypy.CONFIG.PMS_IDENTIFIER
if server_id == jellypy.CONFIG.PMS_IDENTIFIER:
delete_success = database.delete_library_history(section_id=section_id)
else:
logger.warn("Tautulli Libraries :: Library history not deleted for library section_id %s "
"because library server_id %s does not match Plex server identifier %s."
% (section_id, server_id, plexpy.CONFIG.PMS_IDENTIFIER))
% (section_id, server_id, jellypy.CONFIG.PMS_IDENTIFIER))
delete_success = True
if purge_only:
@@ -1151,7 +1151,7 @@ class Libraries(object):
try:
if section_id.isdigit():
[os.remove(os.path.join(plexpy.CONFIG.CACHE_DIR, f)) for f in os.listdir(plexpy.CONFIG.CACHE_DIR)
[os.remove(os.path.join(jellypy.CONFIG.CACHE_DIR, f)) for f in os.listdir(jellypy.CONFIG.CACHE_DIR)
if f.startswith('media_info_%s' % section_id) and f.endswith('.json')]
logger.debug("Tautulli Libraries :: Deleted media info table cache for section_id %s." % section_id)
@@ -1167,7 +1167,7 @@ class Libraries(object):
# Refresh the PMS_URL to make sure the server_id is updated
plextv.get_server_resources()
server_id = plexpy.CONFIG.PMS_IDENTIFIER
server_id = jellypy.CONFIG.PMS_IDENTIFIER
try:
logger.debug("Tautulli Libraries :: Deleting libraries where server_id does not match %s." % server_id)

View File

@@ -22,11 +22,11 @@ import future.moves.queue as queue
import time
import threading
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import logger
else:
from plexpy import logger
from jellypy import logger
class TimedLock(object):

View File

@@ -20,23 +20,23 @@ from io import open
import os
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import helpers
import logger
else:
from plexpy import helpers
from plexpy import logger
from jellypy import helpers
from jellypy import logger
def get_log_tail(window=20, parsed=True, log_type="server"):
if plexpy.CONFIG.PMS_LOGS_FOLDER:
if jellypy.CONFIG.PMS_LOGS_FOLDER:
log_file = ""
if log_type == "server":
log_file = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Server.log')
log_file = os.path.join(jellypy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Server.log')
elif log_type == "scanner":
log_file = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Scanner.log')
log_file = os.path.join(jellypy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Scanner.log')
else:
return []

View File

@@ -32,13 +32,13 @@ import sys
import threading
import traceback
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import helpers
from config import _BLACKLIST_KEYS, _WHITELIST_KEYS
else:
from plexpy import helpers
from plexpy.config import _BLACKLIST_KEYS, _WHITELIST_KEYS
from jellypy import helpers
from jellypy.config import _BLACKLIST_KEYS, _WHITELIST_KEYS
# These settings are for file logging only
@@ -96,7 +96,7 @@ class BlacklistFilter(logging.Filter):
super(BlacklistFilter, self).__init__()
def filter(self, record):
if not plexpy.CONFIG.LOG_BLACKLIST:
if not jellypy.CONFIG.LOG_BLACKLIST:
return True
for item in _BLACKLIST_WORDS:
@@ -131,7 +131,7 @@ class RegexFilter(logging.Filter):
self.regex = re.compile(r'')
def filter(self, record):
if not plexpy.CONFIG.LOG_BLACKLIST:
if not jellypy.CONFIG.LOG_BLACKLIST:
return True
try:
@@ -349,7 +349,7 @@ def initLogger(console=False, log_dir=False, verbose=False):
# Add filters to log handlers
# Only add filters after the config file has been initialized
# Nothing prior to initialization should contain sensitive information
if not plexpy.DEV and plexpy.CONFIG:
if not jellypy.DEV and jellypy.CONFIG:
log_handlers = logger.handlers + \
logger_api.handlers + \
logger_plex_websocket.handlers + \

View File

@@ -30,23 +30,23 @@ except ImportError:
if HAS_PYOBJC:
import rumps
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import logger
import versioncheck
else:
from plexpy import common
from plexpy import logger
from plexpy import versioncheck
from jellypy import common
from jellypy import logger
from jellypy import versioncheck
class MacOSSystemTray(object):
def __init__(self):
self.image_dir = os.path.join(plexpy.PROG_DIR, 'data/interfaces/', plexpy.CONFIG.INTERFACE, 'images')
self.image_dir = os.path.join(jellypy.PROG_DIR, 'data/interfaces/', jellypy.CONFIG.INTERFACE, 'images')
self.icon = os.path.join(self.image_dir, 'logo-flat-white.ico')
if plexpy.UPDATE_AVAILABLE:
if jellypy.UPDATE_AVAILABLE:
self.update_title = 'Check for Updates - Update Available!'
else:
self.update_title = 'Check for Updates'
@@ -61,10 +61,10 @@ class MacOSSystemTray(object):
rumps.MenuItem('Restart', callback=self.tray_restart),
rumps.MenuItem('Quit', callback=self.tray_quit)
]
if not plexpy.FROZEN:
if not jellypy.FROZEN:
self.menu.insert(6, rumps.MenuItem('Update', callback=self.tray_update))
self.menu[2].state = plexpy.CONFIG.LAUNCH_STARTUP
self.menu[3].state = plexpy.CONFIG.LAUNCH_BROWSER
self.menu[2].state = jellypy.CONFIG.LAUNCH_STARTUP
self.menu[3].state = jellypy.CONFIG.LAUNCH_BROWSER
self.tray_icon = rumps.App(common.PRODUCT, icon=self.icon, template=True,
menu=self.menu, quit_button=None)
@@ -84,50 +84,50 @@ class MacOSSystemTray(object):
self.tray_icon.icon = kwargs['icon']
def tray_open(self, tray_icon):
plexpy.launch_browser(plexpy.CONFIG.HTTP_HOST, plexpy.HTTP_PORT, plexpy.HTTP_ROOT)
jellypy.launch_browser(jellypy.CONFIG.HTTP_HOST, jellypy.HTTP_PORT, jellypy.HTTP_ROOT)
def tray_startup(self, tray_icon):
plexpy.CONFIG.LAUNCH_STARTUP = not plexpy.CONFIG.LAUNCH_STARTUP
jellypy.CONFIG.LAUNCH_STARTUP = not jellypy.CONFIG.LAUNCH_STARTUP
set_startup()
def tray_browser(self, tray_icon):
plexpy.CONFIG.LAUNCH_BROWSER = not plexpy.CONFIG.LAUNCH_BROWSER
jellypy.CONFIG.LAUNCH_BROWSER = not jellypy.CONFIG.LAUNCH_BROWSER
set_startup()
def tray_check_update(self, tray_icon):
versioncheck.check_update()
def tray_update(self, tray_icon):
if plexpy.UPDATE_AVAILABLE:
plexpy.SIGNAL = 'update'
if jellypy.UPDATE_AVAILABLE:
jellypy.SIGNAL = 'update'
else:
self.update_title = 'Check for Updates - No Update Available'
self.menu[5].title = self.update_title
def tray_restart(self, tray_icon):
plexpy.SIGNAL = 'restart'
jellypy.SIGNAL = 'restart'
def tray_quit(self, tray_icon):
plexpy.SIGNAL = 'shutdown'
jellypy.SIGNAL = 'shutdown'
def change_tray_update_icon(self):
if plexpy.UPDATE_AVAILABLE:
if jellypy.UPDATE_AVAILABLE:
self.update_title = 'Check for Updates - Update Available!'
else:
self.update_title = 'Check for Updates'
self.menu[5].title = self.update_title
def change_tray_icons(self):
self.tray_icon.menu['Start Tautulli at Login'].state = plexpy.CONFIG.LAUNCH_STARTUP
self.tray_icon.menu['Open Browser when Tautulli Starts'].state = plexpy.CONFIG.LAUNCH_BROWSER
self.tray_icon.menu['Start Tautulli at Login'].state = jellypy.CONFIG.LAUNCH_STARTUP
self.tray_icon.menu['Open Browser when Tautulli Starts'].state = jellypy.CONFIG.LAUNCH_BROWSER
def set_startup():
if plexpy.MAC_SYS_TRAY_ICON:
plexpy.MAC_SYS_TRAY_ICON.change_tray_icons()
if jellypy.MAC_SYS_TRAY_ICON:
jellypy.MAC_SYS_TRAY_ICON.change_tray_icons()
if plexpy.INSTALL_TYPE == 'macos':
if plexpy.CONFIG.LAUNCH_STARTUP:
if jellypy.INSTALL_TYPE == 'macos':
if jellypy.CONFIG.LAUNCH_STARTUP:
try:
subprocess.Popen(['osascript',
'-e', 'tell application "System Events"',
@@ -162,11 +162,11 @@ def set_startup():
plist_file_path = os.path.join(launch_agents, plist_file)
exe = sys.executable
run_args = [arg for arg in plexpy.ARGS if arg != '--nolaunch']
if plexpy.FROZEN:
run_args = [arg for arg in jellypy.ARGS if arg != '--nolaunch']
if jellypy.FROZEN:
args = [exe] + run_args
else:
args = [exe, plexpy.FULL_PATH] + run_args
args = [exe, jellypy.FULL_PATH] + run_args
plist_dict = {
'Label': common.PRODUCT,
@@ -174,7 +174,7 @@ def set_startup():
'RunAtLoad': True
}
if plexpy.CONFIG.LAUNCH_STARTUP:
if jellypy.CONFIG.LAUNCH_STARTUP:
if not os.path.exists(launch_agents):
try:
os.makedirs(launch_agents)

View File

@@ -21,15 +21,15 @@ from future.builtins import str
import requests
import threading
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import database
import helpers
import logger
else:
from plexpy import database
from plexpy import helpers
from plexpy import logger
from jellypy import database
from jellypy import helpers
from jellypy import logger
TEMP_DEVICE_TOKEN = None

View File

@@ -23,17 +23,17 @@ import os
from apscheduler.triggers.cron import CronTrigger
import email.utils
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import database
import helpers
import logger
import newsletters
else:
from plexpy import database
from plexpy import helpers
from plexpy import logger
from plexpy import newsletters
from jellypy import database
from jellypy import helpers
from jellypy import logger
from jellypy import newsletters
NEWSLETTER_SCHED = None
@@ -48,7 +48,7 @@ def add_newsletter_each(newsletter_id=None, notify_action=None, **kwargs):
'newsletter_id': newsletter_id,
'notify_action': notify_action}
data.update(kwargs)
plexpy.NOTIFY_QUEUE.put(data)
jellypy.NOTIFY_QUEUE.put(data)
def schedule_newsletters(newsletter_id=None):
@@ -211,7 +211,7 @@ def get_newsletter(newsletter_uuid=None, newsletter_id_name=None):
end_date.replace('-', ''),
newsletter_uuid)
newsletter_folder = plexpy.CONFIG.NEWSLETTER_DIR or os.path.join(plexpy.DATA_DIR, 'newsletters')
newsletter_folder = jellypy.CONFIG.NEWSLETTER_DIR or os.path.join(jellypy.DATA_DIR, 'newsletters')
newsletter_file_fp = os.path.join(newsletter_folder, newsletter_file)
if newsletter_file in os.listdir(newsletter_folder):

View File

@@ -29,8 +29,8 @@ from mako import exceptions
import os
import re
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import database
import helpers
@@ -40,14 +40,14 @@ if plexpy.PYTHON2:
import pmsconnect
from notifiers import send_notification, EMAIL
else:
from plexpy import common
from plexpy import database
from plexpy import helpers
from plexpy import libraries
from plexpy import logger
from plexpy import newsletter_handler
from plexpy import pmsconnect
from plexpy.notifiers import send_notification, EMAIL
from jellypy import common
from jellypy import database
from jellypy import helpers
from jellypy import libraries
from jellypy import logger
from jellypy import newsletter_handler
from jellypy import pmsconnect
from jellypy.notifiers import send_notification, EMAIL
AGENT_IDS = {
@@ -319,14 +319,14 @@ def blacklist_logger():
def serve_template(templatename, **kwargs):
if plexpy.CONFIG.NEWSLETTER_CUSTOM_DIR:
if jellypy.CONFIG.NEWSLETTER_CUSTOM_DIR:
logger.info("Tautulli Newsletters :: Using custom newsletter template directory.")
template_dir = plexpy.CONFIG.NEWSLETTER_CUSTOM_DIR
template_dir = jellypy.CONFIG.NEWSLETTER_CUSTOM_DIR
else:
interface_dir = os.path.join(str(plexpy.PROG_DIR), 'data/interfaces/')
template_dir = os.path.join(str(interface_dir), plexpy.CONFIG.NEWSLETTER_TEMPLATES)
interface_dir = os.path.join(str(jellypy.PROG_DIR), 'data/interfaces/')
template_dir = os.path.join(str(interface_dir), jellypy.CONFIG.NEWSLETTER_TEMPLATES)
if not plexpy.CONFIG.NEWSLETTER_INLINE_STYLES:
if not jellypy.CONFIG.NEWSLETTER_INLINE_STYLES:
templatename = templatename.replace('.html', '.internal.html')
_hplookup = TemplateLookup(directories=[template_dir], default_filters=['unicode', 'h'])
@@ -344,7 +344,7 @@ def generate_newsletter_uuid():
db = database.MonitorDatabase()
while not uuid or uuid_exists:
uuid = plexpy.generate_uuid()[:8]
uuid = jellypy.generate_uuid()[:8]
result = db.select_single(
'SELECT EXISTS(SELECT uuid FROM newsletter_log WHERE uuid = ?) as uuid_exists', [uuid])
uuid_exists = result['uuid_exists']
@@ -528,7 +528,7 @@ class Newsletter(object):
def _save(self):
newsletter_file = self.filename_formatted
newsletter_folder = plexpy.CONFIG.NEWSLETTER_DIR or os.path.join(plexpy.DATA_DIR, 'newsletters')
newsletter_folder = jellypy.CONFIG.NEWSLETTER_DIR or os.path.join(jellypy.DATA_DIR, 'newsletters')
newsletter_file_fp = os.path.join(newsletter_folder, newsletter_file)
# In case the user has deleted it manually
@@ -552,7 +552,7 @@ class Newsletter(object):
newsletter_stripped = ''.join(l.strip() for l in self.newsletter.splitlines())
plaintext = 'HTML email support is required to view the newsletter.\n'
if plexpy.CONFIG.NEWSLETTER_SELF_HOSTED and plexpy.CONFIG.HTTP_BASE_URL:
if jellypy.CONFIG.NEWSLETTER_SELF_HOSTED and jellypy.CONFIG.HTTP_BASE_URL:
plaintext += self._DEFAULT_BODY.format(**self.parameters)
email_reply_msg_id = self.email_reply_msg_id if self.config['threaded'] else None
@@ -589,15 +589,15 @@ class Newsletter(object):
return parameters
def _build_params(self):
date_format = helpers.momentjs_to_arrow(plexpy.CONFIG.DATE_FORMAT)
date_format = helpers.momentjs_to_arrow(jellypy.CONFIG.DATE_FORMAT)
if plexpy.CONFIG.NEWSLETTER_SELF_HOSTED and plexpy.CONFIG.HTTP_BASE_URL:
base_url = plexpy.CONFIG.HTTP_BASE_URL + plexpy.HTTP_ROOT + 'newsletter/'
if jellypy.CONFIG.NEWSLETTER_SELF_HOSTED and jellypy.CONFIG.HTTP_BASE_URL:
base_url = jellypy.CONFIG.HTTP_BASE_URL + jellypy.HTTP_ROOT + 'newsletter/'
else:
base_url = helpers.get_plexpy_url() + '/newsletter/'
parameters = {
'server_name': plexpy.CONFIG.PMS_NAME,
'server_name': jellypy.CONFIG.PMS_NAME,
'start_date': self.start_date.format(date_format),
'end_date': self.end_date.format(date_format),
'current_year': self.start_date.year,
@@ -616,13 +616,13 @@ class Newsletter(object):
'newsletter_uuid': self.uuid,
'newsletter_id': self.newsletter_id,
'newsletter_id_name': self.newsletter_id_name,
'newsletter_password': plexpy.CONFIG.NEWSLETTER_PASSWORD
'newsletter_password': jellypy.CONFIG.NEWSLETTER_PASSWORD
}
return parameters
def build_text(self):
from plexpy.notification_handler import CustomFormatter
from jellypy.notification_handler import CustomFormatter
custom_formatter = CustomFormatter()
try:
@@ -655,7 +655,7 @@ class Newsletter(object):
return subject, body, message
def build_filename(self):
from plexpy.notification_handler import CustomFormatter
from jellypy.notification_handler import CustomFormatter
custom_formatter = CustomFormatter()
try:
@@ -702,7 +702,7 @@ class RecentlyAdded(Newsletter):
_TEMPLATE = 'recently_added.html'
def _get_recently_added(self, media_type=None):
from plexpy.notification_handler import format_group_index
from jellypy.notification_handler import format_group_index
pms_connect = pmsconnect.PmsConnect()
@@ -818,7 +818,7 @@ class RecentlyAdded(Newsletter):
return recently_added
def retrieve_data(self):
from plexpy.notification_handler import get_img_info, set_hash_image_info
from jellypy.notification_handler import get_img_info, set_hash_image_info
if not self.config['incl_libraries']:
logger.warn("Tautulli Newsletters :: Failed to retrieve %s newsletter data: no libraries selected." % self.NAME)
@@ -948,8 +948,8 @@ class RecentlyAdded(Newsletter):
newsletter_libraries.append(s['section_name'])
parameters['newsletter_libraries'] = ', '.join(sorted(newsletter_libraries))
parameters['pms_identifier'] = plexpy.CONFIG.PMS_IDENTIFIER
parameters['pms_web_url'] = plexpy.CONFIG.PMS_WEB_URL
parameters['pms_identifier'] = jellypy.CONFIG.PMS_IDENTIFIER
parameters['pms_web_url'] = jellypy.CONFIG.PMS_WEB_URL
return parameters

View File

@@ -39,8 +39,8 @@ import time
import musicbrainzngs
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import activity_processor
import common
import database
@@ -52,20 +52,20 @@ if plexpy.PYTHON2:
import request
from newsletter_handler import notify as notify_newsletter
else:
from plexpy import activity_processor
from plexpy import common
from plexpy import database
from plexpy import datafactory
from plexpy import logger
from plexpy import helpers
from plexpy import notifiers
from plexpy import pmsconnect
from plexpy import request
from plexpy.newsletter_handler import notify as notify_newsletter
from jellypy import activity_processor
from jellypy import common
from jellypy import database
from jellypy import datafactory
from jellypy import logger
from jellypy import helpers
from jellypy import notifiers
from jellypy import pmsconnect
from jellypy import request
from jellypy.newsletter_handler import notify as notify_newsletter
def process_queue():
queue = plexpy.NOTIFY_QUEUE
queue = jellypy.NOTIFY_QUEUE
while True:
params = queue.get()
@@ -148,14 +148,14 @@ def add_notifier_each(notifier_id=None, notify_action=None, stream_data=None, ti
'timeline_data': timeline_data,
'parameters': parameters}
data.update(kwargs)
plexpy.NOTIFY_QUEUE.put(data)
jellypy.NOTIFY_QUEUE.put(data)
else:
logger.debug("Tautulli NotificationHandler :: Custom notification conditions not satisfied, skipping notifier_id %s." % notifier['id'])
# Add on_concurrent and on_newdevice to queue if action is on_play
if notify_action == 'on_play':
plexpy.NOTIFY_QUEUE.put({'stream_data': stream_data.copy(), 'notify_action': 'on_concurrent'})
plexpy.NOTIFY_QUEUE.put({'stream_data': stream_data.copy(), 'notify_action': 'on_newdevice'})
jellypy.NOTIFY_QUEUE.put({'stream_data': stream_data.copy(), 'notify_action': 'on_concurrent'})
jellypy.NOTIFY_QUEUE.put({'stream_data': stream_data.copy(), 'notify_action': 'on_newdevice'})
def notify_conditions(notify_action=None, stream_data=None, timeline_data=None):
@@ -186,27 +186,27 @@ def notify_conditions(notify_action=None, stream_data=None, timeline_data=None):
if result:
user_sessions = [s for s in result['sessions'] if s['user_id'] == stream_data['user_id']]
if plexpy.CONFIG.NOTIFY_CONCURRENT_BY_IP:
evaluated = len(Counter(s['ip_address'] for s in user_sessions)) >= plexpy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD
if jellypy.CONFIG.NOTIFY_CONCURRENT_BY_IP:
evaluated = len(Counter(s['ip_address'] for s in user_sessions)) >= jellypy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD
else:
evaluated = len(user_sessions) >= plexpy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD
evaluated = len(user_sessions) >= jellypy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD
elif notify_action == 'on_newdevice':
data_factory = datafactory.DataFactory()
user_devices = data_factory.get_user_devices(user_id=stream_data['user_id'],
history_only=not plexpy.CONFIG.NOTIFY_NEW_DEVICE_INITIAL_ONLY)
history_only=not jellypy.CONFIG.NOTIFY_NEW_DEVICE_INITIAL_ONLY)
evaluated = stream_data['machine_id'] not in user_devices
elif stream_data['media_type'] in ('movie', 'episode', 'clip'):
progress_percent = helpers.get_percent(stream_data['view_offset'], stream_data['duration'])
if notify_action == 'on_stop':
evaluated = (plexpy.CONFIG.NOTIFY_CONSECUTIVE or
(stream_data['media_type'] == 'movie' and progress_percent < plexpy.CONFIG.MOVIE_WATCHED_PERCENT) or
(stream_data['media_type'] == 'episode' and progress_percent < plexpy.CONFIG.TV_WATCHED_PERCENT))
evaluated = (jellypy.CONFIG.NOTIFY_CONSECUTIVE or
(stream_data['media_type'] == 'movie' and progress_percent < jellypy.CONFIG.MOVIE_WATCHED_PERCENT) or
(stream_data['media_type'] == 'episode' and progress_percent < jellypy.CONFIG.TV_WATCHED_PERCENT))
elif notify_action == 'on_resume':
evaluated = plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99
evaluated = jellypy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99
# All other activity notify actions
else:
@@ -497,9 +497,9 @@ def set_notify_success(notification_id):
def build_media_notify_params(notify_action=None, session=None, timeline=None, manual_trigger=False, **kwargs):
# Get time formats
date_format = helpers.momentjs_to_arrow(plexpy.CONFIG.DATE_FORMAT)
time_format = helpers.momentjs_to_arrow(plexpy.CONFIG.TIME_FORMAT)
duration_format = helpers.momentjs_to_arrow(plexpy.CONFIG.TIME_FORMAT, duration=True)
date_format = helpers.momentjs_to_arrow(jellypy.CONFIG.DATE_FORMAT)
time_format = helpers.momentjs_to_arrow(jellypy.CONFIG.TIME_FORMAT)
duration_format = helpers.momentjs_to_arrow(jellypy.CONFIG.TIME_FORMAT, duration=True)
# Get metadata for the item
if session:
@@ -598,8 +598,8 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
plex_web_rating_key = notify_params['rating_key']
notify_params['plex_url'] = '{web_url}#!/server/{pms_identifier}/details?key=%2Flibrary%2Fmetadata%2F{rating_key}'.format(
web_url=plexpy.CONFIG.PMS_WEB_URL,
pms_identifier=plexpy.CONFIG.PMS_IDENTIFIER,
web_url=jellypy.CONFIG.PMS_WEB_URL,
pms_identifier=jellypy.CONFIG.PMS_IDENTIFIER,
rating_key=plex_web_rating_key)
# Check external guids
@@ -646,7 +646,7 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
notify_params['lastfm_url'] = 'https://www.last.fm/music/' + notify_params['lastfm_id']
# Get TheMovieDB info (for movies and tv only)
if plexpy.CONFIG.THEMOVIEDB_LOOKUP and notify_params['media_type'] in ('movie', 'show', 'season', 'episode'):
if jellypy.CONFIG.THEMOVIEDB_LOOKUP and notify_params['media_type'] in ('movie', 'show', 'season', 'episode'):
if notify_params.get('themoviedb_id'):
themoveidb_json = get_themoviedb_info(rating_key=rating_key,
media_type=notify_params['media_type'],
@@ -689,7 +689,7 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
notify_params['themoviedb_id'], 'show' if lookup_media_type == 'tv' else 'movie')
# Get TVmaze info (for tv shows only)
if plexpy.CONFIG.TVMAZE_LOOKUP and notify_params['media_type'] in ('show', 'season', 'episode'):
if jellypy.CONFIG.TVMAZE_LOOKUP and notify_params['media_type'] in ('show', 'season', 'episode'):
if notify_params.get('thetvdb_id') or notify_params.get('imdb_id') or notify_params.get('plex_id'):
if notify_params['media_type'] == 'episode':
lookup_key = notify_params['grandparent_rating_key']
@@ -716,7 +716,7 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
notify_params['trakt_url'] = 'https://trakt.tv/search/imdb/' + notify_params['imdb_id']
# Get MusicBrainz info (for music only)
if plexpy.CONFIG.MUSICBRAINZ_LOOKUP and notify_params['media_type'] in ('artist', 'album', 'track'):
if jellypy.CONFIG.MUSICBRAINZ_LOOKUP and notify_params['media_type'] in ('artist', 'album', 'track'):
artist = release = recording = tracks = tnum = None
if notify_params['media_type'] == 'artist':
musicbrainz_type = 'artist'
@@ -772,13 +772,13 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
img_info = get_img_info(img=poster_thumb, rating_key=poster_key, title=poster_title, fallback=fallback)
poster_info = {'poster_title': img_info['img_title'], 'poster_url': img_info['img_url']}
notify_params.update(poster_info)
elif img_service == 'self-hosted' and plexpy.CONFIG.HTTP_BASE_URL:
elif img_service == 'self-hosted' and jellypy.CONFIG.HTTP_BASE_URL:
img_hash = set_hash_image_info(img=poster_thumb, fallback=fallback)
poster_info = {'poster_title': poster_title,
'poster_url': plexpy.CONFIG.HTTP_BASE_URL + plexpy.HTTP_ROOT + 'image/' + img_hash}
'poster_url': jellypy.CONFIG.HTTP_BASE_URL + jellypy.HTTP_ROOT + 'image/' + img_hash}
notify_params.update(poster_info)
if ((manual_trigger or plexpy.CONFIG.NOTIFY_GROUP_RECENTLY_ADDED_GRANDPARENT)
if ((manual_trigger or jellypy.CONFIG.NOTIFY_GROUP_RECENTLY_ADDED_GRANDPARENT)
and notify_params['media_type'] in ('show', 'artist')):
show_name = notify_params['title']
episode_name = ''
@@ -797,7 +797,7 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
child_count = len(child_num)
grandchild_count = ''
elif ((manual_trigger or plexpy.CONFIG.NOTIFY_GROUP_RECENTLY_ADDED_PARENT)
elif ((manual_trigger or jellypy.CONFIG.NOTIFY_GROUP_RECENTLY_ADDED_PARENT)
and notify_params['media_type'] in ('season', 'album')):
show_name = notify_params['parent_title']
episode_name = ''
@@ -850,16 +850,16 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
available_params = {
# Global paramaters
'tautulli_version': common.RELEASE,
'tautulli_remote': plexpy.CONFIG.GIT_REMOTE,
'tautulli_branch': plexpy.CONFIG.GIT_BRANCH,
'tautulli_commit': plexpy.CURRENT_VERSION,
'server_name': plexpy.CONFIG.PMS_NAME,
'server_ip': plexpy.CONFIG.PMS_IP,
'server_port': plexpy.CONFIG.PMS_PORT,
'server_url': plexpy.CONFIG.PMS_URL,
'server_machine_id': plexpy.CONFIG.PMS_IDENTIFIER,
'server_platform': plexpy.CONFIG.PMS_PLATFORM,
'server_version': plexpy.CONFIG.PMS_VERSION,
'tautulli_remote': jellypy.CONFIG.GIT_REMOTE,
'tautulli_branch': jellypy.CONFIG.GIT_BRANCH,
'tautulli_commit': jellypy.CURRENT_VERSION,
'server_name': jellypy.CONFIG.PMS_NAME,
'server_ip': jellypy.CONFIG.PMS_IP,
'server_port': jellypy.CONFIG.PMS_PORT,
'server_url': jellypy.CONFIG.PMS_URL,
'server_machine_id': jellypy.CONFIG.PMS_IDENTIFIER,
'server_platform': jellypy.CONFIG.PMS_PLATFORM,
'server_version': jellypy.CONFIG.PMS_VERSION,
'action': notify_action.split('on_')[-1],
'current_year': now.year,
'current_month': now.month,
@@ -1096,8 +1096,8 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
def build_server_notify_params(notify_action=None, **kwargs):
# Get time formats
date_format = plexpy.CONFIG.DATE_FORMAT.replace('Do','')
time_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','')
date_format = jellypy.CONFIG.DATE_FORMAT.replace('Do', '')
time_format = jellypy.CONFIG.TIME_FORMAT.replace('Do', '')
update_channel = pmsconnect.PmsConnect().get_server_update_channel()
@@ -1111,16 +1111,16 @@ def build_server_notify_params(notify_action=None, **kwargs):
available_params = {
# Global paramaters
'tautulli_version': common.RELEASE,
'tautulli_remote': plexpy.CONFIG.GIT_REMOTE,
'tautulli_branch': plexpy.CONFIG.GIT_BRANCH,
'tautulli_commit': plexpy.CURRENT_VERSION,
'server_name': plexpy.CONFIG.PMS_NAME,
'server_ip': plexpy.CONFIG.PMS_IP,
'server_port': plexpy.CONFIG.PMS_PORT,
'server_url': plexpy.CONFIG.PMS_URL,
'server_platform': plexpy.CONFIG.PMS_PLATFORM,
'server_version': plexpy.CONFIG.PMS_VERSION,
'server_machine_id': plexpy.CONFIG.PMS_IDENTIFIER,
'tautulli_remote': jellypy.CONFIG.GIT_REMOTE,
'tautulli_branch': jellypy.CONFIG.GIT_BRANCH,
'tautulli_commit': jellypy.CURRENT_VERSION,
'server_name': jellypy.CONFIG.PMS_NAME,
'server_ip': jellypy.CONFIG.PMS_IP,
'server_port': jellypy.CONFIG.PMS_PORT,
'server_url': jellypy.CONFIG.PMS_URL,
'server_platform': jellypy.CONFIG.PMS_PLATFORM,
'server_version': jellypy.CONFIG.PMS_VERSION,
'server_machine_id': jellypy.CONFIG.PMS_IDENTIFIER,
'action': notify_action.split('on_')[-1],
'current_year': now.year,
'current_month': now.month,
@@ -1464,7 +1464,7 @@ def set_hash_image_info(img=None, rating_key=None, width=750, height=1000,
rating_key = img_rating_key
img_string = '{}.{}.{}.{}.{}.{}.{}.{}'.format(
plexpy.CONFIG.PMS_UUID, img, rating_key, width, height, opacity, background, blur, fallback)
jellypy.CONFIG.PMS_UUID, img, rating_key, width, height, opacity, background, blur, fallback)
img_hash = hashlib.sha256(img_string.encode('utf-8')).hexdigest()
if add_to_db:
@@ -1572,7 +1572,7 @@ def lookup_themoviedb_by_id(rating_key=None, thetvdb_id=None, imdb_id=None, titl
else:
logger.debug("Tautulli NotificationHandler :: Looking up The Movie Database info for '{} ({})'.".format(title, year))
params = {'api_key': plexpy.CONFIG.THEMOVIEDB_APIKEY}
params = {'api_key': jellypy.CONFIG.THEMOVIEDB_APIKEY}
if thetvdb_id or imdb_id:
params['external_source'] = 'tvdb_id' if thetvdb_id else 'imdb_id'
@@ -1650,7 +1650,7 @@ def get_themoviedb_info(rating_key=None, media_type=None, themoviedb_id=None):
logger.debug("Tautulli NotificationHandler :: Looking up The Movie Database info for themoviedb_id '{}'.".format(themoviedb_id))
params = {'api_key': plexpy.CONFIG.THEMOVIEDB_APIKEY}
params = {'api_key': jellypy.CONFIG.THEMOVIEDB_APIKEY}
response, err_msg, req_msg = request.request_response2('https://api.themoviedb.org/3/{}/{}'.format(media_type, themoviedb_id), params=params)
if response and not err_msg:
@@ -1870,7 +1870,7 @@ class CustomFormatter(Formatter):
obj = self.convert_field(obj, conversion)
# expand the format spec, if needed
if plexpy.PYTHON2:
if jellypy.PYTHON2:
format_spec = self._vformat(format_spec, args, kwargs,
used_args, recursion_depth - 1)
else:
@@ -1889,7 +1889,7 @@ class CustomFormatter(Formatter):
result.append(suffix)
# result.append(self.format_field(obj, format_spec))
if plexpy.PYTHON2:
if jellypy.PYTHON2:
return ''.join(result)
else:
return ''.join(result), auto_arg_index

View File

@@ -57,8 +57,8 @@ import gntp.notifier
import facebook
import twitter
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import database
import helpers
@@ -68,14 +68,14 @@ if plexpy.PYTHON2:
import request
import users
else:
from plexpy import common
from plexpy import database
from plexpy import helpers
from plexpy import logger
from plexpy import mobile_app
from plexpy import pmsconnect
from plexpy import request
from plexpy import users
from jellypy import common
from jellypy import database
from jellypy import helpers
from jellypy import logger
from jellypy import mobile_app
from jellypy import pmsconnect
from jellypy import request
from jellypy import users
BROWSER_NOTIFIERS = {}
@@ -943,7 +943,7 @@ class ANDROIDAPP(Notifier):
'cipher_text': base64.b64encode(encrypted_data),
'nonce': base64.b64encode(nonce),
'salt': base64.b64encode(salt),
'server_id': plexpy.CONFIG.PMS_UUID}
'server_id': jellypy.CONFIG.PMS_UUID}
}
else:
logger.warn("Tautulli Notifiers :: PyCryptodome library is missing. "
@@ -955,7 +955,7 @@ class ANDROIDAPP(Notifier):
'contents': {'en': 'Tautulli Notification'},
'data': {'encrypted': False,
'plain_text': plaintext_data,
'server_id': plexpy.CONFIG.PMS_UUID}
'server_id': jellypy.CONFIG.PMS_UUID}
}
#logger.debug("OneSignal payload: {}".format(payload))
@@ -996,7 +996,7 @@ class ANDROIDAPP(Notifier):
'Instructions can be found in the '
'<a href="' + helpers.anon_url(
'https://github.com/%s/%s-Wiki/wiki/Frequently-Asked-Questions#notifications-pycryptodome'
% (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_REPO)) + '" target="_blank">FAQ</a>.' ,
% (jellypy.CONFIG.GIT_USER, jellypy.CONFIG.GIT_REPO)) + '" target="_blank">FAQ</a>.' ,
'input_type': 'help'
})
else:
@@ -1532,10 +1532,10 @@ class FACEBOOK(Notifier):
def _get_authorization(self, app_id='', app_secret='', redirect_uri=''):
# Temporarily store settings in the config so we can retrieve them in Facebook step 2.
# Assume the user won't be requesting authorization for multiple Facebook notifiers at the same time.
plexpy.CONFIG.FACEBOOK_APP_ID = app_id
plexpy.CONFIG.FACEBOOK_APP_SECRET = app_secret
plexpy.CONFIG.FACEBOOK_REDIRECT_URI = redirect_uri
plexpy.CONFIG.FACEBOOK_TOKEN = 'temp'
jellypy.CONFIG.FACEBOOK_APP_ID = app_id
jellypy.CONFIG.FACEBOOK_APP_SECRET = app_secret
jellypy.CONFIG.FACEBOOK_REDIRECT_URI = redirect_uri
jellypy.CONFIG.FACEBOOK_TOKEN = 'temp'
return facebook.auth_url(app_id=app_id,
canvas_url=redirect_uri,
@@ -1544,9 +1544,9 @@ class FACEBOOK(Notifier):
def _get_credentials(self, code=''):
logger.info("Tautulli Notifiers :: Requesting access token from {name}.".format(name=self.NAME))
app_id = plexpy.CONFIG.FACEBOOK_APP_ID
app_secret = plexpy.CONFIG.FACEBOOK_APP_SECRET
redirect_uri = plexpy.CONFIG.FACEBOOK_REDIRECT_URI
app_id = jellypy.CONFIG.FACEBOOK_APP_ID
app_secret = jellypy.CONFIG.FACEBOOK_APP_SECRET
redirect_uri = jellypy.CONFIG.FACEBOOK_REDIRECT_URI
try:
# Request user access token
@@ -1562,17 +1562,17 @@ class FACEBOOK(Notifier):
response = api.extend_access_token(app_id=app_id,
app_secret=app_secret)
plexpy.CONFIG.FACEBOOK_TOKEN = response['access_token']
jellypy.CONFIG.FACEBOOK_TOKEN = response['access_token']
except Exception as e:
logger.error("Tautulli Notifiers :: Error requesting {name} access token: {e}".format(name=self.NAME, e=e))
plexpy.CONFIG.FACEBOOK_TOKEN = ''
jellypy.CONFIG.FACEBOOK_TOKEN = ''
# Clear out temporary config values
plexpy.CONFIG.FACEBOOK_APP_ID = ''
plexpy.CONFIG.FACEBOOK_APP_SECRET = ''
plexpy.CONFIG.FACEBOOK_REDIRECT_URI = ''
jellypy.CONFIG.FACEBOOK_APP_ID = ''
jellypy.CONFIG.FACEBOOK_APP_SECRET = ''
jellypy.CONFIG.FACEBOOK_REDIRECT_URI = ''
return plexpy.CONFIG.FACEBOOK_TOKEN
return jellypy.CONFIG.FACEBOOK_TOKEN
def _post_facebook(self, **data):
if self.config['group_id']:
@@ -1820,7 +1820,7 @@ class GROWL(Notifier):
return False
# Send it, including an image
image_file = os.path.join(str(plexpy.PROG_DIR),
image_file = os.path.join(str(jellypy.PROG_DIR),
"data/interfaces/default/images/logo-circle.png")
with open(image_file, 'rb') as f:
@@ -2325,7 +2325,7 @@ class PLEX(Notifier):
if self.config['image']:
image = self.config['image']
else:
image = os.path.join(plexpy.DATA_DIR, os.path.abspath("data/interfaces/default/images/logo-circle.png"))
image = os.path.join(jellypy.DATA_DIR, os.path.abspath("data/interfaces/default/images/logo-circle.png"))
for host in hosts:
logger.info("Tautulli Notifiers :: Sending notification command to {name} @ {host}".format(name=self.NAME, host=host))
@@ -2430,8 +2430,8 @@ class PLEXMOBILEAPP(Notifier):
'to': self.config['user_ids'],
'data': {
'provider': {
'identifier': plexpy.CONFIG.PMS_IDENTIFIER,
'title': plexpy.CONFIG.PMS_NAME
'identifier': jellypy.CONFIG.PMS_IDENTIFIER,
'title': jellypy.CONFIG.PMS_NAME
}
}
}
@@ -2536,11 +2536,11 @@ class PLEXMOBILEAPP(Notifier):
data['metadata'] = metadata
data['uri'] = 'server://{}/com.plexapp.plugins.library/library/metadata/{}'.format(
plexpy.CONFIG.PMS_IDENTIFIER, uri_rating_key or pretty_metadata.parameters['rating_key']
jellypy.CONFIG.PMS_IDENTIFIER, uri_rating_key or pretty_metadata.parameters['rating_key']
)
data['play'] = self.config['tap_action'] == 'play'
headers = {'X-Plex-Token': plexpy.CONFIG.PMS_TOKEN}
headers = {'X-Plex-Token': jellypy.CONFIG.PMS_TOKEN}
return self.make_request(self.NOTIFICATION_URL, headers=headers, json=data)
@@ -2977,7 +2977,7 @@ class SCRIPTS(Notifier):
'.php': 'php',
'.pl': 'perl',
'.ps1': 'powershell -executionPolicy bypass -file',
'.py': 'python' if plexpy.FROZEN else sys.executable,
'.py': 'python' if jellypy.FROZEN else sys.executable,
'.pyw': 'pythonw',
'.rb': 'ruby',
'.sh': ''
@@ -3013,13 +3013,13 @@ class SCRIPTS(Notifier):
def run_script(self, script, user_id):
# Common environment variables
custom_env = {
'PLEX_URL': plexpy.CONFIG.PMS_URL,
'PLEX_TOKEN': plexpy.CONFIG.PMS_TOKEN,
'PLEX_URL': jellypy.CONFIG.PMS_URL,
'PLEX_TOKEN': jellypy.CONFIG.PMS_TOKEN,
'PLEX_USER_TOKEN': '',
'TAUTULLI_URL': helpers.get_plexpy_url(hostname='localhost'),
'TAUTULLI_PUBLIC_URL': plexpy.CONFIG.HTTP_BASE_URL + plexpy.HTTP_ROOT,
'TAUTULLI_APIKEY': plexpy.CONFIG.API_KEY,
'TAUTULLI_ENCODING': plexpy.SYS_ENCODING,
'TAUTULLI_PUBLIC_URL': jellypy.CONFIG.HTTP_BASE_URL + jellypy.HTTP_ROOT,
'TAUTULLI_APIKEY': jellypy.CONFIG.API_KEY,
'TAUTULLI_ENCODING': jellypy.SYS_ENCODING,
'TAUTULLI_PYTHON_VERSION': common.PYTHON_VERSION
}
@@ -3027,10 +3027,10 @@ class SCRIPTS(Notifier):
user_tokens = users.Users().get_tokens(user_id=user_id)
custom_env['PLEX_USER_TOKEN'] = str(user_tokens['server_token'])
if self.pythonpath and plexpy.INSTALL_TYPE not in ('windows', 'macos'):
if self.pythonpath and jellypy.INSTALL_TYPE not in ('windows', 'macos'):
custom_env['PYTHONPATH'] = os.pathsep.join([p for p in sys.path if p])
if plexpy.PYTHON2:
if jellypy.PYTHON2:
custom_env = {k.encode('utf-8'): v.encode('utf-8') for k, v in custom_env.items()}
env = os.environ.copy()
@@ -3137,8 +3137,8 @@ class SCRIPTS(Notifier):
script.extend(script_args)
if plexpy.PYTHON2:
script = [s.encode(plexpy.SYS_ENCODING, 'ignore') for s in script]
if jellypy.PYTHON2:
script = [s.encode(jellypy.SYS_ENCODING, 'ignore') for s in script]
logger.debug("Tautulli Notifiers :: Full script is: %s" % script)
logger.debug("Tautulli Notifiers :: Executing script in a new thread.")
@@ -3688,7 +3688,7 @@ class XBMC(Notifier):
if self.config['image']:
image = self.config['image']
else:
image = os.path.join(plexpy.DATA_DIR, os.path.abspath("data/interfaces/default/images/logo-circle.png"))
image = os.path.join(jellypy.DATA_DIR, os.path.abspath("data/interfaces/default/images/logo-circle.png"))
for host in hosts:
logger.info("Tautulli Notifiers :: Sending notification command to XMBC @ " + host)

View File

@@ -21,11 +21,11 @@ from future.builtins import str
from plexapi.server import PlexServer
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import logger
else:
from plexpy import logger
from jellypy import logger
class Plex(object):

View File

@@ -22,19 +22,19 @@ import arrow
import sqlite3
from xml.dom import minidom
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import activity_processor
import database
import helpers
import logger
import users
else:
from plexpy import activity_processor
from plexpy import database
from plexpy import helpers
from plexpy import logger
from plexpy import users
from jellypy import activity_processor
from jellypy import database
from jellypy import helpers
from jellypy import logger
from jellypy import users
def extract_plexivity_xml(xml=None):

View File

@@ -23,8 +23,8 @@ from future.builtins import object
import base64
import json
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import helpers
import http_handler
@@ -33,31 +33,31 @@ if plexpy.PYTHON2:
import pmsconnect
import session
else:
from plexpy import common
from plexpy import helpers
from plexpy import http_handler
from plexpy import logger
from plexpy import users
from plexpy import pmsconnect
from plexpy import session
from jellypy import common
from jellypy import helpers
from jellypy import http_handler
from jellypy import logger
from jellypy import users
from jellypy import pmsconnect
from jellypy import session
def get_server_resources(return_presence=False, return_server=False, return_info=False, **kwargs):
if not return_presence and not return_info:
logger.info("Tautulli PlexTV :: Requesting resources for server...")
server = {'pms_name': plexpy.CONFIG.PMS_NAME,
'pms_version': plexpy.CONFIG.PMS_VERSION,
'pms_platform': plexpy.CONFIG.PMS_PLATFORM,
'pms_ip': plexpy.CONFIG.PMS_IP,
'pms_port': plexpy.CONFIG.PMS_PORT,
'pms_ssl': plexpy.CONFIG.PMS_SSL,
'pms_is_remote': plexpy.CONFIG.PMS_IS_REMOTE,
'pms_is_cloud': plexpy.CONFIG.PMS_IS_CLOUD,
'pms_url': plexpy.CONFIG.PMS_URL,
'pms_url_manual': plexpy.CONFIG.PMS_URL_MANUAL,
'pms_identifier': plexpy.CONFIG.PMS_IDENTIFIER,
'pms_plexpass': plexpy.CONFIG.PMS_PLEXPASS
server = {'pms_name': jellypy.CONFIG.PMS_NAME,
'pms_version': jellypy.CONFIG.PMS_VERSION,
'pms_platform': jellypy.CONFIG.PMS_PLATFORM,
'pms_ip': jellypy.CONFIG.PMS_IP,
'pms_port': jellypy.CONFIG.PMS_PORT,
'pms_ssl': jellypy.CONFIG.PMS_SSL,
'pms_is_remote': jellypy.CONFIG.PMS_IS_REMOTE,
'pms_is_cloud': jellypy.CONFIG.PMS_IS_CLOUD,
'pms_url': jellypy.CONFIG.PMS_URL,
'pms_url_manual': jellypy.CONFIG.PMS_URL_MANUAL,
'pms_identifier': jellypy.CONFIG.PMS_IDENTIFIER,
'pms_plexpass': jellypy.CONFIG.PMS_PLEXPASS
}
if return_info:
@@ -132,8 +132,8 @@ def get_server_resources(return_presence=False, return_server=False, return_info
logger.info("Tautulli PlexTV :: Selected server: %s (%s) (%s - Version %s)",
server['pms_name'], server['pms_url'], server['pms_platform'], server['pms_version'])
plexpy.CONFIG.process_kwargs(server)
plexpy.CONFIG.write()
jellypy.CONFIG.process_kwargs(server)
jellypy.CONFIG.write()
class PlexTV(object):
@@ -147,8 +147,8 @@ class PlexTV(object):
self.token = token
self.urls = 'https://plex.tv'
self.timeout = plexpy.CONFIG.PMS_TIMEOUT
self.ssl_verify = plexpy.CONFIG.VERIFY_SSL_CERT
self.timeout = jellypy.CONFIG.PMS_TIMEOUT
self.ssl_verify = jellypy.CONFIG.VERIFY_SSL_CERT
if self.username is None and self.password is None:
if not self.token:
@@ -158,7 +158,7 @@ class PlexTV(object):
user_tokens = user_data.get_tokens(user_id=session.get_session_user_id())
self.token = user_tokens['server_token']
else:
self.token = plexpy.CONFIG.PMS_TOKEN
self.token = jellypy.CONFIG.PMS_TOKEN
if not self.token:
logger.error("Tautulli PlexTV :: PlexTV called, but no token provided.")
@@ -212,7 +212,7 @@ class PlexTV(object):
if force:
logger.debug("Tautulli PlexTV :: Forcing refresh of Plex.tv token.")
devices_list = self.get_devices_list()
device_id = next((d for d in devices_list if d['device_identifier'] == plexpy.CONFIG.PMS_UUID), {}).get('device_id', None)
device_id = next((d for d in devices_list if d['device_identifier'] == jellypy.CONFIG.PMS_UUID), {}).get('device_id', None)
if device_id:
logger.debug("Tautulli PlexTV :: Removing Tautulli from Plex.tv devices.")
@@ -228,8 +228,8 @@ class PlexTV(object):
user = self.get_token()
if user:
token = user['auth_token']
plexpy.CONFIG.__setattr__('PMS_TOKEN', token)
plexpy.CONFIG.write()
jellypy.CONFIG.__setattr__('PMS_TOKEN', token)
jellypy.CONFIG.write()
logger.info("Tautulli PlexTV :: Updated Plex.tv token for Tautulli.")
return token
@@ -245,7 +245,7 @@ class PlexTV(object):
return None
for a in xml_head:
if helpers.get_xml_attr(a, 'clientIdentifier') == plexpy.CONFIG.PMS_IDENTIFIER \
if helpers.get_xml_attr(a, 'clientIdentifier') == jellypy.CONFIG.PMS_IDENTIFIER \
and 'server' in helpers.get_xml_attr(a, 'provides'):
server_token = helpers.get_xml_attr(a, 'accessToken')
break
@@ -412,7 +412,7 @@ class PlexTV(object):
def get_full_users_list(self):
own_account = self.get_plextv_user_details(output_format='xml')
friends_list = self.get_plextv_friends(output_format='xml')
shared_servers = self.get_plextv_shared_servers(machine_id=plexpy.CONFIG.PMS_IDENTIFIER,
shared_servers = self.get_plextv_shared_servers(machine_id=jellypy.CONFIG.PMS_IDENTIFIER,
output_format='xml')
users_list = []
@@ -498,7 +498,7 @@ class PlexTV(object):
rating_key_filter=None, sync_id_filter=None):
if not machine_id:
machine_id = plexpy.CONFIG.PMS_IDENTIFIER
machine_id = jellypy.CONFIG.PMS_IDENTIFIER
if isinstance(rating_key_filter, list):
rating_key_filter = [str(k) for k in rating_key_filter]
@@ -709,7 +709,7 @@ class PlexTV(object):
return {}
for a in xml_head:
if helpers.get_xml_attr(a, 'machineIdentifier') == plexpy.CONFIG.PMS_IDENTIFIER:
if helpers.get_xml_attr(a, 'machineIdentifier') == jellypy.CONFIG.PMS_IDENTIFIER:
server_times = {"created_at": helpers.get_xml_attr(a, 'createdAt'),
"updated_at": helpers.get_xml_attr(a, 'updatedAt'),
"version": helpers.get_xml_attr(a, 'version')
@@ -824,7 +824,7 @@ class PlexTV(object):
return {}
# Get the updates for the platform
pms_platform = common.PMS_PLATFORM_NAME_OVERRIDES.get(plexpy.CONFIG.PMS_PLATFORM, plexpy.CONFIG.PMS_PLATFORM)
pms_platform = common.PMS_PLATFORM_NAME_OVERRIDES.get(jellypy.CONFIG.PMS_PLATFORM, jellypy.CONFIG.PMS_PLATFORM)
platform_downloads = available_downloads.get('computer').get(pms_platform) or \
available_downloads.get('nas').get(pms_platform)
@@ -833,12 +833,12 @@ class PlexTV(object):
% pms_platform)
return {}
v_old = helpers.cast_to_int("".join(v.zfill(4) for v in plexpy.CONFIG.PMS_VERSION.split('-')[0].split('.')[:4]))
v_old = helpers.cast_to_int("".join(v.zfill(4) for v in jellypy.CONFIG.PMS_VERSION.split('-')[0].split('.')[:4]))
v_new = helpers.cast_to_int("".join(v.zfill(4) for v in platform_downloads.get('version', '').split('-')[0].split('.')[:4]))
if not v_old:
logger.error("Tautulli PlexTV :: Unable to retrieve Plex updates: Invalid current server version: %s."
% plexpy.CONFIG.PMS_VERSION)
% jellypy.CONFIG.PMS_VERSION)
return {}
if not v_new:
logger.error("Tautulli PlexTV :: Unable to retrieve Plex updates: Invalid new server version: %s."
@@ -847,8 +847,8 @@ class PlexTV(object):
# Get proper download
releases = platform_downloads.get('releases', [{}])
release = next((r for r in releases if r['distro'] == plexpy.CONFIG.PMS_UPDATE_DISTRO and
r['build'] == plexpy.CONFIG.PMS_UPDATE_DISTRO_BUILD), releases[0])
release = next((r for r in releases if r['distro'] == jellypy.CONFIG.PMS_UPDATE_DISTRO and
r['build'] == jellypy.CONFIG.PMS_UPDATE_DISTRO_BUILD), releases[0])
download_info = {'update_available': v_new > v_old,
'platform': platform_downloads.get('name'),
@@ -876,13 +876,13 @@ class PlexTV(object):
return False
if subscription and helpers.get_xml_attr(subscription[0], 'active') == '1':
plexpy.CONFIG.__setattr__('PMS_PLEXPASS', 1)
plexpy.CONFIG.write()
jellypy.CONFIG.__setattr__('PMS_PLEXPASS', 1)
jellypy.CONFIG.write()
return True
else:
logger.debug("Tautulli PlexTV :: Plex Pass subscription not found.")
plexpy.CONFIG.__setattr__('PMS_PLEXPASS', 0)
plexpy.CONFIG.write()
jellypy.CONFIG.__setattr__('PMS_PLEXPASS', 0)
jellypy.CONFIG.write()
return False
def get_devices_list(self):
@@ -925,7 +925,7 @@ class PlexTV(object):
for info in status_info:
servers = info.getElementsByTagName('server')
for s in servers:
if helpers.get_xml_attr(s, 'address') == plexpy.CONFIG.PMS_IP:
if helpers.get_xml_attr(s, 'address') == jellypy.CONFIG.PMS_IP:
if helpers.get_xml_attr(info, 'running') == '1':
return True
else:

View File

@@ -21,19 +21,19 @@ from future.builtins import str
import sqlite3
from xml.dom import minidom
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import activity_processor
import database
import helpers
import logger
import users
else:
from plexpy import activity_processor
from plexpy import database
from plexpy import helpers
from plexpy import logger
from plexpy import users
from jellypy import activity_processor
from jellypy import database
from jellypy import helpers
from jellypy import logger
from jellypy import users
def extract_plexwatch_xml(xml=None):

View File

@@ -26,8 +26,8 @@ import time
from future.moves.urllib.parse import quote, quote_plus, urlencode
from xml.dom.minidom import Node
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import activity_processor
import common
import helpers
@@ -38,15 +38,15 @@ if plexpy.PYTHON2:
import session
import users
else:
from plexpy import activity_processor
from plexpy import common
from plexpy import helpers
from plexpy import http_handler
from plexpy import libraries
from plexpy import logger
from plexpy import plextv
from plexpy import session
from plexpy import users
from jellypy import activity_processor
from jellypy import common
from jellypy import helpers
from jellypy import http_handler
from jellypy import libraries
from jellypy import logger
from jellypy import plextv
from jellypy import session
from jellypy import users
def get_server_friendly_name():
@@ -57,13 +57,13 @@ def get_server_friendly_name():
if not server_name:
servers_info = PmsConnect().get_servers_info()
for server in servers_info:
if server['machine_identifier'] == plexpy.CONFIG.PMS_IDENTIFIER:
if server['machine_identifier'] == jellypy.CONFIG.PMS_IDENTIFIER:
server_name = server['name']
break
if server_name and server_name != plexpy.CONFIG.PMS_NAME:
plexpy.CONFIG.__setattr__('PMS_NAME', server_name)
plexpy.CONFIG.write()
if server_name and server_name != jellypy.CONFIG.PMS_NAME:
jellypy.CONFIG.__setattr__('PMS_NAME', server_name)
jellypy.CONFIG.write()
logger.info("Tautulli Pmsconnect :: Server name retrieved.")
return server_name
@@ -78,12 +78,12 @@ class PmsConnect(object):
self.url = url
self.token = token
if not self.url and plexpy.CONFIG.PMS_URL:
self.url = plexpy.CONFIG.PMS_URL
if not self.url and jellypy.CONFIG.PMS_URL:
self.url = jellypy.CONFIG.PMS_URL
elif not self.url:
self.url = 'http://{hostname}:{port}'.format(hostname=plexpy.CONFIG.PMS_IP,
port=plexpy.CONFIG.PMS_PORT)
self.timeout = plexpy.CONFIG.PMS_TIMEOUT
self.url = 'http://{hostname}:{port}'.format(hostname=jellypy.CONFIG.PMS_IP,
port=jellypy.CONFIG.PMS_PORT)
self.timeout = jellypy.CONFIG.PMS_TIMEOUT
if not self.token:
# Check if we should use the admin token, or the guest server token
@@ -92,7 +92,7 @@ class PmsConnect(object):
user_tokens = user_data.get_tokens(user_id=session.get_session_user_id())
self.token = user_tokens['server_token']
else:
self.token = plexpy.CONFIG.PMS_TOKEN
self.token = jellypy.CONFIG.PMS_TOKEN
self.request_handler = http_handler.HTTPHandler(urls=self.url,
token=self.token,
@@ -625,7 +625,7 @@ class PmsConnect(object):
metadata = {}
if not skip_cache and cache_key:
in_file_folder = os.path.join(plexpy.CONFIG.CACHE_DIR, 'session_metadata')
in_file_folder = os.path.join(jellypy.CONFIG.CACHE_DIR, 'session_metadata')
in_file_path = os.path.join(in_file_folder, 'metadata-sessionKey-%s.json' % cache_key)
if not os.path.exists(in_file_folder):
@@ -640,7 +640,7 @@ class PmsConnect(object):
if metadata:
_cache_time = metadata.pop('_cache_time', 0)
# Return cached metadata if less than cache_seconds ago
if return_cache or helpers.timestamp() - _cache_time <= plexpy.CONFIG.METADATA_CACHE_SECONDS:
if return_cache or helpers.timestamp() - _cache_time <= jellypy.CONFIG.METADATA_CACHE_SECONDS:
return metadata
if rating_key:
@@ -649,7 +649,7 @@ class PmsConnect(object):
metadata_xml = self.get_sync_item(str(sync_id), output_format='xml')
elif plex_guid.startswith(('plex://movie', 'plex://episode')):
rating_key = plex_guid.rsplit('/', 1)[-1]
plextv_metadata = PmsConnect(url='https://metadata.provider.plex.tv', token=plexpy.CONFIG.PMS_TOKEN)
plextv_metadata = PmsConnect(url='https://metadata.provider.plex.tv', token=jellypy.CONFIG.PMS_TOKEN)
metadata_xml = plextv_metadata.get_metadata(rating_key, output_format='xml')
else:
return metadata
@@ -1474,7 +1474,7 @@ class PmsConnect(object):
if cache_key:
metadata['_cache_time'] = helpers.timestamp()
out_file_folder = os.path.join(plexpy.CONFIG.CACHE_DIR, 'session_metadata')
out_file_folder = os.path.join(jellypy.CONFIG.CACHE_DIR, 'session_metadata')
out_file_path = os.path.join(out_file_folder, 'metadata-sessionKey-%s.json' % cache_key)
if not os.path.exists(out_file_folder):
@@ -1782,7 +1782,7 @@ class PmsConnect(object):
and not session.getElementsByTagName('Session') \
and not session.getElementsByTagName('TranscodeSession') \
and helpers.get_xml_attr(session, 'ratingKey').isdigit() \
and plexpy.CONFIG.PMS_PLEXPASS:
and jellypy.CONFIG.PMS_PLEXPASS:
plex_tv = plextv.PlexTV()
parent_rating_key = helpers.get_xml_attr(session, 'parentRatingKey')
grandparent_rating_key = helpers.get_xml_attr(session, 'grandparentRatingKey')
@@ -3101,9 +3101,9 @@ class PmsConnect(object):
logger.info("Tautulli is unable to check for Plex updates. Disabling check for Plex updates.")
# Disable check for Plex updates
plexpy.CONFIG.MONITOR_PMS_UPDATES = 0
plexpy.initialize_scheduler()
plexpy.CONFIG.write()
jellypy.CONFIG.MONITOR_PMS_UPDATES = 0
jellypy.initialize_scheduler()
jellypy.CONFIG.write()
return {}
@@ -3123,13 +3123,13 @@ class PmsConnect(object):
def set_server_version(self):
identity = self.get_server_identity()
version = identity.get('version', plexpy.CONFIG.PMS_VERSION)
version = identity.get('version', jellypy.CONFIG.PMS_VERSION)
plexpy.CONFIG.__setattr__('PMS_VERSION', version)
plexpy.CONFIG.write()
jellypy.CONFIG.__setattr__('PMS_VERSION', version)
jellypy.CONFIG.write()
def get_server_update_channel(self):
if plexpy.CONFIG.PMS_UPDATE_CHANNEL == 'plex':
if jellypy.CONFIG.PMS_UPDATE_CHANNEL == 'plex':
update_channel_value = self.get_server_pref('ButlerUpdateChannel')
if update_channel_value == '8':
@@ -3137,4 +3137,4 @@ class PmsConnect(object):
else:
return 'public'
return plexpy.CONFIG.PMS_UPDATE_CHANNEL
return jellypy.CONFIG.PMS_UPDATE_CHANNEL

View File

@@ -25,13 +25,13 @@ import collections
import requests
from requests.packages import urllib3
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import lock
import logger
else:
from plexpy import lock
from plexpy import logger
from jellypy import lock
from jellypy import logger
# Dictionary with last request times, for rate limiting.
@@ -59,7 +59,7 @@ def request_response(url, method="get", auto_raise=True,
# Disable verification of SSL certificates if requested. Note: this could
# pose a security issue!
kwargs["verify"] = bool(plexpy.CONFIG.VERIFY_SSL_CERT)
kwargs["verify"] = bool(jellypy.CONFIG.VERIFY_SSL_CERT)
if not kwargs['verify']:
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
@@ -123,7 +123,7 @@ def request_response(url, method="get", auto_raise=True,
e.response.status_code, cause)
# Debug response
if plexpy.VERBOSE:
if jellypy.VERBOSE:
server_message(e.response)
else:
logger.error("Request raised HTTP error.")
@@ -151,7 +151,7 @@ def request_response2(url, method="get", auto_raise=True,
# Disable verification of SSL certificates if requested. Note: this could
# pose a security issue!
kwargs['verify'] = bool(plexpy.CONFIG.VERIFY_SSL_CERT)
kwargs['verify'] = bool(jellypy.CONFIG.VERIFY_SSL_CERT)
if not kwargs['verify']:
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
@@ -203,7 +203,7 @@ def request_response2(url, method="get", auto_raise=True,
err_msg = "Request raised a HTTP error: {}".format(http_err)
if plexpy.VERBOSE:
if jellypy.VERBOSE:
req_msg = server_message(e.response, return_msg=True)
else:
@@ -264,7 +264,7 @@ def request_json(url, **kwargs):
logger.error("Response returned invalid JSON data")
# Debug response
if plexpy.VERBOSE:
if jellypy.VERBOSE:
server_message(response)

View File

@@ -20,13 +20,13 @@ from future.builtins import str
import cherrypy
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import users
else:
from plexpy import common
from plexpy import users
from jellypy import common
from jellypy import users
def get_session_info():
@@ -68,7 +68,7 @@ def get_session_user_token():
session_user_tokens = users.Users().get_tokens(_session['user_id'])
user_token = session_user_tokens['server_token']
else:
user_token = plexpy.CONFIG.PMS_TOKEN
user_token = jellypy.CONFIG.PMS_TOKEN
return user_token

View File

@@ -23,8 +23,8 @@ from future.moves.urllib.parse import parse_qsl
import httpagentparser
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import database
import datatables
@@ -34,21 +34,21 @@ if plexpy.PYTHON2:
import plextv
import session
else:
from plexpy import common
from plexpy import database
from plexpy import datatables
from plexpy import helpers
from plexpy import libraries
from plexpy import logger
from plexpy import plextv
from plexpy import session
from jellypy import common
from jellypy import database
from jellypy import datatables
from jellypy import helpers
from jellypy import libraries
from jellypy import logger
from jellypy import plextv
from jellypy import session
def refresh_users():
logger.info("Tautulli Users :: Requesting users list refresh...")
result = plextv.PlexTV().get_full_users_list()
server_id = plexpy.CONFIG.PMS_IDENTIFIER
server_id = jellypy.CONFIG.PMS_IDENTIFIER
if not server_id:
logger.error("Tautulli Users :: No PMS identifier, cannot refresh users. Verify server in settings.")
return
@@ -111,7 +111,7 @@ class Users(object):
custom_where = [['users.deleted_user', 0]]
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
if session.get_session_user_id():
custom_where.append(['users.user_id', session.get_session_user_id()])
@@ -486,7 +486,7 @@ class Users(object):
return []
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
if query_days and query_days is not None:
query_days = map(helpers.cast_to_int, query_days.split(','))
@@ -548,7 +548,7 @@ class Users(object):
return []
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
grouping = jellypy.CONFIG.GROUP_HISTORY_TABLES
monitor_db = database.MonitorDatabase()

View File

@@ -27,23 +27,23 @@ import re
import subprocess
import tarfile
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import common
import helpers
import logger
import request
else:
from plexpy import common
from plexpy import helpers
from plexpy import logger
from plexpy import request
from jellypy import common
from jellypy import helpers
from jellypy import logger
from jellypy import request
def runGit(args):
if plexpy.CONFIG.GIT_PATH:
git_locations = ['"' + plexpy.CONFIG.GIT_PATH + '"']
if jellypy.CONFIG.GIT_PATH:
git_locations = ['"' + jellypy.CONFIG.GIT_PATH + '"']
else:
git_locations = ['git']
@@ -56,8 +56,8 @@ def runGit(args):
cmd = cur_git + ' ' + args
try:
logger.debug('Trying to execute: "' + cmd + '" with shell in ' + plexpy.PROG_DIR)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=plexpy.PROG_DIR)
logger.debug('Trying to execute: "' + cmd + '" with shell in ' + jellypy.PROG_DIR)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=jellypy.PROG_DIR)
output, err = p.communicate()
output = output.strip().decode()
@@ -80,18 +80,18 @@ def runGit(args):
def get_version():
if plexpy.FROZEN and common.PLATFORM == 'Windows':
plexpy.INSTALL_TYPE = 'windows'
if jellypy.FROZEN and common.PLATFORM == 'Windows':
jellypy.INSTALL_TYPE = 'windows'
current_version, current_branch = get_version_from_file()
return current_version, 'origin', current_branch
elif plexpy.FROZEN and common.PLATFORM == 'Darwin':
plexpy.INSTALL_TYPE = 'macos'
elif jellypy.FROZEN and common.PLATFORM == 'Darwin':
jellypy.INSTALL_TYPE = 'macos'
current_version, current_branch = get_version_from_file()
return current_version, 'origin', current_branch
elif os.path.isdir(os.path.join(plexpy.PROG_DIR, '.git')):
plexpy.INSTALL_TYPE = 'git'
elif os.path.isdir(os.path.join(jellypy.PROG_DIR, '.git')):
jellypy.INSTALL_TYPE = 'git'
output, err = runGit('rev-parse HEAD')
if not output:
@@ -104,9 +104,9 @@ def get_version():
logger.error('Output does not look like a hash, not using it.')
cur_commit_hash = None
if plexpy.CONFIG.DO_NOT_OVERRIDE_GIT_BRANCH and plexpy.CONFIG.GIT_BRANCH:
if jellypy.CONFIG.DO_NOT_OVERRIDE_GIT_BRANCH and jellypy.CONFIG.GIT_BRANCH:
remote_name = None
branch_name = plexpy.CONFIG.GIT_BRANCH
branch_name = jellypy.CONFIG.GIT_BRANCH
else:
remote_branch, err = runGit('rev-parse --abbrev-ref --symbolic-full-name @{u}')
@@ -116,16 +116,16 @@ def get_version():
else:
remote_name = branch_name = None
if not remote_name and plexpy.CONFIG.GIT_REMOTE:
logger.error('Could not retrieve remote name from git. Falling back to %s.' % plexpy.CONFIG.GIT_REMOTE)
remote_name = plexpy.CONFIG.GIT_REMOTE
if not remote_name and jellypy.CONFIG.GIT_REMOTE:
logger.error('Could not retrieve remote name from git. Falling back to %s.' % jellypy.CONFIG.GIT_REMOTE)
remote_name = jellypy.CONFIG.GIT_REMOTE
if not remote_name:
logger.error('Could not retrieve remote name from git. Defaulting to origin.')
branch_name = 'origin'
if not branch_name and plexpy.CONFIG.GIT_BRANCH:
logger.error('Could not retrieve branch name from git. Falling back to %s.' % plexpy.CONFIG.GIT_BRANCH)
branch_name = plexpy.CONFIG.GIT_BRANCH
if not branch_name and jellypy.CONFIG.GIT_BRANCH:
logger.error('Could not retrieve branch name from git. Falling back to %s.' % jellypy.CONFIG.GIT_BRANCH)
branch_name = jellypy.CONFIG.GIT_BRANCH
if not branch_name:
logger.error('Could not retrieve branch name from git. Defaulting to master.')
branch_name = 'master'
@@ -133,20 +133,20 @@ def get_version():
return cur_commit_hash, remote_name, branch_name
else:
if plexpy.DOCKER:
plexpy.INSTALL_TYPE = 'docker'
elif plexpy.SNAP:
plexpy.INSTALL_TYPE = 'snap'
if jellypy.DOCKER:
jellypy.INSTALL_TYPE = 'docker'
elif jellypy.SNAP:
jellypy.INSTALL_TYPE = 'snap'
else:
plexpy.INSTALL_TYPE = 'source'
jellypy.INSTALL_TYPE = 'source'
current_version, current_branch = get_version_from_file()
return current_version, 'origin', current_branch
def get_version_from_file():
version_file = os.path.join(plexpy.PROG_DIR, 'version.txt')
branch_file = os.path.join(plexpy.PROG_DIR, 'branch.txt')
version_file = os.path.join(jellypy.PROG_DIR, 'version.txt')
branch_file = os.path.join(jellypy.PROG_DIR, 'branch.txt')
if os.path.isfile(version_file):
with open(version_file, 'r') as f:
@@ -166,30 +166,30 @@ def get_version_from_file():
def check_update(scheduler=False, notify=False, use_cache=False):
check_github(scheduler=scheduler, notify=notify, use_cache=use_cache)
if not plexpy.CURRENT_VERSION:
plexpy.UPDATE_AVAILABLE = None
elif plexpy.COMMITS_BEHIND > 0 and \
(plexpy.common.BRANCH in ('master', 'beta') or plexpy.SNAP or plexpy.FROZEN) and \
plexpy.common.RELEASE != plexpy.LATEST_RELEASE:
plexpy.UPDATE_AVAILABLE = 'release'
elif plexpy.COMMITS_BEHIND > 0 and \
not plexpy.SNAP and not plexpy.FROZEN and \
plexpy.CURRENT_VERSION != plexpy.LATEST_VERSION:
plexpy.UPDATE_AVAILABLE = 'commit'
if not jellypy.CURRENT_VERSION:
jellypy.UPDATE_AVAILABLE = None
elif jellypy.COMMITS_BEHIND > 0 and \
(jellypy.common.BRANCH in ('master', 'beta') or jellypy.SNAP or jellypy.FROZEN) and \
jellypy.common.RELEASE != jellypy.LATEST_RELEASE:
jellypy.UPDATE_AVAILABLE = 'release'
elif jellypy.COMMITS_BEHIND > 0 and \
not jellypy.SNAP and not jellypy.FROZEN and \
jellypy.CURRENT_VERSION != jellypy.LATEST_VERSION:
jellypy.UPDATE_AVAILABLE = 'commit'
else:
plexpy.UPDATE_AVAILABLE = False
jellypy.UPDATE_AVAILABLE = False
if plexpy.WIN_SYS_TRAY_ICON:
plexpy.WIN_SYS_TRAY_ICON.change_tray_update_icon()
elif plexpy.MAC_SYS_TRAY_ICON:
plexpy.MAC_SYS_TRAY_ICON.change_tray_update_icon()
if jellypy.WIN_SYS_TRAY_ICON:
jellypy.WIN_SYS_TRAY_ICON.change_tray_update_icon()
elif jellypy.MAC_SYS_TRAY_ICON:
jellypy.MAC_SYS_TRAY_ICON.change_tray_update_icon()
def check_github(scheduler=False, notify=False, use_cache=False):
plexpy.COMMITS_BEHIND = 0
jellypy.COMMITS_BEHIND = 0
if plexpy.CONFIG.GIT_TOKEN:
headers = {'Authorization': 'token {}'.format(plexpy.CONFIG.GIT_TOKEN)}
if jellypy.CONFIG.GIT_TOKEN:
headers = {'Authorization': 'token {}'.format(jellypy.CONFIG.GIT_TOKEN)}
else:
headers = {}
@@ -197,118 +197,118 @@ def check_github(scheduler=False, notify=False, use_cache=False):
if not version:
# Get the latest version available from github
logger.info('Retrieving latest version information from GitHub')
url = 'https://api.github.com/repos/%s/%s/commits/%s' % (plexpy.CONFIG.GIT_USER,
plexpy.CONFIG.GIT_REPO,
plexpy.CONFIG.GIT_BRANCH)
url = 'https://api.github.com/repos/%s/%s/commits/%s' % (jellypy.CONFIG.GIT_USER,
jellypy.CONFIG.GIT_REPO,
jellypy.CONFIG.GIT_BRANCH)
version = request.request_json(url, headers=headers, timeout=20,
validator=lambda x: type(x) == dict)
github_cache('version', github_data=version)
if version is None:
logger.warn('Could not get the latest version from GitHub. Are you running a local development version?')
return plexpy.CURRENT_VERSION
return jellypy.CURRENT_VERSION
plexpy.LATEST_VERSION = version['sha']
logger.debug("Latest version is %s", plexpy.LATEST_VERSION)
jellypy.LATEST_VERSION = version['sha']
logger.debug("Latest version is %s", jellypy.LATEST_VERSION)
# See how many commits behind we are
if not plexpy.CURRENT_VERSION:
if not jellypy.CURRENT_VERSION:
logger.info('You are running an unknown version of Tautulli. Run the updater to identify your version')
return plexpy.LATEST_VERSION
return jellypy.LATEST_VERSION
if plexpy.LATEST_VERSION == plexpy.CURRENT_VERSION:
if jellypy.LATEST_VERSION == jellypy.CURRENT_VERSION:
logger.info('Tautulli is up to date')
return plexpy.LATEST_VERSION
return jellypy.LATEST_VERSION
commits = github_cache('commits', use_cache=use_cache)
if not commits:
logger.info('Comparing currently installed version with latest GitHub version')
url = 'https://api.github.com/repos/%s/%s/compare/%s...%s' % (plexpy.CONFIG.GIT_USER,
plexpy.CONFIG.GIT_REPO,
plexpy.LATEST_VERSION,
plexpy.CURRENT_VERSION)
url = 'https://api.github.com/repos/%s/%s/compare/%s...%s' % (jellypy.CONFIG.GIT_USER,
jellypy.CONFIG.GIT_REPO,
jellypy.LATEST_VERSION,
jellypy.CURRENT_VERSION)
commits = request.request_json(url, headers=headers, timeout=20, whitelist_status_code=404,
validator=lambda x: type(x) == dict)
github_cache('commits', github_data=commits)
if commits is None:
logger.warn('Could not get commits behind from GitHub.')
return plexpy.LATEST_VERSION
return jellypy.LATEST_VERSION
try:
plexpy.COMMITS_BEHIND = int(commits['behind_by'])
logger.debug("In total, %d commits behind", plexpy.COMMITS_BEHIND)
jellypy.COMMITS_BEHIND = int(commits['behind_by'])
logger.debug("In total, %d commits behind", jellypy.COMMITS_BEHIND)
except KeyError:
logger.info('Cannot compare versions. Are you running a local development version?')
plexpy.COMMITS_BEHIND = 0
jellypy.COMMITS_BEHIND = 0
if plexpy.COMMITS_BEHIND > 0:
logger.info('New version is available. You are %s commits behind' % plexpy.COMMITS_BEHIND)
if jellypy.COMMITS_BEHIND > 0:
logger.info('New version is available. You are %s commits behind' % jellypy.COMMITS_BEHIND)
releases = github_cache('releases', use_cache=use_cache)
if not releases:
url = 'https://api.github.com/repos/%s/%s/releases' % (plexpy.CONFIG.GIT_USER,
plexpy.CONFIG.GIT_REPO)
url = 'https://api.github.com/repos/%s/%s/releases' % (jellypy.CONFIG.GIT_USER,
jellypy.CONFIG.GIT_REPO)
releases = request.request_json(url, timeout=20, whitelist_status_code=404,
validator=lambda x: type(x) == list)
github_cache('releases', github_data=releases)
if releases is None:
logger.warn('Could not get releases from GitHub.')
return plexpy.LATEST_VERSION
return jellypy.LATEST_VERSION
if plexpy.CONFIG.GIT_BRANCH == 'master':
if jellypy.CONFIG.GIT_BRANCH == 'master':
release = next((r for r in releases if not r['prerelease']), releases[0])
elif plexpy.CONFIG.GIT_BRANCH == 'beta':
elif jellypy.CONFIG.GIT_BRANCH == 'beta':
release = next((r for r in releases if not r['tag_name'].endswith('-nightly')), releases[0])
elif plexpy.CONFIG.GIT_BRANCH == 'nightly':
elif jellypy.CONFIG.GIT_BRANCH == 'nightly':
release = next((r for r in releases), releases[0])
else:
release = releases[0]
plexpy.LATEST_RELEASE = release['tag_name']
jellypy.LATEST_RELEASE = release['tag_name']
if notify:
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_plexpyupdate',
jellypy.NOTIFY_QUEUE.put({'notify_action': 'on_plexpyupdate',
'plexpy_download_info': release,
'plexpy_update_commit': plexpy.LATEST_VERSION,
'plexpy_update_behind': plexpy.COMMITS_BEHIND})
'plexpy_update_commit': jellypy.LATEST_VERSION,
'plexpy_update_behind': jellypy.COMMITS_BEHIND})
if plexpy.PYTHON2:
if jellypy.PYTHON2:
logger.warn('Tautulli is running using Python 2. Unable to run automatic update.')
elif scheduler and plexpy.CONFIG.PLEXPY_AUTO_UPDATE and \
not plexpy.DOCKER and not plexpy.SNAP and \
not (plexpy.FROZEN and common.PLATFORM == 'Darwin'):
elif scheduler and jellypy.CONFIG.PLEXPY_AUTO_UPDATE and \
not jellypy.DOCKER and not jellypy.SNAP and \
not (jellypy.FROZEN and common.PLATFORM == 'Darwin'):
logger.info('Running automatic update.')
plexpy.shutdown(restart=True, update=True)
jellypy.shutdown(restart=True, update=True)
elif plexpy.COMMITS_BEHIND == 0:
elif jellypy.COMMITS_BEHIND == 0:
logger.info('Tautulli is up to date')
return plexpy.LATEST_VERSION
return jellypy.LATEST_VERSION
def update():
if plexpy.PYTHON2:
if jellypy.PYTHON2:
logger.warn('Tautulli is running using Python 2. Unable to update.')
return
if not plexpy.UPDATE_AVAILABLE:
if not jellypy.UPDATE_AVAILABLE:
return
if plexpy.INSTALL_TYPE in ('docker', 'snap', 'macos'):
if jellypy.INSTALL_TYPE in ('docker', 'snap', 'macos'):
return
elif plexpy.INSTALL_TYPE == 'windows':
elif jellypy.INSTALL_TYPE == 'windows':
logger.info('Calling Windows scheduled task to update Tautulli')
CREATE_NO_WINDOW = 0x08000000
subprocess.Popen(['SCHTASKS', '/Run', '/TN', 'TautulliUpdateTask'],
creationflags=CREATE_NO_WINDOW)
elif plexpy.INSTALL_TYPE == 'git':
output, err = runGit('pull --ff-only {} {}'.format(plexpy.CONFIG.GIT_REMOTE,
plexpy.CONFIG.GIT_BRANCH))
elif jellypy.INSTALL_TYPE == 'git':
output, err = runGit('pull --ff-only {} {}'.format(jellypy.CONFIG.GIT_REMOTE,
jellypy.CONFIG.GIT_BRANCH))
if not output:
logger.error('Unable to download latest version')
@@ -320,12 +320,12 @@ def update():
elif line.endswith(('Aborting', 'Aborting.')):
logger.error('Unable to update from git: ' + line)
elif plexpy.INSTALL_TYPE == 'source':
tar_download_url = 'https://github.com/{}/{}/tarball/{}'.format(plexpy.CONFIG.GIT_USER,
plexpy.CONFIG.GIT_REPO,
plexpy.CONFIG.GIT_BRANCH)
update_dir = os.path.join(plexpy.DATA_DIR, 'update')
version_path = os.path.join(plexpy.PROG_DIR, 'version.txt')
elif jellypy.INSTALL_TYPE == 'source':
tar_download_url = 'https://github.com/{}/{}/tarball/{}'.format(jellypy.CONFIG.GIT_USER,
jellypy.CONFIG.GIT_REPO,
jellypy.CONFIG.GIT_BRANCH)
update_dir = os.path.join(jellypy.DATA_DIR, 'update')
version_path = os.path.join(jellypy.PROG_DIR, 'version.txt')
logger.info('Downloading update from: ' + tar_download_url)
data = request.request_content(tar_download_url)
@@ -334,8 +334,8 @@ def update():
logger.error("Unable to retrieve new version from '%s', can't update", tar_download_url)
return
download_name = plexpy.CONFIG.GIT_BRANCH + '-github'
tar_download_path = os.path.join(plexpy.DATA_DIR, download_name)
download_name = jellypy.CONFIG.GIT_BRANCH + '-github'
tar_download_path = os.path.join(jellypy.DATA_DIR, download_name)
# Save tar to disk
with open(tar_download_path, 'wb') as f:
@@ -363,7 +363,7 @@ def update():
dirname = dirname[len(content_dir) + 1:]
for curfile in filenames:
old_path = os.path.join(content_dir, dirname, curfile)
new_path = os.path.join(plexpy.PROG_DIR, dirname, curfile)
new_path = os.path.join(jellypy.PROG_DIR, dirname, curfile)
if os.path.isfile(new_path):
os.remove(new_path)
@@ -372,7 +372,7 @@ def update():
# Update version.txt
try:
with open(version_path, 'w') as f:
f.write(str(plexpy.LATEST_VERSION))
f.write(str(jellypy.LATEST_VERSION))
except IOError as e:
logger.error(
"Unable to write current version to version.txt, update not complete: %s",
@@ -382,18 +382,18 @@ def update():
def reset_git_install():
if plexpy.INSTALL_TYPE == 'git':
logger.info('Attempting to reset git install to "{}/{}/{}"'.format(plexpy.CONFIG.GIT_REMOTE,
plexpy.CONFIG.GIT_BRANCH,
if jellypy.INSTALL_TYPE == 'git':
logger.info('Attempting to reset git install to "{}/{}/{}"'.format(jellypy.CONFIG.GIT_REMOTE,
jellypy.CONFIG.GIT_BRANCH,
common.RELEASE))
output, err = runGit('remote set-url {} https://github.com/{}/{}.git'.format(plexpy.CONFIG.GIT_REMOTE,
plexpy.CONFIG.GIT_USER,
plexpy.CONFIG.GIT_REPO))
output, err = runGit('fetch {}'.format(plexpy.CONFIG.GIT_REMOTE))
output, err = runGit('checkout {}'.format(plexpy.CONFIG.GIT_BRANCH))
output, err = runGit('branch -u {}/{}'.format(plexpy.CONFIG.GIT_REMOTE,
plexpy.CONFIG.GIT_BRANCH))
output, err = runGit('remote set-url {} https://github.com/{}/{}.git'.format(jellypy.CONFIG.GIT_REMOTE,
jellypy.CONFIG.GIT_USER,
jellypy.CONFIG.GIT_REPO))
output, err = runGit('fetch {}'.format(jellypy.CONFIG.GIT_REMOTE))
output, err = runGit('checkout {}'.format(jellypy.CONFIG.GIT_BRANCH))
output, err = runGit('branch -u {}/{}'.format(jellypy.CONFIG.GIT_REMOTE,
jellypy.CONFIG.GIT_BRANCH))
output, err = runGit('reset --hard {}'.format(common.RELEASE))
if not output:
@@ -410,12 +410,12 @@ def reset_git_install():
def checkout_git_branch():
if plexpy.INSTALL_TYPE == 'git':
logger.info('Attempting to checkout git branch "{}/{}"'.format(plexpy.CONFIG.GIT_REMOTE,
plexpy.CONFIG.GIT_BRANCH))
if jellypy.INSTALL_TYPE == 'git':
logger.info('Attempting to checkout git branch "{}/{}"'.format(jellypy.CONFIG.GIT_REMOTE,
jellypy.CONFIG.GIT_BRANCH))
output, err = runGit('fetch {}'.format(plexpy.CONFIG.GIT_REMOTE))
output, err = runGit('checkout {}'.format(plexpy.CONFIG.GIT_BRANCH))
output, err = runGit('fetch {}'.format(jellypy.CONFIG.GIT_REMOTE))
output, err = runGit('checkout {}'.format(jellypy.CONFIG.GIT_BRANCH))
if not output:
logger.error('Unable to change git branch.')
@@ -426,13 +426,13 @@ def checkout_git_branch():
logger.error('Unable to checkout from git: ' + line)
return
output, err = runGit('pull {} {}'.format(plexpy.CONFIG.GIT_REMOTE,
plexpy.CONFIG.GIT_BRANCH))
output, err = runGit('pull {} {}'.format(jellypy.CONFIG.GIT_REMOTE,
jellypy.CONFIG.GIT_BRANCH))
def github_cache(cache, github_data=None, use_cache=True):
timestamp = helpers.timestamp()
cache_filepath = os.path.join(plexpy.CONFIG.CACHE_DIR, 'github_{}.json'.format(cache))
cache_filepath = os.path.join(jellypy.CONFIG.CACHE_DIR, 'github_{}.json'.format(cache))
if github_data:
cache_data = {'github_data': github_data, '_cache_time': timestamp}
@@ -447,7 +447,7 @@ def github_cache(cache, github_data=None, use_cache=True):
try:
with open(cache_filepath, 'r', encoding='utf-8') as cache_file:
cache_data = json.load(cache_file)
if timestamp - cache_data['_cache_time'] < plexpy.CONFIG.CHECK_GITHUB_CACHE_SECONDS:
if timestamp - cache_data['_cache_time'] < jellypy.CONFIG.CHECK_GITHUB_CACHE_SECONDS:
logger.debug('Using cached GitHub %s data', cache)
return cache_data['github_data']
except:
@@ -455,7 +455,7 @@ def github_cache(cache, github_data=None, use_cache=True):
def read_changelog(latest_only=False, since_prev_release=False):
changelog_file = os.path.join(plexpy.PROG_DIR, 'CHANGELOG.md')
changelog_file = os.path.join(jellypy.PROG_DIR, 'CHANGELOG.md')
if not os.path.isfile(changelog_file):
return '<h4>Missing changelog file</h4>'
@@ -470,7 +470,7 @@ def read_changelog(latest_only=False, since_prev_release=False):
list_pattern = re.compile(r'(^[ \t]*\*\s)(.+)')
beta_release = False
prev_release = str(plexpy.PREV_RELEASE)
prev_release = str(jellypy.PREV_RELEASE)
with open(changelog_file, "r") as logfile:
for line in logfile:

View File

@@ -28,19 +28,19 @@ import time
import certifi
import websocket
import plexpy
if plexpy.PYTHON2:
import jellypy
if jellypy.PYTHON2:
import activity_handler
import activity_pinger
import activity_processor
import database
import logger
else:
from plexpy import activity_handler
from plexpy import activity_pinger
from plexpy import activity_processor
from plexpy import database
from plexpy import logger
from jellypy import activity_handler
from jellypy import activity_pinger
from jellypy import activity_processor
from jellypy import database
from jellypy import logger
name = 'websocket'
@@ -66,30 +66,30 @@ def start_thread():
def on_connect():
if plexpy.PLEX_SERVER_UP is None:
plexpy.PLEX_SERVER_UP = True
if jellypy.PLEX_SERVER_UP is None:
jellypy.PLEX_SERVER_UP = True
if not plexpy.PLEX_SERVER_UP:
if not jellypy.PLEX_SERVER_UP:
logger.info("Tautulli WebSocket :: The Plex Media Server is back up.")
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_intup'})
plexpy.PLEX_SERVER_UP = True
jellypy.NOTIFY_QUEUE.put({'notify_action': 'on_intup'})
jellypy.PLEX_SERVER_UP = True
plexpy.initialize_scheduler()
if plexpy.CONFIG.WEBSOCKET_MONITOR_PING_PONG:
jellypy.initialize_scheduler()
if jellypy.CONFIG.WEBSOCKET_MONITOR_PING_PONG:
send_ping()
def on_disconnect():
if plexpy.PLEX_SERVER_UP is None:
plexpy.PLEX_SERVER_UP = False
if jellypy.PLEX_SERVER_UP is None:
jellypy.PLEX_SERVER_UP = False
if plexpy.PLEX_SERVER_UP:
if jellypy.PLEX_SERVER_UP:
logger.info("Tautulli WebSocket :: Unable to get a response from the server, Plex server is down.")
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_intdown'})
plexpy.PLEX_SERVER_UP = False
jellypy.NOTIFY_QUEUE.put({'notify_action': 'on_intdown'})
jellypy.PLEX_SERVER_UP = False
activity_processor.ActivityProcessor().set_temp_stopped()
plexpy.initialize_scheduler()
jellypy.initialize_scheduler()
def reconnect():
@@ -106,14 +106,14 @@ def shutdown():
def close():
logger.info("Tautulli WebSocket :: Disconnecting websocket...")
plexpy.WEBSOCKET.close()
plexpy.WS_CONNECTED = False
jellypy.WEBSOCKET.close()
jellypy.WS_CONNECTED = False
def send_ping():
if plexpy.WS_CONNECTED:
if jellypy.WS_CONNECTED:
# logger.debug("Tautulli WebSocket :: Sending ping.")
plexpy.WEBSOCKET.ping("Hi?")
jellypy.WEBSOCKET.ping("Hi?")
global pong_timer
pong_timer = threading.Timer(5.0, wait_pong)
@@ -127,7 +127,7 @@ def wait_pong():
logger.warn("Tautulli WebSocket :: Failed to receive pong from websocket, ping attempt %s." % str(pong_count))
if pong_count >= plexpy.CONFIG.WEBSOCKET_CONNECTION_ATTEMPTS:
if pong_count >= jellypy.CONFIG.WEBSOCKET_CONNECTION_ATTEMPTS:
pong_count = 0
close()
@@ -144,24 +144,24 @@ def receive_pong():
def run():
from websocket import create_connection
if plexpy.CONFIG.PMS_SSL and plexpy.CONFIG.PMS_URL[:5] == 'https':
uri = plexpy.CONFIG.PMS_URL.replace('https://', 'wss://') + '/:/websockets/notifications'
if jellypy.CONFIG.PMS_SSL and jellypy.CONFIG.PMS_URL[:5] == 'https':
uri = jellypy.CONFIG.PMS_URL.replace('https://', 'wss://') + '/:/websockets/notifications'
secure = 'secure '
if plexpy.CONFIG.VERIFY_SSL_CERT:
if jellypy.CONFIG.VERIFY_SSL_CERT:
sslopt = {'ca_certs': certifi.where()}
else:
sslopt = {'cert_reqs': ssl.CERT_NONE}
else:
uri = 'ws://%s:%s/:/websockets/notifications' % (
plexpy.CONFIG.PMS_IP,
plexpy.CONFIG.PMS_PORT
jellypy.CONFIG.PMS_IP,
jellypy.CONFIG.PMS_PORT
)
secure = ''
sslopt = None
# Set authentication token (if one is available)
if plexpy.CONFIG.PMS_TOKEN:
header = ["X-Plex-Token: %s" % plexpy.CONFIG.PMS_TOKEN]
if jellypy.CONFIG.PMS_TOKEN:
header = ["X-Plex-Token: %s" % jellypy.CONFIG.PMS_TOKEN]
else:
header = []
@@ -172,18 +172,18 @@ def run():
# Try an open the websocket connection
logger.info("Tautulli WebSocket :: Opening %swebsocket." % secure)
try:
plexpy.WEBSOCKET = create_connection(uri, header=header, sslopt=sslopt)
jellypy.WEBSOCKET = create_connection(uri, header=header, sslopt=sslopt)
logger.info("Tautulli WebSocket :: Ready")
plexpy.WS_CONNECTED = True
jellypy.WS_CONNECTED = True
except (websocket.WebSocketException, IOError, Exception) as e:
logger.error("Tautulli WebSocket :: %s.", e)
if plexpy.WS_CONNECTED:
if jellypy.WS_CONNECTED:
on_connect()
while plexpy.WS_CONNECTED:
while jellypy.WS_CONNECTED:
try:
process(*receive(plexpy.WEBSOCKET))
process(*receive(jellypy.WEBSOCKET))
# successfully received data, reset reconnects counter
reconnects = 0
@@ -195,19 +195,19 @@ def run():
if reconnects == 0:
logger.warn("Tautulli WebSocket :: Connection has closed.")
if not plexpy.CONFIG.PMS_IS_CLOUD and reconnects < plexpy.CONFIG.WEBSOCKET_CONNECTION_ATTEMPTS:
if not jellypy.CONFIG.PMS_IS_CLOUD and reconnects < jellypy.CONFIG.WEBSOCKET_CONNECTION_ATTEMPTS:
reconnects += 1
# Sleep 5 between connection attempts
if reconnects > 1:
time.sleep(plexpy.CONFIG.WEBSOCKET_CONNECTION_TIMEOUT)
time.sleep(jellypy.CONFIG.WEBSOCKET_CONNECTION_TIMEOUT)
logger.warn("Tautulli WebSocket :: Reconnection attempt %s." % str(reconnects))
try:
plexpy.WEBSOCKET = create_connection(uri, header=header)
jellypy.WEBSOCKET = create_connection(uri, header=header)
logger.info("Tautulli WebSocket :: Ready")
plexpy.WS_CONNECTED = True