Cleaning up YouTube downloads
<p>I have a friend who is trying to clean up YouTube downloads like these:</p>

<pre><code>Google I_O 2012 - App Engine Overview(720p_H.264-AAC).mp4
Google I_O 2012 - App Engine Overview(360p_H.264-AAC).mp4
Google I_O 2012 - Android Fireside Chat(720p_H.264-AAC).mp4
Google I_O 2012 - Android Fireside Chat(360p_H.264-AAC).mp4
Google I_O 2012 - Android Developer Sandbox Interviews(720p_H.264-AAC).mp4
Google I_O 2012 - Android Developer Sandbox Interviews(360p_H.264-AAC).mp4
Google I_O 2012 - Android Design for Success(720p_H.264-AAC).mp4
Google I_O 2012 - Android Design for Success(360p_H.264-AAC).mp4
... hundreds of files ...
</code></pre>

<p>particularly, he'd like to just keep the highest res of videos which he downloaded in multiple formats.</p>

<p>I am very much a beginner without any formal schooling, but I wanted to put together a script for him to do that on a few hundreds of videos. The script is attached below. Upon first execution of it, it used to kill the wrong files, but I tracked that down to performing lexicographical comparison of resolution "strings" rather than "int"s (i.e. 1024p lower than 360p, etc.). I fixed that and had a major sweep through his content. Now he's mad at me for having killed many, many good files, keeping the wrong versions. I don't know what could be wrong with the script anymore?</p>

<p>Can you spot the "current" mistake?</p>

<p>Any other advice for a beginner would be <em>very much</em> appreciated! I don't think the code below is correct, pythonic, efficient or anything like that.. but I'd love to learn from it!</p>

<p>Incidentally: how best to debug such code? With VBScript in Office I used to have a step-by-step debugger to help me.. (feel free to ignore this question following the principle: one question per post)</p>

<pre><code>#!/usr/bin/env python2.7

import sys
import os
import re
import blist
import pprint

N_REQUIRED_ARGUMENTS = 2

YOUTUBE_FILE_REGEX = re.compile(r'^(.*)\((\d+)(p_H.264-AAC\)\.mp4)$')

def show_usage():

  script_name = os.path.basename(sys.argv[0])
  print('Usage: {} directory_to_inspect'.format(script_name))

def main():

  if len(sys.argv) != N_REQUIRED_ARGUMENTS:
    show_usage()
    sys.exit(0)

  directory_to_inspect = sys.argv[1]

  if not os.path.isdir(directory_to_inspect):
    print('Error: path does not appear to be a directory "{}".'.format(
      directory_to_inspect))
    show_usage()
    sys.exit(0)

  directory_files = os.listdir(directory_to_inspect)

  videos_seen = {}

  for filename in directory_files:

    match = YOUTUBE_FILE_REGEX.match(filename)

    if not match:
      continue

    video_title = match.group(1)
    video_resolution = int(match.group(2))

    if not video_title in videos_seen:

      videos_seen[video_title] = {
        'resolutions_seen': blist.sortedset([video_resolution]),
        'to_keep': set([filename]),
        'to_delete': set(),
      }

    else:

      video_info = videos_seen[video_title]

      resolutions_seen = video_info['resolutions_seen']
      to_delete = video_info['to_delete']
      to_keep = video_info['to_keep']

      max_resolution_seen = resolutions_seen[-1]
      if video_resolution &lt; max_resolution_seen:
        to_delete.add(filename)
      else:
        to_delete.add(to_keep.pop())
        to_keep.add(filename)

      resolutions_seen.add(video_resolution)

  for video_group in videos_seen:
        video_info = videos_seen[video_group]

        print(video_group)

for video_group in videos_seen:
  video_info = videos_seen[video_group]

  print(video_group)

  for video_to_keep in video_info['to_keep']:
    print('- Keep: {}'.format(video_to_keep))

  for video_to_delete in video_info['to_delete']:
    print('- Delete: {}'.format(video_to_delete))


if __name__ == '__main__':
  main()
</code></pre>
