forked from CopyBot/sptnr
Add per-song update cache with configurable duration, and force-update option.
This commit is contained in:
@@ -23,6 +23,8 @@ if os.path.exists(".env"):
|
|||||||
# Record the start time
|
# Record the start time
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
|
CACHE_FILE = "song_update_cache.json"
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
NAV_BASE_URL = os.getenv("NAV_BASE_URL")
|
NAV_BASE_URL = os.getenv("NAV_BASE_URL")
|
||||||
NAV_USER = os.getenv("NAV_USER")
|
NAV_USER = os.getenv("NAV_USER")
|
||||||
@@ -95,6 +97,25 @@ class NoColorFormatter(logging.Formatter):
|
|||||||
return super(NoColorFormatter, self).format(record)
|
return super(NoColorFormatter, self).format(record)
|
||||||
|
|
||||||
|
|
||||||
|
def load_cache():
|
||||||
|
if os.path.exists(CACHE_FILE):
|
||||||
|
with open(CACHE_FILE, "r") as f:
|
||||||
|
return json.load(f)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def save_cache(cache):
|
||||||
|
with open(CACHE_FILE, "w") as f:
|
||||||
|
json.dump(CACHE, f)
|
||||||
|
|
||||||
|
def should_update(song_id):
|
||||||
|
if CACHE_DURATION == 0:
|
||||||
|
return True
|
||||||
|
last_update_ts = CACHE.get(song_id)
|
||||||
|
if not last_update_ts:
|
||||||
|
return True
|
||||||
|
return (time.time() - last_update_ts) > (CACHE_DURATION * 86400)
|
||||||
|
|
||||||
|
|
||||||
# Set up the stream handler (console logging) without timestamp
|
# Set up the stream handler (console logging) without timestamp
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO, format="%(message)s", handlers=[logging.StreamHandler()]
|
level=logging.INFO, format="%(message)s", handlers=[logging.StreamHandler()]
|
||||||
@@ -165,6 +186,13 @@ parser.add_argument(
|
|||||||
type=int,
|
type=int,
|
||||||
help="limit to processing [NUM] artists from the start index",
|
help="limit to processing [NUM] artists from the start index",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-d",
|
||||||
|
"--cache-duration",
|
||||||
|
type=int,
|
||||||
|
default=7,
|
||||||
|
help="Number of days to cache song updates (0 to force update every time)",
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-v", "--version", action="version", version=f"%(prog)s {__version__}"
|
"-v", "--version", action="version", version=f"%(prog)s {__version__}"
|
||||||
@@ -177,9 +205,12 @@ ARTIST_IDs = args.artist if args.artist else []
|
|||||||
ALBUM_IDs = args.album if args.album else []
|
ALBUM_IDs = args.album if args.album else []
|
||||||
START = args.start
|
START = args.start
|
||||||
LIMIT = args.limit
|
LIMIT = args.limit
|
||||||
|
CACHE_DURATION = args.cache_duration
|
||||||
|
|
||||||
logging.info(f"{BOLD}Version:{RESET} {LIGHT_YELLOW}sptnr v{__version__}{RESET}")
|
logging.info(f"{BOLD}Version:{RESET} {LIGHT_YELLOW}sptnr v{__version__}{RESET}")
|
||||||
|
|
||||||
|
CACHE = load_cache()
|
||||||
|
|
||||||
if args.preview:
|
if args.preview:
|
||||||
logging.info(f"{LIGHT_YELLOW}Preview mode, no changes will be made.{RESET}")
|
logging.info(f"{LIGHT_YELLOW}Preview mode, no changes will be made.{RESET}")
|
||||||
PREVIEW = 1
|
PREVIEW = 1
|
||||||
@@ -237,6 +268,11 @@ def process_track(track_id, artist_name, album, track_name):
|
|||||||
# Declare global variables
|
# Declare global variables
|
||||||
global FOUND_AND_UPDATED, UNMATCHED_TRACKS, NOT_FOUND, TOTAL_TRACKS
|
global FOUND_AND_UPDATED, UNMATCHED_TRACKS, NOT_FOUND, TOTAL_TRACKS
|
||||||
|
|
||||||
|
|
||||||
|
if not should_update(track_id):
|
||||||
|
print(f"Skipping {track_name}, recently updated.")
|
||||||
|
return
|
||||||
|
|
||||||
def search_spotify(query, max_retries=3):
|
def search_spotify(query, max_retries=3):
|
||||||
|
|
||||||
SPOTIFY_TOKEN = spotify_token_manager.get_token()
|
SPOTIFY_TOKEN = spotify_token_manager.get_token()
|
||||||
@@ -314,6 +350,8 @@ def process_track(track_id, artist_name, album, track_name):
|
|||||||
nav_url = f"{NAV_BASE_URL}/rest/setRating?u={NAV_USER}&p=enc:{HEX_ENCODED_PASS}&v=1.12.0&c=myapp&id={track_id}&rating={rating}"
|
nav_url = f"{NAV_BASE_URL}/rest/setRating?u={NAV_USER}&p=enc:{HEX_ENCODED_PASS}&v=1.12.0&c=myapp&id={track_id}&rating={rating}"
|
||||||
requests.get(nav_url, timeout=5)
|
requests.get(nav_url, timeout=5)
|
||||||
FOUND_AND_UPDATED += 1
|
FOUND_AND_UPDATED += 1
|
||||||
|
CACHE[track_id] = time.time()
|
||||||
|
save_cache(CACHE)
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
logging.error(f"Failed to update rating in Navidrome: {e}")
|
logging.error(f"Failed to update rating in Navidrome: {e}")
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user