yutipy 1.4.0__tar.gz → 1.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of yutipy might be problematic. Click here for more details.
- {yutipy-1.4.0 → yutipy-1.4.2}/.github/workflows/release.yml +0 -14
- {yutipy-1.4.0 → yutipy-1.4.2}/PKG-INFO +2 -2
- {yutipy-1.4.0 → yutipy-1.4.2}/pyproject.toml +1 -1
- {yutipy-1.4.0 → yutipy-1.4.2}/requirements.txt +1 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy/__init__.py +2 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy/itunes.py +14 -4
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy/spotify.py +10 -3
- yutipy-1.4.2/yutipy/utils/__init__.py +13 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy/utils/cheap_utils.py +26 -2
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy/yutipy_music.py +25 -18
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy.egg-info/PKG-INFO +2 -2
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy.egg-info/SOURCES.txt +0 -1
- yutipy-1.4.0/.github/release-drafter.yml +0 -16
- yutipy-1.4.0/yutipy/utils/__init__.py +0 -7
- {yutipy-1.4.0 → yutipy-1.4.2}/.gitattributes +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/.github/FUNDING.yml +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/.github/workflows/pytest-unit-testing.yml +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/.gitignore +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/.readthedocs.yaml +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/LICENSE +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/MANIFEST.in +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/README.md +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/Makefile +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/_static/yutipy_header.png +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/_static/yutipy_logo.png +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/api_reference.rst +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/available_platforms.rst +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/conf.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/faq.rst +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/index.rst +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/installation.rst +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/make.bat +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/requirements.txt +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/docs/usage_examples.rst +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/requirements-dev.txt +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/setup.cfg +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/tests/__init__.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/tests/test_deezer.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/tests/test_itunes.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/tests/test_kkbox.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/tests/test_models.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/tests/test_musicyt.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/tests/test_spotify.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/tests/test_utils.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/tests/test_yutipy_music.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy/deezer.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy/exceptions.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy/kkbox.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy/models.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy/musicyt.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy/utils/logger.py +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy.egg-info/dependency_links.txt +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy.egg-info/requires.txt +0 -0
- {yutipy-1.4.0 → yutipy-1.4.2}/yutipy.egg-info/top_level.txt +0 -0
|
@@ -54,25 +54,12 @@ jobs:
|
|
|
54
54
|
path: dist/
|
|
55
55
|
- name: Publish distribution 📦 to PyPI
|
|
56
56
|
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
|
|
57
|
-
draft-release:
|
|
58
|
-
name: Draft Release Notes
|
|
59
|
-
runs-on: ubuntu-latest
|
|
60
|
-
permissions:
|
|
61
|
-
contents: read
|
|
62
|
-
needs:
|
|
63
|
-
- publish-to-pypi
|
|
64
|
-
steps:
|
|
65
|
-
- name: Draft Release Notes
|
|
66
|
-
uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0
|
|
67
|
-
with:
|
|
68
|
-
config-name: .github/release-drafter.yml
|
|
69
57
|
github-release:
|
|
70
58
|
name: >-
|
|
71
59
|
Sign the Python 🐍 distribution 📦 with Sigstore
|
|
72
60
|
and upload them to GitHub Release
|
|
73
61
|
needs:
|
|
74
62
|
- publish-to-pypi
|
|
75
|
-
- draft-release
|
|
76
63
|
runs-on: ubuntu-latest
|
|
77
64
|
|
|
78
65
|
permissions:
|
|
@@ -98,7 +85,6 @@ jobs:
|
|
|
98
85
|
gh release create
|
|
99
86
|
"$GITHUB_REF_NAME"
|
|
100
87
|
--repo "$GITHUB_REPOSITORY"
|
|
101
|
-
--notes-file .github/release-drafter.yml
|
|
102
88
|
--generate-notes
|
|
103
89
|
- name: Upload artifact signatures to GitHub Release
|
|
104
90
|
env:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yutipy
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.2
|
|
4
4
|
Summary: A simple package for retrieving music information from various music platforms APIs.
|
|
5
5
|
Author: Cheap Nightbot
|
|
6
6
|
Author-email: Cheap Nightbot <hi@cheapnightbot.slmail.me>
|
|
@@ -33,7 +33,7 @@ Project-URL: Repository, https://github.com/CheapNightbot/yutipy.git
|
|
|
33
33
|
Project-URL: Issues, https://github.com/CheapNightbot/yutipy/issues
|
|
34
34
|
Project-URL: Changelog, https://github.com/CheapNightbot/yutipy/blob/master/CHANGELOG.md
|
|
35
35
|
Project-URL: funding, https://ko-fi.com/cheapnightbot
|
|
36
|
-
Keywords: music,API,Deezer,iTunes,Spotify,YouTube Music,search,retrieve,information,yutify
|
|
36
|
+
Keywords: music,API,Deezer,iTunes,Spotify,YouTube Music,search,retrieve,information,yutify,KKBox
|
|
37
37
|
Classifier: Development Status :: 4 - Beta
|
|
38
38
|
Classifier: Intended Audience :: Developers
|
|
39
39
|
Classifier: Topic :: Software Development :: Libraries
|
|
@@ -22,7 +22,7 @@ maintainers = [
|
|
|
22
22
|
description = "A simple package for retrieving music information from various music platforms APIs."
|
|
23
23
|
readme = "README.md"
|
|
24
24
|
license = {file = "LICENSE"}
|
|
25
|
-
keywords = ["music", "API", "Deezer", "iTunes", "Spotify", "YouTube Music", "search", "retrieve", "information", "yutify"]
|
|
25
|
+
keywords = ["music", "API", "Deezer", "iTunes", "Spotify", "YouTube Music", "search", "retrieve", "information", "yutify", "KKBox"]
|
|
26
26
|
classifiers = [
|
|
27
27
|
"Development Status :: 4 - Beta",
|
|
28
28
|
"Intended Audience :: Developers",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from .deezer import Deezer
|
|
2
2
|
from .itunes import Itunes
|
|
3
|
+
from .kkbox import KKBox
|
|
3
4
|
from .models import MusicInfo
|
|
4
5
|
from .musicyt import MusicYT
|
|
5
6
|
from .spotify import Spotify
|
|
@@ -8,6 +9,7 @@ from .yutipy_music import YutipyMusic
|
|
|
8
9
|
__all__ = [
|
|
9
10
|
"Deezer",
|
|
10
11
|
"Itunes",
|
|
12
|
+
"KKBox",
|
|
11
13
|
"MusicInfo",
|
|
12
14
|
"MusicYT",
|
|
13
15
|
"Spotify",
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
from pprint import pprint
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Dict, Optional
|
|
4
4
|
|
|
5
5
|
import requests
|
|
6
6
|
|
|
7
7
|
from yutipy.exceptions import (
|
|
8
8
|
InvalidResponseException,
|
|
9
9
|
InvalidValueException,
|
|
10
|
-
NetworkException,
|
|
11
10
|
ItunesException,
|
|
11
|
+
NetworkException,
|
|
12
12
|
)
|
|
13
13
|
from yutipy.models import MusicInfo
|
|
14
|
-
from yutipy.utils.cheap_utils import
|
|
14
|
+
from yutipy.utils.cheap_utils import (
|
|
15
|
+
are_strings_similar,
|
|
16
|
+
guess_album_type,
|
|
17
|
+
is_valid_string,
|
|
18
|
+
)
|
|
15
19
|
|
|
16
20
|
|
|
17
21
|
class Itunes:
|
|
@@ -180,7 +184,13 @@ class Itunes:
|
|
|
180
184
|
album_title, album_type = result["collectionName"].split("-")
|
|
181
185
|
return album_title.strip(), album_type.strip()
|
|
182
186
|
except ValueError:
|
|
183
|
-
|
|
187
|
+
guess = guess_album_type(result.get("trackCount", 1))
|
|
188
|
+
guessed_right = are_strings_similar(
|
|
189
|
+
result.get("wrapperType", "x"), guess, use_translation=False
|
|
190
|
+
)
|
|
191
|
+
return result["collectionName"], (
|
|
192
|
+
result["wrapperType"] if guessed_right else guess
|
|
193
|
+
)
|
|
184
194
|
|
|
185
195
|
def _format_release_date(self, release_date: str) -> str:
|
|
186
196
|
"""
|
|
@@ -17,6 +17,7 @@ from yutipy.exceptions import (
|
|
|
17
17
|
from yutipy.models import MusicInfo
|
|
18
18
|
from yutipy.utils.cheap_utils import (
|
|
19
19
|
are_strings_similar,
|
|
20
|
+
guess_album_type,
|
|
20
21
|
is_valid_string,
|
|
21
22
|
separate_artists,
|
|
22
23
|
)
|
|
@@ -175,6 +176,7 @@ class Spotify:
|
|
|
175
176
|
self.normalize_non_english = normalize_non_english
|
|
176
177
|
|
|
177
178
|
music_info = None
|
|
179
|
+
artist_ids = None
|
|
178
180
|
queries = [
|
|
179
181
|
f"?q=artist:{artist} track:{song}&type=track&limit={limit}",
|
|
180
182
|
f"?q=artist:{artist} album:{song}&type=album&limit={limit}",
|
|
@@ -199,7 +201,7 @@ class Spotify:
|
|
|
199
201
|
if response.status_code != 200:
|
|
200
202
|
raise SpotifyException(f"Failed to search for music: {response.json()}")
|
|
201
203
|
|
|
202
|
-
artist_ids = self._get_artists_ids(artist)
|
|
204
|
+
artist_ids = artist_ids if artist_ids else self._get_artists_ids(artist)
|
|
203
205
|
music_info = self._find_music_info(
|
|
204
206
|
artist, song, response.json(), artist_ids
|
|
205
207
|
)
|
|
@@ -449,10 +451,15 @@ class Spotify:
|
|
|
449
451
|
]
|
|
450
452
|
|
|
451
453
|
if matching_artists:
|
|
454
|
+
guess = guess_album_type(album.get("total_tracks", 1))
|
|
455
|
+
guessed_right = are_strings_similar(
|
|
456
|
+
album.get("album_type", "x"), guess, use_translation=False
|
|
457
|
+
)
|
|
458
|
+
|
|
452
459
|
return MusicInfo(
|
|
453
460
|
album_art=album["images"][0]["url"],
|
|
454
461
|
album_title=album["name"],
|
|
455
|
-
album_type=album
|
|
462
|
+
album_type=album.get("album_type") if guessed_right else guess,
|
|
456
463
|
artists=", ".join(artists_name),
|
|
457
464
|
genre=None,
|
|
458
465
|
id=album["id"],
|
|
@@ -461,7 +468,7 @@ class Spotify:
|
|
|
461
468
|
release_date=album["release_date"],
|
|
462
469
|
tempo=None,
|
|
463
470
|
title=album["name"],
|
|
464
|
-
type=
|
|
471
|
+
type=album.get("type"),
|
|
465
472
|
upc=None,
|
|
466
473
|
url=album["external_urls"]["spotify"],
|
|
467
474
|
)
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import pykakasi
|
|
1
2
|
import requests
|
|
2
3
|
from rapidfuzz import fuzz
|
|
3
4
|
from rapidfuzz.utils import default_process
|
|
4
5
|
|
|
6
|
+
kakasi = pykakasi.kakasi()
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
def translate_text(
|
|
7
10
|
text: str,
|
|
@@ -72,18 +75,29 @@ def are_strings_similar(
|
|
|
72
75
|
Returns:
|
|
73
76
|
bool: True if the strings are similar, otherwise False.
|
|
74
77
|
"""
|
|
78
|
+
|
|
75
79
|
if use_translation:
|
|
76
|
-
|
|
80
|
+
translated_str1 = (
|
|
77
81
|
translate_text(str1, session=translation_session)["destination-text"]
|
|
78
82
|
if translation_session
|
|
79
83
|
else translate_text(str1)["destination-text"]
|
|
80
84
|
)
|
|
81
|
-
|
|
85
|
+
translated_str2 = (
|
|
82
86
|
translate_text(str2, session=translation_session)["destination-text"]
|
|
83
87
|
if translation_session
|
|
84
88
|
else translate_text(str2)["destination-text"]
|
|
85
89
|
)
|
|
86
90
|
|
|
91
|
+
similarity_score = fuzz.WRatio(
|
|
92
|
+
translated_str1, translated_str2, processor=default_process
|
|
93
|
+
)
|
|
94
|
+
if similarity_score > threshold:
|
|
95
|
+
return True
|
|
96
|
+
|
|
97
|
+
# Use transliterated strings for comparison
|
|
98
|
+
str1 = "".join(item["hepburn"] for item in kakasi.convert(str1)) or str1
|
|
99
|
+
str2 = "".join(item["hepburn"] for item in kakasi.convert(str2)) or str2
|
|
100
|
+
|
|
87
101
|
similarity_score = fuzz.WRatio(str1, str2, processor=default_process)
|
|
88
102
|
return similarity_score > threshold
|
|
89
103
|
|
|
@@ -117,5 +131,15 @@ def is_valid_string(string: str) -> bool:
|
|
|
117
131
|
return bool(string and (string.isalnum() or not string.isspace()))
|
|
118
132
|
|
|
119
133
|
|
|
134
|
+
def guess_album_type(total_tracks: int):
|
|
135
|
+
"""Just guessing the album type (i.e. single, ep or album) by total track counts."""
|
|
136
|
+
if total_tracks == 1:
|
|
137
|
+
return "single"
|
|
138
|
+
if 3 <= total_tracks <= 5:
|
|
139
|
+
return "ep"
|
|
140
|
+
if total_tracks >= 7:
|
|
141
|
+
return "album"
|
|
142
|
+
|
|
143
|
+
|
|
120
144
|
if __name__ == "__main__":
|
|
121
145
|
separate_artists("Artist A ft. Artist B")
|
|
@@ -98,6 +98,20 @@ class YutipyMusic:
|
|
|
98
98
|
|
|
99
99
|
self.normalize_non_english = normalize_non_english
|
|
100
100
|
|
|
101
|
+
attributes = [
|
|
102
|
+
"album_title",
|
|
103
|
+
"album_type",
|
|
104
|
+
"artists",
|
|
105
|
+
"genre",
|
|
106
|
+
"isrc",
|
|
107
|
+
"lyrics",
|
|
108
|
+
"release_date",
|
|
109
|
+
"tempo",
|
|
110
|
+
"title",
|
|
111
|
+
"type",
|
|
112
|
+
"upc",
|
|
113
|
+
]
|
|
114
|
+
|
|
101
115
|
with ThreadPoolExecutor() as executor:
|
|
102
116
|
futures = {
|
|
103
117
|
executor.submit(
|
|
@@ -113,14 +127,16 @@ class YutipyMusic:
|
|
|
113
127
|
for future in as_completed(futures):
|
|
114
128
|
service_name = futures[future]
|
|
115
129
|
result = future.result()
|
|
116
|
-
self._combine_results(result, service_name)
|
|
130
|
+
self._combine_results(result, service_name, attributes)
|
|
117
131
|
|
|
118
132
|
if len(self.music_info.url) == 0:
|
|
119
133
|
return None
|
|
120
134
|
|
|
121
135
|
return self.music_info
|
|
122
136
|
|
|
123
|
-
def _combine_results(
|
|
137
|
+
def _combine_results(
|
|
138
|
+
self, result: Optional[MusicInfo], service_name: str, attributes: list
|
|
139
|
+
) -> None:
|
|
124
140
|
"""
|
|
125
141
|
Combines the results from different services.
|
|
126
142
|
|
|
@@ -134,25 +150,16 @@ class YutipyMusic:
|
|
|
134
150
|
if not result:
|
|
135
151
|
return
|
|
136
152
|
|
|
137
|
-
attributes = [
|
|
138
|
-
"album_title",
|
|
139
|
-
"album_type",
|
|
140
|
-
"artists",
|
|
141
|
-
"genre",
|
|
142
|
-
"isrc",
|
|
143
|
-
"lyrics",
|
|
144
|
-
"release_date",
|
|
145
|
-
"tempo",
|
|
146
|
-
"title",
|
|
147
|
-
"type",
|
|
148
|
-
"upc",
|
|
149
|
-
]
|
|
150
|
-
|
|
151
153
|
for attr in attributes:
|
|
152
154
|
if getattr(result, attr) and (
|
|
153
|
-
not getattr(self.music_info, attr)
|
|
155
|
+
not getattr(self.music_info, attr)
|
|
156
|
+
or (attr in ["genre", "album_type"] and service_name == "itunes")
|
|
154
157
|
):
|
|
155
|
-
setattr(
|
|
158
|
+
setattr(
|
|
159
|
+
self.music_info,
|
|
160
|
+
attr,
|
|
161
|
+
getattr(result, attributes.pop(attributes.index(attr))),
|
|
162
|
+
)
|
|
156
163
|
|
|
157
164
|
if result.album_art:
|
|
158
165
|
current_priority = self.album_art_priority.index(service_name)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yutipy
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.2
|
|
4
4
|
Summary: A simple package for retrieving music information from various music platforms APIs.
|
|
5
5
|
Author: Cheap Nightbot
|
|
6
6
|
Author-email: Cheap Nightbot <hi@cheapnightbot.slmail.me>
|
|
@@ -33,7 +33,7 @@ Project-URL: Repository, https://github.com/CheapNightbot/yutipy.git
|
|
|
33
33
|
Project-URL: Issues, https://github.com/CheapNightbot/yutipy/issues
|
|
34
34
|
Project-URL: Changelog, https://github.com/CheapNightbot/yutipy/blob/master/CHANGELOG.md
|
|
35
35
|
Project-URL: funding, https://ko-fi.com/cheapnightbot
|
|
36
|
-
Keywords: music,API,Deezer,iTunes,Spotify,YouTube Music,search,retrieve,information,yutify
|
|
36
|
+
Keywords: music,API,Deezer,iTunes,Spotify,YouTube Music,search,retrieve,information,yutify,KKBox
|
|
37
37
|
Classifier: Development Status :: 4 - Beta
|
|
38
38
|
Classifier: Intended Audience :: Developers
|
|
39
39
|
Classifier: Topic :: Software Development :: Libraries
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
name-template: 'v$NEXT_PATCH_VERSION'
|
|
2
|
-
tag-template: 'v$NEXT_PATCH_VERSION'
|
|
3
|
-
categories:
|
|
4
|
-
- title: '🚀 New Features'
|
|
5
|
-
label: 'feature'
|
|
6
|
-
- title: '🐛 Bug Fixes'
|
|
7
|
-
label: 'bug'
|
|
8
|
-
- title: '🧰 Maintenance'
|
|
9
|
-
label: 'maintenance'
|
|
10
|
-
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
|
|
11
|
-
template: |
|
|
12
|
-
## What's Changed
|
|
13
|
-
|
|
14
|
-
$CHANGES
|
|
15
|
-
|
|
16
|
-
**Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...$NEW_TAG
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|