tsv.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import codecs
  2. import csv
  3. import logging
  4. from datetime import datetime
  5. import pytz
  6. import requests
  7. from music.utils import (
  8. get_or_create_album,
  9. get_or_create_artist,
  10. get_or_create_track,
  11. )
  12. from scrobbles.constants import AsTsvColumn
  13. from scrobbles.models import Scrobble
  14. from vrobbler.apps.scrobbles.utils import timestamp_user_tz_to_utc
  15. logger = logging.getLogger(__name__)
  16. def process_audioscrobbler_tsv_file(file_path, user_id, user_tz=None):
  17. """Takes a path to a file of TSV data and imports it as past scrobbles"""
  18. new_scrobbles = []
  19. if not user_tz:
  20. user_tz = pytz.utc
  21. is_os_file = "https://" not in file_path
  22. if not is_os_file:
  23. r = requests.get(file_path)
  24. tsv_data = codecs.iterdecode(r.iter_lines(), "utf-8")
  25. else:
  26. tsv_data = open(file_path)
  27. source = "Audioscrobbler File"
  28. rows = csv.reader(tsv_data, delimiter="\t")
  29. rockbox_info = ""
  30. for row_num, row in enumerate(rows):
  31. if row_num in [0, 1, 2]:
  32. if "Rockbox" in row[0]:
  33. source = "Rockbox"
  34. rockbox_info += row[0] + "\n"
  35. continue
  36. if len(row) > 8:
  37. logger.warning(
  38. "Improper row length during Audioscrobbler import",
  39. extra={"row": row},
  40. )
  41. continue
  42. track = get_or_create_track(
  43. {
  44. "title": row[AsTsvColumn["TRACK_NAME"].value],
  45. "mbid": row[AsTsvColumn["MB_ID"].value],
  46. "artist_name": row[AsTsvColumn["ARTIST_NAME"].value],
  47. "album_name": row[AsTsvColumn["ALBUM_NAME"].value],
  48. "run_time_seconds": int(
  49. row[AsTsvColumn["RUN_TIME_SECONDS"].value]
  50. ),
  51. },
  52. {
  53. "TRACK_MB_ID": "mbid",
  54. "TRACK_TITLE": "track_title",
  55. "ALBUM_NAME": "album_name",
  56. "ARTIST_NAME": "artist_name",
  57. "RUN_TIME": "run_time_seconds",
  58. },
  59. )
  60. # TODO Set all this up as constants
  61. if row[AsTsvColumn["COMPLETE"].value] == "S":
  62. logger.info(f"Skipping track {track} because not finished")
  63. continue
  64. timestamp = timestamp_user_tz_to_utc(
  65. int(row[AsTsvColumn["TIMESTAMP"].value]), user_tz
  66. )
  67. new_scrobble = Scrobble(
  68. user_id=user_id,
  69. timestamp=timestamp,
  70. source=source,
  71. log={"rockbox_info": rockbox_info},
  72. track=track,
  73. played_to_completion=True,
  74. in_progress=False,
  75. media_type=Scrobble.MediaType.TRACK,
  76. )
  77. existing = Scrobble.objects.filter(
  78. timestamp=timestamp, track=track
  79. ).first()
  80. if existing:
  81. logger.debug(f"Skipping existing scrobble {new_scrobble}")
  82. continue
  83. logger.debug(f"Queued scrobble {new_scrobble} for creation")
  84. new_scrobbles.append(new_scrobble)
  85. if is_os_file:
  86. tsv_data.close()
  87. created = Scrobble.objects.bulk_create(new_scrobbles)
  88. logger.info(
  89. f"Created {len(created)} scrobbles",
  90. extra={"created_scrobbles": created},
  91. )
  92. return created