Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge up 0.7.x to main #248

Merged
merged 104 commits into from
Apr 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
88b0b40
Add date_value helper to format dates from plex
glensc Apr 9, 2021
9f4b7ec
Add collected_at property
glensc Apr 9, 2021
f0baf0c
Restart websocket if connection was closed
glensc Apr 10, 2021
c3fe8f6
Add logic to fill collected_at for library items
glensc Apr 9, 2021
7ff33b8
Add to_json method to plex media item
glensc Apr 9, 2021
9afcc6c
Implement collected_at for movies
glensc Apr 9, 2021
a6cdbac
The collected_at value must be iso8601-formatted
glensc Apr 9, 2021
aa45f23
Movies is a list
glensc Apr 9, 2021
5eecd16
Add title and year
glensc Apr 9, 2021
885027f
Merge pull request #211 from glensc/collected-date-value
glensc Apr 10, 2021
cc3e232
Merge pull request #213 from glensc/recover-websocket-close
glensc Apr 10, 2021
18bcac8
Show progressbar when processing section
glensc Apr 9, 2021
dfea5a0
Merge pull request #212 from glensc/click-progressbar
glensc Apr 10, 2021
5a6b0c3
Use property type to check media type
glensc Apr 10, 2021
0e05c13
Merge pull request #218 from glensc/type-matching
glensc Apr 10, 2021
b4d9d4c
Merge branch 'main' into 0.7.x
glensc Apr 11, 2021
7be829f
Remove memoize and results collection in section items
glensc Apr 11, 2021
8dadbd8
Cleanup unused imports
glensc Apr 11, 2021
64f35d8
Move section items filtering out of library section
glensc Apr 11, 2021
e292d3e
Show processed items count
glensc Apr 11, 2021
3342200
Merge pull request #224 from glensc/interacive-progressbar
glensc Apr 11, 2021
e096728
Fix typo in log message
glensc Apr 11, 2021
4e0183e
Unify log messages
glensc Apr 11, 2021
e4816d5
Simplify logging by using Plex episode object
glensc Apr 7, 2021
37bbf9b
Add methods to wrap episodes with PlexLibraryItem
glensc Apr 7, 2021
992db7a
Update to use PlexLibraryItem
glensc Apr 7, 2021
ed10cb7
Cleanup unused pm
glensc Apr 7, 2021
26e0e60
Remove TypeError check
glensc Apr 11, 2021
56e3f2c
Merge pull request #225 from glensc/tv-shows-episode-object
glensc Apr 11, 2021
32f64a6
Add test_tv_lookup test
glensc Apr 10, 2021
b969b1c
Merge pull request #215 from glensc/tvshow-type
glensc Apr 12, 2021
6345f5b
Merge collected_at for episodes collection
glensc Apr 12, 2021
fb60b12
Merge pull request #233 from glensc/episode_collected_at
glensc Apr 12, 2021
1cfc871
Add TraktBatch to handle batching add_to_collection calls
glensc Apr 12, 2021
b0aec1e
Use batch to submit add collection calls
glensc Apr 12, 2021
c93e5e0
Skip submitting empty collection
glensc Apr 12, 2021
3b8fec6
Report updated collections
glensc Apr 12, 2021
5a63f4f
Minimize printed result
glensc Apr 12, 2021
acda791
Merge pull request #232 from glensc/collection-batch
glensc Apr 12, 2021
65132df
Add inspect command
glensc Apr 10, 2021
bbbf3d5
Inspect: Print audio stream detail
glensc Apr 10, 2021
14566c9
Print something of video stream
glensc Apr 10, 2021
90375b2
Convert numeric value to integer
glensc Apr 14, 2021
4babe56
Rename movie to media to respect that tv is not movie
glensc Apr 14, 2021
eba55ea
Print media guid/guids
glensc Apr 14, 2021
d2dfe66
Include trakt match in output
glensc Apr 14, 2021
b5c6519
Merge pull request #237 from glensc/inspect-command
glensc Apr 15, 2021
ade5f9b
Swap media_type/type names
glensc Apr 15, 2021
f7f0f27
Drop un-needed media_type
glensc Apr 15, 2021
daf63b3
Rename find_movie to more appropriate find_by_media
glensc Apr 15, 2021
3efc370
Cleanup unused imports
glensc Apr 15, 2021
e43ae61
Update rate_limit to also catch ConnectionError
glensc Apr 15, 2021
ff295a0
Merge pull request #238 from glensc/cleanups
glensc Apr 15, 2021
54e2045
Cleanup code to yield te.instance directly rather resolve it later
glensc Apr 15, 2021
968c650
Merge pull request #241 from glensc/cleanup-instance
glensc Apr 15, 2021
0981c21
Sort imports
glensc Apr 15, 2021
eb508f4
Add plex-login command
glensc Apr 10, 2021
7e28363
Skip Plex log in if already have token
glensc Apr 10, 2021
108077f
Impement plex login with click module
glensc Apr 10, 2021
12d1832
Add methods to choose plex server
glensc Apr 13, 2021
944e410
Choose server in a loop
glensc Apr 13, 2021
90a6c87
Add ui to choose Plex server
glensc Apr 13, 2021
1838974
Pick managed user if owned server was chosen
glensc Apr 13, 2021
39ce2ed
Add notice about long wait and errors
glensc Apr 13, 2021
1029430
Update the help text
glensc Apr 13, 2021
616825b
Add semantic styles helper
glensc Apr 13, 2021
79d9ff6
Use style helpers for color style
glensc Apr 13, 2021
b19639e
Catch only NotFound exception
glensc Apr 14, 2021
4df6081
Save .env on plex-login success
glensc Apr 15, 2021
73cc775
Update pytrakt to 3.1.0
glensc Apr 15, 2021
364c190
Add test that invalid id rises MethodNotAllowedException
glensc Apr 15, 2021
2b8deb4
Cleanup JSONDecodeError which is no longer thrown
glensc Apr 15, 2021
8cd418a
Add semantic styles helper
glensc Apr 13, 2021
70c49dc
Merge pull request #244 from glensc/click-styles
glensc Apr 15, 2021
05d18db
Add trakt login command
glensc Apr 15, 2021
a37b30f
Implement trakt device auth sequence
glensc Apr 15, 2021
7fbd3b4
Use coloured click prompts
glensc Apr 15, 2021
1c5eddf
Add search api to plex
glensc Apr 16, 2021
db72be7
Add test for searching named show
glensc Apr 16, 2021
17a4468
Merge pull request #246 from glensc/add-search-api
glensc Apr 16, 2021
b211df6
Split internal logic of for_each_episode to iterate episodes
glensc Apr 16, 2021
b24a8de
Add --show option to filter by show name
glensc Apr 16, 2021
c640c52
Implement syncing only specific show
glensc Apr 16, 2021
f784a0e
Merge pull request #247 from glensc/show-by-name-syncing
glensc Apr 16, 2021
6049ecd
Merge pull request #242 from glensc/pytrakt-3.1.0
glensc Apr 16, 2021
1b34061
Merge pull request #243 from glensc/trakt-login-command
glensc Apr 16, 2021
ed6d95d
Merge pull request #230 from glensc/login-command
glensc Apr 16, 2021
1b50351
Merge pull request #239 from glensc/catch-ConnectionError
glensc Apr 16, 2021
ddbb1db
Add method to find by episode plex object
glensc Apr 15, 2021
c7a9577
Use trakt.find_episode method for syncing
glensc Apr 15, 2021
0425df7
Skip episodes of provider none
glensc Apr 15, 2021
ab4e113
Inspect: Show inspected object
glensc Apr 16, 2021
50b1817
Merge pull request #250 from Taxel/trakt-find-episodes
glensc Apr 16, 2021
43df131
Add search_by_id plain method
glensc Apr 16, 2021
5b6bbf0
Use search_by_id method
glensc Apr 16, 2021
39599d5
Add is_episode, show_id properties
glensc Apr 15, 2021
e288edf
Add support for finding episodes in show/season/episode form
glensc Apr 16, 2021
cbd41ad
Update test_tv_lookup with working result
glensc Apr 16, 2021
96ac42f
Merge pull request #251 from glensc/find-by-id
glensc Apr 16, 2021
35155d3
Add logging.append to default config
glensc Apr 16, 2021
921c05b
Add built in defaults to support older config.json
glensc Apr 16, 2021
548029a
Use logging.append config for logging
glensc Apr 16, 2021
f94bc56
Load defaults from default_config_file only
glensc Apr 17, 2021
f0fef2c
Merge pull request #253 from glensc/logging-truncate-config
glensc Apr 17, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ click = "==7.1.2"
plexapi = "==4.5.0"
python-dotenv = "==0.15.0"
requests-cache = "==0.5.2"
trakt = "==3.0.0"
trakt = "==3.1.0"

[requires]
python_version = "3"
8 changes: 4 additions & 4 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions config.default.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"log_debug_messages": false,
"logging": {
"append": false
},
"sync": {
"liked_lists": true,
"watchlist": true,
Expand Down
9 changes: 8 additions & 1 deletion plex_trakt_sync/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import click

from plex_trakt_sync.commands.clear_collections import clear_collections
from plex_trakt_sync.commands.inspect import inspect
from plex_trakt_sync.commands.plex_login import plex_login
from plex_trakt_sync.commands.sync import sync
from plex_trakt_sync.commands.trakt_login import trakt_login
from plex_trakt_sync.commands.watch import watch


Expand All @@ -14,6 +18,9 @@ def cli(ctx):
sync()


cli.add_command(sync)
cli.add_command(clear_collections)
cli.add_command(inspect)
cli.add_command(plex_login)
cli.add_command(sync)
cli.add_command(trakt_login)
cli.add_command(watch)
44 changes: 44 additions & 0 deletions plex_trakt_sync/commands/inspect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import click
from plexapi.server import PlexServer
from plex_trakt_sync.config import CONFIG
from plex_trakt_sync.plex_api import PlexApi
from plex_trakt_sync.trakt_api import TraktApi


@click.command()
@click.argument('input')
def inspect(input):
"""
Inspect details of an object
"""

url = CONFIG["PLEX_BASEURL"]
token = CONFIG["PLEX_TOKEN"]
server = PlexServer(url, token)
plex = PlexApi(server)
trakt = TraktApi()

if input.isnumeric():
input = int(input)

m = plex.fetch_item(input)
print(f"Inspecting: {m}")

media = m.item
print(f"Guid: '{media.guid}'")
print(f"Guids: {media.guids}")

audio = media.media[0].parts[0].audioStreams()[0]
print(f"Audio: '{audio.audioChannelLayout}', '{audio.displayTitle}'")

video = media.media[0].parts[0].videoStreams()[0]
print(f"Video: '{video.codec}'")

print(f"Provider: {m.provider}")
print(f"Id: {m.id}")

try:
tm = trakt.find_by_media(m)
print(f"Trakt match: {tm}")
except Exception as e:
print(f"Error: {e}")
148 changes: 148 additions & 0 deletions plex_trakt_sync/commands/plex_login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
from typing import List

import click
from click import Choice
from plexapi.exceptions import Unauthorized, NotFound
from plexapi.myplex import MyPlexAccount, MyPlexResource
from plexapi.server import PlexServer

from plex_trakt_sync.config import CONFIG
from plex_trakt_sync.style import prompt, error, success, title, comment

PROMPT_PLEX_PASSWORD = prompt("Please enter your Plex password")
PROMPT_PLEX_USERNAME = prompt("Please enter your Plex username")
PROMPT_PLEX_RELOGIN = prompt("You already have Plex Access Token, do you want to log in again?")
PROMPT_MANAGED_USER = prompt("Do you want to use managed user instead of main account?")
SUCCESS_MESSAGE = success("Plex Media Server Authentication Token and base URL have been added to .env file")


def myplex_login(username, password):
while True:
username = click.prompt(PROMPT_PLEX_USERNAME, type=str, default=username)
password = click.prompt(PROMPT_PLEX_PASSWORD, type=str, default=password, hide_input=True, show_default=False)
try:
return MyPlexAccount(username, password)
except Unauthorized as e:
click.echo(error(f"Log in to Plex failed: {e}, Try again."))


def choose_managed_user(account: MyPlexAccount):
users = [u.title for u in account.users() if u.friend]
if not users:
return None

click.echo(success("Managed user(s) found:"))
users = sorted(users)
for user in users:
click.echo(f"- {user}")

if not click.confirm(PROMPT_MANAGED_USER):
return None

# choice = prompt_choice(users)
user = click.prompt(
title("Please select:"),
type=Choice(users),
show_default=True,
)

# Sanity check, even the user can't input invalid user
user_account = account.user(user)
if user_account:
return user

return None


def prompt_server(servers: List[MyPlexResource]):
def fmt_server(s):
details = comment(f"{s.product}/{s.productVersion} on {s.device}: {s.platform}/{s.platformVersion}")
return f"- {s.name}: [Last seen: {comment(str(s.lastSeenAt))}, Server: {details}]"

owned_servers = [s for s in servers if s.owned]
unowned_servers = [s for s in servers if not s.owned]

server_names = []
if owned_servers:
click.echo(success(f"{len(owned_servers)} owned servers found:"))
for s in owned_servers:
click.echo(fmt_server(s))
server_names.append(s.name)
if unowned_servers:
click.echo(success(f"{len(owned_servers)} unowned servers found:"))
for s in unowned_servers:
click.echo(fmt_server(s))
server_names.append(s.name)

return click.prompt(
title("Select default server:"),
type=Choice(server_names),
show_default=True,
)


def pick_server(account: MyPlexAccount):
servers = account.resources()
if not servers:
return None

if len(servers) == 1:
return servers[0]

server_name = prompt_server(servers)

# Sanity check, even the user can't choose invalid resource
server = account.resource(server_name)
if server:
return server

return None


def choose_server(account: MyPlexAccount):
while True:
try:
server = pick_server(account)
# Connect to obtain baseUrl
click.echo(title(f"Attempting to connect to {server.name}. This may take time and print some errors."))
plex = server.connect()
# Validate connection again, the way we connect
plex = PlexServer(token=server.accessToken, baseurl=plex._baseurl)
return [server, plex]
except NotFound as e:
click.secho(f"{e}, Try another server, {type(e)}")


@click.command()
@click.option("--username", help="Plex login", default=CONFIG["PLEX_USERNAME"])
@click.option("--password", help="Plex password")
def plex_login(username, password):
"""
Log in to Plex Account to obtain Access Token. Optionally can use managed user on servers that you own.
"""

if CONFIG["PLEX_TOKEN"]:
if not click.confirm(PROMPT_PLEX_RELOGIN, default=True):
return

account = myplex_login(username, password)
click.echo(success("Login to MyPlex was successful!"))

[server, plex] = choose_server(account)
click.echo(success(f"Connection to {plex.friendlyName} established successfully!"))

token = server.accessToken
user = username
if server.owned:
managed_user = choose_managed_user(account)
if managed_user:
user = managed_user
token = account.user(managed_user).get_token(plex.machineIdentifier)

CONFIG["PLEX_USERNAME"] = user
CONFIG["PLEX_TOKEN"] = token
CONFIG["PLEX_BASEURL"] = plex._baseurl
CONFIG["PLEX_FALLBACKURL"] = "http://localhost:32400"
CONFIG.save()

click.echo(SUCCESS_MESSAGE)
Loading