Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions playlist_length/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .__version__ import __version__

__version__ = __version__
__author__ = 'Karan Suthar, Mohit Solanki'
__license__ = 'MIT License'
__description__ = 'A command-line tool to calculate the length of videos in a directory'
__author__ = "Karan Suthar, Mohit Solanki"
__license__ = "MIT License"
__description__ = "A command-line tool to calculate the length of videos in a directory"
2 changes: 1 addition & 1 deletion playlist_length/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.6.1'
__version__ = "1.6.1"
83 changes: 43 additions & 40 deletions playlist_length/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
from .__version__ import __version__


DURATION_REGEX = re.compile(r'duration=(.*)')
DURATION_REGEX = re.compile(r"duration=(.*)")

REGEX_MAP = {
'video': re.compile(r'video|Video'),
'audio': re.compile(r'audio|Audio'),
'audio/video': re.compile(r'audio|video|Audio|Video'),
"video": re.compile(r"video|Video"),
"audio": re.compile(r"audio|Audio"),
"audio/video": re.compile(r"audio|video|Audio|Video"),
}


Expand All @@ -31,7 +31,7 @@ def duration(file_path):
command = ["ffprobe", "-show_entries", "format=duration", "-i", file_path]
pipe = sp.Popen(command, stdout=sp.PIPE, stderr=sp.STDOUT)
out, error = pipe.communicate()
match_object = None if error else DURATION_REGEX.search(out.decode('utf-8'))
match_object = None if error else DURATION_REGEX.search(out.decode("utf-8"))
if match_object is None:
return 0
length = float(match_object.group(1)) / 60
Expand All @@ -51,13 +51,12 @@ def is_media_file(file_path):


def get_all_files(BASE_PATH, no_subdir):

def with_subdir():
return (
os.path.join(root, file)
for root, _, files in os.walk(BASE_PATH)
for file in files
if file[0] != '.'
if file[0] != "."
)

def without_subdir():
Expand All @@ -72,80 +71,84 @@ def without_subdir():

def calculate_length(BASE_PATH, no_subdir, media_type):
if not os.path.isdir(BASE_PATH):
return bold(red('Error: This doesn\'t seem to be a valid directory.'))
return bold(red("Error: This doesn't seem to be a valid directory."))

all_files = get_all_files(BASE_PATH, no_subdir)

with ProcessPoolExecutor() as executor:
sys.stdout.write('\n')
sys.stdout.write("\n")
video_files = []
tasks = [executor.submit(is_media_file, file_path) for file_path in all_files]

for task in tqdm(
as_completed(tasks), total=len(tasks), desc='Filtering {}'.format(media_type)
as_completed(tasks),
total=len(tasks),
desc="Filtering {}".format(media_type),
):
path = task.result()
if path is not None:
video_files.append(path)

if not video_files:
return bold(red('Seems like there are no {} files. ¯\_(ツ)_/¯'.format(media_type)))
return bold(
red("Seems like there are no {} files. ¯\_(ツ)_/¯".format(media_type))
)

with ProcessPoolExecutor() as executor:
sys.stdout.write('\n')
sys.stdout.write("\n")
result = list(
tqdm(
executor.map(duration, video_files),
total=len(video_files),
desc='Calculating time',
desc="Calculating time",
)
)

length = round(sum(result))

if length < 60:
minutes_string = pluralize(length, base='minute', suffix='s')
result = 'Length of all {} is {}.'.format(media_type, minutes_string)
minutes_string = pluralize(length, base="minute", suffix="s")
result = "Length of all {} is {}.".format(media_type, minutes_string)
else:
hours, minutes = divmod(length, 60)
hours_string = pluralize(hours, base='hour', suffix='s')
minutes_string = pluralize(minutes, base='minute', suffix='s')
result = 'Length of all {} is {} and {}.'.format(
hours_string = pluralize(hours, base="hour", suffix="s")
minutes_string = pluralize(minutes, base="minute", suffix="s")
result = "Length of all {} is {} and {}.".format(
media_type, hours_string, minutes_string
)
return bold(green(result))


def get_parser():
parser = argparse.ArgumentParser(
description='''
description="""
Output the total duration of all the audio and video files in the given directory.
'''
"""
)
parser.add_argument(
'path',
help='Path to a directory. Defaults to current directory',
"path",
help="Path to a directory. Defaults to current directory",
type=str,
nargs='?',
default='.',
nargs="?",
default=".",
)
parser.add_argument(
'--no-subdir',
help='Don\'t look for videos in sub directories.',
action='store_true',
"--no-subdir",
help="Don't look for videos in sub directories.",
action="store_true",
)
parser.add_argument(
'--media-type',
help='Type of media file to you want to check.',
"--media-type",
help="Type of media file to you want to check.",
type=str,
choices=['audio', 'video', 'both'],
default='video',
choices=["audio", "video", "both"],
default="video",
)
parser.add_argument(
'-v',
'--version',
action='version',
version='%(prog)s {version}'.format(version=__version__),
"-v",
"--version",
action="version",
version="%(prog)s {version}".format(version=__version__),
)
return parser

Expand All @@ -154,14 +157,14 @@ def main():
try:
parser = get_parser()
args = parser.parse_args()
if args.media_type == 'both':
args.media_type = 'audio/video'
if args.media_type == "both":
args.media_type = "audio/video"
# why pass every time to `is_media_file` inject to globals intead ;)
globals()['media_type'] = REGEX_MAP[args.media_type]
globals()["media_type"] = REGEX_MAP[args.media_type]
result = calculate_length(args.path, args.no_subdir, args.media_type)
except (KeyboardInterrupt, SystemExit):
sys.stdout.write('\nPlease Wait... Exiting Gracefully!\n')
sys.stdout.write("\nPlease Wait... Exiting Gracefully!\n")
else:
sys.stdout.write('\n{}\n\n'.format(result))
sys.stdout.write("\n{}\n\n".format(result))
finally:
sys.exit()
4 changes: 2 additions & 2 deletions playlist_length/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def pluralize(number, base, suffix):
if number < 2:
return '{} {}'.format(number, base)
return '{} {}{}'.format(number, base, suffix)
return "{} {}".format(number, base)
return "{} {}{}".format(number, base, suffix)
40 changes: 19 additions & 21 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,30 @@


requires = (
'huepy==0.9.6',
'python-magic>=0.4.15',
'tqdm>=4.19.9',
"huepy==0.9.6",
"python-magic>=0.4.15",
"tqdm>=4.19.9",
'futures;python_version<"3.4"',
)

setup(
name='playlist-length',
name="playlist-length",
version=__version__,
description='A command-line tool to get length of all videos in a directory',
long_description=open('README.md').read().strip(),
long_description_content_type='text/markdown',
author='Karan Suthar',
author_email='[email protected]',
url='http://github.com/karansthr/playlist-length',
packages=['playlist_length'],
description="A command-line tool to get length of all videos in a directory",
long_description=open("README.md").read().strip(),
long_description_content_type="text/markdown",
author="Karan Suthar",
author_email="[email protected]",
url="http://github.com/karansthr/playlist-length",
packages=["playlist_length"],
install_requires=requires,
license='MIT License',
keywords='videolength playlist-length',
entry_points={
'console_scripts': ['playlistlen=playlist_length.main:main'],
},
license="MIT License",
keywords="videolength playlist-length",
entry_points={"console_scripts": ["playlistlen=playlist_length.main:main"],},
project_urls={
'Bug Reports': 'https://github.com/karansthr/playlist-length/issues',
'Source': 'https://github.com/karansthr/playlist-length/',
'Blog': 'https://fosstack.com/tips/videos-playlist-length-calculator/',
'About': 'https://fosstack.com/about/'
}
"Bug Reports": "https://github.com/karansthr/playlist-length/issues",
"Source": "https://github.com/karansthr/playlist-length/",
"Blog": "https://fosstack.com/tips/videos-playlist-length-calculator/",
"About": "https://fosstack.com/about/",
},
)