예제 #1
0
    def add_movies(self, url, movie_list=[], movie_ids=[], max_age=0):
        """
        add movies to list
        """
        max_date = add_years(max_age * -1)
        print(u"Retrieving the trakt list: {}".format(url))
        data = {}
        if max_age != 0:
            data['extended'] = 'full'
        movie_data = self._handle_request('get', url, data=data)
        for meta in movie_data:
            if 'movie' not in meta:
                meta['movie'] = meta
            # Skip already added movies
            if meta['movie']['ids']['imdb'] in movie_ids:
                continue
            if not meta['movie']['year']:
                continue
            # Skip old movies
            if max_age != 0 \
                    and (max_date > datetime.datetime.strptime(
                            meta['movie']['released'], '%Y-%m-%d')):
                continue
            movie_list.append({
                'id': meta['movie']['ids']['imdb'],
                'tmdb_id': meta['movie']['ids'].get('tmdb', ''),
                'title': meta['movie']['title'],
                'year': meta['movie']['year'],
            })
            movie_ids.append(meta['movie']['ids']['imdb'])
            if meta['movie']['ids'].get('tmdb'):
                movie_ids.append('tmdb' + str(meta['movie']['ids']['tmdb']))

        return movie_list, movie_ids
예제 #2
0
    def add_movies(self, url, movie_list=None, movie_ids=None, max_age=0):
        if not movie_list:
            movie_list = []
        if not movie_ids:
            movie_ids = []
        max_date = add_years(max_age * -1)
        logs.info(u"Retrieving the trakt list: {}".format(url))
        data = {}
        if max_age != 0:
            data['extended'] = 'full'
        movie_data = self._handle_request('get', url, data=data)
        for m in movie_data:
            if 'movie' not in m:
                m['movie'] = m
            # Skip already added movies
            if m['movie']['ids']['imdb'] in movie_ids:
                continue
            if not m['movie']['year']:  # TODO: Handle this better?
                continue
            # Skip old movies
            if max_age != 0 \
                    and (max_date > datetime.datetime.strptime(
                        m['movie']['released'], '%Y-%m-%d')):
                continue
            movie_list.append({
                'id': m['movie']['ids']['imdb'],
                'tmdb_id': str(m['movie']['ids'].get('tmdb', '')),
                'title': m['movie']['title'],
                'year': m['movie']['year'],
            })
            movie_ids.append(m['movie']['ids']['imdb'])
            if m['movie']['ids'].get('tmdb'):
                movie_ids.append('tmdb' + str(m['movie']['ids']['tmdb']))

        return movie_list, movie_ids
예제 #3
0
    def _extend_over_planning_horizon(self, selected_days, extracted_series,
                                      extracted_weights):
        """

        :param selected_days: output of reprensentative days selection
        :param extracted_series: output of reprensentative days selection
        :param extracted_weights: output of reprensentative days selection
        :return: 3 lists with selected_days, extracted_series, and extracted_weights extended to the investment
        horizon with progressions applied if any.
        """
        logging.info(
            'Extending representative days of first year over investment horizon with progressions...'
        )

        # Simply replicate days and weights with a time shift of one year
        days = [{add_years(k, i): v
                 for k, v in selected_days[0].items()}
                for i in range(self.sizing_config.investment_horizon)]
        weights = [{
            add_years(k, i): v
            for k, v in extracted_weights[0].items()
        } for i in range(self.sizing_config.investment_horizon)]

        # Extend series to investment horizon
        init_series = extracted_series[0].copy()
        series = [init_series]
        current_series = init_series.copy()
        # Fetch progressions first, if any.
        progressions = self._get_progressions()

        for i in range(1, self.sizing_config.investment_horizon):
            # Compute number of days of the year (some have 366 ...)
            current_year = current_series.index[0].year
            one_year_delta = (datetime(current_year + 1, 1, 1) -
                              datetime(current_year, 1, 1))

            new_series = current_series.copy()
            # Add a year
            new_series.index += one_year_delta
            # apply progressions
            for device_name, progression in progressions.items():
                new_series[device_name] *= (1 + progression)

            series.append(new_series)
            current_series = new_series

        return days, series, weights
예제 #4
0
    def __determine_season(self):
        """Attempt to determine the season from `start` and `end`. Note: all we
        care about is the years.

        Returns:
            {'start': datetime, 'end': datetime}: Any date in the starting year
                of the season followed by `self.end`
        """
        if self.start.year == self.end.year:
            start = utils.add_years(self.start, -1)
        else:
            start = self.start
        return {'start': start, 'end': self.end}
예제 #5
0
def process_cakeday_message(message, database):
    log.info("Processing cakeday")

    if database.get_cakeday(message.author.name) is not None:
        log.info("Cakeday already exists")
        return ["It looks like you already have a cakeday reminder set."]

    account_created = utils.datetime_from_timestamp(message.author.created_utc)
    next_anniversary = utils.add_years(
        account_created,
        utils.datetime_now().year - account_created.year)
    if next_anniversary < utils.datetime_now():
        next_anniversary = utils.add_years(next_anniversary, 1)
    log.debug(
        f"u/{message.author.name} created {utils.get_datetime_string(account_created)}, "
        f"anniversary {utils.get_datetime_string(next_anniversary)}")

    cakeday = Cakeday(message.author.name, next_anniversary)
    database.add_cakeday(cakeday)

    return cakeday.render_confirmation(
        database.get_settings(message.author.name).timezone)
예제 #6
0
파일: forms.py 프로젝트: pesikj/ballot_box
class ExportResultsForm(FlaskForm):
    body = SelectField(u'Jednotka',
                       choices=filter(lambda o: o[0][:4] == "body", UNITS))
    membertype = SelectField(u'Funkce',
                             choices=[('Member', u'Člen'),
                                      ('Coordinator', u'Koordinátor'),
                                      ('Vicepresident', u'Místopředseda'),
                                      ('President', u'Předseda')])
    since = DateField(u'Od',
                      format='%Y-%m-%d',
                      default=datetime.datetime.now())
    till = DateField(u'Do',
                     format='%Y-%m-%d',
                     default=add_years(datetime.datetime.now(), 2))
예제 #7
0
    def add_movies(self, url, movie_list=None, movie_ids=None, max_age=0):
        if not movie_list:
            movie_list = []
        if not movie_ids:
            movie_ids = []
        max_date = add_years(max_age * -1)
        logs.info(u"Retrieving the IMDB list: {}".format(url))

        (imdb_ids, imdb_titles, imdb_years) = self._handle_request(url)
        for i, imdb_id in enumerate(imdb_ids):
            # Skip already added movies
            if imdb_id in movie_ids:
                continue

            if self.tmdb:
                tmdb_data = self.tmdb.get_tmdb_from_imdb(imdb_id, 'movie')

            if tmdb_data and tmdb_data['release_date']:
                date = datetime.datetime.strptime(tmdb_data['release_date'],
                                                  '%Y-%m-%d')
            elif imdb_years[i]:
                date = datetime.datetime(int(str(imdb_years[i]).strip("()")),
                                         12, 31)
            else:
                date = datetime.date.today()

            # Skip old movies
            if max_age != 0 and (max_date > date):
                continue
            movie_list.append({
                'id':
                imdb_id,
                'tmdb_id':
                tmdb_data['id'] if tmdb_data else None,
                'title':
                tmdb_data['title'] if tmdb_data else imdb_titles[i],
                'year':
                date.year,
            })
            movie_ids.append(imdb_id)
            if tmdb_data and tmdb_data['id']:
                movie_ids.append('tmdb' + str(tmdb_data['id']))

        return movie_list, movie_ids
예제 #8
0
    def bump_cakeday(self, cakeday):
        if cakeday.db_id is None:
            log.warning(f"This cakeday doesn't exist: {cakeday.user}")

        c = self.dbConn.cursor()
        log.debug("Bumping cakeday one year")
        try:
            c.execute(
                '''
				UPDATE cakedays
				SET CakedayDate = ?
				WHERE ID = ?
			''', (utils.get_datetime_string(utils.add_years(cakeday.date_time,
                                                   1)), cakeday.db_id))
        except sqlite3.IntegrityError as err:
            log.warning(f"Failed to bump cakeday: {err}")
            return False

        self.dbConn.commit()

        return True
예제 #9
0
    def _remove_old_items_from_library(self, unmatched_items):
        logs.info(u"Removing symlinks for items "
                  "which no longer qualify ".format(
                      library=self.recipe['new_library']['name']))
        count = 0
        updated_paths = []
        deleted_items = []
        max_date = add_years((self.recipe['new_library']['max_age'] or 0) * -1)
        if self.library_type == 'movie':
            for movie in unmatched_items:
                if not self.recipe['new_library']['remove_from_library']:
                    # Only remove older than max_age
                    if not self.recipe['new_library']['max_age'] \
                            or (movie.originallyAvailableAt and
                                max_date < movie.originallyAvailableAt):
                        continue

                for part in movie.iterParts():
                    old_path_file = part.file
                    old_path, file_name = os.path.split(old_path_file)

                    folder_name = os.path.relpath(
                        old_path, self.recipe['new_library']['folder'])

                    if folder_name == '.':
                        new_path = os.path.join(
                            self.recipe['new_library']['folder'], file_name)
                        dir = False
                    else:
                        new_path = os.path.join(
                            self.recipe['new_library']['folder'], folder_name)
                        dir = True

                    if (dir and os.path.exists(new_path)) or (
                            not dir and os.path.isfile(new_path)):
                        try:
                            if os.name == 'nt':
                                # Python 3.2+ only
                                if sys.version_info < (3, 2):
                                    assert os.path.islink(new_path)
                                if dir:
                                    os.rmdir(new_path)
                                else:
                                    os.remove(new_path)
                            else:
                                assert os.path.islink(new_path)
                                os.unlink(new_path)
                            count += 1
                            deleted_items.append(movie)
                            updated_paths.append(new_path)
                        except Exception as e:
                            logs.error(u"Remove symlink failed for "
                                       "{path}: {e}".format(path=new_path,
                                                            e=e))
        else:
            for tv_show in unmatched_items:
                done = False
                if done:
                    continue
                for episode in tv_show.episodes():
                    if done:
                        break
                    for part in episode.iterParts():
                        if done:
                            break
                        old_path_file = part.file
                        old_path, file_name = os.path.split(old_path_file)

                        folder_name = ''
                        new_library_folder = \
                            self.recipe['new_library']['folder']
                        old_path = os.path.join(
                            new_library_folder,
                            old_path.replace(new_library_folder, '').strip(
                                os.sep).split(os.sep)[0])
                        folder_name = os.path.relpath(old_path,
                                                      new_library_folder)

                        new_path = os.path.join(
                            self.recipe['new_library']['folder'], folder_name)
                        if os.path.exists(new_path):
                            try:
                                if os.name == 'nt':
                                    # Python 3.2+ only
                                    if sys.version_info < (3, 2):
                                        assert os.path.islink(new_path)
                                    os.rmdir(new_path)
                                else:
                                    assert os.path.islink(new_path)
                                    os.unlink(new_path)
                                count += 1
                                deleted_items.append(tv_show)
                                updated_paths.append(new_path)
                                done = True
                                break
                            except Exception as e:
                                logs.error(u"Remove symlink failed for "
                                           "{path}: {e}".format(path=new_path,
                                                                e=e))
                        else:
                            done = True
                            break

        logs.info(u"Removed symlinks for {count} items.".format(count=count))
        for item in deleted_items:
            logs.info(u"{title} ({year})".format(title=item.title,
                                                 year=item.year))
예제 #10
0
    def _run(self):
        item_list = []  # TODO Replace with dict, scrap item_ids?
        item_ids = []
        force_imdb_id_match = False

        # Get the trakt lists
        for url in self.recipe['source_list_urls']:
            if 'api.trakt.tv' in url:
                (item_list, item_ids) = self.trakt.add_items(
                    self.library_type, url, item_list, item_ids,
                    self.recipe['new_library']['max_age'] or 0)
            elif 'imdb.com/chart' in url:
                (item_list, item_ids) = self.imdb.add_items(
                    self.library_type, url, item_list, item_ids,
                    self.recipe['new_library']['max_age'] or 0)
            else:
                raise Exception(
                    "Unsupported source list: {url}".format(url=url))

        if self.recipe['weighted_sorting']['enabled']:
            if self.config['tmdb']['api_key']:
                print(u"Getting data from TMDb to add weighted sorting...")
                item_list = self.weighted_sorting(item_list)
            else:
                print(u"Warning: TMDd API key is required "
                      u"for weighted sorting")

        # Get list of items from the Plex server
        source_libraries = []
        for library_config in self.source_library_config:
            print(u"Trying to match with items from the '{}' library ".format(
                library_config['name']))
            try:
                source_library = self.plex.server.library.section(
                    library_config['name'])
            except:  # FIXME
                raise Exception("The '{}' library does not exist".format(
                    library_config['name']))

            # FIXME: Hack until a new plexapi version is released. 3.0.4?
            if 'guid' not in source_library.ALLOWED_FILTERS:
                source_library.ALLOWED_FILTERS += ('guid', )

            source_libraries.append(source_library)

        # Create a list of matching items
        matching_items = []
        missing_items = []
        matching_total = 0
        nonmatching_idx = []
        max_count = self.recipe['new_library']['max_count']

        for i, item in enumerate(item_list):
            match = False
            if max_count > 0 and matching_total >= max_count:
                nonmatching_idx.append(i)
                continue
            res = []
            for source_library in source_libraries:
                lres = source_library.search(guid='imdb://' + str(item['id']))
                if not lres and item.get('tmdb_id'):
                    lres += source_library.search(guid='themoviedb://' +
                                                  str(item['tmdb_id']))
                if not lres and item.get('tvdb_id'):
                    lres += source_library.search(guid='thetvdb://' +
                                                  str(item['tvdb_id']))
                if lres:
                    res += lres
            if not res:
                missing_items.append((i, item))
                nonmatching_idx.append(i)
                continue

            for r in res:
                imdb_id = None
                tmdb_id = None
                tvdb_id = None
                if r.guid is not None and 'imdb://' in r.guid:
                    imdb_id = r.guid.split('imdb://')[1].split('?')[0]
                elif r.guid is not None and 'themoviedb://' in r.guid:
                    tmdb_id = r.guid.split('themoviedb://')[1].split('?')[0]
                elif r.guid is not None and 'thetvdb://' in r.guid:
                    tvdb_id = (r.guid.split('thetvdb://')[1].split('?')
                               [0].split('/')[0])

                if ((imdb_id and imdb_id == str(item['id']))
                        or (tmdb_id and tmdb_id == str(item['tmdb_id']))
                        or (tvdb_id and tvdb_id == str(item['tvdb_id']))):
                    if not match:
                        match = True
                        matching_total += 1
                    matching_items.append(r)

            if match:
                if self.recipe['new_library']['sort_title']['absolute']:
                    print(u"{} {} ({})".format(i + 1, item['title'],
                                               item['year']))
                else:
                    print(u"{} {} ({})".format(matching_total, item['title'],
                                               item['year']))
            else:
                missing_items.append((i, item))
                nonmatching_idx.append(i)

        if not self.recipe['new_library']['sort_title']['absolute']:
            for i in reversed(nonmatching_idx):
                del item_list[i]

        # Create symlinks for all items in your library on the trakt watched
        print(u"Creating symlinks for {count} matching items in the "
              u"library...".format(count=matching_total))

        try:
            if not os.path.exists(self.recipe['new_library']['folder']):
                os.mkdir(self.recipe['new_library']['folder'])
        except:
            print(u"Unable to create the new library folder "
                  u"'{folder}'.".format(
                      folder=self.recipe['new_library']['folder']))
            print(u"Exiting script.")
            return 0

        count = 0
        updated_paths = []
        new_items = []
        if self.library_type == 'movie':
            for movie in matching_items:
                for part in movie.iterParts():
                    old_path_file = part.file
                    old_path, file_name = os.path.split(old_path_file)

                    folder_name = ''
                    for library_config in self.source_library_config:
                        for f in library_config['folders']:
                            f = os.path.abspath(f)
                            if old_path.lower().startswith(f.lower()):
                                folder_name = os.path.relpath(old_path, f)
                                break
                        else:
                            continue

                        if folder_name == '.':
                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                file_name)
                            dir = False
                        else:
                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                folder_name)
                            dir = True
                            parent_path = os.path.dirname(
                                os.path.abspath(new_path))
                            if not os.path.exists(parent_path):
                                try:
                                    os.makedirs(parent_path)
                                except OSError as e:
                                    if e.errno == errno.EEXIST \
                                            and os.path.isdir(parent_path):
                                        pass
                                    else:
                                        raise
                            # Clean up old, empty directories
                            if os.path.exists(new_path) \
                                    and not os.listdir(new_path):
                                os.rmdir(new_path)

                        if (dir and not os.path.exists(new_path)) \
                                or not dir and not os.path.isfile(new_path):
                            try:
                                if os.name == 'nt':
                                    if dir:
                                        subprocess.call([
                                            'mklink', '/D', new_path, old_path
                                        ],
                                                        shell=True)
                                    else:
                                        subprocess.call([
                                            'mklink', new_path, old_path_file
                                        ],
                                                        shell=True)
                                else:
                                    if dir:
                                        os.symlink(old_path, new_path)
                                    else:
                                        os.symlink(old_path_file, new_path)
                                count += 1
                                new_items.append(movie)
                                updated_paths.append(new_path)
                            except Exception as e:
                                print(u"Symlink failed for {path}: {e}".format(
                                    path=new_path, e=e))
        else:
            for tv_show in matching_items:
                done = False
                if done:
                    continue
                for episode in tv_show.episodes():
                    if done:
                        break
                    for part in episode.iterParts():
                        old_path_file = part.file
                        old_path, file_name = os.path.split(old_path_file)

                        folder_name = ''
                        for library_config in self.source_library_config:
                            for f in library_config['folders']:
                                if old_path.lower().startswith(f.lower()):
                                    old_path = os.path.join(
                                        f,
                                        old_path.replace(f, '').strip(
                                            os.sep).split(os.sep)[0])
                                    folder_name = os.path.relpath(old_path, f)
                                    break
                            else:
                                continue

                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                folder_name)

                            if not os.path.exists(new_path):
                                try:
                                    if os.name == 'nt':
                                        subprocess.call([
                                            'mklink', '/D', new_path, old_path
                                        ],
                                                        shell=True)
                                    else:
                                        os.symlink(old_path, new_path)
                                    count += 1
                                    new_items.append(tv_show)
                                    updated_paths.append(new_path)
                                    done = True
                                    break
                                except Exception as e:
                                    print(u"Symlink failed for {path}: {e}".
                                          format(path=new_path, e=e))
                            else:
                                done = True
                                break

        print(u"Created symlinks for {count} new items:".format(count=count))
        for item in new_items:
            print(u"{title} ({year})".format(title=item.title, year=item.year))

        # Check if the new library exists in Plex
        print(u"Creating the '{}' library in Plex...".format(
            self.recipe['new_library']['name']))
        try:
            new_library = self.plex.server.library.section(
                self.recipe['new_library']['name'])
            print(u"Library already exists in Plex. Scanning the library...")

            new_library.update()
        except plexapi.exceptions.NotFound:
            self.plex.create_new_library(self.recipe['new_library']['name'],
                                         self.recipe['new_library']['folder'],
                                         self.library_type)
            new_library = self.plex.server.library.section(
                self.recipe['new_library']['name'])

        # Wait for metadata to finish downloading before continuing
        print(u"Waiting for metadata to finish downloading...")
        new_library = self.plex.server.library.section(
            self.recipe['new_library']['name'])
        while new_library.refreshing:
            time.sleep(5)
            new_library = self.plex.server.library.section(
                self.recipe['new_library']['name'])

        # Retrieve a list of items from the new library
        print(u"Retrieving a list of items from the '{library}' library in "
              u"Plex...".format(library=self.recipe['new_library']['name']))
        all_new_items = new_library.all()

        # Create a dictionary of {imdb_id: item}
        imdb_map = {}
        for m in all_new_items:
            imdb_id = None
            tmdb_id = None
            tvdb_id = None
            if m.guid is not None and 'imdb://' in m.guid:
                imdb_id = m.guid.split('imdb://')[1].split('?')[0]
            elif m.guid is not None and 'themoviedb://' in m.guid:
                tmdb_id = m.guid.split('themoviedb://')[1].split('?')[0]
            elif m.guid is not None and 'thetvdb://' in m.guid:
                tvdb_id = (
                    m.guid.split('thetvdb://')[1].split('?')[0].split('/')[0])
            else:
                imdb_id = None

            if imdb_id and str(imdb_id) in item_ids:
                imdb_map[imdb_id] = m
            elif tmdb_id and ('tmdb' + str(tmdb_id)) in item_ids:
                imdb_map['tmdb' + str(tmdb_id)] = m
            elif tvdb_id and ('tvdb' + str(tvdb_id)) in item_ids:
                imdb_map['tvdb' + str(tvdb_id)] = m
            elif force_imdb_id_match:
                # Only IMDB ID found for some items
                if tmdb_id:
                    imdb_id = self.tmdb.get_imdb_id(tmdb_id)
                elif tvdb_id:
                    imdb_id = self.tvdb.get_imdb_id(tvdb_id)
                if imdb_id and str(imdb_id) in item_ids:
                    imdb_map[imdb_id] = m
                else:
                    imdb_map[m.ratingKey] = m
            else:
                imdb_map[m.ratingKey] = m

        # Modify the sort titles
        if self.recipe['new_library']['sort']:
            print(u"Setting the sort titles for the '{}' library...".format(
                self.recipe['new_library']['name']))
        if self.recipe['new_library']['sort_title']['absolute']:
            for i, m in enumerate(item_list):
                item = imdb_map.pop(m['id'], None)
                if not item:
                    item = imdb_map.pop('tmdb' + str(m.get('tmdb_id', '')),
                                        None)
                if not item:
                    item = imdb_map.pop('tvdb' + str(m.get('tvdb_id', '')),
                                        None)
                if item and self.recipe['new_library']['sort']:
                    self.plex.set_sort_title(
                        new_library.key, item.ratingKey, i + 1, m['title'],
                        self.library_type,
                        self.recipe['new_library']['sort_title']['format'],
                        self.recipe['new_library']['sort_title']['visible'])
        else:
            i = 0
            for m in item_list:
                item = imdb_map.pop(m['id'], None)
                if not item:
                    item = imdb_map.pop('tmdb' + str(m.get('tmdb_id', '')),
                                        None)
                if not item:
                    item = imdb_map.pop('tvdb' + str(m.get('tvdb_id', '')),
                                        None)
                if item and self.recipe['new_library']['sort']:
                    i += 1
                    self.plex.set_sort_title(
                        new_library.key, item.ratingKey, i, m['title'],
                        self.library_type,
                        self.recipe['new_library']['sort_title']['format'],
                        self.recipe['new_library']['sort_title']['visible'])

        if self.recipe['new_library']['remove_from_library'] \
                or self.recipe['new_library'].get('remove_old', False):
            # Remove items from the new library which no longer qualify
            print(u"Removing symlinks for items "
                  "which no longer qualify ".format(
                      library=self.recipe['new_library']['name']))
            count = 0
            updated_paths = []
            deleted_items = []
            max_date = add_years(
                (self.recipe['new_library']['max_age'] or 0) * -1)
            if self.library_type == 'movie':
                for movie in imdb_map.values():
                    if not self.recipe['new_library']['remove_from_library']:
                        # Only remove older than max_age
                        if not self.recipe['new_library']['max_age'] \
                                or (max_date < movie.originallyAvailableAt):
                            continue

                    for part in movie.iterParts():
                        old_path_file = part.file
                        old_path, file_name = os.path.split(old_path_file)

                        folder_name = os.path.relpath(
                            old_path, self.recipe['new_library']['folder'])

                        if folder_name == '.':
                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                file_name)
                            dir = False
                        else:
                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                folder_name)
                            dir = True

                        if (dir and os.path.exists(new_path)) or (
                                not dir and os.path.isfile(new_path)):
                            try:
                                if os.name == 'nt':
                                    # Python 3.2+ only
                                    if sys.version_info < (3, 2):
                                        assert os.path.islink(new_path)
                                    if dir:
                                        os.rmdir(new_path)
                                    else:
                                        os.remove(new_path)
                                else:
                                    assert os.path.islink(new_path)
                                    os.unlink(new_path)
                                count += 1
                                deleted_items.append(movie)
                                updated_paths.append(new_path)
                            except Exception as e:
                                print(u"Remove symlink failed for "
                                      "{path}: {e}".format(path=new_path, e=e))
            else:
                for tv_show in imdb_map.values():
                    done = False
                    if done:
                        continue
                    for episode in tv_show.episodes():
                        if done:
                            break
                        for part in episode.iterParts():
                            if done:
                                break
                            old_path_file = part.file
                            old_path, file_name = os.path.split(old_path_file)

                            folder_name = ''
                            new_library_folder = \
                                self.recipe['new_library']['folder']
                            old_path = os.path.join(
                                new_library_folder,
                                old_path.replace(new_library_folder, '').strip(
                                    os.sep).split(os.sep)[0])
                            folder_name = os.path.relpath(
                                old_path, new_library_folder)

                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                folder_name)
                            if os.path.exists(new_path):
                                try:
                                    if os.name == 'nt':
                                        # Python 3.2+ only
                                        if sys.version_info < (3, 2):
                                            assert os.path.islink(new_path)
                                        os.rmdir(new_path)
                                    else:
                                        assert os.path.islink(new_path)
                                        os.unlink(new_path)
                                    count += 1
                                    deleted_items.append(tv_show)
                                    updated_paths.append(new_path)
                                    done = True
                                    break
                                except Exception as e:
                                    print(u"Remove symlink failed for "
                                          "{path}: {e}".format(path=new_path,
                                                               e=e))
                            else:
                                done = True
                                break

            print(u"Removed symlinks for {count} items.".format(count=count))
            for item in deleted_items:
                print(u"{title} ({year})".format(title=item.title,
                                                 year=item.year))

            # Scan the library to clean up the deleted items
            print(u"Scanning the '{library}' library...".format(
                library=self.recipe['new_library']['name']))
            new_library.update()
            time.sleep(10)
            new_library = self.plex.server.library.section(
                self.recipe['new_library']['name'])
            while new_library.refreshing:
                time.sleep(5)
                new_library = self.plex.server.library.section(
                    self.recipe['new_library']['name'])
            new_library.emptyTrash()
            all_new_items = new_library.all()
        else:
            while imdb_map:
                imdb_id, item = imdb_map.popitem()
                i += 1
                self.plex.set_sort_title(
                    new_library.key, item.ratingKey, i, item.title,
                    self.library_type,
                    self.recipe['new_library']['sort_title']['format'],
                    self.recipe['new_library']['sort_title']['visible'])

        return missing_items, len(all_new_items)
예제 #11
0
    def _run(self):
        force_imdb_id_match = False

        item_list, item_ids = self._get_source_list_urls()
        item_list = self._apply_weighted_sorting(item_list)
        source_libraries = self._get_source_libraries()

        # Create a list of matching items
        matching_items = []
        missing_items = []
        matching_total = 0
        nonmatching_idx = []
        max_count = self.recipe['new_library']['max_count']

        for i, item in enumerate(item_list):
            match = False
            if max_count > 0 and matching_total >= max_count:
                nonmatching_idx.append(i)
                continue

            results = self._get_show_results(source_libraries, item)
            if not results:
                missing_items.append((i, item))
                nonmatching_idx.append(i)
                continue

            for result in results:
                imdb_id, tmdb_id, tvdb_id = self._get_show_ids(result)

                if self._imdb_matches(imdb_id, item) or \
                    self._tmdb_matches(tmdb_id, item) or \
                    self._tvdb_matches(tvdb_id, item):

                    if not match:
                        match = True
                        matching_total += 1

                    matching_items.append(result)

            if match:
                if self.recipe['new_library']['sort_title']['absolute']:
                    print(u"{} {} ({})".format(i + 1, item['title'],
                                               item['year']))
                else:
                    print(u"{} {} ({})".format(matching_total, item['title'],
                                               item['year']))
            else:
                missing_items.append((i, item))
                nonmatching_idx.append(i)

        if not self.recipe['new_library']['sort_title']['absolute']:
            for i in reversed(nonmatching_idx):
                del item_list[i]

        # Create symlinks for all items in your library on the trakt watched
        print("""
            Creating symlinks for {count} matching items in the 
            library...""".format( \
                count=matching_total))

        try:
            if not os.path.exists(self.recipe['new_library']['folder']):
                os.mkdir(self.recipe['new_library']['folder'])
        except:
            print(u"Unable to create the new library folder "
                  u"'{folder}'.".format(
                      folder=self.recipe['new_library']['folder']))
            print(u"Exiting script.")
            return 0

        count = 0
        updated_paths = []
        new_items = []
        if self.library_type == 'movie':
            for movie in matching_items:
                for part in movie.iterParts():
                    old_path_file = part.file
                    old_path, file_name = os.path.split(old_path_file)

                    folder_name = ''
                    for library_config in self.source_library_config:
                        for fldr in library_config['folders']:
                            fldr = os.path.abspath(fldr)
                            if old_path.lower().startswith(fldr.lower()):
                                folder_name = os.path.relpath(old_path, fldr)
                                break
                        else:
                            continue

                        if folder_name == '.':
                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                file_name)
                            drct = False
                        else:
                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                folder_name)
                            drct = True
                            parent_path = os.path.dirname(
                                os.path.abspath(new_path))
                            if not os.path.exists(parent_path):
                                try:
                                    os.makedirs(parent_path)
                                except OSError as err:
                                    if err.errno == errno.EEXIST \
                                            and os.path.isdir(parent_path):
                                        pass
                                    else:
                                        raise
                            # Clean up old, empty directories
                            if os.path.exists(new_path) \
                                    and not os.listdir(new_path):
                                os.rmdir(new_path)

                        if (drct and not os.path.exists(new_path)) \
                                or not drct and not os.path.isfile(new_path):
                            try:
                                if os.name == 'nt':
                                    if drct:
                                        subprocess.call([
                                            'mklink', '/D', new_path, old_path
                                        ],
                                                        shell=True)
                                    else:
                                        subprocess.call([
                                            'mklink', new_path, old_path_file
                                        ],
                                                        shell=True)
                                else:
                                    if drct:
                                        os.symlink(old_path, new_path)
                                    else:
                                        os.symlink(old_path_file, new_path)
                                count += 1
                                new_items.append(movie)
                                updated_paths.append(new_path)
                            except Exception as err:
                                print(u"Symlink failed for {path}: {error}".
                                      format(path=new_path, error=err))
        else:
            for tv_show in matching_items:
                done = False
                if done:
                    continue
                for episode in tv_show.episodes():
                    if done:
                        break
                    for part in episode.iterParts():
                        old_path_file = part.file
                        old_path, file_name = os.path.split(old_path_file)

                        folder_name = ''
                        for library_config in self.source_library_config:
                            for fldr in library_config['folders']:
                                if old_path.lower().startswith(fldr.lower()):
                                    old_path = \
                                        os.path.join(fldr, \
                                            old_path.replace(fldr, \
                                                '').strip(os.sep).split( \
                                                    os.sep)[0])
                                    folder_name = os.path.relpath(
                                        old_path, fldr)
                                    break
                            else:
                                continue

                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                folder_name)

                            if not os.path.exists(new_path):
                                try:
                                    if os.name == 'nt':
                                        subprocess.call([
                                            'mklink', '/D', new_path, old_path
                                        ],
                                                        shell=True)
                                    else:
                                        os.symlink(old_path, new_path)
                                    count += 1
                                    new_items.append(tv_show)
                                    updated_paths.append(new_path)
                                    done = True
                                    break
                                except Exception as err:
                                    print(
                                        u"Symlink failed for {path}: {error}".
                                        format(path=new_path, error=err))
                            else:
                                done = True
                                break

        print(u"Created symlinks for {count} new items:".format(count=count))
        for item in new_items:
            print(u"{title} ({year})".format(title=item.title, year=item.year))

        # Check if the new library exists in Plex
        print(u"Creating the '{}' library in Plex...".format(
            self.recipe['new_library']['name']))
        try:
            new_library = self.plex.server.library.section(
                self.recipe['new_library']['name'])
            print(u"Library already exists in Plex. Scanning the library...")

            new_library.update()
        except plexapi.exceptions.NotFound:
            self.plex.create_new_library(self.recipe['new_library']['name'],
                                         self.recipe['new_library']['folder'],
                                         self.library_type)
            new_library = self.plex.server.library.section(
                self.recipe['new_library']['name'])

        # Wait for metadata to finish downloading before continuing
        print(u"Waiting for metadata to finish downloading...")
        new_library = self.plex.server.library.section(
            self.recipe['new_library']['name'])
        while new_library.refreshing:
            time.sleep(5)
            new_library = self.plex.server.library.section(
                self.recipe['new_library']['name'])

        # Retrieve a list of items from the new library
        print(u"Retrieving a list of items from the '{library}' library in "
              u"Plex...".format(library=self.recipe['new_library']['name']))
        all_new_items = new_library.all()

        # Create a dictionary of {imdb_id: item}
        imdb_map = {}
        for mymovie in all_new_items:
            imdb_id = None
            tmdb_id = None
            tvdb_id = None
            if mymovie.guid is not None and 'imdb://' in mymovie.guid:
                imdb_id = mymovie.guid.split('imdb://')[1].split('?')[0]
            elif mymovie.guid is not None and 'themoviedb://' in mymovie.guid:
                tmdb_id = mymovie.guid.split('themoviedb://')[1].split('?')[0]
            elif mymovie.guid is not None and 'thetvdb://' in mymovie.guid:
                tvdb_id = ( \
                    mymovie.guid.split('thetvdb://')[1].split('?')[0].split('/')[0])
            else:
                imdb_id = None

            if imdb_id and str(imdb_id) in item_ids:
                imdb_map[imdb_id] = mymovie
            elif tmdb_id and ('tmdb' + str(tmdb_id)) in item_ids:
                imdb_map['tmdb' + str(tmdb_id)] = mymovie
            elif tvdb_id and ('tvdb' + str(tvdb_id)) in item_ids:
                imdb_map['tvdb' + str(tvdb_id)] = mymovie
            elif force_imdb_id_match:
                # Only IMDB ID found for some items
                if tmdb_id:
                    imdb_id = self.tmdb.get_imdb_id(tmdb_id)
                elif tvdb_id:
                    imdb_id = self.tvdb.get_imdb_id(tvdb_id)
                if imdb_id and str(imdb_id) in item_ids:
                    imdb_map[imdb_id] = mymovie
                else:
                    imdb_map[mymovie.ratingKey] = mymovie
            else:
                imdb_map[mymovie.ratingKey] = mymovie

        # Modify the sort titles
        if self.recipe['new_library']['sort']:
            print(u"Setting the sort titles for the '{}' library...".format(
                self.recipe['new_library']['name']))
        if self.recipe['new_library']['sort_title']['absolute']:
            for i, mymovie in enumerate(item_list):
                item = imdb_map.pop(mymovie['id'], None)
                if not item:
                    item = imdb_map.pop(
                        'tmdb' + str(mymovie.get('tmdb_id', '')), None)
                if not item:
                    item = imdb_map.pop(
                        'tvdb' + str(mymovie.get('tvdb_id', '')), None)
                if item and self.recipe['new_library']['sort']:
                    self.plex.set_sort_title(
                        new_library.key, item.ratingKey, i + 1,
                        mymovie['title'], self.library_type,
                        self.recipe['new_library']['sort_title']['format'],
                        self.recipe['new_library']['sort_title']['visible'])
        else:
            i = 0
            for mymovie in item_list:
                item = imdb_map.pop(mymovie['id'], None)
                if not item:
                    item = imdb_map.pop(
                        'tmdb' + str(mymovie.get('tmdb_id', '')), None)
                if not item:
                    item = imdb_map.pop(
                        'tvdb' + str(mymovie.get('tvdb_id', '')), None)
                if item and self.recipe['new_library']['sort']:
                    i += 1
                    self.plex.set_sort_title(
                        new_library.key, item.ratingKey, i, mymovie['title'],
                        self.library_type,
                        self.recipe['new_library']['sort_title']['format'],
                        self.recipe['new_library']['sort_title']['visible'])

        if self.recipe['new_library']['remove_from_library'] \
                or self.recipe['new_library'].get('remove_old', False):
            # Remove items from the new library which no longer qualify
            print(u"Removing symlinks for items "
                  "which no longer qualify ".format(
                      library=self.recipe['new_library']['name']))
            count = 0
            updated_paths = []
            deleted_items = []
            max_date = add_years(
                (self.recipe['new_library']['max_age'] or 0) * -1)
            if self.library_type == 'movie':
                for movie in imdb_map.values():
                    if not self.recipe['new_library']['remove_from_library']:
                        # Only remove older than max_age
                        if not self.recipe['new_library']['max_age'] \
                                or (max_date < movie.originallyAvailableAt):
                            continue

                    for part in movie.iterParts():
                        old_path_file = part.file
                        old_path, file_name = os.path.split(old_path_file)

                        folder_name = os.path.relpath(
                            old_path, self.recipe['new_library']['folder'])

                        if folder_name == '.':
                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                file_name)
                            drct = False
                        else:
                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                folder_name)
                            drct = True

                        if (drct and os.path.exists(new_path)) or (
                                not drct and os.path.isfile(new_path)):
                            try:
                                if os.name == 'nt':
                                    # Python 3.2+ only
                                    if sys.version_info < (3, 2):
                                        assert os.path.islink(new_path)
                                    if drct:
                                        os.rmdir(new_path)
                                    else:
                                        os.remove(new_path)
                                else:
                                    assert os.path.islink(new_path)
                                    os.unlink(new_path)
                                count += 1
                                deleted_items.append(movie)
                                updated_paths.append(new_path)
                            except Exception as err:
                                print(u"Remove symlink failed for "
                                      "{path}: {error}".format(path=new_path,
                                                               error=err))
            else:
                for tv_show in imdb_map.values():
                    done = False
                    if done:
                        continue
                    for episode in tv_show.episodes():
                        if done:
                            break
                        for part in episode.iterParts():
                            if done:
                                break
                            old_path_file = part.file
                            old_path, file_name = os.path.split(old_path_file)

                            folder_name = ''
                            new_library_folder = \
                                self.recipe['new_library']['folder']
                            old_path = os.path.join(
                                new_library_folder,
                                old_path.replace(new_library_folder, '').strip(
                                    os.sep).split(os.sep)[0])
                            folder_name = os.path.relpath(
                                old_path, new_library_folder)

                            new_path = os.path.join(
                                self.recipe['new_library']['folder'],
                                folder_name)
                            if os.path.exists(new_path):
                                try:
                                    if os.name == 'nt':
                                        # Python 3.2+ only
                                        if sys.version_info < (3, 2):
                                            assert os.path.islink(new_path)
                                        os.rmdir(new_path)
                                    else:
                                        assert os.path.islink(new_path)
                                        os.unlink(new_path)
                                    count += 1
                                    deleted_items.append(tv_show)
                                    updated_paths.append(new_path)
                                    done = True
                                    break
                                except Exception as err:
                                    print(u"Remove symlink failed for "
                                          "{path}: {e}".format(path=new_path,
                                                               err=err))
                            else:
                                done = True
                                break

            print(u"Removed symlinks for {count} items.".format(count=count))
            for item in deleted_items:
                print(u"{title} ({year})".format(title=item.title,
                                                 year=item.year))

            # Scan the library to clean up the deleted items
            print(u"Scanning the '{library}' library...".format(
                library=self.recipe['new_library']['name']))
            new_library.update()
            time.sleep(10)
            new_library = self.plex.server.library.section(
                self.recipe['new_library']['name'])
            while new_library.refreshing:
                time.sleep(5)
                new_library = self.plex.server.library.section(
                    self.recipe['new_library']['name'])
            new_library.emptyTrash()
            all_new_items = new_library.all()
        else:
            while imdb_map:
                imdb_id, item = imdb_map.popitem()
                i += 1
                self.plex.set_sort_title(
                    new_library.key, item.ratingKey, i, item.title,
                    self.library_type,
                    self.recipe['new_library']['sort_title']['format'],
                    self.recipe['new_library']['sort_title']['visible'])

        return missing_items, len(all_new_items)