tiny-essentials 1.28.14 → 1.28.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -42,34 +42,36 @@ var objChecker = require('./objChecker.cjs');
42
42
 
43
43
  /**
44
44
  * @typedef {Object} ILyricsText
45
- * @property {string} text - The lyric text content.
45
+ * @property {string} [text] - The lyric text content.
46
46
  * @property {number} [timestamp] - The timestamp associated with this lyric line.
47
47
  */
48
48
 
49
49
  /**
50
50
  * @typedef {Object} TimestampFormat
51
- * @property {number} notSynchronized - Indicates if the timestamp is not synchronized.
52
- * @property {number} mpegFrameNumber - The MPEG frame number.
53
- * @property {number} milliseconds - The time in milliseconds.
51
+ * @property {number} [notSynchronized] - Indicates if the timestamp is not synchronized.
52
+ * @property {number} [mpegFrameNumber] - The MPEG frame number.
53
+ * @property {number} [milliseconds] - The time in milliseconds.
54
54
  */
55
55
 
56
56
  /**
57
57
  * @typedef {Object} LyricsContentType
58
- * @property {number} other - Content type for other.
59
- * @property {number} lyrics - Content type for lyrics.
60
- * @property {number} text - Content type for text.
61
- * @property {number} movement_part - Content type for movement parts.
62
- * @property {number} events - Content type for events.
63
- * @property {number} chord - Content type for chords.
64
- * @property {number} trivia_pop - Content type for trivia/pop.
58
+ * @property {number} [other] - Content type for other.
59
+ * @property {number} [lyrics] - Content type for lyrics.
60
+ * @property {number} [text] - Content type for text.
61
+ * @property {number} [movement_part] - Content type for movement parts.
62
+ * @property {number} [events] - Content type for events.
63
+ * @property {number} [chord] - Content type for chords.
64
+ * @property {number} [trivia_pop] - Content type for trivia/pop.
65
65
  */
66
66
 
67
67
  /**
68
68
  * @typedef {Object} ILyricsTag
69
69
  * @property {string} [text] - The text content of the lyrics.
70
- * @property {ILyricsText[]} syncText - An array of synchronized lyric text objects.
71
- * @property {TimestampFormat} timeStampFormat - The format of the timestamp.
72
- * @property {LyricsContentType} contentType - The type of lyrical content.
70
+ * @property {string} [descriptor] - A descriptor for the lyrics.
71
+ * @property {string} [language] - The language of the lyrics.
72
+ * @property {ILyricsText[]} [syncText] - An array of synchronized lyric text objects.
73
+ * @property {TimestampFormat} [timeStampFormat] - The format of the timestamp.
74
+ * @property {LyricsContentType} [contentType] - The type of lyrical content.
73
75
  */
74
76
 
75
77
  /**
@@ -693,33 +695,37 @@ const valMediaContentMetadata = (common) => {
693
695
 
694
696
  if (
695
697
  !isArray(common.lyrics, (v) => {
696
- const isLyricsContentType = (/** @type {LyricsContentType} */ v) =>
697
- v !== null &&
698
- typeof v === 'object' &&
699
- isNumber(v.other, true) &&
700
- isNumber(v.lyrics, true) &&
701
- isNumber(v.text, true) &&
702
- isNumber(v.movement_part, true) &&
703
- isNumber(v.events, true) &&
704
- isNumber(v.chord, true) &&
705
- isNumber(v.trivia_pop, true);
706
-
707
- const isTimestampFormat = (/** @type {TimestampFormat} */ v) =>
708
- v !== null &&
709
- typeof v === 'object' &&
710
- isNumber(v.notSynchronized, true) &&
711
- isNumber(v.mpegFrameNumber, true) &&
712
- isNumber(v.milliseconds, true);
698
+ const isLyricsContentType = (/** @type {LyricsContentType|null|undefined} */ v) =>
699
+ v === undefined ||
700
+ (v !== null &&
701
+ typeof v === 'object' &&
702
+ isNumber(v.other) &&
703
+ isNumber(v.lyrics) &&
704
+ isNumber(v.text) &&
705
+ isNumber(v.movement_part) &&
706
+ isNumber(v.events) &&
707
+ isNumber(v.chord) &&
708
+ isNumber(v.trivia_pop));
709
+
710
+ const isTimestampFormat = (/** @type {TimestampFormat|null|undefined} */ v) =>
711
+ v === undefined ||
712
+ (v !== null &&
713
+ typeof v === 'object' &&
714
+ isNumber(v.notSynchronized) &&
715
+ isNumber(v.mpegFrameNumber) &&
716
+ isNumber(v.milliseconds));
713
717
 
714
718
  return (
715
719
  v !== null &&
716
720
  typeof v === 'object' &&
717
721
  isString(v.text) &&
718
- isArray(
719
- v.syncText,
720
- (v) =>
721
- v !== null && typeof v === 'object' && isString(v.text, true) && isNumber(v.timestamp),
722
- ) &&
722
+ isString(v.descriptor) &&
723
+ isString(v.language) &&
724
+ (!Array.isArray(v) ||
725
+ isArray(
726
+ v.syncText,
727
+ (v) => v !== null && typeof v === 'object' && isString(v.text) && isNumber(v.timestamp),
728
+ )) &&
723
729
  isTimestampFormat(v.timeStampFormat) &&
724
730
  isLyricsContentType(v.contentType)
725
731
  );
@@ -773,192 +779,182 @@ const extractMediaId3Tags = async (url, parseFile, convertBase64toBlob = true) =
773
779
  checkString(url, 'url');
774
780
  checkFunction(parseFile, 'parseFile');
775
781
 
776
- try {
777
- // 1. Download the file from the provided URL
778
- const response = await fetch(url);
782
+ // 1. Download the file from the provided URL
783
+ const response = await fetch(url);
779
784
 
780
- if (!response.ok)
781
- throw new Error(`Failed to fetch audio file: ${response.status} ${response.statusText}`);
785
+ if (!response.ok)
786
+ throw new Error(`Failed to fetch audio file: ${response.status} ${response.statusText}`);
782
787
 
783
- // 2. Convert the response into a Blob so the parser can read it
784
- const blob = await response.blob();
788
+ // 2. Convert the response into a Blob so the parser can read it
789
+ const blob = await response.blob();
785
790
 
786
- // 3. Use the provided parser function on the Blob
787
- const metadata = await parseFile(blob);
791
+ // 3. Use the provided parser function on the Blob to read metadata
792
+ const metadata = await parseFile(blob);
788
793
 
789
- // 4. Complete Validation of the parsed metadata structure
790
- if (!metadata || typeof metadata.common !== 'object')
791
- throw new TypeError('Invalid metadata: "common" property is missing.');
792
- if (typeof metadata.common['performer:instrument'] !== undefined)
793
- // @ts-ignore
794
- metadata.common.performer_instrument = metadata.common['performer:instrument'];
795
- valFetchMediaContent(metadata);
794
+ // 4. Complete Validation of the parsed metadata structure
795
+ if (!metadata || typeof metadata.common !== 'object')
796
+ throw new TypeError('Invalid metadata: "common" property is missing.');
797
+ if (typeof metadata.common['performer:instrument'] !== undefined)
798
+ // @ts-ignore
799
+ metadata.common.performer_instrument = metadata.common['performer:instrument'];
800
+ valFetchMediaContent(metadata);
796
801
 
797
- const common = metadata.common;
798
- valMediaContentMetadata(common);
802
+ const common = metadata.common;
803
+ valMediaContentMetadata(common);
799
804
 
800
- /**
801
- * @type {(value: [string, any]) => boolean}
802
- */
803
- const filterContent = ([_, value]) =>
804
- Array.isArray(value)
805
- ? value.length > 0
806
- : objChecker.isJsonObject(value)
807
- ? (() => {
808
- value;
809
- const d = Object.fromEntries(Object.entries(value).filter(filterContent));
810
- const amount = objChecker.countObj(d);
811
- return amount > 0;
812
- })()
813
- : value !== null;
814
-
815
- // Fix blob values.
816
- const picture =
817
- common?.picture?.map((value) => ({
818
- ...value,
819
- data: convertBase64toBlob ? convertToBlobUrl(value.data, value.format) : value.data,
820
- })) ?? [];
821
-
822
- metadata.common = {
823
- ...metadata.common,
824
- picture: picture.map((value) => ({
825
- ...value,
826
- data: '',
827
- })),
828
- };
805
+ /**
806
+ * @type {(value: [string, any]) => boolean}
807
+ */
808
+ const filterContent = ([_, value]) =>
809
+ Array.isArray(value)
810
+ ? value.length > 0
811
+ : objChecker.isJsonObject(value)
812
+ ? (() => {
813
+ const d = Object.fromEntries(Object.entries(value).filter(filterContent));
814
+ const amount = objChecker.countObj(d);
815
+ return amount > 0;
816
+ })()
817
+ : value !== null;
818
+
819
+ // Fix blob values.
820
+ const picture =
821
+ common?.picture?.map((value) => ({
822
+ ...value,
823
+ data: convertBase64toBlob ? convertToBlobUrl(value.data, value.format) : value.data,
824
+ })) ?? [];
825
+
826
+ metadata.common = {
827
+ ...metadata.common,
828
+ picture: picture.map((value) => ({
829
+ ...value,
830
+ data: '',
831
+ })),
832
+ };
829
833
 
830
- // Sanitize metadata.native to prevent Uint8Array leakage
831
- if (convertBase64toBlob) {
832
- Object.keys(metadata.native).forEach((key) => {
833
- metadata.native[key] = metadata.native[key].map((item) => {
834
- // Check if item.value is an object and contains a 'data' property that is a Uint8Array
835
- if (
836
- item.value &&
837
- typeof item.value === 'object' &&
838
- item.value.data instanceof Uint8Array
839
- ) {
840
- const index =
841
- common?.picture?.findIndex(
842
- (item2) =>
843
- item2.data === item.value.data &&
844
- item2.format === item.value.format &&
845
- item2.description === item.value.description &&
846
- item2.name === item.value.name,
847
- ) ?? -1;
848
- const data = picture[index];
849
- if (data) {
850
- return { ...item, value: { ...item.value, data: '' } };
851
- }
834
+ // Sanitize metadata.native to prevent Uint8Array leakage
835
+ if (convertBase64toBlob) {
836
+ Object.keys(metadata.native).forEach((key) => {
837
+ metadata.native[key] = metadata.native[key].map((item) => {
838
+ // Check if item.value is an object and contains a 'data' property that is a Uint8Array
839
+ if (item.value && typeof item.value === 'object' && item.value.data instanceof Uint8Array) {
840
+ const index =
841
+ common?.picture?.findIndex(
842
+ (item2) =>
843
+ item2.data === item.value.data &&
844
+ item2.format === item.value.format &&
845
+ item2.description === item.value.description &&
846
+ item2.name === item.value.name,
847
+ ) ?? -1;
848
+ const data = picture[index];
849
+ if (data) {
850
+ return { ...item, value: { ...item.value, data: '' } };
852
851
  }
853
- return item;
854
- });
852
+ }
853
+ return item;
855
854
  });
856
- }
857
-
858
- // 5. Return the specific metadata fields requested
859
- // We structure the return to match the MediaContentMetadata typedef
860
- /** @type {MediaContentMetadata<PictureDataType>} */
861
- const result = Object.fromEntries(
862
- Object.entries({
863
- title: common?.title ?? null,
864
- album: common?.album ?? null,
865
- albumartist: common?.albumartist ?? null,
866
- albumartists: common?.albumartists ?? [],
867
- genre: common?.genre ?? [],
868
- label: common?.label ?? [],
869
- composer: common?.composer ?? [],
870
- year: common?.year ?? null,
871
- artist: common?.artist ?? null,
872
- artists: common?.artists ?? [],
873
- disk: common?.disk ? { no: common.disk.no, of: common.disk.of } : null,
874
- track: common?.track ? { no: common.track.no, of: common.track.of } : null,
875
- movementIndex: common?.movementIndex
876
- ? { no: common.movementIndex.no, of: common.movementIndex.of }
877
- : null,
878
- picture,
879
- date: common?.date ?? null,
880
- originaldate: common?.originaldate ?? null,
881
- originalyear: common?.originalyear ?? null,
882
- releasedate: common?.releasedate ?? null,
883
- comment: common?.comment ?? [],
884
- lyrics: common?.lyrics ?? [],
885
- albumsort: common?.albumsort ?? null,
886
- titlesort: common?.titlesort ?? null,
887
- work: common?.work ?? null,
888
- artistsort: common?.artistsort ?? null,
889
- albumartistsort: common?.albumartistsort ?? null,
890
- composersort: common?.composersort ?? null,
891
- lyricist: common?.lyricist ?? [],
892
- writer: common?.writer ?? [],
893
- conductor: common?.conductor ?? [],
894
- remixer: common?.remixer ?? [],
895
- arranger: common?.arranger ?? [],
896
- engineer: common?.engineer ?? [],
897
- publisher: common?.publisher ?? [],
898
- producer: common?.producer ?? [],
899
- djmixer: common?.djmixer ?? [],
900
- mixer: common?.mixer ?? [],
901
- technician: common?.technician ?? [],
902
- grouping: common?.grouping ?? null,
903
- subtitle: common?.subtitle ?? [],
904
- description: common?.description ?? [],
905
- longDescription: common?.longDescription ?? null,
906
- discsubtitle: common?.discsubtitle ?? [],
907
- totaltracks: common?.totaltracks ?? null,
908
- totaldiscs: common?.totaldiscs ?? null,
909
- movementTotal: common?.movementTotal ?? null,
910
- compilation: common?.compilation ?? null,
911
- rating: common?.rating ?? [],
912
- bpm: common?.bpm ?? null,
913
- mood: common?.mood ?? null,
914
- media: common?.media ?? null,
915
- catalognumber: common?.catalognumber ?? [],
916
- tvShow: common?.tvShow ?? null,
917
- tvShowSort: common?.tvShowSort ?? null,
918
- tvSeason: common?.tvSeason ?? null,
919
- tvEpisode: common?.tvEpisode ?? null,
920
- tvEpisodeId: common?.tvEpisodeId ?? null,
921
- tvNetwork: common?.tvNetwork ?? null,
922
- podcast: common?.podcast ?? null,
923
- podcasturl: common?.podcasturl ?? null,
924
- releasestatus: common?.releasestatus ?? null,
925
- releasetype: common?.releasetype ?? [],
926
- releasecountry: common?.releasecountry ?? null,
927
- script: common?.script ?? null,
928
- language: common?.language ?? null,
929
- copyright: common?.copyright ?? null,
930
- license: common?.license ?? null,
931
- encodedby: common?.encodedby ?? null,
932
- encodersettings: common?.encodersettings ?? null,
933
- gapless: common?.gapless ?? null,
934
- barcode: common?.barcode ?? null,
935
- isrc: common?.isrc ?? [],
936
- asin: common?.asin ?? null,
937
- website: common?.website ?? null,
938
- performer_instrument: common?.performer_instrument ?? [],
939
- averageLevel: common?.averageLevel ?? null,
940
- peakLevel: common?.peakLevel ?? null,
941
- notes: common?.notes ?? [],
942
- originalalbum: common?.originalalbum ?? null,
943
- originalartist: common?.originalartist ?? null,
944
- key: common?.key ?? null,
945
- category: common?.category ?? [],
946
- hdVideo: common?.hdVideo ?? null,
947
- keywords: common?.keywords ?? [],
948
- movement: common?.movement ?? null,
949
- podcastId: common?.podcastId ?? null,
950
- showMovement: common?.showMovement ?? null,
951
- stik: common?.stik ?? null,
952
- playCounter: common?.playCounter ?? null,
953
- }).filter(filterContent),
954
- );
955
-
956
- result._fetchData = metadata;
957
- return result;
958
- } catch (error) {
959
- // Re-throwing the error allows the caller to handle specific failure cases
960
- throw error;
855
+ });
961
856
  }
857
+
858
+ // 5. Return the specific metadata fields requested
859
+ // We structure the return to match the MediaContentMetadata typedef
860
+ /** @type {MediaContentMetadata<PictureDataType>} */
861
+ const result = Object.fromEntries(
862
+ Object.entries({
863
+ title: common?.title ?? null,
864
+ album: common?.album ?? null,
865
+ albumartist: common?.albumartist ?? null,
866
+ albumartists: common?.albumartists ?? [],
867
+ genre: common?.genre ?? [],
868
+ label: common?.label ?? [],
869
+ composer: common?.composer ?? [],
870
+ year: common?.year ?? null,
871
+ artist: common?.artist ?? null,
872
+ artists: common?.artists ?? [],
873
+ disk: common?.disk ? { no: common.disk.no, of: common.disk.of } : null,
874
+ track: common?.track ? { no: common.track.no, of: common.track.of } : null,
875
+ movementIndex: common?.movementIndex
876
+ ? { no: common.movementIndex.no, of: common.movementIndex.of }
877
+ : null,
878
+ picture,
879
+ date: common?.date ?? null,
880
+ originaldate: common?.originaldate ?? null,
881
+ originalyear: common?.originalyear ?? null,
882
+ releasedate: common?.releasedate ?? null,
883
+ comment: common?.comment ?? [],
884
+ lyrics: common?.lyrics ?? [],
885
+ albumsort: common?.albumsort ?? null,
886
+ titlesort: common?.titlesort ?? null,
887
+ work: common?.work ?? null,
888
+ artistsort: common?.artistsort ?? null,
889
+ albumartistsort: common?.albumartistsort ?? null,
890
+ composersort: common?.composersort ?? null,
891
+ lyricist: common?.lyricist ?? [],
892
+ writer: common?.writer ?? [],
893
+ conductor: common?.conductor ?? [],
894
+ remixer: common?.remixer ?? [],
895
+ arranger: common?.arranger ?? [],
896
+ engineer: common?.engineer ?? [],
897
+ publisher: common?.publisher ?? [],
898
+ producer: common?.producer ?? [],
899
+ djmixer: common?.djmixer ?? [],
900
+ mixer: common?.mixer ?? [],
901
+ technician: common?.technician ?? [],
902
+ grouping: common?.grouping ?? null,
903
+ subtitle: common?.subtitle ?? [],
904
+ description: common?.description ?? [],
905
+ longDescription: common?.longDescription ?? null,
906
+ discsubtitle: common?.discsubtitle ?? [],
907
+ totaltracks: common?.totaltracks ?? null,
908
+ totaldiscs: common?.totaldiscs ?? null,
909
+ movementTotal: common?.movementTotal ?? null,
910
+ compilation: common?.compilation ?? null,
911
+ rating: common?.rating ?? [],
912
+ bpm: common?.bpm ?? null,
913
+ mood: common?.mood ?? null,
914
+ media: common?.media ?? null,
915
+ catalognumber: common?.catalognumber ?? [],
916
+ tvShow: common?.tvShow ?? null,
917
+ tvShowSort: common?.tvShowSort ?? null,
918
+ tvSeason: common?.tvSeason ?? null,
919
+ tvEpisode: common?.tvEpisode ?? null,
920
+ tvEpisodeId: common?.tvEpisodeId ?? null,
921
+ tvNetwork: common?.tvNetwork ?? null,
922
+ podcast: common?.podcast ?? null,
923
+ podcasturl: common?.podcasturl ?? null,
924
+ releasestatus: common?.releasestatus ?? null,
925
+ releasetype: common?.releasetype ?? [],
926
+ releasecountry: common?.releasecountry ?? null,
927
+ script: common?.script ?? null,
928
+ language: common?.language ?? null,
929
+ copyright: common?.copyright ?? null,
930
+ license: common?.license ?? null,
931
+ encodedby: common?.encodedby ?? null,
932
+ encodersettings: common?.encodersettings ?? null,
933
+ gapless: common?.gapless ?? null,
934
+ barcode: common?.barcode ?? null,
935
+ isrc: common?.isrc ?? [],
936
+ asin: common?.asin ?? null,
937
+ website: common?.website ?? null,
938
+ performer_instrument: common?.performer_instrument ?? [],
939
+ averageLevel: common?.averageLevel ?? null,
940
+ peakLevel: common?.peakLevel ?? null,
941
+ notes: common?.notes ?? [],
942
+ originalalbum: common?.originalalbum ?? null,
943
+ originalartist: common?.originalartist ?? null,
944
+ key: common?.key ?? null,
945
+ category: common?.category ?? [],
946
+ hdVideo: common?.hdVideo ?? null,
947
+ keywords: common?.keywords ?? [],
948
+ movement: common?.movement ?? null,
949
+ podcastId: common?.podcastId ?? null,
950
+ showMovement: common?.showMovement ?? null,
951
+ stik: common?.stik ?? null,
952
+ playCounter: common?.playCounter ?? null,
953
+ }).filter(filterContent),
954
+ );
955
+
956
+ result._fetchData = metadata;
957
+ return result;
962
958
  };
963
959
 
964
960
  /**
@@ -45,7 +45,7 @@ export type ILyricsText = {
45
45
  /**
46
46
  * - The lyric text content.
47
47
  */
48
- text: string;
48
+ text?: string;
49
49
  /**
50
50
  * - The timestamp associated with this lyric line.
51
51
  */
@@ -55,63 +55,71 @@ export type TimestampFormat = {
55
55
  /**
56
56
  * - Indicates if the timestamp is not synchronized.
57
57
  */
58
- notSynchronized: number;
58
+ notSynchronized?: number;
59
59
  /**
60
60
  * - The MPEG frame number.
61
61
  */
62
- mpegFrameNumber: number;
62
+ mpegFrameNumber?: number;
63
63
  /**
64
64
  * - The time in milliseconds.
65
65
  */
66
- milliseconds: number;
66
+ milliseconds?: number;
67
67
  };
68
68
  export type LyricsContentType = {
69
69
  /**
70
70
  * - Content type for other.
71
71
  */
72
- other: number;
72
+ other?: number;
73
73
  /**
74
74
  * - Content type for lyrics.
75
75
  */
76
- lyrics: number;
76
+ lyrics?: number;
77
77
  /**
78
78
  * - Content type for text.
79
79
  */
80
- text: number;
80
+ text?: number;
81
81
  /**
82
82
  * - Content type for movement parts.
83
83
  */
84
- movement_part: number;
84
+ movement_part?: number;
85
85
  /**
86
86
  * - Content type for events.
87
87
  */
88
- events: number;
88
+ events?: number;
89
89
  /**
90
90
  * - Content type for chords.
91
91
  */
92
- chord: number;
92
+ chord?: number;
93
93
  /**
94
94
  * - Content type for trivia/pop.
95
95
  */
96
- trivia_pop: number;
96
+ trivia_pop?: number;
97
97
  };
98
98
  export type ILyricsTag = {
99
99
  /**
100
100
  * - The text content of the lyrics.
101
101
  */
102
102
  text?: string;
103
+ /**
104
+ * - A descriptor for the lyrics.
105
+ */
106
+ descriptor?: string;
107
+ /**
108
+ * - The language of the lyrics.
109
+ */
110
+ language?: string;
103
111
  /**
104
112
  * - An array of synchronized lyric text objects.
105
113
  */
106
- syncText: ILyricsText[];
114
+ syncText?: ILyricsText[];
107
115
  /**
108
116
  * - The format of the timestamp.
109
117
  */
110
- timeStampFormat: TimestampFormat;
118
+ timeStampFormat?: TimestampFormat;
111
119
  /**
112
120
  * - The type of lyrical content.
113
121
  */
114
- contentType: LyricsContentType;
122
+ contentType?: LyricsContentType;
115
123
  };
116
124
  export type IRating = {
117
125
  /**