main.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. from jellyfin_api_client.models import *
  2. from jellyfin_api_client.api.items import get_items, get_item_user_data
  3. from jellyfin_api_client.api.user import get_users
  4. from jellyfin_api_client.api.playlists import create_playlist, update_playlist
  5. from jellyfin_api_client.types import Response
  6. from jellyfin_api_client import AuthenticatedClient
  7. import os
  8. import random
  9. from dotenv import load_dotenv
  10. from pprint import pp
  11. load_dotenv()
  12. def log_response(response):
  13. request = response.request
  14. if response.status_code >= 400:
  15. print(f"{request.method} {request.url} - Status {response.status_code}")
  16. raise Exception(response.read())
  17. server_url = os.getenv('SERVER_URL')
  18. api_token = os.getenv('API_TOKEN')
  19. device = os.getenv('HOSTNAME')
  20. user_names = os.getenv('USER_NAMES').split()
  21. playlist_name = os.getenv('PLAYLIST')
  22. item_count = int(os.getenv('ITEM_COUNT'))
  23. client = AuthenticatedClient(
  24. base_url=server_url,
  25. prefix="",
  26. token=f"MediaBrowser Client=\"jellyfin-client\", Device=\"{device}\", DeviceId=\"1234\", Version=\"1.0.0\", Token=\"{api_token}\"",
  27. httpx_args={"event_hooks": {"response": [log_response]}})
  28. with client as client:
  29. users = get_users.sync(client=client)
  30. users = [user for user in users if user.name in user_names]
  31. playlists = get_items.sync(
  32. client=client,
  33. recursive=True,
  34. include_item_types=[BaseItemKind.PLAYLIST],
  35. search_term=playlist_name
  36. )
  37. songs: list[BaseItemDto] = []
  38. for user in users:
  39. result = get_items.sync(
  40. client=client,
  41. user_id=user.id,
  42. recursive=True,
  43. enable_images=False,
  44. include_item_types=[BaseItemKind.AUDIO],
  45. limit=item_count,
  46. sort_by=[ItemSortBy.PLAYCOUNT, ItemSortBy.RANDOM])
  47. play_count_min = min(s.user_data.play_count for s in result.items)
  48. play_count_max = max(s.user_data.play_count for s in result.items)
  49. print(f"Got {len(result.items)} songs for user {user.name} (played {play_count_min} to {play_count_max} times)")
  50. for item in result.items:
  51. if any(item.id == s.id for s in songs):
  52. continue
  53. play_count = item.user_data.play_count
  54. for u in users:
  55. if u.id == user.id:
  56. continue
  57. user_data = get_item_user_data.sync(item.id, client=client, user_id=u.id)
  58. play_count += user_data.play_count
  59. item.user_data.play_count = play_count
  60. songs.append(item)
  61. print(f"Selecting from {len(songs)} unique songs...")
  62. random.shuffle(songs)
  63. songs.sort(key=lambda s: s.user_data.play_count)
  64. songs = songs[:item_count]
  65. play_count_min = min(s.user_data.play_count for s in songs)
  66. play_count_max = max(s.user_data.play_count for s in songs)
  67. print(f"Using the {len(songs)} least played songs (played {play_count_min} to {play_count_max} times)")
  68. try:
  69. playlist_id = next(p.id for p in playlists.items if p.name == playlist_name)
  70. body = UpdatePlaylistDto(
  71. name=playlist_name,
  72. users=[PlaylistUserPermissions(user_id=u.id, can_edit=True) for u in users],
  73. ids=[item.id for item in songs],
  74. is_public=True
  75. )
  76. update_playlist.sync(
  77. playlist_id=playlist_id,
  78. client=client,
  79. body=body
  80. )
  81. except StopIteration:
  82. create_playlist.sync(
  83. client=client,
  84. body=CreatePlaylistDto(
  85. name=playlist_name,
  86. user_id=users[0].id,
  87. users=[PlaylistUserPermissions(user_id=u.id, can_edit=True) for u in users],
  88. ids=[item.id for item in songs],
  89. is_public=True,
  90. media_type=CreatePlaylistDtoMediaType.AUDIO
  91. )
  92. )
  93. print(f"Successfully updated playlist '{playlist_name}' with {len(songs)} songs")