mirror of
https://github.com/Xevion/spotify-explicit.git
synced 2025-12-06 13:16:32 -06:00
118 lines
3.9 KiB
Python
118 lines
3.9 KiB
Python
import os
|
|
import sys
|
|
import json
|
|
import logging
|
|
import datetime
|
|
import collections
|
|
import numpy as np
|
|
import dateutil.parser
|
|
import PIL.Image as Image
|
|
import matplotlib.pyplot as plt
|
|
|
|
# Gets all files in tracks folder, returns them in parsed JSON
|
|
def get_files():
|
|
folder = os.path.join(sys.path[0], 'tracks')
|
|
files = []
|
|
for file in os.listdir(folder):
|
|
with open(os.path.join(os.path.join(folder, file))) as file:
|
|
files.append(
|
|
json.load(file)
|
|
)
|
|
return files
|
|
|
|
# Simple function to combine a bunch of items from different files
|
|
def combine_files(files):
|
|
items = []
|
|
for file in files:
|
|
items.extend(file['items'])
|
|
return items
|
|
|
|
# Prints the data in a interesting format
|
|
def print_data(data):
|
|
for i, item in enumerate(data):
|
|
date = dateutil.parser.parse(item['added_at'])
|
|
explicit = '!' if item['track']['explicit'] else ' '
|
|
track_name = item['track']['name']
|
|
artists = ' & '.join(artist['name'] for artist in item['track']['artists'])
|
|
print('[{}] {} "{}" by {}'.format(date, explicit, track_name, artists))
|
|
|
|
def process_data(data):
|
|
# Process the data by Month/Year, then by Safe/Explicit
|
|
scores = {}
|
|
for item in data:
|
|
date = dateutil.parser.parse(item['added_at']).strftime('%b %Y')
|
|
if date not in scores.keys():
|
|
scores[date] = [0, 0]
|
|
scores[date][1 if item['track']['explicit'] else 0] += 1
|
|
|
|
# Create simplified arrays for each piece of data
|
|
months = list(scores.keys())[::-1]
|
|
safe, explicit = [], []
|
|
for item in list(scores.values())[::-1]:
|
|
safe.append(item[0])
|
|
explicit.append(item[1])
|
|
|
|
# Done processing date properly, start plotting work
|
|
logging.info('Processed data, creating plot from data')
|
|
# Weird numpy stuff
|
|
n = len(scores.values())
|
|
ind = np.arange(n)
|
|
width = 0.55
|
|
# Resizer figuresize to be 2.0 wider
|
|
plt.figure(figsize=(10.0, 6.0))
|
|
# Stacked Bars
|
|
p1 = plt.bar(ind, explicit, width)
|
|
p2 = plt.bar(ind, safe, width, bottom=explicit) # bottom= just has the bar sit on top of the explicit
|
|
# Plot labeling
|
|
plt.title('Song Count by Safe/Explicit')
|
|
plt.ylabel('Song Count')
|
|
plt.xlabel('Month')
|
|
plt.xticks(ind, months, rotation=270) # Rotation 90 will have the
|
|
plt.legend((p1[0], p2[0]), ('Explicit', 'Safe'))
|
|
fig = plt.gcf() # Magic to save to image and then show
|
|
|
|
# Save the figure, overwriting anything in your way
|
|
logging.info('Saving the figure to the \'export\' folder')
|
|
export_folder = os.path.join(sys.path[0], 'export')
|
|
if not os.path.exists(export_folder):
|
|
os.makedirs(export_folder)
|
|
plt.tight_layout()
|
|
fig.savefig(
|
|
os.path.join(
|
|
export_folder,
|
|
datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
|
|
),
|
|
dpi=100,
|
|
quality=95
|
|
)
|
|
|
|
# Finally show the figure to
|
|
logging.info('Showing plot to User')
|
|
plt.show()
|
|
|
|
# Copy the figure to your clipboard to paste in Excel
|
|
# logging.info('Copying the plot data to clipboard')
|
|
# copy(months, safe, explicit)
|
|
|
|
# Simple method for exporting data to a table like format
|
|
# Will paste into Excel very easily
|
|
def copy(months, safe, explicit):
|
|
from pyperclip import copy
|
|
top = 'Period\tSafe\tExplicit\n'
|
|
copy(top + '\n'.join([
|
|
f'{item[0]}\t{item[1]}\t{item[2]}' for item in zip(months, safe, explicit)
|
|
]))
|
|
|
|
def main():
|
|
logging.basicConfig(level=logging.INFO)
|
|
logging.info("Reading track files")
|
|
files = get_files()
|
|
logging.info(f"Read and parse {len(files)} track files")
|
|
logging.info("Combining into single track file for ease of access")
|
|
data = combine_files(files)
|
|
data.sort(key=lambda item : dateutil.parser.parse(item['added_at']).timestamp(), reverse=True)
|
|
logging.info(f'File combined with {len(data)} items')
|
|
logging.info('Processing file...')
|
|
process_data(data)
|
|
|
|
main() |