"""
Get information from "BDMV" directory trees
"""
import collections
import os
import re
from ... import utils
natsort = utils.LazyModule(module='natsort', namespace=globals())
[docs]
def is_dvd(content_path, *, multidisc=False):
"""
Whether `content_path` contains a "VIDEO_TS" subdirectory
Also look for "VIDEO_TS.IFO" exists directly in `content_path`.
If `multidisc` is truthy, also look for a "VIDEO_TS" directory in any subdirectory, but not
recursively.
"""
if os.path.isdir(content_path):
if os.path.isdir(os.path.join(content_path, 'VIDEO_TS')):
return True
if os.path.exists(os.path.join(content_path, 'VIDEO_TS.IFO')):
return True
if multidisc:
for subdir in utils.fs.listdir(content_path):
if os.path.isdir(os.path.join(content_path, subdir, 'VIDEO_TS')):
return True
return False
[docs]
def get_disc_paths(content_path):
"""
Return sequence of subdirectories that contain a "VIDEO_TS" directory
If `content_path` contains a "VIDEO_TS.IFO" file, return `content_path`.
Return empty sequence by default.
"""
if os.path.isdir(content_path):
discpaths = []
# Most likely single-disc release.
if os.path.isdir(os.path.join(content_path, 'VIDEO_TS')):
discpaths.append(content_path)
# The .VOB files may also be in `content_path` with no "VIDEO_TS" directory.
if os.path.exists(os.path.join(content_path, 'VIDEO_TS.IFO')):
discpaths.append(content_path)
# Find more discs in subdirectories.
for name in utils.fs.listdir(content_path):
subpath = os.path.join(content_path, name)
if name != 'VIDEO_TS' and is_dvd(subpath):
discpaths.append(subpath)
return tuple(natsort.natsorted(discpaths))
return ()
[docs]
def get_playlists(discpath):
"""
Return sequence of :class:`~.Playlist` instances from VIDEO_TS subdirectory
Return empty sequence if no playlists are found.
Playlists with a runtime of less than 3 minutes are ignored.
Each playlist represents one Video Title Set, e.g. ``VTS_01_*``, ``VTS_02_*``, ``VTS_03_*``,
etc. Each playlist's :attr:`.Playlist.filepath` is the .IFO file and the :attr:`.Playlist.items`
are .VOB files.
:param discpath: Path to directory that contains a "VIDEO_TS" subdirectory
"""
video_ts_path = _get_video_ts_directory(discpath)
if not video_ts_path:
return ()
playlists = collections.defaultdict(dict)
vob_sets = collections.defaultdict(list)
for filename in utils.fs.listdir(video_ts_path):
match = re.search(r'^(VTS_\d+)_\d+\.[A-Z]+$', filename)
if match:
set_name = match.group(1)
filepath = os.path.join(video_ts_path, filename)
file_extension = utils.fs.file_extension(filename).lower()
if file_extension == 'ifo':
playlists[set_name]['filepath'] = filepath
playlists[set_name]['discpath'] = discpath
playlists[set_name]['duration'] = utils.mediainfo.get_duration_from_mediainfo(filepath)
elif file_extension == 'vob':
vob_sets[set_name].append(filepath)
# Move Video Title Sets to each playlist's `items`.
for set_name, items in vob_sets.items():
playlists[set_name]['items'] = tuple(sorted(items))
# Remove playlist with less than 3 minutes runtime.
for set_name, playlist in tuple(playlists.items()):
if playlist['duration'] < 180:
del playlists[set_name]
playlists = tuple(
natsort.natsorted(
(
utils.disc.Playlist(**playlist)
for playlist in playlists.values()
),
key=lambda playlist: playlist.filepath,
)
)
utils.disc.playlist.mark_main_playlists(playlists)
return playlists
def _get_video_ts_directory(discpath):
"""
Return the path of the directory that contains the DVD files
This may be ``<discpath>/VIDEO_TS`` or ``<discpath>``.
:raise errors.ContentError: if `discpath` does not contain DVD files
"""
if os.path.isdir(os.path.join(discpath, 'VIDEO_TS')):
return os.path.join(discpath, 'VIDEO_TS')
elif os.path.exists(os.path.join(discpath, 'VIDEO_TS.IFO')):
return discpath