test_views.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. from datetime import datetime, timedelta
  2. from unittest.mock import patch
  3. from django.utils import timezone
  4. import pytest
  5. import time_machine
  6. from django.urls import reverse
  7. from music.models import Track
  8. from podcasts.models import PodcastEpisode
  9. from scrobbles.models import Scrobble
  10. @pytest.mark.django_db
  11. def test_get_not_allowed_from_mopidy(client, valid_auth_token):
  12. url = reverse("scrobbles:mopidy-webhook")
  13. headers = {"Authorization": f"Token {valid_auth_token}"}
  14. response = client.get(url, headers=headers)
  15. assert response.status_code == 405
  16. @pytest.mark.django_db
  17. def test_bad_mopidy_request_data(client, valid_auth_token):
  18. url = reverse("scrobbles:mopidy-webhook")
  19. headers = {"Authorization": f"Token {valid_auth_token}"}
  20. response = client.post(url, headers)
  21. assert response.status_code == 400
  22. assert (
  23. response.data["detail"]
  24. == "JSON parse error - Expecting value: line 1 column 1 (char 0)"
  25. )
  26. @pytest.mark.parametrize(
  27. "seconds, expected_percent_played, expected_scrobble_id",
  28. [
  29. (1, 1, 1),
  30. (58, 96, 1),
  31. (59, 98, 1),
  32. (60, 100, 1),
  33. (1, 1, 1),
  34. (1, 1, 1),
  35. ],
  36. )
  37. @pytest.mark.django_db
  38. def test_scrobble_mopidy_track(
  39. client,
  40. mopidy_track,
  41. valid_auth_token,
  42. seconds,
  43. expected_percent_played,
  44. expected_scrobble_id,
  45. ):
  46. url = reverse("scrobbles:mopidy-webhook")
  47. headers = {"Authorization": f"Token {valid_auth_token}"}
  48. # Start new scrobble
  49. minutes = 0
  50. calc_seconds = seconds
  51. if seconds >= 60:
  52. minutes = 1
  53. calc_seconds = calc_seconds % 10
  54. with time_machine.travel(datetime(2024, 1, 14, 12, minutes, calc_seconds)):
  55. mopidy_track.request_data["playback_time_ticks"] = seconds * 1000
  56. response = client.post(
  57. url,
  58. mopidy_track.request_json,
  59. content_type="application/json",
  60. headers=headers,
  61. )
  62. assert response.status_code == 200
  63. assert response.data == {"scrobble_id": expected_scrobble_id}
  64. scrobble = Scrobble.objects.get(id=1)
  65. assert scrobble.percent_played == expected_percent_played
  66. assert scrobble.media_obj.__class__ == Track
  67. assert scrobble.media_obj.title == "Same in the End"
  68. @pytest.mark.skip(reason="Allmusic API is unstable")
  69. @pytest.mark.django_db
  70. def test_scrobble_mopidy_same_track_different_album(
  71. client,
  72. mopidy_track,
  73. mopidy_track_diff_album_request_data,
  74. valid_auth_token,
  75. ):
  76. url = reverse("scrobbles:mopidy-webhook")
  77. headers = {"Authorization": f"Token {valid_auth_token}"}
  78. response = client.post(
  79. url,
  80. mopidy_track.request_data,
  81. content_type="application/json",
  82. headers=headers,
  83. )
  84. assert response.status_code == 200
  85. assert response.data == {"scrobble_id": 1}
  86. scrobble = Scrobble.objects.last()
  87. assert scrobble.media_obj.album.name == "Sublime"
  88. response = client.post(
  89. url,
  90. mopidy_track_diff_album_request_data,
  91. content_type="application/json",
  92. )
  93. assert response.status_code == 200
  94. assert response.data == {"scrobble_id": 2}
  95. scrobble = Scrobble.objects.last()
  96. assert scrobble.media_obj.__class__ == Track
  97. assert scrobble.media_obj.album.name == "Gold"
  98. assert scrobble.media_obj.title == "Same in the End"
  99. @pytest.mark.django_db
  100. def test_scrobble_mopidy_podcast(
  101. client, mopidy_podcast_request_data, valid_auth_token
  102. ):
  103. url = reverse("scrobbles:mopidy-webhook")
  104. headers = {"Authorization": f"Token {valid_auth_token}"}
  105. response = client.post(
  106. url,
  107. mopidy_podcast_request_data,
  108. content_type="application/json",
  109. headers=headers,
  110. )
  111. assert response.status_code == 200
  112. assert response.data == {"scrobble_id": 1}
  113. scrobble = Scrobble.objects.get(id=1)
  114. assert scrobble.media_obj.__class__ == PodcastEpisode
  115. assert scrobble.media_obj.title == "Up First"
  116. @pytest.mark.django_db
  117. @patch("music.utils.lookup_artist_from_mb", return_value={})
  118. @patch(
  119. "music.utils.lookup_album_dict_from_mb",
  120. return_value={"year": "1999", "mb_group_id": 1},
  121. )
  122. @patch("music.utils.lookup_track_from_mb", return_value={})
  123. @patch("music.models.lookup_artist_from_tadb", return_value={})
  124. @patch("music.models.lookup_album_from_tadb", return_value={"year": "1999"})
  125. @patch("music.models.Album.fetch_artwork", return_value=None)
  126. @patch("music.models.Album.scrape_allmusic", return_value=None)
  127. def test_scrobble_jellyfin_track(
  128. mock_lookup_artist,
  129. mock_lookup_album,
  130. mock_lookup_track,
  131. mock_lookup_artist_tadb,
  132. mock_lookup_album_tadb,
  133. mock_fetch_artwork,
  134. mock_scrape_allmusic,
  135. client,
  136. jellyfin_track,
  137. valid_auth_token,
  138. ):
  139. url = reverse("scrobbles:jellyfin-webhook")
  140. headers = {"Authorization": f"Token {valid_auth_token}"}
  141. with time_machine.travel(datetime(2024, 1, 14, 12, 00, 1)):
  142. jellyfin_track.request_data["UtcTimestamp"] = timezone.now().strftime(
  143. "%Y-%m-%d %H:%M:%S"
  144. )
  145. response = client.post(
  146. url,
  147. jellyfin_track.request_json,
  148. content_type="application/json",
  149. headers=headers,
  150. )
  151. assert response.status_code == 200
  152. assert response.data == {"scrobble_id": 1}
  153. scrobble = Scrobble.objects.get(id=1)
  154. assert scrobble.media_obj.__class__ == Track
  155. assert scrobble.media_obj.title == "Emotion"
  156. with time_machine.travel(datetime(2024, 1, 14, 12, 0, 58)):
  157. jellyfin_track.request_data["UtcTimestamp"] = timezone.now().strftime(
  158. "%Y-%m-%d %H:%M:%S"
  159. )
  160. response = client.post(
  161. url,
  162. jellyfin_track.request_json,
  163. content_type="application/json",
  164. headers=headers,
  165. )
  166. assert response.status_code == 200
  167. assert response.data == {"scrobble_id": 1}
  168. scrobble = Scrobble.objects.get(id=1)
  169. assert scrobble.media_obj.__class__ == Track
  170. assert scrobble.media_obj.title == "Emotion"
  171. with time_machine.travel(datetime(2024, 1, 14, 12, 1, 1)):
  172. jellyfin_track.request_data["UtcTimestamp"] = timezone.now().strftime(
  173. "%Y-%m-%d %H:%M:%S"
  174. )
  175. response = client.post(
  176. url,
  177. jellyfin_track.request_json,
  178. content_type="application/json",
  179. headers=headers,
  180. )
  181. assert response.status_code == 200
  182. assert response.data == {"scrobble_id": 2}
  183. scrobble = Scrobble.objects.get(id=1)
  184. assert scrobble.media_obj.__class__ == Track
  185. assert scrobble.media_obj.title == "Emotion"