Пример #1
0
    def remove_tags(self, part_item):
        SublerCLI = os.path.join(sys.path[0], "SublerCLI-v010")
        filepath = part_item.modified_file_path()
        
        #removal of artwork doesn't seem to work
        all_tags = ["{Artwork:}", "{HD Video:}", "{Gapless:}", "{Content Rating:}", "{Media Kind:}", "{Name:}", "{Artist:}", "{Album Artist:}", "{Album:}", "{Grouping:}", "{Composer:}", "{Comments:}", "{Genre:}", "{Release Date:}", "{Track #:}", "{Disk #:}", "{TV Show:}", "{TV Episode #:}", "{TV Network:}", "{TV Episode ID:}", "{TV Season:}", "{Description:}", "{Long Description:}", "{Rating:}", "{Rating Annotation:}", "{Studio:}", "{Cast:}", "{Director:}", "{Codirector:}", "{Producers:}", "{Screenwriters:}", "{Lyrics:}", "{Copyright:}", "{Encoding Tool:}", "{Encoded By:}", "{contentID:}"]#these are currently not supported in subler cli tool, "{XID:}", "{iTunes Account:}", "{Sort Name:}", "{Sort Artist:}", "{Sort Album Artist:}", "{Sort Album:}", "{Sort Composer:}", "{Sort TV Show:}"]
        logging.warning("removing tags...")
        
        #Create the command line command
        tag_removal_cmd = ['%s' % SublerCLI]
        
        if self.opts.optimize:
            action_description = "Tags removed and optimized"
            tag_removal_cmd.append("-O")
        else:
            action_description = "Tags removed"
        #end if optimize

        tag_removal_cmd.append("-t")
        tag_removal_cmd.append("".join(all_tags))
        tag_removal_cmd.append("-i")
        tag_removal_cmd.append(filepath)
        
        success = self.execute_command(filepath, tag_removal_cmd, action_description)
        if success:
            Summary().metadata_removal_succeeded()
        else:
            Summary().metadata_removal_failed()
    def tag(self, part_item):
        SublerCLI = os.path.join(sys.path[0], "SublerCLI")
        filepath = part_item.modified_file_path()
        directory = os.path.dirname(filepath)
        filename = os.path.basename(filepath)
        filename_without_extension = os.path.splitext(filename)[0]

        logging.warning("tagging...")

        #Create the command line command
        tag_cmd = ['%s' % SublerCLI]

        if self.opts.optimize:
            action_description = "Tags added and optimized"
            tag_cmd.append("-optimize")
        else:
            action_description = "Tags added"
        #end if optimize

        if self.opts.embed_subtitles:
            action_description += ", and any subtitles embedded"
            compatible_sidecar_subtitles = self.get_all_sidecar_subtitles(
                directory, filename_without_extension, codec='srt')
            if len(compatible_sidecar_subtitles) == 0:
                logging.warning("Found no 'srt' subtitle files to embed...")
            else:
                for sub in compatible_sidecar_subtitles:
                    tag_cmd.append("-s")
                    tag_cmd.append(os.path.join(directory, sub))

        if self.opts.chapter_previews:
            action_description += ", and chapter previews generated"
            tag_cmd.append("-p")

        tag_cmd.append("-metadata")
        tag_cmd.append(part_item.tag_string())  #also downloads the artwork
        tag_cmd.append("-source")
        tag_cmd.append(filepath)
        tag_cmd.append("-destination")
        tmp_filepath = filepath + "_tmp"
        tag_cmd.append(tmp_filepath)

        success = self.execute_command(filepath, tag_cmd, action_description)
        if success:
            Summary().metadata_embedded_succeeded()
            logging.info("Replacing old file with tagged one...")
            shutil.move(tmp_filepath, filepath)
        else:
            Summary().metadata_embedded_failed()
            logging.info("Cleaning up temporary file...")
            os.unlink(tmp_filepath)
Пример #3
0
 def add_to_itunes(self, part_item):
     if self.video_item.__class__.__name__ == "MovieItem":
         itunes_playlist = "Movies"
     else:
         itunes_playlist = "TV Shows"
     
     item_title = self.video_item.title
     actionable_file_path = part_item.modified_file_path()
     
     if not self.opts.force:
         logging.warning("Finding '%s' in iTunes..." % actionable_file_path)
         
         search_string = 'set currentItems to search playlist "%s" for "%s" only displayed' % (itunes_playlist, item_title)
         delimiter = "###"
         result_creation_string = 'set output to output & "%s"' % delimiter
         does_item_exist_command = ["osascript", '-e', 'tell application "iTunes"', '-e', 'try' ,'-e', search_string, '-e', 'set output to ""', '-e', 'repeat with currentItem in currentItems', '-e', 'set loc to (location of currentItem)', '-e', 'if output is not equal to "" then', '-e', result_creation_string, '-e', 'end if', '-e', 'set output to output & POSIX path of loc', '-e', 'end repeat', '-e', 'output', '-e', 'end try', '-e', 'end tell']
         logging.debug("'find in iTunes' script: %s" % (does_item_exist_command))
         result_string = subprocess.Popen(does_item_exist_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn = self.preexec).communicate()[0].rstrip()
         result_file_paths = result_string.split(delimiter)
         logging.debug("Find results in iTunes: %s" % result_file_paths)
         for file_path in result_file_paths:
             unicode_filepath = normalize('NFC', file_path.decode('utf-8'))
             if unicode_filepath == actionable_file_path:
                 logging.warning("  Already added to iTunes")
                 return
             #end if result == actionable_file_path:
         #end for file_path in result_file_paths
     #end if not self.opts.force
     
     logging.warning("  Adding to iTunes...")
     file_str = 'set p to (POSIX file "%s")' % actionable_file_path
     add_to_playlist_str = 'add p to playlist "%s"' % itunes_playlist
     add_to_itunes_command = ['osascript', '-e', 'try', '-e', file_str, '-e', 'tell application "iTunes"', '-e', add_to_playlist_str, '-e', 'end tell', '-e', 'end try']
     logging.debug("'add to iTunes' script: %s" % (add_to_itunes_command))
     result = subprocess.Popen(add_to_itunes_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn = self.preexec).communicate()[0].rstrip()
     if result.startswith("file track id"):
         Summary().add_to_itunes_succeeded()
         logging.warning("    Adding additional metadata to item in iTunes...")
         current_item_str = 'tell %s' % result
         set_rating_str = 'set rating to %i as integer' % self.video_item.itunes_rating()
         set_play_count_str = 'set played count to %s as integer' % self.video_item.view_count
         add_metadata_to_itunes_command = ['osascript', '-e', 'try', '-e', 'tell application "iTunes"', '-e', current_item_str, '-e', set_play_count_str, '-e', set_rating_str, '-e', 'end tell', '-e', 'end tell', '-e', 'end try']
         logging.debug("'add additional metadata iTunes' script: %s" % (add_metadata_to_itunes_command))
         subprocess.call(add_metadata_to_itunes_command)
     else:
         Summary().add_to_itunes_failed()
         logging.critical("Failed 'add to iTunes' for '%s'. Incorrect path or not a compatible file type?" % (actionable_file_path) )
Пример #4
0
 def optimize(self, part_item):
     SublerCLI = os.path.join(sys.path[0], "SublerCLI-v010")
     filepath = part_item.modified_file_path()
     
     logging.warning("optimizing file...")
     
     action_description = "Tags optimized"
     #Create the command line command
     optimize_cmd = ['%s' % SublerCLI]
     optimize_cmd.append("-O")
     optimize_cmd.append("-i")
     optimize_cmd.append(filepath)
     
     success = self.execute_command(filepath, optimize_cmd, action_description)
     if success:
         Summary().metadata_optimized_succeeded()
     else:
         Summary().metadata_optimized_failed()
Пример #5
0
    def process(self):
        skipped_all = True

        if self.opts.gather_statistics:
            skipped_all = False
            LibraryStatistics().add_item(self.video_item)
        #end if gather_statistics
        for index, media_item in enumerate(self.media_items):
            logging.warning("processing %d/%d media_items" %
                            (index + 1, len(self.media_items)))
            part_items = media_item.part_items
            for index2, part_item in enumerate(part_items):
                no_action = True
                logging.warning(" processing %d/%d part_items" %
                                (index2 + 1, len(part_items)))
                Summary().increment_parts_processed()
                if self.opts.removetags and self.canTag(part_item):
                    skipped_all = no_action = False
                    self.remove_tags(part_item)
                #end if removetags
                if self.opts.tag and self.canTag(part_item) and self.shouldTag(
                        part_item):
                    skipped_all = no_action = False
                    self.tag(part_item)
                #end if tag
                if self.opts.optimize and not self.opts.tag and not self.opts.removetags and self.canTag(
                        part_item):
                    #optimize is done together with tagging or removing, so only needs to be done here if it's the exclusive action
                    skipped_all = no_action = False
                    self.optimize(part_item)
                #end if optimize
                if self.opts.export_resources:
                    skipped_all = no_action = False
                    self.export_resources(part_item)
                #end if export_resouces
                if self.opts.add_to_itunes:
                    skipped_all = no_action = False
                    self.add_to_itunes(part_item)
                #end if add_to_itunes
                if self.opts.open_file_location and not no_action:
                    logging.warning("opening '%s'..." %
                                    part_item.modified_file_path())
                    command = ['open', "-R", part_item.modified_file_path()]
                    subprocess.call(command)
                #end if self.opts.open_file_location
            #end for part_items
        #end for media_items
        if skipped_all:
            logging.warning(
                "skipping: found no suitable files for specified tasks")
        #end if skipped_all

    #end def process_item


#end MediaPartProcessor
Пример #6
0
    def export_resources(self, part_item):
        part_item_file_path = part_item.modified_file_path()
        directory = os.path.dirname(part_item_file_path)
        filename = os.path.basename(part_item_file_path)
        filename_without_extension = os.path.splitext(filename)[0]

        #=== subtitles ===
        #build up language_code dict
        if self.opts.export_subtitles:
            logging.warning("attempting to export subtitles...")
            subtitle_stream_type = "3"
            all_non_embedded_subtitles = []
            for stream_item in part_item.stream_items:
                if stream_item.stream_type == subtitle_stream_type and stream_item.key != "":
                    all_non_embedded_subtitles.append(stream_item)
                #end if
            #end for
            number_of_non_embedded_subtitles = len(all_non_embedded_subtitles)
            if number_of_non_embedded_subtitles == 0:
                logging.warning("no subtitles found")
            else:
                logging.warning("found %d subtitle(s)" %
                                number_of_non_embedded_subtitles)

                categorized_subtitles = {}
                for subtitle in all_non_embedded_subtitles:
                    key = (subtitle.language_code, subtitle.codec)
                    if categorized_subtitles.has_key(key):
                        categorized_subtitles[key].append(subtitle)
                    else:
                        categorized_subtitles[key] = [subtitle]
                    #end if has_key
                #end for all_subtitles

                exported_subtitles = 0
                for key, subtitles in categorized_subtitles.iteritems():
                    #key = (eng, srt), (eng, sub), (fre, srt), etc.
                    language_code = key[0]
                    codec = key[1]
                    #get all existing sub files. example filename: Sopranos - S01E01 - The Pilot*.eng.srt
                    compatible_sidecar_subtitles = self.get_all_sidecar_subtitles(
                        directory, filename_without_extension, language_code,
                        codec)
                    if len(compatible_sidecar_subtitles) > 0:
                        logging.warning(
                            "Subtitle file(s) with language code '%s' of type '%s' already exist. Skipping all matching..."
                            % (language_code, codec))
                        continue
                    #end if

                    #export subs
                    i = 0
                    for subtitle in subtitles:
                        if i == 0:
                            subtitle_filename = "%s.%s.%s" % (
                                filename_without_extension, language_code,
                                codec)
                        else:
                            subtitle_filename = "%s.%02d.%s.%s" % (
                                filename_without_extension, i, language_code,
                                codec)
                        #end if
                        subtitle_full_path = os.path.join(
                            directory, subtitle_filename)
                        success = subtitle.export_to_path(subtitle_full_path)
                        if success:
                            i += 1
                            exported_subtitles += 1
                            Summary().subtitle_export_succeeded()
                        else:
                            Summary().subtitle_export_failed()
                        #end success
                    #end for subtitles
                #end for categorized_subtitles
                logging.warning(
                    "exported %d subtitle(s), skipped %d" %
                    (exported_subtitles,
                     (number_of_non_embedded_subtitles - exported_subtitles)))
            #end if len(all_non_embedded_subtitles) == 0:
        #end if subtitles

        if self.opts.export_artwork:
            logging.error("artwork export not yet implemented...")
Пример #7
0
def main():
    signal.signal(signal.SIGINT, signal_handler)
    
    root = logging.getLogger()
    root.setLevel(logging.WARNING)
    root.addHandler(ColorizingStreamHandler())
    
    parser = OptionParser(usage="\
%prog [options]\n\
Example 1: %prog --tag\n\
Example 2: %prog --tag -b --username='******' --interactive-password\n\
\ttag everything in the library, and authenticate to Plex Home as user [email protected] with password being prompted for (password can also be supplied using the --password option)\n\
Example 3: %prog -bq --tag --remove-all-tags --optimize --export-subtitles --embed-subtitles -ip 192.168.0.2 --port 55400\n\
Example 4: %prog --subtitles -m 'D:\Movies' '/Volumes/Media/Movies' -m '\\' '/'\n\
Example 5: %prog -tb --batch-mediatype=movie --batch-breadcrumb='kids>cars'\n\
\tonly tag movies who are in a section containing the word 'kids' and movies who's name contains 'cars'\n\
Example 6: %prog -tb --batch-mediatype=show --batch-breadcrumb='>lost>season 1>pilot'\n\
\tonly tag tv episodes, matches all sections, show name contains lost, season 1, episode title contains 'pilot'\n\
Example 7: %prog -tb --batch-breadcrumb='tv>weeds>>goat'\n\
\tonly tag items who are in a section who's title contains 'tv', where the movie or show name contains 'weeds', any season and episode title contains 'goat' \n\
%prog -h for full list of options\n\n\
Filepaths to media items in PMS need to be the same as on machine that is running this script (can be worked around by using the -m option to modify the file path).\
")
    parser.add_option(  "-t", "--tag", action="store_true", dest="tag",
                        help="tag all compatible file types, and update any previously tagged files (if metadata in plex has changed)")
    parser.add_option(  "--tag-update", action="store_true", dest="tag_update",
                        help="update previously tagged files if the PMS entry has changed since last time (modification time)")
    parser.add_option(  "--tag-tv-prefer-season-artwork", action="store_true", dest="tag_prefer_season_artwork",
                        help="when tagging tv show episodes, the season artwork will be used instead of the episode thumbnail")
    
    parser.add_option(  "-r", "--remove-tags", action="store_true", dest="removetags",
                        help="remove all compatible tags from the files")
    parser.add_option(  "-f", "--force", action="store_true", dest="force",
                        help="ignore previous work and steam ahead with task (will re-tag previously tagged files, re-enters data into TV, etc.)")
                        
    parser.add_option(  "-o", "--optimize", action="store_true", dest="optimize",
                        help="interleave the audio and video samples, and put the \"MooV\" atom at the beginning of the file")
    parser.add_option(  "--chapter-previews", action="store_true", dest="chapter_previews",
                        help="generate preview images for any chapter markers")
                        
    parser.add_option(  "--export-subtitles", action="store_true", dest="export_subtitles",
                        help="export any subtitles to the same path as the video file")
    parser.add_option(  "--embed-subtitles", action="store_true", dest="embed_subtitles",
                        help="embed compatible files with a compatible \"sidecar\" subtitle file if present")
                        
    parser.add_option(  "--export-artwork", action="store_true", dest="export_artwork",
                        help="export the artwork to the same path as the video file")
    parser.add_option(  "--stats", action="store_true", dest="gather_statistics",
                        help="gather \"interesting\" statistics about the items being processed")
    parser.add_option(  "-m", action="append", type="string", dest="path_modifications", nargs=2, metavar="<find> <replace>",
                        help="perform a find & replace operation on the pms' media file paths (useful if you are running the script on a different machine than the one who is hosting the pms, i.e. the mount paths are different). Supply multiple times to perform several different replacements (operations are performed in order supplied).")
    parser.add_option(  "--open", action="store_true", dest="open_file_location",
                        help="open a Finder window at the containing folder of the file just processed (Mac OS X only)")

    parser.add_option(  "--add-to-tv", action="store_true", dest="add_to_tv",
                        help="adds the item to TV if not already present")
                        
    parser.add_option(  "-i", "--ip", action="store", dest="ip", type="string",
                        help="specify an alternate IP address that hosts a PMS to connect to (default is localhost)")
    parser.add_option(  "-p", "--port", action="store", dest="port", type="int",
                        help="specify an alternate port number to use when connecting to the PMS (default is 32400)")
                        
    parser.add_option(  "--username", action="store", dest="username", type="string",
                        help="specify the username to use when authenticating with the PMS (default is no authentication)")
    parser.add_option(  "--password", action="store", dest="password", type="string",
                        help="specify the password to use when authenticating with the PMS (default is no authentication)")
    parser.add_option(  "--interactive-password", action="store_true", dest="interactive_password",
                        help="the password to use when authenticating with the PMS will be supplied interactively")
    
    parser.add_option(  "--interactive", action="store_true", dest="interactive",
                        help="interactivly select files to operate on [default]")
    parser.add_option(  "-b", "--batch", action="store_false", dest="interactive",
                        help="disable interactive mode. Requires no human intervention once launched, and will perform operations on all valid files")
    parser.add_option(  "--batch-mediatype", action="store", dest="batch_mediatype", type="choice", choices=["any", "movie", "show"], metavar="[movie/show]",
                        help="only specified media type will be processed")
    parser.add_option(  "--batch-breadcrumb", action="store", dest="batch_breadcrumb", type="string", metavar="breadcrumb",
                        help="only items matching the breadcrumb trail will be processed. Components seperated by '>' (case insensitive)")

    parser.add_option(  "-v", "--verbose", dest="verbose", action="callback", 
                        callback=setLogLevel, help='increase verbosity (can be supplied 0-2 times)')
    parser.add_option(  "-q", "--quiet", action="store_true", dest="quiet",
                        help="ninja-like processing (can only be used when in batch mode)")
    parser.add_option(  "-d", "--dry-run", action="store_true", dest="dryrun",
                        help="pretend to do the job, but never actually change or export anything. Pretends that all tasks succeed. Useful for testing purposes")

    parser.set_defaults( tag=False, tag_update=False, tag_prefer_season_artwork=False, remove_tags=False, 
                        optimize=False, chapter_previews=False, embed_subtitles=False,
                        export_resources=False, export_subtitles=False, export_artwork=False, 
                        gather_statistics=False, open_file_location=False, add_to_tv=False,
                        force_tagging=False, dryrun=False,
                        interactive=True, quiet=False, batch_mediatype="any", batch_breadcrumb="",
                        ip="localhost", port=32400, username="", password="", interactive_password=False,
                        path_modifications=[])
    
    try:
        opts, args = parser.parse_args()
    except OptionValueError as e:
        parser.error(e)
    
    if opts.export_subtitles or opts.export_artwork:
        opts.export_resources = True
    
    if not opts.tag and not opts.removetags and not opts.optimize and not opts.export_resources and not opts.add_to_tv and not opts.gather_statistics:
        parser.error("No task to perform. Our work here is done...")
    
    if opts.tag_prefer_season_artwork and not opts.tag:
        parser.error("Cannot prefer season artwork when not tagging...")
        
    if opts.chapter_previews and not opts.tag:
        parser.error("Cannot generate chapter previews when not tagging...")
        
    if opts.embed_subtitles and not opts.tag:
        parser.error("Cannot embed subtitles when not tagging...")
        
    if opts.tag_update and not opts.tag:
        parser.error("Cannot update tags when not tagging...")
    
    if opts.interactive and ( opts.batch_mediatype != "any" or len(opts.batch_breadcrumb) > 0):
        parser.error("Cannot use batch filtering options when batch mode is not active...")
        
    if opts.interactive_password:
        opts.password = getpass.getpass("Password $")
        
    if (len(opts.username) > 0 and not len(opts.password) > 0) or (len(opts.password) > 0 and not len(opts.username) > 0):
        parser.error("Must supply both username and password when using authentication to connect to PMS...")
    
    if len(opts.batch_breadcrumb) > 0:
        opts.batch_breadcrumb = opts.batch_breadcrumb.lower().split(">")
        opts.batch_breadcrumb.reverse()
    
    if opts.quiet:
        root.setLevel(logging.ERROR)
    
    if opts.interactive and not root.isEnabledFor(logging.INFO):
        root.setLevel(logging.INFO)
    
    if opts.dryrun:
        logging.critical( "WARNING, RUNNING IN 'DRY RUN MODE'. NO ACTUAL CHANGES WILL BE MADE" )
    elif opts.removetags:
        logging.critical( "WARNING, TAGS WILL BE REMOVED PERMANENTLY" )
    elif opts.force:
        logging.critical( "FORCE MODE ENABLED. THIS WILL BYPASS ANY 'HAS THIS BEEN DONE BEFORE' CHECKS" )
    
    logging.error( generate_centered_padded_string(" Plex Media Tagger Started ") )
    
    if opts.gather_statistics:
        statistics = LibraryStatistics()
    summary = Summary()
    request_handler = PmsRequestHandler()
    request_handler.ip = opts.ip
    request_handler.port = opts.port
    request_handler.setup_opener(opts.username, opts.password)
    
    global section_processor
    section_processor = SectionProcessor(opts, request_handler)
    
    logging.error( "Connecting to PMS at %s:%d" % (opts.ip, opts.port) )
    sections_container = request_handler.get_sections_container()
    media_container = sections_container.getroot()
    title = media_container.attrib['title1']
    section_elements = media_container.getchildren()
    
    section_element_choice = '' #default is empty == all
    if opts.interactive:
        logging.info( "List of sections for %s" % title )
        for index, section_element in enumerate(section_elements):
            logging.info( "%d. %s" %(index, section_element.attrib['title']) )
        #end for
        if len(section_elements) == 0:
            logging.error( "No sections found" )
        else:    
            logging.warning( "empty input equals all" )
    
            #ask user what sections should be processed
            section_element_choice = raw_input("Section to process $")
            if section_element_choice != '':
                try:
                    section_element_choice = int(section_element_choice)
                except ValueError, e:
                    logging.debug(e)
                    logging.critical( "'%s' is not a valid section number" % input )
                    sys.exit(1)
Пример #8
0
	model_path = './model'

	tf.reset_default_graph()

	"""
    Creates the master worker that maintains the master network.
    We then initialize the workers array.
    """
	global_episodes = tf.Variable(0, dtype=tf.int32, name='global_episodes', trainable=False)
	total_frames = tf.Variable(0, dtype=tf.int32, name='total_frames', trainable=False)
	learning_rate = tf.train.polynomial_decay(LEARNING_RATE, total_frames, MAX_ITERATION // 2,
											  LEARNING_RATE * 0.1)

	with tf.device("/cpu:0"):
		summary_writer = tf.summary.FileWriter("./train/" + SUMMARY_NAME + str(BETA[BETA_i]))
		summary = Summary(summary_writer)
		master_worker = Worker('global', env, GAMMA, learning_rate, global_episodes, total_frames, model_path, False,
							   False, num_workers, summary, BETA)
		workers = []
		for i in range(num_workers):
			print (i)
			workers.append(
				Worker(i, env, GAMMA, learning_rate, global_episodes, total_frames, model_path, render, save_img,
					   num_workers, summary, BETA[BETA_i]))

	"""
    Initializes tensorflow variables
    """
	with tf.Session(config=tf.ConfigProto(intra_op_parallelism_threads=1)) as session:
		saver = tf.train.Saver(max_to_keep=5)
		if load: