eyeD3 0.9.8a1__py3-none-any.whl → 0.9.8a5__py3-none-any.whl

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.
eyed3/__regarding__.py CHANGED
@@ -22,13 +22,13 @@ class Version:
22
22
 
23
23
 
24
24
  project_name = "eyeD3"
25
- version = "0.9.8a1"
25
+ version = "0.9.8a5"
26
26
  version_info = Version(
27
27
  0, 9, 8,
28
28
  None,
29
- ('a', 1),
29
+ ('a', 5),
30
30
  None,
31
- "Refuse/Resist",
31
+ "With Fear I Kiss the Burning Darkness",
32
32
  )
33
33
 
34
34
  author = "Travis Shirk"
eyed3/core.py CHANGED
@@ -268,14 +268,27 @@ class Date:
268
268
  "%Y-%m-%d %H:%M:%S",
269
269
  "%Y-00-00",
270
270
  "%Y%m%d",
271
+ # Special formats to support ID3v2.3 TDAT and TIME frames.
272
+ # See https://github.com/nicfit/eyeD3/pull/623 and frames.Date.date setter
273
+ "D%d-%m",
274
+ "T%H:%M",
271
275
  ]
272
276
  """Valid time stamp formats per ISO 8601 and used by `strptime`."""
273
277
 
274
- def __init__(self, year, month=None, day=None,
278
+ @classmethod
279
+ def __new__(cls, *args, **kwargs):
280
+ if ([arg for arg in args[1:] if arg is not None] or
281
+ [kwarg for kwarg in kwargs.values() if kwarg is not None]):
282
+ return super().__new__(cls)
283
+ else:
284
+ return
285
+
286
+ def __init__(self, year=None, month=None, day=None,
275
287
  hour=None, minute=None, second=None):
276
288
  # Validate with datetime
277
289
  from datetime import datetime
278
- _ = datetime(year, month if month is not None else 1,
290
+ _ = datetime(year if year is not None else 1899,
291
+ month if month is not None else 1,
279
292
  day if day is not None else 1,
280
293
  hour if hour is not None else 0,
281
294
  minute if minute is not None else 0,
@@ -383,6 +396,8 @@ class Date:
383
396
  # Here is the difference with Python date/datetime objects, some
384
397
  # of the members can be None
385
398
  kwargs = {}
399
+ if "%Y" in fmt:
400
+ kwargs["year"] = pdate.tm_year
386
401
  if "%m" in fmt:
387
402
  kwargs["month"] = pdate.tm_mon
388
403
  if "%d" in fmt:
@@ -394,23 +409,35 @@ class Date:
394
409
  if "%S" in fmt:
395
410
  kwargs["second"] = pdate.tm_sec
396
411
 
397
- return Date(pdate.tm_year, **kwargs)
412
+ return Date(**kwargs)
398
413
 
399
414
  def __str__(self):
400
415
  """Returns date strings that conform to ISO-8601.
401
416
  The returned string will be no larger than 17 characters."""
402
- s = "%d" % self.year
403
- if self.month:
404
- s += "-%s" % str(self.month).rjust(2, '0')
405
- if self.day:
406
- s += "-%s" % str(self.day).rjust(2, '0')
407
- if self.hour is not None:
408
- s += "T%s" % str(self.hour).rjust(2, '0')
409
- if self.minute is not None:
410
- s += ":%s" % str(self.minute).rjust(2, '0')
411
- if self.second is not None:
412
- s += ":%s" % str(self.second).rjust(2, '0')
413
- return s
417
+ s = "" # the string
418
+ c = "" # the separator character
419
+ if self.year is not None: # branch 1, aka "there is a year, maybe more"
420
+ s += "%d" % self.year
421
+ c = "-"
422
+ if self.month is not None: # there is a month
423
+ s += c + "%s" % str(self.month).rjust(2, '0')
424
+ if self.day is not None: # there is a day
425
+ s += c + "%s" % str(self.day).rjust(2, '0')
426
+ else: # branch 2, aka "we start without a year" aka "D%d-%m" format
427
+ c = "D"
428
+ if (self.day is not None) and (self.month is not None): # checking both
429
+ s += c + "%s" % str(self.day).rjust(2, '0')
430
+ c = "-"
431
+ s += c + "%s" % str(self.month).rjust(2, '0')
432
+ return s # We send a "Ddd-mm" string for 'TDAT'
433
+ # Here is the 'TIME' part, which starts or continues the string from branch 1
434
+ c = "T"
435
+ if self.hour is not None:
436
+ s += c + "%s" % str(self.hour).rjust(2, '0')
437
+ c = ":"
438
+ if self.minute is not None:
439
+ s += c + "%s" % str(self.minute).rjust(2, '0')
440
+ return s # We send either a YYYY-mm-ddTHH:MM, or just a THH:MM (for 'TIME')
414
441
 
415
442
 
416
443
  def parseError(ex) -> None:
eyed3/id3/__init__.py CHANGED
@@ -130,11 +130,11 @@ class Genre:
130
130
  # valid id will set name
131
131
  if name and name != self.name:
132
132
  log.warning(f"Genre ID takes precedence and remapped '{name}' to '{self.name}'")
133
- except ValueError:
133
+ except ValueError as ex:
134
134
  log.warning(f"Invalid numeric genre ID: {id}")
135
135
  if not name:
136
136
  # Gave an invalid ID and no name to fallback on
137
- raise
137
+ raise GenreException from ex
138
138
  self.name = name
139
139
  self.id = None
140
140
  else:
eyed3/id3/apple.py CHANGED
@@ -10,6 +10,8 @@ TKWD_FID = b"TKWD"
10
10
  TDES_FID = b"TDES"
11
11
  TGID_FID = b"TGID"
12
12
  GRP1_FID = b"GRP1"
13
+ MVNM_FID = b"MVNM"
14
+ MVIN_FID = b"MVIN"
13
15
 
14
16
 
15
17
  class PCST(Frame):
@@ -56,3 +58,17 @@ class GRP1(TextFrame):
56
58
 
57
59
  def __init__(self, _=None, **kwargs):
58
60
  super().__init__(GRP1_FID, **kwargs)
61
+
62
+
63
+ class MVNM(TextFrame):
64
+ """Movement name. An Apple extension for classical music."""
65
+
66
+ def __init__(self, _=None, **kwargs):
67
+ super().__init__(MVNM_FID, **kwargs)
68
+
69
+
70
+ class MVIN(TextFrame):
71
+ """Movement index (e.g. "3/9"). An Apple extension for classical music."""
72
+
73
+ def __init__(self, _=None, **kwargs):
74
+ super().__init__(MVIN_FID, **kwargs)
eyed3/id3/frames.py CHANGED
@@ -319,7 +319,8 @@ class TextFrame(Frame):
319
319
  @staticmethod
320
320
  def isValidFrameId(fid: bytes) -> bool:
321
321
  return (fid[0:1] == b'T' or
322
- fid in [b"XSOA", b"XSOP", b"XSOT", b"XDOR", b"WFED", b"GRP1"])
322
+ fid in [b"XSOA", b"XSOP", b"XSOT", b"XDOR", b"WFED", b"GRP1",
323
+ b"MVNM", b"MVIN"])
323
324
 
324
325
 
325
326
  class UserTextFrame(TextFrame):
@@ -411,7 +412,11 @@ class DateFrame(TextFrame):
411
412
  self.text = ""
412
413
  return
413
414
 
414
- self.text = str(date)
415
+ str_date = str(date)
416
+ if ((DorT := str_date[0]) in ("D", "T")) and (len(str_date) <= 6): # maxlength 6
417
+ str_date = str_date.replace(DorT, "", 1)
418
+ str_date = str_date.replace("-" if DorT == "D" else ":", "")
419
+ self.text = str_date
415
420
 
416
421
  def _initEncoding(self):
417
422
  # Dates are always latin1 since they are always represented in ISO 8601
@@ -2258,4 +2263,8 @@ NONSTANDARD_ID3_FRAMES = {
2258
2263
  ID3_V2, TextFrame),
2259
2264
  b"GRP1": ("iTunes extension; grouping.",
2260
2265
  ID3_V2, apple.GRP1),
2266
+ b"MVNM": ("iTunes extension; movement name.",
2267
+ ID3_V2, apple.MVNM),
2268
+ b"MVIN": ("iTunes extension; movement index.",
2269
+ ID3_V2, apple.MVIN)
2261
2270
  }
eyed3/id3/tag.py CHANGED
@@ -556,11 +556,11 @@ class Tag(core.Tag):
556
556
  date = core.Date.parse(date)
557
557
  self._setDate(b"TYER", str(date.year))
558
558
  if None not in (date.month, date.day):
559
- date_str = "%s%s" % (str(date.day).rjust(2, "0"),
559
+ date_str = "D%s-%s" % (str(date.day).rjust(2, "0"),
560
560
  str(date.month).rjust(2, "0"))
561
561
  self._setDate(b"TDAT", date_str)
562
562
  if None not in (date.hour, date.minute):
563
- date_str = "%s%s" % (str(date.hour).rjust(2, "0"),
563
+ date_str = "T%s:%s" % (str(date.hour).rjust(2, "0"),
564
564
  str(date.minute).rjust(2, "0"))
565
565
  self._setDate(b"TIME", date_str)
566
566
 
eyed3/plugins/mimetype.py CHANGED
@@ -9,32 +9,6 @@ from eyed3.utils.log import getLogger
9
9
 
10
10
  log = getLogger(__name__)
11
11
 
12
- # python-magic
13
- try:
14
- import magic
15
-
16
- class MagicTypes(magic.Magic):
17
- def __init__(self):
18
- magic.Magic.__init__(self, mime=True, mime_encoding=False, keep_going=True)
19
-
20
- def guess_type(self, filename, all_types=False):
21
- try:
22
- types = self.from_file(filename)
23
- except UnicodeEncodeError:
24
- # https://github.com/ahupp/python-magic/pull/144
25
- types = self.from_file(filename.encode("utf-8", 'surrogateescape'))
26
-
27
- delim = r"\012- "
28
- if all_types:
29
- return types.split(delim)
30
- else:
31
- return types.split(delim)[0]
32
-
33
- _python_magic = MagicTypes()
34
-
35
- except ImportError:
36
- _python_magic = None
37
-
38
12
 
39
13
  class MimetypesPlugin(eyed3.plugins.LoaderPlugin):
40
14
  NAMES = ["mimetypes"]
@@ -47,16 +21,12 @@ class MimetypesPlugin(eyed3.plugins.LoaderPlugin):
47
21
  g.add_argument("--status", action="store_true", help="Print dot status.")
48
22
  g.add_argument("--parse-files", action="store_true", help="Parse each file.")
49
23
  g.add_argument("--hide-notfound", action="store_true")
50
- if _python_magic:
51
- g.add_argument("-M", "--use-pymagic", action="store_true",
52
- help="Use python-magic to determine mimetype.")
53
- self.magic = None
24
+
54
25
  self.start_t = None
55
26
  self.mime_types = Counter()
56
27
 
57
28
  def start(self, args, config):
58
29
  super().start(args, config)
59
- self.magic = "pymagic" if self.args.use_pymagic else "filetype"
60
30
  self.start_t = time.time()
61
31
 
62
32
  def handleFile(self, f, *args, **kwargs):
@@ -70,11 +40,7 @@ class MimetypesPlugin(eyed3.plugins.LoaderPlugin):
70
40
  else:
71
41
  self._num_loaded += 1
72
42
 
73
- if self.magic == "pymagic":
74
- mtype = _python_magic.guess_type(f)
75
- else:
76
- mtype = guessMimetype(f)
77
-
43
+ mtype = guessMimetype(f)
78
44
  self.mime_types[mtype] += 1
79
45
  if not self.args.hide_notfound:
80
46
  if mtype is None and Path(f).suffix.lower() in (".mp3",):
@@ -87,7 +53,6 @@ class MimetypesPlugin(eyed3.plugins.LoaderPlugin):
87
53
  t = time.time() - self.start_t
88
54
  print(f"\nVisited {self._num_visited} files")
89
55
  print(f"Processed {self._num_loaded} files")
90
- print(f"magic: {self.magic}")
91
56
  print(f"time: {eyed3.utils.formatTime(t)} seconds")
92
57
  if self.mime_types:
93
58
  pprint.pprint(self.mime_types)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eyeD3
3
- Version: 0.9.8a1
3
+ Version: 0.9.8a5
4
4
  Summary: Python audio data toolkit (ID3 and MP3)
5
5
  Author-email: Travis Shirk <travis@pobox.com>
6
6
  Project-URL: homepage, https://eyeD3.nicfit.net/
@@ -56,21 +56,16 @@ Status
56
56
  .. image:: https://img.shields.io/pypi/v/eyeD3.svg
57
57
  :target: https://pypi.python.org/pypi/eyeD3/
58
58
  :alt: Latest Version
59
- .. image:: https://img.shields.io/pypi/status/eyeD3.svg
60
- :target: https://pypi.python.org/pypi/eyeD3/
61
- :alt: Project Status
62
- .. image:: https://travis-ci.org/nicfit/eyeD3.svg?branch=master
63
- :target: https://travis-ci.org/nicfit/eyeD3
64
- :alt: Build Status
65
59
  .. image:: https://img.shields.io/pypi/l/eyeD3.svg
66
60
  :target: https://pypi.python.org/pypi/eyeD3/
67
61
  :alt: License
68
62
  .. image:: https://img.shields.io/pypi/pyversions/eyeD3.svg
69
63
  :target: https://pypi.python.org/pypi/eyeD3/
70
64
  :alt: Supported Python versions
71
- .. image:: https://coveralls.io/repos/nicfit/eyeD3/badge.svg
72
- :target: https://coveralls.io/r/nicfit/eyeD3
73
- :alt: Coverage Status
65
+ .. image:: https://img.shields.io/pypi/dm/eyeD3
66
+ :alt: PyPI - Downloads
67
+ .. image:: https://img.shields.io/github/stars/nicfit/eyeD3
68
+ :alt: GitHub Repo stars
74
69
 
75
70
 
76
71
  About
@@ -145,7 +140,7 @@ Features
145
140
  Get Started
146
141
  -----------
147
142
 
148
- Python >= 3.7 is required.
143
+ Python >= 3.9 is required.
149
144
 
150
145
  For `installation instructions`_ or more complete `documentation`_ see
151
146
  http://eyeD3.nicfit.net/
@@ -1,14 +1,14 @@
1
1
  eyed3/__about__.py,sha256=QCoElK7Jl5lwbzVtc3oXYwfo2bwzlCb_S0_oI5HsIyQ,1001
2
2
  eyed3/__init__.py,sha256=byYZrNCjfzdoQ8hCaBwoDAfP8DfwmuHK0-tPpFRncuc,1356
3
- eyed3/__regarding__.py,sha256=dXiMFmtZaWAFF8iRsvyKvP-bwC9c3lbNiEgKz79xdM0,1082
4
- eyed3/core.py,sha256=ymrKZK2-0QpzZfppQI1xgSFSOe128HcYWwY6NFpSGQg,13657
3
+ eyed3/__regarding__.py,sha256=HmmkZWF0wMtimaLB7KBsCiPG6WjAIGDhN8zvUMsyARo,1106
4
+ eyed3/core.py,sha256=3NCP0GGBG0wMJovy7cK_l0obj-9Zbm_PHDt2zdswEKw,14967
5
5
  eyed3/main.py,sha256=mNf2afmfIn19tlnduVMytd9IOAZchNEkVxDVjDjvtP8,10991
6
6
  eyed3/mimetype.py,sha256=xFQxSbzERpg8H3XmAyJFEk65myXcUJ64p3e7mUByf8k,3292
7
- eyed3/id3/__init__.py,sha256=5Gkm7dX_ujY0LHY4DbkhLcMB0ZtQ6uMdbWtipZHUUVQ,13895
8
- eyed3/id3/apple.py,sha256=nQ1U7u4ObG9XcHSkqjsJaOzlyCJ8b4Kj1R7CiFj4wq4,1431
9
- eyed3/id3/frames.py,sha256=2H1iWUvZQ07H-uEqqT2t77uCzF4fgpVzlDQ7df6kNNU,83519
7
+ eyed3/id3/__init__.py,sha256=iFb8v_w5bQMOiFsCTg8IvSmnqHvPLTaIubUMO6kxOpo,13924
8
+ eyed3/id3/apple.py,sha256=i7YZivx7Zi8b-6R98HdZQsllshJhcGGU7gdzouDGOZQ,1839
9
+ eyed3/id3/frames.py,sha256=hiNE8AbNBqHeKdOBUM_iaU5kgo4ri6zWGlwl8gh-tbM,83975
10
10
  eyed3/id3/headers.py,sha256=VXMln18qzZNopq2UY8lfq7h2tYXKae1Rejp2aaFg2Fc,23981
11
- eyed3/id3/tag.py,sha256=cr9cCSgPVEaWZ0PoLLPC5Im2Tc_e6_Rc3zlw42SWUUk,73054
11
+ eyed3/id3/tag.py,sha256=gUhtpx8-A44BkJmnyM15BiMbra0cxTK0NsPsw2qbJUw,73058
12
12
  eyed3/mp3/__init__.py,sha256=W1MKl7lmOtTD06rsUJaFnWC0PIsUMUhEi5NkLYkWy00,6605
13
13
  eyed3/mp3/headers.py,sha256=8b6Bav0ZOB1BQSceQW_SCcU1Z4IZlWpEJrhqsbBzTe8,32592
14
14
  eyed3/plugins/__init__.py,sha256=nSEud7L2EjiNy0dvIcEx82G5yPUswKv2i9eXk4YZUAo,7445
@@ -21,7 +21,7 @@ eyed3/plugins/itunes.py,sha256=AkUUbYQZ4SQCDJU77GZ7OPcMN_MY0SEDyi-mLIuxR5o,2033
21
21
  eyed3/plugins/jsontag.py,sha256=xPYzZ4sBIaunp5tdwTXAvpMJumuNwzAJ1-paAJPJLsE,4609
22
22
  eyed3/plugins/lameinfo.py,sha256=UevBAUViHJppP_qHWCUFM2BteaXCelvkQWDB_eSHHZ0,3576
23
23
  eyed3/plugins/lastfm.py,sha256=mcW4ocHCFOxDPk8vbcRsialhdKzH2XEzgXcoJHC9W90,1352
24
- eyed3/plugins/mimetype.py,sha256=ECwHqQZwE9r3v-W7BLXgVPiNNaQ6JkdJTLPBnLsLwuo,2958
24
+ eyed3/plugins/mimetype.py,sha256=fYkiZAtSd7GPRj_gyusrzm61d7sJ29YNQ20Y6UiHL20,1792
25
25
  eyed3/plugins/nfo.py,sha256=9lC-EcgiOLGidOYHgkDoQvTRGt43InT62uC4gn4Bur8,4705
26
26
  eyed3/plugins/pymod.py,sha256=05bquce3kRtgn7JIIMH3vkIJ5pVpohHmC3PkxWdJpXY,2559
27
27
  eyed3/plugins/stats.py,sha256=fYPSxRyty9qRDimhxwNeM86bU76a95ZdxHs9JfkVYk8,15146
@@ -33,10 +33,10 @@ eyed3/utils/binfuncs.py,sha256=E1UuTFNc5o-tHrUk6g9XytMgGFtk7fOrzlTuFFzBWI4,3955
33
33
  eyed3/utils/console.py,sha256=1DllCbtHS0vry218lL6EcHVWvZfUthpnAGimq0zkUX0,17567
34
34
  eyed3/utils/log.py,sha256=TESTslOurwATIwmLU45P0rj1kiYf3bXxLNJnc-QrBXg,1484
35
35
  eyed3/utils/prompt.py,sha256=56Gbd00LPAsp_k4MzTqhTudu2eOLFA3TSeeTESkKSI0,2735
36
- eyed3-0.9.8a1.dist-info/licenses/AUTHORS.rst,sha256=FM5ejB4iI-N96B-ZkWTpBV7ZUr344vfkWxc-XuNQ638,1380
37
- eyed3-0.9.8a1.dist-info/licenses/LICENSE,sha256=yjcqfZJWCx-p9tgytEDovNYtmt-ohwyYKH3qtm2YMQ4,35148
38
- eyed3-0.9.8a1.dist-info/METADATA,sha256=zSDTH0JI0L43ZwZAV4-FO7-Pe4OiAblcSr3TmZxhMqg,5997
39
- eyed3-0.9.8a1.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
40
- eyed3-0.9.8a1.dist-info/entry_points.txt,sha256=tNVkF9g-_swrPgCLayGq9N6c_B_wFPsnHFyR4PqlGWU,43
41
- eyed3-0.9.8a1.dist-info/top_level.txt,sha256=zeurONV1_zm-Vtqv947t4FQnUSmHIFLVzD6SFEa1p4M,6
42
- eyed3-0.9.8a1.dist-info/RECORD,,
36
+ eyed3-0.9.8a5.dist-info/licenses/AUTHORS.rst,sha256=0rp2QqSd1-fnmPiVkmp9JkP7KTKYtshkjU_V1sW3eKE,1607
37
+ eyed3-0.9.8a5.dist-info/licenses/LICENSE,sha256=yjcqfZJWCx-p9tgytEDovNYtmt-ohwyYKH3qtm2YMQ4,35148
38
+ eyed3-0.9.8a5.dist-info/METADATA,sha256=8LvVxON0D8lAT3f-y8S3fgvHak7EO6OzJ2ORvezsREs,5763
39
+ eyed3-0.9.8a5.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
40
+ eyed3-0.9.8a5.dist-info/entry_points.txt,sha256=tNVkF9g-_swrPgCLayGq9N6c_B_wFPsnHFyR4PqlGWU,43
41
+ eyed3-0.9.8a5.dist-info/top_level.txt,sha256=zeurONV1_zm-Vtqv947t4FQnUSmHIFLVzD6SFEa1p4M,6
42
+ eyed3-0.9.8a5.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.1)
2
+ Generator: setuptools (79.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -37,3 +37,9 @@ and has been contributed to by (ordered by date of first contribution):
37
37
  * grun <grunseid@gmail.com>
38
38
  * guiweber <guillaume.web@gmail.com>
39
39
  * zhu <zhumumu@gmail.com>
40
+ * Michał Górny <mgorny@gentoo.org>
41
+ * Jonathan Herlin <Jonte@jherlin.se>
42
+ * Ramiro Gómez <code@ramiro.org>
43
+ * Steve Kowalik <steven@wedontsleep.org>
44
+ * gersonkurz <gerson.kurz@gmail.com>
45
+ * obskyr <powpowd@gmail.com>