Skip to content
This repository was archived by the owner on Jan 23, 2025. It is now read-only.

Commit 2cea380

Browse files
committed
Merge remote-tracking branch 'origin/encoder-decoder' into encoder-decoder
changes: README.md updated + some minor code optimizations
1 parent 92ee45e commit 2cea380

File tree

3 files changed

+74
-82
lines changed

3 files changed

+74
-82
lines changed

README.md

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Example: The video is called `video.mpg`, the metadata file shall be named `vide
1414

1515
## Limitations
1616
* Media type 'others' is currently not supported.
17-
* Some fields are not yet supported. See list below.
17+
* All known fields are supported in this version (See list below).
1818

1919
## How to use the code
2020

@@ -34,15 +34,15 @@ Here's an example piece of code. Other examples can be found in the unit test cl
3434
writer = VsMetaMovieEncoder()
3535
3636
info = writer.info
37-
info.episodeTitle = 'Nach der Hochzeit'
3837
info.showTitle = 'Kino - Filme'
39-
info.setEpisodeDate(date(2021, 3, 8))
38+
info.episodeTitle = 'Nach der Hochzeit'
39+
info.episodeReleaseDate = date(2021, 3, 8)
4040
info.chapterSummary = 'Um die drohende Schließung seines indischen Waisenhauses abzuwenden...'
4141
4242
writeVsMetaFile(os.path.join(os.path.dirname(os.path.realpath(__file__)),'videp.mp4.vsmeta'), writer.encode(info))
4343
```
4444

45-
The code is available on PyPI and can be installed with command `pip install vsMetaEncoder`.
45+
The code will be available on PyPI soon and can be installed with command `pip install vsMetaCodec`.
4646

4747

4848
# Field mapping
@@ -54,45 +54,50 @@ Here's how to use the vsMetaInfo class for the different media types.
5454
To encode the episode of a series, use the `vsMetaInfo` class with a `vsMetaSeriesEncoder`.
5555
Have a look at the test classes to see how it works best. The table below describes how to set the `vsMetaInfo` properties.
5656

57-
| Field in Video Station | vsMetaInfo property | Remark |
58-
|---------------------------|---------------------------|--------------------------------------------------------------------------------|
59-
| TV Show Name | `showTitle` | |
60-
| Publishing Date | `setEpisodeReleaseDate()` | Use method instead of direct value assignment. |
61-
| Episode Title | `episodeTitle` | |
62-
| Season | `season` | If not set, defaulted with publishing year of episode. |
63-
| Episode | `episode` | If not set, defaulted with week number x 10 plus weekday number (Monday is 1). |
64-
| Publishing Date (Episode) | `setShowDate()` | Use method instead of direct value assignment. |
65-
| Locked | `episodeLocked` | |
66-
| Summary | `chapterSummary` | |
67-
68-
Not supported yet:
69-
70-
* Classification
71-
* Rating
72-
* Genre
73-
* Cast
74-
* Author
57+
| Field in Video Station | vsMetaInfo property | Remark |
58+
|---------------------------|---------------------------|-----------------------------------------------------------------------------|
59+
| TV Show Name | `showTitle` | assign any tv show name as text of type 'str' |
60+
| Episode Title | `episodeTitle` | assign any text of type 'str' |
61+
| Publishing Date | `episodeReleaseDate` | assign any date of type 'date' or 'str' in ISO format |
62+
| Season | `season` | type int: If not set, defaulted with publishing year of episode. |
63+
| Episode | `episode` | type int: If not set, defaulted with week no. x 10 + weekday no. (Monday=1) |
64+
| Publishing Date (Episode) | `tvshowReleaseDate` | assign any date of type 'date' or 'str' in ISO format |
65+
| Poster (of Serie) | `posterImageInfo.image` | assign a jpg-image as bytestring (the md5-hash is calculated automatically) |
66+
| Locked | `episodeLocked` | assign 'True' if 'VideoStation' may not alter the vsmeta file content |
67+
| Summary | `chapterSummary` | assign any text of type 'str' |
68+
| Classification | `classification` | assign any text of type 'str' |
69+
| Rating | `rating` | assign any float value in the range of 0.0. to 10.0 or -1.0 for unknown |
70+
| Cast | `list.cast[]` | append 'actor names' of type 'str' to the list |
71+
| Genre | `list.genre[]` | append 'genres' of type 'str' to the list, e.g. 'Drama', 'Action' |
72+
| Director | `list.director[]` | append 'director names' of type 'str' to the list |
73+
| Writer | `list.writer[]` | append 'author names' of type 'str' to the list |
74+
| Poster (of Episode) | `episodeImageInfo.image` | assign a jpg-image as bytestring (the md5-hash is calculated automatically) |
75+
| Background (of Serie) | `backdropImageInfo.image` | assign a jpg-image as bytestring (the md5-hash is calculated automatically) |
7576

7677
## Movies
7778

7879
To encode a TV film or movie, use the `vsMetaInfo` class with a `vsMetaMoviesEncoder`.
7980
The property names might be confusing, don't think too much about it - just use them as listed below.
8081

81-
| Field in Video Station | vsMetaInfo property | Remark |
82-
|------------------------|---------------------|----------------------------------------------------------------------|
83-
| Title | `showTitle` | |
84-
| Short Title | `episodeTitle` | |
85-
| Publishing Date | `setEpisodeDate()` | Use method instead of direct value assignment. |
86-
| Locked | `episodeLocked` | |
87-
| Summary | `chapterSummary` | |
88-
89-
Not supported yet:
90-
91-
* Classification
92-
* Rating
93-
* Genre
94-
* Cast
95-
* Author
82+
| Field in Video Station | vsMetaInfo property | Remark |
83+
|---------------------------|---------------------------|-----------------------------------------------------------------------------|
84+
| Title | `showTitle` | assign any title text of type 'str' |
85+
| Short Title | `episodeTitle` | assign any short title text of type 'str' |
86+
| Publishing Date | `episodeReleaseDate` | assign any date of type 'date' or 'str' in ISO format |
87+
| Season | `season` | N/A - not used, set to 0 |
88+
| Episode | `episode` | N/A - not used, set to 0 |
89+
| Publishing Date (Episode) | `tvshowReleaseDate` | N/A - not used, set to 1900-01-01 |
90+
| Poster (of Serie) | `posterImageInfo.image` | N/A - not used, set to VsImageInfo() |
91+
| Locked | `episodeLocked` | assign 'True' if 'VideoStation' may not alter the vsmeta file content |
92+
| Summary | `chapterSummary` | assign any text of type 'str' |
93+
| Classification | `classification` | assign any text of type 'str' |
94+
| Rating | `rating` | assign any float value in the range of 0.0. to 10.0 or -1.0 for unknown |
95+
| Cast | `list.cast[]` | append 'actor names' of type 'str' to the list |
96+
| Genre | `list.genre[]` | append 'genres' of type 'str' to the list, e.g. 'Drama', 'Action' |
97+
| Director | `list.director[]` | append 'director names' of type 'str' to the list |
98+
| Writer | `list.writer[]` | append 'author names' of type 'str' to the list |
99+
| Poster (of Movie) | `episodeImageInfo.image` | assign a jpg-image as bytestring (the md5-hash is calculated automatically) |
100+
| Background (of Movie) | `backdropImageInfo.image` | assign a jpg-image as bytestring (the md5-hash is calculated automatically) |
96101

97102
## Media type 'other'
98103

src/vsmetaCodec/vsmetaBase.py

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import hashlib
21
import base64
32
from datetime import datetime, date
43
from vsmetaCodec.vsmetaInfo import VsMetaInfo
@@ -99,6 +98,22 @@ def year_of_date(release_date: str | date) -> int:
9998
year = release_date.year
10099
return year if year != 1900 else 0
101100

101+
@staticmethod
102+
def b64encodeImage(image: bytes, last_char_nl: bool = False) -> str:
103+
converted_string = base64.b64encode(image).decode()
104+
b64_enc_str = ''
105+
length = len(converted_string)
106+
block_size = 76
107+
for pos in range(0, length - 1, block_size): # insert '\n' every 76 characters
108+
if (length - pos) < block_size:
109+
block_size = length - pos
110+
b64_enc_str += converted_string[pos:pos + block_size]
111+
if block_size == length - pos: # last block ?
112+
b64_enc_str += '\n' if last_char_nl else ''
113+
else:
114+
b64_enc_str += '\n' # not the last block -> append '\n'
115+
return b64_enc_str
116+
102117
# -------------------------------------------------------
103118
# Write here on meta level, stored low level with instance of VsMetaCode()
104119
# -------------------------------------------------------
@@ -147,7 +162,7 @@ def _writePoster(self):
147162
image_str = self.b64encodeImage(episode_img.image, episode_img.b64LastCharIsNewLine)
148163
self.encContent.writeTag(int(index + 1).to_bytes(1, 'big'), image_str)
149164
self.encContent.writeTag(self.TAG_EPISODE_THUMB_MD5)
150-
self.encContent.writeTag(int(index + 1).to_bytes(1, 'big'), episode_img.md5str)
165+
self.encContent.writeTag(int(index + 1).to_bytes(1, 'big'), episode_img.calcHashMd5Hex())
151166

152167
def _writeGroup1(self):
153168
# group 1 payload
@@ -181,10 +196,11 @@ def _writeGroup2(self):
181196
if len(self.info.tvshowSummary) > 0:
182197
grp2_content.writeTag(self.TAG2_TVSHOW_SUMMARY, self.info.tvshowSummary)
183198

184-
image_bytes = None if self.info.posterImageInfo is None else self.info.posterImageInfo.image
199+
img_info = self.info.posterImageInfo
200+
image_bytes = None if img_info is None else img_info.image
185201
if image_bytes is not None and len(image_bytes) > 0:
186202
grp2_content.writeTag(self.TAG2_POSTER_DATA, self.b64encodeImage(image_bytes))
187-
grp2_content.writeTag(self.TAG2_POSTER_MD5, self.calcMD5(image_bytes))
203+
grp2_content.writeTag(self.TAG2_POSTER_MD5, img_info.calcHashMd5Hex())
188204

189205
if len(self.info.tvshowMetaJson) > 0:
190206
grp2_content.writeTag(self.TAG2_TVSHOW_META_JSON, self.info.tvshowMetaJson)
@@ -199,39 +215,18 @@ def _writeGroup2(self):
199215
self.encContent.writeTag(b'\x01', grp2_content) # group 2 - occurence no. \x01?
200216

201217
def _writeGroup3(self) -> VsMetaCode:
202-
# group3 content may not be written to self.encContent directly, because it is also written into
203-
# group2 content for encoding of TV-Series.
204-
# Remark: The returned bytes don't yet include a group3 TAG or length of the package.
205-
# This has to be preceded by the calling method differently for movies (TAG_GROUP3) and series (TAG2_GROUP3).
218+
# group3 content may not be written to self.encContent directly, because it is also written into the group2
219+
# content when encoding TV-Series.
220+
# Remark: The returned bytes don't yet include a group3 TAG or length of the package, as this has to be done
221+
# by the method calling _writeGroup3() in different ways for movies (TAG_GROUP3) and series (TAG2_GROUP3).
206222
grp3_content = VsMetaCode()
207-
if self.info.backdropImageInfo.image is not None\
208-
and len(self.info.backdropImageInfo.image) > 0\
223+
img_info = self.info.backdropImageInfo
224+
if img_info.image is not None and len(img_info.image) > 0\
209225
and self.info.timestamp > int(datetime(1900, 1, 1, 0, 0).timestamp()):
210226
# group 3 payload = backdrop_data, backdrop_MD5, timestamp
211-
img_info = self.info.backdropImageInfo
212227
image_str = self.b64encodeImage(img_info.image, img_info.b64LastCharIsNewLine)
213228
grp3_content.writeTag(self.TAG3_BACKDROP_DATA, image_str)
214-
grp3_content.writeTag(self.TAG3_BACKDROP_MD5, self.calcMD5(img_info.image))
229+
grp3_content.writeTag(self.TAG3_BACKDROP_MD5, img_info.calcHashMd5Hex())
215230
grp3_content.writeTag(self.TAG3_TIMESTAMP, int(self.info.timestamp))
216231

217232
return grp3_content # return the grp3_content (it might be empty!)
218-
219-
@staticmethod
220-
def calcMD5(image: bytes) -> str:
221-
return hashlib.md5(image).hexdigest()
222-
223-
@staticmethod
224-
def b64encodeImage(image: bytes, last_char_nl: bool = False) -> str:
225-
converted_string = base64.b64encode(image).decode()
226-
b64_enc_str = ''
227-
length = len(converted_string)
228-
block_size = 76
229-
for pos in range(0, length - 1, block_size): # insert '\n' every 76 characters
230-
if (length - pos) < block_size:
231-
block_size = length - pos
232-
b64_enc_str += converted_string[pos:pos + block_size]
233-
if block_size == length - pos: # last block ?
234-
b64_enc_str += '\n' if last_char_nl else ''
235-
else:
236-
b64_enc_str += '\n' # not the last block -> append '\n'
237-
return b64_enc_str

src/vsmetaCodec/vsmetaDecoder.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,21 @@
66

77
class VsMetaDecoder(VsMetaBase):
88

9-
def __init__(self):
10-
super(VsMetaDecoder, self).__init__()
11-
self._header = VsMetaBase.TAG_FILE_HEADER_OTHER
12-
self.info = VsMetaInfo()
13-
self.info.episodeLocked = False
14-
159
def decode(self, encoded_data: bytes = None) -> int:
1610
if encoded_data is not None:
17-
self.__init__()
11+
self.info = VsMetaInfo()
12+
self.info.episodeLocked = False
1813
self.encContent = VsMetaCode(encoded_data)
14+
return self._readVsMetaEncoded(self.encContent)
1915

20-
tag = self.encContent.readHeader()
16+
def _readVsMetaEncoded(self, code: VsMetaCode) -> int:
17+
tag = code.readHeader()
2118
if tag != self.TAG_FILE_HEADER_MOVIE and\
2219
tag != self.TAG_FILE_HEADER_SERIES:
2320
error = "This is not a vsmeta movie or series file"
2421
raise Exception(error)
25-
else:
26-
self._header = tag
27-
return self._readVsMetaEncoded(self.encContent)
2822

29-
def _readVsMetaEncoded(self, code: VsMetaCode) -> int:
3023
episode_img = VsMetaImageInfo()
31-
3224
while code.byteCountAhead() > 0:
3325
tag = code.readTag()
3426
if tag == self.TAG_SHOW_TITLE:

0 commit comments

Comments
 (0)