fix: implement retry logic with ETag synchronization for Tidal playlist modifications and add test script
This commit is contained in:
9
app.py
9
app.py
@@ -256,8 +256,9 @@ with tab_my:
|
|||||||
st.session_state[tracks_key] = tracks
|
st.session_state[tracks_key] = tracks
|
||||||
if err:
|
if err:
|
||||||
st.session_state[f"tracks_err_{pid}"] = err
|
st.session_state[f"tracks_err_{pid}"] = err
|
||||||
st.rerun()
|
cached_tracks = tracks
|
||||||
else:
|
|
||||||
|
if cached_tracks is not None:
|
||||||
err = st.session_state.get(f"tracks_err_{pid}")
|
err = st.session_state.get(f"tracks_err_{pid}")
|
||||||
if err:
|
if err:
|
||||||
st.warning(err)
|
st.warning(err)
|
||||||
@@ -274,7 +275,7 @@ with tab_my:
|
|||||||
st.dataframe(
|
st.dataframe(
|
||||||
pd.DataFrame(rows),
|
pd.DataFrame(rows),
|
||||||
hide_index=True,
|
hide_index=True,
|
||||||
use_container_width=True,
|
width="stretch",
|
||||||
height=min(40 + len(rows) * 35, 300),
|
height=min(40 + len(rows) * 35, 300),
|
||||||
column_config={
|
column_config={
|
||||||
"": st.column_config.TextColumn("", width="small"),
|
"": st.column_config.TextColumn("", width="small"),
|
||||||
@@ -400,7 +401,7 @@ with tab_nf:
|
|||||||
for a, t in items
|
for a, t in items
|
||||||
]
|
]
|
||||||
if nf_rows:
|
if nf_rows:
|
||||||
st.dataframe(pd.DataFrame(nf_rows), hide_index=True, use_container_width=True,
|
st.dataframe(pd.DataFrame(nf_rows), hide_index=True, width="stretch",
|
||||||
height=min(80 + len(nf_rows) * 35, 500))
|
height=min(80 + len(nf_rows) * 35, 500))
|
||||||
else:
|
else:
|
||||||
st.info("No entries for this filter.")
|
st.info("No entries for this filter.")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"watched": [
|
"watched": [
|
||||||
|
"2Dz5fstoYCa1wm2sOtZlwT",
|
||||||
"2sLEYLo3a6dDHbl4ypUkcl",
|
"2sLEYLo3a6dDHbl4ypUkcl",
|
||||||
"3Sjb6ZlsPxIpzOMZVoq1pW",
|
"3Sjb6ZlsPxIpzOMZVoq1pW",
|
||||||
"3eNcChQ2KssR8QjuV7KUEc",
|
"3eNcChQ2KssR8QjuV7KUEc",
|
||||||
|
|||||||
@@ -5,12 +5,27 @@ import tidalapi
|
|||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
from tqdm.asyncio import tqdm as atqdm
|
from tqdm.asyncio import tqdm as atqdm
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
def _remove_indices_from_playlist(playlist: tidalapi.UserPlaylist, indices: List[int]):
|
def _remove_indices_from_playlist(playlist: tidalapi.UserPlaylist, indices: List[int]):
|
||||||
headers = {'If-None-Match': playlist._etag}
|
if not playlist._etag:
|
||||||
index_string = ",".join(map(str, indices))
|
|
||||||
playlist.request.request('DELETE', (playlist._base_url + '/items/%s') % (playlist.id, index_string), headers=headers)
|
|
||||||
playlist._reparse()
|
playlist._reparse()
|
||||||
|
|
||||||
|
for attempt in range(5):
|
||||||
|
headers = {'If-None-Match': playlist._etag} if playlist._etag else None
|
||||||
|
index_string = ",".join(map(str, indices))
|
||||||
|
try:
|
||||||
|
res = playlist.request.request('DELETE', (playlist._base_url + '/items/%s') % (playlist.id, index_string), headers=headers)
|
||||||
|
playlist._etag = res.headers.get('etag', playlist._etag)
|
||||||
|
playlist.num_tracks = max(0, playlist.num_tracks - len(indices))
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
if "412" in str(e) and attempt < 4:
|
||||||
|
time.sleep(1)
|
||||||
|
playlist._reparse()
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
def clear_tidal_playlist(playlist: tidalapi.UserPlaylist, chunk_size: int=20):
|
def clear_tidal_playlist(playlist: tidalapi.UserPlaylist, chunk_size: int=20):
|
||||||
with tqdm(desc="Erasing existing tracks from Tidal playlist", total=playlist.num_tracks) as progress:
|
with tqdm(desc="Erasing existing tracks from Tidal playlist", total=playlist.num_tracks) as progress:
|
||||||
while playlist.num_tracks:
|
while playlist.num_tracks:
|
||||||
@@ -19,11 +34,23 @@ def clear_tidal_playlist(playlist: tidalapi.UserPlaylist, chunk_size: int=20):
|
|||||||
progress.update(len(indices))
|
progress.update(len(indices))
|
||||||
|
|
||||||
def add_multiple_tracks_to_playlist(playlist: tidalapi.UserPlaylist, track_ids: List[int], chunk_size: int=20):
|
def add_multiple_tracks_to_playlist(playlist: tidalapi.UserPlaylist, track_ids: List[int], chunk_size: int=20):
|
||||||
|
if not playlist._etag:
|
||||||
|
playlist._reparse()
|
||||||
|
|
||||||
offset = 0
|
offset = 0
|
||||||
with tqdm(desc="Adding new tracks to Tidal playlist", total=len(track_ids)) as progress:
|
with tqdm(desc="Adding new tracks to Tidal playlist", total=len(track_ids)) as progress:
|
||||||
while offset < len(track_ids):
|
while offset < len(track_ids):
|
||||||
count = min(chunk_size, len(track_ids) - offset)
|
count = min(chunk_size, len(track_ids) - offset)
|
||||||
|
for attempt in range(5):
|
||||||
|
try:
|
||||||
playlist.add(track_ids[offset:offset+chunk_size])
|
playlist.add(track_ids[offset:offset+chunk_size])
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
if "412" in str(e) and attempt < 4:
|
||||||
|
time.sleep(1)
|
||||||
|
playlist._reparse()
|
||||||
|
else:
|
||||||
|
raise
|
||||||
offset += count
|
offset += count
|
||||||
progress.update(count)
|
progress.update(count)
|
||||||
|
|
||||||
|
|||||||
2
test_tidal_delete.py
Normal file
2
test_tidal_delete.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import requests
|
||||||
|
# I just want to write a quick script to test if the E-Tag is updated correctly
|
||||||
Reference in New Issue
Block a user