Skip to content

Commit

Permalink
implement cache
Browse files Browse the repository at this point in the history
  • Loading branch information
sigma67 committed Apr 20, 2023
1 parent e4151e8 commit 65db890
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 25 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,6 @@ venv.bak/
.idea
noresults.txt
*.ini
*.bin
*.txt
*.json
38 changes: 38 additions & 0 deletions spotify_to_ytmusic/cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import bz2
import json
from pathlib import Path
from typing import Dict


class Cache:
_cache: Dict[str, str]
filepath: Path = Path(__file__).parent.joinpath("cache.bin")

def __init__(self):
self._cache = {}
if self.filepath.is_file():
self._load(self.filepath)

def __contains__(self, item):
return item in self._cache

def __getitem__(self, key):
return self._cache[key]

def __setitem__(self, key, value):
self._cache[key] = value

def save(self):
self._save(self.filepath)

def _load(self, path: Path):
with open(path, "rb") as file:
data = bz2.decompress(file.read())

self._cache.update(json.loads(data))

def _save(self, path: Path):
byte_data = json.dumps(self._cache)
compressed_byte_data = bz2.compress(byte_data.encode("utf8"))
with open(path, "wb") as file:
file.write(compressed_byte_data)
2 changes: 1 addition & 1 deletion spotify_to_ytmusic/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def all(args):
)
print(playlist_id)
except Exception as ex:
print(f"Could not transfer playlist {p['name']}. {str(ex)}")
raise Exception(f"Could not transfer playlist {p['name']}") from ex


def create(args):
Expand Down
4 changes: 1 addition & 3 deletions spotify_to_ytmusic/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ def __init__(self, filepath: Optional[Path] = None):
if filepath:
self.filepath = filepath
if not self.filepath.is_file():
raise FileNotFoundError(
f"No settings.ini not found! Please run \n\n spotify_to_ytmusic setup"
)
raise FileNotFoundError(f"No settings.ini found! Please run spotify_to_ytmusic setup")
self.config.read(self.filepath)

def __getitem__(self, key):
Expand Down
36 changes: 21 additions & 15 deletions spotify_to_ytmusic/ytmusic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from ytmusicapi import YTMusic

from spotify_to_ytmusic.cache import Cache
from spotify_to_ytmusic.match import get_best_fit_song_id
from spotify_to_ytmusic.settings import Settings

Expand All @@ -24,23 +25,28 @@ def search_songs(self, tracks):
videoIds = []
songs = list(tracks)
notFound = list()
print("Searching YouTube...")
for i, song in enumerate(songs):
name = re.sub(r" \(feat.*\..+\)", "", song["name"])
query = song["artist"] + " " + name
query = query.replace(" &", "")
result = self.api.search(query)
if len(result) == 0:
notFound.append(query)
else:
targetSong = get_best_fit_song_id(result, song)
if targetSong is None:
notFound.append(query)
cache = Cache()
try:
for i, song in enumerate(songs):
if not i % 10:
print(f"YouTube tracks: {i}/{len(songs)}")
name = re.sub(r" \(feat.*\..+\)", "", song["name"])
query = song["artist"] + " " + name
query = query.replace(" &", "")
if query in cache:
targetSong = cache[query]
else:
videoIds.append(targetSong)
result = self.api.search(query)
if not len(result) or not (targetSong := get_best_fit_song_id(result, song)):
notFound.append(query)
continue

cache[query] = targetSong

videoIds.append(targetSong)

if i > 0 and i % 10 == 0:
print(f"YouTube tracks: {i}/{len(songs)}")
finally:
cache.save()

with open(path + "noresults_youtube.txt", "w", encoding="utf-8") as f:
f.write("\n".join(notFound))
Expand Down
15 changes: 11 additions & 4 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
import shutil
import time
import unittest
Expand Down Expand Up @@ -27,16 +28,17 @@ def test_create(self):
main()

with mock.patch(
"sys.argv", ["", "create", TEST_PLAYLIST, "-n", "test", "-i", "test-playlist", "-d"]
"sys.argv",
["", "create", TEST_PLAYLIST, "-n", "spotify_to_ytmusic", "-i", "test-playlist", "-d"],
):
main()

time.sleep(2)
with mock.patch("sys.argv", ["", "update", TEST_PLAYLIST, "test"]):
with mock.patch("sys.argv", ["", "update", TEST_PLAYLIST, "spotify_to_ytmusic"]):
main()

time.sleep(2)
with mock.patch("sys.argv", ["", "remove", "test"]), mock.patch(
with mock.patch("sys.argv", ["", "remove", "spotify\_to\_ytmusic"]), mock.patch(
"sys.stdout", new=StringIO()
) as fakeOutput, mock.patch("builtins.input", side_effect="y"):
main()
Expand All @@ -48,7 +50,12 @@ def test_setup(self):
tmp_path = Path(__file__).parent.joinpath("settings.tmp")
example_path = Settings.filepath.parent.joinpath("settings.ini.example")
shutil.copy(example_path, tmp_path)
with mock.patch("sys.argv", ["", "setup"]), mock.patch("builtins.input", return_value="3"):
with mock.patch("sys.argv", ["", "setup"]), mock.patch(
"builtins.input", return_value="3"
), mock.patch(
"ytmusicapi.auth.oauth.YTMusicOAuth.get_token_from_code",
return_value=json.loads(Settings()["youtube"]["headers"]),
):
main()
assert tmp_path.is_file()
tmp_path.unlink()
Expand Down
5 changes: 3 additions & 2 deletions tests/test_spotipy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@


class TestSpotify(unittest.TestCase):

def setUp(self) -> None:
self.spotify = Spotify()

def test_getSpotifyPlaylist(self):
data = self.spotify.getSpotifyPlaylist("https://open.spotify.com/playlist/03ICMYsVsC4I2SZnERcQJb")
data = self.spotify.getSpotifyPlaylist(
"https://open.spotify.com/playlist/03ICMYsVsC4I2SZnERcQJb"
)
self.assertEqual(len(data), 3)
self.assertGreater(len(data["tracks"]), 190)

Expand Down

0 comments on commit 65db890

Please sign in to comment.