Rename; Removed deps from repo
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
.git
|
||||
.github
|
||||
.gitignore
|
||||
contrib
|
||||
init-scripts
|
||||
package
|
||||
pylintrc
|
||||
snap
|
||||
*.md
|
||||
!CHANGELOG*.md
|
||||
start.bat
|
||||
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@@ -1,3 +0,0 @@
|
||||
github: JonnyWong16
|
||||
patreon: Tautulli
|
||||
custom: ["https://bit.ly/2InPp15", "https://bit.ly/2WTq83m"]
|
||||
20
.github/pull_request_template.md
vendored
20
.github/pull_request_template.md
vendored
@@ -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
|
||||
115
.github/workflows/publish-docker.yml
vendored
115
.github/workflows/publish-docker.yml
vendored
@@ -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
|
||||
194
.github/workflows/publish-installers.yml
vendored
194
.github/workflows/publish-installers.yml
vendored
@@ -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
|
||||
94
.github/workflows/publish-snap.yml
vendored
94
.github/workflows/publish-snap.yml
vendored
@@ -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
|
||||
28
.github/workflows/pull-requests.yml
vendored
28
.github/workflows/pull-requests.yml
vendored
@@ -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
343
.gitignore
vendored
@@ -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
|
||||
|
||||
26
Dockerfile
26
Dockerfile
@@ -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
|
||||
@@ -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__":
|
||||
24
PlexPy.py
24
PlexPy.py
@@ -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()
|
||||
10
README.md
10
README.md
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -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))
|
||||
@@ -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.")
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -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):
|
||||
@@ -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
|
||||
@@ -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'
|
||||
|
||||
@@ -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 []
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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):
|
||||
@@ -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 []
|
||||
|
||||
@@ -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 + \
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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):
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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):
|
||||
@@ -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):
|
||||
@@ -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:
|
||||
@@ -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):
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
@@ -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
|
||||