STARTED IMPLEMENTING DB
STARTED IMPLEMENTING DB
This commit is contained in:
parent
021f8a6905
commit
5a699c3937
@ -24,13 +24,13 @@ Total : 43 files, 2560 codes, 558 comments, 774 blanks, all 3892 lines
|
|||||||
| [src/music_kraken/audio_source/sources/source.py](/src/music_kraken/not_used_anymore/sources/source.py) | Python | 11 | 5 | 8 | 24 |
|
| [src/music_kraken/audio_source/sources/source.py](/src/music_kraken/not_used_anymore/sources/source.py) | Python | 11 | 5 | 8 | 24 |
|
||||||
| [src/music_kraken/audio_source/sources/youtube.py](/src/music_kraken/not_used_anymore/sources/youtube.py) | Python | 71 | 4 | 24 | 99 |
|
| [src/music_kraken/audio_source/sources/youtube.py](/src/music_kraken/not_used_anymore/sources/youtube.py) | Python | 71 | 4 | 24 | 99 |
|
||||||
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 11 | 1 | 4 | 16 |
|
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 11 | 1 | 4 | 16 |
|
||||||
| [src/music_kraken/database/database.py](/src/music_kraken/database/database.py) | Python | 191 | 102 | 45 | 338 |
|
| [src/music_kraken/database/database.py](/src/music_kraken/database/old_database.py) | Python | 191 | 102 | 45 | 338 |
|
||||||
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | 40 | 5 | 11 | 56 |
|
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | 40 | 5 | 11 | 56 |
|
||||||
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/database.py) | Python | 172 | 78 | 55 | 305 |
|
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/old_database.py) | Python | 172 | 78 | 55 | 305 |
|
||||||
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/database/objects/__init__.py) | Python | 11 | 0 | 4 | 15 |
|
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/objects/__init__.py) | Python | 11 | 0 | 4 | 15 |
|
||||||
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/database/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
||||||
| [src/music_kraken/database/objects/database_object.py](/src/music_kraken/database/objects/database_object.py) | Python | 21 | 5 | 11 | 37 |
|
| [src/music_kraken/database/objects/database_object.py](/src/music_kraken/objects/database_object.py) | Python | 21 | 5 | 11 | 37 |
|
||||||
| [src/music_kraken/database/objects/song.py](/src/music_kraken/database/objects/song.py) | Python | 179 | 52 | 60 | 291 |
|
| [src/music_kraken/database/objects/song.py](/src/music_kraken/objects/song.py) | Python | 179 | 52 | 60 | 291 |
|
||||||
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | 125 | 20 | 45 | 190 |
|
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | 125 | 20 | 45 | 190 |
|
||||||
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 10 | 0 | 7 | 17 |
|
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 10 | 0 | 7 | 17 |
|
||||||
| [src/music_kraken/lyrics/__init__.py](/src/music_kraken/lyrics/__init__.py) | Python | 0 | 0 | 1 | 1 |
|
| [src/music_kraken/lyrics/__init__.py](/src/music_kraken/lyrics/__init__.py) | Python | 0 | 0 | 1 | 1 |
|
||||||
|
@ -16,14 +16,14 @@ Total : 20 files, 700 codes, 165 comments, 162 blanks, all 1027 lines
|
|||||||
| [src/music_kraken/audio_source/fetch_source.py](/src/music_kraken/not_used_anymore/fetch_source.py) | Python | 0 | 0 | -1 | -1 |
|
| [src/music_kraken/audio_source/fetch_source.py](/src/music_kraken/not_used_anymore/fetch_source.py) | Python | 0 | 0 | -1 | -1 |
|
||||||
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | -4 | 1 | 1 | -2 |
|
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | -4 | 1 | 1 | -2 |
|
||||||
| [src/music_kraken/database/artist.py](/src/music_kraken/database/artist.py) | Python | -11 | 0 | -5 | -16 |
|
| [src/music_kraken/database/artist.py](/src/music_kraken/database/artist.py) | Python | -11 | 0 | -5 | -16 |
|
||||||
| [src/music_kraken/database/database.py](/src/music_kraken/database/database.py) | Python | 25 | 22 | 4 | 51 |
|
| [src/music_kraken/database/database.py](/src/music_kraken/database/old_database.py) | Python | 25 | 22 | 4 | 51 |
|
||||||
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | 40 | 5 | 11 | 56 |
|
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | 40 | 5 | 11 | 56 |
|
||||||
| [src/music_kraken/database/metadata.py](/src/music_kraken/database/metadata.py) | Python | -13 | 0 | -5 | -18 |
|
| [src/music_kraken/database/metadata.py](/src/music_kraken/database/metadata.py) | Python | -13 | 0 | -5 | -18 |
|
||||||
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/database.py) | Python | 172 | 78 | 55 | 305 |
|
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/old_database.py) | Python | 172 | 78 | 55 | 305 |
|
||||||
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/database/objects/__init__.py) | Python | 11 | 0 | 4 | 15 |
|
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/objects/__init__.py) | Python | 11 | 0 | 4 | 15 |
|
||||||
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/database/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
||||||
| [src/music_kraken/database/objects/database_object.py](/src/music_kraken/database/objects/database_object.py) | Python | 21 | 5 | 11 | 37 |
|
| [src/music_kraken/database/objects/database_object.py](/src/music_kraken/objects/database_object.py) | Python | 21 | 5 | 11 | 37 |
|
||||||
| [src/music_kraken/database/objects/song.py](/src/music_kraken/database/objects/song.py) | Python | 179 | 52 | 60 | 291 |
|
| [src/music_kraken/database/objects/song.py](/src/music_kraken/objects/song.py) | Python | 179 | 52 | 60 | 291 |
|
||||||
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | 39 | -5 | 12 | 46 |
|
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | 39 | -5 | 12 | 46 |
|
||||||
| [src/music_kraken/database/source.py](/src/music_kraken/database/source.py) | Python | -5 | 0 | -2 | -7 |
|
| [src/music_kraken/database/source.py](/src/music_kraken/database/source.py) | Python | -5 | 0 | -2 | -7 |
|
||||||
| [src/music_kraken/database/target.py](/src/music_kraken/database/target.py) | Python | -22 | 0 | -9 | -31 |
|
| [src/music_kraken/database/target.py](/src/music_kraken/database/target.py) | Python | -22 | 0 | -9 | -31 |
|
||||||
|
@ -24,13 +24,13 @@ Total : 45 files, 2886 codes, 594 comments, 854 blanks, all 4334 lines
|
|||||||
| [src/music_kraken/audio_source/sources/source.py](/src/music_kraken/not_used_anymore/sources/source.py) | Python | 11 | 5 | 8 | 24 |
|
| [src/music_kraken/audio_source/sources/source.py](/src/music_kraken/not_used_anymore/sources/source.py) | Python | 11 | 5 | 8 | 24 |
|
||||||
| [src/music_kraken/audio_source/sources/youtube.py](/src/music_kraken/not_used_anymore/sources/youtube.py) | Python | 71 | 4 | 24 | 99 |
|
| [src/music_kraken/audio_source/sources/youtube.py](/src/music_kraken/not_used_anymore/sources/youtube.py) | Python | 71 | 4 | 24 | 99 |
|
||||||
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 11 | 1 | 4 | 16 |
|
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 11 | 1 | 4 | 16 |
|
||||||
| [src/music_kraken/database/database.py](/src/music_kraken/database/database.py) | Python | 191 | 102 | 45 | 338 |
|
| [src/music_kraken/database/database.py](/src/music_kraken/database/old_database.py) | Python | 191 | 102 | 45 | 338 |
|
||||||
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | 40 | 5 | 11 | 56 |
|
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | 40 | 5 | 11 | 56 |
|
||||||
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/database.py) | Python | 327 | 98 | 89 | 514 |
|
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/old_database.py) | Python | 327 | 98 | 89 | 514 |
|
||||||
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/database/objects/__init__.py) | Python | 10 | 0 | 3 | 13 |
|
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/objects/__init__.py) | Python | 10 | 0 | 3 | 13 |
|
||||||
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/database/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
||||||
| [src/music_kraken/database/objects/database_object.py](/src/music_kraken/database/objects/database_object.py) | Python | 28 | 7 | 13 | 48 |
|
| [src/music_kraken/database/objects/database_object.py](/src/music_kraken/objects/database_object.py) | Python | 28 | 7 | 13 | 48 |
|
||||||
| [src/music_kraken/database/objects/song.py](/src/music_kraken/database/objects/song.py) | Python | 255 | 61 | 86 | 402 |
|
| [src/music_kraken/database/objects/song.py](/src/music_kraken/objects/song.py) | Python | 255 | 61 | 86 | 402 |
|
||||||
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | 125 | 20 | 45 | 190 |
|
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | 125 | 20 | 45 | 190 |
|
||||||
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 12 | 0 | 8 | 20 |
|
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 12 | 0 | 8 | 20 |
|
||||||
| [src/music_kraken/lyrics/__init__.py](/src/music_kraken/lyrics/__init__.py) | Python | 0 | 0 | 1 | 1 |
|
| [src/music_kraken/lyrics/__init__.py](/src/music_kraken/lyrics/__init__.py) | Python | 0 | 0 | 1 | 1 |
|
||||||
|
@ -12,10 +12,10 @@ Total : 10 files, 326 codes, 36 comments, 80 blanks, all 442 lines
|
|||||||
| filename | language | code | comment | blank | total |
|
| filename | language | code | comment | blank | total |
|
||||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||||
| [src/goof.py](/src/goof.py) | Python | 30 | -1 | 7 | 36 |
|
| [src/goof.py](/src/goof.py) | Python | 30 | -1 | 7 | 36 |
|
||||||
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/database.py) | Python | 155 | 20 | 34 | 209 |
|
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/old_database.py) | Python | 155 | 20 | 34 | 209 |
|
||||||
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/database/objects/__init__.py) | Python | -1 | 0 | -1 | -2 |
|
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/objects/__init__.py) | Python | -1 | 0 | -1 | -2 |
|
||||||
| [src/music_kraken/database/objects/database_object.py](/src/music_kraken/database/objects/database_object.py) | Python | 7 | 2 | 2 | 11 |
|
| [src/music_kraken/database/objects/database_object.py](/src/music_kraken/objects/database_object.py) | Python | 7 | 2 | 2 | 11 |
|
||||||
| [src/music_kraken/database/objects/song.py](/src/music_kraken/database/objects/song.py) | Python | 76 | 9 | 26 | 111 |
|
| [src/music_kraken/database/objects/song.py](/src/music_kraken/objects/song.py) | Python | 76 | 9 | 26 | 111 |
|
||||||
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 2 | 0 | 1 | 3 |
|
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 2 | 0 | 1 | 3 |
|
||||||
| [src/music_kraken/metadata/sources/__init__.py](/src/music_kraken/not_used_anymore/metadata/sources/__init__.py) | Python | 3 | 0 | 2 | 5 |
|
| [src/music_kraken/metadata/sources/__init__.py](/src/music_kraken/not_used_anymore/metadata/sources/__init__.py) | Python | 3 | 0 | 2 | 5 |
|
||||||
| [src/music_kraken/metadata/sources/musicbrainz.py](/src/music_kraken/not_used_anymore/metadata/sources/musicbrainz.py) | Python | 42 | 6 | 9 | 57 |
|
| [src/music_kraken/metadata/sources/musicbrainz.py](/src/music_kraken/not_used_anymore/metadata/sources/musicbrainz.py) | Python | 42 | 6 | 9 | 57 |
|
||||||
|
@ -24,15 +24,15 @@ Total : 49 files, 3402 codes, 663 comments, 973 blanks, all 5038 lines
|
|||||||
| [src/music_kraken/audio_source/sources/source.py](/src/music_kraken/not_used_anymore/sources/source.py) | Python | 11 | 5 | 8 | 24 |
|
| [src/music_kraken/audio_source/sources/source.py](/src/music_kraken/not_used_anymore/sources/source.py) | Python | 11 | 5 | 8 | 24 |
|
||||||
| [src/music_kraken/audio_source/sources/youtube.py](/src/music_kraken/not_used_anymore/sources/youtube.py) | Python | 71 | 4 | 24 | 99 |
|
| [src/music_kraken/audio_source/sources/youtube.py](/src/music_kraken/not_used_anymore/sources/youtube.py) | Python | 71 | 4 | 24 | 99 |
|
||||||
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 12 | 1 | 4 | 17 |
|
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 12 | 1 | 4 | 17 |
|
||||||
| [src/music_kraken/database/database.py](/src/music_kraken/database/database.py) | Python | 191 | 102 | 45 | 338 |
|
| [src/music_kraken/database/database.py](/src/music_kraken/database/old_database.py) | Python | 191 | 102 | 45 | 338 |
|
||||||
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | 40 | 5 | 11 | 56 |
|
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | 40 | 5 | 11 | 56 |
|
||||||
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/database.py) | Python | 401 | 109 | 107 | 617 |
|
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/old_database.py) | Python | 401 | 109 | 107 | 617 |
|
||||||
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/database/objects/__init__.py) | Python | 14 | 0 | 4 | 18 |
|
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/objects/__init__.py) | Python | 14 | 0 | 4 | 18 |
|
||||||
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/database/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
||||||
| [src/music_kraken/database/objects/metadata.py](/src/music_kraken/database/objects/metadata.py) | Python | 245 | 52 | 50 | 347 |
|
| [src/music_kraken/database/objects/metadata.py](/src/music_kraken/objects/metadata.py) | Python | 245 | 52 | 50 | 347 |
|
||||||
| [src/music_kraken/database/objects/parents.py](/src/music_kraken/database/objects/parents.py) | Python | 46 | 8 | 23 | 77 |
|
| [src/music_kraken/database/objects/parents.py](/src/music_kraken/objects/parents.py) | Python | 46 | 8 | 23 | 77 |
|
||||||
| [src/music_kraken/database/objects/song.py](/src/music_kraken/database/objects/song.py) | Python | 258 | 52 | 76 | 386 |
|
| [src/music_kraken/database/objects/song.py](/src/music_kraken/objects/song.py) | Python | 258 | 52 | 76 | 386 |
|
||||||
| [src/music_kraken/database/objects/source.py](/src/music_kraken/database/objects/source.py) | Python | 46 | 7 | 13 | 66 |
|
| [src/music_kraken/database/objects/source.py](/src/music_kraken/objects/source.py) | Python | 46 | 7 | 13 | 66 |
|
||||||
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | 125 | 20 | 45 | 190 |
|
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | 125 | 20 | 45 | 190 |
|
||||||
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 12 | 0 | 8 | 20 |
|
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 12 | 0 | 8 | 20 |
|
||||||
| [src/music_kraken/lyrics/__init__.py](/src/music_kraken/lyrics/__init__.py) | Python | 0 | 0 | 1 | 1 |
|
| [src/music_kraken/lyrics/__init__.py](/src/music_kraken/lyrics/__init__.py) | Python | 0 | 0 | 1 | 1 |
|
||||||
|
@ -14,13 +14,13 @@ Total : 16 files, 516 codes, 69 comments, 119 blanks, all 704 lines
|
|||||||
| [src/goof.py](/src/goof.py) | Python | 42 | 2 | 10 | 54 |
|
| [src/goof.py](/src/goof.py) | Python | 42 | 2 | 10 | 54 |
|
||||||
| [src/music_kraken/__init__.py](/src/music_kraken/__init__.py) | Python | 1 | 0 | 0 | 1 |
|
| [src/music_kraken/__init__.py](/src/music_kraken/__init__.py) | Python | 1 | 0 | 0 | 1 |
|
||||||
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 1 | 0 | 0 | 1 |
|
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 1 | 0 | 0 | 1 |
|
||||||
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/database.py) | Python | 74 | 11 | 18 | 103 |
|
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/old_database.py) | Python | 74 | 11 | 18 | 103 |
|
||||||
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/database/objects/__init__.py) | Python | 4 | 0 | 1 | 5 |
|
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/objects/__init__.py) | Python | 4 | 0 | 1 | 5 |
|
||||||
| [src/music_kraken/database/objects/database_object.py](/src/music_kraken/database/objects/database_object.py) | Python | -28 | -7 | -13 | -48 |
|
| [src/music_kraken/database/objects/database_object.py](/src/music_kraken/objects/database_object.py) | Python | -28 | -7 | -13 | -48 |
|
||||||
| [src/music_kraken/database/objects/metadata.py](/src/music_kraken/database/objects/metadata.py) | Python | 245 | 52 | 50 | 347 |
|
| [src/music_kraken/database/objects/metadata.py](/src/music_kraken/objects/metadata.py) | Python | 245 | 52 | 50 | 347 |
|
||||||
| [src/music_kraken/database/objects/parents.py](/src/music_kraken/database/objects/parents.py) | Python | 46 | 8 | 23 | 77 |
|
| [src/music_kraken/database/objects/parents.py](/src/music_kraken/objects/parents.py) | Python | 46 | 8 | 23 | 77 |
|
||||||
| [src/music_kraken/database/objects/song.py](/src/music_kraken/database/objects/song.py) | Python | 3 | -9 | -10 | -16 |
|
| [src/music_kraken/database/objects/song.py](/src/music_kraken/objects/song.py) | Python | 3 | -9 | -10 | -16 |
|
||||||
| [src/music_kraken/database/objects/source.py](/src/music_kraken/database/objects/source.py) | Python | 46 | 7 | 13 | 66 |
|
| [src/music_kraken/database/objects/source.py](/src/music_kraken/objects/source.py) | Python | 46 | 7 | 13 | 66 |
|
||||||
| [src/music_kraken/static_files/new_db.sql](/src/music_kraken/static_files/new_db.sql) | SQLite | 1 | 0 | 0 | 1 |
|
| [src/music_kraken/static_files/new_db.sql](/src/music_kraken/static_files/new_db.sql) | SQLite | 1 | 0 | 0 | 1 |
|
||||||
| [src/music_kraken/tagging/__init__.py](/src/music_kraken/tagging/__init__.py) | Python | 8 | 0 | 1 | 9 |
|
| [src/music_kraken/tagging/__init__.py](/src/music_kraken/tagging/__init__.py) | Python | 8 | 0 | 1 | 9 |
|
||||||
| [src/music_kraken/tagging/id3.py](/src/music_kraken/tagging/id3.py) | Python | 51 | 4 | 20 | 75 |
|
| [src/music_kraken/tagging/id3.py](/src/music_kraken/tagging/id3.py) | Python | 51 | 4 | 20 | 75 |
|
||||||
|
@ -24,15 +24,15 @@ Total : 49 files, 3404 codes, 664 comments, 974 blanks, all 5042 lines
|
|||||||
| [src/music_kraken/audio_source/sources/source.py](/src/music_kraken/not_used_anymore/sources/source.py) | Python | 11 | 5 | 8 | 24 |
|
| [src/music_kraken/audio_source/sources/source.py](/src/music_kraken/not_used_anymore/sources/source.py) | Python | 11 | 5 | 8 | 24 |
|
||||||
| [src/music_kraken/audio_source/sources/youtube.py](/src/music_kraken/not_used_anymore/sources/youtube.py) | Python | 71 | 4 | 24 | 99 |
|
| [src/music_kraken/audio_source/sources/youtube.py](/src/music_kraken/not_used_anymore/sources/youtube.py) | Python | 71 | 4 | 24 | 99 |
|
||||||
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 12 | 1 | 4 | 17 |
|
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 12 | 1 | 4 | 17 |
|
||||||
| [src/music_kraken/database/database.py](/src/music_kraken/database/database.py) | Python | 191 | 102 | 45 | 338 |
|
| [src/music_kraken/database/database.py](/src/music_kraken/database/old_database.py) | Python | 191 | 102 | 45 | 338 |
|
||||||
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | 40 | 5 | 11 | 56 |
|
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | 40 | 5 | 11 | 56 |
|
||||||
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/database.py) | Python | 402 | 110 | 107 | 619 |
|
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/old_database.py) | Python | 402 | 110 | 107 | 619 |
|
||||||
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/database/objects/__init__.py) | Python | 15 | 0 | 5 | 20 |
|
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/objects/__init__.py) | Python | 15 | 0 | 5 | 20 |
|
||||||
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/database/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
||||||
| [src/music_kraken/database/objects/metadata.py](/src/music_kraken/database/objects/metadata.py) | Python | 245 | 52 | 50 | 347 |
|
| [src/music_kraken/database/objects/metadata.py](/src/music_kraken/objects/metadata.py) | Python | 245 | 52 | 50 | 347 |
|
||||||
| [src/music_kraken/database/objects/parents.py](/src/music_kraken/database/objects/parents.py) | Python | 46 | 8 | 23 | 77 |
|
| [src/music_kraken/database/objects/parents.py](/src/music_kraken/objects/parents.py) | Python | 46 | 8 | 23 | 77 |
|
||||||
| [src/music_kraken/database/objects/song.py](/src/music_kraken/database/objects/song.py) | Python | 258 | 52 | 76 | 386 |
|
| [src/music_kraken/database/objects/song.py](/src/music_kraken/objects/song.py) | Python | 258 | 52 | 76 | 386 |
|
||||||
| [src/music_kraken/database/objects/source.py](/src/music_kraken/database/objects/source.py) | Python | 46 | 7 | 13 | 66 |
|
| [src/music_kraken/database/objects/source.py](/src/music_kraken/objects/source.py) | Python | 46 | 7 | 13 | 66 |
|
||||||
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | 125 | 20 | 45 | 190 |
|
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | 125 | 20 | 45 | 190 |
|
||||||
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 12 | 0 | 8 | 20 |
|
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 12 | 0 | 8 | 20 |
|
||||||
| [src/music_kraken/lyrics/__init__.py](/src/music_kraken/lyrics/__init__.py) | Python | 0 | 0 | 1 | 1 |
|
| [src/music_kraken/lyrics/__init__.py](/src/music_kraken/lyrics/__init__.py) | Python | 0 | 0 | 1 | 1 |
|
||||||
|
@ -11,7 +11,7 @@ Total : 2 files, 2 codes, 1 comments, 1 blanks, all 4 lines
|
|||||||
## Files
|
## Files
|
||||||
| filename | language | code | comment | blank | total |
|
| filename | language | code | comment | blank | total |
|
||||||
| :--- | :--- | ---: | ---: | ---: | ---: |
|
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||||
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/database.py) | Python | 1 | 1 | 0 | 2 |
|
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/old_database.py) | Python | 1 | 1 | 0 | 2 |
|
||||||
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/database/objects/__init__.py) | Python | 1 | 0 | 1 | 2 |
|
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/objects/__init__.py) | Python | 1 | 0 | 1 | 2 |
|
||||||
|
|
||||||
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
@ -17,14 +17,14 @@ Total : 50 files, 3575 codes, 775 comments, 1028 blanks, all 5378 lines
|
|||||||
| [src/music_kraken/__init__.py](/src/music_kraken/__init__.py) | Python | 63 | 26 | 33 | 122 |
|
| [src/music_kraken/__init__.py](/src/music_kraken/__init__.py) | Python | 63 | 26 | 33 | 122 |
|
||||||
| [src/music_kraken/__main__.py](/src/music_kraken/__main__.py) | Python | 3 | 2 | 3 | 8 |
|
| [src/music_kraken/__main__.py](/src/music_kraken/__main__.py) | Python | 3 | 2 | 3 | 8 |
|
||||||
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 18 | 0 | 5 | 23 |
|
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 18 | 0 | 5 | 23 |
|
||||||
| [src/music_kraken/database/database.py](/src/music_kraken/database/database.py) | Python | 429 | 112 | 111 | 652 |
|
| [src/music_kraken/database/database.py](/src/music_kraken/database/old_database.py) | Python | 429 | 112 | 111 | 652 |
|
||||||
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/database/objects/__init__.py) | Python | 20 | 0 | 7 | 27 |
|
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/objects/__init__.py) | Python | 20 | 0 | 7 | 27 |
|
||||||
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/database/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
| [src/music_kraken/database/objects/artist.py](/src/music_kraken/objects/artist.py) | Python | 18 | 0 | 5 | 23 |
|
||||||
| [src/music_kraken/database/objects/formatted_text.py](/src/music_kraken/database/objects/formatted_text.py) | Python | 48 | 57 | 16 | 121 |
|
| [src/music_kraken/database/objects/formatted_text.py](/src/music_kraken/objects/formatted_text.py) | Python | 48 | 57 | 16 | 121 |
|
||||||
| [src/music_kraken/database/objects/metadata.py](/src/music_kraken/database/objects/metadata.py) | Python | 251 | 68 | 61 | 380 |
|
| [src/music_kraken/database/objects/metadata.py](/src/music_kraken/objects/metadata.py) | Python | 251 | 68 | 61 | 380 |
|
||||||
| [src/music_kraken/database/objects/parents.py](/src/music_kraken/database/objects/parents.py) | Python | 40 | 8 | 19 | 67 |
|
| [src/music_kraken/database/objects/parents.py](/src/music_kraken/objects/parents.py) | Python | 40 | 8 | 19 | 67 |
|
||||||
| [src/music_kraken/database/objects/song.py](/src/music_kraken/database/objects/song.py) | Python | 323 | 64 | 85 | 472 |
|
| [src/music_kraken/database/objects/song.py](/src/music_kraken/objects/song.py) | Python | 323 | 64 | 85 | 472 |
|
||||||
| [src/music_kraken/database/objects/source.py](/src/music_kraken/database/objects/source.py) | Python | 116 | 38 | 41 | 195 |
|
| [src/music_kraken/database/objects/source.py](/src/music_kraken/objects/source.py) | Python | 116 | 38 | 41 | 195 |
|
||||||
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 12 | 0 | 8 | 20 |
|
| [src/music_kraken/database/temp_database.py](/src/music_kraken/database/temp_database.py) | Python | 12 | 0 | 8 | 20 |
|
||||||
| [src/music_kraken/not_used_anymore/__init__.py](/src/music_kraken/not_used_anymore/__init__.py) | Python | 0 | 0 | 3 | 3 |
|
| [src/music_kraken/not_used_anymore/__init__.py](/src/music_kraken/not_used_anymore/__init__.py) | Python | 0 | 0 | 3 | 3 |
|
||||||
| [src/music_kraken/not_used_anymore/fetch_audio.py](/src/music_kraken/not_used_anymore/fetch_audio.py) | Python | 75 | 12 | 20 | 107 |
|
| [src/music_kraken/not_used_anymore/fetch_audio.py](/src/music_kraken/not_used_anymore/fetch_audio.py) | Python | 75 | 12 | 20 | 107 |
|
||||||
|
@ -24,15 +24,15 @@ Total : 55 files, 171 codes, 111 comments, 54 blanks, all 336 lines
|
|||||||
| [src/music_kraken/audio_source/sources/source.py](/src/music_kraken/audio_source/sources/source.py) | Python | -11 | -5 | -8 | -24 |
|
| [src/music_kraken/audio_source/sources/source.py](/src/music_kraken/audio_source/sources/source.py) | Python | -11 | -5 | -8 | -24 |
|
||||||
| [src/music_kraken/audio_source/sources/youtube.py](/src/music_kraken/audio_source/sources/youtube.py) | Python | -71 | -4 | -24 | -99 |
|
| [src/music_kraken/audio_source/sources/youtube.py](/src/music_kraken/audio_source/sources/youtube.py) | Python | -71 | -4 | -24 | -99 |
|
||||||
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 6 | -1 | 1 | 6 |
|
| [src/music_kraken/database/__init__.py](/src/music_kraken/database/__init__.py) | Python | 6 | -1 | 1 | 6 |
|
||||||
| [src/music_kraken/database/database.py](/src/music_kraken/database/database.py) | Python | 238 | 10 | 66 | 314 |
|
| [src/music_kraken/database/database.py](/src/music_kraken/database/old_database.py) | Python | 238 | 10 | 66 | 314 |
|
||||||
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | -40 | -5 | -11 | -56 |
|
| [src/music_kraken/database/get_song.py](/src/music_kraken/database/get_song.py) | Python | -40 | -5 | -11 | -56 |
|
||||||
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/new_database.py) | Python | -402 | -110 | -107 | -619 |
|
| [src/music_kraken/database/new_database.py](/src/music_kraken/database/new_database.py) | Python | -402 | -110 | -107 | -619 |
|
||||||
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/database/objects/__init__.py) | Python | 5 | 0 | 2 | 7 |
|
| [src/music_kraken/database/objects/__init__.py](/src/music_kraken/objects/__init__.py) | Python | 5 | 0 | 2 | 7 |
|
||||||
| [src/music_kraken/database/objects/formatted_text.py](/src/music_kraken/database/objects/formatted_text.py) | Python | 48 | 57 | 16 | 121 |
|
| [src/music_kraken/database/objects/formatted_text.py](/src/music_kraken/objects/formatted_text.py) | Python | 48 | 57 | 16 | 121 |
|
||||||
| [src/music_kraken/database/objects/metadata.py](/src/music_kraken/database/objects/metadata.py) | Python | 6 | 16 | 11 | 33 |
|
| [src/music_kraken/database/objects/metadata.py](/src/music_kraken/objects/metadata.py) | Python | 6 | 16 | 11 | 33 |
|
||||||
| [src/music_kraken/database/objects/parents.py](/src/music_kraken/database/objects/parents.py) | Python | -6 | 0 | -4 | -10 |
|
| [src/music_kraken/database/objects/parents.py](/src/music_kraken/objects/parents.py) | Python | -6 | 0 | -4 | -10 |
|
||||||
| [src/music_kraken/database/objects/song.py](/src/music_kraken/database/objects/song.py) | Python | 65 | 12 | 9 | 86 |
|
| [src/music_kraken/database/objects/song.py](/src/music_kraken/objects/song.py) | Python | 65 | 12 | 9 | 86 |
|
||||||
| [src/music_kraken/database/objects/source.py](/src/music_kraken/database/objects/source.py) | Python | 70 | 31 | 28 | 129 |
|
| [src/music_kraken/database/objects/source.py](/src/music_kraken/objects/source.py) | Python | 70 | 31 | 28 | 129 |
|
||||||
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | -125 | -20 | -45 | -190 |
|
| [src/music_kraken/database/song.py](/src/music_kraken/database/song.py) | Python | -125 | -20 | -45 | -190 |
|
||||||
| [src/music_kraken/lyrics/__init__.py](/src/music_kraken/lyrics/__init__.py) | Python | 0 | 0 | -1 | -1 |
|
| [src/music_kraken/lyrics/__init__.py](/src/music_kraken/lyrics/__init__.py) | Python | 0 | 0 | -1 | -1 |
|
||||||
| [src/music_kraken/lyrics/genius.py](/src/music_kraken/lyrics/genius.py) | Python | -115 | -16 | -42 | -173 |
|
| [src/music_kraken/lyrics/genius.py](/src/music_kraken/lyrics/genius.py) | Python | -115 | -16 | -42 | -173 |
|
||||||
|
@ -6,3 +6,7 @@ pydub~=0.25.1
|
|||||||
youtube_dl
|
youtube_dl
|
||||||
beautifulsoup4~=4.11.1
|
beautifulsoup4~=4.11.1
|
||||||
pycountry~=22.3.5
|
pycountry~=22.3.5
|
||||||
|
python-dateutil~=2.8.2
|
||||||
|
pandoc~=2.3
|
||||||
|
peewee~=3.15.4
|
||||||
|
setuptools~=60.2.0
|
@ -17,7 +17,7 @@ from music_kraken.tagging import (
|
|||||||
write_many_metadata
|
write_many_metadata
|
||||||
)
|
)
|
||||||
|
|
||||||
import music_kraken.database.database as db
|
import music_kraken.database.old_database as db
|
||||||
|
|
||||||
import pycountry
|
import pycountry
|
||||||
import logging
|
import logging
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
from . import (
|
from . import (
|
||||||
temp_database,
|
temp_database,
|
||||||
objects,
|
old_database
|
||||||
database
|
|
||||||
)
|
)
|
||||||
|
from .. import objects
|
||||||
|
|
||||||
MusicObject = objects.MusicObject
|
MusicObject = objects.MusicObject
|
||||||
|
|
||||||
|
113
src/music_kraken/database/data_models.py
Normal file
113
src/music_kraken/database/data_models.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
from typing import List, Union, Type
|
||||||
|
from peewee import (
|
||||||
|
SqliteDatabase,
|
||||||
|
PostgresqlDatabase,
|
||||||
|
MySQLDatabase,
|
||||||
|
Model,
|
||||||
|
CharField,
|
||||||
|
IntegerField,
|
||||||
|
BooleanField,
|
||||||
|
ForeignKeyField,
|
||||||
|
TextField
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Album(Model):
|
||||||
|
"""A class representing an album in the music database."""
|
||||||
|
|
||||||
|
title: str = CharField()
|
||||||
|
label: str = CharField()
|
||||||
|
album_status: str = CharField()
|
||||||
|
language: str = CharField()
|
||||||
|
date: str = CharField()
|
||||||
|
date_format: str = CharField()
|
||||||
|
country: str = CharField()
|
||||||
|
barcode: str = CharField()
|
||||||
|
albumsort: int = IntegerField()
|
||||||
|
is_split: bool = BooleanField(default=False)
|
||||||
|
|
||||||
|
|
||||||
|
class Artist(Model):
|
||||||
|
"""A class representing an artist in the music database."""
|
||||||
|
|
||||||
|
name: str = CharField()
|
||||||
|
|
||||||
|
|
||||||
|
class Song(Model):
|
||||||
|
"""A class representing a song in the music database."""
|
||||||
|
|
||||||
|
name: str = CharField()
|
||||||
|
isrc: str = CharField()
|
||||||
|
length: int = IntegerField()
|
||||||
|
tracksort: int = IntegerField()
|
||||||
|
genre: str = CharField()
|
||||||
|
album: ForeignKeyField = ForeignKeyField(Album, backref='songs')
|
||||||
|
|
||||||
|
|
||||||
|
class Source(Model):
|
||||||
|
"""A class representing a source of a song in the music database."""
|
||||||
|
|
||||||
|
type: str = CharField()
|
||||||
|
src: str = CharField()
|
||||||
|
url: str = CharField()
|
||||||
|
|
||||||
|
content_type: str = CharField()
|
||||||
|
content_id: int = IntegerField()
|
||||||
|
content: ForeignKeyField = ForeignKeyField('self', backref='content_items', null=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def content_object(self) -> Union[Song, Album, Artist, None]:
|
||||||
|
"""Get the content associated with the source as an object."""
|
||||||
|
if self.content_type == 'Song':
|
||||||
|
return Song.get(Song.id == self.content_id)
|
||||||
|
elif self.content_type == 'Album':
|
||||||
|
return Album.get(Album.id == self.content_id)
|
||||||
|
elif self.content_type == 'Artist':
|
||||||
|
return Artist.get(Artist.id == self.content_id)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@content_object.setter
|
||||||
|
def content_object(self, value: Union[Song, Album, Artist]) -> None:
|
||||||
|
"""Set the content associated with the source as an object."""
|
||||||
|
self.content_type = value.__class__.__name__
|
||||||
|
self.content_id = value.id
|
||||||
|
|
||||||
|
|
||||||
|
class Target(Model):
|
||||||
|
"""A class representing a target of a song in the music database."""
|
||||||
|
|
||||||
|
file: str = CharField()
|
||||||
|
path: str = CharField()
|
||||||
|
song = ForeignKeyField(Song, backref='targets')
|
||||||
|
|
||||||
|
|
||||||
|
class Lyrics(Model):
|
||||||
|
"""A class representing lyrics of a song in the music database."""
|
||||||
|
|
||||||
|
text: str = TextField()
|
||||||
|
language: str = CharField()
|
||||||
|
song = ForeignKeyField(Song, backref='lyrics')
|
||||||
|
|
||||||
|
|
||||||
|
class SongArtist(Model):
|
||||||
|
"""A class representing the relationship between a song and an artist."""
|
||||||
|
|
||||||
|
song: ForeignKeyField = ForeignKeyField(Song, backref='song_artists')
|
||||||
|
artist: ForeignKeyField = ForeignKeyField(Artist, backref='song_artists')
|
||||||
|
is_feature: bool = BooleanField(default=False)
|
||||||
|
|
||||||
|
|
||||||
|
class AlbumArtist(Model):
|
||||||
|
"""A class representing the relationship between an album and an artist."""
|
||||||
|
|
||||||
|
album: ForeignKeyField = ForeignKeyField(Album, backref='album_artists')
|
||||||
|
artist: ForeignKeyField = ForeignKeyField(Artist, backref='album_artists')
|
||||||
|
|
||||||
|
|
||||||
|
class Models:
|
||||||
|
def __init__(self, database: Union[SqliteDatabase, PostgresqlDatabase, MySQLDatabase]):
|
||||||
|
self.database: Union[SqliteDatabase, PostgresqlDatabase, MySQLDatabase] = database
|
||||||
|
|
||||||
|
def get_obj(self, _model: Model):
|
||||||
|
_model._meta.database = self.database
|
@ -1,702 +1,79 @@
|
|||||||
import sqlite3
|
from typing import Optional, Union
|
||||||
import os
|
from enum import Enum
|
||||||
import logging
|
from peewee import (
|
||||||
from typing import List, Tuple
|
SqliteDatabase,
|
||||||
from pkg_resources import resource_string
|
MySQLDatabase,
|
||||||
import datetime
|
PostgresqlDatabase,
|
||||||
import pycountry
|
|
||||||
|
|
||||||
from .objects.parents import Reference
|
|
||||||
from .objects.source import Source
|
|
||||||
from .objects import (
|
|
||||||
Song,
|
|
||||||
Lyrics,
|
|
||||||
Target,
|
|
||||||
Artist,
|
|
||||||
Album,
|
|
||||||
ID3Timestamp,
|
|
||||||
SourceTypes,
|
|
||||||
SourcePages,
|
|
||||||
SourceAttribute
|
|
||||||
)
|
)
|
||||||
|
|
||||||
"""
|
from . import data_models
|
||||||
import peewee
|
|
||||||
|
|
||||||
db = peewee.SqliteDatabase('music.db')
|
|
||||||
|
|
||||||
class BaseModel(peewee.Model):
|
|
||||||
class Meta:
|
|
||||||
database = db
|
|
||||||
|
|
||||||
class Artist(BaseModel):
|
|
||||||
name = peewee.CharField()
|
|
||||||
|
|
||||||
class Song(BaseModel):
|
|
||||||
title = peewee.CharField()
|
|
||||||
artist = peewee.ManyToManyField(Artist, backref='songs')
|
|
||||||
|
|
||||||
db.connect()
|
|
||||||
db.create_tables([Artist, Song, Song.artist.get_through_model()], safe=True)
|
|
||||||
|
|
||||||
# Adding a song and its artists
|
|
||||||
beatles = Artist.create(name='The Beatles')
|
|
||||||
rolling_stones = Artist.create(name='The Rolling Stones')
|
|
||||||
song = Song.create(title='Hey Jude')
|
|
||||||
song.artist.add(beatles, rolling_stones)
|
|
||||||
|
|
||||||
# Querying songs by artist
|
|
||||||
songs = Song.select().join(Song.artist).where(Artist.name == 'The Beatles')
|
|
||||||
for song in songs:
|
|
||||||
print(song.title)
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
logger = logging.getLogger("database")
|
|
||||||
|
|
||||||
# Due to this not being deployed on a Server **HOPEFULLY**
|
|
||||||
# I don't need to parameterize stuff like the where and
|
|
||||||
# use complicated query builder
|
|
||||||
SONG_QUERY = """
|
|
||||||
SELECT
|
|
||||||
Song.id AS song_id, Song.name AS title, Song.isrc AS isrc, Song.length AS length, Song.album_id as album_id, Song.tracksort,
|
|
||||||
Target.id AS target_id, Target.file AS file, Target.path AS path, Song.genre AS genre
|
|
||||||
FROM Song
|
|
||||||
LEFT JOIN Target ON Song.id=Target.song_id
|
|
||||||
WHERE {where};
|
|
||||||
"""
|
|
||||||
SOURCE_QUERY = """
|
|
||||||
SELECT id, type, src, url, song_id
|
|
||||||
FROM Source
|
|
||||||
WHERE {where};
|
|
||||||
"""
|
|
||||||
LYRICS_QUERY = """
|
|
||||||
SELECT id, text, language, song_id
|
|
||||||
FROM Lyrics
|
|
||||||
WHERE {where};
|
|
||||||
"""
|
|
||||||
ALBUM_QUERY_UNJOINED = """
|
|
||||||
SELECT Album.id AS album_id, title, label, album_status, language, date, date_format, country, barcode, albumsort, is_split
|
|
||||||
FROM Album
|
|
||||||
WHERE {where};
|
|
||||||
"""
|
|
||||||
ALBUM_QUERY_JOINED = """
|
|
||||||
SELECT a.id AS album_id, a.title, a.label, a.album_status, a.language, a.date, a.date_format, a.country, a.barcode, a.albumsort, a.is_split
|
|
||||||
FROM Song
|
|
||||||
INNER JOIN Album a ON Song.album_id=a.id
|
|
||||||
WHERE {where};
|
|
||||||
"""
|
|
||||||
ARTIST_QUERY = """
|
|
||||||
SELECT id as artist_id, name as artist_name
|
|
||||||
FROM Artist
|
|
||||||
WHERE {where};
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
class DatabaseType(Enum):
|
||||||
|
SQLITE = "sqlite"
|
||||||
|
POSTGRESQL = "postgresql"
|
||||||
|
MYSQL = "mysql"
|
||||||
|
|
||||||
class Database:
|
class Database:
|
||||||
def __init__(self, database_file: str):
|
database: Union[SqliteDatabase, PostgresqlDatabase, MySQLDatabase]
|
||||||
self.database_file: str = database_file
|
|
||||||
self.connection, self.cursor = self.reset_cursor()
|
|
||||||
|
|
||||||
self.cursor = self.connection.cursor()
|
def __init__(
|
||||||
|
self,
|
||||||
|
db_type: DatabaseType,
|
||||||
|
db_name: str,
|
||||||
|
db_user: Optional[str] = None,
|
||||||
|
db_password: Optional[str] = None,
|
||||||
|
db_host: Optional[str] = None,
|
||||||
|
db_port: Optional[int] = None
|
||||||
|
):
|
||||||
|
self.db_type = db_type
|
||||||
|
self.db_name = db_name
|
||||||
|
self.db_user = db_user
|
||||||
|
self.db_password = db_password
|
||||||
|
self.db_host = db_host
|
||||||
|
self.db_port = db_port
|
||||||
|
|
||||||
def reset(self):
|
self.initialize_database()
|
||||||
"""
|
|
||||||
Deletes all Data from the database if it exists
|
|
||||||
and resets the schema defined in self.structure_file
|
|
||||||
"""
|
|
||||||
logger.info(f"resetting the database")
|
|
||||||
|
|
||||||
# deleting the database
|
def create_database(self) -> Union[SqliteDatabase, PostgresqlDatabase, MySQLDatabase]:
|
||||||
del self.connection
|
"""Create a database instance based on the configured database type and parameters.
|
||||||
del self.cursor
|
|
||||||
os.remove(self.database_file)
|
|
||||||
|
|
||||||
# newly creating the database
|
Returns:
|
||||||
self.reset_cursor()
|
The created database instance, or None if an invalid database type was specified.
|
||||||
query = resource_string("music_kraken", "static_files/new_db.sql").decode('utf-8')
|
|
||||||
|
|
||||||
# fill the database with the schematic
|
|
||||||
self.cursor.executescript(query)
|
|
||||||
self.connection.commit()
|
|
||||||
|
|
||||||
def reset_cursor(self) -> Tuple[sqlite3.Connection, sqlite3.Cursor]:
|
|
||||||
self.connection = sqlite3.connect(self.database_file)
|
|
||||||
# This is necessary that fetching rows returns dicts instead of tuple
|
|
||||||
self.connection.row_factory = sqlite3.Row
|
|
||||||
|
|
||||||
self.cursor = self.connection.cursor()
|
|
||||||
return self.connection, self.cursor
|
|
||||||
|
|
||||||
def push_one(self, db_object: Song | Lyrics | Target | Artist | Source | Album):
|
|
||||||
if db_object.dynamic:
|
|
||||||
return
|
|
||||||
|
|
||||||
if type(db_object) == Song:
|
|
||||||
return self.push_song(song=db_object, pushed=set())
|
|
||||||
|
|
||||||
"""
|
|
||||||
if type(db_object) == Lyrics:
|
|
||||||
return self.push_lyrics(lyrics=db_object)
|
|
||||||
|
|
||||||
if type(db_object) == Target:
|
|
||||||
return self.push_target(target=db_object)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if type(db_object) == Artist:
|
# SQLITE
|
||||||
return self.push_artist(artist=db_object, pushed=set())
|
if self.db_type == DatabaseType.SQLITE:
|
||||||
|
return SqliteDatabase(self.db_name)
|
||||||
|
|
||||||
"""
|
# POSTGRES
|
||||||
if type(db_object) == Source:
|
if self.db_type == DatabaseType.POSTGRESQL:
|
||||||
# needs to have the property type_enum or type_str set
|
return PostgresqlDatabase(
|
||||||
return self.push_source(source=db_object)
|
self.db_name,
|
||||||
"""
|
user=self.db_user,
|
||||||
|
password=self.db_password,
|
||||||
if type(db_object) == Album:
|
host=self.db_host,
|
||||||
return self.push_album(album=db_object, pushed=set())
|
port=self.db_port,
|
||||||
|
|
||||||
logger.warning(f"type {type(db_object)} isn't yet supported by the db")
|
|
||||||
|
|
||||||
def push(self, db_object_list: List[Song | Lyrics | Target | Artist | Source | Album]):
|
|
||||||
"""
|
|
||||||
This function is used to Write the data of any db_object to the database
|
|
||||||
|
|
||||||
It syncs a whole list of db_objects to the database and is meant
|
|
||||||
as the primary method to add to the database.
|
|
||||||
|
|
||||||
:param db_object_list:
|
|
||||||
"""
|
|
||||||
|
|
||||||
for db_object in db_object_list:
|
|
||||||
self.push_one(db_object)
|
|
||||||
|
|
||||||
def push_album(self, album: Album, pushed: set):
|
|
||||||
table = "Album"
|
|
||||||
query = f"INSERT OR REPLACE INTO {table} (id, title, label, album_status, language, date, date_format, country, barcode, albumsort, is_split) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
|
|
||||||
|
|
||||||
if album.id in pushed:
|
|
||||||
return
|
|
||||||
pushed.add(album.id)
|
|
||||||
|
|
||||||
date_format, date = album.date.get_timestamp_w_format()
|
|
||||||
|
|
||||||
values = (
|
|
||||||
album.id,
|
|
||||||
album.title,
|
|
||||||
album.label,
|
|
||||||
album.album_status,
|
|
||||||
album.iso_639_2_language,
|
|
||||||
date,
|
|
||||||
date_format,
|
|
||||||
album.country,
|
|
||||||
album.barcode,
|
|
||||||
album.albumsort,
|
|
||||||
album.is_split
|
|
||||||
)
|
|
||||||
self.cursor.execute(query, values)
|
|
||||||
self.connection.commit()
|
|
||||||
|
|
||||||
for song in album.tracklist:
|
|
||||||
self.push_song(song, pushed=pushed)
|
|
||||||
for artist in album.artists:
|
|
||||||
self.push_artist_album(artist_ref=artist.reference, album_ref=album.reference)
|
|
||||||
self.push_artist(artist, pushed=pushed)
|
|
||||||
|
|
||||||
for source in album.source_list:
|
|
||||||
source.type_enum = SourceTypes.ALBUM
|
|
||||||
source.add_song(album)
|
|
||||||
self.push_source(source=source)
|
|
||||||
|
|
||||||
def push_song(self, song: Song, pushed: set):
|
|
||||||
if song.dynamic:
|
|
||||||
return
|
|
||||||
|
|
||||||
if song.id in pushed:
|
|
||||||
return
|
|
||||||
pushed.add(song.id)
|
|
||||||
|
|
||||||
# ADDING THE DATA FOR THE SONG OBJECT
|
|
||||||
"""
|
|
||||||
db_field - object attribute
|
|
||||||
-------------------------------
|
|
||||||
id - id
|
|
||||||
name - title
|
|
||||||
"""
|
|
||||||
table = "Song"
|
|
||||||
|
|
||||||
values = (
|
|
||||||
song.id,
|
|
||||||
song.title,
|
|
||||||
song.isrc,
|
|
||||||
song.length,
|
|
||||||
song.get_album_id(),
|
|
||||||
song.tracksort,
|
|
||||||
song.genre
|
|
||||||
)
|
|
||||||
query = f"INSERT OR REPLACE INTO {table} (id, name, isrc, length, album_id, tracksort, genre) VALUES (?, ?, ?, ?, ?, ?, ?);"
|
|
||||||
|
|
||||||
self.cursor.execute(query, values)
|
|
||||||
self.connection.commit()
|
|
||||||
|
|
||||||
# add sources
|
|
||||||
for source in song.source_list:
|
|
||||||
source.add_song(song)
|
|
||||||
source.type_enum = SourceTypes.SONG
|
|
||||||
self.push_source(source=source)
|
|
||||||
|
|
||||||
# add lyrics
|
|
||||||
for single_lyrics in song.lyrics:
|
|
||||||
single_lyrics.add_song(song)
|
|
||||||
self.push_lyrics(lyrics=single_lyrics)
|
|
||||||
|
|
||||||
# add target
|
|
||||||
song.target.add_song(song)
|
|
||||||
self.push_target(target=song.target)
|
|
||||||
|
|
||||||
for main_artist in song.main_artist_list:
|
|
||||||
self.push_artist_song(artist_ref=Reference(main_artist.id), song_ref=Reference(song.id), is_feature=False)
|
|
||||||
self.push_artist(artist=main_artist, pushed=pushed)
|
|
||||||
|
|
||||||
for feature_artist in song.feature_artist_list:
|
|
||||||
self.push_artist_song(artist_ref=Reference(feature_artist.id), song_ref=Reference(song.id), is_feature=True)
|
|
||||||
self.push_artist(artist=feature_artist, pushed=pushed)
|
|
||||||
|
|
||||||
if song.album is not None:
|
|
||||||
self.push_album(song.album, pushed=pushed)
|
|
||||||
|
|
||||||
def push_lyrics(self, lyrics: Lyrics):
|
|
||||||
if lyrics.dynamic:
|
|
||||||
return
|
|
||||||
|
|
||||||
table = "Lyrics"
|
|
||||||
query = f"INSERT OR REPLACE INTO {table} (id, song_id, text, language) VALUES (?, ?, ?, ?);"
|
|
||||||
values = (
|
|
||||||
lyrics.id,
|
|
||||||
lyrics.song_ref_id,
|
|
||||||
lyrics.text,
|
|
||||||
lyrics.language
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.cursor.execute(query, values)
|
# MYSQL
|
||||||
self.connection.commit()
|
if self.db_type == DatabaseType.MYSQL:
|
||||||
|
return MySQLDatabase(
|
||||||
def push_source(self, source: Source):
|
self.db_name,
|
||||||
if source.dynamic:
|
user=self.db_user,
|
||||||
return
|
password=self.db_password,
|
||||||
|
host=self.db_host,
|
||||||
table = "Source"
|
port=self.db_port,
|
||||||
query = f"INSERT OR REPLACE INTO {table} (id, type, song_id, src, url) VALUES (?, ?, ?, ?, ?);"
|
|
||||||
values = (
|
|
||||||
source.id,
|
|
||||||
source.type_str,
|
|
||||||
source.song_ref_id,
|
|
||||||
source.page_str,
|
|
||||||
source.url
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.cursor.execute(query, values)
|
raise ValueError("define a Valid database type")
|
||||||
self.connection.commit()
|
|
||||||
|
|
||||||
def push_target(self, target: Target):
|
def initialize_database(self):
|
||||||
if target.dynamic:
|
|
||||||
return
|
|
||||||
|
|
||||||
table = "Target"
|
|
||||||
query = f"INSERT OR REPLACE INTO {table} (id, song_id, file, path) VALUES (?, ?, ?, ?);"
|
|
||||||
values = (
|
|
||||||
target.id,
|
|
||||||
target.song_ref_id,
|
|
||||||
target.file,
|
|
||||||
target.path
|
|
||||||
)
|
|
||||||
|
|
||||||
self.cursor.execute(query, values)
|
|
||||||
self.connection.commit()
|
|
||||||
|
|
||||||
def push_artist_song(self, artist_ref: Reference, song_ref: Reference, is_feature: bool):
|
|
||||||
table = "SongArtist"
|
|
||||||
# checking if already exists
|
|
||||||
query = f"SELECT * FROM {table} WHERE song_id=\"{song_ref.id}\" AND artist_id=\"{artist_ref.id}\""
|
|
||||||
self.cursor.execute(query)
|
|
||||||
if len(self.cursor.fetchall()) > 0:
|
|
||||||
# join already exists
|
|
||||||
return
|
|
||||||
|
|
||||||
query = f"INSERT OR REPLACE INTO {table} (song_id, artist_id, is_feature) VALUES (?, ?, ?);"
|
|
||||||
values = (
|
|
||||||
song_ref.id,
|
|
||||||
artist_ref.id,
|
|
||||||
is_feature
|
|
||||||
)
|
|
||||||
|
|
||||||
self.cursor.execute(query, values)
|
|
||||||
self.connection.commit()
|
|
||||||
|
|
||||||
def push_artist_album(self, artist_ref: Reference, album_ref: Reference):
|
|
||||||
table = "AlbumArtist"
|
|
||||||
# checking if already exists
|
|
||||||
query = f"SELECT * FROM {table} WHERE album_id=\"{album_ref.id}\" AND artist_id=\"{artist_ref.id}\""
|
|
||||||
self.cursor.execute(query)
|
|
||||||
if len(self.cursor.fetchall()) > 0:
|
|
||||||
# join already exists
|
|
||||||
return
|
|
||||||
|
|
||||||
query = f"INSERT OR REPLACE INTO {table} (album_id, artist_id) VALUES (?, ?);"
|
|
||||||
values = (
|
|
||||||
album_ref.id,
|
|
||||||
artist_ref.id
|
|
||||||
)
|
|
||||||
|
|
||||||
self.cursor.execute(query, values)
|
|
||||||
self.connection.commit()
|
|
||||||
|
|
||||||
def push_artist(self, artist: Artist, pushed: set):
|
|
||||||
if artist.dynamic:
|
|
||||||
return
|
|
||||||
if artist.id in pushed:
|
|
||||||
return
|
|
||||||
pushed.add(artist.id)
|
|
||||||
|
|
||||||
table = "Artist"
|
|
||||||
query = f"INSERT OR REPLACE INTO {table} (id, name) VALUES (?, ?);"
|
|
||||||
values = (
|
|
||||||
artist.id,
|
|
||||||
artist.name
|
|
||||||
)
|
|
||||||
|
|
||||||
self.cursor.execute(query, values)
|
|
||||||
self.connection.commit()
|
|
||||||
|
|
||||||
for song in artist.feature_songs:
|
|
||||||
self.push_artist_song(artist_ref=artist.reference, song_ref=song.reference, is_feature=True)
|
|
||||||
self.push_song(song=song, pushed=pushed)
|
|
||||||
|
|
||||||
for song in artist.main_songs:
|
|
||||||
self.push_artist_song(artist_ref=artist.reference, song_ref=song.reference, is_feature=False)
|
|
||||||
self.push_song(song=song, pushed=pushed)
|
|
||||||
|
|
||||||
for album in artist.main_albums:
|
|
||||||
self.push_artist_album(artist_ref=artist.reference, album_ref=album.reference)
|
|
||||||
|
|
||||||
for source in artist.source_list:
|
|
||||||
source.type_enum = SourceTypes.ARTIST
|
|
||||||
source.add_song(artist)
|
|
||||||
self.push_source(source)
|
|
||||||
|
|
||||||
def pull_lyrics(self, song_ref: Reference = None, lyrics_ref: Reference = None) -> List[Lyrics]:
|
|
||||||
"""
|
"""
|
||||||
Gets a list of sources. if lyrics_ref is passed in the List will most likely only
|
Connect to the database
|
||||||
contain one Element if everything goes accordingly.
|
initialize the previously defined databases
|
||||||
**If neither song_ref nor lyrics_ref are passed in it will return ALL lyrics**
|
create tables if they don't exist.
|
||||||
:param song_ref:
|
|
||||||
:param lyrics_ref:
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
|
self.database = self.create_database()
|
||||||
|
|
||||||
where = "1=1"
|
self.database.connect()
|
||||||
if song_ref is not None:
|
|
||||||
where = f"song_id=\"{song_ref.id}\""
|
|
||||||
elif lyrics_ref is not None:
|
|
||||||
where = f"id=\"{lyrics_ref.id}\""
|
|
||||||
|
|
||||||
query = LYRICS_QUERY.format(where=where)
|
|
||||||
self.cursor.execute(query)
|
|
||||||
|
|
||||||
lyrics_rows = self.cursor.fetchall()
|
|
||||||
return [Lyrics(
|
|
||||||
id_=lyrics_row['id'],
|
|
||||||
text=lyrics_row['text'],
|
|
||||||
language=lyrics_row['language']
|
|
||||||
) for lyrics_row in lyrics_rows]
|
|
||||||
|
|
||||||
def pull_sources(self, artist_ref: Reference = None, song_ref: Reference = None, source_ref: Reference = None, album_ref: Reference = None) -> List[Source]:
|
|
||||||
"""
|
|
||||||
Gets a list of sources. if source_ref is passed in the List will most likely only
|
|
||||||
contain one Element if everything goes accordingly.
|
|
||||||
**If neither song_ref nor source_ref are passed in it will return ALL sources**
|
|
||||||
:param artist_ref:
|
|
||||||
:param song_ref:
|
|
||||||
:param source_ref:
|
|
||||||
:param type_str: the thing the source belongs to like eg. "song" or "album"
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
where = "1=1"
|
|
||||||
if song_ref is not None:
|
|
||||||
where = f"song_id=\"{song_ref.id}\""
|
|
||||||
elif source_ref is not None:
|
|
||||||
where = f"id=\"{source_ref.id}\" AND type=\"{SourceTypes.SONG.value}\""
|
|
||||||
elif artist_ref is not None:
|
|
||||||
where = f"song_id=\"{artist_ref.id}\" AND type=\"{SourceTypes.ARTIST.value}\""
|
|
||||||
elif album_ref is not None:
|
|
||||||
where = f"song_id=\"{album_ref.id}\" AND type=\"{SourceTypes.ALBUM.value}\""
|
|
||||||
|
|
||||||
query = SOURCE_QUERY.format(where=where)
|
|
||||||
self.cursor.execute(query)
|
|
||||||
|
|
||||||
source_rows = self.cursor.fetchall()
|
|
||||||
|
|
||||||
return [
|
|
||||||
Source(
|
|
||||||
page_enum=SourcePages(source_row['src']),
|
|
||||||
type_enum=SourceTypes(source_row['type']),
|
|
||||||
url=source_row['url'],
|
|
||||||
id_=source_row['id']
|
|
||||||
) for source_row in source_rows
|
|
||||||
]
|
|
||||||
|
|
||||||
def pull_artist_song(self, song_ref: Reference = None, artist_ref: Reference = None) -> List[tuple]:
|
|
||||||
table = "SongArtist"
|
|
||||||
wheres = []
|
|
||||||
if song_ref is not None:
|
|
||||||
wheres.append(f"song_id=\"{song_ref.id}\"")
|
|
||||||
if artist_ref is not None:
|
|
||||||
wheres.append(f"artist_id=\"{artist_ref.id}\"")
|
|
||||||
where_str = ""
|
|
||||||
if len(wheres) > 0:
|
|
||||||
where_str = "WHERE " + " AND ".join(wheres)
|
|
||||||
|
|
||||||
query = f"SELECT * FROM {table} {where_str};"
|
|
||||||
self.cursor.execute(query)
|
|
||||||
joins = self.cursor.fetchall()
|
|
||||||
|
|
||||||
return [(
|
|
||||||
Reference(join["song_id"]),
|
|
||||||
Reference(join["artist_id"]),
|
|
||||||
bool(join["is_feature"])
|
|
||||||
) for join in joins]
|
|
||||||
|
|
||||||
def pull_artist_album(self, album_ref: Reference = None, artist_ref: Reference = None) -> List[tuple]:
|
|
||||||
table = "AlbumArtist"
|
|
||||||
wheres = []
|
|
||||||
if album_ref is not None:
|
|
||||||
wheres.append(f"album_id=\"{album_ref.id}\"")
|
|
||||||
if artist_ref is not None:
|
|
||||||
wheres.append(f"artist_id=\"{artist_ref.id}\"")
|
|
||||||
where_str = ""
|
|
||||||
if len(wheres) > 0:
|
|
||||||
where_str = "WHERE " + " AND ".join(wheres)
|
|
||||||
|
|
||||||
query = f"SELECT * FROM {table} {where_str};"
|
|
||||||
self.cursor.execute(query)
|
|
||||||
joins = self.cursor.fetchall()
|
|
||||||
|
|
||||||
return [(
|
|
||||||
Reference(join["album_id"]),
|
|
||||||
Reference(join["artist_id"])
|
|
||||||
) for join in joins]
|
|
||||||
|
|
||||||
def get_artist_from_row(self, artist_row, exclude_relations: set = None, flat: bool = False) -> Artist:
|
|
||||||
if exclude_relations is None:
|
|
||||||
exclude_relations = set()
|
|
||||||
new_exclude_relations: set = set(exclude_relations)
|
|
||||||
new_exclude_relations.add(Artist)
|
|
||||||
|
|
||||||
artist_id = artist_row['artist_id']
|
|
||||||
|
|
||||||
artist_obj = Artist(
|
|
||||||
id_=artist_id,
|
|
||||||
name=artist_row['artist_name'],
|
|
||||||
source_list=self.pull_sources(artist_ref=Reference(id_=artist_id))
|
|
||||||
)
|
|
||||||
if flat:
|
|
||||||
return artist_obj
|
|
||||||
|
|
||||||
# fetch songs :D
|
|
||||||
for song_ref, _, is_feature in self.pull_artist_song(artist_ref=Reference(id_=artist_id)):
|
|
||||||
new_songs = self.pull_songs(song_ref=song_ref, exclude_relations=new_exclude_relations)
|
|
||||||
if len(new_songs) < 1:
|
|
||||||
continue
|
|
||||||
new_song = new_songs[0]
|
|
||||||
|
|
||||||
if is_feature:
|
|
||||||
artist_obj.feature_songs.append(new_song)
|
|
||||||
else:
|
|
||||||
artist_obj.main_songs.append(new_song)
|
|
||||||
|
|
||||||
# fetch albums
|
|
||||||
for album_ref, _ in self.pull_artist_album(artist_ref=Reference(id_=artist_id)):
|
|
||||||
new_albums = self.pull_albums(album_ref=album_ref, exclude_relations=new_exclude_relations)
|
|
||||||
if len(new_albums) < 1:
|
|
||||||
continue
|
|
||||||
artist_obj.main_albums.append(new_albums[0])
|
|
||||||
|
|
||||||
return artist_obj
|
|
||||||
|
|
||||||
def pull_artists(self, artist_ref: Reference = None, exclude_relations: set = None, flat: bool = False) -> List[Artist]:
|
|
||||||
"""
|
|
||||||
|
|
||||||
:param artist_ref:
|
|
||||||
:param exclude_relations:
|
|
||||||
:param flat: if it is true it ONLY fetches the artist data
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
where = "1=1"
|
|
||||||
if artist_ref is not None:
|
|
||||||
where = f"Artist.id=\"{artist_ref.id}\""
|
|
||||||
|
|
||||||
query = ARTIST_QUERY.format(where=where)
|
|
||||||
self.cursor.execute(query)
|
|
||||||
|
|
||||||
artist_rows = self.cursor.fetchall()
|
|
||||||
return [(
|
|
||||||
self.get_artist_from_row(artist_row, exclude_relations=exclude_relations, flat=flat)
|
|
||||||
) for artist_row in artist_rows]
|
|
||||||
|
|
||||||
def get_song_from_row(self, song_result, exclude_relations: set = None) -> Song:
|
|
||||||
if exclude_relations is None:
|
|
||||||
exclude_relations = set()
|
|
||||||
new_exclude_relations: set = set(exclude_relations)
|
|
||||||
new_exclude_relations.add(Song)
|
|
||||||
|
|
||||||
song_id = song_result['song_id']
|
|
||||||
|
|
||||||
# maybee fetch album
|
|
||||||
|
|
||||||
song_obj = Song(
|
|
||||||
id_=song_id,
|
|
||||||
title=song_result['title'],
|
|
||||||
isrc=song_result['isrc'],
|
|
||||||
length=song_result['length'],
|
|
||||||
tracksort=song_result['tracksort'],
|
|
||||||
genre=song_result['genre'],
|
|
||||||
target=Target(
|
|
||||||
id_=song_result['target_id'],
|
|
||||||
file=song_result['file'],
|
|
||||||
path=song_result['path']
|
|
||||||
),
|
|
||||||
source_list=self.pull_sources(song_ref=Reference(id_=song_id)),
|
|
||||||
lyrics=self.pull_lyrics(song_ref=Reference(id_=song_id)),
|
|
||||||
)
|
|
||||||
|
|
||||||
if Album not in exclude_relations and song_result['album_id'] is not None:
|
|
||||||
album_obj = self.pull_albums(album_ref=Reference(song_result['album_id']),
|
|
||||||
exclude_relations=new_exclude_relations)
|
|
||||||
if len(album_obj) > 0:
|
|
||||||
song_obj.album = album_obj[0]
|
|
||||||
|
|
||||||
flat_artist = Artist in exclude_relations
|
|
||||||
|
|
||||||
main_artists = []
|
|
||||||
feature_artists = []
|
|
||||||
for song_ref, artist_ref, is_feature in self.pull_artist_song(song_ref=Reference(song_id)):
|
|
||||||
if is_feature:
|
|
||||||
feature_artists.extend(self.pull_artists(artist_ref=artist_ref, flat=flat_artist))
|
|
||||||
else:
|
|
||||||
main_artists.extend(self.pull_artists(artist_ref=artist_ref, flat=flat_artist))
|
|
||||||
|
|
||||||
song_obj.main_artist_list = main_artists
|
|
||||||
song_obj.feature_artist_list = feature_artists
|
|
||||||
|
|
||||||
return song_obj
|
|
||||||
|
|
||||||
def pull_songs(self, song_ref: Reference = None, album_ref: Reference = None, exclude_relations: set = set()) -> \
|
|
||||||
List[Song]:
|
|
||||||
"""
|
|
||||||
This function is used to get one song (including its children like Sources etc)
|
|
||||||
from one song id (a reference object)
|
|
||||||
:param exclude_relations:
|
|
||||||
By default all relations are pulled by this funktion. If the class object of for
|
|
||||||
example the Artists is in the set it won't get fetched.
|
|
||||||
This is done to prevent an infinite recursion.
|
|
||||||
:param song_ref:
|
|
||||||
:param album_ref:
|
|
||||||
:return requested_song:
|
|
||||||
"""
|
|
||||||
|
|
||||||
where = "1=1"
|
|
||||||
if song_ref is not None:
|
|
||||||
where = f"Song.id=\"{song_ref.id}\""
|
|
||||||
elif album_ref is not None:
|
|
||||||
where = f"Song.album_id=\"{album_ref.id}\""
|
|
||||||
|
|
||||||
query = SONG_QUERY.format(where=where)
|
|
||||||
self.cursor.execute(query)
|
|
||||||
|
|
||||||
song_rows = self.cursor.fetchall()
|
|
||||||
|
|
||||||
return [self.get_song_from_row(
|
|
||||||
song_result=song_result,
|
|
||||||
exclude_relations=exclude_relations
|
|
||||||
) for song_result in song_rows]
|
|
||||||
|
|
||||||
def get_album_from_row(self, album_result, exclude_relations=None) -> Album:
|
|
||||||
if exclude_relations is None:
|
|
||||||
exclude_relations = set()
|
|
||||||
new_exclude_relations: set = exclude_relations.copy()
|
|
||||||
new_exclude_relations.add(Album)
|
|
||||||
|
|
||||||
album_id = album_result['album_id']
|
|
||||||
language = album_result['language']
|
|
||||||
if language is not None:
|
|
||||||
language = pycountry.languages.get(alpha_3=album_result['language'])
|
|
||||||
|
|
||||||
album_obj = Album(
|
|
||||||
id_=album_id,
|
|
||||||
title=album_result['title'],
|
|
||||||
label=album_result['label'],
|
|
||||||
album_status=album_result['album_status'],
|
|
||||||
language=language,
|
|
||||||
date=ID3Timestamp.strptime(album_result['date'], album_result['date_format']),
|
|
||||||
country=album_result['country'],
|
|
||||||
barcode=album_result['barcode'],
|
|
||||||
is_split=album_result['is_split'],
|
|
||||||
albumsort=album_result['albumsort'],
|
|
||||||
source_list=self.pull_sources(album_ref=Reference(id_=album_id))
|
|
||||||
)
|
|
||||||
|
|
||||||
if Song not in exclude_relations:
|
|
||||||
# getting the tracklist
|
|
||||||
tracklist: List[Song] = self.pull_songs(
|
|
||||||
album_ref=Reference(id_=album_id),
|
|
||||||
exclude_relations=new_exclude_relations
|
|
||||||
)
|
|
||||||
album_obj.set_tracklist(tracklist=tracklist)
|
|
||||||
|
|
||||||
flat_artist = Artist in exclude_relations
|
|
||||||
for _, artist_ref in self.pull_artist_album(album_ref=Reference(id_=album_id)):
|
|
||||||
artists = self.pull_artists(artist_ref, flat=flat_artist, exclude_relations=new_exclude_relations)
|
|
||||||
if len(artists) < 1:
|
|
||||||
continue
|
|
||||||
album_obj.artists.append(artists[0])
|
|
||||||
|
|
||||||
return album_obj
|
|
||||||
|
|
||||||
def pull_albums(self, album_ref: Reference = None, song_ref: Reference = None, exclude_relations: set = None) -> \
|
|
||||||
List[Album]:
|
|
||||||
"""
|
|
||||||
This function is used to get matching albums/releses
|
|
||||||
from one song id (a reference object)
|
|
||||||
:param exclude_relations:
|
|
||||||
By default all relations are pulled by this funktion. If the class object of for
|
|
||||||
example the Artists is in the set it won't get fetched.
|
|
||||||
This is done to prevent an infinite recursion.
|
|
||||||
:param album_ref:
|
|
||||||
:return requested_album_list:
|
|
||||||
"""
|
|
||||||
if exclude_relations is None:
|
|
||||||
exclude_relations = set()
|
|
||||||
|
|
||||||
query = ALBUM_QUERY_UNJOINED
|
|
||||||
where = "1=1"
|
|
||||||
if album_ref is not None:
|
|
||||||
query = ALBUM_QUERY_UNJOINED
|
|
||||||
where = f"Album.id=\"{album_ref.id}\""
|
|
||||||
elif song_ref is not None:
|
|
||||||
query = ALBUM_QUERY_JOINED
|
|
||||||
where = f"Song.id=\"{song_ref.id}\""
|
|
||||||
|
|
||||||
query = query.format(where=where)
|
|
||||||
self.cursor.execute(query)
|
|
||||||
|
|
||||||
album_rows = self.cursor.fetchall()
|
|
||||||
|
|
||||||
return [self.get_album_from_row(
|
|
||||||
album_result=album_row,
|
|
||||||
exclude_relations=exclude_relations
|
|
||||||
) for album_row in album_rows]
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
cache = Database("")
|
|
||||||
|
@ -2,7 +2,7 @@ from collections import defaultdict
|
|||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
from .objects import MusicObject
|
from src.music_kraken.objects import MusicObject
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This is a cache for the objects, that et pulled out of the database.
|
This is a cache for the objects, that et pulled out of the database.
|
||||||
|
700
src/music_kraken/database/old_database.py
Normal file
700
src/music_kraken/database/old_database.py
Normal file
@ -0,0 +1,700 @@
|
|||||||
|
import sqlite3
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from typing import List, Tuple
|
||||||
|
from pkg_resources import resource_string
|
||||||
|
import pycountry
|
||||||
|
|
||||||
|
from src.music_kraken.objects.parents import Reference
|
||||||
|
from src.music_kraken.objects.source import Source
|
||||||
|
from src.music_kraken.objects import (
|
||||||
|
Song,
|
||||||
|
Lyrics,
|
||||||
|
Target,
|
||||||
|
Artist,
|
||||||
|
Album,
|
||||||
|
ID3Timestamp,
|
||||||
|
SourceTypes,
|
||||||
|
SourcePages
|
||||||
|
)
|
||||||
|
|
||||||
|
"""
|
||||||
|
import peewee
|
||||||
|
|
||||||
|
db = peewee.SqliteDatabase('music.db')
|
||||||
|
|
||||||
|
class BaseModel(peewee.Model):
|
||||||
|
class Meta:
|
||||||
|
database = db
|
||||||
|
|
||||||
|
class Artist(BaseModel):
|
||||||
|
name = peewee.CharField()
|
||||||
|
|
||||||
|
class Song(BaseModel):
|
||||||
|
title = peewee.CharField()
|
||||||
|
artist = peewee.ManyToManyField(Artist, backref='songs')
|
||||||
|
|
||||||
|
db.connect()
|
||||||
|
db.create_tables([Artist, Song, Song.artist.get_through_model()], safe=True)
|
||||||
|
|
||||||
|
# Adding a song and its artists
|
||||||
|
beatles = Artist.create(name='The Beatles')
|
||||||
|
rolling_stones = Artist.create(name='The Rolling Stones')
|
||||||
|
song = Song.create(title='Hey Jude')
|
||||||
|
song.artist.add(beatles, rolling_stones)
|
||||||
|
|
||||||
|
# Querying songs by artist
|
||||||
|
songs = Song.select().join(Song.artist).where(Artist.name == 'The Beatles')
|
||||||
|
for song in songs:
|
||||||
|
print(song.title)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
logger = logging.getLogger("database")
|
||||||
|
|
||||||
|
# Due to this not being deployed on a Server **HOPEFULLY**
|
||||||
|
# I don't need to parameterize stuff like the where and
|
||||||
|
# use complicated query builder
|
||||||
|
SONG_QUERY = """
|
||||||
|
SELECT
|
||||||
|
Song.id AS song_id, Song.name AS title, Song.isrc AS isrc, Song.length AS length, Song.album_id as album_id, Song.tracksort,
|
||||||
|
Target.id AS target_id, Target.file AS file, Target.path AS path, Song.genre AS genre
|
||||||
|
FROM Song
|
||||||
|
LEFT JOIN Target ON Song.id=Target.song_id
|
||||||
|
WHERE {where};
|
||||||
|
"""
|
||||||
|
SOURCE_QUERY = """
|
||||||
|
SELECT id, type, src, url, song_id
|
||||||
|
FROM Source
|
||||||
|
WHERE {where};
|
||||||
|
"""
|
||||||
|
LYRICS_QUERY = """
|
||||||
|
SELECT id, text, language, song_id
|
||||||
|
FROM Lyrics
|
||||||
|
WHERE {where};
|
||||||
|
"""
|
||||||
|
ALBUM_QUERY_UNJOINED = """
|
||||||
|
SELECT Album.id AS album_id, title, label, album_status, language, date, date_format, country, barcode, albumsort, is_split
|
||||||
|
FROM Album
|
||||||
|
WHERE {where};
|
||||||
|
"""
|
||||||
|
ALBUM_QUERY_JOINED = """
|
||||||
|
SELECT a.id AS album_id, a.title, a.label, a.album_status, a.language, a.date, a.date_format, a.country, a.barcode, a.albumsort, a.is_split
|
||||||
|
FROM Song
|
||||||
|
INNER JOIN Album a ON Song.album_id=a.id
|
||||||
|
WHERE {where};
|
||||||
|
"""
|
||||||
|
ARTIST_QUERY = """
|
||||||
|
SELECT id as artist_id, name as artist_name
|
||||||
|
FROM Artist
|
||||||
|
WHERE {where};
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class Database:
|
||||||
|
def __init__(self, database_file: str):
|
||||||
|
self.database_file: str = database_file
|
||||||
|
self.connection, self.cursor = self.reset_cursor()
|
||||||
|
|
||||||
|
self.cursor = self.connection.cursor()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
"""
|
||||||
|
Deletes all Data from the database if it exists
|
||||||
|
and resets the schema defined in self.structure_file
|
||||||
|
"""
|
||||||
|
logger.info(f"resetting the database")
|
||||||
|
|
||||||
|
# deleting the database
|
||||||
|
del self.connection
|
||||||
|
del self.cursor
|
||||||
|
os.remove(self.database_file)
|
||||||
|
|
||||||
|
# newly creating the database
|
||||||
|
self.reset_cursor()
|
||||||
|
query = resource_string("music_kraken", "static_files/new_db.sql").decode('utf-8')
|
||||||
|
|
||||||
|
# fill the database with the schematic
|
||||||
|
self.cursor.executescript(query)
|
||||||
|
self.connection.commit()
|
||||||
|
|
||||||
|
def reset_cursor(self) -> Tuple[sqlite3.Connection, sqlite3.Cursor]:
|
||||||
|
self.connection = sqlite3.connect(self.database_file)
|
||||||
|
# This is necessary that fetching rows returns dicts instead of tuple
|
||||||
|
self.connection.row_factory = sqlite3.Row
|
||||||
|
|
||||||
|
self.cursor = self.connection.cursor()
|
||||||
|
return self.connection, self.cursor
|
||||||
|
|
||||||
|
def push_one(self, db_object: Song | Lyrics | Target | Artist | Source | Album):
|
||||||
|
if db_object.dynamic:
|
||||||
|
return
|
||||||
|
|
||||||
|
if type(db_object) == Song:
|
||||||
|
return self.push_song(song=db_object, pushed=set())
|
||||||
|
|
||||||
|
"""
|
||||||
|
if type(db_object) == Lyrics:
|
||||||
|
return self.push_lyrics(lyrics=db_object)
|
||||||
|
|
||||||
|
if type(db_object) == Target:
|
||||||
|
return self.push_target(target=db_object)
|
||||||
|
"""
|
||||||
|
|
||||||
|
if type(db_object) == Artist:
|
||||||
|
return self.push_artist(artist=db_object, pushed=set())
|
||||||
|
|
||||||
|
"""
|
||||||
|
if type(db_object) == Source:
|
||||||
|
# needs to have the property type_enum or type_str set
|
||||||
|
return self.push_source(source=db_object)
|
||||||
|
"""
|
||||||
|
|
||||||
|
if type(db_object) == Album:
|
||||||
|
return self.push_album(album=db_object, pushed=set())
|
||||||
|
|
||||||
|
logger.warning(f"type {type(db_object)} isn't yet supported by the db")
|
||||||
|
|
||||||
|
def push(self, db_object_list: List[Song | Lyrics | Target | Artist | Source | Album]):
|
||||||
|
"""
|
||||||
|
This function is used to Write the data of any db_object to the database
|
||||||
|
|
||||||
|
It syncs a whole list of db_objects to the database and is meant
|
||||||
|
as the primary method to add to the database.
|
||||||
|
|
||||||
|
:param db_object_list:
|
||||||
|
"""
|
||||||
|
|
||||||
|
for db_object in db_object_list:
|
||||||
|
self.push_one(db_object)
|
||||||
|
|
||||||
|
def push_album(self, album: Album, pushed: set):
|
||||||
|
table = "Album"
|
||||||
|
query = f"INSERT OR REPLACE INTO {table} (id, title, label, album_status, language, date, date_format, country, barcode, albumsort, is_split) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
|
||||||
|
|
||||||
|
if album.id in pushed:
|
||||||
|
return
|
||||||
|
pushed.add(album.id)
|
||||||
|
|
||||||
|
date_format, date = album.date.get_timestamp_w_format()
|
||||||
|
|
||||||
|
values = (
|
||||||
|
album.id,
|
||||||
|
album.title,
|
||||||
|
album.label,
|
||||||
|
album.album_status,
|
||||||
|
album.iso_639_2_language,
|
||||||
|
date,
|
||||||
|
date_format,
|
||||||
|
album.country,
|
||||||
|
album.barcode,
|
||||||
|
album.albumsort,
|
||||||
|
album.is_split
|
||||||
|
)
|
||||||
|
self.cursor.execute(query, values)
|
||||||
|
self.connection.commit()
|
||||||
|
|
||||||
|
for song in album.tracklist:
|
||||||
|
self.push_song(song, pushed=pushed)
|
||||||
|
for artist in album.artists:
|
||||||
|
self.push_artist_album(artist_ref=artist.reference, album_ref=album.reference)
|
||||||
|
self.push_artist(artist, pushed=pushed)
|
||||||
|
|
||||||
|
for source in album.source_list:
|
||||||
|
source.type_enum = SourceTypes.ALBUM
|
||||||
|
source.add_song(album)
|
||||||
|
self.push_source(source=source)
|
||||||
|
|
||||||
|
def push_song(self, song: Song, pushed: set):
|
||||||
|
if song.dynamic:
|
||||||
|
return
|
||||||
|
|
||||||
|
if song.id in pushed:
|
||||||
|
return
|
||||||
|
pushed.add(song.id)
|
||||||
|
|
||||||
|
# ADDING THE DATA FOR THE SONG OBJECT
|
||||||
|
"""
|
||||||
|
db_field - object attribute
|
||||||
|
-------------------------------
|
||||||
|
id - id
|
||||||
|
name - title
|
||||||
|
"""
|
||||||
|
table = "Song"
|
||||||
|
|
||||||
|
values = (
|
||||||
|
song.id,
|
||||||
|
song.title,
|
||||||
|
song.isrc,
|
||||||
|
song.length,
|
||||||
|
song.get_album_id(),
|
||||||
|
song.tracksort,
|
||||||
|
song.genre
|
||||||
|
)
|
||||||
|
query = f"INSERT OR REPLACE INTO {table} (id, name, isrc, length, album_id, tracksort, genre) VALUES (?, ?, ?, ?, ?, ?, ?);"
|
||||||
|
|
||||||
|
self.cursor.execute(query, values)
|
||||||
|
self.connection.commit()
|
||||||
|
|
||||||
|
# add sources
|
||||||
|
for source in song.source_list:
|
||||||
|
source.add_song(song)
|
||||||
|
source.type_enum = SourceTypes.SONG
|
||||||
|
self.push_source(source=source)
|
||||||
|
|
||||||
|
# add lyrics
|
||||||
|
for single_lyrics in song.lyrics:
|
||||||
|
single_lyrics.add_song(song)
|
||||||
|
self.push_lyrics(lyrics=single_lyrics)
|
||||||
|
|
||||||
|
# add target
|
||||||
|
song.target.add_song(song)
|
||||||
|
self.push_target(target=song.target)
|
||||||
|
|
||||||
|
for main_artist in song.main_artist_list:
|
||||||
|
self.push_artist_song(artist_ref=Reference(main_artist.id), song_ref=Reference(song.id), is_feature=False)
|
||||||
|
self.push_artist(artist=main_artist, pushed=pushed)
|
||||||
|
|
||||||
|
for feature_artist in song.feature_artist_list:
|
||||||
|
self.push_artist_song(artist_ref=Reference(feature_artist.id), song_ref=Reference(song.id), is_feature=True)
|
||||||
|
self.push_artist(artist=feature_artist, pushed=pushed)
|
||||||
|
|
||||||
|
if song.album is not None:
|
||||||
|
self.push_album(song.album, pushed=pushed)
|
||||||
|
|
||||||
|
def push_lyrics(self, lyrics: Lyrics):
|
||||||
|
if lyrics.dynamic:
|
||||||
|
return
|
||||||
|
|
||||||
|
table = "Lyrics"
|
||||||
|
query = f"INSERT OR REPLACE INTO {table} (id, song_id, text, language) VALUES (?, ?, ?, ?);"
|
||||||
|
values = (
|
||||||
|
lyrics.id,
|
||||||
|
lyrics.song_ref_id,
|
||||||
|
lyrics.text,
|
||||||
|
lyrics.language
|
||||||
|
)
|
||||||
|
|
||||||
|
self.cursor.execute(query, values)
|
||||||
|
self.connection.commit()
|
||||||
|
|
||||||
|
def push_source(self, source: Source):
|
||||||
|
if source.dynamic:
|
||||||
|
return
|
||||||
|
|
||||||
|
table = "Source"
|
||||||
|
query = f"INSERT OR REPLACE INTO {table} (id, type, song_id, src, url) VALUES (?, ?, ?, ?, ?);"
|
||||||
|
values = (
|
||||||
|
source.id,
|
||||||
|
source.type_str,
|
||||||
|
source.song_ref_id,
|
||||||
|
source.page_str,
|
||||||
|
source.url
|
||||||
|
)
|
||||||
|
|
||||||
|
self.cursor.execute(query, values)
|
||||||
|
self.connection.commit()
|
||||||
|
|
||||||
|
def push_target(self, target: Target):
|
||||||
|
if target.dynamic:
|
||||||
|
return
|
||||||
|
|
||||||
|
table = "Target"
|
||||||
|
query = f"INSERT OR REPLACE INTO {table} (id, song_id, file, path) VALUES (?, ?, ?, ?);"
|
||||||
|
values = (
|
||||||
|
target.id,
|
||||||
|
target.song_ref_id,
|
||||||
|
target.file,
|
||||||
|
target.path
|
||||||
|
)
|
||||||
|
|
||||||
|
self.cursor.execute(query, values)
|
||||||
|
self.connection.commit()
|
||||||
|
|
||||||
|
def push_artist_song(self, artist_ref: Reference, song_ref: Reference, is_feature: bool):
|
||||||
|
table = "SongArtist"
|
||||||
|
# checking if already exists
|
||||||
|
query = f"SELECT * FROM {table} WHERE song_id=\"{song_ref.id}\" AND artist_id=\"{artist_ref.id}\""
|
||||||
|
self.cursor.execute(query)
|
||||||
|
if len(self.cursor.fetchall()) > 0:
|
||||||
|
# join already exists
|
||||||
|
return
|
||||||
|
|
||||||
|
query = f"INSERT OR REPLACE INTO {table} (song_id, artist_id, is_feature) VALUES (?, ?, ?);"
|
||||||
|
values = (
|
||||||
|
song_ref.id,
|
||||||
|
artist_ref.id,
|
||||||
|
is_feature
|
||||||
|
)
|
||||||
|
|
||||||
|
self.cursor.execute(query, values)
|
||||||
|
self.connection.commit()
|
||||||
|
|
||||||
|
def push_artist_album(self, artist_ref: Reference, album_ref: Reference):
|
||||||
|
table = "AlbumArtist"
|
||||||
|
# checking if already exists
|
||||||
|
query = f"SELECT * FROM {table} WHERE album_id=\"{album_ref.id}\" AND artist_id=\"{artist_ref.id}\""
|
||||||
|
self.cursor.execute(query)
|
||||||
|
if len(self.cursor.fetchall()) > 0:
|
||||||
|
# join already exists
|
||||||
|
return
|
||||||
|
|
||||||
|
query = f"INSERT OR REPLACE INTO {table} (album_id, artist_id) VALUES (?, ?);"
|
||||||
|
values = (
|
||||||
|
album_ref.id,
|
||||||
|
artist_ref.id
|
||||||
|
)
|
||||||
|
|
||||||
|
self.cursor.execute(query, values)
|
||||||
|
self.connection.commit()
|
||||||
|
|
||||||
|
def push_artist(self, artist: Artist, pushed: set):
|
||||||
|
if artist.dynamic:
|
||||||
|
return
|
||||||
|
if artist.id in pushed:
|
||||||
|
return
|
||||||
|
pushed.add(artist.id)
|
||||||
|
|
||||||
|
table = "Artist"
|
||||||
|
query = f"INSERT OR REPLACE INTO {table} (id, name) VALUES (?, ?);"
|
||||||
|
values = (
|
||||||
|
artist.id,
|
||||||
|
artist.name
|
||||||
|
)
|
||||||
|
|
||||||
|
self.cursor.execute(query, values)
|
||||||
|
self.connection.commit()
|
||||||
|
|
||||||
|
for song in artist.feature_songs:
|
||||||
|
self.push_artist_song(artist_ref=artist.reference, song_ref=song.reference, is_feature=True)
|
||||||
|
self.push_song(song=song, pushed=pushed)
|
||||||
|
|
||||||
|
for song in artist.main_songs:
|
||||||
|
self.push_artist_song(artist_ref=artist.reference, song_ref=song.reference, is_feature=False)
|
||||||
|
self.push_song(song=song, pushed=pushed)
|
||||||
|
|
||||||
|
for album in artist.main_albums:
|
||||||
|
self.push_artist_album(artist_ref=artist.reference, album_ref=album.reference)
|
||||||
|
|
||||||
|
for source in artist.source_list:
|
||||||
|
source.type_enum = SourceTypes.ARTIST
|
||||||
|
source.add_song(artist)
|
||||||
|
self.push_source(source)
|
||||||
|
|
||||||
|
def pull_lyrics(self, song_ref: Reference = None, lyrics_ref: Reference = None) -> List[Lyrics]:
|
||||||
|
"""
|
||||||
|
Gets a list of sources. if lyrics_ref is passed in the List will most likely only
|
||||||
|
contain one Element if everything goes accordingly.
|
||||||
|
**If neither song_ref nor lyrics_ref are passed in it will return ALL lyrics**
|
||||||
|
:param song_ref:
|
||||||
|
:param lyrics_ref:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
where = "1=1"
|
||||||
|
if song_ref is not None:
|
||||||
|
where = f"song_id=\"{song_ref.id}\""
|
||||||
|
elif lyrics_ref is not None:
|
||||||
|
where = f"id=\"{lyrics_ref.id}\""
|
||||||
|
|
||||||
|
query = LYRICS_QUERY.format(where=where)
|
||||||
|
self.cursor.execute(query)
|
||||||
|
|
||||||
|
lyrics_rows = self.cursor.fetchall()
|
||||||
|
return [Lyrics(
|
||||||
|
id_=lyrics_row['id'],
|
||||||
|
text=lyrics_row['text'],
|
||||||
|
language=lyrics_row['language']
|
||||||
|
) for lyrics_row in lyrics_rows]
|
||||||
|
|
||||||
|
def pull_sources(self, artist_ref: Reference = None, song_ref: Reference = None, source_ref: Reference = None, album_ref: Reference = None) -> List[Source]:
|
||||||
|
"""
|
||||||
|
Gets a list of sources. if source_ref is passed in the List will most likely only
|
||||||
|
contain one Element if everything goes accordingly.
|
||||||
|
**If neither song_ref nor source_ref are passed in it will return ALL sources**
|
||||||
|
:param artist_ref:
|
||||||
|
:param song_ref:
|
||||||
|
:param source_ref:
|
||||||
|
:param type_str: the thing the source belongs to like eg. "song" or "album"
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
where = "1=1"
|
||||||
|
if song_ref is not None:
|
||||||
|
where = f"song_id=\"{song_ref.id}\""
|
||||||
|
elif source_ref is not None:
|
||||||
|
where = f"id=\"{source_ref.id}\" AND type=\"{SourceTypes.SONG.value}\""
|
||||||
|
elif artist_ref is not None:
|
||||||
|
where = f"song_id=\"{artist_ref.id}\" AND type=\"{SourceTypes.ARTIST.value}\""
|
||||||
|
elif album_ref is not None:
|
||||||
|
where = f"song_id=\"{album_ref.id}\" AND type=\"{SourceTypes.ALBUM.value}\""
|
||||||
|
|
||||||
|
query = SOURCE_QUERY.format(where=where)
|
||||||
|
self.cursor.execute(query)
|
||||||
|
|
||||||
|
source_rows = self.cursor.fetchall()
|
||||||
|
|
||||||
|
return [
|
||||||
|
Source(
|
||||||
|
page_enum=SourcePages(source_row['src']),
|
||||||
|
type_enum=SourceTypes(source_row['type']),
|
||||||
|
url=source_row['url'],
|
||||||
|
id_=source_row['id']
|
||||||
|
) for source_row in source_rows
|
||||||
|
]
|
||||||
|
|
||||||
|
def pull_artist_song(self, song_ref: Reference = None, artist_ref: Reference = None) -> List[tuple]:
|
||||||
|
table = "SongArtist"
|
||||||
|
wheres = []
|
||||||
|
if song_ref is not None:
|
||||||
|
wheres.append(f"song_id=\"{song_ref.id}\"")
|
||||||
|
if artist_ref is not None:
|
||||||
|
wheres.append(f"artist_id=\"{artist_ref.id}\"")
|
||||||
|
where_str = ""
|
||||||
|
if len(wheres) > 0:
|
||||||
|
where_str = "WHERE " + " AND ".join(wheres)
|
||||||
|
|
||||||
|
query = f"SELECT * FROM {table} {where_str};"
|
||||||
|
self.cursor.execute(query)
|
||||||
|
joins = self.cursor.fetchall()
|
||||||
|
|
||||||
|
return [(
|
||||||
|
Reference(join["song_id"]),
|
||||||
|
Reference(join["artist_id"]),
|
||||||
|
bool(join["is_feature"])
|
||||||
|
) for join in joins]
|
||||||
|
|
||||||
|
def pull_artist_album(self, album_ref: Reference = None, artist_ref: Reference = None) -> List[tuple]:
|
||||||
|
table = "AlbumArtist"
|
||||||
|
wheres = []
|
||||||
|
if album_ref is not None:
|
||||||
|
wheres.append(f"album_id=\"{album_ref.id}\"")
|
||||||
|
if artist_ref is not None:
|
||||||
|
wheres.append(f"artist_id=\"{artist_ref.id}\"")
|
||||||
|
where_str = ""
|
||||||
|
if len(wheres) > 0:
|
||||||
|
where_str = "WHERE " + " AND ".join(wheres)
|
||||||
|
|
||||||
|
query = f"SELECT * FROM {table} {where_str};"
|
||||||
|
self.cursor.execute(query)
|
||||||
|
joins = self.cursor.fetchall()
|
||||||
|
|
||||||
|
return [(
|
||||||
|
Reference(join["album_id"]),
|
||||||
|
Reference(join["artist_id"])
|
||||||
|
) for join in joins]
|
||||||
|
|
||||||
|
def get_artist_from_row(self, artist_row, exclude_relations: set = None, flat: bool = False) -> Artist:
|
||||||
|
if exclude_relations is None:
|
||||||
|
exclude_relations = set()
|
||||||
|
new_exclude_relations: set = set(exclude_relations)
|
||||||
|
new_exclude_relations.add(Artist)
|
||||||
|
|
||||||
|
artist_id = artist_row['artist_id']
|
||||||
|
|
||||||
|
artist_obj = Artist(
|
||||||
|
id_=artist_id,
|
||||||
|
name=artist_row['artist_name'],
|
||||||
|
source_list=self.pull_sources(artist_ref=Reference(id_=artist_id))
|
||||||
|
)
|
||||||
|
if flat:
|
||||||
|
return artist_obj
|
||||||
|
|
||||||
|
# fetch songs :D
|
||||||
|
for song_ref, _, is_feature in self.pull_artist_song(artist_ref=Reference(id_=artist_id)):
|
||||||
|
new_songs = self.pull_songs(song_ref=song_ref, exclude_relations=new_exclude_relations)
|
||||||
|
if len(new_songs) < 1:
|
||||||
|
continue
|
||||||
|
new_song = new_songs[0]
|
||||||
|
|
||||||
|
if is_feature:
|
||||||
|
artist_obj.feature_songs.append(new_song)
|
||||||
|
else:
|
||||||
|
artist_obj.main_songs.append(new_song)
|
||||||
|
|
||||||
|
# fetch albums
|
||||||
|
for album_ref, _ in self.pull_artist_album(artist_ref=Reference(id_=artist_id)):
|
||||||
|
new_albums = self.pull_albums(album_ref=album_ref, exclude_relations=new_exclude_relations)
|
||||||
|
if len(new_albums) < 1:
|
||||||
|
continue
|
||||||
|
artist_obj.main_albums.append(new_albums[0])
|
||||||
|
|
||||||
|
return artist_obj
|
||||||
|
|
||||||
|
def pull_artists(self, artist_ref: Reference = None, exclude_relations: set = None, flat: bool = False) -> List[Artist]:
|
||||||
|
"""
|
||||||
|
|
||||||
|
:param artist_ref:
|
||||||
|
:param exclude_relations:
|
||||||
|
:param flat: if it is true it ONLY fetches the artist data
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
where = "1=1"
|
||||||
|
if artist_ref is not None:
|
||||||
|
where = f"Artist.id=\"{artist_ref.id}\""
|
||||||
|
|
||||||
|
query = ARTIST_QUERY.format(where=where)
|
||||||
|
self.cursor.execute(query)
|
||||||
|
|
||||||
|
artist_rows = self.cursor.fetchall()
|
||||||
|
return [(
|
||||||
|
self.get_artist_from_row(artist_row, exclude_relations=exclude_relations, flat=flat)
|
||||||
|
) for artist_row in artist_rows]
|
||||||
|
|
||||||
|
def get_song_from_row(self, song_result, exclude_relations: set = None) -> Song:
|
||||||
|
if exclude_relations is None:
|
||||||
|
exclude_relations = set()
|
||||||
|
new_exclude_relations: set = set(exclude_relations)
|
||||||
|
new_exclude_relations.add(Song)
|
||||||
|
|
||||||
|
song_id = song_result['song_id']
|
||||||
|
|
||||||
|
# maybee fetch album
|
||||||
|
|
||||||
|
song_obj = Song(
|
||||||
|
id_=song_id,
|
||||||
|
title=song_result['title'],
|
||||||
|
isrc=song_result['isrc'],
|
||||||
|
length=song_result['length'],
|
||||||
|
tracksort=song_result['tracksort'],
|
||||||
|
genre=song_result['genre'],
|
||||||
|
target=Target(
|
||||||
|
id_=song_result['target_id'],
|
||||||
|
file=song_result['file'],
|
||||||
|
path=song_result['path']
|
||||||
|
),
|
||||||
|
source_list=self.pull_sources(song_ref=Reference(id_=song_id)),
|
||||||
|
lyrics=self.pull_lyrics(song_ref=Reference(id_=song_id)),
|
||||||
|
)
|
||||||
|
|
||||||
|
if Album not in exclude_relations and song_result['album_id'] is not None:
|
||||||
|
album_obj = self.pull_albums(album_ref=Reference(song_result['album_id']),
|
||||||
|
exclude_relations=new_exclude_relations)
|
||||||
|
if len(album_obj) > 0:
|
||||||
|
song_obj.album = album_obj[0]
|
||||||
|
|
||||||
|
flat_artist = Artist in exclude_relations
|
||||||
|
|
||||||
|
main_artists = []
|
||||||
|
feature_artists = []
|
||||||
|
for song_ref, artist_ref, is_feature in self.pull_artist_song(song_ref=Reference(song_id)):
|
||||||
|
if is_feature:
|
||||||
|
feature_artists.extend(self.pull_artists(artist_ref=artist_ref, flat=flat_artist))
|
||||||
|
else:
|
||||||
|
main_artists.extend(self.pull_artists(artist_ref=artist_ref, flat=flat_artist))
|
||||||
|
|
||||||
|
song_obj.main_artist_list = main_artists
|
||||||
|
song_obj.feature_artist_list = feature_artists
|
||||||
|
|
||||||
|
return song_obj
|
||||||
|
|
||||||
|
def pull_songs(self, song_ref: Reference = None, album_ref: Reference = None, exclude_relations: set = set()) -> \
|
||||||
|
List[Song]:
|
||||||
|
"""
|
||||||
|
This function is used to get one song (including its children like Sources etc)
|
||||||
|
from one song id (a reference object)
|
||||||
|
:param exclude_relations:
|
||||||
|
By default all relations are pulled by this funktion. If the class object of for
|
||||||
|
example the Artists is in the set it won't get fetched.
|
||||||
|
This is done to prevent an infinite recursion.
|
||||||
|
:param song_ref:
|
||||||
|
:param album_ref:
|
||||||
|
:return requested_song:
|
||||||
|
"""
|
||||||
|
|
||||||
|
where = "1=1"
|
||||||
|
if song_ref is not None:
|
||||||
|
where = f"Song.id=\"{song_ref.id}\""
|
||||||
|
elif album_ref is not None:
|
||||||
|
where = f"Song.album_id=\"{album_ref.id}\""
|
||||||
|
|
||||||
|
query = SONG_QUERY.format(where=where)
|
||||||
|
self.cursor.execute(query)
|
||||||
|
|
||||||
|
song_rows = self.cursor.fetchall()
|
||||||
|
|
||||||
|
return [self.get_song_from_row(
|
||||||
|
song_result=song_result,
|
||||||
|
exclude_relations=exclude_relations
|
||||||
|
) for song_result in song_rows]
|
||||||
|
|
||||||
|
def get_album_from_row(self, album_result, exclude_relations=None) -> Album:
|
||||||
|
if exclude_relations is None:
|
||||||
|
exclude_relations = set()
|
||||||
|
new_exclude_relations: set = exclude_relations.copy()
|
||||||
|
new_exclude_relations.add(Album)
|
||||||
|
|
||||||
|
album_id = album_result['album_id']
|
||||||
|
language = album_result['language']
|
||||||
|
if language is not None:
|
||||||
|
language = pycountry.languages.get(alpha_3=album_result['language'])
|
||||||
|
|
||||||
|
album_obj = Album(
|
||||||
|
id_=album_id,
|
||||||
|
title=album_result['title'],
|
||||||
|
label=album_result['label'],
|
||||||
|
album_status=album_result['album_status'],
|
||||||
|
language=language,
|
||||||
|
date=ID3Timestamp.strptime(album_result['date'], album_result['date_format']),
|
||||||
|
country=album_result['country'],
|
||||||
|
barcode=album_result['barcode'],
|
||||||
|
is_split=album_result['is_split'],
|
||||||
|
albumsort=album_result['albumsort'],
|
||||||
|
source_list=self.pull_sources(album_ref=Reference(id_=album_id))
|
||||||
|
)
|
||||||
|
|
||||||
|
if Song not in exclude_relations:
|
||||||
|
# getting the tracklist
|
||||||
|
tracklist: List[Song] = self.pull_songs(
|
||||||
|
album_ref=Reference(id_=album_id),
|
||||||
|
exclude_relations=new_exclude_relations
|
||||||
|
)
|
||||||
|
album_obj.set_tracklist(tracklist=tracklist)
|
||||||
|
|
||||||
|
flat_artist = Artist in exclude_relations
|
||||||
|
for _, artist_ref in self.pull_artist_album(album_ref=Reference(id_=album_id)):
|
||||||
|
artists = self.pull_artists(artist_ref, flat=flat_artist, exclude_relations=new_exclude_relations)
|
||||||
|
if len(artists) < 1:
|
||||||
|
continue
|
||||||
|
album_obj.artists.append(artists[0])
|
||||||
|
|
||||||
|
return album_obj
|
||||||
|
|
||||||
|
def pull_albums(self, album_ref: Reference = None, song_ref: Reference = None, exclude_relations: set = None) -> \
|
||||||
|
List[Album]:
|
||||||
|
"""
|
||||||
|
This function is used to get matching albums/releses
|
||||||
|
from one song id (a reference object)
|
||||||
|
:param exclude_relations:
|
||||||
|
By default all relations are pulled by this funktion. If the class object of for
|
||||||
|
example the Artists is in the set it won't get fetched.
|
||||||
|
This is done to prevent an infinite recursion.
|
||||||
|
:param album_ref:
|
||||||
|
:return requested_album_list:
|
||||||
|
"""
|
||||||
|
if exclude_relations is None:
|
||||||
|
exclude_relations = set()
|
||||||
|
|
||||||
|
query = ALBUM_QUERY_UNJOINED
|
||||||
|
where = "1=1"
|
||||||
|
if album_ref is not None:
|
||||||
|
query = ALBUM_QUERY_UNJOINED
|
||||||
|
where = f"Album.id=\"{album_ref.id}\""
|
||||||
|
elif song_ref is not None:
|
||||||
|
query = ALBUM_QUERY_JOINED
|
||||||
|
where = f"Song.id=\"{song_ref.id}\""
|
||||||
|
|
||||||
|
query = query.format(where=where)
|
||||||
|
self.cursor.execute(query)
|
||||||
|
|
||||||
|
album_rows = self.cursor.fetchall()
|
||||||
|
|
||||||
|
return [self.get_album_from_row(
|
||||||
|
album_result=album_row,
|
||||||
|
exclude_relations=exclude_relations
|
||||||
|
) for album_row in album_rows]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
cache = Database("")
|
@ -1,4 +1,4 @@
|
|||||||
from .database import Database
|
from .old_database import Database
|
||||||
|
|
||||||
from ..utils.shared import (
|
from ..utils.shared import (
|
||||||
TEMP_DATABASE_PATH,
|
TEMP_DATABASE_PATH,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from ...utils.shared import (
|
from src.music_kraken.utils.shared import (
|
||||||
DATABASE_LOGGER as logger
|
DATABASE_LOGGER as logger
|
||||||
)
|
)
|
||||||
from .parents import (
|
from .parents import (
|
@ -1,7 +1,7 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from .source import SourceAttribute
|
from .source import SourceAttribute
|
||||||
from ...utils import string_processing
|
from src.music_kraken.utils import string_processing
|
||||||
|
|
||||||
class Collection:
|
class Collection:
|
||||||
"""
|
"""
|
@ -1,6 +1,6 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from ...utils.shared import (
|
from src.music_kraken.utils.shared import (
|
||||||
SONG_LOGGER as logger
|
SONG_LOGGER as logger
|
||||||
)
|
)
|
||||||
|
|
@ -8,7 +8,7 @@ from .metadata import (
|
|||||||
ID3Timestamp,
|
ID3Timestamp,
|
||||||
MetadataAttribute
|
MetadataAttribute
|
||||||
)
|
)
|
||||||
from ...utils.shared import (
|
from src.music_kraken.utils.shared import (
|
||||||
MUSIC_DIR,
|
MUSIC_DIR,
|
||||||
DATABASE_LOGGER as logger
|
DATABASE_LOGGER as logger
|
||||||
)
|
)
|
@ -0,0 +1,41 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
class TreeNode:
|
||||||
|
"""A class representing a binary tree node."""
|
||||||
|
|
||||||
|
def __init__(self, val: int = 0, left: Optional['TreeNode'] = None, right: Optional['TreeNode'] = None):
|
||||||
|
"""
|
||||||
|
Initializes a new instance of the TreeNode class.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
val: The value of the node.
|
||||||
|
left: The left child of the node.
|
||||||
|
right: The right child of the node.
|
||||||
|
"""
|
||||||
|
self.val = val
|
||||||
|
self.left = left
|
||||||
|
self.right = right
|
||||||
|
|
||||||
|
|
||||||
|
def invert_tree(root: Optional[TreeNode]) -> Optional[TreeNode]:
|
||||||
|
"""
|
||||||
|
Inverts a binary tree.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
root: The root node of the binary tree.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The root node of the inverted binary tree.
|
||||||
|
"""
|
||||||
|
if root is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Swap left and right children of the root node
|
||||||
|
root.left, root.right = root.right, root.left
|
||||||
|
|
||||||
|
# Recursively invert the left and right subtrees
|
||||||
|
invert_tree(root.left)
|
||||||
|
invert_tree(root.right)
|
||||||
|
|
||||||
|
return root
|
Loading…
Reference in New Issue
Block a user