| 1 |  |  | #!/usr/bin/env python3 | 
            
                                                        
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 3 | 1 |  | import glob | 
            
                                                        
            
                                    
            
            
                | 4 | 1 |  | import logging | 
            
                                                        
            
                                    
            
            
                | 5 | 1 |  | import os | 
            
                                                        
            
                                    
            
            
                | 6 | 1 |  | import shutil | 
            
                                                        
            
                                    
            
            
                | 7 | 1 |  | import sys | 
            
                                                        
            
                                    
            
            
                | 8 |  |  | import time | 
            
                                                        
            
                                    
            
            
                | 9 | 1 |  | from time import sleep | 
            
                                                        
            
                                    
            
            
                | 10 | 1 |  |  | 
            
                                                        
            
                                    
            
            
                | 11 |  |  | import click | 
            
                                                        
            
                                    
            
            
                | 12 | 1 |  |  | 
            
                                                        
            
                                    
            
            
                | 13 | 1 |  | from music_album_creation.ffprobe_client import FFProbeClient | 
            
                                                        
            
                                    
            
            
                | 14 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 15 | 1 |  | from .audio_segmentation import ( | 
            
                                                        
            
                                    
            
            
                | 16 |  |  |     AudioSegmenter, | 
            
                                                        
            
                                    
            
            
                | 17 | 1 |  |     SegmentationInformation, | 
            
                                                        
            
                                    
            
            
                | 18 | 1 |  |     TracksInformation, | 
            
                                                        
            
                                    
            
            
                | 19 |  |  | ) | 
            
                                                        
            
                                    
            
            
                | 20 | 1 |  | from .audio_segmentation.data import TrackTimestampsSequenceError | 
            
                                                        
            
                                    
            
            
                | 21 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 22 | 1 |  | # 'front-end', interface, interactive dialogs are imported below | 
            
                                                        
            
                                    
            
            
                | 23 |  |  | from .dialogs import DialogCommander as inout | 
            
                                                        
            
                                    
            
            
                | 24 |  |  | from .downloading import ( | 
            
                                                        
            
                                    
            
            
                | 25 |  |  |     InvalidUrlError, | 
            
                                                        
            
                                    
            
            
                | 26 | 1 |  |     TokenParameterNotInVideoInfoError, | 
            
                                                        
            
                                    
            
            
                | 27 |  |  |     UnavailableVideoError, | 
            
                                                        
            
                                    
            
            
                | 28 |  |  | ) | 
            
                                                        
            
                                    
            
            
                | 29 | 1 |  | from .ffmpeg import FFProbe | 
            
                                                        
            
                                    
            
            
                | 30 |  |  | from .metadata import MetadataDealer | 
            
                                                        
            
                                    
            
            
                | 31 |  |  | from .music_master import MusicMaster | 
            
                                                        
            
                                    
            
            
                | 32 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 33 |  |  | ffprobe = FFProbe(os.environ.get('MUSIC_FFPROBE', 'ffprobe')) | 
            
                                                        
            
                                    
            
            
                | 34 |  |  | ffprobe_client = FFProbeClient(ffprobe) | 
            
                                                        
            
                                    
            
            
                | 35 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 36 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 37 |  |  | if os.name == 'nt': | 
            
                                                        
            
                                    
            
            
                | 38 |  |  |     from pyreadline import Readline | 
            
                                                        
            
                                    
            
            
                | 39 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 40 |  |  |     readline = Readline() | 
            
                                                        
            
                                    
            
            
                | 41 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 42 |  |  | this_dir = os.path.dirname(os.path.realpath(__file__)) | 
            
                                                        
            
                                    
            
            
                | 43 |  |  | logger = logging.getLogger(__name__) | 
            
                                                        
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 45 | 1 |  |  | 
            
                                                        
            
                                    
            
            
                | 46 | 1 |  | def music_lib_directory(verbose=True): | 
            
                                                        
            
                                    
            
            
                | 47 |  |  |     music_dir = os.getenv('MUSIC_LIB_ROOT', None) | 
            
                                                        
            
                                    
            
            
                | 48 |  |  |     if music_dir is None: | 
            
                                                        
            
                                    
            
            
                | 49 |  |  |         print( | 
            
                                                        
            
                                    
            
            
                | 50 |  |  |             "Please set the environment variable MUSIC_LIB_ROOT to point to a directory that stores music." | 
            
                                                        
            
                                    
            
            
                | 51 |  |  |         ) | 
            
                                                        
            
                                    
            
            
                | 52 | 1 |  |         sys.exit(0) | 
            
                                                        
            
                                    
            
            
                | 53 | 1 |  |     if not os.path.isdir(music_dir): | 
            
                                                        
            
                                    
            
            
                | 54 | 1 |  |         try: | 
            
                                                        
            
                                    
            
            
                | 55 | 1 |  |             os.makedirs(music_dir) | 
            
                                                        
            
                                    
            
            
                | 56 | 1 |  |             if verbose: | 
            
                                                        
            
                                    
            
            
                | 57 |  |  |                 print("Created directory '{}'".format(music_dir)) | 
            
                                                        
            
                                    
            
            
                | 58 |  |  |         except (PermissionError, FileNotFoundError) as e: | 
            
                                                        
            
                                    
            
            
                | 59 |  |  |             print(e) | 
            
                                                        
            
                                    
            
            
                | 60 |  |  |             sys.exit(1) | 
            
                                                        
            
                                    
            
            
                | 61 |  |  |     return music_dir | 
            
                                                        
            
                                    
            
            
                | 62 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 63 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 64 |  |  | @click.command() | 
            
                                                        
            
                                    
            
            
                | 65 |  |  | @click.option( | 
            
                                                        
            
                                    
            
            
                | 66 |  |  |     '--tracks_info', | 
            
                                                        
            
                                    
            
            
                | 67 |  |  |     '-t_i', | 
            
                                                        
            
                                    
            
            
                | 68 |  |  |     type=click.File('r'), | 
            
                                                        
            
                                    
            
            
                | 69 |  |  |     help='File in which there is tracks information necessary to segment a music ablum into tracks.' | 
            
                                                        
            
                                    
            
            
                | 70 |  |  |     'If not provided, a prompt will allow you to type the input tracks information.', | 
            
                                                        
            
                                    
            
            
                | 71 |  |  | ) | 
            
                                                        
            
                                    
            
            
                | 72 |  |  | @click.option( | 
            
                                                        
            
                                    
            
            
                | 73 |  |  |     '--track_name/--no-track_name', | 
            
                                                        
            
                                    
            
            
                | 74 |  |  |     default=True, | 
            
                                                        
            
                                    
            
            
                | 75 |  |  |     show_default=True, | 
            
                                                        
            
                                    
            
            
                | 76 |  |  |     help='Whether to extract the track names from the mp3 files and write them as metadata correspondingly', | 
            
                                                        
            
                                    
            
            
                | 77 |  |  | ) | 
            
                                                        
            
                                    
            
            
                | 78 |  |  | @click.option( | 
            
                                                        
            
                                    
            
            
                | 79 |  |  |     '--track_number/--no-track_number', | 
            
                                                        
            
                                    
            
            
                | 80 |  |  |     default=True, | 
            
                                                        
            
                                    
            
            
                | 81 |  |  |     show_default=True, | 
            
                                                        
            
                                    
            
            
                | 82 |  |  |     help='Whether to extract the track numbers from the mp3 files and write them as metadata correspondingly', | 
            
                                                        
            
                                    
            
            
                | 83 |  |  | ) | 
            
                                                        
            
                                    
            
            
                | 84 |  |  | @click.option( | 
            
                                                        
            
                                    
            
            
                | 85 |  |  |     '--artist', | 
            
                                                        
            
                                    
            
            
                | 86 |  |  |     '-a', | 
            
                                                        
            
                                    
            
            
                | 87 |  |  |     help="If given, then value shall be used as the PTE1 tag: 'Lead performer(s)/Soloist(s)'.  In the music player 'clementine' it corresponds to the 'artist' column (and not the 'Album artist column) ", | 
            
                                                        
            
                                    
            
            
                | 88 |  |  | ) | 
            
                                                        
            
                                    
            
            
                | 89 |  |  | @click.option( | 
            
                                                        
            
                                    
            
            
                | 90 |  |  |     '--album_artist', | 
            
                                                        
            
                                    
            
            
                | 91 |  |  |     help="If given, then value shall be used as the TPE2 tag: 'Band/orchestra/accompaniment'.  In the music player 'clementine' it corresponds to the 'Album artist' column", | 
            
                                                        
            
                                    
            
            
                | 92 |  |  | ) | 
            
                                                        
            
                                    
            
            
                | 93 |  |  | @click.option('--video_url', '-u', help='the youtube video url') | 
            
                                                        
            
                                    
            
            
                | 94 |  |  | def main(tracks_info, track_name, track_number, artist, album_artist, video_url): | 
            
                                                        
            
                                    
            
            
                | 95 |  |  |     music_dir = music_lib_directory(verbose=True) | 
            
                                                        
            
                                    
            
            
                | 96 |  |  |     print("Music library: {}".format(music_dir)) | 
            
                                                        
            
                                    
            
            
                | 97 |  |  |     logger.error("Music library: {}".format(str(music_dir))) | 
            
                                                        
            
                                    
            
            
                | 98 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 99 |  |  |     ## Render Logo | 
            
                                                        
            
                                    
            
            
                | 100 |  |  |     inout.logo() | 
            
                                                        
            
                                    
            
            
                | 101 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 102 |  |  |     print('\n') | 
            
                                                        
            
                                    
            
            
                | 103 |  |  |     if not video_url: | 
            
                                                        
            
                                    
            
            
                | 104 |  |  |         video_url = inout.input_youtube_url_dialog() | 
            
                                                        
            
                                    
            
            
                | 105 |  |  |         print('\n') | 
            
                                                        
            
                                    
            
            
                | 106 |  |  |     logger.error(f"URL {video_url}") | 
            
                                                        
            
                                    
            
            
                | 107 |  |  |     ## Init | 
            
                                                        
            
                                    
            
            
                | 108 |  |  |     music_master = MusicMaster(music_dir) | 
            
                                                        
            
                                    
            
            
                | 109 |  |  |     # Segments Audio files into tracks and stores them in the system's temp dir (ie /tmp on Debian) | 
            
                                                        
            
                                    
            
            
                | 110 |  |  |     audio_segmenter = AudioSegmenter() | 
            
                                                        
            
                                    
            
            
                | 111 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 112 |  |  |     ## DOWNLOAD | 
            
                                                        
            
                                    
            
            
                | 113 |  |  |     while 1: | 
            
                                                        
            
                                    
            
            
                | 114 |  |  |         try: | 
            
                                                        
            
                                    
            
            
                | 115 |  |  |             album_file = music_master.url2mp3( | 
            
                                                        
            
                                    
            
            
                | 116 |  |  |                 video_url, suppress_certificate_validation=False, force_download=False | 
            
                                                        
            
                                    
            
            
                | 117 |  |  |             ) | 
            
                                                        
            
                                    
            
            
                | 118 |  |  |             break | 
            
                                                        
            
                                    
            
            
                | 119 |  |  |         except TokenParameterNotInVideoInfoError as e: | 
            
                                                        
            
                                    
            
            
                | 120 |  |  |             print(e, '\n') | 
            
                                                        
            
                                    
            
            
                | 121 |  |  |             if inout.update_and_retry_dialog()['update-youtube-dl']: | 
            
                                                        
            
                                    
            
            
                | 122 |  |  |                 music_master.update_youtube() | 
            
                                                        
            
                                    
            
            
                | 123 |  |  |             else: | 
            
                                                        
            
                                    
            
            
                | 124 |  |  |                 print("Exiting ..") | 
            
                                                        
            
                                    
            
            
                | 125 |  |  |                 sys.exit(1) | 
            
                                                        
            
                                    
            
            
                | 126 |  |  |         except (InvalidUrlError, UnavailableVideoError) as e: | 
            
                                                        
            
                                    
            
            
                | 127 |  |  |             print(e, '\n') | 
            
                                                        
            
                                    
            
            
                | 128 |  |  |             video_url = inout.input_youtube_url_dialog() | 
            
                                                        
            
                                    
            
            
                | 129 |  |  |             print('\n') | 
            
                                                        
            
                                    
            
            
                | 130 |  |  |     print('\n') | 
            
                                                        
            
                                    
            
            
                | 131 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 132 |  |  |     print("Album file: {}".format(album_file)) | 
            
                                                        
            
                                    
            
            
                | 133 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 134 |  |  |     ### RECEIVE TRACKS INFORMATION | 
            
                                                        
            
                                    
            
            
                | 135 |  |  |     if tracks_info: | 
            
                                                        
            
                                    
            
            
                | 136 |  |  |         tracks_info = TracksInformation.from_multiline(tracks_info.read().strip()) | 
            
                                                        
            
                                    
            
            
                | 137 |  |  |     else:  # Interactive track type input | 
            
                                                        
            
                                    
            
            
                | 138 |  |  |         sleep(0.5) | 
            
                                                        
            
                                    
            
            
                | 139 |  |  |         tracks_info = TracksInformation.from_multiline( | 
            
                                                        
            
                                    
            
            
                | 140 |  |  |             inout.interactive_track_info_input_dialog().strip() | 
            
                                                        
            
                                    
            
            
                | 141 |  |  |         ) | 
            
                                                        
            
                                    
            
            
                | 142 |  |  |         print() | 
            
                                                        
            
                                    
            
            
                | 143 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 144 |  |  |     # Ask user if the input represents song timestamps (withing the whole playtime) OR | 
            
                                                        
            
                                    
            
            
                | 145 |  |  |     # if the input represents song durations (that sum up to the total playtime) | 
            
                                                        
            
                                    
            
            
                | 146 |  |  |     answer = inout.track_information_type_dialog() | 
            
                                                        
            
                                    
            
            
                | 147 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 148 |  |  |     segmentation_info = SegmentationInformation.from_tracks_information( | 
            
                                                        
            
                                    
            
            
                | 149 |  |  |         tracks_info, hhmmss_type=answer.lower() | 
            
                                                        
            
                                    
            
            
                | 150 |  |  |     ) | 
            
                                                        
            
                                    
            
            
                | 151 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 152 |  |  |     # SEGMENTATION | 
            
                                                        
            
                                    
            
            
                | 153 |  |  |     try: | 
            
                                                        
            
                                    
            
            
                | 154 |  |  |         audio_file_paths = audio_segmenter.segment( | 
            
                                                        
            
                                    
            
            
                | 155 |  |  |             album_file, | 
            
                                                        
            
                                    
            
            
                | 156 |  |  |             segmentation_info, | 
            
                                                        
            
                                    
            
            
                | 157 |  |  |             sleep_seconds=0, | 
            
                                                        
            
                                    
            
            
                | 158 |  |  |         ) | 
            
                                                        
            
                                    
            
            
                | 159 |  |  |     except TrackTimestampsSequenceError as e: | 
            
                                                        
            
                                    
            
            
                | 160 | 1 |  |         print(e) | 
            
                                                        
            
                                    
            
            
                | 161 |  |  |         sys.exit(1) | 
            
                                                        
            
                                    
            
            
                | 162 | 1 |  |         # TODO capture ctrl-D to signal possible change of type from timestamp to durations and vice-versa... | 
            
                                                        
            
                                    
            
            
                | 163 |  |  |         # in order to put the above statement outside of while loop | 
            
                                                        
            
                                    
            
            
                | 164 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 165 |  |  |     # TODO re-implement the below using the ffmpeg proxy | 
            
                                                        
            
                                    
            
            
                | 166 |  |  |     durations = [ | 
            
                                                        
            
                                    
            
            
                | 167 | 1 |  |         time.strftime( | 
            
                                                        
            
                                    
            
            
                | 168 |  |  |             '%H:%M:%S', | 
            
                                                        
            
                                    
            
            
                | 169 |  |  |             time.gmtime(int(float(ffprobe_client.get_stream_info(f)['format']['duration']))), | 
            
                                                        
            
                                    
            
            
                | 170 |  |  |         ) | 
            
                                                        
            
                                    
            
            
                | 171 |  |  |         for f in audio_file_paths | 
            
                                                        
            
                                    
            
            
                | 172 |  |  |     ] | 
            
                                                        
            
                                    
            
            
                | 173 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 174 |  |  |     # durations = [StringParser.hhmmss_format(getattr(mutagen.File(t).info, 'length', 0)) for t in audio_file_paths] | 
            
                                                        
            
                                    
            
            
                | 175 |  |  |     max_row_length = max(len(_[0]) + len(_[1]) for _ in zip(audio_file_paths, durations)) | 
            
                                                        
            
                                    
            
            
                | 176 |  |  |     print("\n\nThese are the tracks created.\n") | 
            
                                                        
            
                                    
            
            
                | 177 |  |  |     print( | 
            
                                                        
            
                                    
            
            
                | 178 |  |  |         '\n'.join( | 
            
                                                        
            
                                    
            
            
                | 179 |  |  |             sorted( | 
            
                                                        
            
                                    
            
            
                | 180 |  |  |                 [ | 
            
                                                        
            
                                    
            
            
                | 181 |  |  |                     ' {}{}  {}'.format(t, (max_row_length - len(t) - len(d)) * ' ', d) | 
            
                                                        
            
                                    
            
            
                | 182 |  |  |                     for t, d in zip(audio_file_paths, durations) | 
            
                                                        
            
                                    
            
            
                | 183 | 1 |  |                 ] | 
            
                                                        
            
                                    
            
            
                | 184 |  |  |             ) | 
            
                                                        
            
                                    
            
            
                | 185 |  |  |         ), | 
            
                                                        
            
                                    
            
            
                | 186 |  |  |         '\n', | 
            
                                                        
            
                                    
            
            
                | 187 |  |  |     ) | 
            
                                                        
            
                                    
            
            
                | 188 |  |  |     # TODO | 
            
                                                        
            
                                    
            
            
                | 189 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 190 |  |  |     ### STORE TRACKS IN DIR in MUSIC LIBRARY ROOT | 
            
                                                        
            
                                    
            
            
                | 191 |  |  |     while 1: | 
            
                                                        
            
                                    
            
            
                | 192 |  |  |         print(type(music_dir), type(music_master.guessed_info)) | 
            
                                                        
            
                                    
            
            
                | 193 |  |  |         print(music_dir) | 
            
                                                        
            
                                    
            
            
                | 194 |  |  |         print(music_master.guessed_info) | 
            
                                                        
            
                                    
            
            
                | 195 |  |  |         album_dir = inout.album_directory_path_dialog(music_dir, **music_master.guessed_info) | 
            
                                                        
            
                                    
            
            
                | 196 |  |  |         try: | 
            
                                                        
            
                                    
            
            
                | 197 |  |  |             os.makedirs(album_dir) | 
            
                                                        
            
                                    
            
            
                | 198 |  |  |         except FileExistsError: | 
            
                                                        
            
                                    
            
            
                | 199 |  |  |             if not inout.confirm_copy_tracks_dialog(album_dir): | 
            
                                                        
            
                                    
            
            
                | 200 |  |  |                 continue | 
            
                                                        
            
                                    
            
            
                | 201 |  |  |         except FileNotFoundError: | 
            
                                                        
            
                                    
            
            
                | 202 |  |  |             print("The selected destination directory '{}' is not valid.".format(album_dir)) | 
            
                                                        
            
                                    
            
            
                | 203 |  |  |             continue | 
            
                                                        
            
                                    
            
            
                | 204 |  |  |         except PermissionError: | 
            
                                                        
            
                                    
            
            
                | 205 |  |  |             print( | 
            
                                                        
            
                                    
            
            
                | 206 |  |  |                 "You don't have permision to create a directory in path '{}'".format(album_dir) | 
            
                                                        
            
                                    
            
            
                | 207 |  |  |             ) | 
            
                                                        
            
                                    
            
            
                | 208 |  |  |             continue | 
            
                                                        
            
                                    
            
            
                | 209 |  |  |         try: | 
            
                                                        
            
                                    
            
            
                | 210 |  |  |             for track in audio_file_paths: | 
            
                                                        
            
                                    
            
            
                | 211 |  |  |                 destination_file_path = os.path.join(album_dir, os.path.basename(track)) | 
            
                                                        
            
                                    
            
            
                | 212 |  |  |                 if os.path.isfile(destination_file_path): | 
            
                                                        
            
                                    
            
            
                | 213 |  |  |                     print( | 
            
                                                        
            
                                    
            
            
                | 214 |  |  |                         " File '{}' already exists. in '{}'. Skipping".format( | 
            
                                                        
            
                                    
            
            
                | 215 |  |  |                             os.path.basename(track), album_dir | 
            
                                                        
            
                                    
            
            
                | 216 |  |  |                         ) | 
            
                                                        
            
                                    
            
            
                | 217 |  |  |                     ) | 
            
                                                        
            
                                    
            
            
                | 218 |  |  |                 else: | 
            
                                                        
            
                                    
            
            
                | 219 |  |  |                     shutil.copyfile(track, destination_file_path) | 
            
                                                        
            
                                    
            
            
                | 220 |  |  |             print("Album tracks reside in '{}'".format(album_dir)) | 
            
                                                        
            
                                    
            
            
                | 221 |  |  |             break | 
            
                                                        
            
                                    
            
            
                | 222 |  |  |         except PermissionError: | 
            
                                                        
            
                                    
            
            
                | 223 |  |  |             print( | 
            
                                                        
            
                                    
            
            
                | 224 |  |  |                 "Can't copy tracks to '{}' folder. You don't have write permissions in this directory".format( | 
            
                                                        
            
                                    
            
            
                | 225 |  |  |                     album_dir | 
            
                                                        
            
                                    
            
            
                | 226 |  |  |                 ) | 
            
                                                        
            
                                    
            
            
                | 227 |  |  |             ) | 
            
                                                        
            
                                    
            
            
                | 228 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 229 |  |  |     ### WRITE METADATA | 
            
                                                        
            
                                    
            
            
                | 230 |  |  |     md = MetadataDealer() | 
            
                                                        
            
                                    
            
            
                | 231 |  |  |     answers = inout.interactive_metadata_dialogs(**music_master.guessed_info) | 
            
                                                        
            
                                    
            
            
                | 232 |  |  |     md.set_album_metadata( | 
            
                                                        
            
                                    
            
            
                | 233 |  |  |         album_dir, | 
            
                                                        
            
                                    
            
            
                | 234 |  |  |         track_number=track_number, | 
            
                                                        
            
                                    
            
            
                | 235 |  |  |         track_name=track_name, | 
            
                                                        
            
                                    
            
            
                | 236 |  |  |         artist=answers['artist'], | 
            
                                                        
            
                                    
            
            
                | 237 |  |  |         album_artist=answers['album-artist'], | 
            
                                                        
            
                                    
            
            
                | 238 |  |  |         album=answers['album'], | 
            
                                                        
            
                                    
            
            
                | 239 |  |  |         year=answers['year'], | 
            
                                                        
            
                                    
            
            
                | 240 |  |  |     ) | 
            
                                                        
            
                                    
            
            
                | 241 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 242 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 243 |  |  | class TabCompleter: | 
            
                                                        
            
                                    
            
            
                | 244 |  |  |     """A tab completer that can either complete from the filesystem or from a list.""" | 
            
                                                        
            
                                    
            
            
                | 245 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 246 |  |  |     def pathCompleter(self, text, state): | 
            
                                                        
            
                                    
            
            
                | 247 |  |  |         """This is the tab completer for systems paths. Only tested on *nix systems""" | 
            
                                                        
            
                                    
            
            
                | 248 |  |  |         _ = readline.get_line_buffer().split() | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                        
            
                                    
            
            
                | 249 |  |  |         return [x for x in glob.glob(text + '*')][state] | 
            
                                                        
            
                                    
            
            
                | 250 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 251 |  |  |     def createListCompleter(self, ll): | 
            
                                                        
            
                                    
            
            
                | 252 |  |  |         """ | 
            
                                                        
            
                                    
            
            
                | 253 |  |  |         This is a closure that creates a method that autocompletes from the given list. Since the autocomplete | 
            
                                                        
            
                                    
            
            
                | 254 |  |  |         function can't be given a list to complete from a closure is used to create the listCompleter function with a | 
            
                                                        
            
                                    
            
            
                | 255 |  |  |         list to complete from. | 
            
                                                        
            
                                    
            
            
                | 256 |  |  |         """ | 
            
                                                        
            
                                    
            
            
                | 257 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 258 |  |  |         def listCompleter(text, state): | 
            
                                                        
            
                                    
            
            
                | 259 |  |  |             line = readline.get_line_buffer() | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                        
            
                                    
            
            
                | 260 |  |  |             if not line: | 
            
                                                        
            
                                    
            
            
                | 261 |  |  |                 return [c + " " for c in ll][state] | 
            
                                                        
            
                                    
            
            
                | 262 |  |  |             else: | 
            
                                                        
            
                                    
            
            
                | 263 |  |  |                 return [c + " " for c in ll if c.startswith(line)][state] | 
            
                                                        
            
                                    
            
            
                | 264 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 265 |  |  |         self.listCompleter = listCompleter | 
            
                                                        
            
                                    
            
            
                | 266 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 267 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 268 |  |  | if __name__ == '__main__': | 
            
                                                        
            
                                    
            
            
                | 269 |  |  |     completer = TabCompleter() | 
            
                                                        
            
                                    
            
            
                | 270 |  |  |     readline.set_completer_delims('\t') | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                        
            
                                    
            
            
                | 271 |  |  |     readline.parse_and_bind("tab: complete") | 
            
                                                        
            
                                    
            
            
                | 272 |  |  |     readline.set_completer(completer.pathCompleter) | 
            
                                                        
            
                                    
            
            
                | 273 |  |  |     main() | 
            
                                                        
            
                                    
            
            
                | 274 |  |  |  |