11from datetime import date
22from vsmetaEncoder .vsmetaInfo import VsMetaInfo
3+ from vsmetaEncoder .vsmetaListInfo import VsMetaListInfo
4+ from vsmetaEncoder .vsmetaImageInfo import VsMetaImageInfo
35
46class VsMetaBase ():
57
6- TAG_FILE_HEADER = b'\x08 \x02 '
8+ TAG_FILE_HEADER_MOVIE = b'\x08 \x01 '
9+ TAG_FILE_HEADER_SERIES = b'\x08 \x02 '
10+ TAG_FILE_HEADER_OTHER = b'\x08 \x03 '
711
812 TAG_SHOW_TITLE = b'\x12 '
913 TAG_SHOW_TITLE2 = b'\x1A '
@@ -44,18 +48,109 @@ class VsMetaBase():
4448
4549 def __init__ (self ):
4650
47- self .encodedContent : bytes
51+ self .encodedContent = bytes ()
4852 self .info = VsMetaInfo ()
4953
50- def _writeTag (self , tag : bytes , value = None , intBytes : int = 1 , signed : bool = True ):
54+ def encode (self , info : VsMetaInfo = None ) -> bytes :
55+
56+ self .info = info
57+ self ._writeEncodedContent ()
58+ return self .encodedContent
59+
60+ # ------------------------------------
61+ # Write at meta file level - using methods at lower level to "really" write at file level
62+ # ------------------------------------
63+ def _writeFileHeader (self ):
64+ self ._writeTag ( self .TAG_FILE_HEADER_OTHER )
65+
66+ def _writeShowTitle (self ):
67+ self ._writeTag ( self .TAG_SHOW_TITLE , self .info .showTitle2 or self .info .showTitle )
68+ self ._writeTag ( self .TAG_SHOW_TITLE2 , self .info .showTitle2 or self .info .showTitle )
69+
70+ def _writeEpisodeTitle (self ):
71+ self ._writeTag ( self .TAG_EPISODE_TITLE , self .info .episodeTitle )
72+
73+ def _writeEpisodeDate (self ):
74+ if self .info .year != 0 :
75+ self ._writeTag ( self .TAG_YEAR , self .info .year , intBytes = 1 if self .info .year == 0 else 2 )
76+
77+ if self .info .year != 0 : self ._writeTag ( self .TAG_EPISODE_RELEASE_DATE , self .info .episodeReleaseDate )
78+
79+ def _writeEpisodeLocked (self , locked :bool = True ):
80+ self ._writeTag ( self .TAG_EPISODE_LOCKED , locked )
81+
82+ def _writeClassification (self ):
83+ self ._writeTag ( self .TAG_CLASSIFICATION , 0 )
84+
85+ def _writeRating (self ):
86+ self ._writeTag ( self .TAG_RATING , b'\xFF \xFF \xFF \xFF \xFF \xFF \xFF \xFF \xFF \x01 ' )
87+
88+ def _writeSummary (self ):
89+ if len (self .info .chapterSummary ) > 0 :
90+ self ._writeTag (self .TAG_CHAPTER_SUMMARY , self .info .chapterSummary )
91+
92+ def _writeEncodedContent (self ):
93+ # intialization only, implementation in child classes
94+ self .encodedContent = bytes () # ensure empty.
95+
96+ def _writeEpisodeMetaJSON (self ):
97+ if len (self .info .episodeMetaJson ) > 0 :
98+ self ._writeTag ( self .TAG_EPISODE_META_JSON , self .info .episodeMetaJson )
99+
100+ def _writeGroup1 (self ):
101+ self ._writeTag ( self .info .TAG_GROUP1 )
102+ # TODO TAG1_CAST, GENRE, DIRECTOR, WRITER
103+
104+ def _writeGroup2 (self ):
105+
106+ #tv show year
107+ tvshowYear = 0
108+ if (self .info .tvshowReleaseDate .year != 1900 ):
109+ tvshowYear = self .info .tvshowReleaseDate .year
110+ tvshowYear += 2048
111+
112+ self ._writeTag ( self .TAG_GROUP2 )
113+ self ._writeTag ( b'\x01 ' ) # group 2 - occurence no. 1?
114+ #group 2 payload
115+ group2Content = bytes ()
116+ group2Content += self .TAG2_SEASON + self ._writeSpecialInt (self .info .season )
117+ group2Content += self .TAG2_EPISODE + self ._writeSpecialInt (self .info .episode )
118+ if self .info .tvshowReleaseDate != date (1900 , 1 , 1 ):
119+ group2Content += self .TAG2_TV_SHOW_YEAR + self ._writeInt (tvshowYear , 2 , True )
120+ group2Content += self .TAG2_RELEASE_DATE_TV_SHOW
121+ group2Content += self ._writeDate (self .info .tvshowReleaseDate )
122+ else :
123+ group2Content += self .TAG2_TV_SHOW_YEAR + self ._writeInt (0 , 1 , True )
124+ if self .info .tvshowLocked : group2Content += self .TAG2_LOCKED + self ._writeBool (True )
125+ if len (self .info .tvshowMetaJson ) > 0 :
126+ group2Content += self .TAG2_TVSHOW_META_JSON
127+ group2Content += self ._writeStr (self .info .tvshowMetaJson )
128+
129+ group2Content = len (group2Content ).to_bytes (1 , 'big' ) + group2Content # length of group 2 payload
130+
131+ self .encodedContent += group2Content
132+
133+ # TODO tvshowsummary,
134+ # TODO tvshowposter, md5, tv_show_metajson
135+ self ._writeGroup3
136+
137+ def _writeGroup3 (self , info : VsMetaInfo ):
138+ pass
139+ # TODO tvshowBackdrop, MD5, timestamp
140+
141+ # ------------------------------------
142+ # Write at file level
143+ # ------------------------------------
144+
145+ def _writeTag (self , tag : bytes , value = None , intBytes : int = 0 , signed : bool = True ):
51146
52147 #write tag
53148 self .encodedContent += self ._writeBinary (tag )
54149 if value is None : return
55150
56151 #write content
57152 if (type (value ) == str ): self .encodedContent += self ._writeStr (value )
58- if (type (value ) == int ): self .encodedContent += self ._writeInt (value , intBytes , signed )
153+ if (type (value ) == int ): self .encodedContent += self ._writeSpecialInt (value )
59154 if (type (value ) == date ): self .encodedContent += self ._writeDate (value )
60155 if (type (value ) == bool ): self .encodedContent += self ._writeBool (value )
61156 if (type (value ) == bytes ): self .encodedContent += self ._writeBinary (value )
@@ -79,13 +174,22 @@ def _writeStr(self, text : str, withBOM : bool = False) -> bytes:
79174 textAsByte = bytes ( text , encoding )
80175
81176 returnValue = bytes ()
82- returnValue += len (textAsByte ).to_bytes (1 , 'big' )
177+ lengthTByte = len (textAsByte )
178+ returnValue += self ._writeSpecialInt (lengthTByte )
83179 returnValue += textAsByte
84180 return returnValue
85181
86- def _writeInt (self , numberValue : int = 0 , bytesToUse : int = 1 , signed : bool = True ) -> bytes :
182+ def _writeInt (self , numberValue : int = 0 , bytesToUse : int = 0 , signed : bool = True ) -> bytes :
87183
88184 returnValue = bytes ()
185+
186+ # ok, the following looks very pragmatic...
187+ if bytesToUse == 0 :
188+ bytesToUse = 1
189+ if numberValue >= (2 ** (1 * 8 )): bytesToUse = 2
190+ if numberValue >= (2 ** 16 ): bytesToUse = 3
191+ if numberValue >= (2 ** 24 ): bytesToUse = 4
192+
89193 returnValue += numberValue .to_bytes (bytesToUse , byteorder = "little" , signed = signed )
90194 return returnValue
91195
@@ -95,3 +199,20 @@ def _writeDate(self, dateValue : date) -> bytes:
95199 returnValue += b'\x0a ' # length of date field, x0a = 10
96200 returnValue += bytes (dateValue .strftime ("%Y-%m-%d" ), 'utf-8' )
97201 return returnValue
202+
203+ def _writeSpecialInt (self , valueI :int ) -> bytes :
204+
205+ returnValue = b''
206+ num = valueI
207+ hasMore = True
208+
209+ while hasMore :
210+
211+ value1 = (num & 0b01111111 )
212+ num = num >> 7
213+ hasMore = False if num == 0 else True
214+ value2 = 0x80 if hasMore else 0x00
215+
216+ returnValue += (value1 | value2 ).to_bytes (1 , 'little' )
217+
218+ return returnValue
0 commit comments