tocparser 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tocparser/__init__.py ADDED
@@ -0,0 +1,88 @@
1
+ """Parse and write cdrdao TOC files.
2
+
3
+ >>> from tocparser import parse, dumps
4
+ >>> toc = parse('CD_DA\\nTRACK AUDIO\\nFILE "hurt.wav" 0\\n')
5
+ >>> toc.tracks[0].mode.value
6
+ 'AUDIO'
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from importlib.metadata import version
12
+
13
+ from tocparser.errors import (
14
+ Loc,
15
+ TocError,
16
+ TocParseError,
17
+ TocValidationError,
18
+ )
19
+ from tocparser.models import (
20
+ CdText,
21
+ CdTextBlock,
22
+ CdTextEncoding,
23
+ CdTextItemName,
24
+ CdTextValue,
25
+ ContentItem,
26
+ DataFile,
27
+ DataMode,
28
+ DiscType,
29
+ End,
30
+ Fifo,
31
+ File,
32
+ Silence,
33
+ Start,
34
+ SubChannelMode,
35
+ Toc,
36
+ Track,
37
+ TrackMode,
38
+ TrackStatement,
39
+ Zero,
40
+ )
41
+ from tocparser.parser import parse, parse_file
42
+ from tocparser.serializer import dump, dumps
43
+ from tocparser.times import (
44
+ FRAMES_PER_SECOND,
45
+ SAMPLES_PER_FRAME,
46
+ SECONDS_PER_MINUTE,
47
+ Msf,
48
+ Time,
49
+ )
50
+
51
+ __version__ = version("tocparser")
52
+
53
+ __all__ = [
54
+ "FRAMES_PER_SECOND",
55
+ "SAMPLES_PER_FRAME",
56
+ "SECONDS_PER_MINUTE",
57
+ "CdText",
58
+ "CdTextBlock",
59
+ "CdTextEncoding",
60
+ "CdTextItemName",
61
+ "CdTextValue",
62
+ "ContentItem",
63
+ "DataFile",
64
+ "DataMode",
65
+ "DiscType",
66
+ "End",
67
+ "Fifo",
68
+ "File",
69
+ "Loc",
70
+ "Msf",
71
+ "Silence",
72
+ "Start",
73
+ "SubChannelMode",
74
+ "Time",
75
+ "Toc",
76
+ "TocError",
77
+ "TocParseError",
78
+ "TocValidationError",
79
+ "Track",
80
+ "TrackMode",
81
+ "TrackStatement",
82
+ "Zero",
83
+ "__version__",
84
+ "dump",
85
+ "dumps",
86
+ "parse",
87
+ "parse_file",
88
+ ]
tocparser/errors.py ADDED
@@ -0,0 +1,80 @@
1
+ """Exceptions raised by :mod:`tocparser`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TypeAlias
6
+
7
+ __all__ = [
8
+ "Loc",
9
+ "TocError",
10
+ "TocParseError",
11
+ "TocValidationError",
12
+ ]
13
+
14
+ #: A path into a model, made of field names and indexes, e.g.
15
+ #: ``("tracks", 0, "statements", 2)``.
16
+ Loc: TypeAlias = tuple[str | int, ...]
17
+
18
+
19
+ class TocError(Exception):
20
+ """Base class for every error raised by :mod:`tocparser`."""
21
+
22
+
23
+ class TocParseError(TocError):
24
+ """The input is not syntactically valid.
25
+
26
+ Mirrors cdrdao's ``file:line: message`` reporting.
27
+ """
28
+
29
+ def __init__(
30
+ self,
31
+ message: str,
32
+ *,
33
+ line: int | None = None,
34
+ column: int | None = None,
35
+ filename: str | None = None,
36
+ ) -> None:
37
+ self.message = message
38
+ self.line = line
39
+ self.column = column
40
+ self.filename = filename
41
+ super().__init__(_format_location(message, filename, line, column))
42
+
43
+
44
+ class TocValidationError(TocError):
45
+ """The input breaks a rule cdrdao itself enforces.
46
+
47
+ ``loc`` locates the problem inside the model that raised it, so an error
48
+ raised while building models by hand still says where it is. ``line`` is
49
+ only known when the error comes from parsing text.
50
+ """
51
+
52
+ def __init__(
53
+ self,
54
+ message: str,
55
+ *,
56
+ line: int | None = None,
57
+ filename: str | None = None,
58
+ loc: Loc = (),
59
+ ) -> None:
60
+ self.message = message
61
+ self.line = line
62
+ self.filename = filename
63
+ self.loc = loc
64
+ super().__init__(_format_location(message, filename, line, None))
65
+
66
+
67
+ def _format_location(
68
+ message: str,
69
+ filename: str | None,
70
+ line: int | None,
71
+ column: int | None,
72
+ ) -> str:
73
+ location = ""
74
+ if filename is not None:
75
+ location += f"{filename}:"
76
+ if line is not None:
77
+ location += f"{line}:"
78
+ if column is not None:
79
+ location += f"{column}:"
80
+ return f"{location} {message}" if location else message
tocparser/grammar.lark ADDED
@@ -0,0 +1,89 @@
1
+ // Grammar for cdrdao TOC files.
2
+ //
3
+ // Derived from cdrdao's own ANTLR grammar, trackdb/TocParser.g at tag
4
+ // rel_1_2_6, and the TOC FILES section of cdrdao(1). Where the two disagree
5
+ // the grammar is the authority: FIRST_TRACK_NO, END, CD_I, MODE0, SWAP,
6
+ // #offset, RESERVED1..RESERVED4, CLOSED, ENCODING_* and the string escapes are
7
+ // all missing from the man page. Rule and token names follow TocParser.g so the
8
+ // two can be compared side by side.
9
+
10
+ toc: (catalog | disc_type)* first_track_no? cd_text_global? track+
11
+
12
+ catalog: "CATALOG" STRING
13
+ disc_type: DISC_TYPE
14
+ first_track_no: "FIRST_TRACK_NO" INT
15
+
16
+ track: "TRACK" MODE SUB_CHANNEL_MODE? track_flag* cd_text_track? pregap? \
17
+ track_statement+ index*
18
+
19
+ ?track_flag: isrc | copy | pre_emphasis | channels
20
+ isrc: "ISRC" STRING
21
+ copy: NO? "COPY"
22
+ pre_emphasis: NO? "PRE_EMPHASIS"
23
+ channels: CHANNELS
24
+
25
+ pregap: "PREGAP" msf
26
+ index: "INDEX" msf
27
+
28
+ ?track_statement: file | datafile | fifo | silence | zero | start | end
29
+
30
+ file: FILE_KEYWORD STRING SWAP? offset? time time?
31
+ datafile: "DATAFILE" STRING offset? time?
32
+ fifo: "FIFO" STRING time
33
+ silence: "SILENCE" time
34
+ zero: "ZERO" MODE? SUB_CHANNEL_MODE? time
35
+ start: "START" msf?
36
+ end: "END" msf?
37
+
38
+ offset: "#" INT
39
+ msf: MSF
40
+ time: MSF | INT
41
+
42
+ // A global CD_TEXT block may open with a language map; a track one may not.
43
+ cd_text_global: "CD_TEXT" "{" language_map? cd_text_block* "}"
44
+ cd_text_track: "CD_TEXT" "{" cd_text_block* "}"
45
+
46
+ language_map: "LANGUAGE_MAP" "{" language_map_entry+ "}"
47
+ language_map_entry: INT ":" language_code
48
+ language_code: INT | LANGUAGE_EN
49
+
50
+ // cdrdao 1.2.5 added an optional encoding at the top of a language block.
51
+ cd_text_block: "LANGUAGE" INT "{" CD_TEXT_ENCODING? cd_text_item* "}"
52
+ cd_text_item: CD_TEXT_ITEM cd_text_value
53
+ cd_text_value: STRING | binary_data
54
+ binary_data: "{" (INT ("," INT)*)? "}"
55
+
56
+ NO: "NO"
57
+ SWAP: "SWAP"
58
+ LANGUAGE_EN: "EN"
59
+ CHANNELS: "TWO_CHANNEL_AUDIO" | "FOUR_CHANNEL_AUDIO"
60
+ FILE_KEYWORD: "AUDIOFILE" | "FILE"
61
+ DISC_TYPE: "CD_DA" | "CD_ROM_XA" | "CD_ROM" | "CD_I"
62
+
63
+ CD_TEXT_ENCODING: "ENCODING_ISO_8859_1" | "ENCODING_ASCII" | "ENCODING_MS_JIS" \
64
+ | "ENCODING_KOREAN" | "ENCODING_MANDARIN"
65
+
66
+ // MODE0 is only legal after ZERO; the transformer rejects it as a track mode.
67
+ MODE: "MODE1_RAW" | "MODE1" | "MODE2_FORM_MIX" | "MODE2_FORM1" | "MODE2_FORM2" \
68
+ | "MODE2_RAW" | "MODE2" | "MODE0" | "AUDIO"
69
+
70
+ SUB_CHANNEL_MODE: "RW_RAW" | "RW"
71
+
72
+ CD_TEXT_ITEM: "TITLE" | "PERFORMER" | "SONGWRITER" | "COMPOSER" | "ARRANGER" \
73
+ | "MESSAGE" | "DISC_ID" | "GENRE" | "TOC_INFO1" | "TOC_INFO2" \
74
+ | "RESERVED1" | "RESERVED2" | "RESERVED3" | "RESERVED4" \
75
+ | "CLOSED" \
76
+ | "UPC_EAN" | "ISRC" | "SIZE_INFO"
77
+
78
+ // Inside a string a backslash may only introduce another backslash, a quote,
79
+ // or three digits; cdrdao rejects any other use of one. Raw newlines and tabs
80
+ // are accepted, as cdrdao accepts them.
81
+ STRING: /"(?:\\[0-9][0-9][0-9]|\\["\\]|[^"\\])*"/
82
+
83
+ MSF.2: /[0-9]+:[0-9]+:[0-9]+/
84
+ INT: /[0-9]+/
85
+ COMMENT: /\/\/[^\n]*/
86
+
87
+ %import common.WS
88
+ %ignore WS
89
+ %ignore COMMENT