Skip to content

Instantly share code, notes, and snippets.

@billettg
Created July 2, 2024 10:26
Show Gist options
  • Save billettg/2500fd16c82fd554b0caad3d98668161 to your computer and use it in GitHub Desktop.
Save billettg/2500fd16c82fd554b0caad3d98668161 to your computer and use it in GitHub Desktop.
Sample code for PIN authentication using Plex API
import uuid
import random
import time
import requests
import logging
# Configure logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
# Constants
APP_NAME = "My App"
BASE_URL = "https://plex.tv/api/v2"
# In-memory storage for client identifier and access token
client_identifier = None
access_token = None
# Function to generate or retrieve client identifier
def get_client_identifier():
global client_identifier
if not client_identifier:
client_identifier = str(uuid.uuid4())
logging.debug(f"Generated new client identifier: {client_identifier}")
else:
logging.debug(f"Using existing client identifier: {client_identifier}")
return client_identifier
# Function to check if access token is valid
def is_access_token_valid(client_identifier, access_token):
headers = {
"accept": "application/json",
}
data = {
"X-Plex-Product": APP_NAME,
"X-Plex-Client-Identifier": client_identifier,
"X-Plex-Token": access_token,
}
logging.debug(f"Checking access token validity for client identifier: {client_identifier}")
response = requests.get(f"{BASE_URL}/user", headers=headers, data=data)
logging.debug(f"Received response: {response.status_code}")
return response.status_code == 200
# Function to generate a new 4-digit PIN
def generate_pin(client_identifier):
headers = {
"accept": "application/json",
}
data = {
"strong": "false",
"X-Plex-Product": APP_NAME,
"X-Plex-Client-Identifier": client_identifier,
}
logging.debug(f"Generating new PIN for client identifier: {client_identifier}")
response = requests.post(f"{BASE_URL}/pins", headers=headers, data=data)
pin_data = response.json()
print(pin_data)
pin_id = pin_data["id"]
pin_code = pin_data["code"]
logging.debug(f"Generated PIN: {pin_code} with ID: {pin_id}")
return pin_id, pin_code
# Function to poll for access token
def poll_for_access_token(pin_id, pin_code, client_identifier):
headers = {
"accept": "application/json",
}
data = {
"X-Plex-Client-Identifier": client_identifier,
"code": pin_code,
}
logging.debug(f"Starting to poll for access token with PIN ID: {pin_id} and PIN code: {pin_code}")
while True:
response = requests.get(f"{BASE_URL}/pins/{pin_id}", headers=headers, data=data)
pin_data = response.json()
logging.debug(f"Polled PIN data: {pin_data}")
if "authToken" in pin_data and pin_data["authToken"]:
logging.debug("Access token found.")
return pin_data["authToken"]
if pin_data.get("expiresIn", 0) <= 0:
logging.debug("PIN expired.")
break
time.sleep(1)
return None
# Main function
def authenticate_with_plex():
global client_identifier, access_token
client_identifier = get_client_identifier()
if access_token and is_access_token_valid(client_identifier, access_token):
logging.debug("Access token is valid.")
return access_token
logging.debug("Access token is missing or invalid. Generating a new PIN...")
pin_id, pin_code = generate_pin(client_identifier)
# Inform the user to visit plex.tv/link and enter the pin_code
logging.info(f"Please navigate to: https://plex.tv/link and enter the code: {pin_code}")
logging.debug("Polling for access token...")
access_token = poll_for_access_token(pin_id, pin_code, client_identifier)
if access_token:
logging.debug("Access token obtained successfully.")
else:
logging.debug("Failed to obtain access token.")
return access_token
if __name__ == "__main__":
authenticate_with_plex()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment