diff --git a/src/file_formatter.py b/src/file_formatter.py index 0033ed7e713b1..820b23204e374 100644 --- a/src/file_formatter.py +++ b/src/file_formatter.py @@ -12,7 +12,6 @@ class Formatter: - TRACK_NO = "No." TITLE = "Title" ARTISTS = "Artist(s)" @@ -42,17 +41,20 @@ def readme(cls, prev_content: str, playlists: Mapping[PlaylistID, Playlist]) -> return "\n".join(new_lines) + "\n" @classmethod - def metadata_json(cls, playlists: Mapping[PlaylistID, Playlist]) -> str: - metadata_dict = {} + def metadata_full_json(cls, playlists: Mapping[PlaylistID, Playlist]) -> str: + data = {} for playlist_id, playlist in playlists.items(): playlist_dict = dataclasses.asdict(playlist) del playlist_dict["tracks"] - metadata_dict[playlist_id] = playlist_dict - return json.dumps( - metadata_dict, - indent=2, - sort_keys=True, - ) + data[playlist_id] = playlist_dict + return json.dumps(data, indent=2, sort_keys=True) + + @classmethod + def metadata_compact_json(cls, playlists: Mapping[PlaylistID, Playlist]) -> str: + data = {} + for playlist_id, playlist in playlists.items(): + data[playlist_id] = playlist.unique_name + return json.dumps(data, separators=(",", ":"), sort_keys=True) @classmethod def plain(cls, playlist_id: PlaylistID, playlist: Playlist) -> str: diff --git a/src/file_manager.py b/src/file_manager.py index 3c49381837859..e06c42d7af4ce 100644 --- a/src/file_manager.py +++ b/src/file_manager.py @@ -28,6 +28,7 @@ def ensure_subdirs_exist(self) -> None: self._get_plain_dir(), self._get_pretty_dir(), self._get_cumulative_dir(), + self._get_metadata_dir(), ]: directory.mkdir(parents=True, exist_ok=True) @@ -101,9 +102,15 @@ def get_cumulative_json_path(self, playlist_id: PlaylistID) -> pathlib.Path: def get_cumulative_markdown_path(self, playlist_id: PlaylistID) -> pathlib.Path: return self._get_cumulative_dir() / f"{playlist_id}.md" - def get_metadata_json_path(self) -> pathlib.Path: + def get_old_metadata_json_path(self) -> pathlib.Path: return self._playlists_dir / "metadata.json" + def get_metadata_full_json_path(self) -> pathlib.Path: + return self._get_metadata_dir() / "metadata-full.json" + + def get_metadata_compact_json_path(self) -> pathlib.Path: + return self._get_metadata_dir() / "metadata-compact.json" + def get_readme_path(self) -> pathlib.Path: return self._playlists_dir.parent / "README.md" @@ -119,6 +126,9 @@ def _get_pretty_dir(self) -> pathlib.Path: def _get_cumulative_dir(self) -> pathlib.Path: return self._playlists_dir / "cumulative" + def _get_metadata_dir(self) -> pathlib.Path: + return self._playlists_dir / "metadata" + @classmethod def _remove_suffix(cls, string: str, suffix: str) -> str: if not suffix: diff --git a/src/file_updater.py b/src/file_updater.py index b3e979e32c8fd..a7ba075259a16 100644 --- a/src/file_updater.py +++ b/src/file_updater.py @@ -248,13 +248,20 @@ async def _update_files_impl( # Check for unexpected files in playlist directories file_manager.ensure_no_unexpected_files() - # Write metadata.json - metadata_json_path = file_manager.get_metadata_json_path() - prev_content = cls._get_file_content_or_empty_string(metadata_json_path) - cls._write_to_file_if_content_changed( - prev_content=prev_content, - content=Formatter.metadata_json(playlists) + "\n", - path=metadata_json_path, + # Update all metadata files + metadata_full_content = Formatter.metadata_full_json(playlists) + "\n" + metadata_compact_content = Formatter.metadata_compact_json(playlists) + "\n" + cls._maybe_update_file( + path=file_manager.get_old_metadata_json_path(), + content=metadata_full_content, + ) + cls._maybe_update_file( + path=file_manager.get_metadata_full_json_path(), + content=metadata_full_content, + ) + cls._maybe_update_file( + path=file_manager.get_metadata_compact_json_path(), + content=metadata_compact_content, ) # Lastly, update README.md @@ -292,3 +299,12 @@ def _write_to_file_if_content_changed( logger.info(f" Writing updates to file: {path}") with open(path, "w") as f: f.write(content) + + @classmethod + def _maybe_update_file(cls, path: pathlib.Path, content: str) -> None: + prev_content = cls._get_file_content_or_empty_string(path) + cls._write_to_file_if_content_changed( + prev_content=prev_content, + content=content, + path=path, + ) diff --git a/src/tests/test_file_updater.py b/src/tests/test_file_updater.py index 15e3a65db3a0c..e0f8c65b58905 100644 --- a/src/tests/test_file_updater.py +++ b/src/tests/test_file_updater.py @@ -308,6 +308,9 @@ async def test_readme_and_metadata_json(self, mock_logger: Mock) -> None: for playlist_id in "abcd": (registry_dir / playlist_id).touch() + metadata_dir = self.playlists_dir / "metadata" + metadata_dir.mkdir(parents=True) + pretty_dir = self.playlists_dir / "pretty" pretty_dir.mkdir(parents=True) for playlist_id in "ac": @@ -350,53 +353,60 @@ async def test_readme_and_metadata_json(self, mock_logger: Mock) -> None: """ ), ) - with open(self.playlists_dir / "metadata.json", "r") as f: + for path in [ + self.playlists_dir / "metadata.json", + metadata_dir / "metadata-full.json", + ]: + with open(path, "r") as f: + content = f.read() + self.assertEqual( + content, + textwrap.dedent( + """\ + { + "a": { + "description": "description", + "num_followers": 0, + "original_name": "name_a", + "owner": { + "name": "owner_name", + "url": "owner_url" + }, + "snapshot_id": "snapshot_id", + "unique_name": "name_a", + "url": "url_a" + }, + "b": { + "description": "description", + "num_followers": 0, + "original_name": "name_b", + "owner": { + "name": "owner_name", + "url": "owner_url" + }, + "snapshot_id": "snapshot_id", + "unique_name": "name_b", + "url": "url_b" + }, + "c": { + "description": "description", + "num_followers": 0, + "original_name": " name_c ", + "owner": { + "name": "owner_name", + "url": "owner_url" + }, + "snapshot_id": "snapshot_id", + "unique_name": " name_c ", + "url": "url_c" + } + } + """ + ), + ) + with open(metadata_dir / "metadata-compact.json", "r") as f: content = f.read() - self.assertEqual( - content, - textwrap.dedent( - """\ - { - "a": { - "description": "description", - "num_followers": 0, - "original_name": "name_a", - "owner": { - "name": "owner_name", - "url": "owner_url" - }, - "snapshot_id": "snapshot_id", - "unique_name": "name_a", - "url": "url_a" - }, - "b": { - "description": "description", - "num_followers": 0, - "original_name": "name_b", - "owner": { - "name": "owner_name", - "url": "owner_url" - }, - "snapshot_id": "snapshot_id", - "unique_name": "name_b", - "url": "url_b" - }, - "c": { - "description": "description", - "num_followers": 0, - "original_name": " name_c ", - "owner": { - "name": "owner_name", - "url": "owner_url" - }, - "snapshot_id": "snapshot_id", - "unique_name": " name_c ", - "url": "url_c" - } - } - """ - ), - ) + self.assertEqual(content, '{"a":"name_a","b":"name_b","c":" name_c "}\n') async def test_success(self) -> None: # TODO