fixed readme + id3 timestamps

This commit is contained in:
Hellow 2023-01-13 14:37:15 +01:00
parent 8a7335c741
commit 54a4be29ea
7 changed files with 141 additions and 35 deletions

View File

@ -24,6 +24,11 @@ pip install music-kraken
music-kraken
```
### Notes for Python 3.9
Unfortunately I use features that newly git introduced in [Python 3.10](https://docs.python.org/3/library/types.html#types.UnionType).
So unfortunately you **CAN'T** run this programm with python 3.9. [#10][i10]
### Notes for WSL
If you choose to run it in WSL, make sure ` ~/.local/bin` is added to your `$PATH` [#2][i2]
@ -331,5 +336,6 @@ To get the Lyrics, I scrape them, and put those in the USLT ID3 Tags of for exam
For the lyrics source the page [https://genius.com/](https://genius.com/) is easily sufficient. It has most songs. Some songs are not present though, but that is fine, because the lyrics are optional anyways.
[i10]: https://github.com/HeIIow2/music-downloader/issues/10
[i2]: https://github.com/HeIIow2/music-downloader/issues/2
[mb]: https://musicbrainz.org/

View File

@ -16,6 +16,9 @@ from music_kraken.tagging import (
import music_kraken.database.new_database as db
import datetime
import pycountry
def div(msg: str = ""):
print("-" * 50 + msg + "-" * 50)
@ -39,7 +42,10 @@ feature_artist = Artist(
)
album_input = Album(
title="One Final Action"
title="One Final Action",
date=datetime.date(1986, 3, 1),
language=pycountry.languages.get(alpha_2="en"),
label="cum productions"
)
album_input.artists = [
main_artist,
@ -62,7 +68,7 @@ song_input = Song(
],
album=album_input,
main_artist_list=[main_artist],
feature_artist_list=[feature_artist]
feature_artist_list=[feature_artist],
)
other_song = Song(

View File

@ -3,6 +3,8 @@ import os
import logging
from typing import List, Tuple
from pkg_resources import resource_string
import datetime
import pycountry
from .objects.parents import Reference
from .objects.source import Source
@ -40,12 +42,12 @@ FROM Lyrics
WHERE {where};
"""
ALBUM_QUERY_UNJOINED = """
SELECT Album.id AS album_id, title, copyright, album_status, language, year, date, country, barcode, albumsort, is_split
SELECT Album.id AS album_id, title, label, album_status, language, date, country, barcode, albumsort, is_split
FROM Album
WHERE {where};
"""
ALBUM_QUERY_JOINED = """
SELECT a.id AS album_id, a.title, a.copyright, a.album_status, a.language, a.year, a.date, a.country, a.barcode, a.albumsort, a.is_split
SELECT a.id AS album_id, a.title, a.label, a.album_status, a.language, a.date, a.country, a.barcode, a.albumsort, a.is_split
FROM Song
INNER JOIN Album a ON Song.album_id=a.id
WHERE {where};
@ -131,16 +133,15 @@ class Database:
def push_album(self, album: Album):
table = "Album"
query = f"INSERT OR REPLACE INTO {table} (id, title, copyright, album_status, language, year, date, country, barcode, albumsort, is_split) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
query = f"INSERT OR REPLACE INTO {table} (id, title, label, album_status, language, date, country, barcode, albumsort, is_split) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
values = (
album.id,
album.title,
album.copyright,
album.label,
album.album_status,
album.language,
album.year,
album.date,
album.iso_639_2_language,
album.date.strftime("%Y-%m-%d"),
album.country,
album.barcode,
album.albumsort,
@ -541,11 +542,10 @@ class Database:
album_obj = Album(
id_=album_id,
title=album_result['title'],
copyright_=album_result['copyright'],
label=album_result['label'],
album_status=album_result['album_status'],
language=album_result['language'],
year=album_result['year'],
date=album_result['date'],
language=pycountry.languages.get(alpha_3=album_result['language']),
date=datetime.datetime.strptime(album_result['date'], "%Y-%m-%d").date(),
country=album_result['country'],
barcode=album_result['barcode'],
is_split=album_result['is_split'],

View File

@ -1,6 +1,7 @@
from enum import Enum
from typing import List, Dict, Tuple
from mutagen import id3
import datetime
from .parents import (
ID3Metadata
@ -10,6 +11,9 @@ from .parents import (
class Mapping(Enum):
"""
These frames belong to the id3 standart
https://web.archive.org/web/20220830091059/https://id3.org/id3v2.4.0-frames
https://id3lib.sourceforge.net/id3/id3v2com-00.html
https://mutagen-specs.readthedocs.io/en/latest/id3/id3v2.4.0-frames.html
"""
# Textframes
TITLE = "TIT2"
@ -37,7 +41,7 @@ class Mapping(Enum):
LYRICIST = "TEXT"
WRITER = "TEXT"
ARTIST = "TPE1"
LANGUAGE = "TLAN"
LANGUAGE = "TLAN" # https://en.wikipedia.org/wiki/ISO_639-2
ITUNESCOMPILATION = "TCMP"
REMIXED_BY = "TPE4"
RADIO_STATION_OWNER = "TRSO"
@ -58,6 +62,7 @@ class Mapping(Enum):
ALBUM = "TALB"
ALBUMSORTORDER = "TSOA"
ALBUMARTISTSORTORDER = "TSO2"
TAGGING_TIME = "TDTG"
SOURCE_WEBPAGE_URL = "WOAS"
FILE_WEBPAGE_URL = "WOAF"
@ -93,6 +98,91 @@ class Mapping(Enum):
return cls.get_url_instance(key, value)
class ID3Timestamp(datetime.datetime):
def __init__(
self,
year: int = None,
month: int = None,
day: int = None,
hour: int = None,
minute: int = None,
second: int = None,
microsecond=0,
tzinfo=None,
*,
fold=0
):
self.has_year = year is not None
self.has_month = month is not None
self.has_day = day is not None
self.has_hour = hour is not None
self.has_minute = minute is not None
self.has_second = second is not None
self.has_microsecond = microsecond is not None
if not self.has_year:
year = 1
if not self.has_month:
month = 1
if not self.has_day:
day = 1
super().__init__(
year=year,
month=month,
day=day,
hour=hour,
minute=minute,
second=second,
microsecond=microsecond,
tzinfo=tzinfo,
fold=fold
)
def get_timestamp(self) -> str:
"""
https://mutagen-specs.readthedocs.io/en/latest/id3/id3v2.4.0-structure.html
The timestamp fields are based on a subset of ISO 8601. When being as precise as possible the format of a
time string is
- yyyy-MM-ddTHH:mm:ss
- (year[%Y], -, month[%m], -, day[%d], T, hour (out of 24)[%H], :, minutes[%M], :, seconds[%S])
- %Y-%m-%dT%H:%M:%S
but the precision may be reduced by removing as many time indicators as wanted. Hence valid timestamps are
- yyyy
- yyyy-MM
- yyyy-MM-dd
- yyyy-MM-ddTHH
- yyyy-MM-ddTHH:mm
- yyyy-MM-ddTHH:mm:ss
All time stamps are UTC. For durations, use the slash character as described in 8601,
and for multiple non-contiguous dates, use multiple strings, if allowed by the frame definition.
:return timestamp: as timestamp in the format of the id3 time as above described
"""
if self.has_year and self.has_month and self.has_day and self.has_hour and self.has_minute and self.has_second:
return self.strftime("%Y-%m-%dT%H:%M:%S")
if self.has_year and self.has_month and self.has_day and self.has_hour and self.has_minute:
return self.strftime("%Y-%m-%dT%H:%M")
if self.has_year and self.has_month and self.has_day and self.has_hour:
return self.strftime("%Y-%m-%dT%H")
if self.has_year and self.has_month and self.has_day:
return self.strftime("%Y-%m-%d")
if self.has_year and self.has_month:
return self.strftime("%Y-%m")
if self.has_year:
return self.strftime("%Y")
return ""
def __str__(self) -> str:
return self.timestamp
def __repr__(self) -> str:
return self.timestamp
timestamp: str = property(fget=get_timestamp)
class Metadata:
"""
Shall only be read or edited via the Song object.

View File

@ -1,6 +1,7 @@
import os
from typing import List, Tuple, Dict
from mutagen.easyid3 import EasyID3
import datetime
import pycountry
from .metadata import (
Mapping as ID3_MAPPING,
@ -278,11 +279,10 @@ class Album(DatabaseObject, ID3Metadata):
self,
id_: str = None,
title: str = None,
copyright_: str = None,
label: str = None,
album_status: str = None,
language: str = None,
year: str = None,
date: str = None,
language: pycountry.Languages = None,
date: datetime.date = None,
country: str = None,
barcode: str = None,
is_split: bool = False,
@ -291,20 +291,10 @@ class Album(DatabaseObject, ID3Metadata):
) -> None:
DatabaseObject.__init__(self, id_=id_, dynamic=dynamic)
self.title: str = title
self.copyright: str = copyright_
self.album_status: str = album_status
"""
TODO
MAKE SURE THIS IS IN THE CORRECT FORMAT
"""
self.language: str = language
"""
TODO
only store the date in a python date object and derive the
year from it
"""
self.year: str = year
self.date: str = date
self.label = label
self.language: pycountry.Languages = language
self.date: datetime.date = date
self.country: str = country
"""
TODO
@ -344,10 +334,25 @@ class Album(DatabaseObject, ID3Metadata):
return {
ID3_MAPPING.ALBUM: [self.title],
ID3_MAPPING.COPYRIGHT: [self.copyright],
ID3_MAPPING.LANGUAGE: [self.language],
ID3_MAPPING.LANGUAGE: [self.iso_639_2_language],
ID3_MAPPING.ALBUM_ARTIST: [a.name for a in self.artists]
}
def get_copyright(self) -> str:
if self.date.year == 1 or self.label is None:
return None
return f"{self.date.year} {self.label}"
def get_iso_639_2_lang(self) -> str:
if self.language is None:
return None
return self.language.alpha_3
copyright = property(fget=get_copyright)
iso_639_2_language = property(fget=get_iso_639_2_lang)
"""

View File

@ -26,10 +26,9 @@ CREATE TABLE Album
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
title TEXT,
copyright TEXT,
label TEXT,
album_status TEXT,
language TEXT,
year TEXT,
date TEXT,
country TEXT,
barcode TEXT,

Binary file not shown.